work on toasts
This commit is contained in:
parent
606f69929a
commit
9745f29547
19 changed files with 223 additions and 31 deletions
|
@ -12,6 +12,7 @@
|
||||||
<file>./graphics/Breeze/actions/32/arrow-up-double.svg</file>
|
<file>./graphics/Breeze/actions/32/arrow-up-double.svg</file>
|
||||||
<file>./graphics/Breeze/actions/32/call-start.svg</file>
|
<file>./graphics/Breeze/actions/32/call-start.svg</file>
|
||||||
<file>./graphics/Breeze/actions/32/dialog-cancel.svg</file>
|
<file>./graphics/Breeze/actions/32/dialog-cancel.svg</file>
|
||||||
|
<file>./graphics/Breeze/actions/22/dialog-close.svg</file>
|
||||||
<file>./graphics/Breeze/status/64/dialog-error.svg</file>
|
<file>./graphics/Breeze/status/64/dialog-error.svg</file>
|
||||||
<file>./graphics/Breeze/status/64/dialog-information.svg</file>
|
<file>./graphics/Breeze/status/64/dialog-information.svg</file>
|
||||||
<file>./graphics/Breeze/actions/32/dialog-ok.svg</file>
|
<file>./graphics/Breeze/actions/32/dialog-ok.svg</file>
|
||||||
|
@ -53,6 +54,7 @@
|
||||||
<file>./graphics/Breeze/actions/32/go-previous.svg</file>
|
<file>./graphics/Breeze/actions/32/go-previous.svg</file>
|
||||||
<file>./graphics/Breeze/actions/32/go-up.svg</file>
|
<file>./graphics/Breeze/actions/32/go-up.svg</file>
|
||||||
<file>./graphics/Breeze/actions/22/gtk-cancel.svg</file>
|
<file>./graphics/Breeze/actions/22/gtk-cancel.svg</file>
|
||||||
|
<file>./graphics/Breeze/actions/22/gtk-close.svg</file>
|
||||||
<file>./graphics/Breeze/actions/22/gtk-edit.svg</file>
|
<file>./graphics/Breeze/actions/22/gtk-edit.svg</file>
|
||||||
<file>./graphics/Breeze/actions/32/help-about.svg</file>
|
<file>./graphics/Breeze/actions/32/help-about.svg</file>
|
||||||
<file>./graphics/Breeze/actions/22/help-contents.svg</file>
|
<file>./graphics/Breeze/actions/22/help-contents.svg</file>
|
||||||
|
@ -101,6 +103,7 @@
|
||||||
<file>./graphics/Breeze Dark/actions/32/arrow-up-double.svg</file>
|
<file>./graphics/Breeze Dark/actions/32/arrow-up-double.svg</file>
|
||||||
<file>./graphics/Breeze Dark/actions/32/call-start.svg</file>
|
<file>./graphics/Breeze Dark/actions/32/call-start.svg</file>
|
||||||
<file>./graphics/Breeze Dark/actions/32/dialog-cancel.svg</file>
|
<file>./graphics/Breeze Dark/actions/32/dialog-cancel.svg</file>
|
||||||
|
<file>./graphics/Breeze Dark/actions/22/dialog-close.svg</file>
|
||||||
<file>./graphics/Breeze Dark/status/64/dialog-error.svg</file>
|
<file>./graphics/Breeze Dark/status/64/dialog-error.svg</file>
|
||||||
<file>./graphics/Breeze Dark/status/64/dialog-information.svg</file>
|
<file>./graphics/Breeze Dark/status/64/dialog-information.svg</file>
|
||||||
<file>./graphics/Breeze Dark/actions/32/dialog-ok.svg</file>
|
<file>./graphics/Breeze Dark/actions/32/dialog-ok.svg</file>
|
||||||
|
@ -142,6 +145,7 @@
|
||||||
<file>./graphics/Breeze Dark/actions/32/go-previous.svg</file>
|
<file>./graphics/Breeze Dark/actions/32/go-previous.svg</file>
|
||||||
<file>./graphics/Breeze Dark/actions/32/go-up.svg</file>
|
<file>./graphics/Breeze Dark/actions/32/go-up.svg</file>
|
||||||
<file>./graphics/Breeze Dark/actions/22/gtk-cancel.svg</file>
|
<file>./graphics/Breeze Dark/actions/22/gtk-cancel.svg</file>
|
||||||
|
<file>./graphics/Breeze Dark/actions/22/gtk-close.svg</file>
|
||||||
<file>./graphics/Breeze Dark/actions/22/gtk-edit.svg</file>
|
<file>./graphics/Breeze Dark/actions/22/gtk-edit.svg</file>
|
||||||
<file>./graphics/Breeze Dark/actions/32/help-about.svg</file>
|
<file>./graphics/Breeze Dark/actions/32/help-about.svg</file>
|
||||||
<file>./graphics/Breeze Dark/actions/22/help-contents.svg</file>
|
<file>./graphics/Breeze Dark/actions/22/help-contents.svg</file>
|
||||||
|
@ -226,6 +230,7 @@
|
||||||
<file>./graphics/Faenza/actions/64/go-previous.png</file>
|
<file>./graphics/Faenza/actions/64/go-previous.png</file>
|
||||||
<file>./graphics/Faenza/actions/64/go-up.png</file>
|
<file>./graphics/Faenza/actions/64/go-up.png</file>
|
||||||
<file>./graphics/Faenza/actions/64/gtk-cancel.png</file>
|
<file>./graphics/Faenza/actions/64/gtk-cancel.png</file>
|
||||||
|
<file>./graphics/Faenza/actions/64/gtk-close.png</file>
|
||||||
<file>./graphics/Faenza/actions/64/gtk-edit.png</file>
|
<file>./graphics/Faenza/actions/64/gtk-edit.png</file>
|
||||||
<file>./graphics/Faenza/actions/64/help-about.png</file>
|
<file>./graphics/Faenza/actions/64/help-about.png</file>
|
||||||
<file>./graphics/Faenza/actions/64/help-contents.png</file>
|
<file>./graphics/Faenza/actions/64/help-contents.png</file>
|
||||||
|
@ -274,6 +279,7 @@
|
||||||
<file>./graphics/Numix/22/actions/browser-download.svg</file>
|
<file>./graphics/Numix/22/actions/browser-download.svg</file>
|
||||||
<file>./graphics/Numix/22/actions/call-start.svg</file>
|
<file>./graphics/Numix/22/actions/call-start.svg</file>
|
||||||
<file>./graphics/Numix/22/actions/dialog-cancel.svg</file>
|
<file>./graphics/Numix/22/actions/dialog-cancel.svg</file>
|
||||||
|
<file>./graphics/Numix/22/actions/dialog-close.svg</file>
|
||||||
<file>./graphics/Numix/22/status/dialog-error.svg</file>
|
<file>./graphics/Numix/22/status/dialog-error.svg</file>
|
||||||
<file>./graphics/Numix/22/status/dialog-information.svg</file>
|
<file>./graphics/Numix/22/status/dialog-information.svg</file>
|
||||||
<file>./graphics/Numix/22/actions/dialog-no.svg</file>
|
<file>./graphics/Numix/22/actions/dialog-no.svg</file>
|
||||||
|
@ -315,6 +321,7 @@
|
||||||
<file>./graphics/Numix/22/actions/go-previous.svg</file>
|
<file>./graphics/Numix/22/actions/go-previous.svg</file>
|
||||||
<file>./graphics/Numix/22/actions/go-up.svg</file>
|
<file>./graphics/Numix/22/actions/go-up.svg</file>
|
||||||
<file>./graphics/Numix/22/actions/gtk-cancel.svg</file>
|
<file>./graphics/Numix/22/actions/gtk-cancel.svg</file>
|
||||||
|
<file>./graphics/Numix/22/actions/gtk-close.svg</file>
|
||||||
<file>./graphics/Numix/22/actions/gtk-edit.svg</file>
|
<file>./graphics/Numix/22/actions/gtk-edit.svg</file>
|
||||||
<file>./graphics/Numix/22/categories/help-about.svg</file>
|
<file>./graphics/Numix/22/categories/help-about.svg</file>
|
||||||
<file>./graphics/Numix/22/actions/help-contents.svg</file>
|
<file>./graphics/Numix/22/actions/help-contents.svg</file>
|
||||||
|
|
|
@ -93,6 +93,8 @@ set(SOURCES
|
||||||
gui/messagepreviewer.h
|
gui/messagepreviewer.h
|
||||||
gui/messagesview.cpp
|
gui/messagesview.cpp
|
||||||
gui/messagesview.h
|
gui/messagesview.h
|
||||||
|
gui/notifications/basetoastnotification.cpp
|
||||||
|
gui/notifications/basetoastnotification.h
|
||||||
gui/notifications/notificationseditor.cpp
|
gui/notifications/notificationseditor.cpp
|
||||||
gui/notifications/notificationseditor.h
|
gui/notifications/notificationseditor.h
|
||||||
gui/notifications/singlenotificationeditor.cpp
|
gui/notifications/singlenotificationeditor.cpp
|
||||||
|
@ -173,6 +175,10 @@ set(SOURCES
|
||||||
gui/tabcontent.h
|
gui/tabcontent.h
|
||||||
gui/tabwidget.cpp
|
gui/tabwidget.cpp
|
||||||
gui/tabwidget.h
|
gui/tabwidget.h
|
||||||
|
gui/notifications/toastnotification.cpp
|
||||||
|
gui/notifications/toastnotification.h
|
||||||
|
gui/notifications/toastnotificationsmanager.cpp
|
||||||
|
gui/notifications/toastnotificationsmanager.h
|
||||||
gui/webviewers/webviewer.h
|
gui/webviewers/webviewer.h
|
||||||
gui/richtexteditor/mrichtextedit.cpp
|
gui/richtexteditor/mrichtextedit.cpp
|
||||||
gui/richtexteditor/mrichtextedit.h
|
gui/richtexteditor/mrichtextedit.h
|
||||||
|
@ -447,6 +453,7 @@ set(UI_FILES
|
||||||
gui/notifications/singlenotificationeditor.ui
|
gui/notifications/singlenotificationeditor.ui
|
||||||
gui/reusable/networkproxydetails.ui
|
gui/reusable/networkproxydetails.ui
|
||||||
gui/itemdetails.ui
|
gui/itemdetails.ui
|
||||||
|
gui/notifications/toastnotification.ui
|
||||||
gui/richtexteditor/mrichtextedit.ui
|
gui/richtexteditor/mrichtextedit.ui
|
||||||
gui/newspaperpreviewer.ui
|
gui/newspaperpreviewer.ui
|
||||||
gui/reusable/searchtextwidget.ui
|
gui/reusable/searchtextwidget.ui
|
||||||
|
|
|
@ -99,7 +99,7 @@ bool MessageObject::isDuplicateWithAttribute(MessageObject::DuplicateCheck attri
|
||||||
qDebugNN << LOGSEC_DB << "Executed SQL for message duplicates check:"
|
qDebugNN << LOGSEC_DB << "Executed SQL for message duplicates check:"
|
||||||
<< QUOTE_W_SPACE_DOT(DatabaseFactory::lastExecutedQuery(q));
|
<< QUOTE_W_SPACE_DOT(DatabaseFactory::lastExecutedQuery(q));
|
||||||
|
|
||||||
if (q.record().value(0).toInt() > 0) {
|
if (q.value(0).toInt() > 0) {
|
||||||
// Whoops, we have the "same" message in database.
|
// Whoops, we have the "same" message in database.
|
||||||
qDebugNN << LOGSEC_CORE << "Message" << QUOTE_W_SPACE(title()) << "was identified as duplicate by filter script.";
|
qDebugNN << LOGSEC_CORE << "Message" << QUOTE_W_SPACE(title()) << "was identified as duplicate by filter script.";
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -160,7 +160,7 @@ void MessagesModel::repopulate() {
|
||||||
|
|
||||||
bool MessagesModel::setData(const QModelIndex& index, const QVariant& value, int role) {
|
bool MessagesModel::setData(const QModelIndex& index, const QVariant& value, int role) {
|
||||||
Q_UNUSED(role)
|
Q_UNUSED(role)
|
||||||
m_cache->setData(index, value, record(index.row()));
|
m_cache->setData(index, value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -609,9 +609,7 @@ bool MessagesModel::setMessageRead(int row_index, RootItem::ReadStatus read) {
|
||||||
|
|
||||||
Message message = messageAt(row_index);
|
Message message = messageAt(row_index);
|
||||||
|
|
||||||
if (!m_selectedItem->getParentServiceRoot()->onBeforeSetMessagesRead(m_selectedItem,
|
if (!m_selectedItem->getParentServiceRoot()->onBeforeSetMessagesRead(m_selectedItem, {message}, read)) {
|
||||||
QList<Message>() << message,
|
|
||||||
read)) {
|
|
||||||
// Cannot change read status of the item. Abort.
|
// Cannot change read status of the item. Abort.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -760,7 +758,7 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList& messages) {
|
||||||
msgs.append(msg);
|
msgs.append(msg);
|
||||||
message_ids.append(QString::number(msg.m_id));
|
message_ids.append(QString::number(msg.m_id));
|
||||||
|
|
||||||
if (qobject_cast<RecycleBin*>(m_selectedItem) != nullptr) {
|
if (m_selectedItem->kind() == RootItem::Kind::Bin) {
|
||||||
setData(index(message.row(), MSG_DB_PDELETED_INDEX), 1);
|
setData(index(message.row(), MSG_DB_PDELETED_INDEX), 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -22,9 +22,17 @@ class MessagesModel : public QSqlQueryModel, public MessagesModelSqlLayer {
|
||||||
public:
|
public:
|
||||||
// Enum which describes basic highlighting schemes
|
// Enum which describes basic highlighting schemes
|
||||||
// for messages.
|
// for messages.
|
||||||
enum class MessageHighlighter { NoHighlighting = 1, HighlightUnread = 2, HighlightImportant = 4 };
|
enum class MessageHighlighter {
|
||||||
|
NoHighlighting = 1,
|
||||||
|
HighlightUnread = 2,
|
||||||
|
HighlightImportant = 4
|
||||||
|
};
|
||||||
|
|
||||||
enum class MessageUnreadIcon { Dot = 1, Envelope = 2, FeedIcon = 3 };
|
enum class MessageUnreadIcon {
|
||||||
|
Dot = 1,
|
||||||
|
Envelope = 2,
|
||||||
|
FeedIcon = 3
|
||||||
|
};
|
||||||
|
|
||||||
Q_ENUM(MessageUnreadIcon)
|
Q_ENUM(MessageUnreadIcon)
|
||||||
|
|
||||||
|
@ -43,8 +51,6 @@ class MessagesModel : public QSqlQueryModel, public MessagesModelSqlLayer {
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
|
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
|
||||||
Qt::ItemFlags flags(const QModelIndex& index) const;
|
Qt::ItemFlags flags(const QModelIndex& index) const;
|
||||||
|
|
||||||
// Returns message at given index.
|
|
||||||
|
|
||||||
QList<Message> messagesAt(const QList<int>& row_indices) const;
|
QList<Message> messagesAt(const QList<int>& row_indices) const;
|
||||||
Message messageAt(int row_index) const;
|
Message messageAt(int row_index) const;
|
||||||
int messageId(int row_index) const;
|
int messageId(int row_index) const;
|
||||||
|
|
|
@ -2,11 +2,13 @@
|
||||||
|
|
||||||
#include "core/messagesmodelcache.h"
|
#include "core/messagesmodelcache.h"
|
||||||
|
|
||||||
|
#include "core/messagesmodel.h"
|
||||||
|
|
||||||
MessagesModelCache::MessagesModelCache(QObject* parent) : QObject(parent) {}
|
MessagesModelCache::MessagesModelCache(QObject* parent) : QObject(parent) {}
|
||||||
|
|
||||||
void MessagesModelCache::setData(const QModelIndex& index, const QVariant& value, const QSqlRecord& record) {
|
void MessagesModelCache::setData(const QModelIndex& index, const QVariant& value) {
|
||||||
if (!m_msgCache.contains(index.row())) {
|
if (!m_msgCache.contains(index.row())) {
|
||||||
m_msgCache[index.row()] = record;
|
m_msgCache[index.row()] = static_cast<const MessagesModel*>(index.model())->record(index.row());
|
||||||
}
|
}
|
||||||
|
|
||||||
m_msgCache[index.row()].setValue(index.column(), value);
|
m_msgCache[index.row()].setValue(index.column(), value);
|
||||||
|
|
|
@ -22,7 +22,7 @@ class MessagesModelCache : public QObject {
|
||||||
QVariant data(const QModelIndex& idx);
|
QVariant data(const QModelIndex& idx);
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
void setData(const QModelIndex& index, const QVariant& value, const QSqlRecord& record);
|
void setData(const QModelIndex& index, const QVariant& value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QHash<int, QSqlRecord> m_msgCache;
|
QHash<int, QSqlRecord> m_msgCache;
|
||||||
|
|
|
@ -2716,15 +2716,14 @@ QList<MessageFilter*> DatabaseQueries::getMessageFilters(const QSqlDatabase& db,
|
||||||
QList<MessageFilter*> filters;
|
QList<MessageFilter*> filters;
|
||||||
|
|
||||||
q.setForwardOnly(true);
|
q.setForwardOnly(true);
|
||||||
q.prepare(QSL("SELECT * FROM MessageFilters;"));
|
q.prepare(QSL("SELECT id, name, script FROM MessageFilters;"));
|
||||||
|
|
||||||
if (q.exec()) {
|
if (q.exec()) {
|
||||||
while (q.next()) {
|
while (q.next()) {
|
||||||
auto rec = q.record();
|
auto* filter = new MessageFilter(q.value(0).toInt());
|
||||||
auto* filter = new MessageFilter(rec.value(0).toInt());
|
|
||||||
|
|
||||||
filter->setName(rec.value(1).toString());
|
filter->setName(q.value(1).toString());
|
||||||
filter->setScript(rec.value(2).toString());
|
filter->setScript(q.value(2).toString());
|
||||||
|
|
||||||
filters.append(filter);
|
filters.append(filter);
|
||||||
}
|
}
|
||||||
|
@ -2753,9 +2752,7 @@ QMultiMap<QString, int> DatabaseQueries::messageFiltersInFeeds(const QSqlDatabas
|
||||||
|
|
||||||
if (q.exec()) {
|
if (q.exec()) {
|
||||||
while (q.next()) {
|
while (q.next()) {
|
||||||
auto rec = q.record();
|
filters_in_feeds.insert(q.value(1).toString(), q.value(0).toInt());
|
||||||
|
|
||||||
filters_in_feeds.insert(rec.value(1).toString(), rec.value(0).toInt());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ok != nullptr) {
|
if (ok != nullptr) {
|
||||||
|
|
|
@ -47,6 +47,8 @@
|
||||||
#include <QDesktopWidget>
|
#include <QDesktopWidget>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <QWindow>
|
||||||
|
|
||||||
FormMain::FormMain(QWidget* parent, Qt::WindowFlags f)
|
FormMain::FormMain(QWidget* parent, Qt::WindowFlags f)
|
||||||
: QMainWindow(parent, f), m_ui(new Ui::FormMain), m_trayMenu(nullptr), m_statusBar(nullptr) {
|
: QMainWindow(parent, f), m_ui(new Ui::FormMain), m_trayMenu(nullptr), m_statusBar(nullptr) {
|
||||||
qDebugNN << LOGSEC_GUI
|
qDebugNN << LOGSEC_GUI
|
||||||
|
|
|
@ -255,7 +255,8 @@ void MessagesView::reloadSelections() {
|
||||||
const bool is_current_selected =
|
const bool is_current_selected =
|
||||||
selectionModel()->selectedRows().contains(m_proxyModel->index(current_index.row(), 0, current_index.parent()));
|
selectionModel()->selectedRows().contains(m_proxyModel->index(current_index.row(), 0, current_index.parent()));
|
||||||
const QModelIndex mapped_current_index = m_proxyModel->mapToSource(current_index);
|
const QModelIndex mapped_current_index = m_proxyModel->mapToSource(current_index);
|
||||||
const Message selected_message = m_sourceModel->messageAt(mapped_current_index.row());
|
const int selected_message_id =
|
||||||
|
m_sourceModel->data(mapped_current_index.row(), MSG_DB_ID_INDEX, Qt::ItemDataRole::EditRole).toInt();
|
||||||
const int col = header()->sortIndicatorSection();
|
const int col = header()->sortIndicatorSection();
|
||||||
const Qt::SortOrder ord = header()->sortIndicatorOrder();
|
const Qt::SortOrder ord = header()->sortIndicatorOrder();
|
||||||
bool do_not_mark_read_on_select = false;
|
bool do_not_mark_read_on_select = false;
|
||||||
|
@ -264,19 +265,21 @@ void MessagesView::reloadSelections() {
|
||||||
sort(col, ord, true, false, false, true);
|
sort(col, ord, true, false, false, true);
|
||||||
|
|
||||||
// Now, we must find the same previously focused message.
|
// Now, we must find the same previously focused message.
|
||||||
if (selected_message.m_id > 0) {
|
if (selected_message_id > 0) {
|
||||||
if (m_proxyModel->rowCount() == 0 || !is_current_selected) {
|
if (m_proxyModel->rowCount() == 0 || !is_current_selected) {
|
||||||
current_index = QModelIndex();
|
current_index = QModelIndex();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (int i = 0; i < m_proxyModel->rowCount(); i++) {
|
for (int i = 0; i < m_proxyModel->rowCount(); i++) {
|
||||||
QModelIndex msg_idx = m_proxyModel->index(i, MSG_DB_TITLE_INDEX);
|
QModelIndex msg_idx = m_proxyModel->index(i, MSG_DB_TITLE_INDEX);
|
||||||
Message msg = m_sourceModel->messageAt(m_proxyModel->mapToSource(msg_idx).row());
|
QModelIndex msg_source_idx = m_proxyModel->mapToSource(msg_idx);
|
||||||
|
int msg_id = m_sourceModel->data(msg_source_idx.row(), MSG_DB_ID_INDEX, Qt::ItemDataRole::EditRole).toInt();
|
||||||
|
|
||||||
if (msg.m_id == selected_message.m_id) {
|
if (msg_id == selected_message_id) {
|
||||||
current_index = msg_idx;
|
current_index = msg_idx;
|
||||||
|
|
||||||
if (!msg.m_isRead /* && selected_message.m_isRead */) {
|
if (!m_sourceModel->data(msg_source_idx.row(), MSG_DB_READ_INDEX, Qt::ItemDataRole::EditRole)
|
||||||
|
.toBool() /* && selected_message.m_isRead */) {
|
||||||
do_not_mark_read_on_select = true;
|
do_not_mark_read_on_select = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,7 +299,7 @@ void MessagesView::reloadSelections() {
|
||||||
m_processingRightMouseButton = do_not_mark_read_on_select;
|
m_processingRightMouseButton = do_not_mark_read_on_select;
|
||||||
|
|
||||||
setCurrentIndex(current_index);
|
setCurrentIndex(current_index);
|
||||||
reselectIndexes(QModelIndexList() << current_index);
|
reselectIndexes({current_index});
|
||||||
|
|
||||||
m_processingRightMouseButton = false;
|
m_processingRightMouseButton = false;
|
||||||
}
|
}
|
||||||
|
@ -867,8 +870,10 @@ void MessagesView::openSelectedMessagesWithExternalTool() {
|
||||||
auto rws = selectionModel()->selectedRows();
|
auto rws = selectionModel()->selectedRows();
|
||||||
|
|
||||||
for (const QModelIndex& index : qAsConst(rws)) {
|
for (const QModelIndex& index : qAsConst(rws)) {
|
||||||
const QString link = m_sourceModel->messageAt(m_proxyModel->mapToSource(index).row())
|
const QString link =
|
||||||
.m_url.replace(QRegularExpression(QSL("[\\t\\n]")), QString());
|
m_sourceModel->data(m_proxyModel->mapToSource(index).row(), MSG_DB_URL_INDEX, Qt::ItemDataRole::EditRole)
|
||||||
|
.toString()
|
||||||
|
.replace(QRegularExpression(QSL("[\\t\\n]")), QString());
|
||||||
|
|
||||||
if (!link.isEmpty()) {
|
if (!link.isEmpty()) {
|
||||||
if (!tool.run(link)) {
|
if (!tool.run(link)) {
|
||||||
|
|
24
src/librssguard/gui/notifications/basetoastnotification.cpp
Normal file
24
src/librssguard/gui/notifications/basetoastnotification.cpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// For license of this file, see <project-root-folder>/LICENSE.md.
|
||||||
|
|
||||||
|
#include "gui/notifications/basetoastnotification.h"
|
||||||
|
|
||||||
|
#include "miscellaneous/iconfactory.h"
|
||||||
|
|
||||||
|
BaseToastNotification::BaseToastNotification(QWidget* parent) : QDialog(parent) {
|
||||||
|
setAttribute(Qt::WidgetAttribute::WA_ShowWithoutActivating);
|
||||||
|
setAttribute(Qt::WidgetAttribute::WA_TranslucentBackground);
|
||||||
|
|
||||||
|
setWindowFlags(
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
Qt::WindowType::SubWindow |
|
||||||
|
#else
|
||||||
|
Qt::WindowType::Tool |
|
||||||
|
#endif
|
||||||
|
Qt::WindowType::FramelessWindowHint | Qt::WindowType::WindowStaysOnTopHint | Qt::WindowType::WindowSystemMenuHint);
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseToastNotification::~BaseToastNotification() {}
|
||||||
|
|
||||||
|
void BaseToastNotification::setupCloseButton(QAbstractButton* btn) {
|
||||||
|
btn->setIcon(qApp->icons()->fromTheme(QSL("dialog-close"), QSL("gtk-close")));
|
||||||
|
}
|
21
src/librssguard/gui/notifications/basetoastnotification.h
Normal file
21
src/librssguard/gui/notifications/basetoastnotification.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// For license of this file, see <project-root-folder>/LICENSE.md.
|
||||||
|
|
||||||
|
#ifndef BASETOASTNOTIFICATION_H
|
||||||
|
#define BASETOASTNOTIFICATION_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
class QAbstractButton;
|
||||||
|
|
||||||
|
class BaseToastNotification : public QDialog {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit BaseToastNotification(QWidget* parent = nullptr);
|
||||||
|
virtual ~BaseToastNotification();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void setupCloseButton(QAbstractButton* btn);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BASETOASTNOTIFICATION_H
|
|
@ -0,0 +1,59 @@
|
||||||
|
// For license of this file, see <project-root-folder>/LICENSE.md.
|
||||||
|
|
||||||
|
#include "gui/notifications/toastnotificationsmanager.h"
|
||||||
|
|
||||||
|
#include "gui/notifications/toastnotification.h"
|
||||||
|
|
||||||
|
ToastNotificationsManager::ToastNotificationsManager(QObject* parent)
|
||||||
|
: QObject(parent), m_position(NotificationPosition::BottomRight), m_screen(-1) {}
|
||||||
|
|
||||||
|
ToastNotificationsManager::~ToastNotificationsManager() {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<BaseToastNotification*> ToastNotificationsManager::activeNotifications() const {
|
||||||
|
return m_activeNotifications;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ToastNotificationsManager::screen() const {
|
||||||
|
return m_screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToastNotificationsManager::setScreen(int screen) {
|
||||||
|
m_screen = screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
ToastNotificationsManager::NotificationPosition ToastNotificationsManager::position() const {
|
||||||
|
return m_position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToastNotificationsManager::setPosition(NotificationPosition position) {
|
||||||
|
m_position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToastNotificationsManager::clear() {
|
||||||
|
for (BaseToastNotification* nt : m_activeNotifications) {
|
||||||
|
nt->close();
|
||||||
|
nt->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_activeNotifications.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToastNotificationsManager::showNotification(Notification::Event event,
|
||||||
|
const GuiMessage& msg,
|
||||||
|
const GuiAction& action) {
|
||||||
|
// Remove top existing notifications as long as their combined height with height of this
|
||||||
|
// new notification extends.
|
||||||
|
|
||||||
|
ToastNotification* notif = new ToastNotification(event, msg, action, qApp->mainFormWidget());
|
||||||
|
|
||||||
|
auto aa = notif->height();
|
||||||
|
|
||||||
|
notif->show();
|
||||||
|
|
||||||
|
auto bb = notif->height();
|
||||||
|
auto cc = notif->height();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToastNotificationsManager::showNotification(const QList<Message>& new_messages) {}
|
|
@ -0,0 +1,48 @@
|
||||||
|
// For license of this file, see <project-root-folder>/LICENSE.md.
|
||||||
|
|
||||||
|
#ifndef TOASTNOTIFICATIONSMANAGER_H
|
||||||
|
#define TOASTNOTIFICATIONSMANAGER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "miscellaneous/application.h"
|
||||||
|
|
||||||
|
class BaseToastNotification;
|
||||||
|
class ToastNotification;
|
||||||
|
|
||||||
|
class ToastNotificationsManager : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum NotificationPosition {
|
||||||
|
TopLeft = 0,
|
||||||
|
TopRight = 1,
|
||||||
|
BottomLeft = 2,
|
||||||
|
BottomRight = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit ToastNotificationsManager(QObject* parent = nullptr);
|
||||||
|
virtual ~ToastNotificationsManager();
|
||||||
|
|
||||||
|
QList<BaseToastNotification*> activeNotifications() const;
|
||||||
|
|
||||||
|
// Screen ID, setting this to -1 means using default/primary
|
||||||
|
// monitor.
|
||||||
|
int screen() const;
|
||||||
|
void setScreen(int screen);
|
||||||
|
|
||||||
|
NotificationPosition position() const;
|
||||||
|
void setPosition(NotificationPosition position);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void clear();
|
||||||
|
void showNotification(Notification::Event event, const GuiMessage& msg, const GuiAction& action);
|
||||||
|
void showNotification(const QList<Message>& new_messages);
|
||||||
|
|
||||||
|
private:
|
||||||
|
NotificationPosition m_position;
|
||||||
|
int m_screen;
|
||||||
|
QList<BaseToastNotification*> m_activeNotifications;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TOASTNOTIFICATIONSMANAGER_H
|
|
@ -17,6 +17,7 @@
|
||||||
#include "gui/dialogs/formlog.h"
|
#include "gui/dialogs/formlog.h"
|
||||||
#include "gui/dialogs/formmain.h"
|
#include "gui/dialogs/formmain.h"
|
||||||
#include "gui/messagebox.h"
|
#include "gui/messagebox.h"
|
||||||
|
#include "gui/notifications/toastnotificationsmanager.h"
|
||||||
#include "gui/toolbars/statusbar.h"
|
#include "gui/toolbars/statusbar.h"
|
||||||
#include "gui/webviewers/qtextbrowser/textbrowserviewer.h"
|
#include "gui/webviewers/qtextbrowser/textbrowserviewer.h"
|
||||||
#include "miscellaneous/feedreader.h"
|
#include "miscellaneous/feedreader.h"
|
||||||
|
@ -108,6 +109,7 @@ Application::Application(const QString& id, int& argc, char** argv, const QStrin
|
||||||
m_database = new DatabaseFactory(this);
|
m_database = new DatabaseFactory(this);
|
||||||
m_downloadManager = nullptr;
|
m_downloadManager = nullptr;
|
||||||
m_notifications = new NotificationFactory(this);
|
m_notifications = new NotificationFactory(this);
|
||||||
|
m_toastNotifications = new ToastNotificationsManager(this);
|
||||||
m_shouldRestart = false;
|
m_shouldRestart = false;
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
#if defined(Q_OS_WIN)
|
||||||
|
@ -679,6 +681,8 @@ void Application::showGuiMessageCore(Notification::Event event,
|
||||||
GuiMessageDestination dest,
|
GuiMessageDestination dest,
|
||||||
const GuiAction& action,
|
const GuiAction& action,
|
||||||
QWidget* parent) {
|
QWidget* parent) {
|
||||||
|
m_toastNotifications->showNotification(event, msg, action);
|
||||||
|
|
||||||
if (SystemTrayIcon::areNotificationsEnabled()) {
|
if (SystemTrayIcon::areNotificationsEnabled()) {
|
||||||
auto notification = m_notifications->notificationForEvent(event);
|
auto notification = m_notifications->notificationForEvent(event);
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ class QWebEngineDownloadItem;
|
||||||
|
|
||||||
class WebFactory;
|
class WebFactory;
|
||||||
class NotificationFactory;
|
class NotificationFactory;
|
||||||
|
class ToastNotificationsManager;
|
||||||
class WebViewer;
|
class WebViewer;
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
#if defined(Q_OS_WIN)
|
||||||
|
@ -277,6 +278,7 @@ class RSSGUARD_DLLSPEC Application : public SingleApplication {
|
||||||
DatabaseFactory* m_database;
|
DatabaseFactory* m_database;
|
||||||
DownloadManager* m_downloadManager;
|
DownloadManager* m_downloadManager;
|
||||||
NotificationFactory* m_notifications;
|
NotificationFactory* m_notifications;
|
||||||
|
ToastNotificationsManager* m_toastNotifications;
|
||||||
NodeJs* m_nodejs;
|
NodeJs* m_nodejs;
|
||||||
QThreadPool* m_workHorsePool;
|
QThreadPool* m_workHorsePool;
|
||||||
bool m_shouldRestart;
|
bool m_shouldRestart;
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
class Settings;
|
class Settings;
|
||||||
|
|
||||||
class NotificationFactory : public QObject {
|
class NotificationFactory : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit NotificationFactory(QObject* parent = nullptr);
|
explicit NotificationFactory(QObject* parent = nullptr);
|
||||||
|
@ -26,7 +26,6 @@ class NotificationFactory : public QObject {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<Notification> m_notifications = {};
|
QList<Notification> m_notifications = {};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NOTIFICATIONFACTORY_H
|
#endif // NOTIFICATIONFACTORY_H
|
||||||
|
|
|
@ -60,6 +60,14 @@ QList<QAction*> SearchsNode::contextMenuFeedsList() {
|
||||||
return QList<QAction*>{m_actProbeNew};
|
return QList<QAction*>{m_actProbeNew};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SearchsNode::countOfUnreadMessages() const {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SearchsNode::countOfAllMessages() const {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
void SearchsNode::createProbe() {
|
void SearchsNode::createProbe() {
|
||||||
FormAddEditProbe frm(qApp->mainFormWidget());
|
FormAddEditProbe frm(qApp->mainFormWidget());
|
||||||
Search* new_prb = frm.execForAdd();
|
Search* new_prb = frm.execForAdd();
|
||||||
|
|
|
@ -19,6 +19,9 @@ class SearchsNode : public RootItem {
|
||||||
virtual QList<Message> undeletedMessages() const;
|
virtual QList<Message> undeletedMessages() const;
|
||||||
virtual QList<QAction*> contextMenuFeedsList();
|
virtual QList<QAction*> contextMenuFeedsList();
|
||||||
|
|
||||||
|
virtual int countOfUnreadMessages() const;
|
||||||
|
virtual int countOfAllMessages() const;
|
||||||
|
|
||||||
Search* probeById(const QString& custom_id);
|
Search* probeById(const QString& custom_id);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
Loading…
Add table
Reference in a new issue