From be952a9d148a9611a3653a81e2ea5a11296f0665 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Thu, 26 Jul 2018 00:38:15 -0400 Subject: [PATCH 1/6] Qt: add options for new/delete playlist --- intl/msg_hash_ja.h | 12 +++++++ intl/msg_hash_us.h | 12 +++++++ msg_hash.h | 6 ++++ ui/drivers/qt/ui_qt_window.cpp | 66 ++++++++++++++++++++++++++++++---- ui/drivers/ui_qt.h | 3 +- 5 files changed, 91 insertions(+), 8 deletions(-) diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index 4309fcb8b3..69ece6caf1 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -3638,3 +3638,15 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_GRID_MAX_COUNT "「すべてのプレイリスト」アイコンの最大個数:") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SHOW_HIDDEN_FILES, "隠しファイルとフォルダを表示:") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_NEW_PLAYLIST, + "新規プレイリスト") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_ENTER_NEW_PLAYLIST_NAME, + "新しいプレイリストの名前を入力してください:") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DELETE_PLAYLIST, + "プレイリストを削除") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST, + "「%1」というプレイリストを削除しますか?") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_QUESTION, + "質問") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE, + "ファイル削除に失敗しました。") diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index f9a0321199..295f349e00 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -3796,3 +3796,15 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_GRID_MAX_COUNT "\"All Playlists\" max grid entries:") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SHOW_HIDDEN_FILES, "Show hidden files and folders:") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_NEW_PLAYLIST, + "New Playlist") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_ENTER_NEW_PLAYLIST_NAME, + "Please enter the new playlist name:") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DELETE_PLAYLIST, + "Delete Playlist") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST, + "Are you sure you want to delete the playlist \"%1\"?") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_QUESTION, + "Question") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE, + "Could not delete file.") diff --git a/msg_hash.h b/msg_hash.h index 985bff2205..2cafb7af5a 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1879,6 +1879,12 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_QT_VIEW_TYPE_ICONS, MENU_ENUM_LABEL_VALUE_QT_VIEW_TYPE_LIST, MENU_ENUM_LABEL_VALUE_QT_PROGRESS, + MENU_ENUM_LABEL_VALUE_QT_NEW_PLAYLIST, + MENU_ENUM_LABEL_VALUE_QT_ENTER_NEW_PLAYLIST_NAME, + MENU_ENUM_LABEL_VALUE_QT_DELETE_PLAYLIST, + MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST, + MENU_ENUM_LABEL_VALUE_QT_QUESTION, + MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE, MENU_LABEL(MIDI_INPUT), MENU_LABEL(MIDI_OUTPUT), diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 0b8d94b9ea..03f13d1617 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include "../ui_qt.h" @@ -977,7 +978,7 @@ void MainWindow::setCustomThemeString(QString qss) m_customThemeString = qss; } -bool MainWindow::showMessageBox(QString msg, MessageBoxType msgType, Qt::WindowModality modality) +bool MainWindow::showMessageBox(QString msg, MessageBoxType msgType, Qt::WindowModality modality, bool showDontAsk) { QPointer msgBoxPtr; QMessageBox *msgBox = NULL; @@ -985,13 +986,16 @@ bool MainWindow::showMessageBox(QString msg, MessageBoxType msgType, Qt::WindowM msgBoxPtr = new QMessageBox(this); msgBox = msgBoxPtr.data(); - checkBox = new QCheckBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_DONT_SHOW_AGAIN), msgBox); msgBox->setWindowModality(modality); msgBox->setTextFormat(Qt::RichText); - /* QMessageBox::setCheckBox() is available since 5.2 */ - msgBox->setCheckBox(checkBox); + if (showDontAsk) + { + checkBox = new QCheckBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_DONT_SHOW_AGAIN), msgBox); + /* QMessageBox::setCheckBox() is available since 5.2 */ + msgBox->setCheckBox(checkBox); + } switch (msgType) { @@ -1013,6 +1017,13 @@ bool MainWindow::showMessageBox(QString msg, MessageBoxType msgType, Qt::WindowM msgBox->setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ERROR)); break; } + case MSGBOX_TYPE_QUESTION: + { + msgBox->setIcon(QMessageBox::Question); + msgBox->setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_QUESTION)); + msgBox->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + break; + } default: break; } @@ -1023,7 +1034,10 @@ bool MainWindow::showMessageBox(QString msg, MessageBoxType msgType, Qt::WindowM if (!msgBoxPtr) return true; - if (checkBox->isChecked()) + if (checkBox && checkBox->isChecked()) + return false; + + if (msgBox->result() == QMessageBox::Cancel) return false; return true; @@ -1036,6 +1050,8 @@ void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&) QScopedPointer associateMenu; QScopedPointer hiddenPlaylistsMenu; QScopedPointer hideAction; + QScopedPointer newPlaylistAction; + QScopedPointer deletePlaylistAction; QPointer selectedAction; QPoint cursorPos = QCursor::pos(); QListWidgetItem *selectedItem = m_listWidget->itemAt(m_listWidget->viewport()->mapFromGlobal(cursorPos)); @@ -1044,6 +1060,7 @@ void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&) QString currentPlaylistDirPath; QString currentPlaylistPath; QString currentPlaylistFileName; + QFile currentPlaylistFile; QByteArray currentPlaylistFileNameArray; QFileInfo currentPlaylistFileInfo; QMap coreList; @@ -1069,6 +1086,9 @@ void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&) stcores = string_split(settings->arrays.playlist_cores, ";"); currentPlaylistPath = selectedItem->data(Qt::UserRole).toString(); + + currentPlaylistFile.setFileName(currentPlaylistPath); + currentPlaylistFileInfo = QFileInfo(currentPlaylistPath); currentPlaylistFileName = currentPlaylistFileInfo.fileName(); currentPlaylistDirPath = currentPlaylistFileInfo.absoluteDir().absolutePath(); @@ -1080,11 +1100,19 @@ void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&) menu->setObjectName("menu"); hiddenPlaylistsMenu.reset(new QMenu(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_HIDDEN_PLAYLISTS), this)); + hideAction.reset(new QAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_HIDE), this)); + newPlaylistAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_NEW_PLAYLIST)) + "...", this)); + hiddenPlaylistsMenu->setObjectName("hiddenPlaylistsMenu"); - hideAction.reset(new QAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_HIDE), this)); - menu->addAction(hideAction.data()); + menu->addAction(newPlaylistAction.data()); + + if (currentPlaylistFile.exists()) + { + deletePlaylistAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_DELETE_PLAYLIST)) + "...", this)); + menu->addAction(deletePlaylistAction.data()); + } for (j = 0; j < m_listWidget->count() && m_listWidget->count() > 0; j++) { @@ -1180,6 +1208,30 @@ void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&) strlcpy(settings->arrays.playlist_cores, new_playlist_cores, sizeof(settings->arrays.playlist_cores)); } + else if (selectedAction == deletePlaylistAction.data()) + { + if (currentPlaylistFile.exists()) + { + if (ui_window.qtWindow->showMessageBox(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST)).arg(selectedItem->text()), MainWindow::MSGBOX_TYPE_QUESTION, Qt::ApplicationModal, false)) + { + if (currentPlaylistFile.remove()) + reloadPlaylists(); + else + ui_window.qtWindow->showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal, false); + } + } + } + else if (selectedAction == newPlaylistAction.data()) + { + QString name = QInputDialog::getText(this, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_NEW_PLAYLIST), msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ENTER_NEW_PLAYLIST_NAME)); + QString newPlaylistPath = playlistDirAbsPath + "/" + name + file_path_str(FILE_PATH_LPL_EXTENSION); + QFile file(newPlaylistPath); + + if (file.open(QIODevice::WriteOnly)) + file.close(); + + reloadPlaylists(); + } else if (selectedAction == hideAction.data()) { int row = m_listWidget->row(selectedItem); diff --git a/ui/drivers/ui_qt.h b/ui/drivers/ui_qt.h index 3912428a2c..1b1ebb5865 100644 --- a/ui/drivers/ui_qt.h +++ b/ui/drivers/ui_qt.h @@ -261,6 +261,7 @@ public: MSGBOX_TYPE_INFO, MSGBOX_TYPE_WARNING, MSGBOX_TYPE_ERROR, + MSGBOX_TYPE_QUESTION, }; MainWindow(QWidget *parent = NULL); @@ -288,7 +289,7 @@ public: QString getThemeString(Theme theme); QHash getSelectedCore(); void showStatusMessage(QString msg, unsigned priority, unsigned duration, bool flush); - bool showMessageBox(QString msg, MessageBoxType msgType = MSGBOX_TYPE_INFO, Qt::WindowModality modality = Qt::ApplicationModal); + bool showMessageBox(QString msg, MessageBoxType msgType = MSGBOX_TYPE_INFO, Qt::WindowModality modality = Qt::ApplicationModal, bool showDontAsk = true); bool setCustomThemeFile(QString filePath); void setCustomThemeString(QString qss); const QString& customThemeString() const; From fcdeebe672ce10b8c39a1fd0c476b051dd6f55c8 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Thu, 26 Jul 2018 23:34:29 -0400 Subject: [PATCH 2/6] Qt: initial drag&drop to add playlist entries. no scanning or filtering yet --- intl/msg_hash_ja.h | 4 + intl/msg_hash_us.h | 4 + msg_hash.h | 2 + ui/drivers/qt/ui_qt_window.cpp | 149 +++++++++++++++++++++++++++++++-- ui/drivers/ui_qt.h | 3 + 5 files changed, 155 insertions(+), 7 deletions(-) diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index 69ece6caf1..20d9fafb45 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -3650,3 +3650,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_QUESTION, "質問") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE, "ファイル削除に失敗しました。") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_GATHERING_LIST_OF_FILES, + "ファイルの一覧を構築しています...") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_ADDING_FILES_TO_PLAYLIST, + "ファイルをプレイリストに追加しています...") diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 295f349e00..767256a865 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -3808,3 +3808,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_QUESTION, "Question") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE, "Could not delete file.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_GATHERING_LIST_OF_FILES, + "Gathering list of files...") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_ADDING_FILES_TO_PLAYLIST, + "Adding files to playlist...") diff --git a/msg_hash.h b/msg_hash.h index 2cafb7af5a..727cc2fd0e 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1885,6 +1885,8 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST, MENU_ENUM_LABEL_VALUE_QT_QUESTION, MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE, + MENU_ENUM_LABEL_VALUE_QT_GATHERING_LIST_OF_FILES, + MENU_ENUM_LABEL_VALUE_QT_ADDING_FILES_TO_PLAYLIST, MENU_LABEL(MIDI_INPUT), MENU_LABEL(MIDI_OUTPUT), diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 03f13d1617..823edff0d8 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include #include "../ui_qt.h" @@ -588,6 +590,8 @@ MainWindow::MainWindow(QWidget *parent) : qRegisterMetaType >("ThumbnailWidget"); + setAcceptDrops(true); + m_gridProgressWidget = new QWidget(); gridProgressLabel = new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PROGRESS), m_gridProgressWidget); @@ -811,6 +815,137 @@ MainWindow::~MainWindow() removeGridItems(); } +void MainWindow::dragEnterEvent(QDragEnterEvent *event) +{ + const QMimeData *data = event->mimeData(); + + if (data->hasUrls()) + event->acceptProposedAction(); +} + +static void addDirectoryFilesToList(QStringList &list, QDir &dir) +{ + QStringList dirList = dir.entryList(QStringList(), QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System, QDir::Name); + int i; + + for (i = 0; i < dirList.count(); i++) + { + QString path(dir.path() + "/" + dirList.at(i)); + QFileInfo fileInfo(path); + + if (fileInfo.isDir()) + { + QDir fileInfoDir(path); + + addDirectoryFilesToList(list, fileInfoDir); + continue; + } + + if (fileInfo.isFile()) + { + list.append(fileInfo.absoluteFilePath()); + } + } +} + +void MainWindow::dropEvent(QDropEvent *event) +{ + const QMimeData *data = event->mimeData(); + + if (data->hasUrls()) + { + QList urls = data->urls(); + QStringList list; + QString currentPlaylistPath; + QListWidgetItem *currentItem = m_listWidget->currentItem(); + QByteArray currentPlaylistArray; + const char *currentPlaylistData = NULL; + playlist_t *playlist = NULL; + + if (currentItem) + { + currentPlaylistPath = currentItem->data(Qt::UserRole).toString(); + + if (!currentPlaylistPath.isEmpty()) + { + currentPlaylistArray = currentPlaylistPath.toUtf8(); + currentPlaylistData = currentPlaylistArray.constData(); + } + } + + QProgressDialog dialog(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_GATHERING_LIST_OF_FILES), "Cancel", 0, 0, this); + int i; + + dialog.setWindowModality(Qt::ApplicationModal); + + for (i = 0; i < urls.count(); i++) + { + QString path(urls.at(i).toLocalFile()); + QFileInfo fileInfo(path); + + if (dialog.wasCanceled()) + return; + + if (i % 25 == 0) + qApp->processEvents(); + + if (fileInfo.isDir()) + { + QDir dir(path); + addDirectoryFilesToList(list, dir); + continue; + } + + if (fileInfo.isFile()) + { + list.append(fileInfo.absoluteFilePath()); + } + } + + dialog.setLabelText(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ADDING_FILES_TO_PLAYLIST)); + dialog.setMaximum(list.count()); + + playlist = playlist_init(currentPlaylistData, COLLECTION_SIZE); + + for (i = 0; i < list.count(); i++) + { + QString fileName = list.at(i); + QFileInfo fileInfo; + QByteArray fileBaseNameArray; + QByteArray pathArray; + const char *pathData = NULL; + const char *fileNameNoExten = NULL; + + if (dialog.wasCanceled()) + { + playlist_free(playlist); + return; + } + + if (fileName.isEmpty()) + continue; + + fileInfo = fileName; + fileBaseNameArray = fileInfo.baseName().toUtf8(); + fileNameNoExten = fileBaseNameArray.constData(); + + /* a modal QProgressDialog calls processEvents() automatically in setValue() */ + dialog.setValue(i + 1); + + pathArray = fileName.toUtf8(); + pathData = pathArray.constData(); + + playlist_push(playlist, pathData, fileNameNoExten, + "DETECT", "DETECT", fileNameNoExten, "00000000|crc"); + } + + playlist_write_file(playlist); + playlist_free(playlist); + + reloadPlaylists(); + } +} + void MainWindow::onGridItemClicked() { QHash hash; @@ -883,9 +1018,9 @@ inline void MainWindow::calcGridItemSize(GridItem *item, int zoomValue) void MainWindow::onZoomValueChanged(int value) { - int i = 0; + int i; - for (i = 0; i < m_gridItems.count() && m_gridItems.count() > 0; i++) + for (i = 0; i < m_gridItems.count(); i++) { GridItem *item = m_gridItems.at(i); calcGridItemSize(item, value); @@ -1114,7 +1249,7 @@ void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&) menu->addAction(deletePlaylistAction.data()); } - for (j = 0; j < m_listWidget->count() && m_listWidget->count() > 0; j++) + for (j = 0; j < m_listWidget->count(); j++) { QListWidgetItem *item = m_listWidget->item(j); bool hidden = m_listWidget->isItemHidden(item); @@ -1431,7 +1566,7 @@ void MainWindow::reloadPlaylists() if (hiddenPlaylists.contains(QFileInfo(settings->paths.path_content_video_history).fileName())) m_listWidget->setRowHidden(m_listWidget->row(videoPlaylistsItem), true); - for (i = 0; i < m_playlistFiles.count() && m_playlistFiles.count() > 0; i++) + for (i = 0; i < m_playlistFiles.count(); i++) { QListWidgetItem *item = NULL; const QString &file = m_playlistFiles.at(i); @@ -2710,7 +2845,7 @@ void MainWindow::onViewClosedDocksAboutToShow() return; } - for (i = 0; i < dockWidgets.count() && dockWidgets.count() > 0; i++) + for (i = 0; i < dockWidgets.count(); i++) { const QDockWidget *dock = dockWidgets.at(i); @@ -3414,7 +3549,7 @@ void MainWindow::initContentGridLayout() QStringList playlists; int i = 0; - for (i = 0; i < m_playlistFiles.count() && m_playlistFiles.count() > 0; i++) + for (i = 0; i < m_playlistFiles.count(); i++) { const QString &playlist = m_playlistFiles.at(i); playlists.append(playlistDir.absoluteFilePath(playlist)); @@ -3481,7 +3616,7 @@ void MainWindow::initContentTableWidget() QStringList playlists; int i = 0; - for (i = 0; i < m_playlistFiles.count() && m_playlistFiles.count() > 0; i++) + for (i = 0; i < m_playlistFiles.count(); i++) { const QString &playlist = m_playlistFiles.at(i); playlists.append(playlistDir.absoluteFilePath(playlist)); diff --git a/ui/drivers/ui_qt.h b/ui/drivers/ui_qt.h index 1b1ebb5865..0a87b23dd4 100644 --- a/ui/drivers/ui_qt.h +++ b/ui/drivers/ui_qt.h @@ -34,6 +34,7 @@ #include #include #include +#include extern "C" { #include @@ -437,6 +438,8 @@ private: protected: void closeEvent(QCloseEvent *event); void keyPressEvent(QKeyEvent *event); + void dragEnterEvent(QDragEnterEvent *event); + void dropEvent(QDropEvent *event); }; Q_DECLARE_METATYPE(ThumbnailWidget) From 45d38dcccf59a7be3b56dce7d38ba32f269d32ce Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Fri, 27 Jul 2018 23:45:48 -0400 Subject: [PATCH 3/6] Qt: add dialog to choose core/database for new playlist entries --- intl/msg_hash_ja.h | 8 ++ intl/msg_hash_us.h | 8 ++ msg_hash.h | 4 + ui/drivers/qt/ui_qt_window.cpp | 243 +++++++++++++++++++++++++++++++-- ui/drivers/ui_qt.h | 23 ++++ 5 files changed, 274 insertions(+), 12 deletions(-) diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index 20d9fafb45..ef42845b81 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -3654,3 +3654,11 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_GATHERING_LIST_OF_FILES, "ファイルの一覧を構築しています...") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_ADDING_FILES_TO_PLAYLIST, "ファイルをプレイリストに追加しています...") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY, + "プレイリストエントリー") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_CORE, + "コア:") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_DATABASE, + "データベース:") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_FOR_THUMBNAILS, + "(サムネイルを見つかることに使う)") diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 767256a865..300c2336bd 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -3812,3 +3812,11 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_GATHERING_LIST_OF_FILES, "Gathering list of files...") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_ADDING_FILES_TO_PLAYLIST, "Adding files to playlist...") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY, + "Playlist Entry") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_CORE, + "Core:") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_DATABASE, + "Database:") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_FOR_THUMBNAILS, + "(used to find thumbnails)") diff --git a/msg_hash.h b/msg_hash.h index 727cc2fd0e..3b9dd94e1a 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1887,6 +1887,10 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE, MENU_ENUM_LABEL_VALUE_QT_GATHERING_LIST_OF_FILES, MENU_ENUM_LABEL_VALUE_QT_ADDING_FILES_TO_PLAYLIST, + MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY, + MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_CORE, + MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_DATABASE, + MENU_ENUM_LABEL_VALUE_QT_FOR_THUMBNAILS, MENU_LABEL(MIDI_INPUT), MENU_LABEL(MIDI_OUTPUT), diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 823edff0d8..b959e32265 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -128,9 +128,19 @@ static void scan_finished_handler(void *task_data, void *user_data, const char * } #endif -inline static bool comp_hash_label_key(const QHash &lhs, const QHash &rhs) +inline static bool comp_string_lower(const QString &lhs, const QString &rhs) { - return lhs.value("label") < rhs.value("label"); + return lhs.toLower() < rhs.toLower(); +} + +inline static bool comp_hash_ui_display_name_key_lower(const QHash &lhs, const QHash &rhs) +{ + return lhs.value("ui_display_name").toLower() < rhs.value("ui_display_name").toLower(); +} + +inline static bool comp_hash_label_key_lower(const QHash &lhs, const QHash &rhs) +{ + return lhs.value("label").toLower() < rhs.value("label").toLower(); } GridItem::GridItem() : @@ -279,6 +289,151 @@ void CoreInfoDialog::showCoreInfo() show(); } +PlaylistEntryDialog::PlaylistEntryDialog(MainWindow *mainwindow, QWidget *parent) : + QDialog(parent) + ,m_mainwindow(mainwindow) + ,m_settings(mainwindow->settings()) + ,m_coreComboBox(new QComboBox(this)) + ,m_databaseComboBox(new QComboBox(this)) +{ + QFormLayout *form = new QFormLayout(); + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + QVBoxLayout *databaseVBoxLayout = new QVBoxLayout(); + QLabel *databaseLabel = new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_FOR_THUMBNAILS), this); + + databaseVBoxLayout->addWidget(m_databaseComboBox); + databaseVBoxLayout->addWidget(databaseLabel); + + setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY)); + + form->setFormAlignment(Qt::AlignCenter); + form->setLabelAlignment(Qt::AlignCenter); + + setLayout(new QVBoxLayout(this)); + + connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + + connect(this, SIGNAL(accepted()), this, SLOT(onAccepted())); + connect(this, SIGNAL(rejected()), this, SLOT(onRejected())); + + form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_CORE), m_coreComboBox); + form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_DATABASE), databaseVBoxLayout); + + qobject_cast(layout())->addLayout(form); + layout()->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding)); + layout()->addWidget(buttonBox); +} + +void PlaylistEntryDialog::loadPlaylistOptions() +{ + core_info_list_t *core_info_list = NULL; + const core_info_t *core_info = NULL; + unsigned i = 0; + int j = 0; + + m_coreComboBox->clear(); + m_databaseComboBox->clear(); + + m_coreComboBox->addItem(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CORE_SELECTION_ASK)); + m_databaseComboBox->addItem(QString("<") + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE) + ">"); + + core_info_get_list(&core_info_list); + + if (core_info_list && core_info_list->count > 0) + { + QVector > allCores; + QStringList allDatabases; + + for (i = 0; i < core_info_list->count; i++) + { + const core_info_t *core = &core_info_list->list[i]; + QStringList databases = QString(core->databases).split("|"); + QHash hash; + QString ui_display_name; + + hash["core_name"] = core->core_name; + hash["core_display_name"] = core->display_name; + hash["core_path"] = core->path; + hash["core_databases"] = core->databases; + + ui_display_name = hash.value("core_name"); + + if (ui_display_name.isEmpty()) + ui_display_name = hash.value("core_display_name"); + if (ui_display_name.isEmpty()) + ui_display_name = QFileInfo(hash.value("core_path")).fileName(); + if (ui_display_name.isEmpty()) + continue; + + hash["ui_display_name"] = ui_display_name; + + for (j = 0; j < databases.count(); j++) + { + QString database = databases.at(j); + + if (database.isEmpty()) + continue; + + if (!allDatabases.contains(database)) + allDatabases.append(database); + } + + if (!allCores.contains(hash)) + allCores.append(hash); + } + + std::sort(allCores.begin(), allCores.end(), comp_hash_ui_display_name_key_lower); + std::sort(allDatabases.begin(), allDatabases.end(), comp_string_lower); + + for (j = 0; j < allCores.count(); j++) + { + const QHash &hash = allCores.at(j); + + m_coreComboBox->addItem(hash.value("ui_display_name"), QVariant::fromValue(hash)); + } + + for (j = 0; j < allDatabases.count(); j++) + { + QString database = allDatabases.at(j); + m_databaseComboBox->addItem(database, database); + } + } +} + +const QHash PlaylistEntryDialog::getSelectedCore() +{ + return m_coreComboBox->currentData(Qt::UserRole).value >(); +} + +const QString PlaylistEntryDialog::getSelectedDatabase() +{ + return m_databaseComboBox->currentData(Qt::UserRole).toString(); +} + +void PlaylistEntryDialog::onAccepted() +{ +} + +void PlaylistEntryDialog::onRejected() +{ +} + +bool PlaylistEntryDialog::showDialog() +{ + loadPlaylistOptions(); + + if (exec() == QDialog::Accepted) + return true; + + return false; +} + +void PlaylistEntryDialog::hideDialog() +{ + reject(); +} + ViewOptionsDialog::ViewOptionsDialog(MainWindow *mainwindow, QWidget *parent) : QDialog(parent) ,m_mainwindow(mainwindow) @@ -571,6 +726,7 @@ MainWindow::MainWindow(QWidget *parent) : ,m_currentGridWidget(NULL) ,m_allPlaylistsListMaxCount(0) ,m_allPlaylistsGridMaxCount(0) + ,m_playlistEntryDialog(NULL) { settings_t *settings = config_get_ptr(); QDir playlistDir(settings->paths.directory_playlist); @@ -667,6 +823,7 @@ MainWindow::MainWindow(QWidget *parent) : /* ViewOptionsDialog needs m_settings set before it's constructed */ m_settings = new QSettings(configDir + "/retroarch_qt.cfg", QSettings::IniFormat, this); m_viewOptionsDialog = new ViewOptionsDialog(this, 0); + m_playlistEntryDialog = new PlaylistEntryDialog(this, 0); /* default NULL parameter for parent wasn't added until 5.7 */ m_startCorePushButton->setDefaultAction(new QAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_START_CORE), m_startCorePushButton)); @@ -859,8 +1016,13 @@ void MainWindow::dropEvent(QDropEvent *event) QString currentPlaylistPath; QListWidgetItem *currentItem = m_listWidget->currentItem(); QByteArray currentPlaylistArray; + QScopedPointer dialog(NULL); + PlaylistEntryDialog *playlistDialog = playlistEntryDialog(); + QHash selectedCore; + QString selectedDatabase; const char *currentPlaylistData = NULL; playlist_t *playlist = NULL; + int i; if (currentItem) { @@ -873,17 +1035,21 @@ void MainWindow::dropEvent(QDropEvent *event) } } - QProgressDialog dialog(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_GATHERING_LIST_OF_FILES), "Cancel", 0, 0, this); - int i; + if (!playlistDialog->showDialog()) + return; - dialog.setWindowModality(Qt::ApplicationModal); + selectedCore = m_playlistEntryDialog->getSelectedCore(); + selectedDatabase = m_playlistEntryDialog->getSelectedDatabase(); + + dialog.reset(new QProgressDialog(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_GATHERING_LIST_OF_FILES), "Cancel", 0, 0, this)); + dialog->setWindowModality(Qt::ApplicationModal); for (i = 0; i < urls.count(); i++) { QString path(urls.at(i).toLocalFile()); QFileInfo fileInfo(path); - if (dialog.wasCanceled()) + if (dialog->wasCanceled()) return; if (i % 25 == 0) @@ -902,8 +1068,8 @@ void MainWindow::dropEvent(QDropEvent *event) } } - dialog.setLabelText(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ADDING_FILES_TO_PLAYLIST)); - dialog.setMaximum(list.count()); + dialog->setLabelText(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ADDING_FILES_TO_PLAYLIST)); + dialog->setMaximum(list.count()); playlist = playlist_init(currentPlaylistData, COLLECTION_SIZE); @@ -913,10 +1079,16 @@ void MainWindow::dropEvent(QDropEvent *event) QFileInfo fileInfo; QByteArray fileBaseNameArray; QByteArray pathArray; + QByteArray corePathArray; + QByteArray coreNameArray; + QByteArray databaseArray; const char *pathData = NULL; const char *fileNameNoExten = NULL; + const char *corePathData = NULL; + const char *coreNameData = NULL; + const char *databaseData = NULL; - if (dialog.wasCanceled()) + if (dialog->wasCanceled()) { playlist_free(playlist); return; @@ -930,13 +1102,55 @@ void MainWindow::dropEvent(QDropEvent *event) fileNameNoExten = fileBaseNameArray.constData(); /* a modal QProgressDialog calls processEvents() automatically in setValue() */ - dialog.setValue(i + 1); + dialog->setValue(i + 1); pathArray = fileName.toUtf8(); pathData = pathArray.constData(); + if (selectedCore.isEmpty()) + { + corePathData = "DETECT"; + coreNameData = "DETECT"; + } + else + { + corePathArray = selectedCore.value("core_path").toUtf8(); + coreNameArray = selectedCore.value("core_name").toUtf8(); + corePathData = corePathArray.constData(); + coreNameData = coreNameArray.constData(); + } + + if (selectedDatabase.isEmpty()) + { + databaseArray = QFileInfo(currentPlaylistPath).fileName().toUtf8(); + databaseData = databaseArray.constData(); + } + else + { + selectedDatabase += file_path_str(FILE_PATH_LPL_EXTENSION); + databaseArray = selectedDatabase.toUtf8(); + databaseData = databaseArray.constData(); + } + + if (path_is_compressed_file(pathData)) + { + struct string_list *list = file_archive_get_file_list(pathData, NULL); + + if (list) + { + if (list->size == 1) + { + /* assume archives with one file should have that file loaded directly */ + pathArray = (QString(pathData) + "#" + list->elems[0].data).toUtf8(); + pathData = pathArray.constData(); + } + + string_list_free(list); + } + } + playlist_push(playlist, pathData, fileNameNoExten, - "DETECT", "DETECT", fileNameNoExten, "00000000|crc"); + corePathData, coreNameData, "00000000|crc", databaseData); } playlist_write_file(playlist); @@ -2394,6 +2608,11 @@ bool MainWindow::isCoreLoaded() return true; } +PlaylistEntryDialog* MainWindow::playlistEntryDialog() +{ + return m_playlistEntryDialog; +} + ViewOptionsDialog* MainWindow::viewOptionsDialog() { return m_viewOptionsDialog; @@ -3405,7 +3624,7 @@ void MainWindow::addPlaylistItemsToGrid(const QStringList &paths, bool add) } } finish: - std::sort(items.begin(), items.end(), comp_hash_label_key); + std::sort(items.begin(), items.end(), comp_hash_label_key_lower); addPlaylistHashToGrid(items); } diff --git a/ui/drivers/ui_qt.h b/ui/drivers/ui_qt.h index 0a87b23dd4..a9b017ea3a 100644 --- a/ui/drivers/ui_qt.h +++ b/ui/drivers/ui_qt.h @@ -164,6 +164,27 @@ private slots: void onLastWindowClosed(); }; +class PlaylistEntryDialog : public QDialog +{ + Q_OBJECT +public: + PlaylistEntryDialog(MainWindow *mainwindow, QWidget *parent = 0); + const QHash getSelectedCore(); + const QString getSelectedDatabase(); +public slots: + bool showDialog(); + void hideDialog(); + void onAccepted(); + void onRejected(); +private: + void loadPlaylistOptions(); + + MainWindow *m_mainwindow; + QSettings *m_settings; + QComboBox *m_coreComboBox; + QComboBox *m_databaseComboBox; +}; + class ViewOptionsDialog : public QDialog { Q_OBJECT @@ -300,6 +321,7 @@ public: ViewType getCurrentViewType(); void setAllPlaylistsListMaxCount(int count); void setAllPlaylistsGridMaxCount(int count); + PlaylistEntryDialog* playlistEntryDialog(); signals: void thumbnailChanged(const QPixmap &pixmap); @@ -434,6 +456,7 @@ private: QPointer m_currentGridWidget; int m_allPlaylistsListMaxCount; int m_allPlaylistsGridMaxCount; + PlaylistEntryDialog *m_playlistEntryDialog; protected: void closeEvent(QCloseEvent *event); From 489601fadbf2a328a5d9e53f887c674f718494e3 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Fri, 27 Jul 2018 23:52:27 -0400 Subject: [PATCH 4/6] Qt: allow right-click in empty portion of playlist widget --- ui/drivers/qt/ui_qt_window.cpp | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index b959e32265..88d40773a1 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -1426,37 +1426,40 @@ void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&) bool specialPlaylist = false; bool foundHiddenPlaylist = false; - if (!selectedItem) - return; - new_playlist_names[0] = new_playlist_cores[0] = '\0'; stnames = string_split(settings->arrays.playlist_names, ";"); stcores = string_split(settings->arrays.playlist_cores, ";"); - currentPlaylistPath = selectedItem->data(Qt::UserRole).toString(); + if (selectedItem) + { + currentPlaylistPath = selectedItem->data(Qt::UserRole).toString(); + currentPlaylistFile.setFileName(currentPlaylistPath); - currentPlaylistFile.setFileName(currentPlaylistPath); + currentPlaylistFileInfo = QFileInfo(currentPlaylistPath); + currentPlaylistFileName = currentPlaylistFileInfo.fileName(); + currentPlaylistDirPath = currentPlaylistFileInfo.absoluteDir().absolutePath(); - currentPlaylistFileInfo = QFileInfo(currentPlaylistPath); - currentPlaylistFileName = currentPlaylistFileInfo.fileName(); - currentPlaylistDirPath = currentPlaylistFileInfo.absoluteDir().absolutePath(); - - currentPlaylistFileNameArray.append(currentPlaylistFileName); - currentPlaylistFileNameData = currentPlaylistFileNameArray.constData(); + currentPlaylistFileNameArray.append(currentPlaylistFileName); + currentPlaylistFileNameData = currentPlaylistFileNameArray.constData(); + } menu.reset(new QMenu(this)); menu->setObjectName("menu"); hiddenPlaylistsMenu.reset(new QMenu(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_HIDDEN_PLAYLISTS), this)); - hideAction.reset(new QAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_HIDE), this)); newPlaylistAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_NEW_PLAYLIST)) + "...", this)); hiddenPlaylistsMenu->setObjectName("hiddenPlaylistsMenu"); - menu->addAction(hideAction.data()); menu->addAction(newPlaylistAction.data()); + if (selectedItem) + { + hideAction.reset(new QAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_HIDE), this)); + menu->addAction(hideAction.data()); + } + if (currentPlaylistFile.exists()) { deletePlaylistAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_DELETE_PLAYLIST)) + "...", this)); From c883a81c4279a4e5c90d7d9acee46d865b92a94a Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sat, 28 Jul 2018 10:39:21 -0400 Subject: [PATCH 5/6] Qt: only allow dropping files onto center list/grid view --- ui/drivers/qt/ui_qt_window.cpp | 349 ++++++++++++++++++--------------- ui/drivers/ui_qt.cpp | 4 +- ui/drivers/ui_qt.h | 21 +- 3 files changed, 209 insertions(+), 165 deletions(-) diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 88d40773a1..bc4e3d1d9b 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #include "../ui_qt.h" @@ -143,6 +145,40 @@ inline static bool comp_hash_label_key_lower(const QHash &lhs, return lhs.value("label").toLower() < rhs.value("label").toLower(); } +static void addDirectoryFilesToList(QStringList &list, QDir &dir) +{ + QStringList dirList = dir.entryList(QStringList(), QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System, QDir::Name); + int i; + + for (i = 0; i < dirList.count(); i++) + { + QString path(dir.path() + "/" + dirList.at(i)); + QFileInfo fileInfo(path); + + if (fileInfo.isDir()) + { + QDir fileInfoDir(path); + + addDirectoryFilesToList(list, fileInfoDir); + continue; + } + + if (fileInfo.isFile()) + { + list.append(fileInfo.absoluteFilePath()); + } + } +} + +/* https://gist.github.com/andrey-str/0f9c7709cbf0c9c49ef9 */ +static void setElidedText(QLabel *label, QWidget *clipWidget, int padding, const QString &text) +{ + QFontMetrics metrix(label->font()); + int width = clipWidget->width() - padding; + QString clippedText = metrix.elidedText(text, Qt::ElideRight, width); + label->setText(clippedText); +} + GridItem::GridItem() : QObject() ,widget(NULL) @@ -155,15 +191,6 @@ GridItem::GridItem() : { } -/* https://gist.github.com/andrey-str/0f9c7709cbf0c9c49ef9 */ -static void setElidedText(QLabel *label, QWidget *clipWidget, int padding, const QString &text) -{ - QFontMetrics metrix(label->font()); - int width = clipWidget->width() - padding; - QString clippedText = metrix.elidedText(text, Qt::ElideRight, width); - label->setText(clippedText); -} - TreeView::TreeView(QWidget *parent) : QTreeView(parent) { @@ -183,6 +210,41 @@ void TreeView::selectionChanged(const QItemSelection &selected, const QItemSelec emit itemsSelected(list); } +FileDropWidget::FileDropWidget(QWidget *parent) : + QWidget(parent) +{ + setAcceptDrops(true); +} + +void FileDropWidget::dragEnterEvent(QDragEnterEvent *event) +{ + const QMimeData *data = event->mimeData(); + + if (data->hasUrls()) + event->acceptProposedAction(); +} + +void FileDropWidget::dropEvent(QDropEvent *event) +{ + const QMimeData *data = event->mimeData(); + + if (data->hasUrls()) + { + QList urls = data->urls(); + QStringList files; + int i; + + for (i = 0; i < urls.count(); i++) + { + QString path(urls.at(i).toLocalFile()); + + files.append(path); + } + + emit filesDropped(files); + } +} + TableWidget::TableWidget(QWidget *parent) : QTableWidget(parent) { @@ -714,7 +776,7 @@ MainWindow::MainWindow(QWidget *parent) : ,m_gridWidget(new QWidget(this)) ,m_gridScrollArea(new QScrollArea(m_gridWidget)) ,m_gridItems() - ,m_gridLayoutWidget(new QWidget()) + ,m_gridLayoutWidget(new FileDropWidget()) ,m_zoomSlider(NULL) ,m_lastZoomSliderValue(0) ,m_pendingItemUpdates() @@ -746,8 +808,6 @@ MainWindow::MainWindow(QWidget *parent) : qRegisterMetaType >("ThumbnailWidget"); - setAcceptDrops(true); - m_gridProgressWidget = new QWidget(); gridProgressLabel = new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PROGRESS), m_gridProgressWidget); @@ -935,6 +995,8 @@ MainWindow::MainWindow(QWidget *parent) : connect(m_zoomSlider, SIGNAL(valueChanged(int)), this, SLOT(onZoomValueChanged(int))); connect(viewTypeIconsAction, SIGNAL(triggered()), this, SLOT(onIconViewClicked())); connect(viewTypeListAction, SIGNAL(triggered()), this, SLOT(onListViewClicked())); + connect(m_tableWidget, SIGNAL(filesDropped(QStringList)), this, SLOT(onPlaylistFilesDropped(QStringList))); + connect(m_gridLayoutWidget, SIGNAL(filesDropped(QStringList)), this, SLOT(onPlaylistFilesDropped(QStringList))); /* make sure these use an auto connection so it will be queued if called from a different thread (some facilities in RA log messages from other threads) */ connect(this, SIGNAL(gotLogMessage(const QString&)), this, SLOT(onGotLogMessage(const QString&)), Qt::AutoConnection); @@ -972,29 +1034,61 @@ MainWindow::~MainWindow() removeGridItems(); } -void MainWindow::dragEnterEvent(QDragEnterEvent *event) +void MainWindow::onPlaylistFilesDropped(QStringList files) { - const QMimeData *data = event->mimeData(); - - if (data->hasUrls()) - event->acceptProposedAction(); + addFilesToPlaylist(files); } -static void addDirectoryFilesToList(QStringList &list, QDir &dir) +/* Takes a list of files and folders and adds them to the currently selected playlist. Folders will have their contents added recursively. */ +void MainWindow::addFilesToPlaylist(QStringList files) { - QStringList dirList = dir.entryList(QStringList(), QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System, QDir::Name); + QStringList list; + QString currentPlaylistPath; + QListWidgetItem *currentItem = m_listWidget->currentItem(); + QByteArray currentPlaylistArray; + QScopedPointer dialog(NULL); + PlaylistEntryDialog *playlistDialog = playlistEntryDialog(); + QHash selectedCore; + QString selectedDatabase; + const char *currentPlaylistData = NULL; + playlist_t *playlist = NULL; int i; - for (i = 0; i < dirList.count(); i++) + if (currentItem) { - QString path(dir.path() + "/" + dirList.at(i)); + currentPlaylistPath = currentItem->data(Qt::UserRole).toString(); + + if (!currentPlaylistPath.isEmpty()) + { + currentPlaylistArray = currentPlaylistPath.toUtf8(); + currentPlaylistData = currentPlaylistArray.constData(); + } + } + + if (!playlistDialog->showDialog()) + return; + + selectedCore = m_playlistEntryDialog->getSelectedCore(); + selectedDatabase = m_playlistEntryDialog->getSelectedDatabase(); + + dialog.reset(new QProgressDialog(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_GATHERING_LIST_OF_FILES), "Cancel", 0, 0, this)); + dialog->setWindowModality(Qt::ApplicationModal); + + for (i = 0; i < files.count(); i++) + { + QString path(files.at(i)); QFileInfo fileInfo(path); + if (dialog->wasCanceled()) + return; + + if (i % 25 == 0) + qApp->processEvents(); + if (fileInfo.isDir()) { - QDir fileInfoDir(path); - - addDirectoryFilesToList(list, fileInfoDir); + QDir dir(path); + addDirectoryFilesToList(list, dir); continue; } @@ -1003,161 +1097,96 @@ static void addDirectoryFilesToList(QStringList &list, QDir &dir) list.append(fileInfo.absoluteFilePath()); } } -} -void MainWindow::dropEvent(QDropEvent *event) -{ - const QMimeData *data = event->mimeData(); + dialog->setLabelText(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ADDING_FILES_TO_PLAYLIST)); + dialog->setMaximum(list.count()); - if (data->hasUrls()) + playlist = playlist_init(currentPlaylistData, COLLECTION_SIZE); + + for (i = 0; i < list.count(); i++) { - QList urls = data->urls(); - QStringList list; - QString currentPlaylistPath; - QListWidgetItem *currentItem = m_listWidget->currentItem(); - QByteArray currentPlaylistArray; - QScopedPointer dialog(NULL); - PlaylistEntryDialog *playlistDialog = playlistEntryDialog(); - QHash selectedCore; - QString selectedDatabase; - const char *currentPlaylistData = NULL; - playlist_t *playlist = NULL; - int i; + QString fileName = list.at(i); + QFileInfo fileInfo; + QByteArray fileBaseNameArray; + QByteArray pathArray; + QByteArray corePathArray; + QByteArray coreNameArray; + QByteArray databaseArray; + const char *pathData = NULL; + const char *fileNameNoExten = NULL; + const char *corePathData = NULL; + const char *coreNameData = NULL; + const char *databaseData = NULL; - if (currentItem) + if (dialog->wasCanceled()) { - currentPlaylistPath = currentItem->data(Qt::UserRole).toString(); - - if (!currentPlaylistPath.isEmpty()) - { - currentPlaylistArray = currentPlaylistPath.toUtf8(); - currentPlaylistData = currentPlaylistArray.constData(); - } - } - - if (!playlistDialog->showDialog()) + playlist_free(playlist); return; - - selectedCore = m_playlistEntryDialog->getSelectedCore(); - selectedDatabase = m_playlistEntryDialog->getSelectedDatabase(); - - dialog.reset(new QProgressDialog(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_GATHERING_LIST_OF_FILES), "Cancel", 0, 0, this)); - dialog->setWindowModality(Qt::ApplicationModal); - - for (i = 0; i < urls.count(); i++) - { - QString path(urls.at(i).toLocalFile()); - QFileInfo fileInfo(path); - - if (dialog->wasCanceled()) - return; - - if (i % 25 == 0) - qApp->processEvents(); - - if (fileInfo.isDir()) - { - QDir dir(path); - addDirectoryFilesToList(list, dir); - continue; - } - - if (fileInfo.isFile()) - { - list.append(fileInfo.absoluteFilePath()); - } } - dialog->setLabelText(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_ADDING_FILES_TO_PLAYLIST)); - dialog->setMaximum(list.count()); + if (fileName.isEmpty()) + continue; - playlist = playlist_init(currentPlaylistData, COLLECTION_SIZE); + fileInfo = fileName; + fileBaseNameArray = fileInfo.baseName().toUtf8(); + fileNameNoExten = fileBaseNameArray.constData(); - for (i = 0; i < list.count(); i++) + /* a modal QProgressDialog calls processEvents() automatically in setValue() */ + dialog->setValue(i + 1); + + pathArray = fileName.toUtf8(); + pathData = pathArray.constData(); + + if (selectedCore.isEmpty()) { - QString fileName = list.at(i); - QFileInfo fileInfo; - QByteArray fileBaseNameArray; - QByteArray pathArray; - QByteArray corePathArray; - QByteArray coreNameArray; - QByteArray databaseArray; - const char *pathData = NULL; - const char *fileNameNoExten = NULL; - const char *corePathData = NULL; - const char *coreNameData = NULL; - const char *databaseData = NULL; + corePathData = "DETECT"; + coreNameData = "DETECT"; + } + else + { + corePathArray = selectedCore.value("core_path").toUtf8(); + coreNameArray = selectedCore.value("core_name").toUtf8(); + corePathData = corePathArray.constData(); + coreNameData = coreNameArray.constData(); + } - if (dialog->wasCanceled()) + if (selectedDatabase.isEmpty()) + { + databaseArray = QFileInfo(currentPlaylistPath).fileName().toUtf8(); + databaseData = databaseArray.constData(); + } + else + { + selectedDatabase += file_path_str(FILE_PATH_LPL_EXTENSION); + databaseArray = selectedDatabase.toUtf8(); + databaseData = databaseArray.constData(); + } + + if (path_is_compressed_file(pathData)) + { + struct string_list *list = file_archive_get_file_list(pathData, NULL); + + if (list) { - playlist_free(playlist); - return; - } - - if (fileName.isEmpty()) - continue; - - fileInfo = fileName; - fileBaseNameArray = fileInfo.baseName().toUtf8(); - fileNameNoExten = fileBaseNameArray.constData(); - - /* a modal QProgressDialog calls processEvents() automatically in setValue() */ - dialog->setValue(i + 1); - - pathArray = fileName.toUtf8(); - pathData = pathArray.constData(); - - if (selectedCore.isEmpty()) - { - corePathData = "DETECT"; - coreNameData = "DETECT"; - } - else - { - corePathArray = selectedCore.value("core_path").toUtf8(); - coreNameArray = selectedCore.value("core_name").toUtf8(); - corePathData = corePathArray.constData(); - coreNameData = coreNameArray.constData(); - } - - if (selectedDatabase.isEmpty()) - { - databaseArray = QFileInfo(currentPlaylistPath).fileName().toUtf8(); - databaseData = databaseArray.constData(); - } - else - { - selectedDatabase += file_path_str(FILE_PATH_LPL_EXTENSION); - databaseArray = selectedDatabase.toUtf8(); - databaseData = databaseArray.constData(); - } - - if (path_is_compressed_file(pathData)) - { - struct string_list *list = file_archive_get_file_list(pathData, NULL); - - if (list) + if (list->size == 1) { - if (list->size == 1) - { - /* assume archives with one file should have that file loaded directly */ - pathArray = (QString(pathData) + "#" + list->elems[0].data).toUtf8(); - pathData = pathArray.constData(); - } - - string_list_free(list); + /* assume archives with one file should have that file loaded directly */ + pathArray = (QString(pathData) + "#" + list->elems[0].data).toUtf8(); + pathData = pathArray.constData(); } - } - playlist_push(playlist, pathData, fileNameNoExten, - corePathData, coreNameData, "00000000|crc", databaseData); + string_list_free(list); + } } - playlist_write_file(playlist); - playlist_free(playlist); - - reloadPlaylists(); + playlist_push(playlist, pathData, fileNameNoExten, + corePathData, coreNameData, "00000000|crc", databaseData); } + + playlist_write_file(playlist); + playlist_free(playlist); + + reloadPlaylists(); } void MainWindow::onGridItemClicked() diff --git a/ui/drivers/ui_qt.cpp b/ui/drivers/ui_qt.cpp index a7e9c7f846..2777830585 100644 --- a/ui/drivers/ui_qt.cpp +++ b/ui/drivers/ui_qt.cpp @@ -275,9 +275,11 @@ static void* ui_companion_qt_init(void) listWidget = mainwindow->playlistListWidget(); - widget = new QWidget(mainwindow); + widget = new FileDropWidget(mainwindow); widget->setObjectName("tableWidget"); + QObject::connect(widget, SIGNAL(filesDropped(QStringList)), mainwindow, SLOT(onPlaylistFilesDropped(QStringList))); + layout = new QVBoxLayout(); layout->addWidget(mainwindow->contentTableWidget()); layout->addWidget(mainwindow->contentGridWidget()); diff --git a/ui/drivers/ui_qt.h b/ui/drivers/ui_qt.h index a9b017ea3a..337a640781 100644 --- a/ui/drivers/ui_qt.h +++ b/ui/drivers/ui_qt.h @@ -34,7 +34,6 @@ #include #include #include -#include extern "C" { #include @@ -65,6 +64,8 @@ class QFormLayout; class QStyle; class QScrollArea; class QSlider; +class QDragEnterEvent; +class QDropEvent; class LoadCoreWindow; class MainWindow; class ThumbnailWidget; @@ -139,6 +140,18 @@ protected slots: void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); }; +class FileDropWidget : public QWidget +{ + Q_OBJECT +public: + FileDropWidget(QWidget *parent = 0); +signals: + void filesDropped(QStringList files); +protected: + void dragEnterEvent(QDragEnterEvent *event); + void dropEvent(QDropEvent *event); +}; + class TableWidget : public QTableWidget { Q_OBJECT @@ -146,7 +159,7 @@ public: TableWidget(QWidget *parent = 0); signals: void enterPressed(); -protected slots: +protected: void keyPressEvent(QKeyEvent *event); }; @@ -322,6 +335,7 @@ public: void setAllPlaylistsListMaxCount(int count); void setAllPlaylistsGridMaxCount(int count); PlaylistEntryDialog* playlistEntryDialog(); + void addFilesToPlaylist(QStringList files); signals: void thumbnailChanged(const QPixmap &pixmap); @@ -389,6 +403,7 @@ private slots: void onPendingItemUpdates(); void onGridItemDoubleClicked(); void onGridItemClicked(); + void onPlaylistFilesDropped(QStringList files); private: void setCurrentCoreLabel(); @@ -461,8 +476,6 @@ private: protected: void closeEvent(QCloseEvent *event); void keyPressEvent(QKeyEvent *event); - void dragEnterEvent(QDragEnterEvent *event); - void dropEvent(QDropEvent *event); }; Q_DECLARE_METATYPE(ThumbnailWidget) From 8835e2d9a21d90f76a7dacacf1dc04c923f2e2d2 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sat, 28 Jul 2018 11:48:24 -0400 Subject: [PATCH 6/6] Qt: add delete key option to list/grid view to remove playlist items --- intl/msg_hash_ja.h | 4 ++ intl/msg_hash_us.h | 4 ++ msg_hash.h | 2 + ui/drivers/qt/ui_qt_window.cpp | 94 +++++++++++++++++++++++++++++++++- ui/drivers/ui_qt.cpp | 1 + ui/drivers/ui_qt.h | 5 ++ 6 files changed, 109 insertions(+), 1 deletion(-) diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index ef42845b81..258976db24 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -3662,3 +3662,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_DATABASE, "データベース:") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_FOR_THUMBNAILS, "(サムネイルを見つかることに使う)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST_ITEM, + "「%1」というアイテムを削除しますか?") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CANNOT_ADD_TO_ALL_PLAYLISTS, + "まずひとつのプレイリストを選択してください。") diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 300c2336bd..4bb2a4a11c 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -3820,3 +3820,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_DATABASE, "Database:") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_FOR_THUMBNAILS, "(used to find thumbnails)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST_ITEM, + "Are you sure you want to delete the item \"%1\"?") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CANNOT_ADD_TO_ALL_PLAYLISTS, + "Please choose a single playlist first.") diff --git a/msg_hash.h b/msg_hash.h index 3b9dd94e1a..6feca0ecff 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1883,6 +1883,7 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_QT_ENTER_NEW_PLAYLIST_NAME, MENU_ENUM_LABEL_VALUE_QT_DELETE_PLAYLIST, MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST, + MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST_ITEM, MENU_ENUM_LABEL_VALUE_QT_QUESTION, MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE, MENU_ENUM_LABEL_VALUE_QT_GATHERING_LIST_OF_FILES, @@ -1891,6 +1892,7 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_CORE, MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_DATABASE, MENU_ENUM_LABEL_VALUE_QT_FOR_THUMBNAILS, + MENU_ENUM_LABEL_VALUE_QT_CANNOT_ADD_TO_ALL_PLAYLISTS, MENU_LABEL(MIDI_INPUT), MENU_LABEL(MIDI_OUTPUT), diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index bc4e3d1d9b..b883fa031f 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -216,6 +216,17 @@ FileDropWidget::FileDropWidget(QWidget *parent) : setAcceptDrops(true); } +void FileDropWidget::keyPressEvent(QKeyEvent *event) +{ + if (event->key() == Qt::Key_Delete) + { + event->accept(); + emit deletePressed(); + } + else + QWidget::keyPressEvent(event); +} + void FileDropWidget::dragEnterEvent(QDragEnterEvent *event) { const QMimeData *data = event->mimeData(); @@ -257,6 +268,11 @@ void TableWidget::keyPressEvent(QKeyEvent *event) event->accept(); emit enterPressed(); } + else if (event->key() == Qt::Key_Delete) + { + event->accept(); + emit deletePressed(); + } else QTableWidget::keyPressEvent(event); } @@ -984,6 +1000,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(m_tableWidget, SIGNAL(currentItemChanged(QTableWidgetItem*, QTableWidgetItem*)), this, SLOT(onCurrentTableItemChanged(QTableWidgetItem*, QTableWidgetItem*))); connect(m_tableWidget, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), this, SLOT(onContentItemDoubleClicked(QTableWidgetItem*))); connect(m_tableWidget, SIGNAL(enterPressed()), this, SLOT(onTableWidgetEnterPressed())); + connect(m_tableWidget, SIGNAL(deletePressed()), this, SLOT(onTableWidgetDeletePressed())); connect(m_startCorePushButton, SIGNAL(clicked()), this, SLOT(onStartCoreClicked())); connect(m_coreInfoPushButton, SIGNAL(clicked()), m_coreInfoDialog, SLOT(showCoreInfo())); connect(m_runPushButton, SIGNAL(clicked()), this, SLOT(onRunClicked())); @@ -995,7 +1012,6 @@ MainWindow::MainWindow(QWidget *parent) : connect(m_zoomSlider, SIGNAL(valueChanged(int)), this, SLOT(onZoomValueChanged(int))); connect(viewTypeIconsAction, SIGNAL(triggered()), this, SLOT(onIconViewClicked())); connect(viewTypeListAction, SIGNAL(triggered()), this, SLOT(onListViewClicked())); - connect(m_tableWidget, SIGNAL(filesDropped(QStringList)), this, SLOT(onPlaylistFilesDropped(QStringList))); connect(m_gridLayoutWidget, SIGNAL(filesDropped(QStringList)), this, SLOT(onPlaylistFilesDropped(QStringList))); /* make sure these use an auto connection so it will be queued if called from a different thread (some facilities in RA log messages from other threads) */ @@ -1065,6 +1081,12 @@ void MainWindow::addFilesToPlaylist(QStringList files) } } + if (currentPlaylistPath == ALL_PLAYLISTS_TOKEN) + { + ui_window.qtWindow->showMessageBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CANNOT_ADD_TO_ALL_PLAYLISTS), MainWindow::MSGBOX_TYPE_ERROR, Qt::ApplicationModal); + return; + } + if (!playlistDialog->showDialog()) return; @@ -2380,6 +2402,67 @@ void MainWindow::onTableWidgetEnterPressed() onRunClicked(); } +void MainWindow::onTableWidgetDeletePressed() +{ + deleteCurrentPlaylistItem(); +} + +void MainWindow::deleteCurrentPlaylistItem() +{ + QTableWidgetItem *contentItem = m_tableWidget->currentItem(); + QListWidgetItem *playlistItem = m_listWidget->currentItem(); + QHash contentHash; + QString playlistPath; + QByteArray playlistArray; + ViewType viewType = getCurrentViewType(); + playlist_t *playlist = NULL; + const char *playlistData = NULL; + unsigned index = 0; + bool ok = false; + + if (!playlistItem) + return; + + playlistPath = playlistItem->data(Qt::UserRole).toString(); + + if (playlistPath.isEmpty()) + return; + + if (viewType == VIEW_TYPE_LIST) + { + if (!contentItem) + return; + + contentHash = contentItem->data(Qt::UserRole).value >(); + } + else if (viewType == VIEW_TYPE_ICONS) + contentHash = m_currentGridHash; + else + return; + + if (contentHash.isEmpty()) + return; + + playlistArray = playlistPath.toUtf8(); + playlistData = playlistArray.constData(); + + index = contentHash.value("index").toUInt(&ok); + + if (!ok) + return; + + if (!ui_window.qtWindow->showMessageBox(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST_ITEM)).arg(contentHash["label"]), MainWindow::MSGBOX_TYPE_QUESTION, Qt::ApplicationModal, false)) + return; + + playlist = playlist_init(playlistData, COLLECTION_SIZE); + + playlist_delete_index(playlist, index); + playlist_write_file(playlist); + playlist_free(playlist); + + reloadPlaylists(); +} + void MainWindow::onContentItemDoubleClicked(QTableWidgetItem*) { onRunClicked(); @@ -2415,6 +2498,8 @@ QHash MainWindow::getSelectedCore() contentHash = contentItem->data(Qt::UserRole).value >(); else if (viewType == VIEW_TYPE_ICONS) contentHash = m_currentGridHash; + else + return coreHash; switch(coreSelection) { @@ -2620,6 +2705,8 @@ void MainWindow::onRunClicked() contentHash = item->data(Qt::UserRole).value >(); else if (viewType == VIEW_TYPE_ICONS) contentHash = m_currentGridHash; + else + return; loadContent(contentHash); #endif @@ -3073,6 +3160,8 @@ void MainWindow::onSearchLineEditEdited(const QString &text) break; } + default: + break; } } @@ -3300,6 +3389,7 @@ void MainWindow::setCurrentViewType(ViewType viewType) case VIEW_TYPE_LIST: default: { + m_viewType = VIEW_TYPE_LIST; m_gridWidget->hide(); m_tableWidget->show(); break; @@ -3932,6 +4022,8 @@ QVector > MainWindow::getPlaylistItems(QString pathStrin else hash["path"] = path; + hash["index"] = QString::number(i); + if (string_is_empty(label)) { hash["label"] = path; diff --git a/ui/drivers/ui_qt.cpp b/ui/drivers/ui_qt.cpp index 2777830585..e3fde1f24b 100644 --- a/ui/drivers/ui_qt.cpp +++ b/ui/drivers/ui_qt.cpp @@ -279,6 +279,7 @@ static void* ui_companion_qt_init(void) widget->setObjectName("tableWidget"); QObject::connect(widget, SIGNAL(filesDropped(QStringList)), mainwindow, SLOT(onPlaylistFilesDropped(QStringList))); + QObject::connect(widget, SIGNAL(deletePressed()), mainwindow, SLOT(deleteCurrentPlaylistItem())); layout = new QVBoxLayout(); layout->addWidget(mainwindow->contentTableWidget()); diff --git a/ui/drivers/ui_qt.h b/ui/drivers/ui_qt.h index 337a640781..3fcbb8a979 100644 --- a/ui/drivers/ui_qt.h +++ b/ui/drivers/ui_qt.h @@ -147,9 +147,11 @@ public: FileDropWidget(QWidget *parent = 0); signals: void filesDropped(QStringList files); + void deletePressed(); protected: void dragEnterEvent(QDragEnterEvent *event); void dropEvent(QDropEvent *event); + void keyPressEvent(QKeyEvent *event); }; class TableWidget : public QTableWidget @@ -159,6 +161,7 @@ public: TableWidget(QWidget *parent = 0); signals: void enterPressed(); + void deletePressed(); protected: void keyPressEvent(QKeyEvent *event); }; @@ -358,6 +361,7 @@ public slots: void loadContent(const QHash &contentHash); void onStartCoreClicked(); void onTableWidgetEnterPressed(); + void onTableWidgetDeletePressed(); void selectBrowserDir(QString path); void resizeThumbnails(bool one, bool two, bool three); void onResizeThumbnailOne(); @@ -373,6 +377,7 @@ public slots: void onIconViewClicked(); void onListViewClicked(); void onTabWidgetIndexChanged(int index); + void deleteCurrentPlaylistItem(); private slots: void onLoadCoreClicked(const QStringList &extensionFilters = QStringList());