This commit is contained in:
Martin Rotter 2017-09-10 12:01:10 +02:00
parent cbf2fbec8d
commit 631f225110
12 changed files with 194 additions and 23 deletions

View File

@ -44,7 +44,7 @@ on_success:
- for /f "tokens=*" %%F in ('dir /b *.exe') do curl --upload-file %%F https://transfer.sh/%%F --silent >> ..\rssguard-wiki\Windows-development-builds.md
- echo.>> ..\rssguard-wiki\Windows-development-builds.md
- cd ..\rssguard-wiki
- git pull origin master
- git add *.*
- git commit -m "New files."
- git pull origin master
- git push origin master

View File

@ -29,7 +29,7 @@ echo "\n" >> ./build-wiki/Mac-OS-X-development-builds.md
cat ./build-wiki/Mac-OS-X-development-builds.md
cd ./build-wiki
git pull origin master
git add *.*
git commit -m "New files."
git pull origin master
git push origin master

View File

@ -2,6 +2,7 @@
—————
Added:
▪ Added support for arbitrary external tools (settings category "Web browser & e-mail & proxy") which can open URLs of selected messages. (#136)
▪ Standard account is now automatically added if RSS Guard is started with empty database.
▪ Menu action "Select next unread message" in "Messages" menu now works across all feeds, so user can navigate through all unread messages with a sigle keyboard shortcut. (#132, #6)
▪ Added two bindable menu actions (in menu "Web browser & tabs") which allow to cycle among tabs. (#6)

View File

@ -27,7 +27,6 @@
#include "gui/guiutilities.h"
#include <QNetworkReply>
#include <QProcess>
#if defined(Q_OS_WIN)
#include <windows.h>

View File

@ -32,6 +32,8 @@
#include <QScrollBar>
#include <QTimer>
#include <QMenu>
#include <QFileIconProvider>
#include <QProcess>
MessagesView::MessagesView(QWidget* parent)
@ -180,6 +182,28 @@ void MessagesView::initializeContextMenu() {
}
m_contextMenu->clear();
QFileIconProvider icon_provider;
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);
act_tool->setIcon(icon_provider.icon(tool));
act_tool->setToolTip(tool);
menu->addAction(act_tool);
connect(act_tool, &QAction::triggered, this, &MessagesView::openSelectedMessagesWithExternalTool);
}
if (menu->actions().isEmpty()) {
QAction* act_not_tools = new QAction("No external tools activated");
act_not_tools->setEnabled(false);
menu->addAction(act_not_tools);
}
m_contextMenu->addMenu(menu);
m_contextMenu->addActions(QList<QAction*>() <<
qApp->mainForm()->m_ui->m_actionSendMessageViaEmail <<
qApp->mainForm()->m_ui->m_actionOpenSelectedSourceArticlesExternally <<
@ -479,7 +503,26 @@ void MessagesView::searchMessages(const QString& pattern) {
}
void MessagesView::filterMessages(MessagesModel::MessageHighlighter filter) {
m_sourceModel->highlightMessages(filter);
m_sourceModel->highlightMessages(filter);
}
void MessagesView::openSelectedMessagesWithExternalTool() {
QAction* sndr = qobject_cast<QAction*>(sender());
if (sndr != nullptr) {
const QString& tool = sndr->toolTip();
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)) {
qApp->showGuiMessage(tr("Cannot run external tool"), tr("External tool '%1' could not be started."),
QSystemTrayIcon::Critical);
}
}
}
}
}
void MessagesView::adjustColumns() {

View File

@ -77,6 +77,8 @@ class MessagesView : public QTreeView {
void filterMessages(MessagesModel::MessageHighlighter filter);
private slots:
void openSelectedMessagesWithExternalTool();
// Marks given indexes as selected.
void reselectIndexes(const QModelIndexList& indexes);

View File

@ -29,14 +29,18 @@
SettingsBrowserMail::SettingsBrowserMail(Settings* settings, QWidget* parent)
: SettingsPanel(settings, parent), m_ui(new Ui::SettingsBrowserMail) {
m_ui->setupUi(this);
GuiUtilities::setLabelAsNotice(*m_ui->label, false);
GuiUtilities::setLabelAsNotice(*m_ui->m_lblExternalEmailInfo, false);
GuiUtilities::setLabelAsNotice(*m_ui->m_lblProxyInfo, false);
GuiUtilities::setLabelAsNotice(*m_ui->m_lblToolInfo, false);
#if defined(USE_WEBENGINE)
m_ui->m_checkOpenLinksInExternal->setVisible(false);
#else
connect(m_ui->m_checkOpenLinksInExternal, &QCheckBox::stateChanged, this, &SettingsBrowserMail::dirtifySettings);
#endif
connect(m_ui->m_cmbProxyType, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
&SettingsBrowserMail::dirtifySettings);
connect(m_ui->m_txtProxyHost, &QLineEdit::textChanged, this, &SettingsBrowserMail::dirtifySettings);
@ -58,6 +62,13 @@ SettingsBrowserMail::SettingsBrowserMail(Settings* settings, QWidget* parent)
connect(m_ui->m_cmbExternalEmailPreset, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
&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_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());
});
}
SettingsBrowserMail::~SettingsBrowserMail() {
@ -107,7 +118,23 @@ void SettingsBrowserMail::onProxyTypeChanged(int index) {
m_ui->m_lblProxyInfo->setEnabled(is_proxy_selected);
m_ui->m_lblProxyPassword->setEnabled(is_proxy_selected);
m_ui->m_lblProxyPort->setEnabled(is_proxy_selected);
m_ui->m_lblProxyUsername->setEnabled(is_proxy_selected);
m_ui->m_lblProxyUsername->setEnabled(is_proxy_selected);
}
QStringList SettingsBrowserMail::externalTools() const {
QStringList list;
for (int i = 0; i < m_ui->m_listTools->count(); i++) {
list.append(m_ui->m_listTools->item(i)->text());
}
return list;
}
void SettingsBrowserMail::setExternalTools(const QStringList& list) {
foreach (const QString& tool, list) {
m_ui->m_listTools->addItem(tool);
}
}
void SettingsBrowserMail::changeDefaultEmailArguments(int index) {
@ -134,18 +161,21 @@ void SettingsBrowserMail::selectEmailExecutable() {
void SettingsBrowserMail::loadSettings() {
onBeginLoadSettings();
#if !defined(USE_WEBENGINE)
m_ui->m_checkOpenLinksInExternal->setChecked(settings()->value(GROUP(Browser),
SETTING(Browser::OpenLinksInExternalBrowserRightAway)).toBool());
#endif
// Load settings of web browser GUI.
// Load settings of web browser GUI.
m_ui->m_cmbExternalBrowserPreset->addItem(tr("Opera 12 or older"), QSL("-nosession %1"));
m_ui->m_txtExternalBrowserExecutable->setText(settings()->value(GROUP(Browser),
SETTING(Browser::CustomExternalBrowserExecutable)).toString());
m_ui->m_txtExternalBrowserArguments->setText(settings()->value(GROUP(Browser),
SETTING(Browser::CustomExternalBrowserArguments)).toString());
m_ui->m_grpCustomExternalBrowser->setChecked(settings()->value(GROUP(Browser), SETTING(Browser::CustomExternalBrowserEnabled)).toBool());
// Load settings of e-mail.
// Load settings of e-mail.
m_ui->m_cmbExternalEmailPreset->addItem(tr("Mozilla Thunderbird"), QSL("-compose \"subject='%1',body='%2'\""));
m_ui->m_txtExternalEmailExecutable->setText(settings()->value(GROUP(Browser), SETTING(Browser::CustomExternalEmailExecutable)).toString());
m_ui->m_txtExternalEmailArguments->setText(settings()->value(GROUP(Browser), SETTING(Browser::CustomExternalEmailArguments)).toString());
@ -154,7 +184,8 @@ void SettingsBrowserMail::loadSettings() {
m_ui->m_cmbProxyType->addItem(tr("System proxy"), QNetworkProxy::DefaultProxy);
m_ui->m_cmbProxyType->addItem(tr("Socks5"), QNetworkProxy::Socks5Proxy);
m_ui->m_cmbProxyType->addItem(tr("Http"), QNetworkProxy::HttpProxy);
// Load the settings.
// Load the settings.
QNetworkProxy::ProxyType selected_proxy_type = static_cast<QNetworkProxy::ProxyType>(settings()->value(GROUP(Proxy),
SETTING(Proxy::Type)).toInt());
m_ui->m_cmbProxyType->setCurrentIndex(m_ui->m_cmbProxyType->findData(selected_proxy_type));
@ -162,19 +193,24 @@ void SettingsBrowserMail::loadSettings() {
m_ui->m_txtProxyUsername->setText(settings()->value(GROUP(Proxy), SETTING(Proxy::Username)).toString());
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());
onEndLoadSettings();
}
void SettingsBrowserMail::saveSettings() {
onBeginSaveSettings();
#if !defined(USE_WEBENGINE)
settings()->setValue(GROUP(Browser), Browser::OpenLinksInExternalBrowserRightAway, m_ui->m_checkOpenLinksInExternal->isChecked());
#endif
// Save settings of GUI of web browser.
// Save settings of GUI of web browser.
settings()->setValue(GROUP(Browser), Browser::CustomExternalBrowserEnabled, m_ui->m_grpCustomExternalBrowser->isChecked());
settings()->setValue(GROUP(Browser), Browser::CustomExternalBrowserExecutable, m_ui->m_txtExternalBrowserExecutable->text());
settings()->setValue(GROUP(Browser), Browser::CustomExternalBrowserArguments, m_ui->m_txtExternalBrowserArguments->text());
// Save settings of e-mail.
// Save settings of e-mail.
settings()->setValue(GROUP(Browser), Browser::CustomExternalEmailExecutable, m_ui->m_txtExternalEmailExecutable->text());
settings()->setValue(GROUP(Browser), Browser::CustomExternalEmailArguments, m_ui->m_txtExternalEmailArguments->text());
settings()->setValue(GROUP(Browser), Browser::CustomExternalEmailEnabled, m_ui->m_grpCustomExternalEmail->isChecked());
@ -183,7 +219,32 @@ void SettingsBrowserMail::saveSettings() {
settings()->setValue(GROUP(Proxy), Proxy::Username, m_ui->m_txtProxyUsername->text());
settings()->setValue(GROUP(Proxy), Proxy::Password, TextFactory::encrypt(m_ui->m_txtProxyPassword->text()));
settings()->setValue(GROUP(Proxy), Proxy::Port, m_ui->m_spinProxyPort->value());
// Reload settings for all network access managers.
settings()->setValue(GROUP(Browser), Browser::ExternalTools, externalTools());
// Reload settings for all network access managers.
SilentNetworkAccessManager::instance()->loadSettings();
onEndSaveSettings();
onEndSaveSettings();
}
void SettingsBrowserMail::addExternalTool() {
QString executable_file = QFileDialog::getOpenFileName(this,
tr("Select external tool"),
qApp->homeFolder(),
//: File filter for external tool selection dialog.
#if defined(Q_OS_LINUX)
tr("Executables (*)"));
#else
tr("Executables (*.*)"));
#endif
if (!executable_file.isEmpty()) {
m_ui->m_listTools->addItem(QDir::toNativeSeparators(executable_file));
}
}
void SettingsBrowserMail::deleteSelectedExternalTool() {
if (m_ui->m_listTools->currentRow() >= 0) {
m_ui->m_listTools->takeItem(m_ui->m_listTools->currentRow());
}
}

View File

@ -38,6 +38,8 @@ class SettingsBrowserMail : public SettingsPanel {
void saveSettings();
private slots:
void addExternalTool();
void deleteSelectedExternalTool();
void changeDefaultBrowserArguments(int index);
void selectBrowserExecutable();
void changeDefaultEmailArguments(int index);
@ -46,6 +48,9 @@ class SettingsBrowserMail : public SettingsPanel {
void onProxyTypeChanged(int index);
private:
QStringList externalTools() const;
void setExternalTools(const QStringList& list);
Ui::SettingsBrowserMail* m_ui;
};

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>658</width>
<height>200</height>
<height>330</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
@ -229,6 +229,53 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>External tools</string>
</attribute>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="m_lblToolInfo">
<property name="text">
<string>On this page, you can setup a list of external tools which can open URLs of selected messages.</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QPushButton" name="m_btnAddTool">
<property name="text">
<string>Add external tool</string>
</property>
</widget>
<widget class="QPushButton" name="m_btnDeleteTool">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Delete selected external tool</string>
</property>
</widget>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QListWidget" name="m_listTools">
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="uniformItemSizes">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="m_tabProxy">
<attribute name="title">
<string>Proxy</string>

View File

@ -286,6 +286,8 @@ DVALUE(QString) Browser::CustomExternalEmailExecutableDef = QString();
DKEY Browser::CustomExternalEmailArguments = "external_email_arguments";
DVALUE(char*) Browser::CustomExternalEmailArgumentsDef = "";
DKEY Browser::ExternalTools = "external_tools";
DVALUE(QStringList) Browser::ExternalToolsDef = QStringList();
// Categories.
DKEY CategoriesExpandStates::ID = "categories_expand_states";

View File

@ -316,6 +316,9 @@ namespace Browser {
KEY CustomExternalEmailExecutable;
VALUE(QString) CustomExternalEmailExecutableDef;
KEY ExternalTools;
VALUE(QStringList) ExternalToolsDef;
KEY CustomExternalEmailArguments;
VALUE(char*) CustomExternalEmailArgumentsDef;
}

View File

@ -35,7 +35,6 @@
#include <QMetaObject>
#include <QMimeData>
#include <QMetaEnum>
#include <QProcess>
#include <QSettings>
#include <QDebug>
@ -47,7 +46,8 @@ DownloadItem::DownloadItem(QNetworkReply* reply, QWidget* parent) : QWidget(pare
m_ui->setupUi(this);
m_ui->m_btnTryAgain->hide();
m_requestFileName = qApp->settings()->value(GROUP(Downloads), SETTING(Downloads::AlwaysPromptForFilename)).toBool();
connect(m_ui->m_btnStopDownload, &QToolButton::clicked, this, &DownloadItem::stop);
connect(m_ui->m_btnStopDownload, &QToolButton::clicked, this, &DownloadItem::stop);
connect(m_ui->m_btnOpenFile, &QToolButton::clicked, this, &DownloadItem::openFile);
connect(m_ui->m_btnTryAgain, &QToolButton::clicked, this, &DownloadItem::tryAgain);
connect(m_ui->m_btnOpenFolder, &QToolButton::clicked, this, &DownloadItem::openFolder);
@ -69,16 +69,19 @@ void DownloadItem::init() {
m_ui->m_btnOpenFolder->setEnabled(false);
m_url = m_reply->url();
m_reply->setParent(this);
connect(m_reply, &QNetworkReply::readyRead, this, &DownloadItem::downloadReadyRead);
connect(m_reply, &QNetworkReply::readyRead, this, &DownloadItem::downloadReadyRead);
connect(m_reply, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error), this, &DownloadItem::error);
connect(m_reply, &QNetworkReply::downloadProgress, this, &DownloadItem::downloadProgress);
connect(m_reply, &QNetworkReply::metaDataChanged, this, &DownloadItem::metaDataChanged);
connect(m_reply, &QNetworkReply::finished, this, &DownloadItem::finished);
// Reset info.
// Reset info.
m_ui->m_lblInfoDownload->clear();
m_ui->m_progressDownload->setValue(0);
getFileName();
// Start timer for the download estimation.
// Start timer for the download estimation.
m_downloadTime.start();
if (m_reply->error() != QNetworkReply::NoError) {
@ -119,7 +122,8 @@ void DownloadItem::getFileName() {
}
m_output.setFileName(chosen_filename);
// Check file path for saving.
// Check file path for saving.
const QDir save_dir = QFileInfo(m_output.fileName()).dir();
if (!save_dir.exists() && !save_dir.mkpath(save_dir.absolutePath())) {
@ -275,7 +279,8 @@ void DownloadItem::downloadReadyRead() {
void DownloadItem::error(QNetworkReply::NetworkError code) {
Q_UNUSED(code)
m_ui->m_lblInfoDownload->setText(tr("Error: %1").arg(m_reply->errorString()));
m_ui->m_lblInfoDownload->setText(tr("Error: %1").arg(m_reply->errorString()));
m_ui->m_btnTryAgain->setEnabled(true);
m_ui->m_btnTryAgain->setVisible(true);
emit downloadFinished();
@ -511,7 +516,8 @@ void DownloadManager::addItem(DownloadItem* item) {
connect(item, &DownloadItem::statusChanged, this, static_cast<void (DownloadManager::*)()>(&DownloadManager::updateRow));
connect(item, &DownloadItem::progress, this, &DownloadManager::itemProgress);
connect(item, &DownloadItem::downloadFinished, this, &DownloadManager::itemFinished);
const int row = m_downloads.count();
const int row = m_downloads.count();
m_model->beginInsertRows(QModelIndex(), row, row);
m_downloads.append(item);
m_model->endInsertRows();
@ -519,7 +525,8 @@ void DownloadManager::addItem(DownloadItem* item) {
QIcon icon = style()->standardIcon(QStyle::SP_FileIcon);
item->m_ui->m_lblFileIcon->setPixmap(icon.pixmap(DOWNLOADER_ICON_SIZE, DOWNLOADER_ICON_SIZE));
m_ui->m_viewDownloads->setRowHeight(row, item->sizeHint().height());
// Just in case of download finishes before it is actually added.
// Just in case of download finishes before it is actually added.
updateRow(item);
}
@ -572,7 +579,8 @@ void DownloadManager::updateRow(DownloadItem* item) {
item->m_ui->m_lblFileIcon->setPixmap(icon.pixmap(DOWNLOADER_ICON_SIZE, DOWNLOADER_ICON_SIZE));
int old_height = m_ui->m_viewDownloads->rowHeight(row);
m_ui->m_viewDownloads->setRowHeight(row, qMax(old_height, item->minimumSizeHint().height()));
// Remove the item if:
// Remove the item if:
// a) It is not downloading and private browsing is enabled.
// OR
// b) Item is already downloaded and it should be remove from downloader list.