Reworked external tools, now in internal web browser too, can be used with media in web browser

This commit is contained in:
Martin Rotter 2021-03-15 11:14:17 +01:00
parent 9f929fb787
commit 7c42177d21
15 changed files with 164 additions and 63 deletions

View File

@ -30,7 +30,7 @@
<url type="donation">https://martinrotter.github.io/donate/</url>
<content_rating type="oars-1.1" />
<releases>
<release version="3.9.0" date="2021-03-12"/>
<release version="3.9.0" date="2021-03-15"/>
</releases>
<content_rating type="oars-1.0">
<content_attribute id="violence-cartoon">none</content_attribute>

@ -1 +1 @@
Subproject commit 9c10723bfbaf6cb85107d6ee16e0324e9e487749
Subproject commit 47f4125753452eff8800dbd6600c5a05540b15d9

View File

@ -82,8 +82,8 @@
#define GOOGLE_SEARCH_URL "https://www.google.com/search?q=%1&ie=utf-8&oe=utf-8"
#define GOOGLE_SUGGEST_URL "http://suggestqueries.google.com/complete/search?output=toolbar&hl=en&q=%1"
#define EXTERNAL_TOOL_SEPARATOR "###"
#define EXTERNAL_TOOL_PARAM_SEPARATOR "|||"
#define EXECUTION_LINE_SEPARATOR "#"
#define EXTERNAL_TOOL_SEPARATOR "|||"
#define USER_DATA_PLACEHOLDER "%data%"
#define CLI_LOG_SHORT "l"

View File

@ -100,6 +100,8 @@ MessageBrowser::MessageBrowser(bool should_resize_to_fit, QWidget* parent)
m_searchWidget->hide();
installEventFilter(this);
reloadFontSettings();
}
void MessageBrowser::clear() {

View File

@ -71,7 +71,7 @@ MessagePreviewer::MessagePreviewer(bool should_resize_to_fit, QWidget* parent)
createConnections();
m_actionSwitchImportance->setCheckable(true);
reloadFontSettings();
//reloadFontSettings();
clear();
}

View File

