ability to open URL of article directly with keystroke

This commit is contained in:
Martin Rotter 2022-02-01 08:16:46 +01:00
parent efebb0199d
commit 4b984b4fc0
13 changed files with 106 additions and 54 deletions

View File

@ -26,7 +26,7 @@
<url type="donation">https://github.com/sponsors/martinrotter</url> <url type="donation">https://github.com/sponsors/martinrotter</url>
<content_rating type="oars-1.1" /> <content_rating type="oars-1.1" />
<releases> <releases>
<release version="4.1.2" date="2022-01-31"/> <release version="4.1.2" date="2022-02-01"/>
</releases> </releases>
<content_rating type="oars-1.0"> <content_rating type="oars-1.0">
<content_attribute id="violence-cartoon">none</content_attribute> <content_attribute id="violence-cartoon">none</content_attribute>

View File

@ -29,7 +29,7 @@ BEGIN
VALUE "LegalCopyright", "@APP_COPYRIGHT@" VALUE "LegalCopyright", "@APP_COPYRIGHT@"
VALUE "OriginalFilename", "@CMAKE_PROJECT_NAME@.exe" VALUE "OriginalFilename", "@CMAKE_PROJECT_NAME@.exe"
VALUE "ProductName", "@APP_NAME@" VALUE "ProductName", "@APP_NAME@"
VALUE "ProductVersion","@CMAKE_PROJECT_VERSION@" VALUE "ProductVersion","@CMAKE_PROJECT_VERSION@-@APP_REVISION@"
END END
END END

View File

