Allow multiple selections in the file open dialog

Fix for bug #4315.
This commit is contained in:
Daniel Ramoeller 2022-12-20 11:55:25 +01:00 committed by Jean-Marc Lasgouttes
parent 3324793b8b
commit f608328059
5 changed files with 97 additions and 68 deletions

View File

@ -133,21 +133,39 @@ FileDialog::Result FileDialog::save(QString const & path,
FileDialog::Result FileDialog::open(QString const & path, FileDialog::Result FileDialog::open(QString const & path,
QStringList const & filters, QString const & suggested) QStringList const & filters, QString const & suggested)
{
FileDialog::Result result;
FileDialog::Results results = openMulti(path, filters, suggested, false);
result.first = results.first;
result.second = results.second.at(0);
return result;
}
FileDialog::Results FileDialog::openMulti(QString const & path,
QStringList const & filters, QString const & suggested, bool multi)
{ {
LYXERR(Debug::GUI, "Select with path \"" << path LYXERR(Debug::GUI, "Select with path \"" << path
<< "\", mask \"" << filters.join(";;") << "\", mask \"" << filters.join(";;")
<< "\", suggested \"" << suggested << '"'); << "\", suggested \"" << suggested << '"');
FileDialog::Result result; FileDialog::Results results;
result.first = FileDialog::Chosen; results.first = FileDialog::Chosen;
if (lyxrc.use_native_filedialog) { if (lyxrc.use_native_filedialog) {
QString const startsWith = makeAbsPath(suggested, path); QString const startsWith = makeAbsPath(suggested, path);
QString const file = QFileDialog::getOpenFileName(qApp->focusWidget(), QStringList files;
title_, startsWith, filters.join(";;")); if (multi)
if (file.isNull()) files = QFileDialog::getOpenFileNames(qApp->focusWidget(),
result.first = FileDialog::Later; title_, startsWith, filters.join(";;"));
else else
result.second = internalPath(file); files << QFileDialog::getOpenFileName(qApp->focusWidget(),
title_, startsWith, filters.join(";;"));
if (files.isEmpty())
results.first = FileDialog::Later;
else {
for (const auto& file : files)
results.second << internalPath(file);
}
} else { } else {
LyXFileDialog dlg(title_, path, filters, private_->b1, private_->b2); LyXFileDialog dlg(title_, path, filters, private_->b1, private_->b2);
@ -158,12 +176,12 @@ FileDialog::Result FileDialog::open(QString const & path,
int res = dlg.exec(); int res = dlg.exec();
LYXERR(Debug::GUI, "result " << res); LYXERR(Debug::GUI, "result " << res);
if (res == QDialog::Accepted) if (res == QDialog::Accepted)
result.second = internalPath(dlg.selectedFiles()[0]); results.second << internalPath(dlg.selectedFiles()[0]);
else else
result.first = FileDialog::Later; results.first = FileDialog::Later;
dlg.hide(); dlg.hide();
} }
return result; return results;
} }

View File

@ -41,6 +41,9 @@ public:
/// result return /// result return
typedef std::pair<FileDialog::ResultType, QString> Result; typedef std::pair<FileDialog::ResultType, QString> Result;
/// result return
typedef std::pair<FileDialog::ResultType, QStringList> Results;
/** /**
* Constructs a file dialog with title \param title. * Constructs a file dialog with title \param title.
* *
@ -58,6 +61,9 @@ public:
/// Choose a file for opening, starting in directory \c path. /// Choose a file for opening, starting in directory \c path.
Result open(QString const & path, QStringList const & filters, Result open(QString const & path, QStringList const & filters,
QString const & suggested = QString()); QString const & suggested = QString());
/// Choose several files for opening, starting in directory \c path.
Results openMulti(QString const & path, QStringList const & filters,
QString const & suggested = QString(), bool multi = true);
/// Choose a directory, starting in directory \c path. /// Choose a directory, starting in directory \c path.
Result opendir(QString const & path = QString(), Result opendir(QString const & path = QString(),

View File

@ -1858,7 +1858,7 @@ void GuiApplication::dispatch(FuncRequest const & cmd, DispatchResult & dr)
// We want the ui session to be saved per document and not per // We want the ui session to be saved per document and not per
// window number. The filename crc is a good enough identifier. // window number. The filename crc is a good enough identifier.
createView(support::checksum(fname)); createView(support::checksum(fname));
current_view_->openDocument(fname, cmd.origin()); current_view_->openDocuments(fname, cmd.origin());
if (!current_view_->documentBufferView()) if (!current_view_->documentBufferView())
current_view_->close(); current_view_->close();
else if (cmd.origin() == FuncRequest::LYXSERVER) { else if (cmd.origin() == FuncRequest::LYXSERVER) {
@ -1867,7 +1867,7 @@ void GuiApplication::dispatch(FuncRequest const & cmd, DispatchResult & dr)
current_view_->showNormal(); current_view_->showNormal();
} }
} else { } else {
current_view_->openDocument(fname, cmd.origin()); current_view_->openDocuments(fname, cmd.origin());
if (cmd.origin() == FuncRequest::LYXSERVER) { if (cmd.origin() == FuncRequest::LYXSERVER) {
current_view_->raise(); current_view_->raise();
current_view_->activateWindow(); current_view_->activateWindow();

View File

@ -2792,7 +2792,7 @@ Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
} }
void GuiView::openDocument(string const & fname, int origin) void GuiView::openDocuments(string const & fname, int origin)
{ {
string initpath = lyxrc.document_path; string initpath = lyxrc.document_path;
@ -2803,10 +2803,10 @@ void GuiView::openDocument(string const & fname, int origin)
initpath = trypath; initpath = trypath;
} }
string filename; QStringList files;
if (fname.empty()) { if (fname.empty()) {
FileDialog dlg(qt_("Select document to open")); FileDialog dlg(qt_("Select documents to open"));
dlg.setButton1(qt_("D&ocuments"), toqstr(lyxrc.document_path)); dlg.setButton1(qt_("D&ocuments"), toqstr(lyxrc.document_path));
dlg.setButton2(qt_("&Examples"), toqstr(lyxrc.example_path)); dlg.setButton2(qt_("&Examples"), toqstr(lyxrc.example_path));
@ -2815,74 +2815,79 @@ void GuiView::openDocument(string const & fname, int origin)
qt_("LyX Document Backups (*.lyx~)"), qt_("LyX Document Backups (*.lyx~)"),
qt_("All Files (*.*)") qt_("All Files (*.*)")
}); });
FileDialog::Result result = FileDialog::Results results =
dlg.open(toqstr(initpath), filter); dlg.openMulti(toqstr(initpath), filter);
if (result.first == FileDialog::Later) if (results.first == FileDialog::Later)
return; return;
filename = fromqstr(result.second); files = results.second;
// check selected filename // check selected filename
if (filename.empty()) { if (files.isEmpty()) {
message(_("Canceled.")); message(_("Canceled."));
return; return;
} }
} else } else
filename = fname; files << toqstr(fname);
// get absolute path of file and add ".lyx" to the filename if // iterate over all selected files
// necessary. for (auto const & file : files) {
FileName const fullname = string filename = fromqstr(file);
fileSearch(string(), filename, "lyx", support::may_not_exist);
if (!fullname.empty())
filename = fullname.absFileName();
if (!fullname.onlyPath().isDirectory()) { // get absolute path of file and add ".lyx" to the filename if
Alert::warning(_("Invalid filename"), // necessary.
bformat(_("The directory in the given path\n%1$s\ndoes not exist."), FileName const fullname =
from_utf8(fullname.absFileName()))); fileSearch(string(), filename, "lyx", support::may_not_exist);
return; if (!fullname.empty())
} filename = fullname.absFileName();
// if the file doesn't exist and isn't already open (bug 6645), if (!fullname.onlyPath().isDirectory()) {
// let the user create one Alert::warning(_("Invalid filename"),
if (!fullname.exists() && !theBufferList().exists(fullname) && bformat(_("The directory in the given path\n%1$s\ndoes not exist."),
!LyXVC::file_not_found_hook(fullname)) { from_utf8(fullname.absFileName())));
// see bug #12609 continue;
if (origin == FuncRequest::MENU) {
docstring const & msg =
bformat(_("File\n"
"%1$s\n"
"does not exist. Create empty file?"),
from_utf8(filename));
int ret = Alert::prompt(_("File does not exist"),
msg, 0, 1,
_("Create &File"),
_("&Cancel"));
if (ret == 1)
return;
} }
Buffer * const b = newFile(filename, string(), true);
if (b)
setBuffer(b);
return;
}
docstring const disp_fn = makeDisplayPath(filename); // if the file doesn't exist and isn't already open (bug 6645),
message(bformat(_("Opening document %1$s..."), disp_fn)); // let the user create one
if (!fullname.exists() && !theBufferList().exists(fullname) &&
!LyXVC::file_not_found_hook(fullname)) {
// see bug #12609
if (origin == FuncRequest::MENU) {
docstring const & msg =
bformat(_("File\n"
"%1$s\n"
"does not exist. Create empty file?"),
from_utf8(filename));
int ret = Alert::prompt(_("File does not exist"),
msg, 0, 1,
_("Create &File"),
_("&Cancel"));
if (ret == 1)
continue;
}
Buffer * const b = newFile(filename, string(), true);
if (b)
setBuffer(b);
continue;
}
docstring str2; docstring const disp_fn = makeDisplayPath(filename);
Buffer * buf = loadDocument(fullname); message(bformat(_("Opening document %1$s..."), disp_fn));
if (buf) {
str2 = bformat(_("Document %1$s opened."), disp_fn); docstring str2;
if (buf->lyxvc().inUse()) Buffer * buf = loadDocument(fullname);
str2 += " " + from_utf8(buf->lyxvc().versionString()) + if (buf) {
" " + _("Version control detected."); str2 = bformat(_("Document %1$s opened."), disp_fn);
} else { if (buf->lyxvc().inUse())
str2 = bformat(_("Could not open document %1$s"), disp_fn); str2 += " " + from_utf8(buf->lyxvc().versionString()) +
" " + _("Version control detected.");
} else {
str2 = bformat(_("Could not open document %1$s"), disp_fn);
}
message(str2);
} }
message(str2);
} }
// FIXME: clean that // FIXME: clean that

View File

@ -164,7 +164,7 @@ public:
/// closes the buffer /// closes the buffer
bool closeBuffer(Buffer & buf); bool closeBuffer(Buffer & buf);
/// ///
void openDocument(std::string const & filename, int origin); void openDocuments(std::string const & filename, int origin);
/// ///
void importDocument(std::string const &); void importDocument(std::string const &);