Reformated using astyle, added some astyle scripts.

This commit is contained in:
Martin Rotter 2017-07-21 06:53:23 +02:00
parent 14473722b0
commit 208284e80d
304 changed files with 34084 additions and 34464 deletions

26
.astylerc Executable file
View file

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

64
astyle-format-all.sh Executable file
View file

@ -0,0 +1,64 @@
#!/bin/bash
#
# This file is part of RSS Guard.
#
# Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
# Copyright (C) 2010-2014 by David Rosca <nowrep@gmail.com>
#
# RSS Guard is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# RSS Guard is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with RSS Guard. If not, see <http:#www.gnu.org/licenses/>.
function usage {
echo "Usage: $0 \"root-directory\"..."
exit 1
}
if [ $# -eq 0 ]; then
usage
fi
ASTYLE_CMD="astyle"
ASTYLE_RC=".astylerc"
# Check all args.
for dir in "$@"; do
if [ ! -d "${dir}" ]; then
echo "\"${dir}\" is not a directory..."
usage
fi
done
# Run the thing.
for dir in "$@"; do
pushd "${dir}"
if [ ! -r "$ASTYLE_RC" ]; then
echo "No $ASTYLE_RC in pwd \"$PWD\"..."
continue
fi
for f in $(find . \
-name '*.c' \
-o -name '*.cc' \
-o -name '*.cpp' \
-o -name '*.h' \
-o -name '*.hh' \
-o -name '*.hpp'); do
"${ASTYLE_CMD}" --options="$ASTYLE_RC" "${f}"
done
# Remove backup files.
find . -name "*.orig" | xargs --no-run-if-empty rm -v
popd
done

View file

@ -39,7 +39,6 @@ FeedDownloader::~FeedDownloader() {
m_mutex->tryLock();
m_mutex->unlock();
delete m_mutex;
qDebug("Destroying FeedDownloader instance.");
}
@ -51,10 +50,12 @@ void FeedDownloader::updateAvailableFeeds() {
while (!m_feeds.isEmpty()) {
connect(m_feeds.first(), &Feed::messagesObtained, this, &FeedDownloader::oneFeedUpdateFinished,
(Qt::ConnectionType)(Qt::UniqueConnection | Qt::AutoConnection));
if (m_threadPool->tryStart(m_feeds.first())) {
m_feeds.removeFirst();
m_feedsUpdating++;
}
else {
// We want to start update of some feeds but all working threads are occupied.
break;
@ -69,14 +70,13 @@ void FeedDownloader::updateFeeds(const QList<Feed*> &feeds) {
qDebug("No feeds to update in worker thread, aborting update.");
finalizeUpdate();
}
else {
qDebug().nospace() << "Starting feed updates from worker in thread: \'" << QThread::currentThreadId() << "\'.";
m_feeds = feeds;
m_feedsOriginalCount = m_feeds.size();
m_results.clear();
m_feedsUpdated = m_feedsUpdating = 0;
// Job starts now.
emit updateStarted();
updateAvailableFeeds();
@ -90,22 +90,16 @@ void FeedDownloader::stopRunningUpdate() {
void FeedDownloader::oneFeedUpdateFinished(const QList<Message>& messages, bool error_during_obtaining) {
QMutexLocker locker(m_mutex);
m_feedsUpdated++;
m_feedsUpdating--;
Feed* feed = qobject_cast<Feed*>(sender());
disconnect(feed, &Feed::messagesObtained, this, &FeedDownloader::oneFeedUpdateFinished);
// Now, we check if there are any feeds we would like to update too.
updateAvailableFeeds();
// Now make sure, that messages are actually stored to SQL in a locked state.
qDebug().nospace() << "Saving messages of feed "
<< feed->id() << " in thread: \'"
<< QThread::currentThreadId() << "\'.";
int updated_messages = feed->updateMessages(messages, error_during_obtaining);
/*
@ -128,9 +122,7 @@ void FeedDownloader::oneFeedUpdateFinished(const QList<Message> &messages, bool
void FeedDownloader::finalizeUpdate() {
qDebug().nospace() << "Finished feed updates in thread: \'" << QThread::currentThreadId() << "\'.";
m_results.sort();
// Update of feeds has finished.
// NOTE: This means that now "update lock" can be unlocked
// and feeds can be added/edited/deleted and application

View file

@ -40,27 +40,21 @@
FeedsModel::FeedsModel(QObject* parent) : QAbstractItemModel(parent) {
setObjectName(QSL("FeedsModel"));
// Create root item.
m_rootItem = new RootItem();
//: Name of root item of feed list which can be seen in feed add/edit dialog.
m_rootItem->setTitle(tr("Root"));
m_rootItem->setIcon(qApp->icons()->fromTheme(QSL("folder")));
// Setup icons.
m_countsIcon = qApp->icons()->fromTheme(QSL("mail-mark-unread"));
//: 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() {
qDebug("Destroying FeedsModel instance.");
// Delete all model items.
delete m_rootItem;
}
@ -97,6 +91,7 @@ bool FeedsModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int
if (action == Qt::IgnoreAction) {
return true;
}
else if (action != Qt::MoveAction) {
return false;
}
@ -106,13 +101,13 @@ bool FeedsModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int
if (dragged_items_data.isEmpty()) {
return false;
}
else {
QDataStream stream(&dragged_items_data, QIODevice::ReadOnly);
while (!stream.atEnd()) {
quintptr 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);
@ -131,7 +126,6 @@ bool FeedsModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int
QSystemTrayIcon::Warning,
qApp->mainFormWidget(),
true);
qDebug("Dragged item cannot be dragged into different account. Cancelling drag-drop action.");
return false;
}
@ -157,7 +151,6 @@ Qt::ItemFlags FeedsModel::flags(const QModelIndex &index) const {
Qt::ItemFlags base_flags = QAbstractItemModel::flags(index);
const RootItem* item_for_index = itemForIndex(index);
Qt::ItemFlags additional_flags = item_for_index->additionalFlags();
return base_flags | additional_flags;
}
@ -171,6 +164,7 @@ QVariant FeedsModel::headerData(int section, Qt::Orientation orientation, int ro
if (section == FDS_MODEL_TITLE_INDEX) {
return m_headerData.at(FDS_MODEL_TITLE_INDEX);
}
else {
return QVariant();
}
@ -182,6 +176,7 @@ QVariant FeedsModel::headerData(int section, Qt::Orientation orientation, int ro
if (section == FDS_MODEL_COUNTS_INDEX) {
return m_countsIcon;
}
else {
return QVariant();
}
@ -202,6 +197,7 @@ QModelIndex FeedsModel::index(int row, int column, const QModelIndex &parent) co
if (child_item) {
return createIndex(row, column, child_item);
}
else {
return QModelIndex();
}
@ -218,6 +214,7 @@ QModelIndex FeedsModel::parent(const QModelIndex &child) const {
if (parent_item == m_rootItem) {
return QModelIndex();
}
else {
return createIndex(parent_item->row(), 0, parent_item);
}
@ -227,6 +224,7 @@ int FeedsModel::rowCount(const QModelIndex &parent) const {
if (parent.column() > 0) {
return 0;
}
else {
return itemForIndex(parent)->childCount();
}
@ -251,11 +249,9 @@ void FeedsModel::removeItem(const QModelIndex &index) {
RootItem* deleting_item = itemForIndex(index);
QModelIndex parent_index = index.parent();
RootItem* parent_item = deleting_item->parent();
beginRemoveRows(parent_index, index.row(), index.row());
parent_item->removeChild(deleting_item);
endRemoveRows();
deleting_item->deleteLater();
notifyWithCounts();
}
@ -266,11 +262,9 @@ void FeedsModel::removeItem(RootItem *deleting_item) {
QModelIndex index = indexForItem(deleting_item);
QModelIndex parent_index = index.parent();
RootItem* parent_item = deleting_item->parent();
beginRemoveRows(parent_index, index.row(), index.row());
parent_item->removeChild(deleting_item);
endRemoveRows();
deleting_item->deleteLater();
notifyWithCounts();
}
@ -292,7 +286,6 @@ void FeedsModel::reassignNodeToNewParent(RootItem *original_node, RootItem *new_
}
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);
new_parent->appendChild(original_node);
@ -360,6 +353,7 @@ QList<Feed*> FeedsModel::feedsForScheduledUpdate(bool auto_update_now) {
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.
@ -379,7 +373,6 @@ QList<Message> FeedsModel::messagesForItem(RootItem *item) const {
int FeedsModel::columnCount(const QModelIndex& parent) const {
Q_UNUSED(parent)
return FEEDS_VIEW_COLUMN_COUNT;
}
@ -387,6 +380,7 @@ RootItem *FeedsModel::itemForIndex(const QModelIndex &index) const {
if (index.isValid() && index.model() == this) {
return static_cast<RootItem*>(index.internalPointer());
}
else {
return m_rootItem;
}
@ -437,10 +431,8 @@ void FeedsModel::reloadChangedLayout(QModelIndexList list) {
if (indx.isValid()) {
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));
list.append(indx_parent);
}
}
@ -460,6 +452,7 @@ void FeedsModel::onItemDataChanged(const QList<RootItem *> &items) {
qDebug("There is request to reload feed model for more than %d items, reloading model fully.", RELOAD_MODEL_BORDER_NUM);
reloadWholeLayout();
}
else {
qDebug("There is request to reload feed model, reloading the %d items individually.", items.size());
@ -478,11 +471,9 @@ void FeedsModel::reloadWholeLayout() {
bool FeedsModel::addServiceAccount(ServiceRoot* root, bool freshly_activated) {
int new_row_index = m_rootItem->childCount();
beginInsertRows(indexForItem(m_rootItem), new_row_index, new_row_index);
m_rootItem->appendChild(root);
endInsertRows();
// Connect.
connect(root, &ServiceRoot::itemRemovalRequested, this, static_cast<void (FeedsModel::*)(RootItem*)>(&FeedsModel::removeItem));
connect(root, &ServiceRoot::itemReassignmentRequested, this, &FeedsModel::reassignNodeToNewParent);
@ -490,7 +481,6 @@ bool FeedsModel::addServiceAccount(ServiceRoot *root, bool freshly_activated) {
connect(root, &ServiceRoot::reloadMessageListRequested, this, &FeedsModel::reloadMessageListRequested);
connect(root, &ServiceRoot::itemExpandRequested, this, &FeedsModel::itemExpandRequested);
connect(root, &ServiceRoot::itemExpandStateSaveRequested, this, &FeedsModel::itemExpandStateSaveRequested);
root->start(freshly_activated);
return true;
}

View file

@ -71,6 +71,7 @@ QModelIndexList FeedsProxyModel::match(const QModelIndex &start, int role, const
result.append(idx);
}
}
// QString based matching.
else {
if (entered_text.isEmpty()) {
@ -84,30 +85,35 @@ QModelIndexList FeedsProxyModel::match(const QModelIndex &start, int role, const
if (QRegExp(entered_text, cs).exactMatch(item_text)) {
result.append(idx);
}
break;
case Qt::MatchWildcard:
if (QRegExp(entered_text, cs, QRegExp::Wildcard).exactMatch(item_text)) {
result.append(idx);
}
break;
case Qt::MatchStartsWith:
if (item_text.startsWith(entered_text, cs)) {
result.append(idx);
}
break;
case Qt::MatchEndsWith:
if (item_text.endsWith(entered_text, cs)) {
result.append(idx);
}
break;
case Qt::MatchFixedString:
if (item_text.compare(entered_text, cs) == 0) {
result.append(idx);
}
break;
case Qt::MatchContains:
@ -115,6 +121,7 @@ QModelIndexList FeedsProxyModel::match(const QModelIndex &start, int role, const
if (item_text.contains(entered_text, cs)) {
result.append(idx);
}
break;
}
}
@ -149,23 +156,28 @@ bool FeedsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right
// User wants to sort according to counts.
return left_item->countOfUnreadMessages() < right_item->countOfUnreadMessages();
}
else {
// In other cases, sort by title.
return QString::localeAwareCompare(left_item->title(), right_item->title()) < 0;
}
}
else if (left_item->kind() == RootItemKind::Bin) {
// Left item is recycle bin. Make sure it is "biggest" item if we have selected ascending order.
return sortOrder() == Qt::DescendingOrder;
}
else if (right_item->kind() == RootItemKind::Bin) {
// Right item is recycle bin. Make sure it is "smallest" item if we have selected descending order.
return sortOrder() == Qt::AscendingOrder;
}
else if (left_item->kind() == RootItemKind::Feed) {
// Left item is feed, right item is category.
return false;
}
else {
// Left item is category, right item is feed.
// NOTE: Category is in fact "more" than feed but we consider it to be "less" because it should be "placed"
@ -174,6 +186,7 @@ bool FeedsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right
return true;
}
}
else {
return false;
}
@ -184,7 +197,6 @@ bool FeedsProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source
if (should_show && m_hiddenIndices.contains(QPair<int, QModelIndex>(source_row, source_parent))) {
const_cast<FeedsProxyModel*>(this)->m_hiddenIndices.removeAll(QPair<int, QModelIndex>(source_row, source_parent));
// Load status.
emit expandAfterFilterIn(m_sourceModel->index(source_row, 0, source_parent));
}
@ -213,10 +225,12 @@ bool FeedsProxyModel::filterAcceptsRowInternal(int source_row, const QModelIndex
// Recycle bin is always displayed.
return true;
}
else if (item->isParentOf(m_selectedItem)/* || item->isChildOf(m_selectedItem)*/ || m_selectedItem == item) {
// Currently selected item and all its parents and children must be displayed.
return true;
}
else {
// NOTE: If item has < 0 of unread message it may mean, that the count
// of unread messages is not (yet) known, display that item too.

View file

@ -33,10 +33,10 @@ QList<Enclosure> Enclosures::decodeEnclosuresFromString(const QString &enclosure
if (single_enclosure.contains(ECNLOSURES_INNER_SEPARATOR)) {
QStringList mime_url = single_enclosure.split(ECNLOSURES_INNER_SEPARATOR);
enclosure.m_mimeType = QByteArray::fromBase64(mime_url.at(0).toLocal8Bit());
enclosure.m_url = QByteArray::fromBase64(mime_url.at(1).toLocal8Bit());
}
else {
enclosure.m_url = QByteArray::fromBase64(single_enclosure.toLocal8Bit());
}
@ -54,6 +54,7 @@ QString Enclosures::encodeEnclosuresToString(const QList<Enclosure> &enclosures)
if (enclosure.m_mimeType.isEmpty()) {
enclosures_str.append(enclosure.m_url.toLocal8Bit().toBase64());
}
else {
enclosures_str.append(QString(enclosure.m_mimeType.toLocal8Bit().toBase64()) +
ECNLOSURES_INNER_SEPARATOR +
@ -80,7 +81,6 @@ Message Message::fromSqlRecord(const QSqlRecord &record, bool *result) {
}
Message message;
message.m_id = record.value(MSG_DB_ID_INDEX).toInt();
message.m_isRead = record.value(MSG_DB_READ_INDEX).toBool();
message.m_isImportant = record.value(MSG_DB_IMPORTANT_INDEX).toBool();

View file

@ -37,7 +37,6 @@ MessagesModel::MessagesModel(QObject *parent)
setupIcons();
setupHeaderData();
updateDateFormat();
loadMessages(nullptr);
}
@ -62,7 +61,6 @@ void MessagesModel::repopulate() {
bool MessagesModel::setData(const QModelIndex& index, const QVariant& value, int role) {
Q_UNUSED(role)
m_cache->setData(index, value, record(index.row()));
return true;
}
@ -72,7 +70,6 @@ void MessagesModel::setupFonts() {
m_normalFont = Application::font("MessagesView");
m_boldFont = m_normalFont;
m_boldFont.setBold(true);
m_normalStrikedFont = m_normalFont;
m_boldStrikedFont = m_boldFont;
m_normalStrikedFont.setStrikeOut(true);
@ -85,6 +82,7 @@ void MessagesModel::loadMessages(RootItem *item) {
if (item == nullptr) {
setFilter(QSL(DEFAULT_SQL_MESSAGES_FILTER));
}
else {
if (!item->getParentServiceRoot()->loadMessagesForItem(item, this)) {
setFilter(QSL("true != true"));
@ -140,6 +138,7 @@ void MessagesModel::updateDateFormat() {
if (qApp->settings()->value(GROUP(Messages), SETTING(Messages::UseCustomDate)).toBool()) {
m_customDateFormat = qApp->settings()->value(GROUP(Messages), SETTING(Messages::CustomDateFormat)).toString();
}
else {
m_customDateFormat = QString();
}
@ -171,7 +170,6 @@ void MessagesModel::setupHeaderData() {
/*: Tooltip for custom ID of message.*/ tr("Custom ID") <<
/*: Tooltip for custom hash string of message.*/ tr("Custom hash") <<
/*: Tooltip for custom ID of feed of message.*/ tr("Feed ID");;
m_tooltipData << tr("Id of the message.") << tr("Is message read?") <<
tr("Is message deleted?") << tr("Is message important?") <<
tr("Id of feed which this message belongs to.") <<
@ -184,7 +182,6 @@ void MessagesModel::setupHeaderData() {
Qt::ItemFlags MessagesModel::flags(const QModelIndex& index) const {
Q_UNUSED(index)
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemNeverHasChildren;
}
@ -205,18 +202,21 @@ QVariant MessagesModel::data(const QModelIndex &idx, int role) const {
if (m_customDateFormat.isEmpty()) {
return dt.toString(Qt::DefaultLocaleShortDate);
}
else {
return dt.toString(m_customDateFormat);
}
}
else if (index_column == MSG_DB_AUTHOR_INDEX) {
const QString author_name = QSqlQueryModel::data(idx, role).toString();
return author_name.isEmpty() ? QSL("-") : author_name;
}
else if (index_column != MSG_DB_IMPORTANT_INDEX && index_column != MSG_DB_READ_INDEX) {
return QSqlQueryModel::data(idx, role);
}
else {
return QVariant();
}
@ -228,7 +228,6 @@ QVariant MessagesModel::data(const QModelIndex &idx, int role) const {
case Qt::FontRole: {
QModelIndex idx_read = index(idx.row(), MSG_DB_READ_INDEX);
QVariant data_read = data(idx_read, Qt::EditRole);
const bool is_bin = qobject_cast<RecycleBin*>(loadedItem()) != nullptr;
bool is_deleted;
@ -236,6 +235,7 @@ QVariant MessagesModel::data(const QModelIndex &idx, int role) const {
QModelIndex idx_del = index(idx.row(), MSG_DB_PDELETED_INDEX);
is_deleted = data(idx_del, Qt::EditRole).toBool();
}
else {
QModelIndex idx_del = index(idx.row(), MSG_DB_DELETED_INDEX);
is_deleted = data(idx_del, Qt::EditRole).toBool();
@ -246,6 +246,7 @@ QVariant MessagesModel::data(const QModelIndex &idx, int role) const {
if (data_read.toBool()) {
return striked ? m_normalStrikedFont : m_normalFont;
}
else {
return striked ? m_boldStrikedFont : m_boldFont;
}
@ -256,14 +257,12 @@ QVariant MessagesModel::data(const QModelIndex &idx, int role) const {
case HighlightImportant: {
QModelIndex idx_important = index(idx.row(), MSG_DB_IMPORTANT_INDEX);
QVariant dta = m_cache->containsData(idx_important.row()) ? m_cache->data(idx_important) : QSqlQueryModel::data(idx_important);
return dta.toInt() == 1 ? QColor(Qt::blue) : QVariant();
}
case HighlightUnread: {
QModelIndex idx_read = index(idx.row(), MSG_DB_READ_INDEX);
QVariant dta = m_cache->containsData(idx_read.row()) ? m_cache->data(idx_read) : QSqlQueryModel::data(idx_read);
return dta.toInt() == 0 ? QColor(Qt::blue) : QVariant();
}
@ -278,15 +277,15 @@ QVariant MessagesModel::data(const QModelIndex &idx, int role) const {
if (index_column == MSG_DB_READ_INDEX) {
QModelIndex idx_read = index(idx.row(), MSG_DB_READ_INDEX);
QVariant dta = m_cache->containsData(idx_read.row()) ? m_cache->data(idx_read) : QSqlQueryModel::data(idx_read);
return dta.toInt() == 1 ? m_readIcon : m_unreadIcon;
}
else if (index_column == MSG_DB_IMPORTANT_INDEX) {
QModelIndex idx_important = index(idx.row(), MSG_DB_IMPORTANT_INDEX);
QVariant dta = m_cache->containsData(idx_important.row()) ? m_cache->data(idx_important) : QSqlQueryModel::data(idx_important);
return dta.toInt() == 1 ? m_favoriteIcon : QVariant();
}
else {
return QVariant();
}
@ -323,6 +322,7 @@ bool MessagesModel::setMessageRead(int row_index, RootItem::ReadStatus read) {
if (DatabaseQueries::markMessagesReadUnread(m_db, QStringList() << QString::number(message.m_id), read)) {
return m_selectedItem->getParentServiceRoot()->onAfterSetMessagesRead(m_selectedItem, QList<Message>() << message, read);
}
else {
return false;
}
@ -371,10 +371,10 @@ bool MessagesModel::switchMessageImportance(int row_index) {
// Commit changes.
if (DatabaseQueries::markMessageImportant(m_db, message.m_id, next_importance)) {
emit dataChanged(index(row_index, 0), index(row_index, MSG_DB_FEED_CUSTOM_ID_INDEX), QVector<int>() << Qt::FontRole);
return m_selectedItem->getParentServiceRoot()->onAfterSwitchMessageImportance(m_selectedItem,
QList<QPair<Message, RootItem::Importance>>() << pair);
}
else {
return false;
}
@ -388,12 +388,10 @@ bool MessagesModel::switchBatchMessageImportance(const QModelIndexList &messages
foreach (const QModelIndex& message, messages) {
const Message msg = messageAt(message.row());
RootItem::Importance message_importance = messageImportance((message.row()));
message_states.append(QPair<Message, RootItem::Importance>(msg, message_importance == RootItem::Important ?
RootItem::NotImportant :
RootItem::Important));
message_ids.append(QString::number(msg.m_id));
QModelIndex idx_msg_imp = index(message.row(), MSG_DB_IMPORTANT_INDEX);
setData(idx_msg_imp, message_importance == RootItem::Important ?
(int) RootItem::NotImportant :
@ -409,6 +407,7 @@ bool MessagesModel::switchBatchMessageImportance(const QModelIndexList &messages
if (DatabaseQueries::switchMessagesImportance(m_db, message_ids)) {
return m_selectedItem->getParentServiceRoot()->onAfterSwitchMessageImportance(m_selectedItem, message_states);
}
else {
return false;
}
@ -421,13 +420,13 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages) {
// Obtain IDs of all desired messages.
foreach (const QModelIndex& message, messages) {
const Message msg = messageAt(message.row());
msgs.append(msg);
message_ids.append(QString::number(msg.m_id));
if (qobject_cast<RecycleBin*>(m_selectedItem) != nullptr) {
setData(index(message.row(), MSG_DB_PDELETED_INDEX), 1);
}
else {
setData(index(message.row(), MSG_DB_DELETED_INDEX), 1);
}
@ -444,6 +443,7 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages) {
if (m_selectedItem->kind() != RootItemKind::Bin) {
deleted = DatabaseQueries::deleteOrRestoreMessagesToFromBin(m_db, message_ids, true);
}
else {
deleted = DatabaseQueries::permanentlyDeleteMessages(m_db, message_ids);
}
@ -451,6 +451,7 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages) {
if (deleted) {
return m_selectedItem->getParentServiceRoot()->onAfterMessagesDelete(m_selectedItem, msgs);
}
else {
return false;
}
@ -463,10 +464,8 @@ bool MessagesModel::setBatchMessagesRead(const QModelIndexList &messages, RootIt
// Obtain IDs of all desired messages.
foreach (const QModelIndex& message, messages) {
Message msg = messageAt(message.row());
msgs.append(msg);
message_ids.append(QString::number(msg.m_id));
setData(index(message.row(), MSG_DB_READ_INDEX), (int) read);
}
@ -479,6 +478,7 @@ bool MessagesModel::setBatchMessagesRead(const QModelIndexList &messages, RootIt
if (DatabaseQueries::markMessagesReadUnread(m_db, message_ids, read)) {
return m_selectedItem->getParentServiceRoot()->onAfterSetMessagesRead(m_selectedItem, msgs, read);
}
else {
return false;
}
@ -491,10 +491,8 @@ bool MessagesModel::setBatchMessagesRestored(const QModelIndexList &messages) {
// Obtain IDs of all desired messages.
foreach (const QModelIndex& message, messages) {
const Message msg = messageAt(message.row());
msgs.append(msg);
message_ids.append(QString::number(msg.m_id));
setData(index(message.row(), MSG_DB_PDELETED_INDEX), 0);
setData(index(message.row(), MSG_DB_DELETED_INDEX), 0);
}
@ -508,6 +506,7 @@ bool MessagesModel::setBatchMessagesRestored(const QModelIndexList &messages) {
if (DatabaseQueries::deleteOrRestoreMessagesToFromBin(m_db, message_ids, false)) {
return m_selectedItem->getParentServiceRoot()->onAfterMessagesRestoredFromBin(m_selectedItem, msgs);
}
else {
return false;
}
@ -518,11 +517,13 @@ QVariant MessagesModel::headerData(int section, Qt::Orientation orientation, int
switch (role) {
case Qt::DisplayRole:
// Display textual headers for all columns except "read" and
// "important" columns.
if (section != MSG_DB_READ_INDEX && section != MSG_DB_IMPORTANT_INDEX) {
return m_headerData.at(section);
}
else {
return QVariant();
}

View file

@ -25,7 +25,6 @@ MessagesModelSqlLayer::MessagesModelSqlLayer()
: m_filter(QSL(DEFAULT_SQL_MESSAGES_FILTER)), m_fieldNames(QMap<int, QString>()),
m_sortColumns(QList<int>()), m_sortOrders(QList<Qt::SortOrder>()) {
m_db = qApp->database()->connection(QSL("MessagesModel"), DatabaseFactory::FromSettings);
m_fieldNames[MSG_DB_ID_INDEX] = "Messages.id";
m_fieldNames[MSG_DB_READ_INDEX] = "Messages.is_read";
m_fieldNames[MSG_DB_DELETED_INDEX] = "Messages.is_deleted";
@ -65,6 +64,7 @@ void MessagesModelSqlLayer::addSortState(int column, Qt::SortOrder order) {
m_sortColumns.append(column);
m_sortOrders.append(order);
}
else {
m_sortColumns.prepend(column);
m_sortOrders.prepend(order);
@ -91,12 +91,12 @@ QString MessagesModelSqlLayer::orderByClause() const {
if (m_sortColumns.isEmpty()) {
return QString();
}
else {
QStringList sorts;
for (int i = 0; i < m_sortColumns.size(); i++) {
QString field_name(m_fieldNames[m_sortColumns[i]]);
sorts.append(field_name + (m_sortOrders[i] == Qt::AscendingOrder ? QSL(" ASC") : QSL(" DESC")));
}

View file

@ -22,7 +22,6 @@
MessagesProxyModel::MessagesProxyModel(MessagesModel* source_model, QObject* parent)
: QSortFilterProxyModel(parent), m_sourceModel(source_model) {
setObjectName(QSL("MessagesProxyModel"));
setSortRole(Qt::EditRole);
setSortCaseSensitivity(Qt::CaseInsensitive);
@ -60,6 +59,7 @@ QModelIndex MessagesProxyModel::getNextUnreadItemIndex(int default_row, int max_
// We found unread message, mark it.
return proxy_index;
}
else {
default_row++;
}
@ -71,7 +71,6 @@ QModelIndex MessagesProxyModel::getNextUnreadItemIndex(int default_row, int max_
bool MessagesProxyModel::lessThan(const QModelIndex& left, const QModelIndex& right) const {
Q_UNUSED(left)
Q_UNUSED(right)
// NOTE: Comparisons are done by SQL servers itself, not client-side.
return false;
}
@ -84,6 +83,7 @@ QModelIndexList MessagesProxyModel::mapListFromSource(const QModelIndexList &ind
// Construct new source index.
mapped_indexes << mapFromSource(m_sourceModel->index(index.row(), index.column()));
}
else {
mapped_indexes << mapFromSource(index);
}
@ -119,6 +119,7 @@ QModelIndexList MessagesProxyModel::match(const QModelIndex &start, int role,
result.append(idx);
}
}
// QString based matching.
else {
if (entered_text.isEmpty()) {
@ -132,30 +133,35 @@ QModelIndexList MessagesProxyModel::match(const QModelIndex &start, int role,
if (QRegExp(entered_text, case_sensitivity).exactMatch(item_text)) {
result.append(idx);
}
break;
case Qt::MatchWildcard:
if (QRegExp(entered_text, case_sensitivity, QRegExp::Wildcard).exactMatch(item_text)) {
result.append(idx);
}
break;
case Qt::MatchStartsWith:
if (item_text.startsWith(entered_text, case_sensitivity)) {
result.append(idx);
}
break;
case Qt::MatchEndsWith:
if (item_text.endsWith(entered_text, case_sensitivity)) {
result.append(idx);
}
break;
case Qt::MatchFixedString:
if (item_text.compare(entered_text, case_sensitivity) == 0) {
result.append(idx);
}
break;
case Qt::MatchContains:
@ -163,6 +169,7 @@ QModelIndexList MessagesProxyModel::match(const QModelIndex &start, int role,
if (item_text.contains(entered_text, case_sensitivity)) {
result.append(idx);
}
break;
}
}

View file

@ -30,7 +30,6 @@ DynamicShortcutsWidget::DynamicShortcutsWidget(QWidget *parent) : QWidget(parent
// Create layout for this control and set is as active.
m_layout = new QGridLayout(this);
m_layout->setMargin(0);
setLayout(m_layout);
}
@ -49,6 +48,7 @@ bool DynamicShortcutsWidget::areShortcutsUnique() const {
// Problem, two identical non-empty shortcuts found.
return false;
}
else {
all_shortcuts.append(binding.second->shortcut());
}
@ -66,7 +66,6 @@ void DynamicShortcutsWidget::updateShortcuts() {
void DynamicShortcutsWidget::populate(QList<QAction*> actions) {
m_actionBindings.clear();
qSort(actions.begin(), actions.end(), DynamicShortcutsWidget::lessThan);
int row_id = 0;
// FIXME: Maybe separate actions into "categories". Each category will start with label.
@ -80,31 +79,24 @@ void DynamicShortcutsWidget::populate(QList<QAction*> actions) {
// Create shortcut catcher for this action and set default shortcut.
ShortcutCatcher* catcher = new ShortcutCatcher(this);
catcher->setDefaultShortcut(action->shortcut());
// Store information for re-initialization of shortcuts
// of actions when widget gets "confirmed".
QPair<QAction*, ShortcutCatcher*> new_binding;
new_binding.first = action;
new_binding.second = catcher;
m_actionBindings << new_binding;
// Add new catcher to our control.
QLabel* action_label = new QLabel(this);
action_label->setText(action->text().remove(QSL("&")));
action_label->setToolTip(action->toolTip());
action_label->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
QLabel* action_icon = new QLabel(this);
action_icon->setPixmap(action->icon().pixmap(ICON_SIZE_SETTINGS, ICON_SIZE_SETTINGS));
action_icon->setToolTip(action->toolTip());
m_layout->addWidget(action_icon, row_id, 0);
m_layout->addWidget(action_label, row_id, 1);
m_layout->addWidget(catcher, row_id, 2);
row_id++;
connect(catcher, &ShortcutCatcher::shortcutChanged, this, &DynamicShortcutsWidget::setupChanged);
}

View file

@ -93,11 +93,13 @@ void ShortcutButton::keyPressEvent(QKeyEvent *event) {
break;
default:
// We now have a valid key press.
if (pressed_key) {
if ((pressed_key == Qt::Key_Backtab) && (m_catcher->m_modifierKeys & Qt::SHIFT)) {
pressed_key = Qt::Key_Tab | m_catcher->m_modifierKeys;
}
else {
pressed_key |= m_catcher->m_modifierKeys;
}
@ -130,7 +132,6 @@ void ShortcutButton::keyReleaseEvent(QKeyEvent *event) {
}
event->accept();
const Qt::KeyboardModifiers new_modifiers = event->modifiers() &
(Qt::SHIFT | Qt::CTRL | Qt::ALT | Qt::META);

View file

@ -58,34 +58,28 @@ ShortcutCatcher::ShortcutCatcher(QWidget *parent)
m_layout = new QHBoxLayout(this);
m_layout->setMargin(0);
m_layout->setSpacing(1);
// Create reset button.
m_btnReset = new PlainToolButton(this);
m_btnReset->setIcon(qApp->icons()->fromTheme(QSL("document-revert")));
m_btnReset->setFocusPolicy(Qt::NoFocus);
m_btnReset->setToolTip(tr("Reset to original shortcut."));
// Create clear button.
m_btnClear = new PlainToolButton(this);
m_btnClear->setIcon(qApp->icons()->fromTheme(QSL("list-remove")));
m_btnClear->setFocusPolicy(Qt::NoFocus);
m_btnClear->setToolTip(tr("Clear current shortcut."));
// Clear main shortcut catching button.
m_btnChange = new ShortcutButton(this);
m_btnChange->setFocusPolicy(Qt::StrongFocus);
m_btnChange->setToolTip(tr("Click and hit new shortcut."));
// Add both buttons to the layout.
m_layout->addWidget(m_btnChange);
m_layout->addWidget(m_btnReset);
m_layout->addWidget(m_btnClear);
// Establish needed connections.
connect(m_btnReset, &QToolButton::clicked, this, &ShortcutCatcher::resetShortcut);
connect(m_btnClear, &QToolButton::clicked, this, &ShortcutCatcher::clearShortcut);
connect(m_btnChange, &QToolButton::clicked, this, &ShortcutCatcher::startRecording);
// Prepare initial state of the control.
updateDisplayShortcut();
}
@ -104,7 +98,6 @@ void ShortcutCatcher::startRecording() {
m_isRecording = true;
m_btnChange->setDown(true);
m_btnChange->grabKeyboard();
updateDisplayShortcut();
}
@ -112,9 +105,7 @@ void ShortcutCatcher::doneRecording() {
m_isRecording = false;
m_btnChange->releaseKeyboard();
m_btnChange->setDown(false);
updateDisplayShortcut();
emit shortcutChanged(m_currentSequence);
}
@ -133,15 +124,19 @@ void ShortcutCatcher::updateDisplayShortcut() {
if (!str.isEmpty()) {
str.append(QSL(","));
}
if (m_modifierKeys & Qt::META) {
str += QL1S("Meta + ");
}
if (m_modifierKeys & Qt::CTRL) {
str += QL1S("Ctrl + ");
}
if (m_modifierKeys & Qt::ALT) {
str += QL1S("Alt + ");
}
if (m_modifierKeys & Qt::SHIFT) {
str += QL1S("Shift + ");
}

View file

@ -48,7 +48,6 @@ void ClickableLabel::setFallbackIcon(const QIcon &fallbackIcon) {
void ClickableLabel::updateIcon() {
if (!m_themeIcon.isEmpty()) {
const QIcon icon = qApp->icons()->fromTheme(m_themeIcon);
if (!icon.isNull()) {
@ -72,13 +71,16 @@ void ClickableLabel::mouseReleaseEvent(QMouseEvent* ev) {
if (ev->modifiers() == Qt::ControlModifier) {
emit middleClicked(ev->globalPos());
}
else {
emit clicked(ev->globalPos());
}
}
else if (ev->button() == Qt::MiddleButton && rect().contains(ev->pos())) {
emit middleClicked(ev->globalPos());
}
else {
QLabel::mouseReleaseEvent(ev);
}

View file

@ -34,7 +34,6 @@ QColor ColorLabel::color() const {
void ColorLabel::setColor(const QColor& color) {
m_color = color;
repaint();
}

View file

@ -25,11 +25,9 @@
ComboBoxWithStatus::ComboBoxWithStatus(QWidget* parent)
: WidgetWithStatus(parent) {
m_wdgInput = new QComboBox(this);
// Set correct size for the tool button.
const int txt_input_height = m_wdgInput->sizeHint().height();
m_btnStatus->setFixedSize(txt_input_height, txt_input_height);
// Compose the layout.
m_layout->addWidget(m_wdgInput);
m_layout->addWidget(m_btnStatus);

View file

@ -27,19 +27,14 @@
FormAbout::FormAbout(QWidget* parent) : QDialog(parent), m_ui(new Ui::FormAbout()) {
m_ui->setupUi(this);
// Set flags and attributes.
setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint);
setWindowIcon(qApp->icons()->fromTheme(QSL("help-about")));
//: About RSS Guard dialog title.
setWindowTitle(tr("About %1").arg(APP_NAME));
m_ui->m_lblIcon->setPixmap(QPixmap(APP_ICON_PATH));
// Load information from embedded text files.
loadLicenseAndInformation();
// Load additional paths information.
loadSettingsAndPaths();
}
@ -52,6 +47,7 @@ void FormAbout::loadSettingsAndPaths() {
if (qApp->settings()->type() == SettingsProperties::Portable) {
m_ui->m_txtPathsSettingsType->setText(tr("FULLY portable"));
}
else {
m_ui->m_txtPathsSettingsType->setText(tr("NOT portable"));
}
@ -65,34 +61,39 @@ void FormAbout::loadSettingsAndPaths() {
void FormAbout::loadLicenseAndInformation() {
QFile file;
file.setFileName(APP_INFO_PATH + QL1S("/COPYING_GNU_GPL_HTML"));
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
m_ui->m_txtLicenseGnu->setText(QString::fromUtf8(file.readAll()));
}
else {
m_ui->m_txtLicenseGnu->setText(tr("License not found."));
}
file.close();
file.close();
file.setFileName(APP_INFO_PATH + QL1S("/COPYING_BSD"));
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
m_ui->m_txtLicenseBsd->setText(QString::fromUtf8(file.readAll()));
}
else {
m_ui->m_txtLicenseBsd->setText(tr("License not found."));
}
file.close();
file.close();
file.setFileName(APP_INFO_PATH + QL1S("/CHANGELOG"));
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
m_ui->m_txtChangelog->setText(QString::fromUtf8(file.readAll()));
}
else {
m_ui->m_txtChangelog->setText(tr("Changelog not found."));
}
file.close();
file.close();
// Set other informative texts.
m_ui->m_lblDesc->setText(tr("<b>%8</b><br>"
"<b>Version:</b> %1 (built on %2/%3)<br>"
@ -107,7 +108,6 @@ void FormAbout::loadLicenseAndInformation() {
qVersion(),
QT_VERSION_STR,
APP_NAME));
m_ui->m_txtInfo->setText(tr("<body>%5 is a (very) tiny feed reader."
"<br><br>This software is distributed under the terms of GNU General Public License, version 3."
"<br><br>Contacts:"

View file

@ -29,11 +29,9 @@
FormAddAccount::FormAddAccount(const QList<ServiceEntryPoint*>& entry_points, FeedsModel* model, QWidget* parent)
: QDialog(parent), m_ui(new Ui::FormAddAccount), m_model(model), m_entryPoints(entry_points) {
m_ui->setupUi(this);
// Set flags and attributes.
setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint);
setWindowIcon(qApp->icons()->fromTheme(QSL("document-new")));
connect(m_ui->m_listEntryPoints, &QListWidget::itemDoubleClicked, this, &FormAddAccount::addSelectedAccount);
connect(m_ui->m_buttonBox, &QDialogButtonBox::accepted, this, &FormAddAccount::addSelectedAccount);
connect(m_ui->m_listEntryPoints, &QListWidget::itemSelectionChanged, this, &FormAddAccount::displayActiveEntryPointDetails);
@ -46,13 +44,13 @@ FormAddAccount::~FormAddAccount() {
void FormAddAccount::addSelectedAccount() {
accept();
ServiceEntryPoint* point = selectedEntryPoint();
ServiceRoot* new_root = point->createNewRoot();
if (new_root != nullptr) {
m_model->addServiceAccount(new_root, true);
}
else {
qCritical("Cannot create new account.");
}
@ -60,7 +58,6 @@ void FormAddAccount::addSelectedAccount() {
void FormAddAccount::displayActiveEntryPointDetails() {
const ServiceEntryPoint* point = selectedEntryPoint();
m_ui->m_txtAuthor->setText(point->author());
m_ui->m_txtDescription->setText(point->description());
m_ui->m_txtName->setText(point->name());

View file

@ -31,17 +31,14 @@
FormBackupDatabaseSettings::FormBackupDatabaseSettings(QWidget* parent) : QDialog(parent), m_ui(new Ui::FormBackupDatabaseSettings) {
m_ui->setupUi(this);
m_ui->m_txtBackupName->lineEdit()->setPlaceholderText(tr("Common name for backup files"));
setWindowIcon(qApp->icons()->fromTheme(QSL("document-export")));
setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint);
connect(m_ui->m_checkBackupDatabase, &QCheckBox::toggled, this, &FormBackupDatabaseSettings::checkOkButton);
connect(m_ui->m_checkBackupSettings, &QCheckBox::toggled, this, &FormBackupDatabaseSettings::checkOkButton);
connect(m_ui->m_buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &FormBackupDatabaseSettings::performBackup);
connect(m_ui->m_txtBackupName->lineEdit(), &BaseLineEdit::textChanged, this, &FormBackupDatabaseSettings::checkBackupNames);
connect(m_ui->m_txtBackupName->lineEdit(), &BaseLineEdit::textChanged, this, &FormBackupDatabaseSettings::checkOkButton);
connect(m_ui->m_btnSelectFolder, &QPushButton::clicked, this, &FormBackupDatabaseSettings::selectFolderInitial);
selectFolder(qApp->getDocumentsFolderPath());
m_ui->m_txtBackupName->lineEdit()->setText(QString(APP_LOW_NAME) + QL1S("_") + QDateTime::currentDateTime().toString(QSL("yyyyMMddHHmm")));
m_ui->m_lblResult->setStatus(WidgetWithStatus::Warning, tr("No operation executed yet."), tr("No operation executed yet."));
@ -64,6 +61,7 @@ void FormBackupDatabaseSettings::performBackup() {
tr("Backup was created successfully and stored in target directory."),
tr("Backup was created successfully."));
}
catch (const ApplicationException& ex) {
m_ui->m_lblResult->setStatus(WidgetWithStatus::Error, ex.message(), tr("Backup failed."));
}
@ -88,6 +86,7 @@ void FormBackupDatabaseSettings::checkBackupNames(const QString &name) {
if (name.simplified().isEmpty()) {
m_ui->m_txtBackupName->setStatus(WidgetWithStatus::Error, tr("Backup name cannot be empty."));
}
else {
m_ui->m_txtBackupName->setStatus(WidgetWithStatus::Ok, tr("Backup name looks okay."));
}

View file

@ -28,11 +28,9 @@
FormDatabaseCleanup::FormDatabaseCleanup(QWidget* parent) : QDialog(parent), m_ui(new Ui::FormDatabaseCleanup), m_cleaner(nullptr) {
m_ui->setupUi(this);
// Set flags and attributes.
setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint | Qt::WindowTitleHint);
setWindowIcon(qApp->icons()->fromTheme(QSL("edit-clear")));
connect(m_ui->m_spinDays, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &FormDatabaseCleanup::updateDaysSuffix);
m_ui->m_spinDays->setValue(DEFAULT_DAYS_TO_DELETE_MSG);
m_ui->m_lblResult->setStatus(WidgetWithStatus::Information, tr("I am ready."), tr("I am ready."));
@ -50,7 +48,6 @@ void FormDatabaseCleanup::setCleaner(DatabaseCleaner *cleaner) {
}
m_cleaner = cleaner;
connect(m_ui->m_btnBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &FormDatabaseCleanup::startPurging);
connect(this, &FormDatabaseCleanup::purgeRequested, m_cleaner, &DatabaseCleaner::purgeDatabaseData);
connect(m_cleaner, &DatabaseCleaner::purgeStarted, this, &FormDatabaseCleanup::onPurgeStarted);
@ -62,6 +59,7 @@ void FormDatabaseCleanup::closeEvent(QCloseEvent *event) {
if (m_ui->m_progressBar->isEnabled()) {
event->ignore();
}
else {
QDialog::closeEvent(event);
}
@ -71,6 +69,7 @@ void FormDatabaseCleanup::keyPressEvent(QKeyEvent *event) {
if (m_ui->m_progressBar->isEnabled()) {
event->ignore();
}
else {
QDialog::keyPressEvent(event);
}
@ -82,14 +81,12 @@ void FormDatabaseCleanup::updateDaysSuffix(int number) {
void FormDatabaseCleanup::startPurging() {
CleanerOrders orders;
orders.m_removeRecycleBin = m_ui->m_checkRemoveRecycleBin->isChecked();
orders.m_removeOldMessages = m_ui->m_checkRemoveOldMessages->isChecked();
orders.m_barrierForRemovingOldMessagesInDays = m_ui->m_spinDays->value();
orders.m_removeReadMessages = m_ui->m_checkRemoveReadMessages->isChecked();
orders.m_shrinkDatabase = m_ui->m_checkShrink->isEnabled() && m_ui->m_checkShrink->isChecked();
orders.m_removeStarredMessages = m_ui->m_checkRemoveStarredMessages->isChecked();
emit purgeRequested(orders);
}
@ -113,6 +110,7 @@ void FormDatabaseCleanup::onPurgeFinished(bool finished) {
if (finished) {
m_ui->m_lblResult->setStatus(WidgetWithStatus::Ok, tr("Database cleanup is completed."), tr("Database cleanup is completed."));
}
else {
m_ui->m_lblResult->setStatus(WidgetWithStatus::Error, tr("Database cleanup failed."), tr("Database cleanup failed."));
}
@ -123,10 +121,8 @@ void FormDatabaseCleanup::onPurgeFinished(bool finished) {
void FormDatabaseCleanup::loadDatabaseInfo() {
qint64 file_size = qApp->database()->getDatabaseFileSize();
qint64 data_size = qApp->database()->getDatabaseDataSize();
QString file_size_str = file_size > 0 ? QString::number(file_size / 1000000.0) + QL1S(" MB") : tr("unknown");
QString data_size_str = data_size > 0 ? QString::number(data_size / 1000000.0) + QL1S(" MB") : tr("unknown");
m_ui->m_txtFileSize->setText(tr("file: %1, data: %2").arg(file_size_str, data_size_str));
m_ui->m_txtDatabaseType->setText(qApp->database()->humanDriverName(qApp->database()->activeDatabaseDriver()));
m_ui->m_checkShrink->setEnabled(qApp->database()->activeDatabaseDriver() == DatabaseFactory::SQLITE ||

View file

@ -63,47 +63,35 @@
FormMain::FormMain(QWidget* parent, Qt::WindowFlags f)
: QMainWindow(parent, f), m_ui(new Ui::FormMain) {
m_ui->setupUi(this);
#if defined(USE_WEBENGINE)
m_adblockIcon = new AdBlockIcon(this);
m_adblockIconAction = m_adblockIcon->menuAction();
m_adblockIconAction->setObjectName(QSL("m_adblockIconAction"));
m_ui->m_menuTools->addAction(m_adblockIconAction);
#endif
qApp->setMainForm(this);
// Add these actions to the list of actions of the main window.
// This allows to use actions via shortcuts
// even if main menu is not visible.
addActions(allActions());
#if defined(USE_WEBENGINE)
addAction(m_adblockIconAction);
#endif
m_statusBar = new StatusBar(this);
setStatusBar(m_statusBar);
// Prepare main window and tabs.
prepareMenus();
// Prepare tabs.
//m_ui->m_tabWidget->initializeTabs();
tabWidget()->feedMessageViewer()->feedsToolBar()->loadSavedActions();
tabWidget()->feedMessageViewer()->messagesToolBar()->loadSavedActions();
// Establish connections.
createConnections();
updateMessageButtonsAvailability();
updateFeedButtonsAvailability();
// Setup some appearance of the window.
setupIcons();
loadSize();
m_statusBar->loadSavedActions();
}
@ -128,12 +116,11 @@ void FormMain::showDbCleanupAssistant() {
QScopedPointer<FormDatabaseCleanup> form_pointer(new FormDatabaseCleanup(this));
form_pointer.data()->setCleaner(qApp->feedReader()->databaseCleaner());
form_pointer.data()->exec();
qApp->feedUpdateLock()->unlock();
tabWidget()->feedMessageViewer()->messagesView()->reloadSelections();
qApp->feedReader()->feedsModel()->reloadCountsOfWholeModel();
}
else {
qApp->showGuiMessage(tr("Cannot cleanup database"),
tr("Cannot cleanup database, because another critical action is running."),
@ -143,7 +130,6 @@ void FormMain::showDbCleanupAssistant() {
QList<QAction*> FormMain::allActions() const {
QList<QAction*> actions;
// Add basic actions.
actions << m_ui->m_actionSettings;
actions << m_ui->m_actionDownloadManager;
@ -164,7 +150,6 @@ QList<QAction*> FormMain::allActions() const {
actions << m_ui->m_actionSwitchListHeaders;
actions << m_ui->m_actionSwitchStatusBar;
actions << m_ui->m_actionSwitchMessageListOrientation;
// Add feeds/messages actions.
actions << m_ui->m_actionOpenSelectedSourceArticlesExternally;
actions << m_ui->m_actionOpenSelectedMessagesInternally;
@ -196,15 +181,12 @@ QList<QAction*> FormMain::allActions() const {
actions << m_ui->m_actionSelectPreviousMessage;
actions << m_ui->m_actionSelectNextUnreadMessage;
actions << m_ui->m_actionExpandCollapseItem;
#if defined(USE_WEBENGINE)
actions << m_ui->m_actionTabNewWebBrowser;
actions << m_adblockIconAction;
#endif
actions << m_ui->m_actionTabsCloseAll;
actions << m_ui->m_actionTabsCloseAllExceptCurrent;
return actions;
}
@ -216,7 +198,6 @@ void FormMain::prepareMenus() {
#else
m_trayMenu = new QMenu(QSL(APP_NAME), this);
#endif
// Add needed items to the menu.
m_trayMenu->addAction(m_ui->m_actionSwitchMainWindow);
m_trayMenu->addSeparator();
@ -225,7 +206,6 @@ void FormMain::prepareMenus() {
m_trayMenu->addSeparator();
m_trayMenu->addAction(m_ui->m_actionSettings);
m_trayMenu->addAction(m_ui->m_actionQuit);
qDebug("Creating tray icon menu.");
}
@ -233,7 +213,6 @@ void FormMain::prepareMenus() {
m_ui->m_menuWebBrowserTabs->removeAction(m_ui->m_actionTabNewWebBrowser);
m_ui->m_menuWebBrowserTabs->setTitle(tr("Tabs"));
#endif
#if defined(Q_OS_MAC)
m_ui->m_actionSwitchMainMenu->setVisible(false);
m_ui->m_actionFullscreen->setVisible(false);
@ -245,10 +224,12 @@ void FormMain::switchFullscreenMode() {
qApp->settings()->setValue(GROUP(GUI), GUI::IsMainWindowMaximizedBeforeFullscreen, isMaximized());
showFullScreen();
}
else {
if (qApp->settings()->value(GROUP(GUI), SETTING(GUI::IsMainWindowMaximizedBeforeFullscreen)).toBool()) {
setWindowState((windowState() & ~Qt::WindowFullScreen) | Qt::WindowMaximized);
}
else {
showNormal();
}
@ -263,7 +244,6 @@ void FormMain::updateAddItemMenu() {
QMenu* root_menu = new QMenu(activated_root->title(), m_ui->m_menuAddItem);
root_menu->setIcon(activated_root->icon());
root_menu->setToolTip(activated_root->description());
QList<QAction*> specific_root_actions = activated_root->addItemMenu();
if (activated_root->supportsCategoryAdding()) {
@ -299,6 +279,7 @@ void FormMain::updateAddItemMenu() {
m_ui->m_menuAddItem->addAction(m_ui->m_actionAddCategoryIntoSelectedAccount);
m_ui->m_menuAddItem->addAction(m_ui->m_actionAddFeedIntoSelectedAccount);
}
else {
m_ui->m_menuAddItem->addAction(m_ui->m_actionNoActions);
}
@ -311,7 +292,6 @@ void FormMain::updateRecycleBinMenu() {
QMenu* root_menu = new QMenu(activated_root->title(), m_ui->m_menuRecycleBin);
root_menu->setIcon(activated_root->icon());
root_menu->setToolTip(activated_root->description());
RecycleBin* bin = activated_root->recycleBin();
QList<QAction*> context_menu;
@ -322,6 +302,7 @@ void FormMain::updateRecycleBinMenu() {
no_action->setEnabled(false);
root_menu->addAction(no_action);
}
else if ((context_menu = bin->contextMenu()).isEmpty()) {
QAction* no_action = new QAction(qApp->icons()->fromTheme(QSL("dialog-error")),
tr("No actions possible"),
@ -329,6 +310,7 @@ void FormMain::updateRecycleBinMenu() {
no_action->setEnabled(false);
root_menu->addAction(no_action);
}
else {
root_menu->addActions(context_menu);
}
@ -351,7 +333,6 @@ void FormMain::updateAccountsMenu() {
QMenu* root_menu = new QMenu(activated_root->title(), m_ui->m_menuAccounts);
root_menu->setIcon(activated_root->icon());
root_menu->setToolTip(activated_root->description());
QList<QAction*> root_actions = activated_root->serviceMenu();
if (root_actions.isEmpty()) {
@ -361,6 +342,7 @@ void FormMain::updateAccountsMenu() {
no_action->setEnabled(false);
root_menu->addAction(no_action);
}
else {
root_menu->addActions(root_actions);
}
@ -379,7 +361,6 @@ void FormMain::updateAccountsMenu() {
void FormMain::onFeedUpdatesFinished(const FeedDownloadResults& results) {
Q_UNUSED(results)
statusBar()->clearProgressFeeds();
tabWidget()->feedMessageViewer()->messagesView()->reloadSelections();
}
@ -398,8 +379,8 @@ void FormMain::onFeedUpdatesProgress(const Feed *feed, int current, int total) {
void FormMain::updateMessageButtonsAvailability() {
const bool one_message_selected = tabWidget()->feedMessageViewer()->messagesView()->selectionModel()->selectedRows().size() == 1;
const bool atleast_one_message_selected = !tabWidget()->feedMessageViewer()->messagesView()->selectionModel()->selectedRows().isEmpty();
const bool bin_loaded = tabWidget()->feedMessageViewer()->messagesView()->sourceModel()->loadedItem() != nullptr && tabWidget()->feedMessageViewer()->messagesView()->sourceModel()->loadedItem()->kind() == RootItemKind::Bin;
const bool bin_loaded = tabWidget()->feedMessageViewer()->messagesView()->sourceModel()->loadedItem() != nullptr
&& tabWidget()->feedMessageViewer()->messagesView()->sourceModel()->loadedItem()->kind() == RootItemKind::Bin;
m_ui->m_actionDeleteSelectedMessages->setEnabled(atleast_one_message_selected);
m_ui->m_actionRestoreSelectedMessages->setEnabled(atleast_one_message_selected && bin_loaded);
m_ui->m_actionMarkSelectedMessagesAsRead->setEnabled(atleast_one_message_selected);
@ -418,7 +399,6 @@ void FormMain::updateFeedButtonsAvailability() {
const bool feed_selected = anything_selected && selected_item->kind() == RootItemKind::Feed;
const bool category_selected = anything_selected && selected_item->kind() == RootItemKind::Category;
const bool service_selected = anything_selected && selected_item->kind() == RootItemKind::ServiceRoot;
m_ui->m_actionStopRunningItemsUpdate->setEnabled(is_update_running);
m_ui->m_actionBackupDatabaseSettings->setEnabled(!critical_action_running);
m_ui->m_actionCleanupDatabase->setEnabled(!critical_action_running);
@ -431,12 +411,10 @@ void FormMain::updateFeedButtonsAvailability() {
m_ui->m_actionUpdateSelectedItems->setEnabled(!critical_action_running && (feed_selected || category_selected || service_selected));
m_ui->m_actionViewSelectedItemsNewspaperMode->setEnabled(anything_selected);
m_ui->m_actionExpandCollapseItem->setEnabled(anything_selected);
m_ui->m_actionServiceDelete->setEnabled(service_selected);
m_ui->m_actionServiceEdit->setEnabled(service_selected);
m_ui->m_actionAddFeedIntoSelectedAccount->setEnabled(anything_selected);
m_ui->m_actionAddCategoryIntoSelectedAccount->setEnabled(anything_selected);
m_ui->m_menuAddItem->setEnabled(!critical_action_running);
m_ui->m_menuAccounts->setEnabled(!critical_action_running);
m_ui->m_menuRecycleBin->setEnabled(!critical_action_running);
@ -447,11 +425,13 @@ void FormMain::switchVisibility(bool force_hide) {
if (SystemTrayIcon::isSystemTrayActivated()) {
hide();
}
else {
// Window gets minimized in single-window mode.
showMinimized();
}
}
else {
display();
}
@ -460,19 +440,16 @@ void FormMain::switchVisibility(bool force_hide) {
void FormMain::display() {
// Make sure window is not minimized.
setWindowState(windowState() & ~Qt::WindowMinimized);
// Display the window and make sure it is raised on top.
show();
activateWindow();
raise();
// Raise alert event. Check the documentation for more info on this.
Application::alert(this);
}
void FormMain::setupIcons() {
IconFactory* icon_theme_factory = qApp->icons();
// Setup icons of this main window.
m_ui->m_actionDownloadManager->setIcon(icon_theme_factory->fromTheme(QSL("emblem-downloads")));
m_ui->m_actionSettings->setIcon(icon_theme_factory->fromTheme(QSL("document-properties")));
@ -486,7 +463,6 @@ void FormMain::setupIcons() {
m_ui->m_actionRestoreDatabaseSettings->setIcon(icon_theme_factory->fromTheme(QSL("document-import")));
m_ui->m_actionDonate->setIcon(icon_theme_factory->fromTheme(QSL("applications-office")));
m_ui->m_actionDisplayWiki->setIcon(icon_theme_factory->fromTheme(QSL("applications-science")));
// View.
m_ui->m_actionSwitchMainWindow->setIcon(icon_theme_factory->fromTheme(QSL("window-close")));
m_ui->m_actionFullscreen->setIcon(icon_theme_factory->fromTheme(QSL("view-fullscreen")));
@ -497,7 +473,6 @@ void FormMain::setupIcons() {
m_ui->m_actionSwitchStatusBar->setIcon(icon_theme_factory->fromTheme(QSL("dialog-information")));
m_ui->m_actionSwitchMessageListOrientation->setIcon(icon_theme_factory->fromTheme(QSL("view-restore")));
m_ui->m_menuShowHide->setIcon(icon_theme_factory->fromTheme(QSL("view-restore")));
// Feeds/messages.
m_ui->m_menuAddItem->setIcon(icon_theme_factory->fromTheme(QSL("list-add")));
m_ui->m_actionStopRunningItemsUpdate->setIcon(icon_theme_factory->fromTheme(QSL("process-stop")));
@ -533,12 +508,10 @@ void FormMain::setupIcons() {
m_ui->m_actionServiceDelete->setIcon(icon_theme_factory->fromTheme(QSL("list-remove")));
m_ui->m_actionAddFeedIntoSelectedAccount->setIcon(icon_theme_factory->fromTheme(QSL("application-rss+xml")));
m_ui->m_actionAddCategoryIntoSelectedAccount->setIcon(icon_theme_factory->fromTheme(QSL("folder")));
// Tabs & web browser.
m_ui->m_actionTabNewWebBrowser->setIcon(icon_theme_factory->fromTheme(QSL("tab-new")));
m_ui->m_actionTabsCloseAll->setIcon(icon_theme_factory->fromTheme(QSL("window-close")));
m_ui->m_actionTabsCloseAllExceptCurrent->setIcon(icon_theme_factory->fromTheme(QSL("window-close")));
// Setup icons on TabWidget too.
m_ui->m_tabWidget->setupIcons();
}
@ -546,14 +519,12 @@ void FormMain::setupIcons() {
void FormMain::loadSize() {
const QRect screen = qApp->desktop()->screenGeometry();
const Settings* settings = qApp->settings();
// Reload main window size & position.
resize(settings->value(GROUP(GUI), GUI::MainWindowInitialSize, size()).toSize());
move(settings->value(GROUP(GUI), GUI::MainWindowInitialPosition, screen.center() - rect().center()).toPoint());
if (settings->value(GROUP(GUI), SETTING(GUI::MainWindowStartsMaximized)).toBool()) {
setWindowState(windowState() | Qt::WindowMaximized);
// We process events so that window is really maximized fast.
qApp->processEvents();
}
@ -566,13 +537,11 @@ void FormMain::loadSize() {
// Hide the main menu if user wants it.
m_ui->m_actionSwitchMainMenu->setChecked(settings->value(GROUP(GUI), SETTING(GUI::MainMenuVisible)).toBool());
// Adjust dimensions of "feeds & messages" widget.
m_ui->m_tabWidget->feedMessageViewer()->loadSize();
m_ui->m_actionSwitchToolBars->setChecked(settings->value(GROUP(GUI), SETTING(GUI::ToolbarsVisible)).toBool());
m_ui->m_actionSwitchListHeaders->setChecked(settings->value(GROUP(GUI), SETTING(GUI::ListHeadersVisible)).toBool());
m_ui->m_actionSwitchStatusBar->setChecked(settings->value(GROUP(GUI), SETTING(GUI::StatusBarVisible)).toBool());
// Make sure that only unread feeds are shown if user has that feature set on.
m_ui->m_actionShowOnlyUnreadItems->setChecked(settings->value(GROUP(Feeds), SETTING(Feeds::ShowOnlyUnreadFeeds)).toBool());
}
@ -584,18 +553,15 @@ void FormMain::saveSize() {
if (is_fullscreen) {
m_ui->m_actionFullscreen->setChecked(false);
// We (process events to really) un-fullscreen, so that we can determine if window is really maximized.
qApp->processEvents();
}
if (isMaximized()) {
is_maximized = true;
// Window is maximized, we store that fact to settings and unmaximize.
qApp->settings()->setValue(GROUP(GUI), GUI::IsMainWindowMaximizedBeforeFullscreen, isMaximized());
setWindowState((windowState() & ~Qt::WindowMaximized) | Qt::WindowActive);
// We process events to really have window un-maximized.
qApp->processEvents();
}
@ -606,7 +572,6 @@ void FormMain::saveSize() {
settings->setValue(GROUP(GUI), GUI::MainWindowStartsMaximized, is_maximized);
settings->setValue(GROUP(GUI), GUI::MainWindowStartsFullscreen, is_fullscreen);
settings->setValue(GROUP(GUI), GUI::StatusBarVisible, m_ui->m_actionSwitchStatusBar->isChecked());
m_ui->m_tabWidget->feedMessageViewer()->saveSize();
}
@ -615,53 +580,43 @@ void FormMain::createConnections() {
connect(m_ui->m_menuAddItem, &QMenu::aboutToShow, this, &FormMain::updateAddItemMenu);
connect(m_ui->m_menuRecycleBin, &QMenu::aboutToShow, this, &FormMain::updateRecycleBinMenu);
connect(m_ui->m_menuAccounts, &QMenu::aboutToShow, this, &FormMain::updateAccountsMenu);
connect(m_ui->m_actionServiceDelete, &QAction::triggered, m_ui->m_actionDeleteSelectedItem, &QAction::triggered);
connect(m_ui->m_actionServiceEdit, &QAction::triggered, m_ui->m_actionEditSelectedItem, &QAction::triggered);
// Menu "File" connections.
connect(m_ui->m_actionBackupDatabaseSettings, &QAction::triggered, this, &FormMain::backupDatabaseSettings);
connect(m_ui->m_actionRestoreDatabaseSettings, &QAction::triggered, this, &FormMain::restoreDatabaseSettings);
connect(m_ui->m_actionQuit, &QAction::triggered, qApp, &Application::quit);
connect(m_ui->m_actionServiceAdd, &QAction::triggered, this, &FormMain::showAddAccountDialog);
connect(m_ui->m_actionRestart, &QAction::triggered, qApp, &Application::restart);
// Menu "View" connections.
connect(m_ui->m_actionFullscreen, &QAction::toggled, this, &FormMain::switchFullscreenMode);
connect(m_ui->m_actionSwitchMainMenu, &QAction::toggled, m_ui->m_menuBar, &QMenuBar::setVisible);
connect(m_ui->m_actionSwitchMainWindow, &QAction::triggered, this, &FormMain::switchVisibility);
connect(m_ui->m_actionSwitchStatusBar, &QAction::toggled, statusBar(), &StatusBar::setVisible);
// Menu "Tools" connections.
connect(m_ui->m_actionSettings, &QAction::triggered, this, &FormMain::showSettings);
connect(m_ui->m_actionDownloadManager, &QAction::triggered, m_ui->m_tabWidget, &TabWidget::showDownloadManager);
connect(m_ui->m_actionCleanupDatabase, &QAction::triggered, this, &FormMain::showDbCleanupAssistant);
// Menu "Help" connections.
connect(m_ui->m_actionAboutGuard, &QAction::triggered, this, &FormMain::showAbout);
connect(m_ui->m_actionCheckForUpdates, &QAction::triggered, this, &FormMain::showUpdates);
connect(m_ui->m_actionReportBug, &QAction::triggered, this, &FormMain::reportABug);
connect(m_ui->m_actionDonate, &QAction::triggered, this, &FormMain::donate);
connect(m_ui->m_actionDisplayWiki, &QAction::triggered, this, &FormMain::showWiki);
// Tab widget connections.
connect(m_ui->m_actionTabsCloseAllExceptCurrent, &QAction::triggered, m_ui->m_tabWidget, &TabWidget::closeAllTabsExceptCurrent);
connect(m_ui->m_actionTabsCloseAll, &QAction::triggered, m_ui->m_tabWidget, &TabWidget::closeAllTabs);
connect(m_ui->m_actionTabNewWebBrowser, &QAction::triggered, m_ui->m_tabWidget, &TabWidget::addEmptyBrowser);
connect(tabWidget()->feedMessageViewer()->feedsView(), &FeedsView::itemSelected, this, &FormMain::updateFeedButtonsAvailability);
connect(qApp->feedUpdateLock(), &Mutex::locked, this, &FormMain::updateFeedButtonsAvailability);
connect(qApp->feedUpdateLock(), &Mutex::unlocked, this, &FormMain::updateFeedButtonsAvailability);
connect(tabWidget()->feedMessageViewer()->messagesView(), &MessagesView::currentMessageRemoved,
this, &FormMain::updateMessageButtonsAvailability);
connect(tabWidget()->feedMessageViewer()->messagesView(), &MessagesView::currentMessageChanged,
this, &FormMain::updateMessageButtonsAvailability);
connect(qApp->feedReader(), &FeedReader::feedUpdatesStarted, this, &FormMain::onFeedUpdatesStarted);
connect(qApp->feedReader(), &FeedReader::feedUpdatesProgress, this, &FormMain::onFeedUpdatesProgress);
connect(qApp->feedReader(), &FeedReader::feedUpdatesFinished, this, &FormMain::onFeedUpdatesFinished);
// Toolbar forwardings.
connect(m_ui->m_actionAddFeedIntoSelectedAccount, &QAction::triggered,
tabWidget()->feedMessageViewer()->feedsView(), &FeedsView::addFeedIntoSelectedAccount);

View file

@ -28,13 +28,10 @@
FormRestoreDatabaseSettings::FormRestoreDatabaseSettings(QWidget* parent)
: QDialog(parent), m_ui(new Ui::FormRestoreDatabaseSettings), m_shouldRestart(false) {
m_ui->setupUi(this);
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."));
setWindowIcon(qApp->icons()->fromTheme(QSL("document-import")));
setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint);
connect(m_btnRestart, &QPushButton::clicked, this, [ = ]() {
m_shouldRestart = true;
close();
@ -43,7 +40,6 @@ FormRestoreDatabaseSettings::FormRestoreDatabaseSettings(QWidget *parent)
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_buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(performRestoration()));
selectFolder(qApp->getDocumentsFolderPath());
}
@ -67,6 +63,7 @@ void FormRestoreDatabaseSettings::performRestoration() {
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(),
tr("Database and/or settings were not copied to restoration directory successully."));
@ -95,6 +92,7 @@ void FormRestoreDatabaseSettings::selectFolder(QString folder) {
m_ui->m_lblSelectFolder->setStatus(WidgetWithStatus::Ok, QDir::toNativeSeparators(folder),
tr("Good source directory is specified."));
}
else {
return;
}
@ -110,7 +108,6 @@ void FormRestoreDatabaseSettings::selectFolder(QString folder) {
QDir::Files | QDir::NoDotAndDotDot | QDir::Readable |
QDir::CaseSensitive | QDir::NoSymLinks,
QDir::Name);
m_ui->m_listDatabase->clear();
m_ui->m_listSettings->clear();

View file

@ -35,19 +35,15 @@
FormSettings::FormSettings(QWidget* parent) : QDialog(parent), m_panels(QList<SettingsPanel*>()), m_ui(new Ui::FormSettings), m_settings(qApp->settings()) {
m_ui->setupUi(this);
// Set flags and attributes.
setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint | Qt::WindowTitleHint);
setWindowIcon(qApp->icons()->fromTheme(QSL("emblem-system")));
m_btnApply = m_ui->m_buttonBox->button(QDialogButtonBox::Apply);
m_btnApply->setEnabled(false);
// Establish needed connections.
connect(m_ui->m_buttonBox, &QDialogButtonBox::accepted, this, &FormSettings::saveSettings);
connect(m_ui->m_buttonBox, &QDialogButtonBox::rejected, this, &FormSettings::cancelSettings);
connect(m_btnApply, &QPushButton::clicked, this, &FormSettings::applySettings);
addSettingsPanel(new SettingsGeneral(m_settings, this));
addSettingsPanel(new SettingsDatabase(m_settings, this));
addSettingsPanel(new SettingsGui(m_settings, this));
@ -56,7 +52,6 @@ FormSettings::FormSettings(QWidget *parent) : QDialog(parent), m_panels(QList<Se
addSettingsPanel(new SettingsBrowserMail(m_settings, this));
addSettingsPanel(new SettingsDownloads(m_settings, this));
addSettingsPanel(new SettingsFeedsMessages(m_settings, this));
m_ui->m_listSettings->setCurrentRow(0);
}
@ -72,7 +67,6 @@ void FormSettings::saveSettings() {
void FormSettings::applySettings() {
// Save all settings.
m_settings->checkSettings();
QStringList panels_for_restart;
foreach (SettingsPanel* panel, m_panels) {
@ -88,7 +82,6 @@ void FormSettings::applySettings() {
if (!panels_for_restart.isEmpty()) {
const QStringList changed_settings_description = panels_for_restart.replaceInStrings(QRegExp(QSL("^")), QString::fromUtf8(""));
const QMessageBox::StandardButton clicked_button = MessageBox::show(this,
QMessageBox::Question,
tr("Critical settings were changed"),
@ -118,6 +111,7 @@ void FormSettings::cancelSettings() {
if (changed_panels.isEmpty()) {
reject();
}
else {
const QStringList changed_settings_description = changed_panels.replaceInStrings(QRegExp(QSL("^")), QString::fromUtf8(""));
@ -139,7 +133,6 @@ void FormSettings::addSettingsPanel(SettingsPanel *panel) {
m_panels.append(panel);
m_ui->m_stackedSettings->addWidget(panel);
panel->loadSettings();
connect(panel, &SettingsPanel::settingsChanged, [this]() {
m_btnApply->setEnabled(true);
});

View file

@ -38,7 +38,6 @@ FormUpdate::FormUpdate(QWidget *parent)
m_ui->setupUi(this);
m_ui->m_lblCurrentRelease->setText(APP_VERSION);
m_ui->m_tabInfo->removeTab(1);
// Set flags and attributes.
setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint | Qt::WindowTitleHint);
setWindowIcon(qApp->icons()->fromTheme(QSL("help-about")));
@ -47,6 +46,7 @@ FormUpdate::FormUpdate(QWidget *parent)
m_btnUpdate = m_ui->m_buttonBox->addButton(tr("Download selected update"), QDialogButtonBox::ActionRole);
m_btnUpdate->setToolTip(tr("Download new installation files."));
}
else {
m_btnUpdate = m_ui->m_buttonBox->addButton(tr("Go to application website"), QDialogButtonBox::ActionRole);
m_btnUpdate->setToolTip(tr("Go to application website to get update packages manually."));
@ -74,7 +74,6 @@ void FormUpdate::checkForUpdates() {
if (update.second != QNetworkReply::NoError) {
m_updateInfo = UpdateInfo();
m_ui->m_tabInfo->setEnabled(false);
//: Unknown release.
m_ui->m_lblAvailableRelease->setText(tr("unknown"));
m_ui->m_txtChanges->clear();
@ -82,9 +81,9 @@ void FormUpdate::checkForUpdates() {
tr("Error: '%1'.").arg(NetworkFactory::networkErrorText(update.second)),
tr("List with updates was not\ndownloaded successfully."));
}
else {
const bool self_update_supported = isSelfUpdateSupported();
m_updateInfo = update.first.at(0);
m_ui->m_tabInfo->setEnabled(true);
m_ui->m_lblAvailableRelease->setText(m_updateInfo.m_availableVersion);
@ -100,6 +99,7 @@ void FormUpdate::checkForUpdates() {
loadAvailableFiles();
}
}
else {
m_ui->m_lblStatus->setStatus(WidgetWithStatus::Warning,
tr("No new release available."),
@ -119,7 +119,6 @@ void FormUpdate::updateProgress(qint64 bytes_received, qint64 bytes_total) {
2)),
tr("Downloading update..."));
m_ui->m_lblStatus->repaint();
m_lastDownloadedBytes = bytes_received;
}
}
@ -135,21 +134,20 @@ void FormUpdate::saveUpdateFile(const QByteArray &file_contents) {
if (output_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
qDebug("Storing update file to temporary location '%s'.",
qPrintable(QDir::toNativeSeparators(output_file.fileName())));
output_file.write(file_contents);
output_file.flush();
output_file.close();
qDebug("Update file contents was successfuly saved.");
m_updateFilePath = output_file.fileName();
m_readyToInstall = true;
}
else {
qDebug("Cannot save downloaded update file because target temporary file '%s' cannot be "
"opened for writing.", qPrintable(output_file_name));
}
}
else {
qDebug("Cannot save downloaded update file because no TEMP directory is available.");
}
@ -168,6 +166,7 @@ void FormUpdate::loadAvailableFiles() {
if (m_ui->m_listFiles->count() > 0) {
m_ui->m_listFiles->setCurrentRow(0);
}
else {
m_btnUpdate->setEnabled(false);
}
@ -202,6 +201,7 @@ void FormUpdate::startUpdate() {
url_file = m_ui->m_listFiles->currentItem()->data(Qt::UserRole).toString();
m_ui->m_listFiles->setEnabled(false);
}
else {
url_file = APP_URL;
}
@ -209,7 +209,6 @@ void FormUpdate::startUpdate() {
if (m_readyToInstall) {
close();
qDebug("Preparing to launch external installer '%s'.", qPrintable(QDir::toNativeSeparators(m_updateFilePath)));
#if defined(Q_OS_WIN)
HINSTANCE exec_result = ShellExecute(nullptr,
nullptr,
@ -220,24 +219,24 @@ void FormUpdate::startUpdate() {
if (((int)exec_result) <= 32) {
qDebug("External updater was not launched due to error.");
qApp->showGuiMessage(tr("Cannot update application"),
tr("Cannot launch external updater. Update application manually."),
QSystemTrayIcon::Warning, this);
}
else {
qApp->quit();
}
#endif
}
else if (update_for_this_system) {
// Nothing is downloaded yet, but update for this system
// is available and self-update feature is present.
if (m_downloader == nullptr) {
// Initialie downloader.
m_downloader = new Downloader(this);
connect(m_downloader, &Downloader::progress, this, &FormUpdate::updateProgress);
connect(m_downloader, &Downloader::completed, this, &FormUpdate::updateCompleted);
updateProgress(0, 100);
@ -247,6 +246,7 @@ void FormUpdate::startUpdate() {
m_btnUpdate->setEnabled(false);
m_downloader->downloadFile(url_file);
}
else {
// Self-update and package are not available.
if (!WebFactory::instance()->openUrlInExternalBrowser(url_file)) {

View file

@ -67,6 +67,7 @@ void DiscoverFeedsButton::linkTriggered(QAction *action) {
if (root->supportsFeedAdding()) {
root->addNewFeed(url);
}
else {
qApp->showGuiMessage(tr("Not supported"),
tr("Given account does not support adding feeds."),
@ -84,7 +85,6 @@ void DiscoverFeedsButton::fillMenu() {
foreach (const QString& url, m_addresses) {
if (root->supportsFeedAdding()) {
QAction* url_action = root_menu->addAction(root->icon(), url);
url_action->setProperty("url", url);
url_action->setProperty("root", QVariant::fromValue((void*) root));
}

View file

@ -28,6 +28,7 @@ void EditTableView::keyPressEvent(QKeyEvent *event) {
removeSelected();
event->accept();
}
else {
QAbstractItemView::keyPressEvent(event);
}

View file

@ -110,15 +110,11 @@ FeedsToolBar *FeedMessageViewer::feedsToolBar() const {
void FeedMessageViewer::saveSize() {
Settings* settings = qApp->settings();
m_feedsView->saveAllExpandStates();
// Store offsets of splitters.
settings->setValue(GROUP(GUI), GUI::SplitterFeeds, QString(m_feedSplitter->saveState().toBase64()));
settings->setValue(GROUP(GUI), GUI::SplitterMessages, QString(m_messageSplitter->saveState().toBase64()));
settings->setValue(GROUP(GUI), GUI::MessageViewState, QString(m_messagesView->header()->saveState().toBase64()));
// Store "visibility" of toolbars and list headers.
settings->setValue(GROUP(GUI), GUI::ToolbarsVisible, m_toolBarsEnabled);
settings->setValue(GROUP(GUI), GUI::ListHeadersVisible, m_listHeadersEnabled);
@ -126,11 +122,9 @@ void FeedMessageViewer::saveSize() {
void FeedMessageViewer::loadSize() {
const Settings* settings = qApp->settings();
// Restore offsets of splitters.
m_feedSplitter->restoreState(QByteArray::fromBase64(settings->value(GROUP(GUI), SETTING(GUI::SplitterFeeds)).toString().toLocal8Bit()));
m_messageSplitter->restoreState(QByteArray::fromBase64(settings->value(GROUP(GUI), SETTING(GUI::SplitterMessages)).toString().toLocal8Bit()));
m_messagesView->header()->restoreState(QByteArray::fromBase64(settings->value(GROUP(GUI), SETTING(GUI::MessageViewState)).toString().toLocal8Bit()));
}
@ -150,6 +144,7 @@ void FeedMessageViewer::switchMessageSplitterOrientation() {
if (m_messageSplitter->orientation() == Qt::Vertical) {
m_messageSplitter->setOrientation(Qt::Horizontal);
}
else {
m_messageSplitter->setOrientation(Qt::Vertical);
}
@ -173,6 +168,7 @@ void FeedMessageViewer::switchFeedComponentVisibility() {
if (sen != nullptr) {
m_feedsWidget->setVisible(sen->isChecked());
}
else {
m_feedsWidget->setVisible(!m_feedsWidget->isVisible());
}
@ -184,6 +180,7 @@ void FeedMessageViewer::toggleShowOnlyUnreadFeeds() {
if (origin == nullptr) {
m_feedsView->model()->invalidateReadFeedsFilter(true, false);
}
else {
m_feedsView->model()->invalidateReadFeedsFilter(true, origin->isChecked());
}
@ -193,7 +190,6 @@ void FeedMessageViewer::createConnections() {
// Filtering & searching.
connect(m_toolBarMessages, &MessagesToolBar::messageSearchPatternChanged, m_messagesView, &MessagesView::searchMessages);
connect(m_toolBarMessages, &MessagesToolBar::messageFilterChanged, m_messagesView, &MessagesView::filterMessages);
#if defined(USE_WEBENGINE)
connect(m_messagesView, &MessagesView::currentMessageRemoved, m_messagesBrowser, &WebBrowser::clear);
connect(m_messagesView, &MessagesView::currentMessageChanged, m_messagesBrowser, &WebBrowser::loadMessage);
@ -209,10 +205,8 @@ void FeedMessageViewer::createConnections() {
connect(m_messagesBrowser, &MessagePreviewer::markMessageImportant,
m_messagesView->sourceModel(), &MessagesModel::setMessageImportantById);
#endif
// If user selects feeds, load their messages.
connect(m_feedsView, &FeedsView::itemSelected, m_messagesView, &MessagesView::loadItem);
// State of many messages is changed, then we need
// to reload selections.
connect(m_feedsView->sourceModel(), &FeedsModel::reloadMessageListRequested,
@ -224,16 +218,12 @@ void FeedMessageViewer::initialize() {
m_toolBarFeeds->setFloatable(false);
m_toolBarFeeds->setMovable(false);
m_toolBarFeeds->setAllowedAreas(Qt::TopToolBarArea);
m_toolBarMessages->setFloatable(false);
m_toolBarMessages->setMovable(false);
m_toolBarMessages->setAllowedAreas(Qt::TopToolBarArea);
m_toolBarFeeds->loadSavedActions();
m_toolBarMessages->loadSavedActions();
m_messagesBrowser->clear();
// Now refresh visual setup.
refreshVisualProperties();
}
@ -243,12 +233,10 @@ void FeedMessageViewer::initializeViews() {
m_messagesWidget = new QWidget(this);
m_feedSplitter = new QSplitter(Qt::Horizontal, this);
m_messageSplitter = new QSplitter(Qt::Vertical, this);
// Instantiate needed components.
QVBoxLayout* central_layout = new QVBoxLayout(this);
QVBoxLayout* feed_layout = new QVBoxLayout(m_feedsWidget);
QVBoxLayout* message_layout = new QVBoxLayout(m_messagesWidget);
// Set layout properties.
central_layout->setMargin(0);
central_layout->setSpacing(0);
@ -256,11 +244,9 @@ void FeedMessageViewer::initializeViews() {
feed_layout->setSpacing(0);
message_layout->setMargin(0);
message_layout->setSpacing(0);
// Set views.
m_feedsView->setFrameStyle(QFrame::NoFrame);
m_messagesView->setFrameStyle(QFrame::NoFrame);
// Setup message splitter.
m_messageSplitter->setObjectName(QSL("MessageSplitter"));
m_messageSplitter->setHandleWidth(1);
@ -268,25 +254,20 @@ void FeedMessageViewer::initializeViews() {
m_messageSplitter->setChildrenCollapsible(false);
m_messageSplitter->addWidget(m_messagesView);
m_messageSplitter->addWidget(m_messagesBrowser);
// Assemble message-related components to single widget.
message_layout->addWidget(m_toolBarMessages);
message_layout->addWidget(m_messageSplitter);
// Assemble feed-related components to another widget.
feed_layout->addWidget(m_toolBarFeeds);
feed_layout->addWidget(m_feedsView);
// Assembler everything together.
m_feedSplitter->setHandleWidth(1);
m_feedSplitter->setOpaqueResize(false);
m_feedSplitter->setChildrenCollapsible(false);
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);
@ -296,7 +277,6 @@ void FeedMessageViewer::initializeViews() {
void FeedMessageViewer::refreshVisualProperties() {
const Qt::ToolButtonStyle button_style = static_cast<Qt::ToolButtonStyle>(qApp->settings()->value(GROUP(GUI),
SETTING(GUI::ToolbarStyle)).toInt());
m_toolBarFeeds->setToolButtonStyle(button_style);
m_toolBarMessages->setToolButtonStyle(button_style);
}

View file

@ -59,25 +59,23 @@ QList<QAction*> FeedsToolBar::getSpecificActions(const QStringList &actions) {
// Add existing standard action.
spec_actions.append(matching_action);
}
else if (action_name == SEPARATOR_ACTION_NAME) {
// Add new separator.
QAction* act = new QAction(this);
act->setSeparator(true);
spec_actions.append(act);
}
else if (action_name == SPACER_ACTION_NAME) {
// Add new spacer.
QWidget* spacer = new QWidget(this);
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QWidgetAction* action = new QWidgetAction(this);
action->setDefaultWidget(spacer);
action->setIcon(qApp->icons()->fromTheme(QSL("system-search")));
action->setProperty("type", SPACER_ACTION_NAME);
action->setProperty("name", tr("Toolbar spacer"));
spec_actions.append(action);
}
}
@ -101,5 +99,4 @@ QStringList FeedsToolBar::defaultActions() const {
QStringList FeedsToolBar::savedActions() const {
return qApp->settings()->value(GROUP(GUI), SETTING(GUI::FeedsToolbarActions)).toString().split(',',
QString::SkipEmptyParts);
}

View file

@ -49,18 +49,15 @@ FeedsView::FeedsView(QWidget *parent)
m_contextMenuEmptySpace(nullptr),
m_contextMenuOtherItems(nullptr) {
setObjectName(QSL("FeedsView"));
// Allocate models.
m_sourceModel = qApp->feedReader()->feedsModel();
m_proxyModel = qApp->feedReader()->feedsProxyModel();
// Connections.
connect(m_sourceModel, &FeedsModel::requireItemValidationAfterDragDrop, this, &FeedsView::validateItemAfterDragDrop);
connect(m_sourceModel, &FeedsModel::itemExpandRequested, this, &FeedsView::onItemExpandRequested);
connect(m_sourceModel, &FeedsModel::itemExpandStateSaveRequested, this, &FeedsView::onItemExpandStateSaveRequested);
connect(header(), &QHeaderView::sortIndicatorChanged, this, &FeedsView::saveSortState);
connect(m_proxyModel, &FeedsProxyModel::expandAfterFilterIn, this, &FeedsView::expandItemDelayed);
setModel(m_proxyModel);
setupAppearance();
}
@ -81,6 +78,7 @@ QList<Feed*> FeedsView::selectedFeeds() const {
if (current_index.isValid()) {
return m_sourceModel->feedsForIndex(m_proxyModel->mapToSource(current_index));
}
else {
return QList<Feed*>();
}
@ -92,6 +90,7 @@ RootItem *FeedsView::selectedItem() const {
if (selected_rows.isEmpty()) {
return nullptr;
}
else {
RootItem* selected_item = m_sourceModel->itemForIndex(m_proxyModel->mapToSource(selected_rows.at(0)));
return selected_item == m_sourceModel->rootItem() ? nullptr : selected_item;
@ -113,10 +112,8 @@ void FeedsView::saveExpandStates(RootItem *item) {
// Iterate all categories and save their expand statuses.
foreach (const RootItem* item, items) {
const QString setting_name = item->hashCode();
QModelIndex source_index = sourceModel()->indexForItem(item);
QModelIndex visible_index = model()->mapFromSource(source_index);
settings->setValue(GROUP(CategoriesExpandStates),
setting_name,
isExpanded(visible_index));
@ -126,13 +123,11 @@ void FeedsView::saveExpandStates(RootItem *item) {
void FeedsView::loadAllExpandStates() {
const Settings* settings = qApp->settings();
QList<RootItem*> expandable_items;
expandable_items.append(sourceModel()->rootItem()->getSubTree(RootItemKind::Category | RootItemKind::ServiceRoot));
// Iterate all categories and save their expand statuses.
foreach (const RootItem* item, expandable_items) {
const QString setting_name = item->hashCode();
setExpanded(model()->mapFromSource(sourceModel()->indexForItem(item)),
settings->value(GROUP(CategoriesExpandStates), setting_name, item->childCount() > 0).toBool());
}
@ -148,6 +143,7 @@ void FeedsView::sortByColumn(int column, Qt::SortOrder order) {
if (column == old_column && order == old_order) {
m_proxyModel->sort(column, order);
}
else {
QTreeView::sortByColumn(column, order);
}
@ -162,6 +158,7 @@ void FeedsView::addFeedIntoSelectedAccount() {
if (root->supportsFeedAdding()) {
root->addNewFeed();
}
else {
qApp->showGuiMessage(tr("Not supported"),
tr("Selected account does not support adding of new feeds."),
@ -180,6 +177,7 @@ void FeedsView::addCategoryIntoSelectedAccount() {
if (root->supportsCategoryAdding()) {
root->addNewCategory();
}
else {
qApp->showGuiMessage(tr("Not supported"),
tr("Selected account does not support adding of new categories."),
@ -229,6 +227,7 @@ void FeedsView::editSelectedItem() {
if (selectedItem()->canBeEdited()) {
selectedItem()->editViaGui();
}
else {
qApp->showGuiMessage(tr("Cannot edit item"),
tr("Selected item cannot be edited, this is not (yet?) supported."),
@ -249,7 +248,6 @@ void FeedsView::deleteSelectedItem() {
qApp->showGuiMessage(tr("Cannot delete item"),
tr("Selected item cannot be deleted because another critical operation is ongoing."),
QSystemTrayIcon::Warning, qApp->mainFormWidget(), true);
// Thus, cannot delete and quit the method.
return;
}
@ -285,6 +283,7 @@ void FeedsView::deleteSelectedItem() {
true);
}
}
else {
qApp->showGuiMessage(tr("Cannot delete \"%1\"").arg(selected_item->title()),
tr("This item cannot be deleted, because it does not support it\nor this functionality is not implemented yet."),
@ -372,12 +371,12 @@ QMenu *FeedsView::initializeContextMenuCategories(RootItem *clicked_item) {
if (m_contextMenuCategories == nullptr) {
m_contextMenuCategories = new QMenu(tr("Context menu for categories"), this);
}
else {
m_contextMenuCategories->clear();
}
QList<QAction*> specific_actions = clicked_item->contextMenu();
m_contextMenuCategories->addActions(QList<QAction*>() <<
qApp->mainForm()->m_ui->m_actionUpdateSelectedItems <<
qApp->mainForm()->m_ui->m_actionEditSelectedItem <<
@ -398,12 +397,12 @@ QMenu *FeedsView::initializeContextMenuFeeds(RootItem *clicked_item) {
if (m_contextMenuFeeds == nullptr) {
m_contextMenuFeeds = new QMenu(tr("Context menu for categories"), this);
}
else {
m_contextMenuFeeds->clear();
}
QList<QAction*> specific_actions = clicked_item->contextMenu();
m_contextMenuFeeds->addActions(QList<QAction*>() <<
qApp->mainForm()->m_ui->m_actionUpdateSelectedItems <<
qApp->mainForm()->m_ui->m_actionEditSelectedItem <<
@ -434,6 +433,7 @@ QMenu *FeedsView::initializeContextMenuOtherItem(RootItem *clicked_item) {
if (m_contextMenuOtherItems == nullptr) {
m_contextMenuOtherItems = new QMenu(tr("Context menu for other items"), this);
}
else {
m_contextMenuOtherItems->clear();
}
@ -444,6 +444,7 @@ QMenu *FeedsView::initializeContextMenuOtherItem(RootItem *clicked_item) {
m_contextMenuOtherItems->addSeparator();
m_contextMenuOtherItems->addActions(specific_actions);
}
else {
m_contextMenuOtherItems->addAction(qApp->mainForm()->m_ui->m_actionNoActions);
}
@ -455,7 +456,6 @@ void FeedsView::setupAppearance() {
// Setup column resize strategies.
header()->setSectionResizeMode(FDS_MODEL_TITLE_INDEX, QHeaderView::Stretch);
header()->setSectionResizeMode(FDS_MODEL_COUNTS_INDEX, QHeaderView::ResizeToContents);
setUniformRowHeights(true);
setAnimated(true);
setSortingEnabled(true);
@ -477,7 +477,6 @@ void FeedsView::setupAppearance() {
void FeedsView::selectionChanged(const QItemSelection& selected, const QItemSelection& deselected) {
RootItem* selected_item = selectedItem();
m_proxyModel->setSelectedItem(selected_item);
QTreeView::selectionChanged(selected, deselected);
emit itemSelected(selected_item);
@ -503,14 +502,17 @@ void FeedsView::contextMenuEvent(QContextMenuEvent *event) {
// Display context menu for categories.
initializeContextMenuCategories(clicked_item)->exec(event->globalPos());
}
else if (clicked_item->kind() == RootItemKind::Feed) {
// Display context menu for feeds.
initializeContextMenuFeeds(clicked_item)->exec(event->globalPos());
}
else {
initializeContextMenuOtherItem(clicked_item)->exec(event->globalPos());
}
}
else {
// Display menu for empty space.
initializeContextMenuEmptySpace()->exec(event->globalPos());
@ -553,7 +555,6 @@ void FeedsView::onItemExpandRequested(const QList<RootItem*> &items, bool exp) {
foreach (const RootItem* item, items) {
QModelIndex source_index = m_sourceModel->indexForItem(item);
QModelIndex proxy_index = m_proxyModel->mapFromSource(source_index);
//setExpanded(proxy_index, !exp);
setExpanded(proxy_index, exp);
}

View file

@ -28,6 +28,7 @@ void GuiUtilities::setLabelAsNotice(QLabel *label, bool is_warning) {
if (is_warning) {
label->setStyleSheet(QSL("font-weight: bold; font-style: italic; color: red"));
}
else {
label->setStyleSheet(QSL("font-style: italic;"));
}

View file

@ -25,11 +25,9 @@
LabelWithStatus::LabelWithStatus(QWidget* parent)
: WidgetWithStatus(parent) {
m_wdgInput = new QLabel(this);
// Set correct size for the tool button.
int label_height = m_wdgInput->sizeHint().height();
m_btnStatus->setFixedSize(label_height, label_height);
// Compose the layout.
m_layout->addWidget(m_wdgInput);
m_layout->addWidget(m_btnStatus);

View file

@ -26,13 +26,10 @@
LineEditWithStatus::LineEditWithStatus(QWidget* parent)
: WidgetWithStatus(parent) {
m_wdgInput = new BaseLineEdit(this);
setFocusProxy(m_wdgInput);
// Set correct size for the tool button.
const int txt_input_height = m_wdgInput->sizeHint().height();
m_btnStatus->setFixedSize(txt_input_height, txt_input_height);
// Compose the layout.
m_layout->addWidget(m_wdgInput);
m_layout->addWidget(m_btnStatus);

View file

@ -33,7 +33,6 @@ LocationLineEdit::~LocationLineEdit() {
void LocationLineEdit::focusOutEvent(QFocusEvent* event) {
BaseLineEdit::focusOutEvent(event);
// User now left text box, when he enters it again and clicks,
// then all text should be selected.
m_mouseSelectsAllText = true;
@ -43,10 +42,10 @@ void LocationLineEdit::mousePressEvent(QMouseEvent *event) {
if (m_mouseSelectsAllText) {
event->ignore();
selectAll();
// User clicked and all text was selected.
m_mouseSelectsAllText = false;
}
else {
BaseLineEdit::mousePressEvent(event);
}

View file

@ -37,7 +37,6 @@ MessageBox::~MessageBox() {
void MessageBox::setIcon(QMessageBox::Icon icon) {
// Determine correct status icon size.
const int icon_size = qApp->style()->pixelMetric(QStyle::PM_MessageBoxIconSize, 0, this);
// Setup status icon.
setIconPixmap(iconForStatus(icon).pixmap(icon_size, icon_size));
}
@ -45,13 +44,11 @@ void MessageBox::setIcon(QMessageBox::Icon icon) {
void MessageBox::setCheckBox(QMessageBox* msg_box, const QString& text, bool* data) {
// Add "don't show this again checkbox.
QCheckBox* check_box = new QCheckBox(msg_box);
check_box->setChecked(*data);
check_box->setText(text);
connect(check_box, &QCheckBox::toggled, [ = ](bool checked) {
*data = checked;
});
msg_box->setCheckBox(check_box);
}
@ -86,7 +83,6 @@ QMessageBox::StandardButton MessageBox::show(QWidget *parent,
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);
@ -104,6 +100,7 @@ QMessageBox::StandardButton MessageBox::show(QWidget *parent,
if (msg_box.exec() == -1) {
return QMessageBox::Cancel;
}
else {
return msg_box.standardButton(msg_box.clickedButton());
}

View file

@ -38,20 +38,18 @@ void MessagePreviewer::createConnections() {
if (open_externally_now) {
WebFactory::instance()->openUrlInExternalBrowser(url.toString());
}
else {
// User clicked some URL. Open it in external browser or download?
MessageBox box(qApp->mainForm());
box.setText(tr("You clicked some link. You can download the link contents or open it in external web browser."));
box.setInformativeText(tr("What action do you want to take?"));
box.setDetailedText(url.toString());
QAbstractButton* btn_open = box.addButton(tr("Open in external browser"), QMessageBox::ActionRole);
QAbstractButton* btn_download = box.addButton(tr("Download"), QMessageBox::ActionRole);
QAbstractButton* btn_cancel = box.addButton(QMessageBox::Cancel);
bool always;
MessageBox::setCheckBox(&box, tr("Always open links in external browser."), &always);
box.setDefaultButton(QMessageBox::Cancel);
box.exec();
@ -63,6 +61,7 @@ void MessagePreviewer::createConnections() {
if (box.clickedButton() == btn_open) {
WebFactory::instance()->openUrlInExternalBrowser(url.toString());
}
else if (box.clickedButton() == btn_download) {
qApp->downloadManager()->download(url);
}
@ -72,6 +71,7 @@ void MessagePreviewer::createConnections() {
btn_cancel->deleteLater();
}
}
else {
MessageBox::show(qApp->mainForm(), QMessageBox::Warning, tr("Incorrect link"),
tr("Selected hyperlink is invalid."));
@ -93,7 +93,6 @@ void MessagePreviewer::createConnections() {
static_cast<void (QTextBrowser::*)(const QString&)>(&QTextBrowser::highlighted),
[ = ](const QString & text) {
Q_UNUSED(text)
QToolTip::showText(QCursor::pos(), tr("Click this link to download it or open it with external browser."), this);
});
}
@ -105,11 +104,8 @@ MessagePreviewer::MessagePreviewer(QWidget *parent) : QWidget(parent),
m_toolBar = new QToolBar(this);
m_toolBar->setOrientation(Qt::Vertical);
m_ui->m_layout->addWidget(m_toolBar, 0, 0, -1, 1);
createConnections();
m_actionSwitchImportance->setCheckable(true);
reloadFontSettings();
clear();
}
@ -120,10 +116,8 @@ MessagePreviewer::~MessagePreviewer() {
void MessagePreviewer::reloadFontSettings() {
const Settings* settings = qApp->settings();
QFont fon;
fon.fromString(settings->value(GROUP(Messages),
SETTING(Messages::PreviewerFontStandard)).toString());
m_ui->m_txtMessage->setFont(fon);
}
@ -144,10 +138,8 @@ void MessagePreviewer::loadMessage(const Message &message, RootItem *root) {
if (!m_root.isNull()) {
m_actionSwitchImportance->setChecked(m_message.m_isImportant);
m_ui->m_txtMessage->setHtml(prepareHtmlForMessage(m_message));
updateButtons();
show();
m_ui->m_txtMessage->verticalScrollBar()->triggerAction(QScrollBar::SliderToMinimum);
}
}
@ -172,7 +164,6 @@ void MessagePreviewer::markMessageAsReadUnread(RootItem::ReadStatus read) {
QList<Message>() << m_message,
read);
m_message.m_isRead = read == RootItem::Read;
emit markMessageRead(m_message.m_id, read);
updateButtons();
}
@ -188,13 +179,11 @@ void MessagePreviewer::switchMessageImportance(bool checked) {
RootItem::Important))) {
DatabaseQueries::switchMessagesImportance(qApp->database()->connection(objectName(), DatabaseFactory::FromSettings),
QStringList() << QString::number(m_message.m_id));
m_root->getParentServiceRoot()->onAfterSwitchMessageImportance(m_root.data(),
QList<ImportanceChange>() << ImportanceChange(m_message,
m_message.m_isImportant ?
RootItem::NotImportant :
RootItem::Important));
emit markMessageImportant(m_message.m_id, checked ? RootItem::Important : RootItem::NotImportant);
m_message.m_isImportant = checked;
}
@ -208,7 +197,6 @@ void MessagePreviewer::updateButtons() {
QString MessagePreviewer::prepareHtmlForMessage(const Message& message) {
QString html = QString("<h2 align=\"center\">%1</h2>").arg(message.m_title);
html += QString("[url] <a href=\"%1\">%1</a><br/>").arg(message.m_url);
foreach (const Enclosure& enc, message.m_enclosures) {
@ -217,18 +205,15 @@ QString MessagePreviewer::prepareHtmlForMessage(const Message &message) {
int offset = 0;
QRegExp imgTagRegex("\\<img[^\\>]*src\\s*=\\s*\"([^\"]*)\"[^\\>]*\\>", Qt::CaseInsensitive);
imgTagRegex.setMinimal(true);
while ((offset = imgTagRegex.indexIn(message.m_contents, offset)) != -1) {
m_pictures.append(imgTagRegex.cap(1));
offset += imgTagRegex.matchedLength();
html += QString("[%2] <a href=\"%1\">%1</a><br/>").arg(imgTagRegex.cap(1), tr("image"));
}
html += "<br/>";
html += message.m_contents;
return html;
}

View file

@ -39,10 +39,8 @@ MessagesToolBar::~MessagesToolBar() {
QList<QAction*> MessagesToolBar::availableActions() const {
QList<QAction*> available_actions = qApp->userActions();
available_actions.append(m_actionSearchMessages);
available_actions.append(m_actionMessageHighlighter);
return available_actions;
}
@ -72,33 +70,33 @@ QList<QAction*> MessagesToolBar::getSpecificActions(const QStringList &actions)
// Add existing standard action.
spec_actions.append(matching_action);
}
else if (action_name == SEPARATOR_ACTION_NAME) {
// Add new separator.
QAction* act = new QAction(this);
act->setSeparator(true);
spec_actions.append(act);
}
else if (action_name == SEACRH_MESSAGES_ACTION_NAME) {
// Add search box.
spec_actions.append(m_actionSearchMessages);
}
else if (action_name == HIGHLIGHTER_ACTION_NAME) {
// Add filter button.
spec_actions.append(m_actionMessageHighlighter);
}
else if (action_name == SPACER_ACTION_NAME) {
// Add new spacer.
QWidget* spacer = new QWidget(this);
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QWidgetAction* action = new QWidgetAction(this);
action->setDefaultWidget(spacer);
action->setIcon(qApp->icons()->fromTheme(QSL("go-jump")));
action->setProperty("type", SPACER_ACTION_NAME);
action->setProperty("name", tr("Toolbar spacer"));
spec_actions.append(action);
}
}
@ -117,7 +115,6 @@ void MessagesToolBar::loadSpecificActions(const QList<QAction*> &actions) {
void MessagesToolBar::handleMessageHighlighterChange(QAction* action) {
m_btnMessageHighlighter->setIcon(action->icon());
m_btnMessageHighlighter->setToolTip(action->text());
emit messageFilterChanged(action->data().value<MessagesModel::MessageHighlighter>());
}
@ -125,14 +122,12 @@ void MessagesToolBar::initializeSearchBox() {
m_txtSearchMessages = new MessagesSearchLineEdit(this);
m_txtSearchMessages->setFixedWidth(FILTER_WIDTH);
m_txtSearchMessages->setPlaceholderText(tr("Search messages"));
// Setup wrapping action for search box.
m_actionSearchMessages = new QWidgetAction(this);
m_actionSearchMessages->setDefaultWidget(m_txtSearchMessages);
m_actionSearchMessages->setIcon(qApp->icons()->fromTheme(QSL("system-search")));
m_actionSearchMessages->setProperty("type", SEACRH_MESSAGES_ACTION_NAME);
m_actionSearchMessages->setProperty("name", tr("Message search box"));
connect(m_txtSearchMessages, &MessagesSearchLineEdit::textChanged, this, &MessagesToolBar::messageSearchPatternChanged);
}
@ -144,19 +139,16 @@ void MessagesToolBar::initializeHighlighter() {
tr("Highlight unread messages"))->setData(QVariant::fromValue(MessagesModel::HighlightUnread));
m_menuMessageHighlighter->addAction(qApp->icons()->fromTheme(QSL("mail-mark-important")),
tr("Highlight important messages"))->setData(QVariant::fromValue(MessagesModel::HighlightImportant));
m_btnMessageHighlighter = new QToolButton(this);
m_btnMessageHighlighter->setToolTip(tr("Display all messages"));
m_btnMessageHighlighter->setMenu(m_menuMessageHighlighter);
m_btnMessageHighlighter->setPopupMode(QToolButton::MenuButtonPopup);
m_btnMessageHighlighter->setIcon(qApp->icons()->fromTheme(QSL("mail-mark-read")));
m_actionMessageHighlighter = new QWidgetAction(this);
m_actionMessageHighlighter->setDefaultWidget(m_btnMessageHighlighter);
m_actionMessageHighlighter->setIcon(m_btnMessageHighlighter->icon());
m_actionMessageHighlighter->setProperty("type", HIGHLIGHTER_ACTION_NAME);
m_actionMessageHighlighter->setProperty("name", tr("Message highlighter"));
connect(m_menuMessageHighlighter, SIGNAL(triggered(QAction*)),
this, SLOT(handleMessageHighlighterChange(QAction*)));
}

View file

@ -38,12 +38,10 @@ MessagesView::MessagesView(QWidget *parent)
: QTreeView(parent), m_contextMenu(nullptr), m_columnsAdjusted(false) {
m_sourceModel = qApp->feedReader()->messagesModel();
m_proxyModel = qApp->feedReader()->messagesProxyModel();
// Forward count changes to the view.
createConnections();
setModel(m_proxyModel);
setupAppearance();
header()->setContextMenuPolicy(Qt::CustomContextMenu);
connect(header(), &QHeaderView::customContextMenuRequested, [ = ](const QPoint & point) {
TreeViewColumnsMenu mm(header());
@ -74,7 +72,6 @@ void MessagesView::sort(int column, Qt::SortOrder order, bool repopulate_data, b
void MessagesView::createConnections() {
connect(this, &MessagesView::doubleClicked, this, &MessagesView::openSelectedSourceMessagesExternally);
// Adjust columns when layout gets changed.
connect(header(), &QHeaderView::geometriesChanged, this, &MessagesView::adjustColumns);
connect(header(), &QHeaderView::sortIndicatorChanged, this, &MessagesView::onSortIndicatorChanged);
@ -90,13 +87,11 @@ void MessagesView::keyboardSearch(const QString &search) {
void MessagesView::reloadSelections() {
const QDateTime dt1 = QDateTime::currentDateTime();
QModelIndex current_index = selectionModel()->currentIndex();
const QModelIndex mapped_current_index = m_proxyModel->mapToSource(current_index);
const Message selected_message = m_sourceModel->messageAt(mapped_current_index.row());
const int col = header()->sortIndicatorSection();
const Qt::SortOrder ord = header()->sortIndicatorOrder();
// Reload the model now.
sort(col, ord, true, false, false);
@ -105,6 +100,7 @@ void MessagesView::reloadSelections() {
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);
@ -127,6 +123,7 @@ void MessagesView::reloadSelections() {
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.
@ -134,7 +131,6 @@ void MessagesView::reloadSelections() {
}
const QDateTime dt2 = QDateTime::currentDateTime();
qDebug("Reloading of msg selections took %lld miliseconds.", dt1.msecsTo(dt2));
}
@ -151,7 +147,6 @@ void MessagesView::setupAppearance() {
setAllColumnsShowFocus(false);
setSelectionMode(QAbstractItemView::ExtendedSelection);
setItemDelegate(new StyledItemDelegateWithoutFocus(this));
header()->setDefaultSectionSize(MESSAGES_VIEW_DEFAULT_COL);
header()->setMinimumSectionSize(MESSAGES_VIEW_MINIMUM_COL);
header()->setCascadingSectionResizes(false);
@ -174,10 +169,10 @@ void MessagesView::contextMenuEvent(QContextMenuEvent *event) {
TreeViewColumnsMenu menu(header());
menu.exec(event->globalPos());
}
else {
// Context menu is not initialized, initialize.
initializeContextMenu();
m_contextMenu->exec(event->globalPos());
}
}
@ -238,7 +233,6 @@ void MessagesView::mousePressEvent(QMouseEvent *event) {
}
}
break;
}
@ -251,21 +245,19 @@ void MessagesView::selectionChanged(const QItemSelection &selected, const QItemS
const QModelIndexList selected_rows = selectionModel()->selectedRows();
const QModelIndex current_index = currentIndex();
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) {
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();
}
@ -280,11 +272,9 @@ void MessagesView::selectionChanged(const QItemSelection &selected, const QItemS
void MessagesView::loadItem(RootItem* item) {
const int col = header()->sortIndicatorSection();
const Qt::SortOrder ord = header()->sortIndicatorOrder();
scrollToTop();
sort(col, ord, false, true, false);
m_sourceModel->loadMessages(item);
// Messages are loaded, make sure that previously
// active message is not shown in browser.
// BUG: Qt 5 is probably bugged here. Selections
@ -352,13 +342,13 @@ void MessagesView::setSelectedMessagesReadStatus(RootItem::ReadStatus read) {
QModelIndexList selected_indexes = selectionModel()->selectedRows();
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()) {
emit currentMessageChanged(m_sourceModel->messageAt(m_proxyModel->mapToSource(current_index).row()), m_sourceModel->loadedItem());
}
else {
emit currentMessageRemoved();
}
@ -373,7 +363,6 @@ void MessagesView::deleteSelectedMessages() {
const QModelIndexList selected_indexes = selectionModel()->selectedRows();
const QModelIndexList mapped_indexes = m_proxyModel->mapListToSource(selected_indexes);
m_sourceModel->setBatchMessagesDeleted(mapped_indexes);
current_index = moveCursor(QAbstractItemView::MoveDown, Qt::NoModifier);
@ -381,6 +370,7 @@ void MessagesView::deleteSelectedMessages() {
setCurrentIndex(current_index);
emit currentMessageChanged(m_sourceModel->messageAt(m_proxyModel->mapToSource(current_index).row()), m_sourceModel->loadedItem());
}
else {
emit currentMessageRemoved();
}
@ -395,14 +385,13 @@ void MessagesView::restoreSelectedMessages() {
const QModelIndexList selected_indexes = selectionModel()->selectedRows();
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()) {
emit currentMessageChanged(m_sourceModel->messageAt(m_proxyModel->mapToSource(current_index).row()), m_sourceModel->loadedItem());
}
else {
emit currentMessageRemoved();
}
@ -417,13 +406,13 @@ void MessagesView::switchSelectedMessagesImportance() {
QModelIndexList selected_indexes = selectionModel()->selectedRows();
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()) {
emit currentMessageChanged(m_sourceModel->messageAt(m_proxyModel->mapToSource(current_index).row()), m_sourceModel->loadedItem());
}
else {
// Messages were probably removed from the model, nothing can
// be selected and no message can be displayed.
@ -465,7 +454,6 @@ void MessagesView::selectPreviousItem() {
void MessagesView::selectNextUnreadItem() {
// FIXME: Use this to solve #112.
const QModelIndexList selected_rows = selectionModel()->selectedRows();
int active_row;
@ -473,6 +461,7 @@ void MessagesView::selectNextUnreadItem() {
// Okay, something is selected, start from it.
active_row = selected_rows.at(0).row();
}
else {
active_row = 0;
}
@ -493,6 +482,7 @@ void MessagesView::searchMessages(const QString &pattern) {
if (selectionModel()->selectedRows().size() == 0) {
emit currentMessageRemoved();
}
else {
// Scroll to selected message, it could become scrolled out due to filter change.
scrollTo(selectionModel()->selectedRows().at(0));
@ -506,7 +496,6 @@ void MessagesView::filterMessages(MessagesModel::MessageHighlighter filter) {
void MessagesView::adjustColumns() {
if (header()->count() > 0 && !m_columnsAdjusted) {
m_columnsAdjusted = true;
// Setup column resize strategies.
header()->setSectionResizeMode(MSG_DB_ID_INDEX, QHeaderView::Interactive);
header()->setSectionResizeMode(MSG_DB_READ_INDEX, QHeaderView::ResizeToContents);
@ -519,10 +508,8 @@ void MessagesView::adjustColumns() {
header()->setSectionResizeMode(MSG_DB_DCREATED_INDEX, QHeaderView::Interactive);
header()->setSectionResizeMode(MSG_DB_CONTENTS_INDEX, QHeaderView::Interactive);
header()->setSectionResizeMode(MSG_DB_PDELETED_INDEX, QHeaderView::Interactive);
//header()->resizeSection(MSG_DB_READ_INDEX, MESSAGES_VIEW_MINIMUM_COL);
//header()->resizeSection(MSG_DB_IMPORTANT_INDEX, MESSAGES_VIEW_MINIMUM_COL);
// Hide columns.
hideColumn(MSG_DB_ID_INDEX);
hideColumn(MSG_DB_DELETED_INDEX);
@ -534,7 +521,6 @@ void MessagesView::adjustColumns() {
hideColumn(MSG_DB_CUSTOM_ID_INDEX);
hideColumn(MSG_DB_CUSTOM_HASH_INDEX);
hideColumn(MSG_DB_FEED_CUSTOM_ID_INDEX);
qDebug("Adjusting column resize modes for MessagesView.");
}
}

View file

@ -42,9 +42,7 @@ void NewspaperPreviewer::showMoreMessages() {
Message msg = m_messages.takeFirst();
MessagePreviewer* prev = new MessagePreviewer(this);
QMargins margins = prev->layout()->contentsMargins();
connect(prev, &MessagePreviewer::requestMessageListReload, this, &NewspaperPreviewer::requestMessageListReload);
margins.setRight(0);
prev->layout()->setContentsMargins(margins);
prev->setFixedHeight(300);
@ -56,6 +54,7 @@ void NewspaperPreviewer::showMoreMessages() {
m_ui->m_btnShowMoreMessages->setEnabled(!m_messages.isEmpty());
m_ui->scrollArea->verticalScrollBar()->setValue(current_scroll);
}
else {
qApp->showGuiMessage(tr("Cannot show more messages"),
tr("Cannot show more messages because parent feed was removed."),

View file

@ -33,10 +33,8 @@ PlainToolButton::~PlainToolButton() {
void PlainToolButton::paintEvent(QPaintEvent* e) {
Q_UNUSED(e)
QPainter p(this);
QRect rect(QPoint(0, 0), size());
// Set padding.
rect.adjust(m_padding, m_padding, -m_padding, -m_padding);
@ -45,6 +43,7 @@ void PlainToolButton::paintEvent(QPaintEvent *e) {
p.setOpacity(0.7);
}
}
else {
p.setOpacity(0.3);
}

View file

@ -29,17 +29,14 @@
SettingsBrowserMail::SettingsBrowserMail(Settings* settings, QWidget* parent)
: SettingsPanel(settings, parent), m_ui(new Ui::SettingsBrowserMail) {
m_ui->setupUi(this);
GuiUtilities::setLabelAsNotice(m_ui->label, false);
GuiUtilities::setLabelAsNotice(m_ui->m_lblExternalEmailInfo, false);
GuiUtilities::setLabelAsNotice(m_ui->m_lblProxyInfo, false);
#if defined(USE_WEBENGINE)
m_ui->m_checkOpenLinksInExternal->setVisible(false);
#else
connect(m_ui->m_checkOpenLinksInExternal, &QCheckBox::stateChanged, this, &SettingsBrowserMail::dirtifySettings);
#endif
connect(m_ui->m_cmbProxyType, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &SettingsBrowserMail::dirtifySettings);
connect(m_ui->m_txtProxyHost, &QLineEdit::textChanged, this, &SettingsBrowserMail::dirtifySettings);
connect(m_ui->m_txtProxyPassword, &QLineEdit::textChanged, this, &SettingsBrowserMail::dirtifySettings);
@ -51,7 +48,6 @@ SettingsBrowserMail::SettingsBrowserMail(Settings *settings, QWidget *parent)
connect(m_ui->m_txtExternalBrowserExecutable, &QLineEdit::textChanged, this, &SettingsBrowserMail::dirtifySettings);
connect(m_ui->m_txtExternalEmailArguments, &QLineEdit::textChanged, this, &SettingsBrowserMail::dirtifySettings);
connect(m_ui->m_txtExternalEmailExecutable, &QLineEdit::textChanged, this, &SettingsBrowserMail::dirtifySettings);
connect(m_ui->m_cmbProxyType, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &SettingsBrowserMail::onProxyTypeChanged);
connect(m_ui->m_checkShowPassword, &QCheckBox::stateChanged, this, &SettingsBrowserMail::displayProxyPassword);
connect(m_ui->m_cmbExternalBrowserPreset, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &SettingsBrowserMail::changeDefaultBrowserArguments);
@ -91,6 +87,7 @@ void SettingsBrowserMail::displayProxyPassword(int state) {
if (state == Qt::Checked) {
m_ui->m_txtProxyPassword->setEchoMode(QLineEdit::Normal);
}
else {
m_ui->m_txtProxyPassword->setEchoMode(QLineEdit::PasswordEchoOnEdit);
}
@ -99,7 +96,6 @@ void SettingsBrowserMail::displayProxyPassword(int state) {
void SettingsBrowserMail::onProxyTypeChanged(int index) {
const QNetworkProxy::ProxyType selected_type = static_cast<QNetworkProxy::ProxyType>(m_ui->m_cmbProxyType->itemData(index).toInt());
const bool is_proxy_selected = selected_type != QNetworkProxy::NoProxy && selected_type != QNetworkProxy::DefaultProxy;
m_ui->m_txtProxyHost->setEnabled(is_proxy_selected);
m_ui->m_txtProxyPassword->setEnabled(is_proxy_selected);
m_ui->m_txtProxyUsername->setEnabled(is_proxy_selected);
@ -137,66 +133,53 @@ void SettingsBrowserMail::selectEmailExecutable() {
void SettingsBrowserMail::loadSettings() {
onBeginLoadSettings();
#if !defined(USE_WEBENGINE)
m_ui->m_checkOpenLinksInExternal->setChecked(settings()->value(GROUP(Browser),
SETTING(Browser::OpenLinksInExternalBrowserRightAway)).toBool());
#endif
// Load settings of web browser GUI.
m_ui->m_cmbExternalBrowserPreset->addItem(tr("Opera 12 or older"), QSL("-nosession %1"));
m_ui->m_txtExternalBrowserExecutable->setText(settings()->value(GROUP(Browser), SETTING(Browser::CustomExternalBrowserExecutable)).toString());
m_ui->m_txtExternalBrowserArguments->setText(settings()->value(GROUP(Browser), SETTING(Browser::CustomExternalBrowserArguments)).toString());
m_ui->m_grpCustomExternalBrowser->setChecked(settings()->value(GROUP(Browser), SETTING(Browser::CustomExternalBrowserEnabled)).toBool());
// Load settings of e-mail.
m_ui->m_cmbExternalEmailPreset->addItem(tr("Mozilla Thunderbird"), QSL("-compose \"subject='%1',body='%2'\""));
m_ui->m_txtExternalEmailExecutable->setText(settings()->value(GROUP(Browser), SETTING(Browser::CustomExternalEmailExecutable)).toString());
m_ui->m_txtExternalEmailArguments->setText(settings()->value(GROUP(Browser), SETTING(Browser::CustomExternalEmailArguments)).toString());
m_ui->m_grpCustomExternalEmail->setChecked(settings()->value(GROUP(Browser), SETTING(Browser::CustomExternalEmailEnabled)).toBool());
m_ui->m_cmbProxyType->addItem(tr("No proxy"), QNetworkProxy::NoProxy);
m_ui->m_cmbProxyType->addItem(tr("System proxy"), QNetworkProxy::DefaultProxy);
m_ui->m_cmbProxyType->addItem(tr("Socks5"), QNetworkProxy::Socks5Proxy);
m_ui->m_cmbProxyType->addItem(tr("Http"), QNetworkProxy::HttpProxy);
// Load the settings.
QNetworkProxy::ProxyType selected_proxy_type = static_cast<QNetworkProxy::ProxyType>(settings()->value(GROUP(Proxy), SETTING(Proxy::Type)).toInt());
m_ui->m_cmbProxyType->setCurrentIndex(m_ui->m_cmbProxyType->findData(selected_proxy_type));
m_ui->m_txtProxyHost->setText(settings()->value(GROUP(Proxy), SETTING(Proxy::Host)).toString());
m_ui->m_txtProxyUsername->setText(settings()->value(GROUP(Proxy), SETTING(Proxy::Username)).toString());
m_ui->m_txtProxyPassword->setText(TextFactory::decrypt(settings()->value(GROUP(Proxy), SETTING(Proxy::Password)).toString()));
m_ui->m_spinProxyPort->setValue(settings()->value(GROUP(Proxy), SETTING(Proxy::Port)).toInt());
onEndLoadSettings();
}
void SettingsBrowserMail::saveSettings() {
onBeginSaveSettings();
#if !defined(USE_WEBENGINE)
settings()->setValue(GROUP(Browser), Browser::OpenLinksInExternalBrowserRightAway, m_ui->m_checkOpenLinksInExternal->isChecked());
#endif
// Save settings of GUI of web browser.
settings()->setValue(GROUP(Browser), Browser::CustomExternalBrowserEnabled, m_ui->m_grpCustomExternalBrowser->isChecked());
settings()->setValue(GROUP(Browser), Browser::CustomExternalBrowserExecutable, m_ui->m_txtExternalBrowserExecutable->text());
settings()->setValue(GROUP(Browser), Browser::CustomExternalBrowserArguments, m_ui->m_txtExternalBrowserArguments->text());
// Save settings of e-mail.
settings()->setValue(GROUP(Browser), Browser::CustomExternalEmailExecutable, m_ui->m_txtExternalEmailExecutable->text());
settings()->setValue(GROUP(Browser), Browser::CustomExternalEmailArguments, m_ui->m_txtExternalEmailArguments->text());
settings()->setValue(GROUP(Browser), Browser::CustomExternalEmailEnabled, m_ui->m_grpCustomExternalEmail->isChecked());
settings()->setValue(GROUP(Proxy), Proxy::Type, m_ui->m_cmbProxyType->itemData(m_ui->m_cmbProxyType->currentIndex()));
settings()->setValue(GROUP(Proxy), Proxy::Host, m_ui->m_txtProxyHost->text());
settings()->setValue(GROUP(Proxy), Proxy::Username, m_ui->m_txtProxyUsername->text());
settings()->setValue(GROUP(Proxy), Proxy::Password, TextFactory::encrypt(m_ui->m_txtProxyPassword->text()));
settings()->setValue(GROUP(Proxy), Proxy::Port, m_ui->m_spinProxyPort->value());
// Reload settings for all network access managers.
SilentNetworkAccessManager::instance()->loadSettings();
onEndSaveSettings();
}

View file

@ -27,11 +27,9 @@
SettingsDatabase::SettingsDatabase(Settings* settings, QWidget* parent)
: SettingsPanel(settings, parent), m_ui(new Ui::SettingsDatabase) {
m_ui->setupUi(this);
GuiUtilities::setLabelAsNotice(m_ui->m_lblDataStorageWarning, true);
GuiUtilities::setLabelAsNotice(m_ui->m_lblMysqlInfo, false);
GuiUtilities::setLabelAsNotice(m_ui->m_lblSqliteInMemoryWarnings, true);
connect(m_ui->m_cmbDatabaseDriver, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &SettingsDatabase::dirtifySettings);
connect(m_ui->m_checkSqliteUseInMemoryDatabase, &QCheckBox::toggled, this, &SettingsDatabase::dirtifySettings);
connect(m_ui->m_txtMysqlDatabase->lineEdit(), &QLineEdit::textChanged, this, &SettingsDatabase::dirtifySettings);
@ -40,7 +38,6 @@ SettingsDatabase::SettingsDatabase(Settings *settings, QWidget *parent)
connect(m_ui->m_checkUseTransactions, &QCheckBox::toggled, this, &SettingsDatabase::dirtifySettings);
connect(m_ui->m_txtMysqlUsername->lineEdit(), &QLineEdit::textChanged, this, &SettingsDatabase::dirtifySettings);
connect(m_ui->m_spinMysqlPort, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &SettingsDatabase::dirtifySettings);
connect(m_ui->m_cmbDatabaseDriver, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &SettingsDatabase::selectSqlBackend);
connect(m_ui->m_checkMysqlShowPassword, &QCheckBox::toggled, this, &SettingsDatabase::switchMysqlPasswordVisiblity);
connect(m_ui->m_txtMysqlUsername->lineEdit(), &BaseLineEdit::textChanged, this, &SettingsDatabase::onMysqlUsernameChanged);
@ -48,7 +45,6 @@ SettingsDatabase::SettingsDatabase(Settings *settings, QWidget *parent)
connect(m_ui->m_txtMysqlPassword->lineEdit(), &BaseLineEdit::textChanged, this, &SettingsDatabase::onMysqlPasswordChanged);
connect(m_ui->m_txtMysqlDatabase->lineEdit(), &BaseLineEdit::textChanged, this, &SettingsDatabase::onMysqlDatabaseChanged);
connect(m_ui->m_btnMysqlTestSetup, &QPushButton::clicked, this, &SettingsDatabase::mysqlTestConnection);
connect(m_ui->m_cmbDatabaseDriver, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &SettingsDatabase::requireRestart);
connect(m_ui->m_checkSqliteUseInMemoryDatabase, &QCheckBox::toggled, this, &SettingsDatabase::requireRestart);
connect(m_ui->m_spinMysqlPort, &QSpinBox::editingFinished, this, &SettingsDatabase::requireRestart);
@ -69,7 +65,6 @@ void SettingsDatabase::mysqlTestConnection() {
m_ui->m_txtMysqlPassword->lineEdit()->text());
const QString interpretation = qApp->database()->mysqlInterpretErrorCode(error_code);
switch (error_code) {
case DatabaseFactory::MySQLOk:
case DatabaseFactory::MySQLUnknownDatabase:
@ -86,6 +81,7 @@ void SettingsDatabase::onMysqlHostnameChanged(const QString &new_hostname) {
if (new_hostname.isEmpty()) {
m_ui->m_txtMysqlHostname->setStatus(LineEditWithStatus::Warning, tr("Hostname is empty."));
}
else {
m_ui->m_txtMysqlHostname->setStatus(LineEditWithStatus::Ok, tr("Hostname looks ok."));
}
@ -95,6 +91,7 @@ void SettingsDatabase::onMysqlUsernameChanged(const QString &new_username) {
if (new_username.isEmpty()) {
m_ui->m_txtMysqlUsername->setStatus(LineEditWithStatus::Warning, tr("Username is empty."));
}
else {
m_ui->m_txtMysqlUsername->setStatus(LineEditWithStatus::Ok, tr("Username looks ok."));
}
@ -104,6 +101,7 @@ void SettingsDatabase::onMysqlPasswordChanged(const QString &new_password) {
if (new_password.isEmpty()) {
m_ui->m_txtMysqlPassword->setStatus(LineEditWithStatus::Warning, tr("Password is empty."));
}
else {
m_ui->m_txtMysqlPassword->setStatus(LineEditWithStatus::Ok, tr("Password looks ok."));
}
@ -113,6 +111,7 @@ void SettingsDatabase::onMysqlDatabaseChanged(const QString &new_database) {
if (new_database.isEmpty()) {
m_ui->m_txtMysqlDatabase->setStatus(LineEditWithStatus::Warning, tr("Working database is empty."));
}
else {
m_ui->m_txtMysqlDatabase->setStatus(LineEditWithStatus::Ok, tr("Working database is ok."));
}
@ -124,9 +123,11 @@ void SettingsDatabase::selectSqlBackend(int index) {
if (selected_db_driver == APP_DB_SQLITE_DRIVER) {
m_ui->m_stackedDatabaseDriver->setCurrentIndex(0);
}
else if (selected_db_driver == APP_DB_MYSQL_DRIVER) {
m_ui->m_stackedDatabaseDriver->setCurrentIndex(1);
}
else {
qWarning("GUI for given database driver '%s' is not available.", qPrintable(selected_db_driver));
}
@ -138,13 +139,10 @@ void SettingsDatabase::switchMysqlPasswordVisiblity(bool visible) {
void SettingsDatabase::loadSettings() {
onBeginLoadSettings();
m_ui->m_checkUseTransactions->setChecked(qApp->settings()->value(GROUP(Database), SETTING(Database::UseTransactions)).toBool());
m_ui->m_lblMysqlTestResult->setStatus(WidgetWithStatus::Information, tr("No connection test triggered so far."), tr("You did not executed any connection test yet."));
// Load SQLite.
m_ui->m_cmbDatabaseDriver->addItem(qApp->database()->humanDriverName(DatabaseFactory::SQLITE), APP_DB_SQLITE_DRIVER);
// Load in-memory database status.
m_ui->m_checkSqliteUseInMemoryDatabase->setChecked(settings()->value(GROUP(Database), SETTING(Database::UseInMemory)).toBool());
@ -153,22 +151,18 @@ void SettingsDatabase::loadSettings() {
onMysqlUsernameChanged(QString());
onMysqlPasswordChanged(QString());
onMysqlDatabaseChanged(QString());
// Load MySQL.
m_ui->m_cmbDatabaseDriver->addItem(qApp->database()->humanDriverName(DatabaseFactory::MYSQL), APP_DB_MYSQL_DRIVER);
// Setup placeholders.
m_ui->m_txtMysqlHostname->lineEdit()->setPlaceholderText(tr("Hostname of your MySQL server"));
m_ui->m_txtMysqlUsername->lineEdit()->setPlaceholderText(tr("Username to login with"));
m_ui->m_txtMysqlPassword->lineEdit()->setPlaceholderText(tr("Password for your username"));
m_ui->m_txtMysqlDatabase->lineEdit()->setPlaceholderText(tr("Working database which you have full access to."));
m_ui->m_txtMysqlHostname->lineEdit()->setText(settings()->value(GROUP(Database), SETTING(Database::MySQLHostname)).toString());
m_ui->m_txtMysqlUsername->lineEdit()->setText(settings()->value(GROUP(Database), SETTING(Database::MySQLUsername)).toString());
m_ui->m_txtMysqlPassword->lineEdit()->setText(TextFactory::decrypt(settings()->value(GROUP(Database), SETTING(Database::MySQLPassword)).toString()));
m_ui->m_txtMysqlDatabase->lineEdit()->setText(settings()->value(GROUP(Database), SETTING(Database::MySQLDatabase)).toString());
m_ui->m_spinMysqlPort->setValue(settings()->value(GROUP(Database), SETTING(Database::MySQLPort)).toInt());
m_ui->m_checkMysqlShowPassword->setChecked(false);
}
@ -183,17 +177,13 @@ void SettingsDatabase::loadSettings() {
void SettingsDatabase::saveSettings() {
onBeginSaveSettings();
// Setup in-memory database status.
const bool original_inmemory = settings()->value(GROUP(Database), SETTING(Database::UseInMemory)).toBool();
const bool new_inmemory = m_ui->m_checkSqliteUseInMemoryDatabase->isChecked();
qApp->settings()->setValue(GROUP(Database), Database::UseTransactions, m_ui->m_checkUseTransactions->isChecked());
// Save data storage settings.
QString original_db_driver = settings()->value(GROUP(Database), SETTING(Database::ActiveDriver)).toString();
QString selected_db_driver = m_ui->m_cmbDatabaseDriver->itemData(m_ui->m_cmbDatabaseDriver->currentIndex()).toString();
// Save SQLite.
settings()->setValue(GROUP(Database), Database::UseInMemory, new_inmemory);

View file

@ -27,11 +27,9 @@
SettingsDownloads::SettingsDownloads(Settings* settings, QWidget* parent)
: SettingsPanel(settings, parent), m_ui(new Ui::SettingsDownloads) {
m_ui->setupUi(this);
connect(m_ui->m_checkOpenManagerWhenDownloadStarts, &QCheckBox::toggled, this, &SettingsDownloads::dirtifySettings);
connect(m_ui->m_txtDownloadsTargetDirectory, &QLineEdit::textChanged, this, &SettingsDownloads::dirtifySettings);
connect(m_ui->m_rbDownloadsAskEachFile, &QRadioButton::toggled, this, &SettingsDownloads::dirtifySettings);
connect(m_ui->m_btnDownloadsTargetDirectory, &QPushButton::clicked, this, &SettingsDownloads::selectDownloadsDirectory);
}
@ -52,24 +50,20 @@ void SettingsDownloads::selectDownloadsDirectory() {
void SettingsDownloads::loadSettings() {
onBeginLoadSettings();
m_ui->m_checkOpenManagerWhenDownloadStarts->setChecked(settings()->value(GROUP(Downloads),
SETTING(Downloads::ShowDownloadsWhenNewDownloadStarts)).toBool());
m_ui->m_txtDownloadsTargetDirectory->setText(QDir::toNativeSeparators(settings()->value(GROUP(Downloads),
SETTING(Downloads::TargetDirectory)).toString()));
m_ui->m_rbDownloadsAskEachFile->setChecked(settings()->value(GROUP(Downloads),
SETTING(Downloads::AlwaysPromptForFilename)).toBool());
onEndLoadSettings();
}
void SettingsDownloads::saveSettings() {
onBeginSaveSettings();
settings()->setValue(GROUP(Downloads), Downloads::ShowDownloadsWhenNewDownloadStarts, m_ui->m_checkOpenManagerWhenDownloadStarts->isChecked());
settings()->setValue(GROUP(Downloads), Downloads::TargetDirectory, m_ui->m_txtDownloadsTargetDirectory->text());
settings()->setValue(GROUP(Downloads), Downloads::AlwaysPromptForFilename, m_ui->m_rbDownloadsAskEachFile->isChecked());
qApp->downloadManager()->setDownloadDirectory(m_ui->m_txtDownloadsTargetDirectory->text());
onEndSaveSettings();
}

View file

@ -34,9 +34,7 @@ SettingsFeedsMessages::SettingsFeedsMessages(Settings *settings, QWidget *parent
: SettingsPanel(settings, parent), m_ui(new Ui::SettingsFeedsMessages) {
m_ui->setupUi(this);
initializeMessageDateFormats();
GuiUtilities::setLabelAsNotice(m_ui->label_9, false);
connect(m_ui->m_checkAutoUpdateNotification, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings);
connect(m_ui->m_checkAutoUpdate, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings);
connect(m_ui->m_checkKeppMessagesInTheMiddle, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings);
@ -52,7 +50,6 @@ SettingsFeedsMessages::SettingsFeedsMessages(Settings *settings, QWidget *parent
connect(m_ui->m_cmbMessagesDateTimeFormat, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &SettingsFeedsMessages::dirtifySettings);
connect(m_ui->m_cmbCountsFeedList, &QComboBox::currentTextChanged, this, &SettingsFeedsMessages::dirtifySettings);
connect(m_ui->m_cmbCountsFeedList, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &SettingsFeedsMessages::dirtifySettings);
connect(m_ui->m_btnChangeMessagesFont, &QPushButton::clicked, this, &SettingsFeedsMessages::changeMessagesFont);
if (!m_ui->m_spinFeedUpdateTimeout->suffix().startsWith(' ')) {
@ -65,7 +62,8 @@ SettingsFeedsMessages::~SettingsFeedsMessages() {
}
void SettingsFeedsMessages::initializeMessageDateFormats() {
QStringList best_formats; best_formats << QSL("d/M/yyyy hh:mm:ss") << QSL("ddd, d. M. yy hh:mm:ss") <<
QStringList best_formats;
best_formats << QSL("d/M/yyyy hh:mm:ss") << QSL("ddd, d. M. yy hh:mm:ss") <<
QSL("yyyy-MM-dd HH:mm:ss.z") << QSL("yyyy-MM-ddThh:mm:ss") <<
QSL("MMM d yyyy hh:mm:ss");;
const QLocale current_locale = qApp->localization()->loadedLocale();
@ -90,7 +88,6 @@ void SettingsFeedsMessages::changeMessagesFont() {
void SettingsFeedsMessages::loadSettings() {
onBeginLoadSettings();
m_ui->m_checkAutoUpdateNotification->setChecked(settings()->value(GROUP(Feeds), SETTING(Feeds::EnableAutoUpdateNotification)).toBool());
m_ui->m_checkKeppMessagesInTheMiddle->setChecked(settings()->value(GROUP(Messages), SETTING(Messages::KeepCursorInCenter)).toBool());
m_ui->m_checkRemoveReadMessagesOnExit->setChecked(settings()->value(GROUP(Messages), SETTING(Messages::ClearReadOnExit)).toBool());
@ -101,9 +98,7 @@ void SettingsFeedsMessages::loadSettings() {
m_ui->m_cmbCountsFeedList->addItems(QStringList() << "(%unread)" << "[%unread]" << "%unread/%all" << "%unread-%all" << "[%unread|%all]");
m_ui->m_cmbCountsFeedList->setEditText(settings()->value(GROUP(Feeds), SETTING(Feeds::CountFormat)).toString());
m_ui->m_spinHeightImageAttachments->setValue(settings()->value(GROUP(Messages), SETTING(Messages::MessageHeadImageHeight)).toInt());
initializeMessageDateFormats();
m_ui->m_checkMessagesDateTimeFormat->setChecked(settings()->value(GROUP(Messages), SETTING(Messages::UseCustomDate)).toBool());
const int index_format = m_ui->m_cmbMessagesDateTimeFormat->findData(settings()->value(GROUP(Messages), SETTING(Messages::CustomDateFormat)).toString());
@ -116,13 +111,11 @@ void SettingsFeedsMessages::loadSettings() {
fon.fromString(settings()->value(GROUP(Messages),
SETTING(Messages::PreviewerFontStandard)).toString());
m_ui->m_lblMessagesFont->setFont(fon);
onEndLoadSettings();
}
void SettingsFeedsMessages::saveSettings() {
onBeginSaveSettings();
settings()->setValue(GROUP(Feeds), Feeds::EnableAutoUpdateNotification, m_ui->m_checkAutoUpdateNotification->isChecked());
settings()->setValue(GROUP(Messages), Messages::KeepCursorInCenter, m_ui->m_checkKeppMessagesInTheMiddle->isChecked());
settings()->setValue(GROUP(Messages), Messages::ClearReadOnExit, m_ui->m_checkRemoveReadMessagesOnExit->isChecked());
@ -135,16 +128,12 @@ void SettingsFeedsMessages::saveSettings() {
settings()->setValue(GROUP(Messages), Messages::MessageHeadImageHeight, m_ui->m_spinHeightImageAttachments->value());
settings()->setValue(GROUP(Messages), Messages::CustomDateFormat,
m_ui->m_cmbMessagesDateTimeFormat->itemData(m_ui->m_cmbMessagesDateTimeFormat->currentIndex()).toString());
// Save fonts.
settings()->setValue(GROUP(Messages), Messages::PreviewerFontStandard, m_ui->m_lblMessagesFont->font().toString());
qApp->mainForm()->tabWidget()->feedMessageViewer()->loadMessageViewerFonts();
qApp->feedReader()->updateAutoUpdateStatus();
qApp->feedReader()->feedsModel()->reloadWholeLayout();
qApp->feedReader()->messagesModel()->updateDateFormat();
qApp->feedReader()->messagesModel()->reloadWholeLayout();
onEndSaveSettings();
}

View file

@ -25,7 +25,6 @@ SettingsGeneral::SettingsGeneral(Settings *settings, QWidget *parent)
: SettingsPanel(settings, parent), m_ui(new Ui::SettingsGeneral) {
m_ui->setupUi(this);
m_ui->m_checkAutostart->setText(m_ui->m_checkAutostart->text().arg(APP_NAME));
connect(m_ui->m_checkAutostart, &QCheckBox::stateChanged, this, &SettingsGeneral::dirtifySettings);
connect(m_ui->m_checkForUpdatesOnStart, &QCheckBox::stateChanged, this, &SettingsGeneral::dirtifySettings);
connect(m_ui->m_checkRemoveTrolltechJunk, &QCheckBox::stateChanged, this, &SettingsGeneral::dirtifySettings);
@ -37,9 +36,7 @@ SettingsGeneral::~SettingsGeneral() {
void SettingsGeneral::loadSettings() {
onBeginLoadSettings();
m_ui->m_checkForUpdatesOnStart->setChecked(settings()->value(GROUP(General), SETTING(General::UpdateOnStartup)).toBool());
// Load auto-start status.
const SystemFactory::AutoStartStatus autostart_status = qApp->system()->getAutoStartStatus();
@ -64,7 +61,6 @@ void SettingsGeneral::loadSettings() {
#else
m_ui->m_checkRemoveTrolltechJunk->setVisible(false);
#endif
onEndLoadSettings();
}
@ -75,12 +71,12 @@ void SettingsGeneral::saveSettings() {
if (m_ui->m_checkAutostart->isChecked()) {
qApp->system()->setAutoStartStatus(SystemFactory::Enabled);
}
else {
qApp->system()->setAutoStartStatus(SystemFactory::Disabled);
}
settings()->setValue(GROUP(General), General::UpdateOnStartup, m_ui->m_checkForUpdatesOnStart->isChecked());
settings()->setValue(GROUP(General), General::RemoveTrolltechJunk, m_ui->m_checkRemoveTrolltechJunk->isChecked());
onEndSaveSettings();
}

View file

@ -34,12 +34,10 @@
SettingsGui::SettingsGui(Settings* settings, QWidget* parent) : SettingsPanel(settings, parent), m_ui(new Ui::SettingsGui) {
m_ui->setupUi(this);
m_ui->m_editorMessagesToolbar->activeItemsWidget()->viewport()->installEventFilter(this);
m_ui->m_editorFeedsToolbar->activeItemsWidget()->viewport()->installEventFilter(this);
m_ui->m_editorMessagesToolbar->availableItemsWidget()->viewport()->installEventFilter(this);
m_ui->m_editorFeedsToolbar->availableItemsWidget()->viewport()->installEventFilter(this);
m_ui->m_treeSkins->setColumnCount(4);
m_ui->m_treeSkins->setHeaderHidden(false);
m_ui->m_treeSkins->setHeaderLabels(QStringList()
@ -47,13 +45,11 @@ SettingsGui::SettingsGui(Settings *settings, QWidget *parent) : SettingsPanel(se
<< /*: Version column of skin list. */ tr("Version")
<< tr("Author")
<< tr("E-mail"));
// Setup skins.
m_ui->m_treeSkins->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
m_ui->m_treeSkins->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
m_ui->m_treeSkins->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
m_ui->m_treeSkins->header()->setSectionResizeMode(3, QHeaderView::ResizeToContents);
connect(m_ui->m_cmbIconTheme, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &SettingsGui::requireRestart);
connect(m_ui->m_cmbIconTheme, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &SettingsGui::dirtifySettings);
connect(m_ui->m_treeSkins, &QTreeWidget::currentItemChanged, this, &SettingsGui::dirtifySettings);
@ -71,7 +67,6 @@ SettingsGui::SettingsGui(Settings *settings, QWidget *parent) : SettingsPanel(se
connect(m_ui->m_editorMessagesToolbar, &ToolBarEditor::setupChanged, this, &SettingsGui::dirtifySettings);
connect(m_ui->m_editorStatusbar, &ToolBarEditor::setupChanged, this, &SettingsGui::dirtifySettings);
connect(m_ui->m_listStyles, &QListWidget::currentItemChanged, this, &SettingsGui::dirtifySettings);
connect(m_ui->m_cmbSelectToolBar, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), m_ui->m_stackedToolbars, &QStackedWidget::setCurrentIndex);
}
@ -101,6 +96,7 @@ void SettingsGui::loadSettings() {
if (SystemTrayIcon::isSystemTrayAvailable()) {
m_ui->m_grpTray->setChecked(settings()->value(GROUP(GUI), SETTING(GUI::UseTrayIcon)).toBool());
}
// Tray icon is not supported on this machine.
else {
m_ui->m_grpTray->setTitle(m_ui->m_grpTray->title() + QL1C(' ') + tr("(Tray icon is not available.)"));
@ -109,10 +105,8 @@ void SettingsGui::loadSettings() {
m_ui->m_checkHidden->setChecked(settings()->value(GROUP(GUI), SETTING(GUI::MainWindowStartsHidden)).toBool());
m_ui->m_checkHideWhenMinimized->setChecked(settings()->value(GROUP(GUI), SETTING(GUI::HideMainWindowWhenMinimized)).toBool());
// Load fancy notification settings.
m_ui->m_checkEnableNotifications->setChecked(settings()->value(GROUP(GUI), SETTING(GUI::EnableNotifications)).toBool());
// Load settings of icon theme.
const QString current_theme = qApp->icons()->currentIconTheme();
@ -122,6 +116,7 @@ void SettingsGui::loadSettings() {
//: Label for disabling icon theme.
m_ui->m_cmbIconTheme->addItem(tr("no icon theme/system icon theme"), APP_NO_THEME);
}
else {
m_ui->m_cmbIconTheme->addItem(icon_theme_name, icon_theme_name);
}
@ -132,6 +127,7 @@ void SettingsGui::loadSettings() {
// Because "no icon theme" lies at the index 0.
m_ui->m_cmbIconTheme->setCurrentIndex(0);
}
else {
m_ui->m_cmbIconTheme->setCurrentText(current_theme);
}
@ -146,7 +142,6 @@ void SettingsGui::loadSettings() {
skin.m_author <<
skin.m_email);
new_item->setData(0, Qt::UserRole, QVariant::fromValue(skin));
// Add this skin and mark it as active if its active now.
m_ui->m_treeSkins->addTopLevelItem(new_item);
@ -179,28 +174,23 @@ void SettingsGui::loadSettings() {
m_ui->m_checkCloseTabsDoubleClick->setChecked(settings()->value(GROUP(GUI), SETTING(GUI::TabCloseDoubleClick)).toBool());
m_ui->m_checkNewTabDoubleClick->setChecked(settings()->value(GROUP(GUI), SETTING(GUI::TabNewDoubleClick)).toBool());
m_ui->m_checkHideTabBarIfOneTabVisible->setChecked(settings()->value(GROUP(GUI), SETTING(GUI::HideTabBarIfOnlyOneTab)).toBool());
// Load toolbar button style.
m_ui->m_cmbToolbarButtonStyle->addItem(tr("Icon only"), Qt::ToolButtonIconOnly);
m_ui->m_cmbToolbarButtonStyle->addItem(tr("Text only"), Qt::ToolButtonTextOnly);
m_ui->m_cmbToolbarButtonStyle->addItem(tr("Text beside icon"), Qt::ToolButtonTextBesideIcon);
m_ui->m_cmbToolbarButtonStyle->addItem(tr("Text under icon"), Qt::ToolButtonTextUnderIcon);
m_ui->m_cmbToolbarButtonStyle->addItem(tr("Follow OS style"), Qt::ToolButtonFollowStyle);
m_ui->m_cmbToolbarButtonStyle->setCurrentIndex(m_ui->m_cmbToolbarButtonStyle->findData(settings()->value(GROUP(GUI),
SETTING(GUI::ToolbarStyle)).toInt()));
// Load toolbars.
m_ui->m_editorFeedsToolbar->loadFromToolBar(qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsToolBar());
m_ui->m_editorMessagesToolbar->loadFromToolBar(qApp->mainForm()->tabWidget()->feedMessageViewer()->messagesToolBar());
m_ui->m_editorStatusbar->loadFromToolBar(qApp->mainForm()->statusBar());
onEndLoadSettings();
}
void SettingsGui::saveSettings() {
onBeginSaveSettings();
// Save toolbar.
settings()->setValue(GROUP(GUI), GUI::ToolbarStyle, m_ui->m_cmbToolbarButtonStyle->itemData(m_ui->m_cmbToolbarButtonStyle->currentIndex()));
@ -211,6 +201,7 @@ void SettingsGui::saveSettings() {
if (m_ui->m_grpTray->isChecked()) {
qApp->showTrayIcon();
}
else {
qApp->deleteTrayIcon();
}
@ -218,10 +209,8 @@ void SettingsGui::saveSettings() {
settings()->setValue(GROUP(GUI), GUI::MainWindowStartsHidden, m_ui->m_checkHidden->isChecked());
settings()->setValue(GROUP(GUI), GUI::HideMainWindowWhenMinimized, m_ui->m_checkHideWhenMinimized->isChecked());
// Save notifications.
settings()->setValue(GROUP(GUI), GUI::EnableNotifications, m_ui->m_checkEnableNotifications->isChecked());
// Save selected icon theme.
QString selected_icon_theme = m_ui->m_cmbIconTheme->itemData(m_ui->m_cmbIconTheme->currentIndex()).toString();
QString original_icon_theme = qApp->icons()->currentIconTheme();
@ -259,13 +248,10 @@ void SettingsGui::saveSettings() {
settings()->setValue(GROUP(GUI), GUI::TabCloseDoubleClick, m_ui->m_checkCloseTabsDoubleClick->isChecked());
settings()->setValue(GROUP(GUI), GUI::TabNewDoubleClick, m_ui->m_checkNewTabDoubleClick->isChecked());
settings()->setValue(GROUP(GUI), GUI::HideTabBarIfOnlyOneTab, m_ui->m_checkHideTabBarIfOneTabVisible->isChecked());
m_ui->m_editorFeedsToolbar->saveToolBar();
m_ui->m_editorMessagesToolbar->saveToolBar();
m_ui->m_editorStatusbar->saveToolBar();
qApp->mainForm()->tabWidget()->checkTabBarVisibility();
qApp->mainForm()->tabWidget()->feedMessageViewer()->refreshVisualProperties();
onEndSaveSettings();
}

View file

@ -26,19 +26,16 @@
SettingsLocalization::SettingsLocalization(Settings* settings, QWidget* parent)
: SettingsPanel(settings, parent), m_ui(new Ui::SettingsLocalization) {
m_ui->setupUi(this);
m_ui->m_treeLanguages->setColumnCount(3);
m_ui->m_treeLanguages->setHeaderHidden(false);
m_ui->m_treeLanguages->setHeaderLabels(QStringList()
<< /*: Language column of language list. */ tr("Language")
<< /*: Lang. code column of language list. */ tr("Code")
<< tr("Author"));
// Setup languages.
m_ui->m_treeLanguages->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
m_ui->m_treeLanguages->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
m_ui->m_treeLanguages->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
connect(m_ui->m_treeLanguages, &QTreeWidget::currentItemChanged, this, &SettingsLocalization::requireRestart);
connect(m_ui->m_treeLanguages, &QTreeWidget::currentItemChanged, this, &SettingsLocalization::dirtifySettings);
}
@ -59,7 +56,6 @@ void SettingsLocalization::loadSettings() {
}
m_ui->m_treeLanguages->sortByColumn(0, Qt::AscendingOrder);
QList<QTreeWidgetItem*> matching_items = m_ui->m_treeLanguages->findItems(qApp->localization()->loadedLanguage(), Qt::MatchContains, 1);
if (!matching_items.isEmpty()) {

View file

@ -30,7 +30,6 @@ void SettingsPanel::onBeginLoadSettings() {
void SettingsPanel::onEndLoadSettings() {
m_isLoading = false;
setRequiresRestart(false);
setIsDirty(false);
}

View file

@ -24,7 +24,6 @@
SettingsShortcuts::SettingsShortcuts(Settings* settings, QWidget* parent)
: SettingsPanel(settings, parent), m_ui(new Ui::SettingsShortcuts) {
m_ui->setupUi(this);
connect(m_ui->m_shortcuts, &DynamicShortcutsWidget::setupChanged, this, &SettingsShortcuts::dirtifySettings);
}
@ -34,17 +33,13 @@ SettingsShortcuts::~SettingsShortcuts() {
void SettingsShortcuts::loadSettings() {
onBeginLoadSettings();
m_ui->m_shortcuts->populate(qApp->userActions());
onEndLoadSettings();
}
void SettingsShortcuts::saveSettings() {
onBeginSaveSettings();
m_ui->m_shortcuts->updateShortcuts();
DynamicShortcuts::save(qApp->userActions());
onEndSaveSettings();
}

View file

@ -31,42 +31,33 @@
StatusBar::StatusBar(QWidget* parent) : QStatusBar(parent), m_mutex(new Mutex(QMutex::NonRecursive, this)) {
setSizeGripEnabled(false);
setContentsMargins(2, 0, 2, 2);
m_barProgressFeeds = new QProgressBar(this);
m_barProgressFeeds->setTextVisible(false);
m_barProgressFeeds->setFixedWidth(100);
m_barProgressFeeds->setVisible(false);
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->setObjectName(QSL("m_barProgressFeedsAction"));
m_lblProgressFeeds = new QLabel(this);
m_lblProgressFeeds->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
m_lblProgressFeeds->setVisible(false);
m_lblProgressFeeds->setObjectName(QSL("m_lblProgressFeeds"));
m_lblProgressFeedsAction = new QAction(qApp->icons()->fromTheme(QSL("application-rss+xml")), tr("Feed update label"), this);
m_lblProgressFeedsAction->setObjectName(QSL("m_lblProgressFeedsAction"));
m_barProgressDownload = new QProgressBar(this);
m_barProgressDownload->setTextVisible(true);
m_barProgressDownload->setFixedWidth(100);
m_barProgressDownload->setVisible(false);
m_barProgressDownload->setObjectName(QSL("m_barProgressDownload"));
m_barProgressDownloadAction = new QAction(qApp->icons()->fromTheme(QSL("emblem-downloads")), tr("File download progress bar"), this);
m_barProgressDownloadAction->setObjectName(QSL("m_barProgressDownloadAction"));
m_lblProgressDownload = new QLabel(this);
m_lblProgressDownload->setText("Downloading files in background");
m_lblProgressDownload->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
m_lblProgressDownload->setVisible(false);
m_lblProgressDownload->setObjectName(QSL("m_lblProgressDownload"));
m_lblProgressDownloadAction = new QAction(qApp->icons()->fromTheme(QSL("emblem-downloads")), tr("File download label"), this);
m_lblProgressDownloadAction->setObjectName(QSL("m_lblProgressDownloadAction"));
m_lblProgressDownload->installEventFilter(this);
m_barProgressDownload->installEventFilter(this);
}
@ -78,11 +69,9 @@ StatusBar::~StatusBar() {
QList<QAction*> StatusBar::availableActions() const {
QList<QAction*> actions = qApp->userActions();
// Now, add placeholder actions for custom stuff.
actions << m_barProgressDownloadAction << m_barProgressFeedsAction <<
m_lblProgressDownloadAction << m_lblProgressFeedsAction;
return actions;
}
@ -92,7 +81,6 @@ QList<QAction*> StatusBar::changeableActions() const {
void StatusBar::saveChangeableActions(const QStringList& actions) {
QMutexLocker locker(*m_mutex);
qApp->settings()->setValue(GROUP(GUI), GUI::StatusbarActions, actions.join(QSL(",")));
loadSpecificActions(getSpecificActions(actions));
}
@ -121,57 +109,56 @@ QList<QAction*> StatusBar::getSpecificActions(const QStringList &actions) {
if (matching_action == m_barProgressDownloadAction) {
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(""));
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;
@ -208,7 +195,6 @@ void StatusBar::loadSpecificActions(const QList<QAction*> &actions) {
foreach (QAction* act, actions) {
QWidget* widget = act->property("widget").isValid() ? static_cast<QWidget*>(act->property("widget").value<void*>()) : nullptr;
addAction(act);
// And also add widget.
@ -234,7 +220,6 @@ void StatusBar::clear() {
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_action = act->property("should_remove_action").isValid();
removeAction(act);
if (widget != nullptr) {
@ -256,7 +241,6 @@ void StatusBar::showProgressFeeds(int progress, const QString &label) {
if (actions().contains(m_barProgressFeedsAction)) {
m_lblProgressFeeds->setVisible(true);
m_barProgressFeeds->setVisible(true);
m_lblProgressFeeds->setText(label);
m_barProgressFeeds->setValue(progress);
}

View file

@ -54,13 +54,10 @@ SystemTrayIcon::SystemTrayIcon(const QString &normal_icon, const QString &plain_
m_bubbleClickTarget(nullptr),
m_bubbleClickSlot(nullptr) {
qDebug("Creating SystemTrayIcon instance.");
m_font.setBold(true);
// Initialize icon.
setNumber();
setContextMenu(parent->trayMenu());
// Create necessary connections.
connect(this, &SystemTrayIcon::activated, this, &SystemTrayIcon::onActivated);
}
@ -100,7 +97,6 @@ void SystemTrayIcon::showPrivate() {
// the settings window) gets closed. Behavior for main window
// is handled explicitly by FormMain::closeEvent() method.
qApp->setQuitOnLastWindowClosed(false);
// Display the tray icon.
QSystemTrayIcon::show();
emit shown();
@ -124,12 +120,11 @@ void SystemTrayIcon::setNumber(int number, bool any_new_message) {
setToolTip(QSL(APP_LONG_NAME));
QSystemTrayIcon::setIcon(QIcon(m_normalIcon));
}
else {
setToolTip(tr("%1\nUnread news: %2").arg(QSL(APP_LONG_NAME), QString::number(number)));
QPixmap background(m_plainPixmap);
QPainter tray_painter;
// FIXME: Here draw different background instead of different color of number.
tray_painter.begin(&background);
tray_painter.setPen(any_new_message ? Qt::black : Qt::black);
@ -143,14 +138,17 @@ void SystemTrayIcon::setNumber(int number, bool any_new_message) {
tray_painter.setFont(m_font);
tray_painter.drawText(QRect(0, 0, 128, 128), Qt::AlignVCenter | Qt::AlignCenter, QChar(8734));
}
else {
// Smaller number if it has 3 digits.
if (number > 99) {
m_font.setPixelSize(55);
}
else if (number > 9) {
m_font.setPixelSize(80);
}
// Bigger number if it has just one digit.
else {
m_font.setPixelSize(100);

View file

@ -44,12 +44,10 @@ void TabBar::setTabType(int index, const TabBar::TabType &type) {
case TabBar::DownloadManager:
case TabBar::Closable: {
PlainToolButton* close_button = new PlainToolButton(this);
close_button->setIcon(qApp->icons()->fromTheme(QSL("application-exit")));
close_button->setToolTip(tr("Close this tab."));
close_button->setText(tr("Close tab"));
close_button->setFixedSize(iconSize());
// Close underlying tab when button is clicked.
connect(close_button, &PlainToolButton::clicked, this, &TabBar::closeTabViaButton);
setTabButton(index, button_position, close_button);
@ -77,7 +75,6 @@ void TabBar::closeTabViaButton() {
for (int i = 0; i < count(); i++) {
if (tabButton(i, button_position) == close_button) {
emit tabCloseRequested(i);
return;
}
}
@ -96,6 +93,7 @@ void TabBar::wheelEvent(QWheelEvent *event) {
number_of_tabs - 1 :
current_index - 1);
}
else if (event->delta() < 0) {
// Scroll to the RIGHT tab.
setCurrentIndex(current_index == number_of_tabs - 1 ?
@ -107,7 +105,6 @@ void TabBar::wheelEvent(QWheelEvent *event) {
void TabBar::mousePressEvent(QMouseEvent* event) {
QTabBar::mousePressEvent(event);
const int tab_index = tabAt(event->pos());
// Check if user clicked on some tab or on empty space.
@ -126,7 +123,6 @@ void TabBar::mousePressEvent(QMouseEvent *event) {
void TabBar::mouseDoubleClickEvent(QMouseEvent* event) {
QTabBar::mouseDoubleClickEvent(event);
const int tab_index = tabAt(event->pos());
// Check if user clicked on some tab or on empty space.
@ -141,6 +137,7 @@ void TabBar::mouseDoubleClickEvent(QMouseEvent *event) {
}
}
}
else {
emit emptySpaceDoubleClicked();
}

View file

@ -59,7 +59,6 @@ void TabWidget::setupMainMenuButton() {
m_btnMainMenu->setToolTip(tr("Displays main menu."));
m_btnMainMenu->setIcon(qApp->icons()->fromTheme(QSL("go-home")));
m_btnMainMenu->setPopupMode(QToolButton::InstantPopup);
connect(m_btnMainMenu, &PlainToolButton::clicked, this, &TabWidget::openMainMenu);
}
@ -78,10 +77,8 @@ void TabWidget::openMainMenu() {
QPoint button_position = m_btnMainMenu->pos();
const QSize target_size = m_btnMainMenu->size() / 2.0;
button_position.setX(button_position.x() + target_size.width());
button_position.setY(button_position.y() + target_size.height());
m_menuMain->exec(mapToGlobal(button_position));
}
@ -106,6 +103,7 @@ void TabWidget::checkTabBarVisibility() {
setCornerWidget(m_btnMainMenu, Qt::TopLeftCorner);
m_btnMainMenu->setVisible(true);
}
else {
setCornerWidget(0, Qt::TopLeftCorner);
setCornerWidget(0, Qt::TopRightCorner);
@ -118,7 +116,6 @@ void TabWidget::checkTabBarVisibility() {
void TabWidget::tabInserted(int index) {
QTabWidget::tabInserted(index);
checkTabBarVisibility();
const int count_of_tabs = count();
if (index < count_of_tabs - 1 && count_of_tabs > 1) {
@ -130,7 +127,6 @@ void TabWidget::tabInserted(int index) {
void TabWidget::tabRemoved(int index) {
QTabWidget::tabRemoved(index);
checkTabBarVisibility();
const int count_of_tabs = count();
if (index < count_of_tabs && count_of_tabs > 1) {
@ -143,7 +139,6 @@ void TabWidget::createConnections() {
connect(tabBar(), &TabBar::tabCloseRequested, this, &TabWidget::closeTab);
connect(tabBar(), &TabBar::emptySpaceDoubleClicked, this, &TabWidget::addEmptyBrowser);
connect(tabBar(), &TabBar::tabMoved, this, &TabWidget::fixContentsAfterMove);
connect(feedMessageViewer()->messagesView(), &MessagesView::openMessagesInNewspaperView, this, &TabWidget::addNewspaperView);
connect(feedMessageViewer()->feedsView(), &FeedsView::openMessagesInNewspaperView, this, &TabWidget::addNewspaperView);
}
@ -171,10 +166,12 @@ bool TabWidget::closeTab(int index) {
removeTab(index, true);
return true;
}
else if (tabBar()->tabType(index) == TabBar::DownloadManager) {
removeTab(index, false);
return true;
}
else {
return false;
}
@ -207,15 +204,11 @@ int TabWidget::addNewspaperView(RootItem *root, const QList<Message> &messages)
#else
NewspaperPreviewer* prev = new NewspaperPreviewer(root, messages, this);
#endif
int index = addTab(prev, qApp->icons()->fromTheme(QSL("format-justify-fill")), tr("Newspaper view"), TabBar::Closable);
setCurrentIndex(index);
#if defined(USE_WEBENGINE)
prev->loadMessages(messages, root);
#endif
return index;
}
@ -233,11 +226,9 @@ int TabWidget::addLinkedBrowser(const QString &initial_url) {
int TabWidget::addBrowser(bool move_after_current, bool make_active, const QUrl& initial_url) {
#if defined(USE_WEBENGINE)
// Create new WebBrowser.
WebBrowser* browser = new WebBrowser(this);
int final_index;
#if defined (Q_OS_MACOS)
const QString browser_tab_name = tr(" Web browser");
#else
@ -249,6 +240,7 @@ int TabWidget::addBrowser(bool move_after_current, bool make_active, const QUrl
final_index = insertTab(currentIndex() + 1, browser, qApp->icons()->fromTheme(QSL("text-html")),
browser_tab_name, TabBar::Closable);
}
else {
// Add new browser as the last tab.
final_index = addTab(browser, qApp->icons()->fromTheme(QSL("text-html")),
@ -260,7 +252,6 @@ int TabWidget::addBrowser(bool move_after_current, bool make_active, const QUrl
// Make connections.
connect(browser, &WebBrowser::titleChanged, this, &TabWidget::changeTitle);
connect(browser, &WebBrowser::iconChanged, this, &TabWidget::changeIcon);
// Setup the tab index.
browser->setIndex(final_index);
@ -279,15 +270,14 @@ int TabWidget::addBrowser(bool move_after_current, bool make_active, const QUrl
#else
Q_UNUSED(move_after_current)
Q_UNUSED(make_active)
WebFactory::instance()->openUrlInExternalBrowser(initial_url.toString());
return -1;
#endif
}
void TabWidget::indentTabText(int index) {
#if defined (Q_OS_MACOS)
if (tabBar()->tabType(index) != TabBar::FeedReader && !tabIcon(index).isNull()) {
// We have closable tab with some icon, fix the title.
const QString text = tabText(index);
@ -296,6 +286,7 @@ void TabWidget::indentTabText(int index){
setTabText(index, QSL(" ") + text);
}
}
#else
Q_UNUSED(index)
#endif
@ -313,7 +304,6 @@ int TabWidget::addTab(TabContent *widget, const QIcon &icon, const QString &labe
const int index = QTabWidget::addTab(widget, icon, label);
tabBar()->setTabType(index, type);
indentTabText(index);
return index;
}
@ -321,7 +311,6 @@ int TabWidget::addTab(TabContent *widget, const QString &label, const TabBar::Ta
const int index = QTabWidget::addTab(widget, label);
tabBar()->setTabType(index, type);
indentTabText(index);
return index;
}
@ -329,7 +318,6 @@ int TabWidget::insertTab(int index, QWidget *widget, const QIcon &icon, const QS
const int tab_index = QTabWidget::insertTab(index, widget, icon, label);
tabBar()->setTabType(tab_index, type);
indentTabText(index);
return tab_index;
}
@ -337,7 +325,6 @@ int TabWidget::insertTab(int index, QWidget *widget, const QString &label, const
const int tab_index = QTabWidget::insertTab(index, widget, label);
tabBar()->setTabType(tab_index, type);
indentTabText(index);
return tab_index;
}

5
src/gui/timespinbox.cpp Normal file → Executable file
View file

@ -37,6 +37,7 @@ double TimeSpinBox::valueFromText(const QString &text) const {
if (ok) {
return value;
}
else {
QRegExp rx("\\b[0-9]{1,}\\b");
QStringList numbers;
@ -55,6 +56,7 @@ double TimeSpinBox::valueFromText(const QString &text) const {
if (numbers.size() == 2) {
return (numbers.at(0).toDouble() * 60.0) + numbers.at(1).toDouble();
}
else {
return -1.0;
}
@ -65,10 +67,8 @@ QString TimeSpinBox::textFromValue(double val) const {
int minutes_total = (int)val;
int minutes_val = minutes_total % 60;
int hours_val = (minutes_total - minutes_val) / 60;
QString hours = tr("%n hour(s)", "", hours_val);
QString minutes = tr("%n minute(s)", "", minutes_val);
return hours + tr(" and ") + minutes;
}
@ -83,6 +83,5 @@ void TimeSpinBox::fixup(QString &input) const {
QValidator::State TimeSpinBox::validate(QString& input, int& pos) const {
Q_UNUSED(pos)
return (valueFromText(input) != -1.0) ? QValidator::Acceptable : QValidator::Intermediate;
}

View file

@ -26,25 +26,20 @@
ToolBarEditor::ToolBarEditor(QWidget* parent)
: QWidget(parent), m_ui(new Ui::ToolBarEditor) {
m_ui->setupUi(this);
// Create connections.
connect(m_ui->m_btnInsertSeparator, &QToolButton::clicked, this, &ToolBarEditor::insertSeparator);
connect(m_ui->m_btnInsertSpacer, &QToolButton::clicked, this, &ToolBarEditor::insertSpacer);
connect(m_ui->m_btnAddSelectedAction, &QToolButton::clicked, this, &ToolBarEditor::addSelectedAction);
connect(m_ui->m_btnDeleteAllActions, &QToolButton::clicked, this, &ToolBarEditor::deleteAllActions);
connect(m_ui->m_btnDeleteSelectedAction, &QToolButton::clicked, this, &ToolBarEditor::deleteSelectedAction);
connect(m_ui->m_btnMoveActionUp, &QToolButton::clicked, this, &ToolBarEditor::moveActionUp);
connect(m_ui->m_btnMoveActionDown, &QToolButton::clicked, this, &ToolBarEditor::moveActionDown);
connect(m_ui->m_btnReset, &QToolButton::clicked, this, &ToolBarEditor::resetToolBar);
connect(m_ui->m_listAvailableActions, &QListWidget::itemSelectionChanged, this, &ToolBarEditor::updateActionsAvailability);
connect(m_ui->m_listActivatedActions, &QListWidget::itemSelectionChanged, this, &ToolBarEditor::updateActionsAvailability);
connect(m_ui->m_listActivatedActions, &QListWidget::itemDoubleClicked, this, &ToolBarEditor::deleteSelectedAction);
connect(m_ui->m_listAvailableActions, &QListWidget::itemDoubleClicked, this, &ToolBarEditor::addSelectedAction);
m_ui->m_listActivatedActions->installEventFilter(this);
m_ui->m_btnInsertSeparator->setIcon(qApp->icons()->fromTheme(QSL("insert-object")));
m_ui->m_btnInsertSpacer->setIcon(qApp->icons()->fromTheme(QSL("go-jump")));
m_ui->m_btnAddSelectedAction->setIcon(qApp->icons()->fromTheme(QSL("back")));
@ -61,10 +56,8 @@ ToolBarEditor::~ToolBarEditor() {
void ToolBarEditor::loadFromToolBar(BaseBar* tool_bar) {
m_toolBar = tool_bar;
QList<QAction*> activated_actions = m_toolBar->changeableActions();
QList<QAction*> available_actions = m_toolBar->availableActions();
loadEditor(activated_actions, available_actions);
}
@ -97,11 +90,13 @@ void ToolBarEditor::loadEditor(const QList<QAction *> activated_actions, const Q
action_item->setText(tr("Separator"));
action_item->setToolTip(tr("Separator"));
}
else if (action->property("type").isValid()) {
action_item->setData(Qt::UserRole, action->property("type").toString());
action_item->setText(action->property("name").toString());
action_item->setToolTip(action_item->text());
}
else {
action_item->setData(Qt::UserRole, action->objectName());
action_item->setToolTip(action->toolTip());
@ -118,11 +113,13 @@ void ToolBarEditor::loadEditor(const QList<QAction *> activated_actions, const Q
action_item->setToolTip(tr("Separator"));
action_item->setIcon(qApp->icons()->fromTheme(QSL("insert-object")));
}
else if (action->property("type").isValid()) {
action_item->setData(Qt::UserRole, action->property("type").toString());
action_item->setText(action->property("name").toString());
action_item->setToolTip(action_item->text());
}
else {
action_item->setData(Qt::UserRole, action->objectName());
action_item->setToolTip(action->toolTip());
@ -144,10 +141,12 @@ bool ToolBarEditor::eventFilter(QObject *object, QEvent *event) {
deleteSelectedAction();
return true;
}
else if (key_event->key() == Qt::Key_Down && key_event->modifiers() & Qt::ControlModifier) {
moveActionDown();
return true;
}
else if (key_event->key() == Qt::Key_Up && key_event->modifiers() & Qt::ControlModifier) {
moveActionUp();
return true;
@ -171,27 +170,21 @@ void ToolBarEditor::updateActionsAvailability() {
void ToolBarEditor::insertSpacer() {
const int current_row = m_ui->m_listActivatedActions->currentRow();
QListWidgetItem* item = new QListWidgetItem(tr("Toolbar spacer"));
item->setIcon(qApp->icons()->fromTheme(QSL("go-jump")));
item->setData(Qt::UserRole, SPACER_ACTION_NAME);
m_ui->m_listActivatedActions->insertItem(current_row + 1, item);
m_ui->m_listActivatedActions->setCurrentRow(current_row + 1);
emit setupChanged();
}
void ToolBarEditor::insertSeparator() {
const int current_row = m_ui->m_listActivatedActions->currentRow();
QListWidgetItem* item = new QListWidgetItem(tr("Separator"));
item->setData(Qt::UserRole, SEPARATOR_ACTION_NAME);
item->setToolTip(tr("Separator"));
item->setIcon(qApp->icons()->fromTheme(QSL("insert-object")));
m_ui->m_listActivatedActions->insertItem(current_row + 1, item);
m_ui->m_listActivatedActions->setCurrentRow(current_row + 1);
emit setupChanged();
}
@ -201,11 +194,9 @@ void ToolBarEditor::moveActionDown() {
if (items.size() == 1 && m_ui->m_listActivatedActions->currentRow() < m_ui->m_listActivatedActions->count() - 1) {
QListWidgetItem* selected_item = items.at(0);
int row = m_ui->m_listActivatedActions->row(selected_item);
m_ui->m_listActivatedActions->takeItem(row++);
m_ui->m_listActivatedActions->insertItem(row, selected_item);
m_ui->m_listActivatedActions->setCurrentRow(row);
emit setupChanged();
}
}
@ -216,11 +207,9 @@ void ToolBarEditor::moveActionUp() {
if (items.size() == 1 && m_ui->m_listActivatedActions->currentRow() > 0) {
QListWidgetItem* selected_item = items.at(0);
int row = m_ui->m_listActivatedActions->row(selected_item);
m_ui->m_listActivatedActions->takeItem(row--);
m_ui->m_listActivatedActions->insertItem(row, selected_item);
m_ui->m_listActivatedActions->setCurrentRow(row);
emit setupChanged();
}
}
@ -230,12 +219,10 @@ void ToolBarEditor::addSelectedAction() {
if (items.size() == 1) {
QListWidgetItem* selected_item = items.at(0);
m_ui->m_listActivatedActions->insertItem(
m_ui->m_listActivatedActions->currentRow() + 1,
m_ui->m_listAvailableActions->takeItem(m_ui->m_listAvailableActions->row(selected_item)));
m_ui->m_listActivatedActions->setCurrentRow(m_ui->m_listActivatedActions->currentRow() + 1);
emit setupChanged();
}
}
@ -249,9 +236,9 @@ void ToolBarEditor::deleteSelectedAction() {
if (data_item == SEPARATOR_ACTION_NAME || data_item == SPACER_ACTION_NAME) {
m_ui->m_listActivatedActions->takeItem(m_ui->m_listActivatedActions->row(selected_item));
updateActionsAvailability();
}
else {
m_ui->m_listAvailableActions->insertItem(
m_ui->m_listAvailableActions->currentRow() + 1,

View file

@ -32,20 +32,16 @@ void TreeViewColumnsMenu::prepareMenu() {
for (int i = 0; i < header_view->count(); i++) {
QAction* act = addAction(header_view->model()->headerData(i, Qt::Horizontal, Qt::EditRole).toString());
act->setData(i);
act->setCheckable(true);
act->setChecked(!header_view->isSectionHidden(i));
connect(act, &QAction::toggled, this, &TreeViewColumnsMenu::actionTriggered);
}
}
void TreeViewColumnsMenu::actionTriggered(bool toggle) {
Q_UNUSED(toggle)
QAction* send_act = qobject_cast<QAction*>(sender());
header()->setSectionHidden(send_act->data().toInt(), !send_act->isChecked());
}

View file

@ -95,19 +95,23 @@ void TreeWidget::filterString(const QString &string) {
QList<QTreeWidgetItem*> _allItems = allItems();
QList<QTreeWidgetItem*> parents;
bool stringIsEmpty = string.isEmpty();
foreach (QTreeWidgetItem* item, _allItems) {
bool containsString = stringIsEmpty || item->text(0).contains(string, Qt::CaseInsensitive);
if (containsString) {
item->setHidden(false);
if (item->parent()) {
if (!parents.contains(item->parent())) {
parents << item->parent();
}
}
}
else {
item->setHidden(true);
if (item->parent()) {
item->parent()->setHidden(true);
}
@ -121,6 +125,7 @@ void TreeWidget::filterString(const QString &string) {
if (stringIsEmpty) {
parentItem->setExpanded(m_showMode == ItemsExpanded);
}
else {
parentItem->setExpanded(true);
}
@ -161,6 +166,7 @@ bool TreeWidget::appendToParentItem(QTreeWidgetItem *parent, QTreeWidgetItem *it
bool TreeWidget::prependToParentItem(const QString& parentText, QTreeWidgetItem* item) {
QList<QTreeWidgetItem*> list = findItems(parentText, Qt::MatchExactly);
if (list.count() == 0) {
return false;
}

View file

@ -30,8 +30,12 @@ class TreeWidget : public QTreeWidget {
enum ItemShowMode { ItemsCollapsed = 0, ItemsExpanded = 1 };
ItemShowMode defaultItemShowMode() { return m_showMode; }
void setDefaultItemShowMode(ItemShowMode mode) { m_showMode = mode; }
ItemShowMode defaultItemShowMode() {
return m_showMode;
}
void setDefaultItemShowMode(ItemShowMode mode) {
m_showMode = mode;
}
QList<QTreeWidgetItem*> allItems();
bool appendToParentItem(const QString& parentText, QTreeWidgetItem* item);

View file

@ -36,19 +36,15 @@
void WebBrowser::createConnections() {
connect(m_webView, &WebViewer::messageStatusChangeRequested, this, &WebBrowser::receiveMessageStatusChangeRequest);
connect(m_txtLocation, &LocationLineEdit::submitted,
this, static_cast<void (WebBrowser::*)(const QString&)>(&WebBrowser::loadUrl));
connect(m_webView, &WebViewer::urlChanged, this, &WebBrowser::updateUrl);
// Change location textbox status according to webpage status.
connect(m_webView, &WebViewer::loadStarted, this, &WebBrowser::onLoadingStarted);
connect(m_webView, &WebViewer::loadProgress, this, &WebBrowser::onLoadingProgress);
connect(m_webView, &WebViewer::loadFinished, this, &WebBrowser::onLoadingFinished);
// Forward title/icon changes.
connect(m_webView, &WebViewer::titleChanged, this, &WebBrowser::onTitleChanged);
#if QT_VERSION >= 0x050700
connect(m_webView, &WebViewer::iconChanged, this, &WebBrowser::onIconChanged);
#endif
@ -56,7 +52,6 @@ void WebBrowser::createConnections() {
void WebBrowser::updateUrl(const QUrl& url) {
QString url_string = url.toString();
m_txtLocation->setText(url_string);
//setNavigationBarVisible(url_string != INTERNAL_URL_EMPTY && url_string != INTERNAL_URL_NEWSPAPER);
}
@ -77,14 +72,11 @@ WebBrowser::WebBrowser(QWidget *parent) : TabContent(parent),
m_actionForward(m_webView->pageAction(QWebEnginePage::Forward)),
m_actionReload(m_webView->pageAction(QWebEnginePage::Reload)),
m_actionStop(m_webView->pageAction(QWebEnginePage::Stop)) {
// Initialize the components and layout.
initializeLayout();
setFocusProxy(m_txtLocation);
setTabOrder(m_txtLocation, m_toolBar);
setTabOrder(m_toolBar, m_webView);
createConnections();
reloadFontSettings();
}
@ -98,7 +90,6 @@ void WebBrowser::reloadFontSettings() {
QFont fon;
fon.fromString(qApp->settings()->value(GROUP(Messages),
SETTING(Messages::PreviewerFontStandard)).toString());
QWebEngineSettings::globalSettings()->setFontFamily(QWebEngineSettings::StandardFont, fon.family());
QWebEngineSettings::globalSettings()->setFontSize(QWebEngineSettings::DefaultFontSize, fon.pointSize());
}
@ -167,6 +158,7 @@ void WebBrowser::onTitleChanged(const QString &new_title) {
//: Webbrowser tab title when no title is available.
emit titleChanged(m_index, tr("No title"));
}
else {
emit titleChanged(m_index, new_title);
}
@ -182,7 +174,6 @@ void WebBrowser::initializeLayout() {
m_toolBar->setFloatable(false);
m_toolBar->setMovable(false);
m_toolBar->setAllowedAreas(Qt::TopToolBarArea);
// Modify action texts.
m_actionBack->setText(tr("Back"));
m_actionBack->setToolTip(tr("Go back."));
@ -192,11 +183,8 @@ void WebBrowser::initializeLayout() {
m_actionReload->setToolTip(tr("Reload current web page."));
m_actionStop->setText(tr("Stop"));
m_actionStop->setToolTip(tr("Stop web page loading."));
QWidgetAction* act_discover = new QWidgetAction(this);
act_discover->setDefaultWidget(m_btnDiscoverFeeds);
// Add needed actions into toolbar.
m_toolBar->addAction(m_actionBack);
m_toolBar->addAction(m_actionForward);
@ -204,14 +192,12 @@ void WebBrowser::initializeLayout() {
m_toolBar->addAction(m_actionStop);
m_toolBar->addAction(act_discover);
m_toolBar->addWidget(m_txtLocation);
m_loadingProgress = new QProgressBar(this);
m_loadingProgress->setFixedHeight(5);
m_loadingProgress->setMinimum(0);
m_loadingProgress->setTextVisible(false);
m_loadingProgress->setMaximum(100);
m_loadingProgress->setAttribute(Qt::WA_TranslucentBackground);
// Setup layout.
m_layout->addWidget(m_toolBar);
m_layout->addWidget(m_webView);
@ -237,6 +223,7 @@ void WebBrowser::onLoadingFinished(bool success) {
this->m_btnDiscoverFeeds->setFeedAddresses(NetworkFactory::extractFeedLinksFromHtmlPage(m_webView->url(), result));
});
}
else {
m_btnDiscoverFeeds->clearFeedAddresses();
}
@ -258,7 +245,6 @@ void WebBrowser::markMessageAsRead(int id, bool read) {
m_root->getParentServiceRoot()->onAfterSetMessagesRead(m_root.data(),
QList<Message>() << *msg,
read ? RootItem::Read : RootItem::Unread);
emit markMessageRead(msg->m_id, read ? RootItem::Read : RootItem::Unread);
msg->m_isRead = read ? RootItem::Read : RootItem::Unread;
}
@ -276,13 +262,11 @@ void WebBrowser::switchMessageImportance(int id, bool checked) {
RootItem::Important))) {
DatabaseQueries::switchMessagesImportance(qApp->database()->connection(objectName(), DatabaseFactory::FromSettings),
QStringList() << QString::number(msg->m_id));
m_root->getParentServiceRoot()->onAfterSwitchMessageImportance(m_root.data(),
QList<ImportanceChange>() << ImportanceChange(*msg,
msg->m_isImportant ?
RootItem::NotImportant :
RootItem::Important));
emit markMessageImportant(msg->m_id, msg->m_isImportant ? RootItem::NotImportant : RootItem::Important);
msg->m_isImportant = checked;
}

View file

@ -31,7 +31,6 @@
WebViewer::WebViewer(QWidget* parent) : QWebEngineView(parent) {
WebPage* page = new WebPage(this);
connect(page, &WebPage::messageStatusChangeRequested, this, &WebViewer::messageStatusChangeRequested);
setPage(page);
}
@ -57,6 +56,7 @@ bool WebViewer::increaseWebPageZoom() {
setZoomFactor(zoomFactor() + ZOOM_FACTOR_STEP);
return true;
}
else {
return false;
}
@ -67,6 +67,7 @@ bool WebViewer::decreaseWebPageZoom() {
setZoomFactor(zoomFactor() - ZOOM_FACTOR_STEP);
return true;
}
else {
return false;
}
@ -79,6 +80,7 @@ bool WebViewer::resetWebPageZoom() {
setZoomFactor(new_factor);
return true;
}
else {
return false;
}
@ -123,7 +125,6 @@ void WebViewer::loadMessages(const QList<Message> &messages) {
m_messageContents = skin.m_layoutMarkupWrapper.arg(messages.size() == 1 ? messages.at(0).m_title : tr("Newspaper view"),
messages_layout);
bool previously_enabled = isEnabled();
setEnabled(false);
displayMessage();
setEnabled(previously_enabled);
@ -135,7 +136,6 @@ void WebViewer::loadMessage(const Message &message) {
void WebViewer::clear() {
bool previously_enabled = isEnabled();
setEnabled(false);
setHtml("<!DOCTYPE html><html><body</body></html>", QUrl(INTERNAL_URL_BLANK));
setEnabled(previously_enabled);
@ -143,11 +143,8 @@ void WebViewer::clear() {
void WebViewer::contextMenuEvent(QContextMenuEvent* event) {
event->accept();
QMenu* menu = page()->createStandardContextMenu();
menu->addAction(qApp->mainForm()->adblockIcon()->menuAction());
const QPoint pos = event->globalPos();
QPoint p(pos.x(), pos.y() + 1);
menu->popup(p);
@ -155,12 +152,12 @@ void WebViewer::contextMenuEvent(QContextMenuEvent *event) {
QWebEngineView* WebViewer::createWindow(QWebEnginePage::WebWindowType type) {
Q_UNUSED(type)
int index = qApp->mainForm()->tabWidget()->addBrowser(false, false);
if (index >= 0) {
return qApp->mainForm()->tabWidget()->widget(index)->webBrowser()->viewer();
}
else {
return nullptr;
}
@ -173,6 +170,7 @@ void WebViewer::wheelEvent(QWheelEvent *event) {
if (event->delta() > 0) {
increaseWebPageZoom();
}
else if (event->delta() < 0) {
decreaseWebPageZoom();
}

View file

@ -28,16 +28,13 @@ WidgetWithStatus::WidgetWithStatus(QWidget *parent)
m_layout = new QHBoxLayout(this);
m_btnStatus = new PlainToolButton(this);
m_btnStatus->setFocusPolicy(Qt::NoFocus);
m_iconProgress = qApp->icons()->fromTheme(QSL("view-refresh"));
m_iconInformation = qApp->icons()->fromTheme(QSL("dialog-information"));
m_iconWarning = qApp->icons()->fromTheme(QSL("dialog-warning"));
m_iconError = qApp->icons()->fromTheme(QSL("dialog-error"));
m_iconOk = qApp->icons()->fromTheme(QSL("dialog-yes"));
// Set layout properties.
m_layout->setMargin(0);
setLayout(m_layout);
setStatus(Information, QString());
}

View file

@ -49,7 +49,6 @@ int main(int argc, char *argv[]) {
qDebug("Usage: rssguard [OPTIONS]\n\n"
"Option\t\tMeaning\n"
"-h\t\tDisplays this help.");
return EXIT_SUCCESS;
}
}
@ -60,13 +59,10 @@ int main(int argc, char *argv[]) {
QObject::tr("LANG_ABBREV");
//: Name of translator - optional.
QObject::tr("LANG_AUTHOR");
// Ensure that ini format is used as application settings storage on Mac OS.
QSettings::setDefaultFormat(QSettings::IniFormat);
// Setup debug output system.
qInstallMessageHandler(Debugging::debugHandler);
// Instantiate base application object.
Application application(APP_LOW_NAME, argc, argv);
qDebug("Instantiated Application class.");
@ -79,49 +75,37 @@ int main(int argc, char *argv[]) {
// Load localization and setup locale before any widget is constructed.
qApp->localization()->loadActiveLanguage();
application.setFeedReader(new FeedReader(&application));
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#ifdef Q_OS_MAC
QApplication::setAttribute(Qt::AA_DontShowIconsInMenus);
disableWindowTabbing();
#endif
// Register needed metatypes.
qRegisterMetaType<QList<Message>>("QList<Message>");
qRegisterMetaType<QList<RootItem*>>("QList<RootItem*>");
// Just call this instance, so that is is created in main GUI thread.
WebFactory::instance();
// Add an extra path for non-system icon themes and set current icon theme
// and skin.
qApp->icons()->setupSearchPaths();
qApp->icons()->loadCurrentIconTheme();
qApp->skins()->loadCurrentSkin();
// These settings needs to be set before any QSettings object.
Application::setApplicationName(APP_NAME);
Application::setApplicationVersion(APP_VERSION);
Application::setOrganizationDomain(APP_URL);
Application::setWindowIcon(QIcon(APP_ICON_PATH));
// Load activated accounts.
qApp->feedReader()->feedsModel()->loadActivatedServiceAccounts();
// Setup single-instance behavior.
QObject::connect(&application, &Application::messageReceived, &application, &Application::processExecutionMessage);
qDebug().nospace() << "Creating main application form in thread: \'" << QThread::currentThreadId() << "\'.";
// Instantiate main application window.
FormMain main_window;
// Set correct information for main window.
main_window.setWindowTitle(APP_LONG_NAME);
// Now is a good time to initialize dynamic keyboard shortcuts.
DynamicShortcuts::load(qApp->userActions());
@ -130,6 +114,7 @@ int main(int argc, char *argv[]) {
qDebug("Hiding the main window when the application is starting.");
main_window.switchVisibility(true);
}
else {
qDebug("Showing the main window when the application is starting.");
main_window.show();
@ -145,6 +130,7 @@ int main(int argc, char *argv[]) {
"version by clicking this popup notification.").arg(APP_LONG_NAME),
QSystemTrayIcon::NoIcon, 0, false, &main_window, SLOT(showAbout()));
}
else {
qApp->showGuiMessage(QSL(APP_NAME), QObject::tr("Welcome to %1.").arg(APP_NAME), QSystemTrayIcon::NoIcon);
}
@ -154,7 +140,6 @@ int main(int argc, char *argv[]) {
}
qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->loadAllExpandStates();
// Enter global event loop.
return Application::exec();
}

View file

@ -59,12 +59,9 @@ Application::Application(const QString &id, int &argc, char **argv)
connect(this, &Application::aboutToQuit, this, &Application::onAboutToQuit);
connect(this, &Application::commitDataRequest, this, &Application::onCommitData);
connect(this, &Application::saveStateRequest, this, &Application::onSaveState);
#if defined(USE_WEBENGINE)
connect(QWebEngineProfile::defaultProfile(), &QWebEngineProfile::downloadRequested, this, &Application::downloadRequested);
QWebEngineProfile::defaultProfile()->setRequestInterceptor(m_urlInterceptor);
// TODO: Teď tam žádný nastavení není, ale jestli se DNT třeba
// přidá do dialogu nastavení, tak toto volat při ukládání nastavení.
m_urlInterceptor->loadSettings();
@ -96,6 +93,7 @@ bool Application::isFirstRun(const QString &version) {
// Check this only if checked version is equal to actual version.
return settings()->value(GROUP(General), QString(General::FirstRun) + QL1C('_') + version, true).toBool();
}
else {
return false;
}
@ -143,7 +141,6 @@ void Application::eliminateFirstRun(const QString &version) {
void Application::setFeedReader(FeedReader* feed_reader) {
m_feedReader = feed_reader;
connect(m_feedReader, &FeedReader::feedUpdatesStarted, this, &Application::onFeedUpdatesStarted);
connect(m_feedReader, &FeedReader::feedUpdatesProgress, this, &Application::onFeedUpdatesProgress);
connect(m_feedReader, &FeedReader::feedUpdatesFinished, this, &Application::onFeedUpdatesFinished);
@ -160,7 +157,6 @@ IconFactory *Application::icons() {
DownloadManager* Application::downloadManager() {
if (m_downloadManager == nullptr) {
m_downloadManager = new DownloadManager();
connect(m_downloadManager, &DownloadManager::downloadFinished, mainForm()->statusBar(), &StatusBar::clearProgressDownload);
connect(m_downloadManager, &DownloadManager::downloadProgressed, mainForm()->statusBar(), &StatusBar::showProgressDownload);
}
@ -212,6 +208,7 @@ QString Application::getUserDataPath() {
if (settings()->type() == SettingsProperties::Portable) {
return getUserDataAppPath();
}
else {
return getUserDataHomePath();
}
@ -224,6 +221,7 @@ QString Application::getUserDataHomePath() {
if (QDir().exists(home_folder)) {
return home_folder;
}
else {
return getConfigHomePath() + QDir::separator() + QSL(APP_NAME);
}
@ -284,18 +282,19 @@ void Application::restoreDatabaseSettings(bool restore_database, bool restore_se
void Application::processExecutionMessage(const QString& message) {
qDebug("Received '%s' execution message from another application instance.", qPrintable(message));
const QStringList messages = message.split(ARGUMENTS_LIST_SEPARATOR);
if (messages.contains(APP_QUIT_INSTANCE)) {
quit();
}
else {
foreach (const QString& msg, messages) {
if (msg == APP_IS_RUNNING) {
showGuiMessage(APP_NAME, tr("Application is already running."), QSystemTrayIcon::Information);
mainForm()->display();
}
else if (msg.startsWith(QL1S(URI_SCHEME_FEED_SHORT))) {
// Application was running, and someone wants to add new feed.
StandardServiceRoot* root = qApp->feedReader()->feedsModel()->standardServiceRoot();
@ -303,6 +302,7 @@ void Application::processExecutionMessage(const QString &message) {
if (root != nullptr) {
root->checkArgumentForFeedAdding(msg);
}
else {
showGuiMessage(tr("Cannot add feed"),
tr("Feed cannot be added because standard RSS/ATOM account is not enabled."),
@ -341,7 +341,6 @@ void Application::deleteTrayIcon() {
m_mainForm->display();
delete m_trayIcon;
m_trayIcon = nullptr;
// Make sure that application quits when last window is closed.
setQuitOnLastWindowClosed(true);
}
@ -354,10 +353,12 @@ void Application::showGuiMessage(const QString &title, const QString &message,
if (SystemTrayIcon::areNotificationsEnabled() && SystemTrayIcon::isSystemTrayActivated()) {
trayIcon()->showMessage(title, message, message_type, TRAY_ICON_BUBBLE_TIMEOUT, invokation_target, invokation_slot);
}
else if (show_at_least_msgbox) {
// Tray icon or OSD is not available, display simple text box.
MessageBox::show(parent, (QMessageBox::Icon) message_type, title, message);
}
else {
qDebug("Silencing GUI message: '%s'.", qPrintable(message));
}
@ -365,14 +366,12 @@ void Application::showGuiMessage(const QString &title, const QString &message,
void Application::onCommitData(QSessionManager& manager) {
qDebug("OS asked application to commit its data.");
manager.setRestartHint(QSessionManager::RestartNever);
manager.release();
}
void Application::onSaveState(QSessionManager& manager) {
qDebug("OS asked application to save its state.");
manager.setRestartHint(QSessionManager::RestartNever);
manager.release();
}
@ -380,22 +379,16 @@ void Application::onSaveState(QSessionManager &manager) {
void Application::onAboutToQuit() {
eliminateFirstRun();
eliminateFirstRun(APP_VERSION);
#if defined(USE_WEBENGINE)
AdBlockManager::instance()->save();
#endif
// Make sure that we obtain close lock BEFORE even trying to quit the application.
const bool locked_safely = feedUpdateLock()->tryLock(4 * CLOSE_LOCK_TIMEOUT);
processEvents();
qDebug("Cleaning up resources and saving application state.");
#if defined(Q_OS_WIN)
system()->removeTrolltechJunkRegistryKeys();
#endif
qApp->feedReader()->quit();
database()->saveDatabase();
@ -406,10 +399,10 @@ void Application::onAboutToQuit() {
if (locked_safely) {
// Application obtained permission to close in a safe way.
qDebug("Close lock was obtained safely.");
// We locked the lock to exit peacefully, unlock it to avoid warnings.
feedUpdateLock()->unlock();
}
else {
// Request for write lock timed-out. This means
// that some critical action can be processed right now.
@ -426,6 +419,7 @@ void Application::onAboutToQuit() {
if (QProcess::startDetached(QString("\"") + QDir::toNativeSeparators(applicationFilePath()) + QString("\""))) {
qDebug("New application instance was started.");
}
else {
qWarning("New application instance was not started successfully.");
}

View file

@ -47,6 +47,7 @@ void AutoSaver::changeOccurred() {
if (m_firstChange.elapsed() > MAXWAIT) {
saveIfNeccessary();
}
else {
m_timer.start(AUTOSAVE_IN, this);
}
@ -56,6 +57,7 @@ void AutoSaver::timerEvent(QTimerEvent *event) {
if (event->timerId() == m_timer.timerId()) {
saveIfNeccessary();
}
else {
QObject::timerEvent(event);
}

View file

@ -32,10 +32,8 @@ DatabaseCleaner::~DatabaseCleaner() {
void DatabaseCleaner::purgeDatabaseData(const CleanerOrders& which_data) {
qDebug().nospace() << "Performing database cleanup in thread: \'" << QThread::currentThreadId() << "\'.";
// Inform everyone about the start of the process.
emit purgeStarted();
bool result = true;
const int difference = 99 / 8;
int progress = 0;
@ -44,10 +42,8 @@ void DatabaseCleaner::purgeDatabaseData(const CleanerOrders &which_data) {
if (which_data.m_removeReadMessages) {
progress += difference;
emit purgeProgress(progress, tr("Removing read messages..."));
// Remove read messages.
result &= purgeReadMessages(database);
progress += difference;
emit purgeProgress(progress, tr("Read messages purged..."));
}
@ -55,10 +51,8 @@ void DatabaseCleaner::purgeDatabaseData(const CleanerOrders &which_data) {
if (which_data.m_removeRecycleBin) {
progress += difference;
emit purgeProgress(progress, tr("Purging recycle bin..."));
// Remove read messages.
result &= purgeRecycleBin(database);
progress += difference;
emit purgeProgress(progress, tr("Recycle bin purged..."));
}
@ -66,10 +60,8 @@ void DatabaseCleaner::purgeDatabaseData(const CleanerOrders &which_data) {
if (which_data.m_removeOldMessages) {
progress += difference;
emit purgeProgress(progress, tr("Removing old messages..."));
// Remove old messages.
result &= purgeOldMessages(database, which_data.m_barrierForRemovingOldMessagesInDays);
progress += difference;
emit purgeProgress(progress, tr("Old messages purged..."));
}
@ -77,10 +69,8 @@ void DatabaseCleaner::purgeDatabaseData(const CleanerOrders &which_data) {
if (which_data.m_shrinkDatabase) {
progress += difference;
emit purgeProgress(progress, tr("Shrinking database file..."));
// Call driver-specific vacuuming function.
result &= qApp->database()->vacuumDatabase();
progress += difference;
emit purgeProgress(progress, tr("Database file shrinked..."));
}

View file

@ -44,6 +44,7 @@ qint64 DatabaseFactory::getDatabaseFileSize() const {
if (m_activeDatabaseDriver == SQLITE || m_activeDatabaseDriver == SQLITE_MEMORY) {
return QFileInfo(sqliteDatabaseFilePath()).size();
}
else {
return 0;
}
@ -59,6 +60,7 @@ qint64 DatabaseFactory::getDatabaseDataSize() const {
query.next();
result *= query.value(0).value<qint64>();
}
else {
return 0;
}
@ -67,12 +69,14 @@ qint64 DatabaseFactory::getDatabaseDataSize() const {
query.next();
result *= query.value(0).value<qint64>();
}
else {
return 0;
}
return result;
}
else if (m_activeDatabaseDriver == MYSQL) {
QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings);
qint64 result = 1;
@ -87,10 +91,12 @@ qint64 DatabaseFactory::getDatabaseDataSize() const {
return result;
}
else {
return 0;
}
}
else {
return 0;
}
@ -99,7 +105,6 @@ qint64 DatabaseFactory::getDatabaseDataSize() const {
DatabaseFactory::MySQLError DatabaseFactory::mysqlTestConnection(const QString& hostname, int port, const QString& w_database,
const QString& username, const QString& password) {
QSqlDatabase database = QSqlDatabase::addDatabase(APP_DB_MYSQL_DRIVER, APP_DB_MYSQL_TEST);
database.setHostName(hostname);
database.setPort(port);
database.setUserName(username);
@ -111,20 +116,22 @@ DatabaseFactory::MySQLError DatabaseFactory::mysqlTestConnection(const QString &
if (!query.lastError().isValid() && query.next()) {
qDebug("Checked MySQL database, version is '%s'.", qPrintable(query.value(0).toString()));
// Connection succeeded, clean up the mess and return OK status.
database.close();
return MySQLOk;
}
else {
database.close();
return MySQLUnknownError;
}
}
else if (database.lastError().isValid()) {
// Connection failed, do cleanup and return specific error code.
return static_cast<MySQLError>(database.lastError().number());
}
else {
return MySQLUnknownError;
}
@ -180,6 +187,7 @@ void DatabaseFactory::finishRestoration() {
QFile::remove(backup_database_file);
qDebug("Database file was restored successully.");
}
else {
qCritical("Database file was NOT restored due to error when copying the file.");
}
@ -192,15 +200,14 @@ void DatabaseFactory::sqliteAssemblyDatabaseFilePath() {
QSqlDatabase DatabaseFactory::sqliteInitializeInMemoryDatabase() {
QSqlDatabase database = QSqlDatabase::addDatabase(APP_DB_SQLITE_DRIVER);
database.setDatabaseName(QSL(":memory:"));
if (!database.open()) {
qFatal("In-memory SQLite database was NOT opened. Delivered error message: '%s'", qPrintable(database.lastError().text()));
}
else {
QSqlQuery query_db(database);
query_db.setForwardOnly(true);
query_db.exec(QSL("PRAGMA encoding = \"UTF-8\""));
query_db.exec(QSL("PRAGMA synchronous = OFF"));
@ -209,13 +216,11 @@ QSqlDatabase DatabaseFactory::sqliteInitializeInMemoryDatabase() {
query_db.exec(QSL("PRAGMA cache_size = 16384"));
query_db.exec(QSL("PRAGMA count_changes = OFF"));
query_db.exec(QSL("PRAGMA temp_store = MEMORY"));
// Sample query which checks for existence of tables.
query_db.exec(QSL("SELECT inf_value FROM Information WHERE inf_key = 'schema_version'"));
if (query_db.lastError().isValid()) {
qWarning("Error occurred. In-memory SQLite database is not initialized. Initializing now.");
QFile file_init(APP_SQL_PATH + QDir::separator() + APP_DB_SQLITE_INIT);
if (!file_init.open(QIODevice::ReadOnly | QIODevice::Text)) {
@ -239,9 +244,9 @@ QSqlDatabase DatabaseFactory::sqliteInitializeInMemoryDatabase() {
database.commit();
qDebug("In-memory SQLite database backend should be ready now.");
}
else {
query_db.next();
qDebug("In-memory SQLite database connection seems to be established.");
qDebug("In-memory SQLite database has version '%s'.", qPrintable(query_db.value(0).toString()));
}
@ -249,10 +254,8 @@ QSqlDatabase DatabaseFactory::sqliteInitializeInMemoryDatabase() {
// Loading messages from file-based database.
QSqlDatabase file_database = sqliteConnection(objectName(), StrictlyFileBased);
QSqlQuery copy_contents(database);
// Attach database.
copy_contents.exec(QString("ATTACH DATABASE '%1' AS 'storage';").arg(file_database.databaseName()));
// Copy all stuff.
// WARNING: All tables belong here.
QStringList tables;
@ -262,6 +265,7 @@ QSqlDatabase DatabaseFactory::sqliteInitializeInMemoryDatabase() {
tables.append(copy_contents.value(0).toString());
}
}
else {
qFatal("Cannot obtain list of table names from file-base SQLite database.");
}
@ -271,23 +275,19 @@ QSqlDatabase DatabaseFactory::sqliteInitializeInMemoryDatabase() {
}
qDebug("Copying data from file-based database into working in-memory database.");
// Detach database and finish.
copy_contents.exec(QSL("DETACH 'storage'"));
copy_contents.finish();
query_db.finish();
}
// Everything is initialized now.
m_sqliteInMemoryDatabaseInitialized = true;
return database;
}
QSqlDatabase DatabaseFactory::sqliteInitializeFileBasedDatabase(const QString& connection_name) {
finishRestoration();
// Prepare file paths.
const QDir db_path(m_sqliteDatabaseFilePath);
QFile db_file(db_path.absoluteFilePath(APP_DB_SQLITE_FILE));
@ -305,7 +305,6 @@ QSqlDatabase DatabaseFactory::sqliteInitializeFileBasedDatabase(const QString &c
// Folders are created. Create new QSQLDatabase object.
QSqlDatabase database;
database = QSqlDatabase::addDatabase(APP_DB_SQLITE_DRIVER, connection_name);
database.setDatabaseName(db_file.fileName());
@ -313,9 +312,9 @@ QSqlDatabase DatabaseFactory::sqliteInitializeFileBasedDatabase(const QString &c
qFatal("File-based SQLite database was NOT opened. Delivered error message: '%s'",
qPrintable(database.lastError().text()));
}
else {
QSqlQuery query_db(database);
query_db.setForwardOnly(true);
query_db.exec(QSL("PRAGMA encoding = \"UTF-8\""));
query_db.exec(QSL("PRAGMA synchronous = OFF"));
@ -328,7 +327,6 @@ QSqlDatabase DatabaseFactory::sqliteInitializeFileBasedDatabase(const QString &c
// Sample query which checks for existence of tables.
if (!query_db.exec(QSL("SELECT inf_value FROM Information WHERE inf_key = 'schema_version'"))) {
qWarning("Error occurred. File-based SQLite database is not initialized. Initializing now.");
QFile file_init(APP_SQL_PATH + QDir::separator() + APP_DB_SQLITE_INIT);
if (!file_init.open(QIODevice::ReadOnly | QIODevice::Text)) {
@ -354,6 +352,7 @@ QSqlDatabase DatabaseFactory::sqliteInitializeFileBasedDatabase(const QString &c
query_db.finish();
qDebug("File-based SQLite database backend should be ready now.");
}
else {
query_db.next();
const QString installed_db_schema = query_db.value(0).toString();
@ -365,6 +364,7 @@ QSqlDatabase DatabaseFactory::sqliteInitializeFileBasedDatabase(const QString &c
qPrintable(installed_db_schema),
APP_DB_SCHEMA_VERSION);
}
else {
qFatal("Database schema was not updated from '%s' to '%s' successully.",
qPrintable(installed_db_schema),
@ -381,7 +381,6 @@ QSqlDatabase DatabaseFactory::sqliteInitializeFileBasedDatabase(const QString &c
// Everything is initialized now.
m_sqliteFileBasedDatabaseinitialized = true;
return database;
}
@ -397,6 +396,7 @@ bool DatabaseFactory::sqliteUpdateDatabaseSchema(QSqlDatabase database, const QS
if (IOFactory::copyFile(sqliteDatabaseFilePath(), sqliteDatabaseFilePath() + ".bak")) {
qDebug("Creating backup of SQLite DB file.");
}
else {
qFatal("Creation of backup SQLite DB file failed.");
}
@ -501,9 +501,11 @@ QString DatabaseFactory::humanDriverName(const QString &driver_code) const {
if (driver_code == APP_DB_SQLITE_DRIVER) {
return humanDriverName(SQLITE);
}
else if (driver_code == APP_DB_MYSQL_DRIVER) {
return humanDriverName(MYSQL);
}
else {
return humanDriverName(SQLITE);
}
@ -518,6 +520,7 @@ QString DatabaseFactory::obtainBeginTransactionSql() const {
if (m_activeDatabaseDriver == DatabaseFactory::SQLITE || m_activeDatabaseDriver == DatabaseFactory::SQLITE_MEMORY) {
return QSL("BEGIN IMMEDIATE TRANSACTION;");
}
else {
return QSL("START TRANSACTION;");
}
@ -525,14 +528,11 @@ QString DatabaseFactory::obtainBeginTransactionSql() const {
void DatabaseFactory::sqliteSaveMemoryDatabase() {
qDebug("Saving in-memory working database back to persistent file-based storage.");
QSqlDatabase database = sqliteConnection(objectName(), StrictlyInMemory);
QSqlDatabase file_database = sqliteConnection(objectName(), StrictlyFileBased);
QSqlQuery copy_contents(database);
// Attach database.
copy_contents.exec(QString(QSL("ATTACH DATABASE '%1' AS 'storage';")).arg(file_database.databaseName()));
// Copy all stuff.
// WARNING: All tables belong here.
QStringList tables;
@ -542,6 +542,7 @@ void DatabaseFactory::sqliteSaveMemoryDatabase() {
tables.append(copy_contents.value(0).toString());
}
}
else {
qFatal("Cannot obtain list of table names from file-base SQLite database.");
}
@ -562,22 +563,21 @@ void DatabaseFactory::determineDriver() {
if (db_driver == APP_DB_MYSQL_DRIVER && QSqlDatabase::isDriverAvailable(APP_DB_SQLITE_DRIVER)) {
// User wants to use MySQL and MySQL is actually available. Use it.
m_activeDatabaseDriver = MYSQL;
qDebug("Working database source was as MySQL database.");
}
else {
// User wants to use SQLite, which is always available. Check if file-based
// or in-memory database will be used.
if (qApp->settings()->value(GROUP(Database), SETTING(Database::UseInMemory)).toBool()) {
// Use in-memory SQLite database.
m_activeDatabaseDriver = SQLITE_MEMORY;
qDebug("Working database source was determined as SQLite in-memory database.");
}
else {
// Use strictly file-base SQLite database.
m_activeDatabaseDriver = SQLITE;
qDebug("Working database source was determined as SQLite file-based database.");
}
@ -594,21 +594,21 @@ QSqlDatabase DatabaseFactory::mysqlConnection(const QString &connection_name) {
// Return initialized database.
return mysqlInitializeDatabase(connection_name);
}
else {
QSqlDatabase database;
if (QSqlDatabase::contains(connection_name)) {
qDebug("MySQL connection '%s' is already active.", qPrintable(connection_name));
// This database connection was added previously, no need to
// setup its properties.
database = QSqlDatabase::database(connection_name);
}
else {
// Database connection with this name does not exist
// yet, add it and set it up.
database = QSqlDatabase::addDatabase(APP_DB_MYSQL_DRIVER, connection_name);
database.setHostName(qApp->settings()->value(GROUP(Database), SETTING(Database::MySQLHostname)).toString());
database.setPort(qApp->settings()->value(GROUP(Database), SETTING(Database::MySQLPort)).toInt());
database.setUserName(qApp->settings()->value(GROUP(Database), SETTING(Database::MySQLUsername)).toString());
@ -620,6 +620,7 @@ QSqlDatabase DatabaseFactory::mysqlConnection(const QString &connection_name) {
qFatal("MySQL database was NOT opened. Delivered error message: '%s'.",
qPrintable(database.lastError().text()));
}
else {
qDebug("MySQL database connection '%s' to file '%s' seems to be established.",
qPrintable(connection_name),
@ -634,7 +635,6 @@ QSqlDatabase DatabaseFactory::mysqlInitializeDatabase(const QString &connection_
// Folders are created. Create new QSQLDatabase object.
QSqlDatabase database = QSqlDatabase::addDatabase(APP_DB_MYSQL_DRIVER, connection_name);
const QString database_name = qApp->settings()->value(GROUP(Database), SETTING(Database::MySQLDatabase)).toString();
database.setHostName(qApp->settings()->value(GROUP(Database), SETTING(Database::MySQLHostname)).toString());
database.setPort(qApp->settings()->value(GROUP(Database), SETTING(Database::MySQLPort)).toInt());
database.setUserName(qApp->settings()->value(GROUP(Database), SETTING(Database::MySQLUsername)).toString());
@ -642,7 +642,6 @@ QSqlDatabase DatabaseFactory::mysqlInitializeDatabase(const QString &connection_
if (!database.open()) {
qCritical("MySQL database was NOT opened. Delivered error message: '%s'", qPrintable(database.lastError().text()));
// Now, we will display error warning and return SQLite connection.
// Also, we set the SQLite driver as active one.
qApp->settings()->setValue(GROUP(Database), Database::ActiveDriver, APP_DB_SQLITE_DRIVER);
@ -650,9 +649,9 @@ QSqlDatabase DatabaseFactory::mysqlInitializeDatabase(const QString &connection_
MessageBox::show(nullptr, QMessageBox::Critical, tr("MySQL database not available"),
tr("%1 cannot use MySQL storage, it is not available. %1 is now switching to SQLite database. Start your MySQL server "
"and make adjustments in application settings.").arg(APP_NAME));
return connection(objectName(), FromSettings);
}
else {
QSqlQuery query_db(database);
query_db.setForwardOnly(true);
@ -660,7 +659,6 @@ QSqlDatabase DatabaseFactory::mysqlInitializeDatabase(const QString &connection_
if (!query_db.exec(QString("USE %1").arg(database_name)) || !query_db.exec(QSL("SELECT inf_value FROM Information WHERE inf_key = 'schema_version'"))) {
// If no "rssguard" database exists or schema version is wrong, then initialize it.
qWarning("Error occurred. MySQL database is not initialized. Initializing now.");
QFile file_init(APP_SQL_PATH + QDir::separator() + APP_DB_MYSQL_INIT);
if (!file_init.open(QIODevice::ReadOnly | QIODevice::Text)) {
@ -686,10 +684,10 @@ QSqlDatabase DatabaseFactory::mysqlInitializeDatabase(const QString &connection_
database.commit();
qDebug("MySQL database backend should be ready now.");
}
else {
// Database was previously initialized. Now just check the schema version.
query_db.next();
const QString installed_db_schema = query_db.value(0).toString();
if (installed_db_schema < APP_DB_SCHEMA_VERSION) {
@ -697,8 +695,8 @@ QSqlDatabase DatabaseFactory::mysqlInitializeDatabase(const QString &connection_
qDebug("Database schema was updated from '%s' to '%s' successully or it is already up to date.",
qPrintable(installed_db_schema),
APP_DB_SCHEMA_VERSION);
}
else {
qFatal("Database schema was not updated from '%s' to '%s' successully.",
qPrintable(installed_db_schema),
@ -712,14 +710,12 @@ QSqlDatabase DatabaseFactory::mysqlInitializeDatabase(const QString &connection_
// Everything is initialized now.
m_mysqlDatabaseInitialized = true;
return database;
}
bool DatabaseFactory::mysqlVacuumDatabase() {
QSqlDatabase database = mysqlConnection(objectName());
QSqlQuery query_vacuum(database);
return query_vacuum.exec(QSL("OPTIMIZE TABLE rssguard.feeds;")) && query_vacuum.exec(QSL("OPTIMIZE TABLE rssguard.messages;"));
}
@ -732,15 +728,16 @@ QSqlDatabase DatabaseFactory::sqliteConnection(const QString &connection_name, D
// It is not initialized yet.
return sqliteInitializeInMemoryDatabase();
}
else {
QSqlDatabase database = QSqlDatabase::database();
database.setDatabaseName(QSL(":memory:"));
if (!database.isOpen() && !database.open()) {
qFatal("In-memory SQLite database was NOT opened. Delivered error message: '%s'.",
qPrintable(database.lastError().text()));
}
else {
qDebug("In-memory SQLite database connection seems to be established.");
}
@ -748,30 +745,30 @@ QSqlDatabase DatabaseFactory::sqliteConnection(const QString &connection_name, D
return database;
}
}
else {
// We request file-based database.
if (!m_sqliteFileBasedDatabaseinitialized) {
// File-based database is not yet initialised.
return sqliteInitializeFileBasedDatabase(connection_name);
}
else {
QSqlDatabase database;
if (QSqlDatabase::contains(connection_name)) {
qDebug("SQLite connection '%s' is already active.", qPrintable(connection_name));
// This database connection was added previously, no need to
// setup its properties.
database = QSqlDatabase::database(connection_name);
}
else {
// Database connection with this name does not exist
// yet, add it and set it up.
database = QSqlDatabase::addDatabase(APP_DB_SQLITE_DRIVER, connection_name);
const QDir db_path(m_sqliteDatabaseFilePath);
QFile db_file(db_path.absoluteFilePath(APP_DB_SQLITE_FILE));
// Setup database file path.
database.setDatabaseName(db_file.fileName());
}
@ -780,6 +777,7 @@ QSqlDatabase DatabaseFactory::sqliteConnection(const QString &connection_name, D
qFatal("File-based SQLite database was NOT opened. Delivered error message: '%s'.",
qPrintable(database.lastError().text()));
}
else {
qDebug("File-based SQLite database connection '%s' to file '%s' seems to be established.",
qPrintable(connection_name),
@ -797,16 +795,17 @@ bool DatabaseFactory::sqliteVacuumDatabase() {
if (m_activeDatabaseDriver == SQLITE) {
database = sqliteConnection(objectName(), StrictlyFileBased);
}
else if (m_activeDatabaseDriver == SQLITE_MEMORY) {
sqliteSaveMemoryDatabase();
database = sqliteConnection(objectName(), StrictlyFileBased);
}
else {
return false;
}
QSqlQuery query_vacuum(database);
return query_vacuum.exec(QSL("VACUUM"));
}

View file

@ -41,7 +41,6 @@
bool DatabaseQueries::markMessagesReadUnread(QSqlDatabase db, const QStringList& ids, RootItem::ReadStatus read) {
QSqlQuery q(db);
q.setForwardOnly(true);
return q.exec(QString(QSL("UPDATE Messages SET is_read = %2 WHERE id IN (%1);"))
.arg(ids.join(QSL(", ")), read == RootItem::Read ? QSL("1") : QSL("0")));
}
@ -57,7 +56,6 @@ bool DatabaseQueries::markMessageImportant(QSqlDatabase db, int id, RootItem::Im
q.bindValue(QSL(":id"), id);
q.bindValue(QSL(":important"), (int) importance);
// Commit changes.
return q.exec();
}
@ -67,10 +65,8 @@ bool DatabaseQueries::markFeedsReadUnread(QSqlDatabase db, const QStringList &id
q.setForwardOnly(true);
q.prepare(QString("UPDATE Messages SET is_read = :read "
"WHERE feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0 AND account_id = :account_id;").arg(ids.join(QSL(", "))));
q.bindValue(QSL(":read"), read == RootItem::Read ? 1 : 0);
q.bindValue(QSL(":account_id"), account_id);
return q.exec();
}
@ -79,10 +75,8 @@ bool DatabaseQueries::markBinReadUnread(QSqlDatabase db, int account_id, RootIte
q.setForwardOnly(true);
q.prepare("UPDATE Messages SET is_read = :read "
"WHERE is_deleted = 1 AND is_pdeleted = 0 AND account_id = :account_id;");
q.bindValue(QSL(":read"), read == RootItem::Read ? 1 : 0);
q.bindValue(QSL(":account_id"), account_id);
return q.exec();
}
@ -90,31 +84,26 @@ bool DatabaseQueries::markAccountReadUnread(QSqlDatabase db, int account_id, Roo
QSqlQuery q(db);
q.setForwardOnly(true);
q.prepare(QSL("UPDATE Messages SET is_read = :read WHERE is_pdeleted = 0 AND account_id = :account_id;"));
q.bindValue(QSL(":account_id"), account_id);
q.bindValue(QSL(":read"), read == RootItem::Read ? 1 : 0);
return q.exec();
}
bool DatabaseQueries::switchMessagesImportance(QSqlDatabase db, const QStringList& ids) {
QSqlQuery q(db);
q.setForwardOnly(true);
return q.exec(QString(QSL("UPDATE Messages SET is_important = NOT is_important WHERE id IN (%1);")).arg(ids.join(QSL(", "))));
}
bool DatabaseQueries::permanentlyDeleteMessages(QSqlDatabase db, const QStringList& ids) {
QSqlQuery q(db);
q.setForwardOnly(true);
return q.exec(QString(QSL("UPDATE Messages SET is_pdeleted = 1 WHERE id IN (%1);")).arg(ids.join(QSL(", "))));
}
bool DatabaseQueries::deleteOrRestoreMessagesToFromBin(QSqlDatabase db, const QStringList& ids, bool deleted) {
QSqlQuery q(db);
q.setForwardOnly(true);
return q.exec(QString(QSL("UPDATE Messages SET is_deleted = %2, is_pdeleted = %3 WHERE id IN (%1);")).arg(ids.join(QSL(", ")),
QString::number(deleted ? 1 : 0),
QString::number(0)));
@ -126,7 +115,6 @@ bool DatabaseQueries::restoreBin(QSqlDatabase db, int account_id) {
q.prepare("UPDATE Messages SET is_deleted = 0 "
"WHERE is_deleted = 1 AND is_pdeleted = 0 AND account_id = :account_id;");
q.bindValue(QSL(":account_id"), account_id);
return q.exec();
}
@ -134,7 +122,6 @@ bool DatabaseQueries::purgeImportantMessages(QSqlDatabase db) {
QSqlQuery q(db);
q.setForwardOnly(true);
q.prepare(QSL("DELETE FROM Messages WHERE is_important = 1;"));
return q.exec();
}
@ -143,40 +130,31 @@ bool DatabaseQueries::purgeReadMessages(QSqlDatabase db) {
q.setForwardOnly(true);
q.prepare(QSL("DELETE FROM Messages WHERE is_important = :is_important AND is_deleted = :is_deleted AND is_read = :is_read;"));
q.bindValue(QSL(":is_read"), 1);
// Remove only messages which are NOT in recycle bin.
q.bindValue(QSL(":is_deleted"), 0);
// Remove only messages which are NOT starred.
q.bindValue(QSL(":is_important"), 0);
return q.exec();
}
bool DatabaseQueries::purgeOldMessages(QSqlDatabase db, int older_than_days) {
QSqlQuery q(db);
const qint64 since_epoch = QDateTime::currentDateTimeUtc().addDays(-older_than_days).toMSecsSinceEpoch();
q.setForwardOnly(true);
q.prepare(QSL("DELETE FROM Messages WHERE is_important = :is_important AND date_created < :date_created;"));
q.bindValue(QSL(":date_created"), since_epoch);
// Remove only messages which are NOT starred.
q.bindValue(QSL(":is_important"), 0);
return q.exec();
}
bool DatabaseQueries::purgeRecycleBin(QSqlDatabase db) {
QSqlQuery q(db);
q.setForwardOnly(true);
q.prepare(QSL("DELETE FROM Messages WHERE is_important = :is_important AND is_deleted = :is_deleted;"));
q.bindValue(QSL(":is_deleted"), 1);
// Remove only messages which are NOT starred.
q.bindValue(QSL(":is_important"), 0);
return q.exec();
}
@ -191,6 +169,7 @@ QMap<int,QPair<int,int> > DatabaseQueries::getMessageCountsForCategory(QSqlDatab
"WHERE feed IN (SELECT custom_id FROM Feeds WHERE category = :category AND account_id = :account_id) AND is_deleted = 0 AND is_pdeleted = 0 AND account_id = :account_id "
"GROUP BY feed;");
}
else {
q.prepare("SELECT feed, sum((is_read + 1) % 2) FROM Messages "
"WHERE feed IN (SELECT custom_id FROM Feeds WHERE category = :category AND account_id = :account_id) AND is_deleted = 0 AND is_pdeleted = 0 AND account_id = :account_id "
@ -207,9 +186,9 @@ QMap<int,QPair<int,int> > DatabaseQueries::getMessageCountsForCategory(QSqlDatab
if (including_total_counts) {
int total_count = q.value(2).toInt();
counts.insert(feed_id, QPair<int, int>(unread_count, total_count));
}
else {
counts.insert(feed_id, QPair<int, int>(unread_count, 0));
}
@ -219,6 +198,7 @@ QMap<int,QPair<int,int> > DatabaseQueries::getMessageCountsForCategory(QSqlDatab
*ok = true;
}
}
else {
if (ok != nullptr) {
*ok = false;
@ -239,6 +219,7 @@ QMap<int,QPair<int,int> > DatabaseQueries::getMessageCountsForAccount(QSqlDataba
"WHERE is_deleted = 0 AND is_pdeleted = 0 AND account_id = :account_id "
"GROUP BY feed;");
}
else {
q.prepare("SELECT feed, sum((is_read + 1) % 2) FROM Messages "
"WHERE is_deleted = 0 AND is_pdeleted = 0 AND account_id = :account_id "
@ -254,9 +235,9 @@ QMap<int,QPair<int,int> > DatabaseQueries::getMessageCountsForAccount(QSqlDataba
if (including_total_counts) {
int total_count = q.value(2).toInt();
counts.insert(feed_id, QPair<int, int>(unread_count, total_count));
}
else {
counts.insert(feed_id, QPair<int, int>(unread_count, 0));
}
@ -266,6 +247,7 @@ QMap<int,QPair<int,int> > DatabaseQueries::getMessageCountsForAccount(QSqlDataba
*ok = true;
}
}
else {
if (ok != nullptr) {
*ok = false;
@ -284,6 +266,7 @@ int DatabaseQueries::getMessageCountsForFeed(QSqlDatabase db, int feed_custom_id
q.prepare("SELECT count(*) FROM Messages "
"WHERE feed = :feed AND is_deleted = 0 AND is_pdeleted = 0 AND account_id = :account_id;");
}
else {
q.prepare("SELECT count(*) FROM Messages "
"WHERE feed = :feed AND is_deleted = 0 AND is_pdeleted = 0 AND is_read = 0 AND account_id = :account_id;");
@ -299,6 +282,7 @@ int DatabaseQueries::getMessageCountsForFeed(QSqlDatabase db, int feed_custom_id
return q.value(0).toInt();
}
else {
if (ok != nullptr) {
*ok = false;
@ -316,6 +300,7 @@ int DatabaseQueries::getMessageCountsForBin(QSqlDatabase db, int account_id, boo
q.prepare("SELECT count(*) FROM Messages "
"WHERE is_deleted = 1 AND is_pdeleted = 0 AND account_id = :account_id;");
}
else {
q.prepare("SELECT count(*) FROM Messages "
"WHERE is_read = 0 AND is_deleted = 1 AND is_pdeleted = 0 AND account_id = :account_id;");
@ -330,6 +315,7 @@ int DatabaseQueries::getMessageCountsForBin(QSqlDatabase db, int account_id, boo
return q.value(0).toInt();
}
else {
if (ok != nullptr) {
*ok = false;
@ -346,7 +332,6 @@ QList<Message> DatabaseQueries::getUndeletedMessagesForFeed(QSqlDatabase db, int
q.prepare("SELECT * "
"FROM Messages "
"WHERE is_deleted = 0 AND is_pdeleted = 0 AND feed = :feed AND account_id = :account_id;");
q.bindValue(QSL(":feed"), feed_custom_id);
q.bindValue(QSL(":account_id"), account_id);
@ -364,6 +349,7 @@ QList<Message> DatabaseQueries::getUndeletedMessagesForFeed(QSqlDatabase db, int
*ok = true;
}
}
else {
if (ok != nullptr) {
*ok = false;
@ -380,7 +366,6 @@ QList<Message> DatabaseQueries::getUndeletedMessagesForBin(QSqlDatabase db, int
q.prepare("SELECT * "
"FROM Messages "
"WHERE is_deleted = 1 AND is_pdeleted = 0 AND account_id = :account_id;");
q.bindValue(QSL(":account_id"), account_id);
if (q.exec()) {
@ -397,6 +382,7 @@ QList<Message> DatabaseQueries::getUndeletedMessagesForBin(QSqlDatabase db, int
*ok = true;
}
}
else {
if (ok != nullptr) {
*ok = false;
@ -429,6 +415,7 @@ QList<Message> DatabaseQueries::getUndeletedMessagesForAccount(QSqlDatabase db,
*ok = true;
}
}
else {
if (ok != nullptr) {
*ok = false;
@ -452,18 +439,15 @@ int DatabaseQueries::updateMessages(QSqlDatabase db,
}
bool use_transactions = qApp->settings()->value(GROUP(Database), SETTING(Database::UseTransactions)).toBool();
// Does not make any difference, since each feed now has
// its own "custom ID" (standard feeds have their custom ID equal to primary key ID).
int updated_messages = 0;
// Prepare queries.
QSqlQuery query_select_with_url(db);
QSqlQuery query_select_with_id(db);
QSqlQuery query_update(db);
QSqlQuery query_insert(db);
QSqlQuery query_begin_transaction(db);
// Here we have query which will check for existence of the "same" message in given feed.
// The two message are the "same" if:
// 1) they belong to the same feed AND,
@ -472,19 +456,16 @@ int DatabaseQueries::updateMessages(QSqlDatabase db,
query_select_with_url.setForwardOnly(true);
query_select_with_url.prepare("SELECT id, date_created, is_read, is_important, contents FROM Messages "
"WHERE feed = :feed AND title = :title AND url = :url AND author = :author AND account_id = :account_id;");
// When we have custom ID of the message, we can check directly for existence
// of that particular message.
query_select_with_id.setForwardOnly(true);
query_select_with_id.prepare("SELECT id, date_created, is_read, is_important, contents FROM Messages "
"WHERE custom_id = :custom_id AND account_id = :account_id;");
// Used to insert new messages.
query_insert.setForwardOnly(true);
query_insert.prepare("INSERT INTO Messages "
"(feed, title, is_read, is_important, url, author, date_created, contents, enclosures, custom_id, custom_hash, account_id) "
"VALUES (:feed, :title, :is_read, :is_important, :url, :author, :date_created, :contents, :enclosures, :custom_id, :custom_hash, :account_id);");
// Used to update existing messages.
query_update.setForwardOnly(true);
query_update.prepare("UPDATE Messages "
@ -501,13 +482,13 @@ int DatabaseQueries::updateMessages(QSqlDatabase db,
if (message.m_url.startsWith(QL1S("//"))) {
message.m_url = QString(URI_SCHEME_HTTP) + message.m_url.mid(2);
}
else if (message.m_url.startsWith(QL1S("/"))) {
QString new_message_url = QUrl(url).toString(QUrl::RemoveUserInfo |
QUrl::RemovePath |
QUrl::RemoveQuery |
QUrl::RemoveFilename |
QUrl::StripTrailingSlash);
new_message_url += message.m_url;
message.m_url = new_message_url;
}
@ -534,12 +515,14 @@ int DatabaseQueries::updateMessages(QSqlDatabase db,
is_important_existing_message = query_select_with_url.value(3).toBool();
contents_existing_message = query_select_with_url.value(4).toString();
}
else if (query_select_with_url.lastError().isValid()) {
qWarning("Failed to check for existing message in DB via URL: '%s'.", qPrintable(query_select_with_url.lastError().text()));
}
query_select_with_url.finish();
}
else {
// We can recognize existing messages via their custom ID.
// NOTE: This concerns messages from custom accounts, like TT-RSS or ownCloud News.
@ -553,6 +536,7 @@ int DatabaseQueries::updateMessages(QSqlDatabase db,
is_important_existing_message = query_select_with_id.value(3).toBool();
contents_existing_message = query_select_with_id.value(4).toString();
}
else if (query_select_with_id.lastError().isValid()) {
qDebug("Failed to check for existing message in DB via ID: '%s'.", qPrintable(query_select_with_id.lastError().text()));
}
@ -567,7 +551,8 @@ int DatabaseQueries::updateMessages(QSqlDatabase db,
// Now, we update it if at least one of next conditions is true:
// 1) Message has custom ID AND (its date OR read status OR starred status are changed).
// 2) Message has its date fetched from feed AND its date is different from date in DB and contents is changed.
if (/* 1 */ (!message.m_customId.isEmpty() && (message.m_created.toMSecsSinceEpoch() != date_existing_message || message.m_isRead != is_read_existing_message || message.m_isImportant != is_important_existing_message)) ||
if (/* 1 */ (!message.m_customId.isEmpty() && (message.m_created.toMSecsSinceEpoch() != date_existing_message || message.m_isRead != is_read_existing_message
|| message.m_isImportant != is_important_existing_message)) ||
/* 2 */ (message.m_createdFromFeed && message.m_created.toMSecsSinceEpoch() != date_existing_message && message.m_contents != contents_existing_message)) {
// Message exists, it is changed, update it.
query_update.bindValue(QSL(":title"), message.m_title);
@ -579,12 +564,12 @@ int DatabaseQueries::updateMessages(QSqlDatabase db,
query_update.bindValue(QSL(":contents"), message.m_contents);
query_update.bindValue(QSL(":enclosures"), Enclosures::encodeEnclosuresToString(message.m_enclosures));
query_update.bindValue(QSL(":id"), id_existing_message);
*any_message_changed = true;
if (query_update.exec() && !message.m_isRead) {
updated_messages++;
}
else if (query_update.lastError().isValid()) {
qWarning("Failed to update message in DB: '%s'.", qPrintable(query_update.lastError().text()));
}
@ -593,6 +578,7 @@ int DatabaseQueries::updateMessages(QSqlDatabase db,
qDebug("Updating message '%s' in DB.", qPrintable(message.m_title));
}
}
else {
// Message with this URL is not fetched in this feed yet.
query_insert.bindValue(QSL(":feed"), feed_custom_id);
@ -612,6 +598,7 @@ int DatabaseQueries::updateMessages(QSqlDatabase db,
updated_messages++;
qDebug("Added new message '%s' to DB.", qPrintable(message.m_title));
}
else if (query_insert.lastError().isValid()) {
qWarning("Failed to insert message to DB: '%s' - message title is '%s'.",
qPrintable(query_insert.lastError().text()),
@ -639,6 +626,7 @@ int DatabaseQueries::updateMessages(QSqlDatabase db,
updated_messages = 0;
}
}
else {
if (ok != nullptr) {
*ok = true;
@ -655,19 +643,18 @@ bool DatabaseQueries::purgeMessagesFromBin(QSqlDatabase db, bool clear_only_read
if (clear_only_read) {
q.prepare(QSL("UPDATE Messages SET is_pdeleted = 1 WHERE is_read = 1 AND is_deleted = 1 AND account_id = :account_id;"));
}
else {
q.prepare(QSL("UPDATE Messages SET is_pdeleted = 1 WHERE is_deleted = 1 AND account_id = :account_id;"));
}
q.bindValue(QSL(":account_id"), account_id);
return q.exec();
}
bool DatabaseQueries::deleteAccount(QSqlDatabase db, int account_id) {
QSqlQuery query(db);
query.setForwardOnly(true);
QStringList queries;
queries << QSL("DELETE FROM Messages WHERE account_id = :account_id;") <<
QSL("DELETE FROM Feeds WHERE account_id = :account_id;") <<
@ -682,6 +669,7 @@ bool DatabaseQueries::deleteAccount(QSqlDatabase db, int account_id) {
qCritical("Removing of account from DB failed, this is critical: '%s'.", qPrintable(query.lastError().text()));
return false;
}
else {
query.finish();
}
@ -698,20 +686,15 @@ bool DatabaseQueries::deleteAccountData(QSqlDatabase db, int account_id, bool de
if (delete_messages_too) {
q.prepare(QSL("DELETE FROM Messages WHERE account_id = :account_id;"));
q.bindValue(QSL(":account_id"), account_id);
result &= q.exec();
}
q.prepare(QSL("DELETE FROM Feeds WHERE account_id = :account_id;"));
q.bindValue(QSL(":account_id"), account_id);
result &= q.exec();
q.prepare(QSL("DELETE FROM Categories WHERE account_id = :account_id;"));
q.bindValue(QSL(":account_id"), account_id);
result &= q.exec();
return result;
}
@ -724,6 +707,7 @@ bool DatabaseQueries::cleanFeeds(QSqlDatabase db, const QStringList &ids, bool c
"WHERE feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0 AND is_read = 1 AND account_id = :account_id;")
.arg(ids.join(QSL(", "))));
}
else {
q.prepare(QString("UPDATE Messages SET is_deleted = :deleted "
"WHERE feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0 AND account_id = :account_id;")
@ -737,6 +721,7 @@ bool DatabaseQueries::cleanFeeds(QSqlDatabase db, const QStringList &ids, bool c
qDebug("Cleaning of feeds failed: '%s'.", qPrintable(q.lastError().text()));
return false;
}
else {
return true;
}
@ -744,7 +729,6 @@ bool DatabaseQueries::cleanFeeds(QSqlDatabase db, const QStringList &ids, bool c
bool DatabaseQueries::purgeLeftoverMessages(QSqlDatabase db, int account_id) {
QSqlQuery q(db);
q.setForwardOnly(true);
q.prepare(QSL("DELETE FROM Messages WHERE account_id = :account_id AND feed NOT IN (SELECT custom_id FROM Feeds WHERE account_id = :account_id);"));
q.bindValue(QSL(":account_id"), account_id);
@ -753,6 +737,7 @@ bool DatabaseQueries::purgeLeftoverMessages(QSqlDatabase db, int account_id) {
qWarning("Removing of left over messages failed: '%s'.", qPrintable(q.lastError().text()));
return false;
}
else {
return true;
}
@ -779,13 +764,14 @@ bool DatabaseQueries::storeAccountTree(QSqlDatabase db, RootItem *tree_root, int
if (query_category.exec()) {
child->setId(query_category.lastInsertId().toInt());
}
else {
return false;
}
}
else if (child->kind() == RootItemKind::Feed) {
Feed* feed = child->toFeed();
query_feed.bindValue(QSL(":title"), feed->title());
query_feed.bindValue(QSL(":icon"), qApp->icons()->toByteArray(feed->icon()));
query_feed.bindValue(QSL(":category"), feed->parent()->customId());
@ -798,6 +784,7 @@ bool DatabaseQueries::storeAccountTree(QSqlDatabase db, RootItem *tree_root, int
if (query_feed.exec()) {
feed->setId(query_feed.lastInsertId().toInt());
}
else {
return false;
}
@ -817,6 +804,7 @@ QStringList DatabaseQueries::customIdsOfMessagesFromAccount(QSqlDatabase db, int
if (ok != nullptr) {
*ok = q.exec();
}
else {
q.exec();
}
@ -838,6 +826,7 @@ QStringList DatabaseQueries::customIdsOfMessagesFromBin(QSqlDatabase db, int acc
if (ok != nullptr) {
*ok = q.exec();
}
else {
q.exec();
}
@ -860,6 +849,7 @@ QStringList DatabaseQueries::customIdsOfMessagesFromFeed(QSqlDatabase db, int fe
if (ok != nullptr) {
*ok = q.exec();
}
else {
q.exec();
}
@ -884,7 +874,6 @@ QList<ServiceRoot*> DatabaseQueries::getOwnCloudAccounts(QSqlDatabase db, bool *
root->network()->setAuthPassword(TextFactory::decrypt(query.value(2).toString()));
root->network()->setUrl(query.value(3).toString());
root->network()->setForceServerSideUpdate(query.value(4).toBool());
root->updateTitle();
roots.append(root);
}
@ -893,6 +882,7 @@ QList<ServiceRoot*> DatabaseQueries::getOwnCloudAccounts(QSqlDatabase db, bool *
*ok = true;
}
}
else {
qWarning("OwnCloud: Getting list of activated accounts failed: '%s'.", qPrintable(query.lastError().text()));
@ -920,7 +910,6 @@ QList<ServiceRoot*> DatabaseQueries::getTtRssAccounts(QSqlDatabase db, bool *ok)
root->network()->setAuthPassword(TextFactory::decrypt(query.value(5).toString()));
root->network()->setUrl(query.value(6).toString());
root->network()->setForceServerSideUpdate(query.value(7).toBool());
root->updateTitle();
roots.append(root);
}
@ -929,6 +918,7 @@ QList<ServiceRoot*> DatabaseQueries::getTtRssAccounts(QSqlDatabase db, bool *ok)
*ok = true;
}
}
else {
qWarning("TT-RSS: Getting list of activated accounts failed: '%s'.", qPrintable(query.lastError().text()));
@ -942,18 +932,15 @@ QList<ServiceRoot*> DatabaseQueries::getTtRssAccounts(QSqlDatabase db, bool *ok)
bool DatabaseQueries::deleteOwnCloudAccount(QSqlDatabase db, int account_id) {
QSqlQuery q(db);
q.setForwardOnly(true);
q.prepare(QSL("DELETE FROM OwnCloudAccounts WHERE id = :id;"));
q.bindValue(QSL(":id"), account_id);
return q.exec();
}
bool DatabaseQueries::overwriteOwnCloudAccount(QSqlDatabase db, const QString& username, const QString& password,
const QString& url, bool force_server_side_feed_update, int account_id) {
QSqlQuery query(db);
query.prepare("UPDATE OwnCloudAccounts "
"SET username = :username, password = :password, url = :url, force_update = :force_update "
"WHERE id = :id;");
@ -966,6 +953,7 @@ bool DatabaseQueries::overwriteOwnCloudAccount(QSqlDatabase db, const QString &u
if (query.exec()) {
return true;
}
else {
qWarning("ownCloud: Updating account failed: '%s'.", qPrintable(query.lastError().text()));
return false;
@ -976,7 +964,6 @@ bool DatabaseQueries::createOwnCloudAccount(QSqlDatabase db, int id_to_assign, c
const QString& password, const QString& url,
bool force_server_side_feed_update) {
QSqlQuery q(db);
q.prepare("INSERT INTO OwnCloudAccounts (id, username, password, url, force_update) "
"VALUES (:id, :username, :password, :url, :force_update);");
q.bindValue(QSL(":id"), id_to_assign);
@ -988,6 +975,7 @@ bool DatabaseQueries::createOwnCloudAccount(QSqlDatabase db, int id_to_assign, c
if (q.exec()) {
return true;
}
else {
qWarning("ownCloud: Inserting of new account failed: '%s'.", qPrintable(q.lastError().text()));
return false;
@ -1009,7 +997,6 @@ int DatabaseQueries::createAccount(QSqlDatabase db, const QString &code, bool *o
}
int id_to_assign = q.value(0).toInt() + 1;
q.prepare(QSL("INSERT INTO Accounts (id, type) VALUES (:id, :type);"));
q.bindValue(QSL(":id"), id_to_assign);
q.bindValue(QSL(":type"), code);
@ -1021,6 +1008,7 @@ int DatabaseQueries::createAccount(QSqlDatabase db, const QString &code, bool *o
return id_to_assign;
}
else {
if (ok != nullptr) {
*ok = false;
@ -1033,7 +1021,6 @@ int DatabaseQueries::createAccount(QSqlDatabase db, const QString &code, bool *o
Assignment DatabaseQueries::getOwnCloudCategories(QSqlDatabase db, int account_id, bool* ok) {
Assignment categories;
// Obtain data for categories from the database.
QSqlQuery q(db);
q.setForwardOnly(true);
@ -1052,7 +1039,6 @@ Assignment DatabaseQueries::getOwnCloudCategories(QSqlDatabase db, int account_i
AssignmentItem pair;
pair.first = q.value(CAT_DB_PARENT_ID_INDEX).toInt();
pair.second = new OwnCloudCategory(q.record());
categories << pair;
}
@ -1065,7 +1051,6 @@ Assignment DatabaseQueries::getOwnCloudCategories(QSqlDatabase db, int account_i
Assignment DatabaseQueries::getOwnCloudFeeds(QSqlDatabase db, int account_id, bool* ok) {
Assignment feeds;
QSqlQuery q(db);
q.setForwardOnly(true);
q.prepare(QSL("SELECT * FROM Feeds WHERE account_id = :account_id;"));
@ -1083,7 +1068,6 @@ Assignment DatabaseQueries::getOwnCloudFeeds(QSqlDatabase db, int account_id, bo
AssignmentItem pair;
pair.first = q.value(FDS_DB_CATEGORY_INDEX).toInt();
pair.second = new OwnCloudFeed(q.record());
feeds << pair;
}
@ -1097,7 +1081,6 @@ Assignment DatabaseQueries::getOwnCloudFeeds(QSqlDatabase db, int account_id, bo
bool DatabaseQueries::deleteFeed(QSqlDatabase db, int feed_custom_id, int account_id) {
QSqlQuery q(db);
q.setForwardOnly(true);
// Remove all messages from this feed.
q.prepare(QSL("DELETE FROM Messages WHERE feed = :feed AND account_id = :account_id;"));
q.bindValue(QSL(":feed"), feed_custom_id);
@ -1111,18 +1094,15 @@ bool DatabaseQueries::deleteFeed(QSqlDatabase db, int feed_custom_id, int accoun
q.prepare(QSL("DELETE FROM Feeds WHERE custom_id = :feed AND account_id = :account_id;"));
q.bindValue(QSL(":feed"), feed_custom_id);
q.bindValue(QSL(":account_id"), account_id);
return q.exec();
}
bool DatabaseQueries::deleteCategory(QSqlDatabase db, int id) {
QSqlQuery q(db);
// Remove this category from database.
q.setForwardOnly(true);
q.prepare(QSL("DELETE FROM Categories WHERE id = :category;"));
q.bindValue(QSL(":category"), id);
return q.exec();
}
@ -1130,7 +1110,6 @@ int DatabaseQueries::addCategory(QSqlDatabase db, int parent_id, int account_id,
const QString& description, QDateTime creation_date, const QIcon& icon,
bool* ok) {
QSqlQuery q(db);
q.setForwardOnly(true);
q.prepare("INSERT INTO Categories "
"(parent_id, title, description, date_created, icon, account_id) "
@ -1152,19 +1131,18 @@ int DatabaseQueries::addCategory(QSqlDatabase db, int parent_id, int account_id,
// Query failed.
return 0;
}
else {
if (ok != nullptr) {
*ok = true;
}
int new_id = q.lastInsertId().toInt();
// Now set custom ID in the DB.
q.prepare(QSL("UPDATE Categories SET custom_id = :custom_id WHERE id = :id;"));
q.bindValue(QSL(":custom_id"), QString::number(new_id));
q.bindValue(QSL(":id"), new_id);
q.exec();
return new_id;
}
}
@ -1172,7 +1150,6 @@ int DatabaseQueries::addCategory(QSqlDatabase db, int parent_id, int account_id,
bool DatabaseQueries::editCategory(QSqlDatabase db, int parent_id, int category_id,
const QString& title, const QString& description, const QIcon& icon) {
QSqlQuery q(db);
q.setForwardOnly(true);
q.prepare("UPDATE Categories "
"SET title = :title, description = :description, icon = :icon, parent_id = :parent_id "
@ -1182,7 +1159,6 @@ bool DatabaseQueries::editCategory(QSqlDatabase db, int parent_id, int category_
q.bindValue(QSL(":icon"), qApp->icons()->toByteArray(icon));
q.bindValue(QSL(":parent_id"), parent_id);
q.bindValue(QSL(":id"), category_id);
return q.exec();
}
@ -1193,9 +1169,7 @@ int DatabaseQueries::addFeed(QSqlDatabase db, int parent_id, int account_id, con
Feed::AutoUpdateType auto_update_type,
int auto_update_interval, StandardFeed::Type feed_format, bool* ok) {
QSqlQuery q(db);
qDebug() << "Adding feed with title '" << title.toUtf8() << "' to DB.";
q.setForwardOnly(true);
q.prepare("INSERT INTO Feeds "
"(title, description, date_created, icon, category, encoding, url, protected, username, password, update_type, update_interval, type, account_id) "
@ -1214,6 +1188,7 @@ int DatabaseQueries::addFeed(QSqlDatabase db, int parent_id, int account_id, con
if (password.isEmpty()) {
q.bindValue(QSL(":password"), password);
}
else {
q.bindValue(QSL(":password"), TextFactory::encrypt(password));
}
@ -1224,7 +1199,6 @@ int DatabaseQueries::addFeed(QSqlDatabase db, int parent_id, int account_id, con
if (q.exec()) {
int new_id = q.lastInsertId().toInt();
// Now set custom ID in the DB.
q.prepare(QSL("UPDATE Feeds SET custom_id = :custom_id WHERE id = :id;"));
q.bindValue(QSL(":custom_id"), QString::number(new_id));
@ -1237,6 +1211,7 @@ int DatabaseQueries::addFeed(QSqlDatabase db, int parent_id, int account_id, con
return new_id;
}
else {
if (ok != nullptr) {
*ok = false;
@ -1255,7 +1230,6 @@ bool DatabaseQueries::editFeed(QSqlDatabase db, int parent_id, int feed_id, cons
int auto_update_interval, StandardFeed::Type feed_format) {
QSqlQuery q(db);
q.setForwardOnly(true);
q.prepare("UPDATE Feeds "
"SET title = :title, description = :description, icon = :icon, category = :category, encoding = :encoding, url = :url, protected = :protected, username = :username, password = :password, update_type = :update_type, update_interval = :update_interval, type = :type "
"WHERE id = :id;");
@ -1271,6 +1245,7 @@ bool DatabaseQueries::editFeed(QSqlDatabase db, int parent_id, int feed_id, cons
if (password.isEmpty()) {
q.bindValue(QSL(":password"), password);
}
else {
q.bindValue(QSL(":password"), TextFactory::encrypt(password));
}
@ -1279,30 +1254,25 @@ bool DatabaseQueries::editFeed(QSqlDatabase db, int parent_id, int feed_id, cons
q.bindValue(QSL(":update_interval"), auto_update_interval);
q.bindValue(QSL(":type"), feed_format);
q.bindValue(QSL(":id"), feed_id);
return q.exec();
}
bool DatabaseQueries::editBaseFeed(QSqlDatabase db, int feed_id, Feed::AutoUpdateType auto_update_type,
int auto_update_interval) {
QSqlQuery q(db);
q.setForwardOnly(true);
q.prepare("UPDATE Feeds "
"SET update_type = :update_type, update_interval = :update_interval "
"WHERE id = :id;");
q.bindValue(QSL(":update_type"), (int) auto_update_type);
q.bindValue(QSL(":update_interval"), auto_update_interval);
q.bindValue(QSL(":id"), feed_id);
return q.exec();
}
QList<ServiceRoot*> DatabaseQueries::getAccounts(QSqlDatabase db, bool* ok) {
QSqlQuery q(db);
QList<ServiceRoot*> roots;
q.setForwardOnly(true);
q.prepare(QSL("SELECT id FROM Accounts WHERE type = :type;"));
q.bindValue(QSL(":type"), SERVICE_CODE_STD_RSS);
@ -1318,6 +1288,7 @@ QList<ServiceRoot*> DatabaseQueries::getAccounts(QSqlDatabase db, bool *ok) {
*ok = true;
}
}
else {
if (ok != nullptr) {
*ok = false;
@ -1329,7 +1300,6 @@ QList<ServiceRoot*> DatabaseQueries::getAccounts(QSqlDatabase db, bool *ok) {
Assignment DatabaseQueries::getCategories(QSqlDatabase db, int account_id, bool* ok) {
Assignment categories;
// Obtain data for categories from the database.
QSqlQuery q(db);
q.setForwardOnly(true);
@ -1344,6 +1314,7 @@ Assignment DatabaseQueries::getCategories(QSqlDatabase db, int account_id, bool
*ok = false;
}
}
else {
if (ok != nullptr) {
*ok = true;
@ -1354,7 +1325,6 @@ Assignment DatabaseQueries::getCategories(QSqlDatabase db, int account_id, bool
AssignmentItem pair;
pair.first = q.value(CAT_DB_PARENT_ID_INDEX).toInt();
pair.second = new StandardCategory(q.record());
categories << pair;
}
@ -1364,7 +1334,6 @@ Assignment DatabaseQueries::getCategories(QSqlDatabase db, int account_id, bool
Assignment DatabaseQueries::getFeeds(QSqlDatabase db, int account_id, bool* ok) {
Assignment feeds;
QSqlQuery q(db);
q.setForwardOnly(true);
q.prepare(QSL("SELECT * FROM Feeds WHERE account_id = :account_id;"));
q.bindValue(QSL(":account_id"), account_id);
@ -1395,7 +1364,6 @@ Assignment DatabaseQueries::getFeeds(QSqlDatabase db, int account_id, bool *ok)
pair.first = q.value(FDS_DB_CATEGORY_INDEX).toInt();
pair.second = new StandardFeed(q.record());
qobject_cast<StandardFeed*>(pair.second)->setType(type);
feeds << pair;
break;
}
@ -1410,11 +1378,9 @@ Assignment DatabaseQueries::getFeeds(QSqlDatabase db, int account_id, bool *ok)
bool DatabaseQueries::deleteTtRssAccount(QSqlDatabase db, int account_id) {
QSqlQuery q(db);
q.setForwardOnly(true);
q.prepare(QSL("DELETE FROM TtRssAccounts WHERE id = :id;"));
q.bindValue(QSL(":id"), account_id);
// Remove extra entry in "Tiny Tiny RSS accounts list" and then delete
// all the categories/feeds and messages.
return q.exec();
@ -1424,7 +1390,6 @@ bool DatabaseQueries::overwriteTtRssAccount(QSqlDatabase db, const QString &user
bool auth_protected, const QString& auth_username, const QString& auth_password,
const QString& url, bool force_server_side_feed_update, int account_id) {
QSqlQuery q(db);
q.prepare("UPDATE TtRssAccounts "
"SET username = :username, password = :password, url = :url, auth_protected = :auth_protected, "
"auth_username = :auth_username, auth_password = :auth_password, force_update = :force_update "
@ -1441,6 +1406,7 @@ bool DatabaseQueries::overwriteTtRssAccount(QSqlDatabase db, const QString &user
if (q.exec()) {
return true;
}
else {
qWarning("TT-RSS: Updating account failed: '%s'.", qPrintable(q.lastError().text()));
return false;
@ -1452,7 +1418,6 @@ bool DatabaseQueries::createTtRssAccount(QSqlDatabase db, int id_to_assign, cons
const QString& auth_password, const QString& url,
bool force_server_side_feed_update) {
QSqlQuery q(db);
q.prepare("INSERT INTO TtRssAccounts (id, username, password, auth_protected, auth_username, auth_password, url, force_update) "
"VALUES (:id, :username, :password, :auth_protected, :auth_username, :auth_password, :url, :force_update);");
q.bindValue(QSL(":id"), id_to_assign);
@ -1467,6 +1432,7 @@ bool DatabaseQueries::createTtRssAccount(QSqlDatabase db, int id_to_assign, cons
if (q.exec()) {
return true;
}
else {
qWarning("TT-RSS: Saving of new account failed: '%s'.", qPrintable(q.lastError().text()));
return false;
@ -1475,7 +1441,6 @@ bool DatabaseQueries::createTtRssAccount(QSqlDatabase db, int id_to_assign, cons
Assignment DatabaseQueries::getTtRssCategories(QSqlDatabase db, int account_id, bool* ok) {
Assignment categories;
// Obtain data for categories from the database.
QSqlQuery query_categories(db);
query_categories.setForwardOnly(true);
@ -1489,6 +1454,7 @@ Assignment DatabaseQueries::getTtRssCategories(QSqlDatabase db, int account_id,
*ok = false;
}
}
else {
if (ok != nullptr) {
*ok = true;
@ -1499,7 +1465,6 @@ Assignment DatabaseQueries::getTtRssCategories(QSqlDatabase db, int account_id,
AssignmentItem pair;
pair.first = query_categories.value(CAT_DB_PARENT_ID_INDEX).toInt();
pair.second = new TtRssCategory(query_categories.record());
categories << pair;
}
@ -1508,7 +1473,6 @@ Assignment DatabaseQueries::getTtRssCategories(QSqlDatabase db, int account_id,
Assignment DatabaseQueries::getTtRssFeeds(QSqlDatabase db, int account_id, bool* ok) {
Assignment feeds;
// All categories are now loaded.
QSqlQuery query_feeds(db);
query_feeds.setForwardOnly(true);
@ -1522,6 +1486,7 @@ Assignment DatabaseQueries::getTtRssFeeds(QSqlDatabase db, int account_id, bool
*ok = false;
}
}
else {
if (ok != nullptr) {
*ok = true;
@ -1532,7 +1497,6 @@ Assignment DatabaseQueries::getTtRssFeeds(QSqlDatabase db, int account_id, bool
AssignmentItem pair;
pair.first = query_feeds.value(FDS_DB_CATEGORY_INDEX).toInt();
pair.second = new TtRssFeed(query_feeds.record());
feeds << pair;
}

View file

@ -32,16 +32,15 @@ Debugging::Debugging() {
void Debugging::performLog(const char* message, QtMsgType type, const char* file, const char* function, int line) {
const char* type_string = typeToString(type);
std::time_t t = std::time(nullptr);
char mbstr[32];
std::strftime(mbstr, sizeof(mbstr), "%y/%d/%m %H:%M:%S", std::localtime(&t));
// Write to console.
if (file == 0 || function == 0 || line < 0) {
fprintf(stderr, "[%s] %s: %s (%s)\n", APP_LOW_NAME, type_string, message, mbstr);
}
else {
fprintf(stderr, "[%s] %s (%s)\n Type: %s\n File: %s (line %d)\n Function: %s\n\n",
APP_LOW_NAME, message, mbstr, type_string, file, line, function);

View file

@ -45,7 +45,6 @@ FeedReader::FeedReader(QObject *parent)
m_feedsProxyModel = new FeedsProxyModel(m_feedsModel, this);
m_messagesModel = new MessagesModel(this);
m_messagesProxyModel = new MessagesProxyModel(m_messagesModel, this);
connect(m_cacheSaveFutureWatcher, &QFutureWatcher<void>::finished, this, &FeedReader::asyncCacheSaveFinished);
connect(m_autoUpdateTimer, &QTimer::timeout, this, &FeedReader::executeNextAutoUpdate);
updateAutoUpdateStatus();
@ -84,17 +83,14 @@ void FeedReader::updateFeeds(const QList<Feed*> &feeds) {
if (m_feedDownloader == nullptr) {
m_feedDownloader = new FeedDownloader();
m_feedDownloaderThread = new QThread();
// Downloader setup.
qRegisterMetaType<QList<Feed*>>("QList<Feed*>");
m_feedDownloader->moveToThread(m_feedDownloaderThread);
connect(m_feedDownloaderThread, &QThread::finished, m_feedDownloaderThread, &QThread::deleteLater);
connect(m_feedDownloader, &FeedDownloader::updateFinished, this, &FeedReader::feedUpdatesFinished);
connect(m_feedDownloader, &FeedDownloader::updateProgress, this, &FeedReader::feedUpdatesProgress);
connect(m_feedDownloader, &FeedDownloader::updateStarted, this, &FeedReader::feedUpdatesStarted);
connect(m_feedDownloader, &FeedDownloader::updateFinished, qApp->feedUpdateLock(), &Mutex::unlock);
// Connections are made, start the feed downloader thread.
m_feedDownloaderThread->start();
}
@ -118,6 +114,7 @@ void FeedReader::updateAutoUpdateStatus() {
m_autoUpdateTimer->start();
qDebug("Auto-update timer started with interval %d.", m_autoUpdateTimer->interval());
}
else {
qDebug("Auto-update timer is already running.");
}
@ -153,12 +150,10 @@ DatabaseCleaner *FeedReader::databaseCleaner() {
if (m_dbCleaner == nullptr) {
m_dbCleaner = new DatabaseCleaner();
m_dbCleanerThread = new QThread();
// Downloader setup.
qRegisterMetaType<CleanerOrders>("CleanerOrders");
m_dbCleaner->moveToThread(m_dbCleanerThread);
connect(m_dbCleanerThread, SIGNAL(finished()), m_dbCleanerThread, SLOT(deleteLater()));
// Connections are made, start the feed downloader thread.
m_dbCleanerThread->start();
}
@ -181,7 +176,6 @@ MessagesModel *FeedReader::messagesModel() const {
void FeedReader::executeNextAutoUpdate() {
if (!qApp->feedUpdateLock()->tryLock()) {
qDebug("Delaying scheduled feed auto-updates for one minute due to another running update.");
// Cannot update, quit.
return;
}
@ -194,12 +188,10 @@ void FeedReader::executeNextAutoUpdate() {
}
qDebug("Starting auto-update event, pass %d/%d.", m_globalAutoUpdateRemainingInterval, m_globalAutoUpdateInitialInterval);
// Pass needed interval data and lets the model decide which feeds
// should be updated in this pass.
QList<Feed*> feeds_for_update = m_feedsModel->feedsForScheduledUpdate(m_globalAutoUpdateEnabled &&
m_globalAutoUpdateRemainingInterval == 0);
qApp->feedUpdateLock()->unlock();
if (!feeds_for_update.isEmpty()) {
@ -230,6 +222,7 @@ void FeedReader::checkServicesForAsyncOperations(bool wait_for_future) {
qWarning("Waiting for previously started saving of cached service data.");
m_cacheSaveFutureWatcher->future().waitForFinished();
}
else {
qWarning("Some cached service data are being saved now, so aborting this saving cycle.");
// Some cache saving is now running.
@ -248,6 +241,7 @@ void FeedReader::checkServicesForAsyncOperations(bool wait_for_future) {
qDebug("Waiting for saving of cached service data to finish.");
future.waitForFinished();
}
else {
m_cacheSaveFutureWatcher->setFuture(future);
}
@ -255,7 +249,6 @@ void FeedReader::checkServicesForAsyncOperations(bool wait_for_future) {
void FeedReader::asyncCacheSaveFinished() {
qDebug("I will start next check for cached service data in 30 seconds.");
QTimer::singleShot(30000, [&] {
qDebug("Starting next check for cached service data in NOW.");
checkServicesForAsyncOperations(false);

View file

@ -31,15 +31,12 @@ IconFactory::~IconFactory() {
QIcon IconFactory::fromByteArray(QByteArray array) {
array = QByteArray::fromBase64(array);
QIcon icon;
QBuffer buffer(&array);
buffer.open(QIODevice::ReadOnly);
QDataStream in(&buffer);
in.setVersion(QDataStream::Qt_4_7);
in >> icon;
buffer.close();
return icon;
}
@ -48,11 +45,9 @@ QByteArray IconFactory::toByteArray(const QIcon &icon) {
QByteArray array;
QBuffer buffer(&array);
buffer.open(QIODevice::WriteOnly);
QDataStream out(&buffer);
out.setVersion(QDataStream::Qt_4_7);
out << icon;
buffer.close();
return array.toBase64();
}
@ -61,6 +56,7 @@ QPixmap IconFactory::pixmap(const QString &name) {
if (QIcon::themeName() == APP_NO_THEME) {
return QPixmap();
}
else {
return QIcon::fromTheme(name).pixmap(64, 64);
}
@ -110,6 +106,7 @@ void IconFactory::loadCurrentIconTheme() {
qDebug("Loading icon theme '%s'.", qPrintable(theme_name_from_settings));
QIcon::setThemeName(theme_name_from_settings);
}
else {
// Desired icon theme is not currently available.
// Install "default" icon theme instead.
@ -120,12 +117,11 @@ void IconFactory::loadCurrentIconTheme() {
}
QStringList IconFactory::installedIconThemes() const {
QStringList icon_theme_names; icon_theme_names << APP_NO_THEME;
QStringList icon_theme_names;
icon_theme_names << APP_NO_THEME;
// Iterate all directories with icon themes.
QStringList icon_themes_paths = QIcon::themeSearchPaths();
QStringList filters_index;
filters_index.append("index.theme");
icon_themes_paths.removeDuplicates();
@ -146,6 +142,5 @@ QStringList IconFactory::installedIconThemes() const {
}
icon_theme_names.removeDuplicates();
return icon_theme_names;
}

View file

@ -39,7 +39,6 @@ bool IOFactory::isFolderWritable(const QString &folder) {
}
real_file += "test-permissions-file";
return QTemporaryFile(real_file).open();
}
@ -63,6 +62,7 @@ QString IOFactory::ensureUniqueFilename(const QString &name, const QString &appe
if (index < 0) {
tmp_filename.append(append_string);
}
else {
tmp_filename = tmp_filename.left(index) + append_string + tmp_filename.mid(index);
}
@ -73,7 +73,6 @@ QString IOFactory::ensureUniqueFilename(const QString &name, const QString &appe
QString IOFactory::filterBadCharsFromFilename(const QString& name) {
QString value = name;
value.replace(QL1C('/'), QL1C('-'));
value.remove(QL1C('\\'));
value.remove(QL1C(':'));
@ -83,7 +82,6 @@ QString IOFactory::filterBadCharsFromFilename(const QString &name) {
value.remove(QL1C('<'));
value.remove(QL1C('>'));
value.remove(QL1C('|'));
return value;
}
@ -96,6 +94,7 @@ QByteArray IOFactory::readTextFile(const QString &file_path) {
input_file.close();
return input_data;
}
else {
throw IOException(tr("Cannot open file '%1' for reading.").arg(QDir::toNativeSeparators(file_path)));
}
@ -103,7 +102,6 @@ QByteArray IOFactory::readTextFile(const QString &file_path) {
void IOFactory::writeTextFile(const QString& file_path, const QByteArray& data, const QString& encoding) {
Q_UNUSED(encoding)
QFile input_file(file_path);
QTextStream stream(&input_file);
@ -113,6 +111,7 @@ void IOFactory::writeTextFile(const QString &file_path, const QByteArray &data,
input_file.flush();
input_file.close();
}
else {
throw IOException(tr("Cannot open file '%1' for writting.").arg(QDir::toNativeSeparators(file_path)));
}

View file

@ -40,18 +40,17 @@ void Localization::loadActiveLanguage() {
QTranslator* qt_translator = new QTranslator(qApp);
QTranslator* app_translator = new QTranslator(qApp);
QString desired_localization = desiredLanguage();
qDebug("Starting to load active localization. Desired localization is '%s'.", qPrintable(desired_localization));
if (app_translator->load(QLocale(desired_localization), "rssguard", QSL("_"), APP_LANG_PATH)) {
const QString real_loaded_locale = app_translator->translate("QObject", "LANG_ABBREV");
Application::installTranslator(app_translator);
qDebug("Application localization '%s' loaded successfully, specifically sublocalization '%s' was loaded.",
qPrintable(desired_localization),
qPrintable(real_loaded_locale));
desired_localization = real_loaded_locale;
}
else {
qWarning("Application localization '%s' was not loaded. Loading '%s' instead.",
qPrintable(desired_localization),
@ -63,6 +62,7 @@ void Localization::loadActiveLanguage() {
Application::installTranslator(qt_translator);
qDebug("Qt localization '%s' loaded successfully.", qPrintable(desired_localization));
}
else {
qWarning("Qt localization '%s' was not loaded.", qPrintable(desired_localization));
}
@ -85,7 +85,6 @@ QList<Language> Localization::installedLanguages() const {
new_language.m_author = translator.translate("QObject", "LANG_AUTHOR");
new_language.m_email = translator.translate("QObject", "LANG_EMAIL");
new_language.m_name = QLocale(new_language.m_code).nativeLanguageName();
languages << new_language;
}
}

View file

@ -101,7 +101,8 @@ DKEY GUI::FeedsToolbarActions = "feeds_toolbar";
DVALUE(char*) GUI::FeedsToolbarActionsDef = "m_actionUpdateAllItems,m_actionStopRunningItemsUpdate,m_actionMarkAllItemsRead";
DKEY GUI::StatusbarActions = "status_bar";
DVALUE(char*) GUI::StatusbarActionsDef = "m_lblProgressFeedsAction,m_barProgressFeedsAction,m_actionUpdateAllItems,m_actionUpdateSelectedItems,m_actionStopRunningItemsUpdate,m_actionFullscreen,m_actionQuit";
DVALUE(char*) GUI::StatusbarActionsDef =
"m_lblProgressFeedsAction,m_barProgressFeedsAction,m_actionUpdateAllItems,m_actionUpdateSelectedItems,m_actionStopRunningItemsUpdate,m_actionFullscreen,m_actionQuit";
DKEY GUI::MainWindowInitialSize = "window_size";
DKEY GUI::MainWindowInitialPosition = "window_position";
@ -152,7 +153,8 @@ DKEY GUI::HideTabBarIfOnlyOneTab = "hide_tabbar_one_tab";
DVALUE(bool) GUI::HideTabBarIfOnlyOneTabDef = false;
DKEY GUI::MessagesToolbarDefaultButtons = "messages_toolbar";
DVALUE(char*) GUI::MessagesToolbarDefaultButtonsDef = "m_actionMarkSelectedMessagesAsRead,m_actionMarkSelectedMessagesAsUnread,m_actionSwitchImportanceOfSelectedMessages,separator,highlighter,spacer,search";
DVALUE(char*) GUI::MessagesToolbarDefaultButtonsDef =
"m_actionMarkSelectedMessagesAsRead,m_actionMarkSelectedMessagesAsUnread,m_actionSwitchImportanceOfSelectedMessages,separator,highlighter,spacer,search";
DKEY GUI::DefaultSortColumnFeeds = "default_sort_column_feeds";
DVALUE(int) GUI::DefaultSortColumnFeedsDef = FDS_MODEL_TITLE_INDEX;
@ -299,7 +301,6 @@ QString Settings::pathName() const {
QSettings::Status Settings::checkSettings() {
qDebug("Syncing settings.");
sync();
return status();
}
@ -321,6 +322,7 @@ void Settings::finishRestoration(const QString &desired_settings_file_path) {
QFile::remove(backup_settings_file);
qDebug("Settings file was restored successully.");
}
else {
qCritical("Settings file was NOT restored due to error when copying the file.");
}
@ -329,14 +331,11 @@ void Settings::finishRestoration(const QString &desired_settings_file_path) {
Settings* Settings::setupSettings(QObject* parent) {
Settings* new_settings;
// If settings file exists (and is writable) in executable file working directory
// (in subdirectory APP_CFG_PATH), then use it (portable settings).
// Otherwise use settings file stored in home path.
const SettingsProperties properties = determineProperties();
finishRestoration(properties.m_absoluteSettingsFileName);
// Portable settings are available, use them.
new_settings = new Settings(properties.m_absoluteSettingsFileName, QSettings::IniFormat, properties.m_type, parent);
@ -344,6 +343,7 @@ Settings *Settings::setupSettings(QObject *parent) {
if (properties.m_type == SettingsProperties::Portable) {
qDebug("Initializing settings in '%s' (portable way).", qPrintable(QDir::toNativeSeparators(properties.m_absoluteSettingsFileName)));
}
else {
qDebug("Initializing settings in '%s' (non-portable way).", qPrintable(QDir::toNativeSeparators(properties.m_absoluteSettingsFileName)));
}
@ -353,12 +353,9 @@ Settings *Settings::setupSettings(QObject *parent) {
SettingsProperties Settings::determineProperties() {
SettingsProperties properties;
properties.m_settingsSuffix = QDir::separator() + QSL(APP_CFG_PATH) + QDir::separator() + QSL(APP_CFG_FILE);
const QString app_path = qApp->getUserDataAppPath();
const QString home_path = qApp->getUserDataHomePath();
// We will use PORTABLE settings only and only if it is available and NON-PORTABLE
// settings was not initialized before.
#if defined (Q_OS_LINUX) || defined (Q_OS_MACOS)
@ -376,12 +373,12 @@ SettingsProperties Settings::determineProperties() {
properties.m_type = SettingsProperties::Portable;
properties.m_baseDirectory = app_path;
}
else {
properties.m_type = SettingsProperties::NonPortable;
properties.m_baseDirectory = home_path;
}
properties.m_absoluteSettingsFileName = properties.m_baseDirectory + properties.m_settingsSuffix;
return properties;
}

21
src/miscellaneous/simplecrypt/simplecrypt.cpp Normal file → Executable file
View file

@ -60,6 +60,7 @@ void SimpleCrypt::setKey(quint64 key) {
void SimpleCrypt::splitKey() {
m_keyParts.clear();
m_keyParts.resize(8);
for (int i = 0; i < 8; i++) {
quint64 part = m_key;
@ -90,6 +91,7 @@ QByteArray SimpleCrypt::encryptToByteArray(QByteArray plaintext) {
ba = qCompress(ba, 9); //maximum compression
flags |= CryptoFlagCompression;
}
else if (m_compressionMode == CompressionAuto) {
QByteArray compressed = qCompress(ba, 9);
@ -100,11 +102,13 @@ QByteArray SimpleCrypt::encryptToByteArray(QByteArray plaintext) {
}
QByteArray integrityProtection;
if (m_protectionMode == ProtectionChecksum) {
flags |= CryptoFlagChecksum;
QDataStream s(&integrityProtection, QIODevice::WriteOnly);
s << qChecksum(ba.constData(), ba.length());
}
else if (m_protectionMode == ProtectionHash) {
flags |= CryptoFlagHash;
QCryptographicHash hash(QCryptographicHash::Sha1);
@ -115,7 +119,6 @@ QByteArray SimpleCrypt::encryptToByteArray(QByteArray plaintext) {
//prepend a random char to the string
char randomChar = char(qrand() & 0xFF);
ba = randomChar + integrityProtection + ba;
int pos(0);
char lastChar(0);
int cnt = ba.count();
@ -130,7 +133,6 @@ QByteArray SimpleCrypt::encryptToByteArray(QByteArray plaintext) {
resultArray.append(char(0x03)); //version for future updates to algorithm
resultArray.append(char(flags)); //encryption flags
resultArray.append(ba);
m_lastError = ErrorNoError;
return resultArray;
}
@ -152,21 +154,18 @@ QString SimpleCrypt::decryptToString(const QString &cyphertext) {
QByteArray cyphertextArray = QByteArray::fromBase64(cyphertext.toLatin1());
QByteArray plaintextArray = decryptToByteArray(cyphertextArray);
QString plaintext = QString::fromUtf8(plaintextArray, plaintextArray.size());
return plaintext;
}
QString SimpleCrypt::decryptToString(QByteArray cypher) {
QByteArray ba = decryptToByteArray(cypher);
QString plaintext = QString::fromUtf8(ba, ba.size());
return plaintext;
}
QByteArray SimpleCrypt::decryptToByteArray(const QString& cyphertext) {
QByteArray cyphertextArray = QByteArray::fromBase64(cyphertext.toLatin1());
QByteArray ba = decryptToByteArray(cyphertextArray);
return ba;
}
@ -192,7 +191,6 @@ QByteArray SimpleCrypt::decryptToByteArray(QByteArray cypher) {
}
CryptoFlags flags = CryptoFlags(ba.at(1));
ba = ba.mid(2);
int pos(0);
int cnt(ba.count());
@ -206,13 +204,14 @@ QByteArray SimpleCrypt::decryptToByteArray(QByteArray cypher) {
}
ba = ba.mid(1); //chop off the random number at the start
bool integrityOk(true);
if (flags.testFlag(CryptoFlagChecksum)) {
if (ba.length() < 2) {
m_lastError = ErrorIntegrityFailed;
return QByteArray();
}
quint16 storedChecksum;
{
QDataStream s(&ba, QIODevice::ReadOnly);
@ -221,11 +220,14 @@ QByteArray SimpleCrypt::decryptToByteArray(QByteArray cypher) {
ba = ba.mid(2);
quint16 checksum = qChecksum(ba.constData(), ba.length());
integrityOk = (checksum == storedChecksum);
} else if (flags.testFlag(CryptoFlagHash)) {
}
else if (flags.testFlag(CryptoFlagHash)) {
if (ba.length() < 20) {
m_lastError = ErrorIntegrityFailed;
return QByteArray();
}
QByteArray storedHash = ba.left(20);
ba = ba.mid(20);
QCryptographicHash hash(QCryptographicHash::Sha1);
@ -238,8 +240,9 @@ QByteArray SimpleCrypt::decryptToByteArray(QByteArray cypher) {
return QByteArray();
}
if (flags.testFlag(CryptoFlagCompression))
if (flags.testFlag(CryptoFlagCompression)) {
ba = qUncompress(ba);
}
m_lastError = ErrorNoError;
return ba;

24
src/miscellaneous/simplecrypt/simplecrypt.h Normal file → Executable file
View file

@ -110,7 +110,9 @@ class SimpleCrypt {
/**
Returns true if SimpleCrypt has been initialized with a key.
*/
bool hasKey() const {return !m_keyParts.isEmpty();}
bool hasKey() const {
return !m_keyParts.isEmpty();
}
/**
Sets the compression mode to use when encrypting data. The default mode is Auto.
@ -118,11 +120,15 @@ class SimpleCrypt {
Note that decryption is not influenced by this mode, as the decryption recognizes
what mode was used when encrypting.
*/
void setCompressionMode(CompressionMode mode) {m_compressionMode = mode;}
void setCompressionMode(CompressionMode mode) {
m_compressionMode = mode;
}
/**
Returns the CompressionMode that is currently in use.
*/
CompressionMode compressionMode() const {return m_compressionMode;}
CompressionMode compressionMode() const {
return m_compressionMode;
}
/**
Sets the integrity mode to use when encrypting data. The default mode is Checksum.
@ -130,16 +136,22 @@ class SimpleCrypt {
Note that decryption is not influenced by this mode, as the decryption recognizes
what mode was used when encrypting.
*/
void setIntegrityProtectionMode(IntegrityProtectionMode mode) {m_protectionMode = mode;}
void setIntegrityProtectionMode(IntegrityProtectionMode mode) {
m_protectionMode = mode;
}
/**
Returns the IntegrityProtectionMode that is currently in use.
*/
IntegrityProtectionMode integrityProtectionMode() const {return m_protectionMode;}
IntegrityProtectionMode integrityProtectionMode() const {
return m_protectionMode;
}
/**
Returns the last error that occurred.
*/
Error lastError() const {return m_lastError;}
Error lastError() const {
return m_lastError;
}
/**
Encrypts the @arg plaintext string with the key the class was initialized with, and returns

View file

@ -40,6 +40,7 @@ void SimpleRegExp::setMinimal(bool minimal) {
if (minimal) {
opt = patternOptions() | QRegularExpression::InvertedGreedinessOption;
}
else {
opt = patternOptions() & ~QRegularExpression::InvertedGreedinessOption;
}
@ -56,6 +57,7 @@ int SimpleRegExp::indexIn(const QString &str, int offset) const {
that->m_capturedTexts.clear();
return -1;
}
else {
that->m_matchedLength = m.capturedLength();
that->m_capturedTexts = m.capturedTexts();
@ -71,6 +73,7 @@ QString SimpleRegExp::cap(int nth) const {
if (nth >= 0 && m_capturedTexts.size() > nth) {
return m_capturedTexts.at(nth);
}
else {
return QString();
}

View file

@ -33,10 +33,8 @@ SkinFactory::~SkinFactory() {
void SkinFactory::loadCurrentSkin() {
QList<QString> skin_names_to_try;
skin_names_to_try.append(selectedSkinName());
skin_names_to_try.append(APP_SKIN_DEFAULT);
bool skin_parsed;
Skin skin_data;
QString skin_name;
@ -47,13 +45,12 @@ void SkinFactory::loadCurrentSkin() {
if (skin_parsed) {
loadSkinFromData(skin_data);
// Set this 'Skin' object as active one.
m_currentSkin = skin_data;
qDebug("Skin '%s' loaded.", qPrintable(skin_name));
return;
}
else {
qWarning("Failed to load skin '%s'.", qPrintable(skin_name));
}
@ -85,7 +82,6 @@ QString SkinFactory::selectedSkinName() const {
Skin SkinFactory::skinInfo(const QString& skin_name, bool* ok) const {
Skin skin;
QStringList base_skin_folders;
base_skin_folders.append(APP_SKIN_PATH);
base_skin_folders.append(getUserSkinBaseFolder());
@ -95,7 +91,6 @@ Skin SkinFactory::skinInfo(const QString &skin_name, bool *ok) const {
if (QFile::exists(metadata_file)) {
QFile skin_file(metadata_file);
QDomDocument dokument;
if (!skin_file.open(QIODevice::Text | QIODevice::ReadOnly) || !dokument.setContent(&skin_file, true)) {
@ -107,26 +102,19 @@ Skin SkinFactory::skinInfo(const QString &skin_name, bool *ok) const {
}
const QDomNode skin_node = dokument.namedItem(QSL("skin"));
// Obtain visible skin name.
skin.m_visibleName = skin_name;
// Obtain author.
skin.m_author = skin_node.namedItem(QSL("author")).namedItem(QSL("name")).toElement().text();
// Obtain email.
skin.m_email = skin_node.namedItem(QSL("author")).namedItem(QSL("email")).toElement().text();
// Obtain version.
skin.m_version = skin_node.attributes().namedItem(QSL("version")).toAttr().value();
// Obtain other information.
skin.m_baseName = skin_name;
// Free resources.
skin_file.close();
skin_file.deleteLater();
// Here we use "/" instead of QDir::separator() because CSS2.1 url field
// accepts '/' as path elements separator.
//
@ -135,19 +123,14 @@ Skin SkinFactory::skinInfo(const QString &skin_name, bool *ok) const {
// So if one uses "##/images/border.png" in QSS then it is
// replaced by fully absolute path and target file can
// be safely loaded.
skin.m_layoutMarkupWrapper = QString::fromUtf8(IOFactory::readTextFile(skin_folder + QL1S("html_wrapper.html")));
skin.m_layoutMarkupWrapper = skin.m_layoutMarkupWrapper.replace(QSL("##"), APP_SKIN_PATH + QL1S("/") + skin_name);
skin.m_enclosureImageMarkup = QString::fromUtf8(IOFactory::readTextFile(skin_folder + QL1S("html_enclosure_image.html")));
skin.m_enclosureImageMarkup = skin.m_enclosureImageMarkup.replace(QSL("##"), APP_SKIN_PATH + QL1S("/") + skin_name);
skin.m_layoutMarkup = QString::fromUtf8(IOFactory::readTextFile(skin_folder + QL1S("html_single_message.html")));
skin.m_layoutMarkup = skin.m_layoutMarkup.replace(QSL("##"), APP_SKIN_PATH + QL1S("/") + skin_name);
skin.m_enclosureMarkup = QString::fromUtf8(IOFactory::readTextFile(skin_folder + QL1S("html_enclosure_every.html")));
skin.m_enclosureMarkup = skin.m_enclosureMarkup.replace(QSL("##"), APP_SKIN_PATH + QL1S("/") + skin_name);
skin.m_rawData = QString::fromUtf8(IOFactory::readTextFile(skin_folder + QL1S("theme.css")));
skin.m_rawData = skin.m_rawData.replace(QSL("##"), APP_SKIN_PATH + QL1S("/") + skin_name);

View file

@ -59,6 +59,7 @@ SystemFactory::AutoStartStatus SystemFactory::getAutoStartStatus() const {
if (autostart_enabled) {
return SystemFactory::Enabled;
}
else {
return SystemFactory::Disabled;
}
@ -79,9 +80,9 @@ SystemFactory::AutoStartStatus SystemFactory::getAutoStartStatus() const {
// File exists, we must read it and check if "Hidden" attribute is defined and what is its value.
QSettings desktop_settings(desktop_file_location, QSettings::IniFormat);
bool hidden_value = desktop_settings.value(QSL("Desktop Entry/Hidden"), false).toBool();
return hidden_value ? SystemFactory::Disabled : SystemFactory::Enabled;
}
else {
return SystemFactory::Disabled;
}
@ -102,6 +103,7 @@ QString SystemFactory::getAutostartDesktopFileLocation() const {
// in 'autostart' subdirectory.
desktop_file_location = xdg_config_path + QSL("/autostart/") + APP_DESKTOP_ENTRY_FILE;
}
else {
// Desired variable is not set, look for the default 'autostart' subdirectory.
const QString home_directory(qgetenv("HOME"));
@ -141,6 +143,7 @@ bool SystemFactory::setAutoStartStatus(const AutoStartStatus &new_status) {
default:
return false;
}
#elif defined(Q_OS_LINUX)
// Note that we expect here that no other program uses
// "rssguard.desktop" desktop file.
@ -160,7 +163,6 @@ bool SystemFactory::setAutoStartStatus(const AutoStartStatus &new_status) {
}
const QString source_autostart_desktop_file = QString(APP_DESKTOP_ENTRY_PATH) + QDir::separator() + APP_DESKTOP_SOURCE_ENTRY_FILE;
return QFile::copy(source_autostart_desktop_file, destination_file);
}
@ -170,6 +172,7 @@ bool SystemFactory::setAutoStartStatus(const AutoStartStatus &new_status) {
default:
return false;
}
#else
return false;
#endif
@ -179,12 +182,11 @@ bool SystemFactory::setAutoStartStatus(const AutoStartStatus &new_status) {
bool SystemFactory::removeTrolltechJunkRegistryKeys() {
if (qApp->settings()->value(GROUP(General), SETTING(General::RemoveTrolltechJunk)).toBool()) {
QSettings registry_key(QSL("HKEY_CURRENT_USER\\Software\\TrollTech"), QSettings::NativeFormat);
registry_key.remove(QSL(""));
registry_key.sync();
return registry_key.status() == QSettings::NoError;
}
else {
return false;
}
@ -208,7 +210,6 @@ QString SystemFactory::getUsername() const {
QPair<QList<UpdateInfo>, QNetworkReply::NetworkError> SystemFactory::checkForUpdates() const {
QPair<QList<UpdateInfo>, QNetworkReply::NetworkError> result;
QByteArray releases_json;
result.second = NetworkFactory::performNetworkOperation(RELEASES_LIST, DOWNLOAD_TIMEOUT, QByteArray(), QString(),
releases_json, QNetworkAccessManager::GetOperation).first;
@ -231,6 +232,7 @@ bool SystemFactory::isVersionNewer(const QString &new_version, const QString &ba
// New version is indeed higher thatn current version.
return true;
}
else if (new_number < base_number) {
return false;
}
@ -241,10 +243,12 @@ bool SystemFactory::isVersionNewer(const QString &new_version, const QString &ba
// Versions are the same.
return false;
}
else {
if (new_version_tkn.isEmpty()) {
return false;
}
else {
return new_version_tkn.join(QString()).toInt() > 0;
}
@ -266,27 +270,22 @@ bool SystemFactory::openFolderFile(const QString &file_path) {
QList<UpdateInfo> SystemFactory::parseUpdatesFile(const QByteArray& updates_file) const {
QList<UpdateInfo> updates;
QJsonArray document = QJsonDocument::fromJson(updates_file).array();
for (int i = 0; i < document.size(); i++) {
QJsonObject release = document.at(i).toObject();
UpdateInfo update;
update.m_date = QDateTime::fromString(release["published_at"].toString(), QSL("yyyy-MM-ddTHH:mm:ssZ"));
update.m_availableVersion = release["tag_name"].toString();
update.m_changes = release["body"].toString();
QJsonArray assets = release["assets"].toArray();
for (int j = 0; j < assets.size(); j++) {
QJsonObject asset = assets.at(j).toObject();
UpdateUrl url;
url.m_fileUrl = asset["browser_download_url"].toString();
url.m_name = asset["name"].toString();
url.m_size = asset["size"].toVariant().toString() + tr(" bytes");
update.m_urls.append(url);
}
@ -296,7 +295,6 @@ QList<UpdateInfo> SystemFactory::parseUpdatesFile(const QByteArray &updates_file
qSort(updates.begin(), updates.end(), [](const UpdateInfo & a, const UpdateInfo & b) -> bool {
return a.m_date > b.m_date;
});
return updates;
}

View file

@ -60,14 +60,14 @@ QDateTime TextFactory::parseDateTime(const QString &date_time) {
QTime time_zone_offset;
const QLocale locale(QLocale::C);
bool positive_time_zone_offset = false;
QStringList date_patterns; date_patterns << QSL("yyyy-MM-ddTHH:mm:ss") << QSL("MMM dd yyyy hh:mm:ss") <<
QStringList date_patterns;
date_patterns << QSL("yyyy-MM-ddTHH:mm:ss") << QSL("MMM dd yyyy hh:mm:ss") <<
QSL("MMM d yyyy hh:mm:ss") << QSL("ddd, dd MMM yyyy HH:mm:ss") <<
QSL("dd MMM yyyy") << QSL("yyyy-MM-dd HH:mm:ss.z") << QSL("yyyy-MM-dd") <<
QSL("yyyy") << QSL("yyyy-MM") << QSL("yyyy-MM-dd") << QSL("yyyy-MM-ddThh:mm") <<
QSL("yyyy-MM-ddThh:mm:ss");
QStringList timezone_offset_patterns; timezone_offset_patterns << QSL("+hh:mm") << QSL("-hh:mm") << QSL("+hhmm")
QStringList timezone_offset_patterns;
timezone_offset_patterns << QSL("+hh:mm") << QSL("-hh:mm") << QSL("+hhmm")
<< QSL("-hhmm") << QSL("+hh") << QSL("-hh");
if (input_date.size() >= TIMEZONE_OFFSET_LIMIT) {
@ -96,11 +96,13 @@ QDateTime TextFactory::parseDateTime(const QString &date_time) {
// the original UTC.
return dt.addSecs(- QTime(0, 0, 0, 0).secsTo(time_zone_offset));
}
else {
// Vice versa.
return dt.addSecs(QTime(0, 0, 0, 0).secsTo(time_zone_offset));
}
}
else {
return dt;
}
@ -127,6 +129,7 @@ QString TextFactory::shorten(const QString &input, int text_length_limit) {
if (input.size() > text_length_limit) {
return input.left(text_length_limit - ELLIPSIS_LENGTH) + QString(ELLIPSIS_LENGTH, QL1C('.'));
}
else {
return input;
}
@ -140,6 +143,7 @@ quint64 TextFactory::initializeSecretEncryptionKey() {
try {
s_encryptionKey = (quint64) QString(IOFactory::readTextFile(encryption_file_path)).toLongLong();
}
catch (ApplicationException) {
// Well, key does not exist or is invalid, generate and save one.
s_encryptionKey = generateSecretEncryptionKey();

View file

@ -26,7 +26,6 @@
AdBlockAddSubscriptionDialog::AdBlockAddSubscriptionDialog(QWidget* parent)
: QDialog(parent), m_ui(new Ui::AdBlockAddSubscriptionDialog) {
m_ui->setupUi(this);
m_knownSubscriptions << Subscription(QSL("EasyList (English)"), ADBLOCK_EASYLIST_URL)
<< Subscription(QSL("BSI Lista Polska (Polish)"), QSL("http://www.bsi.info.pl/filtrABP.txt"))
<< Subscription(QSL("EasyList Czech and Slovak (Czech)"), QSL("https://raw.githubusercontent.com/tomasko126/easylistczechandslovak/master/filters.txt"))
@ -70,6 +69,7 @@ void AdBlockAddSubscriptionDialog::indexChanged(int index) {
m_ui->title->clear();
m_ui->url->clear();
}
else {
int pos = subscription.m_title.indexOf(QLatin1Char('('));
QString title = subscription.m_title;
@ -80,7 +80,6 @@ void AdBlockAddSubscriptionDialog::indexChanged(int index) {
m_ui->title->setText(title);
m_ui->title->setCursorPosition(0);
m_ui->url->setText(subscription.m_url);
m_ui->url->setCursorPosition(0);
}

View file

@ -34,13 +34,10 @@ AdBlockDialog::AdBlockDialog(QWidget* parent)
: QWidget(parent), m_ui(new Ui::AdBlockDialog), m_manager(AdBlockManager::instance()), m_currentTreeWidget(0), m_currentSubscription(0), m_loaded(false) {
setAttribute(Qt::WA_DeleteOnClose);
m_ui->setupUi(this);
#ifdef Q_OS_MACOS
m_ui->tabWidget->setDocumentMode(false);
#endif
m_ui->adblockCheckBox->setChecked(m_manager->isEnabled());
QMenu* menu = new QMenu(m_ui->buttonOptions);
m_actionAddRule = menu->addAction(tr("Add rule"), this, SLOT(addRule()));
m_actionRemoveRule = menu->addAction(tr("Remove rule"), this, SLOT(removeRule()));
@ -50,16 +47,12 @@ AdBlockDialog::AdBlockDialog(QWidget* parent)
menu->addAction(tr("Update subscriptions"), m_manager, SLOT(updateAllSubscriptions()));
menu->addSeparator();
menu->addAction(tr("Learn about writing rules..."), this, SLOT(learnAboutRules()));
m_ui->buttonOptions->setMenu(menu);
connect(menu, SIGNAL(aboutToShow()), this, SLOT(aboutToShowMenu()));
connect(m_ui->adblockCheckBox, SIGNAL(toggled(bool)), this, SLOT(enableAdBlock(bool)));
connect(m_ui->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(currentChanged(int)));
connect(m_ui->buttonBox, &QDialogButtonBox::clicked, this, &AdBlockDialog::close);
load();
m_ui->buttonBox->setFocus();
}
@ -102,7 +95,6 @@ void AdBlockDialog::addSubscription() {
if (AdBlockSubscription* subscription = m_manager->addSubscription(title, url)) {
AdBlockTreeWidget* tree = new AdBlockTreeWidget(subscription, m_ui->tabWidget);
int index = m_ui->tabWidget->insertTab(m_ui->tabWidget->count() - 1, tree, subscription->title());
m_ui->tabWidget->setCurrentIndex(index);
}
}
@ -131,7 +123,6 @@ void AdBlockDialog::enableAdBlock(bool state) {
void AdBlockDialog::aboutToShowMenu() {
bool subscriptionEditable = m_currentSubscription && m_currentSubscription->canEditRules();
bool subscriptionRemovable = m_currentSubscription && m_currentSubscription->canBeRemoved();
m_actionAddRule->setEnabled(subscriptionEditable);
m_actionRemoveRule->setEnabled(subscriptionEditable);
m_actionRemoveSubscription->setEnabled(subscriptionRemovable);
@ -159,6 +150,5 @@ void AdBlockDialog::load() {
}
m_loaded = true;
QTimer::singleShot(50, this, SLOT(loadSubscriptions()));
}

View file

@ -37,10 +37,8 @@ AdBlockIcon::AdBlockIcon(QWidget* parent)
setCursor(Qt::PointingHandCursor);
setToolTip(tr("AdBlock lets you block unwanted content on web pages"));
setFixedSize(16, 16);
connect(this, SIGNAL(clicked(QPoint)), this, SLOT(showMenu(QPoint)));
connect(AdBlockManager::instance(), SIGNAL(enabledChanged(bool)), this, SLOT(setEnabled(bool)));
m_enabled = AdBlockManager::instance()->isEnabled();
}
@ -52,10 +50,10 @@ AdBlockIcon::~AdBlockIcon() {
void AdBlockIcon::popupBlocked(const QString& ruleString, const QUrl& url) {
int index = ruleString.lastIndexOf(QLatin1String(" ("));
const QString subscriptionName = ruleString.left(index);
const QString filter = ruleString.mid(index + 2, ruleString.size() - index - 3);
AdBlockSubscription* subscription = AdBlockManager::instance()->subscriptionByName(subscriptionName);
if (filter.isEmpty() || !subscription) {
return;
}
@ -64,7 +62,6 @@ void AdBlockIcon::popupBlocked(const QString &ruleString, const QUrl &url) {
pair.first = new AdBlockRule(filter, subscription);
pair.second = url;
m_blockedPopups.append(pair);
qApp->showGuiMessage(tr("Blocked popup window"), tr("AdBlock blocked unwanted popup window."), QSystemTrayIcon::Information);
if (!m_flashTimer) {
@ -77,7 +74,6 @@ void AdBlockIcon::popupBlocked(const QString &ruleString, const QUrl &url) {
m_flashTimer->setInterval(500);
m_flashTimer->start();
connect(m_flashTimer, &QTimer::timeout, this, &AdBlockIcon::animateIcon);
}
@ -103,13 +99,10 @@ void AdBlockIcon::createMenu(QMenu *menu) {
}
menu->clear();
AdBlockManager* manager = AdBlockManager::instance();
AdBlockCustomList* customList = manager->customList();
WebPage* page = qApp->mainForm()->tabWidget()->currentWidget()->webBrowser()->viewer()->page();
const QUrl pageUrl = page->url();
menu->addAction(tr("Show AdBlock &settings"), manager, SLOT(showDialog()));
menu->addSeparator();
@ -117,19 +110,16 @@ void AdBlockIcon::createMenu(QMenu *menu) {
const QString host = page->url().host().contains(QLatin1String("www.")) ? pageUrl.host().mid(4) : pageUrl.host();
const QString hostFilter = QString("@@||%1^$document").arg(host);
const QString pageFilter = QString("@@|%1|$document").arg(pageUrl.toString());
QAction* act = menu->addAction(tr("Disable on %1").arg(host));
act->setCheckable(true);
act->setChecked(customList->containsFilter(hostFilter));
act->setData(hostFilter);
connect(act, SIGNAL(triggered()), this, SLOT(toggleCustomFilter()));
act = menu->addAction(tr("Disable only on this page"));
act->setCheckable(true);
act->setChecked(customList->containsFilter(pageFilter));
act->setData(pageFilter);
connect(act, SIGNAL(triggered()), this, SLOT(toggleCustomFilter()));
menu->addSeparator();
}
@ -138,10 +128,8 @@ void AdBlockIcon::createMenu(QMenu *menu) {
for (int i = 0; i < m_blockedPopups.count(); i++) {
const QPair<AdBlockRule*, QUrl>& pair = m_blockedPopups.at(i);
QString address = pair.second.toString().right(55);
QString actionText = tr("%1 with (%2)").arg(address, pair.first->filter()).replace(QL1C('&'), QL1S("&&"));
QAction* action = menu->addAction(actionText, manager, SLOT(showRule()));
action->setData(QVariant::fromValue((void*)pair.first));
}
@ -151,7 +139,6 @@ void AdBlockIcon::createMenu(QMenu *menu) {
void AdBlockIcon::showMenu(const QPoint& pos) {
QMenu menu;
createMenu(&menu);
menu.exec(pos);
}
@ -169,6 +156,7 @@ void AdBlockIcon::toggleCustomFilter() {
if (customList->containsFilter(filter)) {
customList->removeFilter(filter);
}
else {
AdBlockRule* rule = new AdBlockRule(filter, customList);
customList->addRule(rule);
@ -186,6 +174,7 @@ void AdBlockIcon::animateIcon() {
if (pixmap()->isNull()) {
setPixmap(qApp->icons()->miscIcon(ADBLOCK_ICON_ACTIVE).pixmap(16));
}
else {
setPixmap(QPixmap());
}
@ -195,7 +184,6 @@ void AdBlockIcon::stopAnimation() {
m_timerTicks = 0;
m_flashTimer->stop();
disconnect(m_flashTimer, SIGNAL(timeout()), this, SLOT(animateIcon()));
setEnabled(m_enabled);
}
@ -203,6 +191,7 @@ void AdBlockIcon::setEnabled(bool enabled) {
if (enabled) {
setPixmap(qApp->icons()->miscIcon(ADBLOCK_ICON_ACTIVE).pixmap(16));
}
else {
setPixmap(qApp->icons()->miscIcon(ADBLOCK_ICON_DISABLED).pixmap(16));
}

View file

@ -46,9 +46,13 @@ AdBlockManager::AdBlockManager(QObject* parent)
load();
}
AdBlockManager::~AdBlockManager() { qDeleteAll(m_subscriptions); }
AdBlockManager::~AdBlockManager() {
qDeleteAll(m_subscriptions);
}
AdBlockManager* AdBlockManager::instance() { return qz_adblock_manager(); }
AdBlockManager* AdBlockManager::instance() {
return qz_adblock_manager();
}
void AdBlockManager::setEnabled(bool enabled) {
if (m_enabled == enabled) {
@ -57,17 +61,16 @@ void AdBlockManager::setEnabled(bool enabled) {
m_enabled = enabled;
emit enabledChanged(enabled);
qApp->settings()->setValue(GROUP(AdBlock), AdBlock::AdBlockEnabled, m_enabled);
load();
// TODO: Reload user stylesheet.
// mApp->reloadUserStyleSheet();
QMutexLocker locker(&m_mutex);
if (m_enabled) {
m_matcher->update();
}
else {
m_matcher->clear();
}
@ -102,7 +105,6 @@ bool AdBlockManager::block(QWebEngineUrlRequestInfo& request) {
// We are blocking main URL frame, we can display "AdBlock error page" or
// redirect to somewhere.
// TODO: dodělat lepší
// TODO request.redirect() přesměrovat na "chybovou stranku";
// QUrl url(QSL("rssguard:adblock"));
// QUrlQuery query;
@ -111,9 +113,9 @@ bool AdBlockManager::block(QWebEngineUrlRequestInfo& request) {
// blockedRule->subscription()->title());
// url.setQuery(query);
// request.redirect(url);
request.block(true);
}
else {
request.block(true);
}
@ -122,7 +124,9 @@ bool AdBlockManager::block(QWebEngineUrlRequestInfo& request) {
return res;
}
QStringList AdBlockManager::disabledRules() const { return m_disabledRules; }
QStringList AdBlockManager::disabledRules() const {
return m_disabledRules;
}
void AdBlockManager::addDisabledRule(const QString& filter) {
m_disabledRules.append(filter);
@ -134,7 +138,6 @@ void AdBlockManager::removeDisabledRule(const QString& filter) {
bool AdBlockManager::addSubscriptionFromUrl(const QUrl& url) {
const QList<QPair<QString, QString>> queryItems = QUrlQuery(url).queryItems(QUrl::FullyDecoded);
QString subscriptionTitle;
QString subscriptionUrl;
@ -144,6 +147,7 @@ bool AdBlockManager::addSubscriptionFromUrl(const QUrl& url) {
if (pair.first == QL1S("location")) {
subscriptionUrl = pair.second;
}
else if (pair.first == QL1S("title")) {
subscriptionTitle = pair.second;
}
@ -154,7 +158,6 @@ bool AdBlockManager::addSubscriptionFromUrl(const QUrl& url) {
}
const QString message = tr("Do you want to add <b>%1</b> subscription?").arg(subscriptionTitle);
QMessageBox::StandardButton result = QMessageBox::question(nullptr, tr("Add AdBlock subscription"), message,
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
@ -174,8 +177,8 @@ AdBlockSubscription* AdBlockManager::addSubscription(const QString& title, const
QString fileName = title + QSL(".txt");
QString filePath = storedListsPath() + QDir::separator() + fileName;
QByteArray data = QString("Title: %1\nUrl: %2\n[Adblock Plus 1.1.1]").arg(title, url).toLatin1();
QSaveFile file(filePath);
if (!file.open(QFile::WriteOnly)) {
qWarning("Cannot save AdBlock subscription to file '%s'.", qPrintable(filePath));
return 0;
@ -183,19 +186,15 @@ AdBlockSubscription* AdBlockManager::addSubscription(const QString& title, const
file.write(data);
file.commit();
AdBlockSubscription* subscription = new AdBlockSubscription(title, this);
subscription->setUrl(QUrl(url));
subscription->setFilePath(filePath);
subscription->loadSubscription(m_disabledRules);
m_subscriptions.insert(m_subscriptions.count() - 1, subscription);
// TODO: po změně subskripce přehrat user css?
// connect(subscription, SIGNAL(subscriptionUpdated()), mApp,
// SLOT(reloadUserStyleSheet()));
connect(subscription, SIGNAL(subscriptionChanged()), this, SLOT(updateMatcher()));
return subscription;
}
@ -208,10 +207,8 @@ bool AdBlockManager::removeSubscription(AdBlockSubscription *subscription) {
QFile(subscription->filePath()).remove();
m_subscriptions.removeOne(subscription);
m_matcher->update();
delete subscription;
return true;
}
@ -278,7 +275,6 @@ void AdBlockManager::load() {
AdBlockSubscription* subscription = new AdBlockSubscription(title, this);
subscription->setUrl(url);
subscription->setFilePath(absolutePath);
m_subscriptions.append(subscription);
}
@ -289,7 +285,6 @@ void AdBlockManager::load() {
// Load all subscriptions
foreach (AdBlockSubscription* subscription, m_subscriptions) {
subscription->loadSubscription(m_disabledRules);
// TODO: po zmene subskripce prehrat user css?
// connect(subscription, SIGNAL(subscriptionUpdated()), mApp,
// SLOT(reloadUserStyleSheet()));
@ -302,13 +297,11 @@ void AdBlockManager::load() {
m_matcher->update();
m_loaded = true;
qApp->urlIinterceptor()->installUrlInterceptor(m_interceptor);
}
void AdBlockManager::updateMatcher() {
QMutexLocker locker(&m_mutex);
m_matcher->update();
}
@ -333,7 +326,9 @@ void AdBlockManager::save() {
qApp->settings()->setValue(GROUP(AdBlock), AdBlock::DisabledRules, m_disabledRules);
}
bool AdBlockManager::isEnabled() const { return m_enabled; }
bool AdBlockManager::isEnabled() const {
return m_enabled;
}
bool AdBlockManager::canRunOnScheme(const QString& scheme) const {
return !(scheme == QSL("file") || scheme == QSL("qrc") || scheme == QSL("data") || scheme == QSL("abp"));
@ -347,6 +342,7 @@ QString AdBlockManager::elementHidingRules(const QUrl& url) const {
if (!isEnabled() || !canRunOnScheme(url.scheme()) || !canBeBlocked(url)) {
return QString();
}
else {
return m_matcher->elementHidingRules();
}
@ -356,6 +352,7 @@ QString AdBlockManager::elementHidingRulesForDomain(const QUrl& url) const {
if (!isEnabled() || !canRunOnScheme(url.scheme()) || !canBeBlocked(url)) {
return QString();
}
else {
return m_matcher->elementHidingRulesForDomain(url.host());
}
@ -379,7 +376,6 @@ AdBlockDialog *AdBlockManager::showDialog() {
m_adBlockDialog.data()->show();
m_adBlockDialog.data()->raise();
m_adBlockDialog.data()->activateWindow();
return m_adBlockDialog.data();
}

View file

@ -61,8 +61,7 @@ class AdBlockManager : public QObject {
bool addSubscriptionFromUrl(const QUrl& url);
AdBlockSubscription *addSubscription(const QString& title,
const QString &url);
AdBlockSubscription* addSubscription(const QString& title, const QString& url);
bool removeSubscription(AdBlockSubscription* subscription);
AdBlockCustomList* customList() const;

View file

@ -115,6 +115,7 @@ QString AdBlockMatcher::elementHidingRulesForDomain(const QString &domain) const
rules.append(QSL("{display:none !important;}\n"));
addedRulesCount = 0;
}
else {
rules.append(rule->cssSelector() + QLatin1Char(','));
addedRulesCount++;
@ -131,7 +132,6 @@ QString AdBlockMatcher::elementHidingRulesForDomain(const QString &domain) const
void AdBlockMatcher::update() {
clear();
QHash<QString, const AdBlockRule*> cssRulesHash;
QVector<const AdBlockRule*> exceptionCssRules;
@ -152,21 +152,26 @@ void AdBlockMatcher::update() {
if (rule->isException()) {
exceptionCssRules.append(rule);
}
else {
cssRulesHash.insert(rule->cssSelector(), rule);
}
}
else if (rule->isDocument()) {
m_documentRules.append(rule);
}
else if (rule->isElemhide()) {
m_elemhideRules.append(rule);
}
else if (rule->isException()) {
if (!m_networkExceptionTree.add(rule)) {
m_networkExceptionRules.append(rule);
}
}
else {
if (!m_networkBlockTree.add(rule)) {
m_networkBlockRules.append(rule);
@ -186,7 +191,6 @@ void AdBlockMatcher::update() {
AdBlockRule* copiedRule = originalRule->copy();
copiedRule->m_options |= AdBlockRule::DomainRestrictedOption;
copiedRule->m_blockedDomains.append(rule->m_allowedDomains);
cssRulesHash[rule->cssSelector()] = copiedRule;
m_createdRules.append(copiedRule);
}
@ -204,11 +208,13 @@ void AdBlockMatcher::update() {
if (rule->isDomainRestricted()) {
m_domainRestrictedCssRules.append(rule);
}
else if (Q_UNLIKELY(hidingRulesCount == 1000)) {
m_elementHidingRules.append(rule->cssSelector());
m_elementHidingRules.append(QL1S("{display:none !important;} "));
hidingRulesCount = 0;
}
else {
m_elementHidingRules.append(rule->cssSelector() + QLatin1Char(','));
hidingRulesCount++;

View file

@ -91,7 +91,6 @@ AdBlockRule::~AdBlockRule() {
AdBlockRule* AdBlockRule::copy() const {
AdBlockRule* rule = new AdBlockRule();
rule->m_subscription = m_subscription;
rule->m_type = m_type;
rule->m_options = m_options;
@ -179,10 +178,10 @@ bool AdBlockRule::urlMatch(const QUrl &url) const {
if (!hasOption(DocumentOption) && !hasOption(ElementHideOption)) {
return false;
}
else {
const QString encodedUrl = url.toEncoded();
const QString domain = url.host();
return stringMatch(domain, encodedUrl);
}
}
@ -260,6 +259,7 @@ bool AdBlockRule::matchDomain(const QString &domain) const {
}
}
}
else if (m_allowedDomains.isEmpty()) {
foreach (const QString& d, m_blockedDomains) {
if (isMatchingDomain(domain, d)) {
@ -269,6 +269,7 @@ bool AdBlockRule::matchDomain(const QString &domain) const {
return true;
}
else {
foreach (const QString& d, m_blockedDomains) {
if (isMatchingDomain(domain, d)) {
@ -290,51 +291,42 @@ bool AdBlockRule::matchThirdParty(const QWebEngineUrlRequestInfo &request) const
// Third-party matching should be performed on second-level domains.
const QString firstPartyHost = toSecondLevelDomain(request.firstPartyUrl());
const QString host = toSecondLevelDomain(request.requestUrl());
bool match = firstPartyHost != host;
return hasException(ThirdPartyOption) ? !match : match;
}
bool AdBlockRule::matchObject(const QWebEngineUrlRequestInfo& request) const {
bool match = request.resourceType() == QWebEngineUrlRequestInfo::ResourceTypeObject;
return hasException(ObjectOption) ? !match : match;
}
bool AdBlockRule::matchSubdocument(const QWebEngineUrlRequestInfo& request) const {
bool match = request.resourceType() == QWebEngineUrlRequestInfo::ResourceTypeSubFrame;
return hasException(SubdocumentOption) ? !match : match;
}
bool AdBlockRule::matchXmlHttpRequest(const QWebEngineUrlRequestInfo& request) const {
bool match = request.resourceType() == QWebEngineUrlRequestInfo::ResourceTypeXhr;
return hasException(XMLHttpRequestOption) ? !match : match;
}
bool AdBlockRule::matchImage(const QWebEngineUrlRequestInfo& request) const {
bool match = request.resourceType() == QWebEngineUrlRequestInfo::ResourceTypeImage;
return hasException(ImageOption) ? !match : match;
}
bool AdBlockRule::matchScript(const QWebEngineUrlRequestInfo& request) const {
bool match = request.resourceType() == QWebEngineUrlRequestInfo::ResourceTypeScript;
return hasException(ScriptOption) ? !match : match;
}
bool AdBlockRule::matchStyleSheet(const QWebEngineUrlRequestInfo& request) const {
bool match = request.resourceType() == QWebEngineUrlRequestInfo::ResourceTypeStylesheet;
return hasException(StyleSheetOption) ? !match : match;
}
bool AdBlockRule::matchObjectSubrequest(const QWebEngineUrlRequestInfo& request) const {
bool match = request.resourceType() == QWebEngineUrlRequestInfo::ResourceTypeSubResource;
return hasException(ObjectSubrequestOption) ? !match : match;
}
@ -364,7 +356,6 @@ void AdBlockRule::parseFilter() {
m_isException = parsedLine.at(pos + 1) == QL1C('@');
m_matchString = parsedLine.mid(m_isException ? pos + 3 : pos + 2);
// CSS rule cannot have more options -> stop parsing.
return;
}
@ -387,58 +378,70 @@ void AdBlockRule::parseFilter() {
parseDomains(option.mid(7), QL1C('|'));
++handledOptions;
}
else if (option == QL1S("match-case")) {
m_caseSensitivity = Qt::CaseSensitive;
++handledOptions;
}
else if (option.endsWith(QL1S("third-party"))) {
setOption(ThirdPartyOption);
setException(ThirdPartyOption, option.startsWith(QL1C('~')));
++handledOptions;
}
else if (option.endsWith(QL1S("object"))) {
setOption(ObjectOption);
setException(ObjectOption, option.startsWith(QL1C('~')));
++handledOptions;
}
else if (option.endsWith(QL1S("subdocument"))) {
setOption(SubdocumentOption);
setException(SubdocumentOption, option.startsWith(QL1C('~')));
++handledOptions;
}
else if (option.endsWith(QL1S("xmlhttprequest"))) {
setOption(XMLHttpRequestOption);
setException(XMLHttpRequestOption, option.startsWith(QL1C('~')));
++handledOptions;
}
else if (option.endsWith(QL1S("image"))) {
setOption(ImageOption);
setException(ImageOption, option.startsWith(QL1C('~')));
++handledOptions;
}
else if (option.endsWith(QL1S("script"))) {
setOption(ScriptOption);
setException(ScriptOption, option.startsWith(QL1C('~')));
++handledOptions;
}
else if (option.endsWith(QL1S("stylesheet"))) {
setOption(StyleSheetOption);
setException(StyleSheetOption, option.startsWith(QL1C('~')));
++handledOptions;
}
else if (option.endsWith(QL1S("object-subrequest"))) {
setOption(ObjectSubrequestOption);
setException(ObjectSubrequestOption, option.startsWith(QL1C('~')));
++handledOptions;
}
else if (option == QL1S("document") && m_isException) {
setOption(DocumentOption);
++handledOptions;
}
else if (option == QL1S("elemhide") && m_isException) {
setOption(ElementHideOption);
++handledOptions;
}
else if (option == QL1S("collapse")) {
// Hiding placeholders of blocked elements is enabled by default.
++handledOptions;
@ -459,7 +462,6 @@ void AdBlockRule::parseFilter() {
if (parsedLine.startsWith(QL1C('/')) && parsedLine.endsWith(QL1C('/'))) {
parsedLine = parsedLine.mid(1);
parsedLine = parsedLine.left(parsedLine.size() - 1);
m_type = RegExpMatchRule;
m_regExp = new RegExp;
m_regExp->regExp = SimpleRegExp(parsedLine, m_caseSensitivity);
@ -480,7 +482,6 @@ void AdBlockRule::parseFilter() {
if (filterIsOnlyDomain(parsedLine)) {
parsedLine = parsedLine.mid(2);
parsedLine = parsedLine.left(parsedLine.size() - 1);
m_type = DomainMatchRule;
m_matchString = parsedLine;
return;
@ -489,7 +490,6 @@ void AdBlockRule::parseFilter() {
// If rule contains only | at end, we can also use string matching.
if (filterIsOnlyEndsMatch(parsedLine)) {
parsedLine = parsedLine.left(parsedLine.size() - 1);
m_type = StringEndsMatchRule;
m_matchString = parsedLine;
return;
@ -517,9 +517,11 @@ void AdBlockRule::parseDomains(const QString &domains, const QChar &separator) {
if (domain.isEmpty()) {
continue;
}
if (domain.startsWith(QL1C('~'))) {
m_blockedDomains.append(domain.mid(1));
}
else {
m_allowedDomains.append(domain);
}
@ -578,11 +580,11 @@ static bool wordCharacter(const QChar &c) {
QString AdBlockRule::createRegExpFromFilter(const QString& filter) const {
QString parsed;
parsed.reserve(filter.size());
bool hadWildcard = false; // Filter multiple wildcards.
for (int i = 0; i < filter.size(); ++i) {
const QChar c = filter.at(i);
switch (c.toLatin1()) {
case '^':
parsed.append(QL1S("(?:[^\\w\\d\\-.%]|$)"));
@ -592,6 +594,7 @@ QString AdBlockRule::createRegExpFromFilter(const QString &filter) const {
if (!hadWildcard) {
parsed.append(QL1S(".*"));
}
break;
case '|':
@ -600,21 +603,26 @@ QString AdBlockRule::createRegExpFromFilter(const QString &filter) const {
parsed.append(QL1S("^[\\w\\-]+:\\/+(?!\\/)(?:[^\\/]+\\.)?"));
i++;
}
else {
parsed.append('^');
}
break;
}
else if (i == filter.size() - 1) {
parsed.append(QL1C('$'));
break;
}
// fallthrough
default:
if (!wordCharacter(c)) {
parsed.append(QL1C('\\') + c);
}
else {
parsed.append(c);
}
@ -641,16 +649,20 @@ bool AdBlockRule::stringMatch(const QString &domain, const QString &encodedUrl)
if (m_type == StringContainsMatchRule) {
return encodedUrl.contains(m_matchString, m_caseSensitivity);
}
else if (m_type == DomainMatchRule) {
return isMatchingDomain(domain, m_matchString);
}
else if (m_type == StringEndsMatchRule) {
return encodedUrl.endsWith(m_matchString, m_caseSensitivity);
}
else if (m_type == RegExpMatchRule) {
if (!isMatchingRegExpStrings(encodedUrl)) {
return false;
}
else {
return (m_regExp->regExp.indexIn(encodedUrl) != -1);
}
@ -669,7 +681,6 @@ bool AdBlockRule::matchDomain(const QString &pattern, const QString &domain) con
}
int index = domain.indexOf(pattern);
return index > 0 && domain[index - 1] == QLatin1Char('.');
}
@ -717,7 +728,6 @@ QStringList AdBlockRule::parseRegExpFilter(const QString &filter) const {
}
list.removeDuplicates();
return list;
}

View file

@ -63,7 +63,6 @@ bool AdBlockSearchTree::add(const AdBlockRule *rule) {
}
node->rule = rule;
return true;
}
@ -93,7 +92,6 @@ const AdBlockRule *AdBlockSearchTree::prefixSearch(const QWebEngineUrlRequestInf
}
QChar c = string[0];
Node* node = m_root->children.value(c);
if (!node) {

View file

@ -101,7 +101,6 @@ void AdBlockSubscription::loadSubscription(const QStringList &disabledRules) {
QTextStream textStream(&file);
textStream.setCodec("UTF-8");
// Header is on 3rd line.
textStream.readLine(1024);
textStream.readLine(1024);
@ -140,7 +139,6 @@ void AdBlockSubscription::updateSubscription() {
}
SilentNetworkAccessManager* mgs = new SilentNetworkAccessManager(this);
m_reply = mgs->get(QNetworkRequest(m_url));
connect(m_reply, &QNetworkReply::finished, this, &AdBlockSubscription::subscriptionDownloaded);
}
@ -167,7 +165,6 @@ void AdBlockSubscription::subscriptionDownloaded() {
}
loadSubscription(AdBlockManager::instance()->disabledRules());
emit subscriptionUpdated();
emit subscriptionChanged();
}
@ -179,6 +176,7 @@ bool AdBlockSubscription::saveDownloadedData(const QByteArray &data) {
qWarning("Unable to open AdBlock file '%s' for writing.", qPrintable(m_filePath));
return false;
}
else {
// Write subscription header
file.write(QString("Title: %1\nUrl: %2\n").arg(title(), url().toString()).toUtf8());
@ -192,6 +190,7 @@ const AdBlockRule *AdBlockSubscription::rule(int offset) const {
if (IS_IN_ARRAY(offset, m_rules)) {
return m_rules[offset];
}
else {
return 0;
}
@ -206,7 +205,6 @@ const AdBlockRule *AdBlockSubscription::enableRule(int offset) {
AdBlockRule* rule = m_rules[offset];
rule->setEnabled(true);
AdBlockManager::instance()->removeDisabledRule(rule->filter());
emit subscriptionChanged();
if (rule->isCssRule()) {
@ -216,6 +214,7 @@ const AdBlockRule *AdBlockSubscription::enableRule(int offset) {
return rule;
}
else {
return 0;
}
@ -229,7 +228,6 @@ const AdBlockRule *AdBlockSubscription::disableRule(int offset) {
AdBlockRule* rule = m_rules[offset];
rule->setEnabled(false);
AdBlockManager::instance()->addDisabledRule(rule->filter());
emit subscriptionChanged();
if (rule->isCssRule()) {
@ -279,7 +277,6 @@ void AdBlockCustomList::loadSubscription(const QStringList &disabledRules) {
// DuckDuckGo ad whitelist rules
// They cannot be removed, but can be disabled.
// Please consider not disabling them. Thanks!
const QString ddg1 = QSL("@@||duckduckgo.com^$document");
const QString ddg2 = QSL("duckduckgo.com#@#.has-ad");
QString rules;
@ -287,8 +284,8 @@ void AdBlockCustomList::loadSubscription(const QStringList &disabledRules) {
try {
rules = QString::fromUtf8(IOFactory::readTextFile(filePath()));
}
catch (ApplicationException&) {
catch (ApplicationException&) {
}
QFile file(filePath());
@ -301,15 +298,16 @@ void AdBlockCustomList::loadSubscription(const QStringList &disabledRules) {
QTextStream stream(&file);
stream.setCodec("UTF-8");
if (!rules.contains(ddg1 + QL1S("\n")))
if (!rules.contains(ddg1 + QL1S("\n"))) {
stream << ddg1 << endl;
}
if (!rules.contains(QL1S("\n") + ddg2))
if (!rules.contains(QL1S("\n") + ddg2)) {
stream << ddg2 << endl;
}
}
file.close();
AdBlockSubscription::loadSubscription(disabledRules);
}
@ -322,7 +320,6 @@ void AdBlockCustomList::saveSubscription() {
}
QTextStream textStream(&file);
textStream.setCodec("UTF-8");
textStream << "Title: " << title() << endl;
textStream << "Url: " << url().toString() << endl;
@ -367,7 +364,6 @@ bool AdBlockCustomList::removeFilter(const QString &filter) {
int AdBlockCustomList::addRule(AdBlockRule* rule) {
m_rules.append(rule);
emit subscriptionChanged();
if (rule->isCssRule()) {
@ -385,9 +381,7 @@ bool AdBlockCustomList::removeRule(int offset) {
AdBlockRule* rule = m_rules.at(offset);
const QString filter = rule->filter();
m_rules.remove(offset);
emit subscriptionChanged();
if (rule->isCssRule()) {
@ -396,7 +390,6 @@ bool AdBlockCustomList::removeRule(int offset) {
}
AdBlockManager::instance()->removeDisabledRule(filter);
delete rule;
return true;
}
@ -408,7 +401,6 @@ const AdBlockRule *AdBlockCustomList::replaceRule(AdBlockRule *rule, int offset)
AdBlockRule* oldRule = m_rules.at(offset);
m_rules[offset] = rule;
emit subscriptionChanged();
if (rule->isCssRule() || oldRule->isCssRule()) {

View file

@ -34,7 +34,6 @@ AdBlockTreeWidget::AdBlockTreeWidget(AdBlockSubscription *subscription, QWidget
setHeaderHidden(true);
setAlternatingRowColors(true);
setLayoutDirection(Qt::LeftToRight);
connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuRequested(QPoint)));
connect(this, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(itemChanged(QTreeWidgetItem*)));
connect(m_subscription, SIGNAL(subscriptionUpdated()), this, SLOT(subscriptionUpdated()));
@ -49,12 +48,12 @@ void AdBlockTreeWidget::showRule(const AdBlockRule *rule) {
if (!m_topItem && rule) {
m_ruleToBeSelected = rule->filter();
}
else if (!m_ruleToBeSelected.isEmpty()) {
QList<QTreeWidgetItem*> items = findItems(m_ruleToBeSelected, Qt::MatchRecursive);
if (!items.isEmpty()) {
QTreeWidgetItem* item = items.at(0);
setCurrentItem(item);
scrollToItem(item, QAbstractItemView::PositionAtCenter);
}
@ -92,27 +91,25 @@ void AdBlockTreeWidget::itemChanged(QTreeWidgetItem *item) {
}
m_itemChangingBlock = true;
int offset = item->data(0, Qt::UserRole + 10).toInt();
const AdBlockRule* oldRule = m_subscription->rule(offset);
if (item->checkState(0) == Qt::Unchecked && oldRule->isEnabled()) {
// Disable rule.
const AdBlockRule* rule = m_subscription->disableRule(offset);
adjustItemFeatures(item, rule);
}
else if (item->checkState(0) == Qt::Checked && !oldRule->isEnabled()) {
// Enable rule.
const AdBlockRule* rule = m_subscription->enableRule(offset);
adjustItemFeatures(item, rule);
}
else if (m_subscription->canEditRules()) {
// Custom rule has been changed.
AdBlockRule* newRule = new AdBlockRule(item->text(0), m_subscription);
const AdBlockRule* rule = m_subscription->replaceRule(newRule, offset);
adjustItemFeatures(item, rule);
}
@ -142,16 +139,13 @@ void AdBlockTreeWidget::addRule() {
AdBlockRule* rule = new AdBlockRule(newRule, m_subscription);
int offset = m_subscription->addRule(rule);
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0, newRule);
item->setData(0, Qt::UserRole + 10, offset);
item->setFlags(item->flags() | Qt::ItemIsEditable);
m_itemChangingBlock = true;
m_topItem->addChild(item);
m_itemChangingBlock = false;
adjustItemFeatures(item, rule);
}
@ -163,14 +157,12 @@ void AdBlockTreeWidget::removeRule() {
}
int offset = item->data(0, Qt::UserRole + 10).toInt();
m_subscription->removeRule(offset);
deleteItem(item);
}
void AdBlockTreeWidget::subscriptionUpdated() {
refresh();
m_itemChangingBlock = true;
m_topItem->setText(0, tr("%1 (recently updated)").arg(m_subscription->title()));
m_itemChangingBlock = false;
@ -178,7 +170,6 @@ void AdBlockTreeWidget::subscriptionUpdated() {
void AdBlockTreeWidget::subscriptionError(const QString& message) {
refresh();
m_itemChangingBlock = true;
m_topItem->setText(0, tr("%1 (Error: %2)").arg(m_subscription->title(), message));
m_itemChangingBlock = false;
@ -206,6 +197,7 @@ void AdBlockTreeWidget::adjustItemFeatures(QTreeWidgetItem* item, const AdBlockR
item->setForeground(0, QColor(Qt::darkGreen));
item->setFont(0, QFont());
}
else if (rule->isCssRule()) {
item->setForeground(0, QColor(Qt::darkBlue));
item->setFont(0, QFont());
@ -227,19 +219,16 @@ void AdBlockTreeWidget::keyPressEvent(QKeyEvent* event) {
void AdBlockTreeWidget::refresh() {
m_itemChangingBlock = true;
clear();
QFont boldFont;
boldFont.setBold(true);
m_topItem = new QTreeWidgetItem(this);
m_topItem->setText(0, m_subscription->title());
m_topItem->setFont(0, boldFont);
m_topItem->setExpanded(true);
addTopLevelItem(m_topItem);
const QVector<AdBlockRule*>& allRules = m_subscription->allRules();
int index = 0;
foreach (const AdBlockRule* rule, allRules) {
QTreeWidgetItem* item = new QTreeWidgetItem(m_topItem);
item->setText(0, rule->filter());

View file

@ -43,12 +43,13 @@ void BaseNetworkAccessManager::loadSettings() {
// No extra setting is needed, set new proxy and exit this method.
setProxy(QNetworkProxy::NoProxy);
}
else if (selected_proxy_type == QNetworkProxy::DefaultProxy) {
setProxy(QNetworkProxy::applicationProxy());
}
else {
const Settings* settings = qApp->settings();
// Custom proxy is selected, set it up.
new_proxy.setType(selected_proxy_type);
new_proxy.setHostName(settings->value(GROUP(Proxy), SETTING(Proxy::Host)).toString());
@ -70,13 +71,10 @@ QNetworkReply *BaseNetworkAccessManager::createRequest(QNetworkAccessManager::Op
const QNetworkRequest& request,
QIODevice* outgoingData) {
QNetworkRequest new_request = request;
// This rapidly speeds up loading of web sites.
// NOTE: https://en.wikipedia.org/wiki/HTTP_pipelining
new_request.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
// Setup custom user-agent.
new_request.setRawHeader(USER_AGENT_HTTP_HEADER, QString(APP_USERAGENT).toLocal8Bit());
return QNetworkAccessManager::createRequest(op, new_request, outgoingData);
}

View file

@ -27,10 +27,8 @@ Downloader::Downloader(QObject *parent)
m_timer(new QTimer(this)), m_customHeaders(QHash<QByteArray, QByteArray>()), m_inputData(QByteArray()),
m_targetProtected(false), m_targetUsername(QString()), m_targetPassword(QString()),
m_lastOutputData(QByteArray()), m_lastOutputError(QNetworkReply::NoError), m_lastContentType(QVariant()) {
m_timer->setInterval(DOWNLOAD_TIMEOUT);
m_timer->setSingleShot(true);
connect(m_timer, &QTimer::timeout, this, &Downloader::cancel);
}
@ -52,7 +50,6 @@ void Downloader::manipulateData(const QString &url, QNetworkAccessManager::Opera
int timeout, bool protected_contents, const QString& username, const QString& password) {
QNetworkRequest request;
QString non_const_url = url;
QHashIterator<QByteArray, QByteArray> i(m_customHeaders);
while (i.hasNext()) {
@ -61,7 +58,6 @@ void Downloader::manipulateData(const QString &url, QNetworkAccessManager::Opera
}
m_inputData = data;
// Set url for this request and fire it up.
m_timer->setInterval(timeout);
@ -69,6 +65,7 @@ void Downloader::manipulateData(const QString &url, QNetworkAccessManager::Opera
qDebug("Replacing URI schemes for '%s'.", qPrintable(non_const_url));
request.setUrl(non_const_url.replace(QRegExp(QString('^') + URI_SCHEME_FEED), QString(URI_SCHEME_HTTP)));
}
else {
request.setUrl(non_const_url);
}
@ -80,12 +77,15 @@ void Downloader::manipulateData(const QString &url, QNetworkAccessManager::Opera
if (operation == QNetworkAccessManager::PostOperation) {
runPostRequest(request, m_inputData);
}
else if (operation == QNetworkAccessManager::GetOperation) {
runGetRequest(request);
}
else if (operation == QNetworkAccessManager::PutOperation) {
runPutRequest(request, m_inputData);
}
else if (operation == QNetworkAccessManager::DeleteOperation) {
runDeleteRequest(request);
}
@ -94,9 +94,7 @@ void Downloader::manipulateData(const QString &url, QNetworkAccessManager::Opera
void Downloader::finished() {
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
QNetworkAccessManager::Operation reply_operation = reply->operation();
m_timer->stop();
// In this phase, some part of downloading process is completed.
const QUrl redirection_url = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
@ -108,6 +106,7 @@ void Downloader::finished() {
if (redirection_url.host().isEmpty()) {
request.setUrl(QUrl(reply->request().url().scheme() + QSL("://") + reply->request().url().host() + redirection_url.toString()));
}
else {
request.setUrl(redirection_url);
}
@ -118,26 +117,28 @@ void Downloader::finished() {
if (reply_operation == QNetworkAccessManager::GetOperation) {
runGetRequest(request);
}
else if (reply_operation == QNetworkAccessManager::PostOperation) {
runPostRequest(request, m_inputData);
}
else if (reply_operation == QNetworkAccessManager::PutOperation) {
runPutRequest(request, m_inputData);
}
else if (reply_operation == QNetworkAccessManager::DeleteOperation) {
runDeleteRequest(request);
}
}
else {
// No redirection is indicated. Final file is obtained in our "reply" object.
// Read the data into output buffer.
m_lastOutputData = reply->readAll();
m_lastContentType = reply->header(QNetworkRequest::ContentTypeHeader);
m_lastOutputError = reply->error();
m_activeReply->deleteLater();
m_activeReply = nullptr;
emit completed(m_lastOutputError, m_lastOutputData);
}
}
@ -153,11 +154,9 @@ void Downloader::progressInternal(qint64 bytes_received, qint64 bytes_total) {
void Downloader::runDeleteRequest(const QNetworkRequest& request) {
m_timer->start();
m_activeReply = m_downloadManager->deleteResource(request);
m_activeReply->setProperty("protected", m_targetProtected);
m_activeReply->setProperty("username", m_targetUsername);
m_activeReply->setProperty("password", m_targetPassword);
connect(m_activeReply, &QNetworkReply::downloadProgress, this, &Downloader::progressInternal);
connect(m_activeReply, &QNetworkReply::finished, this, &Downloader::finished);
}
@ -165,11 +164,9 @@ void Downloader::runDeleteRequest(const QNetworkRequest &request) {
void Downloader::runPutRequest(const QNetworkRequest& request, const QByteArray& data) {
m_timer->start();
m_activeReply = m_downloadManager->put(request, data);
m_activeReply->setProperty("protected", m_targetProtected);
m_activeReply->setProperty("username", m_targetUsername);
m_activeReply->setProperty("password", m_targetPassword);
connect(m_activeReply, &QNetworkReply::downloadProgress, this, &Downloader::progressInternal);
connect(m_activeReply, &QNetworkReply::finished, this, &Downloader::finished);
}
@ -177,11 +174,9 @@ void Downloader::runPutRequest(const QNetworkRequest &request, const QByteArray
void Downloader::runPostRequest(const QNetworkRequest& request, const QByteArray& data) {
m_timer->start();
m_activeReply = m_downloadManager->post(request, data);
m_activeReply->setProperty("protected", m_targetProtected);
m_activeReply->setProperty("username", m_targetUsername);
m_activeReply->setProperty("password", m_targetPassword);
connect(m_activeReply, &QNetworkReply::downloadProgress, this, &Downloader::progressInternal);
connect(m_activeReply, &QNetworkReply::finished, this, &Downloader::finished);
}
@ -189,11 +184,9 @@ void Downloader::runPostRequest(const QNetworkRequest &request, const QByteArray
void Downloader::runGetRequest(const QNetworkRequest& request) {
m_timer->start();
m_activeReply = m_downloadManager->get(request);
m_activeReply->setProperty("protected", m_targetProtected);
m_activeReply->setProperty("username", m_targetUsername);
m_activeReply->setProperty("password", m_targetPassword);
connect(m_activeReply, &QNetworkReply::downloadProgress, this, &Downloader::progressInternal);
connect(m_activeReply, &QNetworkReply::finished, this, &Downloader::finished);
}

View file

@ -46,9 +46,7 @@ DownloadItem::DownloadItem(QNetworkReply *reply, QWidget *parent) : QWidget(pare
m_gettingFileName(false), m_canceledFileSelect(false) {
m_ui->setupUi(this);
m_ui->m_btnTryAgain->hide();
m_requestFileName = qApp->settings()->value(GROUP(Downloads), SETTING(Downloads::AlwaysPromptForFilename)).toBool();
connect(m_ui->m_btnStopDownload, &QToolButton::clicked, this, &DownloadItem::stop);
connect(m_ui->m_btnOpenFile, &QToolButton::clicked, this, &DownloadItem::openFile);
connect(m_ui->m_btnTryAgain, &QToolButton::clicked, this, &DownloadItem::tryAgain);
@ -71,18 +69,15 @@ void DownloadItem::init() {
m_ui->m_btnOpenFolder->setEnabled(false);
m_url = m_reply->url();
m_reply->setParent(this);
connect(m_reply, &QNetworkReply::readyRead, this, &DownloadItem::downloadReadyRead);
connect(m_reply, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error), this, &DownloadItem::error);
connect(m_reply, &QNetworkReply::downloadProgress, this, &DownloadItem::downloadProgress);
connect(m_reply, &QNetworkReply::metaDataChanged, this, &DownloadItem::metaDataChanged);
connect(m_reply, &QNetworkReply::finished, this, &DownloadItem::finished);
// Reset info.
m_ui->m_lblInfoDownload->clear();
m_ui->m_progressDownload->setValue(0);
getFileName();
// Start timer for the download estimation.
m_downloadTime.start();
@ -111,7 +106,6 @@ void DownloadItem::getFileName() {
if (chosen_filename.isEmpty()) {
stop();
m_ui->m_progressDownload->setVisible(false);
m_ui->m_lblLocalFilename->setText(tr("Selection of local file cancelled."));
m_canceledFileSelect = true;
@ -119,20 +113,17 @@ void DownloadItem::getFileName() {
}
const QFileInfo file_info = QFileInfo(chosen_filename);
qApp->settings()->setValue(GROUP(Downloads), Downloads::TargetExplicitDirectory,
QDir::toNativeSeparators(QFileInfo(chosen_filename).absolutePath()));
qApp->downloadManager()->setDownloadDirectory(file_info.absoluteDir().absolutePath());
}
m_output.setFileName(chosen_filename);
// Check file path for saving.
const QDir save_dir = QFileInfo(m_output.fileName()).dir();
if (!save_dir.exists() && !save_dir.mkpath(save_dir.absolutePath())) {
stop();
m_ui->m_progressDownload->setVisible(false);
m_ui->m_lblInfoDownload->setText(tr("Download directory couldn't be created"));
return;
@ -186,7 +177,8 @@ QString DownloadItem::saveFileName(const QString &directory) const {
do {
name = directory + base_name + QL1C('-') + QString::number(i++) + end_name;
} while (QFile::exists(name));
}
while (QFile::exists(name));
}
return name;
@ -199,7 +191,6 @@ void DownloadItem::stop() {
m_ui->m_btnTryAgain->setEnabled(true);
m_ui->m_btnTryAgain->show();
setUpdatesEnabled(true);
m_reply->abort();
emit downloadFinished();
}
@ -234,7 +225,6 @@ void DownloadItem::tryAgain() {
m_ui->m_btnStopDownload->setEnabled(true);
m_ui->m_btnStopDownload->setVisible(true);
m_ui->m_progressDownload->setVisible(true);
QNetworkReply* new_download = qApp->downloadManager()->networkManager()->get(QNetworkRequest(m_url));
if (m_reply) {
@ -246,7 +236,6 @@ void DownloadItem::tryAgain() {
}
m_reply = new_download;
init();
emit statusChanged();
}
@ -264,7 +253,6 @@ void DownloadItem::downloadReadyRead() {
if (!m_output.open(QIODevice::WriteOnly)) {
m_ui->m_lblInfoDownload->setText(tr("Error opening output file: %1").arg(m_output.errorString()));
stop();
emit statusChanged();
return;
}
@ -276,6 +264,7 @@ void DownloadItem::downloadReadyRead() {
m_ui->m_lblInfoDownload->setText(tr("Error when saving file: %1").arg(m_output.errorString()));
m_ui->m_btnStopDownload->click();
}
else {
m_startedSaving = true;
@ -287,11 +276,9 @@ void DownloadItem::downloadReadyRead() {
void DownloadItem::error(QNetworkReply::NetworkError code) {
Q_UNUSED(code)
m_ui->m_lblInfoDownload->setText(tr("Error: %1").arg(m_reply->errorString()));
m_ui->m_btnTryAgain->setEnabled(true);
m_ui->m_btnTryAgain->setVisible(true);
emit downloadFinished();
}
@ -302,7 +289,6 @@ void DownloadItem::metaDataChanged() {
m_url = locationHeader.toUrl();
m_reply->deleteLater();
m_reply = qApp->downloadManager()->networkManager()->get(QNetworkRequest(m_url));
init();
return;
}
@ -317,7 +303,6 @@ void DownloadItem::downloadProgress(qint64 bytes_received, qint64 bytes_total) {
m_lastProgressTime = now;
m_bytesReceived = bytes_received;
qint64 currentValue = 0;
qint64 totalValue = 0;
@ -328,7 +313,6 @@ void DownloadItem::downloadProgress(qint64 bytes_received, qint64 bytes_total) {
m_ui->m_progressDownload->setValue(currentValue);
m_ui->m_progressDownload->setMaximum(totalValue);
emit progress(currentValue, totalValue);
updateDownloadInfoLabel();
}
@ -360,6 +344,7 @@ double DownloadItem::currentSpeed() const {
if (!downloading()) {
return -1.0;
}
else {
return m_bytesReceived * 1000.0 / m_downloadTime.elapsed();
}
@ -374,7 +359,6 @@ void DownloadItem::updateDownloadInfoLabel() {
bool running = !downloadedSuccessfully();
double speed = currentSpeed();
double time_remaining = remainingTime();
QString info;
if (running) {
@ -389,10 +373,12 @@ void DownloadItem::updateDownloadInfoLabel() {
DownloadManager::dataString((int)speed),
remaining);
}
else {
if (m_bytesReceived == bytes_total) {
info = DownloadManager::dataString(m_output.size());
}
else {
info = tr("%1 of %2 - download completed").arg(DownloadManager::dataString(m_bytesReceived),
DownloadManager::dataString(m_bytesReceived));
@ -424,7 +410,6 @@ void DownloadItem::finished() {
m_ui->m_btnOpenFolder->setEnabled(true);
m_output.close();
updateDownloadInfoLabel();
emit statusChanged();
emit downloadFinished();
@ -450,7 +435,6 @@ DownloadManager::DownloadManager(QWidget *parent) : TabContent(parent), m_ui(new
m_ui->m_viewDownloads->setAlternatingRowColors(true);
m_ui->m_viewDownloads->horizontalHeader()->setStretchLastSection(true);
m_ui->m_viewDownloads->setModel(m_model);
setDownloadDirectory(qApp->settings()->value(GROUP(Downloads), SETTING(Downloads::TargetDirectory)).toString());
connect(m_ui->m_btnCleanup, &QPushButton::clicked, this, &DownloadManager::cleanup);
load();
@ -459,7 +443,6 @@ DownloadManager::DownloadManager(QWidget *parent) : TabContent(parent), m_ui(new
DownloadManager::~DownloadManager() {
m_autoSaver->changeOccurred();
m_autoSaver->saveIfNeccessary();
qDebug("Destroying DownloadManager instance.");
}
@ -489,6 +472,7 @@ int DownloadManager::downloadProgress() const {
if (bytes_total <= 0) {
return -1;
}
else {
return (bytes_received * 100.0) / bytes_total;
}
@ -530,17 +514,14 @@ void DownloadManager::addItem(DownloadItem *item) {
connect(item, &DownloadItem::statusChanged, this, static_cast<void (DownloadManager::*)()>(&DownloadManager::updateRow));
connect(item, &DownloadItem::progress, this, &DownloadManager::itemProgress);
connect(item, &DownloadItem::downloadFinished, this, &DownloadManager::itemFinished);
const int row = m_downloads.count();
m_model->beginInsertRows(QModelIndex(), row, row);
m_downloads.append(item);
m_model->endInsertRows();
m_ui->m_viewDownloads->setIndexWidget(m_model->index(row, 0), item);
QIcon icon = style()->standardIcon(QStyle::SP_FileIcon);
item->m_ui->m_lblFileIcon->setPixmap(icon.pixmap(DOWNLOADER_ICON_SIZE, DOWNLOADER_ICON_SIZE));
m_ui->m_viewDownloads->setRowHeight(row, item->sizeHint().height());
// Just in case of download finishes before it is actually added.
updateRow(item);
}
@ -569,6 +550,7 @@ void DownloadManager::itemProgress() {
if (progress < 0) {
emit downloadFinished();
}
else {
emit downloadProgressed(progress, tr("Downloading %n file(s)...", "", activeDownloads()));
}
@ -592,10 +574,8 @@ void DownloadManager::updateRow(DownloadItem *item) {
}
item->m_ui->m_lblFileIcon->setPixmap(icon.pixmap(DOWNLOADER_ICON_SIZE, DOWNLOADER_ICON_SIZE));
int old_height = m_ui->m_viewDownloads->rowHeight(row);
m_ui->m_viewDownloads->setRowHeight(row, qMax(old_height, item->minimumSizeHint().height()));
// Remove the item if:
// a) It is not downloading and private browsing is enabled.
// OR
@ -644,7 +624,6 @@ void DownloadManager::save() const {
settings->remove(GROUP(Downloads), key);
settings->remove(GROUP(Downloads), QString(Downloads::ItemLocation).arg(i));
settings->remove(GROUP(Downloads), QString(Downloads::ItemDone).arg(i));
i++;
}
}
@ -652,7 +631,6 @@ void DownloadManager::save() const {
void DownloadManager::load() {
const Settings* settings = qApp->settings();
int i = 0;
// Restore the policy.
m_removePolicy = static_cast<RemovePolicy>(settings->value(GROUP(Downloads), SETTING(Downloads::RemovePolicy)).toInt());
@ -666,9 +644,7 @@ void DownloadManager::load() {
DownloadItem* item = new DownloadItem(0, this);
item->m_output.setFileName(file_name);
item->m_url = url;
item->updateInfoAndUrlLabel();
item->m_ui->m_btnStopDownload->setVisible(false);
item->m_ui->m_btnStopDownload->setEnabled(false);
item->m_ui->m_btnTryAgain->setVisible(!done);
@ -710,6 +686,7 @@ QString DownloadManager::timeString(double time_remaining) {
time_remaining = floor(time_remaining);
remaining = tr("%n minutes remaining", "", (int) time_remaining);
}
else {
time_remaining = floor(time_remaining);
remaining = tr("%n seconds remaining", "", (int) time_remaining);
@ -726,14 +703,17 @@ QString DownloadManager::dataString(qint64 size) {
new_size = size;
unit = tr("bytes");
}
else if (size < 1024 * 1024) {
new_size = (double)size / (double)1024;
unit = tr("kB");
}
else if (size < 1024 * 1024 * 1024) {
new_size = (double)size / (double)(1024 * 1024);
unit = tr("MB");
}
else {
new_size = (double)size / (double)(1024 * 1024 * 1024);
unit = tr("GB");

View file

@ -69,11 +69,9 @@ GoogleSuggest::GoogleSuggest(LocationLineEdit *editor, QObject *parent)
popup->setFrameStyle(QFrame::Box | QFrame::Plain);
popup->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
popup->installEventFilter(this);
timer = new QTimer(this);
timer->setSingleShot(true);
timer->setInterval(500);
connect(popup.data(), &QListWidget::itemClicked, this, &GoogleSuggest::doneCompletion);
connect(timer, &QTimer::timeout, this, &GoogleSuggest::autoSuggest);
connect(editor, &LocationLineEdit::textEdited, timer, static_cast<void (QTimer::*)()>(&QTimer::start));
@ -154,7 +152,6 @@ void GoogleSuggest::doneCompletion() {
timer->stop();
popup->hide();
editor->setFocus();
QListWidgetItem* item = popup->currentItem();
if (item != nullptr) {
@ -169,7 +166,6 @@ void GoogleSuggest::preventSuggest() {
void GoogleSuggest::autoSuggest() {
m_enteredText = QUrl::toPercentEncoding(editor->text());
QString url = QString(GOOGLE_SUGGEST_URL).arg(m_enteredText);
connect(SilentNetworkAccessManager::instance()->get(QNetworkRequest(QString(url))), &QNetworkReply::finished,
this, &GoogleSuggest::handleNetworkData);
}
@ -181,10 +177,8 @@ void GoogleSuggest::handleNetworkData() {
QStringList choices;
QDomDocument xml;
QByteArray response = reply->readAll();
const QTextCodec* c = QTextCodec::codecForUtfText(response);
xml.setContent(c->toUnicode(response));
QDomNodeList suggestions = xml.elementsByTagName(QSL("suggestion"));
for (int i = 0; i < suggestions.size(); i++) {

View file

@ -47,6 +47,7 @@ QStringList NetworkFactory::extractFeedLinksFromHtmlPage(const QUrl &url, const
if (feed_link.startsWith(QL1S("//"))) {
feed_link = QString(URI_SCHEME_HTTP) + feed_link.mid(2);
}
else if (feed_link.startsWith(QL1C('/'))) {
feed_link = url.toString(QUrl::RemovePath | QUrl::RemoveQuery | QUrl::StripTrailingSlash) + feed_link;
}
@ -163,19 +164,16 @@ NetworkResult NetworkFactory::performNetworkOperation(const QString &url, int ti
if (set_basic_header) {
QString basic_value = username + ":" + password;
QString header_value = QString("Basic ") + QString(basic_value.toUtf8().toBase64());
downloader.appendRawHeader("Authorization", header_value.toLocal8Bit());
}
// We need to quit event loop when the download finishes.
QObject::connect(&downloader, &Downloader::completed, &loop, &QEventLoop::quit);
downloader.manipulateData(url, operation, input_data, timeout, protected_contents, username, password);
loop.exec();
output = downloader.lastOutputData();
result.first = downloader.lastOutputError();
result.second = downloader.lastContentType();
return result;
}
@ -187,17 +185,13 @@ NetworkResult NetworkFactory::downloadFeedFile(const QString &url, int timeout,
Downloader downloader;
QEventLoop loop;
NetworkResult result;
downloader.appendRawHeader("Accept", ACCEPT_HEADER_FOR_FEED_DOWNLOADER);
// We need to quit event loop when the download finishes.
QObject::connect(&downloader, &Downloader::completed, &loop, &QEventLoop::quit);
downloader.downloadFile(url, timeout, protected_contents, username, password);
loop.exec();
output = downloader.lastOutputData();
result.first = downloader.lastOutputError();
result.second = downloader.lastContentType();
return result;
}

View file

@ -49,12 +49,11 @@ void SilentNetworkAccessManager::onAuthenticationRequired(QNetworkReply *reply,
authenticator->setUser(reply->property("username").toString());
authenticator->setPassword(reply->property("password").toString());
reply->setProperty("authentication-given", true);
qDebug("Item '%s' requested authentication and got it.", qPrintable(reply->url().toString()));
}
else {
reply->setProperty("authentication-given", false);
// Authentication is required but this feed does not contain it.
qWarning("Item '%s' requested authentication but username/password is not available.", qPrintable(reply->url().toString()));
}

View file

@ -39,10 +39,10 @@ bool WebFactory::sendMessageViaEmail(const Message &message) {
if (qApp->settings()->value(GROUP(Browser), SETTING(Browser::CustomExternalEmailEnabled)).toBool()) {
const QString browser = qApp->settings()->value(GROUP(Browser), SETTING(Browser::CustomExternalEmailExecutable)).toString();
const QString arguments = qApp->settings()->value(GROUP(Browser), SETTING(Browser::CustomExternalEmailArguments)).toString();
return QProcess::startDetached(QString("\"") + browser + QSL("\" ") + arguments.arg(message.m_title,
stripTags(message.m_contents)));
}
else {
// Send it via mailto protocol.
// NOTE: http://en.wikipedia.org/wiki/Mailto
@ -55,11 +55,8 @@ bool WebFactory::openUrlInExternalBrowser(const QString &url) {
if (qApp->settings()->value(GROUP(Browser), SETTING(Browser::CustomExternalBrowserEnabled)).toBool()) {
const QString browser = qApp->settings()->value(GROUP(Browser), SETTING(Browser::CustomExternalBrowserExecutable)).toString();
const QString arguments = qApp->settings()->value(GROUP(Browser), SETTING(Browser::CustomExternalBrowserArguments)).toString();
const QString call_line = "\"" + browser + "\" \"" + arguments.arg(url) + "\"";
qDebug("Running command '%s'.", qPrintable(call_line));
const bool result = QProcess::startDetached(call_line);
if (!result) {
@ -68,6 +65,7 @@ bool WebFactory::openUrlInExternalBrowser(const QString &url) {
return result;
}
else {
return QDesktopServices::openUrl(url);
}

View file

@ -42,19 +42,24 @@ void WebPage::javaScriptAlert(const QUrl &securityOrigin, const QString &msg) {
if (action == QSL("read")) {
emit messageStatusChangeRequested(message_id, MarkRead);
}
else if (action == QSL("unread")) {
emit messageStatusChangeRequested(message_id, MarkUnread);
}
else if (action == QSL("starred")) {
emit messageStatusChangeRequested(message_id, MarkStarred);
}
else if (action == QSL("unstarred")) {
emit messageStatusChangeRequested(message_id, MarkUnstarred);
}
else {
QWebEnginePage::javaScriptAlert(securityOrigin, msg);
}
}
else {
QWebEnginePage::javaScriptAlert(securityOrigin, msg);
}
@ -65,6 +70,7 @@ bool WebPage::acceptNavigationRequest(const QUrl &url, NavigationType type, bool
setHtml(view()->messageContents(), QUrl(INTERNAL_URL_MESSAGE));
return true;
}
else {
return QWebEnginePage::acceptNavigationRequest(url, type, isMainFrame);
}

View file

@ -68,9 +68,9 @@ namespace QtLP_Private {
const char* QtLocalPeer::ack = "ack";
QtLocalPeer::QtLocalPeer(QObject* parent, const QString& appId)
: QObject(parent), id(appId)
{
: QObject(parent), id(appId) {
QString prefix = id;
if (id.isEmpty()) {
id = QCoreApplication::applicationFilePath();
#if defined(Q_OS_WIN)
@ -78,28 +78,29 @@ QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId)
#endif
prefix = id.section(QLatin1Char('/'), -1);
}
prefix.remove(QRegExp("[^a-zA-Z]"));
prefix.truncate(6);
QByteArray idc = id.toUtf8();
quint16 idNum = qChecksum(idc.constData(), idc.size());
socketName = QLatin1String("qtsingleapp-") + prefix
+ QLatin1Char('-') + QString::number(idNum, 16);
#if defined(Q_OS_WIN)
if (!pProcessIdToSessionId) {
QLibrary lib("kernel32");
pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
}
if (pProcessIdToSessionId) {
DWORD sessionId = 0;
pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
socketName += QLatin1Char('-') + QString::number(sessionId, 16);
}
#else
socketName += QLatin1Char('-') + QString::number(::getuid(), 16);
#endif
server = new QLocalServer(this);
QString lockName = QDir(QDir::tempPath()).absolutePath()
+ QLatin1Char('/') + socketName
@ -116,42 +117,52 @@ QtLocalPeer::~QtLocalPeer() {
bool QtLocalPeer::isClient()
{
if (lockFile.isLocked())
bool QtLocalPeer::isClient() {
if (lockFile.isLocked()) {
return false;
}
if (!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false))
if (!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false)) {
return true;
}
bool res = server->listen(socketName);
#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0))
// ### Workaround
if (!res && server->serverError() == QAbstractSocket::AddressInUseError) {
QFile::remove(QDir::cleanPath(QDir::tempPath()) + QLatin1Char('/') + socketName);
res = server->listen(socketName);
}
#endif
if (!res)
if (!res) {
qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString()));
}
QObject::connect(server, &QLocalServer::newConnection, this, &QtLocalPeer::receiveConnection);
return false;
}
bool QtLocalPeer::sendMessage(const QString &message, int timeout)
{
if (!isClient())
bool QtLocalPeer::sendMessage(const QString& message, int timeout) {
if (!isClient()) {
return false;
}
QLocalSocket socket;
bool connOk = false;
for (int i = 0; i < 2; i++) {
// Try twice, in case the other instance is just starting up
socket.connectToServer(socketName);
connOk = socket.waitForConnected(timeout / 2);
if (connOk || i)
if (connOk || i) {
break;
}
int ms = 250;
#if defined(Q_OS_WIN)
Sleep(DWORD(ms));
@ -160,30 +171,39 @@ bool QtLocalPeer::sendMessage(const QString &message, int timeout)
nanosleep(&ts, nullptr);
#endif
}
if (!connOk)
if (!connOk) {
return false;
}
QByteArray uMsg(message.toUtf8());
QDataStream ds(&socket);
ds.writeBytes(uMsg.constData(), uMsg.size());
bool res = socket.waitForBytesWritten(timeout);
if (res) {
res &= socket.waitForReadyRead(timeout); // wait for ack
if (res)
if (res) {
res &= (socket.read(qstrlen(ack)) == ack);
}
}
return res;
}
void QtLocalPeer::receiveConnection()
{
void QtLocalPeer::receiveConnection() {
QLocalSocket* socket = server->nextPendingConnection();
if (!socket)
return;
while (socket->bytesAvailable() < (int)sizeof(quint32))
if (!socket) {
return;
}
while (socket->bytesAvailable() < (int)sizeof(quint32)) {
socket->waitForReadyRead();
}
QDataStream ds(socket);
QByteArray uMsg;
quint32 remaining;
@ -191,16 +211,20 @@ void QtLocalPeer::receiveConnection()
uMsg.resize(remaining);
int got = 0;
char* uMsgBuf = uMsg.data();
do {
got = ds.readRawData(uMsgBuf, remaining);
remaining -= got;
uMsgBuf += got;
} while (remaining && got >= 0 && socket->waitForReadyRead(2000));
}
while (remaining && got >= 0 && socket->waitForReadyRead(2000));
if (got < 0) {
qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData());
delete socket;
return;
}
QString message(QString::fromUtf8(uMsg));
socket->write(ack, qstrlen(ack));
socket->waitForBytesWritten(1000);

8
src/qtsingleapplication/qtlocalpeer.h Normal file → Executable file
View file

@ -47,8 +47,7 @@
#include "qtlockedfile.h"
class QtLocalPeer : public QObject
{
class QtLocalPeer : public QObject {
Q_OBJECT
public:
@ -56,8 +55,9 @@ public:
~QtLocalPeer();
bool isClient();
bool sendMessage(const QString& message, int timeout);
QString applicationId() const
{ return id; }
QString applicationId() const {
return id;
}
Q_SIGNALS:
void messageReceived(const QString& message);

16
src/qtsingleapplication/qtlockedfile.cpp Normal file → Executable file
View file

@ -81,8 +81,7 @@
\sa QFile::QFile()
*/
QtLockedFile::QtLockedFile()
: QFile()
{
: QFile() {
#ifdef Q_OS_WIN
wmutex = 0;
rmutex = 0;
@ -98,8 +97,7 @@ QtLockedFile::QtLockedFile()
\sa QFile::QFile()
*/
QtLockedFile::QtLockedFile(const QString& name)
: QFile(name)
{
: QFile(name) {
#ifdef Q_OS_WIN
wmutex = 0;
rmutex = 0;
@ -120,12 +118,12 @@ QtLockedFile::QtLockedFile(const QString &name)
\sa QFile::open(), QFile::resize()
*/
bool QtLockedFile::open(OpenMode mode)
{
bool QtLockedFile::open(OpenMode mode) {
if (mode & QIODevice::Truncate) {
qWarning("QtLockedFile::open(): Truncate mode not allowed.");
return false;
}
return QFile::open(mode);
}
@ -135,8 +133,7 @@ bool QtLockedFile::open(OpenMode mode)
\sa lockMode()
*/
bool QtLockedFile::isLocked() const
{
bool QtLockedFile::isLocked() const {
return m_lock_mode != NoLock;
}
@ -146,8 +143,7 @@ bool QtLockedFile::isLocked() const
\sa isLocked()
*/
QtLockedFile::LockMode QtLockedFile::lockMode() const
{
QtLockedFile::LockMode QtLockedFile::lockMode() const {
return m_lock_mode;
}

3
src/qtsingleapplication/qtlockedfile.h Normal file → Executable file
View file

@ -64,8 +64,7 @@
namespace QtLP_Private {
class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile
{
class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile {
Q_OBJECT
public:

40
src/qtsingleapplication/qtlockedfile_unix.cpp Normal file → Executable file
View file

@ -45,57 +45,71 @@
#include "qtlockedfile.h"
bool QtLockedFile::lock(LockMode mode, bool block)
{
bool QtLockedFile::lock(LockMode mode, bool block) {
if (!isOpen()) {
qWarning("QtLockedFile::lock(): file is not opened");
return false;
}
if (mode == NoLock)
if (mode == NoLock) {
return unlock();
}
if (mode == m_lock_mode)
if (mode == m_lock_mode) {
return true;
}
if (m_lock_mode != NoLock)
if (m_lock_mode != NoLock) {
unlock();
}
struct flock fl;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK;
int cmd = block ? F_SETLKW : F_SETLK;
int ret = fcntl(handle(), cmd, &fl);
if (ret == -1) {
if (errno != EINTR && errno != EAGAIN)
if (errno != EINTR && errno != EAGAIN) {
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
return false;
}
return false;
}
m_lock_mode = mode;
return true;
}
bool QtLockedFile::unlock()
{
bool QtLockedFile::unlock() {
if (!isOpen()) {
qWarning("QtLockedFile::unlock(): file is not opened");
return false;
}
if (!isLocked())
if (!isLocked()) {
return true;
}
struct flock fl;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = F_UNLCK;
int ret = fcntl(handle(), F_SETLKW, &fl);
if (ret == -1) {
@ -107,9 +121,9 @@ bool QtLockedFile::unlock()
return true;
}
QtLockedFile::~QtLockedFile()
{
if (isOpen())
QtLockedFile::~QtLockedFile() {
if (isOpen()) {
unlock();
}
}

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