Finalized uncrustify config, will reformat it all.

This commit is contained in:
Martin Rotter 2017-09-19 09:02:51 +02:00
parent 7b62a456a6
commit dd4a96f51f
15 changed files with 2304 additions and 1986 deletions

View File

@ -3,6 +3,10 @@
set FOR foreach set FOR foreach
set FOR forever set FOR forever
# SIGNAL/SLOT Qt macros have special formatting options. See options_for_QT.cpp for details.
# Default=True
use_options_overriding_for_qt_macros = true # false/true
## General. ## General.
newlines = auto # auto/lf/crlf/cr newlines = auto # auto/lf/crlf/cr
@ -13,10 +17,270 @@ input_tab_size = 2 # number
# The size of tabs in the output (only used if align_with_tabs=true) # The size of tabs in the output (only used if align_with_tabs=true)
output_tab_size = 2 # number output_tab_size = 2 # number
# Control what to do with the UTF-8 BOM (recommend 'remove')
utf8_bom = remove # ignore/add/remove/force
## Spaces. ## Spaces.
# Add or remove space around arithmetic operator '+', '-', '/', '*', etc
# also '>>>' '<<' '>>' '%' '|'
sp_arith = force # ignore/add/remove/force
# Add or remove space around assignment operator '=', '+=', etc
sp_assign = force # ignore/add/remove/force
# Add or remove space after ','
sp_after_comma = force # ignore/add/remove/force
# Add or remove space around '=' in C++11 lambda capture specifications. Overrides sp_assign
sp_cpp_lambda_assign = remove # ignore/add/remove/force
# Add or remove space after the capture specification in C++11 lambda.
sp_cpp_lambda_paren = remove # ignore/add/remove/force
# Add or remove space around assignment operator '=' in a prototype
sp_assign_default = force # ignore/add/remove/force
# Add or remove space around assignment '=' in enum
sp_enum_assign = force # ignore/add/remove/force
# Add or remove space before pointer star '*'
sp_before_ptr_star = remove # ignore/add/remove/force
# Add or remove space before pointer star '*' that isn't followed by a variable name
# If set to 'ignore', sp_before_ptr_star is used instead.
sp_before_unnamed_ptr_star = remove # ignore/add/remove/force
# Add or remove space between pointer stars '*'
sp_between_ptr_star = remove # ignore/add/remove/force
# Add or remove space after pointer star '*', if followed by a word.
sp_after_ptr_star = force # ignore/add/remove/force
# Add or remove space after pointer star '*', if followed by a qualifier.
sp_after_ptr_star_qualifier = force # ignore/add/remove/force
# Add or remove space after a pointer star '*', if followed by a func proto/def.
sp_after_ptr_star_func = force # ignore/add/remove/force
# Add or remove space after a pointer star '*', if followed by an open paren (function types).
sp_ptr_star_paren = force # ignore/add/remove/force
# Add or remove space before a pointer star '*', if followed by a func proto/def.
sp_before_ptr_star_func = remove # ignore/add/remove/force
# Add or remove space before a reference sign '&'
sp_before_byref = remove # ignore/add/remove/force
# Add or remove space before a reference sign '&' that isn't followed by a variable name
# If set to 'ignore', sp_before_byref is used instead.
sp_before_unnamed_byref = remove # ignore/add/remove/force
# Add or remove space after reference sign '&', if followed by a word.
sp_after_byref = force # ignore/add/remove/force
# Add or remove space after a reference sign '&', if followed by a func proto/def.
sp_after_byref_func = force # ignore/add/remove/force
# Add or remove space before a reference sign '&', if followed by a func proto/def.
sp_before_byref_func = remove # ignore/add/remove/force
# Add or remove space between '>' and '>' in '>>' (template stuff C++/C# only). Default=Add
sp_angle_shift = remove # ignore/add/remove/force
# Permit removal of the space between '>>' in 'foo<bar<int> >' (C++11 only). Default=False
# sp_angle_shift cannot remove the space without this option.
sp_permit_cpp11_shift = true # false/true
## Indents. ## Indents.
# The number of columns to indent per level.
# Usually 2, 3, 4, or 8. Default=8
indent_columns = 2 # unsigned number
# How to use tabs when indenting code
# 0=spaces only
# 1=indent with tabs to brace level, align with spaces (default)
# 2=indent and align with tabs, using spaces when not on a tabstop
indent_with_tabs = 0 # number
# Whether to indent strings broken by '\' so that they line up
indent_align_string = true # false/true
# Whether the 'namespace' body is indented
indent_namespace = true # false/true
# Whether the 'class' body is indented
indent_class = true # false/true
# Same as indent_label, but for access specifiers that are followed by a colon. Default=1
indent_access_spec = 2 # number
# Indent the code after an access specifier by one level.
# If set, this option forces 'indent_access_spec=0'
indent_access_spec_body = true # false/true
# Spaces to indent 'case' from 'switch'
# Usually 0 or indent_columns.
indent_switch_case = 2 # unsigned number
# indent the continuation of ternary operator.
# 0: (Default) off
# 1: When the `if_false` is a continuation, indent it under `if_false`
# 2: When the `:` is a continuation, indent it under `?`
indent_ternary_operator = 2 # unsigned number
## Newlines.
# Whether to collapse empty blocks between '{' and '}'
nl_collapse_empty_body = true # false/true
# Add or remove newlines at the start of the file
nl_start_of_file = remove # ignore/add/remove/force
# The number of blank lines after a block of variable definitions at the top of a function body
# 0 = No change (default)
nl_func_var_def_blk = 1 # unsigned number
# The number of newlines before a block of typedefs
# 0 = No change (default)
# the option 'nl_after_access_spec' takes preference over 'nl_typedef_blk_start'
nl_typedef_blk_start = 2 # unsigned number
# The number of newlines after a block of typedefs
# 0 = No change (default)
nl_typedef_blk_end = 2 # unsigned number
# The maximum consecutive newlines within a block of typedefs
# 0 = No change (default)
nl_typedef_blk_in = 2 # unsigned number
# The number of newlines after a block of variable definitions not at the top of a function body
# 0 = No change (default)
nl_var_def_blk_end = 2 # unsigned number
# The maximum consecutive newlines within a block of variable definitions
# 0 = No change (default)
nl_var_def_blk_in = 1 # unsigned number
# Add or remove newline between 'enum' and '{'
nl_enum_brace = remove # ignore/add/remove/force
# Add or remove newline between 'enum' and 'class'
nl_enum_class = remove # ignore/add/remove/force
# Add or remove newline between 'enum class' and the identifier
nl_enum_class_identifier = remove # ignore/add/remove/force
# Add or remove newline between 'if' and '{'
nl_if_brace = remove # ignore/add/remove/force
# Add or remove newline between '}' and 'else'
nl_brace_else = force # ignore/add/remove/force
# Add or remove newline between 'else' and '{'
nl_else_brace = remove # ignore/add/remove/force
# Add or remove newline between 'else' and 'if'
nl_else_if = remove # ignore/add/remove/force
# Add or remove newline before 'if'/'else if' closing parenthesis
nl_before_if_closing_paren = remove # ignore/add/remove/force
# Whether to put a newline after 'case' statement
nl_after_case = false # false/true
# Whether to put a newline before 'case' statement, not after the first 'case'
nl_before_case = true # false/true
# Whether to remove blanks after '#ifxx' and '#elxx', or before '#elxx' and '#endif'. Does not affect top-level #ifdefs.
nl_squeeze_ifdef = true # false/true
# Add or remove blank line after 'if' statement.
# Add/Force work only if the next token is not a closing brace
nl_after_if = force # ignore/add/remove/force
# Add or remove blank line after 'for' statement
nl_after_for = force # ignore/add/remove/force
# Add or remove blank line after 'while' statement
nl_after_while = force # ignore/add/remove/force
# Add or remove blank line after 'switch' statement
nl_after_switch = force # ignore/add/remove/force
# Add or remove blank line after 'do/while' statement
nl_after_do = force # ignore/add/remove/force
## Blank line options
# The maximum consecutive newlines (3 = 2 blank lines)
nl_max = 2 # unsigned number
# The minimum number of newlines before a multi-line comment.
# Doesn't apply if after a brace open or another multi-line comment.
nl_before_block_comment = 2 # unsigned number
# The minimum number of newlines before a single-line C comment.
# Doesn't apply if after a brace open or other single-line C comments.
nl_before_c_comment = 2 # unsigned number
# The minimum number of newlines before a CPP comment.
# Doesn't apply if after a brace open or other CPP comments.
nl_before_cpp_comment = 2 # unsigned number
# The number of newlines before a class definition
nl_before_class = 2 # unsigned number
# The number of newlines after '}' or ';' of a class definition
nl_after_class = 2 # unsigned number
# The number of newlines after '}' of a multi-line function body
nl_after_func_body = 2 # unsigned number
# The number of newlines after '}' of a multi-line function body in a class declaration
nl_after_func_body_class = 2 # unsigned number
# The number of newlines after '}' of a single line function body
nl_after_func_body_one_liner = 2 # unsigned number
# The number of newlines before a 'private:', 'public:', 'protected:', 'signals:', or 'slots:' label.
# Will not change the newline count if after a brace open.
# 0 = No change.
nl_before_access_spec = 2 # unsigned number
# The number of newlines after a try-catch-finally block that isn't followed by a brace close.
# 0 = No change.
nl_after_try_catch_finally = 2 # unsigned number
# How aggressively to remove extra newlines not in preproc.
# 0: No change
# 1: Remove most newlines not handled by other config
# 2: Remove all newlines and reformat completely by config
nl_remove_extra_newlines = 0 # unsigned number
## Splitting.
# Try to limit code width to N number of columns
code_width = 140 # unsigned number
# Whether to fully split long function protos/calls at commas
ls_func_split_full = true # false/true
## Comments.
# Set the comment reflow mode (Default=0)
# 0: no reflowing (apart from the line wrapping due to cmt_width)
# 1: no touching at all
# 2: full reflow
cmt_reflow_mode = 2 # number
# Whether to convert all tabs to spaces in comments. Default is to leave tabs inside comments alone, unless used for indenting.
cmt_convert_tab_to_spaces = true # false/true
# Whether to group c-comments that look like they are in a block
cmt_c_group = true # false/true
## Modifications. ## Modifications.
# If True, will sort consecutive single-line '#include' statements [C/C++] and '#import' statements [Obj-C] # If True, will sort consecutive single-line '#include' statements [C/C++] and '#import' statements [Obj-C]

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,525 +19,546 @@
#include "core/feedsmodel.h" #include "core/feedsmodel.h"
#include "definitions/definitions.h" #include "definitions/definitions.h"
#include "services/abstract/feed.h" #include "miscellaneous/databasefactory.h"
#include "miscellaneous/feedreader.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/textfactory.h"
#include "services/abstract/category.h" #include "services/abstract/category.h"
#include "services/abstract/serviceroot.h" #include "services/abstract/feed.h"
#include "services/abstract/recyclebin.h" #include "services/abstract/recyclebin.h"
#include "services/abstract/serviceentrypoint.h" #include "services/abstract/serviceentrypoint.h"
#include "services/abstract/serviceroot.h"
#include "services/standard/standardserviceentrypoint.h" #include "services/standard/standardserviceentrypoint.h"
#include "services/standard/standardserviceroot.h" #include "services/standard/standardserviceroot.h"
#include "miscellaneous/textfactory.h"
#include "miscellaneous/databasefactory.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/feedreader.h"
#include <QMimeData>
#include <QPair>
#include <QSqlError> #include <QSqlError>
#include <QSqlRecord> #include <QSqlRecord>
#include <QPair>
#include <QStack> #include <QStack>
#include <QMimeData>
#include <QTimer> #include <QTimer>
#include <algorithm> #include <algorithm>
FeedsModel::FeedsModel(QObject* parent) : QAbstractItemModel(parent) { FeedsModel::FeedsModel(QObject* parent) : QAbstractItemModel(parent) {
setObjectName(QSL("FeedsModel")); setObjectName(QSL("FeedsModel"));
// Create root item.
m_rootItem = new RootItem(); // Create root item.
// : Name of root item of feed list which can be seen in feed add/edit dialog. m_rootItem = new RootItem();
m_rootItem->setTitle(tr("Root"));
m_rootItem->setIcon(qApp->icons()->fromTheme(QSL("folder"))); // : Name of root item of feed list which can be seen in feed add/edit dialog.
// Setup icons. m_rootItem->setTitle(tr("Root"));
m_countsIcon = qApp->icons()->fromTheme(QSL("mail-mark-unread")); m_rootItem->setIcon(qApp->icons()->fromTheme(QSL("folder")));
// : Title text in the feed list header.
m_headerData << tr("Title"); // Setup icons.
m_tooltipData << /*: Feed list header "titles" column tooltip.*/ tr("Titles of feeds/categories.") m_countsIcon = qApp->icons()->fromTheme(QSL("mail-mark-unread"));
<< /*: Feed list header "counts" column tooltip.*/ tr("Counts of unread/all mesages.");
// : Title text in the feed list header.
m_headerData << tr("Title");
m_tooltipData << /*: Feed list header "titles" column tooltip.*/ tr("Titles of feeds/categories.") <<
/*: Feed list header "counts" column tooltip.*/ tr("Counts of unread/all mesages.");
} }
FeedsModel::~FeedsModel() { FeedsModel::~FeedsModel() {
qDebug("Destroying FeedsModel instance."); qDebug("Destroying FeedsModel instance.");
// Delete all model items.
delete m_rootItem; // Delete all model items.
delete m_rootItem;
} }
QMimeData* FeedsModel::mimeData(const QModelIndexList& indexes) const { QMimeData* FeedsModel::mimeData(const QModelIndexList& indexes) const {
QMimeData* mime_data = new QMimeData(); QMimeData* mime_data = new QMimeData();
QByteArray encoded_data; QByteArray encoded_data;
QDataStream stream(&encoded_data, QIODevice::WriteOnly); QDataStream stream(&encoded_data, QIODevice::WriteOnly);
foreach (const QModelIndex& index, indexes) { foreach (const QModelIndex& index, indexes) {
if (index.column() != 0) { if (index.column() != 0) {
continue; continue;
} }
RootItem* item_for_index = itemForIndex(index); RootItem* item_for_index = itemForIndex(index);
if (item_for_index->kind() != RootItemKind::Root) { if (item_for_index->kind() != RootItemKind::Root) {
stream << (quintptr) item_for_index; stream << (quintptr) item_for_index;
} }
} }
mime_data->setData(QSL(MIME_TYPE_ITEM_POINTER), encoded_data); mime_data->setData(QSL(MIME_TYPE_ITEM_POINTER), encoded_data);
return mime_data;
return mime_data;
} }
QStringList FeedsModel::mimeTypes() const { QStringList FeedsModel::mimeTypes() const {
return QStringList() << QSL(MIME_TYPE_ITEM_POINTER); return QStringList() << QSL(MIME_TYPE_ITEM_POINTER);
} }
bool FeedsModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) { bool FeedsModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column,
Q_UNUSED(row) const QModelIndex& parent) {
Q_UNUSED(column) Q_UNUSED(row)
Q_UNUSED(column)
if (action == Qt::IgnoreAction) { if (action == Qt::IgnoreAction) {
return true; return true;
} }
else if (action != Qt::MoveAction) { else if (action != Qt::MoveAction) {
return false; return false;
} }
QByteArray dragged_items_data = data->data(QSL(MIME_TYPE_ITEM_POINTER)); QByteArray dragged_items_data = data->data(QSL(MIME_TYPE_ITEM_POINTER));
if (dragged_items_data.isEmpty()) { if (dragged_items_data.isEmpty()) {
return false; return false;
} }
else { else {
QDataStream stream(&dragged_items_data, QIODevice::ReadOnly); QDataStream stream(&dragged_items_data, QIODevice::ReadOnly);
while (!stream.atEnd()) { while (!stream.atEnd()) {
quintptr pointer_to_item; quintptr pointer_to_item; stream >> pointer_to_item;
stream >> pointer_to_item;
// We have item we want to drag, we also determine the target item.
RootItem* dragged_item = (RootItem*) pointer_to_item;
RootItem* target_item = itemForIndex(parent);
ServiceRoot* dragged_item_root = dragged_item->getParentServiceRoot();
ServiceRoot* target_item_root = target_item->getParentServiceRoot();
if (dragged_item == target_item || dragged_item->parent() == target_item) { // We have item we want to drag, we also determine the target item.
qDebug("Dragged item is equal to target item or its parent is equal to target item. Cancelling drag-drop action."); RootItem* dragged_item = (RootItem*) pointer_to_item;
return false; RootItem* target_item = itemForIndex(parent);
} ServiceRoot* dragged_item_root = dragged_item->getParentServiceRoot();
ServiceRoot* target_item_root = target_item->getParentServiceRoot();
if (dragged_item_root != target_item_root) { if (dragged_item == target_item || dragged_item->parent() == target_item) {
// Transferring of items between different accounts is not possible. qDebug("Dragged item is equal to target item or its parent is equal to target item. Cancelling drag-drop action.");
qApp->showGuiMessage(tr("Cannot perform drag & drop operation"), return false;
tr("You can't transfer dragged item into different account, this is not supported."), }
QSystemTrayIcon::Warning,
qApp->mainFormWidget(),
true);
qDebug("Dragged item cannot be dragged into different account. Cancelling drag-drop action.");
return false;
}
if (dragged_item->performDragDropChange(target_item)) { if (dragged_item_root != target_item_root) {
// Drag & drop is supported by the dragged item and was // Transferring of items between different accounts is not possible.
// completed on data level and in item hierarchy. qApp->showGuiMessage(tr("Cannot perform drag & drop operation"),
emit requireItemValidationAfterDragDrop(indexForItem(dragged_item)); tr("You can't transfer dragged item into different account, this is not supported."),
} QSystemTrayIcon::Warning,
} qApp->mainFormWidget(),
true);
qDebug("Dragged item cannot be dragged into different account. Cancelling drag-drop action.");
return false;
}
return true; if (dragged_item->performDragDropChange(target_item)) {
} // Drag & drop is supported by the dragged item and was
// completed on data level and in item hierarchy.
emit requireItemValidationAfterDragDrop(indexForItem(dragged_item));
}
}
return false; return true;
}
return false;
} }
Qt::DropActions FeedsModel::supportedDropActions() const { Qt::DropActions FeedsModel::supportedDropActions() const {
return Qt::MoveAction; return Qt::MoveAction;
} }
Qt::ItemFlags FeedsModel::flags(const QModelIndex& index) const { Qt::ItemFlags FeedsModel::flags(const QModelIndex& index) const {
Qt::ItemFlags base_flags = QAbstractItemModel::flags(index); const RootItem* item_for_index = itemForIndex(index);
const RootItem* item_for_index = itemForIndex(index);
Qt::ItemFlags additional_flags = item_for_index->additionalFlags(); Qt::ItemFlags base_flags = QAbstractItemModel::flags(index);
return base_flags | additional_flags; Qt::ItemFlags additional_flags = item_for_index->additionalFlags();
return base_flags | additional_flags;
} }
QVariant FeedsModel::headerData(int section, Qt::Orientation orientation, int role) const { QVariant FeedsModel::headerData(int section, Qt::Orientation orientation, int role) const {
if (orientation != Qt::Horizontal) { if (orientation != Qt::Horizontal) {
return QVariant(); return QVariant();
} }
switch (role) { switch (role) {
case Qt::DisplayRole: case Qt::DisplayRole:
if (section == FDS_MODEL_TITLE_INDEX) { if (section == FDS_MODEL_TITLE_INDEX) {
return m_headerData.at(FDS_MODEL_TITLE_INDEX); return m_headerData.at(FDS_MODEL_TITLE_INDEX);
} }
else { else {
return QVariant(); return QVariant();
} }
case Qt::ToolTipRole: case Qt::ToolTipRole:
return m_tooltipData.at(section); return m_tooltipData.at(section);
case Qt::DecorationRole: case Qt::DecorationRole:
if (section == FDS_MODEL_COUNTS_INDEX) { if (section == FDS_MODEL_COUNTS_INDEX) {
return m_countsIcon; return m_countsIcon;
} }
else { else {
return QVariant(); return QVariant();
} }
default: default:
return QVariant(); return QVariant();
} }
} }
QModelIndex FeedsModel::index(int row, int column, const QModelIndex& parent) const { QModelIndex FeedsModel::index(int row, int column, const QModelIndex& parent) const {
if (!hasIndex(row, column, parent)) { if (!hasIndex(row, column, parent)) {
return QModelIndex(); return QModelIndex();
} }
RootItem* parent_item = itemForIndex(parent); RootItem* parent_item = itemForIndex(parent);
RootItem* child_item = parent_item->child(row); RootItem* child_item = parent_item->child(row);
if (child_item) { if (child_item) {
return createIndex(row, column, child_item); return createIndex(row, column, child_item);
} }
else { else {
return QModelIndex(); return QModelIndex();
} }
} }
QModelIndex FeedsModel::parent(const QModelIndex& child) const { QModelIndex FeedsModel::parent(const QModelIndex& child) const {
if (!child.isValid()) { if (!child.isValid()) {
return QModelIndex(); return QModelIndex();
} }
RootItem* child_item = itemForIndex(child); RootItem* child_item = itemForIndex(child);
RootItem* parent_item = child_item->parent(); RootItem* parent_item = child_item->parent();
if (parent_item == m_rootItem) { if (parent_item == m_rootItem) {
return QModelIndex(); return QModelIndex();
} }
else { else {
return createIndex(parent_item->row(), 0, parent_item); return createIndex(parent_item->row(), 0, parent_item);
} }
} }
int FeedsModel::rowCount(const QModelIndex& parent) const { int FeedsModel::rowCount(const QModelIndex& parent) const {
if (parent.column() > 0) { if (parent.column() > 0) {
return 0; return 0;
} }
else { else {
return itemForIndex(parent)->childCount(); return itemForIndex(parent)->childCount();
} }
} }
int FeedsModel::countOfAllMessages() const { int FeedsModel::countOfAllMessages() const {
return m_rootItem->countOfAllMessages(); return m_rootItem->countOfAllMessages();
} }
int FeedsModel::countOfUnreadMessages() const { int FeedsModel::countOfUnreadMessages() const {
return m_rootItem->countOfUnreadMessages(); return m_rootItem->countOfUnreadMessages();
} }
void FeedsModel::reloadCountsOfWholeModel() { void FeedsModel::reloadCountsOfWholeModel() {
m_rootItem->updateCounts(true); m_rootItem->updateCounts(true);
reloadWholeLayout(); reloadWholeLayout();
notifyWithCounts(); notifyWithCounts();
} }
void FeedsModel::removeItem(const QModelIndex& index) { void FeedsModel::removeItem(const QModelIndex& index) {
if (index.isValid()) { if (index.isValid()) {
RootItem* deleting_item = itemForIndex(index); RootItem* deleting_item = itemForIndex(index);
QModelIndex parent_index = index.parent(); QModelIndex parent_index = index.parent();
RootItem* parent_item = deleting_item->parent(); RootItem* parent_item = deleting_item->parent();
beginRemoveRows(parent_index, index.row(), index.row());
parent_item->removeChild(deleting_item); beginRemoveRows(parent_index, index.row(), index.row());
endRemoveRows(); parent_item->removeChild(deleting_item);
deleting_item->deleteLater(); endRemoveRows();
notifyWithCounts(); deleting_item->deleteLater();
} notifyWithCounts();
}
} }
void FeedsModel::removeItem(RootItem* deleting_item) { void FeedsModel::removeItem(RootItem* deleting_item) {
if (deleting_item != nullptr) { if (deleting_item != nullptr) {
QModelIndex index = indexForItem(deleting_item); QModelIndex index = indexForItem(deleting_item);
QModelIndex parent_index = index.parent(); QModelIndex parent_index = index.parent();
RootItem* parent_item = deleting_item->parent(); RootItem* parent_item = deleting_item->parent();
beginRemoveRows(parent_index, index.row(), index.row());
parent_item->removeChild(deleting_item); beginRemoveRows(parent_index, index.row(), index.row());
endRemoveRows(); parent_item->removeChild(deleting_item);
deleting_item->deleteLater(); endRemoveRows();
notifyWithCounts(); deleting_item->deleteLater();
} notifyWithCounts();
}
} }
void FeedsModel::reassignNodeToNewParent(RootItem* original_node, RootItem* new_parent) { void FeedsModel::reassignNodeToNewParent(RootItem* original_node, RootItem* new_parent) {
RootItem* original_parent = original_node->parent(); RootItem* original_parent = original_node->parent();
if (original_parent != new_parent) { if (original_parent != new_parent) {
if (original_parent != nullptr) { if (original_parent != nullptr) {
int original_index_of_item = original_parent->childItems().indexOf(original_node); int original_index_of_item = original_parent->childItems().indexOf(original_node);
if (original_index_of_item >= 0) { if (original_index_of_item >= 0) {
// Remove the original item from the model... // Remove the original item from the model...
beginRemoveRows(indexForItem(original_parent), original_index_of_item, original_index_of_item); beginRemoveRows(indexForItem(original_parent), original_index_of_item, original_index_of_item);
original_parent->removeChild(original_node); original_parent->removeChild(original_node);
endRemoveRows(); endRemoveRows();
} }
} }
int new_index_of_item = new_parent->childCount(); int new_index_of_item = new_parent->childCount();
// ... and insert it under the new parent.
beginInsertRows(indexForItem(new_parent), new_index_of_item, new_index_of_item); // ... and insert it under the new parent.
new_parent->appendChild(original_node); beginInsertRows(indexForItem(new_parent), new_index_of_item, new_index_of_item);
endInsertRows(); new_parent->appendChild(original_node);
} endInsertRows();
}
} }
QList<ServiceRoot*>FeedsModel::serviceRoots() const { QList<ServiceRoot*>FeedsModel::serviceRoots() const {
QList<ServiceRoot*>roots; QList<ServiceRoot*>roots;
foreach (RootItem* root, m_rootItem->childItems()) { foreach (RootItem* root, m_rootItem->childItems()) {
if (root->kind() == RootItemKind::ServiceRoot) { if (root->kind() == RootItemKind::ServiceRoot) {
roots.append(root->toServiceRoot()); roots.append(root->toServiceRoot());
} }
} }
return roots; return roots;
} }
bool FeedsModel::containsServiceRootFromEntryPoint(const ServiceEntryPoint* point) const { bool FeedsModel::containsServiceRootFromEntryPoint(const ServiceEntryPoint* point) const {
foreach (const ServiceRoot* root, serviceRoots()) { foreach (const ServiceRoot* root, serviceRoots()) {
if (root->code() == point->code()) { if (root->code() == point->code()) {
return true; return true;
} }
} }
return false; return false;
} }
StandardServiceRoot* FeedsModel::standardServiceRoot() const { StandardServiceRoot* FeedsModel::standardServiceRoot() const {
foreach (ServiceRoot* root, serviceRoots()) { foreach (ServiceRoot* root, serviceRoots()) {
StandardServiceRoot* std_service_root; StandardServiceRoot* std_service_root;
if ((std_service_root = dynamic_cast<StandardServiceRoot*>(root)) != nullptr) { if ((std_service_root = dynamic_cast<StandardServiceRoot*>(root)) != nullptr) {
return std_service_root; return std_service_root;
} }
} }
return nullptr; return nullptr;
} }
QList<Feed*>FeedsModel::feedsForScheduledUpdate(bool auto_update_now) { QList<Feed*>FeedsModel::feedsForScheduledUpdate(bool auto_update_now) {
QList<Feed*>feeds_for_update; QList<Feed*>feeds_for_update;
foreach (Feed* feed, m_rootItem->getSubTreeFeeds()) { foreach (Feed* feed, m_rootItem->getSubTreeFeeds()) {
switch (feed->autoUpdateType()) { switch (feed->autoUpdateType()) {
case Feed::DontAutoUpdate: case Feed::DontAutoUpdate:
// Do not auto-update this feed ever.
continue;
case Feed::DefaultAutoUpdate: // Do not auto-update this feed ever.
if (auto_update_now) { continue;
feeds_for_update.append(feed);
}
break; case Feed::DefaultAutoUpdate:
case Feed::SpecificAutoUpdate: if (auto_update_now) {
default: feeds_for_update.append(feed);
int remaining_interval = feed->autoUpdateRemainingInterval(); }
if (--remaining_interval <= 0) { break;
// Interval of this feed passed, include this feed in the output list
// and reset the interval.
feeds_for_update.append(feed);
feed->setAutoUpdateRemainingInterval(feed->autoUpdateInitialInterval());
}
else {
// Interval did not pass, set new decremented interval and do NOT
// include this feed in the output list.
feed->setAutoUpdateRemainingInterval(remaining_interval);
}
break; case Feed::SpecificAutoUpdate:
} default:
} int remaining_interval = feed->autoUpdateRemainingInterval();
return feeds_for_update; if (--remaining_interval <= 0) {
// Interval of this feed passed, include this feed in the output list
// and reset the interval.
feeds_for_update.append(feed);
feed->setAutoUpdateRemainingInterval(feed->autoUpdateInitialInterval());
}
else {
// Interval did not pass, set new decremented interval and do NOT
// include this feed in the output list.
feed->setAutoUpdateRemainingInterval(remaining_interval);
}
break;
}
}
return feeds_for_update;
} }
QList<Message>FeedsModel::messagesForItem(RootItem* item) const { QList<Message>FeedsModel::messagesForItem(RootItem* item) const {
return item->undeletedMessages(); return item->undeletedMessages();
} }
int FeedsModel::columnCount(const QModelIndex& parent) const { int FeedsModel::columnCount(const QModelIndex& parent) const {
Q_UNUSED(parent) Q_UNUSED(parent) return FEEDS_VIEW_COLUMN_COUNT;
return FEEDS_VIEW_COLUMN_COUNT;
} }
RootItem* FeedsModel::itemForIndex(const QModelIndex& index) const { RootItem* FeedsModel::itemForIndex(const QModelIndex& index) const {
if (index.isValid() && index.model() == this) { if (index.isValid() && index.model() == this) {
return static_cast<RootItem*>(index.internalPointer()); return static_cast<RootItem*>(index.internalPointer());
} }
else { else {
return m_rootItem; return m_rootItem;
} }
} }
QModelIndex FeedsModel::indexForItem(const RootItem* item) const { QModelIndex FeedsModel::indexForItem(const RootItem* item) const {
if (item == nullptr || item->kind() == RootItemKind::Root) { if (item == nullptr || item->kind() == RootItemKind::Root) {
// Root item lies on invalid index.
return QModelIndex();
}
QStack<const RootItem*>chain; // Root item lies on invalid index.
return QModelIndex();
}
while (item->kind() != RootItemKind::Root) { QStack<const RootItem*>chain;
chain.push(item);
item = item->parent();
}
// Now, we have complete chain list: parent --- ..... --- parent --- leaf (item). while (item->kind() != RootItemKind::Root) {
QModelIndex target_index = indexForItem(m_rootItem); chain.push(item);
item = item->parent();
}
// We go through the stack and create our target index. // Now, we have complete chain list: parent --- ..... --- parent --- leaf (item).
while (!chain.isEmpty()) { QModelIndex target_index = indexForItem(m_rootItem);
const RootItem* parent_item = chain.pop();
target_index = index(parent_item->parent()->childItems().indexOf(const_cast<RootItem* const>(parent_item)), 0, target_index);
}
return target_index; // We go through the stack and create our target index.
while (!chain.isEmpty()) {
const RootItem* parent_item = chain.pop();
target_index = index(parent_item->parent()->childItems().indexOf(const_cast<RootItem* const>(parent_item)),
0,
target_index);
}
return target_index;
} }
bool FeedsModel::hasAnyFeedNewMessages() const { bool FeedsModel::hasAnyFeedNewMessages() const {
foreach (const Feed* feed, m_rootItem->getSubTreeFeeds()) { foreach (const Feed* feed, m_rootItem->getSubTreeFeeds()) {
if (feed->status() == Feed::NewMessages) { if (feed->status() == Feed::NewMessages) {
return true; return true;
} }
} }
return false; return false;
} }
RootItem* FeedsModel::rootItem() const { RootItem* FeedsModel::rootItem() const {
return m_rootItem; return m_rootItem;
} }
void FeedsModel::reloadChangedLayout(QModelIndexList list) { void FeedsModel::reloadChangedLayout(QModelIndexList list) {
while (!list.isEmpty()) { while (!list.isEmpty()) {
QModelIndex indx = list.takeFirst(); QModelIndex indx = list.takeFirst();
if (indx.isValid()) { if (indx.isValid()) {
QModelIndex indx_parent = indx.parent(); QModelIndex indx_parent = indx.parent();
// Underlying data are changed.
emit dataChanged(index(indx.row(), 0, indx_parent), index(indx.row(), FDS_MODEL_COUNTS_INDEX, indx_parent)); // Underlying data are changed.
list.append(indx_parent); emit dataChanged(index(indx.row(), 0, indx_parent), index(indx.row(), FDS_MODEL_COUNTS_INDEX, indx_parent));
}
} list.append(indx_parent);
}
}
} }
void FeedsModel::reloadChangedItem(RootItem* item) { void FeedsModel::reloadChangedItem(RootItem* item) {
QModelIndex index_item = indexForItem(item); reloadChangedLayout(QModelIndexList() << indexForItem(item));
reloadChangedLayout(QModelIndexList() << index_item);
} }
void FeedsModel::notifyWithCounts() { void FeedsModel::notifyWithCounts() {
emit messageCountsChanged(countOfUnreadMessages(), hasAnyFeedNewMessages()); emit messageCountsChanged(countOfUnreadMessages(), hasAnyFeedNewMessages());
} }
void FeedsModel::onItemDataChanged(const QList<RootItem*>& items) { void FeedsModel::onItemDataChanged(const QList<RootItem*>& items) {
if (items.size() > RELOAD_MODEL_BORDER_NUM) { if (items.size() > RELOAD_MODEL_BORDER_NUM) {
qDebug("There is request to reload feed model for more than %d items, reloading model fully.", RELOAD_MODEL_BORDER_NUM); qDebug("There is request to reload feed model for more than %d items, reloading model fully.", RELOAD_MODEL_BORDER_NUM);
reloadWholeLayout(); reloadWholeLayout();
} }
else { else {
qDebug("There is request to reload feed model, reloading the %d items individually.", items.size()); qDebug("There is request to reload feed model, reloading the %d items individually.", items.size());
foreach (RootItem* item, items) { foreach (RootItem* item, items) {
reloadChangedItem(item); reloadChangedItem(item);
} }
} }
notifyWithCounts(); notifyWithCounts();
} }
void FeedsModel::reloadWholeLayout() { void FeedsModel::reloadWholeLayout() {
emit layoutAboutToBeChanged(); emit layoutAboutToBeChanged();
emit layoutChanged(); emit layoutChanged();
} }
bool FeedsModel::addServiceAccount(ServiceRoot* root, bool freshly_activated) { bool FeedsModel::addServiceAccount(ServiceRoot* root, bool freshly_activated) {
int new_row_index = m_rootItem->childCount(); int new_row_index = m_rootItem->childCount();
beginInsertRows(indexForItem(m_rootItem), new_row_index, new_row_index);
m_rootItem->appendChild(root); beginInsertRows(indexForItem(m_rootItem), new_row_index, new_row_index);
endInsertRows(); m_rootItem->appendChild(root);
// Connect. endInsertRows();
connect(root, &ServiceRoot::itemRemovalRequested, this, static_cast<void (FeedsModel::*)(RootItem*)>(&FeedsModel::removeItem));
connect(root, &ServiceRoot::itemReassignmentRequested, this, &FeedsModel::reassignNodeToNewParent); // Connect.
connect(root, &ServiceRoot::dataChanged, this, &FeedsModel::onItemDataChanged); connect(root, &ServiceRoot::itemRemovalRequested, this, static_cast<void (FeedsModel::*)(RootItem*)>(&FeedsModel::removeItem));
connect(root, &ServiceRoot::reloadMessageListRequested, this, &FeedsModel::reloadMessageListRequested); connect(root, &ServiceRoot::itemReassignmentRequested, this, &FeedsModel::reassignNodeToNewParent);
connect(root, &ServiceRoot::itemExpandRequested, this, &FeedsModel::itemExpandRequested); connect(root, &ServiceRoot::dataChanged, this, &FeedsModel::onItemDataChanged);
connect(root, &ServiceRoot::itemExpandStateSaveRequested, this, &FeedsModel::itemExpandStateSaveRequested); connect(root, &ServiceRoot::reloadMessageListRequested, this, &FeedsModel::reloadMessageListRequested);
root->start(freshly_activated); connect(root, &ServiceRoot::itemExpandRequested, this, &FeedsModel::itemExpandRequested);
return true; connect(root, &ServiceRoot::itemExpandStateSaveRequested, this, &FeedsModel::itemExpandStateSaveRequested);
root->start(freshly_activated);
return true;
} }
bool FeedsModel::restoreAllBins() { bool FeedsModel::restoreAllBins() {
bool result = true; bool result = true;
foreach (ServiceRoot* root, serviceRoots()) { foreach (ServiceRoot* root, serviceRoots()) {
RecycleBin* bin_of_root = root->recycleBin(); RecycleBin* bin_of_root = root->recycleBin();
if (bin_of_root != nullptr) { if (bin_of_root != nullptr) {
result &= bin_of_root->restore(); result &= bin_of_root->restore();
} }
} }
return result; return result;
} }
bool FeedsModel::emptyAllBins() { bool FeedsModel::emptyAllBins() {
bool result = true; bool result = true;
foreach (ServiceRoot* root, serviceRoots()) { foreach (ServiceRoot* root, serviceRoots()) {
RecycleBin* bin_of_root = root->recycleBin(); RecycleBin* bin_of_root = root->recycleBin();
if (bin_of_root != nullptr) { if (bin_of_root != nullptr) {
result &= bin_of_root->empty(); result &= bin_of_root->empty();
} }
} }
return result; return result;
} }
void FeedsModel::loadActivatedServiceAccounts() { void FeedsModel::loadActivatedServiceAccounts() {
// Iterate all globally available feed "service plugins". // Iterate all globally available feed "service plugins".
foreach (const ServiceEntryPoint* entry_point, qApp->feedReader()->feedServices()) { foreach (const ServiceEntryPoint* entry_point, qApp->feedReader()->feedServices()) {
// Load all stored root nodes from the entry point and add those to the model. // Load all stored root nodes from the entry point and add those to the model.
QList<ServiceRoot*>roots = entry_point->initializeSubtree(); QList<ServiceRoot*>roots = entry_point->initializeSubtree();
foreach (ServiceRoot* root, roots) { foreach (ServiceRoot* root, roots) {
addServiceAccount(root, false); addServiceAccount(root, false);
} }
} }
if (serviceRoots().isEmpty()) { if (serviceRoots().isEmpty()) {
QTimer::singleShot(2000, [this]() { QTimer::singleShot(2000, [this]() {
addServiceAccount(StandardServiceEntryPoint().createNewRoot(), true); addServiceAccount(StandardServiceEntryPoint().createNewRoot(), true);
}); });
} }
} }
void FeedsModel::stopServiceAccounts() { void FeedsModel::stopServiceAccounts() {
foreach (ServiceRoot* account, serviceRoots()) { foreach (ServiceRoot* account, serviceRoots()) {
account->stop(); account->stop();
} }
} }
QList<Feed*>FeedsModel::feedsForIndex(const QModelIndex& index) const { QList<Feed*>FeedsModel::feedsForIndex(const QModelIndex& index) const {
return itemForIndex(index)->getSubTreeFeeds(); return itemForIndex(index)->getSubTreeFeeds();
} }
bool FeedsModel::markItemRead(RootItem* item, RootItem::ReadStatus read) { bool FeedsModel::markItemRead(RootItem* item, RootItem::ReadStatus read) {
return item->markAsReadUnread(read); return item->markAsReadUnread(read);
} }
bool FeedsModel::markItemCleared(RootItem* item, bool clean_read_only) { bool FeedsModel::markItemCleared(RootItem* item, bool clean_read_only) {
return item->cleanMessages(clean_read_only); return item->cleanMessages(clean_read_only);
} }

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,7 +21,6 @@
#include <QAbstractItemModel> #include <QAbstractItemModel>
#include "core/message.h"
#include "services/abstract/rootitem.h" #include "services/abstract/rootitem.h"
class Category; class Category;
@ -30,153 +30,152 @@ class ServiceEntryPoint;
class StandardServiceRoot; class StandardServiceRoot;
class FeedsModel : public QAbstractItemModel { class FeedsModel : public QAbstractItemModel {
Q_OBJECT Q_OBJECT
public: public:
// Constructors and destructors. explicit FeedsModel(QObject* parent = 0);
explicit FeedsModel(QObject* parent = 0); virtual ~FeedsModel();
virtual ~FeedsModel();
// Model implementation. // Model implementation.
inline QVariant data(const QModelIndex& index, int role) const { inline QVariant data(const QModelIndex& index, int role) const {
// Return data according to item. // Return data according to item.
return itemForIndex(index)->data(index.column(), role); return itemForIndex(index)->data(index.column(), role);
} }
// Drag & drop. // Drag & drop.
QMimeData* mimeData(const QModelIndexList& indexes) const; QMimeData* mimeData(const QModelIndexList& indexes) const;
QStringList mimeTypes() const;
bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent);
Qt::DropActions supportedDropActions() const;
Qt::ItemFlags flags(const QModelIndex& index) const;
// Other subclassed methods. QStringList mimeTypes() const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const; bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent);
QModelIndex index(int row, int column, const QModelIndex& parent) const; Qt::DropActions supportedDropActions() const;
QModelIndex parent(const QModelIndex& child) const; Qt::ItemFlags flags(const QModelIndex& index) const;
int columnCount(const QModelIndex& parent) const;
int rowCount(const QModelIndex& parent) const;
// Returns counts of ALL/UNREAD (non-deleted) messages for the model. // Other subclassed methods.
int countOfAllMessages() const; QVariant headerData(int section, Qt::Orientation orientation, int role) const;
int countOfUnreadMessages() const; QModelIndex index(int row, int column, const QModelIndex& parent) const;
QModelIndex parent(const QModelIndex& child) const;
int columnCount(const QModelIndex& parent) const;
int rowCount(const QModelIndex& parent) const;
// Returns all activated service roots. // Returns counts of ALL/UNREAD (non-deleted) messages for the model.
// NOTE: Service root nodes are lying directly UNDER int countOfAllMessages() const;
// the model root item. int countOfUnreadMessages() const;
QList<ServiceRoot*>serviceRoots() const;
// Determines if there is any account activated from given entry point. // Returns all activated service roots.
bool containsServiceRootFromEntryPoint(const ServiceEntryPoint* point) const; // NOTE: Service root nodes are lying directly UNDER
// the model root item.
QList<ServiceRoot*>serviceRoots() const;
// Direct and the only global accessor to standard service root. // Determines if there is any account activated from given entry point.
StandardServiceRoot* standardServiceRoot() const; bool containsServiceRootFromEntryPoint(const ServiceEntryPoint* point) const;
// Returns the list of feeds which should be updated // Direct and the only global accessor to standard service root.
// according to auto-update schedule. StandardServiceRoot* standardServiceRoot() const;
// Variable "auto_update_now" is true, when global timeout
// for scheduled auto-update was met and global auto-update strategy is enabled
// so feeds with "default" auto-update strategy should be updated.
//
// This method might change some properties of some feeds.
QList<Feed*>feedsForScheduledUpdate(bool auto_update_now);
// Returns (undeleted) messages for given feeds. // Returns the list of feeds which should be updated
// This is usually used for displaying whole feeds // according to auto-update schedule.
// in "newspaper" mode. // Variable "auto_update_now" is true, when global timeout
QList<Message>messagesForItem(RootItem* item) const; // for scheduled auto-update was met and global auto-update strategy is enabled
// so feeds with "default" auto-update strategy should be updated.
//
// This method might change some properties of some feeds.
QList<Feed*>feedsForScheduledUpdate(bool auto_update_now);
// Returns ALL RECURSIVE CHILD feeds contained within single index. // Returns (undeleted) messages for given feeds.
QList<Feed*>feedsForIndex(const QModelIndex& index) const; // This is usually used for displaying whole feeds
// in "newspaper" mode.
QList<Message>messagesForItem(RootItem* item) const;
// Returns feed/category which lies at the specified index or // Returns ALL RECURSIVE CHILD feeds contained within single index.
// root item if index is invalid. QList<Feed*>feedsForIndex(const QModelIndex& index) const;
RootItem* itemForIndex(const QModelIndex& index) const;
// Returns source QModelIndex on which lies given item. // Returns feed/category which lies at the specified index or
// NOTE: This goes through all available indexes and // root item if index is invalid.
// checks their bound items manually, there is no RootItem* itemForIndex(const QModelIndex& index) const;
// other way to to this.
QModelIndex indexForItem(const RootItem* item) const;
// Determines if any feed has any new messages. // Returns source QModelIndex on which lies given item.
bool hasAnyFeedNewMessages() const; // NOTE: This goes through all available indexes and
// checks their bound items manually, there is no
// other way to to this.
QModelIndex indexForItem(const RootItem* item) const;
// Access to root item. // Determines if any feed has any new messages.
RootItem* rootItem() const; bool hasAnyFeedNewMessages() const;
public slots: // Access to root item.
// Loads feed/categories from the database. RootItem* rootItem() const;
void loadActivatedServiceAccounts();
// Stops all accounts before exit. public slots:
void stopServiceAccounts(); void loadActivatedServiceAccounts();
// Reloads counts of all feeds/categories/whatever in the model. // Stops all accounts before exit.
void reloadCountsOfWholeModel(); void stopServiceAccounts();
// Checks if new parent node is different from one used by original node. // Reloads counts of all feeds/categories/whatever in the model.
// If it is, then it reassigns original_node to new parent. void reloadCountsOfWholeModel();
void reassignNodeToNewParent(RootItem* original_node, RootItem* new_parent);
// Adds given service root account. // Checks if new parent node is different from one used by original node.
bool addServiceAccount(ServiceRoot* root, bool freshly_activated); // If it is, then it reassigns original_node to new parent.
void reassignNodeToNewParent(RootItem* original_node, RootItem* new_parent);
// Removes item with given index. // Adds given service root account.
// NOTE: Also deletes item from memory. bool addServiceAccount(ServiceRoot* root, bool freshly_activated);
void removeItem(const QModelIndex& index);
void removeItem(RootItem* deleting_item);
// Recycle bins operations. // Removes item with given index.
bool restoreAllBins(); // NOTE: Also deletes item from memory.
bool emptyAllBins(); void removeItem(const QModelIndex& index);
void removeItem(RootItem* deleting_item);
// Feeds operations. // Recycle bins operations.
bool markItemRead(RootItem* item, RootItem::ReadStatus read); bool restoreAllBins();
bool markItemCleared(RootItem* item, bool clean_read_only); bool emptyAllBins();
// Signals that properties (probably counts) // Feeds operations.
// of ALL items have changed. bool markItemRead(RootItem* item, RootItem::ReadStatus read);
void reloadWholeLayout(); bool markItemCleared(RootItem* item, bool clean_read_only);
// Signals that SOME data of this model need // Signals that properties (probably counts)
// to be reloaded by ALL attached views. // of ALL items have changed.
// NOTE: This reloads all parent valid indexes too. void reloadWholeLayout();
void reloadChangedLayout(QModelIndexList list);
// Invalidates data under index for the item. // Signals that SOME data of this model need
void reloadChangedItem(RootItem* item); // to be reloaded by ALL attached views.
// NOTE: This reloads all parent valid indexes too.
void reloadChangedLayout(QModelIndexList list);
// Notifies other components about messages // Invalidates data under index for the item.
// counts. void reloadChangedItem(RootItem* item);
void notifyWithCounts();
private slots: // Notifies other components about messages
void onItemDataChanged(const QList<RootItem*>& items); // counts.
void notifyWithCounts();
signals: private slots:
// Emitted if counts of messages are changed. void onItemDataChanged(const QList<RootItem*>& items);
void messageCountsChanged(int unread_messages, bool any_feed_has_unread_messages);
// Emitted if any item requested that any view should expand it. signals:
void itemExpandRequested(QList<RootItem*>items, bool expand); void messageCountsChanged(int unread_messages, bool any_feed_has_unread_messages);
// Emitted if any item requested that its expand states should be explicitly saved. // Emitted if any item requested that any view should expand it.
// NOTE: Normally expand states are saved when application quits. void itemExpandRequested(QList<RootItem*>items, bool expand);
void itemExpandStateSaveRequested(RootItem* subtree_root);
// Emitted when there is a need of reloading of displayed messages. // Emitted if any item requested that its expand states should be explicitly saved.
void reloadMessageListRequested(bool mark_selected_messages_read); // NOTE: Normally expand states are saved when application quits.
void itemExpandStateSaveRequested(RootItem* subtree_root);
// There was some drag/drop operation, notify view about this. // Emitted when there is a need of reloading of displayed messages.
// NOTE: View will probably expand dropped index. void reloadMessageListRequested(bool mark_selected_messages_read);
void requireItemValidationAfterDragDrop(const QModelIndex& source_index);
private: // There was some drag/drop operation, notify view about this.
RootItem* m_rootItem; // NOTE: View will probably expand dropped index.
QList<QString>m_headerData; void requireItemValidationAfterDragDrop(const QModelIndex& source_index);
QList<QString>m_tooltipData;
QIcon m_countsIcon; private:
RootItem* m_rootItem;
QList<QString> m_headerData;
QList<QString> m_tooltipData;
QIcon m_countsIcon;
}; };
#endif // FEEDSMODEL_H #endif // FEEDSMODEL_H

