2015-09-06 20:20:00 +02:00
|
|
|
#include "./mainwindow.h"
|
|
|
|
#include "./settingsdialog.h"
|
|
|
|
#include "./renamefilesdialog.h"
|
2016-03-03 22:21:15 +01:00
|
|
|
#include "./dbquerywidget.h"
|
2016-02-29 23:59:46 +01:00
|
|
|
#include "./tageditorwidget.h"
|
2015-04-22 19:33:53 +02:00
|
|
|
|
2015-09-06 20:20:00 +02:00
|
|
|
#include "../application/settings.h"
|
|
|
|
#include "../misc/utility.h"
|
2016-04-24 21:07:36 +02:00
|
|
|
#include "../misc/htmlinfo.h"
|
2015-09-06 15:41:17 +02:00
|
|
|
|
2015-12-05 22:55:05 +01:00
|
|
|
#include "ui_mainwindow.h"
|
2015-04-22 19:33:53 +02:00
|
|
|
|
2016-02-29 23:59:46 +01:00
|
|
|
#include <tagparser/mediafileinfo.h>
|
2015-04-22 19:33:53 +02:00
|
|
|
|
|
|
|
#include <qtutilities/aboutdialog/aboutdialog.h>
|
2015-07-07 00:46:43 +02:00
|
|
|
#include <qtutilities/misc/dialogutils.h>
|
2016-02-05 20:24:03 +01:00
|
|
|
#include <qtutilities/misc/desktoputils.h>
|
2016-03-10 22:13:43 +01:00
|
|
|
#include <qtutilities/misc/trylocker.h>
|
2016-02-05 20:24:03 +01:00
|
|
|
|
|
|
|
#include <c++utilities/conversion/stringconversion.h>
|
|
|
|
#include <c++utilities/io/path.h>
|
2015-04-22 19:33:53 +02:00
|
|
|
|
|
|
|
#include <QMessageBox>
|
|
|
|
#include <QFileDialog>
|
|
|
|
#include <QFileSystemModel>
|
|
|
|
#include <QTextStream>
|
2016-06-06 20:29:12 +02:00
|
|
|
#include <QTextCodec>
|
2015-04-22 19:33:53 +02:00
|
|
|
|
|
|
|
#include <iomanip>
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace Utility;
|
|
|
|
using namespace Media;
|
2015-07-07 00:46:43 +02:00
|
|
|
using namespace Dialogs;
|
2015-12-27 19:49:17 +01:00
|
|
|
using namespace Widgets;
|
2016-03-10 22:13:43 +01:00
|
|
|
using namespace ThreadingUtils;
|
2015-04-22 19:33:53 +02:00
|
|
|
|
|
|
|
namespace QtGui {
|
|
|
|
|
2015-07-08 00:21:21 +02:00
|
|
|
/*!
|
|
|
|
* \brief The LoadingResult enum specifies whether the file could be parsed.
|
|
|
|
*/
|
|
|
|
enum LoadingResult : char
|
|
|
|
{
|
|
|
|
ParsingSuccessful,
|
|
|
|
FatalParsingError,
|
|
|
|
IoError
|
|
|
|
};
|
|
|
|
|
2015-04-22 19:33:53 +02:00
|
|
|
/*!
|
|
|
|
* \class QtGui::MainWindow
|
2016-02-29 23:59:46 +01:00
|
|
|
* \brief The MainWindow class provides the main window of the Tag Editor's Qt GUI.
|
2015-04-22 19:33:53 +02:00
|
|
|
*/
|
|
|
|
|
2016-02-29 23:59:46 +01:00
|
|
|
/*!
|
|
|
|
* \brief Shortcut to access file operation mutex of TagEditorWidget.
|
|
|
|
*/
|
2016-11-23 21:46:33 +01:00
|
|
|
bool MainWindow::fileOperationOngoing() const
|
2016-02-29 23:59:46 +01:00
|
|
|
{
|
2016-11-23 21:46:33 +01:00
|
|
|
return m_ui->tagEditorWidget->fileOperationOngoing();
|
2016-02-29 23:59:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Shortcut to access MediaFileInfo of TagEditorWidget.
|
|
|
|
*/
|
|
|
|
MediaFileInfo &MainWindow::fileInfo()
|
|
|
|
{
|
|
|
|
return m_ui->tagEditorWidget->fileInfo();
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:33:53 +02:00
|
|
|
/*!
|
|
|
|
* \brief Constructs a new main window.
|
|
|
|
*/
|
|
|
|
MainWindow::MainWindow(QWidget *parent) :
|
|
|
|
QMainWindow(parent, Qt::Window),
|
|
|
|
m_ui(new Ui::MainWindow()),
|
2016-08-07 19:59:33 +02:00
|
|
|
m_internalFileSelection(false),
|
2015-04-22 19:33:53 +02:00
|
|
|
m_aboutDlg(nullptr),
|
2016-03-03 22:21:15 +01:00
|
|
|
m_settingsDlg(nullptr),
|
|
|
|
m_dbQueryWidget(nullptr)
|
2015-04-22 19:33:53 +02:00
|
|
|
{
|
2015-08-07 21:27:01 +02:00
|
|
|
// setup UI
|
2015-04-22 19:33:53 +02:00
|
|
|
m_ui->setupUi(this);
|
|
|
|
#ifdef Q_OS_WIN32
|
2016-03-03 22:21:15 +01:00
|
|
|
setStyleSheet(dialogStyle() + QStringLiteral("#tagEditorWidget { color: palette(text); background-color: palette(base); }"));
|
2015-04-22 19:33:53 +02:00
|
|
|
#else
|
2015-09-26 20:37:16 +02:00
|
|
|
setStyleSheet(dialogStyle());
|
2015-04-22 19:33:53 +02:00
|
|
|
#endif
|
2016-03-03 22:21:15 +01:00
|
|
|
|
2015-04-22 19:33:53 +02:00
|
|
|
// restore geometry and state
|
2016-10-24 20:15:10 +02:00
|
|
|
const auto &settings = Settings::values();
|
|
|
|
restoreGeometry(settings.mainWindow.geometry);
|
|
|
|
restoreState(settings.mainWindow.state);
|
2016-03-03 22:21:15 +01:00
|
|
|
|
2015-04-22 19:33:53 +02:00
|
|
|
// setup file model and file tree view
|
|
|
|
m_fileModel = new QFileSystemModel(this);
|
|
|
|
m_fileModel->setRootPath(QString());
|
|
|
|
m_fileFilterModel = new FileFilterProxyModel(this);
|
2016-01-25 19:23:33 +01:00
|
|
|
m_fileFilterModel->setExtensionsToBeFiltered(QStringList() << QStringLiteral("bak") << QStringLiteral("tmp"));
|
2015-04-22 19:33:53 +02:00
|
|
|
m_fileFilterModel->setSourceModel(m_fileModel);
|
2016-10-24 20:15:10 +02:00
|
|
|
m_fileFilterModel->setFilterEnabled(settings.fileBrowser.hideBackupFiles);
|
2015-04-22 19:33:53 +02:00
|
|
|
m_ui->filesTreeView->sortByColumn(0, Qt::AscendingOrder);
|
|
|
|
m_ui->filesTreeView->setModel(m_fileFilterModel);
|
|
|
|
m_ui->filesTreeView->setColumnWidth(0, 300);
|
2016-03-03 22:21:15 +01:00
|
|
|
|
2015-04-22 19:33:53 +02:00
|
|
|
// setup path line edit
|
|
|
|
m_ui->pathLineEdit->setCompletionModel(m_fileModel);
|
2016-03-03 22:21:15 +01:00
|
|
|
|
2016-02-29 23:59:46 +01:00
|
|
|
// apply initial file status
|
|
|
|
handleFileStatusChange(false, false);
|
2016-03-03 22:21:15 +01:00
|
|
|
|
|
|
|
// dbquery dock widget
|
2016-10-24 20:15:10 +02:00
|
|
|
if(settings.dbQuery.widgetShown) {
|
2016-12-01 22:23:01 +01:00
|
|
|
initDbQueryWidget();
|
2016-03-03 22:21:15 +01:00
|
|
|
}
|
|
|
|
|
2016-09-25 23:59:04 +02:00
|
|
|
// restore locked
|
2016-10-24 20:15:10 +02:00
|
|
|
setLayoutLocked(settings.mainWindow.layoutLocked);
|
2016-09-25 23:59:04 +02:00
|
|
|
|
2015-05-05 23:08:49 +02:00
|
|
|
// connect signals and slots, install event filter
|
2015-04-22 19:33:53 +02:00
|
|
|
// menu: application
|
|
|
|
connect(m_ui->actionSettings, &QAction::triggered, this, &MainWindow::showSettingsDlg);
|
2016-10-09 19:44:06 +02:00
|
|
|
connect(m_ui->actionOpen_MusicBrainz_search, &QAction::triggered, this, &MainWindow::toggleDbQueryWidget);
|
2016-09-25 23:59:04 +02:00
|
|
|
connect(m_ui->lockLayout, &QAction::triggered, this, &MainWindow::toggleLayoutLocked);
|
2015-04-22 19:33:53 +02:00
|
|
|
connect(m_ui->actionQuit, &QAction::triggered, this, &MainWindow::close);
|
|
|
|
// menu: file
|
|
|
|
connect(m_ui->actionOpen, &QAction::triggered, this, &MainWindow::showOpenFileDlg);
|
2016-02-29 23:59:46 +01:00
|
|
|
connect(m_ui->actionSave, &QAction::triggered, m_ui->tagEditorWidget, &TagEditorWidget::applyEntriesAndSaveChangings);
|
2016-05-01 20:07:04 +02:00
|
|
|
connect(m_ui->actionSave_as, &QAction::triggered, this, &MainWindow::showSaveAsDlg);
|
2016-02-29 23:59:46 +01:00
|
|
|
connect(m_ui->actionDelete_all_tags, &QAction::triggered, m_ui->tagEditorWidget, &TagEditorWidget::deleteAllTagsAndSave);
|
2015-04-22 19:33:53 +02:00
|
|
|
connect(m_ui->actionSave_file_information, &QAction::triggered, this, &MainWindow::saveFileInformation);
|
2016-02-29 23:59:46 +01:00
|
|
|
connect(m_ui->actionClose, &QAction::triggered, m_ui->tagEditorWidget, &TagEditorWidget::closeFile);
|
|
|
|
connect(m_ui->actionReload, &QAction::triggered, m_ui->tagEditorWidget, &TagEditorWidget::reparseFile);
|
2015-10-14 20:15:10 +02:00
|
|
|
connect(m_ui->actionExternalPlayer, &QAction::triggered, this, &MainWindow::spawnExternalPlayer);
|
2015-04-22 19:33:53 +02:00
|
|
|
// menu: directory
|
2016-02-29 23:59:46 +01:00
|
|
|
connect(m_ui->actionSelect_next_file, &QAction::triggered, this, static_cast<void(MainWindow::*)(void)>(&MainWindow::selectNextFile));
|
|
|
|
connect(m_ui->actionSelect_next_file_and_save_current, &QAction::triggered, m_ui->tagEditorWidget, &TagEditorWidget::saveAndShowNextFile);
|
2015-04-22 19:33:53 +02:00
|
|
|
connect(m_ui->actionRename_files, &QAction::triggered, this, &MainWindow::showRenameFilesDlg);
|
|
|
|
// menu: help
|
|
|
|
connect(m_ui->actionAbout, &QAction::triggered, this, &MainWindow::showAboutDlg);
|
2016-02-29 23:59:46 +01:00
|
|
|
// tag editor widget
|
|
|
|
connect(m_ui->tagEditorWidget, &TagEditorWidget::nextFileSelected, this, static_cast<void(MainWindow::*)(void)>(&MainWindow::selectNextFile));
|
2016-08-07 19:59:33 +02:00
|
|
|
connect(m_ui->tagEditorWidget, &TagEditorWidget::fileStatusChanged, this, &MainWindow::handleFileStatusChange);
|
2016-02-29 23:59:46 +01:00
|
|
|
connect(m_ui->tagEditorWidget, &TagEditorWidget::statusMessage, m_ui->statusBar, &QStatusBar::showMessage);
|
2016-08-07 19:59:33 +02:00
|
|
|
connect(m_ui->tagEditorWidget, &TagEditorWidget::currentPathChanged, this, &MainWindow::handleCurrentPathChanged);
|
2015-04-22 19:33:53 +02:00
|
|
|
// misc
|
|
|
|
connect(m_ui->pathLineEdit, &QLineEdit::textEdited, this, &MainWindow::pathEntered);
|
|
|
|
connect(m_ui->filesTreeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &MainWindow::fileSelected);
|
2016-02-29 23:59:46 +01:00
|
|
|
connect(m_ui->selectNextCommandLinkButton, &QCommandLinkButton::clicked, this, static_cast<void(MainWindow::*)(void)>(&MainWindow::selectNextFile));
|
2015-04-22 19:33:53 +02:00
|
|
|
// apply settings
|
2016-10-24 20:15:10 +02:00
|
|
|
setCurrentDirectory(settings.mainWindow.currentFileBrowserDirectory);
|
2015-04-22 19:33:53 +02:00
|
|
|
applySettingsFromDialog();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Destroys the main window.
|
|
|
|
*/
|
|
|
|
MainWindow::~MainWindow()
|
|
|
|
{}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns directory the file browser is currently showning.
|
|
|
|
*/
|
2016-09-25 23:59:04 +02:00
|
|
|
QString MainWindow::currentDirectory() const
|
2015-04-22 19:33:53 +02:00
|
|
|
{
|
|
|
|
return m_ui->pathLineEdit->text();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Sets the directory the file browser is showing.
|
|
|
|
* If a file is specified the file will be opended.
|
|
|
|
*/
|
|
|
|
void MainWindow::setCurrentDirectory(const QString &path)
|
|
|
|
{
|
|
|
|
m_ui->pathLineEdit->editText(path);
|
|
|
|
}
|
|
|
|
|
2016-09-25 23:59:04 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns whether the layout is \a locked.
|
|
|
|
*/
|
|
|
|
bool MainWindow::isLayoutLocked() const
|
|
|
|
{
|
|
|
|
return m_ui->fileSelectionDockWidget->features() == QDockWidget::NoDockWidgetFeatures;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Sets whether the layout is \a locked.
|
|
|
|
*/
|
|
|
|
void MainWindow::setLayoutLocked(bool locked)
|
|
|
|
{
|
|
|
|
if(locked != isLayoutLocked()) {
|
|
|
|
if(locked) {
|
|
|
|
m_ui->fileSelectionDockWidget->setFeatures(QDockWidget::NoDockWidgetFeatures);
|
|
|
|
m_ui->dbQueryDockWidget->setFeatures(QDockWidget::NoDockWidgetFeatures);
|
|
|
|
m_ui->lockLayout->setText(tr("Unlock layout"));
|
|
|
|
m_ui->lockLayout->setIcon(QIcon::fromTheme(QStringLiteral("unlock")));
|
|
|
|
} else {
|
|
|
|
m_ui->fileSelectionDockWidget->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
|
|
|
|
m_ui->dbQueryDockWidget->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetClosable);
|
|
|
|
m_ui->lockLayout->setText(tr("Lock layout"));
|
|
|
|
m_ui->lockLayout->setIcon(QIcon::fromTheme(QStringLiteral("lock")));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::toggleLayoutLocked()
|
|
|
|
{
|
|
|
|
setLayoutLocked(!isLayoutLocked());
|
|
|
|
}
|
|
|
|
|
2016-02-29 23:59:46 +01:00
|
|
|
/*!
|
|
|
|
* \brief Starts parsing the specified file.
|
|
|
|
*/
|
|
|
|
void MainWindow::startParsing(const QString &path)
|
|
|
|
{
|
|
|
|
m_ui->tagEditorWidget->startParsing(path, true);
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:33:53 +02:00
|
|
|
/*!
|
2016-01-07 19:42:51 +01:00
|
|
|
* \brief
|
|
|
|
* - Saves the applications settings relating the state of the main window.
|
|
|
|
* - Updates the info webview when the palette changed.
|
2015-04-22 19:33:53 +02:00
|
|
|
*/
|
2016-01-07 19:42:51 +01:00
|
|
|
bool MainWindow::event(QEvent *event)
|
2015-04-22 19:33:53 +02:00
|
|
|
{
|
2016-10-24 20:15:10 +02:00
|
|
|
auto &settings = Settings::values();
|
2016-01-07 19:42:51 +01:00
|
|
|
switch(event->type()) {
|
|
|
|
case QEvent::Close:
|
|
|
|
// save settings
|
2016-10-24 20:15:10 +02:00
|
|
|
settings.mainWindow.geometry = saveGeometry();
|
|
|
|
settings.mainWindow.state = saveState();
|
|
|
|
settings.mainWindow.currentFileBrowserDirectory = currentDirectory();
|
|
|
|
settings.mainWindow.layoutLocked = isLayoutLocked();
|
|
|
|
settings.dbQuery.widgetShown = m_ui->dbQueryDockWidget->isVisible();
|
2016-01-07 19:42:51 +01:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
;
|
|
|
|
}
|
|
|
|
return QMainWindow::event(event);
|
2015-04-22 19:33:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief This private slot is called when the entered text of m_ui->pathLineEdit which represents the current directory changes.
|
2016-02-05 20:24:03 +01:00
|
|
|
*
|
2015-04-22 19:33:53 +02:00
|
|
|
* If the text is a valid path the current index of the m_ui->filesTreeView is updated to show the path. This invokes the file
|
|
|
|
* selected slot.
|
|
|
|
*/
|
|
|
|
void MainWindow::pathEntered()
|
|
|
|
{
|
2016-08-07 19:59:33 +02:00
|
|
|
const QString path = m_ui->pathLineEdit->text();
|
2015-04-22 19:33:53 +02:00
|
|
|
if(!path.isEmpty()) {
|
2016-08-07 19:59:33 +02:00
|
|
|
const QModelIndex index = m_fileFilterModel->mapFromSource(m_fileModel->index(path));
|
2015-04-22 19:33:53 +02:00
|
|
|
if(index.isValid()) {
|
|
|
|
m_ui->filesTreeView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect);
|
2016-02-05 20:24:03 +01:00
|
|
|
m_ui->pathLineEdit->setProperty("classNames", QStringList());
|
2015-04-22 19:33:53 +02:00
|
|
|
} else {
|
2016-02-05 20:24:03 +01:00
|
|
|
m_ui->pathLineEdit->setProperty("classNames", QStringList() << QStringLiteral("input-invalid"));
|
2015-04-22 19:33:53 +02:00
|
|
|
}
|
2016-02-05 20:24:03 +01:00
|
|
|
updateStyle(m_ui->pathLineEdit);
|
2015-04-22 19:33:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief This private slot is called when the selected file or directory changes.
|
2016-08-07 19:59:33 +02:00
|
|
|
*
|
2015-04-22 19:33:53 +02:00
|
|
|
* If a directory is selected the m_ui->pathLineEdit will be updated.
|
|
|
|
* If a file is selected it will be opened.
|
|
|
|
*/
|
|
|
|
void MainWindow::fileSelected()
|
|
|
|
{
|
2016-08-07 19:59:33 +02:00
|
|
|
if(!m_internalFileSelection) {
|
|
|
|
const QModelIndexList selectedIndexes = m_ui->filesTreeView->selectionModel()->selectedRows();
|
|
|
|
if(selectedIndexes.count() == 1) {
|
2016-08-14 22:49:47 +02:00
|
|
|
const QString path(m_fileModel->filePath(m_fileFilterModel->mapToSource(selectedIndexes.at(0))));
|
|
|
|
const QFileInfo fileInfo(path);
|
2016-08-07 19:59:33 +02:00
|
|
|
if(fileInfo.isFile()) {
|
|
|
|
startParsing(path);
|
|
|
|
m_ui->pathLineEdit->setText(fileInfo.dir().path());
|
|
|
|
} else if(fileInfo.isDir()) {
|
|
|
|
m_ui->pathLineEdit->setText(path);
|
|
|
|
}
|
|
|
|
m_ui->pathLineEdit->setProperty("classNames", QStringList());
|
|
|
|
updateStyle(m_ui->pathLineEdit);
|
2015-04-22 19:33:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Updates the status of the relevant widgets (enabled/disabled, visible/hidden) according to the
|
|
|
|
* current "file status" (opened/closed, has tags/no tags).
|
|
|
|
*/
|
2016-02-29 23:59:46 +01:00
|
|
|
void MainWindow::handleFileStatusChange(bool opened, bool hasTag)
|
2015-04-22 19:33:53 +02:00
|
|
|
{
|
2016-02-29 23:59:46 +01:00
|
|
|
// actions to save, delete, close
|
2015-04-22 19:33:53 +02:00
|
|
|
m_ui->actionSave->setEnabled(opened);
|
|
|
|
m_ui->actionDelete_all_tags->setEnabled(hasTag);
|
|
|
|
m_ui->actionSave_file_information->setEnabled(opened);
|
2016-05-01 20:07:04 +02:00
|
|
|
m_ui->actionSave_as->setEnabled(opened);
|
2015-04-22 19:33:53 +02:00
|
|
|
m_ui->actionClose->setEnabled(opened);
|
2015-09-21 22:56:09 +02:00
|
|
|
m_ui->actionReload->setEnabled(opened);
|
2015-10-14 20:15:10 +02:00
|
|
|
m_ui->actionExternalPlayer->setEnabled(opened);
|
2015-07-07 00:46:43 +02:00
|
|
|
// window title
|
2016-02-29 23:59:46 +01:00
|
|
|
setWindowTitle(Dialogs::generateWindowTitle(opened ? DocumentStatus::Saved : DocumentStatus::NoDocument, m_ui->tagEditorWidget->currentPath()));
|
2015-04-22 19:33:53 +02:00
|
|
|
}
|
|
|
|
|
2016-08-07 19:59:33 +02:00
|
|
|
/*!
|
|
|
|
* \brief Handles that the current path has changed by the tag editor widget itself.
|
|
|
|
*/
|
2016-08-14 22:49:47 +02:00
|
|
|
void MainWindow::handleCurrentPathChanged(const QString &newPath)
|
2015-04-22 19:33:53 +02:00
|
|
|
{
|
2016-02-29 23:59:46 +01:00
|
|
|
// ensure the current file is still selected
|
2016-08-07 19:59:33 +02:00
|
|
|
m_internalFileSelection = true;
|
2016-08-14 22:49:47 +02:00
|
|
|
const QModelIndex index = m_fileFilterModel->mapFromSource(m_fileModel->index(newPath));
|
2016-02-29 23:59:46 +01:00
|
|
|
if(index.isValid()) {
|
|
|
|
m_ui->filesTreeView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect);
|
2016-08-14 22:49:47 +02:00
|
|
|
m_ui->pathLineEdit->setText(QFileInfo(newPath).dir().path());
|
|
|
|
m_ui->pathLineEdit->setProperty("classNames", QStringList());
|
|
|
|
updateStyle(m_ui->pathLineEdit);
|
2015-04-22 19:33:53 +02:00
|
|
|
}
|
2016-08-07 19:59:33 +02:00
|
|
|
m_internalFileSelection = false;
|
2016-02-29 23:59:46 +01:00
|
|
|
// ensure this is the active window
|
|
|
|
activateWindow();
|
2015-08-07 23:49:32 +02:00
|
|
|
}
|
|
|
|
|
2015-10-14 20:15:10 +02:00
|
|
|
/*!
|
|
|
|
* \brief Spawns an external player for the current file.
|
|
|
|
*/
|
|
|
|
void MainWindow::spawnExternalPlayer()
|
|
|
|
{
|
2016-02-29 23:59:46 +01:00
|
|
|
const QString ¤tPath = m_ui->tagEditorWidget->currentPath();
|
|
|
|
if(!currentPath.isEmpty()) {
|
|
|
|
DesktopUtils::openLocalFileOrDir(currentPath);
|
2015-10-14 20:15:10 +02:00
|
|
|
} else {
|
|
|
|
m_ui->statusBar->showMessage(tr("No file opened."));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-03 22:21:15 +01:00
|
|
|
/*!
|
2016-12-01 22:23:01 +01:00
|
|
|
* \brief Initializes m_dbQueryWidget is not already initialized.
|
2016-03-03 22:21:15 +01:00
|
|
|
*/
|
2016-12-01 22:23:01 +01:00
|
|
|
void MainWindow::initDbQueryWidget()
|
2016-03-03 22:21:15 +01:00
|
|
|
{
|
|
|
|
if(!m_dbQueryWidget) {
|
|
|
|
m_ui->dbQueryDockWidget->setWidget(m_dbQueryWidget = new DbQueryWidget(m_ui->tagEditorWidget, this));
|
2016-12-01 22:23:01 +01:00
|
|
|
connect(m_ui->tagEditorWidget, &TagEditorWidget::tagValuesLoaded, m_dbQueryWidget, static_cast<void(DbQueryWidget::*)(void)>(&DbQueryWidget::autoInsertMatchingResults), Qt::DirectConnection);
|
2016-03-03 22:21:15 +01:00
|
|
|
}
|
2016-12-01 22:23:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Toggles visibility of the database query widget.
|
|
|
|
*/
|
|
|
|
void MainWindow::toggleDbQueryWidget()
|
|
|
|
{
|
|
|
|
initDbQueryWidget();
|
2016-10-09 19:44:06 +02:00
|
|
|
m_ui->dbQueryDockWidget->setVisible(m_ui->dbQueryDockWidget->isHidden());
|
2016-03-03 22:21:15 +01:00
|
|
|
}
|
|
|
|
|
2015-04-22 19:33:53 +02:00
|
|
|
/*!
|
|
|
|
* \brief Shows the about dialog.
|
|
|
|
*/
|
|
|
|
void MainWindow::showAboutDlg()
|
|
|
|
{
|
|
|
|
if(!m_aboutDlg) {
|
|
|
|
m_aboutDlg = new Dialogs::AboutDialog(this, tr("A tag editing utility supporting ID3, MP4 (iTunes style), Vorbis and Matroska tags."), QImage(QStringLiteral(":/tageditor/icons/hicolor/128x128/apps/tageditor.png")));
|
|
|
|
}
|
|
|
|
if(m_aboutDlg->isHidden()) {
|
|
|
|
m_aboutDlg->show();
|
|
|
|
} else {
|
|
|
|
m_aboutDlg->activateWindow();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Shows the settings dialog (modal).
|
|
|
|
*/
|
|
|
|
void MainWindow::showSettingsDlg()
|
|
|
|
{
|
|
|
|
if(!m_settingsDlg) {
|
|
|
|
m_settingsDlg = new SettingsDialog(this);
|
2016-05-26 02:15:41 +02:00
|
|
|
connect(m_settingsDlg, &SettingsDialog::applied, this, &MainWindow::applySettingsFromDialog);
|
|
|
|
connect(m_settingsDlg, &SettingsDialog::applied, m_ui->tagEditorWidget, &TagEditorWidget::applySettingsFromDialog);
|
2015-04-22 19:33:53 +02:00
|
|
|
}
|
2016-05-26 02:15:41 +02:00
|
|
|
m_settingsDlg->exec();
|
2015-04-22 19:33:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Shows the "Rename files" dialog (instance of RenameFilesDialog).
|
|
|
|
*/
|
|
|
|
void MainWindow::showRenameFilesDlg()
|
|
|
|
{
|
|
|
|
if(!m_renameFilesDlg) {
|
|
|
|
m_renameFilesDlg.reset(new RenameFilesDialog);
|
|
|
|
}
|
|
|
|
m_renameFilesDlg->setDirectory(currentDirectory());
|
|
|
|
if(m_renameFilesDlg->isHidden()) {
|
|
|
|
m_renameFilesDlg->show();
|
|
|
|
} else {
|
|
|
|
m_renameFilesDlg->activateWindow();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Selects the next file.
|
2016-02-29 23:59:46 +01:00
|
|
|
* \remarks Does nothing if there is currently no file selected.
|
2015-04-22 19:33:53 +02:00
|
|
|
*/
|
|
|
|
void MainWindow::selectNextFile()
|
|
|
|
{
|
|
|
|
QItemSelectionModel *selectionModel = m_ui->filesTreeView->selectionModel();
|
2016-06-14 00:52:03 +02:00
|
|
|
const QModelIndexList selectedIndexes = selectionModel->selectedIndexes();
|
2016-02-29 23:59:46 +01:00
|
|
|
if(!selectedIndexes.isEmpty()) {
|
|
|
|
selectNextFile(selectionModel, selectedIndexes.at(0), false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Selects the file next to the file with the specified index.
|
|
|
|
*
|
|
|
|
* If \a notDeeper is false, this method will not try to go deeper into
|
|
|
|
* the file system tree.
|
|
|
|
*/
|
|
|
|
void MainWindow::selectNextFile(QItemSelectionModel *selectionModel, const QModelIndex ¤tIndex, bool notDeeper)
|
|
|
|
{
|
|
|
|
QModelIndex next;
|
|
|
|
if(!notDeeper && selectionModel->model()->hasChildren(currentIndex)) {
|
|
|
|
// a directory is selected -> go deeper
|
|
|
|
if(m_fileFilterModel->canFetchMore(currentIndex)) {
|
|
|
|
// files and subdirectories have to be fetched
|
2016-06-14 00:52:03 +02:00
|
|
|
// -> QFileSystemModel seems to fetch files and directories async
|
|
|
|
// -> hence fetchMore will return immediatly
|
2016-02-29 23:59:46 +01:00
|
|
|
// -> select next file when rowsInserted is emitted
|
|
|
|
auto conn = make_shared<QMetaObject::Connection>();
|
|
|
|
*conn = connect(m_fileFilterModel, &QAbstractItemModel::rowsInserted, [this, selectionModel, currentIndex, conn] (const QModelIndex &parent, int, int) {
|
|
|
|
disconnect(*conn);
|
|
|
|
if(parent == currentIndex) {
|
2016-03-19 18:34:10 +01:00
|
|
|
const QModelIndex next = m_fileFilterModel->index(0, 0, parent);
|
2016-02-29 23:59:46 +01:00
|
|
|
if(next.isValid()) {
|
2016-03-03 22:21:15 +01:00
|
|
|
if(m_ui->filesTreeView->model()->hasChildren(next)) {
|
|
|
|
// next item is a directory -> keep on searching
|
|
|
|
selectNextFile(selectionModel, next, false);
|
|
|
|
} else {
|
|
|
|
m_ui->filesTreeView->selectionModel()->setCurrentIndex(next, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
|
|
|
|
}
|
2016-02-29 23:59:46 +01:00
|
|
|
} else {
|
|
|
|
selectNextFile(selectionModel, currentIndex, true);
|
2015-04-22 19:33:53 +02:00
|
|
|
}
|
2016-02-29 23:59:46 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
m_fileModel->fetchMore(m_fileFilterModel->mapToSource(currentIndex));
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
// files and subdirectories have been fetched already
|
|
|
|
next = currentIndex.child(0, currentIndex.column());
|
2015-04-22 19:33:53 +02:00
|
|
|
}
|
2016-02-29 23:59:46 +01:00
|
|
|
}
|
|
|
|
if(!next.isValid()) {
|
|
|
|
// not possible to go deeper -> choose next sibling
|
|
|
|
next = currentIndex.sibling(currentIndex.row() + 1, currentIndex.column());
|
|
|
|
}
|
|
|
|
if(!next.isValid()) {
|
|
|
|
// not possible to choose next sibling -> go higher
|
|
|
|
const QModelIndex parent = currentIndex.parent();
|
|
|
|
if(parent.isValid()) {
|
|
|
|
selectNextFile(selectionModel, parent, true);
|
|
|
|
return;
|
2015-04-22 19:33:53 +02:00
|
|
|
}
|
|
|
|
}
|
2016-02-29 23:59:46 +01:00
|
|
|
if(next.isValid()) {
|
2016-03-03 22:21:15 +01:00
|
|
|
if(selectionModel->model()->hasChildren(next)) {
|
|
|
|
// next item is a directory -> keep on searching
|
|
|
|
selectNextFile(selectionModel, next, false);
|
|
|
|
} else {
|
|
|
|
selectionModel->setCurrentIndex(next, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
|
|
|
|
}
|
2016-02-29 23:59:46 +01:00
|
|
|
} else {
|
|
|
|
showNextFileNotFound();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::showNextFileNotFound()
|
|
|
|
{
|
|
|
|
static const QString errormsg(tr("Unable to show the next file because it can't be found anymore."));
|
|
|
|
QMessageBox::warning(this, QApplication::applicationName(), errormsg);
|
|
|
|
m_ui->statusBar->showMessage(errormsg);
|
2015-04-22 19:33:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Shows an open file dialog and opens the selected file.
|
|
|
|
*/
|
|
|
|
void MainWindow::showOpenFileDlg()
|
|
|
|
{
|
2016-05-01 20:07:04 +02:00
|
|
|
const QString path = QFileDialog::getOpenFileName(this, tr("Open file - ") + QCoreApplication::applicationName());
|
2015-04-22 19:33:53 +02:00
|
|
|
if(!path.isEmpty()) {
|
2015-07-08 00:21:21 +02:00
|
|
|
startParsing(path);
|
2015-04-22 19:33:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-01 20:07:04 +02:00
|
|
|
/*!
|
|
|
|
* \brief Shows an save file dialog and triggers saving the changes under the selected location.
|
|
|
|
*/
|
|
|
|
void MainWindow::showSaveAsDlg()
|
|
|
|
{
|
2016-11-18 17:59:53 +01:00
|
|
|
const QString path = QFileDialog::getSaveFileName(this, tr("Save changes as - ") + QCoreApplication::applicationName(),
|
|
|
|
m_ui->tagEditorWidget->currentDir());
|
2016-05-01 20:07:04 +02:00
|
|
|
if(!path.isEmpty()) {
|
|
|
|
m_ui->tagEditorWidget->fileInfo().setSaveFilePath(path.toLocal8Bit().data());
|
|
|
|
m_ui->tagEditorWidget->applyEntriesAndSaveChangings();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:33:53 +02:00
|
|
|
/*!
|
|
|
|
* \brief Saves the file information generated to be displayed in the info web view in a file.
|
|
|
|
*/
|
|
|
|
void MainWindow::saveFileInformation()
|
|
|
|
{
|
2016-11-23 21:46:33 +01:00
|
|
|
if(fileOperationOngoing()) {
|
|
|
|
m_ui->statusBar->showMessage(tr("Unable to save file information because the current process hasn't been finished yet."));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(!fileInfo().isOpen()) {
|
|
|
|
QMessageBox::information(this, QApplication::applicationName(), tr("No file is opened."));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QByteArray htmlData =
|
2016-04-21 23:55:22 +02:00
|
|
|
#ifndef TAGEDITOR_NO_WEBVIEW
|
2016-11-23 21:46:33 +01:00
|
|
|
!m_ui->tagEditorWidget->fileInfoHtml().isEmpty() ?
|
|
|
|
m_ui->tagEditorWidget->fileInfoHtml() :
|
2016-04-21 23:55:22 +02:00
|
|
|
#endif
|
2016-11-23 21:46:33 +01:00
|
|
|
HtmlInfo::generateInfo(fileInfo(), m_ui->tagEditorWidget->originalNotifications());
|
|
|
|
if(htmlData.isEmpty()) {
|
|
|
|
QMessageBox::information(this, QApplication::applicationName(), tr("No file information available."));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QString path = QFileDialog::getSaveFileName(this, tr("Save file information - ") + QCoreApplication::applicationName());
|
|
|
|
if(path.isEmpty()) {
|
|
|
|
QMessageBox::critical(this, QApplication::applicationName(), tr("Unable to open file."));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QFile file(path);
|
|
|
|
if(file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
|
|
|
QTextStream stream(&file);
|
|
|
|
stream.setCodec(QTextCodec::codecForName("UTF-8"));
|
|
|
|
stream << htmlData;
|
|
|
|
file.close();
|
|
|
|
if(file.error() != QFileDevice::NoError) {
|
|
|
|
QMessageBox::critical(this, QApplication::applicationName(), tr("Unable to write to file.\n%1").arg(file.errorString()));
|
2015-04-22 19:33:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Applies settings from Settings namespace. Only settings configurable through the SettingsDialog
|
|
|
|
* will be applied and not settings like the main window's geometry and state.
|
|
|
|
*/
|
|
|
|
void MainWindow::applySettingsFromDialog()
|
|
|
|
{
|
2016-10-24 20:15:10 +02:00
|
|
|
auto &settings = Settings::values();
|
|
|
|
if(m_fileFilterModel->isFilterEnabled() != settings.fileBrowser.hideBackupFiles) {
|
2015-04-22 19:33:53 +02:00
|
|
|
// check this condition to avoid unnecessary model reset
|
2016-10-24 20:15:10 +02:00
|
|
|
m_fileFilterModel->setFilterEnabled(settings.fileBrowser.hideBackupFiles);
|
2016-01-25 19:23:33 +01:00
|
|
|
const QModelIndex index = m_fileFilterModel->mapFromSource(m_fileModel->index(m_ui->pathLineEdit->text()));
|
2015-04-22 19:33:53 +02:00
|
|
|
if(index.isValid()) {
|
|
|
|
m_ui->filesTreeView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::Select);
|
|
|
|
}
|
|
|
|
}
|
2016-10-24 20:15:10 +02:00
|
|
|
if(m_fileModel->isReadOnly() != settings.fileBrowser.readOnly) {
|
|
|
|
m_fileModel->setReadOnly(settings.fileBrowser.readOnly);
|
2015-04-22 19:33:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|