diff --git a/rssguard.pro b/rssguard.pro index c5c41ae62..31aeae742 100755 --- a/rssguard.pro +++ b/rssguard.pro @@ -188,8 +188,7 @@ win32 { } DISTFILES += resources/scripts/astyle/.astylerc \ - resources/scripts/uncrustify/uncrustify.cfg \ - resources/scripts/uncrustify/uncrustify.cfg + resources/scripts/uncrustify/uncrustify.cfg MOC_DIR = $$OUT_PWD/moc RCC_DIR = $$OUT_PWD/rcc @@ -340,7 +339,8 @@ HEADERS += src/core/feeddownloader.h \ src/core/messagesmodelsqllayer.h \ src/gui/treeviewcolumnsmenu.h \ src/services/abstract/labelsrootitem.h \ - src/services/abstract/label.h + src/services/abstract/label.h \ + src/miscellaneous/externaltool.h SOURCES += src/core/feeddownloader.cpp \ src/core/feedsmodel.cpp \ @@ -466,7 +466,8 @@ SOURCES += src/core/feeddownloader.cpp \ src/core/messagesmodelsqllayer.cpp \ src/gui/treeviewcolumnsmenu.cpp \ src/services/abstract/labelsrootitem.cpp \ - src/services/abstract/label.cpp + src/services/abstract/label.cpp \ + src/miscellaneous/externaltool.cpp OBJECTIVE_SOURCES += src/miscellaneous/disablewindowtabbing.mm diff --git a/src/definitions/definitions.h b/src/definitions/definitions.h index bc45e1f9b..0fb237ac7 100755 --- a/src/definitions/definitions.h +++ b/src/definitions/definitions.h @@ -84,6 +84,8 @@ #define GOOGLE_SUGGEST_URL "http://suggestqueries.google.com/complete/search?output=toolbar&hl=en&q=%1" #define ENCRYPTION_FILE_NAME "key.private" #define RELOAD_MODEL_BORDER_NUM 10 +#define EXTERNAL_TOOL_SEPARATOR "###" +#define EXTERNAL_TOOL_PARAM_SEPARATOR "|||" #define MAX_ZOOM_FACTOR 5.0f #define MIN_ZOOM_FACTOR 0.25f diff --git a/src/gui/messagesview.cpp b/src/gui/messagesview.cpp index a7f12ddf5..593eeb02e 100755 --- a/src/gui/messagesview.cpp +++ b/src/gui/messagesview.cpp @@ -24,6 +24,7 @@ #include "network-web/networkfactory.h" #include "network-web/webfactory.h" #include "gui/dialogs/formmain.h" +#include "miscellaneous/externaltool.h" #include "gui/messagebox.h" #include "gui/treeviewcolumnsmenu.h" #include "gui/styleditemdelegatewithoutfocus.h" @@ -187,11 +188,12 @@ void MessagesView::initializeContextMenu() { QMenu* menu = new QMenu(tr("Open with external tool"), m_contextMenu); menu->setIcon(qApp->icons()->fromTheme(QSL("document-open"))); - foreach (const QString& tool, qApp->settings()->value(GROUP(Browser), SETTING(Browser::ExternalTools)).toStringList()) { - QAction* act_tool = new QAction(QFileInfo(tool).fileName(), menu); + foreach (const ExternalTool& tool, ExternalTool::toolsFromSettings()) { + QAction* act_tool = new QAction(QFileInfo(tool.executable()).fileName(), menu); - act_tool->setIcon(icon_provider.icon(tool)); - act_tool->setToolTip(tool); + act_tool->setIcon(icon_provider.icon(tool.executable())); + act_tool->setToolTip(tool.executable()); + act_tool->setData(QVariant::fromValue(tool)); menu->addAction(act_tool); connect(act_tool, &QAction::triggered, this, &MessagesView::openSelectedMessagesWithExternalTool); @@ -510,13 +512,13 @@ void MessagesView::openSelectedMessagesWithExternalTool() { QAction* sndr = qobject_cast(sender()); if (sndr != nullptr) { - const QString& tool = sndr->toolTip(); + auto tool = sndr->data().value(); foreach (const QModelIndex& index, selectionModel()->selectedRows()) { const QString& link = m_sourceModel->messageAt(m_proxyModel->mapToSource(index).row()).m_url; if (!link.isEmpty()) { - if (!QProcess::startDetached(tool, QStringList() << link)) { + if (!QProcess::startDetached(tool.executable(), QStringList() << tool.parameters() << link)) { qApp->showGuiMessage(tr("Cannot run external tool"), tr("External tool '%1' could not be started."), QSystemTrayIcon::Critical); } diff --git a/src/gui/settings/settingsbrowsermail.cpp b/src/gui/settings/settingsbrowsermail.cpp index f28b1da8f..a756738cd 100755 --- a/src/gui/settings/settingsbrowsermail.cpp +++ b/src/gui/settings/settingsbrowsermail.cpp @@ -21,13 +21,15 @@ #include "miscellaneous/application.h" #include "miscellaneous/textfactory.h" #include "gui/guiutilities.h" +#include "miscellaneous/externaltool.h" #include #include +#include SettingsBrowserMail::SettingsBrowserMail(Settings* settings, QWidget* parent) - : SettingsPanel(settings, parent), m_ui(new Ui::SettingsBrowserMail) { + : SettingsPanel(settings, parent), m_ui(new Ui::SettingsBrowserMail) { m_ui->setupUi(this); GuiUtilities::setLabelAsNotice(*m_ui->label, false); @@ -41,6 +43,9 @@ SettingsBrowserMail::SettingsBrowserMail(Settings* settings, QWidget* parent) connect(m_ui->m_checkOpenLinksInExternal, &QCheckBox::stateChanged, this, &SettingsBrowserMail::dirtifySettings); #endif + m_ui->m_listTools->setHeaderLabels(QStringList() << tr("Executable") << tr("Parameters")); + m_ui->m_listTools->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); + connect(m_ui->m_cmbProxyType, static_cast(&QComboBox::currentIndexChanged), this, &SettingsBrowserMail::dirtifySettings); connect(m_ui->m_txtProxyHost, &QLineEdit::textChanged, this, &SettingsBrowserMail::dirtifySettings); @@ -66,8 +71,10 @@ SettingsBrowserMail::SettingsBrowserMail(Settings* settings, QWidget* parent) connect(m_ui->m_btnDeleteTool, &QPushButton::clicked, this, &SettingsBrowserMail::dirtifySettings); connect(m_ui->m_btnAddTool, &QPushButton::clicked, this, &SettingsBrowserMail::addExternalTool); connect(m_ui->m_btnDeleteTool, &QPushButton::clicked, this, &SettingsBrowserMail::deleteSelectedExternalTool); - connect(m_ui->m_listTools, &QListWidget::currentTextChanged, [this](const QString & current_text) { - m_ui->m_btnDeleteTool->setEnabled(!current_text.isEmpty()); + connect(m_ui->m_listTools, &QTreeWidget::currentItemChanged, [this](QTreeWidgetItem * current, QTreeWidgetItem * previous) { + Q_UNUSED(previous) + + m_ui->m_btnDeleteTool->setEnabled(current != nullptr); }); } @@ -121,19 +128,23 @@ void SettingsBrowserMail::onProxyTypeChanged(int index) { m_ui->m_lblProxyUsername->setEnabled(is_proxy_selected); } -QStringList SettingsBrowserMail::externalTools() const { - QStringList list; +QList SettingsBrowserMail::externalTools() const { + QList list; - for (int i = 0; i < m_ui->m_listTools->count(); i++) { - list.append(m_ui->m_listTools->item(i)->text()); + for (int i = 0; i < m_ui->m_listTools->topLevelItemCount(); i++) { + list.append(m_ui->m_listTools->topLevelItem(i)->data(0, Qt::UserRole).value()); } return list; } -void SettingsBrowserMail::setExternalTools(const QStringList& list) { - foreach (const QString& tool, list) { - m_ui->m_listTools->addItem(tool); +void SettingsBrowserMail::setExternalTools(const QList& list) { + foreach (const ExternalTool& tool, list) { + QTreeWidgetItem* item = new QTreeWidgetItem(m_ui->m_listTools, + QStringList() << tool.executable() << tool.parameters()); + item->setData(0, Qt::UserRole, QVariant::fromValue(tool)); + + m_ui->m_listTools->addTopLevelItem(item); } } @@ -194,7 +205,7 @@ void SettingsBrowserMail::loadSettings() { m_ui->m_txtProxyPassword->setText(TextFactory::decrypt(settings()->value(GROUP(Proxy), SETTING(Proxy::Password)).toString())); m_ui->m_spinProxyPort->setValue(settings()->value(GROUP(Proxy), SETTING(Proxy::Port)).toInt()); - setExternalTools(settings()->value(GROUP(Browser), SETTING(Browser::ExternalTools)).toStringList()); + setExternalTools(ExternalTool::toolsFromSettings()); onEndLoadSettings(); } @@ -220,7 +231,9 @@ void SettingsBrowserMail::saveSettings() { settings()->setValue(GROUP(Proxy), Proxy::Password, TextFactory::encrypt(m_ui->m_txtProxyPassword->text())); settings()->setValue(GROUP(Proxy), Proxy::Port, m_ui->m_spinProxyPort->value()); - settings()->setValue(GROUP(Browser), Browser::ExternalTools, externalTools()); + auto tools = externalTools(); + + ExternalTool::setToolsToSettings(tools); // Reload settings for all network access managers. SilentNetworkAccessManager::instance()->loadSettings(); @@ -239,12 +252,23 @@ void SettingsBrowserMail::addExternalTool() { #endif if (!executable_file.isEmpty()) { - m_ui->m_listTools->addItem(QDir::toNativeSeparators(executable_file)); + executable_file = QDir::toNativeSeparators(executable_file); + bool ok; + QString parameters = QInputDialog::getText(this, tr("Enter parameters"), + tr("Enter (optional) parameters separated by single space to send to executable when opening URLs."), + QLineEdit::Normal, QString(), &ok); + + if (ok) { + QTreeWidgetItem* item = new QTreeWidgetItem(m_ui->m_listTools, + QStringList() << QDir::toNativeSeparators(executable_file) << parameters); + item->setData(0, Qt::UserRole, QVariant::fromValue(ExternalTool(executable_file, parameters.split(QSL(" "))))); + m_ui->m_listTools->addTopLevelItem(item); + } } } void SettingsBrowserMail::deleteSelectedExternalTool() { - if (m_ui->m_listTools->currentRow() >= 0) { - m_ui->m_listTools->takeItem(m_ui->m_listTools->currentRow()); + if (!m_ui->m_listTools->selectedItems().isEmpty()) { + m_ui->m_listTools->takeTopLevelItem(m_ui->m_listTools->indexOfTopLevelItem(m_ui->m_listTools->selectedItems().first())); } } diff --git a/src/gui/settings/settingsbrowsermail.h b/src/gui/settings/settingsbrowsermail.h index 562a9b792..584dce46d 100755 --- a/src/gui/settings/settingsbrowsermail.h +++ b/src/gui/settings/settingsbrowsermail.h @@ -20,6 +20,7 @@ #include "gui/settings/settingspanel.h" +#include "miscellaneous/externaltool.h" #include "ui_settingsbrowsermail.h" @@ -34,7 +35,7 @@ class SettingsBrowserMail : public SettingsPanel { return tr("Web browser & e-mail & proxy"); } - void loadSettings(); + void loadSettings(); void saveSettings(); private slots: @@ -48,8 +49,8 @@ class SettingsBrowserMail : public SettingsPanel { void onProxyTypeChanged(int index); private: - QStringList externalTools() const; - void setExternalTools(const QStringList& list); + QList externalTools() const; + void setExternalTools(const QList& list); Ui::SettingsBrowserMail* m_ui; }; diff --git a/src/gui/settings/settingsbrowsermail.ui b/src/gui/settings/settingsbrowsermail.ui index ab01cfb13..924ad50a7 100755 --- a/src/gui/settings/settingsbrowsermail.ui +++ b/src/gui/settings/settingsbrowsermail.ui @@ -262,16 +262,30 @@ - + false true - + + 0 + + true + + false + + + true + + + + 1 + + @@ -428,6 +442,29 @@ + + m_txtProxyPassword + m_checkShowPassword + m_tabBrowserProxy + m_checkOpenLinksInExternal + m_grpCustomExternalBrowser + m_txtExternalBrowserExecutable + m_btnExternalBrowserExecutable + m_txtExternalBrowserArguments + m_cmbExternalBrowserPreset + m_grpCustomExternalEmail + m_txtExternalEmailExecutable + m_btnExternalEmailExecutable + m_txtExternalEmailArguments + m_cmbExternalEmailPreset + m_listTools + m_btnAddTool + m_btnDeleteTool + m_cmbProxyType + m_txtProxyHost + m_spinProxyPort + m_txtProxyUsername + diff --git a/src/gui/toolbareditor.cpp b/src/gui/toolbareditor.cpp index 801cf7753..53d032ca2 100755 --- a/src/gui/toolbareditor.cpp +++ b/src/gui/toolbareditor.cpp @@ -26,6 +26,7 @@ ToolBarEditor::ToolBarEditor(QWidget* parent) : QWidget(parent), m_ui(new Ui::ToolBarEditor) { m_ui->setupUi(this); + // Create connections. connect(m_ui->m_btnInsertSeparator, &QToolButton::clicked, this, &ToolBarEditor::insertSeparator); connect(m_ui->m_btnInsertSpacer, &QToolButton::clicked, this, &ToolBarEditor::insertSpacer); @@ -56,6 +57,7 @@ ToolBarEditor::~ToolBarEditor() { void ToolBarEditor::loadFromToolBar(BaseBar* tool_bar) { m_toolBar = tool_bar; + QList activated_actions = m_toolBar->changeableActions(); QList available_actions = m_toolBar->availableActions(); loadEditor(activated_actions, available_actions); diff --git a/src/miscellaneous/externaltool.cpp b/src/miscellaneous/externaltool.cpp new file mode 100644 index 000000000..0a60e67ad --- /dev/null +++ b/src/miscellaneous/externaltool.cpp @@ -0,0 +1,91 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2017 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#include "miscellaneous/externaltool.h" + +#include "definitions/definitions.h" +#include "miscellaneous/application.h" +#include "exceptions/applicationexception.h" + +#include +#include + + +void ExternalTool::sanitizeParameters() { + m_executable = QDir::toNativeSeparators(m_executable); + m_parameters.removeDuplicates(); + m_parameters.removeAll(QString()); +} + +ExternalTool::ExternalTool() { +} + +ExternalTool::ExternalTool(const ExternalTool& other) : ExternalTool(other.executable(), other.parameters()) { +} + +ExternalTool::ExternalTool(const QString& executable, const QStringList& parameters) + : m_executable(executable), m_parameters(parameters) { + sanitizeParameters(); +} + +QString ExternalTool::toString() { + sanitizeParameters(); + return m_executable + EXTERNAL_TOOL_SEPARATOR + m_parameters.join(EXTERNAL_TOOL_PARAM_SEPARATOR); +} + +QString ExternalTool::executable() const { + return m_executable; +} + +QStringList ExternalTool::parameters() const { + return m_parameters; +} + +ExternalTool ExternalTool::fromString(const QString& str) { + QStringList outer = str.split(EXTERNAL_TOOL_SEPARATOR); + + if (outer.size() != 2) { + throw ApplicationException(QObject::tr("Passed external tool representation is not valid.")); + } + else { + const QString executable = outer.at(0); + const QStringList parameters = outer.at(1).split(EXTERNAL_TOOL_PARAM_SEPARATOR); + + return ExternalTool(executable, parameters); + } +} + +QList ExternalTool::toolsFromSettings() { + QStringList tools_encoded = qApp->settings()->value(GROUP(Browser), SETTING(Browser::ExternalTools)).toStringList(); + QList tools; + + foreach (const QString& tool_encoded, tools_encoded) { + tools.append(ExternalTool::fromString(tool_encoded)); + } + + return tools; +} + +void ExternalTool::setToolsToSettings(QList& tools) { + QStringList encode; + + foreach (ExternalTool tool, tools) { + encode.append(tool.toString()); + } + + qApp->settings()->setValue(GROUP(Browser), Browser::ExternalTools, encode); +} diff --git a/src/miscellaneous/externaltool.h b/src/miscellaneous/externaltool.h new file mode 100644 index 000000000..de445894f --- /dev/null +++ b/src/miscellaneous/externaltool.h @@ -0,0 +1,47 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2017 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#ifndef EXTERNALTOOL_H +#define EXTERNALTOOL_H + +#include +#include + + +class ExternalTool { + public: + explicit ExternalTool(); + ExternalTool(const ExternalTool& other); + explicit ExternalTool(const QString& executable, const QStringList& parameters); + + QString toString(); + QString executable() const; + QStringList parameters() const; + + static ExternalTool fromString(const QString& str); + static QList toolsFromSettings(); + static void setToolsToSettings(QList& tools); + + private: + QString m_executable; + QStringList m_parameters; + void sanitizeParameters(); +}; + +Q_DECLARE_METATYPE(ExternalTool) + +#endif // EXTERNALTOOL_H