@ -183,6 +183,7 @@ QList<QAction*> FormMain::allActions() const {
actions << m_ui->m_actionSendMessageViaEmail; actions << m_ui->m_actionSendMessageViaEmail;
actions << m_ui->m_actionOpenSelectedSourceArticlesExternally; actions << m_ui->m_actionOpenSelectedSourceArticlesExternally;
actions << m_ui->m_actionOpenSelectedMessagesInternally; actions << m_ui->m_actionOpenSelectedMessagesInternally;
actions << m_ui->m_actionOpenSelectedMessagesInternallyNoTab;
actions << m_ui->m_actionAlternateColorsInLists; actions << m_ui->m_actionAlternateColorsInLists;
actions << m_ui->m_actionMessagePreviewEnabled; actions << m_ui->m_actionMessagePreviewEnabled;
actions << m_ui->m_actionMarkAllItemsRead; actions << m_ui->m_actionMarkAllItemsRead;
@ -454,6 +455,7 @@ void FormMain::updateMessageButtonsAvailability() {
m_ui->m_actionRestoreSelectedMessages->setEnabled(atleast_one_message_selected && bin_loaded); m_ui->m_actionRestoreSelectedMessages->setEnabled(atleast_one_message_selected && bin_loaded);
m_ui->m_actionMarkSelectedMessagesAsRead->setEnabled(atleast_one_message_selected); m_ui->m_actionMarkSelectedMessagesAsRead->setEnabled(atleast_one_message_selected);
m_ui->m_actionMarkSelectedMessagesAsUnread->setEnabled(atleast_one_message_selected); m_ui->m_actionMarkSelectedMessagesAsUnread->setEnabled(atleast_one_message_selected);
m_ui->m_actionOpenSelectedMessagesInternallyNoTab->setEnabled(one_message_selected);
m_ui->m_actionOpenSelectedMessagesInternally->setEnabled(atleast_one_message_selected); m_ui->m_actionOpenSelectedMessagesInternally->setEnabled(atleast_one_message_selected);
m_ui->m_actionOpenSelectedSourceArticlesExternally->setEnabled(atleast_one_message_selected); m_ui->m_actionOpenSelectedSourceArticlesExternally->setEnabled(atleast_one_message_selected);
m_ui->m_actionCopyUrlSelectedArticles->setEnabled(atleast_one_message_selected); m_ui->m_actionCopyUrlSelectedArticles->setEnabled(atleast_one_message_selected);
@ -581,6 +583,7 @@ void FormMain::setupIcons() {
m_ui->m_actionSwitchImportanceOfSelectedMessages->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-important"))); m_ui->m_actionSwitchImportanceOfSelectedMessages->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-important")));
m_ui->m_actionOpenSelectedSourceArticlesExternally->setIcon(icon_theme_factory->fromTheme(QSL("document-open"))); m_ui->m_actionOpenSelectedSourceArticlesExternally->setIcon(icon_theme_factory->fromTheme(QSL("document-open")));
m_ui->m_actionOpenSelectedMessagesInternally->setIcon(icon_theme_factory->fromTheme(QSL("document-open"))); m_ui->m_actionOpenSelectedMessagesInternally->setIcon(icon_theme_factory->fromTheme(QSL("document-open")));
m_ui->m_actionOpenSelectedMessagesInternallyNoTab->setIcon(icon_theme_factory->fromTheme(QSL("document-open")));
m_ui->m_actionSendMessageViaEmail->setIcon(icon_theme_factory->fromTheme(QSL("mail-send"))); m_ui->m_actionSendMessageViaEmail->setIcon(icon_theme_factory->fromTheme(QSL("mail-send")));
m_ui->m_actionViewSelectedItemsNewspaperMode->setIcon(icon_theme_factory->fromTheme(QSL("format-justify-fill"))); m_ui->m_actionViewSelectedItemsNewspaperMode->setIcon(icon_theme_factory->fromTheme(QSL("format-justify-fill")));
m_ui->m_actionSelectNextItem->setIcon(icon_theme_factory->fromTheme(QSL("go-down"))); m_ui->m_actionSelectNextItem->setIcon(icon_theme_factory->fromTheme(QSL("go-down")));
@ -785,6 +788,10 @@ void FormMain::createConnections() {
&QAction::triggered, tabWidget()->feedMessageViewer()->messagesView(), &MessagesView::openSelectedSourceMessagesExternally); &QAction::triggered, tabWidget()->feedMessageViewer()->messagesView(), &MessagesView::openSelectedSourceMessagesExternally);
connect(m_ui->m_actionOpenSelectedMessagesInternally, connect(m_ui->m_actionOpenSelectedMessagesInternally,
&QAction::triggered, tabWidget()->feedMessageViewer()->messagesView(), &MessagesView::openSelectedMessagesInternally); &QAction::triggered, tabWidget()->feedMessageViewer()->messagesView(), &MessagesView::openSelectedMessagesInternally);
connect(m_ui->m_actionOpenSelectedMessagesInternallyNoTab,
&QAction::triggered, tabWidget()->feedMessageViewer()->messagesView(), &MessagesView::openSelectedMessageUrl);
connect(m_ui->m_actionSendMessageViaEmail, connect(m_ui->m_actionSendMessageViaEmail,
&QAction::triggered, tabWidget()->feedMessageViewer()->messagesView(), &MessagesView::sendSelectedMessageViaEmail); &QAction::triggered, tabWidget()->feedMessageViewer()->messagesView(), &MessagesView::sendSelectedMessageViaEmail);
connect(m_ui->m_actionMarkAllItemsRead, connect(m_ui->m_actionMarkAllItemsRead,

View File

@ -45,7 +45,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1296</width> <width>1296</width>
<height>23</height> <height>22</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="m_menuFile"> <widget class="QMenu" name="m_menuFile">
@ -140,6 +140,7 @@
</property> </property>
<addaction name="m_actionOpenSelectedSourceArticlesExternally"/> <addaction name="m_actionOpenSelectedSourceArticlesExternally"/>
<addaction name="m_actionOpenSelectedMessagesInternally"/> <addaction name="m_actionOpenSelectedMessagesInternally"/>
<addaction name="m_actionOpenSelectedMessagesInternallyNoTab"/>
<addaction name="m_actionSendMessageViaEmail"/> <addaction name="m_actionSendMessageViaEmail"/>
<addaction name="m_actionMessagePreviewEnabled"/> <addaction name="m_actionMessagePreviewEnabled"/>
<addaction name="m_actionShowOnlyUnreadMessages"/> <addaction name="m_actionShowOnlyUnreadMessages"/>
@ -847,6 +848,11 @@
<string>&amp;Copy URLs of selected articles</string> <string>&amp;Copy URLs of selected articles</string>
</property> </property>
</action> </action>
<action name="m_actionOpenSelectedMessagesInternallyNoTab">
<property name="text">
<string>Open in internal browser (no new tab)</string>
</property>
</action>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>

View File

@ -52,6 +52,7 @@ FeedMessageViewer::FeedMessageViewer(QWidget* parent) : TabContent(parent), m_to
m_messagesBrowser(new MessagePreviewer(false, this)) { m_messagesBrowser(new MessagePreviewer(false, this)) {
initialize(); initialize();
initializeViews(); initializeViews();
createConnections(); createConnections();
} }
@ -262,6 +263,7 @@ void FeedMessageViewer::createConnections() {
m_messagesView->sourceModel(), &MessagesModel::setMessageImportantById); m_messagesView->sourceModel(), &MessagesModel::setMessageImportantById);
connect(m_messagesView, &MessagesView::currentMessageChanged, this, &FeedMessageViewer::displayMessage); connect(m_messagesView, &MessagesView::currentMessageChanged, this, &FeedMessageViewer::displayMessage);
connect(m_messagesView, &MessagesView::openLinkMiniBrowser, m_messagesBrowser, &MessagePreviewer::loadUrl);
// If user selects feeds, load their messages. // If user selects feeds, load their messages.
connect(m_feedsView, &FeedsView::itemSelected, m_messagesView, &MessagesView::loadItem); connect(m_feedsView, &FeedsView::itemSelected, m_messagesView, &MessagesView::loadItem);

View File

@ -40,57 +40,7 @@ MessageBrowser::MessageBrowser(bool should_resize_to_fit, QWidget* parent)
} }
}); });
connect(m_txtBrowser, &QTextBrowser::anchorClicked, [=](const QUrl& url) { connect(m_txtBrowser, &QTextBrowser::anchorClicked, this, &MessageBrowser::onAnchorClicked);
if (url.toString().startsWith(INTERNAL_URL_PASSATTACHMENT) &&
m_root != nullptr &&
m_root->getParentServiceRoot()->downloadAttachmentOnMyOwn(url)) {
return;
}
if (!url.isEmpty()) {
bool open_externally_now = qApp->settings()->value(GROUP(Browser),
SETTING(Browser::OpenLinksInExternalBrowserRightAway)).toBool();
if (open_externally_now) {
qApp->web()->openUrlInExternalBrowser(url.toString());
}
else {
// User clicked some URL. Open it in external browser or download?
MessageBox box(qApp->mainFormWidget());
box.setText(tr("You clicked some link. You can download the link contents or open it in external web browser."));
box.setInformativeText(tr("What action do you want to take?"));
box.setDetailedText(url.toString());
QAbstractButton* btn_open = box.addButton(tr("Open in external browser"), QMessageBox::ButtonRole::ActionRole);
QAbstractButton* btn_download = box.addButton(tr("Download"), QMessageBox::ButtonRole::ActionRole);
QAbstractButton* btn_cancel = box.addButton(QMessageBox::StandardButton::Cancel);
bool always;
MessageBox::setCheckBox(&box, tr("Always open links in external browser."), &always);
box.setDefaultButton(QMessageBox::StandardButton::Cancel);
box.exec();
if (box.clickedButton() != box.button(QMessageBox::StandardButton::Cancel)) {
// Store selected checkbox value.
qApp->settings()->setValue(GROUP(Browser), Browser::OpenLinksInExternalBrowserRightAway, always);
}
if (box.clickedButton() == btn_open) {
qApp->web()->openUrlInExternalBrowser(url.toString());
}
else if (box.clickedButton() == btn_download) {
qApp->downloadManager()->download(url);
}
btn_download->deleteLater();
btn_open->deleteLater();
btn_cancel->deleteLater();
}
}
else {
MessageBox::show(qApp->mainFormWidget(), QMessageBox::Warning, tr("Incorrect link"), tr("Selected hyperlink is invalid."));
}
});
connect(m_txtBrowser, connect(m_txtBrowser,
QOverload<const QUrl&>::of(&QTextBrowser::highlighted), QOverload<const QUrl&>::of(&QTextBrowser::highlighted),
[=](const QUrl& url) { [=](const QUrl& url) {
@ -198,6 +148,58 @@ bool MessageBrowser::eventFilter(QObject* watched, QEvent* event) {
return false; return false;
} }
void MessageBrowser::onAnchorClicked(const QUrl &url) {
if (url.toString().startsWith(INTERNAL_URL_PASSATTACHMENT) &&
m_root != nullptr &&
m_root->getParentServiceRoot()->downloadAttachmentOnMyOwn(url)) {
return;
}
if (!url.isEmpty()) {
bool open_externally_now = qApp->settings()->value(GROUP(Browser),
SETTING(Browser::OpenLinksInExternalBrowserRightAway)).toBool();
if (open_externally_now) {
qApp->web()->openUrlInExternalBrowser(url.toString());
}
else {
// User clicked some URL. Open it in external browser or download?
MessageBox box(qApp->mainFormWidget());
box.setText(tr("You clicked some link. You can download the link contents or open it in external web browser."));
box.setInformativeText(tr("What action do you want to take?"));
box.setDetailedText(url.toString());
QAbstractButton* btn_open = box.addButton(tr("Open in external browser"), QMessageBox::ButtonRole::ActionRole);
QAbstractButton* btn_download = box.addButton(tr("Download"), QMessageBox::ButtonRole::ActionRole);
QAbstractButton* btn_cancel = box.addButton(QMessageBox::StandardButton::Cancel);
bool always;
MessageBox::setCheckBox(&box, tr("Always open links in external browser."), &always);
box.setDefaultButton(QMessageBox::StandardButton::Cancel);
box.exec();
if (box.clickedButton() != box.button(QMessageBox::StandardButton::Cancel)) {
// Store selected checkbox value.
qApp->settings()->setValue(GROUP(Browser), Browser::OpenLinksInExternalBrowserRightAway, always);
}
if (box.clickedButton() == btn_open) {
qApp->web()->openUrlInExternalBrowser(url.toString());
}
else if (box.clickedButton() == btn_download) {
qApp->downloadManager()->download(url);
}
btn_download->deleteLater();
btn_open->deleteLater();
btn_cancel->deleteLater();
}
}
else {
MessageBox::show(qApp->mainFormWidget(), QMessageBox::Warning, tr("Incorrect link"), tr("Selected hyperlink is invalid."));
}
}
void MessageBrowser::reloadFontSettings() { void MessageBrowser::reloadFontSettings() {
const Settings* settings = qApp->settings(); const Settings* settings = qApp->settings();
QFont fon; QFont fon;
@ -206,6 +208,10 @@ void MessageBrowser::reloadFontSettings() {
m_txtBrowser->setFont(fon); m_txtBrowser->setFont(fon);
} }
void MessageBrowser::loadUrl(const QString &url) {
onAnchorClicked(url);
}
void MessageBrowser::loadMessage(const Message& message, RootItem* root) { void MessageBrowser::loadMessage(const Message& message, RootItem* root) {
Q_UNUSED(root) Q_UNUSED(root)

View File

@ -28,11 +28,15 @@ class MessageBrowser : public QWidget {
void setVerticalScrollBarPosition(double pos); void setVerticalScrollBarPosition(double pos);
void clear(bool also_hide); void clear(bool also_hide);
void reloadFontSettings(); void reloadFontSettings();
void loadUrl(const QString& url);
void loadMessage(const Message& message, RootItem* root); void loadMessage(const Message& message, RootItem* root);
protected: protected:
bool eventFilter(QObject* watched, QEvent* event); bool eventFilter(QObject* watched, QEvent* event);
private slots:
void onAnchorClicked(const QUrl& url);
private: private:
QString prepareHtmlForMessage(const Message& message); QString prepareHtmlForMessage(const Message& message);

View File

@ -107,6 +107,15 @@ void MessagePreviewer::hideToolbar() {
m_toolBar->setVisible(false); m_toolBar->setVisible(false);
} }
void MessagePreviewer::loadUrl(const QString &url) {
#if defined(USE_WEBENGINE)
m_txtMessage->loadUrl(url);
#else
m_txtMessage->loadUrl(url);
#endif
}
void MessagePreviewer::loadMessage(const Message& message, RootItem* root) { void MessagePreviewer::loadMessage(const Message& message, RootItem* root) {
bool same_message = message.m_id == m_message.m_id && m_root == root; bool same_message = message.m_id == m_message.m_id && m_root == root;

View File

@ -49,6 +49,7 @@ class MessagePreviewer : public QWidget {
void setToolbarsVisible(bool visible); void setToolbarsVisible(bool visible);
void clear(); void clear();
void hideToolbar(); void hideToolbar();
void loadUrl(const QString& url);
void loadMessage(const Message& message, RootItem* root); void loadMessage(const Message& message, RootItem* root);
private slots: private slots:

View File

@ -373,12 +373,14 @@ void MessagesView::initializeContextMenu() {
<< qApp->mainForm()->m_ui->m_actionSendMessageViaEmail << qApp->mainForm()->m_ui->m_actionSendMessageViaEmail
<< qApp->mainForm()->m_ui->m_actionOpenSelectedSourceArticlesExternally << qApp->mainForm()->m_ui->m_actionOpenSelectedSourceArticlesExternally
<< qApp->mainForm()->m_ui->m_actionOpenSelectedMessagesInternally << qApp->mainForm()->m_ui->m_actionOpenSelectedMessagesInternally
<< qApp->mainForm()->m_ui->m_actionOpenSelectedMessagesInternallyNoTab
<< qApp->mainForm()->m_ui->m_actionCopyUrlSelectedArticles << qApp->mainForm()->m_ui->m_actionCopyUrlSelectedArticles
<< qApp->mainForm()->m_ui->m_actionMarkSelectedMessagesAsRead << qApp->mainForm()->m_ui->m_actionMarkSelectedMessagesAsRead
<< qApp->mainForm()->m_ui->m_actionMarkSelectedMessagesAsUnread << qApp->mainForm()->m_ui->m_actionMarkSelectedMessagesAsUnread
<< qApp->mainForm()->m_ui->m_actionSwitchImportanceOfSelectedMessages << qApp->mainForm()->m_ui->m_actionSwitchImportanceOfSelectedMessages
<< qApp->mainForm()->m_ui->m_actionDeleteSelectedMessages); << qApp->mainForm()->m_ui->m_actionDeleteSelectedMessages);
if (m_sourceModel->loadedItem() != nullptr) { if (m_sourceModel->loadedItem() != nullptr) {
if (m_sourceModel->loadedItem()->kind() == RootItem::Kind::Bin) { if (m_sourceModel->loadedItem()->kind() == RootItem::Kind::Bin) {
m_contextMenu->addAction(qApp->mainForm()->m_ui->m_actionRestoreSelectedMessages); m_contextMenu->addAction(qApp->mainForm()->m_ui->m_actionRestoreSelectedMessages);
@ -542,6 +544,18 @@ void MessagesView::openSelectedMessagesInternally() {
} }
} }
void MessagesView::openSelectedMessageUrl() {
auto rws = selectionModel()->selectedRows();
if (!rws.isEmpty()) {
auto msg = m_sourceModel->messageAt(m_proxyModel->mapToSource(rws.at(0)).row());
if (!msg.m_url.isEmpty()) {
emit openLinkMiniBrowser(msg.m_url);
}
}
}
void MessagesView::sendSelectedMessageViaEmail() { void MessagesView::sendSelectedMessageViaEmail() {
if (selectionModel()->selectedRows().size() == 1) { if (selectionModel()->selectedRows().size() == 1) {
const Message message = m_sourceModel->messageAt(m_proxyModel->mapToSource(selectionModel()->selectedRows().at(0)).row()); const Message message = m_sourceModel->messageAt(m_proxyModel->mapToSource(selectionModel()->selectedRows().at(0)).row());

View File

@ -42,6 +42,7 @@ class MessagesView : public BaseTreeView {
// Message manipulators. // Message manipulators.
void openSelectedSourceMessagesExternally(); void openSelectedSourceMessagesExternally();
void openSelectedMessagesInternally(); void openSelectedMessagesInternally();
void openSelectedMessageUrl();
void sendSelectedMessageViaEmail(); void sendSelectedMessageViaEmail();
// Works with SELECTED messages only. // Works with SELECTED messages only.

View File

@ -126,6 +126,7 @@ void TabWidget::createConnections() {
connect(tabBar(), &TabBar::tabCloseRequested, this, &TabWidget::closeTab); connect(tabBar(), &TabBar::tabCloseRequested, this, &TabWidget::closeTab);
connect(tabBar(), &TabBar::emptySpaceDoubleClicked, this, &TabWidget::addEmptyBrowser); connect(tabBar(), &TabBar::emptySpaceDoubleClicked, this, &TabWidget::addEmptyBrowser);
connect(tabBar(), &TabBar::tabMoved, this, &TabWidget::fixContentsAfterMove); connect(tabBar(), &TabBar::tabMoved, this, &TabWidget::fixContentsAfterMove);
connect(feedMessageViewer()->messagesView(), &MessagesView::openMessagesInNewspaperView, this, &TabWidget::addNewspaperView); connect(feedMessageViewer()->messagesView(), &MessagesView::openMessagesInNewspaperView, this, &TabWidget::addNewspaperView);
connect(feedMessageViewer()->feedsView(), &FeedsView::openMessagesInNewspaperView, this, &TabWidget::addNewspaperView); connect(feedMessageViewer()->feedsView(), &FeedsView::openMessagesInNewspaperView, this, &TabWidget::addNewspaperView);
} }

View File

@ -21,6 +21,7 @@ Downloader::Downloader(QObject* parent)
m_lastOutputData(QByteArray()), m_lastOutputError(QNetworkReply::NoError) { m_lastOutputData(QByteArray()), m_lastOutputError(QNetworkReply::NoError) {
m_timer->setInterval(DOWNLOAD_TIMEOUT); m_timer->setInterval(DOWNLOAD_TIMEOUT);
m_timer->setSingleShot(true); m_timer->setSingleShot(true);
connect(m_timer, &QTimer::timeout, this, &Downloader::cancel); connect(m_timer, &QTimer::timeout, this, &Downloader::cancel);
m_downloadManager->setCookieJar(qApp->web()->cookieJar()); m_downloadManager->setCookieJar(qApp->web()->cookieJar());