Some work on notifications.

This commit is contained in:
Martin Rotter 2015-06-29 18:30:32 +02:00
parent 4b63db95f9
commit a5e1b1b116
12 changed files with 472 additions and 425 deletions

View file

@ -65,8 +65,8 @@ project(rssguard)
set(APP_NAME "RSS Guard") set(APP_NAME "RSS Guard")
set(APP_LOW_NAME "rssguard") set(APP_LOW_NAME "rssguard")
set(APP_VERSION "2.4.1") set(APP_VERSION "2.5.0")
set(FILE_VERSION "2,4,1,0") set(FILE_VERSION "2,5,0,0")
set(APP_AUTHOR "Martin Rotter") set(APP_AUTHOR "Martin Rotter")
set(APP_URL "http://bitbucket.org/skunkos/rssguard") set(APP_URL "http://bitbucket.org/skunkos/rssguard")
set(APP_URL_ISSUES "http://bitbucket.org/skunkos/rssguard/issues") set(APP_URL_ISSUES "http://bitbucket.org/skunkos/rssguard/issues")

View file

@ -1,4 +1,19 @@
<body> <body>
<center><h2>2.5.0</h2></center>
Added:
<ul>
<li>Fancy & modern popup notifications (turned on by default).</li>
</ul>
<hr/>
<center><h2>2.4.2</h2></center>
Fixed:
<ul>
<li>Icon cache is now automatically cleared after most of application is loaded. This should save some memory.</li>
</ul>
<hr/>
<center><h2>2.4.1</h2></center> <center><h2>2.4.1</h2></center>
Added: Added:
<ul> <ul>

View file