View File

@ -220,7 +220,6 @@
#endif #endif
#if defined(Q_OS_LINUX) #if defined(Q_OS_LINUX)
#define APP_DESKTOP_SOURCE_ENTRY_FILE "rssguard.desktop.autostart" #define APP_DESKTOP_SOURCE_ENTRY_FILE "rssguard.desktop.autostart"
#define APP_DESKTOP_ENTRY_FILE "rssguard.desktop" #define APP_DESKTOP_ENTRY_FILE "rssguard.desktop"
@ -233,9 +232,7 @@
#define APP_ICON_PATH QApplication::applicationDirPath() + QString("/../share/pixmaps/rssguard.png") #define APP_ICON_PATH QApplication::applicationDirPath() + QString("/../share/pixmaps/rssguard.png")
#define APP_ICON_PLAIN_PATH QApplication::applicationDirPath() + QString("/../share/rssguard/icons/rssguard_plain.png") #define APP_ICON_PLAIN_PATH QApplication::applicationDirPath() + QString("/../share/rssguard/icons/rssguard_plain.png")
#define APP_INITIAL_FEEDS_PATH QApplication::applicationDirPath() + QString("/../share/rssguard/initial_feeds") #define APP_INITIAL_FEEDS_PATH QApplication::applicationDirPath() + QString("/../share/rssguard/initial_feeds")
#elif defined(Q_OS_OSX) #elif defined(Q_OS_OSX)
#define APP_LANG_PATH QApplication::applicationDirPath() + QString("/../Resources/translations") #define APP_LANG_PATH QApplication::applicationDirPath() + QString("/../Resources/translations")
#define APP_SKIN_PATH QApplication::applicationDirPath() + QString("/../Resources/skins") #define APP_SKIN_PATH QApplication::applicationDirPath() + QString("/../Resources/skins")
#define APP_INFO_PATH QApplication::applicationDirPath() + QString("/../Resources/information") #define APP_INFO_PATH QApplication::applicationDirPath() + QString("/../Resources/information")
@ -245,9 +242,7 @@
#define APP_INFO_PATH QApplication::applicationDirPath() + QString("/../Resources/information") #define APP_INFO_PATH QApplication::applicationDirPath() + QString("/../Resources/information")
#define APP_ICON_PLAIN_PATH QApplication::applicationDirPath() + QString("/../Resources/icons/rssguard_plain.png") #define APP_ICON_PLAIN_PATH QApplication::applicationDirPath() + QString("/../Resources/icons/rssguard_plain.png")
#define APP_INITIAL_FEEDS_PATH QApplication::applicationDirPath() + QString("/../Resources/initial_feeds") #define APP_INITIAL_FEEDS_PATH QApplication::applicationDirPath() + QString("/../Resources/initial_feeds")
#elif defined(Q_OS_WIN) #elif defined(Q_OS_WIN)
#define APP_LANG_PATH QApplication::applicationDirPath() + QString("/translations") #define APP_LANG_PATH QApplication::applicationDirPath() + QString("/translations")
#define APP_SKIN_PATH QApplication::applicationDirPath() + QString("/skins") #define APP_SKIN_PATH QApplication::applicationDirPath() + QString("/skins")
#define APP_INFO_PATH QApplication::applicationDirPath() #define APP_INFO_PATH QApplication::applicationDirPath()
@ -256,7 +251,6 @@
#define APP_ICON_PATH QApplication::applicationDirPath() + QString("/rssguard.png") #define APP_ICON_PATH QApplication::applicationDirPath() + QString("/rssguard.png")
#define APP_ICON_PLAIN_PATH QApplication::applicationDirPath() + QString("/rssguard_plain.png") #define APP_ICON_PLAIN_PATH QApplication::applicationDirPath() + QString("/rssguard_plain.png")
#define APP_INITIAL_FEEDS_PATH QApplication::applicationDirPath() + QString("/initial_feeds") #define APP_INITIAL_FEEDS_PATH QApplication::applicationDirPath() + QString("/initial_feeds")
#endif #endif
#endif // DEFINITIONS_H #endif // DEFINITIONS_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,95 +18,85 @@
#include "gui/dialogs/formabout.h" #include "gui/dialogs/formabout.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/textfactory.h"
#include "miscellaneous/settingsproperties.h"
#include "gui/guiutilities.h"
#include "exceptions/applicationexception.h" #include "exceptions/applicationexception.h"
#include "gui/guiutilities.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/settingsproperties.h"
#include "miscellaneous/textfactory.h"
#include <QFile> #include <QFile>
#include <QTextStream> #include <QTextStream>
FormAbout::FormAbout(QWidget* parent) : QDialog(parent) { FormAbout::FormAbout(QWidget* parent) : QDialog(parent) {
m_ui.setupUi(this); m_ui.setupUi(this);
m_ui.m_lblIcon->setPixmap(QPixmap(APP_ICON_PATH)); m_ui.m_lblIcon->setPixmap(QPixmap(APP_ICON_PATH));
GuiUtilities::applyDialogProperties(*this, qApp->icons()->fromTheme(QSL("help-about")), tr("About %1").arg(APP_NAME)); GuiUtilities::applyDialogProperties(*this, qApp->icons()->fromTheme(QSL("help-about")), tr("About %1").arg(APP_NAME));
loadLicenseAndInformation(); loadLicenseAndInformation();
loadSettingsAndPaths(); loadSettingsAndPaths();
} }
FormAbout::~FormAbout() { FormAbout::~FormAbout() {
qDebug("Destroying FormAbout instance."); qDebug("Destroying FormAbout instance.");
} }
void FormAbout::loadSettingsAndPaths() { void FormAbout::loadSettingsAndPaths() {
if (qApp->settings()->type() == SettingsProperties::Portable) { if (qApp->settings()->type() == SettingsProperties::Portable) {
m_ui.m_txtPathsSettingsType->setText(tr("FULLY portable")); m_ui.m_txtPathsSettingsType->setText(tr("FULLY portable"));
} }
else { else {
m_ui.m_txtPathsSettingsType->setText(tr("NOT portable")); m_ui.m_txtPathsSettingsType->setText(tr("NOT portable"));
} }
m_ui.m_txtPathsDatabaseRoot->setText(QDir::toNativeSeparators(qApp->userDataFolder() + m_ui.m_txtPathsDatabaseRoot->setText(QDir::toNativeSeparators(qApp->userDataFolder() + QDir::separator() + QString(APP_DB_SQLITE_PATH)));
QDir::separator() + m_ui.m_txtPathsSettingsFile->setText(QDir::toNativeSeparators(qApp->settings()->fileName()));
QString(APP_DB_SQLITE_PATH))); m_ui.m_txtPathsSkinsRoot->setText(QDir::toNativeSeparators(qApp->skins()->customSkinBaseFolder()));
m_ui.m_txtPathsSettingsFile->setText(QDir::toNativeSeparators(qApp->settings()->fileName()));
m_ui.m_txtPathsSkinsRoot->setText(QDir::toNativeSeparators(qApp->skins()->customSkinBaseFolder()));
} }
void FormAbout::loadLicenseAndInformation() { void FormAbout::loadLicenseAndInformation() {
try { try {
m_ui.m_txtLicenseGnu->setText(IOFactory::readTextFile(APP_INFO_PATH + QL1S("/COPYING_GNU_GPL_HTML"))); m_ui.m_txtLicenseGnu->setText(IOFactory::readTextFile(APP_INFO_PATH + QL1S("/COPYING_GNU_GPL_HTML")));
} }
catch (...) { catch (...) {
m_ui.m_txtLicenseGnu->setText(tr("License not found.")); m_ui.m_txtLicenseGnu->setText(tr("License not found."));
} }
try { try {
m_ui.m_txtLicenseGnu->setText(IOFactory::readTextFile(APP_INFO_PATH + QL1S("/COPYING_GNU_GPL_HTML"))); m_ui.m_txtLicenseGnu->setText(IOFactory::readTextFile(APP_INFO_PATH + QL1S("/COPYING_GNU_GPL_HTML")));
} }
catch (...) { catch (...) {
m_ui.m_txtLicenseGnu->setText(tr("License not found.")); m_ui.m_txtLicenseGnu->setText(tr("License not found."));
} }
try { try {
m_ui.m_txtChangelog->setText(IOFactory::readTextFile(APP_INFO_PATH + QL1S("/CHANGELOG"))); m_ui.m_txtChangelog->setText(IOFactory::readTextFile(APP_INFO_PATH + QL1S("/CHANGELOG")));
} }
catch (...) { catch (...) {
m_ui.m_txtChangelog->setText(tr("Changelog not found.")); m_ui.m_txtChangelog->setText(tr("Changelog not found."));
} }
try { try {
m_ui.m_txtLicenseBsd->setText(IOFactory::readTextFile(APP_INFO_PATH + QL1S("/COPYING_BSD"))); m_ui.m_txtLicenseBsd->setText(IOFactory::readTextFile(APP_INFO_PATH + QL1S("/COPYING_BSD")));
} }
catch (...) { catch (...) {
m_ui.m_txtLicenseBsd->setText(tr("License not found.")); m_ui.m_txtLicenseBsd->setText(tr("License not found."));
} }
// Set other informative texts. // Set other informative texts.
m_ui.m_lblDesc->setText(tr("<b>%8</b><br>" m_ui.m_lblDesc->setText(tr("<b>%8</b><br>" "<b>Version:</b> %1 (built on %2/%3)<br>" "<b>Revision:</b> %4<br>" "<b>Build date:</b> %5<br>"
"<b>Version:</b> %1 (built on %2/%3)<br>" "<b>Qt:</b> %6 (compiled against %7)<br>").arg(
"<b>Revision:</b> %4<br>" qApp->applicationVersion(), APP_SYSTEM_NAME, APP_SYSTEM_VERSION, APP_REVISION,
"<b>Build date:</b> %5<br>" TextFactory
"<b>Qt:</b> %6 (compiled against %7)<br>").arg(qApp->applicationVersion(), ::parseDateTime(QString("%1 %2").arg(__DATE__, __TIME__)).toString(Qt::DefaultLocaleShortDate),
APP_SYSTEM_NAME, qVersion(), QT_VERSION_STR,
APP_SYSTEM_VERSION, APP_NAME));
APP_REVISION, m_ui.m_txtInfo->setText(tr("<body>%5 is a (very) tiny feed reader."
TextFactory::parseDateTime(QString("%1 %2").arg(__DATE__, "<br><br>This software is distributed under the terms of GNU General Public License, version 3."
__TIME__)).toString(Qt::DefaultLocaleShortDate), "<br><br>Contacts:"
qVersion(), "<ul><li><a href=\"mailto://%1\">%1</a> ~e-mail</li>"
QT_VERSION_STR, "<li><a href=\"%2\">%2</a> ~website</li></ul>"
APP_NAME)); "You can obtain source code for %5 from its website."
m_ui.m_txtInfo->setText(tr("<body>%5 is a (very) tiny feed reader." "<br><br><br>Copyright (C) 2011-%3 %4</body>").arg(APP_EMAIL, APP_URL,
"<br><br>This software is distributed under the terms of GNU General Public License, version 3." QString
"<br><br>Contacts:" ::number(QDateTime::currentDateTime().date().year()),
"<ul><li><a href=\"mailto://%1\">%1</a> ~e-mail</li>" APP_AUTHOR, APP_NAME));
"<li><a href=\"%2\">%2</a> ~website</li></ul>"
"You can obtain source code for %5 from its website."
"<br><br><br>Copyright (C) 2011-%3 %4</body>").arg(APP_EMAIL,
APP_URL,
QString::number(QDateTime::currentDateTime().date().year()),
APP_AUTHOR,
APP_NAME));
} }

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,118 +18,113 @@
#include "gui/dialogs/formrestoredatabasesettings.h" #include "gui/dialogs/formrestoredatabasesettings.h"
#include "gui/messagebox.h"
#include "gui/dialogs/formmain.h"
#include "miscellaneous/iconfactory.h"
#include "exceptions/applicationexception.h" #include "exceptions/applicationexception.h"
#include "gui/dialogs/formmain.h"
#include "gui/messagebox.h"
#include "miscellaneous/iconfactory.h"
#include "QFileDialog" #include "QFileDialog"
FormRestoreDatabaseSettings::FormRestoreDatabaseSettings(QWidget& parent) : QDialog(&parent),
FormRestoreDatabaseSettings::FormRestoreDatabaseSettings(QWidget& parent) m_shouldRestart(false) {
: QDialog(&parent), m_shouldRestart(false) { m_ui.setupUi(this);
m_ui.setupUi(this); m_btnRestart = m_ui.m_buttonBox->addButton(tr("Restart"), QDialogButtonBox::ActionRole);
m_btnRestart = m_ui.m_buttonBox->addButton(tr("Restart"), QDialogButtonBox::ActionRole); m_ui.m_lblResult->setStatus(WidgetWithStatus::Warning, tr("No operation executed yet."), tr("No operation executed yet."));
m_ui.m_lblResult->setStatus(WidgetWithStatus::Warning, tr("No operation executed yet."), tr("No operation executed yet.")); setWindowIcon(qApp->icons()->fromTheme(QSL("document-import")));
setWindowIcon(qApp->icons()->fromTheme(QSL("document-import"))); setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint);
setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint); connect(m_btnRestart, &QPushButton::clicked, this, [=]() {
connect(m_btnRestart, &QPushButton::clicked, this, [ = ]() { m_shouldRestart = true;
m_shouldRestart = true; close();
close(); });
}); connect(m_ui.m_btnSelectFolder, SIGNAL(clicked()), this, SLOT(selectFolder()));
connect(m_ui.m_btnSelectFolder, SIGNAL(clicked()), this, SLOT(selectFolder())); connect(m_ui.m_groupDatabase, SIGNAL(toggled(bool)), this, SLOT(checkOkButton()));
connect(m_ui.m_groupDatabase, SIGNAL(toggled(bool)), this, SLOT(checkOkButton())); connect(m_ui.m_groupSettings, SIGNAL(toggled(bool)), this, SLOT(checkOkButton()));
connect(m_ui.m_groupSettings, SIGNAL(toggled(bool)), this, SLOT(checkOkButton())); connect(m_ui.m_buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(performRestoration()));
connect(m_ui.m_buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(performRestoration())); selectFolder(qApp->documentsFolder());
selectFolder(qApp->documentsFolder());
} }
FormRestoreDatabaseSettings::~FormRestoreDatabaseSettings() { FormRestoreDatabaseSettings::~FormRestoreDatabaseSettings() {
qDebug("Destroying FormRestoreDatabaseSettings instance."); qDebug("Destroying FormRestoreDatabaseSettings instance.");
} }
void FormRestoreDatabaseSettings::performRestoration() { void FormRestoreDatabaseSettings::performRestoration() {
m_ui.m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); m_ui.m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
try { try {
qApp->restoreDatabaseSettings(m_ui.m_groupDatabase->isChecked(), qApp->restoreDatabaseSettings(m_ui.m_groupDatabase->isChecked(),
m_ui.m_groupSettings->isChecked(), m_ui.m_groupSettings->isChecked(),
m_ui.m_listDatabase->currentRow() >= 0 ? m_ui.m_listDatabase->currentRow() >= 0 ? m_ui.m_listDatabase->currentItem()->data(
m_ui.m_listDatabase->currentItem()->data(Qt::UserRole).toString() : Qt::UserRole).toString() : QString(),
QString(), m_ui.m_listSettings->currentRow() >= 0 ? m_ui.m_listSettings->currentItem()->data(
m_ui.m_listSettings->currentRow() >= 0 ? Qt::UserRole).toString() : QString());
m_ui.m_listSettings->currentItem()->data(Qt::UserRole).toString() : m_btnRestart->setEnabled(true);
QString()); m_ui.m_lblResult->setStatus(WidgetWithStatus::Ok, tr("Restoration was initiated. Restart to proceed."),
m_btnRestart->setEnabled(true); tr("You need to restart application for restoration process to finish."));
m_ui.m_lblResult->setStatus(WidgetWithStatus::Ok, tr("Restoration was initiated. Restart to proceed."), }
tr("You need to restart application for restoration process to finish.")); catch (const ApplicationException& ex) {
} m_ui.m_lblResult->setStatus(WidgetWithStatus::Error, ex.message(),
catch (const ApplicationException& ex) { tr("Database and/or settings were not copied to restoration directory successully."));
m_ui.m_lblResult->setStatus(WidgetWithStatus::Error, ex.message(), }
tr("Database and/or settings were not copied to restoration directory successully."));
}
} }
void FormRestoreDatabaseSettings::checkOkButton() { void FormRestoreDatabaseSettings::checkOkButton() {
m_btnRestart->setEnabled(false); m_btnRestart->setEnabled(false);
m_ui.m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!m_ui.m_lblSelectFolder->label()->text().isEmpty() && m_ui.m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!m_ui.m_lblSelectFolder->label()->text().isEmpty() &&
((m_ui.m_groupDatabase->isChecked() && ((m_ui.m_groupDatabase->isChecked() &&
m_ui.m_listDatabase->currentRow() >= 0) || m_ui.m_listDatabase->currentRow() >= 0) ||
(m_ui.m_groupSettings->isChecked() && (m_ui.m_groupSettings->isChecked() &&
m_ui.m_listSettings->currentRow() >= 0))); m_ui.m_listSettings->currentRow() >= 0)));
} }
void FormRestoreDatabaseSettings::selectFolderWithGui() { void FormRestoreDatabaseSettings::selectFolderWithGui() {
selectFolder(); selectFolder();
} }
void FormRestoreDatabaseSettings::selectFolder(QString folder) { void FormRestoreDatabaseSettings::selectFolder(QString folder) {
if (folder.isEmpty()) { if (folder.isEmpty()) {
folder = QFileDialog::getExistingDirectory(this, tr("Select source directory"), m_ui.m_lblSelectFolder->label()->text()); folder = QFileDialog::getExistingDirectory(this, tr("Select source directory"), m_ui.m_lblSelectFolder->label()->text());
} }
if (!folder.isEmpty()) { if (!folder.isEmpty()) {
m_ui.m_lblSelectFolder->setStatus(WidgetWithStatus::Ok, QDir::toNativeSeparators(folder), m_ui.m_lblSelectFolder->setStatus(WidgetWithStatus::Ok, QDir::toNativeSeparators(folder), tr("Good source directory is specified."));
tr("Good source directory is specified.")); }
} else {
else { return;
return; }
}
const QDir selected_folder(folder); const QDir selected_folder(folder);
const QFileInfoList available_databases = selected_folder.entryInfoList(QStringList() const QFileInfoList available_databases = selected_folder.entryInfoList(QStringList() << QString("*") + BACKUP_SUFFIX_DATABASE,
<< QString("*") + BACKUP_SUFFIX_DATABASE, QDir::Files | QDir::NoDotAndDotDot | QDir::Readable | QDir::CaseSensitive | QDir::NoSymLinks,
QDir::Files | QDir::NoDotAndDotDot | QDir::Readable | QDir::Name);
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() QDir::Name);
<< QString("*") + BACKUP_SUFFIX_SETTINGS,
QDir::Files | QDir::NoDotAndDotDot | QDir::Readable |
QDir::CaseSensitive | QDir::NoSymLinks,
QDir::Name);
m_ui.m_listDatabase->clear();
m_ui.m_listSettings->clear();
foreach (const QFileInfo& database_file, available_databases) { m_ui.m_listDatabase->clear();
QListWidgetItem* database_item = new QListWidgetItem(database_file.fileName(), m_ui.m_listDatabase); m_ui.m_listSettings->clear();
database_item->setData(Qt::UserRole, database_file.absoluteFilePath());
database_item->setToolTip(QDir::toNativeSeparators(database_file.absoluteFilePath()));
}
foreach (const QFileInfo& settings_file, available_settings) { foreach (const QFileInfo& database_file, available_databases) {
QListWidgetItem* settings_item = new QListWidgetItem(settings_file.fileName(), m_ui.m_listSettings); QListWidgetItem* database_item = new QListWidgetItem(database_file.fileName(), m_ui.m_listDatabase);
settings_item->setData(Qt::UserRole, settings_file.absoluteFilePath());
settings_item->setToolTip(QDir::toNativeSeparators(settings_file.absoluteFilePath()));
}
if (!available_databases.isEmpty()) { database_item->setData(Qt::UserRole, database_file.absoluteFilePath());
m_ui.m_listDatabase->setCurrentRow(0); database_item->setToolTip(QDir::toNativeSeparators(database_file.absoluteFilePath()));
} }
if (!available_settings.isEmpty()) { foreach (const QFileInfo& settings_file, available_settings) {
m_ui.m_listSettings->setCurrentRow(0); QListWidgetItem* settings_item = new QListWidgetItem(settings_file.fileName(), m_ui.m_listSettings);
}
m_ui.m_groupDatabase->setChecked(!available_databases.isEmpty()); settings_item->setData(Qt::UserRole, settings_file.absoluteFilePath());
m_ui.m_groupSettings->setChecked(!available_settings.isEmpty()); settings_item->setToolTip(QDir::toNativeSeparators(settings_file.absoluteFilePath()));
}
if (!available_databases.isEmpty()) {
m_ui.m_listDatabase->setCurrentRow(0);
}
if (!available_settings.isEmpty()) {
m_ui.m_listSettings->setCurrentRow(0);
}
m_ui.m_groupDatabase->setChecked(!available_databases.isEmpty());
m_ui.m_groupSettings->setChecked(!available_settings.isEmpty());
} }

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,30 +18,30 @@
#include "gui/feedmessageviewer.h" #include "gui/feedmessageviewer.h"
#include "miscellaneous/settings.h"
#include "miscellaneous/databasefactory.h"
#include "miscellaneous/systemfactory.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/mutex.h"
#include "miscellaneous/databasecleaner.h"
#include "miscellaneous/feedreader.h"
#include "core/messagesproxymodel.h"
#include "core/feeddownloader.h" #include "core/feeddownloader.h"
#include "core/feedsproxymodel.h" #include "core/feedsproxymodel.h"
#include "services/standard/standardserviceroot.h" #include "core/messagesproxymodel.h"
#include "services/standard/standardfeed.h" #include "gui/feedstoolbar.h"
#include "services/standard/standardfeedsimportexportmodel.h"
#include "gui/messagesview.h"
#include "gui/feedsview.h" #include "gui/feedsview.h"
#include "gui/statusbar.h"
#include "gui/systemtrayicon.h"
#include "gui/messagebox.h" #include "gui/messagebox.h"
#include "gui/messagestoolbar.h" #include "gui/messagestoolbar.h"
#include "gui/feedstoolbar.h" #include "gui/messagesview.h"
#include "gui/statusbar.h"
#include "gui/systemtrayicon.h"
#include "miscellaneous/databasecleaner.h"
#include "miscellaneous/databasefactory.h"
#include "miscellaneous/feedreader.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/mutex.h"
#include "miscellaneous/settings.h"
#include "miscellaneous/systemfactory.h"
#include "services/standard/standardfeed.h"
#include "services/standard/standardfeedsimportexportmodel.h"
#include "services/standard/standardserviceroot.h"
#include "exceptions/applicationexception.h"
#include "gui/dialogs/formdatabasecleanup.h" #include "gui/dialogs/formdatabasecleanup.h"
#include "gui/dialogs/formmain.h" #include "gui/dialogs/formmain.h"
#include "exceptions/applicationexception.h"
#if defined(USE_WEBENGINE) #if defined(USE_WEBENGINE)
#include "gui/webbrowser.h" #include "gui/webbrowser.h"
@ -48,236 +49,246 @@
#include "gui/messagepreviewer.h" #include "gui/messagepreviewer.h"
#endif #endif
#include <QVBoxLayout> #include <QAction>
#include <QSplitter>
#include <QToolBar>
#include <QDebug> #include <QDebug>
#include <QLineEdit> #include <QLineEdit>
#include <QAction>
#include <QToolButton>
#include <QMenu> #include <QMenu>
#include <QWidgetAction>
#include <QThread>
#include <QProgressBar>
#include <QStatusBar>
#include <QPointer> #include <QPointer>
#include <QProgressBar>
#include <QSplitter>
#include <QStatusBar>
#include <QThread>
#include <QToolBar>
#include <QToolButton>
#include <QVBoxLayout>
#include <QWidgetAction>
FeedMessageViewer::FeedMessageViewer(QWidget* parent) : TabContent(parent), m_toolBarsEnabled(true), m_listHeadersEnabled(true),
m_toolBarFeeds(new FeedsToolBar(tr("Toolbar for feeds"), this)), m_toolBarMessages(new MessagesToolBar(tr("Toolbar for messages"), this)),
m_messagesView(new MessagesView(this)), m_feedsView(new FeedsView(this)),
FeedMessageViewer::FeedMessageViewer(QWidget* parent)
: TabContent(parent),
m_toolBarsEnabled(true),
m_listHeadersEnabled(true),
m_toolBarFeeds(new FeedsToolBar(tr("Toolbar for feeds"), this)),
m_toolBarMessages(new MessagesToolBar(tr("Toolbar for messages"), this)),
m_messagesView(new MessagesView(this)),
m_feedsView(new FeedsView(this)),
#if defined(USE_WEBENGINE) #if defined(USE_WEBENGINE)
m_messagesBrowser(new WebBrowser(this)) { m_messagesBrowser(new WebBrowser(this)) {
#else #else
m_messagesBrowser(new MessagePreviewer(this)) { m_messagesBrowser(new MessagePreviewer(this)) {
#endif #endif
initialize();
initializeViews(); initialize();
loadMessageViewerFonts(); initializeViews();
createConnections(); loadMessageViewerFonts();
createConnections();
} }
FeedMessageViewer::~FeedMessageViewer() { FeedMessageViewer::~FeedMessageViewer() {
qDebug("Destroying FeedMessageViewer instance."); qDebug("Destroying FeedMessageViewer instance.");
} }
#if defined(USE_WEBENGINE) #if defined(USE_WEBENGINE)
WebBrowser* FeedMessageViewer::webBrowser() const { WebBrowser* FeedMessageViewer::webBrowser() const {
return m_messagesBrowser; return m_messagesBrowser;
} }
#endif #endif
FeedsView* FeedMessageViewer::feedsView() const { FeedsView* FeedMessageViewer::feedsView() const {
return m_feedsView; return m_feedsView;
} }
MessagesView* FeedMessageViewer::messagesView() const { MessagesView* FeedMessageViewer::messagesView() const {
return m_messagesView; return m_messagesView;
} }
MessagesToolBar* FeedMessageViewer::messagesToolBar() const { MessagesToolBar* FeedMessageViewer::messagesToolBar() const {
return m_toolBarMessages; return m_toolBarMessages;
} }
FeedsToolBar* FeedMessageViewer::feedsToolBar() const { FeedsToolBar* FeedMessageViewer::feedsToolBar() const {
return m_toolBarFeeds; return m_toolBarFeeds;
} }
void FeedMessageViewer::saveSize() { void FeedMessageViewer::saveSize() {
Settings* settings = qApp->settings(); Settings* settings = qApp->settings();
m_feedsView->saveAllExpandStates();
// Store offsets of splitters. m_feedsView->saveAllExpandStates();
settings->setValue(GROUP(GUI), GUI::SplitterFeeds, QString(m_feedSplitter->saveState().toBase64()));
settings->setValue(GROUP(GUI), GUI::SplitterMessages, QString(m_messageSplitter->saveState().toBase64())); // Store offsets of splitters.
settings->setValue(GROUP(GUI), GUI::MessageViewState, QString(m_messagesView->header()->saveState().toBase64())); settings->setValue(GROUP(GUI), GUI::SplitterFeeds, QString(m_feedSplitter->saveState().toBase64()));
// Store "visibility" of toolbars and list headers. settings->setValue(GROUP(GUI), GUI::SplitterMessages, QString(m_messageSplitter->saveState().toBase64()));
settings->setValue(GROUP(GUI), GUI::ToolbarsVisible, m_toolBarsEnabled); settings->setValue(GROUP(GUI), GUI::MessageViewState, QString(m_messagesView->header()->saveState().toBase64()));
settings->setValue(GROUP(GUI), GUI::ListHeadersVisible, m_listHeadersEnabled);
// Store "visibility" of toolbars and list headers.
settings->setValue(GROUP(GUI), GUI::ToolbarsVisible, m_toolBarsEnabled);
settings->setValue(GROUP(GUI), GUI::ListHeadersVisible, m_listHeadersEnabled);
} }
void FeedMessageViewer::loadSize() { void FeedMessageViewer::loadSize() {
const Settings* settings = qApp->settings(); const Settings* settings = qApp->settings();
// Restore offsets of splitters.
m_feedSplitter->restoreState(QByteArray::fromBase64(settings->value(GROUP(GUI), SETTING(GUI::SplitterFeeds)).toString().toLocal8Bit())); // Restore offsets of splitters.
m_messageSplitter->restoreState(QByteArray::fromBase64(settings->value(GROUP(GUI), m_feedSplitter->restoreState(QByteArray::fromBase64(settings->value(GROUP(GUI), SETTING(GUI::SplitterFeeds)).toString().toLocal8Bit()));
SETTING(GUI::SplitterMessages)).toString().toLocal8Bit())); m_messageSplitter->restoreState(QByteArray::fromBase64(settings->value(GROUP(GUI),
m_messagesView->header()->restoreState(QByteArray::fromBase64(settings->value(GROUP(GUI), SETTING(GUI::SplitterMessages)).toString().toLocal8Bit()));
SETTING(GUI::MessageViewState)).toString().toLocal8Bit())); m_messagesView->header()->restoreState(QByteArray::fromBase64(settings->value(GROUP(GUI),
SETTING(GUI::MessageViewState)).toString().toLocal8Bit()));
} }
void FeedMessageViewer::loadMessageViewerFonts() { void FeedMessageViewer::loadMessageViewerFonts() {
m_messagesBrowser->reloadFontSettings(); m_messagesBrowser->reloadFontSettings();
} }
bool FeedMessageViewer::areToolBarsEnabled() const { bool FeedMessageViewer::areToolBarsEnabled() const {
return m_toolBarsEnabled; return m_toolBarsEnabled;
} }
bool FeedMessageViewer::areListHeadersEnabled() const { bool FeedMessageViewer::areListHeadersEnabled() const {
return m_listHeadersEnabled; return m_listHeadersEnabled;
} }
void FeedMessageViewer::switchMessageSplitterOrientation() { void FeedMessageViewer::switchMessageSplitterOrientation() {
if (m_messageSplitter->orientation() == Qt::Vertical) { if (m_messageSplitter->orientation() == Qt::Vertical) {
m_messageSplitter->setOrientation(Qt::Horizontal); m_messageSplitter->setOrientation(Qt::Horizontal);
} }
else { else {
m_messageSplitter->setOrientation(Qt::Vertical); m_messageSplitter->setOrientation(Qt::Vertical);
} }
} }
void FeedMessageViewer::setToolBarsEnabled(bool enable) { void FeedMessageViewer::setToolBarsEnabled(bool enable) {
m_toolBarsEnabled = enable; m_toolBarsEnabled = enable;
m_toolBarFeeds->setVisible(enable); m_toolBarFeeds->setVisible(enable);
m_toolBarMessages->setVisible(enable); m_toolBarMessages->setVisible(enable);
} }
void FeedMessageViewer::setListHeadersEnabled(bool enable) { void FeedMessageViewer::setListHeadersEnabled(bool enable) {
m_listHeadersEnabled = enable; m_listHeadersEnabled = enable;
m_feedsView->header()->setVisible(enable); m_feedsView->header()->setVisible(enable);
m_messagesView->header()->setVisible(enable); m_messagesView->header()->setVisible(enable);
} }
void FeedMessageViewer::switchFeedComponentVisibility() { void FeedMessageViewer::switchFeedComponentVisibility() {
QAction* sen = qobject_cast<QAction*>(sender()); QAction* sen = qobject_cast<QAction*>(sender());
if (sen != nullptr) { if (sen != nullptr) {
m_feedsWidget->setVisible(sen->isChecked()); m_feedsWidget->setVisible(sen->isChecked());
} }
else { else {
m_feedsWidget->setVisible(!m_feedsWidget->isVisible()); m_feedsWidget->setVisible(!m_feedsWidget->isVisible());
} }
} }
void FeedMessageViewer::toggleShowOnlyUnreadFeeds() { void FeedMessageViewer::toggleShowOnlyUnreadFeeds() {
const QAction* origin = qobject_cast<QAction*>(sender()); const QAction* origin = qobject_cast<QAction*>(sender());
if (origin == nullptr) { if (origin == nullptr) {
m_feedsView->model()->invalidateReadFeedsFilter(true, false); m_feedsView->model()->invalidateReadFeedsFilter(true, false);
} }
else { else {
m_feedsView->model()->invalidateReadFeedsFilter(true, origin->isChecked()); m_feedsView->model()->invalidateReadFeedsFilter(true, origin->isChecked());
} }
} }
void FeedMessageViewer::createConnections() { void FeedMessageViewer::createConnections() {
// Filtering & searching. // Filtering & searching.
connect(m_toolBarMessages, &MessagesToolBar::messageSearchPatternChanged, m_messagesView, &MessagesView::searchMessages); connect(m_toolBarMessages, &MessagesToolBar::messageSearchPatternChanged, m_messagesView, &MessagesView::searchMessages);
connect(m_toolBarMessages, &MessagesToolBar::messageFilterChanged, m_messagesView, &MessagesView::filterMessages); connect(m_toolBarMessages, &MessagesToolBar::messageFilterChanged, m_messagesView, &MessagesView::filterMessages);
#if defined(USE_WEBENGINE) #if defined(USE_WEBENGINE)
connect(m_messagesView, &MessagesView::currentMessageRemoved, m_messagesBrowser, &WebBrowser::clear); connect(m_messagesView, &MessagesView::currentMessageRemoved, m_messagesBrowser, &WebBrowser::clear);
connect(m_messagesView, &MessagesView::currentMessageChanged, m_messagesBrowser, &WebBrowser::loadMessage); connect(m_messagesView, &MessagesView::currentMessageChanged, m_messagesBrowser, &WebBrowser::loadMessage);
connect(m_messagesBrowser, &WebBrowser::markMessageRead, connect(m_messagesBrowser, &WebBrowser::markMessageRead, m_messagesView->sourceModel(), &MessagesModel::setMessageReadById);
m_messagesView->sourceModel(), &MessagesModel::setMessageReadById); connect(m_messagesBrowser, &WebBrowser::markMessageImportant, m_messagesView->sourceModel(), &MessagesModel::setMessageImportantById);
connect(m_messagesBrowser, &WebBrowser::markMessageImportant,
m_messagesView->sourceModel(), &MessagesModel::setMessageImportantById);
#else #else
connect(m_messagesView, &MessagesView::currentMessageRemoved, m_messagesBrowser, &MessagePreviewer::clear); connect(m_messagesView, &MessagesView::currentMessageRemoved, m_messagesBrowser, &MessagePreviewer::clear);
connect(m_messagesView, &MessagesView::currentMessageChanged, m_messagesBrowser, &MessagePreviewer::loadMessage); connect(m_messagesView, &MessagesView::currentMessageChanged, m_messagesBrowser, &MessagePreviewer::loadMessage);
connect(m_messagesBrowser, &MessagePreviewer::markMessageRead, connect(m_messagesBrowser, &MessagePreviewer::markMessageRead, m_messagesView->sourceModel(), &MessagesModel::setMessageReadById);
m_messagesView->sourceModel(), &MessagesModel::setMessageReadById); connect(m_messagesBrowser, &MessagePreviewer::markMessageImportant, m_messagesView->sourceModel(),
connect(m_messagesBrowser, &MessagePreviewer::markMessageImportant, &MessagesModel::setMessageImportantById);
m_messagesView->sourceModel(), &MessagesModel::setMessageImportantById);
#endif #endif
// If user selects feeds, load their messages.
connect(m_feedsView, &FeedsView::itemSelected, m_messagesView, &MessagesView::loadItem); // If user selects feeds, load their messages.
connect(m_feedsView, &FeedsView::itemSelected, m_messagesView, &MessagesView::loadItem);
connect(m_feedsView, &FeedsView::requestViewNextUnreadMessage, m_messagesView, &MessagesView::selectNextUnreadItem); connect(m_feedsView, &FeedsView::requestViewNextUnreadMessage, m_messagesView, &MessagesView::selectNextUnreadItem);
// State of many messages is changed, then we need // State of many messages is changed, then we need
// to reload selections. // to reload selections.
connect(m_feedsView->sourceModel(), &FeedsModel::reloadMessageListRequested, connect(m_feedsView->sourceModel(), &FeedsModel::reloadMessageListRequested, m_messagesView, &MessagesView::reloadSelections);
m_messagesView, &MessagesView::reloadSelections);
} }
void FeedMessageViewer::initialize() { void FeedMessageViewer::initialize() {
// Initialize/populate toolbars. // Initialize/populate toolbars.
m_toolBarFeeds->setFloatable(false); m_toolBarFeeds->setFloatable(false);
m_toolBarFeeds->setMovable(false); m_toolBarFeeds->setMovable(false);
m_toolBarFeeds->setAllowedAreas(Qt::TopToolBarArea); m_toolBarFeeds->setAllowedAreas(Qt::TopToolBarArea);
m_toolBarMessages->setFloatable(false); m_toolBarMessages->setFloatable(false);
m_toolBarMessages->setMovable(false); m_toolBarMessages->setMovable(false);
m_toolBarMessages->setAllowedAreas(Qt::TopToolBarArea); m_toolBarMessages->setAllowedAreas(Qt::TopToolBarArea);
m_toolBarFeeds->loadSavedActions(); m_toolBarFeeds->loadSavedActions();
m_toolBarMessages->loadSavedActions(); m_toolBarMessages->loadSavedActions();
m_messagesBrowser->clear(); m_messagesBrowser->clear();
// Now refresh visual setup.
refreshVisualProperties(); // Now refresh visual setup.
refreshVisualProperties();
} }
void FeedMessageViewer::initializeViews() { void FeedMessageViewer::initializeViews() {
m_feedsWidget = new QWidget(this); m_feedsWidget = new QWidget(this);
m_messagesWidget = new QWidget(this); m_messagesWidget = new QWidget(this);
m_feedSplitter = new QSplitter(Qt::Horizontal, this); m_feedSplitter = new QSplitter(Qt::Horizontal, this);
m_messageSplitter = new QSplitter(Qt::Vertical, this); m_messageSplitter = new QSplitter(Qt::Vertical, this);
// Instantiate needed components.
QVBoxLayout* central_layout = new QVBoxLayout(this); // Instantiate needed components.
QVBoxLayout* feed_layout = new QVBoxLayout(m_feedsWidget); QVBoxLayout* central_layout = new QVBoxLayout(this);
QVBoxLayout* message_layout = new QVBoxLayout(m_messagesWidget); QVBoxLayout* feed_layout = new QVBoxLayout(m_feedsWidget);
// Set layout properties. QVBoxLayout* message_layout = new QVBoxLayout(m_messagesWidget);
central_layout->setMargin(0);
central_layout->setSpacing(0); // Set layout properties.
feed_layout->setMargin(0); central_layout->setMargin(0);
feed_layout->setSpacing(0); central_layout->setSpacing(0);
message_layout->setMargin(0); feed_layout->setMargin(0);
message_layout->setSpacing(0); feed_layout->setSpacing(0);
// Set views. message_layout->setMargin(0);
m_feedsView->setFrameStyle(QFrame::NoFrame); message_layout->setSpacing(0);
m_messagesView->setFrameStyle(QFrame::NoFrame);
// Setup message splitter. // Set views.
m_messageSplitter->setObjectName(QSL("MessageSplitter")); m_feedsView->setFrameStyle(QFrame::NoFrame);
m_messageSplitter->setHandleWidth(1); m_messagesView->setFrameStyle(QFrame::NoFrame);
m_messageSplitter->setOpaqueResize(false);
m_messageSplitter->setChildrenCollapsible(false); // Setup message splitter.
m_messageSplitter->addWidget(m_messagesView); m_messageSplitter->setObjectName(QSL("MessageSplitter"));
m_messageSplitter->addWidget(m_messagesBrowser); m_messageSplitter->setHandleWidth(1);
// Assemble message-related components to single widget. m_messageSplitter->setOpaqueResize(false);
message_layout->addWidget(m_toolBarMessages); m_messageSplitter->setChildrenCollapsible(false);
message_layout->addWidget(m_messageSplitter); m_messageSplitter->addWidget(m_messagesView);
// Assemble feed-related components to another widget. m_messageSplitter->addWidget(m_messagesBrowser);
feed_layout->addWidget(m_toolBarFeeds);
feed_layout->addWidget(m_feedsView); // Assemble message-related components to single widget.
// Assembler everything together. message_layout->addWidget(m_toolBarMessages);
m_feedSplitter->setHandleWidth(1); message_layout->addWidget(m_messageSplitter);
m_feedSplitter->setOpaqueResize(false);
m_feedSplitter->setChildrenCollapsible(false); // Assemble feed-related components to another widget.
m_feedSplitter->addWidget(m_feedsWidget); feed_layout->addWidget(m_toolBarFeeds);
m_feedSplitter->addWidget(m_messagesWidget); feed_layout->addWidget(m_feedsView);
// Add toolbar and main feeds/messages widget to main layout.
central_layout->addWidget(m_feedSplitter); // Assembler everything together.
setTabOrder(m_feedsView, m_messagesView); m_feedSplitter->setHandleWidth(1);
setTabOrder(m_messagesView, m_toolBarFeeds); m_feedSplitter->setOpaqueResize(false);
setTabOrder(m_toolBarFeeds, m_toolBarMessages); m_feedSplitter->setChildrenCollapsible(false);
setTabOrder(m_toolBarMessages, m_messagesBrowser); m_feedSplitter->addWidget(m_feedsWidget);
m_feedSplitter->addWidget(m_messagesWidget);
// Add toolbar and main feeds/messages widget to main layout.
central_layout->addWidget(m_feedSplitter);
setTabOrder(m_feedsView, m_messagesView);
setTabOrder(m_messagesView, m_toolBarFeeds);
setTabOrder(m_toolBarFeeds, m_toolBarMessages);
setTabOrder(m_toolBarMessages, m_messagesBrowser);
} }
void FeedMessageViewer::refreshVisualProperties() { void FeedMessageViewer::refreshVisualProperties() {
const Qt::ToolButtonStyle button_style = static_cast<Qt::ToolButtonStyle>(qApp->settings()->value(GROUP(GUI), const Qt::ToolButtonStyle button_style =
SETTING(GUI::ToolbarStyle)).toInt()); static_cast<Qt::ToolButtonStyle>(qApp->settings()->value(GROUP(GUI), SETTING(GUI::ToolbarStyle)).toInt());
m_toolBarFeeds->setToolButtonStyle(button_style);
m_toolBarMessages->setToolButtonStyle(button_style); m_toolBarFeeds->setToolButtonStyle(button_style);
m_toolBarMessages->setToolButtonStyle(button_style);
} }

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>
// //
@ -41,79 +42,72 @@ class QSplitter;
class QProgressBar; class QProgressBar;
class FeedMessageViewer : public TabContent { class FeedMessageViewer : public TabContent {
Q_OBJECT Q_OBJECT
public: public:
// Constructors and destructors. explicit FeedMessageViewer(QWidget* parent = 0);
explicit FeedMessageViewer(QWidget* parent = 0); virtual ~FeedMessageViewer();
virtual ~FeedMessageViewer();
#if defined(USE_WEBENGINE) #if defined(USE_WEBENGINE)
WebBrowser* webBrowser() const; WebBrowser* webBrowser() const;
#endif #endif
FeedsView* feedsView() const; FeedsView* feedsView() const;
MessagesView* messagesView() const; MessagesView* messagesView() const;
MessagesToolBar* messagesToolBar() const; MessagesToolBar* messagesToolBar() const;
FeedsToolBar* feedsToolBar() const; FeedsToolBar* feedsToolBar() const;
bool areToolBarsEnabled() const; bool areToolBarsEnabled() const;
bool areListHeadersEnabled() const; bool areListHeadersEnabled() const;
public slots: public slots:
// Loads/saves sizes and states of ALL void saveSize();
// underlying widgets, this contains primarily void loadSize();
// splitters, toolbar and views.
void saveSize();
void loadSize();
void loadMessageViewerFonts(); void loadMessageViewerFonts();
// Switches orientation horizontal/vertical. // Switches orientation horizontal/vertical.
void switchMessageSplitterOrientation(); void switchMessageSplitterOrientation();
// Enables/disables main toolbars or list headers. // Enables/disables main toolbars or list headers.
void setToolBarsEnabled(bool enable); void setToolBarsEnabled(bool enable);
void setListHeadersEnabled(bool enable); void setListHeadersEnabled(bool enable);
// Reloads some changeable visual settings. // Reloads some changeable visual settings.
void refreshVisualProperties(); void refreshVisualProperties();
// Switches visibility of feed list and related // Switches visibility of feed list and related
// toolbar. // toolbar.
void switchFeedComponentVisibility(); void switchFeedComponentVisibility();
// Toggles displayed feeds. // Toggles displayed feeds.
void toggleShowOnlyUnreadFeeds(); void toggleShowOnlyUnreadFeeds();
protected: protected:
// Initializes some properties of the widget. void initialize();
void initialize();
// Initializes both messages/feeds views. // Initializes both messages/feeds views.
void initializeViews(); void initializeViews();
// Sets up connections. // Sets up connections.
void createConnections(); void createConnections();
private: private:
bool m_toolBarsEnabled; bool m_toolBarsEnabled;
bool m_listHeadersEnabled; bool m_listHeadersEnabled;
FeedsToolBar* m_toolBarFeeds; FeedsToolBar* m_toolBarFeeds;
MessagesToolBar* m_toolBarMessages; MessagesToolBar* m_toolBarMessages;
QSplitter* m_feedSplitter;
QSplitter* m_feedSplitter; QSplitter* m_messageSplitter;
QSplitter* m_messageSplitter; MessagesView* m_messagesView;
FeedsView* m_feedsView;
MessagesView* m_messagesView; QWidget* m_feedsWidget;
FeedsView* m_feedsView; QWidget* m_messagesWidget;
QWidget* m_feedsWidget;
QWidget* m_messagesWidget;
#if defined(USE_WEBENGINE) #if defined(USE_WEBENGINE)
WebBrowser* m_messagesBrowser; WebBrowser* m_messagesBrowser;
#else #else
MessagePreviewer* m_messagesBrowser; MessagePreviewer* m_messagesBrowser;
#endif #endif
}; };

View File

@ -20,87 +20,82 @@
#include "miscellaneous/application.h" #include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h" #include "miscellaneous/iconfactory.h"
#include <QtGlobal> #include <QCheckBox>
#include <QDialogButtonBox>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QPushButton> #include <QPushButton>
#include <QDialogButtonBox>
#include <QStyle> #include <QStyle>
#include <QCheckBox> #include <QtGlobal>
MessageBox::MessageBox(QWidget* parent) : QMessageBox(parent) { MessageBox::MessageBox(QWidget* parent) : QMessageBox(parent) {}
}
MessageBox::~MessageBox() { MessageBox::~MessageBox() {}
}
void MessageBox::setIcon(QMessageBox::Icon icon) { void MessageBox::setIcon(QMessageBox::Icon icon) {
// Determine correct status icon size. // Determine correct status icon size.
const int icon_size = qApp->style()->pixelMetric(QStyle::PM_MessageBoxIconSize, 0, this); const int icon_size = qApp->style()->pixelMetric(QStyle::PM_MessageBoxIconSize, 0, this);
// Setup status icon.
setIconPixmap(iconForStatus(icon).pixmap(icon_size, icon_size)); // Setup status icon.
setIconPixmap(iconForStatus(icon).pixmap(icon_size, icon_size));
} }
void MessageBox::setCheckBox(QMessageBox* msg_box, const QString& text, bool* data) { void MessageBox::setCheckBox(QMessageBox* msg_box, const QString& text, bool* data) {
// Add "don't show this again checkbox. // Add "don't show this again checkbox.
QCheckBox* check_box = new QCheckBox(msg_box); QCheckBox* check_box = new QCheckBox(msg_box);
check_box->setChecked(*data);
check_box->setText(text); check_box->setChecked(*data);
connect(check_box, &QCheckBox::toggled, [ = ](bool checked) { check_box->setText(text);
*data = checked; connect(check_box, &QCheckBox::toggled, [=](bool checked) {
}); *data = checked;
msg_box->setCheckBox(check_box); });
msg_box->setCheckBox(check_box);
} }
QIcon MessageBox::iconForStatus(QMessageBox::Icon status) { QIcon MessageBox::iconForStatus(QMessageBox::Icon status) {
switch (status) { switch (status) {
case QMessageBox::Information: case QMessageBox::Information:
return qApp->icons()->fromTheme(QSL("dialog-information")); return qApp->icons()->fromTheme(QSL("dialog-information"));
case QMessageBox::Warning: case QMessageBox::Warning:
return qApp->icons()->fromTheme(QSL("dialog-warning")); return qApp->icons()->fromTheme(QSL("dialog-warning"));
case QMessageBox::Critical: case QMessageBox::Critical:
return qApp->icons()->fromTheme(QSL("dialog-error")); return qApp->icons()->fromTheme(QSL("dialog-error"));
case QMessageBox::Question: case QMessageBox::Question:
return qApp->icons()->fromTheme(QSL("dialog-question")); return qApp->icons()->fromTheme(QSL("dialog-question"));
case QMessageBox::NoIcon: case QMessageBox::NoIcon:
default: default:
return QIcon(); return QIcon();
} }
} }
QMessageBox::StandardButton MessageBox::show(QWidget* parent, QMessageBox::StandardButton MessageBox::show(QWidget* parent, QMessageBox::Icon icon, const QString& title, const QString& text,
QMessageBox::Icon icon, const QString& informative_text, const QString& detailed_text, QMessageBox::StandardButtons buttons,
const QString& title, QMessageBox::StandardButton default_button, bool* dont_show_again) {
const QString& text, // Create and find needed components.
const QString& informative_text, MessageBox msg_box(parent);
const QString& detailed_text,
QMessageBox::StandardButtons buttons,
QMessageBox::StandardButton default_button,
bool* dont_show_again) {
// Create and find needed components.
MessageBox msg_box(parent);
// Initialize message box properties.
msg_box.setWindowTitle(title);
msg_box.setText(text);
msg_box.setInformativeText(informative_text);
msg_box.setDetailedText(detailed_text);
msg_box.setIcon(icon);
msg_box.setStandardButtons(buttons);
msg_box.setDefaultButton(default_button);
if (dont_show_again != nullptr) { // Initialize message box properties.
MessageBox::setCheckBox(&msg_box, tr("Do not show this dialog again."), dont_show_again); msg_box.setWindowTitle(title);
} msg_box.setText(text);
msg_box.setInformativeText(informative_text);
msg_box.setDetailedText(detailed_text);
msg_box.setIcon(icon);
msg_box.setStandardButtons(buttons);
msg_box.setDefaultButton(default_button);
// Display it. if (dont_show_again != nullptr) {
if (msg_box.exec() == -1) { MessageBox::setCheckBox(&msg_box, tr("Do not show this dialog again."), dont_show_again);
return QMessageBox::Cancel; }
}
else { // Display it.
return msg_box.standardButton(msg_box.clickedButton()); if (msg_box.exec() == -1) {
} return QMessageBox::Cancel;
}
else {
return msg_box.standardButton(msg_box.clickedButton());
}
} }

View File

@ -1,5 +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>
// //
// RSS Guard is free software: you can redistribute it and/or modify // RSS Guard is free software: you can redistribute it and/or modify
@ -17,175 +17,179 @@
#include "gui/messagesview.h" #include "gui/messagesview.h"
#include "core/messagesproxymodel.h"
#include "core/messagesmodel.h" #include "core/messagesmodel.h"
#include "miscellaneous/settings.h" #include "core/messagesproxymodel.h"
#include "gui/dialogs/formmain.h"
#include "gui/messagebox.h"
#include "gui/styleditemdelegatewithoutfocus.h"
#include "gui/treeviewcolumnsmenu.h"
#include "miscellaneous/externaltool.h"
#include "miscellaneous/feedreader.h" #include "miscellaneous/feedreader.h"
#include "miscellaneous/settings.h"
#include "network-web/networkfactory.h" #include "network-web/networkfactory.h"
#include "network-web/webfactory.h" #include "network-web/webfactory.h"
#include "gui/dialogs/formmain.h"
#include "miscellaneous/externaltool.h"
#include "gui/messagebox.h"
#include "gui/treeviewcolumnsmenu.h"
#include "gui/styleditemdelegatewithoutfocus.h"
#include <QFileIconProvider>
#include <QKeyEvent> #include <QKeyEvent>
#include <QMenu>
#include <QProcess>
#include <QScrollBar> #include <QScrollBar>
#include <QTimer> #include <QTimer>
#include <QMenu>
#include <QFileIconProvider>
#include <QProcess>
MessagesView::MessagesView(QWidget* parent) : QTreeView(parent), m_contextMenu(nullptr), m_columnsAdjusted(false) {
m_sourceModel = qApp->feedReader()->messagesModel();
m_proxyModel = qApp->feedReader()->messagesProxyModel();
MessagesView::MessagesView(QWidget* parent) // Forward count changes to the view.
: QTreeView(parent), m_contextMenu(nullptr), m_columnsAdjusted(false) { createConnections();
m_sourceModel = qApp->feedReader()->messagesModel(); setModel(m_proxyModel);
m_proxyModel = qApp->feedReader()->messagesProxyModel(); setupAppearance();
// Forward count changes to the view. header()->setContextMenuPolicy(Qt::CustomContextMenu);
createConnections(); connect(header(), &QHeaderView::customContextMenuRequested, [=](const QPoint& point) {
setModel(m_proxyModel); TreeViewColumnsMenu mm(header());
setupAppearance(); mm.exec(header()->mapToGlobal(point));
header()->setContextMenuPolicy(Qt::CustomContextMenu); });
connect(header(), &QHeaderView::customContextMenuRequested, [ = ](const QPoint & point) {
TreeViewColumnsMenu mm(header());
mm.exec(header()->mapToGlobal(point));
});
} }
MessagesView::~MessagesView() { MessagesView::~MessagesView() {
qDebug("Destroying MessagesView instance."); qDebug("Destroying MessagesView instance.");
} }
void MessagesView::sort(int column, Qt::SortOrder order, bool repopulate_data, bool change_header, bool emit_changed_from_header) { void MessagesView::sort(int column, Qt::SortOrder order, bool repopulate_data, bool change_header, bool emit_changed_from_header) {
if (change_header && !emit_changed_from_header) { if (change_header && !emit_changed_from_header) {
header()->blockSignals(true); header()->blockSignals(true);
} }
m_sourceModel->addSortState(column, order); m_sourceModel->addSortState(column, order);
if (repopulate_data) { if (repopulate_data) {
m_sourceModel->repopulate(); m_sourceModel->repopulate();
} }
if (change_header) { if (change_header) {
header()->setSortIndicator(column, order); header()->setSortIndicator(column, order);
header()->blockSignals(false); header()->blockSignals(false);
} }
} }
void MessagesView::createConnections() { void MessagesView::createConnections() {
connect(this, &MessagesView::doubleClicked, this, &MessagesView::openSelectedSourceMessagesExternally); connect(this, &MessagesView::doubleClicked, this, &MessagesView::openSelectedSourceMessagesExternally);
// Adjust columns when layout gets changed.
connect(header(), &QHeaderView::geometriesChanged, this, &MessagesView::adjustColumns); // Adjust columns when layout gets changed.
connect(header(), &QHeaderView::sortIndicatorChanged, this, &MessagesView::onSortIndicatorChanged); connect(header(), &QHeaderView::geometriesChanged, this, &MessagesView::adjustColumns);
connect(header(), &QHeaderView::sortIndicatorChanged, this, &MessagesView::onSortIndicatorChanged);
} }
void MessagesView::keyboardSearch(const QString& search) { void MessagesView::keyboardSearch(const QString& search) {
// WARNING: This is quite hacky way how to force selection of next item even // WARNING: This is quite hacky way how to force selection of next item even
// with extended selection enabled. // with extended selection enabled.
setSelectionMode(QAbstractItemView::SingleSelection); setSelectionMode(QAbstractItemView::SingleSelection);
QTreeView::keyboardSearch(search); QTreeView::keyboardSearch(search);
setSelectionMode(QAbstractItemView::ExtendedSelection); setSelectionMode(QAbstractItemView::ExtendedSelection);
} }
void MessagesView::reloadSelections() { void MessagesView::reloadSelections() {
const QDateTime dt1 = QDateTime::currentDateTime(); const QDateTime dt1 = QDateTime::currentDateTime();
QModelIndex current_index = selectionModel()->currentIndex(); QModelIndex current_index = selectionModel()->currentIndex();
const QModelIndex mapped_current_index = m_proxyModel->mapToSource(current_index); const QModelIndex mapped_current_index = m_proxyModel->mapToSource(current_index);
const Message selected_message = m_sourceModel->messageAt(mapped_current_index.row()); const Message selected_message = m_sourceModel->messageAt(mapped_current_index.row());
const int col = header()->sortIndicatorSection(); const int col = header()->sortIndicatorSection();
const Qt::SortOrder ord = header()->sortIndicatorOrder(); const Qt::SortOrder ord = header()->sortIndicatorOrder();
// Reload the model now.
sort(col, ord, true, false, false);
// Now, we must find the same previously focused message. // Reload the model now.
if (selected_message.m_id > 0) { sort(col, ord, true, false, false);
if (m_proxyModel->rowCount() == 0) {
current_index = QModelIndex();
}
else {
for (int i = 0; i < m_proxyModel->rowCount(); i++) {
QModelIndex msg_idx = m_proxyModel->index(i, MSG_DB_TITLE_INDEX);
Message msg = m_sourceModel->messageAt(m_proxyModel->mapToSource(msg_idx).row());
if (msg.m_id == selected_message.m_id) { // Now, we must find the same previously focused message.
current_index = msg_idx; if (selected_message.m_id > 0) {
break; if (m_proxyModel->rowCount() == 0) {
} current_index = QModelIndex();
}
else {
for (int i = 0; i < m_proxyModel->rowCount(); i++) {
QModelIndex msg_idx = m_proxyModel->index(i, MSG_DB_TITLE_INDEX);
Message msg = m_sourceModel->messageAt(m_proxyModel->mapToSource(msg_idx).row());
if (i == m_proxyModel->rowCount() - 1) { if (msg.m_id == selected_message.m_id) {
current_index = QModelIndex(); current_index = msg_idx;
} break;
} }
}
}
if (current_index.isValid()) { if (i == m_proxyModel->rowCount() - 1) {
scrollTo(current_index); current_index = QModelIndex();
setCurrentIndex(current_index); }
reselectIndexes(QModelIndexList() << current_index); }
} }
else { }
// Messages were probably removed from the model, nothing can
// be selected and no message can be displayed.
emit currentMessageRemoved();
}
const QDateTime dt2 = QDateTime::currentDateTime(); if (current_index.isValid()) {
qDebug("Reloading of msg selections took %lld miliseconds.", dt1.msecsTo(dt2)); scrollTo(current_index);
setCurrentIndex(current_index);
reselectIndexes(QModelIndexList() << current_index);
}
else {
// Messages were probably removed from the model, nothing can
// be selected and no message can be displayed.
emit currentMessageRemoved();
}
const QDateTime dt2 = QDateTime::currentDateTime();
qDebug("Reloading of msg selections took %lld miliseconds.", dt1.msecsTo(dt2));
} }
void MessagesView::setupAppearance() { void MessagesView::setupAppearance() {
setUniformRowHeights(true); setUniformRowHeights(true);
setAcceptDrops(false); setAcceptDrops(false);
setDragEnabled(false); setDragEnabled(false);
setDragDropMode(QAbstractItemView::NoDragDrop); setDragDropMode(QAbstractItemView::NoDragDrop);
setExpandsOnDoubleClick(false); setExpandsOnDoubleClick(false);
setRootIsDecorated(false); setRootIsDecorated(false);
setEditTriggers(QAbstractItemView::NoEditTriggers); setEditTriggers(QAbstractItemView::NoEditTriggers);
setItemsExpandable(false); setItemsExpandable(false);
setSortingEnabled(true); setSortingEnabled(true);
setAllColumnsShowFocus(false); setAllColumnsShowFocus(false);
setSelectionMode(QAbstractItemView::ExtendedSelection); setSelectionMode(QAbstractItemView::ExtendedSelection);
setItemDelegate(new StyledItemDelegateWithoutFocus(this)); setItemDelegate(new StyledItemDelegateWithoutFocus(this));
header()->setDefaultSectionSize(MESSAGES_VIEW_DEFAULT_COL); header()->setDefaultSectionSize(MESSAGES_VIEW_DEFAULT_COL);
header()->setMinimumSectionSize(MESSAGES_VIEW_MINIMUM_COL); header()->setMinimumSectionSize(MESSAGES_VIEW_MINIMUM_COL);
header()->setCascadingSectionResizes(false); header()->setCascadingSectionResizes(false);
header()->setStretchLastSection(true); header()->setStretchLastSection(true);
header()->setSortIndicatorShown(true); header()->setSortIndicatorShown(true);
} }
void MessagesView::keyPressEvent(QKeyEvent* event) { void MessagesView::keyPressEvent(QKeyEvent* event) {
QTreeView::keyPressEvent(event); QTreeView::keyPressEvent(event);
if (event->key() == Qt::Key_Delete) { if (event->key() == Qt::Key_Delete) {
deleteSelectedMessages(); deleteSelectedMessages();
} }
} }
void MessagesView::contextMenuEvent(QContextMenuEvent* event) { void MessagesView::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()) {
TreeViewColumnsMenu menu(header()); TreeViewColumnsMenu menu(header());
menu.exec(event->globalPos());
} menu.exec(event->globalPos());
else { }
// Context menu is not initialized, initialize. else {
initializeContextMenu(); // Context menu is not initialized, initialize.
m_contextMenu->exec(event->globalPos()); initializeContextMenu();
} m_contextMenu->exec(event->globalPos());
}
} }
void MessagesView::initializeContextMenu() { void MessagesView::initializeContextMenu() {
if (m_contextMenu == nullptr) { if (m_contextMenu == nullptr) {
m_contextMenu = new QMenu(tr("Context menu for messages"), this); m_contextMenu = new QMenu(tr("Context menu for messages"), this);
} }
m_contextMenu->clear(); m_contextMenu->clear();
QFileIconProvider icon_provider; QFileIconProvider icon_provider;
QMenu* menu = new QMenu(tr("Open with external tool"), m_contextMenu); QMenu* menu = new QMenu(tr("Open with external tool"), m_contextMenu);
menu->setIcon(qApp->icons()->fromTheme(QSL("document-open"))); menu->setIcon(qApp->icons()->fromTheme(QSL("document-open")));
foreach (const ExternalTool& tool, ExternalTool::toolsFromSettings()) { foreach (const ExternalTool& tool, ExternalTool::toolsFromSettings()) {
@ -201,307 +205,304 @@ void MessagesView::initializeContextMenu() {
if (menu->actions().isEmpty()) { if (menu->actions().isEmpty()) {
QAction* act_not_tools = new QAction("No external tools activated"); QAction* act_not_tools = new QAction("No external tools activated");
act_not_tools->setEnabled(false); act_not_tools->setEnabled(false);
menu->addAction(act_not_tools); menu->addAction(act_not_tools);
} }
m_contextMenu->addMenu(menu); m_contextMenu->addMenu(menu);
m_contextMenu->addActions(QList<QAction*>() << 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);
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);
} }
} }
void MessagesView::mousePressEvent(QMouseEvent* event) { void MessagesView::mousePressEvent(QMouseEvent* event) {
QTreeView::mousePressEvent(event); QTreeView::mousePressEvent(event);
switch (event->button()) { switch (event->button()) {
case Qt::LeftButton: { case Qt::LeftButton: {
// Make sure that message importance is switched when user // Make sure that message importance is switched when user
// clicks the "important" column. // clicks the "important" column.
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 = m_proxyModel->mapToSource(clicked_index); const QModelIndex mapped_index = m_proxyModel->mapToSource(clicked_index);
if (mapped_index.column() == MSG_DB_IMPORTANT_INDEX) { if (mapped_index.column() == MSG_DB_IMPORTANT_INDEX) {
if (m_sourceModel->switchMessageImportance(mapped_index.row())) { if (m_sourceModel->switchMessageImportance(mapped_index.row())) {
emit currentMessageChanged(m_sourceModel->messageAt(mapped_index.row()), m_sourceModel->loadedItem()); emit currentMessageChanged(m_sourceModel->messageAt(mapped_index.row()), m_sourceModel->loadedItem());
} }
} }
} }
break; break;
} }
case Qt::MiddleButton: { case Qt::MiddleButton: {
// Make sure that message importance is switched when user // Make sure that message importance is switched when user
// clicks the "important" column. // clicks the "important" column.
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 = m_proxyModel->mapToSource(clicked_index); const QModelIndex mapped_index = m_proxyModel->mapToSource(clicked_index);
const QString url = m_sourceModel->messageAt(mapped_index.row()).m_url; const QString url = m_sourceModel->messageAt(mapped_index.row()).m_url;
if (!url.isEmpty()) { if (!url.isEmpty()) {
qApp->mainForm()->tabWidget()->addLinkedBrowser(url); qApp->mainForm()->tabWidget()->addLinkedBrowser(url);
} }
} }
break; break;
} }
default: default:
break; break;
} }
} }
void MessagesView::selectionChanged(const QItemSelection& selected, const QItemSelection& deselected) { void MessagesView::selectionChanged(const QItemSelection& selected, const QItemSelection& deselected) {
const QModelIndexList selected_rows = selectionModel()->selectedRows(); const QModelIndexList selected_rows = selectionModel()->selectedRows();
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());
if (mapped_current_index.isValid() && selected_rows.count() > 0) { qDebug("Current row changed - row [%d,%d] source [%d, %d].",current_index.row(), current_index.column(),mapped_current_index.row(), mapped_current_index.column());
Message message = m_sourceModel->messageAt(m_proxyModel->mapToSource(current_index).row());
// Set this message as read only if current item
// wasn't changed by "mark selected messages unread" action.
m_sourceModel->setMessageRead(mapped_current_index.row(), RootItem::Read);
message.m_isRead = true;
emit currentMessageChanged(message, m_sourceModel->loadedItem());
}
else {
emit currentMessageRemoved();
}
if (qApp->settings()->value(GROUP(Messages), SETTING(Messages::KeepCursorInCenter)).toBool()) { if (mapped_current_index.isValid() && selected_rows.count() > 0) {
scrollTo(currentIndex(), QAbstractItemView::PositionAtCenter); Message message = m_sourceModel->messageAt(m_proxyModel->mapToSource(current_index).row());
}
QTreeView::selectionChanged(selected, deselected); // Set this message as read only if current item
// wasn't changed by "mark selected messages unread" action.
m_sourceModel->setMessageRead(mapped_current_index.row(), RootItem::Read);
message.m_isRead = true;
emit currentMessageChanged(message, m_sourceModel->loadedItem());
}
else {
emit currentMessageRemoved();
}
if (qApp->settings()->value(GROUP(Messages), SETTING(Messages::KeepCursorInCenter)).toBool()) {
scrollTo(currentIndex(), QAbstractItemView::PositionAtCenter);
}
QTreeView::selectionChanged(selected, deselected);
} }
void MessagesView::loadItem(RootItem* item) { void MessagesView::loadItem(RootItem* item) {
const int col = header()->sortIndicatorSection(); const int col = header()->sortIndicatorSection();
const Qt::SortOrder ord = header()->sortIndicatorOrder(); const Qt::SortOrder ord = header()->sortIndicatorOrder();
scrollToTop();
sort(col, ord, false, true, false); scrollToTop();
m_sourceModel->loadMessages(item); sort(col, ord, false, true, false);
// Messages are loaded, make sure that previously m_sourceModel->loadMessages(item);
// active message is not shown in browser.
// BUG: Qt 5 is probably bugged here. Selections // Messages are loaded, make sure that previously
// should be cleared automatically when SQL model is reset. // active message is not shown in browser.
emit currentMessageRemoved(); // BUG: Qt 5 is probably bugged here. Selections
// should be cleared automatically when SQL model is reset.
emit currentMessageRemoved();
} }
void MessagesView::openSelectedSourceMessagesExternally() { void MessagesView::openSelectedSourceMessagesExternally() {
foreach (const QModelIndex& index, selectionModel()->selectedRows()) { foreach (const QModelIndex& index, selectionModel()->selectedRows()) {
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"), qApp->showGuiMessage(tr("Problem with starting external web browser"),tr("External web browser could not be started."),QSystemTrayIcon::Critical);
tr("External web browser could not be started."), return;
QSystemTrayIcon::Critical); }
return; }
}
}
// Finally, mark opened messages as read. // Finally, mark opened messages as read.
if (!selectionModel()->selectedRows().isEmpty()) { if (!selectionModel()->selectedRows().isEmpty()) {
QTimer::singleShot(0, this, SLOT(markSelectedMessagesRead())); QTimer::singleShot(0, this, SLOT(markSelectedMessagesRead()));
} }
} }
void MessagesView::openSelectedMessagesInternally() { void MessagesView::openSelectedMessagesInternally() {
QList<Message> messages; QList<Message> messages;
foreach (const QModelIndex& index, selectionModel()->selectedRows()) { foreach (const QModelIndex& index, selectionModel()->selectedRows()) {
messages << m_sourceModel->messageAt(m_proxyModel->mapToSource(index).row()); messages << m_sourceModel->messageAt(m_proxyModel->mapToSource(index).row());
} }
if (!messages.isEmpty()) { if (!messages.isEmpty()) {
emit openMessagesInNewspaperView(m_sourceModel->loadedItem(), messages); emit openMessagesInNewspaperView(m_sourceModel->loadedItem(), messages);
} }
} }
void MessagesView::sendSelectedMessageViaEmail() { void MessagesView::sendSelectedMessageViaEmail() {
if (selectionModel()->selectedRows().size() == 1) { if (selectionModel()->selectedRows().size() == 1) {
const Message message = m_sourceModel->messageAt(m_proxyModel->mapToSource(selectionModel()->selectedRows().at(0)).row()); const Message message = m_sourceModel->messageAt(m_proxyModel->mapToSource(selectionModel()->selectedRows().at(0)).row());
if (!qApp->web()->sendMessageViaEmail(message)) { if (!qApp->web()->sendMessageViaEmail(message)) {
MessageBox::show(this, MessageBox::show(this,QMessageBox::Critical,tr("Problem with starting external e-mail client"),tr("External e-mail client could not be started."));
QMessageBox::Critical, }
tr("Problem with starting external e-mail client"), }
tr("External e-mail client could not be started."));
}
}
} }
void MessagesView::markSelectedMessagesRead() { void MessagesView::markSelectedMessagesRead() {
setSelectedMessagesReadStatus(RootItem::Read); setSelectedMessagesReadStatus(RootItem::Read);
} }
void MessagesView::markSelectedMessagesUnread() { void MessagesView::markSelectedMessagesUnread() {
setSelectedMessagesReadStatus(RootItem::Unread); setSelectedMessagesReadStatus(RootItem::Unread);
} }
void MessagesView::setSelectedMessagesReadStatus(RootItem::ReadStatus read) { void MessagesView::setSelectedMessagesReadStatus(RootItem::ReadStatus read) {
QModelIndex current_index = selectionModel()->currentIndex(); QModelIndex current_index = selectionModel()->currentIndex();
if (!current_index.isValid()) { if (!current_index.isValid()) {
return; return;
} }
QModelIndexList selected_indexes = selectionModel()->selectedRows(); QModelIndexList selected_indexes = selectionModel()->selectedRows();
const QModelIndexList mapped_indexes = m_proxyModel->mapListToSource(selected_indexes); const QModelIndexList mapped_indexes = m_proxyModel->mapListToSource(selected_indexes);
m_sourceModel->setBatchMessagesRead(mapped_indexes, read);
current_index = m_proxyModel->index(current_index.row(), current_index.column());
if (current_index.isValid()) { m_sourceModel->setBatchMessagesRead(mapped_indexes, read);
emit currentMessageChanged(m_sourceModel->messageAt(m_proxyModel->mapToSource(current_index).row()), m_sourceModel->loadedItem()); current_index = m_proxyModel->index(current_index.row(), current_index.column());
}
else { if (current_index.isValid()) {
emit currentMessageRemoved(); emit currentMessageChanged(m_sourceModel->messageAt(m_proxyModel->mapToSource(current_index).row()), m_sourceModel->loadedItem());
} }
else {
emit currentMessageRemoved();
}
} }
void MessagesView::deleteSelectedMessages() { void MessagesView::deleteSelectedMessages() {
QModelIndex current_index = selectionModel()->currentIndex(); QModelIndex current_index = selectionModel()->currentIndex();
if (!current_index.isValid()) { if (!current_index.isValid()) {
return; return;
} }
const QModelIndexList selected_indexes = selectionModel()->selectedRows(); const QModelIndexList selected_indexes = selectionModel()->selectedRows();
const QModelIndexList mapped_indexes = m_proxyModel->mapListToSource(selected_indexes); const QModelIndexList mapped_indexes = m_proxyModel->mapListToSource(selected_indexes);
m_sourceModel->setBatchMessagesDeleted(mapped_indexes);
current_index = moveCursor(QAbstractItemView::MoveDown, Qt::NoModifier);
if (current_index.isValid()) { m_sourceModel->setBatchMessagesDeleted(mapped_indexes);
setCurrentIndex(current_index); current_index = moveCursor(QAbstractItemView::MoveDown, Qt::NoModifier);
emit currentMessageChanged(m_sourceModel->messageAt(m_proxyModel->mapToSource(current_index).row()), m_sourceModel->loadedItem());
} if (current_index.isValid()) {
else { setCurrentIndex(current_index);
emit currentMessageRemoved();
} emit currentMessageChanged(m_sourceModel->messageAt(m_proxyModel->mapToSource(current_index).row()), m_sourceModel->loadedItem());
}
else {
emit currentMessageRemoved();
}
} }
void MessagesView::restoreSelectedMessages() { void MessagesView::restoreSelectedMessages() {
QModelIndex current_index = selectionModel()->currentIndex(); QModelIndex current_index = selectionModel()->currentIndex();
if (!current_index.isValid()) { if (!current_index.isValid()) {
return; return;
} }
const QModelIndexList selected_indexes = selectionModel()->selectedRows(); const QModelIndexList selected_indexes = selectionModel()->selectedRows();
const QModelIndexList mapped_indexes = m_proxyModel->mapListToSource(selected_indexes); const QModelIndexList mapped_indexes = m_proxyModel->mapListToSource(selected_indexes);
m_sourceModel->setBatchMessagesRestored(mapped_indexes);
current_index = m_proxyModel->index(current_index.row(), current_index.column());
if (current_index.isValid()) { m_sourceModel->setBatchMessagesRestored(mapped_indexes);
emit currentMessageChanged(m_sourceModel->messageAt(m_proxyModel->mapToSource(current_index).row()), m_sourceModel->loadedItem()); current_index = m_proxyModel->index(current_index.row(), current_index.column());
}
else { if (current_index.isValid()) {
emit currentMessageRemoved(); emit currentMessageChanged(m_sourceModel->messageAt(m_proxyModel->mapToSource(current_index).row()), m_sourceModel->loadedItem());
} }
else {
emit currentMessageRemoved();
}
} }
void MessagesView::switchSelectedMessagesImportance() { void MessagesView::switchSelectedMessagesImportance() {
QModelIndex current_index = selectionModel()->currentIndex(); QModelIndex current_index = selectionModel()->currentIndex();
if (!current_index.isValid()) { if (!current_index.isValid()) {
return; return;
} }
QModelIndexList selected_indexes = selectionModel()->selectedRows(); QModelIndexList selected_indexes = selectionModel()->selectedRows();
const QModelIndexList mapped_indexes = m_proxyModel->mapListToSource(selected_indexes); const QModelIndexList mapped_indexes = m_proxyModel->mapListToSource(selected_indexes);
m_sourceModel->switchBatchMessageImportance(mapped_indexes);
current_index = m_proxyModel->index(current_index.row(), current_index.column());
if (current_index.isValid()) { m_sourceModel->switchBatchMessageImportance(mapped_indexes);
emit currentMessageChanged(m_sourceModel->messageAt(m_proxyModel->mapToSource(current_index).row()), m_sourceModel->loadedItem()); current_index = m_proxyModel->index(current_index.row(), current_index.column());
}
else { if (current_index.isValid()) {
// Messages were probably removed from the model, nothing can emit currentMessageChanged(m_sourceModel->messageAt(m_proxyModel->mapToSource(current_index).row()), m_sourceModel->loadedItem());
// be selected and no message can be displayed. }
emit currentMessageRemoved(); else {
} // Messages were probably removed from the model, nothing can
// be selected and no message can be displayed.
emit currentMessageRemoved();
}
} }
void MessagesView::reselectIndexes(const QModelIndexList& indexes) { void MessagesView::reselectIndexes(const QModelIndexList& indexes) {
if (indexes.size() < RESELECT_MESSAGE_THRESSHOLD) { if (indexes.size() < RESELECT_MESSAGE_THRESSHOLD) {
QItemSelection selection; QItemSelection selection;
foreach (const QModelIndex& index, indexes) { foreach (const QModelIndex& index, indexes) {
selection.merge(QItemSelection(index, index), QItemSelectionModel::Select); selection.merge(QItemSelection(index, index), QItemSelectionModel::Select);
} }
selectionModel()->select(selection, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); selectionModel()->select(selection, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
} }
} }
void MessagesView::selectNextItem() { void MessagesView::selectNextItem() {
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);
selectionModel()->select(index_next, QItemSelectionModel::Select | QItemSelectionModel::Rows); selectionModel()->select(index_next, QItemSelectionModel::Select | QItemSelectionModel::Rows);
setFocus(); setFocus();
} }
} }
void MessagesView::selectPreviousItem() { void MessagesView::selectPreviousItem() {
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);
selectionModel()->select(index_previous, QItemSelectionModel::Select | QItemSelectionModel::Rows); selectionModel()->select(index_previous, QItemSelectionModel::Select | QItemSelectionModel::Rows);
setFocus(); setFocus();
} }
} }
void MessagesView::selectNextUnreadItem() { void MessagesView::selectNextUnreadItem() {
const QModelIndexList selected_rows = selectionModel()->selectedRows(); const QModelIndexList selected_rows = selectionModel()->selectedRows();
int active_row; int active_row;
if (!selected_rows.isEmpty()) { if (!selected_rows.isEmpty()) {
// Okay, something is selected, start from it. // Okay, something is selected, start from it.
active_row = selected_rows.at(0).row(); active_row = selected_rows.at(0).row();
} }
else { else {
active_row = 0; active_row = 0;
} }
const QModelIndex next_unread = m_proxyModel->getNextPreviousUnreadItemIndex(active_row); const QModelIndex next_unread = m_proxyModel->getNextPreviousUnreadItemIndex(active_row);
if (next_unread.isValid()) { if (next_unread.isValid()) {
// We found unread message, mark it. // We found unread message, mark it.
setCurrentIndex(next_unread); setCurrentIndex(next_unread);
selectionModel()->select(next_unread, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); selectionModel()->select(next_unread, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
setFocus(); setFocus();
} }
} }
void MessagesView::searchMessages(const QString& pattern) { void MessagesView::searchMessages(const QString& pattern) {
m_proxyModel->setFilterRegExp(pattern); m_proxyModel->setFilterRegExp(pattern);
if (selectionModel()->selectedRows().size() == 0) { if (selectionModel()->selectedRows().size() == 0) {
emit currentMessageRemoved(); emit currentMessageRemoved();
} }
else { else {
// Scroll to selected message, it could become scrolled out due to filter change. // Scroll to selected message, it could become scrolled out due to filter change.
scrollTo(selectionModel()->selectedRows().at(0)); scrollTo(selectionModel()->selectedRows().at(0));
} }
} }
void MessagesView::filterMessages(MessagesModel::MessageHighlighter filter) { void MessagesView::filterMessages(MessagesModel::MessageHighlighter filter) {
@ -519,8 +520,7 @@ 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()), qApp->showGuiMessage(tr("Cannot run external tool"), tr("External tool '%1' could not be started.").arg(tool.executable()),QSystemTrayIcon::Critical);
QSystemTrayIcon::Critical);
} }
} }
} }
@ -528,39 +528,42 @@ void MessagesView::openSelectedMessagesWithExternalTool() {
} }
void MessagesView::adjustColumns() { void MessagesView::adjustColumns() {
if (header()->count() > 0 && !m_columnsAdjusted) { if (header()->count() > 0 && !m_columnsAdjusted) {
m_columnsAdjusted = true; m_columnsAdjusted = true;
// Setup column resize strategies.
header()->setSectionResizeMode(MSG_DB_ID_INDEX, QHeaderView::Interactive); // Setup column resize strategies.
header()->setSectionResizeMode(MSG_DB_READ_INDEX, QHeaderView::ResizeToContents); header()->setSectionResizeMode(MSG_DB_ID_INDEX, QHeaderView::Interactive);
header()->setSectionResizeMode(MSG_DB_DELETED_INDEX, QHeaderView::Interactive); header()->setSectionResizeMode(MSG_DB_READ_INDEX, QHeaderView::ResizeToContents);
header()->setSectionResizeMode(MSG_DB_IMPORTANT_INDEX, QHeaderView::ResizeToContents); header()->setSectionResizeMode(MSG_DB_DELETED_INDEX, QHeaderView::Interactive);
header()->setSectionResizeMode(MSG_DB_FEED_TITLE_INDEX, QHeaderView::Interactive); header()->setSectionResizeMode(MSG_DB_IMPORTANT_INDEX, QHeaderView::ResizeToContents);
header()->setSectionResizeMode(MSG_DB_TITLE_INDEX, QHeaderView::Interactive); header()->setSectionResizeMode(MSG_DB_FEED_TITLE_INDEX, QHeaderView::Interactive);
header()->setSectionResizeMode(MSG_DB_URL_INDEX, QHeaderView::Interactive); header()->setSectionResizeMode(MSG_DB_TITLE_INDEX, QHeaderView::Interactive);
header()->setSectionResizeMode(MSG_DB_AUTHOR_INDEX, QHeaderView::Interactive); header()->setSectionResizeMode(MSG_DB_URL_INDEX, QHeaderView::Interactive);
header()->setSectionResizeMode(MSG_DB_DCREATED_INDEX, QHeaderView::Interactive); header()->setSectionResizeMode(MSG_DB_AUTHOR_INDEX, QHeaderView::Interactive);
header()->setSectionResizeMode(MSG_DB_CONTENTS_INDEX, QHeaderView::Interactive); header()->setSectionResizeMode(MSG_DB_DCREATED_INDEX, QHeaderView::Interactive);
header()->setSectionResizeMode(MSG_DB_PDELETED_INDEX, QHeaderView::Interactive); header()->setSectionResizeMode(MSG_DB_CONTENTS_INDEX, QHeaderView::Interactive);
//header()->resizeSection(MSG_DB_READ_INDEX, MESSAGES_VIEW_MINIMUM_COL); header()->setSectionResizeMode(MSG_DB_PDELETED_INDEX, QHeaderView::Interactive);
//header()->resizeSection(MSG_DB_IMPORTANT_INDEX, MESSAGES_VIEW_MINIMUM_COL);
// Hide columns. //header()->resizeSection(MSG_DB_READ_INDEX, MESSAGES_VIEW_MINIMUM_COL);
hideColumn(MSG_DB_ID_INDEX); //header()->resizeSection(MSG_DB_IMPORTANT_INDEX, MESSAGES_VIEW_MINIMUM_COL);
hideColumn(MSG_DB_DELETED_INDEX); // Hide columns.
hideColumn(MSG_DB_URL_INDEX); hideColumn(MSG_DB_ID_INDEX);
hideColumn(MSG_DB_CONTENTS_INDEX); hideColumn(MSG_DB_DELETED_INDEX);
hideColumn(MSG_DB_PDELETED_INDEX); hideColumn(MSG_DB_URL_INDEX);
hideColumn(MSG_DB_ENCLOSURES_INDEX); hideColumn(MSG_DB_CONTENTS_INDEX);
hideColumn(MSG_DB_ACCOUNT_ID_INDEX); hideColumn(MSG_DB_PDELETED_INDEX);
hideColumn(MSG_DB_CUSTOM_ID_INDEX); hideColumn(MSG_DB_ENCLOSURES_INDEX);
hideColumn(MSG_DB_CUSTOM_HASH_INDEX); hideColumn(MSG_DB_ACCOUNT_ID_INDEX);
hideColumn(MSG_DB_FEED_CUSTOM_ID_INDEX); hideColumn(MSG_DB_CUSTOM_ID_INDEX);
qDebug("Adjusting column resize modes for MessagesView."); hideColumn(MSG_DB_CUSTOM_HASH_INDEX);
} hideColumn(MSG_DB_FEED_CUSTOM_ID_INDEX);
qDebug("Adjusting column resize modes for MessagesView.");
}
} }
void MessagesView::onSortIndicatorChanged(int column, Qt::SortOrder order) { void MessagesView::onSortIndicatorChanged(int column, Qt::SortOrder order) {
// Repopulate the shit. // Repopulate the shit.
sort(column, order, true, false, false); sort(column, order, true, false, false);
emit currentMessageRemoved();
emit currentMessageRemoved();
} }

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,106 +23,101 @@
#include "services/abstract/rootitem.h" #include "services/abstract/rootitem.h"
#include <QTreeView>
#include <QHeaderView> #include <QHeaderView>
#include <QTreeView>
class MessagesProxyModel; class MessagesProxyModel;
class MessagesView : public QTreeView { class MessagesView : public QTreeView {
Q_OBJECT Q_OBJECT
public: public:
// Constructors and destructors. explicit MessagesView(QWidget* parent = 0);
explicit MessagesView(QWidget* parent = 0); virtual ~MessagesView();
virtual ~MessagesView();
// Model accessors. // Model accessors.
inline MessagesProxyModel* model() const { inline MessagesProxyModel* model() const {
return m_proxyModel; return m_proxyModel;
} }
inline MessagesModel* sourceModel() const { inline MessagesModel* sourceModel() const {
return m_sourceModel; return m_sourceModel;
} }
public slots: public slots:
void keyboardSearch(const QString& search); void keyboardSearch(const QString& search);
// Called after data got changed externally // Called after data got changed externally
// and it needs to be reloaded to the view. // and it needs to be reloaded to the view.
void reloadSelections(); void reloadSelections();
// Loads un-deleted messages from selected feeds. // Loads un-deleted messages from selected feeds.
void loadItem(RootItem* item); void loadItem(RootItem* item);
// Message manipulators. // Message manipulators.
void openSelectedSourceMessagesExternally(); void openSelectedSourceMessagesExternally();
void openSelectedMessagesInternally(); void openSelectedMessagesInternally();
void sendSelectedMessageViaEmail(); void sendSelectedMessageViaEmail();
// Works with SELECTED messages only. // Works with SELECTED messages only.
void setSelectedMessagesReadStatus(RootItem::ReadStatus read); void setSelectedMessagesReadStatus(RootItem::ReadStatus read);
void markSelectedMessagesRead(); void markSelectedMessagesRead();
void markSelectedMessagesUnread(); void markSelectedMessagesUnread();
void switchSelectedMessagesImportance(); void switchSelectedMessagesImportance();
void deleteSelectedMessages(); void deleteSelectedMessages();
void restoreSelectedMessages(); void restoreSelectedMessages();
void selectNextItem(); void selectNextItem();
void selectPreviousItem(); void selectPreviousItem();
void selectNextUnreadItem(); void selectNextUnreadItem();
// Searchs the visible message according to given pattern. // Searchs the visible message according to given pattern.
void searchMessages(const QString& pattern); void searchMessages(const QString& pattern);
void filterMessages(MessagesModel::MessageHighlighter filter); void filterMessages(MessagesModel::MessageHighlighter filter);
private slots: private slots:
void openSelectedMessagesWithExternalTool(); void openSelectedMessagesWithExternalTool();
// Marks given indexes as selected. // Marks given indexes as selected.
void reselectIndexes(const QModelIndexList& indexes); void reselectIndexes(const QModelIndexList& indexes);
// Changes resize mode for all columns. // Changes resize mode for all columns.
void adjustColumns(); void adjustColumns();
// Saves current sort state. // Saves current sort state.
void onSortIndicatorChanged(int column, Qt::SortOrder order); void onSortIndicatorChanged(int column, Qt::SortOrder order);
signals: signals:
// Link/message openers. void openLinkNewTab(const QString& link);
void openLinkNewTab(const QString& link); void openLinkMiniBrowser(const QString& link);
void openLinkMiniBrowser(const QString& link); void openMessagesInNewspaperView(RootItem* root, const QList<Message>& messages);
void openMessagesInNewspaperView(RootItem* root, const QList<Message>& messages);
// Notify others about message selections. // Notify others about message selections.
void currentMessageChanged(const Message& message, RootItem* root); void currentMessageChanged(const Message& message, RootItem* root);
void currentMessageRemoved(); void currentMessageRemoved();
private: private:
void sort(int column, Qt::SortOrder order, bool repopulate_data, bool change_header, bool emit_changed_from_header); void sort(int column, Qt::SortOrder order, bool repopulate_data, bool change_header, bool emit_changed_from_header);
// Creates needed connections. // Creates needed connections.
void createConnections(); void createConnections();
// Initializes context menu. // Initializes context menu.
void initializeContextMenu(); void initializeContextMenu();
// Sets up appearance. // Sets up appearance.
void setupAppearance(); void setupAppearance();
// Event reimplementations. // Event reimplementations.
void contextMenuEvent(QContextMenuEvent* event); void contextMenuEvent(QContextMenuEvent* event);
void mousePressEvent(QMouseEvent* event); void mousePressEvent(QMouseEvent* event);
void keyPressEvent(QKeyEvent* event); void keyPressEvent(QKeyEvent* event);
void selectionChanged(const QItemSelection& selected, const QItemSelection& deselected); void selectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
QMenu* m_contextMenu; QMenu* m_contextMenu;
MessagesProxyModel* m_proxyModel;
MessagesProxyModel* m_proxyModel; MessagesModel* m_sourceModel;
MessagesModel* m_sourceModel; bool m_columnsAdjusted;
bool m_columnsAdjusted;
}; };
#endif // MESSAGESVIEW_H #endif // MESSAGESVIEW_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,245 +19,252 @@
#include "gui/statusbar.h" #include "gui/statusbar.h"
#include "gui/dialogs/formmain.h" #include "gui/dialogs/formmain.h"
#include "gui/tabwidget.h"
#include "gui/plaintoolbutton.h" #include "gui/plaintoolbutton.h"
#include "miscellaneous/mutex.h" #include "gui/tabwidget.h"
#include "miscellaneous/iconfactory.h" #include "miscellaneous/iconfactory.h"
#include "miscellaneous/mutex.h"
#include <QToolButton>
#include <QLabel> #include <QLabel>
#include <QProgressBar> #include <QProgressBar>
#include <QToolButton>
StatusBar::StatusBar(QWidget* parent) : QStatusBar(parent), m_mutex(new Mutex(QMutex::NonRecursive, this)) { StatusBar::StatusBar(QWidget* parent) : QStatusBar(parent), m_mutex(new Mutex(QMutex::NonRecursive, this)) {
setSizeGripEnabled(false); setSizeGripEnabled(false);
setContentsMargins(2, 0, 2, 2); setContentsMargins(2, 0, 2, 2);
m_barProgressFeeds = new QProgressBar(this); m_barProgressFeeds = new QProgressBar(this);
m_barProgressFeeds->setTextVisible(false); m_barProgressFeeds->setTextVisible(false);
m_barProgressFeeds->setFixedWidth(100); m_barProgressFeeds->setFixedWidth(100);
m_barProgressFeeds->setVisible(false); m_barProgressFeeds->setVisible(false);
m_barProgressFeeds->setObjectName(QSL("m_barProgressFeeds")); m_barProgressFeeds->setObjectName(QSL("m_barProgressFeeds"));
m_barProgressFeedsAction = new QAction(qApp->icons()->fromTheme(QSL("application-rss+xml")), tr("Feed update progress bar"), this); m_barProgressFeedsAction = new QAction(qApp->icons()->fromTheme(QSL("application-rss+xml")),tr("Feed update progress bar"),this);
m_barProgressFeedsAction->setObjectName(QSL("m_barProgressFeedsAction")); m_barProgressFeedsAction->setObjectName(QSL("m_barProgressFeedsAction"));
m_lblProgressFeeds = new QLabel(this); m_lblProgressFeeds = new QLabel(this);
m_lblProgressFeeds->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); m_lblProgressFeeds->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
m_lblProgressFeeds->setVisible(false); m_lblProgressFeeds->setVisible(false);
m_lblProgressFeeds->setObjectName(QSL("m_lblProgressFeeds")); m_lblProgressFeeds->setObjectName(QSL("m_lblProgressFeeds"));
m_lblProgressFeedsAction = new QAction(qApp->icons()->fromTheme(QSL("application-rss+xml")), tr("Feed update label"), this); m_lblProgressFeedsAction = new QAction(qApp->icons()->fromTheme(QSL("application-rss+xml")), tr("Feed update label"),this);
m_lblProgressFeedsAction->setObjectName(QSL("m_lblProgressFeedsAction")); m_lblProgressFeedsAction->setObjectName(QSL("m_lblProgressFeedsAction"));
m_barProgressDownload = new QProgressBar(this); m_barProgressDownload = new QProgressBar(this);
m_barProgressDownload->setTextVisible(true); m_barProgressDownload->setTextVisible(true);
m_barProgressDownload->setFixedWidth(100); m_barProgressDownload->setFixedWidth(100);
m_barProgressDownload->setVisible(false); m_barProgressDownload->setVisible(false);
m_barProgressDownload->setObjectName(QSL("m_barProgressDownload")); m_barProgressDownload->setObjectName(QSL("m_barProgressDownload"));
m_barProgressDownloadAction = new QAction(qApp->icons()->fromTheme(QSL("emblem-downloads")), tr("File download progress bar"), this); m_barProgressDownloadAction = new QAction(qApp->icons()->fromTheme(QSL("emblem-downloads")),tr("File download progress bar"),this);
m_barProgressDownloadAction->setObjectName(QSL("m_barProgressDownloadAction")); m_barProgressDownloadAction->setObjectName(QSL("m_barProgressDownloadAction"));
m_lblProgressDownload = new QLabel(this); m_lblProgressDownload = new QLabel(this);
m_lblProgressDownload->setText("Downloading files in background"); m_lblProgressDownload->setText("Downloading files in background");
m_lblProgressDownload->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); m_lblProgressDownload->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
m_lblProgressDownload->setVisible(false); m_lblProgressDownload->setVisible(false);
m_lblProgressDownload->setObjectName(QSL("m_lblProgressDownload")); m_lblProgressDownload->setObjectName(QSL("m_lblProgressDownload"));
m_lblProgressDownloadAction = new QAction(qApp->icons()->fromTheme(QSL("emblem-downloads")), tr("File download label"), this); m_lblProgressDownloadAction = new QAction(qApp->icons()->fromTheme(QSL("emblem-downloads")), tr("File download label"), this);
m_lblProgressDownloadAction->setObjectName(QSL("m_lblProgressDownloadAction")); m_lblProgressDownloadAction->setObjectName(QSL("m_lblProgressDownloadAction"));
m_lblProgressDownload->installEventFilter(this); m_lblProgressDownload->installEventFilter(this);
m_barProgressDownload->installEventFilter(this); m_barProgressDownload->installEventFilter(this);
} }
StatusBar::~StatusBar() { StatusBar::~StatusBar() {
clear(); clear();
qDebug("Destroying StatusBar instance."); qDebug("Destroying StatusBar instance.");
} }
QList<QAction*> StatusBar::availableActions() const { QList<QAction*> StatusBar::availableActions() const {
QList<QAction*> actions = qApp->userActions(); QList<QAction*> actions = qApp->userActions();
// Now, add placeholder actions for custom stuff.
actions << m_barProgressDownloadAction << m_barProgressFeedsAction << // Now, add placeholder actions for custom stuff.
m_lblProgressDownloadAction << m_lblProgressFeedsAction; actions << m_barProgressDownloadAction << m_barProgressFeedsAction << m_lblProgressDownloadAction << m_lblProgressFeedsAction;
return actions;
return actions;
} }
QList<QAction*> StatusBar::changeableActions() const { QList<QAction*> StatusBar::changeableActions() const {
return actions(); return actions();
} }
void StatusBar::saveChangeableActions(const QStringList& actions) { void StatusBar::saveChangeableActions(const QStringList& actions) {
QMutexLocker locker(*m_mutex); QMutexLocker locker(*m_mutex);
qApp->settings()->setValue(GROUP(GUI), GUI::StatusbarActions, actions.join(QSL(",")));
loadSpecificActions(getSpecificActions(actions)); qApp->settings()->setValue(GROUP(GUI), GUI::StatusbarActions, actions.join(QSL(",")));
loadSpecificActions(getSpecificActions(actions));
} }
QStringList StatusBar::defaultActions() const { QStringList StatusBar::defaultActions() const {
return QString(GUI::StatusbarActionsDef).split(',', QString::SkipEmptyParts); return QString(GUI::StatusbarActionsDef).split(',', QString::SkipEmptyParts);
} }
QStringList StatusBar::savedActions() const { QStringList StatusBar::savedActions() const {
return qApp->settings()->value(GROUP(GUI), SETTING(GUI::StatusbarActions)).toString().split(',', QString::SkipEmptyParts); return qApp->settings()->value(GROUP(GUI), SETTING(GUI::StatusbarActions)).toString().split(',',QString::SkipEmptyParts);
} }
QList<QAction*> StatusBar::getSpecificActions(const QStringList& actions) { QList<QAction*> StatusBar::getSpecificActions(const QStringList& actions) {
bool progress_visible = this->actions().contains(m_barProgressFeedsAction) && bool progress_visible = this->actions().contains(m_barProgressFeedsAction) && m_lblProgressFeeds->isVisible() &&
m_lblProgressFeeds->isVisible() && m_barProgressFeeds->isVisible();
m_barProgressFeeds->isVisible();
QList<QAction*> available_actions = availableActions();
QList<QAction*> spec_actions;
// Iterate action names and add respectable actions into the toolbar. QList<QAction*> available_actions = availableActions();
foreach (const QString& action_name, actions) { QList<QAction*> spec_actions;
QAction* matching_action = findMatchingAction(action_name, available_actions);
QAction* action_to_add;
QWidget* widget_to_add;
if (matching_action == m_barProgressDownloadAction) { // Iterate action names and add respectable
widget_to_add = m_barProgressDownload; // actions into the toolbar.
action_to_add = m_barProgressDownloadAction; foreach (const QString& action_name, actions) {
widget_to_add->setVisible(false); QAction* matching_action = findMatchingAction(action_name, available_actions);
} QAction* action_to_add;
else if (matching_action == m_barProgressFeedsAction) { QWidget* widget_to_add;
widget_to_add = m_barProgressFeeds;
action_to_add = m_barProgressFeedsAction;
widget_to_add->setVisible(progress_visible);
}
else if (matching_action == m_lblProgressDownloadAction) {
widget_to_add = m_lblProgressDownload;
action_to_add = m_lblProgressDownloadAction;
widget_to_add->setVisible(false);
}
else if (matching_action == m_lblProgressFeedsAction) {
widget_to_add = m_lblProgressFeeds;
action_to_add = m_lblProgressFeedsAction;
widget_to_add->setVisible(progress_visible);
}
else {
if (action_name == SEPARATOR_ACTION_NAME) {
QLabel* lbl = new QLabel(QString::fromUtf8(""));
widget_to_add = lbl;
action_to_add = new QAction(this);
action_to_add->setSeparator(true);
action_to_add->setProperty("should_remove_action", true);
}
else if (action_name == SPACER_ACTION_NAME) {
QLabel* lbl = new QLabel(QSL("\t\t"));
widget_to_add = lbl;
action_to_add = new QAction(this);
action_to_add->setProperty("should_remove_action", true);
action_to_add->setIcon(qApp->icons()->fromTheme(QSL("system-search")));
action_to_add->setProperty("type", SPACER_ACTION_NAME);
action_to_add->setProperty("name", tr("Toolbar spacer"));
}
else if (matching_action != nullptr) {
// Add originally toolbar action.
PlainToolButton* tool_button = new PlainToolButton(this);
tool_button->reactOnActionChange(matching_action);
widget_to_add = tool_button;
action_to_add = matching_action;
connect(tool_button, &PlainToolButton::clicked, matching_action, &QAction::trigger);
connect(matching_action, &QAction::changed, tool_button, &PlainToolButton::reactOnSenderActionChange);
}
else {
action_to_add = nullptr;
widget_to_add = nullptr;
}
if (action_to_add != nullptr) { if (matching_action == m_barProgressDownloadAction) {
action_to_add->setProperty("should_remove_widget", true); widget_to_add = m_barProgressDownload;
} action_to_add = m_barProgressDownloadAction;
} widget_to_add->setVisible(false);
}
else if (matching_action == m_barProgressFeedsAction) {
widget_to_add = m_barProgressFeeds;
action_to_add = m_barProgressFeedsAction;
widget_to_add->setVisible(progress_visible);
}
else if (matching_action == m_lblProgressDownloadAction) {
widget_to_add = m_lblProgressDownload;
action_to_add = m_lblProgressDownloadAction;
widget_to_add->setVisible(false);
}
else if (matching_action == m_lblProgressFeedsAction) {
widget_to_add = m_lblProgressFeeds;
action_to_add = m_lblProgressFeedsAction;
widget_to_add->setVisible(progress_visible);
}
else {
if (action_name == SEPARATOR_ACTION_NAME) {
QLabel* lbl = new QLabel(QString::fromUtf8(""));
if (action_to_add != nullptr && widget_to_add != nullptr) { widget_to_add = lbl;
action_to_add->setProperty("widget", QVariant::fromValue((void*) widget_to_add)); action_to_add = new QAction(this);
spec_actions.append(action_to_add); action_to_add->setSeparator(true);
} action_to_add->setProperty("should_remove_action", true);
} }
else if (action_name == SPACER_ACTION_NAME) {
QLabel* lbl = new QLabel(QSL("\t\t"));
return spec_actions; widget_to_add = lbl;
action_to_add = new QAction(this);
action_to_add->setProperty("should_remove_action", true);
action_to_add->setIcon(qApp->icons()->fromTheme(QSL("system-search")));
action_to_add->setProperty("type", SPACER_ACTION_NAME);
action_to_add->setProperty("name", tr("Toolbar spacer"));
}
else if (matching_action != nullptr) {
// Add originally toolbar action.
PlainToolButton* tool_button = new PlainToolButton(this);
tool_button->reactOnActionChange(matching_action);
widget_to_add = tool_button;
action_to_add = matching_action;
connect(tool_button, &PlainToolButton::clicked, matching_action, &QAction::trigger);
connect(matching_action, &QAction::changed, tool_button,&PlainToolButton::reactOnSenderActionChange);
}
else {
action_to_add = nullptr;
widget_to_add = nullptr;
}
if (action_to_add != nullptr) {
action_to_add->setProperty("should_remove_widget", true);
}
}
if (action_to_add != nullptr && widget_to_add != nullptr) {
action_to_add->setProperty("widget", QVariant::fromValue((void*) widget_to_add));
spec_actions.append(action_to_add);
}
}
return spec_actions;
} }
void StatusBar::loadSpecificActions(const QList<QAction*>& actions) { void StatusBar::loadSpecificActions(const QList<QAction*>& actions) {
foreach (QAction* act, this->actions()) { foreach (QAction* act, this->actions()) {
QWidget* widget = act->property("widget").isValid() ? static_cast<QWidget*>(act->property("widget").value<void*>()) : nullptr; QWidget* widget = act->property("widget").isValid() ? static_cast<QWidget*>(act->property("widget").value<void*>()) : nullptr;
if (widget != nullptr) { if (widget != nullptr) {
removeWidget(widget); removeWidget(widget);
} }
} }
removeWidget(m_barProgressDownload); removeWidget(m_barProgressDownload);
removeWidget(m_barProgressFeeds); removeWidget(m_barProgressFeeds);
removeWidget(m_lblProgressDownload); removeWidget(m_lblProgressDownload);
removeWidget(m_lblProgressFeeds); removeWidget(m_lblProgressFeeds);
clear(); clear();
foreach (QAction* act, actions) { foreach (QAction* act, actions) {
QWidget* widget = act->property("widget").isValid() ? static_cast<QWidget*>(act->property("widget").value<void*>()) : nullptr; QWidget* widget = act->property("widget").isValid() ? static_cast<QWidget*>(act->property("widget").value<void*>()) : nullptr;
addAction(act);
// And also add widget. addAction(act);
if (widget != nullptr) {
addPermanentWidget(widget); // And also add widget.
} if (widget != nullptr) {
} addPermanentWidget(widget);
}
}
} }
bool StatusBar::eventFilter(QObject* watched, QEvent* event) { bool StatusBar::eventFilter(QObject* watched, QEvent* event) {
if (watched == m_lblProgressDownload || watched == m_barProgressDownload) { if (watched == m_lblProgressDownload || watched == m_barProgressDownload) {
if (event->type() == QEvent::MouseButtonPress) { if (event->type() == QEvent::MouseButtonPress) {
qApp->mainForm()->tabWidget()->showDownloadManager(); qApp->mainForm()->tabWidget()->showDownloadManager();
} }
} }
return false; return false;
} }
void StatusBar::clear() { void StatusBar::clear() {
while (!actions().isEmpty()) { while (!actions().isEmpty()) {
QAction* act = actions().at(0); QAction* act = actions().at(0);
QWidget* widget = act->property("widget").isValid() ? static_cast<QWidget*>(act->property("widget").value<void*>()) : nullptr; QWidget* widget = act->property("widget").isValid() ? static_cast<QWidget*>(act->property("widget").value<void*>()) : nullptr;
bool should_remove_widget = act->property("should_remove_widget").isValid(); bool should_remove_widget = act->property("should_remove_widget").isValid();
bool should_remove_action = act->property("should_remove_action").isValid(); bool should_remove_action = act->property("should_remove_action").isValid();
removeAction(act);
if (widget != nullptr) { removeAction(act);
removeWidget(widget);
widget->setVisible(false);
if (should_remove_widget) { if (widget != nullptr) {
widget->deleteLater(); removeWidget(widget);
} widget->setVisible(false);
if (should_remove_action) { if (should_remove_widget) {
act->deleteLater(); widget->deleteLater();
} }
}
} if (should_remove_action) {
act->deleteLater();
}
}
}
} }
void StatusBar::showProgressFeeds(int progress, const QString& label) { void StatusBar::showProgressFeeds(int progress, const QString& label) {
if (actions().contains(m_barProgressFeedsAction)) { if (actions().contains(m_barProgressFeedsAction)) {
m_lblProgressFeeds->setVisible(true); m_lblProgressFeeds->setVisible(true);
m_barProgressFeeds->setVisible(true); m_barProgressFeeds->setVisible(true);
m_lblProgressFeeds->setText(label); m_lblProgressFeeds->setText(label);
m_barProgressFeeds->setValue(progress); m_barProgressFeeds->setValue(progress);
} }
} }
void StatusBar::clearProgressFeeds() { void StatusBar::clearProgressFeeds() {
m_lblProgressFeeds->setVisible(false); m_lblProgressFeeds->setVisible(false);
m_barProgressFeeds->setVisible(false); m_barProgressFeeds->setVisible(false);
} }
void StatusBar::showProgressDownload(int progress, const QString& tooltip) { void StatusBar::showProgressDownload(int progress, const QString& tooltip) {
if (actions().contains(m_barProgressDownloadAction)) { if (actions().contains(m_barProgressDownloadAction)) {
m_lblProgressDownload->setVisible(true); m_lblProgressDownload->setVisible(true);
m_barProgressDownload->setVisible(true); m_barProgressDownload->setVisible(true);
m_barProgressDownload->setValue(progress); m_barProgressDownload->setValue(progress);
m_barProgressDownload->setToolTip(tooltip); m_barProgressDownload->setToolTip(tooltip);
m_lblProgressDownload->setToolTip(tooltip); m_lblProgressDownload->setToolTip(tooltip);
} }
} }
void StatusBar::clearProgressDownload() { void StatusBar::clearProgressDownload() {
m_lblProgressDownload->setVisible(false); m_lblProgressDownload->setVisible(false);
m_barProgressDownload->setVisible(false); m_barProgressDownload->setVisible(false);
m_barProgressDownload->setValue(0); m_barProgressDownload->setValue(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>
// //
@ -22,55 +23,48 @@
#include "gui/basetoolbar.h" #include "gui/basetoolbar.h"
class QProgressBar; class QProgressBar;
class PlainToolButton; class PlainToolButton;
class QLabel; class QLabel;
class Mutex; class Mutex;
class StatusBar : public QStatusBar, public BaseBar { class StatusBar : public QStatusBar, public BaseBar {
Q_OBJECT Q_OBJECT
public: public:
// Constructors and destructors. explicit StatusBar(QWidget* parent = 0);
explicit StatusBar(QWidget* parent = 0); virtual ~StatusBar();
virtual ~StatusBar();
QList<QAction*> availableActions() const; QList<QAction*> availableActions() const;
QList<QAction*> changeableActions() const; QList<QAction*> changeableActions() const;
void saveChangeableActions(const QStringList& actions); void saveChangeableActions(const QStringList& actions);
QStringList defaultActions() const; QStringList defaultActions() const;
QStringList savedActions() const; QStringList savedActions() const;
QList<QAction*> getSpecificActions(const QStringList& actions); QList<QAction*> getSpecificActions(const QStringList& actions);
void loadSpecificActions(const QList<QAction*>& actions); void loadSpecificActions(const QList<QAction*>& actions);
public slots: public slots:
// Progress bar operations void showProgressFeeds(int progress, const QString& label);
void showProgressFeeds(int progress, const QString& label); void clearProgressFeeds();
void clearProgressFeeds();
void showProgressDownload(int progress, const QString& tooltip); void showProgressDownload(int progress, const QString& tooltip);
void clearProgressDownload(); void clearProgressDownload();
protected: protected:
bool eventFilter(QObject* watched, QEvent* event); bool eventFilter(QObject* watched, QEvent* event);
private: private:
void clear(); void clear();
Mutex* m_mutex; Mutex* m_mutex;
QProgressBar* m_barProgressFeeds;
QProgressBar* m_barProgressFeeds; QAction* m_barProgressFeedsAction;
QAction* m_barProgressFeedsAction; QLabel* m_lblProgressFeeds;
QAction* m_lblProgressFeedsAction;
QLabel* m_lblProgressFeeds; QProgressBar* m_barProgressDownload;
QAction* m_lblProgressFeedsAction; QAction* m_barProgressDownloadAction;
QLabel* m_lblProgressDownload;
QProgressBar* m_barProgressDownload; QAction* m_lblProgressDownloadAction;
QAction* m_barProgressDownloadAction;
QLabel* m_lblProgressDownload;
QAction* m_lblProgressDownloadAction;
}; };
#endif // STATUSBAR_H #endif // STATUSBAR_H

View File

@ -17,12 +17,12 @@
#include "services/owncloud/network/owncloudnetworkfactory.h" #include "services/owncloud/network/owncloudnetworkfactory.h"
#include "services/owncloud/definitions.h"
#include "network-web/networkfactory.h"
#include "miscellaneous/application.h" #include "miscellaneous/application.h"
#include "miscellaneous/settings.h" #include "miscellaneous/settings.h"
#include "miscellaneous/textfactory.h" #include "miscellaneous/textfactory.h"
#include "network-web/networkfactory.h"
#include "services/abstract/rootitem.h" #include "services/abstract/rootitem.h"
#include "services/owncloud/definitions.h"
#include "services/owncloud/owncloudcategory.h" #include "services/owncloud/owncloudcategory.h"
#include "services/owncloud/owncloudfeed.h" #include "services/owncloud/owncloudfeed.h"
@ -33,298 +33,327 @@
OwnCloudNetworkFactory::OwnCloudNetworkFactory() OwnCloudNetworkFactory::OwnCloudNetworkFactory()
: m_url(QString()), m_fixedUrl(QString()), m_forceServerSideUpdate(false), : m_url(QString()), m_fixedUrl(QString()), m_forceServerSideUpdate(false),
m_authUsername(QString()), m_authPassword(QString()), m_batchSize(-1), m_urlUser(QString()), m_urlStatus(QString()), m_authUsername(QString()), m_authPassword(QString()), m_batchSize(-1), m_urlUser(QString()), m_urlStatus(QString()),
m_urlFolders(QString()), m_urlFeeds(QString()), m_urlMessages(QString()), m_urlFeedsUpdate(QString()), m_urlFolders(QString()), m_urlFeeds(QString()), m_urlMessages(QString()), m_urlFeedsUpdate(QString()),
m_urlDeleteFeed(QString()), m_urlRenameFeed(QString()), m_userId(QString()) { m_urlDeleteFeed(QString()), m_urlRenameFeed(QString()), m_userId(QString()) {}
}
OwnCloudNetworkFactory::~OwnCloudNetworkFactory() { OwnCloudNetworkFactory::~OwnCloudNetworkFactory() {}
}
QString OwnCloudNetworkFactory::url() const { QString OwnCloudNetworkFactory::url() const {
return m_url; return m_url;
} }
void OwnCloudNetworkFactory::setUrl(const QString& url) { void OwnCloudNetworkFactory::setUrl(const QString& url) {
m_url = url; m_url = url;
if (url.endsWith('/')) { if (url.endsWith('/')
m_fixedUrl = url; ) {
} m_fixedUrl = url;
else { }
m_fixedUrl = url + '/'; else {
} m_fixedUrl = url + '/';
}
// Store endpoints. // Store endpoints.
m_urlUser = m_fixedUrl + API_PATH + "user"; m_urlUser = m_fixedUrl + API_PATH + "user";
m_urlStatus = m_fixedUrl + API_PATH + "status"; m_urlStatus = m_fixedUrl + API_PATH + "status";
m_urlFolders = m_fixedUrl + API_PATH + "folders"; m_urlFolders = m_fixedUrl + API_PATH + "folders";
m_urlFeeds = m_fixedUrl + API_PATH + "feeds"; m_urlFeeds = m_fixedUrl + API_PATH + "feeds";
m_urlMessages = m_fixedUrl + API_PATH + "items?id=%1&batchSize=%2&type=%3"; m_urlMessages = m_fixedUrl + API_PATH + "items?id=%1&batchSize=%2&type=%3";
m_urlFeedsUpdate = m_fixedUrl + API_PATH + "feeds/update?userId=%1&feedId=%2"; m_urlFeedsUpdate = m_fixedUrl + API_PATH + "feeds/update?userId=%1&feedId=%2";
m_urlDeleteFeed = m_fixedUrl + API_PATH + "feeds/%1"; m_urlDeleteFeed = m_fixedUrl + API_PATH + "feeds/%1";
m_urlRenameFeed = m_fixedUrl + API_PATH + "feeds/%1/rename"; m_urlRenameFeed = m_fixedUrl + API_PATH + "feeds/%1/rename";
setUserId(QString()); setUserId(QString());
} }
bool OwnCloudNetworkFactory::forceServerSideUpdate() const { bool OwnCloudNetworkFactory::forceServerSideUpdate() const {
return m_forceServerSideUpdate; return m_forceServerSideUpdate;
} }
void OwnCloudNetworkFactory::setForceServerSideUpdate(bool force_update) { void OwnCloudNetworkFactory::setForceServerSideUpdate(bool force_update) {
m_forceServerSideUpdate = force_update; m_forceServerSideUpdate = force_update;
} }
QString OwnCloudNetworkFactory::authUsername() const { QString OwnCloudNetworkFactory::authUsername() const {
return m_authUsername; return m_authUsername;
} }
void OwnCloudNetworkFactory::setAuthUsername(const QString& auth_username) { void OwnCloudNetworkFactory::setAuthUsername(const QString& auth_username) {
m_authUsername = auth_username; m_authUsername = auth_username;
setUserId(QString()); setUserId(QString());
} }
QString OwnCloudNetworkFactory::authPassword() const { QString OwnCloudNetworkFactory::authPassword() const {
return m_authPassword; return m_authPassword;
} }
void OwnCloudNetworkFactory::setAuthPassword(const QString& auth_password) { void OwnCloudNetworkFactory::setAuthPassword(const QString& auth_password) {
m_authPassword = auth_password; m_authPassword = auth_password;
setUserId(QString()); setUserId(QString());
} }
QNetworkReply::NetworkError OwnCloudNetworkFactory::lastError() const { QNetworkReply::NetworkError OwnCloudNetworkFactory::lastError() const {
return m_lastError; return m_lastError;
} }
OwnCloudUserResponse OwnCloudNetworkFactory::userInfo() { OwnCloudUserResponse OwnCloudNetworkFactory::userInfo() {
QByteArray result_raw; QByteArray result_raw;
NetworkResult network_reply = NetworkFactory::performNetworkOperation(m_urlUser, NetworkResult network_reply = NetworkFactory::performNetworkOperation(m_urlUser,
qApp->settings()->value(GROUP(Feeds), qApp->settings()->value(GROUP(Feeds),
SETTING(Feeds::UpdateTimeout)).toInt(), SETTING(Feeds::UpdateTimeout)).toInt(),
QByteArray(), QString(), result_raw, QByteArray(), QString(), result_raw,
QNetworkAccessManager::GetOperation, QNetworkAccessManager::GetOperation,
true, m_authUsername, m_authPassword, true, m_authUsername, m_authPassword,
true); true);
OwnCloudUserResponse user_response(QString::fromUtf8(result_raw)); OwnCloudUserResponse user_response(QString::fromUtf8(result_raw));
if (network_reply.first != QNetworkReply::NoError) { if (network_reply.first != QNetworkReply::NoError
qWarning("ownCloud: Obtaining user info failed with error %d.", network_reply.first); ) {
} qWarning("ownCloud: Obtaining user info failed with error %d.", network_reply.first);
}
m_lastError = network_reply.first; m_lastError = network_reply.first;
return user_response; return user_response;
} }
OwnCloudStatusResponse OwnCloudNetworkFactory::status() { OwnCloudStatusResponse OwnCloudNetworkFactory::status() {
QByteArray result_raw; QByteArray result_raw;
NetworkResult network_reply = NetworkFactory::performNetworkOperation(m_urlStatus, NetworkResult network_reply = NetworkFactory::performNetworkOperation(m_urlStatus,
qApp->settings()->value(GROUP(Feeds), qApp->settings()->value(GROUP(Feeds),
SETTING(Feeds::UpdateTimeout)).toInt(), SETTING(Feeds::UpdateTimeout)).toInt(),
QByteArray(), QString(), result_raw, QByteArray(), QString(), result_raw,
QNetworkAccessManager::GetOperation, QNetworkAccessManager::GetOperation,
true, m_authUsername, m_authPassword, true, m_authUsername, m_authPassword,
true); true);
OwnCloudStatusResponse status_response(QString::fromUtf8(result_raw)); OwnCloudStatusResponse status_response(QString::fromUtf8(result_raw));
if (network_reply.first != QNetworkReply::NoError) { if (network_reply.first != QNetworkReply::NoError
qWarning("ownCloud: Obtaining status info failed with error %d.", network_reply.first); ) {
} qWarning("ownCloud: Obtaining status info failed with error %d.", network_reply.first);
}
m_lastError = network_reply.first; m_lastError = network_reply.first;
return status_response; return status_response;
} }
OwnCloudGetFeedsCategoriesResponse OwnCloudNetworkFactory::feedsCategories() { OwnCloudGetFeedsCategoriesResponse OwnCloudNetworkFactory::feedsCategories() {
QByteArray result_raw; QByteArray result_raw;
NetworkResult network_reply = NetworkFactory::performNetworkOperation(m_urlFolders, NetworkResult network_reply = NetworkFactory::performNetworkOperation(m_urlFolders,
qApp->settings()->value(GROUP(Feeds), qApp->settings()->value(GROUP(Feeds),
SETTING(Feeds::UpdateTimeout)).toInt(), SETTING(Feeds::UpdateTimeout)).toInt(),
QByteArray(), QString(), result_raw, QByteArray(), QString(), result_raw,
QNetworkAccessManager::GetOperation, QNetworkAccessManager::GetOperation,
true, m_authUsername, m_authPassword, true, m_authUsername, m_authPassword,
true); true);
if (network_reply.first != QNetworkReply::NoError) { if (network_reply.first != QNetworkReply::NoError
qWarning("ownCloud: Obtaining of categories failed with error %d.", network_reply.first); ) {
m_lastError = network_reply.first; qWarning("ownCloud: Obtaining of categories failed with error %d.", network_reply.first);
return OwnCloudGetFeedsCategoriesResponse(); m_lastError = network_reply.first;
} return OwnCloudGetFeedsCategoriesResponse();
}
QString content_categories = QString::fromUtf8(result_raw); QString content_categories = QString::fromUtf8(result_raw);
// Now, obtain feeds.
network_reply = NetworkFactory::performNetworkOperation(m_urlFeeds,
qApp->settings()->value(GROUP(Feeds),
SETTING(Feeds::UpdateTimeout)).toInt(),
QByteArray(), QString(), result_raw,
QNetworkAccessManager::GetOperation,
true, m_authUsername, m_authPassword,
true);
if (network_reply.first != QNetworkReply::NoError) {
qWarning("ownCloud: Obtaining of feeds failed with error %d.", network_reply.first);
m_lastError = network_reply.first;
return OwnCloudGetFeedsCategoriesResponse();
}
QString content_feeds = QString::fromUtf8(result_raw); // Now, obtain feeds.
m_lastError = network_reply.first; network_reply = NetworkFactory::performNetworkOperation(m_urlFeeds,
return OwnCloudGetFeedsCategoriesResponse(content_categories, content_feeds); qApp->settings()->value(GROUP(Feeds),
SETTING(Feeds::UpdateTimeout)).toInt(),
QByteArray(), QString(), result_raw,
QNetworkAccessManager::GetOperation,
true, m_authUsername, m_authPassword,
true);
if (network_reply.first != QNetworkReply::NoError
) {
qWarning("ownCloud: Obtaining of feeds failed with error %d.", network_reply.first);
m_lastError = network_reply.first;
return OwnCloudGetFeedsCategoriesResponse();
}
QString content_feeds = QString::fromUtf8(result_raw);
m_lastError = network_reply.first;
return OwnCloudGetFeedsCategoriesResponse(content_categories, content_feeds);
} }
bool OwnCloudNetworkFactory::deleteFeed(int feed_id) { bool OwnCloudNetworkFactory::deleteFeed(int feed_id) {
QString final_url = m_urlDeleteFeed.arg(QString::number(feed_id)); QString final_url = m_urlDeleteFeed.arg(QString::number(feed_id));
QByteArray raw_output; QByteArray raw_output;
NetworkResult network_reply = NetworkFactory::performNetworkOperation(final_url, NetworkResult network_reply = NetworkFactory::performNetworkOperation(final_url,
qApp->settings()->value(GROUP(Feeds), qApp->settings()->value(GROUP(Feeds),
SETTING(Feeds::UpdateTimeout)).toInt(), SETTING(Feeds::UpdateTimeout)).toInt(),
QByteArray(), QString(), QByteArray(), QString(),
raw_output, QNetworkAccessManager::DeleteOperation, raw_output, QNetworkAccessManager::DeleteOperation,
true, m_authUsername, m_authPassword, true); true, m_authUsername, m_authPassword, true);
m_lastError = network_reply.first;
if (network_reply.first != QNetworkReply::NoError) { m_lastError = network_reply.first;
qWarning("ownCloud: Obtaining of categories failed with error %d.", network_reply.first);
return false; if (network_reply.first != QNetworkReply::NoError
} ) {
else { qWarning("ownCloud: Obtaining of categories failed with error %d.", network_reply.first);
return true; return false;
} }
else {
return true;
}
} }
bool OwnCloudNetworkFactory::createFeed(const QString& url, int parent_id) { bool OwnCloudNetworkFactory::createFeed(const QString& url, int parent_id) {
QJsonObject json; QJsonObject json;
json["url"] = url;
json["folderId"] = parent_id;
QByteArray result_raw;
NetworkResult network_reply = NetworkFactory::performNetworkOperation(m_urlFeeds,
qApp->settings()->value(GROUP(Feeds),
SETTING(Feeds::UpdateTimeout)).toInt(),
QJsonDocument(json).toJson(QJsonDocument::Compact),
QSL("application/json"),
result_raw,
QNetworkAccessManager::PostOperation,
true, m_authUsername, m_authPassword, true);
m_lastError = network_reply.first;
if (network_reply.first != QNetworkReply::NoError) { json["url"] = url;
qWarning("ownCloud: Creating of category failed with error %d.", network_reply.first); json["folderId"] = parent_id;
return false;
} QByteArray result_raw;
else { NetworkResult network_reply = NetworkFactory::performNetworkOperation(m_urlFeeds,
return true; qApp->settings()->value(GROUP(Feeds),
} SETTING(Feeds::UpdateTimeout)).toInt(),
QJsonDocument(json).toJson(QJsonDocument::Compact),
QSL("application/json"),
result_raw,
QNetworkAccessManager::PostOperation,
true, m_authUsername, m_authPassword, true);
m_lastError = network_reply.first;
if (network_reply.first != QNetworkReply::NoError
) {
qWarning("ownCloud: Creating of category failed with error %d.", network_reply.first);
return false;
}
else {
return true;
}
} }
bool OwnCloudNetworkFactory::renameFeed(const QString& new_name, int feed_id) { bool OwnCloudNetworkFactory::renameFeed(const QString& new_name, int feed_id) {
QString final_url = m_urlRenameFeed.arg(QString::number(feed_id)); QString final_url = m_urlRenameFeed.arg(QString::number(feed_id));
QByteArray result_raw; QByteArray result_raw;
QJsonObject json; QJsonObject json;
json["feedTitle"] = new_name;
NetworkResult network_reply = NetworkFactory::performNetworkOperation(final_url,
qApp->settings()->value(GROUP(Feeds),
SETTING(Feeds::UpdateTimeout)).toInt(),
QJsonDocument(json).toJson(QJsonDocument::Compact),
QSL("application/json"), result_raw,
QNetworkAccessManager::PutOperation,
true, m_authUsername, m_authPassword,
true);
m_lastError = network_reply.first;
if (network_reply.first != QNetworkReply::NoError) { json["feedTitle"] = new_name;
qWarning("ownCloud: Renaming of feed failed with error %d.", network_reply.first);
return false; NetworkResult network_reply = NetworkFactory::performNetworkOperation(
} final_url,
else { qApp->settings()->value(GROUP(Feeds),
return true; SETTING(Feeds::UpdateTimeout)).toInt(),
} QJsonDocument(json).toJson(QJsonDocument::Compact),
QSL("application/json"), result_raw,
QNetworkAccessManager::PutOperation,
true, m_authUsername, m_authPassword,
true);
m_lastError = network_reply.first;
if (network_reply.first != QNetworkReply::NoError
) {
qWarning("ownCloud: Renaming of feed failed with error %d.", network_reply.first);
return false;
}
else {
return true;
}
} }
OwnCloudGetMessagesResponse OwnCloudNetworkFactory::getMessages(int feed_id) { OwnCloudGetMessagesResponse OwnCloudNetworkFactory::getMessages(int feed_id) {
if (forceServerSideUpdate()) { if (forceServerSideUpdate()
triggerFeedUpdate(feed_id); ) {
} triggerFeedUpdate(feed_id);
}
QString final_url = m_urlMessages.arg(QString::number(feed_id), QString final_url = m_urlMessages.arg(QString::number(feed_id),
QString::number(batchSize() <= 0 ? -1 : batchSize()), QString::number(batchSize() <= 0 ? -1 : batchSize()),
QString::number(0)); QString::number(0));
QByteArray result_raw; QByteArray result_raw;
NetworkResult network_reply = NetworkFactory::performNetworkOperation(final_url, NetworkResult network_reply = NetworkFactory::performNetworkOperation(final_url,
qApp->settings()->value(GROUP(Feeds), qApp->settings()->value(GROUP(Feeds),
SETTING(Feeds::UpdateTimeout)).toInt(), SETTING(Feeds::UpdateTimeout)).toInt(),
QByteArray(), QString(), result_raw, QByteArray(), QString(), result_raw,
QNetworkAccessManager::GetOperation, QNetworkAccessManager::GetOperation,
true, m_authUsername, m_authPassword, true, m_authUsername, m_authPassword,
true); true);
OwnCloudGetMessagesResponse msgs_response(QString::fromUtf8(result_raw)); OwnCloudGetMessagesResponse msgs_response(QString::fromUtf8(result_raw));
if (network_reply.first != QNetworkReply::NoError) {
qWarning("ownCloud: Obtaining messages failed with error %d.", network_reply.first);
}
m_lastError = network_reply.first; if (network_reply.first != QNetworkReply::NoError
return msgs_response; ) {
qWarning("ownCloud: Obtaining messages failed with error %d.", network_reply.first);
}
m_lastError = network_reply.first;
return msgs_response;
} }
QNetworkReply::NetworkError OwnCloudNetworkFactory::triggerFeedUpdate(int feed_id) { QNetworkReply::NetworkError OwnCloudNetworkFactory::triggerFeedUpdate(int feed_id) {
if (userId().isEmpty()) { if (userId().isEmpty()
// We need to get user ID first. ) {
OwnCloudUserResponse info = userInfo(); // We need to get user ID first.
OwnCloudUserResponse info = userInfo();
if (lastError() != QNetworkReply::NoError) {
return lastError();
}
else {
// We have new user ID, set it up.
setUserId(info.userId());
}
}
// Now, we can trigger the update. if (lastError() != QNetworkReply::NoError
QByteArray raw_output; ) {
NetworkResult network_reply = NetworkFactory::performNetworkOperation(m_urlFeedsUpdate.arg(userId(), return lastError();
QString::number(feed_id)), }
qApp->settings()->value(GROUP(Feeds), else {
SETTING(Feeds::UpdateTimeout)).toInt(), // We have new user ID, set it up.
QByteArray(), QString(), raw_output, setUserId(info.userId());
QNetworkAccessManager::GetOperation, }
true, m_authUsername, m_authPassword, }
true);
if (network_reply.first != QNetworkReply::NoError) { // Now, we can trigger the update.
qWarning("ownCloud: Feeds update failed with error %d.", network_reply.first); QByteArray raw_output;
} NetworkResult network_reply = NetworkFactory::performNetworkOperation(m_urlFeedsUpdate.arg(userId(),
QString::number(feed_id)),
qApp->settings()->value(GROUP(Feeds),
SETTING(Feeds::UpdateTimeout)).toInt(),
QByteArray(), QString(), raw_output,
QNetworkAccessManager::GetOperation,
true, m_authUsername, m_authPassword,
true);
return (m_lastError = network_reply.first); if (network_reply.first != QNetworkReply::NoError
) {
qWarning("ownCloud: Feeds update failed with error %d.", network_reply.first);
}
return (m_lastError = network_reply.first);
} }
void OwnCloudNetworkFactory::markMessagesRead(RootItem::ReadStatus status, const QStringList& custom_ids) { void OwnCloudNetworkFactory::markMessagesRead(RootItem::ReadStatus status, const QStringList& custom_ids) {
QJsonObject json; QJsonObject json;
QJsonArray ids; QJsonArray ids;
QString final_url; QString final_url;
if (status == RootItem::Read) { if (status == RootItem::Read
final_url = m_fixedUrl + API_PATH + "items/read/multiple"; ) {
} final_url = m_fixedUrl + API_PATH + "items/read/multiple";
else { }
final_url = m_fixedUrl + API_PATH + "items/unread/multiple"; else {
} final_url = m_fixedUrl + API_PATH + "items/unread/multiple";
}
foreach (const QString& id, custom_ids) { foreach (const QString& id, custom_ids) {
ids.append(QJsonValue(id.toInt())); ids.append(QJsonValue(id.toInt()));
} }
json["items"] = ids; json["items"] = ids;
Downloader* downloader = NetworkFactory::performAsyncNetworkOperation(final_url, Downloader* downloader = NetworkFactory::performAsyncNetworkOperation(final_url,
qApp->settings()->value(GROUP(Feeds), qApp->settings()->value(GROUP(Feeds),
SETTING(Feeds::UpdateTimeout)).toInt(), SETTING(Feeds::UpdateTimeout)).toInt(),
QJsonDocument(json).toJson(QJsonDocument::Compact), QJsonDocument(json).toJson(QJsonDocument::Compact),
CONTENT_TYPE, CONTENT_TYPE,
QNetworkAccessManager::PutOperation, QNetworkAccessManager::PutOperation,
true, m_authUsername, m_authPassword, true, m_authUsername, m_authPassword,
true); true);
QObject::connect(downloader, &Downloader::completed, downloader, &Downloader::deleteLater); QObject::connect(downloader, &Downloader::completed, downloader, &Downloader::deleteLater);
} }
@ -332,33 +361,38 @@ void OwnCloudNetworkFactory::markMessagesRead(RootItem::ReadStatus status, const
void OwnCloudNetworkFactory::markMessagesStarred(RootItem::Importance importance, void OwnCloudNetworkFactory::markMessagesStarred(RootItem::Importance importance,
const QStringList& feed_ids, const QStringList& feed_ids,
const QStringList& guid_hashes) { const QStringList& guid_hashes) {
QJsonObject json; QJsonObject json;
QJsonArray ids; QJsonArray ids;
QString final_url; QString final_url;
if (importance == RootItem::Important) { if (importance == RootItem::Important
final_url = m_fixedUrl + API_PATH + "items/star/multiple"; ) {
} final_url = m_fixedUrl + API_PATH + "items/star/multiple";
else { }
final_url = m_fixedUrl + API_PATH + "items/unstar/multiple"; else {
} final_url = m_fixedUrl + API_PATH + "items/unstar/multiple";
}
for (int i = 0; i < feed_ids.size(); i++) { for (int i = 0; i < feed_ids.size(); i++) {
QJsonObject item; QJsonObject item;
item["feedId"] = feed_ids.at(i);
item["guidHash"] = guid_hashes.at(i);
ids.append(item); item["feedId"] = feed_ids.at(i);
} item["guidHash"] = guid_hashes.at(i);
ids.append(item);
}
json["items"] = ids;
json["items"] = ids;
Downloader* downloader = NetworkFactory::performAsyncNetworkOperation(final_url, Downloader* downloader = NetworkFactory::performAsyncNetworkOperation(final_url,
qApp->settings()->value(GROUP(Feeds), qApp->settings()->value(GROUP(Feeds),
SETTING(Feeds::UpdateTimeout)).toInt(), SETTING(Feeds::UpdateTimeout)).toInt(),
QJsonDocument(json).toJson(QJsonDocument::Compact), QJsonDocument(json).toJson(QJsonDocument::Compact),
CONTENT_TYPE, CONTENT_TYPE,
QNetworkAccessManager::PutOperation, QNetworkAccessManager::PutOperation,
true, m_authUsername, m_authPassword, true, m_authUsername, m_authPassword,
true); true);
QObject::connect(downloader, &Downloader::completed, downloader, &Downloader::deleteLater); QObject::connect(downloader, &Downloader::completed, downloader, &Downloader::deleteLater);
} }
@ -380,185 +414,202 @@ void OwnCloudNetworkFactory::setUserId(const QString& userId) {
} }
OwnCloudResponse::OwnCloudResponse(const QString& raw_content) { OwnCloudResponse::OwnCloudResponse(const QString& raw_content) {
m_rawContent = QJsonDocument::fromJson(raw_content.toUtf8()).object(); m_rawContent = QJsonDocument::fromJson(raw_content.toUtf8()).object();
m_emptyString = raw_content.isEmpty(); m_emptyString = raw_content.isEmpty();
} }
OwnCloudResponse::~OwnCloudResponse() { OwnCloudResponse::~OwnCloudResponse() {}
}
bool OwnCloudResponse::isLoaded() const { bool OwnCloudResponse::isLoaded() const {
return !m_emptyString && !m_rawContent.isEmpty(); return !m_emptyString && !m_rawContent.isEmpty();
} }
QString OwnCloudResponse::toString() const { QString OwnCloudResponse::toString() const {
return QJsonDocument(m_rawContent).toJson(QJsonDocument::Compact); return QJsonDocument(m_rawContent).toJson(QJsonDocument::Compact);
} }
OwnCloudUserResponse::OwnCloudUserResponse(const QString& raw_content) : OwnCloudResponse(raw_content) { OwnCloudUserResponse::OwnCloudUserResponse(const QString& raw_content) : OwnCloudResponse(raw_content) {}
}
OwnCloudUserResponse::~OwnCloudUserResponse() { OwnCloudUserResponse::~OwnCloudUserResponse() {}
}
QString OwnCloudUserResponse::displayName() const { QString OwnCloudUserResponse::displayName() const {
if (isLoaded()) { if (isLoaded()
return m_rawContent["displayName"].toString(); ) {
} return m_rawContent["displayName"].toString();
else { }
return QString(); else {
} return QString();
}
} }
QString OwnCloudUserResponse::userId() const { QString OwnCloudUserResponse::userId() const {
if (isLoaded()) { if (isLoaded()
return m_rawContent["userId"].toString(); ) {
} return m_rawContent["userId"].toString();
else { }
return QString(); else {
} return QString();
}
} }
QDateTime OwnCloudUserResponse::lastLoginTime() const { QDateTime OwnCloudUserResponse::lastLoginTime() const {
if (isLoaded()) { if (isLoaded()
return QDateTime::fromMSecsSinceEpoch(m_rawContent["lastLoginTimestamp"].toDouble()); ) {
} return QDateTime::fromMSecsSinceEpoch(m_rawContent["lastLoginTimestamp"].toDouble());
else { }
return QDateTime(); else {
} return QDateTime();
}
} }
QIcon OwnCloudUserResponse::avatar() const { QIcon OwnCloudUserResponse::avatar() const {
if (isLoaded()) { if (isLoaded()
QString image_data = m_rawContent["avatar"].toObject()["data"].toString(); ) {
QByteArray decoded_data = QByteArray::fromBase64(image_data.toLocal8Bit()); QString image_data = m_rawContent["avatar"].toObject()["data"].toString();
QPixmap image; QByteArray decoded_data = QByteArray::fromBase64(image_data.toLocal8Bit());
QPixmap image;
if (image.loadFromData(decoded_data)) {
return QIcon(image);
}
}
return QIcon(); if (image.loadFromData(decoded_data)
) {
return QIcon(image);
}
}
return QIcon();
} }
OwnCloudStatusResponse::OwnCloudStatusResponse(const QString& raw_content) : OwnCloudResponse(raw_content) { OwnCloudStatusResponse::OwnCloudStatusResponse(const QString& raw_content) : OwnCloudResponse(raw_content) {}
}
OwnCloudStatusResponse::~OwnCloudStatusResponse() { OwnCloudStatusResponse::~OwnCloudStatusResponse() {}
}
QString OwnCloudStatusResponse::version() const { QString OwnCloudStatusResponse::version() const {
if (isLoaded()) { if (isLoaded()
return m_rawContent["version"].toString(); ) {
} return m_rawContent["version"].toString();
else { }
return QString(); else {
} return QString();
}
} }
bool OwnCloudStatusResponse::misconfiguredCron() const { bool OwnCloudStatusResponse::misconfiguredCron() const {
if (isLoaded()) { if (isLoaded()
return m_rawContent["warnings"].toObject()["improperlyConfiguredCron"].toBool(); ) {
} return m_rawContent["warnings"].toObject()["improperlyConfiguredCron"].toBool();
else { }
return false; else {
} return false;
}
} }
OwnCloudGetFeedsCategoriesResponse::OwnCloudGetFeedsCategoriesResponse(const QString& raw_categories, OwnCloudGetFeedsCategoriesResponse::OwnCloudGetFeedsCategoriesResponse(const QString& raw_categories,
const QString& raw_feeds) const QString& raw_feeds)
: m_contentCategories(raw_categories), m_contentFeeds(raw_feeds) { : m_contentCategories(raw_categories), m_contentFeeds(raw_feeds) {}
}
OwnCloudGetFeedsCategoriesResponse::~OwnCloudGetFeedsCategoriesResponse() { OwnCloudGetFeedsCategoriesResponse::~OwnCloudGetFeedsCategoriesResponse() {}
}
RootItem* OwnCloudGetFeedsCategoriesResponse::feedsCategories(bool obtain_icons) const { RootItem* OwnCloudGetFeedsCategoriesResponse::feedsCategories(bool obtain_icons) const {
RootItem* parent = new RootItem(); RootItem* parent = new RootItem();
QMap<int, RootItem*>cats;
cats.insert(0, parent);
// Process categories first, then process feeds. QMap<int, RootItem*>cats;
foreach (const QJsonValue& cat, QJsonDocument::fromJson(m_contentCategories.toUtf8()).object()["folders"].toArray()) { cats.insert(0, parent);
QJsonObject item = cat.toObject();
OwnCloudCategory* category = new OwnCloudCategory();
category->setTitle(item["name"].toString());
category->setCustomId(item["id"].toInt());
cats.insert(category->customId(), category);
// All categories in ownCloud are top-level.
parent->appendChild(category);
}
// We have categories added, now add all feeds. // Process categories first, then process feeds.
foreach (const QJsonValue& fed, QJsonDocument::fromJson(m_contentFeeds.toUtf8()).object()["feeds"].toArray()) { foreach (const QJsonValue& cat, QJsonDocument::fromJson(m_contentCategories.toUtf8()).object()["folders"].toArray()) {
QJsonObject item = fed.toObject(); QJsonObject item = cat.toObject();
OwnCloudFeed* feed = new OwnCloudFeed(); OwnCloudCategory* category = new OwnCloudCategory();
if (obtain_icons) {
QString icon_path = item["faviconLink"].toString();
if (!icon_path.isEmpty()) { category->setTitle(item["name"].toString());
QByteArray icon_data; category->setCustomId(item["id"].toInt());
cats.insert(category->customId(), category);
// All categories in ownCloud are top-level.
parent->appendChild(category);
}
if (NetworkFactory::performNetworkOperation(icon_path, DOWNLOAD_TIMEOUT, // We have categories added, now add all feeds.
QByteArray(), QString(), icon_data, foreach (const QJsonValue& fed, QJsonDocument::fromJson(m_contentFeeds.toUtf8()).object()["feeds"].toArray()) {
QNetworkAccessManager::GetOperation).first == QNetworkReply::NoError) { QJsonObject item = fed.toObject();
// Icon downloaded, set it up. OwnCloudFeed* feed = new OwnCloudFeed();
QPixmap icon_pixmap;
icon_pixmap.loadFromData(icon_data);
feed->setIcon(QIcon(icon_pixmap));
}
}
}
feed->setUrl(item["link"].toString());
feed->setTitle(item["title"].toString());
feed->setCustomId(item["id"].toInt());
qDebug("Custom ID of next fetched Nextcloud feed is '%d'.", item["id"].toInt());
cats.value(item["folderId"].toInt())->appendChild(feed);
}
return parent; if (obtain_icons
) {
QString icon_path = item["faviconLink"].toString();
if (!icon_path.isEmpty()
) {
QByteArray icon_data;
if (NetworkFactory::performNetworkOperation(icon_path, DOWNLOAD_TIMEOUT,
QByteArray(), QString(), icon_data,
QNetworkAccessManager::GetOperation).first == QNetworkReply::NoError
) {
// Icon downloaded, set it up.
QPixmap icon_pixmap;
icon_pixmap.loadFromData(icon_data);
feed->setIcon(QIcon(icon_pixmap));
}
}
}
feed->setUrl(item["link"].toString());
feed->setTitle(item["title"].toString());
feed->setCustomId(item["id"].toInt());
qDebug("Custom ID of next fetched Nextcloud feed is '%d'.", item["id"].toInt());
cats.value(item["folderId"].toInt())->appendChild(feed);
}
return parent;
} }
OwnCloudGetMessagesResponse::OwnCloudGetMessagesResponse(const QString& raw_content) : OwnCloudResponse(raw_content) { OwnCloudGetMessagesResponse::OwnCloudGetMessagesResponse(const QString& raw_content) : OwnCloudResponse(raw_content) {}
}
OwnCloudGetMessagesResponse::~OwnCloudGetMessagesResponse() { OwnCloudGetMessagesResponse::~OwnCloudGetMessagesResponse() {}
}
QList<Message>OwnCloudGetMessagesResponse::messages() const { QList<Message>OwnCloudGetMessagesResponse::messages() const {
QList<Message>msgs; QList<Message>msgs;
foreach (const QJsonValue& message, m_rawContent["items"].toArray()) { foreach (const QJsonValue& message, m_rawContent["items"].toArray()) {
QJsonObject message_map = message.toObject(); QJsonObject message_map = message.toObject();
Message msg; Message msg;
msg.m_author = message_map["author"].toString();
msg.m_contents = message_map["body"].toString();
msg.m_created = TextFactory::parseDateTime(message_map["pubDate"].toDouble() * 1000);
msg.m_createdFromFeed = true;
msg.m_customId = QString::number(message_map["id"].toInt());
msg.m_customHash = message_map["guidHash"].toString();
QString enclosure_link = message_map["enclosureLink"].toString();
if (!enclosure_link.isEmpty()) {
Enclosure enclosure;
enclosure.m_mimeType = message_map["enclosureMime"].toString();
enclosure.m_url = enclosure_link;
msg.m_enclosures.append(enclosure);
}
msg.m_feedId = QString::number(message_map["feedId"].toInt()); msg.m_author = message_map["author"].toString();
msg.m_isImportant = message_map["starred"].toBool(); msg.m_contents = message_map["body"].toString();
msg.m_isRead = !message_map["unread"].toBool(); msg.m_created = TextFactory::parseDateTime(message_map["pubDate"].toDouble() * 1000);
msg.m_title = message_map["title"].toString(); msg.m_createdFromFeed = true;
msg.m_url = message_map["url"].toString(); msg.m_customId = QString::number(message_map["id"].toInt());
msgs.append(msg); msg.m_customHash = message_map["guidHash"].toString();
}
return msgs; QString enclosure_link = message_map["enclosureLink"].toString();
if (!enclosure_link.isEmpty()
) {
Enclosure enclosure;
enclosure.m_mimeType = message_map["enclosureMime"].toString();
enclosure.m_url = enclosure_link;
msg.m_enclosures.append(enclosure);
}
msg.m_feedId = QString::number(message_map["feedId"].toInt());
msg.m_isImportant = message_map["starred"].toBool();
msg.m_isRead = !message_map["unread"].toBool();
msg.m_title = message_map["title"].toString();
msg.m_url = message_map["url"].toString();
msgs.append(msg);
}
return msgs;
} }

View File

@ -22,114 +22,114 @@
#include "services/abstract/rootitem.h" #include "services/abstract/rootitem.h"
#include <QDateTime> #include <QDateTime>
#include <QString>
#include <QIcon> #include <QIcon>
#include <QNetworkReply>
#include <QJsonObject> #include <QJsonObject>
#include <QNetworkReply>
#include <QString>
class OwnCloudResponse { class OwnCloudResponse {
public: public:
explicit OwnCloudResponse(const QString& raw_content = QString()); explicit OwnCloudResponse(const QString& raw_content = QString());
virtual ~OwnCloudResponse(); virtual ~OwnCloudResponse();
bool isLoaded() const; bool isLoaded() const;
QString toString() const; QString toString() const;
protected: protected:
QJsonObject m_rawContent; QJsonObject m_rawContent;
bool m_emptyString; bool m_emptyString;
}; };
class OwnCloudUserResponse : public OwnCloudResponse { class OwnCloudUserResponse : public OwnCloudResponse {
public: public:
explicit OwnCloudUserResponse(const QString& raw_content = QString()); explicit OwnCloudUserResponse(const QString& raw_content = QString());
virtual ~OwnCloudUserResponse(); virtual ~OwnCloudUserResponse();
QString userId() const; QString userId() const;
QString displayName() const; QString displayName() const;
QDateTime lastLoginTime() const; QDateTime lastLoginTime() const;
QIcon avatar() const; QIcon avatar() const;
}; };
class OwnCloudGetMessagesResponse : public OwnCloudResponse { class OwnCloudGetMessagesResponse : public OwnCloudResponse {
public: public:
explicit OwnCloudGetMessagesResponse(const QString& raw_content = QString()); explicit OwnCloudGetMessagesResponse(const QString& raw_content = QString());
virtual ~OwnCloudGetMessagesResponse(); virtual ~OwnCloudGetMessagesResponse();
QList<Message> messages() const; QList<Message> messages() const;
}; };
class OwnCloudStatusResponse : public OwnCloudResponse { class OwnCloudStatusResponse : public OwnCloudResponse {
public: public:
explicit OwnCloudStatusResponse(const QString& raw_content = QString()); explicit OwnCloudStatusResponse(const QString& raw_content = QString());
virtual ~OwnCloudStatusResponse(); virtual ~OwnCloudStatusResponse();
QString version() const; QString version() const;
bool misconfiguredCron() const; bool misconfiguredCron() const;
}; };
class RootItem; class RootItem;
class OwnCloudGetFeedsCategoriesResponse { class OwnCloudGetFeedsCategoriesResponse {
public: public:
explicit OwnCloudGetFeedsCategoriesResponse(const QString& raw_categories = QString(), explicit OwnCloudGetFeedsCategoriesResponse(const QString& raw_categories = QString(),
const QString& raw_feeds = QString()); const QString& raw_feeds = QString());
virtual ~OwnCloudGetFeedsCategoriesResponse(); virtual ~OwnCloudGetFeedsCategoriesResponse();
// Returns tree of feeds/categories. // Returns tree of feeds/categories.
// Top-level root of the tree is not needed here. // Top-level root of the tree is not needed here.
// Returned items do not have primary IDs assigned. // Returned items do not have primary IDs assigned.
RootItem* feedsCategories(bool obtain_icons) const; RootItem* feedsCategories(bool obtain_icons) const;
private: private:
QString m_contentCategories; QString m_contentCategories;
QString m_contentFeeds; QString m_contentFeeds;
}; };
class OwnCloudNetworkFactory { class OwnCloudNetworkFactory {
public: public:
explicit OwnCloudNetworkFactory(); explicit OwnCloudNetworkFactory();
virtual ~OwnCloudNetworkFactory(); virtual ~OwnCloudNetworkFactory();
QString url() const; QString url() const;
void setUrl(const QString& url); void setUrl(const QString& url);
bool forceServerSideUpdate() const; bool forceServerSideUpdate() const;
void setForceServerSideUpdate(bool force_update); void setForceServerSideUpdate(bool force_update);
QString authUsername() const; QString authUsername() const;
void setAuthUsername(const QString& auth_username); void setAuthUsername(const QString& auth_username);
QString authPassword() const; QString authPassword() const;
void setAuthPassword(const QString& auth_password); void setAuthPassword(const QString& auth_password);
QString userId() const; QString userId() const;
void setUserId(const QString& userId); void setUserId(const QString& userId);
QNetworkReply::NetworkError lastError() const; QNetworkReply::NetworkError lastError() const;
// Operations. // Operations.
// Get user info. // Get user info.
OwnCloudUserResponse userInfo(); OwnCloudUserResponse userInfo();
// Get version info. // Get version info.
OwnCloudStatusResponse status(); OwnCloudStatusResponse status();
// Get feeds & categories (used for sync-in). // Get feeds & categories (used for sync-in).
OwnCloudGetFeedsCategoriesResponse feedsCategories(); OwnCloudGetFeedsCategoriesResponse feedsCategories();
// Feed operations. // Feed operations.
bool deleteFeed(int feed_id); bool deleteFeed(int feed_id);
bool createFeed(const QString& url, int parent_id); bool createFeed(const QString& url, int parent_id);
bool renameFeed(const QString& new_name, int feed_id); bool renameFeed(const QString& new_name, int feed_id);
// Get messages for given feed. // Get messages for given feed.
OwnCloudGetMessagesResponse getMessages(int feed_id); OwnCloudGetMessagesResponse getMessages(int feed_id);
// Misc methods. // Misc methods.
QNetworkReply::NetworkError triggerFeedUpdate(int feed_id); QNetworkReply::NetworkError triggerFeedUpdate(int feed_id);
void markMessagesRead(RootItem::ReadStatus status, const QStringList& custom_ids); void markMessagesRead(RootItem::ReadStatus status, const QStringList& custom_ids);
void markMessagesStarred(RootItem::Importance importance, const QStringList& feed_ids, const QStringList& guid_hashes); void markMessagesStarred(RootItem::Importance importance, const QStringList& feed_ids, const QStringList& guid_hashes);
@ -141,21 +141,21 @@ class OwnCloudNetworkFactory {
QString m_url; QString m_url;
QString m_fixedUrl; QString m_fixedUrl;
bool m_forceServerSideUpdate; bool m_forceServerSideUpdate;
QString m_authUsername; QString m_authUsername;
QString m_authPassword; QString m_authPassword;
QNetworkReply::NetworkError m_lastError; QNetworkReply::NetworkError m_lastError;
int m_batchSize; int m_batchSize;
// Endpoints. // Endpoints.
QString m_urlUser; QString m_urlUser;
QString m_urlStatus; QString m_urlStatus;
QString m_urlFolders; QString m_urlFolders;
QString m_urlFeeds; QString m_urlFeeds;
QString m_urlMessages; QString m_urlMessages;
QString m_urlFeedsUpdate; QString m_urlFeedsUpdate;
QString m_urlDeleteFeed; QString m_urlDeleteFeed;
QString m_urlRenameFeed; QString m_urlRenameFeed;
QString m_userId; QString m_userId;
}; };
#endif // OWNCLOUDNETWORKFACTORY_H #endif // OWNCLOUDNETWORKFACTORY_H