@ -224,7 +224,7 @@ void MessagesView::initializeContextMenu() {
}
if (menu_ext_tools->actions().isEmpty()) {
QAction* act_not_tools = new QAction("No external tools activated");
QAction* act_not_tools = new QAction(tr("No external tools activated"));
act_not_tools->setEnabled(false);
menu_ext_tools->addAction(act_not_tools);
@ -598,10 +598,10 @@ void MessagesView::openSelectedMessagesWithExternalTool() {
.replace(QRegularExpression("[\\t\\n]"), QString());
if (!link.isEmpty()) {
if (!QProcess::startDetached(tool.executable(), QStringList() << tool.parameters() << link)) {
if (!tool.run(link)) {
qApp->showGuiMessage(tr("Cannot run external tool"),
tr("External tool '%1' could not be started.").arg(tool.executable()),
QSystemTrayIcon::Critical);
QSystemTrayIcon::MessageIcon::Critical);
}
}
}

View File

@ -2,10 +2,12 @@
#include "gui/settings/settingsbrowsermail.h"
#include "exceptions/applicationexception.h"
#include "gui/guiutilities.h"
#include "gui/networkproxydetails.h"
#include "miscellaneous/application.h"
#include "miscellaneous/externaltool.h"
#include "miscellaneous/iconfactory.h"
#include "network-web/silentnetworkaccessmanager.h"
#include "network-web/webfactory.h"
@ -23,6 +25,10 @@ SettingsBrowserMail::SettingsBrowserMail(Settings* settings, QWidget* parent)
GuiUtilities::setLabelAsNotice(*m_ui->m_lblExternalEmailInfo, false);
GuiUtilities::setLabelAsNotice(*m_ui->m_lblToolInfo, false);
m_ui->m_btnAddTool->setIcon(qApp->icons()->fromTheme(QSL("list-add")));
m_ui->m_btnEditTool->setIcon(qApp->icons()->fromTheme(QSL("document-edit")));
m_ui->m_btnDeleteTool->setIcon(qApp->icons()->fromTheme(QSL("list-remove")));
#if defined(USE_WEBENGINE)
m_ui->m_checkOpenLinksInExternal->setVisible(false);
#else
@ -46,13 +52,17 @@ SettingsBrowserMail::SettingsBrowserMail(Settings* settings, QWidget* parent)
&SettingsBrowserMail::changeDefaultEmailArguments);
connect(m_ui->m_btnExternalEmailExecutable, &QPushButton::clicked, this, &SettingsBrowserMail::selectEmailExecutable);
connect(m_ui->m_btnAddTool, &QPushButton::clicked, this, &SettingsBrowserMail::dirtifySettings);
connect(m_ui->m_btnEditTool, &QPushButton::clicked, this, &SettingsBrowserMail::dirtifySettings);
connect(m_ui->m_btnDeleteTool, &QPushButton::clicked, this, &SettingsBrowserMail::dirtifySettings);
connect(m_ui->m_btnAddTool, &QPushButton::clicked, this, &SettingsBrowserMail::addExternalTool);
connect(m_ui->m_btnEditTool, &QPushButton::clicked, this, &SettingsBrowserMail::editSelectedExternalTool);
connect(m_ui->m_btnDeleteTool, &QPushButton::clicked, this, &SettingsBrowserMail::deleteSelectedExternalTool);
connect(m_ui->m_listTools, &QTreeWidget::itemDoubleClicked, this, &SettingsBrowserMail::editSelectedExternalTool);
connect(m_ui->m_listTools, &QTreeWidget::currentItemChanged, this, [this](QTreeWidgetItem* current, QTreeWidgetItem* previous) {
Q_UNUSED(previous)
m_ui->m_btnDeleteTool->setEnabled(current != nullptr);
m_ui->m_btnEditTool->setEnabled(current != nullptr);
});
}
@ -87,7 +97,7 @@ QList<ExternalTool> SettingsBrowserMail::externalTools() const {
QList<ExternalTool> list;
for (int i = 0; i < m_ui->m_listTools->topLevelItemCount(); i++) {
list.append(m_ui->m_listTools->topLevelItem(i)->data(0, Qt::UserRole).value<ExternalTool>());
list.append(m_ui->m_listTools->topLevelItem(i)->data(0, Qt::ItemDataRole::UserRole).value<ExternalTool>());
}
return list;
@ -96,9 +106,9 @@ QList<ExternalTool> SettingsBrowserMail::externalTools() const {
void SettingsBrowserMail::setExternalTools(const QList<ExternalTool>& list) {
for (const ExternalTool& tool : list) {
QTreeWidgetItem* item = new QTreeWidgetItem(m_ui->m_listTools,
QStringList() << tool.executable() << tool.parameters().join(QL1C(' ')));
QStringList() << tool.executable() << tool.parameters());
item->setData(0, Qt::UserRole, QVariant::fromValue(tool));
item->setData(0, Qt::ItemDataRole::UserRole, QVariant::fromValue(tool));
m_ui->m_listTools->addTopLevelItem(item);
}
@ -202,36 +212,66 @@ void SettingsBrowserMail::saveSettings() {
}
void SettingsBrowserMail::addExternalTool() {
QString executable_file = QFileDialog::getOpenFileName(this,
tr("Select external tool"),
qApp->homeFolder(),
try {
auto tool = tweakExternalTool(ExternalTool(qApp->homeFolder(), {}));
QTreeWidgetItem* item = new QTreeWidgetItem(m_ui->m_listTools,
QStringList() << QDir::toNativeSeparators(tool.executable())
<< tool.parameters());
//: File filter for external tool selection dialog.
#if defined(Q_OS_LINUX)
tr("Executables (*)"));
#else
item->setData(0, Qt::ItemDataRole::UserRole, QVariant::fromValue(tool));
m_ui->m_listTools->addTopLevelItem(item);
}
catch (const ApplicationException& ex) {
// NOTE: Tool adding cancelled.
}
}
ExternalTool SettingsBrowserMail::tweakExternalTool(const ExternalTool& tool) const {
QString executable_file = QFileDialog::getOpenFileName(window(),
tr("Select external tool"),
tool.executable(),
#if defined(Q_OS_WIN)
tr("Executables (*.*)"));
#else
tr("Executables (*)"));
#endif
if (!executable_file.isEmpty()) {
executable_file = QDir::toNativeSeparators(executable_file);
bool ok;
QString parameters = QInputDialog::getText(this,
QString parameters = QInputDialog::getText(window(),
tr("Enter parameters"),
tr(
"Enter (optional) parameters separated by single space to send to executable when opening URLs."),
tr("Enter (optional) parameters separated by \"%1\":").arg(EXECUTION_LINE_SEPARATOR),
QLineEdit::EchoMode::Normal,
QString(),
tool.parameters(),
&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);
return ExternalTool(executable_file, parameters);
}
}
throw ApplicationException();
}
void SettingsBrowserMail::editSelectedExternalTool() {
auto* cur_it = m_ui->m_listTools->currentItem();
if (cur_it == nullptr) {
return;
}
auto ext_tool = cur_it->data(0, Qt::ItemDataRole::UserRole).value<ExternalTool>();
try {
ext_tool = tweakExternalTool(ext_tool);
m_ui->m_listTools->currentItem()->setText(0, ext_tool.executable());
m_ui->m_listTools->currentItem()->setText(1, ext_tool.parameters());
m_ui->m_listTools->currentItem()->setData(0, Qt::ItemDataRole::UserRole, QVariant::fromValue(ext_tool));
}
catch (const ApplicationException& ex) {
// NOTE: Tool adding cancelled.
}
}
void SettingsBrowserMail::deleteSelectedExternalTool() {

View File

@ -24,12 +24,16 @@ class SettingsBrowserMail : public SettingsPanel {
private slots:
void addExternalTool();
void editSelectedExternalTool();
void deleteSelectedExternalTool();
void changeDefaultBrowserArguments(int index);
void selectBrowserExecutable();
void changeDefaultEmailArguments(int index);
void selectEmailExecutable();
private:
ExternalTool tweakExternalTool(const ExternalTool& tool) const;
private:
QList<ExternalTool> externalTools() const;
void setExternalTools(const QList<ExternalTool>& list);

View File

@ -262,27 +262,6 @@
<string>External tools</string>
</attribute>
<layout class="QFormLayout" name="formLayout">
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="m_btnAddTool">
<property name="text">
<string>Add external tool</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="m_btnDeleteTool">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Delete selected external tool</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="m_lblToolInfo">
<property name="text">
@ -330,6 +309,37 @@
</property>
</spacer>
</item>
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="m_btnAddTool">
<property name="text">
<string>&amp;Add new external tool</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="m_btnEditTool">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Edit selected external tool</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="m_btnDeleteTool">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Delete selected external tool</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
@ -351,6 +361,7 @@
<tabstop>m_cmbExternalEmailPreset</tabstop>
<tabstop>m_listTools</tabstop>
<tabstop>m_btnAddTool</tabstop>
<tabstop>m_btnEditTool</tabstop>
<tabstop>m_btnDeleteTool</tabstop>
</tabstops>
<resources/>

View File

@ -2,13 +2,13 @@
#include "gui/webbrowser.h"
#include "database/databasequeries.h"
#include "gui/discoverfeedsbutton.h"
#include "gui/locationlineedit.h"
#include "gui/messagebox.h"
#include "gui/searchtextwidget.h"
#include "gui/webviewer.h"
#include "miscellaneous/application.h"
#include "database/databasequeries.h"
#include "miscellaneous/iconfactory.h"
#include "network-web/networkfactory.h"
#include "network-web/webfactory.h"
@ -118,9 +118,9 @@ void WebBrowser::reloadFontSettings() {
fon.fromString(qApp->settings()->value(GROUP(Messages),
SETTING(Messages::PreviewerFontStandard)).toString());
QWebEngineSettings::defaultSettings()->setFontFamily(QWebEngineSettings::StandardFont, fon.family());
QWebEngineSettings::defaultSettings()->setFontFamily(QWebEngineSettings::SerifFont, fon.family());
QWebEngineSettings::defaultSettings()->setFontFamily(QWebEngineSettings::SansSerifFont, fon.family());
QWebEngineSettings::defaultSettings()->setFontFamily(QWebEngineSettings::FontFamily::StandardFont, fon.family());
QWebEngineSettings::defaultSettings()->setFontFamily(QWebEngineSettings::FontFamily::SerifFont, fon.family());
QWebEngineSettings::defaultSettings()->setFontFamily(QWebEngineSettings::FontFamily::SansSerifFont, fon.family());
QWebEngineSettings::defaultSettings()->setFontSize(QWebEngineSettings::DefaultFontSize, fon.pointSize());
}

View File

@ -7,12 +7,14 @@
#include "gui/tabwidget.h"
#include "gui/webbrowser.h"
#include "miscellaneous/application.h"
#include "miscellaneous/externaltool.h"
#include "miscellaneous/skinfactory.h"
#include "network-web/adblock/adblockicon.h"
#include "network-web/adblock/adblockmanager.h"
#include "network-web/webfactory.h"
#include "network-web/webpage.h"
#include <QFileIconProvider>
#include <QOpenGLWidget>
#include <QTimer>
#include <QWebEngineContextMenuData>
@ -162,7 +164,7 @@ void WebViewer::contextMenuEvent(QContextMenuEvent* event) {
if (menu_data.linkUrl().isValid()) {
// Add option to open link in external viewe
menu->addAction(qApp->icons()->fromTheme(QSL("")), tr("Open link in external browser"), [menu_data]() {
menu->addAction(qApp->icons()->fromTheme(QSL("document-open")), tr("Open link in external browser"), [menu_data]() {
qApp->web()->openUrlInExternalBrowser(menu_data.linkUrl().toString());
if (qApp->settings()->value(GROUP(Messages), SETTING(Messages::BringAppToFrontAfterMessageOpenedExternally)).toBool()) {
@ -173,6 +175,35 @@ void WebViewer::contextMenuEvent(QContextMenuEvent* event) {
});
}
if (menu_data.mediaUrl().isValid() || menu_data.linkUrl().isValid()) {
QFileIconProvider icon_provider;
QMenu* menu_ext_tools = new QMenu(tr("Open with external tool"), menu);
menu_ext_tools->setIcon(qApp->icons()->fromTheme(QSL("document-open")));
for (const ExternalTool& tool : ExternalTool::toolsFromSettings()) {
QAction* act_tool = new QAction(QFileInfo(tool.executable()).fileName(), menu_ext_tools);
act_tool->setIcon(icon_provider.icon(tool.executable()));
act_tool->setToolTip(tool.executable());
act_tool->setData(QVariant::fromValue(tool));
menu_ext_tools->addAction(act_tool);
connect(act_tool, &QAction::triggered, this, [this, act_tool, menu_data]() {
openUrlWithExternalTool(act_tool->data().value<ExternalTool>(), menu_data);
});
}
if (menu_ext_tools->actions().isEmpty()) {
QAction* act_not_tools = new QAction("No external tools activated");
act_not_tools->setEnabled(false);
menu_ext_tools->addAction(act_not_tools);
}
menu->addMenu(menu_ext_tools);
}
menu->addAction(qApp->web()->adBlock()->adBlockIcon());
menu->addAction(qApp->web()->engineSettingsAction());
@ -233,6 +264,10 @@ bool WebViewer::eventFilter(QObject* object, QEvent* event) {
return false;
}
void WebViewer::openUrlWithExternalTool(ExternalTool tool, const QWebEngineContextMenuData& target) {
tool.run(target.mediaUrl().isValid() ? target.mediaUrl().toString() : target.linkUrl().toString());
}
RootItem* WebViewer::root() const {
return m_root;
}

View File

@ -6,6 +6,7 @@
#include <QWebEngineView>
#include "core/message.h"
#include "miscellaneous/externaltool.h"
#include "network-web/webpage.h"
class RootItem;
@ -39,6 +40,9 @@ class WebViewer : public QWebEngineView {
virtual bool event(QEvent* event);
virtual bool eventFilter(QObject* object, QEvent* event);
private slots:
void openUrlWithExternalTool(ExternalTool tool, const QWebEngineContextMenuData& target);
private:
RootItem* m_root;
QString m_messageContents;

View File

@ -12,27 +12,25 @@
void ExternalTool::sanitizeParameters() {
m_executable = QDir::toNativeSeparators(m_executable);
m_parameters.removeDuplicates();
m_parameters.removeAll(QString());
}
ExternalTool::ExternalTool(const ExternalTool& other) : ExternalTool(other.executable(), other.parameters()) {}
ExternalTool::ExternalTool(QString executable, QStringList parameters)
ExternalTool::ExternalTool(QString executable, QString parameters)
: m_executable(std::move(executable)), m_parameters(std::move(parameters)) {
sanitizeParameters();
}
QString ExternalTool::toString() {
sanitizeParameters();
return m_executable + EXTERNAL_TOOL_SEPARATOR + m_parameters.join(EXTERNAL_TOOL_PARAM_SEPARATOR);
return m_executable + EXTERNAL_TOOL_SEPARATOR + m_parameters;
}
QString ExternalTool::executable() const {
return m_executable;
}
QStringList ExternalTool::parameters() const {
QString ExternalTool::parameters() const {
return m_parameters;
}
@ -44,7 +42,7 @@ ExternalTool ExternalTool::fromString(const QString& str) {
}
else {
const QString& executable = outer.at(0);
const QStringList parameters = outer.at(1).split(EXTERNAL_TOOL_PARAM_SEPARATOR);
const QString& parameters = outer.at(1);
return ExternalTool(executable, parameters);
}
@ -70,3 +68,7 @@ void ExternalTool::setToolsToSettings(QList<ExternalTool>& tools) {
qApp->settings()->setValue(GROUP(Browser), Browser::ExternalTools, encode);
}
bool ExternalTool::run(const QString& target) {
return IOFactory::startProcessDetached(executable(), QStringList() << parameters() << target);
}

View File

@ -10,19 +10,22 @@ class ExternalTool {
public:
explicit ExternalTool() = default;
ExternalTool(const ExternalTool& other);
explicit ExternalTool(QString executable, QStringList parameters);
explicit ExternalTool(QString executable, QString parameters);
QString toString();
QString executable() const;
QStringList parameters() const;
QString parameters() const;
bool run(const QString& target);
public:
static ExternalTool fromString(const QString& str);
static QList<ExternalTool> toolsFromSettings();
static void setToolsToSettings(QList<ExternalTool>& tools);
private:
QString m_executable;
QStringList m_parameters;
QString m_parameters;
void sanitizeParameters();
};

View File

@ -508,7 +508,7 @@ void StandardFeed::setEncoding(const QString& encoding) {
}
QStringList StandardFeed::prepareExecutionLine(const QString& execution_line) {
auto split_exec = execution_line.split('#',
auto split_exec = execution_line.split(EXECUTION_LINE_SEPARATOR,
#if QT_VERSION >= 0x050F00 // Qt >= 5.15.0
Qt::SplitBehaviorFlags::SkipEmptyParts);
#else