@ -80,7 +80,7 @@ FormMain::FormMain(QWidget *parent, Qt::WindowFlags f)
// Initialize the web factory. // Initialize the web factory.
WebFactory::instance()->loadState(); WebFactory::instance()->loadState();
(new Notification())->notify("abcd abcd abcd abcd abcd abcd \naaa\n\n\nabcd abcd abcd abcd abcd", "def def def def def"); (new Notification())->notify("abcd abcd abcd abcd abcd abcd \naaa\n\n\nabcd abcd abcd abcd abcd", "def def def def def", qApp->icons()->fromTheme("item-update-all"));
} }
FormMain::~FormMain() { FormMain::~FormMain() {

View file

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>979</width> <width>1296</width>
<height>600</height> <height>677</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -47,7 +47,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>979</width> <width>1296</width>
<height>21</height> <height>21</height>
</rect> </rect>
</property> </property>

View file

@ -706,18 +706,25 @@ void FormSettings::loadInterface() {
// Load settings of tray icon. // Load settings of tray icon.
if (SystemTrayIcon::isSystemTrayAvailable()) { if (SystemTrayIcon::isSystemTrayAvailable()) {
m_ui->m_radioTrayOff->setChecked(!settings->value(GROUP(GUI), SETTING(GUI::UseTrayIcon)).toBool()); m_ui->m_grpTray->setChecked(settings->value(GROUP(GUI), SETTING(GUI::UseTrayIcon)).toBool());
} }
// Tray icon is not supported on this machine. // Tray icon is not supported on this machine.
else { else {
m_ui->m_radioTrayOff->setText(tr("Disable (Tray icon is not available.)")); m_ui->m_grpTray->setTitle(m_ui->m_grpTray->title() + QL1C(' ') + tr("(Tray icon is not available.)"));
m_ui->m_radioTrayOff->setChecked(true); m_ui->m_grpTray->setChecked(false);
m_ui->m_grpTray->setDisabled(true);
} }
m_ui->m_checkHidden->setChecked(settings->value(GROUP(GUI), SETTING(GUI::MainWindowStartsHidden)).toBool()); m_ui->m_checkHidden->setChecked(settings->value(GROUP(GUI), SETTING(GUI::MainWindowStartsHidden)).toBool());
m_ui->m_checkHideWhenMinimized->setChecked(settings->value(GROUP(GUI), SETTING(GUI::HideMainWindowWhenMinimized)).toBool()); m_ui->m_checkHideWhenMinimized->setChecked(settings->value(GROUP(GUI), SETTING(GUI::HideMainWindowWhenMinimized)).toBool());
// Load fancy notification settings.
m_ui->m_grpNotifications->setChecked(settings->value(GROUP(GUI), SETTING(GUI::UseFancyNotifications)).toBool());
m_ui->m_cmbNotificationPosition->addItem(tr("Bottom-left corner"), Qt::BottomLeftCorner);
m_ui->m_cmbNotificationPosition->addItem(tr("Top-left corner"), Qt::TopLeftCorner);
m_ui->m_cmbNotificationPosition->addItem(tr("Bottom-right corner"), Qt::BottomRightCorner);
m_ui->m_cmbNotificationPosition->addItem(tr("Top-right corner"), Qt::TopRightCorner);
m_ui->m_cmbNotificationPosition->setCurrentIndex(m_ui->m_cmbNotificationPosition->findData(static_cast<Qt::Corner>(settings->value(GROUP(GUI), SETTING(GUI::FancyNotificationsPosition)).toInt())));
// Load settings of icon theme. // Load settings of icon theme.
QString current_theme = qApp->icons()->currentIconTheme(); QString current_theme = qApp->icons()->currentIconTheme();
@ -804,9 +811,9 @@ void FormSettings::saveInterface() {
// Save tray icon. // Save tray icon.
if (SystemTrayIcon::isSystemTrayAvailable()) { if (SystemTrayIcon::isSystemTrayAvailable()) {
settings->setValue(GROUP(GUI), GUI::UseTrayIcon, m_ui->m_radioTrayOn->isChecked()); settings->setValue(GROUP(GUI), GUI::UseTrayIcon, m_ui->m_grpTray->isChecked());
if (m_ui->m_radioTrayOn->isChecked()) { if (m_ui->m_grpTray->isChecked()) {
qApp->showTrayIcon(); qApp->showTrayIcon();
} }
else { else {
@ -817,6 +824,10 @@ void FormSettings::saveInterface() {
settings->setValue(GROUP(GUI), GUI::MainWindowStartsHidden, m_ui->m_checkHidden->isChecked()); settings->setValue(GROUP(GUI), GUI::MainWindowStartsHidden, m_ui->m_checkHidden->isChecked());
settings->setValue(GROUP(GUI), GUI::HideMainWindowWhenMinimized, m_ui->m_checkHideWhenMinimized->isChecked()); settings->setValue(GROUP(GUI), GUI::HideMainWindowWhenMinimized, m_ui->m_checkHideWhenMinimized->isChecked());
// Save notifications.
settings->setValue(GROUP(GUI), GUI::UseFancyNotifications, m_ui->m_grpNotifications->isChecked());
settings->setValue(GROUP(GUI), GUI::FancyNotificationsPosition, static_cast<Qt::Corner>(m_ui->m_cmbNotificationPosition->itemData(m_ui->m_cmbNotificationPosition->currentIndex()).toInt()));
// Save selected icon theme. // Save selected icon theme.
QString selected_icon_theme = m_ui->m_cmbIconTheme->itemData(m_ui->m_cmbIconTheme->currentIndex()).toString(); QString selected_icon_theme = m_ui->m_cmbIconTheme->itemData(m_ui->m_cmbIconTheme->currentIndex()).toString();
QString original_icon_theme = qApp->icons()->currentIconTheme(); QString original_icon_theme = qApp->icons()->currentIconTheme();

View file

@ -6,7 +6,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>990</width> <width>1032</width>
<height>498</height> <height>498</height>
</rect> </rect>
</property> </property>
@ -88,7 +88,7 @@
<item row="0" column="1"> <item row="0" column="1">
<widget class="QStackedWidget" name="m_stackedSettings"> <widget class="QStackedWidget" name="m_stackedSettings">
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>3</number>
</property> </property>
<widget class="QWidget" name="m_pageGeneral"> <widget class="QWidget" name="m_pageGeneral">
<layout class="QFormLayout" name="formLayout_5"> <layout class="QFormLayout" name="formLayout_5">
@ -419,8 +419,8 @@ MySQL backend will automatically use database with name &quot;rssguard&quot;. Do
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>740</width> <width>100</width>
<height>451</height> <height>30</height>
</rect> </rect>
</property> </property>
<layout class="QHBoxLayout" name="horizontalLayout_4"> <layout class="QHBoxLayout" name="horizontalLayout_4">
@ -465,7 +465,7 @@ MySQL backend will automatically use database with name &quot;rssguard&quot;. Do
<enum>QTabWidget::North</enum> <enum>QTabWidget::North</enum>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>1</number>
</property> </property>
<widget class="QWidget" name="m_tabIconSkin"> <widget class="QWidget" name="m_tabIconSkin">
<attribute name="title"> <attribute name="title">
@ -497,8 +497,8 @@ MySQL backend will automatically use database with name &quot;rssguard&quot;. Do
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>734</width> <width>208</width>
<height>425</height> <height>238</height>
</rect> </rect>
</property> </property>
<layout class="QFormLayout" name="formLayout"> <layout class="QFormLayout" name="formLayout">
@ -608,46 +608,54 @@ MySQL backend will automatically use database with name &quot;rssguard&quot;. Do
<string>Tray area &amp;&amp; notifications</string> <string>Tray area &amp;&amp; notifications</string>
</attribute> </attribute>
<layout class="QFormLayout" name="formLayout_3"> <layout class="QFormLayout" name="formLayout_3">
<item row="0" column="0" colspan="2"> <item row="1" column="0" colspan="2">
<widget class="QGroupBox" name="m_grpTray"> <widget class="QGroupBox" name="m_grpTray">
<property name="title"> <property name="title">
<string>Tray icon</string> <string>Tray icon</string>
</property> </property>
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QFormLayout" name="formLayout_2"> <layout class="QFormLayout" name="formLayout_2">
<property name="fieldGrowthPolicy"> <property name="fieldGrowthPolicy">
<enum>QFormLayout::ExpandingFieldsGrow</enum> <enum>QFormLayout::ExpandingFieldsGrow</enum>
</property> </property>
<item row="0" column="0" colspan="2"> <item row="0" column="0">
<widget class="QRadioButton" name="m_radioTrayOff">
<property name="text">
<string>Disable</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="m_checkHideWhenMinimized"> <widget class="QCheckBox" name="m_checkHideWhenMinimized">
<property name="text"> <property name="text">
<string>Hide main window when it is minimized</string> <string>Hide main window when it is minimized</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0" colspan="2"> <item row="1" column="0" colspan="2">
<widget class="QCheckBox" name="m_checkHidden"> <widget class="QCheckBox" name="m_checkHidden">
<property name="text"> <property name="text">
<string>Start application hidden</string> <string>Start application hidden</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0" colspan="2"> </layout>
<widget class="QRadioButton" name="m_radioTrayOn"> </widget>
<property name="text"> </item>
<string>Enable</string> <item row="0" column="0" colspan="2">
<widget class="QGroupBox" name="m_grpNotifications">
<property name="title">
<string>Fancy &amp;&amp; modern popup notifications</string>
</property> </property>
<property name="checked"> <property name="checkable">
<bool>true</bool> <bool>true</bool>
</property> </property>
<layout class="QFormLayout" name="formLayout_23">
<item row="0" column="0">
<widget class="QLabel" name="m_lblNotificationPosition">
<property name="text">
<string>Notification position</string>
</property>
</widget> </widget>
</item> </item>
<item row="0" column="1">
<widget class="QComboBox" name="m_cmbNotificationPosition"/>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
@ -1564,10 +1572,8 @@ MySQL backend will automatically use database with name &quot;rssguard&quot;. Do
<tabstop>m_scrollIconSkins</tabstop> <tabstop>m_scrollIconSkins</tabstop>
<tabstop>m_cmbIconTheme</tabstop> <tabstop>m_cmbIconTheme</tabstop>
<tabstop>m_treeSkins</tabstop> <tabstop>m_treeSkins</tabstop>
<tabstop>m_radioTrayOff</tabstop>
<tabstop>m_checkHideWhenMinimized</tabstop> <tabstop>m_checkHideWhenMinimized</tabstop>
<tabstop>m_checkHidden</tabstop> <tabstop>m_checkHidden</tabstop>
<tabstop>m_radioTrayOn</tabstop>
<tabstop>m_checkNewTabDoubleClick</tabstop> <tabstop>m_checkNewTabDoubleClick</tabstop>
<tabstop>m_hideTabBarIfOneTabVisible</tabstop> <tabstop>m_hideTabBarIfOneTabVisible</tabstop>
<tabstop>m_checkCloseTabsDoubleClick</tabstop> <tabstop>m_checkCloseTabsDoubleClick</tabstop>
@ -1642,22 +1648,6 @@ MySQL backend will automatically use database with name &quot;rssguard&quot;. Do
</hint> </hint>
</hints> </hints>
</connection> </connection>
<connection>
<sender>m_radioTrayOn</sender>
<signal>toggled(bool)</signal>
<receiver>m_checkHidden</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>508</x>
<y>102</y>
</hint>
<hint type="destinationlabel">
<x>508</x>
<y>151</y>
</hint>
</hints>
</connection>
<connection> <connection>
<sender>m_checkAutoUpdate</sender> <sender>m_checkAutoUpdate</sender>
<signal>toggled(bool)</signal> <signal>toggled(bool)</signal>
@ -1674,22 +1664,6 @@ MySQL backend will automatically use database with name &quot;rssguard&quot;. Do
</hint> </hint>
</hints> </hints>
</connection> </connection>
<connection>
<sender>m_radioTrayOn</sender>
<signal>toggled(bool)</signal>
<receiver>m_checkHideWhenMinimized</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>515</x>
<y>94</y>
</hint>
<hint type="destinationlabel">
<x>357</x>
<y>117</y>
</hint>
</hints>
</connection>
<connection> <connection>
<sender>m_checkMessagesDateTimeFormat</sender> <sender>m_checkMessagesDateTimeFormat</sender>
<signal>toggled(bool)</signal> <signal>toggled(bool)</signal>
@ -1722,5 +1696,37 @@ MySQL backend will automatically use database with name &quot;rssguard&quot;. Do
</hint> </hint>
</hints> </hints>
</connection> </connection>
<connection>
<sender>m_grpNotifications</sender>
<signal>toggled(bool)</signal>
<receiver>m_lblNotificationPosition</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>625</x>
<y>77</y>
</hint>
<hint type="destinationlabel">
<x>326</x>
<y>84</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_grpNotifications</sender>
<signal>toggled(bool)</signal>
<receiver>m_cmbNotificationPosition</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>625</x>
<y>77</y>
</hint>
<hint type="destinationlabel">
<x>696</x>
<y>84</y>
</hint>
</hints>
</connection>
</connections> </connections>
</ui> </ui>

View file

@ -19,6 +19,9 @@
#include "gui/messagebox.h" #include "gui/messagebox.h"
#include "definitions/definitions.h" #include "definitions/definitions.h"
#include "miscellaneous/application.h"
#include "miscellaneous/settings.h"
#include "miscellaneous/textfactory.h"
#include <QApplication> #include <QApplication>
#include <QDesktopWidget> #include <QDesktopWidget>
@ -40,6 +43,10 @@ Notification::Notification() : QWidget(0), m_title(QString()), m_text(QString())
Notification::~Notification() { Notification::~Notification() {
} }
bool Notification::areNotificationsActivated() {
return qApp->settings()->value(GROUP(GUI), SETTING(GUI::UseFancyNotifications)).toBool();
}
void Notification::notify(const QString &text, const QString &title, const QIcon &icon) { void Notification::notify(const QString &text, const QString &title, const QIcon &icon) {
hide(); hide();
@ -61,12 +68,13 @@ void Notification::notify(const QString &text, const QString &title, QSystemTray
void Notification::updateGeometries() { void Notification::updateGeometries() {
// Calculate width and height of notification with given icon and text. // Calculate width and height of notification with given icon and text.
m_width = m_padding + m_width = m_padding +
m_icon.width() + m_padding + /* contents */ qMax(stringWidth(m_title), stringWidth(m_text)) + m_icon.width() + m_padding + /* contents */ qMax(TextFactory::stringWidth(m_title, fontMetrics()),
TextFactory::stringWidth(m_text, fontMetrics())) +
m_padding; m_padding;
m_height = m_padding + m_height = m_padding +
/* contents */ /* contents */
qMax(m_icon.height(), qMax(m_icon.height(),
stringHeight(m_title) + m_padding + stringHeight(m_text)) + TextFactory::stringHeight(m_title, fontMetrics()) + m_padding + TextFactory::stringHeight(m_text, fontMetrics())) +
m_padding; m_padding;
// Calculate real position. // Calculate real position.
@ -130,7 +138,7 @@ void Notification::paintEvent(QPaintEvent *event) {
painter.setPen(Qt::black); painter.setPen(Qt::black);
// Needed heighs/widths. // Needed heighs/widths.
int title_height = stringHeight(m_title); int title_height = TextFactory::stringHeight(m_title, fontMetrics());
int remaining_width = width() - m_padding - m_icon.width() - m_padding /* - here comes contents */ - m_padding; int remaining_width = width() - m_padding - m_icon.width() - m_padding /* - here comes contents */ - m_padding;
int remaining_height = height() - m_padding - title_height - m_padding /* - here comes contents */ - m_padding; int remaining_height = height() - m_padding - title_height - m_padding /* - here comes contents */ - m_padding;
@ -163,29 +171,8 @@ void Notification::leaveEvent(QEvent *event) {
repaint(); repaint();
} }
int Notification::stringHeight(const QString &string) {
int count_lines = string.split(QL1C('\n')).size();
return fontMetrics().height() * count_lines;
}
int Notification::stringWidth(const QString &string) {
QStringList lines = string.split(QL1C('\n'));
int width = 0;
foreach (const QString &line, lines) {
int line_width = fontMetrics().width(line);
if (line_width > width) {
width = line_width;
}
}
return width;
}
void Notification::loadSettings() { void Notification::loadSettings() {
// TODO: načist z nastaveni. m_position = static_cast<Qt::Corner>(qApp->settings()->value(GROUP(GUI), SETTING(GUI::FancyNotificationsPosition)).toInt());
m_position = Qt::BottomRightCorner;
} }
void Notification::setupWidget() { void Notification::setupWidget() {
@ -220,11 +207,4 @@ void Notification::setupWidget() {
// Window will be meant to be on top, but should not steal focus. // Window will be meant to be on top, but should not steal focus.
setFocusPolicy(Qt::NoFocus); setFocusPolicy(Qt::NoFocus);
// TODO: pokracovat
// https://github.com/binaryking/QNotify/blob/master/QNotify.cpp
// http://stackoverflow.com/questions/5823700/notification-window-in-mac-with-or-without-qt
// quiterss
// a odkazy z issue
// promyslet esli tam dat jen ciste label a ikonu, nebo i seznam nejnovesich zprav atp.
} }

View file

@ -31,6 +31,8 @@ class Notification : public QWidget {
explicit Notification(); explicit Notification();
virtual ~Notification(); virtual ~Notification();
inline static bool areNotificationsActivated();
public slots: public slots:
void notify(const QString &text, const QString &title, const QIcon &icon); void notify(const QString &text, const QString &title, const QIcon &icon);
void notify(const QString &text, const QString &title, QSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::Information); void notify(const QString &text, const QString &title, QSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::Information);
@ -42,9 +44,6 @@ class Notification : public QWidget {
void leaveEvent(QEvent *event); void leaveEvent(QEvent *event);
private: private:
int stringHeight(const QString &string);
int stringWidth(const QString &string);
void loadSettings(); void loadSettings();
void setupWidget(); void setupWidget();
void updateGeometries(); void updateGeometries();

View file

@ -105,6 +105,12 @@ DVALUE(bool) GUI::HideMainWindowWhenMinimizedDef = false;
DKEY GUI::UseTrayIcon = "use_tray_icon"; DKEY GUI::UseTrayIcon = "use_tray_icon";
DVALUE(bool) GUI::UseTrayIconDef = true; DVALUE(bool) GUI::UseTrayIconDef = true;
DKEY GUI::UseFancyNotifications = "use_fancy_notifications";
DVALUE(bool) GUI::UseFancyNotificationsDef = true;
DKEY GUI::FancyNotificationsPosition = "fancy_notifications_position";
DVALUE(Qt::Corner) GUI::FancyNotificationsPositionDef = Qt::BottomRightCorner;
DKEY GUI::TabCloseMiddleClick = "tab_close_mid_button"; DKEY GUI::TabCloseMiddleClick = "tab_close_mid_button";
DVALUE(bool) GUI::TabCloseMiddleClickDef = true; DVALUE(bool) GUI::TabCloseMiddleClickDef = true;

View file

@ -117,6 +117,12 @@ namespace GUI {
KEY UseTrayIcon; KEY UseTrayIcon;
VALUE(bool) UseTrayIconDef; VALUE(bool) UseTrayIconDef;
KEY UseFancyNotifications;
VALUE(bool) UseFancyNotificationsDef;
KEY FancyNotificationsPosition;
VALUE(Qt::Corner) FancyNotificationsPositionDef;
KEY TabCloseMiddleClick; KEY TabCloseMiddleClick;
VALUE(bool) TabCloseMiddleClickDef; VALUE(bool) TabCloseMiddleClickDef;

View file

@ -27,6 +27,26 @@
TextFactory::TextFactory() { TextFactory::TextFactory() {
} }
int TextFactory::stringHeight(const QString &string, const QFontMetrics &metrics) {
int count_lines = string.split(QL1C('\n')).size();
return metrics.height() * count_lines;
}
int TextFactory::stringWidth(const QString &string, const QFontMetrics &metrics) {
QStringList lines = string.split(QL1C('\n'));
int width = 0;
foreach (const QString &line, lines) {
int line_width = metrics.width(line);
if (line_width > width) {
width = line_width;
}
}
return width;
}
QDateTime TextFactory::parseDateTime(const QString &date_time) { QDateTime TextFactory::parseDateTime(const QString &date_time) {
QString input_date = date_time.simplified(); QString input_date = date_time.simplified();
QDateTime dt; QDateTime dt;

View file

@ -21,6 +21,7 @@
#include "definitions/definitions.h" #include "definitions/definitions.h"
#include <QDateTime> #include <QDateTime>
#include <QFontMetrics>
class TextFactory { class TextFactory {
@ -34,6 +35,9 @@ class TextFactory {
return lhs.toLower() < rhs.toLower(); return lhs.toLower() < rhs.toLower();
} }
static int stringHeight(const QString &string, const QFontMetrics &metrics);
static int stringWidth(const QString &string, const QFontMetrics &metrics);
// Tries to parse input textual date/time representation. // Tries to parse input textual date/time representation.
// Returns invalid date/time if processing fails. // Returns invalid date/time if processing fails.
// NOTE: This method tries to always return time in UTC+00:00. // NOTE: This method tries to always return time in UTC+00:00.