diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 080a7bd..355cdd6 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -130,7 +130,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(m_ui->actionSave, &QAction::triggered, m_ui->tagEditorWidget, &TagEditorWidget::applyEntriesAndSaveChangings); connect(m_ui->actionSave_as, &QAction::triggered, this, &MainWindow::showSaveAsDlg); connect(m_ui->actionDelete_all_tags, &QAction::triggered, m_ui->tagEditorWidget, &TagEditorWidget::deleteAllTagsAndSave); - connect(m_ui->actionSave_file_information, &QAction::triggered, this, &MainWindow::saveFileInformation); + connect(m_ui->actionSave_file_information, &QAction::triggered, m_ui->tagEditorWidget, &TagEditorWidget::saveFileInfo); connect(m_ui->actionClose, &QAction::triggered, m_ui->tagEditorWidget, &TagEditorWidget::closeFile); connect(m_ui->actionReload, &QAction::triggered, m_ui->tagEditorWidget, &TagEditorWidget::reparseFile); connect(m_ui->actionExternalPlayer, &QAction::triggered, this, &MainWindow::spawnExternalPlayer); @@ -509,49 +509,6 @@ void MainWindow::showSaveAsDlg() } } -/*! - * \brief Saves the file information generated to be displayed in the info web view in a file. - */ -void MainWindow::saveFileInformation() -{ - 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 = - #ifndef TAGEDITOR_NO_WEBVIEW - !m_ui->tagEditorWidget->fileInfoHtml().isEmpty() ? - m_ui->tagEditorWidget->fileInfoHtml() : - #endif - 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())); - } - } -} - /*! * \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. diff --git a/gui/mainwindow.h b/gui/mainwindow.h index 44726e3..a9b35fe 100644 --- a/gui/mainwindow.h +++ b/gui/mainwindow.h @@ -64,7 +64,6 @@ private slots: void showNextFileNotFound(); void showOpenFileDlg(); void showSaveAsDlg(); - void saveFileInformation(); void handleFileStatusChange(bool opened, bool hasTag); void handleCurrentPathChanged(const QString &newPath); diff --git a/gui/tageditorwidget.cpp b/gui/tageditorwidget.cpp index a668e1d..3ffad31 100644 --- a/gui/tageditorwidget.cpp +++ b/gui/tageditorwidget.cpp @@ -12,6 +12,7 @@ #include "../misc/utility.h" #include "ui_tageditorwidget.h" +#include "resources/config.h" #include #include @@ -30,13 +31,17 @@ #include #include +#include #include #include #include #include #include +#include +#include #include #include +#include #include #include #include @@ -152,6 +157,18 @@ TagEditorWidget::TagEditorWidget(QWidget *parent) : TagEditorWidget::~TagEditorWidget() {} +/*! + * \brief Returns the HTML source of the info website. + * \remarks In contrast to fileInfoHtml(), this method will generate file info if not available yet. + */ +const QByteArray &TagEditorWidget::generateFileInfoHtml() +{ + if(m_fileInfoHtml.isEmpty()) { + m_fileInfoHtml = HtmlInfo::generateInfo(m_fileInfo, m_originalNotifications); + } + return m_fileInfoHtml; +} + /*! * \brief Returns whether the file name is visible at the top of the widget. */ @@ -621,21 +638,25 @@ void TagEditorWidget::initInfoView() } /*! - * \brief Updates the info web view to show information about the - * currently opened file. + * \brief Updates the info web view to show information about the currently opened file. */ void TagEditorWidget::updateInfoView() { + // ensure previous file info HTML is cleared in any case + m_fileInfoHtml.clear(); + + // update webview if present #ifndef TAGEDITOR_NO_WEBVIEW if(m_infoWebView) { if(m_fileInfo.isOpen()) { - m_fileInfoHtml = HtmlInfo::generateInfo(m_fileInfo, m_originalNotifications); - m_infoWebView->setContent(m_fileInfoHtml, QStringLiteral("application/xhtml+xml")); + m_infoWebView->setContent(generateFileInfoHtml(), QStringLiteral("application/xhtml+xml")); } else { m_infoWebView->setUrl(QStringLiteral("about:blank")); } } #endif + + // update info model if present if(m_infoModel) { m_infoModel->setFileInfo(m_fileInfo.isOpen() ? &m_fileInfo : nullptr); // resets the model } @@ -680,8 +701,16 @@ void TagEditorWidget::showInfoWebViewContextMenu(const QPoint &) connect(©Action, &QAction::triggered, [this] { QApplication::clipboard()->setText(m_infoWebView->selectedText()); }); + QAction saveAction(QIcon::fromTheme(QStringLiteral("document-save")), tr("Save ..."), nullptr); + saveAction.setDisabled(m_fileInfoHtml.isEmpty()); + connect(&saveAction, &QAction::triggered, this, &TagEditorWidget::saveFileInfo); + QAction openAction(QIcon::fromTheme(QStringLiteral("internet-web-browser")), tr("Open in browser"), nullptr); + openAction.setDisabled(m_fileInfoHtml.isEmpty()); + connect(&openAction, &QAction::triggered, this, &TagEditorWidget::openFileInfoInBrowser); QMenu menu; menu.addAction(©Action); + menu.addAction(&saveAction); + menu.addAction(&openAction); menu.exec(QCursor::pos()); } #endif @@ -1233,6 +1262,75 @@ void TagEditorWidget::closeFile() updateFileStatusStatus(); } +bool TagEditorWidget::handleFileInfoUnavailable() +{ + if(fileOperationOngoing()) { + emit statusMessage(tr("Unable to save file information because the current process hasn't been finished yet.")); + return true; + } + if(!fileInfo().isOpen()) { + QMessageBox::information(this, QApplication::applicationName(), tr("No file is opened.")); + return true; + } + + if(generateFileInfoHtml().isEmpty()) { + QMessageBox::information(this, QApplication::applicationName(), tr("No file information available.")); + return true; + } + return false; +} + +bool TagEditorWidget::writeFileInfoToFile(QFile &file) +{ + if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + QMessageBox::critical(this, QApplication::applicationName(), tr("Unable to open file \"%1\".").arg(file.fileName())); + return false; + } + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + stream << fileInfoHtml(); + file.close(); + + if(file.error() != QFileDevice::NoError) { + QMessageBox::critical(this, QApplication::applicationName(), tr("Unable to write to file \"%1\".\n%2").arg(file.fileName(), file.errorString())); + return false; + } + return true; +} + +/*! + * \brief Saves the file information generated to be displayed in the info web view in a file. + */ +void TagEditorWidget::saveFileInfo() +{ + if(handleFileInfoUnavailable()) { + 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); + writeFileInfoToFile(file); +} + +void TagEditorWidget::openFileInfoInBrowser() +{ + if(handleFileInfoUnavailable()) { + return; + } + + m_temporaryInfoFile = make_unique(QDir::tempPath() + QStringLiteral("/" PROJECT_NAME "-fileinfo-XXXXXX.xhtml")); + if(!writeFileInfoToFile(*m_temporaryInfoFile)) { + return; + } + + QDesktopServices::openUrl(QStringLiteral("file://") + m_temporaryInfoFile->fileName()); +} + /*! * \brief This private slot is invoked the the return key has been pressed in a tag edit. * diff --git a/gui/tageditorwidget.h b/gui/tageditorwidget.h index 9f265db..dae9a06 100644 --- a/gui/tageditorwidget.h +++ b/gui/tageditorwidget.h @@ -14,6 +14,8 @@ QT_FORWARD_DECLARE_CLASS(QFileSystemWatcher) QT_FORWARD_DECLARE_CLASS(QMenu) QT_FORWARD_DECLARE_CLASS(QTreeView) +QT_FORWARD_DECLARE_CLASS(QFile) +QT_FORWARD_DECLARE_CLASS(QTemporaryFile) namespace Media { DECLARE_ENUM_CLASS(TagType, unsigned int); @@ -50,6 +52,7 @@ public: Media::NotificationList &originalNotifications(); bool isTagEditShown() const; const QByteArray &fileInfoHtml() const; + const QByteArray &generateFileInfoHtml(); bool isFileNameVisible() const; void setFileNameVisible(bool visible); bool areButtonsVisible() const; @@ -66,6 +69,8 @@ public slots: bool applyEntriesAndSaveChangings(); bool deleteAllTagsAndSave(); void closeFile(); + void saveFileInfo(); + void openFileInfoInBrowser(); // misc void applySettingsFromDialog(); @@ -108,6 +113,8 @@ private slots: #ifndef TAGEDITOR_NO_WEBVIEW void showInfoWebViewContextMenu(const QPoint &); #endif + bool handleFileInfoUnavailable(); + bool writeFileInfoToFile(QFile &file); private: void updateDocumentTitleEdits(); @@ -130,6 +137,7 @@ private: #endif FileInfoModel *m_infoModel; QTreeView *m_infoTreeView; + std::unique_ptr m_temporaryInfoFile; // tag, file, directory management QString m_currentPath; QFileSystemWatcher *m_fileWatcher; @@ -192,6 +200,8 @@ inline Media::NotificationList &TagEditorWidget::originalNotifications() /*! * \brief Returns the HTML source of the info website. + * \remarks Returns an empty string if no file info has been generated yet. See generateFileInfoHtml() for a method which will ensure + * the file info has been generated. */ inline const QByteArray &TagEditorWidget::fileInfoHtml() const {