Uncrustify reformat.

This commit is contained in:
Martin Rotter 2017-09-19 10:18:21 +02:00
parent dd4a96f51f
commit 0fe6b3e686
297 changed files with 21045 additions and 20234 deletions

View file

@ -1,27 +0,0 @@
--style=java
--indent=spaces=2
--indent-classes
--indent-namespaces
--indent-switches
--indent-labels
--indent-preproc-define
--indent-col1-comments
--max-continuation-indent=100
--break-blocks
--unpad-paren
--pad-oper
--pad-comma
--pad-header
--align-pointer=type
--align-reference=type
--break-closing-braces
--break-one-line-headers
--add-braces
--convert-tabs
--close-templates
--max-code-length=140
--lineend=linux
#--delete-empty-lines
--mode=c
-t -p
-M60Ucv

View file

@ -27,16 +27,14 @@ if [ $# -eq 0 ]; then
usage usage
fi fi
ASTYLE_CMD="astyle" ASTYLE_CMD="uncrustify"
if [[ "$(uname -o)" == "Cygwin" ]]; then if [[ "$(uname -o)" == "Cygwin" ]]; then
ASTYLE_RC="$(cygpath -w $(realpath $(dirname $0)))/.astylerc" ASTYLE_RC="$(cygpath -w $(realpath $(dirname $0)))/uncrustify.cfg"
else else
ASTYLE_RC="$(realpath $(dirname $0))/.astylerc" ASTYLE_RC="$(realpath $(dirname $0))/uncrustify.cfg"
fi fi
ASTYLE_RC="$(cygpath -w $(realpath $(dirname $0)))/.astylerc"
echo "ASTYLE config file: $ASTYLE_RC" echo "ASTYLE config file: $ASTYLE_RC"
# Check all args. # Check all args.
@ -58,11 +56,11 @@ for dir in "$@"; do
-o -name '*.h' \ -o -name '*.h' \
-o -name '*.hh' \ -o -name '*.hh' \
-o -name '*.hpp'); do -o -name '*.hpp'); do
"${ASTYLE_CMD}" --options="$ASTYLE_RC" "${f}" "${ASTYLE_CMD}" -c "$ASTYLE_RC" --replace "${f}"
done done
# Remove backup files. # Remove backup files.
find . -name "*.orig" | xargs --no-run-if-empty rm -v find . -name "*-backup*~*" | xargs --no-run-if-empty rm -v
popd popd
done done

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -17,152 +18,157 @@
#include "core/feeddownloader.h" #include "core/feeddownloader.h"
#include "services/abstract/feed.h"
#include "definitions/definitions.h" #include "definitions/definitions.h"
#include "services/abstract/feed.h"
#include <QThread>
#include <QDebug> #include <QDebug>
#include <QThreadPool>
#include <QMutexLocker> #include <QMutexLocker>
#include <QString> #include <QString>
#include <QThread>
#include <QThreadPool>
FeedDownloader::FeedDownloader(QObject* parent) FeedDownloader::FeedDownloader(QObject* parent)
: QObject(parent), m_feeds(QList<Feed*>()), m_mutex(new QMutex()), m_threadPool(new QThreadPool(this)), : QObject(parent), m_feeds(QList<Feed*>()), m_mutex(new QMutex()), m_threadPool(new QThreadPool(this)),
m_results(FeedDownloadResults()), m_feedsUpdated(0), m_results(FeedDownloadResults()), m_feedsUpdated(0),
m_feedsUpdating(0), m_feedsOriginalCount(0) { m_feedsUpdating(0), m_feedsOriginalCount(0) {
qRegisterMetaType<FeedDownloadResults>("FeedDownloadResults"); qRegisterMetaType<FeedDownloadResults>("FeedDownloadResults");
m_threadPool->setMaxThreadCount(FEED_DOWNLOADER_MAX_THREADS); m_threadPool->setMaxThreadCount(FEED_DOWNLOADER_MAX_THREADS);
} }
FeedDownloader::~FeedDownloader() { FeedDownloader::~FeedDownloader() {
m_mutex->tryLock(); m_mutex->tryLock();
m_mutex->unlock(); m_mutex->unlock();
delete m_mutex; delete m_mutex;
qDebug("Destroying FeedDownloader instance."); qDebug("Destroying FeedDownloader instance.");
} }
bool FeedDownloader::isUpdateRunning() const { bool FeedDownloader::isUpdateRunning() const {
return !m_feeds.isEmpty() || m_feedsUpdating > 0; return !m_feeds.isEmpty() || m_feedsUpdating > 0;
} }
void FeedDownloader::updateAvailableFeeds() { void FeedDownloader::updateAvailableFeeds() {
while (!m_feeds.isEmpty()) { while (!m_feeds.isEmpty()) {
connect(m_feeds.first(), &Feed::messagesObtained, this, &FeedDownloader::oneFeedUpdateFinished, connect(m_feeds.first(), &Feed::messagesObtained, this, &FeedDownloader::oneFeedUpdateFinished,
(Qt::ConnectionType)(Qt::UniqueConnection | Qt::AutoConnection)); (Qt::ConnectionType)(Qt::UniqueConnection | Qt::AutoConnection));
if (m_threadPool->tryStart(m_feeds.first())) { if (m_threadPool->tryStart(m_feeds.first())) {
m_feeds.removeFirst(); m_feeds.removeFirst();
m_feedsUpdating++; m_feedsUpdating++;
} }
else { else {
// We want to start update of some feeds but all working threads are occupied. // We want to start update of some feeds but all working threads are occupied.
break; break;
} }
} }
} }
void FeedDownloader::updateFeeds(const QList<Feed*>& feeds) { void FeedDownloader::updateFeeds(const QList<Feed*>& feeds) {
QMutexLocker locker(m_mutex); QMutexLocker locker(m_mutex);
if (feeds.isEmpty()) { if (feeds.isEmpty()) {
qDebug("No feeds to update in worker thread, aborting update."); qDebug("No feeds to update in worker thread, aborting update.");
finalizeUpdate(); finalizeUpdate();
} }
else { else {
qDebug().nospace() << "Starting feed updates from worker in thread: \'" << QThread::currentThreadId() << "\'."; qDebug().nospace() << "Starting feed updates from worker in thread: \'" << QThread::currentThreadId() << "\'.";
m_feeds = feeds; m_feeds = feeds;
m_feedsOriginalCount = m_feeds.size(); m_feedsOriginalCount = m_feeds.size();
m_results.clear(); m_results.clear();
m_feedsUpdated = m_feedsUpdating = 0; m_feedsUpdated = m_feedsUpdating = 0;
// Job starts now.
emit updateStarted(); // Job starts now.
updateAvailableFeeds(); emit updateStarted();
}
updateAvailableFeeds();
}
} }
void FeedDownloader::stopRunningUpdate() { void FeedDownloader::stopRunningUpdate() {
m_threadPool->clear(); m_threadPool->clear();
m_feeds.clear(); m_feeds.clear();
} }
void FeedDownloader::oneFeedUpdateFinished(const QList<Message>& messages, bool error_during_obtaining) { void FeedDownloader::oneFeedUpdateFinished(const QList<Message>& messages, bool error_during_obtaining) {
QMutexLocker locker(m_mutex); QMutexLocker locker(m_mutex);
m_feedsUpdated++;
m_feedsUpdating--;
Feed* feed = qobject_cast<Feed*>(sender());
disconnect(feed, &Feed::messagesObtained, this, &FeedDownloader::oneFeedUpdateFinished);
// Now, we check if there are any feeds we would like to update too.
updateAvailableFeeds();
// Now make sure, that messages are actually stored to SQL in a locked state.
qDebug().nospace() << "Saving messages of feed "
<< feed->id() << " in thread: \'"
<< QThread::currentThreadId() << "\'.";
int updated_messages = feed->updateMessages(messages, error_during_obtaining);
/* m_feedsUpdated++;
QMetaObject::invokeMethod(feed, "updateMessages", Qt::BlockingQueuedConnection, m_feedsUpdating--;
Q_RETURN_ARG(int, updated_messages), Feed* feed = qobject_cast<Feed*>(sender());
Q_ARG(QList<Message>, messages));
*/
if (updated_messages > 0) { disconnect(feed, &Feed::messagesObtained, this, &FeedDownloader::oneFeedUpdateFinished);
m_results.appendUpdatedFeed(QPair<QString, int>(feed->title(), updated_messages));
}
qDebug("Made progress in feed updates, total feeds count %d/%d (id of feed is %d).", m_feedsUpdated, m_feedsOriginalCount, feed->id()); // Now, we check if there are any feeds we would like to update too.
emit updateProgress(feed, m_feedsUpdated, m_feedsOriginalCount); updateAvailableFeeds();
if (m_feeds.isEmpty() && m_feedsUpdating <= 0) { // Now make sure, that messages are actually stored to SQL in a locked state.
finalizeUpdate(); qDebug().nospace() << "Saving messages of feed "
} << feed->id() << " in thread: \'"
<< QThread::currentThreadId() << "\'.";
int updated_messages = feed->updateMessages(messages, error_during_obtaining);
/*
QMetaObject::invokeMethod(feed, "updateMessages", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(int, updated_messages),
Q_ARG(QList<Message>, messages));
*/
if (updated_messages > 0) {
m_results.appendUpdatedFeed(QPair<QString, int>(feed->title(), updated_messages));
}
qDebug("Made progress in feed updates, total feeds count %d/%d (id of feed is %d).", m_feedsUpdated, m_feedsOriginalCount, feed->id());
emit updateProgress(feed, m_feedsUpdated, m_feedsOriginalCount);
if (m_feeds.isEmpty() && m_feedsUpdating <= 0) {
finalizeUpdate();
}
} }
void FeedDownloader::finalizeUpdate() { void FeedDownloader::finalizeUpdate() {
qDebug().nospace() << "Finished feed updates in thread: \'" << QThread::currentThreadId() << "\'."; qDebug().nospace() << "Finished feed updates in thread: \'" << QThread::currentThreadId() << "\'.";
m_results.sort(); m_results.sort();
// Update of feeds has finished.
// NOTE: This means that now "update lock" can be unlocked // Update of feeds has finished.
// and feeds can be added/edited/deleted and application // NOTE: This means that now "update lock" can be unlocked
// can eventually quit. // and feeds can be added/edited/deleted and application
emit updateFinished(m_results); // can eventually quit.
emit updateFinished(m_results);
} }
FeedDownloadResults::FeedDownloadResults() : m_updatedFeeds(QList<QPair<QString, int>>()) { FeedDownloadResults::FeedDownloadResults() : m_updatedFeeds(QList<QPair<QString, int>>()) {}
}
QString FeedDownloadResults::overview(int how_many_feeds) const { QString FeedDownloadResults::overview(int how_many_feeds) const {
QStringList result; QStringList result;
for (int i = 0, number_items_output = qMin(how_many_feeds, m_updatedFeeds.size()); i < number_items_output; i++) { for (int i = 0, number_items_output = qMin(how_many_feeds, m_updatedFeeds.size()); i < number_items_output; i++) {
result.append(m_updatedFeeds.at(i).first + QSL(": ") + QString::number(m_updatedFeeds.at(i).second)); result.append(m_updatedFeeds.at(i).first + QSL(": ") + QString::number(m_updatedFeeds.at(i).second));
} }
QString res_str = result.join(QSL("\n")); QString res_str = result.join(QSL("\n"));
if (m_updatedFeeds.size() > how_many_feeds) { if (m_updatedFeeds.size() > how_many_feeds) {
res_str += QObject::tr("\n\n+ %n other feeds.", 0, m_updatedFeeds.size() - how_many_feeds); res_str += QObject::tr("\n\n+ %n other feeds.", 0, m_updatedFeeds.size() - how_many_feeds);
} }
return res_str; return res_str;
} }
void FeedDownloadResults::appendUpdatedFeed(const QPair<QString, int>& feed) { void FeedDownloadResults::appendUpdatedFeed(const QPair<QString, int>& feed) {
m_updatedFeeds.append(feed); m_updatedFeeds.append(feed);
} }
void FeedDownloadResults::sort() { void FeedDownloadResults::sort() {
qSort(m_updatedFeeds.begin(), m_updatedFeeds.end(), FeedDownloadResults::lessThan); qSort(m_updatedFeeds.begin(), m_updatedFeeds.end(), FeedDownloadResults::lessThan);
} }
bool FeedDownloadResults::lessThan(const QPair<QString, int>& lhs, const QPair<QString, int>& rhs) { bool FeedDownloadResults::lessThan(const QPair<QString, int>& lhs, const QPair<QString, int>& rhs) {
return lhs.second > rhs.second; return lhs.second > rhs.second;
} }
void FeedDownloadResults::clear() { void FeedDownloadResults::clear() {
m_updatedFeeds.clear(); m_updatedFeeds.clear();
} }
QList<QPair<QString, int>> FeedDownloadResults::updatedFeeds() const { QList<QPair<QString, int>> FeedDownloadResults::updatedFeeds() const {
return m_updatedFeeds; return m_updatedFeeds;
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -24,81 +25,83 @@
#include "core/message.h" #include "core/message.h"
class Feed; class Feed;
class QThreadPool; class QThreadPool;
class QMutex; class QMutex;
// Represents results of batch feed updates. // Represents results of batch feed updates.
class FeedDownloadResults { class FeedDownloadResults {
public: public:
explicit FeedDownloadResults(); explicit FeedDownloadResults();
QList<QPair<QString, int>> updatedFeeds() const; QList<QPair<QString, int>> updatedFeeds() const;
QString overview(int how_many_feeds) const; QString overview(int how_many_feeds) const;
void appendUpdatedFeed(const QPair<QString, int>& feed); void appendUpdatedFeed(const QPair<QString, int>& feed);
void sort(); void sort();
void clear(); void clear();
static bool lessThan(const QPair<QString, int>& lhs, const QPair<QString, int>& rhs); static bool lessThan(const QPair<QString, int>& lhs, const QPair<QString, int>& rhs);
private: private:
// QString represents title if the feed, int represents count of newly downloaded messages.
QList<QPair<QString, int>> m_updatedFeeds; // QString represents title if the feed, int represents count of newly downloaded messages.
QList<QPair<QString, int>> m_updatedFeeds;
}; };
// This class offers means to "update" feeds and "special" categories. // This class offers means to "update" feeds and "special" categories.
// NOTE: This class is used within separate thread. // NOTE: This class is used within separate thread.
class FeedDownloader : public QObject { class FeedDownloader : public QObject {
Q_OBJECT Q_OBJECT
public: public:
// Constructors and destructors.
explicit FeedDownloader(QObject* parent = 0);
virtual ~FeedDownloader();
bool isUpdateRunning() const; // Constructors and destructors.
explicit FeedDownloader(QObject* parent = 0);
virtual ~FeedDownloader();
public slots: bool isUpdateRunning() const;
// Performs update of all feeds from the "feeds" parameter.
// New messages are downloaded for each feed and they
// are stored persistently in the database.
// Appropriate signals are emitted.
void updateFeeds(const QList<Feed*>& feeds);
// Stops running update. public slots:
void stopRunningUpdate();
private slots: // Performs update of all feeds from the "feeds" parameter.
void oneFeedUpdateFinished(const QList<Message>& messages, bool error_during_obtaining); // New messages are downloaded for each feed and they
// are stored persistently in the database.
// Appropriate signals are emitted.
void updateFeeds(const QList<Feed*>& feeds);
signals: // Stops running update.
// Emitted if feed updates started. void stopRunningUpdate();
void updateStarted();
// Emitted if all items from update queue are private slots:
// processed. void oneFeedUpdateFinished(const QList<Message>& messages, bool error_during_obtaining);
void updateFinished(FeedDownloadResults updated_feeds);
// Emitted if any item is processed. signals:
// "Current" number indicates count of processed feeds
// and "total" number indicates total number of feeds
// which were in the initial queue.
void updateProgress(const Feed* feed, int current, int total);
private: // Emitted if feed updates started.
void updateAvailableFeeds(); void updateStarted();
void finalizeUpdate();
QList<Feed*> m_feeds; // Emitted if all items from update queue are
QMutex* m_mutex; // processed.
QThreadPool* m_threadPool; void updateFinished(FeedDownloadResults updated_feeds);
FeedDownloadResults m_results;
int m_feedsUpdated; // Emitted if any item is processed.
int m_feedsUpdating; // "Current" number indicates count of processed feeds
int m_feedsOriginalCount; // and "total" number indicates total number of feeds
// which were in the initial queue.
void updateProgress(const Feed* feed, int current, int total);
private:
void updateAvailableFeeds();
void finalizeUpdate();
QList<Feed*> m_feeds;
QMutex* m_mutex;
QThreadPool* m_threadPool;
FeedDownloadResults m_results;
int m_feedsUpdated;
int m_feedsUpdating;
int m_feedsOriginalCount;
}; };
#endif // FEEDDOWNLOADER_H #endif // FEEDDOWNLOADER_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -17,254 +18,256 @@
#include "core/feedsproxymodel.h" #include "core/feedsproxymodel.h"
#include "core/feedsmodel.h"
#include "definitions/definitions.h" #include "definitions/definitions.h"
#include "miscellaneous/application.h" #include "miscellaneous/application.h"
#include "core/feedsmodel.h"
#include "services/abstract/rootitem.h" #include "services/abstract/rootitem.h"
#include <QTimer> #include <QTimer>
FeedsProxyModel::FeedsProxyModel(FeedsModel* source_model, QObject* parent) FeedsProxyModel::FeedsProxyModel(FeedsModel* source_model, QObject* parent)
: QSortFilterProxyModel(parent), m_sourceModel(source_model), m_selectedItem(nullptr), : QSortFilterProxyModel(parent), m_sourceModel(source_model), m_selectedItem(nullptr),
m_showUnreadOnly(false), m_hiddenIndices(QList<QPair<int, QModelIndex>>()) { m_showUnreadOnly(false), m_hiddenIndices(QList<QPair<int, QModelIndex>>()) {
setObjectName(QSL("FeedsProxyModel")); setObjectName(QSL("FeedsProxyModel"));
setSortRole(Qt::EditRole); setSortRole(Qt::EditRole);
setSortCaseSensitivity(Qt::CaseInsensitive); setSortCaseSensitivity(Qt::CaseInsensitive);
setFilterCaseSensitivity(Qt::CaseInsensitive); setFilterCaseSensitivity(Qt::CaseInsensitive);
setFilterKeyColumn(-1); setFilterKeyColumn(-1);
setFilterRole(Qt::EditRole); setFilterRole(Qt::EditRole);
setDynamicSortFilter(true); setDynamicSortFilter(true);
setSourceModel(m_sourceModel); setSourceModel(m_sourceModel);
} }
FeedsProxyModel::~FeedsProxyModel() { FeedsProxyModel::~FeedsProxyModel() {
qDebug("Destroying FeedsProxyModel instance"); qDebug("Destroying FeedsProxyModel instance");
} }
QModelIndexList FeedsProxyModel::match(const QModelIndex& start, int role, const QVariant& value, int hits, Qt::MatchFlags flags) const { QModelIndexList FeedsProxyModel::match(const QModelIndex& start, int role, const QVariant& value, int hits, Qt::MatchFlags flags) const {
QModelIndexList result; QModelIndexList result;
const uint match_type = flags & 0x0F; const uint match_type = flags & 0x0F;
const Qt::CaseSensitivity cs = Qt::CaseInsensitive; const Qt::CaseSensitivity cs = Qt::CaseInsensitive;
const bool recurse = flags & Qt::MatchRecursive; const bool recurse = flags & Qt::MatchRecursive;
const bool wrap = flags & Qt::MatchWrap; const bool wrap = flags & Qt::MatchWrap;
const bool all_hits = (hits == -1); const bool all_hits = (hits == -1);
QString entered_text; QString entered_text;
const QModelIndex p = parent(start); const QModelIndex p = parent(start);
int from = start.row(); int from = start.row();
int to = rowCount(p); int to = rowCount(p);
for (int i = 0; (wrap && i < 2) || (!wrap && i < 1); ++i) { for (int i = 0; (wrap && i < 2) || (!wrap && i < 1); ++i) {
for (int r = from; (r < to) && (all_hits || result.count() < hits); ++r) { for (int r = from; (r < to) && (all_hits || result.count() < hits); ++r) {
QModelIndex idx = index(r, start.column(), p); QModelIndex idx = index(r, start.column(), p);
if (!idx.isValid()) { if (!idx.isValid()) {
continue; continue;
} }
QModelIndex mapped_idx = mapToSource(idx); QModelIndex mapped_idx = mapToSource(idx);
QVariant item_value = m_sourceModel->itemForIndex(mapped_idx)->title(); QVariant item_value = m_sourceModel->itemForIndex(mapped_idx)->title();
// QVariant based matching. // QVariant based matching.
if (match_type == Qt::MatchExactly) { if (match_type == Qt::MatchExactly) {
if (value == item_value) { if (value == item_value) {
result.append(idx); result.append(idx);
} }
} }
// QString based matching.
else {
if (entered_text.isEmpty()) {
entered_text = value.toString();
}
QString item_text = item_value.toString(); // QString based matching.
else {
if (entered_text.isEmpty()) {
entered_text = value.toString();
}
switch (match_type) { QString item_text = item_value.toString();
case Qt::MatchRegExp:
if (QRegExp(entered_text, cs).exactMatch(item_text)) {
result.append(idx);
}
break; switch (match_type) {
case Qt::MatchRegExp:
if (QRegExp(entered_text, cs).exactMatch(item_text)) {
result.append(idx);
}
case Qt::MatchWildcard: break;
if (QRegExp(entered_text, cs, QRegExp::Wildcard).exactMatch(item_text)) {
result.append(idx);
}
break; case Qt::MatchWildcard:
if (QRegExp(entered_text, cs, QRegExp::Wildcard).exactMatch(item_text)) {
result.append(idx);
}
case Qt::MatchStartsWith: break;
if (item_text.startsWith(entered_text, cs)) {
result.append(idx);
}
break; case Qt::MatchStartsWith:
if (item_text.startsWith(entered_text, cs)) {
result.append(idx);
}
case Qt::MatchEndsWith: break;
if (item_text.endsWith(entered_text, cs)) {
result.append(idx);
}
break; case Qt::MatchEndsWith:
if (item_text.endsWith(entered_text, cs)) {
result.append(idx);
}
case Qt::MatchFixedString: break;
if (item_text.compare(entered_text, cs) == 0) {
result.append(idx);
}
break; case Qt::MatchFixedString:
if (item_text.compare(entered_text, cs) == 0) {
result.append(idx);
}
case Qt::MatchContains: break;
default:
if (item_text.contains(entered_text, cs)) {
result.append(idx);
}
break; case Qt::MatchContains:
} default:
} if (item_text.contains(entered_text, cs)) {
result.append(idx);
}
if (recurse && hasChildren(idx)) { break;
result += match(index(0, idx.column(), idx), role, (entered_text.isEmpty() ? value : entered_text), (all_hits ? -1 : hits - result.count()), }
flags); }
}
}
from = 0; if (recurse && hasChildren(idx)) {
to = start.row(); result +=
} match(index(0, idx.column(), idx), role, (entered_text.isEmpty() ? value : entered_text), (all_hits ? -1 : hits - result.count()),
flags);
}
}
return result; from = 0;
to = start.row();
}
return result;
} }
bool FeedsProxyModel::lessThan(const QModelIndex& left, const QModelIndex& right) const { bool FeedsProxyModel::lessThan(const QModelIndex& left, const QModelIndex& right) const {
if (left.isValid() && right.isValid()) { if (left.isValid() && right.isValid()) {
// Make necessary castings. // Make necessary castings.
const RootItem* left_item = m_sourceModel->itemForIndex(left); const RootItem* left_item = m_sourceModel->itemForIndex(left);
const RootItem* right_item = m_sourceModel->itemForIndex(right); const RootItem* right_item = m_sourceModel->itemForIndex(right);
// NOTE: Here we want to accomplish that ALL // NOTE: Here we want to accomplish that ALL
// categories are queued one after another and all // categories are queued one after another and all
// feeds are queued one after another too. // feeds are queued one after another too.
// Moreover, sort everything alphabetically or // Moreover, sort everything alphabetically or
// by item counts, depending on the sort column. // by item counts, depending on the sort column.
if (left_item->kind() == right_item->kind()) { if (left_item->kind() == right_item->kind()) {
// Both items are feeds or both items are categories. // Both items are feeds or both items are categories.
if (left.column() == FDS_MODEL_COUNTS_INDEX) { if (left.column() == FDS_MODEL_COUNTS_INDEX) {
// User wants to sort according to counts. // User wants to sort according to counts.
return left_item->countOfUnreadMessages() < right_item->countOfUnreadMessages(); return left_item->countOfUnreadMessages() < right_item->countOfUnreadMessages();
} }
else { else {
// In other cases, sort by title. // In other cases, sort by title.
return QString::localeAwareCompare(left_item->title(), right_item->title()) < 0; return QString::localeAwareCompare(left_item->title(), right_item->title()) < 0;
} }
} }
else if (left_item->kind() == RootItemKind::Bin) { else if (left_item->kind() == RootItemKind::Bin) {
// Left item is recycle bin. Make sure it is "biggest" item if we have selected ascending order. // Left item is recycle bin. Make sure it is "biggest" item if we have selected ascending order.
return sortOrder() == Qt::DescendingOrder; return sortOrder() == Qt::DescendingOrder;
} }
else if (right_item->kind() == RootItemKind::Bin) { else if (right_item->kind() == RootItemKind::Bin) {
// Right item is recycle bin. Make sure it is "smallest" item if we have selected descending order. // Right item is recycle bin. Make sure it is "smallest" item if we have selected descending order.
return sortOrder() == Qt::AscendingOrder; return sortOrder() == Qt::AscendingOrder;
} }
else if (left_item->kind() == RootItemKind::Feed) { else if (left_item->kind() == RootItemKind::Feed) {
// Left item is feed, right item is category. // Left item is feed, right item is category.
return false; return false;
} }
else { else {
// Left item is category, right item is feed. // Left item is category, right item is feed.
// NOTE: Category is in fact "more" than feed but we consider it to be "less" because it should be "placed" // NOTE: Category is in fact "more" than feed but we consider it to be "less" because it should be "placed"
// above the "smalles" feed when ascending sort is used. // above the "smalles" feed when ascending sort is used.
// NOTE: We need to keep recycle bin in first position. // NOTE: We need to keep recycle bin in first position.
return true; return true;
} }
} }
else { else {
return false; return false;
} }
} }
bool FeedsProxyModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const { bool FeedsProxyModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const {
bool should_show = filterAcceptsRowInternal(source_row, source_parent); bool should_show = filterAcceptsRowInternal(source_row, source_parent);
if (should_show && m_hiddenIndices.contains(QPair<int, QModelIndex>(source_row, source_parent))) { if (should_show && m_hiddenIndices.contains(QPair<int, QModelIndex>(source_row, source_parent))) {
const_cast<FeedsProxyModel*>(this)->m_hiddenIndices.removeAll(QPair<int, QModelIndex>(source_row, source_parent)); const_cast<FeedsProxyModel*>(this)->m_hiddenIndices.removeAll(QPair<int, QModelIndex>(source_row, source_parent));
// Load status.
emit expandAfterFilterIn(m_sourceModel->index(source_row, 0, source_parent));
}
if (!should_show) { // Load status.
const_cast<FeedsProxyModel*>(this)->m_hiddenIndices.append(QPair<int, QModelIndex>(source_row, source_parent)); emit expandAfterFilterIn(m_sourceModel->index(source_row, 0, source_parent));
} }
return should_show; if (!should_show) {
const_cast<FeedsProxyModel*>(this)->m_hiddenIndices.append(QPair<int, QModelIndex>(source_row, source_parent));
}
return should_show;
} }
bool FeedsProxyModel::filterAcceptsRowInternal(int source_row, const QModelIndex& source_parent) const { bool FeedsProxyModel::filterAcceptsRowInternal(int source_row, const QModelIndex& source_parent) const {
if (!m_showUnreadOnly) { if (!m_showUnreadOnly) {
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
} }
const QModelIndex idx = m_sourceModel->index(source_row, 0, source_parent); const QModelIndex idx = m_sourceModel->index(source_row, 0, source_parent);
if (!idx.isValid()) { if (!idx.isValid()) {
return false; return false;
} }
const RootItem* item = m_sourceModel->itemForIndex(idx); const RootItem* item = m_sourceModel->itemForIndex(idx);
if (item->kind() == RootItemKind::Bin || item->kind() == RootItemKind::ServiceRoot) { if (item->kind() == RootItemKind::Bin || item->kind() == RootItemKind::ServiceRoot) {
// Recycle bin is always displayed. // Recycle bin is always displayed.
return true; return true;
} }
else if (item->isParentOf(m_selectedItem)/* || item->isChildOf(m_selectedItem)*/ || m_selectedItem == item) { else if (item->isParentOf(m_selectedItem) /* || item->isChildOf(m_selectedItem)*/ || m_selectedItem == item) {
// Currently selected item and all its parents and children must be displayed. // Currently selected item and all its parents and children must be displayed.
return true; return true;
} }
else { else {
// NOTE: If item has < 0 of unread message it may mean, that the count // NOTE: If item has < 0 of unread message it may mean, that the count
// of unread messages is not (yet) known, display that item too. // of unread messages is not (yet) known, display that item too.
return item->countOfUnreadMessages() != 0; return item->countOfUnreadMessages() != 0;
} }
} }
const RootItem* FeedsProxyModel::selectedItem() const { const RootItem* FeedsProxyModel::selectedItem() const {
return m_selectedItem; return m_selectedItem;
} }
void FeedsProxyModel::setSelectedItem(const RootItem* selected_item) { void FeedsProxyModel::setSelectedItem(const RootItem* selected_item) {
m_selectedItem = selected_item; m_selectedItem = selected_item;
} }
bool FeedsProxyModel::showUnreadOnly() const { bool FeedsProxyModel::showUnreadOnly() const {
return m_showUnreadOnly; return m_showUnreadOnly;
} }
void FeedsProxyModel::invalidateReadFeedsFilter(bool set_new_value, bool show_unread_only) { void FeedsProxyModel::invalidateReadFeedsFilter(bool set_new_value, bool show_unread_only) {
if (set_new_value) { if (set_new_value) {
setShowUnreadOnly(show_unread_only); setShowUnreadOnly(show_unread_only);
} }
QTimer::singleShot(0, this, &FeedsProxyModel::invalidateFilter); QTimer::singleShot(0, this, &FeedsProxyModel::invalidateFilter);
} }
void FeedsProxyModel::setShowUnreadOnly(bool show_unread_only) { void FeedsProxyModel::setShowUnreadOnly(bool show_unread_only) {
m_showUnreadOnly = show_unread_only; m_showUnreadOnly = show_unread_only;
qApp->settings()->setValue(GROUP(Feeds), Feeds::ShowOnlyUnreadFeeds, show_unread_only); qApp->settings()->setValue(GROUP(Feeds), Feeds::ShowOnlyUnreadFeeds, show_unread_only);
} }
QModelIndexList FeedsProxyModel::mapListToSource(const QModelIndexList& indexes) const { QModelIndexList FeedsProxyModel::mapListToSource(const QModelIndexList& indexes) const {
QModelIndexList source_indexes; QModelIndexList source_indexes;
foreach (const QModelIndex& index, indexes) { foreach (const QModelIndex& index, indexes) {
source_indexes << mapToSource(index); source_indexes << mapToSource(index);
} }
return source_indexes; return source_indexes;
} }
void FeedsProxyModel::invalidateFilter() { void FeedsProxyModel::invalidateFilter() {
QSortFilterProxyModel::invalidateFilter(); QSortFilterProxyModel::invalidateFilter();
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -20,51 +21,54 @@
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
class FeedsModel; class FeedsModel;
class RootItem; class RootItem;
class FeedsProxyModel : public QSortFilterProxyModel { class FeedsProxyModel : public QSortFilterProxyModel {
Q_OBJECT Q_OBJECT
public: public:
// Constructors and destructors.
explicit FeedsProxyModel(FeedsModel* source_model, QObject* parent = 0);
virtual ~FeedsProxyModel();
// Returns index list of items which "match" given value. // Constructors and destructors.
// Used for finding items according to entered title text. explicit FeedsProxyModel(FeedsModel* source_model, QObject* parent = 0);
QModelIndexList match(const QModelIndex& start, int role, const QVariant& value, int hits, Qt::MatchFlags flags) const; virtual ~FeedsProxyModel();
// Maps list of indexes. // Returns index list of items which "match" given value.
QModelIndexList mapListToSource(const QModelIndexList& indexes) const; // Used for finding items according to entered title text.
QModelIndexList match(const QModelIndex& start, int role, const QVariant& value, int hits, Qt::MatchFlags flags) const;
bool showUnreadOnly() const; // Maps list of indexes.
void setShowUnreadOnly(bool show_unread_only); QModelIndexList mapListToSource(const QModelIndexList& indexes) const;
const RootItem* selectedItem() const; bool showUnreadOnly() const;
void setSelectedItem(const RootItem* selected_item); void setShowUnreadOnly(bool show_unread_only);
public slots: const RootItem* selectedItem() const;
void invalidateReadFeedsFilter(bool set_new_value = false, bool show_unread_only = false);
private slots: void setSelectedItem(const RootItem* selected_item);
void invalidateFilter();
signals: public slots:
void expandAfterFilterIn(QModelIndex idx) const; void invalidateReadFeedsFilter(bool set_new_value = false, bool show_unread_only = false);
private: private slots:
// Compares two rows of data. void invalidateFilter();
bool lessThan(const QModelIndex& left, const QModelIndex& right) const;
bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const;
bool filterAcceptsRowInternal(int source_row, const QModelIndex& source_parent) const;
// Source model pointer. signals:
FeedsModel* m_sourceModel; void expandAfterFilterIn(QModelIndex idx) const;
const RootItem* m_selectedItem;
bool m_showUnreadOnly; private:
QList<QPair<int, QModelIndex>> m_hiddenIndices;
// Compares two rows of data.
bool lessThan(const QModelIndex& left, const QModelIndex& right) const;
bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const;
bool filterAcceptsRowInternal(int source_row, const QModelIndex& source_parent) const;
// Source model pointer.
FeedsModel* m_sourceModel;
const RootItem* m_selectedItem;
bool m_showUnreadOnly;
QList<QPair<int, QModelIndex>> m_hiddenIndices;
}; };
#endif // FEEDSPROXYMODEL_H #endif // FEEDSPROXYMODEL_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -21,81 +22,81 @@
#include <QVariant> #include <QVariant>
Enclosure::Enclosure(const QString& url, const QString& mime) : m_url(url), m_mimeType(mime) {}
Enclosure::Enclosure(const QString& url, const QString& mime) : m_url(url), m_mimeType(mime) {
}
QList<Enclosure> Enclosures::decodeEnclosuresFromString(const QString& enclosures_data) { QList<Enclosure> Enclosures::decodeEnclosuresFromString(const QString& enclosures_data) {
QList<Enclosure> enclosures; QList<Enclosure> enclosures;
foreach (const QString& single_enclosure, enclosures_data.split(ENCLOSURES_OUTER_SEPARATOR, QString::SkipEmptyParts)) { foreach (const QString& single_enclosure, enclosures_data.split(ENCLOSURES_OUTER_SEPARATOR, QString::SkipEmptyParts)) {
Enclosure enclosure; Enclosure enclosure;
if (single_enclosure.contains(ECNLOSURES_INNER_SEPARATOR)) { if (single_enclosure.contains(ECNLOSURES_INNER_SEPARATOR)) {
QStringList mime_url = single_enclosure.split(ECNLOSURES_INNER_SEPARATOR); QStringList mime_url = single_enclosure.split(ECNLOSURES_INNER_SEPARATOR);
enclosure.m_mimeType = QByteArray::fromBase64(mime_url.at(0).toLocal8Bit());
enclosure.m_url = QByteArray::fromBase64(mime_url.at(1).toLocal8Bit());
}
else {
enclosure.m_url = QByteArray::fromBase64(single_enclosure.toLocal8Bit());
}
enclosures.append(enclosure); enclosure.m_mimeType = QByteArray::fromBase64(mime_url.at(0).toLocal8Bit());
} enclosure.m_url = QByteArray::fromBase64(mime_url.at(1).toLocal8Bit());
}
else {
enclosure.m_url = QByteArray::fromBase64(single_enclosure.toLocal8Bit());
}
return enclosures; enclosures.append(enclosure);
}
return enclosures;
} }
QString Enclosures::encodeEnclosuresToString(const QList<Enclosure>& enclosures) { QString Enclosures::encodeEnclosuresToString(const QList<Enclosure>& enclosures) {
QStringList enclosures_str; QStringList enclosures_str;
foreach (const Enclosure& enclosure, enclosures) { foreach (const Enclosure& enclosure, enclosures) {
if (enclosure.m_mimeType.isEmpty()) { if (enclosure.m_mimeType.isEmpty()) {
enclosures_str.append(enclosure.m_url.toLocal8Bit().toBase64()); enclosures_str.append(enclosure.m_url.toLocal8Bit().toBase64());
} }
else { else {
enclosures_str.append(QString(enclosure.m_mimeType.toLocal8Bit().toBase64()) + enclosures_str.append(QString(enclosure.m_mimeType.toLocal8Bit().toBase64()) +
ECNLOSURES_INNER_SEPARATOR + ECNLOSURES_INNER_SEPARATOR +
enclosure.m_url.toLocal8Bit().toBase64()); enclosure.m_url.toLocal8Bit().toBase64());
} }
} }
return enclosures_str.join(QString(ENCLOSURES_OUTER_SEPARATOR)); return enclosures_str.join(QString(ENCLOSURES_OUTER_SEPARATOR));
} }
Message::Message() { Message::Message() {
m_title = m_url = m_author = m_contents = m_feedId = m_customId = m_customHash = QSL(""); m_title = m_url = m_author = m_contents = m_feedId = m_customId = m_customHash = QSL("");
m_enclosures = QList<Enclosure>(); m_enclosures = QList<Enclosure>();
m_accountId = m_id = 0; m_accountId = m_id = 0;
m_isRead = m_isImportant = false; m_isRead = m_isImportant = false;
} }
Message Message::fromSqlRecord(const QSqlRecord& record, bool* result) { Message Message::fromSqlRecord(const QSqlRecord& record, bool* result) {
if (record.count() != MSG_DB_CUSTOM_HASH_INDEX + 1) { if (record.count() != MSG_DB_CUSTOM_HASH_INDEX + 1) {
if (result != nullptr) { if (result != nullptr) {
*result = false; *result = false;
return Message(); return Message();
} }
} }
Message message; Message message;
message.m_id = record.value(MSG_DB_ID_INDEX).toInt();
message.m_isRead = record.value(MSG_DB_READ_INDEX).toBool();
message.m_isImportant = record.value(MSG_DB_IMPORTANT_INDEX).toBool();
message.m_feedId = record.value(MSG_DB_FEED_CUSTOM_ID_INDEX).toString();
message.m_title = record.value(MSG_DB_TITLE_INDEX).toString();
message.m_url = record.value(MSG_DB_URL_INDEX).toString();
message.m_author = record.value(MSG_DB_AUTHOR_INDEX).toString();
message.m_created = TextFactory::parseDateTime(record.value(MSG_DB_DCREATED_INDEX).value<qint64>());
message.m_contents = record.value(MSG_DB_CONTENTS_INDEX).toString();
message.m_enclosures = Enclosures::decodeEnclosuresFromString(record.value(MSG_DB_ENCLOSURES_INDEX).toString());
message.m_accountId = record.value(MSG_DB_ACCOUNT_ID_INDEX).toInt();
message.m_customId = record.value(MSG_DB_CUSTOM_ID_INDEX).toString();
message.m_customHash = record.value(MSG_DB_CUSTOM_HASH_INDEX).toString();
if (result != nullptr) { message.m_id = record.value(MSG_DB_ID_INDEX).toInt();
*result = true; message.m_isRead = record.value(MSG_DB_READ_INDEX).toBool();
} message.m_isImportant = record.value(MSG_DB_IMPORTANT_INDEX).toBool();
message.m_feedId = record.value(MSG_DB_FEED_CUSTOM_ID_INDEX).toString();
message.m_title = record.value(MSG_DB_TITLE_INDEX).toString();
message.m_url = record.value(MSG_DB_URL_INDEX).toString();
message.m_author = record.value(MSG_DB_AUTHOR_INDEX).toString();
message.m_created = TextFactory::parseDateTime(record.value(MSG_DB_DCREATED_INDEX).value<qint64>());
message.m_contents = record.value(MSG_DB_CONTENTS_INDEX).toString();
message.m_enclosures = Enclosures::decodeEnclosuresFromString(record.value(MSG_DB_ENCLOSURES_INDEX).toString());
message.m_accountId = record.value(MSG_DB_ACCOUNT_ID_INDEX).toInt();
message.m_customId = record.value(MSG_DB_CUSTOM_ID_INDEX).toString();
message.m_customHash = record.value(MSG_DB_CUSTOM_HASH_INDEX).toString();
if (result != nullptr) {
*result = true;
}
return message; return message;
} }
@ -135,10 +136,10 @@ QDataStream& operator>>(QDataStream& in, Message& myObj) {
} }
uint qHash(Message key, uint seed) { uint qHash(Message key, uint seed) {
Q_UNUSED(seed) Q_UNUSED(seed)
return (key.m_accountId * 10000) + key.m_id; return (key.m_accountId * 10000) + key.m_id;
} }
uint qHash(const Message& key) { uint qHash(const Message& key) {
return (key.m_accountId * 10000) + key.m_id; return (key.m_accountId * 10000) + key.m_id;
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -20,64 +21,62 @@
#include "definitions/definitions.h" #include "definitions/definitions.h"
#include <QDateTime>
#include <QStringList>
#include <QSqlRecord>
#include <QDataStream> #include <QDataStream>
#include <QDateTime>
#include <QSqlRecord>
#include <QStringList>
// Represents single enclosure. // Represents single enclosure.
struct Enclosure { struct Enclosure {
public: public:
explicit Enclosure(const QString& url = QString(), const QString& mime = QString()); explicit Enclosure(const QString& url = QString(), const QString& mime = QString());
QString m_url; QString m_url;
QString m_mimeType; QString m_mimeType;
}; };
// Represents single enclosure. // Represents single enclosure.
class Enclosures { class Enclosures {
public: public:
static QList<Enclosure> decodeEnclosuresFromString(const QString& enclosures_data); static QList<Enclosure> decodeEnclosuresFromString(const QString& enclosures_data);
static QString encodeEnclosuresToString(const QList<Enclosure>& enclosures); static QString encodeEnclosuresToString(const QList<Enclosure>& enclosures);
}; };
// Represents single message. // Represents single message.
class Message { class Message {
public: public:
explicit Message(); explicit Message();
// Creates Message from given record, which contains // Creates Message from given record, which contains
// row from query SELECT * FROM Messages WHERE ....; // row from query SELECT * FROM Messages WHERE ....;
static Message fromSqlRecord(const QSqlRecord& record, bool* result = nullptr); static Message fromSqlRecord(const QSqlRecord& record, bool* result = nullptr);
QString m_title;
QString m_url;
QString m_author;
QString m_contents;
QDateTime m_created;
QString m_feedId;
int m_accountId;
int m_id;
QString m_customId;
QString m_customHash;
bool m_isRead;
bool m_isImportant;
QString m_title; QList<Enclosure> m_enclosures;
QString m_url;
QString m_author;
QString m_contents;
QDateTime m_created;
QString m_feedId;
int m_accountId;
int m_id;
QString m_customId;
QString m_customHash;
bool m_isRead; // Is true if "created" date was obtained directly
bool m_isImportant; // from the feed, otherwise is false
bool m_createdFromFeed;
QList<Enclosure> m_enclosures; friend inline bool operator==(const Message& lhs, const Message& rhs) {
return lhs.m_accountId == rhs.m_accountId && lhs.m_id == rhs.m_id;
}
// Is true if "created" date was obtained directly friend inline bool operator!=(const Message& lhs, const Message& rhs) {
// from the feed, otherwise is false return !(lhs == rhs);
bool m_createdFromFeed; }
friend inline bool operator==(const Message& lhs, const Message& rhs) {
return lhs.m_accountId == rhs.m_accountId && lhs.m_id == rhs.m_id;
}
friend inline bool operator!=(const Message& lhs, const Message& rhs) {
return !(lhs == rhs);
}
}; };
// Serialize message state. // Serialize message state.

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -17,519 +18,549 @@
#include "core/messagesmodel.h" #include "core/messagesmodel.h"
#include "core/messagesmodelcache.h"
#include "definitions/definitions.h" #include "definitions/definitions.h"
#include "miscellaneous/application.h" #include "miscellaneous/application.h"
#include "miscellaneous/textfactory.h"
#include "miscellaneous/databasefactory.h" #include "miscellaneous/databasefactory.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/databasequeries.h" #include "miscellaneous/databasequeries.h"
#include "services/abstract/serviceroot.h" #include "miscellaneous/iconfactory.h"
#include "core/messagesmodelcache.h" #include "miscellaneous/textfactory.h"
#include "services/abstract/recyclebin.h" #include "services/abstract/recyclebin.h"
#include "services/abstract/serviceroot.h"
#include <QSqlField> #include <QSqlField>
MessagesModel::MessagesModel(QObject* parent) MessagesModel::MessagesModel(QObject* parent)
: QSqlQueryModel(parent), MessagesModelSqlLayer(), : QSqlQueryModel(parent), MessagesModelSqlLayer(),
m_cache(new MessagesModelCache(this)), m_messageHighlighter(NoHighlighting), m_customDateFormat(QString()) { m_cache(new MessagesModelCache(this)), m_messageHighlighter(NoHighlighting), m_customDateFormat(QString()) {
setupFonts(); setupFonts();
setupIcons(); setupIcons();
setupHeaderData(); setupHeaderData();
updateDateFormat(); updateDateFormat();
loadMessages(nullptr); loadMessages(nullptr);
} }
MessagesModel::~MessagesModel() { MessagesModel::~MessagesModel() {
qDebug("Destroying MessagesModel instance."); qDebug("Destroying MessagesModel instance.");
} }
void MessagesModel::setupIcons() { void MessagesModel::setupIcons() {
m_favoriteIcon = qApp->icons()->fromTheme(QSL("mail-mark-important")); m_favoriteIcon = qApp->icons()->fromTheme(QSL("mail-mark-important"));
m_readIcon = qApp->icons()->fromTheme(QSL("mail-mark-read")); m_readIcon = qApp->icons()->fromTheme(QSL("mail-mark-read"));
m_unreadIcon = qApp->icons()->fromTheme(QSL("mail-mark-unread")); m_unreadIcon = qApp->icons()->fromTheme(QSL("mail-mark-unread"));
} }
void MessagesModel::repopulate() { void MessagesModel::repopulate() {
m_cache->clear(); m_cache->clear();
setQuery(selectStatement(), m_db); setQuery(selectStatement(), m_db);
while (canFetchMore()) { while (canFetchMore()) {
fetchMore(); fetchMore();
} }
} }
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, record(index.row()));
return true; return true;
} }
void MessagesModel::setupFonts() { void MessagesModel::setupFonts() {
m_normalFont = Application::font("MessagesView"); m_normalFont = Application::font("MessagesView");
m_boldFont = m_normalFont; m_boldFont = m_normalFont;
m_boldFont.setBold(true); m_boldFont.setBold(true);
m_normalStrikedFont = m_normalFont; m_normalStrikedFont = m_normalFont;
m_boldStrikedFont = m_boldFont; m_boldStrikedFont = m_boldFont;
m_normalStrikedFont.setStrikeOut(true); m_normalStrikedFont.setStrikeOut(true);
m_boldStrikedFont.setStrikeOut(true); m_boldStrikedFont.setStrikeOut(true);
} }
void MessagesModel::loadMessages(RootItem* item) { void MessagesModel::loadMessages(RootItem* item) {
m_selectedItem = item; m_selectedItem = item;
if (item == nullptr) { if (item == nullptr) {
setFilter(QSL(DEFAULT_SQL_MESSAGES_FILTER)); setFilter(QSL(DEFAULT_SQL_MESSAGES_FILTER));
} }
else { else {
if (!item->getParentServiceRoot()->loadMessagesForItem(item, this)) { if (!item->getParentServiceRoot()->loadMessagesForItem(item, this)) {
setFilter(QSL("true != true")); setFilter(QSL("true != true"));
qWarning("Loading of messages from item '%s' failed.", qPrintable(item->title())); qWarning("Loading of messages from item '%s' failed.", qPrintable(item->title()));
qApp->showGuiMessage(tr("Loading of messages from item '%1' failed.").arg(item->title()), qApp->showGuiMessage(tr("Loading of messages from item '%1' failed.").arg(item->title()),
tr("Loading of messages failed, maybe messages could not be downloaded."), tr("Loading of messages failed, maybe messages could not be downloaded."),
QSystemTrayIcon::Critical, QSystemTrayIcon::Critical,
qApp->mainFormWidget(), qApp->mainFormWidget(),
true); true);
} }
} }
repopulate(); repopulate();
} }
bool MessagesModel::setMessageImportantById(int id, RootItem::Importance important) { bool MessagesModel::setMessageImportantById(int id, RootItem::Importance important) {
for (int i = 0; i < rowCount(); i++) { for (int i = 0; i < rowCount(); i++) {
int found_id = data(i, MSG_DB_ID_INDEX, Qt::EditRole).toInt(); int found_id = data(i, MSG_DB_ID_INDEX, Qt::EditRole).toInt();
if (found_id == id) { if (found_id == id) {
bool set = setData(index(i, MSG_DB_IMPORTANT_INDEX), important); bool set = setData(index(i, MSG_DB_IMPORTANT_INDEX), important);
if (set) { if (set) {
emit dataChanged(index(i, 0), index(i, MSG_DB_CUSTOM_HASH_INDEX)); emit dataChanged(index(i, 0), index(i, MSG_DB_CUSTOM_HASH_INDEX));
} }
return set; return set;
} }
} }
return false; return false;
} }
void MessagesModel::highlightMessages(MessagesModel::MessageHighlighter highlight) { void MessagesModel::highlightMessages(MessagesModel::MessageHighlighter highlight) {
m_messageHighlighter = highlight; m_messageHighlighter = highlight;
emit layoutAboutToBeChanged(); emit layoutAboutToBeChanged();
emit layoutChanged(); emit layoutChanged();
} }
int MessagesModel::messageId(int row_index) const { int MessagesModel::messageId(int row_index) const {
return data(row_index, MSG_DB_ID_INDEX, Qt::EditRole).toInt(); return data(row_index, MSG_DB_ID_INDEX, Qt::EditRole).toInt();
} }
RootItem::Importance MessagesModel::messageImportance(int row_index) const { RootItem::Importance MessagesModel::messageImportance(int row_index) const {
return (RootItem::Importance) data(row_index, MSG_DB_IMPORTANT_INDEX, Qt::EditRole).toInt(); return (RootItem::Importance) data(row_index, MSG_DB_IMPORTANT_INDEX, Qt::EditRole).toInt();
} }
RootItem* MessagesModel::loadedItem() const { RootItem* MessagesModel::loadedItem() const {
return m_selectedItem; return m_selectedItem;
} }
void MessagesModel::updateDateFormat() { void MessagesModel::updateDateFormat() {
if (qApp->settings()->value(GROUP(Messages), SETTING(Messages::UseCustomDate)).toBool()) { if (qApp->settings()->value(GROUP(Messages), SETTING(Messages::UseCustomDate)).toBool()) {
m_customDateFormat = qApp->settings()->value(GROUP(Messages), SETTING(Messages::CustomDateFormat)).toString(); m_customDateFormat = qApp->settings()->value(GROUP(Messages), SETTING(Messages::CustomDateFormat)).toString();
} }
else { else {
m_customDateFormat = QString(); m_customDateFormat = QString();
} }
} }
void MessagesModel::reloadWholeLayout() { void MessagesModel::reloadWholeLayout() {
emit layoutAboutToBeChanged(); emit layoutAboutToBeChanged();
emit layoutChanged(); emit layoutChanged();
} }
Message MessagesModel::messageAt(int row_index) const { Message MessagesModel::messageAt(int row_index) const {
return Message::fromSqlRecord(m_cache->containsData(row_index) ? m_cache->record(row_index) : record(row_index)); return Message::fromSqlRecord(m_cache->containsData(row_index) ? m_cache->record(row_index) : record(row_index));
} }
void MessagesModel::setupHeaderData() { void MessagesModel::setupHeaderData() {
m_headerData << /*: Tooltip for ID of message.*/ tr("Id") << m_headerData << /*: Tooltip for ID of message.*/ tr("Id") <<
/*: Tooltip for "read" column in msg list.*/ tr("Read") <<
/*: Tooltip for "deleted" column in msg list.*/ tr("Deleted") << /*: Tooltip for "read" column in msg list.*/ tr("Read") <<
/*: Tooltip for "important" column in msg list.*/ tr("Important") <<
/*: Tooltip for name of feed for message.*/ tr("Feed") << /*: Tooltip for "deleted" column in msg list.*/ tr("Deleted") <<
/*: Tooltip for title of message.*/ tr("Title") <<
/*: Tooltip for url of message.*/ tr("Url") << /*: Tooltip for "important" column in msg list.*/ tr("Important") <<
/*: Tooltip for author of message.*/ tr("Author") <<
/*: Tooltip for creation date of message.*/ tr("Created on") << /*: Tooltip for name of feed for message.*/ tr("Feed") <<
/*: Tooltip for contents of message.*/ tr("Contents") <<
/*: Tooltip for "pdeleted" column in msg list.*/ tr("Permanently deleted") << /*: Tooltip for title of message.*/ tr("Title") <<
/*: Tooltip for attachments of message.*/ tr("Attachments") <<
/*: Tooltip for account ID of message.*/ tr("Account ID") << /*: Tooltip for url of message.*/ tr("Url") <<
/*: Tooltip for custom ID of message.*/ tr("Custom ID") <<
/*: Tooltip for custom hash string of message.*/ tr("Custom hash") << /*: Tooltip for author of message.*/ tr("Author") <<
/*: Tooltip for custom ID of feed of message.*/ tr("Feed ID");;
m_tooltipData << tr("Id of the message.") << tr("Is message read?") << /*: Tooltip for creation date of message.*/ tr("Created on") <<
tr("Is message deleted?") << tr("Is message important?") <<
tr("Id of feed which this message belongs to.") << /*: Tooltip for contents of message.*/ tr("Contents") <<
tr("Title of the message.") << tr("Url of the message.") <<
tr("Author of the message.") << tr("Creation date of the message.") << /*: Tooltip for "pdeleted" column in msg list.*/ tr("Permanently deleted") <<
tr("Contents of the message.") << tr("Is message permanently deleted from recycle bin?") <<
tr("List of attachments.") << tr("Account ID of the message.") << tr("Custom ID of the message") << /*: Tooltip for attachments of message.*/ tr("Attachments") <<
tr("Custom hash of the message.") << tr("Custom ID of feed of the message.");
/*: Tooltip for account ID of message.*/ tr("Account ID") <<
/*: Tooltip for custom ID of message.*/ tr("Custom ID") <<
/*: Tooltip for custom hash string of message.*/ tr("Custom hash") <<
/*: Tooltip for custom ID of feed of message.*/ tr("Feed ID");;
m_tooltipData << tr("Id of the message.") << tr("Is message read?") <<
tr("Is message deleted?") << tr("Is message important?") <<
tr("Id of feed which this message belongs to.") <<
tr("Title of the message.") << tr("Url of the message.") <<
tr("Author of the message.") << tr("Creation date of the message.") <<
tr("Contents of the message.") << tr("Is message permanently deleted from recycle bin?") <<
tr("List of attachments.") << tr("Account ID of the message.") << tr("Custom ID of the message") <<
tr("Custom hash of the message.") << tr("Custom ID of feed of the message.");
} }
Qt::ItemFlags MessagesModel::flags(const QModelIndex& index) const { Qt::ItemFlags MessagesModel::flags(const QModelIndex& index) const {
Q_UNUSED(index) Q_UNUSED(index)
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemNeverHasChildren; return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemNeverHasChildren;
} }
QVariant MessagesModel::data(int row, int column, int role) const { QVariant MessagesModel::data(int row, int column, int role) const {
return data(index(row, column), role); return data(index(row, column), role);
} }
QVariant MessagesModel::data(const QModelIndex& idx, int role) const { QVariant MessagesModel::data(const QModelIndex& idx, int role) const {
// This message is not in cache, return real data from live query. // This message is not in cache, return real data from live query.
switch (role) { switch (role) {
// Human readable data for viewing. // Human readable data for viewing.
case Qt::DisplayRole: { case Qt::DisplayRole: {
int index_column = idx.column(); int index_column = idx.column();
if (index_column == MSG_DB_DCREATED_INDEX) { if (index_column == MSG_DB_DCREATED_INDEX) {
QDateTime dt = TextFactory::parseDateTime(QSqlQueryModel::data(idx, role).value<qint64>()).toLocalTime(); QDateTime dt = TextFactory::parseDateTime(QSqlQueryModel::data(idx, role).value<qint64>()).toLocalTime();
if (m_customDateFormat.isEmpty()) { if (m_customDateFormat.isEmpty()) {
return dt.toString(Qt::DefaultLocaleShortDate); return dt.toString(Qt::DefaultLocaleShortDate);
} }
else { else {
return dt.toString(m_customDateFormat); return dt.toString(m_customDateFormat);
} }
} }
else if (index_column == MSG_DB_AUTHOR_INDEX) { else if (index_column == MSG_DB_AUTHOR_INDEX) {
const QString author_name = QSqlQueryModel::data(idx, role).toString(); const QString author_name = QSqlQueryModel::data(idx, role).toString();
return author_name.isEmpty() ? QSL("-") : author_name;
}
else if (index_column != MSG_DB_IMPORTANT_INDEX && index_column != MSG_DB_READ_INDEX) {
return QSqlQueryModel::data(idx, role);
}
else {
return QVariant();
}
}
case Qt::EditRole: return author_name.isEmpty() ? QSL("-") : author_name;
return m_cache->containsData(idx.row()) ? m_cache->data(idx) : QSqlQueryModel::data(idx, role); }
else if (index_column != MSG_DB_IMPORTANT_INDEX && index_column != MSG_DB_READ_INDEX) {
return QSqlQueryModel::data(idx, role);
}
else {
return QVariant();
}
}
case Qt::FontRole: { case Qt::EditRole:
QModelIndex idx_read = index(idx.row(), MSG_DB_READ_INDEX); return m_cache->containsData(idx.row()) ? m_cache->data(idx) : QSqlQueryModel::data(idx, role);
QVariant data_read = data(idx_read, Qt::EditRole);
const bool is_bin = qobject_cast<RecycleBin*>(loadedItem()) != nullptr;
bool is_deleted;
if (is_bin) { case Qt::FontRole: {
QModelIndex idx_del = index(idx.row(), MSG_DB_PDELETED_INDEX); QModelIndex idx_read = index(idx.row(), MSG_DB_READ_INDEX);
is_deleted = data(idx_del, Qt::EditRole).toBool(); QVariant data_read = data(idx_read, Qt::EditRole);
} const bool is_bin = qobject_cast<RecycleBin*>(loadedItem()) != nullptr;
else { bool is_deleted;
QModelIndex idx_del = index(idx.row(), MSG_DB_DELETED_INDEX);
is_deleted = data(idx_del, Qt::EditRole).toBool();
}
const bool striked = is_deleted; if (is_bin) {
QModelIndex idx_del = index(idx.row(), MSG_DB_PDELETED_INDEX);
if (data_read.toBool()) { is_deleted = data(idx_del, Qt::EditRole).toBool();
return striked ? m_normalStrikedFont : m_normalFont; }
} else {
else { QModelIndex idx_del = index(idx.row(), MSG_DB_DELETED_INDEX);
return striked ? m_boldStrikedFont : m_boldFont;
}
}
case Qt::ForegroundRole: is_deleted = data(idx_del, Qt::EditRole).toBool();
switch (m_messageHighlighter) { }
case HighlightImportant: {
QModelIndex idx_important = index(idx.row(), MSG_DB_IMPORTANT_INDEX);
QVariant dta = m_cache->containsData(idx_important.row()) ? m_cache->data(idx_important) : QSqlQueryModel::data(idx_important);
return dta.toInt() == 1 ? QColor(Qt::blue) : QVariant();
}
case HighlightUnread: { const bool striked = is_deleted;
QModelIndex idx_read = index(idx.row(), MSG_DB_READ_INDEX);
QVariant dta = m_cache->containsData(idx_read.row()) ? m_cache->data(idx_read) : QSqlQueryModel::data(idx_read);
return dta.toInt() == 0 ? QColor(Qt::blue) : QVariant();
}
case NoHighlighting: if (data_read.toBool()) {
default: return striked ? m_normalStrikedFont : m_normalFont;
return QVariant(); }
} else {
return striked ? m_boldStrikedFont : m_boldFont;
}
}
case Qt::DecorationRole: { case Qt::ForegroundRole:
const int index_column = idx.column(); switch (m_messageHighlighter) {
case HighlightImportant: {
QModelIndex idx_important = index(idx.row(), MSG_DB_IMPORTANT_INDEX);
QVariant dta = m_cache->containsData(idx_important.row()) ? m_cache->data(idx_important) : QSqlQueryModel::data(idx_important);
if (index_column == MSG_DB_READ_INDEX) { return dta.toInt() == 1 ? QColor(Qt::blue) : QVariant();
QModelIndex idx_read = index(idx.row(), MSG_DB_READ_INDEX); }
QVariant dta = m_cache->containsData(idx_read.row()) ? m_cache->data(idx_read) : QSqlQueryModel::data(idx_read);
return dta.toInt() == 1 ? m_readIcon : m_unreadIcon;
}
else if (index_column == MSG_DB_IMPORTANT_INDEX) {
QModelIndex idx_important = index(idx.row(), MSG_DB_IMPORTANT_INDEX);
QVariant dta = m_cache->containsData(idx_important.row()) ? m_cache->data(idx_important) : QSqlQueryModel::data(idx_important);
return dta.toInt() == 1 ? m_favoriteIcon : QVariant();
}
else {
return QVariant();
}
}
default: case HighlightUnread: {
return QVariant(); QModelIndex idx_read = index(idx.row(), MSG_DB_READ_INDEX);
} QVariant dta = m_cache->containsData(idx_read.row()) ? m_cache->data(idx_read) : QSqlQueryModel::data(idx_read);
return dta.toInt() == 0 ? QColor(Qt::blue) : QVariant();
}
case NoHighlighting:
default:
return QVariant();
}
case Qt::DecorationRole: {
const int index_column = idx.column();
if (index_column == MSG_DB_READ_INDEX) {
QModelIndex idx_read = index(idx.row(), MSG_DB_READ_INDEX);
QVariant dta = m_cache->containsData(idx_read.row()) ? m_cache->data(idx_read) : QSqlQueryModel::data(idx_read);
return dta.toInt() == 1 ? m_readIcon : m_unreadIcon;
}
else if (index_column == MSG_DB_IMPORTANT_INDEX) {
QModelIndex idx_important = index(idx.row(), MSG_DB_IMPORTANT_INDEX);
QVariant dta = m_cache->containsData(idx_important.row()) ? m_cache->data(idx_important) : QSqlQueryModel::data(idx_important);
return dta.toInt() == 1 ? m_favoriteIcon : QVariant();
}
else {
return QVariant();
}
}
default:
return QVariant();
}
} }
bool MessagesModel::setMessageRead(int row_index, RootItem::ReadStatus read) { bool MessagesModel::setMessageRead(int row_index, RootItem::ReadStatus read) {
if (data(row_index, MSG_DB_READ_INDEX, Qt::EditRole).toInt() == read) { if (data(row_index, MSG_DB_READ_INDEX, Qt::EditRole).toInt() == read) {
// Read status is the same is the one currently set. // Read status is the same is the one currently set.
// In that case, no extra work is needed. // In that case, no extra work is needed.
return true; return true;
} }
Message message = messageAt(row_index); Message message = messageAt(row_index);
if (!m_selectedItem->getParentServiceRoot()->onBeforeSetMessagesRead(m_selectedItem, QList<Message>() << message, read)) { if (!m_selectedItem->getParentServiceRoot()->onBeforeSetMessagesRead(m_selectedItem, QList<Message>() << message, read)) {
// Cannot change read status of the item. Abort. // Cannot change read status of the item. Abort.
return false; return false;
} }
// Rewrite "visible" data in the model. // Rewrite "visible" data in the model.
bool working_change = setData(index(row_index, MSG_DB_READ_INDEX), read); bool working_change = setData(index(row_index, MSG_DB_READ_INDEX), read);
if (!working_change) { if (!working_change) {
// If rewriting in the model failed, then cancel all actions. // If rewriting in the model failed, then cancel all actions.
qDebug("Setting of new data to the model failed for message read change."); qDebug("Setting of new data to the model failed for message read change.");
return false; return false;
} }
if (DatabaseQueries::markMessagesReadUnread(m_db, QStringList() << QString::number(message.m_id), read)) { if (DatabaseQueries::markMessagesReadUnread(m_db, QStringList() << QString::number(message.m_id), read)) {
return m_selectedItem->getParentServiceRoot()->onAfterSetMessagesRead(m_selectedItem, QList<Message>() << message, read); return m_selectedItem->getParentServiceRoot()->onAfterSetMessagesRead(m_selectedItem, QList<Message>() << message, read);
} }
else { else {
return false; return false;
} }
} }
bool MessagesModel::setMessageReadById(int id, RootItem::ReadStatus read) { bool MessagesModel::setMessageReadById(int id, RootItem::ReadStatus read) {
for (int i = 0; i < rowCount(); i++) { for (int i = 0; i < rowCount(); i++) {
int found_id = data(i, MSG_DB_ID_INDEX, Qt::EditRole).toInt(); int found_id = data(i, MSG_DB_ID_INDEX, Qt::EditRole).toInt();
if (found_id == id) { if (found_id == id) {
bool set = setData(index(i, MSG_DB_READ_INDEX), read); bool set = setData(index(i, MSG_DB_READ_INDEX), read);
if (set) { if (set) {
emit dataChanged(index(i, 0), index(i, MSG_DB_CUSTOM_HASH_INDEX)); emit dataChanged(index(i, 0), index(i, MSG_DB_CUSTOM_HASH_INDEX));
} }
return set; return set;
} }
} }
return false; return false;
} }
bool MessagesModel::switchMessageImportance(int row_index) { bool MessagesModel::switchMessageImportance(int row_index) {
const QModelIndex target_index = index(row_index, MSG_DB_IMPORTANT_INDEX); const QModelIndex target_index = index(row_index, MSG_DB_IMPORTANT_INDEX);
const RootItem::Importance current_importance = (RootItem::Importance) data(target_index, Qt::EditRole).toInt(); const RootItem::Importance current_importance = (RootItem::Importance) data(target_index, Qt::EditRole).toInt();
const RootItem::Importance next_importance = current_importance == RootItem::Important ? const RootItem::Importance next_importance = current_importance == RootItem::Important ?
RootItem::NotImportant : RootItem::Important; RootItem::NotImportant : RootItem::Important;
const Message message = messageAt(row_index); const Message message = messageAt(row_index);
const QPair<Message, RootItem::Importance> pair(message, next_importance); const QPair<Message, RootItem::Importance> pair(message, next_importance);
if (!m_selectedItem->getParentServiceRoot()->onBeforeSwitchMessageImportance(m_selectedItem, if (!m_selectedItem->getParentServiceRoot()->onBeforeSwitchMessageImportance(m_selectedItem,
QList<QPair<Message, RootItem::Importance>>() << pair)) { QList<QPair<Message, RootItem::Importance>>() << pair)) {
return false; return false;
} }
// Rewrite "visible" data in the model. // Rewrite "visible" data in the model.
const bool working_change = setData(target_index, next_importance); const bool working_change = setData(target_index, next_importance);
if (!working_change) { if (!working_change) {
// If rewriting in the model failed, then cancel all actions. // If rewriting in the model failed, then cancel all actions.
qDebug("Setting of new data to the model failed for message importance change."); qDebug("Setting of new data to the model failed for message importance change.");
return false; return false;
} }
// Commit changes. // Commit changes.
if (DatabaseQueries::markMessageImportant(m_db, message.m_id, next_importance)) { if (DatabaseQueries::markMessageImportant(m_db, message.m_id, next_importance)) {
emit dataChanged(index(row_index, 0), index(row_index, MSG_DB_FEED_CUSTOM_ID_INDEX), QVector<int>() << Qt::FontRole); emit dataChanged(index(row_index, 0), index(row_index, MSG_DB_FEED_CUSTOM_ID_INDEX), QVector<int>() << Qt::FontRole);
return m_selectedItem->getParentServiceRoot()->onAfterSwitchMessageImportance(m_selectedItem,
QList<QPair<Message, RootItem::Importance>>() << pair); return m_selectedItem->getParentServiceRoot()->onAfterSwitchMessageImportance(m_selectedItem,
} QList<QPair<Message, RootItem::Importance>>() << pair);
else { }
return false; else {
} return false;
}
} }
bool MessagesModel::switchBatchMessageImportance(const QModelIndexList& messages) { bool MessagesModel::switchBatchMessageImportance(const QModelIndexList& messages) {
QStringList message_ids; QStringList message_ids;
QList<QPair<Message, RootItem::Importance>> message_states;
// Obtain IDs of all desired messages. QList<QPair<Message, RootItem::Importance>> message_states;
foreach (const QModelIndex& message, messages) {
const Message msg = messageAt(message.row());
RootItem::Importance message_importance = messageImportance((message.row()));
message_states.append(QPair<Message, RootItem::Importance>(msg, message_importance == RootItem::Important ?
RootItem::NotImportant :
RootItem::Important));
message_ids.append(QString::number(msg.m_id));
QModelIndex idx_msg_imp = index(message.row(), MSG_DB_IMPORTANT_INDEX);
setData(idx_msg_imp, message_importance == RootItem::Important ?
(int) RootItem::NotImportant :
(int) RootItem::Important);
}
reloadWholeLayout(); // Obtain IDs of all desired messages.
foreach (const QModelIndex& message, messages) {
const Message msg = messageAt(message.row());
if (!m_selectedItem->getParentServiceRoot()->onBeforeSwitchMessageImportance(m_selectedItem, message_states)) { RootItem::Importance message_importance = messageImportance((message.row()));
return false; message_states.append(QPair<Message, RootItem::Importance>(msg, message_importance == RootItem::Important ?
} RootItem::NotImportant :
RootItem::Important));
message_ids.append(QString::number(msg.m_id));
QModelIndex idx_msg_imp = index(message.row(), MSG_DB_IMPORTANT_INDEX);
if (DatabaseQueries::switchMessagesImportance(m_db, message_ids)) { setData(idx_msg_imp, message_importance == RootItem::Important ?
return m_selectedItem->getParentServiceRoot()->onAfterSwitchMessageImportance(m_selectedItem, message_states); (int) RootItem::NotImportant :
} (int) RootItem::Important);
else { }
return false;
} reloadWholeLayout();
if (!m_selectedItem->getParentServiceRoot()->onBeforeSwitchMessageImportance(m_selectedItem, message_states)) {
return false;
}
if (DatabaseQueries::switchMessagesImportance(m_db, message_ids)) {
return m_selectedItem->getParentServiceRoot()->onAfterSwitchMessageImportance(m_selectedItem, message_states);
}
else {
return false;
}
} }
bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList& messages) { bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList& messages) {
QStringList message_ids; QStringList message_ids;
QList<Message> msgs;
// Obtain IDs of all desired messages. QList<Message> msgs;
foreach (const QModelIndex& message, messages) {
const Message msg = messageAt(message.row());
msgs.append(msg);
message_ids.append(QString::number(msg.m_id));
if (qobject_cast<RecycleBin*>(m_selectedItem) != nullptr) { // Obtain IDs of all desired messages.
setData(index(message.row(), MSG_DB_PDELETED_INDEX), 1); foreach (const QModelIndex& message, messages) {
} const Message msg = messageAt(message.row());
else {
setData(index(message.row(), MSG_DB_DELETED_INDEX), 1);
}
}
reloadWholeLayout(); msgs.append(msg);
message_ids.append(QString::number(msg.m_id));
if (!m_selectedItem->getParentServiceRoot()->onBeforeMessagesDelete(m_selectedItem, msgs)) { if (qobject_cast<RecycleBin*>(m_selectedItem) != nullptr) {
return false; setData(index(message.row(), MSG_DB_PDELETED_INDEX), 1);
} }
else {
setData(index(message.row(), MSG_DB_DELETED_INDEX), 1);
}
}
bool deleted; reloadWholeLayout();
if (m_selectedItem->kind() != RootItemKind::Bin) { if (!m_selectedItem->getParentServiceRoot()->onBeforeMessagesDelete(m_selectedItem, msgs)) {
deleted = DatabaseQueries::deleteOrRestoreMessagesToFromBin(m_db, message_ids, true); return false;
} }
else {
deleted = DatabaseQueries::permanentlyDeleteMessages(m_db, message_ids);
}
if (deleted) { bool deleted;
return m_selectedItem->getParentServiceRoot()->onAfterMessagesDelete(m_selectedItem, msgs);
} if (m_selectedItem->kind() != RootItemKind::Bin) {
else { deleted = DatabaseQueries::deleteOrRestoreMessagesToFromBin(m_db, message_ids, true);
return false; }
} else {
deleted = DatabaseQueries::permanentlyDeleteMessages(m_db, message_ids);
}
if (deleted) {
return m_selectedItem->getParentServiceRoot()->onAfterMessagesDelete(m_selectedItem, msgs);
}
else {
return false;
}
} }
bool MessagesModel::setBatchMessagesRead(const QModelIndexList& messages, RootItem::ReadStatus read) { bool MessagesModel::setBatchMessagesRead(const QModelIndexList& messages, RootItem::ReadStatus read) {
QStringList message_ids; QStringList message_ids;
QList<Message> msgs;
// Obtain IDs of all desired messages. QList<Message> msgs;
foreach (const QModelIndex& message, messages) {
Message msg = messageAt(message.row());
msgs.append(msg);
message_ids.append(QString::number(msg.m_id));
setData(index(message.row(), MSG_DB_READ_INDEX), (int) read);
}
reloadWholeLayout(); // Obtain IDs of all desired messages.
foreach (const QModelIndex& message, messages) {
Message msg = messageAt(message.row());
if (!m_selectedItem->getParentServiceRoot()->onBeforeSetMessagesRead(m_selectedItem, msgs, read)) { msgs.append(msg);
return false; message_ids.append(QString::number(msg.m_id));
} setData(index(message.row(), MSG_DB_READ_INDEX), (int) read);
}
if (DatabaseQueries::markMessagesReadUnread(m_db, message_ids, read)) { reloadWholeLayout();
return m_selectedItem->getParentServiceRoot()->onAfterSetMessagesRead(m_selectedItem, msgs, read);
} if (!m_selectedItem->getParentServiceRoot()->onBeforeSetMessagesRead(m_selectedItem, msgs, read)) {
else { return false;
return false; }
}
if (DatabaseQueries::markMessagesReadUnread(m_db, message_ids, read)) {
return m_selectedItem->getParentServiceRoot()->onAfterSetMessagesRead(m_selectedItem, msgs, read);
}
else {
return false;
}
} }
bool MessagesModel::setBatchMessagesRestored(const QModelIndexList& messages) { bool MessagesModel::setBatchMessagesRestored(const QModelIndexList& messages) {
QStringList message_ids; QStringList message_ids;
QList<Message> msgs;
// Obtain IDs of all desired messages. QList<Message> msgs;
foreach (const QModelIndex& message, messages) {
const Message msg = messageAt(message.row());
msgs.append(msg);
message_ids.append(QString::number(msg.m_id));
setData(index(message.row(), MSG_DB_PDELETED_INDEX), 0);
setData(index(message.row(), MSG_DB_DELETED_INDEX), 0);
}
reloadWholeLayout(); // Obtain IDs of all desired messages.
foreach (const QModelIndex& message, messages) {
const Message msg = messageAt(message.row());
if (!m_selectedItem->getParentServiceRoot()->onBeforeMessagesRestoredFromBin(m_selectedItem, msgs)) { msgs.append(msg);
return false; message_ids.append(QString::number(msg.m_id));
} setData(index(message.row(), MSG_DB_PDELETED_INDEX), 0);
setData(index(message.row(), MSG_DB_DELETED_INDEX), 0);
}
if (DatabaseQueries::deleteOrRestoreMessagesToFromBin(m_db, message_ids, false)) { reloadWholeLayout();
return m_selectedItem->getParentServiceRoot()->onAfterMessagesRestoredFromBin(m_selectedItem, msgs);
} if (!m_selectedItem->getParentServiceRoot()->onBeforeMessagesRestoredFromBin(m_selectedItem, msgs)) {
else { return false;
return false; }
}
if (DatabaseQueries::deleteOrRestoreMessagesToFromBin(m_db, message_ids, false)) {
return m_selectedItem->getParentServiceRoot()->onAfterMessagesRestoredFromBin(m_selectedItem, msgs);
}
else {
return false;
}
} }
QVariant MessagesModel::headerData(int section, Qt::Orientation orientation, int role) const { QVariant MessagesModel::headerData(int section, Qt::Orientation orientation, int role) const {
Q_UNUSED(orientation) Q_UNUSED(orientation)
switch (role) { switch (role) {
case Qt::DisplayRole: case Qt::DisplayRole:
// Display textual headers for all columns except "read" and // Display textual headers for all columns except "read" and
// "important" columns. // "important" columns.
if (section != MSG_DB_READ_INDEX && section != MSG_DB_IMPORTANT_INDEX) { if (section != MSG_DB_READ_INDEX && section != MSG_DB_IMPORTANT_INDEX) {
return m_headerData.at(section); return m_headerData.at(section);
} }
else { else {
return QVariant(); return QVariant();
} }
case Qt::ToolTipRole: case Qt::ToolTipRole:
return m_tooltipData.at(section); return m_tooltipData.at(section);
case Qt::EditRole: case Qt::EditRole:
return m_headerData.at(section); return m_headerData.at(section);
// Display icons for "read" and "important" columns. // Display icons for "read" and "important" columns.
case Qt::DecorationRole: { case Qt::DecorationRole: {
switch (section) { switch (section) {
case MSG_DB_READ_INDEX: case MSG_DB_READ_INDEX:
return m_readIcon; return m_readIcon;
case MSG_DB_IMPORTANT_INDEX: case MSG_DB_IMPORTANT_INDEX:
return m_favoriteIcon; return m_favoriteIcon;
default: default:
return QVariant(); return QVariant();
} }
} }
default: default:
return QVariant(); return QVariant();
} }
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -18,98 +19,99 @@
#ifndef MESSAGESMODEL_H #ifndef MESSAGESMODEL_H
#define MESSAGESMODEL_H #define MESSAGESMODEL_H
#include <QSqlQueryModel>
#include "core/messagesmodelsqllayer.h" #include "core/messagesmodelsqllayer.h"
#include <QSqlQueryModel>
#include "definitions/definitions.h"
#include "core/message.h" #include "core/message.h"
#include "definitions/definitions.h"
#include "services/abstract/rootitem.h" #include "services/abstract/rootitem.h"
#include <QFont> #include <QFont>
#include <QIcon> #include <QIcon>
class MessagesModelCache; class MessagesModelCache;
class MessagesModel : public QSqlQueryModel, public MessagesModelSqlLayer { class MessagesModel : public QSqlQueryModel, public MessagesModelSqlLayer {
Q_OBJECT Q_OBJECT
public: public:
// Enum which describes basic filtering schemes
// for messages.
enum MessageHighlighter {
NoHighlighting = 100,
HighlightUnread = 101,
HighlightImportant = 102
};
// Constructors and destructors. // Enum which describes basic filtering schemes
explicit MessagesModel(QObject* parent = 0); // for messages.
virtual ~MessagesModel(); enum MessageHighlighter {
NoHighlighting = 100,
HighlightUnread = 101,
HighlightImportant = 102
};
// Fetches ALL available data to the model. // Constructors and destructors.
// NOTE: This activates the SQL query and populates the model with new data. explicit MessagesModel(QObject* parent = 0);
void repopulate(); virtual ~MessagesModel();
// Model implementation. // Fetches ALL available data to the model.
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole); // NOTE: This activates the SQL query and populates the model with new data.
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; void repopulate();
QVariant data(int row, int column, int role = Qt::DisplayRole) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
Qt::ItemFlags flags(const QModelIndex& index) const;
// Returns message at given index. // Model implementation.
Message messageAt(int row_index) const; bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
int messageId(int row_index) const; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
RootItem::Importance messageImportance(int row_index) const; QVariant data(int row, int column, int role = Qt::DisplayRole) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
Qt::ItemFlags flags(const QModelIndex& index) const;
RootItem* loadedItem() const; // Returns message at given index.
void updateDateFormat(); Message messageAt(int row_index) const;
void reloadWholeLayout(); int messageId(int row_index) const;
RootItem::Importance messageImportance(int row_index) const;
// SINGLE message manipulators. RootItem* loadedItem() const;
bool switchMessageImportance(int row_index);
bool setMessageRead(int row_index, RootItem::ReadStatus read);
// BATCH messages manipulators. void updateDateFormat();
bool switchBatchMessageImportance(const QModelIndexList& messages); void reloadWholeLayout();
bool setBatchMessagesDeleted(const QModelIndexList& messages);
bool setBatchMessagesRead(const QModelIndexList& messages, RootItem::ReadStatus read);
bool setBatchMessagesRestored(const QModelIndexList& messages);
// Highlights messages. // SINGLE message manipulators.
void highlightMessages(MessageHighlighter highlight); bool switchMessageImportance(int row_index);
bool setMessageRead(int row_index, RootItem::ReadStatus read);
// Loads messages of given feeds. // BATCH messages manipulators.
void loadMessages(RootItem* item); bool switchBatchMessageImportance(const QModelIndexList& messages);
bool setBatchMessagesDeleted(const QModelIndexList& messages);
bool setBatchMessagesRead(const QModelIndexList& messages, RootItem::ReadStatus read);
bool setBatchMessagesRestored(const QModelIndexList& messages);
public slots: // Highlights messages.
// NOTE: These methods DO NOT actually change data in the DB, just in the model. void highlightMessages(MessageHighlighter highlight);
// These are particularly used by msg browser.
bool setMessageImportantById(int id, RootItem::Importance important);
bool setMessageReadById(int id, RootItem::ReadStatus read);
private: // Loads messages of given feeds.
void setupHeaderData(); void loadMessages(RootItem* item);
void setupFonts();
void setupIcons();
MessagesModelCache* m_cache; public slots:
MessageHighlighter m_messageHighlighter;
QString m_customDateFormat; // NOTE: These methods DO NOT actually change data in the DB, just in the model.
RootItem* m_selectedItem; // These are particularly used by msg browser.
QList<QString> m_headerData; bool setMessageImportantById(int id, RootItem::Importance important);
QList<QString> m_tooltipData; bool setMessageReadById(int id, RootItem::ReadStatus read);
QFont m_normalFont; private:
QFont m_boldFont; void setupHeaderData();
QFont m_normalStrikedFont; void setupFonts();
QFont m_boldStrikedFont; void setupIcons();
QIcon m_favoriteIcon; MessagesModelCache* m_cache;
QIcon m_readIcon; MessageHighlighter m_messageHighlighter;
QIcon m_unreadIcon; QString m_customDateFormat;
RootItem* m_selectedItem;
QList<QString> m_headerData;
QList<QString> m_tooltipData;
QFont m_normalFont;
QFont m_boldFont;
QFont m_normalStrikedFont;
QFont m_boldStrikedFont;
QIcon m_favoriteIcon;
QIcon m_readIcon;
QIcon m_unreadIcon;
}; };
Q_DECLARE_METATYPE(MessagesModel::MessageHighlighter) Q_DECLARE_METATYPE(MessagesModel::MessageHighlighter)

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -19,21 +20,18 @@
#include "miscellaneous/textfactory.h" #include "miscellaneous/textfactory.h"
MessagesModelCache::MessagesModelCache(QObject* parent) : QObject(parent), m_msgCache(QHash<int, QSqlRecord>()) {}
MessagesModelCache::MessagesModelCache(QObject* parent) : QObject(parent), m_msgCache(QHash<int, QSqlRecord>()) { MessagesModelCache::~MessagesModelCache() {}
}
MessagesModelCache::~MessagesModelCache() {
}
void MessagesModelCache::setData(const QModelIndex& index, const QVariant& value, const QSqlRecord& record) { void MessagesModelCache::setData(const QModelIndex& index, const QVariant& value, const QSqlRecord& record) {
if (!m_msgCache.contains(index.row())) { if (!m_msgCache.contains(index.row())) {
m_msgCache[index.row()] = record; m_msgCache[index.row()] = record;
} }
m_msgCache[index.row()].setValue(index.column(), value); m_msgCache[index.row()].setValue(index.column(), value);
} }
QVariant MessagesModelCache::data(const QModelIndex& idx) { QVariant MessagesModelCache::data(const QModelIndex& idx) {
return m_msgCache[idx.row()].value(idx.column()); return m_msgCache[idx.row()].value(idx.column());
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -22,34 +23,34 @@
#include "core/message.h" #include "core/message.h"
#include <QVariant>
#include <QModelIndex> #include <QModelIndex>
#include <QVariant>
class MessagesModelCache : public QObject { class MessagesModelCache : public QObject {
Q_OBJECT Q_OBJECT
public: public:
explicit MessagesModelCache(QObject* parent = nullptr); explicit MessagesModelCache(QObject* parent = nullptr);
virtual ~MessagesModelCache(); virtual ~MessagesModelCache();
inline bool containsData(int row_idx) const { inline bool containsData(int row_idx) const {
return m_msgCache.contains(row_idx); return m_msgCache.contains(row_idx);
} }
inline QSqlRecord record(int row_idx) const { inline QSqlRecord record(int row_idx) const {
return m_msgCache.value(row_idx); return m_msgCache.value(row_idx);
} }
inline void clear() { inline void clear() {
m_msgCache.clear(); m_msgCache.clear();
} }
void setData(const QModelIndex& index, const QVariant& value, const QSqlRecord& record); void setData(const QModelIndex& index, const QVariant& value, const QSqlRecord& record);
QVariant data(const QModelIndex& idx);
private: QVariant data(const QModelIndex& idx);
QHash<int, QSqlRecord> m_msgCache;
private:
QHash<int, QSqlRecord> m_msgCache;
}; };
#endif // MESSAGESMODELCACHE_H #endif // MESSAGESMODELCACHE_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -20,84 +21,84 @@
#include "definitions/definitions.h" #include "definitions/definitions.h"
#include "miscellaneous/application.h" #include "miscellaneous/application.h"
MessagesModelSqlLayer::MessagesModelSqlLayer() MessagesModelSqlLayer::MessagesModelSqlLayer()
: m_filter(QSL(DEFAULT_SQL_MESSAGES_FILTER)), m_fieldNames(QMap<int, QString>()), : m_filter(QSL(DEFAULT_SQL_MESSAGES_FILTER)), m_fieldNames(QMap<int, QString>()),
m_sortColumns(QList<int>()), m_sortOrders(QList<Qt::SortOrder>()) { m_sortColumns(QList<int>()), m_sortOrders(QList<Qt::SortOrder>()) {
m_db = qApp->database()->connection(QSL("MessagesModel"), DatabaseFactory::FromSettings); m_db = qApp->database()->connection(QSL("MessagesModel"), DatabaseFactory::FromSettings);
m_fieldNames[MSG_DB_ID_INDEX] = "Messages.id"; m_fieldNames[MSG_DB_ID_INDEX] = "Messages.id";
m_fieldNames[MSG_DB_READ_INDEX] = "Messages.is_read"; m_fieldNames[MSG_DB_READ_INDEX] = "Messages.is_read";
m_fieldNames[MSG_DB_DELETED_INDEX] = "Messages.is_deleted"; m_fieldNames[MSG_DB_DELETED_INDEX] = "Messages.is_deleted";
m_fieldNames[MSG_DB_IMPORTANT_INDEX] = "Messages.is_important"; m_fieldNames[MSG_DB_IMPORTANT_INDEX] = "Messages.is_important";
m_fieldNames[MSG_DB_FEED_TITLE_INDEX] = "Feeds.title"; m_fieldNames[MSG_DB_FEED_TITLE_INDEX] = "Feeds.title";
m_fieldNames[MSG_DB_TITLE_INDEX] = "Messages.title"; m_fieldNames[MSG_DB_TITLE_INDEX] = "Messages.title";
m_fieldNames[MSG_DB_URL_INDEX] = "Messages.url"; m_fieldNames[MSG_DB_URL_INDEX] = "Messages.url";
m_fieldNames[MSG_DB_AUTHOR_INDEX] = "Messages.author"; m_fieldNames[MSG_DB_AUTHOR_INDEX] = "Messages.author";
m_fieldNames[MSG_DB_DCREATED_INDEX] = "Messages.date_created"; m_fieldNames[MSG_DB_DCREATED_INDEX] = "Messages.date_created";
m_fieldNames[MSG_DB_CONTENTS_INDEX] = "Messages.contents"; m_fieldNames[MSG_DB_CONTENTS_INDEX] = "Messages.contents";
m_fieldNames[MSG_DB_PDELETED_INDEX] = "Messages.is_pdeleted"; m_fieldNames[MSG_DB_PDELETED_INDEX] = "Messages.is_pdeleted";
m_fieldNames[MSG_DB_ENCLOSURES_INDEX] = "Messages.enclosures"; m_fieldNames[MSG_DB_ENCLOSURES_INDEX] = "Messages.enclosures";
m_fieldNames[MSG_DB_ACCOUNT_ID_INDEX] = "Messages.account_id"; m_fieldNames[MSG_DB_ACCOUNT_ID_INDEX] = "Messages.account_id";
m_fieldNames[MSG_DB_CUSTOM_ID_INDEX] = "Messages.custom_id"; m_fieldNames[MSG_DB_CUSTOM_ID_INDEX] = "Messages.custom_id";
m_fieldNames[MSG_DB_CUSTOM_HASH_INDEX] = "Messages.custom_hash"; m_fieldNames[MSG_DB_CUSTOM_HASH_INDEX] = "Messages.custom_hash";
m_fieldNames[MSG_DB_FEED_CUSTOM_ID_INDEX] = "Messages.feed"; m_fieldNames[MSG_DB_FEED_CUSTOM_ID_INDEX] = "Messages.feed";
} }
void MessagesModelSqlLayer::addSortState(int column, Qt::SortOrder order) { void MessagesModelSqlLayer::addSortState(int column, Qt::SortOrder order) {
int existing = m_sortColumns.indexOf(column); int existing = m_sortColumns.indexOf(column);
bool is_ctrl_pressed = (QApplication::queryKeyboardModifiers() & Qt::ControlModifier) == Qt::ControlModifier; bool is_ctrl_pressed = (QApplication::queryKeyboardModifiers() & Qt::ControlModifier) == Qt::ControlModifier;
if (existing >= 0) { if (existing >= 0) {
m_sortColumns.removeAt(existing); m_sortColumns.removeAt(existing);
m_sortOrders.removeAt(existing); m_sortOrders.removeAt(existing);
} }
if (m_sortColumns.size() > MAX_MULTICOLUMN_SORT_STATES) { if (m_sortColumns.size() > MAX_MULTICOLUMN_SORT_STATES) {
// We support only limited number of sort states // We support only limited number of sort states
// due to DB performance. // due to DB performance.
m_sortColumns.removeAt(0); m_sortColumns.removeAt(0);
m_sortOrders.removeAt(0); m_sortOrders.removeAt(0);
} }
if (is_ctrl_pressed) { if (is_ctrl_pressed) {
// User is activating the multicolumn sort mode. // User is activating the multicolumn sort mode.
m_sortColumns.append(column); m_sortColumns.append(column);
m_sortOrders.append(order); m_sortOrders.append(order);
} }
else { else {
m_sortColumns.prepend(column); m_sortColumns.prepend(column);
m_sortOrders.prepend(order); m_sortOrders.prepend(order);
} }
qDebug("Added sort state, select statement is now:\n'%s'", qPrintable(selectStatement())); qDebug("Added sort state, select statement is now:\n'%s'", qPrintable(selectStatement()));
} }
void MessagesModelSqlLayer::setFilter(const QString& filter) { void MessagesModelSqlLayer::setFilter(const QString& filter) {
m_filter = filter; m_filter = filter;
} }
QString MessagesModelSqlLayer::formatFields() const { QString MessagesModelSqlLayer::formatFields() const {
return m_fieldNames.values().join(QSL(", ")); return m_fieldNames.values().join(QSL(", "));
} }
QString MessagesModelSqlLayer::selectStatement() const { QString MessagesModelSqlLayer::selectStatement() const {
return QL1S("SELECT ") + formatFields() + return QL1S("SELECT ") + formatFields() +
QSL(" FROM Messages LEFT JOIN Feeds ON Messages.feed = Feeds.custom_id AND Messages.account_id = Feeds.account_id WHERE ") + QSL(" FROM Messages LEFT JOIN Feeds ON Messages.feed = Feeds.custom_id AND Messages.account_id = Feeds.account_id WHERE ") +
m_filter + orderByClause() + QL1C(';'); m_filter + orderByClause() + QL1C(';');
} }
QString MessagesModelSqlLayer::orderByClause() const { QString MessagesModelSqlLayer::orderByClause() const {
if (m_sortColumns.isEmpty()) { if (m_sortColumns.isEmpty()) {
return QString(); return QString();
} }
else { else {
QStringList sorts; QStringList sorts;
for (int i = 0; i < m_sortColumns.size(); i++) { for (int i = 0; i < m_sortColumns.size(); i++) {
QString field_name(m_fieldNames[m_sortColumns[i]]); QString field_name(m_fieldNames[m_sortColumns[i]]);
sorts.append(field_name + (m_sortOrders[i] == Qt::AscendingOrder ? QSL(" ASC") : QSL(" DESC")));
}
return QL1S(" ORDER BY ") + sorts.join(QSL(", ")); sorts.append(field_name + (m_sortOrders[i] == Qt::AscendingOrder ? QSL(" ASC") : QSL(" DESC")));
} }
return QL1S(" ORDER BY ") + sorts.join(QSL(", "));
}
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -15,42 +16,40 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with RSS Guard. If not, see <http://www.gnu.org/licenses/>. // along with RSS Guard. If not, see <http://www.gnu.org/licenses/>.
#ifndef MESSAGESMODELSQLLAYER_H #ifndef MESSAGESMODELSQLLAYER_H
#define MESSAGESMODELSQLLAYER_H #define MESSAGESMODELSQLLAYER_H
#include <QSqlDatabase> #include <QSqlDatabase>
#include <QMap>
#include <QList> #include <QList>
#include <QMap>
class MessagesModelSqlLayer { class MessagesModelSqlLayer {
public: public:
explicit MessagesModelSqlLayer(); explicit MessagesModelSqlLayer();
// Adds this new state to queue of sort states. // Adds this new state to queue of sort states.
void addSortState(int column, Qt::SortOrder order); void addSortState(int column, Qt::SortOrder order);
// Sets SQL WHERE clause, without "WHERE" keyword. // Sets SQL WHERE clause, without "WHERE" keyword.
void setFilter(const QString& filter); void setFilter(const QString& filter);
protected: protected:
QString orderByClause() const; QString orderByClause() const;
QString selectStatement() const; QString selectStatement() const;
QString formatFields() const; QString formatFields() const;
QSqlDatabase m_db; QSqlDatabase m_db;
private: private:
QString m_filter; QString m_filter;
// NOTE: These two lists contain data for multicolumn sorting. // NOTE: These two lists contain data for multicolumn sorting.
// They are always same length. Most important sort column/order // They are always same length. Most important sort column/order
// are located at the start of lists; // are located at the start of lists;
QMap<int, QString> m_fieldNames; QMap<int, QString> m_fieldNames;
QList<int> m_sortColumns; QList<int> m_sortColumns;
QList<Qt::SortOrder> m_sortOrders; QList<Qt::SortOrder> m_sortOrders;
}; };
#endif // MESSAGESMODELSQLLAYER_H #endif // MESSAGESMODELSQLLAYER_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -19,179 +20,180 @@
#include "core/messagesmodel.h" #include "core/messagesmodel.h"
MessagesProxyModel::MessagesProxyModel(MessagesModel* source_model, QObject* parent) MessagesProxyModel::MessagesProxyModel(MessagesModel* source_model, QObject* parent)
: QSortFilterProxyModel(parent), m_sourceModel(source_model) { : QSortFilterProxyModel(parent), m_sourceModel(source_model) {
setObjectName(QSL("MessagesProxyModel")); setObjectName(QSL("MessagesProxyModel"));
setSortRole(Qt::EditRole); setSortRole(Qt::EditRole);
setSortCaseSensitivity(Qt::CaseInsensitive); setSortCaseSensitivity(Qt::CaseInsensitive);
setFilterCaseSensitivity(Qt::CaseInsensitive); setFilterCaseSensitivity(Qt::CaseInsensitive);
setFilterKeyColumn(-1); setFilterKeyColumn(-1);
setFilterRole(Qt::EditRole); setFilterRole(Qt::EditRole);
setDynamicSortFilter(false); setDynamicSortFilter(false);
setSourceModel(m_sourceModel); setSourceModel(m_sourceModel);
} }
MessagesProxyModel::~MessagesProxyModel() { MessagesProxyModel::~MessagesProxyModel() {
qDebug("Destroying MessagesProxyModel instance."); qDebug("Destroying MessagesProxyModel instance.");
} }
QModelIndex MessagesProxyModel::getNextPreviousUnreadItemIndex(int default_row) { QModelIndex MessagesProxyModel::getNextPreviousUnreadItemIndex(int default_row) {
const bool started_from_zero = default_row == 0; const bool started_from_zero = default_row == 0;
QModelIndex next_index = getNextUnreadItemIndex(default_row, rowCount() - 1); QModelIndex next_index = getNextUnreadItemIndex(default_row, rowCount() - 1);
// There is no next message, check previous. // There is no next message, check previous.
if (!next_index.isValid() && !started_from_zero) { if (!next_index.isValid() && !started_from_zero) {
next_index = getNextUnreadItemIndex(0, default_row - 1); next_index = getNextUnreadItemIndex(0, default_row - 1);
} }
return next_index; return next_index;
} }
QModelIndex MessagesProxyModel::getNextUnreadItemIndex(int default_row, int max_row) const { QModelIndex MessagesProxyModel::getNextUnreadItemIndex(int default_row, int max_row) const {
while (default_row <= max_row) { while (default_row <= max_row) {
// Get info if the message is read or not. // Get info if the message is read or not.
const QModelIndex proxy_index = index(default_row, MSG_DB_READ_INDEX); const QModelIndex proxy_index = index(default_row, MSG_DB_READ_INDEX);
const bool is_read = m_sourceModel->data(mapToSource(proxy_index).row(), const bool is_read = m_sourceModel->data(mapToSource(proxy_index).row(),
MSG_DB_READ_INDEX, Qt::EditRole).toInt() == 1; MSG_DB_READ_INDEX, Qt::EditRole).toInt() == 1;
if (!is_read) { if (!is_read) {
// We found unread message, mark it. // We found unread message, mark it.
return proxy_index; return proxy_index;
} }
else { else {
default_row++; default_row++;
} }
} }
return QModelIndex(); return QModelIndex();
} }
bool MessagesProxyModel::lessThan(const QModelIndex& left, const QModelIndex& right) const { bool MessagesProxyModel::lessThan(const QModelIndex& left, const QModelIndex& right) const {
Q_UNUSED(left) Q_UNUSED(left)
Q_UNUSED(right) Q_UNUSED(right)
// NOTE: Comparisons are done by SQL servers itself, not client-side.
return false; // NOTE: Comparisons are done by SQL servers itself, not client-side.
return false;
} }
QModelIndexList MessagesProxyModel::mapListFromSource(const QModelIndexList& indexes, bool deep) const { QModelIndexList MessagesProxyModel::mapListFromSource(const QModelIndexList& indexes, bool deep) const {
QModelIndexList mapped_indexes; QModelIndexList mapped_indexes;
foreach (const QModelIndex& index, indexes) { foreach (const QModelIndex& index, indexes) {
if (deep) { if (deep) {
// Construct new source index. // Construct new source index.
mapped_indexes << mapFromSource(m_sourceModel->index(index.row(), index.column())); mapped_indexes << mapFromSource(m_sourceModel->index(index.row(), index.column()));
} }
else { else {
mapped_indexes << mapFromSource(index); mapped_indexes << mapFromSource(index);
} }
} }
return mapped_indexes; return mapped_indexes;
} }
QModelIndexList MessagesProxyModel::match(const QModelIndex& start, int role, QModelIndexList MessagesProxyModel::match(const QModelIndex& start, int role,
const QVariant& entered_value, int hits, Qt::MatchFlags flags) const { const QVariant& entered_value, int hits, Qt::MatchFlags flags) const {
QModelIndexList result; QModelIndexList result;
const uint match_type = flags & 0x0F; const uint match_type = flags & 0x0F;
const Qt::CaseSensitivity case_sensitivity = Qt::CaseInsensitive; const Qt::CaseSensitivity case_sensitivity = Qt::CaseInsensitive;
const bool wrap = flags & Qt::MatchWrap; const bool wrap = flags & Qt::MatchWrap;
const bool all_hits = (hits == -1); const bool all_hits = (hits == -1);
QString entered_text; QString entered_text;
int from = start.row(); int from = start.row();
int to = rowCount(); int to = rowCount();
for (int i = 0; (wrap && i < 2) || (!wrap && i < 1); i++) { for (int i = 0; (wrap && i < 2) || (!wrap && i < 1); i++) {
for (int r = from; (r < to) && (all_hits || result.count() < hits); r++) { for (int r = from; (r < to) && (all_hits || result.count() < hits); r++) {
QModelIndex idx = index(r, start.column()); QModelIndex idx = index(r, start.column());
if (!idx.isValid()) { if (!idx.isValid()) {
continue; continue;
} }
QVariant item_value = m_sourceModel->data(mapToSource(idx).row(), MSG_DB_TITLE_INDEX, role); QVariant item_value = m_sourceModel->data(mapToSource(idx).row(), MSG_DB_TITLE_INDEX, role);
// QVariant based matching. // QVariant based matching.
if (match_type == Qt::MatchExactly) { if (match_type == Qt::MatchExactly) {
if (entered_value == item_value) { if (entered_value == item_value) {
result.append(idx); result.append(idx);
} }
} }
// QString based matching.
else {
if (entered_text.isEmpty()) {
entered_text = entered_value.toString();
}
QString item_text = item_value.toString(); // QString based matching.
else {
if (entered_text.isEmpty()) {
entered_text = entered_value.toString();
}
switch (match_type) { QString item_text = item_value.toString();
case Qt::MatchRegExp:
if (QRegExp(entered_text, case_sensitivity).exactMatch(item_text)) {
result.append(idx);
}
break; switch (match_type) {
case Qt::MatchRegExp:
if (QRegExp(entered_text, case_sensitivity).exactMatch(item_text)) {
result.append(idx);
}
case Qt::MatchWildcard: break;
if (QRegExp(entered_text, case_sensitivity, QRegExp::Wildcard).exactMatch(item_text)) {
result.append(idx);
}
break; case Qt::MatchWildcard:
if (QRegExp(entered_text, case_sensitivity, QRegExp::Wildcard).exactMatch(item_text)) {
result.append(idx);
}
case Qt::MatchStartsWith: break;
if (item_text.startsWith(entered_text, case_sensitivity)) {
result.append(idx);
}
break; case Qt::MatchStartsWith:
if (item_text.startsWith(entered_text, case_sensitivity)) {
result.append(idx);
}
case Qt::MatchEndsWith: break;
if (item_text.endsWith(entered_text, case_sensitivity)) {
result.append(idx);
}
break; case Qt::MatchEndsWith:
if (item_text.endsWith(entered_text, case_sensitivity)) {
result.append(idx);
}
case Qt::MatchFixedString: break;
if (item_text.compare(entered_text, case_sensitivity) == 0) {
result.append(idx);
}
break; case Qt::MatchFixedString:
if (item_text.compare(entered_text, case_sensitivity) == 0) {
result.append(idx);
}
case Qt::MatchContains: break;
default:
if (item_text.contains(entered_text, case_sensitivity)) {
result.append(idx);
}
break; case Qt::MatchContains:
} default:
} if (item_text.contains(entered_text, case_sensitivity)) {
} result.append(idx);
}
// Prepare for the next iteration. break;
from = 0; }
to = start.row(); }
} }
return result; // Prepare for the next iteration.
from = 0;
to = start.row();
}
return result;
} }
void MessagesProxyModel::sort(int column, Qt::SortOrder order) { void MessagesProxyModel::sort(int column, Qt::SortOrder order) {
// NOTE: Ignore here, sort is done elsewhere (server-side). // NOTE: Ignore here, sort is done elsewhere (server-side).
Q_UNUSED(column) Q_UNUSED(column)
Q_UNUSED(order) Q_UNUSED(order)
} }
QModelIndexList MessagesProxyModel::mapListToSource(const QModelIndexList& indexes) const { QModelIndexList MessagesProxyModel::mapListToSource(const QModelIndexList& indexes) const {
QModelIndexList source_indexes; QModelIndexList source_indexes;
foreach (const QModelIndex& index, indexes) { foreach (const QModelIndex& index, indexes) {
source_indexes << mapToSource(index); source_indexes << mapToSource(index);
} }
return source_indexes; return source_indexes;
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -20,37 +21,37 @@
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
class MessagesModel; class MessagesModel;
class MessagesProxyModel : public QSortFilterProxyModel { class MessagesProxyModel : public QSortFilterProxyModel {
Q_OBJECT Q_OBJECT
public: public:
// Constructors and destructors.
explicit MessagesProxyModel(MessagesModel* source_model, QObject* parent = 0);
virtual ~MessagesProxyModel();
QModelIndex getNextPreviousUnreadItemIndex(int default_row); // Constructors and destructors.
explicit MessagesProxyModel(MessagesModel* source_model, QObject* parent = 0);
virtual ~MessagesProxyModel();
// Maps list of indexes. QModelIndex getNextPreviousUnreadItemIndex(int default_row);
QModelIndexList mapListToSource(const QModelIndexList& indexes) const;
QModelIndexList mapListFromSource(const QModelIndexList& indexes, bool deep = false) const;
// Fix for matching indexes with respect to specifics of the message model. // Maps list of indexes.
QModelIndexList match(const QModelIndex& start, int role, const QVariant& entered_value, int hits, Qt::MatchFlags flags) const; QModelIndexList mapListToSource(const QModelIndexList& indexes) const;
QModelIndexList mapListFromSource(const QModelIndexList& indexes, bool deep = false) const;
// Performs sort of items. // Fix for matching indexes with respect to specifics of the message model.
void sort(int column, Qt::SortOrder order = Qt::AscendingOrder); QModelIndexList match(const QModelIndex& start, int role, const QVariant& entered_value, int hits, Qt::MatchFlags flags) const;
private: // Performs sort of items.
QModelIndex getNextUnreadItemIndex(int default_row, int max_row) const; void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
// Compares two rows of data. private:
bool lessThan(const QModelIndex& left, const QModelIndex& right) const; QModelIndex getNextUnreadItemIndex(int default_row, int max_row) const;
// Source model pointer. // Compares two rows of data.
MessagesModel* m_sourceModel; bool lessThan(const QModelIndex& left, const QModelIndex& right) const;
// Source model pointer.
MessagesModel* m_sourceModel;
}; };
#endif // MESSAGESPROXYMODEL_H #endif // MESSAGESPROXYMODEL_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -46,7 +47,8 @@
#define DEFAULT_LOCALE "en" #define DEFAULT_LOCALE "en"
#define DEFAULT_FEED_ENCODING "UTF-8" #define DEFAULT_FEED_ENCODING "UTF-8"
#define DEFAULT_FEED_TYPE "RSS" #define DEFAULT_FEED_TYPE "RSS"
#define URL_REGEXP "^(http|https|feed|ftp):\\/\\/[\\w\\-_]+(\\.[\\w\\-_]+)+([\\w\\-\\.,@?^=%&amp;:/~\\+#]*[\\w\\-\\@?^=%&amp;/~\\+#])?$" #define URL_REGEXP \
"^(http|https|feed|ftp):\\/\\/[\\w\\-_]+(\\.[\\w\\-_]+)+([\\w\\-\\.,@?^=%&amp;:/~\\+#]*[\\w\\-\\@?^=%&amp;/~\\+#])?$"
#define USER_AGENT_HTTP_HEADER "User-Agent" #define USER_AGENT_HTTP_HEADER "User-Agent"
#define TEXT_TITLE_LIMIT 30 #define TEXT_TITLE_LIMIT 30
#define RESELECT_MESSAGE_THRESSHOLD 500 #define RESELECT_MESSAGE_THRESSHOLD 500
@ -140,6 +142,7 @@
#define APP_THEME_SUFFIX ".png" #define APP_THEME_SUFFIX ".png"
#ifndef QSL #ifndef QSL
// Thin macro wrapper for literal strings. // Thin macro wrapper for literal strings.
// They are much more memory efficient and faster. // They are much more memory efficient and faster.
// Use it for all literals except for two cases: // Use it for all literals except for two cases:
@ -149,12 +152,14 @@
#endif #endif
#ifndef QL1S #ifndef QL1S
// Macro for latin strings. Latin strings are // Macro for latin strings. Latin strings are
// faster than QStrings created from literals. // faster than QStrings created from literals.
#define QL1S(x) QLatin1String(x) #define QL1S(x) QLatin1String(x)
#endif #endif
#ifndef QL1C #ifndef QL1C
// Macro for latin chars. // Macro for latin chars.
#define QL1C(x) QLatin1Char(x) #define QL1C(x) QLatin1Char(x)
#endif #endif

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -23,25 +24,24 @@
#include <QAction> #include <QAction>
DynamicShortcuts::DynamicShortcuts() {}
DynamicShortcuts::DynamicShortcuts() {
}
void DynamicShortcuts::save(const QList<QAction*>& actions) { void DynamicShortcuts::save(const QList<QAction*>& actions) {
Settings* settings = qApp->settings(); Settings* settings = qApp->settings();
foreach (const QAction* action, actions) { foreach (const QAction* action, actions) {
settings->setValue(GROUP(Keyboard), action->objectName(), action->shortcut().toString(QKeySequence::PortableText)); settings->setValue(GROUP(Keyboard), action->objectName(), action->shortcut().toString(QKeySequence::PortableText));
} }
} }
void DynamicShortcuts::load(const QList<QAction*>& actions) { void DynamicShortcuts::load(const QList<QAction*>& actions) {
Settings* settings = qApp->settings(); Settings* settings = qApp->settings();
foreach (QAction* action, actions) { foreach (QAction* action, actions) {
QString shortcut_for_action = settings->value(GROUP(Keyboard), QString shortcut_for_action = settings->value(GROUP(Keyboard),
action->objectName(), action->objectName(),
action->shortcut().toString(QKeySequence::PortableText)).toString(); action->shortcut().toString(QKeySequence::PortableText)).toString();
action->setShortcut(QKeySequence::fromString(shortcut_for_action, QKeySequence::PortableText));
} action->setShortcut(QKeySequence::fromString(shortcut_for_action, QKeySequence::PortableText));
}
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -20,22 +21,23 @@
#include <QList> #include <QList>
class QAction; class QAction;
class DynamicShortcuts { class DynamicShortcuts {
public: public:
// Checks the application settings and then initializes shortcut of
// each action from actions from the settings.
static void load(const QList<QAction*>& actions);
// Stores shortcut of each action from actions into the application // Checks the application settings and then initializes shortcut of
// settings. // each action from actions from the settings.
static void save(const QList<QAction*>& actions); static void load(const QList<QAction*>& actions);
private: // Stores shortcut of each action from actions into the application
// Constructor. // settings.
explicit DynamicShortcuts(); static void save(const QList<QAction*>& actions);
private:
// Constructor.
explicit DynamicShortcuts();
}; };
#endif // DYNAMICSHORTCUTS_H #endif // DYNAMICSHORTCUTS_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -17,93 +18,97 @@
#include "dynamic-shortcuts/dynamicshortcutswidget.h" #include "dynamic-shortcuts/dynamicshortcutswidget.h"
#include "dynamic-shortcuts/shortcutcatcher.h"
#include "dynamic-shortcuts/shortcutbutton.h"
#include "definitions/definitions.h" #include "definitions/definitions.h"
#include "dynamic-shortcuts/shortcutbutton.h"
#include "dynamic-shortcuts/shortcutcatcher.h"
#include <QGridLayout>
#include <QAction> #include <QAction>
#include <QGridLayout>
#include <QLabel> #include <QLabel>
DynamicShortcutsWidget::DynamicShortcutsWidget(QWidget* parent) : QWidget(parent) { DynamicShortcutsWidget::DynamicShortcutsWidget(QWidget* parent) : QWidget(parent) {
// Create layout for this control and set is as active. // Create layout for this control and set is as active.
m_layout = new QGridLayout(this); m_layout = new QGridLayout(this);
m_layout->setMargin(0); m_layout->setMargin(0);
setLayout(m_layout); setLayout(m_layout);
} }
DynamicShortcutsWidget::~DynamicShortcutsWidget() { DynamicShortcutsWidget::~DynamicShortcutsWidget() {
delete m_layout; delete m_layout;
} }
bool DynamicShortcutsWidget::areShortcutsUnique() const { bool DynamicShortcutsWidget::areShortcutsUnique() const {
QList<QKeySequence> all_shortcuts; QList<QKeySequence> all_shortcuts;
// Obtain all shortcuts. // Obtain all shortcuts.
foreach (const ActionBinding& binding, m_actionBindings) { foreach (const ActionBinding& binding, m_actionBindings) {
const QKeySequence new_shortcut = binding.second->shortcut(); const QKeySequence new_shortcut = binding.second->shortcut();
if (!new_shortcut.isEmpty() && all_shortcuts.contains(new_shortcut)) { if (!new_shortcut.isEmpty() && all_shortcuts.contains(new_shortcut)) {
// Problem, two identical non-empty shortcuts found. // Problem, two identical non-empty shortcuts found.
return false; return false;
} }
else { else {
all_shortcuts.append(binding.second->shortcut()); all_shortcuts.append(binding.second->shortcut());
} }
} }
return true; return true;
} }
void DynamicShortcutsWidget::updateShortcuts() { void DynamicShortcutsWidget::updateShortcuts() {
foreach (const ActionBinding& binding, m_actionBindings) { foreach (const ActionBinding& binding, m_actionBindings) {
binding.first->setShortcut(binding.second->shortcut()); binding.first->setShortcut(binding.second->shortcut());
} }
} }
void DynamicShortcutsWidget::populate(QList<QAction*> actions) { void DynamicShortcutsWidget::populate(QList<QAction*> actions) {
m_actionBindings.clear(); m_actionBindings.clear();
qSort(actions.begin(), actions.end(), DynamicShortcutsWidget::lessThan); qSort(actions.begin(), actions.end(), DynamicShortcutsWidget::lessThan);
int row_id = 0; int row_id = 0;
// FIXME: Maybe separate actions into "categories". Each category will start with label. // FIXME: Maybe separate actions into "categories". Each category will start with label.
// I will assign each QAaction a property called "category" with some enum value. // I will assign each QAaction a property called "category" with some enum value.
// Like: // Like:
// File, FeedsCategories, Messages, Tools, WebBrowser, Help // File, FeedsCategories, Messages, Tools, WebBrowser, Help
// This will be setup in FormMain::allActions(). // This will be setup in FormMain::allActions().
// Then here I will process actions into categories. // Then here I will process actions into categories.
foreach (QAction* action, actions) { foreach (QAction* action, actions) {
// Create shortcut catcher for this action and set default shortcut. // Create shortcut catcher for this action and set default shortcut.
ShortcutCatcher* catcher = new ShortcutCatcher(this); ShortcutCatcher* catcher = new ShortcutCatcher(this);
catcher->setDefaultShortcut(action->shortcut());
// Store information for re-initialization of shortcuts
// of actions when widget gets "confirmed".
QPair<QAction*, ShortcutCatcher*> new_binding;
new_binding.first = action;
new_binding.second = catcher;
m_actionBindings << new_binding;
// Add new catcher to our control.
QLabel* action_label = new QLabel(this);
action_label->setText(action->text().remove(QSL("&")));
action_label->setToolTip(action->toolTip());
action_label->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
QLabel* action_icon = new QLabel(this);
action_icon->setPixmap(action->icon().pixmap(ICON_SIZE_SETTINGS, ICON_SIZE_SETTINGS));
action_icon->setToolTip(action->toolTip());
m_layout->addWidget(action_icon, row_id, 0);
m_layout->addWidget(action_label, row_id, 1);
m_layout->addWidget(catcher, row_id, 2);
row_id++;
connect(catcher, &ShortcutCatcher::shortcutChanged, this, &DynamicShortcutsWidget::setupChanged);
}
// Make sure that "spacer" is added. catcher->setDefaultShortcut(action->shortcut());
m_layout->setRowStretch(row_id, 1);
m_layout->setColumnStretch(1, 1); // Store information for re-initialization of shortcuts
// of actions when widget gets "confirmed".
QPair<QAction*, ShortcutCatcher*> new_binding;
new_binding.first = action;
new_binding.second = catcher;
m_actionBindings << new_binding;
// Add new catcher to our control.
QLabel* action_label = new QLabel(this);
action_label->setText(action->text().remove(QSL("&")));
action_label->setToolTip(action->toolTip());
action_label->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
QLabel* action_icon = new QLabel(this);
action_icon->setPixmap(action->icon().pixmap(ICON_SIZE_SETTINGS, ICON_SIZE_SETTINGS));
action_icon->setToolTip(action->toolTip());
m_layout->addWidget(action_icon, row_id, 0);
m_layout->addWidget(action_label, row_id, 1);
m_layout->addWidget(catcher, row_id, 2);
row_id++;
connect(catcher, &ShortcutCatcher::shortcutChanged, this, &DynamicShortcutsWidget::setupChanged);
}
// Make sure that "spacer" is added.
m_layout->setRowStretch(row_id, 1);
m_layout->setColumnStretch(1, 1);
} }
bool DynamicShortcutsWidget::lessThan(QAction* lhs, QAction* rhs) { bool DynamicShortcutsWidget::lessThan(QAction* lhs, QAction* rhs) {
return QString::localeAwareCompare(lhs->text().replace(QL1S("&"), QString()), rhs->text().replace(QL1S("&"), QString())) < 0; return QString::localeAwareCompare(lhs->text().replace(QL1S("&"), QString()), rhs->text().replace(QL1S("&"), QString())) < 0;
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -20,45 +21,46 @@
#include <QWidget> #include <QWidget>
class QGridLayout; class QGridLayout;
class ShortcutCatcher; class ShortcutCatcher;
typedef QPair<QAction*, ShortcutCatcher*> ActionBinding; typedef QPair<QAction*, ShortcutCatcher*> ActionBinding;
class DynamicShortcutsWidget : public QWidget { class DynamicShortcutsWidget : public QWidget {
Q_OBJECT Q_OBJECT
public: public:
// Constructors and destructors.
explicit DynamicShortcutsWidget(QWidget* parent = 0);
virtual ~DynamicShortcutsWidget();
// Updates shortcuts of all actions according to changes. // Constructors and destructors.
// NOTE: No access to settings is done here. explicit DynamicShortcutsWidget(QWidget* parent = 0);
// Shortcuts are fetched from settings when applications starts virtual ~DynamicShortcutsWidget();
// and stored back to settings when application quits.
void updateShortcuts();
// Returns true if all shortcuts are unique, // Updates shortcuts of all actions according to changes.
// otherwise false. // NOTE: No access to settings is done here.
bool areShortcutsUnique() const; // Shortcuts are fetched from settings when applications starts
// and stored back to settings when application quits.
void updateShortcuts();
// Populates this widget with shortcut widgets for given actions. // Returns true if all shortcuts are unique,
// NOTE: This gets initial shortcut for each action from its properties, NOT from // otherwise false.
// the application settings, so shortcuts from settings need to be bool areShortcutsUnique() const;
// assigned to actions before calling this method.
void populate(QList<QAction*> actions);
signals: // Populates this widget with shortcut widgets for given actions.
void setupChanged(); // NOTE: This gets initial shortcut for each action from its properties, NOT from
// the application settings, so shortcuts from settings need to be
// assigned to actions before calling this method.
void populate(QList<QAction*> actions);
private: signals:
static bool lessThan(QAction* lhs, QAction* rhs); void setupChanged();
private: private:
QGridLayout* m_layout; static bool lessThan(QAction* lhs, QAction* rhs);
QList<ActionBinding> m_actionBindings;
private:
QGridLayout* m_layout;
QList<ActionBinding> m_actionBindings;
}; };
#endif // DYNAMICSHORTCUTSOVERVIEW_H #endif // DYNAMICSHORTCUTSOVERVIEW_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -16,32 +17,32 @@
// along with RSS Guard. If not, see <http://www.gnu.org/licenses/>. // along with RSS Guard. If not, see <http://www.gnu.org/licenses/>.
/****************************************************************************** /******************************************************************************
Copyright (c) 2010, Artem Galichkin <doomer3d@gmail.com> Copyright (c) 2010, Artem Galichkin <doomer3d@gmail.com>
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright * Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer. notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright * Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution. documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the * Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission. derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/ *******************************************************************************/
#include "dynamic-shortcuts/shortcutbutton.h" #include "dynamic-shortcuts/shortcutbutton.h"
@ -49,94 +50,92 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QKeyEvent> #include <QKeyEvent>
ShortcutButton::ShortcutButton(ShortcutCatcher* catcher, QWidget* parent) ShortcutButton::ShortcutButton(ShortcutCatcher* catcher, QWidget* parent)
: QPushButton(parent), m_catcher(catcher) { : QPushButton(parent), m_catcher(catcher) {
setMinimumWidth(100); setMinimumWidth(100);
} }
ShortcutButton::~ShortcutButton() { ShortcutButton::~ShortcutButton() {}
}
void ShortcutButton::keyPressEvent(QKeyEvent* event) { void ShortcutButton::keyPressEvent(QKeyEvent* event) {
int pressed_key = event->key(); int pressed_key = event->key();
if (pressed_key == -1) { if (pressed_key == -1) {
m_catcher->doneRecording(); m_catcher->doneRecording();
} }
const Qt::KeyboardModifiers new_modifiers = event->modifiers() & (Qt::SHIFT | Qt::CTRL | Qt::ALT | Qt::META); const Qt::KeyboardModifiers new_modifiers = event->modifiers() & (Qt::SHIFT | Qt::CTRL | Qt::ALT | Qt::META);
if (!m_catcher->m_isRecording && (pressed_key == Qt::Key_Return || pressed_key == Qt::Key_Space)) { if (!m_catcher->m_isRecording && (pressed_key == Qt::Key_Return || pressed_key == Qt::Key_Space)) {
return; return;
} }
if (!m_catcher->m_isRecording) { if (!m_catcher->m_isRecording) {
QPushButton::keyPressEvent(event); QPushButton::keyPressEvent(event);
return; return;
} }
event->accept(); event->accept();
m_catcher->m_modifierKeys = new_modifiers; m_catcher->m_modifierKeys = new_modifiers;
switch (pressed_key) { switch (pressed_key) {
case Qt::Key_AltGr: case Qt::Key_AltGr:
return; return;
case Qt::Key_Shift: case Qt::Key_Shift:
case Qt::Key_Control: case Qt::Key_Control:
case Qt::Key_Alt: case Qt::Key_Alt:
case Qt::Key_Meta: case Qt::Key_Meta:
case Qt::Key_Menu: case Qt::Key_Menu:
m_catcher->controlModifierlessTimout(); m_catcher->controlModifierlessTimout();
m_catcher->updateDisplayShortcut(); m_catcher->updateDisplayShortcut();
break; break;
default: default:
// We now have a valid key press. // We now have a valid key press.
if (pressed_key) { if (pressed_key) {
if ((pressed_key == Qt::Key_Backtab) && (m_catcher->m_modifierKeys & Qt::SHIFT)) { if ((pressed_key == Qt::Key_Backtab) && (m_catcher->m_modifierKeys & Qt::SHIFT)) {
pressed_key = Qt::Key_Tab | m_catcher->m_modifierKeys; pressed_key = Qt::Key_Tab | m_catcher->m_modifierKeys;
} }
else { else {
pressed_key |= m_catcher->m_modifierKeys; pressed_key |= m_catcher->m_modifierKeys;
} }
if (m_catcher->m_numKey == 0) { if (m_catcher->m_numKey == 0) {
m_catcher->m_currentSequence = QKeySequence(pressed_key); m_catcher->m_currentSequence = QKeySequence(pressed_key);
} }
m_catcher->m_numKey++; m_catcher->m_numKey++;
if (m_catcher->m_numKey >= 4) { if (m_catcher->m_numKey >= 4) {
m_catcher->doneRecording(); m_catcher->doneRecording();
return; return;
} }
m_catcher->controlModifierlessTimout(); m_catcher->controlModifierlessTimout();
m_catcher->updateDisplayShortcut(); m_catcher->updateDisplayShortcut();
} }
} }
} }
void ShortcutButton::keyReleaseEvent(QKeyEvent* event) { void ShortcutButton::keyReleaseEvent(QKeyEvent* event) {
if (event->key() == -1) { if (event->key() == -1) {
return; return;
} }
if (!m_catcher->m_isRecording) { if (!m_catcher->m_isRecording) {
QPushButton::keyReleaseEvent(event); QPushButton::keyReleaseEvent(event);
return; return;
} }
event->accept(); event->accept();
const Qt::KeyboardModifiers new_modifiers = event->modifiers() & const Qt::KeyboardModifiers new_modifiers = event->modifiers() &
(Qt::SHIFT | Qt::CTRL | Qt::ALT | Qt::META); (Qt::SHIFT | Qt::CTRL | Qt::ALT | Qt::META);
if (((uint) new_modifiers & m_catcher->m_modifierKeys) < m_catcher->m_modifierKeys) { if (((uint) new_modifiers & m_catcher->m_modifierKeys) < m_catcher->m_modifierKeys) {
m_catcher->m_modifierKeys = new_modifiers; m_catcher->m_modifierKeys = new_modifiers;
m_catcher->controlModifierlessTimout(); m_catcher->controlModifierlessTimout();
m_catcher->updateDisplayShortcut(); m_catcher->updateDisplayShortcut();
} }
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -16,55 +17,55 @@
// along with RSS Guard. If not, see <http://www.gnu.org/licenses/>. // along with RSS Guard. If not, see <http://www.gnu.org/licenses/>.
/****************************************************************************** /******************************************************************************
Copyright (c) 2010, Artem Galichkin <doomer3d@gmail.com> Copyright (c) 2010, Artem Galichkin <doomer3d@gmail.com>
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright * Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer. notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright * Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution. documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the * Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission. derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/ *******************************************************************************/
#ifndef SHORTCUTBUTTON_H #ifndef SHORTCUTBUTTON_H
#define SHORTCUTBUTTON_H #define SHORTCUTBUTTON_H
#include <QPushButton> #include <QPushButton>
class ShortcutCatcher; class ShortcutCatcher;
class ShortcutButton : public QPushButton { class ShortcutButton : public QPushButton {
Q_OBJECT Q_OBJECT
public: public:
// Constructors and destructors.
explicit ShortcutButton(ShortcutCatcher* catcher, QWidget* parent = 0);
virtual ~ShortcutButton();
protected: // Constructors and destructors.
void keyPressEvent(QKeyEvent* event); explicit ShortcutButton(ShortcutCatcher* catcher, QWidget* parent = 0);
void keyReleaseEvent(QKeyEvent* event); virtual ~ShortcutButton();
private: protected:
ShortcutCatcher* m_catcher; void keyPressEvent(QKeyEvent* event);
void keyReleaseEvent(QKeyEvent* event);
private:
ShortcutCatcher* m_catcher;
}; };
#endif // SHORTCUTBUTTON_H #endif // SHORTCUTBUTTON_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -16,32 +17,32 @@
// along with RSS Guard. If not, see <http://www.gnu.org/licenses/>. // along with RSS Guard. If not, see <http://www.gnu.org/licenses/>.
/****************************************************************************** /******************************************************************************
Copyright (c) 2010, Artem Galichkin <doomer3d@gmail.com> Copyright (c) 2010, Artem Galichkin <doomer3d@gmail.com>
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright * Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer. notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright * Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution. documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the * Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission. derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/ *******************************************************************************/
#include "dynamic-shortcuts/shortcutcatcher.h" #include "dynamic-shortcuts/shortcutcatcher.h"
@ -51,119 +52,125 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QHBoxLayout> #include <QHBoxLayout>
ShortcutCatcher::ShortcutCatcher(QWidget* parent) ShortcutCatcher::ShortcutCatcher(QWidget* parent)
: QWidget(parent) { : QWidget(parent) {
// Setup layout of the control // Setup layout of the control
m_layout = new QHBoxLayout(this); m_layout = new QHBoxLayout(this);
m_layout->setMargin(0); m_layout->setMargin(0);
m_layout->setSpacing(1); m_layout->setSpacing(1);
// Create reset button.
m_btnReset = new PlainToolButton(this); // Create reset button.
m_btnReset->setIcon(qApp->icons()->fromTheme(QSL("document-revert"))); m_btnReset = new PlainToolButton(this);
m_btnReset->setFocusPolicy(Qt::NoFocus); m_btnReset->setIcon(qApp->icons()->fromTheme(QSL("document-revert")));
m_btnReset->setToolTip(tr("Reset to original shortcut.")); m_btnReset->setFocusPolicy(Qt::NoFocus);
// Create clear button. m_btnReset->setToolTip(tr("Reset to original shortcut."));
m_btnClear = new PlainToolButton(this);
m_btnClear->setIcon(qApp->icons()->fromTheme(QSL("list-remove"))); // Create clear button.
m_btnClear->setFocusPolicy(Qt::NoFocus); m_btnClear = new PlainToolButton(this);
m_btnClear->setToolTip(tr("Clear current shortcut.")); m_btnClear->setIcon(qApp->icons()->fromTheme(QSL("list-remove")));
// Clear main shortcut catching button. m_btnClear->setFocusPolicy(Qt::NoFocus);
m_btnChange = new ShortcutButton(this); m_btnClear->setToolTip(tr("Clear current shortcut."));
m_btnChange->setFocusPolicy(Qt::StrongFocus);
m_btnChange->setToolTip(tr("Click and hit new shortcut.")); // Clear main shortcut catching button.
// Add both buttons to the layout. m_btnChange = new ShortcutButton(this);
m_layout->addWidget(m_btnChange); m_btnChange->setFocusPolicy(Qt::StrongFocus);
m_layout->addWidget(m_btnReset); m_btnChange->setToolTip(tr("Click and hit new shortcut."));
m_layout->addWidget(m_btnClear);
// Establish needed connections. // Add both buttons to the layout.
connect(m_btnReset, &QToolButton::clicked, this, &ShortcutCatcher::resetShortcut); m_layout->addWidget(m_btnChange);
connect(m_btnClear, &QToolButton::clicked, this, &ShortcutCatcher::clearShortcut); m_layout->addWidget(m_btnReset);
connect(m_btnChange, &QToolButton::clicked, this, &ShortcutCatcher::startRecording); m_layout->addWidget(m_btnClear);
// Prepare initial state of the control.
updateDisplayShortcut(); // Establish needed connections.
connect(m_btnReset, &QToolButton::clicked, this, &ShortcutCatcher::resetShortcut);
connect(m_btnClear, &QToolButton::clicked, this, &ShortcutCatcher::clearShortcut);
connect(m_btnChange, &QToolButton::clicked, this, &ShortcutCatcher::startRecording);
// Prepare initial state of the control.
updateDisplayShortcut();
} }
ShortcutCatcher::~ShortcutCatcher() { ShortcutCatcher::~ShortcutCatcher() {
delete m_btnReset; delete m_btnReset;
delete m_btnChange; delete m_btnChange;
delete m_btnClear; delete m_btnClear;
delete m_layout; delete m_layout;
} }
void ShortcutCatcher::startRecording() { void ShortcutCatcher::startRecording() {
m_numKey = 0; m_numKey = 0;
m_modifierKeys = 0; m_modifierKeys = 0;
m_currentSequence = QKeySequence(); m_currentSequence = QKeySequence();
m_isRecording = true; m_isRecording = true;
m_btnChange->setDown(true); m_btnChange->setDown(true);
m_btnChange->grabKeyboard(); m_btnChange->grabKeyboard();
updateDisplayShortcut(); updateDisplayShortcut();
} }
void ShortcutCatcher::doneRecording() { void ShortcutCatcher::doneRecording() {
m_isRecording = false; m_isRecording = false;
m_btnChange->releaseKeyboard(); m_btnChange->releaseKeyboard();
m_btnChange->setDown(false); m_btnChange->setDown(false);
updateDisplayShortcut(); updateDisplayShortcut();
emit shortcutChanged(m_currentSequence); emit shortcutChanged(m_currentSequence);
} }
void ShortcutCatcher::controlModifierlessTimout() { void ShortcutCatcher::controlModifierlessTimout() {
if (m_numKey && !m_modifierKeys) { if (m_numKey && !m_modifierKeys) {
doneRecording(); doneRecording();
} }
} }
void ShortcutCatcher::updateDisplayShortcut() { void ShortcutCatcher::updateDisplayShortcut() {
QString str = m_currentSequence.toString(QKeySequence::NativeText); QString str = m_currentSequence.toString(QKeySequence::NativeText);
str.replace(QL1S("&"), QL1S("&&"));
if (m_isRecording) { str.replace(QL1S("&"), QL1S("&&"));
if (m_modifierKeys) {
if (!str.isEmpty()) {
str.append(QSL(","));
}
if (m_modifierKeys & Qt::META) { if (m_isRecording) {
str += QL1S("Meta + "); if (m_modifierKeys) {
} if (!str.isEmpty()) {
str.append(QSL(","));
}
if (m_modifierKeys & Qt::CTRL) { if (m_modifierKeys & Qt::META) {
str += QL1S("Ctrl + "); str += QL1S("Meta + ");
} }
if (m_modifierKeys & Qt::ALT) { if (m_modifierKeys & Qt::CTRL) {
str += QL1S("Alt + "); str += QL1S("Ctrl + ");
} }
if (m_modifierKeys & Qt::SHIFT) { if (m_modifierKeys & Qt::ALT) {
str += QL1S("Shift + "); str += QL1S("Alt + ");
} }
}
}
m_btnChange->setText(str); if (m_modifierKeys & Qt::SHIFT) {
str += QL1S("Shift + ");
}
}
}
m_btnChange->setText(str);
} }
QKeySequence ShortcutCatcher::shortcut() const { QKeySequence ShortcutCatcher::shortcut() const {
return m_currentSequence; return m_currentSequence;
} }
void ShortcutCatcher::setDefaultShortcut(const QKeySequence& key) { void ShortcutCatcher::setDefaultShortcut(const QKeySequence& key) {
m_defaultSequence = key; m_defaultSequence = key;
setShortcut(key); setShortcut(key);
} }
void ShortcutCatcher::setShortcut(const QKeySequence& key) { void ShortcutCatcher::setShortcut(const QKeySequence& key) {
m_currentSequence = key; m_currentSequence = key;
doneRecording(); doneRecording();
} }
void ShortcutCatcher::resetShortcut() { void ShortcutCatcher::resetShortcut() {
setShortcut(m_defaultSequence); setShortcut(m_defaultSequence);
} }
void ShortcutCatcher::clearShortcut() { void ShortcutCatcher::clearShortcut() {
setShortcut(QKeySequence()); setShortcut(QKeySequence());
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -16,83 +17,81 @@
// along with RSS Guard. If not, see <http://www.gnu.org/licenses/>. // along with RSS Guard. If not, see <http://www.gnu.org/licenses/>.
/****************************************************************************** /******************************************************************************
Copyright (c) 2010, Artem Galichkin <doomer3d@gmail.com> Copyright (c) 2010, Artem Galichkin <doomer3d@gmail.com>
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright * Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer. notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright * Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution. documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the * Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission. derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/ *******************************************************************************/
#ifndef SHORTCUTCATCHER_H #ifndef SHORTCUTCATCHER_H
#define SHORTCUTCATCHER_H #define SHORTCUTCATCHER_H
#include <QWidget> #include <QWidget>
class QHBoxLayout; class QHBoxLayout;
class QToolButton; class QToolButton;
class ShortcutButton; class ShortcutButton;
class ShortcutCatcher : public QWidget { class ShortcutCatcher : public QWidget {
Q_OBJECT Q_OBJECT
friend class ShortcutButton; friend class ShortcutButton;
public: public:
// Constructors and destructors.
explicit ShortcutCatcher(QWidget* parent = 0);
virtual ~ShortcutCatcher();
void controlModifierlessTimout(); // Constructors and destructors.
void updateDisplayShortcut(); explicit ShortcutCatcher(QWidget* parent = 0);
virtual ~ShortcutCatcher();
QKeySequence shortcut() const; void controlModifierlessTimout();
void setDefaultShortcut(const QKeySequence& key); void updateDisplayShortcut();
void setShortcut(const QKeySequence& key);
public slots: QKeySequence shortcut() const;
void resetShortcut(); void setDefaultShortcut(const QKeySequence& key);
void clearShortcut(); void setShortcut(const QKeySequence& key);
private slots: public slots:
void startRecording(); void resetShortcut();
void doneRecording(); void clearShortcut();
signals: private slots:
void shortcutChanged(const QKeySequence& seguence); void startRecording();
void doneRecording();
private: signals:
QToolButton* m_btnReset; void shortcutChanged(const QKeySequence& seguence);
QToolButton* m_btnClear;
ShortcutButton* m_btnChange;
QHBoxLayout* m_layout;
QKeySequence m_currentSequence; private:
QKeySequence m_defaultSequence; QToolButton* m_btnReset;
QToolButton* m_btnClear;
bool m_isRecording; ShortcutButton* m_btnChange;
int m_numKey; QHBoxLayout* m_layout;
uint m_modifierKeys; QKeySequence m_currentSequence;
QKeySequence m_defaultSequence;
bool m_isRecording;
int m_numKey;
uint m_modifierKeys;
}; };
#endif // KEYSEQUENCECATCHER_H #endif // KEYSEQUENCECATCHER_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -17,13 +18,10 @@
#include "exceptions/applicationexception.h" #include "exceptions/applicationexception.h"
ApplicationException::ApplicationException(const QString& message) : m_message(message) {}
ApplicationException::ApplicationException(const QString& message) : m_message(message) { ApplicationException::~ApplicationException() {}
}
ApplicationException::~ApplicationException() {
}
QString ApplicationException::message() const { QString ApplicationException::message() const {
return m_message; return m_message;
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -20,16 +21,15 @@
#include <QString> #include <QString>
class ApplicationException { class ApplicationException {
public: public:
explicit ApplicationException(const QString& message = QString()); explicit ApplicationException(const QString& message = QString());
virtual ~ApplicationException(); virtual ~ApplicationException();
QString message() const; QString message() const;
private: private:
QString m_message; QString m_message;
}; };
#endif // APPLICATIONEXCEPTION_H #endif // APPLICATIONEXCEPTION_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -17,9 +18,6 @@
#include "exceptions/ioexception.h" #include "exceptions/ioexception.h"
IOException::IOException(const QString& message) : ApplicationException(message) {}
IOException::IOException(const QString& message) : ApplicationException(message) { IOException::~IOException() {}
}
IOException::~IOException() {
}

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -20,11 +21,10 @@
#include "exceptions/applicationexception.h" #include "exceptions/applicationexception.h"
class IOException : public ApplicationException { class IOException : public ApplicationException {
public: public:
explicit IOException(const QString& message = QString()); explicit IOException(const QString& message = QString());
virtual ~IOException(); virtual ~IOException();
}; };
#endif // IOEXCEPTION_H #endif // IOEXCEPTION_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -19,23 +20,21 @@
#include <QKeyEvent> #include <QKeyEvent>
BaseLineEdit::BaseLineEdit(QWidget* parent) : QLineEdit(parent) {}
BaseLineEdit::BaseLineEdit(QWidget* parent) : QLineEdit(parent) { BaseLineEdit::~BaseLineEdit() {}
}
BaseLineEdit::~BaseLineEdit() {
}
void BaseLineEdit::submit(const QString& text) { void BaseLineEdit::submit(const QString& text) {
setText(text); setText(text);
emit submitted(text); emit submitted(text);
} }
void BaseLineEdit::keyPressEvent(QKeyEvent* event) { void BaseLineEdit::keyPressEvent(QKeyEvent* event) {
if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) { if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
emit submitted(text()); emit submitted(text());
event->accept();
}
QLineEdit::keyPressEvent(event); event->accept();
}
QLineEdit::keyPressEvent(event);
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -20,24 +21,25 @@
#include <QLineEdit> #include <QLineEdit>
class BaseLineEdit : public QLineEdit { class BaseLineEdit : public QLineEdit {
Q_OBJECT Q_OBJECT
public: public:
// Constructors and destructors.
explicit BaseLineEdit(QWidget* parent = 0);
virtual ~BaseLineEdit();
public slots: // Constructors and destructors.
void submit(const QString& text); explicit BaseLineEdit(QWidget* parent = 0);
virtual ~BaseLineEdit();
protected: public slots:
void keyPressEvent(QKeyEvent* event); void submit(const QString& text);
signals: protected:
// Emitted if user hits ENTER button. void keyPressEvent(QKeyEvent* event);
void submitted(const QString& text);
signals:
// Emitted if user hits ENTER button.
void submitted(const QString& text);
}; };
#endif // BASELINEEDIT_H #endif // BASELINEEDIT_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -23,28 +24,28 @@
#include <QWidgetAction> #include <QWidgetAction>
BaseToolBar::BaseToolBar(const QString& title, QWidget* parent) : QToolBar(title, parent) { BaseToolBar::BaseToolBar(const QString& title, QWidget* parent) : QToolBar(title, parent) {
// Update right margin of filter textbox. // Update right margin of filter textbox.
QMargins margins = contentsMargins(); QMargins margins = contentsMargins();
margins.setRight(margins.right() + FILTER_RIGHT_MARGIN);
setContentsMargins(margins); margins.setRight(margins.right() + FILTER_RIGHT_MARGIN);
setContentsMargins(margins);
} }
BaseToolBar::~BaseToolBar() { BaseToolBar::~BaseToolBar() {
qDebug("Destroying BaseToolBar instance."); qDebug("Destroying BaseToolBar instance.");
} }
void BaseBar::loadSavedActions() { void BaseBar::loadSavedActions() {
loadSpecificActions(getSpecificActions(savedActions())); loadSpecificActions(getSpecificActions(savedActions()));
} }
QAction* BaseBar::findMatchingAction(const QString& action, const QList<QAction*>& actions) const { QAction* BaseBar::findMatchingAction(const QString& action, const QList<QAction*>& actions) const {
foreach (QAction* act, actions) { foreach (QAction* act, actions) {
if (act->objectName() == action) { if (act->objectName() == action) {
return act; return act;
} }
} }
return nullptr; return nullptr;
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -20,41 +21,41 @@
#include <QToolBar> #include <QToolBar>
class BaseBar { class BaseBar {
public: public:
// Returns all actions which can be added to the toolbar.
virtual QList<QAction*> availableActions() const = 0;
// Returns all changeable actions which are currently included // Returns all actions which can be added to the toolbar.
// in the toolbar. virtual QList<QAction*> availableActions() const = 0;
virtual QList<QAction*> changeableActions() const = 0;
// Sets new "actions" to the toolbar and perhaps saves the toolbar // Returns all changeable actions which are currently included
// state into the settings. // in the toolbar.
virtual void saveChangeableActions(const QStringList& actions) = 0; virtual QList<QAction*> changeableActions() const = 0;
// Returns list of default actions. // Sets new "actions" to the toolbar and perhaps saves the toolbar
virtual QStringList defaultActions() const = 0; // state into the settings.
virtual QStringList savedActions() const = 0; virtual void saveChangeableActions(const QStringList& actions) = 0;
// Loads the toolbar state from settings. // Returns list of default actions.
virtual void loadSavedActions(); virtual QStringList defaultActions() const = 0;
virtual QStringList savedActions() const = 0;
virtual QList<QAction*> getSpecificActions(const QStringList& actions) = 0; // Loads the toolbar state from settings.
virtual void loadSpecificActions(const QList<QAction*>& actions) = 0; virtual void loadSavedActions();
virtual QList<QAction*> getSpecificActions(const QStringList& actions) = 0;
virtual void loadSpecificActions(const QList<QAction*>& actions) = 0;
protected: protected:
QAction* findMatchingAction(const QString& action, const QList<QAction*>& actions) const; QAction* findMatchingAction(const QString& action, const QList<QAction*>& actions) const;
}; };
class BaseToolBar : public QToolBar, public BaseBar { class BaseToolBar : public QToolBar, public BaseBar {
Q_OBJECT Q_OBJECT
public: public:
// Constructors and destructors.
explicit BaseToolBar(const QString& title, QWidget* parent = 0); // Constructors and destructors.
virtual ~BaseToolBar(); explicit BaseToolBar(const QString& title, QWidget* parent = 0);
virtual ~BaseToolBar();
}; };
#endif // TOOLBAR_H #endif // TOOLBAR_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -17,26 +18,24 @@
#include "gui/colorlabel.h" #include "gui/colorlabel.h"
#include <QPaintEvent>
#include <QPainter> #include <QPainter>
#include <QPaintEvent>
ColorLabel::ColorLabel(QWidget* parent) : QLabel(parent), m_color(QColor()) { ColorLabel::ColorLabel(QWidget* parent) : QLabel(parent), m_color(QColor()) {
setFixedWidth(20); setFixedWidth(20);
} }
ColorLabel::~ColorLabel() { ColorLabel::~ColorLabel() {}
}
QColor ColorLabel::color() const { QColor ColorLabel::color() const {
return m_color; return m_color;
} }
void ColorLabel::setColor(const QColor& color) { void ColorLabel::setColor(const QColor& color) {
m_color = color; m_color = color;
repaint(); repaint();
} }
void ColorLabel::paintEvent(QPaintEvent* event) { void ColorLabel::paintEvent(QPaintEvent* event) {
QPainter(this).fillRect(event->rect(), m_color); QPainter(this).fillRect(event->rect(), m_color);
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -20,22 +21,21 @@
#include <QLabel> #include <QLabel>
class ColorLabel : public QLabel { class ColorLabel : public QLabel {
Q_OBJECT Q_OBJECT
public: public:
explicit ColorLabel(QWidget* parent = 0); explicit ColorLabel(QWidget* parent = 0);
virtual ~ColorLabel(); virtual ~ColorLabel();
QColor color() const; QColor color() const;
void setColor(const QColor& color); void setColor(const QColor& color);
protected: protected:
void paintEvent(QPaintEvent* event); void paintEvent(QPaintEvent* event);
private: private:
QColor m_color; QColor m_color;
}; };
#endif // COLORLABEL_H #endif // COLORLABEL_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -21,17 +22,18 @@
#include <QHBoxLayout> #include <QHBoxLayout>
ComboBoxWithStatus::ComboBoxWithStatus(QWidget* parent) ComboBoxWithStatus::ComboBoxWithStatus(QWidget* parent)
: WidgetWithStatus(parent) { : WidgetWithStatus(parent) {
m_wdgInput = new QComboBox(this); m_wdgInput = new QComboBox(this);
// Set correct size for the tool button.
const int txt_input_height = m_wdgInput->sizeHint().height(); // Set correct size for the tool button.
m_btnStatus->setFixedSize(txt_input_height, txt_input_height); const int txt_input_height = m_wdgInput->sizeHint().height();
// Compose the layout.
m_layout->addWidget(m_wdgInput); m_btnStatus->setFixedSize(txt_input_height, txt_input_height);
m_layout->addWidget(m_btnStatus);
// Compose the layout.
m_layout->addWidget(m_wdgInput);
m_layout->addWidget(m_btnStatus);
} }
ComboBoxWithStatus::~ComboBoxWithStatus() { ComboBoxWithStatus::~ComboBoxWithStatus() {}
}

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -22,18 +23,19 @@
#include <QComboBox> #include <QComboBox>
class ComboBoxWithStatus : public WidgetWithStatus { class ComboBoxWithStatus : public WidgetWithStatus {
Q_OBJECT Q_OBJECT
public: public:
// Constructors and destructors.
explicit ComboBoxWithStatus(QWidget* parent = 0); // Constructors and destructors.
virtual ~ComboBoxWithStatus(); explicit ComboBoxWithStatus(QWidget* parent = 0);
virtual ~ComboBoxWithStatus();
inline QComboBox* comboBox() const {
return static_cast<QComboBox*>(m_wdgInput);
}
inline QComboBox* comboBox() const {
return static_cast<QComboBox*>(m_wdgInput);
}
}; };
#endif // COMBOBOXWITHSTATUS_H #endif // COMBOBOXWITHSTATUS_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -24,20 +25,20 @@
#include "definitions/definitions.h" #include "definitions/definitions.h"
class FormAbout : public QDialog { class FormAbout : public QDialog {
Q_OBJECT Q_OBJECT
public: public:
// Constructors and destructors.
explicit FormAbout(QWidget* parent);
virtual ~FormAbout();
private: // Constructors and destructors.
void loadLicenseAndInformation(); explicit FormAbout(QWidget* parent);
void loadSettingsAndPaths(); virtual ~FormAbout();
Ui::FormAbout m_ui; private:
void loadLicenseAndInformation();
void loadSettingsAndPaths();
Ui::FormAbout m_ui;
}; };
#endif // FORMABOUT_H #endif // FORMABOUT_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -17,66 +18,67 @@
#include "gui/dialogs/formaddaccount.h" #include "gui/dialogs/formaddaccount.h"
#include "core/feedsmodel.h"
#include "miscellaneous/application.h" #include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h" #include "miscellaneous/iconfactory.h"
#include "core/feedsmodel.h"
#include "services/standard/standardserviceentrypoint.h" #include "services/standard/standardserviceentrypoint.h"
#include <QListWidget>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QListWidget>
FormAddAccount::FormAddAccount(const QList<ServiceEntryPoint*>& entry_points, FeedsModel* model, QWidget* parent) FormAddAccount::FormAddAccount(const QList<ServiceEntryPoint*>& entry_points, FeedsModel* model, QWidget* parent)
: QDialog(parent), m_ui(new Ui::FormAddAccount), m_model(model), m_entryPoints(entry_points) { : QDialog(parent), m_ui(new Ui::FormAddAccount), m_model(model), m_entryPoints(entry_points) {
m_ui->setupUi(this); m_ui->setupUi(this);
// Set flags and attributes.
setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint); // Set flags and attributes.
setWindowIcon(qApp->icons()->fromTheme(QSL("document-new"))); setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint);
connect(m_ui->m_listEntryPoints, &QListWidget::itemDoubleClicked, this, &FormAddAccount::addSelectedAccount); setWindowIcon(qApp->icons()->fromTheme(QSL("document-new")));
connect(m_ui->m_buttonBox, &QDialogButtonBox::accepted, this, &FormAddAccount::addSelectedAccount); connect(m_ui->m_listEntryPoints, &QListWidget::itemDoubleClicked, this, &FormAddAccount::addSelectedAccount);
connect(m_ui->m_listEntryPoints, &QListWidget::itemSelectionChanged, this, &FormAddAccount::displayActiveEntryPointDetails); connect(m_ui->m_buttonBox, &QDialogButtonBox::accepted, this, &FormAddAccount::addSelectedAccount);
loadEntryPoints(); connect(m_ui->m_listEntryPoints, &QListWidget::itemSelectionChanged, this, &FormAddAccount::displayActiveEntryPointDetails);
loadEntryPoints();
} }
FormAddAccount::~FormAddAccount() { FormAddAccount::~FormAddAccount() {
qDebug("Destroying FormAddAccount instance."); qDebug("Destroying FormAddAccount instance.");
} }
void FormAddAccount::addSelectedAccount() { void FormAddAccount::addSelectedAccount() {
accept(); accept();
ServiceEntryPoint* point = selectedEntryPoint(); ServiceEntryPoint* point = selectedEntryPoint();
ServiceRoot* new_root = point->createNewRoot(); ServiceRoot* new_root = point->createNewRoot();
if (new_root != nullptr) { if (new_root != nullptr) {
m_model->addServiceAccount(new_root, true); m_model->addServiceAccount(new_root, true);
} }
else { else {
qCritical("Cannot create new account."); qCritical("Cannot create new account.");
} }
} }
void FormAddAccount::displayActiveEntryPointDetails() { void FormAddAccount::displayActiveEntryPointDetails() {
const ServiceEntryPoint* point = selectedEntryPoint(); const ServiceEntryPoint* point = selectedEntryPoint();
m_ui->m_txtAuthor->setText(point->author());
m_ui->m_txtDescription->setText(point->description()); m_ui->m_txtAuthor->setText(point->author());
m_ui->m_txtName->setText(point->name()); m_ui->m_txtDescription->setText(point->description());
m_ui->m_txtVersion->setText(point->version()); m_ui->m_txtName->setText(point->name());
m_ui->m_txtVersion->setText(point->version());
} }
ServiceEntryPoint* FormAddAccount::selectedEntryPoint() const { ServiceEntryPoint* FormAddAccount::selectedEntryPoint() const {
return m_entryPoints.at(m_ui->m_listEntryPoints->currentRow()); return m_entryPoints.at(m_ui->m_listEntryPoints->currentRow());
} }
void FormAddAccount::loadEntryPoints() { void FormAddAccount::loadEntryPoints() {
foreach (const ServiceEntryPoint* entry_point, m_entryPoints) { foreach (const ServiceEntryPoint* entry_point, m_entryPoints) {
QListWidgetItem* item = new QListWidgetItem(entry_point->icon(), entry_point->name(), m_ui->m_listEntryPoints); QListWidgetItem* item = new QListWidgetItem(entry_point->icon(), entry_point->name(), m_ui->m_listEntryPoints);
if (entry_point->isSingleInstanceService() && m_model->containsServiceRootFromEntryPoint(entry_point)) { if (entry_point->isSingleInstanceService() && m_model->containsServiceRootFromEntryPoint(entry_point)) {
// Oops, this item cannot be added, it is single instance and is already added. // Oops, this item cannot be added, it is single instance and is already added.
item->setFlags(Qt::NoItemFlags); item->setFlags(Qt::NoItemFlags);
item->setToolTip(tr("This account can be added only once.")); item->setToolTip(tr("This account can be added only once."));
} }
} }
m_ui->m_listEntryPoints->setCurrentRow(m_entryPoints.size() - 1); m_ui->m_listEntryPoints->setCurrentRow(m_entryPoints.size() - 1);
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -22,28 +23,29 @@
#include "ui_formaddaccount.h" #include "ui_formaddaccount.h"
class ServiceEntryPoint; class ServiceEntryPoint;
class FeedsModel; class FeedsModel;
class FormAddAccount : public QDialog { class FormAddAccount : public QDialog {
Q_OBJECT Q_OBJECT
public: public:
explicit FormAddAccount(const QList<ServiceEntryPoint*>& entry_points, FeedsModel* model, QWidget* parent = 0); explicit FormAddAccount(const QList<ServiceEntryPoint*>& entry_points, FeedsModel* model, QWidget* parent = 0);
virtual ~FormAddAccount(); virtual ~FormAddAccount();
private slots: private slots:
void addSelectedAccount(); void addSelectedAccount();
void displayActiveEntryPointDetails(); void displayActiveEntryPointDetails();
private: private:
ServiceEntryPoint* selectedEntryPoint() const; ServiceEntryPoint* selectedEntryPoint() const;
void loadEntryPoints();
QScopedPointer<Ui::FormAddAccount> m_ui; void loadEntryPoints();
FeedsModel* m_model;
QList<ServiceEntryPoint*> m_entryPoints; QScopedPointer<Ui::FormAddAccount> m_ui;
FeedsModel* m_model;
QList<ServiceEntryPoint*> m_entryPoints;
}; };
#endif // FORMADDACCOUNT_H #endif // FORMADDACCOUNT_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -17,82 +18,82 @@
#include "gui/dialogs/formbackupdatabasesettings.h" #include "gui/dialogs/formbackupdatabasesettings.h"
#include "exceptions/applicationexception.h"
#include "miscellaneous/application.h" #include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h" #include "miscellaneous/iconfactory.h"
#include "exceptions/applicationexception.h"
#include <QDialogButtonBox>
#include <QPushButton>
#include <QCheckBox> #include <QCheckBox>
#include <QFileDialog>
#include <QDateTime> #include <QDateTime>
#include <QDialogButtonBox>
#include <QFileDialog>
#include <QPushButton>
FormBackupDatabaseSettings::FormBackupDatabaseSettings(QWidget* parent) : QDialog(parent), m_ui(new Ui::FormBackupDatabaseSettings) { FormBackupDatabaseSettings::FormBackupDatabaseSettings(QWidget* parent) : QDialog(parent), m_ui(new Ui::FormBackupDatabaseSettings) {
m_ui->setupUi(this); m_ui->setupUi(this);
m_ui->m_txtBackupName->lineEdit()->setPlaceholderText(tr("Common name for backup files")); m_ui->m_txtBackupName->lineEdit()->setPlaceholderText(tr("Common name for backup files"));
setWindowIcon(qApp->icons()->fromTheme(QSL("document-export"))); setWindowIcon(qApp->icons()->fromTheme(QSL("document-export")));
setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint); setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint);
connect(m_ui->m_checkBackupDatabase, &QCheckBox::toggled, this, &FormBackupDatabaseSettings::checkOkButton); connect(m_ui->m_checkBackupDatabase, &QCheckBox::toggled, this, &FormBackupDatabaseSettings::checkOkButton);
connect(m_ui->m_checkBackupSettings, &QCheckBox::toggled, this, &FormBackupDatabaseSettings::checkOkButton); connect(m_ui->m_checkBackupSettings, &QCheckBox::toggled, this, &FormBackupDatabaseSettings::checkOkButton);
connect(m_ui->m_buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &FormBackupDatabaseSettings::performBackup); connect(m_ui->m_buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &FormBackupDatabaseSettings::performBackup);
connect(m_ui->m_txtBackupName->lineEdit(), &BaseLineEdit::textChanged, this, &FormBackupDatabaseSettings::checkBackupNames); connect(m_ui->m_txtBackupName->lineEdit(), &BaseLineEdit::textChanged, this, &FormBackupDatabaseSettings::checkBackupNames);
connect(m_ui->m_txtBackupName->lineEdit(), &BaseLineEdit::textChanged, this, &FormBackupDatabaseSettings::checkOkButton); connect(m_ui->m_txtBackupName->lineEdit(), &BaseLineEdit::textChanged, this, &FormBackupDatabaseSettings::checkOkButton);
connect(m_ui->m_btnSelectFolder, &QPushButton::clicked, this, &FormBackupDatabaseSettings::selectFolderInitial); connect(m_ui->m_btnSelectFolder, &QPushButton::clicked, this, &FormBackupDatabaseSettings::selectFolderInitial);
selectFolder(qApp->documentsFolder()); selectFolder(qApp->documentsFolder());
m_ui->m_txtBackupName->lineEdit()->setText(QString(APP_LOW_NAME) + QL1S("_") + QDateTime::currentDateTime().toString(QSL("yyyyMMddHHmm"))); m_ui->m_txtBackupName->lineEdit()->setText(QString(APP_LOW_NAME) + QL1S("_") +
m_ui->m_lblResult->setStatus(WidgetWithStatus::Warning, tr("No operation executed yet."), tr("No operation executed yet.")); QDateTime::currentDateTime().toString(QSL("yyyyMMddHHmm")));
m_ui->m_lblResult->setStatus(WidgetWithStatus::Warning, tr("No operation executed yet."), tr("No operation executed yet."));
if (qApp->database()->activeDatabaseDriver() != DatabaseFactory::SQLITE && if (qApp->database()->activeDatabaseDriver() != DatabaseFactory::SQLITE &&
qApp->database()->activeDatabaseDriver() != DatabaseFactory::SQLITE_MEMORY) { qApp->database()->activeDatabaseDriver() != DatabaseFactory::SQLITE_MEMORY) {
m_ui->m_checkBackupDatabase->setDisabled(true); m_ui->m_checkBackupDatabase->setDisabled(true);
} }
} }
FormBackupDatabaseSettings::~FormBackupDatabaseSettings() { FormBackupDatabaseSettings::~FormBackupDatabaseSettings() {
qDebug("Destroying FormBackupDatabaseSettings instance."); qDebug("Destroying FormBackupDatabaseSettings instance.");
} }
void FormBackupDatabaseSettings::performBackup() { void FormBackupDatabaseSettings::performBackup() {
try { try {
qApp->backupDatabaseSettings(m_ui->m_checkBackupDatabase->isChecked(), m_ui->m_checkBackupSettings->isChecked(), qApp->backupDatabaseSettings(m_ui->m_checkBackupDatabase->isChecked(), m_ui->m_checkBackupSettings->isChecked(),
m_ui->m_lblSelectFolder->label()->text(), m_ui->m_txtBackupName->lineEdit()->text()); m_ui->m_lblSelectFolder->label()->text(), m_ui->m_txtBackupName->lineEdit()->text());
m_ui->m_lblResult->setStatus(WidgetWithStatus::Ok, m_ui->m_lblResult->setStatus(WidgetWithStatus::Ok,
tr("Backup was created successfully and stored in target directory."), tr("Backup was created successfully and stored in target directory."),
tr("Backup was created successfully.")); tr("Backup was created successfully."));
} }
catch (const ApplicationException& ex) { catch (const ApplicationException& ex) {
m_ui->m_lblResult->setStatus(WidgetWithStatus::Error, ex.message(), tr("Backup failed.")); m_ui->m_lblResult->setStatus(WidgetWithStatus::Error, ex.message(), tr("Backup failed."));
} }
} }
void FormBackupDatabaseSettings::selectFolderInitial() { void FormBackupDatabaseSettings::selectFolderInitial() {
selectFolder(); selectFolder();
} }
void FormBackupDatabaseSettings::selectFolder(QString path) { void FormBackupDatabaseSettings::selectFolder(QString path) {
if (path.isEmpty()) { if (path.isEmpty()) {
path = QFileDialog::getExistingDirectory(this, tr("Select destination directory"), m_ui->m_lblSelectFolder->label()->text()); path = QFileDialog::getExistingDirectory(this, tr("Select destination directory"), m_ui->m_lblSelectFolder->label()->text());
} }
if (!path.isEmpty()) { if (!path.isEmpty()) {
m_ui->m_lblSelectFolder->setStatus(WidgetWithStatus::Ok, QDir::toNativeSeparators(path), m_ui->m_lblSelectFolder->setStatus(WidgetWithStatus::Ok, QDir::toNativeSeparators(path),
tr("Good destination directory is specified.")); tr("Good destination directory is specified."));
} }
} }
void FormBackupDatabaseSettings::checkBackupNames(const QString& name) { void FormBackupDatabaseSettings::checkBackupNames(const QString& name) {
if (name.simplified().isEmpty()) { if (name.simplified().isEmpty()) {
m_ui->m_txtBackupName->setStatus(WidgetWithStatus::Error, tr("Backup name cannot be empty.")); m_ui->m_txtBackupName->setStatus(WidgetWithStatus::Error, tr("Backup name cannot be empty."));
} }
else { else {
m_ui->m_txtBackupName->setStatus(WidgetWithStatus::Ok, tr("Backup name looks okay.")); m_ui->m_txtBackupName->setStatus(WidgetWithStatus::Ok, tr("Backup name looks okay."));
} }
} }
void FormBackupDatabaseSettings::checkOkButton() { void FormBackupDatabaseSettings::checkOkButton() {
m_ui->m_buttonBox->button(QDialogButtonBox::Ok)->setDisabled(m_ui->m_txtBackupName->lineEdit()->text().simplified().isEmpty() || m_ui->m_buttonBox->button(QDialogButtonBox::Ok)->setDisabled(m_ui->m_txtBackupName->lineEdit()->text().simplified().isEmpty() ||
m_ui->m_lblSelectFolder->label()->text().simplified().isEmpty() || m_ui->m_lblSelectFolder->label()->text().simplified().isEmpty() ||
(!m_ui->m_checkBackupDatabase->isChecked() && (!m_ui->m_checkBackupDatabase->isChecked() &&
!m_ui->m_checkBackupSettings->isChecked())); !m_ui->m_checkBackupSettings->isChecked()));
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -22,25 +23,24 @@
#include "ui_formbackupdatabasesettings.h" #include "ui_formbackupdatabasesettings.h"
class FormBackupDatabaseSettings : public QDialog { class FormBackupDatabaseSettings : public QDialog {
Q_OBJECT Q_OBJECT
public: public:
// Constructors and destructors
explicit FormBackupDatabaseSettings(QWidget* parent = 0);
virtual ~FormBackupDatabaseSettings();
// Constructors and destructors
explicit FormBackupDatabaseSettings(QWidget* parent = 0);
virtual ~FormBackupDatabaseSettings();
private slots: private slots:
void performBackup(); void performBackup();
void selectFolderInitial(); void selectFolderInitial();
void selectFolder(QString path = QString()); void selectFolder(QString path = QString());
void checkBackupNames(const QString& name); void checkBackupNames(const QString& name);
void checkOkButton(); void checkOkButton();
private: private:
QScopedPointer<Ui::FormBackupDatabaseSettings> m_ui; QScopedPointer<Ui::FormBackupDatabaseSettings> m_ui;
}; };
#endif // FORMBACKUPDATABASECONFIG_H #endif // FORMBACKUPDATABASECONFIG_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -18,111 +19,113 @@
#include "gui/dialogs/formdatabasecleanup.h" #include "gui/dialogs/formdatabasecleanup.h"
#include "miscellaneous/application.h" #include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/databasefactory.h" #include "miscellaneous/databasefactory.h"
#include "miscellaneous/iconfactory.h"
#include <QCloseEvent> #include <QCloseEvent>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QPushButton> #include <QPushButton>
FormDatabaseCleanup::FormDatabaseCleanup(QWidget* parent) : QDialog(parent), m_ui(new Ui::FormDatabaseCleanup), m_cleaner(nullptr) { FormDatabaseCleanup::FormDatabaseCleanup(QWidget* parent) : QDialog(parent), m_ui(new Ui::FormDatabaseCleanup), m_cleaner(nullptr) {
m_ui->setupUi(this); m_ui->setupUi(this);
// Set flags and attributes.
setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint | Qt::WindowTitleHint); // Set flags and attributes.
setWindowIcon(qApp->icons()->fromTheme(QSL("edit-clear"))); setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint | Qt::WindowTitleHint);
connect(m_ui->m_spinDays, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &FormDatabaseCleanup::updateDaysSuffix); setWindowIcon(qApp->icons()->fromTheme(QSL("edit-clear")));
m_ui->m_spinDays->setValue(DEFAULT_DAYS_TO_DELETE_MSG); connect(m_ui->m_spinDays, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &FormDatabaseCleanup::updateDaysSuffix);
m_ui->m_lblResult->setStatus(WidgetWithStatus::Information, tr("I am ready."), tr("I am ready.")); m_ui->m_spinDays->setValue(DEFAULT_DAYS_TO_DELETE_MSG);
loadDatabaseInfo(); m_ui->m_lblResult->setStatus(WidgetWithStatus::Information, tr("I am ready."), tr("I am ready."));
loadDatabaseInfo();
} }
FormDatabaseCleanup::~FormDatabaseCleanup() { FormDatabaseCleanup::~FormDatabaseCleanup() {
qDebug("Destroying FormDatabaseCleanup instance."); qDebug("Destroying FormDatabaseCleanup instance.");
} }
void FormDatabaseCleanup::setCleaner(DatabaseCleaner* cleaner) { void FormDatabaseCleanup::setCleaner(DatabaseCleaner* cleaner) {
if (m_cleaner != nullptr) { if (m_cleaner != nullptr) {
disconnect(this, 0, m_cleaner, 0); disconnect(this, 0, m_cleaner, 0);
disconnect(m_cleaner, 0, this, 0); disconnect(m_cleaner, 0, this, 0);
} }
m_cleaner = cleaner; m_cleaner = cleaner;
connect(m_ui->m_btnBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &FormDatabaseCleanup::startPurging); connect(m_ui->m_btnBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &FormDatabaseCleanup::startPurging);
connect(this, &FormDatabaseCleanup::purgeRequested, m_cleaner, &DatabaseCleaner::purgeDatabaseData); connect(this, &FormDatabaseCleanup::purgeRequested, m_cleaner, &DatabaseCleaner::purgeDatabaseData);
connect(m_cleaner, &DatabaseCleaner::purgeStarted, this, &FormDatabaseCleanup::onPurgeStarted); connect(m_cleaner, &DatabaseCleaner::purgeStarted, this, &FormDatabaseCleanup::onPurgeStarted);
connect(m_cleaner, &DatabaseCleaner::purgeProgress, this, &FormDatabaseCleanup::onPurgeProgress); connect(m_cleaner, &DatabaseCleaner::purgeProgress, this, &FormDatabaseCleanup::onPurgeProgress);
connect(m_cleaner, &DatabaseCleaner::purgeFinished, this, &FormDatabaseCleanup::onPurgeFinished); connect(m_cleaner, &DatabaseCleaner::purgeFinished, this, &FormDatabaseCleanup::onPurgeFinished);
} }
void FormDatabaseCleanup::closeEvent(QCloseEvent* event) { void FormDatabaseCleanup::closeEvent(QCloseEvent* event) {
if (m_ui->m_progressBar->isEnabled()) { if (m_ui->m_progressBar->isEnabled()) {
event->ignore(); event->ignore();
} }
else { else {
QDialog::closeEvent(event); QDialog::closeEvent(event);
} }
} }
void FormDatabaseCleanup::keyPressEvent(QKeyEvent* event) { void FormDatabaseCleanup::keyPressEvent(QKeyEvent* event) {
if (m_ui->m_progressBar->isEnabled()) { if (m_ui->m_progressBar->isEnabled()) {
event->ignore(); event->ignore();
} }
else { else {
QDialog::keyPressEvent(event); QDialog::keyPressEvent(event);
} }
} }
void FormDatabaseCleanup::updateDaysSuffix(int number) { void FormDatabaseCleanup::updateDaysSuffix(int number) {
m_ui->m_spinDays->setSuffix(tr(" day(s)", 0, number)); m_ui->m_spinDays->setSuffix(tr(" day(s)", 0, number));
} }
void FormDatabaseCleanup::startPurging() { void FormDatabaseCleanup::startPurging() {
CleanerOrders orders; CleanerOrders orders;
orders.m_removeRecycleBin = m_ui->m_checkRemoveRecycleBin->isChecked();
orders.m_removeOldMessages = m_ui->m_checkRemoveOldMessages->isChecked(); orders.m_removeRecycleBin = m_ui->m_checkRemoveRecycleBin->isChecked();
orders.m_barrierForRemovingOldMessagesInDays = m_ui->m_spinDays->value(); orders.m_removeOldMessages = m_ui->m_checkRemoveOldMessages->isChecked();
orders.m_removeReadMessages = m_ui->m_checkRemoveReadMessages->isChecked(); orders.m_barrierForRemovingOldMessagesInDays = m_ui->m_spinDays->value();
orders.m_shrinkDatabase = m_ui->m_checkShrink->isEnabled() && m_ui->m_checkShrink->isChecked(); orders.m_removeReadMessages = m_ui->m_checkRemoveReadMessages->isChecked();
orders.m_removeStarredMessages = m_ui->m_checkRemoveStarredMessages->isChecked(); orders.m_shrinkDatabase = m_ui->m_checkShrink->isEnabled() && m_ui->m_checkShrink->isChecked();
emit purgeRequested(orders); orders.m_removeStarredMessages = m_ui->m_checkRemoveStarredMessages->isChecked();
emit purgeRequested(orders);
} }
void FormDatabaseCleanup::onPurgeStarted() { void FormDatabaseCleanup::onPurgeStarted() {
m_ui->m_progressBar->setValue(0); m_ui->m_progressBar->setValue(0);
m_ui->m_progressBar->setEnabled(true); m_ui->m_progressBar->setEnabled(true);
m_ui->m_btnBox->setEnabled(false); m_ui->m_btnBox->setEnabled(false);
m_ui->m_lblResult->setStatus(WidgetWithStatus::Information, tr("Database cleanup is running."), tr("Database cleanup is running.")); m_ui->m_lblResult->setStatus(WidgetWithStatus::Information, tr("Database cleanup is running."), tr("Database cleanup is running."));
} }
void FormDatabaseCleanup::onPurgeProgress(int progress, const QString& description) { void FormDatabaseCleanup::onPurgeProgress(int progress, const QString& description) {
m_ui->m_progressBar->setValue(progress); m_ui->m_progressBar->setValue(progress);
m_ui->m_lblResult->setStatus(WidgetWithStatus::Information, description, description); m_ui->m_lblResult->setStatus(WidgetWithStatus::Information, description, description);
} }
void FormDatabaseCleanup::onPurgeFinished(bool finished) { void FormDatabaseCleanup::onPurgeFinished(bool finished) {
m_ui->m_progressBar->setEnabled(false); m_ui->m_progressBar->setEnabled(false);
m_ui->m_progressBar->setValue(0); m_ui->m_progressBar->setValue(0);
m_ui->m_btnBox->setEnabled(true); m_ui->m_btnBox->setEnabled(true);
if (finished) { if (finished) {
m_ui->m_lblResult->setStatus(WidgetWithStatus::Ok, tr("Database cleanup is completed."), tr("Database cleanup is completed.")); m_ui->m_lblResult->setStatus(WidgetWithStatus::Ok, tr("Database cleanup is completed."), tr("Database cleanup is completed."));
} }
else { else {
m_ui->m_lblResult->setStatus(WidgetWithStatus::Error, tr("Database cleanup failed."), tr("Database cleanup failed.")); m_ui->m_lblResult->setStatus(WidgetWithStatus::Error, tr("Database cleanup failed."), tr("Database cleanup failed."));
} }
loadDatabaseInfo(); loadDatabaseInfo();
} }
void FormDatabaseCleanup::loadDatabaseInfo() { void FormDatabaseCleanup::loadDatabaseInfo() {
qint64 file_size = qApp->database()->getDatabaseFileSize(); qint64 file_size = qApp->database()->getDatabaseFileSize();
qint64 data_size = qApp->database()->getDatabaseDataSize(); qint64 data_size = qApp->database()->getDatabaseDataSize();
QString file_size_str = file_size > 0 ? QString::number(file_size / 1000000.0) + QL1S(" MB") : tr("unknown"); QString file_size_str = file_size > 0 ? QString::number(file_size / 1000000.0) + QL1S(" MB") : tr("unknown");
QString data_size_str = data_size > 0 ? QString::number(data_size / 1000000.0) + QL1S(" MB") : tr("unknown"); QString data_size_str = data_size > 0 ? QString::number(data_size / 1000000.0) + QL1S(" MB") : tr("unknown");
m_ui->m_txtFileSize->setText(tr("file: %1, data: %2").arg(file_size_str, data_size_str));
m_ui->m_txtDatabaseType->setText(qApp->database()->humanDriverName(qApp->database()->activeDatabaseDriver())); m_ui->m_txtFileSize->setText(tr("file: %1, data: %2").arg(file_size_str, data_size_str));
m_ui->m_checkShrink->setEnabled(qApp->database()->activeDatabaseDriver() == DatabaseFactory::SQLITE || m_ui->m_txtDatabaseType->setText(qApp->database()->humanDriverName(qApp->database()->activeDatabaseDriver()));
qApp->database()->activeDatabaseDriver() == DatabaseFactory::SQLITE_MEMORY); m_ui->m_checkShrink->setEnabled(qApp->database()->activeDatabaseDriver() == DatabaseFactory::SQLITE ||
m_ui->m_checkShrink->setChecked(m_ui->m_checkShrink->isEnabled()); qApp->database()->activeDatabaseDriver() == DatabaseFactory::SQLITE_MEMORY);
m_ui->m_checkShrink->setChecked(m_ui->m_checkShrink->isEnabled());
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -24,37 +25,37 @@
#include "miscellaneous/databasecleaner.h" #include "miscellaneous/databasecleaner.h"
class FormDatabaseCleanup : public QDialog { class FormDatabaseCleanup : public QDialog {
Q_OBJECT Q_OBJECT
public: public:
// Constructors.
explicit FormDatabaseCleanup(QWidget* parent = 0);
virtual ~FormDatabaseCleanup();
void setCleaner(DatabaseCleaner* cleaner); // Constructors.
explicit FormDatabaseCleanup(QWidget* parent = 0);
virtual ~FormDatabaseCleanup();
protected: void setCleaner(DatabaseCleaner* cleaner);
void closeEvent(QCloseEvent* event);
void keyPressEvent(QKeyEvent* event);
private slots: protected:
void updateDaysSuffix(int number); void closeEvent(QCloseEvent* event);
void startPurging(); void keyPressEvent(QKeyEvent* event);
void onPurgeStarted();
void onPurgeProgress(int progress, const QString& description);
void onPurgeFinished(bool finished);
signals: private slots:
void purgeRequested(const CleanerOrders& which_data); void updateDaysSuffix(int number);
void startPurging();
void onPurgeStarted();
void onPurgeProgress(int progress, const QString& description);
void onPurgeFinished(bool finished);
private: signals:
void loadDatabaseInfo(); void purgeRequested(const CleanerOrders& which_data);
private: private:
QScopedPointer<Ui::FormDatabaseCleanup> m_ui; void loadDatabaseInfo();
DatabaseCleaner* m_cleaner;
private:
QScopedPointer<Ui::FormDatabaseCleanup> m_ui;
DatabaseCleaner* m_cleaner;
}; };
#endif // FORMDATABASECLEANUP_H #endif // FORMDATABASECLEANUP_H

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -22,86 +23,88 @@
#include "ui_formmain.h" #include "ui_formmain.h"
class StatusBar; class StatusBar;
class FormMain : public QMainWindow { class FormMain : public QMainWindow {
Q_OBJECT Q_OBJECT
friend class TabWidget; friend class TabWidget;
friend class MessagesView; friend class MessagesView;
friend class FeedsView; friend class FeedsView;
public: public:
// Constructors and destructors.
explicit FormMain(QWidget* parent = 0, Qt::WindowFlags f = 0);
virtual ~FormMain();
// Returns menu for the tray icon. // Constructors and destructors.
QMenu* trayMenu() const; explicit FormMain(QWidget* parent = 0, Qt::WindowFlags f = 0);
virtual ~FormMain();
// Returns global tab widget. // Returns menu for the tray icon.
TabWidget* tabWidget() const; QMenu* trayMenu() const;
// Access to statusbar. // Returns global tab widget.
StatusBar* statusBar() const; TabWidget* tabWidget() const;
// Returns list of all globally available actions. // Access to statusbar.
// NOTE: This is used for setting dynamic shortcuts StatusBar* statusBar() const;
// for given actions.
QList<QAction*> allActions() const;
// Loads/saves visual state of the application. // Returns list of all globally available actions.
void loadSize(); // NOTE: This is used for setting dynamic shortcuts
void saveSize(); // for given actions.
QList<QAction*> allActions() const;
public slots: // Loads/saves visual state of the application.
// Displays window on top or switches its visibility. void loadSize();
void display(); void saveSize();
// Switches visibility of main window. public slots:
void switchVisibility(bool force_hide = false);
// Turns on/off fullscreen mode // Displays window on top or switches its visibility.
void switchFullscreenMode(); void display();
private slots: // Switches visibility of main window.
void updateAddItemMenu(); void switchVisibility(bool force_hide = false);
void updateRecycleBinMenu();
void updateAccountsMenu();
void updateMessageButtonsAvailability(); // Turns on/off fullscreen mode
void updateFeedButtonsAvailability(); void switchFullscreenMode();
void onFeedUpdatesStarted(); private slots:
void onFeedUpdatesProgress(const Feed* feed, int current, int total); void updateAddItemMenu();
void onFeedUpdatesFinished(const FeedDownloadResults& results); void updateRecycleBinMenu();
void updateAccountsMenu();
// Displays various dialogs. void updateMessageButtonsAvailability();
void backupDatabaseSettings(); void updateFeedButtonsAvailability();
void restoreDatabaseSettings();
void showWiki();
void showAddAccountDialog();
void showDbCleanupAssistant();
void reportABug();
void donate();
private: void onFeedUpdatesStarted();
// Event handler reimplementations. void onFeedUpdatesProgress(const Feed* feed, int current, int total);
void changeEvent(QEvent* event); void onFeedUpdatesFinished(const FeedDownloadResults& results);
// Creates all needed menus and sets them up. // Displays various dialogs.
void prepareMenus(); void backupDatabaseSettings();
void restoreDatabaseSettings();
void showWiki();
void showAddAccountDialog();
void showDbCleanupAssistant();
void reportABug();
void donate();
// Creates needed connections for this window. private:
void createConnections();
// Sets up proper icons for this widget. // Event handler reimplementations.
void setupIcons(); void changeEvent(QEvent* event);
QScopedPointer<Ui::FormMain> m_ui; // Creates all needed menus and sets them up.
QMenu* m_trayMenu; void prepareMenus();
StatusBar* m_statusBar;
// Creates needed connections for this window.
void createConnections();
// Sets up proper icons for this widget.
void setupIcons();
QScopedPointer<Ui::FormMain> m_ui;
QMenu* m_trayMenu;
StatusBar* m_statusBar;
}; };
#endif // FORMMAIN_H #endif // FORMMAIN_H

View file

@ -93,12 +93,14 @@ void FormRestoreDatabaseSettings::selectFolder(QString folder) {
} }
const QDir selected_folder(folder); const QDir selected_folder(folder);
const QFileInfoList available_databases = selected_folder.entryInfoList(QStringList() << QString("*") + BACKUP_SUFFIX_DATABASE, const QFileInfoList available_databases = selected_folder.entryInfoList(QStringList() << QString(
QDir::Files | QDir::NoDotAndDotDot | QDir::Readable | QDir::CaseSensitive | QDir::NoSymLinks, "*") + BACKUP_SUFFIX_DATABASE,
QDir::Name); QDir::Files | QDir::NoDotAndDotDot | QDir::Readable | QDir::CaseSensitive | QDir::NoSymLinks,
const QFileInfoList available_settings = selected_folder.entryInfoList(QStringList() << QString("*") + BACKUP_SUFFIX_SETTINGS, QDir::Name);
QDir::Files | QDir::NoDotAndDotDot | QDir::Readable | QDir::CaseSensitive | QDir::NoSymLinks, const QFileInfoList available_settings = selected_folder.entryInfoList(QStringList() << QString(
QDir::Name); "*") + BACKUP_SUFFIX_SETTINGS,
QDir::Files | QDir::NoDotAndDotDot | QDir::Readable | QDir::CaseSensitive | QDir::NoSymLinks,
QDir::Name);
m_ui.m_listDatabase->clear(); m_ui.m_listDatabase->clear();
m_ui.m_listSettings->clear(); m_ui.m_listSettings->clear();

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -22,30 +23,29 @@
#include "ui_formrestoredatabasesettings.h" #include "ui_formrestoredatabasesettings.h"
class FormRestoreDatabaseSettings : public QDialog { class FormRestoreDatabaseSettings : public QDialog {
Q_OBJECT Q_OBJECT
public: public:
// Constructors and destructors.
explicit FormRestoreDatabaseSettings(QWidget& parent);
virtual ~FormRestoreDatabaseSettings();
bool shouldRestart() const { // Constructors and destructors.
return m_shouldRestart; explicit FormRestoreDatabaseSettings(QWidget& parent);
} virtual ~FormRestoreDatabaseSettings();
private slots: bool shouldRestart() const {
void performRestoration(); return m_shouldRestart;
void checkOkButton(); }
void selectFolderWithGui();
void selectFolder(QString folder = QString());
private: private slots:
Ui::FormRestoreDatabaseSettings m_ui; void performRestoration();
QPushButton* m_btnRestart; void checkOkButton();
void selectFolderWithGui();
void selectFolder(QString folder = QString());
bool m_shouldRestart; private:
Ui::FormRestoreDatabaseSettings m_ui;
QPushButton* m_btnRestart;
bool m_shouldRestart;
}; };
#endif // FORMRESTOREDATABASESETTINGS_H #endif // FORMRESTOREDATABASESETTINGS_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -18,10 +19,10 @@
#include "gui/dialogs/formsettings.h" #include "gui/dialogs/formsettings.h"
#include "definitions/definitions.h" #include "definitions/definitions.h"
#include "miscellaneous/application.h"
#include "miscellaneous/settings.h"
#include "miscellaneous/iconfactory.h"
#include "gui/messagebox.h" #include "gui/messagebox.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/settings.h"
#include "gui/settings/settingsbrowsermail.h" #include "gui/settings/settingsbrowsermail.h"
#include "gui/settings/settingsdatabase.h" #include "gui/settings/settingsdatabase.h"
@ -32,108 +33,111 @@
#include "gui/settings/settingslocalization.h" #include "gui/settings/settingslocalization.h"
#include "gui/settings/settingsshortcuts.h" #include "gui/settings/settingsshortcuts.h"
FormSettings::FormSettings(QWidget& parent) FormSettings::FormSettings(QWidget& parent)
: QDialog(&parent), m_panels(QList<SettingsPanel*>()), m_settings(*qApp->settings()) { : QDialog(&parent), m_panels(QList<SettingsPanel*>()), m_settings(*qApp->settings()) {
m_ui.setupUi(this); m_ui.setupUi(this);
// Set flags and attributes.
setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint | Qt::WindowTitleHint); // Set flags and attributes.
setWindowIcon(qApp->icons()->fromTheme(QSL("emblem-system"))); setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint | Qt::WindowTitleHint);
m_btnApply = m_ui.m_buttonBox->button(QDialogButtonBox::Apply); setWindowIcon(qApp->icons()->fromTheme(QSL("emblem-system")));
m_btnApply->setEnabled(false); m_btnApply = m_ui.m_buttonBox->button(QDialogButtonBox::Apply);
// Establish needed connections. m_btnApply->setEnabled(false);
connect(m_ui.m_buttonBox, &QDialogButtonBox::accepted, this, &FormSettings::saveSettings);
connect(m_ui.m_buttonBox, &QDialogButtonBox::rejected, this, &FormSettings::cancelSettings); // Establish needed connections.
connect(m_btnApply, &QPushButton::clicked, this, &FormSettings::applySettings); connect(m_ui.m_buttonBox, &QDialogButtonBox::accepted, this, &FormSettings::saveSettings);
addSettingsPanel(new SettingsGeneral(&m_settings, this)); connect(m_ui.m_buttonBox, &QDialogButtonBox::rejected, this, &FormSettings::cancelSettings);
addSettingsPanel(new SettingsDatabase(&m_settings, this)); connect(m_btnApply, &QPushButton::clicked, this, &FormSettings::applySettings);
addSettingsPanel(new SettingsGui(&m_settings, this)); addSettingsPanel(new SettingsGeneral(&m_settings, this));
addSettingsPanel(new SettingsLocalization(&m_settings, this)); addSettingsPanel(new SettingsDatabase(&m_settings, this));
addSettingsPanel(new SettingsShortcuts(&m_settings, this)); addSettingsPanel(new SettingsGui(&m_settings, this));
addSettingsPanel(new SettingsBrowserMail(&m_settings, this)); addSettingsPanel(new SettingsLocalization(&m_settings, this));
addSettingsPanel(new SettingsDownloads(&m_settings, this)); addSettingsPanel(new SettingsShortcuts(&m_settings, this));
addSettingsPanel(new SettingsFeedsMessages(&m_settings, this)); addSettingsPanel(new SettingsBrowserMail(&m_settings, this));
m_ui.m_listSettings->setCurrentRow(0); addSettingsPanel(new SettingsDownloads(&m_settings, this));
addSettingsPanel(new SettingsFeedsMessages(&m_settings, this));
m_ui.m_listSettings->setCurrentRow(0);
} }
FormSettings::~FormSettings() { FormSettings::~FormSettings() {
qDebug("Destroying FormSettings distance."); qDebug("Destroying FormSettings distance.");
} }
void FormSettings::saveSettings() { void FormSettings::saveSettings() {
applySettings(); applySettings();
accept(); accept();
} }
void FormSettings::applySettings() { void FormSettings::applySettings() {
// Save all settings. // Save all settings.
m_settings.checkSettings(); m_settings.checkSettings();
QStringList panels_for_restart; QStringList panels_for_restart;
foreach (SettingsPanel* panel, m_panels) { foreach (SettingsPanel* panel, m_panels) {
if (panel->isDirty()) { if (panel->isDirty()) {
panel->saveSettings(); panel->saveSettings();
} }
if (panel->requiresRestart()) { if (panel->requiresRestart()) {
panels_for_restart.append(panel->title().toLower()); panels_for_restart.append(panel->title().toLower());
panel->setRequiresRestart(false); panel->setRequiresRestart(false);
} }
} }
if (!panels_for_restart.isEmpty()) { if (!panels_for_restart.isEmpty()) {
const QStringList changed_settings_description = panels_for_restart.replaceInStrings(QRegExp(QSL("^")), QString::fromUtf8("")); const QStringList changed_settings_description = panels_for_restart.replaceInStrings(QRegExp(QSL("^")), QString::fromUtf8(""));
const QMessageBox::StandardButton clicked_button = MessageBox::show(this, const QMessageBox::StandardButton clicked_button = MessageBox::show(this,
QMessageBox::Question, QMessageBox::Question,
tr("Critical settings were changed"), tr("Critical settings were changed"),
tr("Some critical settings were changed and will be applied after the application gets restarted. " tr(
"\n\nYou have to restart manually."), "Some critical settings were changed and will be applied after the application gets restarted. "
tr("Do you want to restart now?"), "\n\nYou have to restart manually."),
tr("Changed categories of settings:\n%1.").arg(changed_settings_description .join(QSL(",\n"))), tr("Do you want to restart now?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); tr("Changed categories of settings:\n%1.").arg(
changed_settings_description.join(QSL(",\n"))),
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
if (clicked_button == QMessageBox::Yes) { if (clicked_button == QMessageBox::Yes) {
qApp->restart(); qApp->restart();
} }
} }
m_btnApply->setEnabled(false); m_btnApply->setEnabled(false);
} }
void FormSettings::cancelSettings() { void FormSettings::cancelSettings() {
QStringList changed_panels; QStringList changed_panels;
foreach (SettingsPanel* panel, m_panels) { foreach (SettingsPanel* panel, m_panels) {
if (panel->isDirty()) { if (panel->isDirty()) {
changed_panels.append(panel->title().toLower()); changed_panels.append(panel->title().toLower());
} }
} }
if (changed_panels.isEmpty()) { if (changed_panels.isEmpty()) {
reject(); reject();
} }
else { else {
const QStringList changed_settings_description = changed_panels.replaceInStrings(QRegExp(QSL("^")), QString::fromUtf8("")); const QStringList changed_settings_description = changed_panels.replaceInStrings(QRegExp(QSL("^")), QString::fromUtf8(""));
if (MessageBox::show(this, if (MessageBox::show(this,
QMessageBox::Critical, QMessageBox::Critical,
tr("Some settings are changed and will be lost"), tr("Some settings are changed and will be lost"),
tr("Some settings were changed and by cancelling this dialog, you would lose these changes."), tr("Some settings were changed and by cancelling this dialog, you would lose these changes."),
tr("Do you really want to close this dialog without saving any settings?"), tr("Do you really want to close this dialog without saving any settings?"),
tr("Changed categories of settings:\n%1.").arg(changed_settings_description .join(QSL(",\n"))), tr("Changed categories of settings:\n%1.").arg(changed_settings_description.join(QSL(",\n"))),
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) ==
QMessageBox::Yes) { QMessageBox::Yes) {
reject(); reject();
} }
} }
} }
void FormSettings::addSettingsPanel(SettingsPanel* panel) { void FormSettings::addSettingsPanel(SettingsPanel* panel) {
m_ui.m_listSettings->addItem(panel->title()); m_ui.m_listSettings->addItem(panel->title());
m_panels.append(panel); m_panels.append(panel);
m_ui.m_stackedSettings->addWidget(panel); m_ui.m_stackedSettings->addWidget(panel);
panel->loadSettings(); panel->loadSettings();
connect(panel, &SettingsPanel::settingsChanged, [this]() { connect(panel, &SettingsPanel::settingsChanged, [this]() {
m_btnApply->setEnabled(true); m_btnApply->setEnabled(true);
}); });
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -22,32 +23,33 @@
#include "ui_formsettings.h" #include "ui_formsettings.h"
class Settings; class Settings;
class SettingsPanel; class SettingsPanel;
class FormSettings : public QDialog { class FormSettings : public QDialog {
Q_OBJECT Q_OBJECT
public: public:
// Constructors and destructors.
explicit FormSettings(QWidget& parent);
virtual ~FormSettings();
private slots: // Constructors and destructors.
// Saves settings into global configuration. explicit FormSettings(QWidget& parent);
void saveSettings(); virtual ~FormSettings();
void applySettings();
void cancelSettings();
private: private slots:
void addSettingsPanel(SettingsPanel* panel);
Ui::FormSettings m_ui; // Saves settings into global configuration.
QPushButton* m_btnApply; void saveSettings();
void applySettings();
void cancelSettings();
QList<SettingsPanel*> m_panels; private:
Settings& m_settings; void addSettingsPanel(SettingsPanel* panel);
Ui::FormSettings m_ui;
QPushButton* m_btnApply;
QList<SettingsPanel*> m_panels;
Settings& m_settings;
}; };
#endif // FORMSETTINGS_H #endif // FORMSETTINGS_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -18,13 +19,13 @@
#include "gui/dialogs/formupdate.h" #include "gui/dialogs/formupdate.h"
#include "definitions/definitions.h" #include "definitions/definitions.h"
#include "gui/guiutilities.h"
#include "gui/messagebox.h"
#include "miscellaneous/iconfactory.h" #include "miscellaneous/iconfactory.h"
#include "miscellaneous/iofactory.h" #include "miscellaneous/iofactory.h"
#include "network-web/downloader.h"
#include "network-web/networkfactory.h" #include "network-web/networkfactory.h"
#include "network-web/webfactory.h" #include "network-web/webfactory.h"
#include "network-web/downloader.h"
#include "gui/messagebox.h"
#include "gui/guiutilities.h"
#include <QNetworkReply> #include <QNetworkReply>
@ -32,216 +33,218 @@
#include <windows.h> #include <windows.h>
#endif #endif
FormUpdate::FormUpdate(QWidget* parent) FormUpdate::FormUpdate(QWidget* parent)
: QDialog(parent) { : QDialog(parent) {
m_ui.setupUi(this); m_ui.setupUi(this);
m_ui.m_lblCurrentRelease->setText(APP_VERSION); m_ui.m_lblCurrentRelease->setText(APP_VERSION);
m_ui.m_tabInfo->removeTab(1); m_ui.m_tabInfo->removeTab(1);
m_ui.m_buttonBox->setEnabled(false); m_ui.m_buttonBox->setEnabled(false);
// Set flags and attributes.
GuiUtilities::applyDialogProperties(*this, qApp->icons()->fromTheme(QSL("help-about")));
connect(&m_downloader, &Downloader::progress, this, &FormUpdate::updateProgress);
connect(&m_downloader, &Downloader::completed, this, &FormUpdate::updateCompleted);
if (isSelfUpdateSupported()) { // Set flags and attributes.
m_btnUpdate = m_ui.m_buttonBox->addButton(tr("Download selected update"), QDialogButtonBox::ActionRole); GuiUtilities::applyDialogProperties(*this, qApp->icons()->fromTheme(QSL("help-about")));
m_btnUpdate->setToolTip(tr("Download new installation files.")); connect(&m_downloader, &Downloader::progress, this, &FormUpdate::updateProgress);
} connect(&m_downloader, &Downloader::completed, this, &FormUpdate::updateCompleted);
else {
m_btnUpdate = m_ui.m_buttonBox->addButton(tr("Go to application website"), QDialogButtonBox::ActionRole);
m_btnUpdate->setToolTip(tr("Go to application website to get update packages manually."));
}
m_btnUpdate->setVisible(false); if (isSelfUpdateSupported()) {
connect(m_btnUpdate, &QPushButton::clicked, this, &FormUpdate::startUpdate); m_btnUpdate = m_ui.m_buttonBox->addButton(tr("Download selected update"), QDialogButtonBox::ActionRole);
checkForUpdates(); m_btnUpdate->setToolTip(tr("Download new installation files."));
}
else {
m_btnUpdate = m_ui.m_buttonBox->addButton(tr("Go to application website"), QDialogButtonBox::ActionRole);
m_btnUpdate->setToolTip(tr("Go to application website to get update packages manually."));
}
m_btnUpdate->setVisible(false);
connect(m_btnUpdate, &QPushButton::clicked, this, &FormUpdate::startUpdate);
checkForUpdates();
} }
FormUpdate::~FormUpdate() { FormUpdate::~FormUpdate() {}
}
bool FormUpdate::isSelfUpdateSupported() const { bool FormUpdate::isSelfUpdateSupported() const {
#if defined(Q_OS_WIN) || defined(Q_OS_MAC) #if defined(Q_OS_WIN) || defined(Q_OS_MAC)
return true; return true;
#else #else
return false; return false;
#endif #endif
} }
void FormUpdate::checkForUpdates() { void FormUpdate::checkForUpdates() {
connect(qApp->system(), &SystemFactory::updatesChecked, [this](QPair<QList<UpdateInfo>, QNetworkReply::NetworkError> update) { connect(qApp->system(), &SystemFactory::updatesChecked, [this](QPair<QList<UpdateInfo>, QNetworkReply::NetworkError> update) {
m_ui.m_buttonBox->setEnabled(true); m_ui.m_buttonBox->setEnabled(true);
disconnect(qApp->system(), &SystemFactory::updatesChecked, nullptr, nullptr); disconnect(qApp->system(), &SystemFactory::updatesChecked, nullptr, nullptr);
if (update.second != QNetworkReply::NoError) { if (update.second != QNetworkReply::NoError) {
m_updateInfo = UpdateInfo(); m_updateInfo = UpdateInfo();
m_ui.m_tabInfo->setEnabled(false); m_ui.m_tabInfo->setEnabled(false);
//: Unknown release.
m_ui.m_lblAvailableRelease->setText(tr("unknown"));
m_ui.m_txtChanges->clear();
m_ui.m_lblStatus->setStatus(WidgetWithStatus::Error,
tr("Error: '%1'.").arg(NetworkFactory::networkErrorText(update.second)),
tr("List with updates was not\ndownloaded successfully."));
}
else {
const bool self_update_supported = isSelfUpdateSupported();
m_updateInfo = update.first.at(0);
m_ui.m_tabInfo->setEnabled(true);
m_ui.m_lblAvailableRelease->setText(m_updateInfo.m_availableVersion);
m_ui.m_txtChanges->setText(m_updateInfo.m_changes);
if (SystemFactory::isVersionNewer(m_updateInfo.m_availableVersion, APP_VERSION)) { //: Unknown release.
m_btnUpdate->setVisible(true); m_ui.m_lblAvailableRelease->setText(tr("unknown"));
m_ui.m_lblStatus->setStatus(WidgetWithStatus::Ok, m_ui.m_txtChanges->clear();
tr("New release available."), m_ui.m_lblStatus->setStatus(WidgetWithStatus::Error,
tr("This is new version which can be\ndownloaded.")); tr("Error: '%1'.").arg(NetworkFactory::networkErrorText(update.second)),
tr("List with updates was not\ndownloaded successfully."));
}
else {
const bool self_update_supported = isSelfUpdateSupported();
m_updateInfo = update.first.at(0);
m_ui.m_tabInfo->setEnabled(true);
m_ui.m_lblAvailableRelease->setText(m_updateInfo.m_availableVersion);
m_ui.m_txtChanges->setText(m_updateInfo.m_changes);
if (self_update_supported) { if (SystemFactory::isVersionNewer(m_updateInfo.m_availableVersion, APP_VERSION)) {
loadAvailableFiles(); m_btnUpdate->setVisible(true);
} m_ui.m_lblStatus->setStatus(WidgetWithStatus::Ok,
} tr("New release available."),
else { tr("This is new version which can be\ndownloaded."));
m_ui.m_lblStatus->setStatus(WidgetWithStatus::Warning,
tr("No new release available."), if (self_update_supported) {
tr("This release is not newer than\ncurrently installed one.")); loadAvailableFiles();
} }
} }
}); else {
qApp->system()->checkForUpdates(); m_ui.m_lblStatus->setStatus(WidgetWithStatus::Warning,
tr("No new release available."),
tr("This release is not newer than\ncurrently installed one."));
}
}
});
qApp->system()->checkForUpdates();
} }
void FormUpdate::updateProgress(qint64 bytes_received, qint64 bytes_total) { void FormUpdate::updateProgress(qint64 bytes_received, qint64 bytes_total) {
if (bytes_received - m_lastDownloadedBytes > 500000 || m_lastDownloadedBytes == 0) { if (bytes_received - m_lastDownloadedBytes > 500000 || m_lastDownloadedBytes == 0) {
m_ui.m_lblStatus->setStatus(WidgetWithStatus::Information, m_ui.m_lblStatus->setStatus(WidgetWithStatus::Information,
tr("Downloaded %1% (update size is %2 kB).").arg(QString::number(bytes_total == 0 ? 0 : (bytes_received * 100.0) / bytes_total, tr("Downloaded %1% (update size is %2 kB).").arg(QString::number(bytes_total ==
'f', 0 ? 0 : (bytes_received * 100.0) /
2), bytes_total,
QString::number(bytes_total / 1000, 'f',
'f', 2),
2)), QString::number(bytes_total / 1000,
tr("Downloading update...")); 'f',
m_ui.m_lblStatus->repaint(); 2)),
m_lastDownloadedBytes = bytes_received; tr("Downloading update..."));
} m_ui.m_lblStatus->repaint();
m_lastDownloadedBytes = bytes_received;
}
} }
void FormUpdate::saveUpdateFile(const QByteArray& file_contents) { void FormUpdate::saveUpdateFile(const QByteArray& file_contents) {
const QString url_file = m_ui.m_listFiles->currentItem()->data(Qt::UserRole).toString(); const QString url_file = m_ui.m_listFiles->currentItem()->data(Qt::UserRole).toString();
const QString temp_directory = qApp->tempFolder(); const QString temp_directory = qApp->tempFolder();
if (!temp_directory.isEmpty()) { if (!temp_directory.isEmpty()) {
const QString output_file_name = url_file.mid(url_file.lastIndexOf('/') + 1); const QString output_file_name = url_file.mid(url_file.lastIndexOf('/') + 1);
QFile output_file(temp_directory + QDir::separator() + output_file_name); QFile output_file(temp_directory + QDir::separator() + output_file_name);
if (output_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { if (output_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
qDebug("Storing update file to temporary location '%s'.", qDebug("Storing update file to temporary location '%s'.",
qPrintable(QDir::toNativeSeparators(output_file.fileName()))); qPrintable(QDir::toNativeSeparators(output_file.fileName())));
output_file.write(file_contents); output_file.write(file_contents);
output_file.flush(); output_file.flush();
output_file.close(); output_file.close();
qDebug("Update file contents was successfuly saved."); qDebug("Update file contents was successfuly saved.");
m_updateFilePath = output_file.fileName(); m_updateFilePath = output_file.fileName();
m_readyToInstall = true; m_readyToInstall = true;
} }
else { else {
qDebug("Cannot save downloaded update file because target temporary file '%s' cannot be " qDebug("Cannot save downloaded update file because target temporary file '%s' cannot be "
"opened for writing.", qPrintable(output_file_name)); "opened for writing.", qPrintable(output_file_name));
} }
} }
else { else {
qDebug("Cannot save downloaded update file because no TEMP directory is available."); qDebug("Cannot save downloaded update file because no TEMP directory is available.");
} }
} }
void FormUpdate::loadAvailableFiles() { void FormUpdate::loadAvailableFiles() {
m_ui.m_listFiles->clear(); m_ui.m_listFiles->clear();
foreach (const UpdateUrl& url, m_updateInfo.m_urls) { foreach (const UpdateUrl& url, m_updateInfo.m_urls) {
QListWidgetItem* item = new QListWidgetItem(url.m_name + tr(" (size ") + url.m_size + QSL(")")); QListWidgetItem* item = new QListWidgetItem(url.m_name + tr(" (size ") + url.m_size + QSL(")"));
item->setData(Qt::UserRole, url.m_fileUrl);
item->setToolTip(url.m_fileUrl);
m_ui.m_listFiles->addItem(item);
}
if (m_ui.m_listFiles->count() > 0) { item->setData(Qt::UserRole, url.m_fileUrl);
m_ui.m_listFiles->setCurrentRow(0); item->setToolTip(url.m_fileUrl);
} m_ui.m_listFiles->addItem(item);
else { }
m_btnUpdate->setEnabled(false);
}
m_ui.m_tabInfo->addTab(m_ui.tabFiles, tr("Available update files")); if (m_ui.m_listFiles->count() > 0) {
m_ui.m_tabInfo->setCurrentIndex(1); m_ui.m_listFiles->setCurrentRow(0);
}
else {
m_btnUpdate->setEnabled(false);
}
m_ui.m_tabInfo->addTab(m_ui.tabFiles, tr("Available update files"));
m_ui.m_tabInfo->setCurrentIndex(1);
} }
void FormUpdate::updateCompleted(QNetworkReply::NetworkError status, QByteArray contents) { void FormUpdate::updateCompleted(QNetworkReply::NetworkError status, QByteArray contents) {
qDebug("Download of application update file was completed with code '%d'.", status); qDebug("Download of application update file was completed with code '%d'.", status);
switch (status) { switch (status) {
case QNetworkReply::NoError: case QNetworkReply::NoError:
saveUpdateFile(contents); saveUpdateFile(contents);
m_ui.m_lblStatus->setStatus(WidgetWithStatus::Ok, tr("Downloaded successfully"), m_ui.m_lblStatus->setStatus(WidgetWithStatus::Ok, tr("Downloaded successfully"),
tr("Package was downloaded successfully.\nYou can install it now.")); tr("Package was downloaded successfully.\nYou can install it now."));
m_btnUpdate->setText(tr("Install")); m_btnUpdate->setText(tr("Install"));
m_btnUpdate->setEnabled(true); m_btnUpdate->setEnabled(true);
break; break;
default: default:
m_ui.m_lblStatus->setStatus(WidgetWithStatus::Error, tr("Error occured"), tr("Error occured during downloading of the package.")); m_ui.m_lblStatus->setStatus(WidgetWithStatus::Error, tr("Error occured"), tr("Error occured during downloading of the package."));
m_btnUpdate->setText(tr("Error occured")); m_btnUpdate->setText(tr("Error occured"));
break; break;
} }
} }
void FormUpdate::startUpdate() { void FormUpdate::startUpdate() {
QString url_file; QString url_file;
const bool update_for_this_system = isSelfUpdateSupported(); const bool update_for_this_system = isSelfUpdateSupported();
if (update_for_this_system && m_ui.m_listFiles->currentItem() != nullptr) { if (update_for_this_system && m_ui.m_listFiles->currentItem() != nullptr) {
url_file = m_ui.m_listFiles->currentItem()->data(Qt::UserRole).toString(); url_file = m_ui.m_listFiles->currentItem()->data(Qt::UserRole).toString();
m_ui.m_listFiles->setEnabled(false); m_ui.m_listFiles->setEnabled(false);
} }
else { else {
url_file = APP_URL; url_file = APP_URL;
} }
if (m_readyToInstall) { if (m_readyToInstall) {
close(); close();
qDebug("Preparing to launch external installer '%s'.", qPrintable(QDir::toNativeSeparators(m_updateFilePath))); qDebug("Preparing to launch external installer '%s'.", qPrintable(QDir::toNativeSeparators(m_updateFilePath)));
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
HINSTANCE exec_result = ShellExecute(nullptr, HINSTANCE exec_result = ShellExecute(nullptr,
nullptr, nullptr,
reinterpret_cast<const WCHAR*>(QDir::toNativeSeparators(m_updateFilePath).utf16()), reinterpret_cast<const WCHAR*>(QDir::toNativeSeparators(m_updateFilePath).utf16()),
nullptr, nullptr,
nullptr, nullptr,
SW_NORMAL); SW_NORMAL);
if (exec_result <= (HINSTANCE)32) {
qDebug("External updater was not launched due to error.");
qApp->showGuiMessage(tr("Cannot update application"),
tr("Cannot launch external updater. Update application manually."),
QSystemTrayIcon::Warning, this);
}
else {
qApp->quit();
}
if (exec_result <= (HINSTANCE)32) {
qDebug("External updater was not launched due to error.");
qApp->showGuiMessage(tr("Cannot update application"),
tr("Cannot launch external updater. Update application manually."),
QSystemTrayIcon::Warning, this);
}
else {
qApp->quit();
}
#endif #endif
} }
else if (update_for_this_system) { else if (update_for_this_system) {
updateProgress(0, 100); updateProgress(0, 100);
m_btnUpdate->setText(tr("Downloading update...")); m_btnUpdate->setText(tr("Downloading update..."));
m_btnUpdate->setEnabled(false); m_btnUpdate->setEnabled(false);
m_downloader.downloadFile(url_file); m_downloader.downloadFile(url_file);
} }
else { else {
// Self-update and package are not available. // Self-update and package are not available.
if (!qApp->web()->openUrlInExternalBrowser(url_file)) { if (!qApp->web()->openUrlInExternalBrowser(url_file)) {
qApp->showGuiMessage(tr("Cannot update application"), qApp->showGuiMessage(tr("Cannot update application"),
tr("Cannot navigate to installation file. Check new installation downloads manually on project website."), tr("Cannot navigate to installation file. Check new installation downloads manually on project website."),
QSystemTrayIcon::Warning, QSystemTrayIcon::Warning,
this, true); this, true);
} }
} }
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -25,42 +26,42 @@
#include "miscellaneous/systemfactory.h" #include "miscellaneous/systemfactory.h"
#include "network-web/downloader.h" #include "network-web/downloader.h"
#include <QPushButton>
#include <QNetworkReply> #include <QNetworkReply>
#include <QPushButton>
class FormUpdate : public QDialog { class FormUpdate : public QDialog {
Q_OBJECT Q_OBJECT
public: public:
// Constructors and destructors.
explicit FormUpdate(QWidget* parent);
virtual ~FormUpdate();
// Returns true if application can self-update // Constructors and destructors.
// on current platform. explicit FormUpdate(QWidget* parent);
bool isSelfUpdateSupported() const; virtual ~FormUpdate();
private slots: // Returns true if application can self-update
// Check for updates and interprets the results. // on current platform.
void checkForUpdates(); bool isSelfUpdateSupported() const;
void startUpdate();
void updateProgress(qint64 bytes_received, qint64 bytes_total); private slots:
void updateCompleted(QNetworkReply::NetworkError status, QByteArray contents);
void saveUpdateFile(const QByteArray& file_contents);
private: // Check for updates and interprets the results.
void loadAvailableFiles(); void checkForUpdates();
void startUpdate();
Ui::FormUpdate m_ui; void updateProgress(qint64 bytes_received, qint64 bytes_total);
QPushButton* m_btnUpdate; void updateCompleted(QNetworkReply::NetworkError status, QByteArray contents);
void saveUpdateFile(const QByteArray& file_contents);
Downloader m_downloader; private:
QString m_updateFilePath; void loadAvailableFiles();
UpdateInfo m_updateInfo;
bool m_readyToInstall = false; Ui::FormUpdate m_ui;
qint64 m_lastDownloadedBytes = 0; QPushButton* m_btnUpdate;
Downloader m_downloader;
QString m_updateFilePath;
UpdateInfo m_updateInfo;
bool m_readyToInstall = false;
qint64 m_lastDownloadedBytes = 0;
}; };
#endif // FORMUPDATE_H #endif // FORMUPDATE_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -17,76 +18,75 @@
#include "gui/discoverfeedsbutton.h" #include "gui/discoverfeedsbutton.h"
#include "miscellaneous/application.h" #include "core/feedsmodel.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/feedreader.h"
#include "gui/dialogs/formmain.h" #include "gui/dialogs/formmain.h"
#include "gui/tabwidget.h"
#include "gui/feedmessageviewer.h" #include "gui/feedmessageviewer.h"
#include "gui/feedsview.h" #include "gui/feedsview.h"
#include "core/feedsmodel.h" #include "gui/tabwidget.h"
#include "miscellaneous/application.h"
#include "miscellaneous/feedreader.h"
#include "miscellaneous/iconfactory.h"
#include "services/abstract/serviceroot.h" #include "services/abstract/serviceroot.h"
#include <QVariant> #include <QVariant>
DiscoverFeedsButton::DiscoverFeedsButton(QWidget* parent) : QToolButton(parent), m_addresses(QStringList()) { DiscoverFeedsButton::DiscoverFeedsButton(QWidget* parent) : QToolButton(parent), m_addresses(QStringList()) {
setEnabled(false); setEnabled(false);
setIcon(qApp->icons()->fromTheme(QSL("application-rss+xml"))); setIcon(qApp->icons()->fromTheme(QSL("application-rss+xml")));
setPopupMode(QToolButton::InstantPopup); setPopupMode(QToolButton::InstantPopup);
} }
DiscoverFeedsButton::~DiscoverFeedsButton() { DiscoverFeedsButton::~DiscoverFeedsButton() {}
}
void DiscoverFeedsButton::clearFeedAddresses() { void DiscoverFeedsButton::clearFeedAddresses() {
setFeedAddresses(QStringList()); setFeedAddresses(QStringList());
} }
void DiscoverFeedsButton::setFeedAddresses(const QStringList& addresses) { void DiscoverFeedsButton::setFeedAddresses(const QStringList& addresses) {
setEnabled(!addresses.isEmpty()); setEnabled(!addresses.isEmpty());
setToolTip(addresses.isEmpty() ? setToolTip(addresses.isEmpty() ?
tr("This website does not contain any feeds.") : tr("This website does not contain any feeds.") :
tr("Click me to add feeds from this website.\nThis website contains %n feed(s).", 0, addresses.size())); tr("Click me to add feeds from this website.\nThis website contains %n feed(s).", 0, addresses.size()));
if (menu() == nullptr) { if (menu() == nullptr) {
// Initialize the menu. // Initialize the menu.
setMenu(new QMenu(this)); setMenu(new QMenu(this));
connect(menu(), &QMenu::triggered, this, &DiscoverFeedsButton::linkTriggered); connect(menu(), &QMenu::triggered, this, &DiscoverFeedsButton::linkTriggered);
connect(menu(), &QMenu::aboutToShow, this, &DiscoverFeedsButton::fillMenu); connect(menu(), &QMenu::aboutToShow, this, &DiscoverFeedsButton::fillMenu);
} }
menu()->hide(); menu()->hide();
m_addresses = addresses; m_addresses = addresses;
} }
void DiscoverFeedsButton::linkTriggered(QAction* action) { void DiscoverFeedsButton::linkTriggered(QAction* action) {
const QString url = action->property("url").toString(); const QString url = action->property("url").toString();
ServiceRoot* root = static_cast<ServiceRoot*>(action->property("root").value<void*>()); ServiceRoot* root = static_cast<ServiceRoot*>(action->property("root").value<void*>());
if (root->supportsFeedAdding()) { if (root->supportsFeedAdding()) {
root->addNewFeed(url); root->addNewFeed(url);
} }
else { else {
qApp->showGuiMessage(tr("Not supported"), qApp->showGuiMessage(tr("Not supported"),
tr("Given account does not support adding feeds."), tr("Given account does not support adding feeds."),
QSystemTrayIcon::Warning, QSystemTrayIcon::Warning,
qApp->mainFormWidget(), true); qApp->mainFormWidget(), true);
} }
} }
void DiscoverFeedsButton::fillMenu() { void DiscoverFeedsButton::fillMenu() {
menu()->clear(); menu()->clear();
foreach (const ServiceRoot* root, qApp->feedReader()->feedsModel()->serviceRoots()) { foreach (const ServiceRoot* root, qApp->feedReader()->feedsModel()->serviceRoots()) {
QMenu* root_menu = menu()->addMenu(root->icon(), root->title()); QMenu* root_menu = menu()->addMenu(root->icon(), root->title());
foreach (const QString& url, m_addresses) { foreach (const QString& url, m_addresses) {
if (root->supportsFeedAdding()) { if (root->supportsFeedAdding()) {
QAction* url_action = root_menu->addAction(root->icon(), url); QAction* url_action = root_menu->addAction(root->icon(), url);
url_action->setProperty("url", url);
url_action->setProperty("root", QVariant::fromValue((void*) root)); url_action->setProperty("url", url);
} url_action->setProperty("root", QVariant::fromValue((void*) root));
} }
} }
}
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -20,26 +21,27 @@
#include <QToolButton> #include <QToolButton>
class DiscoverFeedsButton : public QToolButton { class DiscoverFeedsButton : public QToolButton {
Q_OBJECT Q_OBJECT
public: public:
// Constructors.
explicit DiscoverFeedsButton(QWidget* parent = 0);
virtual ~DiscoverFeedsButton();
// Feed addresses manipulators. // Constructors.
void clearFeedAddresses(); explicit DiscoverFeedsButton(QWidget* parent = 0);
void setFeedAddresses(const QStringList& addresses); virtual ~DiscoverFeedsButton();
private slots: // Feed addresses manipulators.
// User chose any of addresses. void clearFeedAddresses();
void linkTriggered(QAction* action); void setFeedAddresses(const QStringList& addresses);
void fillMenu();
private: private slots:
QStringList m_addresses;
// User chose any of addresses.
void linkTriggered(QAction* action);
void fillMenu();
private:
QStringList m_addresses;
}; };
#endif // DISCOVERFEEDSBUTTON_H #endif // DISCOVERFEEDSBUTTON_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -19,50 +20,49 @@
#include <QKeyEvent> #include <QKeyEvent>
EditTableView::EditTableView(QWidget* parent) : QTableView(parent) {}
EditTableView::EditTableView(QWidget* parent) : QTableView(parent) {
}
void EditTableView::keyPressEvent(QKeyEvent* event) { void EditTableView::keyPressEvent(QKeyEvent* event) {
if (model() && event->key() == Qt::Key_Delete) { if (model() && event->key() == Qt::Key_Delete) {
removeSelected(); removeSelected();
event->accept(); event->accept();
} }
else { else {
QAbstractItemView::keyPressEvent(event); QAbstractItemView::keyPressEvent(event);
} }
} }
void EditTableView::removeSelected() { void EditTableView::removeSelected() {
if (!model() || !selectionModel() || !selectionModel()->hasSelection()) { if (!model() || !selectionModel() || !selectionModel()->hasSelection()) {
return; return;
} }
const QModelIndexList selected_rows = selectionModel()->selectedRows(); const QModelIndexList selected_rows = selectionModel()->selectedRows();
if (selected_rows.isEmpty()) { if (selected_rows.isEmpty()) {
return; return;
} }
const int new_selected_row = selected_rows.at(0).row(); const int new_selected_row = selected_rows.at(0).row();
for (int i = selected_rows.count() - 1; i >= 0; i--) { for (int i = selected_rows.count() - 1; i >= 0; i--) {
QModelIndex idx = selected_rows.at(i); QModelIndex idx = selected_rows.at(i);
model()->removeRow(idx.row(), rootIndex());
}
QModelIndex new_selected_index = model()->index(new_selected_row, 0, rootIndex()); model()->removeRow(idx.row(), rootIndex());
}
if (!new_selected_index.isValid()) { QModelIndex new_selected_index = model()->index(new_selected_row, 0, rootIndex());
new_selected_index = model()->index(new_selected_row - 1, 0, rootIndex());
}
selectionModel()->select(new_selected_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); if (!new_selected_index.isValid()) {
setCurrentIndex(new_selected_index); new_selected_index = model()->index(new_selected_row - 1, 0, rootIndex());
}
selectionModel()->select(new_selected_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
setCurrentIndex(new_selected_index);
} }
void EditTableView::removeAll() { void EditTableView::removeAll() {
if (model() != nullptr) { if (model() != nullptr) {
model()->removeRows(0, model()->rowCount(rootIndex()), rootIndex()); model()->removeRows(0, model()->rowCount(rootIndex()), rootIndex());
} }
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -20,19 +21,18 @@
#include <QTableView> #include <QTableView>
class EditTableView : public QTableView { class EditTableView : public QTableView {
Q_OBJECT Q_OBJECT
public: public:
explicit EditTableView(QWidget* parent = 0); explicit EditTableView(QWidget* parent = 0);
public slots: public slots:
void removeSelected(); void removeSelected();
void removeAll(); void removeAll();
private: private:
void keyPressEvent(QKeyEvent* event); void keyPressEvent(QKeyEvent* event);
}; };
#endif // EDITTABLEVIEW_H #endif // EDITTABLEVIEW_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -18,83 +19,85 @@
#include "gui/feedstoolbar.h" #include "gui/feedstoolbar.h"
#include "miscellaneous/application.h" #include "miscellaneous/application.h"
#include "miscellaneous/settings.h"
#include "miscellaneous/iconfactory.h" #include "miscellaneous/iconfactory.h"
#include "miscellaneous/settings.h"
#include <QWidgetAction> #include <QWidgetAction>
FeedsToolBar::FeedsToolBar(const QString& title, QWidget* parent) : BaseToolBar(title, parent) { FeedsToolBar::FeedsToolBar(const QString& title, QWidget* parent) : BaseToolBar(title, parent) {
// Update right margin of filter textbox. // Update right margin of filter textbox.
QMargins margins = contentsMargins(); QMargins margins = contentsMargins();
margins.setRight(margins.right() + FILTER_RIGHT_MARGIN);
setContentsMargins(margins); margins.setRight(margins.right() + FILTER_RIGHT_MARGIN);
setContentsMargins(margins);
} }
FeedsToolBar::~FeedsToolBar() { FeedsToolBar::~FeedsToolBar() {}
}
QList<QAction*> FeedsToolBar::availableActions() const { QList<QAction*> FeedsToolBar::availableActions() const {
return qApp->userActions(); return qApp->userActions();
} }
QList<QAction*> FeedsToolBar::changeableActions() const { QList<QAction*> FeedsToolBar::changeableActions() const {
return actions(); return actions();
} }
void FeedsToolBar::saveChangeableActions(const QStringList& actions) { void FeedsToolBar::saveChangeableActions(const QStringList& actions) {
qApp->settings()->setValue(GROUP(GUI), GUI::FeedsToolbarActions, actions.join(QSL(","))); qApp->settings()->setValue(GROUP(GUI), GUI::FeedsToolbarActions, actions.join(QSL(",")));
loadSpecificActions(getSpecificActions(actions)); loadSpecificActions(getSpecificActions(actions));
} }
QList<QAction*> FeedsToolBar::getSpecificActions(const QStringList& actions) { QList<QAction*> FeedsToolBar::getSpecificActions(const QStringList& actions) {
QList<QAction*> available_actions = availableActions(); QList<QAction*> available_actions = availableActions();
QList<QAction*> spec_actions; QList<QAction*> spec_actions;
// Iterate action names and add respectable actions into the toolbar. // Iterate action names and add respectable actions into the toolbar.
foreach (const QString& action_name, actions) { foreach (const QString& action_name, actions) {
QAction* matching_action = findMatchingAction(action_name, available_actions); QAction* matching_action = findMatchingAction(action_name, available_actions);
if (matching_action != nullptr) { if (matching_action != nullptr) {
// Add existing standard action. // Add existing standard action.
spec_actions.append(matching_action); spec_actions.append(matching_action);
} }
else if (action_name == SEPARATOR_ACTION_NAME) { else if (action_name == SEPARATOR_ACTION_NAME) {
// Add new separator. // Add new separator.
QAction* act = new QAction(this); QAction* act = new QAction(this);
act->setSeparator(true);
spec_actions.append(act);
}
else if (action_name == SPACER_ACTION_NAME) {
// Add new spacer.
QWidget* spacer = new QWidget(this);
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QWidgetAction* action = new QWidgetAction(this);
action->setDefaultWidget(spacer);
action->setIcon(qApp->icons()->fromTheme(QSL("system-search")));
action->setProperty("type", SPACER_ACTION_NAME);
action->setProperty("name", tr("Toolbar spacer"));
spec_actions.append(action);
}
}
return spec_actions; act->setSeparator(true);
spec_actions.append(act);
}
else if (action_name == SPACER_ACTION_NAME) {
// Add new spacer.
QWidget* spacer = new QWidget(this);
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QWidgetAction* action = new QWidgetAction(this);
action->setDefaultWidget(spacer);
action->setIcon(qApp->icons()->fromTheme(QSL("system-search")));
action->setProperty("type", SPACER_ACTION_NAME);
action->setProperty("name", tr("Toolbar spacer"));
spec_actions.append(action);
}
}
return spec_actions;
} }
void FeedsToolBar::loadSpecificActions(const QList<QAction*>& actions) { void FeedsToolBar::loadSpecificActions(const QList<QAction*>& actions) {
clear(); clear();
foreach (QAction* act, actions) { foreach (QAction* act, actions) {
addAction(act); addAction(act);
} }
} }
QStringList FeedsToolBar::defaultActions() const { QStringList FeedsToolBar::defaultActions() const {
return QString(GUI::FeedsToolbarActionsDef).split(',', return QString(GUI::FeedsToolbarActionsDef).split(',',
QString::SkipEmptyParts); QString::SkipEmptyParts);
} }
QStringList FeedsToolBar::savedActions() const { QStringList FeedsToolBar::savedActions() const {
return qApp->settings()->value(GROUP(GUI), SETTING(GUI::FeedsToolbarActions)).toString().split(',', return qApp->settings()->value(GROUP(GUI), SETTING(GUI::FeedsToolbarActions)).toString().split(',',
QString::SkipEmptyParts); QString::SkipEmptyParts);
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -20,24 +21,24 @@
#include "gui/basetoolbar.h" #include "gui/basetoolbar.h"
class FeedsToolBar : public BaseToolBar { class FeedsToolBar : public BaseToolBar {
Q_OBJECT Q_OBJECT
public: public:
// Constructors and destructors.
explicit FeedsToolBar(const QString& title, QWidget* parent = 0);
virtual ~FeedsToolBar();
QList<QAction*> availableActions() const; // Constructors and destructors.
QList<QAction*> changeableActions() const; explicit FeedsToolBar(const QString& title, QWidget* parent = 0);
void saveChangeableActions(const QStringList& actions); virtual ~FeedsToolBar();
QList<QAction*> getSpecificActions(const QStringList& actions); QList<QAction*> availableActions() const;
void loadSpecificActions(const QList<QAction*>& actions); QList<QAction*> changeableActions() const;
void saveChangeableActions(const QStringList& actions);
QStringList defaultActions() const; QList<QAction*> getSpecificActions(const QStringList& actions);
QStringList savedActions() const; void loadSpecificActions(const QList<QAction*>& actions);
QStringList defaultActions() const;
QStringList savedActions() const;
}; };
#endif // FEEDSTOOLBAR_H #endif // FEEDSTOOLBAR_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -17,338 +18,344 @@
#include "gui/feedsview.h" #include "gui/feedsview.h"
#include "definitions/definitions.h"
#include "core/feedsmodel.h" #include "core/feedsmodel.h"
#include "core/feedsproxymodel.h" #include "core/feedsproxymodel.h"
#include "services/abstract/rootitem.h" #include "definitions/definitions.h"
#include "miscellaneous/systemfactory.h" #include "gui/dialogs/formmain.h"
#include "miscellaneous/feedreader.h"
#include "miscellaneous/mutex.h"
#include "gui/systemtrayicon.h"
#include "gui/messagebox.h" #include "gui/messagebox.h"
#include "gui/styleditemdelegatewithoutfocus.h" #include "gui/styleditemdelegatewithoutfocus.h"
#include "gui/dialogs/formmain.h" #include "gui/systemtrayicon.h"
#include "miscellaneous/feedreader.h"
#include "miscellaneous/mutex.h"
#include "miscellaneous/systemfactory.h"
#include "services/abstract/feed.h" #include "services/abstract/feed.h"
#include "services/abstract/rootitem.h"
#include "services/abstract/serviceroot.h" #include "services/abstract/serviceroot.h"
#include "services/standard/gui/formstandardcategorydetails.h"
#include "services/standard/standardcategory.h" #include "services/standard/standardcategory.h"
#include "services/standard/standardfeed.h" #include "services/standard/standardfeed.h"
#include "services/standard/gui/formstandardcategorydetails.h"
#include <QMenu>
#include <QHeaderView>
#include <QContextMenuEvent> #include <QContextMenuEvent>
#include <QPointer> #include <QHeaderView>
#include <QMenu>
#include <QPainter> #include <QPainter>
#include <QPointer>
#include <QTimer> #include <QTimer>
FeedsView::FeedsView(QWidget* parent) FeedsView::FeedsView(QWidget* parent)
: QTreeView(parent), : QTreeView(parent),
m_contextMenuCategories(nullptr), m_contextMenuCategories(nullptr),
m_contextMenuFeeds(nullptr), m_contextMenuFeeds(nullptr),
m_contextMenuEmptySpace(nullptr), m_contextMenuEmptySpace(nullptr),
m_contextMenuOtherItems(nullptr) { m_contextMenuOtherItems(nullptr) {
setObjectName(QSL("FeedsView")); setObjectName(QSL("FeedsView"));
// Allocate models. // Allocate models.
m_sourceModel = qApp->feedReader()->feedsModel(); m_sourceModel = qApp->feedReader()->feedsModel();
m_proxyModel = qApp->feedReader()->feedsProxyModel(); m_proxyModel = qApp->feedReader()->feedsProxyModel();
// Connections. // Connections.
connect(m_sourceModel, &FeedsModel::requireItemValidationAfterDragDrop, this, &FeedsView::validateItemAfterDragDrop); connect(m_sourceModel, &FeedsModel::requireItemValidationAfterDragDrop, this, &FeedsView::validateItemAfterDragDrop);
connect(m_sourceModel, &FeedsModel::itemExpandRequested, this, &FeedsView::onItemExpandRequested); connect(m_sourceModel, &FeedsModel::itemExpandRequested, this, &FeedsView::onItemExpandRequested);
connect(m_sourceModel, &FeedsModel::itemExpandStateSaveRequested, this, &FeedsView::onItemExpandStateSaveRequested); connect(m_sourceModel, &FeedsModel::itemExpandStateSaveRequested, this, &FeedsView::onItemExpandStateSaveRequested);
connect(header(), &QHeaderView::sortIndicatorChanged, this, &FeedsView::saveSortState); connect(header(), &QHeaderView::sortIndicatorChanged, this, &FeedsView::saveSortState);
connect(m_proxyModel, &FeedsProxyModel::expandAfterFilterIn, this, &FeedsView::expandItemDelayed); connect(m_proxyModel, &FeedsProxyModel::expandAfterFilterIn, this, &FeedsView::expandItemDelayed);
setModel(m_proxyModel); setModel(m_proxyModel);
setupAppearance(); setupAppearance();
} }
FeedsView::~FeedsView() { FeedsView::~FeedsView() {
qDebug("Destroying FeedsView instance."); qDebug("Destroying FeedsView instance.");
} }
void FeedsView::setSortingEnabled(bool enable) { void FeedsView::setSortingEnabled(bool enable) {
disconnect(header(), &QHeaderView::sortIndicatorChanged, this, &FeedsView::saveSortState); disconnect(header(), &QHeaderView::sortIndicatorChanged, this, &FeedsView::saveSortState);
QTreeView::setSortingEnabled(enable); QTreeView::setSortingEnabled(enable);
connect(header(), &QHeaderView::sortIndicatorChanged, this, &FeedsView::saveSortState); connect(header(), &QHeaderView::sortIndicatorChanged, this, &FeedsView::saveSortState);
} }
QList<Feed*> FeedsView::selectedFeeds() const { QList<Feed*> FeedsView::selectedFeeds() const {
const QModelIndex current_index = currentIndex(); const QModelIndex current_index = currentIndex();
if (current_index.isValid()) { if (current_index.isValid()) {
return m_sourceModel->feedsForIndex(m_proxyModel->mapToSource(current_index)); return m_sourceModel->feedsForIndex(m_proxyModel->mapToSource(current_index));
} }
else { else {
return QList<Feed*>(); return QList<Feed*>();
} }
} }
RootItem* FeedsView::selectedItem() const { RootItem* FeedsView::selectedItem() const {
const QModelIndexList selected_rows = selectionModel()->selectedRows(); const QModelIndexList selected_rows = selectionModel()->selectedRows();
if (selected_rows.isEmpty()) { if (selected_rows.isEmpty()) {
return nullptr; return nullptr;
} }
else { else {
RootItem* selected_item = m_sourceModel->itemForIndex(m_proxyModel->mapToSource(selected_rows.at(0))); RootItem* selected_item = m_sourceModel->itemForIndex(m_proxyModel->mapToSource(selected_rows.at(0)));
return selected_item == m_sourceModel->rootItem() ? nullptr : selected_item;
} return selected_item == m_sourceModel->rootItem() ? nullptr : selected_item;
}
} }
void FeedsView::onItemExpandStateSaveRequested(RootItem* item) { void FeedsView::onItemExpandStateSaveRequested(RootItem* item) {
saveExpandStates(item); saveExpandStates(item);
} }
void FeedsView::saveAllExpandStates() { void FeedsView::saveAllExpandStates() {
saveExpandStates(sourceModel()->rootItem()); saveExpandStates(sourceModel()->rootItem());
} }
void FeedsView::saveExpandStates(RootItem* item) { void FeedsView::saveExpandStates(RootItem* item) {
Settings* settings = qApp->settings(); Settings* settings = qApp->settings();
QList<RootItem*> items = item->getSubTree(RootItemKind::Category | RootItemKind::ServiceRoot);
// Iterate all categories and save their expand statuses. QList<RootItem*> items = item->getSubTree(RootItemKind::Category | RootItemKind::ServiceRoot);
foreach (const RootItem* item, items) {
const QString setting_name = item->hashCode(); // Iterate all categories and save their expand statuses.
QModelIndex source_index = sourceModel()->indexForItem(item); foreach (const RootItem* item, items) {
QModelIndex visible_index = model()->mapFromSource(source_index); const QString setting_name = item->hashCode();
settings->setValue(GROUP(CategoriesExpandStates), QModelIndex source_index = sourceModel()->indexForItem(item);
setting_name, QModelIndex visible_index = model()->mapFromSource(source_index);
isExpanded(visible_index));
} settings->setValue(GROUP(CategoriesExpandStates),
setting_name,
isExpanded(visible_index));
}
} }
void FeedsView::loadAllExpandStates() { void FeedsView::loadAllExpandStates() {
const Settings* settings = qApp->settings(); const Settings* settings = qApp->settings();
QList<RootItem*> expandable_items;
expandable_items.append(sourceModel()->rootItem()->getSubTree(RootItemKind::Category | RootItemKind::ServiceRoot));
// Iterate all categories and save their expand statuses. QList<RootItem*> expandable_items;
foreach (const RootItem* item, expandable_items) { expandable_items.append(sourceModel()->rootItem()->getSubTree(RootItemKind::Category | RootItemKind::ServiceRoot));
const QString setting_name = item->hashCode();
setExpanded(model()->mapFromSource(sourceModel()->indexForItem(item)),
settings->value(GROUP(CategoriesExpandStates), setting_name, item->childCount() > 0).toBool());
}
sortByColumn(qApp->settings()->value(GROUP(GUI), SETTING(GUI::DefaultSortColumnFeeds)).toInt(), // Iterate all categories and save their expand statuses.
static_cast<Qt::SortOrder>(qApp->settings()->value(GROUP(GUI), SETTING(GUI::DefaultSortOrderFeeds)).toInt())); foreach (const RootItem* item, expandable_items) {
const QString setting_name = item->hashCode();
setExpanded(model()->mapFromSource(sourceModel()->indexForItem(item)),
settings->value(GROUP(CategoriesExpandStates), setting_name, item->childCount() > 0).toBool());
}
sortByColumn(qApp->settings()->value(GROUP(GUI), SETTING(GUI::DefaultSortColumnFeeds)).toInt(),
static_cast<Qt::SortOrder>(qApp->settings()->value(GROUP(GUI), SETTING(GUI::DefaultSortOrderFeeds)).toInt()));
} }
void FeedsView::sortByColumn(int column, Qt::SortOrder order) { void FeedsView::sortByColumn(int column, Qt::SortOrder order) {
const int old_column = header()->sortIndicatorSection(); const int old_column = header()->sortIndicatorSection();
const Qt::SortOrder old_order = header()->sortIndicatorOrder(); const Qt::SortOrder old_order = header()->sortIndicatorOrder();
if (column == old_column && order == old_order) { if (column == old_column && order == old_order) {
m_proxyModel->sort(column, order); m_proxyModel->sort(column, order);
} }
else { else {
QTreeView::sortByColumn(column, order); QTreeView::sortByColumn(column, order);
} }
} }
void FeedsView::addFeedIntoSelectedAccount() { void FeedsView::addFeedIntoSelectedAccount() {
const RootItem* selected = selectedItem(); const RootItem* selected = selectedItem();
if (selected != nullptr) { if (selected != nullptr) {
ServiceRoot* root = selected->getParentServiceRoot(); ServiceRoot* root = selected->getParentServiceRoot();
if (root->supportsFeedAdding()) { if (root->supportsFeedAdding()) {
root->addNewFeed(); root->addNewFeed();
} }
else { else {
qApp->showGuiMessage(tr("Not supported"), qApp->showGuiMessage(tr("Not supported"),
tr("Selected account does not support adding of new feeds."), tr("Selected account does not support adding of new feeds."),
QSystemTrayIcon::Warning, QSystemTrayIcon::Warning,
qApp->mainFormWidget(), true); qApp->mainFormWidget(), true);
} }
} }
} }
void FeedsView::addCategoryIntoSelectedAccount() { void FeedsView::addCategoryIntoSelectedAccount() {
const RootItem* selected = selectedItem(); const RootItem* selected = selectedItem();
if (selected != nullptr) { if (selected != nullptr) {
ServiceRoot* root = selected->getParentServiceRoot(); ServiceRoot* root = selected->getParentServiceRoot();
if (root->supportsCategoryAdding()) { if (root->supportsCategoryAdding()) {
root->addNewCategory(); root->addNewCategory();
} }
else { else {
qApp->showGuiMessage(tr("Not supported"), qApp->showGuiMessage(tr("Not supported"),
tr("Selected account does not support adding of new categories."), tr("Selected account does not support adding of new categories."),
QSystemTrayIcon::Warning, QSystemTrayIcon::Warning,
qApp->mainFormWidget(), true); qApp->mainFormWidget(), true);
} }
} }
} }
void FeedsView::expandCollapseCurrentItem() { void FeedsView::expandCollapseCurrentItem() {
if (selectionModel()->selectedRows().size() == 1) { if (selectionModel()->selectedRows().size() == 1) {
QModelIndex index = selectionModel()->selectedRows().at(0); QModelIndex index = selectionModel()->selectedRows().at(0);
if (!index.child(0, 0).isValid() && index.parent().isValid()) { if (!index.child(0, 0).isValid() && index.parent().isValid()) {
setCurrentIndex(index.parent()); setCurrentIndex(index.parent());
index = index.parent(); index = index.parent();
} }
isExpanded(index) ? collapse(index) : expand(index); isExpanded(index) ? collapse(index) : expand(index);
} }
} }
void FeedsView::updateSelectedItems() { void FeedsView::updateSelectedItems() {
qApp->feedReader()->updateFeeds(selectedFeeds()); qApp->feedReader()->updateFeeds(selectedFeeds());
} }
void FeedsView::clearSelectedFeeds() { void FeedsView::clearSelectedFeeds() {
m_sourceModel->markItemCleared(selectedItem(), false); m_sourceModel->markItemCleared(selectedItem(), false);
} }
void FeedsView::clearAllFeeds() { void FeedsView::clearAllFeeds() {
m_sourceModel->markItemCleared(m_sourceModel->rootItem(), false); m_sourceModel->markItemCleared(m_sourceModel->rootItem(), false);
} }
void FeedsView::editSelectedItem() { void FeedsView::editSelectedItem() {
if (!qApp->feedUpdateLock()->tryLock()) { if (!qApp->feedUpdateLock()->tryLock()) {
// Lock was not obtained because // Lock was not obtained because
// it is used probably by feed updater or application // it is used probably by feed updater or application
// is quitting. // is quitting.
qApp->showGuiMessage(tr("Cannot edit item"), qApp->showGuiMessage(tr("Cannot edit item"),
tr("Selected item cannot be edited because another critical operation is ongoing."), tr("Selected item cannot be edited because another critical operation is ongoing."),
QSystemTrayIcon::Warning, qApp->mainFormWidget(), true); QSystemTrayIcon::Warning, qApp->mainFormWidget(), true);
// Thus, cannot delete and quit the method.
return;
}
if (selectedItem()->canBeEdited()) { // Thus, cannot delete and quit the method.
selectedItem()->editViaGui(); return;
} }
else {
qApp->showGuiMessage(tr("Cannot edit item"),
tr("Selected item cannot be edited, this is not (yet?) supported."),
QSystemTrayIcon::Warning,
qApp->mainFormWidget(),
true);
}
// Changes are done, unlock the update master lock. if (selectedItem()->canBeEdited()) {
qApp->feedUpdateLock()->unlock(); selectedItem()->editViaGui();
}
else {
qApp->showGuiMessage(tr("Cannot edit item"),
tr("Selected item cannot be edited, this is not (yet?) supported."),
QSystemTrayIcon::Warning,
qApp->mainFormWidget(),
true);
}
// Changes are done, unlock the update master lock.
qApp->feedUpdateLock()->unlock();
} }
void FeedsView::deleteSelectedItem() { void FeedsView::deleteSelectedItem() {
if (!qApp->feedUpdateLock()->tryLock()) { if (!qApp->feedUpdateLock()->tryLock()) {
// Lock was not obtained because // Lock was not obtained because
// it is used probably by feed updater or application // it is used probably by feed updater or application
// is quitting. // is quitting.
qApp->showGuiMessage(tr("Cannot delete item"), qApp->showGuiMessage(tr("Cannot delete item"),
tr("Selected item cannot be deleted because another critical operation is ongoing."), tr("Selected item cannot be deleted because another critical operation is ongoing."),
QSystemTrayIcon::Warning, qApp->mainFormWidget(), true); QSystemTrayIcon::Warning, qApp->mainFormWidget(), true);
// Thus, cannot delete and quit the method.
return;
}
if (!currentIndex().isValid()) { // Thus, cannot delete and quit the method.
// Changes are done, unlock the update master lock and exit. return;
qApp->feedUpdateLock()->unlock(); }
return;
}
RootItem* selected_item = selectedItem(); if (!currentIndex().isValid()) {
// Changes are done, unlock the update master lock and exit.
qApp->feedUpdateLock()->unlock();
return;
}
if (selected_item != nullptr) { RootItem* selected_item = selectedItem();
if (selected_item->canBeDeleted()) {
// Ask user first.
if (MessageBox::show(qApp->mainFormWidget(),
QMessageBox::Question,
tr("Deleting \"%1\"").arg(selected_item->title()),
tr("You are about to completely delete item \"%1\".").arg(selected_item->title()),
tr("Are you sure?"),
QString(), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::No) {
// User refused.
qApp->feedUpdateLock()->unlock();
return;
}
// We have deleteable item selected, remove it via GUI. if (selected_item != nullptr) {
if (!selected_item->deleteViaGui()) { if (selected_item->canBeDeleted()) {
qApp->showGuiMessage(tr("Cannot delete \"%1\"").arg(selected_item->title()), // Ask user first.
tr("This item cannot be deleted because something critically failed. Submit bug report."), if (MessageBox::show(qApp->mainFormWidget(),
QSystemTrayIcon::Critical, QMessageBox::Question,
qApp->mainFormWidget(), tr("Deleting \"%1\"").arg(selected_item->title()),
true); tr("You are about to completely delete item \"%1\".").arg(selected_item->title()),
} tr("Are you sure?"),
} QString(), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::No) {
else { // User refused.
qApp->showGuiMessage(tr("Cannot delete \"%1\"").arg(selected_item->title()), qApp->feedUpdateLock()->unlock();
tr("This item cannot be deleted, because it does not support it\nor this functionality is not implemented yet."), return;
QSystemTrayIcon::Critical, }
qApp->mainFormWidget(),
true);
}
}
// Changes are done, unlock the update master lock. // We have deleteable item selected, remove it via GUI.
qApp->feedUpdateLock()->unlock(); if (!selected_item->deleteViaGui()) {
qApp->showGuiMessage(tr("Cannot delete \"%1\"").arg(selected_item->title()),
tr("This item cannot be deleted because something critically failed. Submit bug report."),
QSystemTrayIcon::Critical,
qApp->mainFormWidget(),
true);
}
}
else {
qApp->showGuiMessage(tr("Cannot delete \"%1\"").arg(selected_item->title()),
tr("This item cannot be deleted, because it does not support it\nor this functionality is not implemented yet."),
QSystemTrayIcon::Critical,
qApp->mainFormWidget(),
true);
}
}
// Changes are done, unlock the update master lock.
qApp->feedUpdateLock()->unlock();
} }
void FeedsView::markSelectedItemReadStatus(RootItem::ReadStatus read) { void FeedsView::markSelectedItemReadStatus(RootItem::ReadStatus read) {
m_sourceModel->markItemRead(selectedItem(), read); m_sourceModel->markItemRead(selectedItem(), read);
} }
void FeedsView::markSelectedItemRead() { void FeedsView::markSelectedItemRead() {
markSelectedItemReadStatus(RootItem::Read); markSelectedItemReadStatus(RootItem::Read);
} }
void FeedsView::markSelectedItemUnread() { void FeedsView::markSelectedItemUnread() {
markSelectedItemReadStatus(RootItem::Unread); markSelectedItemReadStatus(RootItem::Unread);
} }
void FeedsView::markAllItemsReadStatus(RootItem::ReadStatus read) { void FeedsView::markAllItemsReadStatus(RootItem::ReadStatus read) {
m_sourceModel->markItemRead(m_sourceModel->rootItem(), read); m_sourceModel->markItemRead(m_sourceModel->rootItem(), read);
} }
void FeedsView::markAllItemsRead() { void FeedsView::markAllItemsRead() {
markAllItemsReadStatus(RootItem::Read); markAllItemsReadStatus(RootItem::Read);
} }
void FeedsView::openSelectedItemsInNewspaperMode() { void FeedsView::openSelectedItemsInNewspaperMode() {
RootItem* selected_item = selectedItem(); RootItem* selected_item = selectedItem();
const QList<Message> messages = m_sourceModel->messagesForItem(selected_item); const QList<Message> messages = m_sourceModel->messagesForItem(selected_item);
if (!messages.isEmpty()) { if (!messages.isEmpty()) {
emit openMessagesInNewspaperView(selected_item, messages); emit openMessagesInNewspaperView(selected_item, messages);
} }
} }
void FeedsView::selectNextItem() { void FeedsView::selectNextItem() {
const QModelIndex& curr_idx = currentIndex(); const QModelIndex& curr_idx = currentIndex();
if (m_proxyModel->hasChildren(curr_idx) && !isExpanded(curr_idx)) { if (m_proxyModel->hasChildren(curr_idx) && !isExpanded(curr_idx)) {
expand(curr_idx); expand(curr_idx);
} }
const QModelIndex& index_next = moveCursor(QAbstractItemView::MoveDown, Qt::NoModifier); const QModelIndex& index_next = moveCursor(QAbstractItemView::MoveDown, Qt::NoModifier);
if (index_next.isValid()) { if (index_next.isValid()) {
setCurrentIndex(index_next); setCurrentIndex(index_next);
setFocus(); setFocus();
} }
} }
void FeedsView::selectPreviousItem() { void FeedsView::selectPreviousItem() {
const QModelIndex& curr_idx = currentIndex(); const QModelIndex& curr_idx = currentIndex();
if (m_proxyModel->hasChildren(curr_idx) && !isExpanded(curr_idx)) { if (m_proxyModel->hasChildren(curr_idx) && !isExpanded(curr_idx)) {
expand(curr_idx); expand(curr_idx);
} }
const QModelIndex& index_previous = moveCursor(QAbstractItemView::MoveUp, Qt::NoModifier); const QModelIndex& index_previous = moveCursor(QAbstractItemView::MoveUp, Qt::NoModifier);
if (index_previous.isValid()) { if (index_previous.isValid()) {
setCurrentIndex(index_previous); setCurrentIndex(index_previous);
setFocus(); setFocus();
} }
} }
@ -416,197 +423,200 @@ QModelIndex FeedsView::nextUnreadItem(QModelIndex default_row) {
} }
void FeedsView::switchVisibility() { void FeedsView::switchVisibility() {
setVisible(!isVisible()); setVisible(!isVisible());
} }
void FeedsView::expandItemDelayed(const QModelIndex& idx) { void FeedsView::expandItemDelayed(const QModelIndex& idx) {
QTimer::singleShot(100, this, [ = ] { QTimer::singleShot(100, this, [ = ] {
setExpanded(m_proxyModel->mapFromSource(idx), true); setExpanded(m_proxyModel->mapFromSource(idx), true);
}); });
} }
QMenu* FeedsView::initializeContextMenuCategories(RootItem* clicked_item) { QMenu* FeedsView::initializeContextMenuCategories(RootItem* clicked_item) {
if (m_contextMenuCategories == nullptr) { if (m_contextMenuCategories == nullptr) {
m_contextMenuCategories = new QMenu(tr("Context menu for categories"), this); m_contextMenuCategories = new QMenu(tr("Context menu for categories"), this);
} }
else { else {
m_contextMenuCategories->clear(); m_contextMenuCategories->clear();
} }
QList<QAction*> specific_actions = clicked_item->contextMenu(); QList<QAction*> specific_actions = clicked_item->contextMenu();
m_contextMenuCategories->addActions(QList<QAction*>() << m_contextMenuCategories->addActions(QList<QAction*>() <<
qApp->mainForm()->m_ui->m_actionUpdateSelectedItems << qApp->mainForm()->m_ui->m_actionUpdateSelectedItems <<
qApp->mainForm()->m_ui->m_actionEditSelectedItem << qApp->mainForm()->m_ui->m_actionEditSelectedItem <<
qApp->mainForm()->m_ui->m_actionViewSelectedItemsNewspaperMode << qApp->mainForm()->m_ui->m_actionViewSelectedItemsNewspaperMode <<
qApp->mainForm()->m_ui->m_actionMarkSelectedItemsAsRead << qApp->mainForm()->m_ui->m_actionMarkSelectedItemsAsRead <<
qApp->mainForm()->m_ui->m_actionMarkSelectedItemsAsUnread << qApp->mainForm()->m_ui->m_actionMarkSelectedItemsAsUnread <<
qApp->mainForm()->m_ui->m_actionDeleteSelectedItem); qApp->mainForm()->m_ui->m_actionDeleteSelectedItem);
if (!specific_actions.isEmpty()) { if (!specific_actions.isEmpty()) {
m_contextMenuCategories->addSeparator(); m_contextMenuCategories->addSeparator();
m_contextMenuCategories->addActions(specific_actions); m_contextMenuCategories->addActions(specific_actions);
} }
return m_contextMenuCategories; return m_contextMenuCategories;
} }
QMenu* FeedsView::initializeContextMenuFeeds(RootItem* clicked_item) { QMenu* FeedsView::initializeContextMenuFeeds(RootItem* clicked_item) {
if (m_contextMenuFeeds == nullptr) { if (m_contextMenuFeeds == nullptr) {
m_contextMenuFeeds = new QMenu(tr("Context menu for categories"), this); m_contextMenuFeeds = new QMenu(tr("Context menu for categories"), this);
} }
else { else {
m_contextMenuFeeds->clear(); m_contextMenuFeeds->clear();
} }
QList<QAction*> specific_actions = clicked_item->contextMenu(); QList<QAction*> specific_actions = clicked_item->contextMenu();
m_contextMenuFeeds->addActions(QList<QAction*>() << m_contextMenuFeeds->addActions(QList<QAction*>() <<
qApp->mainForm()->m_ui->m_actionUpdateSelectedItems << qApp->mainForm()->m_ui->m_actionUpdateSelectedItems <<
qApp->mainForm()->m_ui->m_actionEditSelectedItem << qApp->mainForm()->m_ui->m_actionEditSelectedItem <<
qApp->mainForm()->m_ui->m_actionViewSelectedItemsNewspaperMode << qApp->mainForm()->m_ui->m_actionViewSelectedItemsNewspaperMode <<
qApp->mainForm()->m_ui->m_actionMarkSelectedItemsAsRead << qApp->mainForm()->m_ui->m_actionMarkSelectedItemsAsRead <<
qApp->mainForm()->m_ui->m_actionMarkSelectedItemsAsUnread << qApp->mainForm()->m_ui->m_actionMarkSelectedItemsAsUnread <<
qApp->mainForm()->m_ui->m_actionDeleteSelectedItem); qApp->mainForm()->m_ui->m_actionDeleteSelectedItem);
if (!specific_actions.isEmpty()) { if (!specific_actions.isEmpty()) {
m_contextMenuFeeds->addSeparator(); m_contextMenuFeeds->addSeparator();
m_contextMenuFeeds->addActions(specific_actions); m_contextMenuFeeds->addActions(specific_actions);
} }
return m_contextMenuFeeds; return m_contextMenuFeeds;
} }
QMenu* FeedsView::initializeContextMenuEmptySpace() { QMenu* FeedsView::initializeContextMenuEmptySpace() {
if (m_contextMenuEmptySpace == nullptr) { if (m_contextMenuEmptySpace == nullptr) {
m_contextMenuEmptySpace = new QMenu(tr("Context menu for empty space"), this); m_contextMenuEmptySpace = new QMenu(tr("Context menu for empty space"), this);
m_contextMenuEmptySpace->addAction(qApp->mainForm()->m_ui->m_actionUpdateAllItems); m_contextMenuEmptySpace->addAction(qApp->mainForm()->m_ui->m_actionUpdateAllItems);
m_contextMenuEmptySpace->addSeparator(); m_contextMenuEmptySpace->addSeparator();
} }
return m_contextMenuEmptySpace; return m_contextMenuEmptySpace;
} }
QMenu* FeedsView::initializeContextMenuOtherItem(RootItem* clicked_item) { QMenu* FeedsView::initializeContextMenuOtherItem(RootItem* clicked_item) {
if (m_contextMenuOtherItems == nullptr) { if (m_contextMenuOtherItems == nullptr) {
m_contextMenuOtherItems = new QMenu(tr("Context menu for other items"), this); m_contextMenuOtherItems = new QMenu(tr("Context menu for other items"), this);
} }
else { else {
m_contextMenuOtherItems->clear(); m_contextMenuOtherItems->clear();
} }
QList<QAction*> specific_actions = clicked_item->contextMenu(); QList<QAction*> specific_actions = clicked_item->contextMenu();
if (!specific_actions.isEmpty()) { if (!specific_actions.isEmpty()) {
m_contextMenuOtherItems->addSeparator(); m_contextMenuOtherItems->addSeparator();
m_contextMenuOtherItems->addActions(specific_actions); m_contextMenuOtherItems->addActions(specific_actions);
} }
else { else {
m_contextMenuOtherItems->addAction(qApp->mainForm()->m_ui->m_actionNoActions); m_contextMenuOtherItems->addAction(qApp->mainForm()->m_ui->m_actionNoActions);
} }
return m_contextMenuOtherItems; return m_contextMenuOtherItems;
} }
void FeedsView::setupAppearance() { void FeedsView::setupAppearance() {
// Setup column resize strategies. // Setup column resize strategies.
header()->setSectionResizeMode(FDS_MODEL_TITLE_INDEX, QHeaderView::Stretch); header()->setSectionResizeMode(FDS_MODEL_TITLE_INDEX, QHeaderView::Stretch);
header()->setSectionResizeMode(FDS_MODEL_COUNTS_INDEX, QHeaderView::ResizeToContents); header()->setSectionResizeMode(FDS_MODEL_COUNTS_INDEX, QHeaderView::ResizeToContents);
header()->setStretchLastSection(false); header()->setStretchLastSection(false);
header()->setSortIndicatorShown(false); header()->setSortIndicatorShown(false);
setUniformRowHeights(true); setUniformRowHeights(true);
setAnimated(true); setAnimated(true);
setSortingEnabled(true); setSortingEnabled(true);
setItemsExpandable(true); setItemsExpandable(true);
setExpandsOnDoubleClick(true); setExpandsOnDoubleClick(true);
setEditTriggers(QAbstractItemView::NoEditTriggers); setEditTriggers(QAbstractItemView::NoEditTriggers);
setIndentation(FEEDS_VIEW_INDENTATION); setIndentation(FEEDS_VIEW_INDENTATION);
setAcceptDrops(false); setAcceptDrops(false);
setDragEnabled(true); setDragEnabled(true);
setDropIndicatorShown(true); setDropIndicatorShown(true);
setDragDropMode(QAbstractItemView::InternalMove); setDragDropMode(QAbstractItemView::InternalMove);
setAllColumnsShowFocus(false); setAllColumnsShowFocus(false);
setRootIsDecorated(false); setRootIsDecorated(false);
setSelectionMode(QAbstractItemView::SingleSelection); setSelectionMode(QAbstractItemView::SingleSelection);
setItemDelegate(new StyledItemDelegateWithoutFocus(this)); setItemDelegate(new StyledItemDelegateWithoutFocus(this));
} }
void FeedsView::selectionChanged(const QItemSelection& selected, const QItemSelection& deselected) { void FeedsView::selectionChanged(const QItemSelection& selected, const QItemSelection& deselected) {
RootItem* selected_item = selectedItem(); RootItem* selected_item = selectedItem();
m_proxyModel->setSelectedItem(selected_item);
QTreeView::selectionChanged(selected, deselected); m_proxyModel->setSelectedItem(selected_item);
emit itemSelected(selected_item); QTreeView::selectionChanged(selected, deselected);
m_proxyModel->invalidateReadFeedsFilter(); emit itemSelected(selected_item);
m_proxyModel->invalidateReadFeedsFilter();
} }
void FeedsView::keyPressEvent(QKeyEvent* event) { void FeedsView::keyPressEvent(QKeyEvent* event) {
QTreeView::keyPressEvent(event); QTreeView::keyPressEvent(event);
if (event->key() == Qt::Key_Delete) { if (event->key() == Qt::Key_Delete) {
deleteSelectedItem(); deleteSelectedItem();
} }
} }
void FeedsView::contextMenuEvent(QContextMenuEvent* event) { void FeedsView::contextMenuEvent(QContextMenuEvent* event) {
const QModelIndex clicked_index = indexAt(event->pos()); const QModelIndex clicked_index = indexAt(event->pos());
if (clicked_index.isValid()) { if (clicked_index.isValid()) {
const QModelIndex mapped_index = model()->mapToSource(clicked_index); const QModelIndex mapped_index = model()->mapToSource(clicked_index);
RootItem* clicked_item = sourceModel()->itemForIndex(mapped_index); RootItem* clicked_item = sourceModel()->itemForIndex(mapped_index);
if (clicked_item->kind() == RootItemKind::Category) { if (clicked_item->kind() == RootItemKind::Category) {
// Display context menu for categories. // Display context menu for categories.
initializeContextMenuCategories(clicked_item)->exec(event->globalPos()); initializeContextMenuCategories(clicked_item)->exec(event->globalPos());
} }
else if (clicked_item->kind() == RootItemKind::Feed) { else if (clicked_item->kind() == RootItemKind::Feed) {
// Display context menu for feeds. // Display context menu for feeds.
initializeContextMenuFeeds(clicked_item)->exec(event->globalPos()); initializeContextMenuFeeds(clicked_item)->exec(event->globalPos());
} }
else { else {
initializeContextMenuOtherItem(clicked_item)->exec(event->globalPos()); initializeContextMenuOtherItem(clicked_item)->exec(event->globalPos());
} }
} }
else { else {
// Display menu for empty space. // Display menu for empty space.
initializeContextMenuEmptySpace()->exec(event->globalPos()); initializeContextMenuEmptySpace()->exec(event->globalPos());
} }
} }
void FeedsView::mouseDoubleClickEvent(QMouseEvent* event) { void FeedsView::mouseDoubleClickEvent(QMouseEvent* event) {
QModelIndex idx = indexAt(event->pos()); QModelIndex idx = indexAt(event->pos());
if (idx.isValid()) { if (idx.isValid()) {
RootItem* item = m_sourceModel->itemForIndex(m_proxyModel->mapToSource(idx)); RootItem* item = m_sourceModel->itemForIndex(m_proxyModel->mapToSource(idx));
if (item->kind() == RootItemKind::Feed || item->kind() == RootItemKind::Bin) { if (item->kind() == RootItemKind::Feed || item->kind() == RootItemKind::Bin) {
const QList<Message> messages = m_sourceModel->messagesForItem(item); const QList<Message> messages = m_sourceModel->messagesForItem(item);
if (!messages.isEmpty()) { if (!messages.isEmpty()) {
emit openMessagesInNewspaperView(item, messages); emit openMessagesInNewspaperView(item, messages);
} }
} }
} }
QTreeView::mouseDoubleClickEvent(event); QTreeView::mouseDoubleClickEvent(event);
} }
void FeedsView::saveSortState(int column, Qt::SortOrder order) { void FeedsView::saveSortState(int column, Qt::SortOrder order) {
qApp->settings()->setValue(GROUP(GUI), GUI::DefaultSortColumnFeeds, column); qApp->settings()->setValue(GROUP(GUI), GUI::DefaultSortColumnFeeds, column);
qApp->settings()->setValue(GROUP(GUI), GUI::DefaultSortOrderFeeds, order); qApp->settings()->setValue(GROUP(GUI), GUI::DefaultSortOrderFeeds, order);
} }
void FeedsView::validateItemAfterDragDrop(const QModelIndex& source_index) { void FeedsView::validateItemAfterDragDrop(const QModelIndex& source_index) {
const QModelIndex mapped = m_proxyModel->mapFromSource(source_index); const QModelIndex mapped = m_proxyModel->mapFromSource(source_index);
if (mapped.isValid()) { if (mapped.isValid()) {
expand(mapped); expand(mapped);
setCurrentIndex(mapped); setCurrentIndex(mapped);
} }
} }
void FeedsView::onItemExpandRequested(const QList<RootItem*>& items, bool exp) { void FeedsView::onItemExpandRequested(const QList<RootItem*>& items, bool exp) {
foreach (const RootItem* item, items) { foreach (const RootItem* item, items) {
QModelIndex source_index = m_sourceModel->indexForItem(item); QModelIndex source_index = m_sourceModel->indexForItem(item);
QModelIndex proxy_index = m_proxyModel->mapFromSource(source_index); QModelIndex proxy_index = m_proxyModel->mapFromSource(source_index);
setExpanded(proxy_index, exp);
} setExpanded(proxy_index, exp);
}
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -24,120 +25,119 @@
#include <QStyledItemDelegate> #include <QStyledItemDelegate>
class FeedsProxyModel; class FeedsProxyModel;
class Feed; class Feed;
class Category; class Category;
class FeedsView : public QTreeView { class FeedsView : public QTreeView {
Q_OBJECT Q_OBJECT
public: public:
// Constructors and destructors.
explicit FeedsView(QWidget* parent = 0);
virtual ~FeedsView();
// Fundamental accessors. // Constructors and destructors.
inline FeedsProxyModel* model() const { explicit FeedsView(QWidget* parent = 0);
return m_proxyModel; virtual ~FeedsView();
}
inline FeedsModel* sourceModel() const { // Fundamental accessors.
return m_sourceModel; inline FeedsProxyModel* model() const {
} return m_proxyModel;
}
void setSortingEnabled(bool enable); inline FeedsModel* sourceModel() const {
return m_sourceModel;
}
// Returns list of selected/all feeds. void setSortingEnabled(bool enable);
// NOTE: This is recursive method which returns all descendants.
QList<Feed*> selectedFeeds() const;
// Returns pointers to selected feed/category if they are really // Returns list of selected/all feeds.
// selected. // NOTE: This is recursive method which returns all descendants.
RootItem* selectedItem() const; QList<Feed*> selectedFeeds() const;
// Saves/loads expand states of all nodes (feeds/categories) of the list to/from settings. // Returns pointers to selected feed/category if they are really
void saveAllExpandStates(); // selected.
void loadAllExpandStates(); RootItem* selectedItem() const;
public slots: // Saves/loads expand states of all nodes (feeds/categories) of the list to/from settings.
void sortByColumn(int column, Qt::SortOrder order); void saveAllExpandStates();
void loadAllExpandStates();
void addFeedIntoSelectedAccount(); public slots:
void addCategoryIntoSelectedAccount(); void sortByColumn(int column, Qt::SortOrder order);
void expandCollapseCurrentItem();
// Feed updating. void addFeedIntoSelectedAccount();
void updateSelectedItems(); void addCategoryIntoSelectedAccount();
void expandCollapseCurrentItem();
// Feed read/unread manipulators. // Feed updating.
void markSelectedItemRead(); void updateSelectedItems();
void markSelectedItemUnread();
void markAllItemsRead();
// Newspaper accessors. // Feed read/unread manipulators.
void openSelectedItemsInNewspaperMode(); void markSelectedItemRead();
void markSelectedItemUnread();
void markAllItemsRead();
// Feed clearers. // Newspaper accessors.
void clearSelectedFeeds(); void openSelectedItemsInNewspaperMode();
void clearAllFeeds();
// Base manipulators. // Feed clearers.
void editSelectedItem(); void clearSelectedFeeds();
void deleteSelectedItem(); void clearAllFeeds();
// Selects next/previous item (feed/category) in the list. // Base manipulators.
void selectNextItem(); void editSelectedItem();
void selectPreviousItem(); void deleteSelectedItem();
// Selects next/previous item (feed/category) in the list.
void selectNextItem();
void selectPreviousItem();
void selectNextUnreadItem(); void selectNextUnreadItem();
// Switches visibility of the widget. // Switches visibility of the widget.
void switchVisibility(); void switchVisibility();
signals: signals:
void itemSelected(RootItem* item); void itemSelected(RootItem* item);
void requestViewNextUnreadMessage(); void requestViewNextUnreadMessage();
void openMessagesInNewspaperView(RootItem* root, const QList<Message>& messages); void openMessagesInNewspaperView(RootItem* root, const QList<Message>& messages);
protected: protected:
void selectionChanged(const QItemSelection& selected, const QItemSelection& deselected); void selectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
void keyPressEvent(QKeyEvent* event); void keyPressEvent(QKeyEvent* event);
void contextMenuEvent(QContextMenuEvent* event); void contextMenuEvent(QContextMenuEvent* event);
void mouseDoubleClickEvent(QMouseEvent* event); void mouseDoubleClickEvent(QMouseEvent* event);
private slots: private slots:
void expandItemDelayed(const QModelIndex& idx); void expandItemDelayed(const QModelIndex& idx);
void markSelectedItemReadStatus(RootItem::ReadStatus read); void markSelectedItemReadStatus(RootItem::ReadStatus read);
void markAllItemsReadStatus(RootItem::ReadStatus read); void markAllItemsReadStatus(RootItem::ReadStatus read);
void saveSortState(int column, Qt::SortOrder order); void saveSortState(int column, Qt::SortOrder order);
void validateItemAfterDragDrop(const QModelIndex& source_index); void validateItemAfterDragDrop(const QModelIndex& source_index);
void onItemExpandRequested(const QList<RootItem*>& items, bool exp); void onItemExpandRequested(const QList<RootItem*>& items, bool exp);
void onItemExpandStateSaveRequested(RootItem* item); void onItemExpandStateSaveRequested(RootItem* item);
private: private:
QModelIndex nextPreviousUnreadItem(QModelIndex default_row); QModelIndex nextPreviousUnreadItem(QModelIndex default_row);
QModelIndex nextUnreadItem(QModelIndex default_row); QModelIndex nextUnreadItem(QModelIndex default_row);
// Initializes context menus. // Initializes context menus.
QMenu* initializeContextMenuCategories(RootItem* clicked_item); QMenu* initializeContextMenuCategories(RootItem* clicked_item);
QMenu* initializeContextMenuFeeds(RootItem* clicked_item); QMenu* initializeContextMenuFeeds(RootItem* clicked_item);
QMenu* initializeContextMenuEmptySpace(); QMenu* initializeContextMenuEmptySpace();
QMenu* initializeContextMenuOtherItem(RootItem* clicked_item); QMenu* initializeContextMenuOtherItem(RootItem* clicked_item);
// Sets up appearance of this widget. // Sets up appearance of this widget.
void setupAppearance(); void setupAppearance();
void saveExpandStates(RootItem* item); void saveExpandStates(RootItem* item);
QMenu* m_contextMenuCategories; QMenu* m_contextMenuCategories;
QMenu* m_contextMenuFeeds; QMenu* m_contextMenuFeeds;
QMenu* m_contextMenuEmptySpace; QMenu* m_contextMenuEmptySpace;
QMenu* m_contextMenuOtherItems; QMenu* m_contextMenuOtherItems;
FeedsModel* m_sourceModel;
FeedsModel* m_sourceModel; FeedsProxyModel* m_proxyModel;
FeedsProxyModel* m_proxyModel;
}; };
#endif // FEEDSVIEW_H #endif // FEEDSVIEW_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -19,23 +20,22 @@
#include "definitions/definitions.h" #include "definitions/definitions.h"
void GuiUtilities::setLabelAsNotice(QLabel& label, bool is_warning) { void GuiUtilities::setLabelAsNotice(QLabel& label, bool is_warning) {
label.setMargin(6); label.setMargin(6);
if (is_warning) { if (is_warning) {
label.setStyleSheet(QSL("font-weight: bold; font-style: italic; color: red")); label.setStyleSheet(QSL("font-weight: bold; font-style: italic; color: red"));
} }
else { else {
label.setStyleSheet(QSL("font-style: italic;")); label.setStyleSheet(QSL("font-style: italic;"));
} }
} }
void GuiUtilities::applyDialogProperties(QWidget& widget, const QIcon& icon, const QString& title) { void GuiUtilities::applyDialogProperties(QWidget& widget, const QIcon& icon, const QString& title) {
widget.setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint); widget.setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint);
widget.setWindowIcon(icon); widget.setWindowIcon(icon);
if (!title.isEmpty()) { if (!title.isEmpty()) {
widget.setWindowTitle(title); widget.setWindowTitle(title);
} }
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -18,17 +19,16 @@
#ifndef GUIUTILITIES_H #ifndef GUIUTILITIES_H
#define GUIUTILITIES_H #define GUIUTILITIES_H
#include <QWidget>
#include <QLabel> #include <QLabel>
#include <QWidget>
class GuiUtilities { class GuiUtilities {
public: public:
static void setLabelAsNotice(QLabel& label, bool is_warning); static void setLabelAsNotice(QLabel& label, bool is_warning);
static void applyDialogProperties(QWidget& widget, const QIcon& icon, const QString& title = QString()); static void applyDialogProperties(QWidget& widget, const QIcon& icon, const QString& title = QString());
private: private:
explicit GuiUtilities(); explicit GuiUtilities();
}; };
inline GuiUtilities::GuiUtilities() {} inline GuiUtilities::GuiUtilities() {}

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -21,24 +22,25 @@
#include <QHBoxLayout> #include <QHBoxLayout>
LabelWithStatus::LabelWithStatus(QWidget* parent) LabelWithStatus::LabelWithStatus(QWidget* parent)
: WidgetWithStatus(parent) { : WidgetWithStatus(parent) {
m_wdgInput = new QLabel(this); m_wdgInput = new QLabel(this);
// Set correct size for the tool button.
int label_height = m_wdgInput->sizeHint().height(); // Set correct size for the tool button.
m_btnStatus->setFixedSize(label_height, label_height); int label_height = m_wdgInput->sizeHint().height();
// Compose the layout.
m_layout->addWidget(m_wdgInput); m_btnStatus->setFixedSize(label_height, label_height);
m_layout->addWidget(m_btnStatus);
// Compose the layout.
m_layout->addWidget(m_wdgInput);
m_layout->addWidget(m_btnStatus);
} }
LabelWithStatus::~LabelWithStatus() { LabelWithStatus::~LabelWithStatus() {}
}
void LabelWithStatus::setStatus(WidgetWithStatus::StatusType status, void LabelWithStatus::setStatus(WidgetWithStatus::StatusType status,
const QString& label_text, const QString& label_text,
const QString& status_text) { const QString& status_text) {
WidgetWithStatus::setStatus(status, status_text); WidgetWithStatus::setStatus(status, status_text);
label()->setText(label_text); label()->setText(label_text);
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -22,21 +23,22 @@
#include <QLabel> #include <QLabel>
class LabelWithStatus : public WidgetWithStatus { class LabelWithStatus : public WidgetWithStatus {
Q_OBJECT Q_OBJECT
public: public:
// Constructors and destructors.
explicit LabelWithStatus(QWidget* parent = 0);
virtual ~LabelWithStatus();
void setStatus(StatusType status, const QString& label_text, const QString& status_text); // Constructors and destructors.
explicit LabelWithStatus(QWidget* parent = 0);
virtual ~LabelWithStatus();
void setStatus(StatusType status, const QString& label_text, const QString& status_text);
// Access to label.
inline QLabel* label() const {
return static_cast<QLabel*>(m_wdgInput);
}
// Access to label.
inline QLabel* label() const {
return static_cast<QLabel*>(m_wdgInput);
}
}; };
#endif // LABELWITHSTATUS_H #endif // LABELWITHSTATUS_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -17,23 +18,24 @@
#include "gui/lineeditwithstatus.h" #include "gui/lineeditwithstatus.h"
#include "gui/plaintoolbutton.h"
#include "gui/baselineedit.h" #include "gui/baselineedit.h"
#include "gui/plaintoolbutton.h"
#include <QHBoxLayout> #include <QHBoxLayout>
LineEditWithStatus::LineEditWithStatus(QWidget* parent) LineEditWithStatus::LineEditWithStatus(QWidget* parent)
: WidgetWithStatus(parent) { : WidgetWithStatus(parent) {
m_wdgInput = new BaseLineEdit(this); m_wdgInput = new BaseLineEdit(this);
setFocusProxy(m_wdgInput); setFocusProxy(m_wdgInput);
// Set correct size for the tool button.
const int txt_input_height = m_wdgInput->sizeHint().height(); // Set correct size for the tool button.
m_btnStatus->setFixedSize(txt_input_height, txt_input_height); const int txt_input_height = m_wdgInput->sizeHint().height();
// Compose the layout.
m_layout->addWidget(m_wdgInput); m_btnStatus->setFixedSize(txt_input_height, txt_input_height);
m_layout->addWidget(m_btnStatus);
// Compose the layout.
m_layout->addWidget(m_wdgInput);
m_layout->addWidget(m_btnStatus);
} }
LineEditWithStatus::~LineEditWithStatus() { LineEditWithStatus::~LineEditWithStatus() {}
}

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -22,19 +23,20 @@
#include "gui/baselineedit.h" #include "gui/baselineedit.h"
class LineEditWithStatus : public WidgetWithStatus { class LineEditWithStatus : public WidgetWithStatus {
Q_OBJECT Q_OBJECT
public: public:
// Constructors and destructors.
explicit LineEditWithStatus(QWidget* parent = 0); // Constructors and destructors.
virtual ~LineEditWithStatus(); explicit LineEditWithStatus(QWidget* parent = 0);
virtual ~LineEditWithStatus();
// Access to line edit.
inline BaseLineEdit* lineEdit() const {
return static_cast<BaseLineEdit*>(m_wdgInput);
}
// Access to line edit.
inline BaseLineEdit* lineEdit() const {
return static_cast<BaseLineEdit*>(m_wdgInput);
}
}; };
#endif // LINEEDITWITHSTATUS_H #endif // LINEEDITWITHSTATUS_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -21,31 +22,31 @@
#include <QMouseEvent> #include <QMouseEvent>
LocationLineEdit::LocationLineEdit(QWidget* parent) LocationLineEdit::LocationLineEdit(QWidget* parent)
: BaseLineEdit(parent), m_mouseSelectsAllText(true), m_googleSuggest(new GoogleSuggest(this)) { : BaseLineEdit(parent), m_mouseSelectsAllText(true), m_googleSuggest(new GoogleSuggest(this)) {
setPlaceholderText(tr("Website address goes here")); setPlaceholderText(tr("Website address goes here"));
connect(this, &LocationLineEdit::submitted, m_googleSuggest, &GoogleSuggest::preventSuggest); connect(this, &LocationLineEdit::submitted, m_googleSuggest, &GoogleSuggest::preventSuggest);
} }
LocationLineEdit::~LocationLineEdit() { LocationLineEdit::~LocationLineEdit() {}
}
void LocationLineEdit::focusOutEvent(QFocusEvent* event) { void LocationLineEdit::focusOutEvent(QFocusEvent* event) {
BaseLineEdit::focusOutEvent(event); BaseLineEdit::focusOutEvent(event);
// User now left text box, when he enters it again and clicks,
// then all text should be selected. // User now left text box, when he enters it again and clicks,
m_mouseSelectsAllText = true; // then all text should be selected.
m_mouseSelectsAllText = true;
} }
void LocationLineEdit::mousePressEvent(QMouseEvent* event) { void LocationLineEdit::mousePressEvent(QMouseEvent* event) {
if (m_mouseSelectsAllText) { if (m_mouseSelectsAllText) {
event->ignore(); event->ignore();
selectAll(); selectAll();
// User clicked and all text was selected.
m_mouseSelectsAllText = false; // User clicked and all text was selected.
} m_mouseSelectsAllText = false;
else { }
BaseLineEdit::mousePressEvent(event); else {
} BaseLineEdit::mousePressEvent(event);
}
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -20,25 +21,25 @@
#include "gui/baselineedit.h" #include "gui/baselineedit.h"
class WebBrowser; class WebBrowser;
class GoogleSuggest; class GoogleSuggest;
class LocationLineEdit : public BaseLineEdit { class LocationLineEdit : public BaseLineEdit {
Q_OBJECT Q_OBJECT
public: public:
// Constructors and destructors.
explicit LocationLineEdit(QWidget* parent = 0);
virtual ~LocationLineEdit();
protected: // Constructors and destructors.
void focusOutEvent(QFocusEvent* event); explicit LocationLineEdit(QWidget* parent = 0);
void mousePressEvent(QMouseEvent* event); virtual ~LocationLineEdit();
private: protected:
bool m_mouseSelectsAllText; void focusOutEvent(QFocusEvent* event);
GoogleSuggest* m_googleSuggest; void mousePressEvent(QMouseEvent* event);
private:
bool m_mouseSelectsAllText;
GoogleSuggest* m_googleSuggest;
}; };
#endif // LOCATIONLINEEDIT_H #endif // LOCATIONLINEEDIT_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -27,7 +28,6 @@
#include <QStyle> #include <QStyle>
#include <QtGlobal> #include <QtGlobal>
MessageBox::MessageBox(QWidget* parent) : QMessageBox(parent) {} MessageBox::MessageBox(QWidget* parent) : QMessageBox(parent) {}
MessageBox::~MessageBox() {} MessageBox::~MessageBox() {}
@ -72,9 +72,15 @@ QIcon MessageBox::iconForStatus(QMessageBox::Icon status) {
} }
} }
QMessageBox::StandardButton MessageBox::show(QWidget* parent, QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButton MessageBox::show(QWidget* parent,
const QString& informative_text, const QString& detailed_text, QMessageBox::StandardButtons buttons, QMessageBox::Icon icon,
QMessageBox::StandardButton default_button, bool* dont_show_again) { const QString& title,
const QString& text,
const QString& informative_text,
const QString& detailed_text,
QMessageBox::StandardButtons buttons,
QMessageBox::StandardButton default_button,
bool* dont_show_again) {
// Create and find needed components. // Create and find needed components.
MessageBox msg_box(parent); MessageBox msg_box(parent);

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -18,35 +19,34 @@
#ifndef MESSAGEBOX_H #ifndef MESSAGEBOX_H
#define MESSAGEBOX_H #define MESSAGEBOX_H
#include <QMessageBox>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QMessageBox>
class MessageBox : public QMessageBox { class MessageBox : public QMessageBox {
Q_OBJECT Q_OBJECT
public: public:
// Constructors and destructors.
explicit MessageBox(QWidget* parent = 0);
virtual ~MessageBox();
// Custom icon setting. // Constructors and destructors.
void setIcon(Icon icon); explicit MessageBox(QWidget* parent = 0);
virtual ~MessageBox();
static void setCheckBox(QMessageBox* msg_box, const QString& text, bool* data); // Custom icon setting.
void setIcon(Icon icon);
// Displays custom message box. static void setCheckBox(QMessageBox* msg_box, const QString& text, bool* data);
static QMessageBox::StandardButton show(QWidget* parent,
QMessageBox::Icon icon,
const QString& title,
const QString& text,
const QString& informative_text = QString(),
const QString& detailed_text = QString(),
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
QMessageBox::StandardButton default_button = QMessageBox::Ok,
bool* dont_show_again = nullptr);
static QIcon iconForStatus(QMessageBox::Icon status); // Displays custom message box.
static QMessageBox::StandardButton show(QWidget* parent,
QMessageBox::Icon icon,
const QString& title,
const QString& text,
const QString& informative_text = QString(),
const QString& detailed_text = QString(),
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
QMessageBox::StandardButton default_button = QMessageBox::Ok,
bool* dont_show_again = nullptr);
static QIcon iconForStatus(QMessageBox::Icon status);
}; };
#endif // MESSAGEBOX_H #endif // MESSAGEBOX_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -17,200 +18,206 @@
#include "gui/messagepreviewer.h" #include "gui/messagepreviewer.h"
#include "miscellaneous/application.h"
#include "network-web/webfactory.h"
#include "miscellaneous/databasequeries.h"
#include "gui/messagebox.h"
#include "gui/dialogs/formmain.h" #include "gui/dialogs/formmain.h"
#include "gui/messagebox.h"
#include "miscellaneous/application.h"
#include "miscellaneous/databasequeries.h"
#include "network-web/webfactory.h"
#include "services/abstract/serviceroot.h" #include "services/abstract/serviceroot.h"
#include <QScrollBar> #include <QScrollBar>
#include <QToolBar> #include <QToolBar>
#include <QToolTip> #include <QToolTip>
void MessagePreviewer::createConnections() { void MessagePreviewer::createConnections() {
connect(m_ui->m_txtMessage, &QTextBrowser::anchorClicked, [ = ](const QUrl & url) { connect(m_ui->m_txtMessage, &QTextBrowser::anchorClicked, [=](const QUrl& url) {
if (!url.isEmpty()) { if (!url.isEmpty()) {
bool open_externally_now = qApp->settings()->value(GROUP(Browser), bool open_externally_now = qApp->settings()->value(GROUP(Browser),
SETTING(Browser::OpenLinksInExternalBrowserRightAway)).toBool(); SETTING(Browser::OpenLinksInExternalBrowserRightAway)).toBool();
if (open_externally_now) { if (open_externally_now) {
qApp->web()->openUrlInExternalBrowser(url.toString()); qApp->web()->openUrlInExternalBrowser(url.toString());
} }
else { else {
// User clicked some URL. Open it in external browser or download? // User clicked some URL. Open it in external browser or download?
MessageBox box(qApp->mainForm()); MessageBox box(qApp->mainForm());
box.setText(tr("You clicked some link. You can download the link contents or open it in external web browser.")); 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.setInformativeText(tr("What action do you want to take?"));
box.setDetailedText(url.toString()); box.setDetailedText(url.toString());
QAbstractButton* btn_open = box.addButton(tr("Open in external browser"), QMessageBox::ActionRole); QAbstractButton* btn_open = box.addButton(tr("Open in external browser"), QMessageBox::ActionRole);
QAbstractButton* btn_download = box.addButton(tr("Download"), QMessageBox::ActionRole); QAbstractButton* btn_download = box.addButton(tr("Download"), QMessageBox::ActionRole);
QAbstractButton* btn_cancel = box.addButton(QMessageBox::Cancel); QAbstractButton* btn_cancel = box.addButton(QMessageBox::Cancel);
bool always; bool always;
MessageBox::setCheckBox(&box, tr("Always open links in external browser."), &always); MessageBox::setCheckBox(&box, tr("Always open links in external browser."), &always);
box.setDefaultButton(QMessageBox::Cancel); box.setDefaultButton(QMessageBox::Cancel);
box.exec(); box.exec();
if (box.clickedButton() != box.button(QMessageBox::Cancel)) { if (box.clickedButton() != box.button(QMessageBox::Cancel)) {
// Store selected checkbox value. // Store selected checkbox value.
qApp->settings()->setValue(GROUP(Browser), Browser::OpenLinksInExternalBrowserRightAway, always); qApp->settings()->setValue(GROUP(Browser), Browser::OpenLinksInExternalBrowserRightAway, always);
} }
if (box.clickedButton() == btn_open) { if (box.clickedButton() == btn_open) {
qApp->web()->openUrlInExternalBrowser(url.toString()); qApp->web()->openUrlInExternalBrowser(url.toString());
} }
else if (box.clickedButton() == btn_download) { else if (box.clickedButton() == btn_download) {
qApp->downloadManager()->download(url); qApp->downloadManager()->download(url);
} }
btn_download->deleteLater(); btn_download->deleteLater();
btn_open->deleteLater(); btn_open->deleteLater();
btn_cancel->deleteLater(); btn_cancel->deleteLater();
} }
} }
else { else {
MessageBox::show(qApp->mainForm(), QMessageBox::Warning, tr("Incorrect link"), MessageBox::show(qApp->mainForm(), QMessageBox::Warning, tr("Incorrect link"),
tr("Selected hyperlink is invalid.")); tr("Selected hyperlink is invalid."));
} }
}); });
connect(m_actionMarkRead = m_toolBar->addAction(qApp->icons()->fromTheme("mail-mark-read"), tr("Mark message as read")), connect(m_actionMarkRead = m_toolBar->addAction(qApp->icons()->fromTheme("mail-mark-read"), tr("Mark message as read")),
&QAction::triggered, &QAction::triggered,
this, this,
&MessagePreviewer::markMessageAsRead); &MessagePreviewer::markMessageAsRead);
connect(m_actionMarkUnread = m_toolBar->addAction(qApp->icons()->fromTheme("mail-mark-unread"), tr("Mark message as unread")), connect(m_actionMarkUnread = m_toolBar->addAction(qApp->icons()->fromTheme("mail-mark-unread"), tr("Mark message as unread")),
&QAction::triggered, &QAction::triggered,
this, this,
&MessagePreviewer::markMessageAsUnread); &MessagePreviewer::markMessageAsUnread);
connect(m_actionSwitchImportance = m_toolBar->addAction(qApp->icons()->fromTheme("mail-mark-important"), tr("Switch message importance")), connect(m_actionSwitchImportance = m_toolBar->addAction(qApp->icons()->fromTheme("mail-mark-important"), tr("Switch message importance")),
&QAction::triggered, &QAction::triggered,
this, this,
&MessagePreviewer::switchMessageImportance); &MessagePreviewer::switchMessageImportance);
connect(m_ui->m_txtMessage, connect(m_ui->m_txtMessage,
static_cast<void (QTextBrowser::*)(const QString&)>(&QTextBrowser::highlighted), static_cast<void (QTextBrowser::*)(const QString&)>(&QTextBrowser::highlighted),
[ = ](const QString & text) { [=](const QString& text) {
Q_UNUSED(text) Q_UNUSED(text)
QToolTip::showText(QCursor::pos(), tr("Click this link to download it or open it with external browser."), this); QToolTip::showText(QCursor::pos(), tr("Click this link to download it or open it with external browser."), this);
}); });
} }
MessagePreviewer::MessagePreviewer(QWidget* parent) : QWidget(parent), MessagePreviewer::MessagePreviewer(QWidget* parent) : QWidget(parent),
m_ui(new Ui::MessagePreviewer), m_pictures(QStringList()) { m_ui(new Ui::MessagePreviewer), m_pictures(QStringList()) {
m_ui->setupUi(this); m_ui->setupUi(this);
m_ui->m_txtMessage->viewport()->setAutoFillBackground(true); m_ui->m_txtMessage->viewport()->setAutoFillBackground(true);
m_toolBar = new QToolBar(this); m_toolBar = new QToolBar(this);
m_toolBar->setOrientation(Qt::Vertical); m_toolBar->setOrientation(Qt::Vertical);
m_ui->m_layout->addWidget(m_toolBar, 0, 0, -1, 1); m_ui->m_layout->addWidget(m_toolBar, 0, 0, -1, 1);
createConnections(); createConnections();
m_actionSwitchImportance->setCheckable(true); m_actionSwitchImportance->setCheckable(true);
reloadFontSettings(); reloadFontSettings();
clear(); clear();
} }
MessagePreviewer::~MessagePreviewer() { MessagePreviewer::~MessagePreviewer() {}
}
void MessagePreviewer::reloadFontSettings() { void MessagePreviewer::reloadFontSettings() {
const Settings* settings = qApp->settings(); const Settings* settings = qApp->settings();
QFont fon; QFont fon;
fon.fromString(settings->value(GROUP(Messages),
SETTING(Messages::PreviewerFontStandard)).toString()); fon.fromString(settings->value(GROUP(Messages),
m_ui->m_txtMessage->setFont(fon); SETTING(Messages::PreviewerFontStandard)).toString());
m_ui->m_txtMessage->setFont(fon);
} }
void MessagePreviewer::clear() { void MessagePreviewer::clear() {
m_ui->m_txtMessage->clear(); m_ui->m_txtMessage->clear();
m_pictures.clear(); m_pictures.clear();
hide(); hide();
} }
void MessagePreviewer::hideToolbar() { void MessagePreviewer::hideToolbar() {
m_toolBar->setVisible(false); m_toolBar->setVisible(false);
} }
void MessagePreviewer::loadMessage(const Message& message, RootItem* root) { void MessagePreviewer::loadMessage(const Message& message, RootItem* root) {
m_message = message; m_message = message;
m_root = root; m_root = root;
if (!m_root.isNull()) { if (!m_root.isNull()) {
m_actionSwitchImportance->setChecked(m_message.m_isImportant); m_actionSwitchImportance->setChecked(m_message.m_isImportant);
m_ui->m_txtMessage->setHtml(prepareHtmlForMessage(m_message)); m_ui->m_txtMessage->setHtml(prepareHtmlForMessage(m_message));
updateButtons(); updateButtons();
show(); show();
m_ui->m_txtMessage->verticalScrollBar()->triggerAction(QScrollBar::SliderToMinimum); m_ui->m_txtMessage->verticalScrollBar()->triggerAction(QScrollBar::SliderToMinimum);
} }
} }
void MessagePreviewer::markMessageAsRead() { void MessagePreviewer::markMessageAsRead() {
markMessageAsReadUnread(RootItem::Read); markMessageAsReadUnread(RootItem::Read);
} }
void MessagePreviewer::markMessageAsUnread() { void MessagePreviewer::markMessageAsUnread() {
markMessageAsReadUnread(RootItem::Unread); markMessageAsReadUnread(RootItem::Unread);
} }
void MessagePreviewer::markMessageAsReadUnread(RootItem::ReadStatus read) { void MessagePreviewer::markMessageAsReadUnread(RootItem::ReadStatus read) {
if (!m_root.isNull()) { if (!m_root.isNull()) {
if (m_root->getParentServiceRoot()->onBeforeSetMessagesRead(m_root.data(), if (m_root->getParentServiceRoot()->onBeforeSetMessagesRead(m_root.data(),
QList<Message>() << m_message, QList<Message>() << m_message,
read)) { read)) {
DatabaseQueries::markMessagesReadUnread(qApp->database()->connection(objectName(), DatabaseFactory::FromSettings), DatabaseQueries::markMessagesReadUnread(qApp->database()->connection(objectName(), DatabaseFactory::FromSettings),
QStringList() << QString::number(m_message.m_id), QStringList() << QString::number(m_message.m_id),
read); read);
m_root->getParentServiceRoot()->onAfterSetMessagesRead(m_root.data(), m_root->getParentServiceRoot()->onAfterSetMessagesRead(m_root.data(),
QList<Message>() << m_message, QList<Message>() << m_message,
read); read);
m_message.m_isRead = read == RootItem::Read; m_message.m_isRead = read == RootItem::Read;
emit markMessageRead(m_message.m_id, read); emit markMessageRead(m_message.m_id, read);
updateButtons();
} updateButtons();
} }
}
} }
void MessagePreviewer::switchMessageImportance(bool checked) { void MessagePreviewer::switchMessageImportance(bool checked) {
if (!m_root.isNull()) { if (!m_root.isNull()) {
if (m_root->getParentServiceRoot()->onBeforeSwitchMessageImportance(m_root.data(), if (m_root->getParentServiceRoot()->onBeforeSwitchMessageImportance(m_root.data(),
QList<ImportanceChange>() << ImportanceChange(m_message, QList<ImportanceChange>() << ImportanceChange(m_message,
m_message.m_isImportant ? m_message.
RootItem::NotImportant : m_isImportant ?
RootItem::Important))) { RootItem::NotImportant
:
RootItem::Important)))
{
DatabaseQueries::switchMessagesImportance(qApp->database()->connection(objectName(), DatabaseFactory::FromSettings), DatabaseQueries::switchMessagesImportance(qApp->database()->connection(objectName(), DatabaseFactory::FromSettings),
QStringList() << QString::number(m_message.m_id)); QStringList() << QString::number(m_message.m_id));
m_root->getParentServiceRoot()->onAfterSwitchMessageImportance(m_root.data(), m_root->getParentServiceRoot()->onAfterSwitchMessageImportance(m_root.data(),
QList<ImportanceChange>() << ImportanceChange(m_message, QList<ImportanceChange>() << ImportanceChange(m_message,
m_message.m_isImportant ? m_message.m_isImportant ?
RootItem::NotImportant : RootItem::NotImportant :
RootItem::Important)); RootItem::Important));
emit markMessageImportant(m_message.m_id, checked ? RootItem::Important : RootItem::NotImportant); emit markMessageImportant(m_message.m_id, checked ? RootItem::Important : RootItem::NotImportant);
m_message.m_isImportant = checked;
} m_message.m_isImportant = checked;
} }
}
} }
void MessagePreviewer::updateButtons() { void MessagePreviewer::updateButtons() {
m_actionMarkRead->setEnabled(!m_message.m_isRead); m_actionMarkRead->setEnabled(!m_message.m_isRead);
m_actionMarkUnread->setEnabled(m_message.m_isRead); m_actionMarkUnread->setEnabled(m_message.m_isRead);
} }
QString MessagePreviewer::prepareHtmlForMessage(const Message& message) { QString MessagePreviewer::prepareHtmlForMessage(const Message& message) {
QString html = QString("<h2 align=\"center\">%1</h2>").arg(message.m_title); QString html = QString("<h2 align=\"center\">%1</h2>").arg(message.m_title);
html += QString("[url] <a href=\"%1\">%1</a><br/>").arg(message.m_url);
foreach (const Enclosure& enc, message.m_enclosures) { html += QString("[url] <a href=\"%1\">%1</a><br/>").arg(message.m_url);
html += QString("[%2] <a href=\"%1\">%1</a><br/>").arg(enc.m_url, enc.m_mimeType);
}
int offset = 0; foreach (const Enclosure& enc, message.m_enclosures) {
QRegExp imgTagRegex("\\<img[^\\>]*src\\s*=\\s*\"([^\"]*)\"[^\\>]*\\>", Qt::CaseInsensitive); html += QString("[%2] <a href=\"%1\">%1</a><br/>").arg(enc.m_url, enc.m_mimeType);
imgTagRegex.setMinimal(true); }
while ((offset = imgTagRegex.indexIn(message.m_contents, offset)) != -1) { int offset = 0;
m_pictures.append(imgTagRegex.cap(1)); QRegExp imgTagRegex("\\<img[^\\>]*src\\s*=\\s*\"([^\"]*)\"[^\\>]*\\>", Qt::CaseInsensitive);
offset += imgTagRegex.matchedLength();
html += QString("[%2] <a href=\"%1\">%1</a><br/>").arg(imgTagRegex.cap(1), tr("image"));
}
html += "<br/>"; imgTagRegex.setMinimal(true);
html += message.m_contents;
return html; while ((offset = imgTagRegex.indexIn(message.m_contents, offset)) != -1) {
m_pictures.append(imgTagRegex.cap(1));
offset += imgTagRegex.matchedLength();
html += QString("[%2] <a href=\"%1\">%1</a><br/>").arg(imgTagRegex.cap(1), tr("image"));
}
html += "<br/>";
html += message.m_contents;
return html;
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -27,52 +28,53 @@
#include <QPointer> #include <QPointer>
namespace Ui { namespace Ui {
class MessagePreviewer; class MessagePreviewer;
} }
class QToolBar; class QToolBar;
class MessagePreviewer : public QWidget { class MessagePreviewer : public QWidget {
Q_OBJECT Q_OBJECT
public: public:
explicit MessagePreviewer(QWidget* parent = 0); explicit MessagePreviewer(QWidget* parent = 0);
virtual ~MessagePreviewer(); virtual ~MessagePreviewer();
void reloadFontSettings(); void reloadFontSettings();
public slots: public slots:
void clear(); void clear();
void hideToolbar(); void hideToolbar();
void loadMessage(const Message& message, RootItem* root); void loadMessage(const Message& message, RootItem* root);
private slots: private slots:
void markMessageAsRead(); void markMessageAsRead();
void markMessageAsUnread(); void markMessageAsUnread();
void markMessageAsReadUnread(RootItem::ReadStatus read); void markMessageAsReadUnread(RootItem::ReadStatus read);
void switchMessageImportance(bool checked); void switchMessageImportance(bool checked);
signals: signals:
void markMessageRead(int id, RootItem::ReadStatus read); void markMessageRead(int id, RootItem::ReadStatus read);
void markMessageImportant(int id, RootItem::Importance important); void markMessageImportant(int id, RootItem::Importance important);
void requestMessageListReload(bool mark_current_as_read); void requestMessageListReload(bool mark_current_as_read);
private: private:
void createConnections(); void createConnections();
void updateButtons(); void updateButtons();
QString prepareHtmlForMessage(const Message& message); QString prepareHtmlForMessage(const Message& message);
QToolBar* m_toolBar; QToolBar* m_toolBar;
QScopedPointer<Ui::MessagePreviewer> m_ui;
Message m_message;
QStringList m_pictures;
QPointer<RootItem> m_root;
QAction* m_actionMarkRead; QScopedPointer<Ui::MessagePreviewer> m_ui;
QAction* m_actionMarkUnread; Message m_message;
QAction* m_actionSwitchImportance; QStringList m_pictures;
QPointer<RootItem> m_root;
QAction* m_actionMarkRead;
QAction* m_actionMarkUnread;
QAction* m_actionSwitchImportance;
}; };
#endif // MESSAGEPREVIEWER_H #endif // MESSAGEPREVIEWER_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -17,9 +18,6 @@
#include "gui/messagessearchlineedit.h" #include "gui/messagessearchlineedit.h"
MessagesSearchLineEdit::MessagesSearchLineEdit(QWidget* parent) : BaseLineEdit(parent) {}
MessagesSearchLineEdit::MessagesSearchLineEdit(QWidget* parent) : BaseLineEdit(parent) { MessagesSearchLineEdit::~MessagesSearchLineEdit() {}
}
MessagesSearchLineEdit::~MessagesSearchLineEdit() {
}

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -20,16 +21,16 @@
#include "gui/baselineedit.h" #include "gui/baselineedit.h"
class PlainToolButton; class PlainToolButton;
class MessagesSearchLineEdit : public BaseLineEdit { class MessagesSearchLineEdit : public BaseLineEdit {
Q_OBJECT Q_OBJECT
public: public:
// Constructors and destructors.
explicit MessagesSearchLineEdit(QWidget* parent = 0); // Constructors and destructors.
virtual ~MessagesSearchLineEdit(); explicit MessagesSearchLineEdit(QWidget* parent = 0);
virtual ~MessagesSearchLineEdit();
}; };
#endif // MESSAGESEARCHLINEEDIT_H #endif // MESSAGESEARCHLINEEDIT_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -23,139 +24,141 @@
#include "miscellaneous/iconfactory.h" #include "miscellaneous/iconfactory.h"
#include "miscellaneous/settings.h" #include "miscellaneous/settings.h"
#include <QWidgetAction>
#include <QToolButton>
#include <QMenu> #include <QMenu>
#include <QToolButton>
#include <QWidgetAction>
MessagesToolBar::MessagesToolBar(const QString& title, QWidget* parent) MessagesToolBar::MessagesToolBar(const QString& title, QWidget* parent)
: BaseToolBar(title, parent) { : BaseToolBar(title, parent) {
initializeSearchBox(); initializeSearchBox();
initializeHighlighter(); initializeHighlighter();
} }
MessagesToolBar::~MessagesToolBar() { MessagesToolBar::~MessagesToolBar() {}
}
QList<QAction*> MessagesToolBar::availableActions() const { QList<QAction*> MessagesToolBar::availableActions() const {
QList<QAction*> available_actions = qApp->userActions(); QList<QAction*> available_actions = qApp->userActions();
available_actions.append(m_actionSearchMessages); available_actions.append(m_actionSearchMessages);
available_actions.append(m_actionMessageHighlighter); available_actions.append(m_actionMessageHighlighter);
return available_actions; return available_actions;
} }
QList<QAction*> MessagesToolBar::changeableActions() const { QList<QAction*> MessagesToolBar::changeableActions() const {
return actions(); return actions();
} }
void MessagesToolBar::saveChangeableActions(const QStringList& actions) { void MessagesToolBar::saveChangeableActions(const QStringList& actions) {
qApp->settings()->setValue(GROUP(GUI), GUI::MessagesToolbarDefaultButtons, actions.join(QSL(","))); qApp->settings()->setValue(GROUP(GUI), GUI::MessagesToolbarDefaultButtons, actions.join(QSL(",")));
loadSpecificActions(getSpecificActions(actions)); loadSpecificActions(getSpecificActions(actions));
// If user hidden search messages box, then remove the filter. // If user hidden search messages box, then remove the filter.
if (!changeableActions().contains(m_actionSearchMessages)) { if (!changeableActions().contains(m_actionSearchMessages)) {
m_txtSearchMessages->clear(); m_txtSearchMessages->clear();
} }
} }
QList<QAction*> MessagesToolBar::getSpecificActions(const QStringList& actions) { QList<QAction*> MessagesToolBar::getSpecificActions(const QStringList& actions) {
QList<QAction*> available_actions = availableActions(); QList<QAction*> available_actions = availableActions();
QList<QAction*> spec_actions; QList<QAction*> spec_actions;
// Iterate action names and add respectable actions into the toolbar. // Iterate action names and add respectable actions into the toolbar.
foreach (const QString& action_name, actions) { foreach (const QString& action_name, actions) {
QAction* matching_action = findMatchingAction(action_name, available_actions); QAction* matching_action = findMatchingAction(action_name, available_actions);
if (matching_action != nullptr) { if (matching_action != nullptr) {
// Add existing standard action. // Add existing standard action.
spec_actions.append(matching_action); spec_actions.append(matching_action);
} }
else if (action_name == SEPARATOR_ACTION_NAME) { else if (action_name == SEPARATOR_ACTION_NAME) {
// Add new separator. // Add new separator.
QAction* act = new QAction(this); QAction* act = new QAction(this);
act->setSeparator(true);
spec_actions.append(act);
}
else if (action_name == SEACRH_MESSAGES_ACTION_NAME) {
// Add search box.
spec_actions.append(m_actionSearchMessages);
}
else if (action_name == HIGHLIGHTER_ACTION_NAME) {
// Add filter button.
spec_actions.append(m_actionMessageHighlighter);
}
else if (action_name == SPACER_ACTION_NAME) {
// Add new spacer.
QWidget* spacer = new QWidget(this);
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QWidgetAction* action = new QWidgetAction(this);
action->setDefaultWidget(spacer);
action->setIcon(qApp->icons()->fromTheme(QSL("go-jump")));
action->setProperty("type", SPACER_ACTION_NAME);
action->setProperty("name", tr("Toolbar spacer"));
spec_actions.append(action);
}
}
return spec_actions; act->setSeparator(true);
spec_actions.append(act);
}
else if (action_name == SEACRH_MESSAGES_ACTION_NAME) {
// Add search box.
spec_actions.append(m_actionSearchMessages);
}
else if (action_name == HIGHLIGHTER_ACTION_NAME) {
// Add filter button.
spec_actions.append(m_actionMessageHighlighter);
}
else if (action_name == SPACER_ACTION_NAME) {
// Add new spacer.
QWidget* spacer = new QWidget(this);
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QWidgetAction* action = new QWidgetAction(this);
action->setDefaultWidget(spacer);
action->setIcon(qApp->icons()->fromTheme(QSL("go-jump")));
action->setProperty("type", SPACER_ACTION_NAME);
action->setProperty("name", tr("Toolbar spacer"));
spec_actions.append(action);
}
}
return spec_actions;
} }
void MessagesToolBar::loadSpecificActions(const QList<QAction*>& actions) { void MessagesToolBar::loadSpecificActions(const QList<QAction*>& actions) {
clear(); clear();
foreach (QAction* act, actions) { foreach (QAction* act, actions) {
addAction(act); addAction(act);
} }
} }
void MessagesToolBar::handleMessageHighlighterChange(QAction* action) { void MessagesToolBar::handleMessageHighlighterChange(QAction* action) {
m_btnMessageHighlighter->setIcon(action->icon()); m_btnMessageHighlighter->setIcon(action->icon());
m_btnMessageHighlighter->setToolTip(action->text()); m_btnMessageHighlighter->setToolTip(action->text());
emit messageFilterChanged(action->data().value<MessagesModel::MessageHighlighter>()); emit messageFilterChanged(action->data().value<MessagesModel::MessageHighlighter>());
} }
void MessagesToolBar::initializeSearchBox() { void MessagesToolBar::initializeSearchBox() {
m_txtSearchMessages = new MessagesSearchLineEdit(this); m_txtSearchMessages = new MessagesSearchLineEdit(this);
m_txtSearchMessages->setFixedWidth(FILTER_WIDTH); m_txtSearchMessages->setFixedWidth(FILTER_WIDTH);
m_txtSearchMessages->setPlaceholderText(tr("Search messages")); m_txtSearchMessages->setPlaceholderText(tr("Search messages"));
// Setup wrapping action for search box.
m_actionSearchMessages = new QWidgetAction(this); // Setup wrapping action for search box.
m_actionSearchMessages->setDefaultWidget(m_txtSearchMessages); m_actionSearchMessages = new QWidgetAction(this);
m_actionSearchMessages->setIcon(qApp->icons()->fromTheme(QSL("system-search"))); m_actionSearchMessages->setDefaultWidget(m_txtSearchMessages);
m_actionSearchMessages->setProperty("type", SEACRH_MESSAGES_ACTION_NAME); m_actionSearchMessages->setIcon(qApp->icons()->fromTheme(QSL("system-search")));
m_actionSearchMessages->setProperty("name", tr("Message search box")); m_actionSearchMessages->setProperty("type", SEACRH_MESSAGES_ACTION_NAME);
connect(m_txtSearchMessages, &MessagesSearchLineEdit::textChanged, this, &MessagesToolBar::messageSearchPatternChanged); m_actionSearchMessages->setProperty("name", tr("Message search box"));
connect(m_txtSearchMessages, &MessagesSearchLineEdit::textChanged, this, &MessagesToolBar::messageSearchPatternChanged);
} }
void MessagesToolBar::initializeHighlighter() { void MessagesToolBar::initializeHighlighter() {
m_menuMessageHighlighter = new QMenu(tr("Menu for highlighting messages"), this); m_menuMessageHighlighter = new QMenu(tr("Menu for highlighting messages"), this);
m_menuMessageHighlighter->addAction(qApp->icons()->fromTheme(QSL("mail-mark-read")), m_menuMessageHighlighter->addAction(qApp->icons()->fromTheme(QSL("mail-mark-read")),
tr("No extra highlighting"))->setData(QVariant::fromValue(MessagesModel::NoHighlighting)); tr("No extra highlighting"))->setData(QVariant::fromValue(MessagesModel::NoHighlighting));
m_menuMessageHighlighter->addAction(qApp->icons()->fromTheme(QSL("mail-mark-unread")), m_menuMessageHighlighter->addAction(qApp->icons()->fromTheme(QSL("mail-mark-unread")),
tr("Highlight unread messages"))->setData(QVariant::fromValue(MessagesModel::HighlightUnread)); tr("Highlight unread messages"))->setData(QVariant::fromValue(MessagesModel::HighlightUnread));
m_menuMessageHighlighter->addAction(qApp->icons()->fromTheme(QSL("mail-mark-important")), m_menuMessageHighlighter->addAction(qApp->icons()->fromTheme(QSL("mail-mark-important")),
tr("Highlight important messages"))->setData(QVariant::fromValue(MessagesModel::HighlightImportant)); tr("Highlight important messages"))->setData(QVariant::fromValue(MessagesModel::HighlightImportant));
m_btnMessageHighlighter = new QToolButton(this); m_btnMessageHighlighter = new QToolButton(this);
m_btnMessageHighlighter->setToolTip(tr("Display all messages")); m_btnMessageHighlighter->setToolTip(tr("Display all messages"));
m_btnMessageHighlighter->setMenu(m_menuMessageHighlighter); m_btnMessageHighlighter->setMenu(m_menuMessageHighlighter);
m_btnMessageHighlighter->setPopupMode(QToolButton::MenuButtonPopup); m_btnMessageHighlighter->setPopupMode(QToolButton::MenuButtonPopup);
m_btnMessageHighlighter->setIcon(qApp->icons()->fromTheme(QSL("mail-mark-read"))); m_btnMessageHighlighter->setIcon(qApp->icons()->fromTheme(QSL("mail-mark-read")));
m_actionMessageHighlighter = new QWidgetAction(this); m_actionMessageHighlighter = new QWidgetAction(this);
m_actionMessageHighlighter->setDefaultWidget(m_btnMessageHighlighter); m_actionMessageHighlighter->setDefaultWidget(m_btnMessageHighlighter);
m_actionMessageHighlighter->setIcon(m_btnMessageHighlighter->icon()); m_actionMessageHighlighter->setIcon(m_btnMessageHighlighter->icon());
m_actionMessageHighlighter->setProperty("type", HIGHLIGHTER_ACTION_NAME); m_actionMessageHighlighter->setProperty("type", HIGHLIGHTER_ACTION_NAME);
m_actionMessageHighlighter->setProperty("name", tr("Message highlighter")); m_actionMessageHighlighter->setProperty("name", tr("Message highlighter"));
connect(m_menuMessageHighlighter, SIGNAL(triggered(QAction*)), connect(m_menuMessageHighlighter, SIGNAL(triggered(QAction*)),
this, SLOT(handleMessageHighlighterChange(QAction*))); this, SLOT(handleMessageHighlighterChange(QAction*)));
} }
QStringList MessagesToolBar::defaultActions() const { QStringList MessagesToolBar::defaultActions() const {
return QString(GUI::MessagesToolbarDefaultButtonsDef).split(',', return QString(GUI::MessagesToolbarDefaultButtonsDef).split(',',
QString::SkipEmptyParts); QString::SkipEmptyParts);
} }
QStringList MessagesToolBar::savedActions() const { QStringList MessagesToolBar::savedActions() const {
return qApp->settings()->value(GROUP(GUI), return qApp->settings()->value(GROUP(GUI),
SETTING(GUI::MessagesToolbarDefaultButtons)).toString().split(',', SETTING(GUI::MessagesToolbarDefaultButtons)).toString().split(',',
QString::SkipEmptyParts); QString::SkipEmptyParts);
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -22,61 +23,62 @@
#include "core/messagesmodel.h" #include "core/messagesmodel.h"
class MessagesSearchLineEdit; class MessagesSearchLineEdit;
class QWidgetAction; class QWidgetAction;
class QToolButton; class QToolButton;
class QMenu; class QMenu;
class MessagesToolBar : public BaseToolBar { class MessagesToolBar : public BaseToolBar {
Q_OBJECT Q_OBJECT
public: public:
// Constructors and destructors.
explicit MessagesToolBar(const QString& title, QWidget* parent = 0);
virtual ~MessagesToolBar();
// External access to search line edit. // Constructors and destructors.
inline MessagesSearchLineEdit* searchLineEdit() { explicit MessagesToolBar(const QString& title, QWidget* parent = 0);
return m_txtSearchMessages; virtual ~MessagesToolBar();
}
// Implementation of BaseToolBar interface. // External access to search line edit.
QList<QAction*> availableActions() const; inline MessagesSearchLineEdit* searchLineEdit() {
QList<QAction*> changeableActions() const; return m_txtSearchMessages;
void saveChangeableActions(const QStringList& actions); }
// Loads actions as specified by external actions list. // Implementation of BaseToolBar interface.
// NOTE: This is used primarily for reloading actions QList<QAction*> availableActions() const;
// when they are changed from settings.
void loadSpecificActions(const QList<QAction*>& actions);
QList<QAction*> getSpecificActions(const QStringList& actions); QList<QAction*> changeableActions() const;
void saveChangeableActions(const QStringList& actions);
QStringList defaultActions() const; // Loads actions as specified by external actions list.
QStringList savedActions() const; // NOTE: This is used primarily for reloading actions
// when they are changed from settings.
void loadSpecificActions(const QList<QAction*>& actions);
signals: QList<QAction*> getSpecificActions(const QStringList& actions);
void messageSearchPatternChanged(const QString& pattern);
// Emitted if message filter is changed. QStringList defaultActions() const;
void messageFilterChanged(MessagesModel::MessageHighlighter filter); QStringList savedActions() const;
private slots: signals:
// Called when highlighter gets changed. void messageSearchPatternChanged(const QString& pattern);
void handleMessageHighlighterChange(QAction* action);
private: // Emitted if message filter is changed.
void initializeSearchBox(); void messageFilterChanged(MessagesModel::MessageHighlighter filter);
void initializeHighlighter();
private: private slots:
QWidgetAction* m_actionMessageHighlighter;
QToolButton* m_btnMessageHighlighter;
QMenu* m_menuMessageHighlighter;
QWidgetAction* m_actionSearchMessages; // Called when highlighter gets changed.
MessagesSearchLineEdit* m_txtSearchMessages; void handleMessageHighlighterChange(QAction* action);
private:
void initializeSearchBox();
void initializeHighlighter();
private:
QWidgetAction* m_actionMessageHighlighter;
QToolButton* m_btnMessageHighlighter;
QMenu* m_menuMessageHighlighter;
QWidgetAction* m_actionSearchMessages;
MessagesSearchLineEdit* m_txtSearchMessages;
}; };
#endif // NEWSTOOLBAR_H #endif // NEWSTOOLBAR_H

View file

@ -211,7 +211,9 @@ void MessagesView::initializeContextMenu() {
} }
m_contextMenu->addMenu(menu); m_contextMenu->addMenu(menu);
m_contextMenu->addActions(QList<QAction*>() << qApp->mainForm()->m_ui->m_actionSendMessageViaEmail << qApp->mainForm()->m_ui->m_actionOpenSelectedSourceArticlesExternally << qApp->mainForm()->m_ui->m_actionOpenSelectedMessagesInternally << qApp->mainForm()->m_ui->m_actionMarkSelectedMessagesAsRead << qApp->mainForm()->m_ui->m_actionMarkSelectedMessagesAsUnread << qApp->mainForm()->m_ui->m_actionSwitchImportanceOfSelectedMessages << qApp->mainForm()->m_ui->m_actionDeleteSelectedMessages); m_contextMenu->addActions(
QList<QAction*>() << qApp->mainForm()->m_ui->m_actionSendMessageViaEmail << qApp->mainForm()->m_ui->m_actionOpenSelectedSourceArticlesExternally << qApp->mainForm()->m_ui->m_actionOpenSelectedMessagesInternally << qApp->mainForm()->m_ui->m_actionMarkSelectedMessagesAsRead << qApp->mainForm()->m_ui->m_actionMarkSelectedMessagesAsUnread << qApp->mainForm()->m_ui->m_actionSwitchImportanceOfSelectedMessages <<
qApp->mainForm()->m_ui->m_actionDeleteSelectedMessages);
if (m_sourceModel->loadedItem() != nullptr && m_sourceModel->loadedItem()->kind() == RootItemKind::Bin) { if (m_sourceModel->loadedItem() != nullptr && m_sourceModel->loadedItem()->kind() == RootItemKind::Bin) {
m_contextMenu->addAction(qApp->mainForm()->m_ui->m_actionRestoreSelectedMessages); m_contextMenu->addAction(qApp->mainForm()->m_ui->m_actionRestoreSelectedMessages);
@ -267,7 +269,11 @@ void MessagesView::selectionChanged(const QItemSelection& selected, const QItemS
const QModelIndex current_index = currentIndex(); const QModelIndex current_index = currentIndex();
const QModelIndex mapped_current_index = m_proxyModel->mapToSource(current_index); const QModelIndex mapped_current_index = m_proxyModel->mapToSource(current_index);
qDebug("Current row changed - row [%d,%d] source [%d, %d].",current_index.row(), current_index.column(),mapped_current_index.row(), mapped_current_index.column()); qDebug("Current row changed - row [%d,%d] source [%d, %d].",
current_index.row(),
current_index.column(),
mapped_current_index.row(),
mapped_current_index.column());
if (mapped_current_index.isValid() && selected_rows.count() > 0) { if (mapped_current_index.isValid() && selected_rows.count() > 0) {
Message message = m_sourceModel->messageAt(m_proxyModel->mapToSource(current_index).row()); Message message = m_sourceModel->messageAt(m_proxyModel->mapToSource(current_index).row());
@ -310,7 +316,9 @@ void MessagesView::openSelectedSourceMessagesExternally() {
const QString link = m_sourceModel->messageAt(m_proxyModel->mapToSource(index).row()).m_url; const QString link = m_sourceModel->messageAt(m_proxyModel->mapToSource(index).row()).m_url;
if (!qApp->web()->openUrlInExternalBrowser(link)) { if (!qApp->web()->openUrlInExternalBrowser(link)) {
qApp->showGuiMessage(tr("Problem with starting external web browser"),tr("External web browser could not be started."),QSystemTrayIcon::Critical); qApp->showGuiMessage(tr("Problem with starting external web browser"),
tr("External web browser could not be started."),
QSystemTrayIcon::Critical);
return; return;
} }
} }
@ -338,7 +346,8 @@ void MessagesView::sendSelectedMessageViaEmail() {
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());
if (!qApp->web()->sendMessageViaEmail(message)) { if (!qApp->web()->sendMessageViaEmail(message)) {
MessageBox::show(this,QMessageBox::Critical,tr("Problem with starting external e-mail client"),tr("External e-mail client could not be started.")); MessageBox::show(this, QMessageBox::Critical, tr("Problem with starting external e-mail client"),
tr("External e-mail client could not be started."));
} }
} }
} }
@ -520,7 +529,9 @@ void MessagesView::openSelectedMessagesWithExternalTool() {
if (!link.isEmpty()) { if (!link.isEmpty()) {
if (!QProcess::startDetached(tool.executable(), QStringList() << tool.parameters() << link)) { if (!QProcess::startDetached(tool.executable(), QStringList() << tool.parameters() << link)) {
qApp->showGuiMessage(tr("Cannot run external tool"), tr("External tool '%1' could not be started.").arg(tool.executable()),QSystemTrayIcon::Critical); qApp->showGuiMessage(tr("Cannot run external tool"),
tr("External tool '%1' could not be started.").arg(tool.executable()),
QSystemTrayIcon::Critical);
} }
} }
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -21,31 +22,28 @@
#include "miscellaneous/iconfactory.h" #include "miscellaneous/iconfactory.h"
#include "network-web/networkfactory.h" #include "network-web/networkfactory.h"
MessageTextBrowser::MessageTextBrowser(QWidget* parent) : QTextBrowser(parent) {}
MessageTextBrowser::MessageTextBrowser(QWidget* parent) : QTextBrowser(parent) { MessageTextBrowser::~MessageTextBrowser() {}
}
MessageTextBrowser::~MessageTextBrowser() {
}
QVariant MessageTextBrowser::loadResource(int type, const QUrl& name) { QVariant MessageTextBrowser::loadResource(int type, const QUrl& name) {
Q_UNUSED(name) Q_UNUSED(name)
switch (type) { switch (type) {
case QTextDocument::ImageResource: { case QTextDocument::ImageResource: {
if (m_imagePlaceholder.isNull()) { if (m_imagePlaceholder.isNull()) {
m_imagePlaceholder = qApp->icons()->miscPixmap(QSL("image-placeholder")).scaledToWidth(20, Qt::FastTransformation); m_imagePlaceholder = qApp->icons()->miscPixmap(QSL("image-placeholder")).scaledToWidth(20, Qt::FastTransformation);
} }
return m_imagePlaceholder; return m_imagePlaceholder;
} }
default: default:
return QTextBrowser::loadResource(type, name); return QTextBrowser::loadResource(type, name);
} }
} }
void MessageTextBrowser::wheelEvent(QWheelEvent* e) { void MessageTextBrowser::wheelEvent(QWheelEvent* e) {
QTextBrowser::wheelEvent(e); QTextBrowser::wheelEvent(e);
qApp->settings()->setValue(GROUP(Messages), Messages::PreviewerFontStandard, font().toString()); qApp->settings()->setValue(GROUP(Messages), Messages::PreviewerFontStandard, font().toString());
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -20,21 +21,20 @@
#include <QTextBrowser> #include <QTextBrowser>
class MessageTextBrowser : public QTextBrowser { class MessageTextBrowser : public QTextBrowser {
Q_OBJECT Q_OBJECT
public: public:
explicit MessageTextBrowser(QWidget* parent = 0); explicit MessageTextBrowser(QWidget* parent = 0);
virtual ~MessageTextBrowser(); virtual ~MessageTextBrowser();
QVariant loadResource(int type, const QUrl& name); QVariant loadResource(int type, const QUrl& name);
protected: protected:
void wheelEvent(QWheelEvent* e); void wheelEvent(QWheelEvent* e);
private: private:
QPixmap m_imagePlaceholder; QPixmap m_imagePlaceholder;
}; };
#endif // MESSAGETEXTBROWSER_H #endif // MESSAGETEXTBROWSER_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -17,47 +18,46 @@
#include "gui/newspaperpreviewer.h" #include "gui/newspaperpreviewer.h"
#include "gui/messagepreviewer.h"
#include "gui/dialogs/formmain.h" #include "gui/dialogs/formmain.h"
#include "gui/messagepreviewer.h"
#include "miscellaneous/application.h" #include "miscellaneous/application.h"
#include <QScrollBar> #include <QScrollBar>
NewspaperPreviewer::NewspaperPreviewer(RootItem* root, QList<Message> messages, QWidget* parent) NewspaperPreviewer::NewspaperPreviewer(RootItem* root, QList<Message> messages, QWidget* parent)
: TabContent(parent), m_ui(new Ui::NewspaperPreviewer), m_root(root), m_messages(messages) { : TabContent(parent), m_ui(new Ui::NewspaperPreviewer), m_root(root), m_messages(messages) {
m_ui->setupUi(this); m_ui->setupUi(this);
connect(m_ui->m_btnShowMoreMessages, &QPushButton::clicked, this, &NewspaperPreviewer::showMoreMessages); connect(m_ui->m_btnShowMoreMessages, &QPushButton::clicked, this, &NewspaperPreviewer::showMoreMessages);
showMoreMessages(); showMoreMessages();
} }
NewspaperPreviewer::~NewspaperPreviewer() { NewspaperPreviewer::~NewspaperPreviewer() {}
}
void NewspaperPreviewer::showMoreMessages() { void NewspaperPreviewer::showMoreMessages() {
if (!m_root.isNull()) { if (!m_root.isNull()) {
int current_scroll = m_ui->scrollArea->verticalScrollBar()->value(); int current_scroll = m_ui->scrollArea->verticalScrollBar()->value();
for (int i = 0; i < 10 && !m_messages.isEmpty(); i++) { for (int i = 0; i < 10 && !m_messages.isEmpty(); i++) {
Message msg = m_messages.takeFirst(); Message msg = m_messages.takeFirst();
MessagePreviewer* prev = new MessagePreviewer(this); MessagePreviewer* prev = new MessagePreviewer(this);
QMargins margins = prev->layout()->contentsMargins(); QMargins margins = prev->layout()->contentsMargins();
connect(prev, &MessagePreviewer::requestMessageListReload, this, &NewspaperPreviewer::requestMessageListReload);
margins.setRight(0);
prev->layout()->setContentsMargins(margins);
prev->setFixedHeight(300);
prev->loadMessage(msg, m_root);
m_ui->m_layout->insertWidget(m_ui->m_layout->count() - 2, prev);
}
m_ui->m_btnShowMoreMessages->setText(tr("Show more messages (%n remaining)", "", m_messages.size())); connect(prev, &MessagePreviewer::requestMessageListReload, this, &NewspaperPreviewer::requestMessageListReload);
m_ui->m_btnShowMoreMessages->setEnabled(!m_messages.isEmpty()); margins.setRight(0);
m_ui->scrollArea->verticalScrollBar()->setValue(current_scroll); prev->layout()->setContentsMargins(margins);
} prev->setFixedHeight(300);
else { prev->loadMessage(msg, m_root);
qApp->showGuiMessage(tr("Cannot show more messages"), m_ui->m_layout->insertWidget(m_ui->m_layout->count() - 2, prev);
tr("Cannot show more messages because parent feed was removed."), }
QSystemTrayIcon::Warning,
qApp->mainForm(), true); m_ui->m_btnShowMoreMessages->setText(tr("Show more messages (%n remaining)", "", m_messages.size()));
} m_ui->m_btnShowMoreMessages->setEnabled(!m_messages.isEmpty());
m_ui->scrollArea->verticalScrollBar()->setValue(current_scroll);
}
else {
qApp->showGuiMessage(tr("Cannot show more messages"),
tr("Cannot show more messages because parent feed was removed."),
QSystemTrayIcon::Warning,
qApp->mainForm(), true);
}
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -29,30 +30,29 @@
#include <QPointer> #include <QPointer>
namespace Ui { namespace Ui {
class NewspaperPreviewer; class NewspaperPreviewer;
} }
class RootItem; class RootItem;
class NewspaperPreviewer : public TabContent { class NewspaperPreviewer : public TabContent {
Q_OBJECT Q_OBJECT
public: public:
explicit NewspaperPreviewer(RootItem* root, QList<Message> messages, QWidget* parent = 0); explicit NewspaperPreviewer(RootItem* root, QList<Message> messages, QWidget* parent = 0);
virtual ~NewspaperPreviewer(); virtual ~NewspaperPreviewer();
private slots: private slots:
void showMoreMessages(); void showMoreMessages();
signals: signals:
void requestMessageListReload(bool mark_current_as_read); void requestMessageListReload(bool mark_current_as_read);
private: private:
QScopedPointer<Ui::NewspaperPreviewer> m_ui; QScopedPointer<Ui::NewspaperPreviewer> m_ui;
QPointer<RootItem> m_root; QPointer<RootItem> m_root;
QList<Message> m_messages; QList<Message> m_messages;
}; };
#endif // NEWSPAPERPREVIEWER_H #endif // NEWSPAPERPREVIEWER_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -17,63 +18,61 @@
#include "gui/plaintoolbutton.h" #include "gui/plaintoolbutton.h"
#include <QToolButton> #include <QAction>
#include <QStyle>
#include <QPainter> #include <QPainter>
#include <QPaintEvent> #include <QPaintEvent>
#include <QStyle>
#include <QStyleOption> #include <QStyleOption>
#include <QAction> #include <QToolButton>
PlainToolButton::PlainToolButton(QWidget* parent) : QToolButton(parent), m_padding(0) {}
PlainToolButton::PlainToolButton(QWidget* parent) : QToolButton(parent), m_padding(0) { PlainToolButton::~PlainToolButton() {}
}
PlainToolButton::~PlainToolButton() {
}
void PlainToolButton::paintEvent(QPaintEvent* e) { void PlainToolButton::paintEvent(QPaintEvent* e) {
Q_UNUSED(e) Q_UNUSED(e)
QPainter p(this); QPainter p(this);
QRect rect(QPoint(0, 0), size()); QRect rect(QPoint(0, 0), size());
// Set padding.
rect.adjust(m_padding, m_padding, -m_padding, -m_padding);
if (isEnabled()) { // Set padding.
if (underMouse() || isChecked()) { rect.adjust(m_padding, m_padding, -m_padding, -m_padding);
p.setOpacity(0.7);
}
}
else {
p.setOpacity(0.3);
}
icon().paint(&p, rect); if (isEnabled()) {
if (underMouse() || isChecked()) {
p.setOpacity(0.7);
}
}
else {
p.setOpacity(0.3);
}
icon().paint(&p, rect);
} }
int PlainToolButton::padding() const { int PlainToolButton::padding() const {
return m_padding; return m_padding;
} }
void PlainToolButton::setPadding(int padding) { void PlainToolButton::setPadding(int padding) {
m_padding = padding; m_padding = padding;
repaint(); repaint();
} }
void PlainToolButton::setChecked(bool checked) { void PlainToolButton::setChecked(bool checked) {
QToolButton::setChecked(checked); QToolButton::setChecked(checked);
repaint(); repaint();
} }
void PlainToolButton::reactOnActionChange(QAction* action) { void PlainToolButton::reactOnActionChange(QAction* action) {
if (action != nullptr) { if (action != nullptr) {
setEnabled(action->isEnabled()); setEnabled(action->isEnabled());
setCheckable(action->isCheckable()); setCheckable(action->isCheckable());
setChecked(action->isChecked()); setChecked(action->isChecked());
setIcon(action->icon()); setIcon(action->icon());
setToolTip(action->toolTip()); setToolTip(action->toolTip());
} }
} }
void PlainToolButton::reactOnSenderActionChange() { void PlainToolButton::reactOnSenderActionChange() {
reactOnActionChange(qobject_cast<QAction*>(sender())); reactOnActionChange(qobject_cast<QAction*>(sender()));
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -20,30 +21,31 @@
#include <QToolButton> #include <QToolButton>
class PlainToolButton : public QToolButton { class PlainToolButton : public QToolButton {
Q_OBJECT Q_OBJECT
public: public:
// Contructors and destructors.
explicit PlainToolButton(QWidget* parent = 0);
virtual ~PlainToolButton();
// Padding changers. // Contructors and destructors.
int padding() const; explicit PlainToolButton(QWidget* parent = 0);
void setPadding(int padding); virtual ~PlainToolButton();
public slots: // Padding changers.
void setChecked(bool checked); int padding() const;
void reactOnActionChange(QAction* action); void setPadding(int padding);
void reactOnSenderActionChange();
protected: public slots:
// Custom look. void setChecked(bool checked);
void paintEvent(QPaintEvent* e); void reactOnActionChange(QAction* action);
void reactOnSenderActionChange();
private: protected:
int m_padding;
// Custom look.
void paintEvent(QPaintEvent* e);
private:
int m_padding;
}; };
#endif // CLOSEBUTTON_H #endif // CLOSEBUTTON_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -17,61 +18,61 @@
#include "gui/settings/settingsbrowsermail.h" #include "gui/settings/settingsbrowsermail.h"
#include "network-web/silentnetworkaccessmanager.h"
#include "miscellaneous/application.h"
#include "miscellaneous/textfactory.h"
#include "gui/guiutilities.h" #include "gui/guiutilities.h"
#include "miscellaneous/application.h"
#include "miscellaneous/externaltool.h" #include "miscellaneous/externaltool.h"
#include "miscellaneous/textfactory.h"
#include "network-web/silentnetworkaccessmanager.h"
#include <QNetworkProxy>
#include <QFileDialog> #include <QFileDialog>
#include <QInputDialog> #include <QInputDialog>
#include <QNetworkProxy>
SettingsBrowserMail::SettingsBrowserMail(Settings* settings, QWidget* parent) SettingsBrowserMail::SettingsBrowserMail(Settings* settings, QWidget* parent)
: SettingsPanel(settings, parent), m_ui(new Ui::SettingsBrowserMail) { : SettingsPanel(settings, parent), m_ui(new Ui::SettingsBrowserMail) {
m_ui->setupUi(this); m_ui->setupUi(this);
GuiUtilities::setLabelAsNotice(*m_ui->label, false); GuiUtilities::setLabelAsNotice(*m_ui->label, false);
GuiUtilities::setLabelAsNotice(*m_ui->m_lblExternalEmailInfo, false); GuiUtilities::setLabelAsNotice(*m_ui->m_lblExternalEmailInfo, false);
GuiUtilities::setLabelAsNotice(*m_ui->m_lblProxyInfo, false); GuiUtilities::setLabelAsNotice(*m_ui->m_lblProxyInfo, false);
GuiUtilities::setLabelAsNotice(*m_ui->m_lblToolInfo, false); GuiUtilities::setLabelAsNotice(*m_ui->m_lblToolInfo, false);
#if defined(USE_WEBENGINE) #if defined(USE_WEBENGINE)
m_ui->m_checkOpenLinksInExternal->setVisible(false); m_ui->m_checkOpenLinksInExternal->setVisible(false);
#else #else
connect(m_ui->m_checkOpenLinksInExternal, &QCheckBox::stateChanged, this, &SettingsBrowserMail::dirtifySettings); connect(m_ui->m_checkOpenLinksInExternal, &QCheckBox::stateChanged, this, &SettingsBrowserMail::dirtifySettings);
#endif #endif
m_ui->m_listTools->setHeaderLabels(QStringList() << tr("Executable") << tr("Parameters")); m_ui->m_listTools->setHeaderLabels(QStringList() << tr("Executable") << tr("Parameters"));
m_ui->m_listTools->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); m_ui->m_listTools->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
connect(m_ui->m_cmbProxyType, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, connect(m_ui->m_cmbProxyType, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
&SettingsBrowserMail::dirtifySettings); &SettingsBrowserMail::dirtifySettings);
connect(m_ui->m_txtProxyHost, &QLineEdit::textChanged, this, &SettingsBrowserMail::dirtifySettings); connect(m_ui->m_txtProxyHost, &QLineEdit::textChanged, this, &SettingsBrowserMail::dirtifySettings);
connect(m_ui->m_txtProxyPassword, &QLineEdit::textChanged, this, &SettingsBrowserMail::dirtifySettings); connect(m_ui->m_txtProxyPassword, &QLineEdit::textChanged, this, &SettingsBrowserMail::dirtifySettings);
connect(m_ui->m_txtProxyUsername, &QLineEdit::textChanged, this, &SettingsBrowserMail::dirtifySettings); connect(m_ui->m_txtProxyUsername, &QLineEdit::textChanged, this, &SettingsBrowserMail::dirtifySettings);
connect(m_ui->m_spinProxyPort, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &SettingsBrowserMail::dirtifySettings); connect(m_ui->m_spinProxyPort, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this,
connect(m_ui->m_grpCustomExternalBrowser, &QGroupBox::toggled, this, &SettingsBrowserMail::dirtifySettings); &SettingsBrowserMail::dirtifySettings);
connect(m_ui->m_grpCustomExternalEmail, &QGroupBox::toggled, this, &SettingsBrowserMail::dirtifySettings); connect(m_ui->m_grpCustomExternalBrowser, &QGroupBox::toggled, this, &SettingsBrowserMail::dirtifySettings);
connect(m_ui->m_txtExternalBrowserArguments, &QLineEdit::textChanged, this, &SettingsBrowserMail::dirtifySettings); connect(m_ui->m_grpCustomExternalEmail, &QGroupBox::toggled, this, &SettingsBrowserMail::dirtifySettings);
connect(m_ui->m_txtExternalBrowserExecutable, &QLineEdit::textChanged, this, &SettingsBrowserMail::dirtifySettings); connect(m_ui->m_txtExternalBrowserArguments, &QLineEdit::textChanged, this, &SettingsBrowserMail::dirtifySettings);
connect(m_ui->m_txtExternalEmailArguments, &QLineEdit::textChanged, this, &SettingsBrowserMail::dirtifySettings); connect(m_ui->m_txtExternalBrowserExecutable, &QLineEdit::textChanged, this, &SettingsBrowserMail::dirtifySettings);
connect(m_ui->m_txtExternalEmailExecutable, &QLineEdit::textChanged, this, &SettingsBrowserMail::dirtifySettings); connect(m_ui->m_txtExternalEmailArguments, &QLineEdit::textChanged, this, &SettingsBrowserMail::dirtifySettings);
connect(m_ui->m_cmbProxyType, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, connect(m_ui->m_txtExternalEmailExecutable, &QLineEdit::textChanged, this, &SettingsBrowserMail::dirtifySettings);
&SettingsBrowserMail::onProxyTypeChanged); connect(m_ui->m_cmbProxyType, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
connect(m_ui->m_checkShowPassword, &QCheckBox::stateChanged, this, &SettingsBrowserMail::displayProxyPassword); &SettingsBrowserMail::onProxyTypeChanged);
connect(m_ui->m_cmbExternalBrowserPreset, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, connect(m_ui->m_checkShowPassword, &QCheckBox::stateChanged, this, &SettingsBrowserMail::displayProxyPassword);
&SettingsBrowserMail::changeDefaultBrowserArguments); connect(m_ui->m_cmbExternalBrowserPreset, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
connect(m_ui->m_btnExternalBrowserExecutable, &QPushButton::clicked, this, &SettingsBrowserMail::selectBrowserExecutable); &SettingsBrowserMail::changeDefaultBrowserArguments);
connect(m_ui->m_cmbExternalEmailPreset, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, connect(m_ui->m_btnExternalBrowserExecutable, &QPushButton::clicked, this, &SettingsBrowserMail::selectBrowserExecutable);
&SettingsBrowserMail::changeDefaultEmailArguments); connect(m_ui->m_cmbExternalEmailPreset, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
connect(m_ui->m_btnExternalEmailExecutable, &QPushButton::clicked, this, &SettingsBrowserMail::selectEmailExecutable); &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_btnAddTool, &QPushButton::clicked, this, &SettingsBrowserMail::dirtifySettings);
connect(m_ui->m_btnDeleteTool, &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_btnAddTool, &QPushButton::clicked, this, &SettingsBrowserMail::addExternalTool);
connect(m_ui->m_btnDeleteTool, &QPushButton::clicked, this, &SettingsBrowserMail::deleteSelectedExternalTool); connect(m_ui->m_btnDeleteTool, &QPushButton::clicked, this, &SettingsBrowserMail::deleteSelectedExternalTool);
connect(m_ui->m_listTools, &QTreeWidget::currentItemChanged, [this](QTreeWidgetItem * current, QTreeWidgetItem * previous) { connect(m_ui->m_listTools, &QTreeWidget::currentItemChanged, [this](QTreeWidgetItem* current, QTreeWidgetItem* previous) {
Q_UNUSED(previous) Q_UNUSED(previous)
m_ui->m_btnDeleteTool->setEnabled(current != nullptr); m_ui->m_btnDeleteTool->setEnabled(current != nullptr);
@ -79,52 +80,54 @@ SettingsBrowserMail::SettingsBrowserMail(Settings* settings, QWidget* parent)
} }
SettingsBrowserMail::~SettingsBrowserMail() { SettingsBrowserMail::~SettingsBrowserMail() {
delete m_ui; delete m_ui;
} }
void SettingsBrowserMail::changeDefaultBrowserArguments(int index) { void SettingsBrowserMail::changeDefaultBrowserArguments(int index) {
if (index != 0) { if (index != 0) {
m_ui->m_txtExternalBrowserArguments->setText(m_ui->m_cmbExternalBrowserPreset->itemData(index).toString()); m_ui->m_txtExternalBrowserArguments->setText(m_ui->m_cmbExternalBrowserPreset->itemData(index).toString());
} }
} }
void SettingsBrowserMail::selectBrowserExecutable() { void SettingsBrowserMail::selectBrowserExecutable() {
const QString executable_file = QFileDialog::getOpenFileName(this, const QString executable_file = QFileDialog::getOpenFileName(this,
tr("Select web browser executable"), tr("Select web browser executable"),
qApp->homeFolder(), qApp->homeFolder(),
//: File filter for external browser selection dialog.
//: File filter for external browser selection dialog.
#if defined(Q_OS_LINUX) #if defined(Q_OS_LINUX)
tr("Executables (*)")); tr("Executables (*)"));
#else #else
tr("Executables (*.*)")); tr("Executables (*.*)"));
#endif #endif
if (!executable_file.isEmpty()) { if (!executable_file.isEmpty()) {
m_ui->m_txtExternalBrowserExecutable->setText(QDir::toNativeSeparators(executable_file)); m_ui->m_txtExternalBrowserExecutable->setText(QDir::toNativeSeparators(executable_file));
} }
} }
void SettingsBrowserMail::displayProxyPassword(int state) { void SettingsBrowserMail::displayProxyPassword(int state) {
if (state == Qt::Checked) { if (state == Qt::Checked) {
m_ui->m_txtProxyPassword->setEchoMode(QLineEdit::Normal); m_ui->m_txtProxyPassword->setEchoMode(QLineEdit::Normal);
} }
else { else {
m_ui->m_txtProxyPassword->setEchoMode(QLineEdit::PasswordEchoOnEdit); m_ui->m_txtProxyPassword->setEchoMode(QLineEdit::PasswordEchoOnEdit);
} }
} }
void SettingsBrowserMail::onProxyTypeChanged(int index) { void SettingsBrowserMail::onProxyTypeChanged(int index) {
const QNetworkProxy::ProxyType selected_type = static_cast<QNetworkProxy::ProxyType>(m_ui->m_cmbProxyType->itemData(index).toInt()); const QNetworkProxy::ProxyType selected_type = static_cast<QNetworkProxy::ProxyType>(m_ui->m_cmbProxyType->itemData(index).toInt());
const bool is_proxy_selected = selected_type != QNetworkProxy::NoProxy && selected_type != QNetworkProxy::DefaultProxy; const bool is_proxy_selected = selected_type != QNetworkProxy::NoProxy && selected_type != QNetworkProxy::DefaultProxy;
m_ui->m_txtProxyHost->setEnabled(is_proxy_selected);
m_ui->m_txtProxyPassword->setEnabled(is_proxy_selected); m_ui->m_txtProxyHost->setEnabled(is_proxy_selected);
m_ui->m_txtProxyUsername->setEnabled(is_proxy_selected); m_ui->m_txtProxyPassword->setEnabled(is_proxy_selected);
m_ui->m_spinProxyPort->setEnabled(is_proxy_selected); m_ui->m_txtProxyUsername->setEnabled(is_proxy_selected);
m_ui->m_checkShowPassword->setEnabled(is_proxy_selected); m_ui->m_spinProxyPort->setEnabled(is_proxy_selected);
m_ui->m_lblProxyHost->setEnabled(is_proxy_selected); m_ui->m_checkShowPassword->setEnabled(is_proxy_selected);
m_ui->m_lblProxyInfo->setEnabled(is_proxy_selected); m_ui->m_lblProxyHost->setEnabled(is_proxy_selected);
m_ui->m_lblProxyPassword->setEnabled(is_proxy_selected); m_ui->m_lblProxyInfo->setEnabled(is_proxy_selected);
m_ui->m_lblProxyPort->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);
} }
@ -142,6 +145,7 @@ void SettingsBrowserMail::setExternalTools(const QList<ExternalTool>& list) {
foreach (const ExternalTool& tool, list) { foreach (const ExternalTool& tool, list) {
QTreeWidgetItem* item = new QTreeWidgetItem(m_ui->m_listTools, QTreeWidgetItem* item = new QTreeWidgetItem(m_ui->m_listTools,
QStringList() << tool.executable() << tool.parameters().join(QL1C(' '))); QStringList() << tool.executable() << tool.parameters().join(QL1C(' ')));
item->setData(0, Qt::UserRole, QVariant::fromValue(tool)); item->setData(0, Qt::UserRole, QVariant::fromValue(tool));
m_ui->m_listTools->addTopLevelItem(item); m_ui->m_listTools->addTopLevelItem(item);
@ -149,94 +153,96 @@ void SettingsBrowserMail::setExternalTools(const QList<ExternalTool>& list) {
} }
void SettingsBrowserMail::changeDefaultEmailArguments(int index) { void SettingsBrowserMail::changeDefaultEmailArguments(int index) {
if (index != 0) { if (index != 0) {
m_ui->m_txtExternalEmailArguments->setText(m_ui->m_cmbExternalEmailPreset->itemData(index).toString()); m_ui->m_txtExternalEmailArguments->setText(m_ui->m_cmbExternalEmailPreset->itemData(index).toString());
} }
} }
void SettingsBrowserMail::selectEmailExecutable() { void SettingsBrowserMail::selectEmailExecutable() {
QString executable_file = QFileDialog::getOpenFileName(this, QString executable_file = QFileDialog::getOpenFileName(this,
tr("Select e-mail executable"), tr("Select e-mail executable"),
qApp->homeFolder(), qApp->homeFolder(),
//: File filter for external e-mail selection dialog.
//: File filter for external e-mail selection dialog.
#if defined(Q_OS_LINUX) #if defined(Q_OS_LINUX)
tr("Executables (*)")); tr("Executables (*)"));
#else #else
tr("Executables (*.*)")); tr("Executables (*.*)"));
#endif #endif
if (!executable_file.isEmpty()) { if (!executable_file.isEmpty()) {
m_ui->m_txtExternalEmailExecutable->setText(QDir::toNativeSeparators(executable_file)); m_ui->m_txtExternalEmailExecutable->setText(QDir::toNativeSeparators(executable_file));
} }
} }
void SettingsBrowserMail::loadSettings() { void SettingsBrowserMail::loadSettings() {
onBeginLoadSettings(); onBeginLoadSettings();
#if !defined(USE_WEBENGINE) #if !defined(USE_WEBENGINE)
m_ui->m_checkOpenLinksInExternal->setChecked(settings()->value(GROUP(Browser), m_ui->m_checkOpenLinksInExternal->setChecked(settings()->value(GROUP(Browser),
SETTING(Browser::OpenLinksInExternalBrowserRightAway)).toBool()); SETTING(Browser::OpenLinksInExternalBrowserRightAway)).toBool());
#endif #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_cmbExternalBrowserPreset->addItem(tr("Opera 12 or older"), QSL("-nosession %1"));
m_ui->m_txtExternalBrowserExecutable->setText(settings()->value(GROUP(Browser), m_ui->m_txtExternalBrowserExecutable->setText(settings()->value(GROUP(Browser),
SETTING(Browser::CustomExternalBrowserExecutable)).toString()); SETTING(Browser::CustomExternalBrowserExecutable)).toString());
m_ui->m_txtExternalBrowserArguments->setText(settings()->value(GROUP(Browser), m_ui->m_txtExternalBrowserArguments->setText(settings()->value(GROUP(Browser),
SETTING(Browser::CustomExternalBrowserArguments)).toString()); SETTING(Browser::CustomExternalBrowserArguments)).toString());
m_ui->m_grpCustomExternalBrowser->setChecked(settings()->value(GROUP(Browser), SETTING(Browser::CustomExternalBrowserEnabled)).toBool()); 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_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_txtExternalEmailExecutable->setText(settings()->value(GROUP(Browser),
m_ui->m_txtExternalEmailArguments->setText(settings()->value(GROUP(Browser), SETTING(Browser::CustomExternalEmailArguments)).toString()); SETTING(Browser::CustomExternalEmailExecutable)).toString());
m_ui->m_grpCustomExternalEmail->setChecked(settings()->value(GROUP(Browser), SETTING(Browser::CustomExternalEmailEnabled)).toBool()); m_ui->m_txtExternalEmailArguments->setText(settings()->value(GROUP(Browser), SETTING(Browser::CustomExternalEmailArguments)).toString());
m_ui->m_cmbProxyType->addItem(tr("No proxy"), QNetworkProxy::NoProxy); m_ui->m_grpCustomExternalEmail->setChecked(settings()->value(GROUP(Browser), SETTING(Browser::CustomExternalEmailEnabled)).toBool());
m_ui->m_cmbProxyType->addItem(tr("System proxy"), QNetworkProxy::DefaultProxy); m_ui->m_cmbProxyType->addItem(tr("No proxy"), QNetworkProxy::NoProxy);
m_ui->m_cmbProxyType->addItem(tr("Socks5"), QNetworkProxy::Socks5Proxy); m_ui->m_cmbProxyType->addItem(tr("System proxy"), QNetworkProxy::DefaultProxy);
m_ui->m_cmbProxyType->addItem(tr("Http"), QNetworkProxy::HttpProxy); 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), QNetworkProxy::ProxyType selected_proxy_type = static_cast<QNetworkProxy::ProxyType>(settings()->value(GROUP(Proxy),
SETTING(Proxy::Type)).toInt()); SETTING(Proxy::Type)).toInt());
m_ui->m_cmbProxyType->setCurrentIndex(m_ui->m_cmbProxyType->findData(selected_proxy_type)); m_ui->m_cmbProxyType->setCurrentIndex(m_ui->m_cmbProxyType->findData(selected_proxy_type));
m_ui->m_txtProxyHost->setText(settings()->value(GROUP(Proxy), SETTING(Proxy::Host)).toString()); m_ui->m_txtProxyHost->setText(settings()->value(GROUP(Proxy), SETTING(Proxy::Host)).toString());
m_ui->m_txtProxyUsername->setText(settings()->value(GROUP(Proxy), SETTING(Proxy::Username)).toString()); 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_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()); m_ui->m_spinProxyPort->setValue(settings()->value(GROUP(Proxy), SETTING(Proxy::Port)).toInt());
setExternalTools(ExternalTool::toolsFromSettings()); setExternalTools(ExternalTool::toolsFromSettings());
onEndLoadSettings(); onEndLoadSettings();
} }
void SettingsBrowserMail::saveSettings() { void SettingsBrowserMail::saveSettings() {
onBeginSaveSettings(); onBeginSaveSettings();
#if !defined(USE_WEBENGINE) #if !defined(USE_WEBENGINE)
settings()->setValue(GROUP(Browser), Browser::OpenLinksInExternalBrowserRightAway, m_ui->m_checkOpenLinksInExternal->isChecked()); settings()->setValue(GROUP(Browser), Browser::OpenLinksInExternalBrowserRightAway, m_ui->m_checkOpenLinksInExternal->isChecked());
#endif #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::CustomExternalBrowserEnabled, m_ui->m_grpCustomExternalBrowser->isChecked());
settings()->setValue(GROUP(Browser), Browser::CustomExternalBrowserExecutable, m_ui->m_txtExternalBrowserExecutable->text()); settings()->setValue(GROUP(Browser), Browser::CustomExternalBrowserExecutable, m_ui->m_txtExternalBrowserExecutable->text());
settings()->setValue(GROUP(Browser), Browser::CustomExternalBrowserArguments, m_ui->m_txtExternalBrowserArguments->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::CustomExternalEmailExecutable, m_ui->m_txtExternalEmailExecutable->text());
settings()->setValue(GROUP(Browser), Browser::CustomExternalEmailArguments, m_ui->m_txtExternalEmailArguments->text()); settings()->setValue(GROUP(Browser), Browser::CustomExternalEmailArguments, m_ui->m_txtExternalEmailArguments->text());
settings()->setValue(GROUP(Browser), Browser::CustomExternalEmailEnabled, m_ui->m_grpCustomExternalEmail->isChecked()); settings()->setValue(GROUP(Browser), Browser::CustomExternalEmailEnabled, m_ui->m_grpCustomExternalEmail->isChecked());
settings()->setValue(GROUP(Proxy), Proxy::Type, m_ui->m_cmbProxyType->itemData(m_ui->m_cmbProxyType->currentIndex())); settings()->setValue(GROUP(Proxy), Proxy::Type, m_ui->m_cmbProxyType->itemData(m_ui->m_cmbProxyType->currentIndex()));
settings()->setValue(GROUP(Proxy), Proxy::Host, m_ui->m_txtProxyHost->text()); settings()->setValue(GROUP(Proxy), Proxy::Host, m_ui->m_txtProxyHost->text());
settings()->setValue(GROUP(Proxy), Proxy::Username, m_ui->m_txtProxyUsername->text()); 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::Password, TextFactory::encrypt(m_ui->m_txtProxyPassword->text()));
settings()->setValue(GROUP(Proxy), Proxy::Port, m_ui->m_spinProxyPort->value()); settings()->setValue(GROUP(Proxy), Proxy::Port, m_ui->m_spinProxyPort->value());
auto tools = externalTools(); auto tools = externalTools();
ExternalTool::setToolsToSettings(tools); ExternalTool::setToolsToSettings(tools);
// Reload settings for all network access managers. // Reload settings for all network access managers.
SilentNetworkAccessManager::instance()->loadSettings(); SilentNetworkAccessManager::instance()->loadSettings();
onEndSaveSettings(); onEndSaveSettings();
} }
@ -244,6 +250,7 @@ void SettingsBrowserMail::addExternalTool() {
QString executable_file = QFileDialog::getOpenFileName(this, QString executable_file = QFileDialog::getOpenFileName(this,
tr("Select external tool"), tr("Select external tool"),
qApp->homeFolder(), qApp->homeFolder(),
//: File filter for external tool selection dialog. //: File filter for external tool selection dialog.
#if defined(Q_OS_LINUX) #if defined(Q_OS_LINUX)
tr("Executables (*)")); tr("Executables (*)"));
@ -254,13 +261,18 @@ void SettingsBrowserMail::addExternalTool() {
if (!executable_file.isEmpty()) { if (!executable_file.isEmpty()) {
executable_file = QDir::toNativeSeparators(executable_file); executable_file = QDir::toNativeSeparators(executable_file);
bool ok; bool ok;
QString parameters = QInputDialog::getText(this, tr("Enter parameters"), QString parameters = QInputDialog::getText(this,
tr("Enter (optional) parameters separated by single space to send to executable when opening URLs."), tr("Enter parameters"),
QLineEdit::Normal, QString(), &ok); tr(
"Enter (optional) parameters separated by single space to send to executable when opening URLs."),
QLineEdit::Normal,
QString(),
&ok);
if (ok) { if (ok) {
QTreeWidgetItem* item = new QTreeWidgetItem(m_ui->m_listTools, QTreeWidgetItem* item = new QTreeWidgetItem(m_ui->m_listTools,
QStringList() << QDir::toNativeSeparators(executable_file) << parameters); QStringList() << QDir::toNativeSeparators(executable_file) << parameters);
item->setData(0, Qt::UserRole, QVariant::fromValue(ExternalTool(executable_file, parameters.split(QSL(" "))))); item->setData(0, Qt::UserRole, QVariant::fromValue(ExternalTool(executable_file, parameters.split(QSL(" ")))));
m_ui->m_listTools->addTopLevelItem(item); m_ui->m_listTools->addTopLevelItem(item);
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -23,36 +24,36 @@
#include "miscellaneous/externaltool.h" #include "miscellaneous/externaltool.h"
#include "ui_settingsbrowsermail.h" #include "ui_settingsbrowsermail.h"
class SettingsBrowserMail : public SettingsPanel { class SettingsBrowserMail : public SettingsPanel {
Q_OBJECT Q_OBJECT
public: public:
explicit SettingsBrowserMail(Settings* settings, QWidget* parent = 0); explicit SettingsBrowserMail(Settings* settings, QWidget* parent = 0);
virtual ~SettingsBrowserMail(); virtual ~SettingsBrowserMail();
inline QString title() const { inline QString title() const {
return tr("Web browser & e-mail & proxy"); return tr("Web browser & e-mail & proxy");
} }
void loadSettings(); void loadSettings();
void saveSettings();
private slots: void saveSettings();
private slots:
void addExternalTool(); void addExternalTool();
void deleteSelectedExternalTool(); void deleteSelectedExternalTool();
void changeDefaultBrowserArguments(int index); void changeDefaultBrowserArguments(int index);
void selectBrowserExecutable(); void selectBrowserExecutable();
void changeDefaultEmailArguments(int index); void changeDefaultEmailArguments(int index);
void selectEmailExecutable(); void selectEmailExecutable();
void displayProxyPassword(int state); void displayProxyPassword(int state);
void onProxyTypeChanged(int index); void onProxyTypeChanged(int index);
private: private:
QList<ExternalTool> externalTools() const; QList<ExternalTool> externalTools() const;
void setExternalTools(const QList<ExternalTool>& list); void setExternalTools(const QList<ExternalTool>& list);
Ui::SettingsBrowserMail* m_ui; Ui::SettingsBrowserMail* m_ui;
}; };
#endif // SETTINGSBROWSERMAIL_H #endif // SETTINGSBROWSERMAIL_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -17,190 +18,197 @@
#include "gui/settings/settingsdatabase.h" #include "gui/settings/settingsdatabase.h"
#include "miscellaneous/databasefactory.h"
#include "definitions/definitions.h" #include "definitions/definitions.h"
#include "miscellaneous/application.h"
#include "miscellaneous/textfactory.h"
#include "gui/guiutilities.h" #include "gui/guiutilities.h"
#include "miscellaneous/application.h"
#include "miscellaneous/databasefactory.h"
#include "miscellaneous/textfactory.h"
SettingsDatabase::SettingsDatabase(Settings* settings, QWidget* parent) SettingsDatabase::SettingsDatabase(Settings* settings, QWidget* parent)
: SettingsPanel(settings, parent), m_ui(new Ui::SettingsDatabase) { : SettingsPanel(settings, parent), m_ui(new Ui::SettingsDatabase) {
m_ui->setupUi(this); m_ui->setupUi(this);
GuiUtilities::setLabelAsNotice(*m_ui->m_lblDataStorageWarning, true); GuiUtilities::setLabelAsNotice(*m_ui->m_lblDataStorageWarning, true);
GuiUtilities::setLabelAsNotice(*m_ui->m_lblMysqlInfo, false); GuiUtilities::setLabelAsNotice(*m_ui->m_lblMysqlInfo, false);
GuiUtilities::setLabelAsNotice(*m_ui->m_lblSqliteInMemoryWarnings, true); GuiUtilities::setLabelAsNotice(*m_ui->m_lblSqliteInMemoryWarnings, true);
connect(m_ui->m_cmbDatabaseDriver, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, connect(m_ui->m_cmbDatabaseDriver, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
&SettingsDatabase::dirtifySettings); &SettingsDatabase::dirtifySettings);
connect(m_ui->m_checkSqliteUseInMemoryDatabase, &QCheckBox::toggled, this, &SettingsDatabase::dirtifySettings); connect(m_ui->m_checkSqliteUseInMemoryDatabase, &QCheckBox::toggled, this, &SettingsDatabase::dirtifySettings);
connect(m_ui->m_txtMysqlDatabase->lineEdit(), &QLineEdit::textChanged, this, &SettingsDatabase::dirtifySettings); connect(m_ui->m_txtMysqlDatabase->lineEdit(), &QLineEdit::textChanged, this, &SettingsDatabase::dirtifySettings);
connect(m_ui->m_txtMysqlHostname->lineEdit(), &QLineEdit::textChanged, this, &SettingsDatabase::dirtifySettings); connect(m_ui->m_txtMysqlHostname->lineEdit(), &QLineEdit::textChanged, this, &SettingsDatabase::dirtifySettings);
connect(m_ui->m_txtMysqlPassword->lineEdit(), &QLineEdit::textChanged, this, &SettingsDatabase::dirtifySettings); connect(m_ui->m_txtMysqlPassword->lineEdit(), &QLineEdit::textChanged, this, &SettingsDatabase::dirtifySettings);
connect(m_ui->m_checkUseTransactions, &QCheckBox::toggled, this, &SettingsDatabase::dirtifySettings); connect(m_ui->m_checkUseTransactions, &QCheckBox::toggled, this, &SettingsDatabase::dirtifySettings);
connect(m_ui->m_txtMysqlUsername->lineEdit(), &QLineEdit::textChanged, this, &SettingsDatabase::dirtifySettings); connect(m_ui->m_txtMysqlUsername->lineEdit(), &QLineEdit::textChanged, this, &SettingsDatabase::dirtifySettings);
connect(m_ui->m_spinMysqlPort, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &SettingsDatabase::dirtifySettings); connect(m_ui->m_spinMysqlPort, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &SettingsDatabase::dirtifySettings);
connect(m_ui->m_cmbDatabaseDriver, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, connect(m_ui->m_cmbDatabaseDriver, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
&SettingsDatabase::selectSqlBackend); &SettingsDatabase::selectSqlBackend);
connect(m_ui->m_checkMysqlShowPassword, &QCheckBox::toggled, this, &SettingsDatabase::switchMysqlPasswordVisiblity); connect(m_ui->m_checkMysqlShowPassword, &QCheckBox::toggled, this, &SettingsDatabase::switchMysqlPasswordVisiblity);
connect(m_ui->m_txtMysqlUsername->lineEdit(), &BaseLineEdit::textChanged, this, &SettingsDatabase::onMysqlUsernameChanged); connect(m_ui->m_txtMysqlUsername->lineEdit(), &BaseLineEdit::textChanged, this, &SettingsDatabase::onMysqlUsernameChanged);
connect(m_ui->m_txtMysqlHostname->lineEdit(), &BaseLineEdit::textChanged, this, &SettingsDatabase::onMysqlHostnameChanged); connect(m_ui->m_txtMysqlHostname->lineEdit(), &BaseLineEdit::textChanged, this, &SettingsDatabase::onMysqlHostnameChanged);
connect(m_ui->m_txtMysqlPassword->lineEdit(), &BaseLineEdit::textChanged, this, &SettingsDatabase::onMysqlPasswordChanged); connect(m_ui->m_txtMysqlPassword->lineEdit(), &BaseLineEdit::textChanged, this, &SettingsDatabase::onMysqlPasswordChanged);
connect(m_ui->m_txtMysqlDatabase->lineEdit(), &BaseLineEdit::textChanged, this, &SettingsDatabase::onMysqlDatabaseChanged); connect(m_ui->m_txtMysqlDatabase->lineEdit(), &BaseLineEdit::textChanged, this, &SettingsDatabase::onMysqlDatabaseChanged);
connect(m_ui->m_btnMysqlTestSetup, &QPushButton::clicked, this, &SettingsDatabase::mysqlTestConnection); connect(m_ui->m_btnMysqlTestSetup, &QPushButton::clicked, this, &SettingsDatabase::mysqlTestConnection);
connect(m_ui->m_cmbDatabaseDriver, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, connect(m_ui->m_cmbDatabaseDriver, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
&SettingsDatabase::requireRestart); &SettingsDatabase::requireRestart);
connect(m_ui->m_checkSqliteUseInMemoryDatabase, &QCheckBox::toggled, this, &SettingsDatabase::requireRestart); connect(m_ui->m_checkSqliteUseInMemoryDatabase, &QCheckBox::toggled, this, &SettingsDatabase::requireRestart);
connect(m_ui->m_spinMysqlPort, &QSpinBox::editingFinished, this, &SettingsDatabase::requireRestart); connect(m_ui->m_spinMysqlPort, &QSpinBox::editingFinished, this, &SettingsDatabase::requireRestart);
connect(m_ui->m_txtMysqlHostname->lineEdit(), &BaseLineEdit::textEdited, this, &SettingsDatabase::requireRestart); connect(m_ui->m_txtMysqlHostname->lineEdit(), &BaseLineEdit::textEdited, this, &SettingsDatabase::requireRestart);
connect(m_ui->m_txtMysqlPassword->lineEdit(), &BaseLineEdit::textEdited, this, &SettingsDatabase::requireRestart); connect(m_ui->m_txtMysqlPassword->lineEdit(), &BaseLineEdit::textEdited, this, &SettingsDatabase::requireRestart);
connect(m_ui->m_txtMysqlUsername->lineEdit(), &BaseLineEdit::textEdited, this, &SettingsDatabase::requireRestart); connect(m_ui->m_txtMysqlUsername->lineEdit(), &BaseLineEdit::textEdited, this, &SettingsDatabase::requireRestart);
} }
SettingsDatabase::~SettingsDatabase() { SettingsDatabase::~SettingsDatabase() {
delete m_ui; delete m_ui;
} }
void SettingsDatabase::mysqlTestConnection() { void SettingsDatabase::mysqlTestConnection() {
const DatabaseFactory::MySQLError error_code = qApp->database()->mysqlTestConnection(m_ui->m_txtMysqlHostname->lineEdit()->text(), const DatabaseFactory::MySQLError error_code = qApp->database()->mysqlTestConnection(m_ui->m_txtMysqlHostname->lineEdit()->text(),
m_ui->m_spinMysqlPort->value(), m_ui->m_spinMysqlPort->value(),
m_ui->m_txtMysqlDatabase->lineEdit()->text(), m_ui->m_txtMysqlDatabase->lineEdit()->text(),
m_ui->m_txtMysqlUsername->lineEdit()->text(), m_ui->m_txtMysqlUsername->lineEdit()->text(),
m_ui->m_txtMysqlPassword->lineEdit()->text()); m_ui->m_txtMysqlPassword->lineEdit()->text());
const QString interpretation = qApp->database()->mysqlInterpretErrorCode(error_code); const QString interpretation = qApp->database()->mysqlInterpretErrorCode(error_code);
switch (error_code) { switch (error_code) {
case DatabaseFactory::MySQLOk: case DatabaseFactory::MySQLOk:
case DatabaseFactory::MySQLUnknownDatabase: case DatabaseFactory::MySQLUnknownDatabase:
m_ui->m_lblMysqlTestResult->setStatus(WidgetWithStatus::Ok, interpretation, interpretation); m_ui->m_lblMysqlTestResult->setStatus(WidgetWithStatus::Ok, interpretation, interpretation);
break; break;
default: default:
m_ui->m_lblMysqlTestResult->setStatus(WidgetWithStatus::Error, interpretation, interpretation); m_ui->m_lblMysqlTestResult->setStatus(WidgetWithStatus::Error, interpretation, interpretation);
break; break;
} }
} }
void SettingsDatabase::onMysqlHostnameChanged(const QString& new_hostname) { void SettingsDatabase::onMysqlHostnameChanged(const QString& new_hostname) {
if (new_hostname.isEmpty()) { if (new_hostname.isEmpty()) {
m_ui->m_txtMysqlHostname->setStatus(LineEditWithStatus::Warning, tr("Hostname is empty.")); m_ui->m_txtMysqlHostname->setStatus(LineEditWithStatus::Warning, tr("Hostname is empty."));
} }
else { else {
m_ui->m_txtMysqlHostname->setStatus(LineEditWithStatus::Ok, tr("Hostname looks ok.")); m_ui->m_txtMysqlHostname->setStatus(LineEditWithStatus::Ok, tr("Hostname looks ok."));
} }
} }
void SettingsDatabase::onMysqlUsernameChanged(const QString& new_username) { void SettingsDatabase::onMysqlUsernameChanged(const QString& new_username) {
if (new_username.isEmpty()) { if (new_username.isEmpty()) {
m_ui->m_txtMysqlUsername->setStatus(LineEditWithStatus::Warning, tr("Username is empty.")); m_ui->m_txtMysqlUsername->setStatus(LineEditWithStatus::Warning, tr("Username is empty."));
} }
else { else {
m_ui->m_txtMysqlUsername->setStatus(LineEditWithStatus::Ok, tr("Username looks ok.")); m_ui->m_txtMysqlUsername->setStatus(LineEditWithStatus::Ok, tr("Username looks ok."));
} }
} }
void SettingsDatabase::onMysqlPasswordChanged(const QString& new_password) { void SettingsDatabase::onMysqlPasswordChanged(const QString& new_password) {
if (new_password.isEmpty()) { if (new_password.isEmpty()) {
m_ui->m_txtMysqlPassword->setStatus(LineEditWithStatus::Warning, tr("Password is empty.")); m_ui->m_txtMysqlPassword->setStatus(LineEditWithStatus::Warning, tr("Password is empty."));
} }
else { else {
m_ui->m_txtMysqlPassword->setStatus(LineEditWithStatus::Ok, tr("Password looks ok.")); m_ui->m_txtMysqlPassword->setStatus(LineEditWithStatus::Ok, tr("Password looks ok."));
} }
} }
void SettingsDatabase::onMysqlDatabaseChanged(const QString& new_database) { void SettingsDatabase::onMysqlDatabaseChanged(const QString& new_database) {
if (new_database.isEmpty()) { if (new_database.isEmpty()) {
m_ui->m_txtMysqlDatabase->setStatus(LineEditWithStatus::Warning, tr("Working database is empty.")); m_ui->m_txtMysqlDatabase->setStatus(LineEditWithStatus::Warning, tr("Working database is empty."));
} }
else { else {
m_ui->m_txtMysqlDatabase->setStatus(LineEditWithStatus::Ok, tr("Working database is ok.")); m_ui->m_txtMysqlDatabase->setStatus(LineEditWithStatus::Ok, tr("Working database is ok."));
} }
} }
void SettingsDatabase::selectSqlBackend(int index) { void SettingsDatabase::selectSqlBackend(int index) {
const QString selected_db_driver = m_ui->m_cmbDatabaseDriver->itemData(index).toString(); const QString selected_db_driver = m_ui->m_cmbDatabaseDriver->itemData(index).toString();
if (selected_db_driver == APP_DB_SQLITE_DRIVER) { if (selected_db_driver == APP_DB_SQLITE_DRIVER) {
m_ui->m_stackedDatabaseDriver->setCurrentIndex(0); m_ui->m_stackedDatabaseDriver->setCurrentIndex(0);
} }
else if (selected_db_driver == APP_DB_MYSQL_DRIVER) { else if (selected_db_driver == APP_DB_MYSQL_DRIVER) {
m_ui->m_stackedDatabaseDriver->setCurrentIndex(1); m_ui->m_stackedDatabaseDriver->setCurrentIndex(1);
} }
else { else {
qWarning("GUI for given database driver '%s' is not available.", qPrintable(selected_db_driver)); qWarning("GUI for given database driver '%s' is not available.", qPrintable(selected_db_driver));
} }
} }
void SettingsDatabase::switchMysqlPasswordVisiblity(bool visible) { void SettingsDatabase::switchMysqlPasswordVisiblity(bool visible) {
m_ui->m_txtMysqlPassword->lineEdit()->setEchoMode(visible ? QLineEdit::Normal : QLineEdit::Password); m_ui->m_txtMysqlPassword->lineEdit()->setEchoMode(visible ? QLineEdit::Normal : QLineEdit::Password);
} }
void SettingsDatabase::loadSettings() { void SettingsDatabase::loadSettings() {
onBeginLoadSettings(); onBeginLoadSettings();
m_ui->m_checkUseTransactions->setChecked(qApp->settings()->value(GROUP(Database), SETTING(Database::UseTransactions)).toBool()); m_ui->m_checkUseTransactions->setChecked(qApp->settings()->value(GROUP(Database), SETTING(Database::UseTransactions)).toBool());
m_ui->m_lblMysqlTestResult->setStatus(WidgetWithStatus::Information, tr("No connection test triggered so far."), m_ui->m_lblMysqlTestResult->setStatus(WidgetWithStatus::Information, tr("No connection test triggered so far."),
tr("You did not executed any connection test yet.")); tr("You did not executed any connection test yet."));
// Load SQLite.
m_ui->m_cmbDatabaseDriver->addItem(qApp->database()->humanDriverName(DatabaseFactory::SQLITE), APP_DB_SQLITE_DRIVER);
// Load in-memory database status.
m_ui->m_checkSqliteUseInMemoryDatabase->setChecked(settings()->value(GROUP(Database), SETTING(Database::UseInMemory)).toBool());
if (QSqlDatabase::isDriverAvailable(APP_DB_MYSQL_DRIVER)) { // Load SQLite.
onMysqlHostnameChanged(QString()); m_ui->m_cmbDatabaseDriver->addItem(qApp->database()->humanDriverName(DatabaseFactory::SQLITE), APP_DB_SQLITE_DRIVER);
onMysqlUsernameChanged(QString());
onMysqlPasswordChanged(QString());
onMysqlDatabaseChanged(QString());
// Load MySQL.
m_ui->m_cmbDatabaseDriver->addItem(qApp->database()->humanDriverName(DatabaseFactory::MYSQL), APP_DB_MYSQL_DRIVER);
// Setup placeholders.
m_ui->m_txtMysqlHostname->lineEdit()->setPlaceholderText(tr("Hostname of your MySQL server"));
m_ui->m_txtMysqlUsername->lineEdit()->setPlaceholderText(tr("Username to login with"));
m_ui->m_txtMysqlPassword->lineEdit()->setPlaceholderText(tr("Password for your username"));
m_ui->m_txtMysqlDatabase->lineEdit()->setPlaceholderText(tr("Working database which you have full access to."));
m_ui->m_txtMysqlHostname->lineEdit()->setText(settings()->value(GROUP(Database), SETTING(Database::MySQLHostname)).toString());
m_ui->m_txtMysqlUsername->lineEdit()->setText(settings()->value(GROUP(Database), SETTING(Database::MySQLUsername)).toString());
m_ui->m_txtMysqlPassword->lineEdit()->setText(TextFactory::decrypt(settings()->value(GROUP(Database),
SETTING(Database::MySQLPassword)).toString()));
m_ui->m_txtMysqlDatabase->lineEdit()->setText(settings()->value(GROUP(Database), SETTING(Database::MySQLDatabase)).toString());
m_ui->m_spinMysqlPort->setValue(settings()->value(GROUP(Database), SETTING(Database::MySQLPort)).toInt());
m_ui->m_checkMysqlShowPassword->setChecked(false);
}
int index_current_backend = m_ui->m_cmbDatabaseDriver->findData(settings()->value(GROUP(Database), // Load in-memory database status.
SETTING(Database::ActiveDriver)).toString()); m_ui->m_checkSqliteUseInMemoryDatabase->setChecked(settings()->value(GROUP(Database), SETTING(Database::UseInMemory)).toBool());
if (index_current_backend >= 0) { if (QSqlDatabase::isDriverAvailable(APP_DB_MYSQL_DRIVER)) {
m_ui->m_cmbDatabaseDriver->setCurrentIndex(index_current_backend); onMysqlHostnameChanged(QString());
} onMysqlUsernameChanged(QString());
onMysqlPasswordChanged(QString());
onMysqlDatabaseChanged(QString());
onEndLoadSettings(); // Load MySQL.
m_ui->m_cmbDatabaseDriver->addItem(qApp->database()->humanDriverName(DatabaseFactory::MYSQL), APP_DB_MYSQL_DRIVER);
// Setup placeholders.
m_ui->m_txtMysqlHostname->lineEdit()->setPlaceholderText(tr("Hostname of your MySQL server"));
m_ui->m_txtMysqlUsername->lineEdit()->setPlaceholderText(tr("Username to login with"));
m_ui->m_txtMysqlPassword->lineEdit()->setPlaceholderText(tr("Password for your username"));
m_ui->m_txtMysqlDatabase->lineEdit()->setPlaceholderText(tr("Working database which you have full access to."));
m_ui->m_txtMysqlHostname->lineEdit()->setText(settings()->value(GROUP(Database), SETTING(Database::MySQLHostname)).toString());
m_ui->m_txtMysqlUsername->lineEdit()->setText(settings()->value(GROUP(Database), SETTING(Database::MySQLUsername)).toString());
m_ui->m_txtMysqlPassword->lineEdit()->setText(TextFactory::decrypt(settings()->value(GROUP(Database),
SETTING(Database::MySQLPassword)).toString()));
m_ui->m_txtMysqlDatabase->lineEdit()->setText(settings()->value(GROUP(Database), SETTING(Database::MySQLDatabase)).toString());
m_ui->m_spinMysqlPort->setValue(settings()->value(GROUP(Database), SETTING(Database::MySQLPort)).toInt());
m_ui->m_checkMysqlShowPassword->setChecked(false);
}
int index_current_backend = m_ui->m_cmbDatabaseDriver->findData(settings()->value(GROUP(Database),
SETTING(Database::ActiveDriver)).toString());
if (index_current_backend >= 0) {
m_ui->m_cmbDatabaseDriver->setCurrentIndex(index_current_backend);
}
onEndLoadSettings();
} }
void SettingsDatabase::saveSettings() { void SettingsDatabase::saveSettings() {
onBeginSaveSettings(); onBeginSaveSettings();
// Setup in-memory database status.
const bool original_inmemory = settings()->value(GROUP(Database), SETTING(Database::UseInMemory)).toBool();
const bool new_inmemory = m_ui->m_checkSqliteUseInMemoryDatabase->isChecked();
qApp->settings()->setValue(GROUP(Database), Database::UseTransactions, m_ui->m_checkUseTransactions->isChecked());
// Save data storage settings.
QString original_db_driver = settings()->value(GROUP(Database), SETTING(Database::ActiveDriver)).toString();
QString selected_db_driver = m_ui->m_cmbDatabaseDriver->itemData(m_ui->m_cmbDatabaseDriver->currentIndex()).toString();
// Save SQLite.
settings()->setValue(GROUP(Database), Database::UseInMemory, new_inmemory);
if (QSqlDatabase::isDriverAvailable(APP_DB_MYSQL_DRIVER)) { // Setup in-memory database status.
// Save MySQL. const bool original_inmemory = settings()->value(GROUP(Database), SETTING(Database::UseInMemory)).toBool();
settings()->setValue(GROUP(Database), Database::MySQLHostname, m_ui->m_txtMysqlHostname->lineEdit()->text()); const bool new_inmemory = m_ui->m_checkSqliteUseInMemoryDatabase->isChecked();
settings()->setValue(GROUP(Database), Database::MySQLUsername, m_ui->m_txtMysqlUsername->lineEdit()->text());
settings()->setValue(GROUP(Database), Database::MySQLPassword, TextFactory::encrypt(m_ui->m_txtMysqlPassword->lineEdit()->text()));
settings()->setValue(GROUP(Database), Database::MySQLDatabase, m_ui->m_txtMysqlDatabase->lineEdit()->text());
settings()->setValue(GROUP(Database), Database::MySQLPort, m_ui->m_spinMysqlPort->value());
}
settings()->setValue(GROUP(Database), Database::ActiveDriver, selected_db_driver); qApp->settings()->setValue(GROUP(Database), Database::UseTransactions, m_ui->m_checkUseTransactions->isChecked());
if (original_db_driver != selected_db_driver || original_inmemory != new_inmemory) { // Save data storage settings.
requireRestart(); QString original_db_driver = settings()->value(GROUP(Database), SETTING(Database::ActiveDriver)).toString();
} QString selected_db_driver = m_ui->m_cmbDatabaseDriver->itemData(m_ui->m_cmbDatabaseDriver->currentIndex()).toString();
onEndSaveSettings(); // Save SQLite.
settings()->setValue(GROUP(Database), Database::UseInMemory, new_inmemory);
if (QSqlDatabase::isDriverAvailable(APP_DB_MYSQL_DRIVER)) {
// Save MySQL.
settings()->setValue(GROUP(Database), Database::MySQLHostname, m_ui->m_txtMysqlHostname->lineEdit()->text());
settings()->setValue(GROUP(Database), Database::MySQLUsername, m_ui->m_txtMysqlUsername->lineEdit()->text());
settings()->setValue(GROUP(Database), Database::MySQLPassword, TextFactory::encrypt(m_ui->m_txtMysqlPassword->lineEdit()->text()));
settings()->setValue(GROUP(Database), Database::MySQLDatabase, m_ui->m_txtMysqlDatabase->lineEdit()->text());
settings()->setValue(GROUP(Database), Database::MySQLPort, m_ui->m_spinMysqlPort->value());
}
settings()->setValue(GROUP(Database), Database::ActiveDriver, selected_db_driver);
if (original_db_driver != selected_db_driver || original_inmemory != new_inmemory) {
requireRestart();
}
onEndSaveSettings();
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -22,31 +23,31 @@
#include "ui_settingsdatabase.h" #include "ui_settingsdatabase.h"
class SettingsDatabase : public SettingsPanel { class SettingsDatabase : public SettingsPanel {
Q_OBJECT Q_OBJECT
public: public:
explicit SettingsDatabase(Settings* settings, QWidget* parent = 0); explicit SettingsDatabase(Settings* settings, QWidget* parent = 0);
virtual ~SettingsDatabase(); virtual ~SettingsDatabase();
inline QString title() const { inline QString title() const {
return tr("Data storage"); return tr("Data storage");
} }
void loadSettings(); void loadSettings();
void saveSettings();
private: void saveSettings();
void mysqlTestConnection();
void onMysqlHostnameChanged(const QString& new_hostname);
void onMysqlUsernameChanged(const QString& new_username);
void onMysqlPasswordChanged(const QString& new_password);
void onMysqlDatabaseChanged(const QString& new_database);
void selectSqlBackend(int index);
void switchMysqlPasswordVisiblity(bool visible);
Ui::SettingsDatabase* m_ui; private:
void mysqlTestConnection();
void onMysqlHostnameChanged(const QString& new_hostname);
void onMysqlUsernameChanged(const QString& new_username);
void onMysqlPasswordChanged(const QString& new_password);
void onMysqlDatabaseChanged(const QString& new_database);
void selectSqlBackend(int index);
void switchMysqlPasswordVisiblity(bool visible);
Ui::SettingsDatabase* m_ui;
}; };
#endif // SETTINGSDATABASE_H #endif // SETTINGSDATABASE_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -17,54 +18,53 @@
#include "gui/settings/settingsdownloads.h" #include "gui/settings/settingsdownloads.h"
#include "miscellaneous/application.h"
#include "miscellaneous/settings.h" #include "miscellaneous/settings.h"
#include "network-web/downloadmanager.h" #include "network-web/downloadmanager.h"
#include "miscellaneous/application.h"
#include <QFileDialog> #include <QFileDialog>
SettingsDownloads::SettingsDownloads(Settings* settings, QWidget* parent) SettingsDownloads::SettingsDownloads(Settings* settings, QWidget* parent)
: SettingsPanel(settings, parent), m_ui(new Ui::SettingsDownloads) { : SettingsPanel(settings, parent), m_ui(new Ui::SettingsDownloads) {
m_ui->setupUi(this); m_ui->setupUi(this);
connect(m_ui->m_checkOpenManagerWhenDownloadStarts, &QCheckBox::toggled, this, &SettingsDownloads::dirtifySettings); connect(m_ui->m_checkOpenManagerWhenDownloadStarts, &QCheckBox::toggled, this, &SettingsDownloads::dirtifySettings);
connect(m_ui->m_txtDownloadsTargetDirectory, &QLineEdit::textChanged, this, &SettingsDownloads::dirtifySettings); connect(m_ui->m_txtDownloadsTargetDirectory, &QLineEdit::textChanged, this, &SettingsDownloads::dirtifySettings);
connect(m_ui->m_rbDownloadsAskEachFile, &QRadioButton::toggled, this, &SettingsDownloads::dirtifySettings); connect(m_ui->m_rbDownloadsAskEachFile, &QRadioButton::toggled, this, &SettingsDownloads::dirtifySettings);
connect(m_ui->m_btnDownloadsTargetDirectory, &QPushButton::clicked, this, &SettingsDownloads::selectDownloadsDirectory); connect(m_ui->m_btnDownloadsTargetDirectory, &QPushButton::clicked, this, &SettingsDownloads::selectDownloadsDirectory);
} }
SettingsDownloads::~SettingsDownloads() { SettingsDownloads::~SettingsDownloads() {
delete m_ui; delete m_ui;
} }
void SettingsDownloads::selectDownloadsDirectory() { void SettingsDownloads::selectDownloadsDirectory() {
const QString target_directory = QFileDialog::getExistingDirectory(this, const QString target_directory = QFileDialog::getExistingDirectory(this,
tr("Select downloads target directory"), tr("Select downloads target directory"),
m_ui->m_txtDownloadsTargetDirectory->text() m_ui->m_txtDownloadsTargetDirectory->text()
); );
if (!target_directory.isEmpty()) { if (!target_directory.isEmpty()) {
m_ui->m_txtDownloadsTargetDirectory->setText(QDir::toNativeSeparators(target_directory)); m_ui->m_txtDownloadsTargetDirectory->setText(QDir::toNativeSeparators(target_directory));
} }
} }
void SettingsDownloads::loadSettings() { void SettingsDownloads::loadSettings() {
onBeginLoadSettings(); onBeginLoadSettings();
m_ui->m_checkOpenManagerWhenDownloadStarts->setChecked(settings()->value(GROUP(Downloads), m_ui->m_checkOpenManagerWhenDownloadStarts->setChecked(settings()->value(GROUP(Downloads),
SETTING(Downloads::ShowDownloadsWhenNewDownloadStarts)).toBool()); SETTING(Downloads::ShowDownloadsWhenNewDownloadStarts)).toBool());
m_ui->m_txtDownloadsTargetDirectory->setText(QDir::toNativeSeparators(settings()->value(GROUP(Downloads), m_ui->m_txtDownloadsTargetDirectory->setText(QDir::toNativeSeparators(settings()->value(GROUP(Downloads),
SETTING(Downloads::TargetDirectory)).toString())); SETTING(Downloads::TargetDirectory)).toString()));
m_ui->m_rbDownloadsAskEachFile->setChecked(settings()->value(GROUP(Downloads), m_ui->m_rbDownloadsAskEachFile->setChecked(settings()->value(GROUP(Downloads),
SETTING(Downloads::AlwaysPromptForFilename)).toBool()); SETTING(Downloads::AlwaysPromptForFilename)).toBool());
onEndLoadSettings(); onEndLoadSettings();
} }
void SettingsDownloads::saveSettings() { void SettingsDownloads::saveSettings() {
onBeginSaveSettings(); onBeginSaveSettings();
settings()->setValue(GROUP(Downloads), Downloads::ShowDownloadsWhenNewDownloadStarts, settings()->setValue(GROUP(Downloads), Downloads::ShowDownloadsWhenNewDownloadStarts,
m_ui->m_checkOpenManagerWhenDownloadStarts->isChecked()); m_ui->m_checkOpenManagerWhenDownloadStarts->isChecked());
settings()->setValue(GROUP(Downloads), Downloads::TargetDirectory, m_ui->m_txtDownloadsTargetDirectory->text()); settings()->setValue(GROUP(Downloads), Downloads::TargetDirectory, m_ui->m_txtDownloadsTargetDirectory->text());
settings()->setValue(GROUP(Downloads), Downloads::AlwaysPromptForFilename, m_ui->m_rbDownloadsAskEachFile->isChecked()); settings()->setValue(GROUP(Downloads), Downloads::AlwaysPromptForFilename, m_ui->m_rbDownloadsAskEachFile->isChecked());
qApp->downloadManager()->setDownloadDirectory(m_ui->m_txtDownloadsTargetDirectory->text()); qApp->downloadManager()->setDownloadDirectory(m_ui->m_txtDownloadsTargetDirectory->text());
onEndSaveSettings(); onEndSaveSettings();
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -22,26 +23,26 @@
#include "ui_settingsdownloads.h" #include "ui_settingsdownloads.h"
class SettingsDownloads : public SettingsPanel { class SettingsDownloads : public SettingsPanel {
Q_OBJECT Q_OBJECT
public: public:
explicit SettingsDownloads(Settings* settings, QWidget* parent = 0); explicit SettingsDownloads(Settings* settings, QWidget* parent = 0);
virtual ~SettingsDownloads(); virtual ~SettingsDownloads();
inline QString title() const { inline QString title() const {
return tr("Downloads"); return tr("Downloads");
} }
void loadSettings(); void loadSettings();
void saveSettings();
private slots: void saveSettings();
void selectDownloadsDirectory();
private: private slots:
Ui::SettingsDownloads* m_ui; void selectDownloadsDirectory();
private:
Ui::SettingsDownloads* m_ui;
}; };
#endif // SETTINGSDOWNLOADS_H #endif // SETTINGSDOWNLOADS_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -18,126 +19,128 @@
#include "gui/settings/settingsfeedsmessages.h" #include "gui/settings/settingsfeedsmessages.h"
#include "definitions/definitions.h" #include "definitions/definitions.h"
#include "miscellaneous/application.h"
#include "miscellaneous/feedreader.h"
#include "gui/dialogs/formmain.h" #include "gui/dialogs/formmain.h"
#include "gui/feedmessageviewer.h" #include "gui/feedmessageviewer.h"
#include "gui/feedsview.h" #include "gui/feedsview.h"
#include "gui/guiutilities.h"
#include "gui/messagesview.h" #include "gui/messagesview.h"
#include "gui/timespinbox.h" #include "gui/timespinbox.h"
#include "gui/guiutilities.h" #include "miscellaneous/application.h"
#include "miscellaneous/feedreader.h"
#include <QFontDialog> #include <QFontDialog>
SettingsFeedsMessages::SettingsFeedsMessages(Settings* settings, QWidget* parent) SettingsFeedsMessages::SettingsFeedsMessages(Settings* settings, QWidget* parent)
: SettingsPanel(settings, parent), m_ui(new Ui::SettingsFeedsMessages) { : SettingsPanel(settings, parent), m_ui(new Ui::SettingsFeedsMessages) {
m_ui->setupUi(this); m_ui->setupUi(this);
initializeMessageDateFormats(); initializeMessageDateFormats();
GuiUtilities::setLabelAsNotice(*m_ui->label_9, false); GuiUtilities::setLabelAsNotice(*m_ui->label_9, false);
connect(m_ui->m_checkAutoUpdateNotification, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings); connect(m_ui->m_checkAutoUpdateNotification, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings);
connect(m_ui->m_checkAutoUpdate, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings); connect(m_ui->m_checkAutoUpdate, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings);
connect(m_ui->m_checkKeppMessagesInTheMiddle, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings); connect(m_ui->m_checkKeppMessagesInTheMiddle, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings);
connect(m_ui->m_checkMessagesDateTimeFormat, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings); connect(m_ui->m_checkMessagesDateTimeFormat, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings);
connect(m_ui->m_checkRemoveReadMessagesOnExit, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings); connect(m_ui->m_checkRemoveReadMessagesOnExit, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings);
connect(m_ui->m_checkUpdateAllFeedsOnStartup, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings); connect(m_ui->m_checkUpdateAllFeedsOnStartup, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings);
connect(m_ui->m_spinAutoUpdateInterval, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), connect(m_ui->m_spinAutoUpdateInterval, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
this, &SettingsFeedsMessages::dirtifySettings); this, &SettingsFeedsMessages::dirtifySettings);
connect(m_ui->m_spinHeightImageAttachments, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), connect(m_ui->m_spinHeightImageAttachments, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
this, &SettingsFeedsMessages::dirtifySettings); this, &SettingsFeedsMessages::dirtifySettings);
connect(m_ui->m_checkAutoUpdate, &QCheckBox::toggled, m_ui->m_spinAutoUpdateInterval, &TimeSpinBox::setEnabled); connect(m_ui->m_checkAutoUpdate, &QCheckBox::toggled, m_ui->m_spinAutoUpdateInterval, &TimeSpinBox::setEnabled);
connect(m_ui->m_spinFeedUpdateTimeout, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, connect(m_ui->m_spinFeedUpdateTimeout, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this,
&SettingsFeedsMessages::dirtifySettings); &SettingsFeedsMessages::dirtifySettings);
connect(m_ui->m_cmbMessagesDateTimeFormat, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, connect(m_ui->m_cmbMessagesDateTimeFormat, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
&SettingsFeedsMessages::dirtifySettings); &SettingsFeedsMessages::dirtifySettings);
connect(m_ui->m_cmbCountsFeedList, &QComboBox::currentTextChanged, this, &SettingsFeedsMessages::dirtifySettings); connect(m_ui->m_cmbCountsFeedList, &QComboBox::currentTextChanged, this, &SettingsFeedsMessages::dirtifySettings);
connect(m_ui->m_cmbCountsFeedList, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, connect(m_ui->m_cmbCountsFeedList, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
&SettingsFeedsMessages::dirtifySettings); &SettingsFeedsMessages::dirtifySettings);
connect(m_ui->m_btnChangeMessagesFont, &QPushButton::clicked, this, &SettingsFeedsMessages::changeMessagesFont); connect(m_ui->m_btnChangeMessagesFont, &QPushButton::clicked, this, &SettingsFeedsMessages::changeMessagesFont);
if (!m_ui->m_spinFeedUpdateTimeout->suffix().startsWith(' ')) { if (!m_ui->m_spinFeedUpdateTimeout->suffix().startsWith(' ')) {
m_ui->m_spinFeedUpdateTimeout->setSuffix(QSL(" ") + m_ui->m_spinFeedUpdateTimeout->suffix()); m_ui->m_spinFeedUpdateTimeout->setSuffix(QSL(" ") + m_ui->m_spinFeedUpdateTimeout->suffix());
} }
} }
SettingsFeedsMessages::~SettingsFeedsMessages() { SettingsFeedsMessages::~SettingsFeedsMessages() {
delete m_ui; delete m_ui;
} }
void SettingsFeedsMessages::initializeMessageDateFormats() { void SettingsFeedsMessages::initializeMessageDateFormats() {
QStringList best_formats; QStringList best_formats;
best_formats << QSL("d/M/yyyy hh:mm:ss") << QSL("ddd, d. M. yy hh:mm:ss") <<
QSL("yyyy-MM-dd HH:mm:ss.z") << QSL("yyyy-MM-ddThh:mm:ss") <<
QSL("MMM d yyyy hh:mm:ss");;
const QLocale current_locale = qApp->localization()->loadedLocale();
const QDateTime current_dt = QDateTime::currentDateTime();
foreach (const QString& format, best_formats) { best_formats << QSL("d/M/yyyy hh:mm:ss") << QSL("ddd, d. M. yy hh:mm:ss") <<
m_ui->m_cmbMessagesDateTimeFormat->addItem(current_locale.toString(current_dt, format), format); QSL("yyyy-MM-dd HH:mm:ss.z") << QSL("yyyy-MM-ddThh:mm:ss") <<
} QSL("MMM d yyyy hh:mm:ss");;
const QLocale current_locale = qApp->localization()->loadedLocale();
const QDateTime current_dt = QDateTime::currentDateTime();
foreach (const QString& format, best_formats) {
m_ui->m_cmbMessagesDateTimeFormat->addItem(current_locale.toString(current_dt, format), format);
}
} }
void SettingsFeedsMessages::changeMessagesFont() { void SettingsFeedsMessages::changeMessagesFont() {
bool ok; bool ok;
QFont new_font = QFontDialog::getFont(&ok, m_ui->m_lblMessagesFont->font(), QFont new_font = QFontDialog::getFont(&ok, m_ui->m_lblMessagesFont->font(),
this, tr("Select new font for message viewer"), this, tr("Select new font for message viewer"),
QFontDialog::DontUseNativeDialog); QFontDialog::DontUseNativeDialog);
if (ok) { if (ok) {
m_ui->m_lblMessagesFont->setFont(new_font); m_ui->m_lblMessagesFont->setFont(new_font);
dirtifySettings(); dirtifySettings();
} }
} }
void SettingsFeedsMessages::loadSettings() { void SettingsFeedsMessages::loadSettings() {
onBeginLoadSettings(); onBeginLoadSettings();
m_ui->m_checkAutoUpdateNotification->setChecked(settings()->value(GROUP(Feeds), SETTING(Feeds::EnableAutoUpdateNotification)).toBool()); m_ui->m_checkAutoUpdateNotification->setChecked(settings()->value(GROUP(Feeds), SETTING(Feeds::EnableAutoUpdateNotification)).toBool());
m_ui->m_checkKeppMessagesInTheMiddle->setChecked(settings()->value(GROUP(Messages), SETTING(Messages::KeepCursorInCenter)).toBool()); m_ui->m_checkKeppMessagesInTheMiddle->setChecked(settings()->value(GROUP(Messages), SETTING(Messages::KeepCursorInCenter)).toBool());
m_ui->m_checkRemoveReadMessagesOnExit->setChecked(settings()->value(GROUP(Messages), SETTING(Messages::ClearReadOnExit)).toBool()); m_ui->m_checkRemoveReadMessagesOnExit->setChecked(settings()->value(GROUP(Messages), SETTING(Messages::ClearReadOnExit)).toBool());
m_ui->m_checkAutoUpdate->setChecked(settings()->value(GROUP(Feeds), SETTING(Feeds::AutoUpdateEnabled)).toBool()); m_ui->m_checkAutoUpdate->setChecked(settings()->value(GROUP(Feeds), SETTING(Feeds::AutoUpdateEnabled)).toBool());
m_ui->m_spinAutoUpdateInterval->setValue(settings()->value(GROUP(Feeds), SETTING(Feeds::AutoUpdateInterval)).toInt()); m_ui->m_spinAutoUpdateInterval->setValue(settings()->value(GROUP(Feeds), SETTING(Feeds::AutoUpdateInterval)).toInt());
m_ui->m_spinFeedUpdateTimeout->setValue(settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt()); m_ui->m_spinFeedUpdateTimeout->setValue(settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt());
m_ui->m_checkUpdateAllFeedsOnStartup->setChecked(settings()->value(GROUP(Feeds), SETTING(Feeds::FeedsUpdateOnStartup)).toBool()); m_ui->m_checkUpdateAllFeedsOnStartup->setChecked(settings()->value(GROUP(Feeds), SETTING(Feeds::FeedsUpdateOnStartup)).toBool());
m_ui->m_cmbCountsFeedList->addItems(QStringList() << "(%unread)" << "[%unread]" << "%unread/%all" << "%unread-%all" << "[%unread|%all]"); m_ui->m_cmbCountsFeedList->addItems(QStringList() << "(%unread)" << "[%unread]" << "%unread/%all" << "%unread-%all" << "[%unread|%all]");
m_ui->m_cmbCountsFeedList->setEditText(settings()->value(GROUP(Feeds), SETTING(Feeds::CountFormat)).toString()); m_ui->m_cmbCountsFeedList->setEditText(settings()->value(GROUP(Feeds), SETTING(Feeds::CountFormat)).toString());
m_ui->m_spinHeightImageAttachments->setValue(settings()->value(GROUP(Messages), SETTING(Messages::MessageHeadImageHeight)).toInt()); m_ui->m_spinHeightImageAttachments->setValue(settings()->value(GROUP(Messages), SETTING(Messages::MessageHeadImageHeight)).toInt());
initializeMessageDateFormats(); initializeMessageDateFormats();
m_ui->m_checkMessagesDateTimeFormat->setChecked(settings()->value(GROUP(Messages), SETTING(Messages::UseCustomDate)).toBool()); m_ui->m_checkMessagesDateTimeFormat->setChecked(settings()->value(GROUP(Messages), SETTING(Messages::UseCustomDate)).toBool());
const int index_format = m_ui->m_cmbMessagesDateTimeFormat->findData(settings()->value(GROUP(Messages), const int index_format = m_ui->m_cmbMessagesDateTimeFormat->findData(settings()->value(GROUP(Messages),
SETTING(Messages::CustomDateFormat)).toString()); SETTING(Messages::CustomDateFormat)).toString());
if (index_format >= 0) { if (index_format >= 0) {
m_ui->m_cmbMessagesDateTimeFormat->setCurrentIndex(index_format); m_ui->m_cmbMessagesDateTimeFormat->setCurrentIndex(index_format);
} }
m_ui->m_lblMessagesFont->setText(tr("Font preview")); m_ui->m_lblMessagesFont->setText(tr("Font preview"));
QFont fon; QFont fon;
fon.fromString(settings()->value(GROUP(Messages),
SETTING(Messages::PreviewerFontStandard)).toString()); fon.fromString(settings()->value(GROUP(Messages),
m_ui->m_lblMessagesFont->setFont(fon); SETTING(Messages::PreviewerFontStandard)).toString());
onEndLoadSettings(); m_ui->m_lblMessagesFont->setFont(fon);
onEndLoadSettings();
} }
void SettingsFeedsMessages::saveSettings() { void SettingsFeedsMessages::saveSettings() {
onBeginSaveSettings(); onBeginSaveSettings();
settings()->setValue(GROUP(Feeds), Feeds::EnableAutoUpdateNotification, m_ui->m_checkAutoUpdateNotification->isChecked()); settings()->setValue(GROUP(Feeds), Feeds::EnableAutoUpdateNotification, m_ui->m_checkAutoUpdateNotification->isChecked());
settings()->setValue(GROUP(Messages), Messages::KeepCursorInCenter, m_ui->m_checkKeppMessagesInTheMiddle->isChecked()); settings()->setValue(GROUP(Messages), Messages::KeepCursorInCenter, m_ui->m_checkKeppMessagesInTheMiddle->isChecked());
settings()->setValue(GROUP(Messages), Messages::ClearReadOnExit, m_ui->m_checkRemoveReadMessagesOnExit->isChecked()); settings()->setValue(GROUP(Messages), Messages::ClearReadOnExit, m_ui->m_checkRemoveReadMessagesOnExit->isChecked());
settings()->setValue(GROUP(Feeds), Feeds::AutoUpdateEnabled, m_ui->m_checkAutoUpdate->isChecked()); settings()->setValue(GROUP(Feeds), Feeds::AutoUpdateEnabled, m_ui->m_checkAutoUpdate->isChecked());
settings()->setValue(GROUP(Feeds), Feeds::AutoUpdateInterval, m_ui->m_spinAutoUpdateInterval->value()); settings()->setValue(GROUP(Feeds), Feeds::AutoUpdateInterval, m_ui->m_spinAutoUpdateInterval->value());
settings()->setValue(GROUP(Feeds), Feeds::UpdateTimeout, m_ui->m_spinFeedUpdateTimeout->value()); settings()->setValue(GROUP(Feeds), Feeds::UpdateTimeout, m_ui->m_spinFeedUpdateTimeout->value());
settings()->setValue(GROUP(Feeds), Feeds::FeedsUpdateOnStartup, m_ui->m_checkUpdateAllFeedsOnStartup->isChecked()); settings()->setValue(GROUP(Feeds), Feeds::FeedsUpdateOnStartup, m_ui->m_checkUpdateAllFeedsOnStartup->isChecked());
settings()->setValue(GROUP(Feeds), Feeds::CountFormat, m_ui->m_cmbCountsFeedList->currentText()); settings()->setValue(GROUP(Feeds), Feeds::CountFormat, m_ui->m_cmbCountsFeedList->currentText());
settings()->setValue(GROUP(Messages), Messages::UseCustomDate, m_ui->m_checkMessagesDateTimeFormat->isChecked()); settings()->setValue(GROUP(Messages), Messages::UseCustomDate, m_ui->m_checkMessagesDateTimeFormat->isChecked());
settings()->setValue(GROUP(Messages), Messages::MessageHeadImageHeight, m_ui->m_spinHeightImageAttachments->value()); settings()->setValue(GROUP(Messages), Messages::MessageHeadImageHeight, m_ui->m_spinHeightImageAttachments->value());
settings()->setValue(GROUP(Messages), Messages::CustomDateFormat, settings()->setValue(GROUP(Messages), Messages::CustomDateFormat,
m_ui->m_cmbMessagesDateTimeFormat->itemData(m_ui->m_cmbMessagesDateTimeFormat->currentIndex()).toString()); m_ui->m_cmbMessagesDateTimeFormat->itemData(m_ui->m_cmbMessagesDateTimeFormat->currentIndex()).toString());
// Save fonts.
settings()->setValue(GROUP(Messages), Messages::PreviewerFontStandard, m_ui->m_lblMessagesFont->font().toString()); // Save fonts.
qApp->mainForm()->tabWidget()->feedMessageViewer()->loadMessageViewerFonts(); settings()->setValue(GROUP(Messages), Messages::PreviewerFontStandard, m_ui->m_lblMessagesFont->font().toString());
qApp->feedReader()->updateAutoUpdateStatus(); qApp->mainForm()->tabWidget()->feedMessageViewer()->loadMessageViewerFonts();
qApp->feedReader()->feedsModel()->reloadWholeLayout(); qApp->feedReader()->updateAutoUpdateStatus();
qApp->feedReader()->messagesModel()->updateDateFormat(); qApp->feedReader()->feedsModel()->reloadWholeLayout();
qApp->feedReader()->messagesModel()->reloadWholeLayout(); qApp->feedReader()->messagesModel()->updateDateFormat();
onEndSaveSettings(); qApp->feedReader()->messagesModel()->reloadWholeLayout();
onEndSaveSettings();
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -22,28 +23,28 @@
#include "ui_settingsfeedsmessages.h" #include "ui_settingsfeedsmessages.h"
class SettingsFeedsMessages : public SettingsPanel { class SettingsFeedsMessages : public SettingsPanel {
Q_OBJECT Q_OBJECT
public: public:
explicit SettingsFeedsMessages(Settings* settings, QWidget* parent = 0); explicit SettingsFeedsMessages(Settings* settings, QWidget* parent = 0);
virtual ~SettingsFeedsMessages(); virtual ~SettingsFeedsMessages();
inline QString title() const { inline QString title() const {
return tr("Feeds & messages"); return tr("Feeds & messages");
} }
void loadSettings(); void loadSettings();
void saveSettings();
private slots: void saveSettings();
void changeMessagesFont();
private: private slots:
void initializeMessageDateFormats(); void changeMessagesFont();
Ui::SettingsFeedsMessages* m_ui; private:
void initializeMessageDateFormats();
Ui::SettingsFeedsMessages* m_ui;
}; };
#endif // SETTINGSFEEDSMESSAGES_H #endif // SETTINGSFEEDSMESSAGES_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -17,65 +18,65 @@
#include "gui/settings/settingsgeneral.h" #include "gui/settings/settingsgeneral.h"
#include "miscellaneous/systemfactory.h"
#include "miscellaneous/application.h" #include "miscellaneous/application.h"
#include "miscellaneous/systemfactory.h"
SettingsGeneral::SettingsGeneral(Settings* settings, QWidget* parent) SettingsGeneral::SettingsGeneral(Settings* settings, QWidget* parent)
: SettingsPanel(settings, parent), m_ui(new Ui::SettingsGeneral) { : SettingsPanel(settings, parent), m_ui(new Ui::SettingsGeneral) {
m_ui->setupUi(this); m_ui->setupUi(this);
m_ui->m_checkAutostart->setText(m_ui->m_checkAutostart->text().arg(APP_NAME)); m_ui->m_checkAutostart->setText(m_ui->m_checkAutostart->text().arg(APP_NAME));
connect(m_ui->m_checkAutostart, &QCheckBox::stateChanged, this, &SettingsGeneral::dirtifySettings); connect(m_ui->m_checkAutostart, &QCheckBox::stateChanged, this, &SettingsGeneral::dirtifySettings);
connect(m_ui->m_checkForUpdatesOnStart, &QCheckBox::stateChanged, this, &SettingsGeneral::dirtifySettings); connect(m_ui->m_checkForUpdatesOnStart, &QCheckBox::stateChanged, this, &SettingsGeneral::dirtifySettings);
connect(m_ui->m_checkRemoveTrolltechJunk, &QCheckBox::stateChanged, this, &SettingsGeneral::dirtifySettings); connect(m_ui->m_checkRemoveTrolltechJunk, &QCheckBox::stateChanged, this, &SettingsGeneral::dirtifySettings);
} }
SettingsGeneral::~SettingsGeneral() { SettingsGeneral::~SettingsGeneral() {
delete m_ui; delete m_ui;
} }
void SettingsGeneral::loadSettings() { void SettingsGeneral::loadSettings() {
onBeginLoadSettings(); onBeginLoadSettings();
m_ui->m_checkForUpdatesOnStart->setChecked(settings()->value(GROUP(General), SETTING(General::UpdateOnStartup)).toBool()); m_ui->m_checkForUpdatesOnStart->setChecked(settings()->value(GROUP(General), SETTING(General::UpdateOnStartup)).toBool());
// Load auto-start status.
const SystemFactory::AutoStartStatus autostart_status = qApp->system()->autoStartStatus();
switch (autostart_status) { // Load auto-start status.
case SystemFactory::AutoStartStatus::Enabled: const SystemFactory::AutoStartStatus autostart_status = qApp->system()->autoStartStatus();
m_ui->m_checkAutostart->setChecked(true);
break;
case SystemFactory::AutoStartStatus::Disabled: switch (autostart_status) {
m_ui->m_checkAutostart->setChecked(false); case SystemFactory::AutoStartStatus::Enabled:
break; m_ui->m_checkAutostart->setChecked(true);
break;
default: case SystemFactory::AutoStartStatus::Disabled:
m_ui->m_checkAutostart->setEnabled(false); m_ui->m_checkAutostart->setChecked(false);
m_ui->m_checkAutostart->setText(m_ui->m_checkAutostart->text() + tr(" (not supported on this platform)")); break;
break;
} default:
m_ui->m_checkAutostart->setEnabled(false);
m_ui->m_checkAutostart->setText(m_ui->m_checkAutostart->text() + tr(" (not supported on this platform)"));
break;
}
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
m_ui->m_checkRemoveTrolltechJunk->setVisible(true); m_ui->m_checkRemoveTrolltechJunk->setVisible(true);
m_ui->m_checkRemoveTrolltechJunk->setChecked(settings()->value(GROUP(General), SETTING(General::RemoveTrolltechJunk)).toBool()); m_ui->m_checkRemoveTrolltechJunk->setChecked(settings()->value(GROUP(General), SETTING(General::RemoveTrolltechJunk)).toBool());
#else #else
m_ui->m_checkRemoveTrolltechJunk->setVisible(false); m_ui->m_checkRemoveTrolltechJunk->setVisible(false);
#endif #endif
onEndLoadSettings(); onEndLoadSettings();
} }
void SettingsGeneral::saveSettings() { void SettingsGeneral::saveSettings() {
onBeginSaveSettings(); onBeginSaveSettings();
// If auto-start feature is available and user wants to turn it on, then turn it on. // If auto-start feature is available and user wants to turn it on, then turn it on.
if (m_ui->m_checkAutostart->isChecked()) { if (m_ui->m_checkAutostart->isChecked()) {
qApp->system()->setAutoStartStatus(SystemFactory::AutoStartStatus::Enabled); qApp->system()->setAutoStartStatus(SystemFactory::AutoStartStatus::Enabled);
} }
else { else {
qApp->system()->setAutoStartStatus(SystemFactory::AutoStartStatus::Disabled); qApp->system()->setAutoStartStatus(SystemFactory::AutoStartStatus::Disabled);
} }
settings()->setValue(GROUP(General), General::UpdateOnStartup, m_ui->m_checkForUpdatesOnStart->isChecked()); settings()->setValue(GROUP(General), General::UpdateOnStartup, m_ui->m_checkForUpdatesOnStart->isChecked());
settings()->setValue(GROUP(General), General::RemoveTrolltechJunk, m_ui->m_checkRemoveTrolltechJunk->isChecked()); settings()->setValue(GROUP(General), General::RemoveTrolltechJunk, m_ui->m_checkRemoveTrolltechJunk->isChecked());
onEndSaveSettings(); onEndSaveSettings();
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -22,23 +23,23 @@
#include "ui_settingsgeneral.h" #include "ui_settingsgeneral.h"
class SettingsGeneral : public SettingsPanel { class SettingsGeneral : public SettingsPanel {
Q_OBJECT Q_OBJECT
public: public:
explicit SettingsGeneral(Settings* settings, QWidget* parent = 0); explicit SettingsGeneral(Settings* settings, QWidget* parent = 0);
virtual ~SettingsGeneral(); virtual ~SettingsGeneral();
inline QString title() const { inline QString title() const {
return tr("General"); return tr("General");
} }
void loadSettings(); void loadSettings();
void saveSettings();
private: void saveSettings();
Ui::SettingsGeneral* m_ui;
private:
Ui::SettingsGeneral* m_ui;
}; };
#endif // SETTINGSGENERAL_H #endif // SETTINGSGENERAL_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -17,239 +18,252 @@
#include "gui/settings/settingsgui.h" #include "gui/settings/settingsgui.h"
#include "gui/systemtrayicon.h"
#include "miscellaneous/settings.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
#include "gui/dialogs/formmain.h" #include "gui/dialogs/formmain.h"
#include "gui/tabwidget.h"
#include "gui/feedmessageviewer.h" #include "gui/feedmessageviewer.h"
#include "gui/feedstoolbar.h" #include "gui/feedstoolbar.h"
#include "gui/messagestoolbar.h" #include "gui/messagestoolbar.h"
#include "gui/statusbar.h" #include "gui/statusbar.h"
#include "gui/systemtrayicon.h"
#include "gui/tabwidget.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/settings.h"
#include <QDropEvent> #include <QDropEvent>
#include <QStyleFactory> #include <QStyleFactory>
SettingsGui::SettingsGui(Settings* settings, QWidget* parent) : SettingsPanel(settings, parent), m_ui(new Ui::SettingsGui) {
m_ui->setupUi(this);
m_ui->m_editorMessagesToolbar->activeItemsWidget()->viewport()->installEventFilter(this);
m_ui->m_editorFeedsToolbar->activeItemsWidget()->viewport()->installEventFilter(this);
m_ui->m_editorMessagesToolbar->availableItemsWidget()->viewport()->installEventFilter(this);
m_ui->m_editorFeedsToolbar->availableItemsWidget()->viewport()->installEventFilter(this);
m_ui->m_treeSkins->setColumnCount(4);
m_ui->m_treeSkins->setHeaderHidden(false);
m_ui->m_treeSkins->setHeaderLabels(QStringList()
<< /*: Skin list name column. */ tr("Name")
<< /*: Version column of skin list. */ tr("Version")
<< tr("Author")
<< tr("E-mail"));
SettingsGui::SettingsGui(Settings* settings, QWidget* parent) : SettingsPanel(settings, parent), m_ui(new Ui::SettingsGui) { // Setup skins.
m_ui->setupUi(this); m_ui->m_treeSkins->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
m_ui->m_editorMessagesToolbar->activeItemsWidget()->viewport()->installEventFilter(this); m_ui->m_treeSkins->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
m_ui->m_editorFeedsToolbar->activeItemsWidget()->viewport()->installEventFilter(this); m_ui->m_treeSkins->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
m_ui->m_editorMessagesToolbar->availableItemsWidget()->viewport()->installEventFilter(this); m_ui->m_treeSkins->header()->setSectionResizeMode(3, QHeaderView::ResizeToContents);
m_ui->m_editorFeedsToolbar->availableItemsWidget()->viewport()->installEventFilter(this); connect(m_ui->m_cmbIconTheme, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &SettingsGui::requireRestart);
m_ui->m_treeSkins->setColumnCount(4); connect(m_ui->m_cmbIconTheme, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
m_ui->m_treeSkins->setHeaderHidden(false); &SettingsGui::dirtifySettings);
m_ui->m_treeSkins->setHeaderLabels(QStringList() connect(m_ui->m_treeSkins, &QTreeWidget::currentItemChanged, this, &SettingsGui::dirtifySettings);
<< /*: Skin list name column. */ tr("Name") connect(m_ui->m_grpTray, &QGroupBox::toggled, this, &SettingsGui::dirtifySettings);
<< /*: Version column of skin list. */ tr("Version") connect(m_ui->m_checkEnableNotifications, &QCheckBox::toggled, this, &SettingsGui::dirtifySettings);
<< tr("Author") connect(m_ui->m_checkHidden, &QCheckBox::toggled, this, &SettingsGui::dirtifySettings);
<< tr("E-mail")); connect(m_ui->m_checkHideWhenMinimized, &QCheckBox::toggled, this, &SettingsGui::dirtifySettings);
// Setup skins. connect(m_ui->m_checkHideTabBarIfOneTabVisible, &QCheckBox::toggled, this, &SettingsGui::dirtifySettings);
m_ui->m_treeSkins->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); connect(m_ui->m_checkCloseTabsDoubleClick, &QCheckBox::toggled, this, &SettingsGui::dirtifySettings);
m_ui->m_treeSkins->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents); connect(m_ui->m_checkCloseTabsMiddleClick, &QCheckBox::toggled, this, &SettingsGui::dirtifySettings);
m_ui->m_treeSkins->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents); connect(m_ui->m_checkNewTabDoubleClick, &QCheckBox::toggled, this, &SettingsGui::dirtifySettings);
m_ui->m_treeSkins->header()->setSectionResizeMode(3, QHeaderView::ResizeToContents); connect(m_ui->m_grbCloseTabs, &QGroupBox::toggled, this, &SettingsGui::dirtifySettings);
connect(m_ui->m_cmbIconTheme, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &SettingsGui::requireRestart); connect(m_ui->m_cmbToolbarButtonStyle, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
connect(m_ui->m_cmbIconTheme, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &SettingsGui::dirtifySettings); &SettingsGui::dirtifySettings);
connect(m_ui->m_treeSkins, &QTreeWidget::currentItemChanged, this, &SettingsGui::dirtifySettings); connect(m_ui->m_editorFeedsToolbar, &ToolBarEditor::setupChanged, this, &SettingsGui::dirtifySettings);
connect(m_ui->m_grpTray, &QGroupBox::toggled, this, &SettingsGui::dirtifySettings); connect(m_ui->m_editorMessagesToolbar, &ToolBarEditor::setupChanged, this, &SettingsGui::dirtifySettings);
connect(m_ui->m_checkEnableNotifications, &QCheckBox::toggled, this, &SettingsGui::dirtifySettings); connect(m_ui->m_editorStatusbar, &ToolBarEditor::setupChanged, this, &SettingsGui::dirtifySettings);
connect(m_ui->m_checkHidden, &QCheckBox::toggled, this, &SettingsGui::dirtifySettings); connect(m_ui->m_listStyles, &QListWidget::currentItemChanged, this, &SettingsGui::dirtifySettings);
connect(m_ui->m_checkHideWhenMinimized, &QCheckBox::toggled, this, &SettingsGui::dirtifySettings); connect(m_ui->m_cmbSelectToolBar, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), m_ui->m_stackedToolbars,
connect(m_ui->m_checkHideTabBarIfOneTabVisible, &QCheckBox::toggled, this, &SettingsGui::dirtifySettings); &QStackedWidget::setCurrentIndex);
connect(m_ui->m_checkCloseTabsDoubleClick, &QCheckBox::toggled, this, &SettingsGui::dirtifySettings);
connect(m_ui->m_checkCloseTabsMiddleClick, &QCheckBox::toggled, this, &SettingsGui::dirtifySettings);
connect(m_ui->m_checkNewTabDoubleClick, &QCheckBox::toggled, this, &SettingsGui::dirtifySettings);
connect(m_ui->m_grbCloseTabs, &QGroupBox::toggled, this, &SettingsGui::dirtifySettings);
connect(m_ui->m_cmbToolbarButtonStyle, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
&SettingsGui::dirtifySettings);
connect(m_ui->m_editorFeedsToolbar, &ToolBarEditor::setupChanged, this, &SettingsGui::dirtifySettings);
connect(m_ui->m_editorMessagesToolbar, &ToolBarEditor::setupChanged, this, &SettingsGui::dirtifySettings);
connect(m_ui->m_editorStatusbar, &ToolBarEditor::setupChanged, this, &SettingsGui::dirtifySettings);
connect(m_ui->m_listStyles, &QListWidget::currentItemChanged, this, &SettingsGui::dirtifySettings);
connect(m_ui->m_cmbSelectToolBar, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), m_ui->m_stackedToolbars,
&QStackedWidget::setCurrentIndex);
} }
SettingsGui::~SettingsGui() { SettingsGui::~SettingsGui() {
delete m_ui; delete m_ui;
} }
bool SettingsGui::eventFilter(QObject* obj, QEvent* e) { bool SettingsGui::eventFilter(QObject* obj, QEvent* e) {
Q_UNUSED(obj) Q_UNUSED(obj)
if (e->type() == QEvent::Drop) { if (e->type() == QEvent::Drop) {
QDropEvent* drop_event = static_cast<QDropEvent*>(e); QDropEvent* drop_event = static_cast<QDropEvent*>(e);
if (drop_event->keyboardModifiers() != Qt::NoModifier) { if (drop_event->keyboardModifiers() != Qt::NoModifier) {
drop_event->setDropAction(Qt::MoveAction); drop_event->setDropAction(Qt::MoveAction);
} }
} }
return false; return false;
} }
void SettingsGui::loadSettings() { void SettingsGui::loadSettings() {
onBeginLoadSettings(); onBeginLoadSettings();
// Load settings of tray icon. // Load settings of tray icon.
if (SystemTrayIcon::isSystemTrayAvailable()) { if (SystemTrayIcon::isSystemTrayAvailable()) {
m_ui->m_grpTray->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_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()); // Tray icon is not supported on this machine.
m_ui->m_checkHideWhenMinimized->setChecked(settings()->value(GROUP(GUI), SETTING(GUI::HideMainWindowWhenMinimized)).toBool()); else {
// Load fancy notification settings. m_ui->m_grpTray->setTitle(m_ui->m_grpTray->title() + QL1C(' ') + tr("(Tray icon is not available.)"));
m_ui->m_checkEnableNotifications->setChecked(settings()->value(GROUP(GUI), SETTING(GUI::EnableNotifications)).toBool()); m_ui->m_grpTray->setChecked(false);
// Load settings of icon theme. }
const QString current_theme = qApp->icons()->currentIconTheme();
foreach (const QString& icon_theme_name, qApp->icons()->installedIconThemes()) { m_ui->m_checkHidden->setChecked(settings()->value(GROUP(GUI), SETTING(GUI::MainWindowStartsHidden)).toBool());
if (icon_theme_name == APP_NO_THEME) { m_ui->m_checkHideWhenMinimized->setChecked(settings()->value(GROUP(GUI), SETTING(GUI::HideMainWindowWhenMinimized)).toBool());
// Add just "no theme" on other systems.
//: Label for disabling icon theme.
m_ui->m_cmbIconTheme->addItem(tr("no icon theme/system icon theme"), APP_NO_THEME);
}
else {
m_ui->m_cmbIconTheme->addItem(icon_theme_name, icon_theme_name);
}
}
// Mark active theme. // Load fancy notification settings.
if (current_theme == QSL(APP_NO_THEME)) { m_ui->m_checkEnableNotifications->setChecked(settings()->value(GROUP(GUI), SETTING(GUI::EnableNotifications)).toBool());
// Because "no icon theme" lies at the index 0.
m_ui->m_cmbIconTheme->setCurrentIndex(0);
}
else {
m_ui->m_cmbIconTheme->setCurrentText(current_theme);
}
// Load skin. // Load settings of icon theme.
const QString selected_skin = qApp->skins()->selectedSkinName(); const QString current_theme = qApp->icons()->currentIconTheme();
foreach (const Skin& skin, qApp->skins()->installedSkins()) { foreach (const QString& icon_theme_name, qApp->icons()->installedIconThemes()) {
QTreeWidgetItem* new_item = new QTreeWidgetItem(QStringList() << if (icon_theme_name == APP_NO_THEME) {
skin.m_visibleName << // Add just "no theme" on other systems.
skin.m_version << //: Label for disabling icon theme.
skin.m_author << m_ui->m_cmbIconTheme->addItem(tr("no icon theme/system icon theme"), APP_NO_THEME);
skin.m_email); }
new_item->setData(0, Qt::UserRole, QVariant::fromValue(skin)); else {
// Add this skin and mark it as active if its active now. m_ui->m_cmbIconTheme->addItem(icon_theme_name, icon_theme_name);
m_ui->m_treeSkins->addTopLevelItem(new_item); }
}
if (skin.m_baseName == selected_skin) { // Mark active theme.
m_ui->m_treeSkins->setCurrentItem(new_item); if (current_theme == QSL(APP_NO_THEME)) {
} // Because "no icon theme" lies at the index 0.
} m_ui->m_cmbIconTheme->setCurrentIndex(0);
}
else {
m_ui->m_cmbIconTheme->setCurrentText(current_theme);
}
if (m_ui->m_treeSkins->currentItem() == nullptr && // Load skin.
m_ui->m_treeSkins->topLevelItemCount() > 0) { const QString selected_skin = qApp->skins()->selectedSkinName();
// Currently active skin is NOT available, select another one as selected
// if possible.
m_ui->m_treeSkins->setCurrentItem(m_ui->m_treeSkins->topLevelItem(0));
}
// Load styles. foreach (const Skin& skin, qApp->skins()->installedSkins()) {
foreach (const QString& style_name, QStyleFactory::keys()) { QTreeWidgetItem* new_item = new QTreeWidgetItem(QStringList() <<
m_ui->m_listStyles->addItem(style_name); skin.m_visibleName <<
} skin.m_version <<
skin.m_author <<
skin.m_email);
QList<QListWidgetItem*> items = m_ui->m_listStyles->findItems(settings()->value(GROUP(GUI), SETTING(GUI::Style)).toString(), new_item->setData(0, Qt::UserRole, QVariant::fromValue(skin));
Qt::MatchFixedString);
if (!items.isEmpty()) { // Add this skin and mark it as active if its active now.
m_ui->m_listStyles->setCurrentItem(items.at(0)); m_ui->m_treeSkins->addTopLevelItem(new_item);
}
// Load tab settings. if (skin.m_baseName == selected_skin) {
m_ui->m_checkCloseTabsMiddleClick->setChecked(settings()->value(GROUP(GUI), SETTING(GUI::TabCloseMiddleClick)).toBool()); m_ui->m_treeSkins->setCurrentItem(new_item);
m_ui->m_checkCloseTabsDoubleClick->setChecked(settings()->value(GROUP(GUI), SETTING(GUI::TabCloseDoubleClick)).toBool()); }
m_ui->m_checkNewTabDoubleClick->setChecked(settings()->value(GROUP(GUI), SETTING(GUI::TabNewDoubleClick)).toBool()); }
m_ui->m_checkHideTabBarIfOneTabVisible->setChecked(settings()->value(GROUP(GUI), SETTING(GUI::HideTabBarIfOnlyOneTab)).toBool());
// Load toolbar button style. if (m_ui->m_treeSkins->currentItem() == nullptr &&
m_ui->m_cmbToolbarButtonStyle->addItem(tr("Icon only"), Qt::ToolButtonIconOnly); m_ui->m_treeSkins->topLevelItemCount() > 0) {
m_ui->m_cmbToolbarButtonStyle->addItem(tr("Text only"), Qt::ToolButtonTextOnly); // Currently active skin is NOT available, select another one as selected
m_ui->m_cmbToolbarButtonStyle->addItem(tr("Text beside icon"), Qt::ToolButtonTextBesideIcon); // if possible.
m_ui->m_cmbToolbarButtonStyle->addItem(tr("Text under icon"), Qt::ToolButtonTextUnderIcon); m_ui->m_treeSkins->setCurrentItem(m_ui->m_treeSkins->topLevelItem(0));
m_ui->m_cmbToolbarButtonStyle->addItem(tr("Follow OS style"), Qt::ToolButtonFollowStyle); }
m_ui->m_cmbToolbarButtonStyle->setCurrentIndex(m_ui->m_cmbToolbarButtonStyle->findData(settings()->value(GROUP(GUI),
SETTING(GUI::ToolbarStyle)).toInt())); // Load styles.
// Load toolbars. foreach (const QString& style_name, QStyleFactory::keys()) {
m_ui->m_editorFeedsToolbar->loadFromToolBar(qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsToolBar()); m_ui->m_listStyles->addItem(style_name);
m_ui->m_editorMessagesToolbar->loadFromToolBar(qApp->mainForm()->tabWidget()->feedMessageViewer()->messagesToolBar()); }
m_ui->m_editorStatusbar->loadFromToolBar(qApp->mainForm()->statusBar());
onEndLoadSettings(); QList<QListWidgetItem*> items = m_ui->m_listStyles->findItems(settings()->value(GROUP(GUI), SETTING(GUI::Style)).toString(),
Qt::MatchFixedString);
if (!items.isEmpty()) {
m_ui->m_listStyles->setCurrentItem(items.at(0));
}
// Load tab settings.
m_ui->m_checkCloseTabsMiddleClick->setChecked(settings()->value(GROUP(GUI), SETTING(GUI::TabCloseMiddleClick)).toBool());
m_ui->m_checkCloseTabsDoubleClick->setChecked(settings()->value(GROUP(GUI), SETTING(GUI::TabCloseDoubleClick)).toBool());
m_ui->m_checkNewTabDoubleClick->setChecked(settings()->value(GROUP(GUI), SETTING(GUI::TabNewDoubleClick)).toBool());
m_ui->m_checkHideTabBarIfOneTabVisible->setChecked(settings()->value(GROUP(GUI), SETTING(GUI::HideTabBarIfOnlyOneTab)).toBool());
// Load toolbar button style.
m_ui->m_cmbToolbarButtonStyle->addItem(tr("Icon only"), Qt::ToolButtonIconOnly);
m_ui->m_cmbToolbarButtonStyle->addItem(tr("Text only"), Qt::ToolButtonTextOnly);
m_ui->m_cmbToolbarButtonStyle->addItem(tr("Text beside icon"), Qt::ToolButtonTextBesideIcon);
m_ui->m_cmbToolbarButtonStyle->addItem(tr("Text under icon"), Qt::ToolButtonTextUnderIcon);
m_ui->m_cmbToolbarButtonStyle->addItem(tr("Follow OS style"), Qt::ToolButtonFollowStyle);
m_ui->m_cmbToolbarButtonStyle->setCurrentIndex(m_ui->m_cmbToolbarButtonStyle->findData(settings()->value(GROUP(GUI),
SETTING(
GUI::ToolbarStyle)).toInt()));
// Load toolbars.
m_ui->m_editorFeedsToolbar->loadFromToolBar(qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsToolBar());
m_ui->m_editorMessagesToolbar->loadFromToolBar(qApp->mainForm()->tabWidget()->feedMessageViewer()->messagesToolBar());
m_ui->m_editorStatusbar->loadFromToolBar(qApp->mainForm()->statusBar());
onEndLoadSettings();
} }
void SettingsGui::saveSettings() { void SettingsGui::saveSettings() {
onBeginSaveSettings(); onBeginSaveSettings();
// Save toolbar.
settings()->setValue(GROUP(GUI), GUI::ToolbarStyle, m_ui->m_cmbToolbarButtonStyle->itemData(m_ui->m_cmbToolbarButtonStyle->currentIndex()));
// Save tray icon. // Save toolbar.
if (SystemTrayIcon::isSystemTrayAvailable()) { settings()->setValue(GROUP(GUI), GUI::ToolbarStyle,
settings()->setValue(GROUP(GUI), GUI::UseTrayIcon, m_ui->m_grpTray->isChecked()); m_ui->m_cmbToolbarButtonStyle->itemData(m_ui->m_cmbToolbarButtonStyle->currentIndex()));
if (m_ui->m_grpTray->isChecked()) { // Save tray icon.
qApp->showTrayIcon(); if (SystemTrayIcon::isSystemTrayAvailable()) {
} settings()->setValue(GROUP(GUI), GUI::UseTrayIcon, m_ui->m_grpTray->isChecked());
else {
qApp->deleteTrayIcon();
}
}
settings()->setValue(GROUP(GUI), GUI::MainWindowStartsHidden, m_ui->m_checkHidden->isChecked()); if (m_ui->m_grpTray->isChecked()) {
settings()->setValue(GROUP(GUI), GUI::HideMainWindowWhenMinimized, m_ui->m_checkHideWhenMinimized->isChecked()); qApp->showTrayIcon();
// Save notifications. }
settings()->setValue(GROUP(GUI), GUI::EnableNotifications, m_ui->m_checkEnableNotifications->isChecked()); else {
// Save selected icon theme. qApp->deleteTrayIcon();
QString selected_icon_theme = m_ui->m_cmbIconTheme->itemData(m_ui->m_cmbIconTheme->currentIndex()).toString(); }
QString original_icon_theme = qApp->icons()->currentIconTheme(); }
qApp->icons()->setCurrentIconTheme(selected_icon_theme);
// Check if icon theme was changed. settings()->setValue(GROUP(GUI), GUI::MainWindowStartsHidden, m_ui->m_checkHidden->isChecked());
if (selected_icon_theme != original_icon_theme) { settings()->setValue(GROUP(GUI), GUI::HideMainWindowWhenMinimized, m_ui->m_checkHideWhenMinimized->isChecked());
requireRestart();
}
// Save and activate new skin. // Save notifications.
if (!m_ui->m_treeSkins->selectedItems().isEmpty()) { settings()->setValue(GROUP(GUI), GUI::EnableNotifications, m_ui->m_checkEnableNotifications->isChecked());
const Skin active_skin = m_ui->m_treeSkins->currentItem()->data(0, Qt::UserRole).value<Skin>();
if (qApp->skins()->selectedSkinName() != active_skin.m_baseName) { // Save selected icon theme.
qApp->skins()->setCurrentSkinName(active_skin.m_baseName); QString selected_icon_theme = m_ui->m_cmbIconTheme->itemData(m_ui->m_cmbIconTheme->currentIndex()).toString();
requireRestart(); QString original_icon_theme = qApp->icons()->currentIconTheme();
}
}
// Set new style. qApp->icons()->setCurrentIconTheme(selected_icon_theme);
if (!m_ui->m_listStyles->selectedItems().isEmpty()) {
const QString new_style = m_ui->m_listStyles->currentItem()->text();
const QString old_style = qApp->settings()->value(GROUP(GUI), SETTING(GUI::Style)).toString();
if (old_style != new_style) { // Check if icon theme was changed.
requireRestart(); if (selected_icon_theme != original_icon_theme) {
} requireRestart();
}
qApp->settings()->setValue(GROUP(GUI), GUI::Style, new_style); // Save and activate new skin.
} if (!m_ui->m_treeSkins->selectedItems().isEmpty()) {
const Skin active_skin = m_ui->m_treeSkins->currentItem()->data(0, Qt::UserRole).value<Skin>();
// Save tab settings. if (qApp->skins()->selectedSkinName() != active_skin.m_baseName) {
settings()->setValue(GROUP(GUI), GUI::TabCloseMiddleClick, m_ui->m_checkCloseTabsMiddleClick->isChecked()); qApp->skins()->setCurrentSkinName(active_skin.m_baseName);
settings()->setValue(GROUP(GUI), GUI::TabCloseDoubleClick, m_ui->m_checkCloseTabsDoubleClick->isChecked()); requireRestart();
settings()->setValue(GROUP(GUI), GUI::TabNewDoubleClick, m_ui->m_checkNewTabDoubleClick->isChecked()); }
settings()->setValue(GROUP(GUI), GUI::HideTabBarIfOnlyOneTab, m_ui->m_checkHideTabBarIfOneTabVisible->isChecked()); }
m_ui->m_editorFeedsToolbar->saveToolBar();
m_ui->m_editorMessagesToolbar->saveToolBar(); // Set new style.
m_ui->m_editorStatusbar->saveToolBar(); if (!m_ui->m_listStyles->selectedItems().isEmpty()) {
qApp->mainForm()->tabWidget()->checkTabBarVisibility(); const QString new_style = m_ui->m_listStyles->currentItem()->text();
qApp->mainForm()->tabWidget()->feedMessageViewer()->refreshVisualProperties(); const QString old_style = qApp->settings()->value(GROUP(GUI), SETTING(GUI::Style)).toString();
onEndSaveSettings();
if (old_style != new_style) {
requireRestart();
}
qApp->settings()->setValue(GROUP(GUI), GUI::Style, new_style);
}
// Save tab settings.
settings()->setValue(GROUP(GUI), GUI::TabCloseMiddleClick, m_ui->m_checkCloseTabsMiddleClick->isChecked());
settings()->setValue(GROUP(GUI), GUI::TabCloseDoubleClick, m_ui->m_checkCloseTabsDoubleClick->isChecked());
settings()->setValue(GROUP(GUI), GUI::TabNewDoubleClick, m_ui->m_checkNewTabDoubleClick->isChecked());
settings()->setValue(GROUP(GUI), GUI::HideTabBarIfOnlyOneTab, m_ui->m_checkHideTabBarIfOneTabVisible->isChecked());
m_ui->m_editorFeedsToolbar->saveToolBar();
m_ui->m_editorMessagesToolbar->saveToolBar();
m_ui->m_editorStatusbar->saveToolBar();
qApp->mainForm()->tabWidget()->checkTabBarVisibility();
qApp->mainForm()->tabWidget()->feedMessageViewer()->refreshVisualProperties();
onEndSaveSettings();
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -22,27 +23,28 @@
#include "ui_settingsgui.h" #include "ui_settingsgui.h"
class SettingsGui : public SettingsPanel { class SettingsGui : public SettingsPanel {
Q_OBJECT Q_OBJECT
public: public:
explicit SettingsGui(Settings* settings, QWidget* parent = 0); explicit SettingsGui(Settings* settings, QWidget* parent = 0);
virtual ~SettingsGui(); virtual ~SettingsGui();
inline QString title() const { inline QString title() const {
return tr("User interface"); return tr("User interface");
} }
void loadSettings(); void loadSettings();
void saveSettings();
protected: void saveSettings();
// Does check of controls before dialog can be submitted.
bool eventFilter(QObject* obj, QEvent* e);
private: protected:
Ui::SettingsGui* m_ui;
// Does check of controls before dialog can be submitted.
bool eventFilter(QObject* obj, QEvent* e);
private:
Ui::SettingsGui* m_ui;
}; };
#endif // SETTINGSGUI_H #endif // SETTINGSGUI_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -17,70 +18,71 @@
#include "gui/settings/settingslocalization.h" #include "gui/settings/settingslocalization.h"
#include "miscellaneous/localization.h"
#include "miscellaneous/settings.h"
#include "miscellaneous/application.h" #include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h" #include "miscellaneous/iconfactory.h"
#include "miscellaneous/localization.h"
#include "miscellaneous/settings.h"
SettingsLocalization::SettingsLocalization(Settings* settings, QWidget* parent) SettingsLocalization::SettingsLocalization(Settings* settings, QWidget* parent)
: SettingsPanel(settings, parent), m_ui(new Ui::SettingsLocalization) { : SettingsPanel(settings, parent), m_ui(new Ui::SettingsLocalization) {
m_ui->setupUi(this); m_ui->setupUi(this);
m_ui->m_treeLanguages->setColumnCount(3); m_ui->m_treeLanguages->setColumnCount(3);
m_ui->m_treeLanguages->setHeaderHidden(false); m_ui->m_treeLanguages->setHeaderHidden(false);
m_ui->m_treeLanguages->setHeaderLabels(QStringList() m_ui->m_treeLanguages->setHeaderLabels(QStringList()
<< /*: Language column of language list. */ tr("Language") << /*: Language column of language list. */ tr("Language")
<< /*: Lang. code column of language list. */ tr("Code") << /*: Lang. code column of language list. */ tr("Code")
<< tr("Author")); << tr("Author"));
// Setup languages.
m_ui->m_treeLanguages->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); // Setup languages.
m_ui->m_treeLanguages->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents); m_ui->m_treeLanguages->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
m_ui->m_treeLanguages->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents); m_ui->m_treeLanguages->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
connect(m_ui->m_treeLanguages, &QTreeWidget::currentItemChanged, this, &SettingsLocalization::requireRestart); m_ui->m_treeLanguages->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
connect(m_ui->m_treeLanguages, &QTreeWidget::currentItemChanged, this, &SettingsLocalization::dirtifySettings); connect(m_ui->m_treeLanguages, &QTreeWidget::currentItemChanged, this, &SettingsLocalization::requireRestart);
connect(m_ui->m_treeLanguages, &QTreeWidget::currentItemChanged, this, &SettingsLocalization::dirtifySettings);
} }
SettingsLocalization::~SettingsLocalization() { SettingsLocalization::~SettingsLocalization() {
delete m_ui; delete m_ui;
} }
void SettingsLocalization::loadSettings() { void SettingsLocalization::loadSettings() {
onBeginLoadSettings(); onBeginLoadSettings();
foreach (const Language& language, qApp->localization()->installedLanguages()) { foreach (const Language& language, qApp->localization()->installedLanguages()) {
QTreeWidgetItem* item = new QTreeWidgetItem(m_ui->m_treeLanguages); QTreeWidgetItem* item = new QTreeWidgetItem(m_ui->m_treeLanguages);
item->setText(0, language.m_name);
item->setText(1, language.m_code);
item->setText(2, language.m_author);
item->setIcon(0, qApp->icons()->miscIcon(QString(FLAG_ICON_SUBFOLDER) + QDir::separator() + language.m_code));
}
m_ui->m_treeLanguages->sortByColumn(0, Qt::AscendingOrder); item->setText(0, language.m_name);
QList<QTreeWidgetItem*> matching_items = m_ui->m_treeLanguages->findItems(qApp->localization()->loadedLanguage(), Qt::MatchContains, 1); item->setText(1, language.m_code);
item->setText(2, language.m_author);
item->setIcon(0, qApp->icons()->miscIcon(QString(FLAG_ICON_SUBFOLDER) + QDir::separator() + language.m_code));
}
if (!matching_items.isEmpty()) { m_ui->m_treeLanguages->sortByColumn(0, Qt::AscendingOrder);
m_ui->m_treeLanguages->setCurrentItem(matching_items[0]); QList<QTreeWidgetItem*> matching_items = m_ui->m_treeLanguages->findItems(qApp->localization()->loadedLanguage(), Qt::MatchContains, 1);
}
onEndLoadSettings(); if (!matching_items.isEmpty()) {
m_ui->m_treeLanguages->setCurrentItem(matching_items[0]);
}
onEndLoadSettings();
} }
void SettingsLocalization::saveSettings() { void SettingsLocalization::saveSettings() {
onBeginSaveSettings(); onBeginSaveSettings();
if (m_ui->m_treeLanguages->currentItem() == nullptr) { if (m_ui->m_treeLanguages->currentItem() == nullptr) {
qDebug("No localizations loaded in settings dialog, so no saving for them."); qDebug("No localizations loaded in settings dialog, so no saving for them.");
return; return;
} }
const QString actual_lang = qApp->localization()->loadedLanguage(); const QString actual_lang = qApp->localization()->loadedLanguage();
const QString new_lang = m_ui->m_treeLanguages->currentItem()->text(1); const QString new_lang = m_ui->m_treeLanguages->currentItem()->text(1);
// Save prompt for restart if language has changed. // Save prompt for restart if language has changed.
if (new_lang != actual_lang) { if (new_lang != actual_lang) {
requireRestart(); requireRestart();
settings()->setValue(GROUP(General), General::Language, new_lang); settings()->setValue(GROUP(General), General::Language, new_lang);
} }
onEndSaveSettings(); onEndSaveSettings();
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -22,23 +23,23 @@
#include "ui_settingslocalization.h" #include "ui_settingslocalization.h"
class SettingsLocalization : public SettingsPanel { class SettingsLocalization : public SettingsPanel {
Q_OBJECT Q_OBJECT
public: public:
explicit SettingsLocalization(Settings* settings, QWidget* parent = 0); explicit SettingsLocalization(Settings* settings, QWidget* parent = 0);
virtual ~SettingsLocalization(); virtual ~SettingsLocalization();
inline QString title() const { inline QString title() const {
return tr("Language"); return tr("Language");
} }
void loadSettings(); void loadSettings();
void saveSettings();
private: void saveSettings();
Ui::SettingsLocalization* m_ui;
private:
Ui::SettingsLocalization* m_ui;
}; };
#endif // SETTINGSLOCALIZATION_H #endif // SETTINGSLOCALIZATION_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -19,55 +20,52 @@
#include "miscellaneous/settings.h" #include "miscellaneous/settings.h"
SettingsPanel::SettingsPanel(Settings* settings, QWidget* parent) SettingsPanel::SettingsPanel(Settings* settings, QWidget* parent)
: QWidget(parent), m_requiresRestart(false), m_isDirty(false), m_isLoading(false), m_settings(settings) { : QWidget(parent), m_requiresRestart(false), m_isDirty(false), m_isLoading(false), m_settings(settings) {}
}
void SettingsPanel::onBeginLoadSettings() { void SettingsPanel::onBeginLoadSettings() {
m_isLoading = true; m_isLoading = true;
} }
void SettingsPanel::onEndLoadSettings() { void SettingsPanel::onEndLoadSettings() {
m_isLoading = false; m_isLoading = false;
setRequiresRestart(false); setRequiresRestart(false);
setIsDirty(false); setIsDirty(false);
} }
void SettingsPanel::onBeginSaveSettings() { void SettingsPanel::onBeginSaveSettings() {}
}
void SettingsPanel::onEndSaveSettings() { void SettingsPanel::onEndSaveSettings() {
setIsDirty(false); setIsDirty(false);
} }
void SettingsPanel::dirtifySettings() { void SettingsPanel::dirtifySettings() {
if (!m_isLoading) { if (!m_isLoading) {
setIsDirty(true); setIsDirty(true);
emit settingsChanged(); emit settingsChanged();
} }
} }
bool SettingsPanel::requiresRestart() const { bool SettingsPanel::requiresRestart() const {
return m_requiresRestart; return m_requiresRestart;
} }
void SettingsPanel::setRequiresRestart(bool requiresRestart) { void SettingsPanel::setRequiresRestart(bool requiresRestart) {
m_requiresRestart = requiresRestart; m_requiresRestart = requiresRestart;
} }
void SettingsPanel::requireRestart() { void SettingsPanel::requireRestart() {
setRequiresRestart(true); setRequiresRestart(true);
} }
bool SettingsPanel::isDirty() const { bool SettingsPanel::isDirty() const {
return m_isDirty; return m_isDirty;
} }
void SettingsPanel::setIsDirty(bool is_dirty) { void SettingsPanel::setIsDirty(bool is_dirty) {
m_isDirty = is_dirty; m_isDirty = is_dirty;
} }
Settings* SettingsPanel::settings() const { Settings* SettingsPanel::settings() const {
return m_settings; return m_settings;
} }

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -20,50 +21,49 @@
#include <QWidget> #include <QWidget>
class Settings; class Settings;
class SettingsPanel : public QWidget { class SettingsPanel : public QWidget {
Q_OBJECT Q_OBJECT
public: public:
explicit SettingsPanel(Settings* settings, QWidget* parent = 0); explicit SettingsPanel(Settings* settings, QWidget* parent = 0);
virtual QString title() const = 0; virtual QString title() const = 0;
virtual void loadSettings() = 0;
virtual void saveSettings() = 0;
virtual void loadSettings() = 0; bool requiresRestart() const;
virtual void saveSettings() = 0; bool isDirty() const;
bool requiresRestart() const; void setIsDirty(bool is_dirty);
bool isDirty() const; void setRequiresRestart(bool requiresRestart);
void setIsDirty(bool is_dirty); protected:
void setRequiresRestart(bool requiresRestart); void onBeginLoadSettings();
void onEndLoadSettings();
void onBeginSaveSettings();
void onEndSaveSettings();
protected: // Settings to use to save/load.
void onBeginLoadSettings(); Settings* settings() const;
void onEndLoadSettings();
void onBeginSaveSettings();
void onEndSaveSettings();
// Settings to use to save/load. protected slots:
Settings* settings() const;
protected slots: // Sets this settings panel as dirty (some settings are changed) and emits the signal.
// Sets this settings panel as dirty (some settings are changed) and emits the signal. // NOTE: This will be probably called by subclasses when user changes some stuff.
// NOTE: This will be probably called by subclasses when user changes some stuff. void dirtifySettings();
void dirtifySettings();
void requireRestart(); void requireRestart();
signals: signals:
void settingsChanged(); void settingsChanged();
private: private:
bool m_requiresRestart; bool m_requiresRestart;
bool m_isDirty; bool m_isDirty;
bool m_isLoading; bool m_isLoading;
Settings* m_settings; Settings* m_settings;
}; };
#endif // SETTINGSPANEL_H #endif // SETTINGSPANEL_H

View file

@ -1,4 +1,5 @@
// This file is part of RSS Guard. // This file is part of RSS Guard.
// //
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com> // Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
// //
@ -17,29 +18,28 @@
#include "gui/settings/settingsshortcuts.h" #include "gui/settings/settingsshortcuts.h"
#include "miscellaneous/application.h"
#include "dynamic-shortcuts/dynamicshortcuts.h" #include "dynamic-shortcuts/dynamicshortcuts.h"
#include "miscellaneous/application.h"
SettingsShortcuts::SettingsShortcuts(Settings* settings, QWidget* parent) SettingsShortcuts::SettingsShortcuts(Settings* settings, QWidget* parent)
: SettingsPanel(settings, parent), m_ui(new Ui::SettingsShortcuts) { : SettingsPanel(settings, parent), m_ui(new Ui::SettingsShortcuts) {
m_ui->setupUi(this); m_ui->setupUi(this);
connect(m_ui->m_shortcuts, &DynamicShortcutsWidget::setupChanged, this, &SettingsShortcuts::dirtifySettings); connect(m_ui->m_shortcuts, &DynamicShortcutsWidget::setupChanged, this, &SettingsShortcuts::dirtifySettings);
} }
SettingsShortcuts::~SettingsShortcuts() { SettingsShortcuts::~SettingsShortcuts() {
delete m_ui; delete m_ui;
} }
void SettingsShortcuts::loadSettings() { void SettingsShortcuts::loadSettings() {
onBeginLoadSettings(); onBeginLoadSettings();
m_ui->m_shortcuts->populate(qApp->userActions()); m_ui->m_shortcuts->populate(qApp->userActions());
onEndLoadSettings(); onEndLoadSettings();
} }
void SettingsShortcuts::saveSettings() { void SettingsShortcuts::saveSettings() {
onBeginSaveSettings(); onBeginSaveSettings();
m_ui->m_shortcuts->updateShortcuts(); m_ui->m_shortcuts->updateShortcuts();
DynamicShortcuts::save(qApp->userActions()); DynamicShortcuts::save(qApp->userActions());
onEndSaveSettings(); onEndSaveSettings();
} }

Some files were not shown because too many files have changed in this diff Show more