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_LOW_NAME "rssguard")
set(APP_VERSION "2.4.1")
set(FILE_VERSION "2,4,1,0")
set(APP_VERSION "2.5.0")
set(FILE_VERSION "2,5,0,0")
set(APP_AUTHOR "Martin Rotter")
set(APP_URL "http://bitbucket.org/skunkos/rssguard")
set(APP_URL_ISSUES "http://bitbucket.org/skunkos/rssguard/issues")

View file

@ -1,4 +1,19 @@
<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>
Added:
<ul>

View file

@ -80,7 +80,7 @@ FormMain::FormMain(QWidget *parent, Qt::WindowFlags f)
// Initialize the web factory.
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() {

View file

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

View file

@ -706,18 +706,25 @@ void FormSettings::loadInterface() {
// Load settings of tray icon.
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.
else {
m_ui->m_radioTrayOff->setText(tr("Disable (Tray icon is not available.)"));
m_ui->m_radioTrayOff->setChecked(true);
m_ui->m_grpTray->setDisabled(true);
m_ui->m_grpTray->setTitle(m_ui->m_grpTray->title() + QL1C(' ') + tr("(Tray icon is not available.)"));
m_ui->m_grpTray->setChecked(false);
}
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());
// 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.
QString current_theme = qApp->icons()->currentIconTheme();
@ -804,9 +811,9 @@ void FormSettings::saveInterface() {
// Save tray icon.
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();
}
else {
@ -817,6 +824,10 @@ void FormSettings::saveInterface() {
settings->setValue(GROUP(GUI), GUI::MainWindowStartsHidden, m_ui->m_checkHidden->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.
QString selected_icon_theme = m_ui->m_cmbIconTheme->itemData(m_ui->m_cmbIconTheme->currentIndex()).toString();
QString original_icon_theme = qApp->icons()->currentIconTheme();

View file

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>990</width>
<width>1032</width>
<height>498</height>
</rect>
</property>
@ -88,7 +88,7 @@
<item row="0" column="1">
<widget class="QStackedWidget" name="m_stackedSettings">
<property name="currentIndex">
<number>0</number>
<number>3</number>
</property>
<widget class="QWidget" name="m_pageGeneral">
<layout class="QFormLayout" name="formLayout_5">
@ -419,8 +419,8 @@ MySQL backend will automatically use database with name &quot;rssguard&quot;. Do
<rect>
<x>0</x>
<y>0</y>
<width>740</width>
<height>451</height>
<width>100</width>
<height>30</height>
</rect>
</property>
<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>
</property>
<property name="currentIndex">
<number>0</number>
<number>1</number>
</property>
<widget class="QWidget" name="m_tabIconSkin">
<attribute name="title">
@ -497,8 +497,8 @@ MySQL backend will automatically use database with name &quot;rssguard&quot;. Do
<rect>
<x>0</x>
<y>0</y>
<width>734</width>
<height>425</height>
<width>208</width>
<height>238</height>
</rect>
</property>
<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>
</attribute>
<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">
<property name="title">
<string>Tray icon</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QFormLayout" name="formLayout_2">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::ExpandingFieldsGrow</enum>
</property>
<item row="0" column="0" colspan="2">
<widget class="QRadioButton" name="m_radioTrayOff">
<property name="text">
<string>Disable</string>
</property>
</widget>
</item>
<item row="2" column="0">
<item row="0" column="0">
<widget class="QCheckBox" name="m_checkHideWhenMinimized">
<property name="text">
<string>Hide main window when it is minimized</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<item row="1" column="0" colspan="2">
<widget class="QCheckBox" name="m_checkHidden">
<property name="text">
<string>Start application hidden</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QRadioButton" name="m_radioTrayOn">
<property name="text">
<string>Enable</string>
</layout>
</widget>
</item>
<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 name="checked">
<property name="checkable">
<bool>true</bool>
</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>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="m_cmbNotificationPosition"/>
</item>
</layout>
</widget>
</item>
@ -1564,10 +1572,8 @@ MySQL backend will automatically use database with name &quot;rssguard&quot;. Do
<tabstop>m_scrollIconSkins</tabstop>
<tabstop>m_cmbIconTheme</tabstop>
<tabstop>m_treeSkins</tabstop>
<tabstop>m_radioTrayOff</tabstop>
<tabstop>m_checkHideWhenMinimized</tabstop>
<tabstop>m_checkHidden</tabstop>
<tabstop>m_radioTrayOn</tabstop>
<tabstop>m_checkNewTabDoubleClick</tabstop>
<tabstop>m_hideTabBarIfOneTabVisible</tabstop>
<tabstop>m_checkCloseTabsDoubleClick</tabstop>
@ -1642,22 +1648,6 @@ MySQL backend will automatically use database with name &quot;rssguard&quot;. Do
</hint>
</hints>
</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>
<sender>m_checkAutoUpdate</sender>
<signal>toggled(bool)</signal>
@ -1674,22 +1664,6 @@ MySQL backend will automatically use database with name &quot;rssguard&quot;. Do
</hint>
</hints>
</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>
<sender>m_checkMessagesDateTimeFormat</sender>
<signal>toggled(bool)</signal>
@ -1722,5 +1696,37 @@ MySQL backend will automatically use database with name &quot;rssguard&quot;. Do
</hint>
</hints>
</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>
</ui>

View file

@ -19,6 +19,9 @@
#include "gui/messagebox.h"
#include "definitions/definitions.h"
#include "miscellaneous/application.h"
#include "miscellaneous/settings.h"
#include "miscellaneous/textfactory.h"
#include <QApplication>
#include <QDesktopWidget>
@ -40,6 +43,10 @@ Notification::Notification() : QWidget(0), m_title(QString()), m_text(QString())
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) {
hide();
@ -61,12 +68,13 @@ void Notification::notify(const QString &text, const QString &title, QSystemTray
void Notification::updateGeometries() {
// Calculate width and height of notification with given icon and text.
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_height = m_padding +
/* contents */
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;
// Calculate real position.
@ -130,7 +138,7 @@ void Notification::paintEvent(QPaintEvent *event) {
painter.setPen(Qt::black);
// 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_height = height() - m_padding - title_height - m_padding /* - here comes contents */ - m_padding;
@ -163,29 +171,8 @@ void Notification::leaveEvent(QEvent *event) {
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() {
// TODO: načist z nastaveni.
m_position = Qt::BottomRightCorner;
m_position = static_cast<Qt::Corner>(qApp->settings()->value(GROUP(GUI), SETTING(GUI::FancyNotificationsPosition)).toInt());
}
void Notification::setupWidget() {
@ -220,11 +207,4 @@ void Notification::setupWidget() {
// Window will be meant to be on top, but should not steal focus.
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();
virtual ~Notification();
inline static bool areNotificationsActivated();
public slots:
void notify(const QString &text, const QString &title, const QIcon &icon);
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);
private:
int stringHeight(const QString &string);
int stringWidth(const QString &string);
void loadSettings();
void setupWidget();
void updateGeometries();

View file

@ -105,6 +105,12 @@ DVALUE(bool) GUI::HideMainWindowWhenMinimizedDef = false;
DKEY GUI::UseTrayIcon = "use_tray_icon";
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";
DVALUE(bool) GUI::TabCloseMiddleClickDef = true;

View file

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

View file

@ -27,6 +27,26 @@
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) {
QString input_date = date_time.simplified();
QDateTime dt;

View file

@ -21,6 +21,7 @@
#include "definitions/definitions.h"
#include <QDateTime>
#include <QFontMetrics>
class TextFactory {
@ -34,6 +35,9 @@ class TextFactory {
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.
// Returns invalid date/time if processing fails.
// NOTE: This method tries to always return time in UTC+00:00.