From 65ec100f6a13c0ee9b6edecd2b81552373fa70a0 Mon Sep 17 00:00:00 2001 From: Stephan Witt Date: Sat, 5 Aug 2023 08:56:35 +0200 Subject: [PATCH] #12576 improved file name chooser implementation for GUI dialogs - code reorganization to move the file name chooser methods in GuiDialog class - on Mac add explicit raise of the current dialog window on close of the file browser to work around the bug 12576 --- src/frontends/qt/GuiBibtex.cpp | 4 +- src/frontends/qt/GuiBibtex.h | 4 +- src/frontends/qt/GuiCompare.cpp | 2 +- src/frontends/qt/GuiCompare.h | 2 +- src/frontends/qt/GuiDialog.cpp | 128 +++++++++++++++++++++++++++- src/frontends/qt/GuiDialog.h | 66 +++++++++++++++ src/frontends/qt/GuiExternal.cpp | 2 +- src/frontends/qt/GuiExternal.h | 2 +- src/frontends/qt/GuiGraphics.cpp | 2 +- src/frontends/qt/GuiGraphics.h | 2 +- src/frontends/qt/GuiInclude.cpp | 2 +- src/frontends/qt/GuiInclude.h | 2 +- src/frontends/qt/GuiPrefs.cpp | 140 ++++--------------------------- src/frontends/qt/GuiPrefs.h | 2 +- src/frontends/qt/qt_helpers.h | 41 --------- 15 files changed, 220 insertions(+), 181 deletions(-) diff --git a/src/frontends/qt/GuiBibtex.cpp b/src/frontends/qt/GuiBibtex.cpp index b9c928a2de..757c2c95e4 100644 --- a/src/frontends/qt/GuiBibtex.cpp +++ b/src/frontends/qt/GuiBibtex.cpp @@ -491,7 +491,7 @@ void GuiBibtex::applyView() } -QString GuiBibtex::browseBib(QString const & in_name) const +QString GuiBibtex::browseBib(QString const & in_name) { QString const label1 = qt_("D&ocuments"); QString const dir1 = toqstr(lyxrc.document_path); @@ -501,7 +501,7 @@ QString GuiBibtex::browseBib(QString const & in_name) const } -QString GuiBibtex::browseBst(QString const & in_name) const +QString GuiBibtex::browseBst(QString const & in_name) { QString const label1 = qt_("D&ocuments"); QString const dir1 = toqstr(lyxrc.document_path); diff --git a/src/frontends/qt/GuiBibtex.h b/src/frontends/qt/GuiBibtex.h index 5d54be7554..bd0a0ea536 100644 --- a/src/frontends/qt/GuiBibtex.h +++ b/src/frontends/qt/GuiBibtex.h @@ -56,9 +56,9 @@ private: void updateContents() override; /// Browse for a .bib file - QString browseBib(QString const & in_name) const; + QString browseBib(QString const & in_name); /// Browse for a .bst file - QString browseBst(QString const & in_name) const; + QString browseBst(QString const & in_name); /// get the list of bst files QStringList bibStyles() const; /// get the list of bib files diff --git a/src/frontends/qt/GuiCompare.cpp b/src/frontends/qt/GuiCompare.cpp index e485ec0a54..7a58c7a8cd 100644 --- a/src/frontends/qt/GuiCompare.cpp +++ b/src/frontends/qt/GuiCompare.cpp @@ -153,7 +153,7 @@ void GuiCompare::selectOldFile() } -QString GuiCompare::browse(QString const & in_name) const +QString GuiCompare::browse(QString const & in_name) { QString const title = qt_("Select document"); diff --git a/src/frontends/qt/GuiCompare.h b/src/frontends/qt/GuiCompare.h index e71a13139e..9538083e90 100644 --- a/src/frontends/qt/GuiCompare.h +++ b/src/frontends/qt/GuiCompare.h @@ -80,7 +80,7 @@ private: void enableControls(bool enable); /// browse for a file - QString browse(QString const & in_name) const; + QString browse(QString const & in_name); /// retrieve the buffer from the specified filename Buffer const * bufferFromFileName(std::string const & file) const; diff --git a/src/frontends/qt/GuiDialog.cpp b/src/frontends/qt/GuiDialog.cpp index 70d086c7f8..67793df023 100644 --- a/src/frontends/qt/GuiDialog.cpp +++ b/src/frontends/qt/GuiDialog.cpp @@ -10,12 +10,14 @@ #include +#include "FileDialog.h" +#include "GuiApplication.h" #include "GuiDialog.h" - #include "GuiView.h" #include "qt_helpers.h" #include "support/debug.h" +#include "support/filetools.h" #include #include @@ -156,6 +158,130 @@ void GuiDialog::updateView() setUpdatesEnabled(true); } +QString GuiDialog::browseFile(QString const & filename, + QString const & title, + QStringList const & filters, + bool save, + QString const & label1, + QString const & dir1, + QString const & label2, + QString const & dir2, + QString const & fallback_dir) +{ + QString lastPath = "."; + if (!filename.isEmpty()) + lastPath = onlyPath(filename); + else if(!fallback_dir.isEmpty()) + lastPath = fallback_dir; + + FileDialog dlg(title); + dlg.setButton1(label1, dir1); + dlg.setButton2(label2, dir2); + + FileDialog::Result result; + + if (save) + result = dlg.save(lastPath, filters, onlyFileName(filename)); + else + result = dlg.open(lastPath, filters, onlyFileName(filename)); + + if (guiApp->platformName() == "cocoa") { + QWidget * dialog = asQWidget(); + dialog->raise(); + dialog->activateWindow(); + } + + return result.second; +} + + +/** Launch a file dialog and return the chosen directory. + pathname: a suggested pathname. + title: the title of the dialog. + dir1 = (name, dir), dir2 = (name, dir): extra buttons on the dialog. +*/ +QString GuiDialog::browseDir(QString const & pathname, + QString const & title, + QString const & label1, + QString const & dir1, + QString const & label2, + QString const & dir2) +{ + QString lastPath = "."; + if (!pathname.isEmpty()) + lastPath = onlyPath(pathname); + + FileDialog dlg(title); + dlg.setButton1(label1, dir1); + dlg.setButton2(label2, dir2); + + FileDialog::Result const result = + dlg.opendir(lastPath, onlyFileName(pathname)); + + if (guiApp->platformName() == "cocoa") { + QWidget * dialog = asQWidget(); + dialog->raise(); + dialog->activateWindow(); + } + + return result.second; +} + +QString GuiDialog::browseRelToParent( + QString const & filename, + QString const & relpath, + QString const & title, + QStringList const & filters, + bool save, + QString const & label1, + QString const & dir1, + QString const & label2, + QString const & dir2) +{ + QString const fname = makeAbsPath(filename, relpath); + + QString const outname = + browseFile(fname, title, filters, save, label1, dir1, label2, dir2); + + QString const reloutname = + toqstr(support::makeRelPath(qstring_to_ucs4(outname), qstring_to_ucs4(relpath))); + + if (reloutname.startsWith("../")) + return outname; + else + return reloutname; +} + + +QString GuiDialog::browseRelToSub( + QString const & filename, + QString const & relpath, + QString const & title, + QStringList const & filters, + bool save, + QString const & label1, + QString const & dir1, + QString const & label2, + QString const & dir2) +{ + QString const fname = makeAbsPath(filename, relpath); + + QString const outname = + browseFile(fname, title, filters, save, label1, dir1, label2, dir2); + + QString const reloutname = + toqstr(support::makeRelPath(qstring_to_ucs4(outname), qstring_to_ucs4(relpath))); + + QString testname = reloutname; + testname.remove(QRegularExpression("^(\\.\\./)+")); + + if (testname.contains("/")) + return outname; + else + return reloutname; +} + + } // namespace frontend } // namespace lyx diff --git a/src/frontends/qt/GuiDialog.h b/src/frontends/qt/GuiDialog.h index 160357dbc6..50910f434c 100644 --- a/src/frontends/qt/GuiDialog.h +++ b/src/frontends/qt/GuiDialog.h @@ -112,6 +112,72 @@ public: /// Update the display of the dialog whilst it is still visible. void updateView() override; + + /** Launch a file dialog and return the chosen file. + filename: a suggested filename. + title: the title of the dialog. + filters: *.ps etc. + dir1 = (name, dir), dir2 = (name, dir): extra buttons on the dialog. + */ + QString browseFile(QString const & filename, + QString const & title, + QStringList const & filters, + bool save = false, + QString const & label1 = QString(), + QString const & dir1 = QString(), + QString const & label2 = QString(), + QString const & dir2 = QString(), + QString const & fallback_dir = QString()); + /** Launch a file dialog and return the chosen directory. + pathname: a suggested pathname. + title: the title of the dialog. + dir1 = (name, dir), dir2 = (name, dir): extra buttons on the dialog. + */ + QString browseDir(QString const & pathname, + QString const & title, + QString const & label1 = QString(), + QString const & dir1 = QString(), + QString const & label2 = QString(), + QString const & dir2 = QString()); + /** Wrappers around browseFile which try to provide a filename relative to relpath. + + \param title: title for dialog + + \param filters: *.ps, etc + + \param save: whether to save dialog info (current path, etc) for next use. + + The \param labelN and \param dirN arguments provide for extra buttons + in the dialog (e.g., "Templates" and a path to that directory). + + The difference between the functions concerns when we think we have a + relative path. + + In \c browseRelToParent, we return a relative path only if it IS NOT of + the form "../../foo.txt". + + In \c browseRelToSub, we return a relative path only if it IS of the + form "../../foo.txt". + */ + QString browseRelToParent(QString const & filename, + QString const & relpath, + QString const & title, + QStringList const & filters, + bool save = false, + QString const & label1 = QString(), + QString const & dir1 = QString(), + QString const & label2 = QString(), + QString const & dir2 = QString()); + QString browseRelToSub(QString const & filename, + QString const & relpath, + QString const & title, + QStringList const & filters, + bool save = false, + QString const & label1 = QString(), + QString const & dir1 = QString(), + QString const & label2 = QString(), + QString const & dir2 = QString()); + private: ButtonController bc_; /// are we updating ? diff --git a/src/frontends/qt/GuiExternal.cpp b/src/frontends/qt/GuiExternal.cpp index 372053af3b..c88be8cdb8 100644 --- a/src/frontends/qt/GuiExternal.cpp +++ b/src/frontends/qt/GuiExternal.cpp @@ -682,7 +682,7 @@ static QStringList templateFilters(QString const & template_name) QString GuiExternal::browse(QString const & input, - QString const & template_name) const + QString const & template_name) { QString const title = qt_("Select external file"); QString const bufpath = bufferFilePath(); diff --git a/src/frontends/qt/GuiExternal.h b/src/frontends/qt/GuiExternal.h index d83b1138c3..dfb6c5fec1 100644 --- a/src/frontends/qt/GuiExternal.h +++ b/src/frontends/qt/GuiExternal.h @@ -68,7 +68,7 @@ private: /// QString browse(QString const & input_file, - QString const & template_name) const; + QString const & template_name); /// MapType extra_; diff --git a/src/frontends/qt/GuiGraphics.cpp b/src/frontends/qt/GuiGraphics.cpp index 6801f4c5d0..7ba70fb07a 100644 --- a/src/frontends/qt/GuiGraphics.cpp +++ b/src/frontends/qt/GuiGraphics.cpp @@ -823,7 +823,7 @@ void GuiGraphics::dispatchParams() } -QString GuiGraphics::browse(QString const & in_name) const +QString GuiGraphics::browse(QString const & in_name) { QString const title = qt_("Select graphics file"); diff --git a/src/frontends/qt/GuiGraphics.h b/src/frontends/qt/GuiGraphics.h index 2687c0836b..68ef7ddc5e 100644 --- a/src/frontends/qt/GuiGraphics.h +++ b/src/frontends/qt/GuiGraphics.h @@ -71,7 +71,7 @@ private: /// does the bounding box differ from the file? bool isChangedBB(); /// Browse for a file - QString browse(QString const &) const; + QString browse(QString const &); /// Read the Bounding Box from a eps or ps-file std::string readBoundingBox(std::string const & file); /// test if file exist diff --git a/src/frontends/qt/GuiInclude.cpp b/src/frontends/qt/GuiInclude.cpp index 6120d669ef..73d4690a30 100644 --- a/src/frontends/qt/GuiInclude.cpp +++ b/src/frontends/qt/GuiInclude.cpp @@ -359,7 +359,7 @@ void GuiInclude::browse() } -QString GuiInclude::browse(QString const & in_name, Type in_type) const +QString GuiInclude::browse(QString const & in_name, Type in_type) { QString const title = qt_("Select document to include"); diff --git a/src/frontends/qt/GuiInclude.h b/src/frontends/qt/GuiInclude.h index 1c94692ebe..da3972f9b4 100644 --- a/src/frontends/qt/GuiInclude.h +++ b/src/frontends/qt/GuiInclude.h @@ -79,7 +79,7 @@ private: /// update void updateContents() override {} /// Browse for a file - QString browse(QString const &, Type) const; + QString browse(QString const &, Type); private: /// diff --git a/src/frontends/qt/GuiPrefs.cpp b/src/frontends/qt/GuiPrefs.cpp index a5f4014874..a74d97fcc3 100644 --- a/src/frontends/qt/GuiPrefs.cpp +++ b/src/frontends/qt/GuiPrefs.cpp @@ -80,124 +80,6 @@ using namespace lyx::support; using namespace lyx::support::os; namespace lyx { -namespace frontend { - -///////////////////////////////////////////////////////////////////// -// -// Browser Helpers -// -///////////////////////////////////////////////////////////////////// - -/** Launch a file dialog and return the chosen file. - filename: a suggested filename. - title: the title of the dialog. - filters: *.ps etc. - dir1 = (name, dir), dir2 = (name, dir): extra buttons on the dialog. -*/ -QString browseFile(QString const & filename, - QString const & title, - QStringList const & filters, - bool save = false, - QString const & label1 = QString(), - QString const & dir1 = QString(), - QString const & label2 = QString(), - QString const & dir2 = QString(), - QString const & fallback_dir = QString()) -{ - QString lastPath = "."; - if (!filename.isEmpty()) - lastPath = onlyPath(filename); - else if(!fallback_dir.isEmpty()) - lastPath = fallback_dir; - - FileDialog dlg(title); - dlg.setButton1(label1, dir1); - dlg.setButton2(label2, dir2); - - FileDialog::Result result; - - if (save) - result = dlg.save(lastPath, filters, onlyFileName(filename)); - else - result = dlg.open(lastPath, filters, onlyFileName(filename)); - - return result.second; -} - - -/** Launch a file dialog and return the chosen directory. - pathname: a suggested pathname. - title: the title of the dialog. - dir1 = (name, dir), dir2 = (name, dir): extra buttons on the dialog. -*/ -QString browseDir(QString const & pathname, - QString const & title, - QString const & label1 = QString(), - QString const & dir1 = QString(), - QString const & label2 = QString(), - QString const & dir2 = QString()) -{ - QString lastPath = "."; - if (!pathname.isEmpty()) - lastPath = onlyPath(pathname); - - FileDialog dlg(title); - dlg.setButton1(label1, dir1); - dlg.setButton2(label2, dir2); - - FileDialog::Result const result = - dlg.opendir(lastPath, onlyFileName(pathname)); - - return result.second; -} - - -} // namespace frontend - - -QString browseRelToParent(QString const & filename, QString const & relpath, - QString const & title, QStringList const & filters, bool save, - QString const & label1, QString const & dir1, - QString const & label2, QString const & dir2) -{ - QString const fname = makeAbsPath(filename, relpath); - - QString const outname = - frontend::browseFile(fname, title, filters, save, label1, dir1, label2, dir2); - - QString const reloutname = - toqstr(makeRelPath(qstring_to_ucs4(outname), qstring_to_ucs4(relpath))); - - if (reloutname.startsWith("../")) - return outname; - else - return reloutname; -} - - -QString browseRelToSub(QString const & filename, QString const & relpath, - QString const & title, QStringList const & filters, bool save, - QString const & label1, QString const & dir1, - QString const & label2, QString const & dir2) -{ - QString const fname = makeAbsPath(filename, relpath); - - QString const outname = - frontend::browseFile(fname, title, filters, save, label1, dir1, label2, dir2); - - QString const reloutname = - toqstr(makeRelPath(qstring_to_ucs4(outname), qstring_to_ucs4(relpath))); - - QString testname = reloutname; - testname.remove(QRegularExpression("^(\\.\\./)+")); - - if (testname.contains("/")) - return outname; - else - return reloutname; -} - - ///////////////////////////////////////////////////////////////////// // @@ -1478,7 +1360,7 @@ void PrefPaths::updateRC(LyXRC const & rc) void PrefPaths::selectExampledir() { - QString file = browseDir(internalPath(exampleDirED->text()), + QString file = form_->browseDir(internalPath(exampleDirED->text()), qt_("Select directory for example files")); if (!file.isEmpty()) exampleDirED->setText(file); @@ -1487,7 +1369,7 @@ void PrefPaths::selectExampledir() void PrefPaths::selectTemplatedir() { - QString file = browseDir(internalPath(templateDirED->text()), + QString file = form_->browseDir(internalPath(templateDirED->text()), qt_("Select a document templates directory")); if (!file.isEmpty()) templateDirED->setText(file); @@ -1496,7 +1378,7 @@ void PrefPaths::selectTemplatedir() void PrefPaths::selectTempdir() { - QString file = browseDir(internalPath(tempDirED->text()), + QString file = form_->browseDir(internalPath(tempDirED->text()), qt_("Select a temporary directory")); if (!file.isEmpty()) tempDirED->setText(file); @@ -1505,7 +1387,7 @@ void PrefPaths::selectTempdir() void PrefPaths::selectBackupdir() { - QString file = browseDir(internalPath(backupDirED->text()), + QString file = form_->browseDir(internalPath(backupDirED->text()), qt_("Select a backups directory")); if (!file.isEmpty()) backupDirED->setText(file); @@ -1514,7 +1396,7 @@ void PrefPaths::selectBackupdir() void PrefPaths::selectWorkingdir() { - QString file = browseDir(internalPath(workingDirED->text()), + QString file = form_->browseDir(internalPath(workingDirED->text()), qt_("Select a document directory")); if (!file.isEmpty()) workingDirED->setText(file); @@ -1523,7 +1405,7 @@ void PrefPaths::selectWorkingdir() void PrefPaths::selectThesaurusdir() { - QString file = browseDir(internalPath(thesaurusDirED->text()), + QString file = form_->browseDir(internalPath(thesaurusDirED->text()), qt_("Set the path to the thesaurus dictionaries")); if (!file.isEmpty()) thesaurusDirED->setText(file); @@ -1532,7 +1414,7 @@ void PrefPaths::selectThesaurusdir() void PrefPaths::selectHunspelldir() { - QString file = browseDir(internalPath(hunspellDirED->text()), + QString file = form_->browseDir(internalPath(hunspellDirED->text()), qt_("Set the path to the Hunspell dictionaries")); if (!file.isEmpty()) hunspellDirED->setText(file); @@ -3718,6 +3600,12 @@ QString GuiPreferences::browseLibFile(QString const & dir, guilyxfiles_->passParams(fromqstr(dir)); guilyxfiles_->selectItem(name); guilyxfiles_->exec(); + + if (frontend::guiApp->platformName() == "cocoa") { + QWidget * dialog_ = asQWidget(); + dialog_->raise(); + dialog_->activateWindow(); + } QString const result = uifile_; @@ -3756,7 +3644,7 @@ QString GuiPreferences::browsekbmap(QString const & file) QString GuiPreferences::browse(QString const & file, - QString const & title) const + QString const & title) { return browseFile(file, title, QStringList(), true); } diff --git a/src/frontends/qt/GuiPrefs.h b/src/frontends/qt/GuiPrefs.h index d23759089e..9c25793877 100644 --- a/src/frontends/qt/GuiPrefs.h +++ b/src/frontends/qt/GuiPrefs.h @@ -92,7 +92,7 @@ public: QString browsekbmap(QString const & file); /// general browse - QString browse(QString const & file, QString const & title) const; + QString browse(QString const & file, QString const & title); /// set a color void setColor(ColorCode col, QString const & hex); diff --git a/src/frontends/qt/qt_helpers.h b/src/frontends/qt/qt_helpers.h index 6cad775267..f3230b2d32 100644 --- a/src/frontends/qt/qt_helpers.h +++ b/src/frontends/qt/qt_helpers.h @@ -120,47 +120,6 @@ support::FileName imageLibFileSearch(QString & dir, QString const & name, QString const & ext = QString(), support::search_mode mode = support::must_exist); -/** Wrappers around browseFile which try to provide a filename - relative to relpath. - -\param title: title for dialog - -\param filters: *.ps, etc - -\param save: whether to save dialog info (current path, etc) for next use. - -The \param labelN and \param dirN arguments provide for extra buttons -in the dialog (e.g., "Templates" and a path to that directory). - -The difference between the functions concerns when we think we have a -relative path. - -In \c browseRelToParent, we return a relative path only if it IS NOT of - the form "../../foo.txt". - -In \c browseRelToSub, we return a relative path only if it IS of the - form "../../foo.txt". -*/ -QString browseRelToParent(QString const & filename, - QString const & relpath, - QString const & title, - QStringList const & filters, - bool save = false, - QString const & label1 = QString(), - QString const & dir1 = QString(), - QString const & label2 = QString(), - QString const & dir2 = QString()); - -QString browseRelToSub(QString const & filename, - QString const & relpath, - QString const & title, - QStringList const & filters, - bool save = false, - QString const & label1 = QString(), - QString const & dir1 = QString(), - QString const & label2 = QString(), - QString const & dir2 = QString()); - /** Build filelists of all available bst/cls/sty-files. Done through * kpsewhich and an external script, saved in *Files.lst. * \param arg: cls, sty, bst, or bib, as required by TeXFiles.py.