Merge branch 'master' of bitbucket.org:skunkos/rssguard
This commit is contained in:
commit
107aa0d432
43 changed files with 331 additions and 142 deletions
|
|
@ -19,7 +19,10 @@ You can [support RSS Guard with tiny amounts of money via PayPal](https://www.pa
|
||||||
|
|
||||||
People who donated:
|
People who donated:
|
||||||
|
|
||||||
* Zdenek S. (Sweden).
|
* Zdenek S. (Sweden)
|
||||||
|
* Eloi Garibaldi B.
|
||||||
|
|
||||||
|
I say "thank you" for all your support, donators.
|
||||||
|
|
||||||
- - -
|
- - -
|
||||||
Feeds & Videos
|
Feeds & Videos
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
Added:
|
Added:
|
||||||
|
|
||||||
▪ Added generic "Add new feed" action, which can be accessed via "Feeds & messages" menu. (issue #146)
|
▪ Added generic "Add new feed" action, which can be accessed via "Feeds & messages" menu. (issue #146)
|
||||||
|
▪ Added support for import/export to/from plain TXT file (one feed URL per line). (issue #142)
|
||||||
|
▪ Optimized menu items in "Add new item" submenu. Added two new bindable actions for adding feeds & categories. (issues #146 and #148)
|
||||||
|
|
||||||
Changed:
|
Changed:
|
||||||
|
|
||||||
|
|
@ -12,6 +14,7 @@ Changed:
|
||||||
|
|
||||||
Fixed:
|
Fixed:
|
||||||
|
|
||||||
|
▪ Expand status if items in feed list are now persistent when performing sync-in of TT-RSS accounts. (bug #149)
|
||||||
▪ Fixed problem with importing invalid OPML 2.0 files. (bug #145)
|
▪ Fixed problem with importing invalid OPML 2.0 files. (bug #145)
|
||||||
▪ Fixed error in SQL initialization script which led to problems with in-memory SQLite DBs. (bug #140)
|
▪ Fixed error in SQL initialization script which led to problems with in-memory SQLite DBs. (bug #140)
|
||||||
▪ Fixed problem with saving sort column/order for message list. (bug #141)
|
▪ Fixed problem with saving sort column/order for message list. (bug #141)
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ void FeedDownloader::updateFeeds(const QList<Feed*> &feeds) {
|
||||||
int updated_messages = feeds.at(i)->update();
|
int updated_messages = feeds.at(i)->update();
|
||||||
|
|
||||||
if (updated_messages > 0) {
|
if (updated_messages > 0) {
|
||||||
results.m_updatedFeeds.append(QPair<QString,int>(feeds.at(i)->title(), updated_messages));
|
results.updatedFeeds().append(QPair<QString,int>(feeds.at(i)->title(), updated_messages));
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug("Made progress in feed updates: %d/%d (id of feed is %d).", i + 1, total, feeds.at(i)->id());
|
qDebug("Made progress in feed updates: %d/%d (id of feed is %d).", i + 1, total, feeds.at(i)->id());
|
||||||
|
|
@ -62,7 +62,12 @@ void FeedDownloader::updateFeeds(const QList<Feed*> &feeds) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QString FeedDownloadResults::getOverview(int how_many_feeds) {
|
FeedDownloadResults::FeedDownloadResults() : m_updatedFeeds(QList<QPair<QString,int> >()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
QString FeedDownloadResults::overview(int how_many_feeds) {
|
||||||
qSort(m_updatedFeeds.begin(), m_updatedFeeds.end(), FeedDownloadResults::lessThan);
|
qSort(m_updatedFeeds.begin(), m_updatedFeeds.end(), FeedDownloadResults::lessThan);
|
||||||
|
|
||||||
QStringList result;
|
QStringList result;
|
||||||
|
|
@ -79,3 +84,11 @@ QString FeedDownloadResults::getOverview(int how_many_feeds) {
|
||||||
|
|
||||||
return res_str;
|
return res_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FeedDownloadResults::lessThan(const QPair<QString, int> &lhs, const QPair<QString, int> &rhs) {
|
||||||
|
return lhs.second > rhs.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QPair<QString,int> > &FeedDownloadResults::updatedFeeds() {
|
||||||
|
return m_updatedFeeds;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,16 +26,16 @@
|
||||||
class Feed;
|
class Feed;
|
||||||
|
|
||||||
// Represents results of batch feed updates.
|
// Represents results of batch feed updates.
|
||||||
struct FeedDownloadResults {
|
class FeedDownloadResults {
|
||||||
explicit FeedDownloadResults() : m_updatedFeeds(QList<QPair<QString,int> >()) {
|
public:
|
||||||
}
|
explicit FeedDownloadResults();
|
||||||
|
|
||||||
QString getOverview(int how_many_feeds);
|
QList<QPair<QString,int> > &updatedFeeds();
|
||||||
|
QString overview(int how_many_feeds);
|
||||||
|
|
||||||
static bool lessThan(const QPair<QString,int> &lhs, const QPair<QString,int> &rhs) {
|
static bool lessThan(const QPair<QString,int> &lhs, const QPair<QString,int> &rhs);
|
||||||
return lhs.second > rhs.second;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
private:
|
||||||
// QString represents title if the feed, int represents count of newly downloaded messages.
|
// QString represents title if the feed, int represents count of newly downloaded messages.
|
||||||
QList<QPair<QString,int> > m_updatedFeeds;
|
QList<QPair<QString,int> > m_updatedFeeds;
|
||||||
};
|
};
|
||||||
|
|
@ -69,7 +69,7 @@ class FeedDownloader : public QObject {
|
||||||
// "Current" number indicates count of processed feeds
|
// "Current" number indicates count of processed feeds
|
||||||
// and "total" number indicates total number of feeds
|
// and "total" number indicates total number of feeds
|
||||||
// which were in the initial queue.
|
// which were in the initial queue.
|
||||||
void progress(Feed *feed, int current, int total);
|
void progress(const Feed *feed, int current, int total);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FEEDDOWNLOADER_H
|
#endif // FEEDDOWNLOADER_H
|
||||||
|
|
|
||||||
|
|
@ -172,9 +172,9 @@ void FeedsModel::onFeedUpdatesFinished(FeedDownloadResults results) {
|
||||||
qApp->feedUpdateLock()->unlock();
|
qApp->feedUpdateLock()->unlock();
|
||||||
qApp->mainForm()->statusBar()->clearProgressFeeds();
|
qApp->mainForm()->statusBar()->clearProgressFeeds();
|
||||||
|
|
||||||
if (!results.m_updatedFeeds.isEmpty()) {
|
if (!results.updatedFeeds().isEmpty()) {
|
||||||
// Now, inform about results via GUI message/notification.
|
// Now, inform about results via GUI message/notification.
|
||||||
qApp->showGuiMessage(tr("New messages downloaded"), results.getOverview(10), QSystemTrayIcon::NoIcon,
|
qApp->showGuiMessage(tr("New messages downloaded"), results.overview(10), QSystemTrayIcon::NoIcon,
|
||||||
0, false, qApp->icons()->fromTheme(QSL("item-update-all")));
|
0, false, qApp->icons()->fromTheme(QSL("item-update-all")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -691,6 +691,7 @@ bool FeedsModel::addServiceAccount(ServiceRoot *root, bool freshly_activated) {
|
||||||
connect(root, SIGNAL(dataChanged(QList<RootItem*>)), this, SLOT(onItemDataChanged(QList<RootItem*>)));
|
connect(root, SIGNAL(dataChanged(QList<RootItem*>)), this, SLOT(onItemDataChanged(QList<RootItem*>)));
|
||||||
connect(root, SIGNAL(reloadMessageListRequested(bool)), this, SIGNAL(reloadMessageListRequested(bool)));
|
connect(root, SIGNAL(reloadMessageListRequested(bool)), this, SIGNAL(reloadMessageListRequested(bool)));
|
||||||
connect(root, SIGNAL(itemExpandRequested(QList<RootItem*>,bool)), this, SIGNAL(itemExpandRequested(QList<RootItem*>,bool)));
|
connect(root, SIGNAL(itemExpandRequested(QList<RootItem*>,bool)), this, SIGNAL(itemExpandRequested(QList<RootItem*>,bool)));
|
||||||
|
connect(root, SIGNAL(itemExpandStateSaveRequested(RootItem*)), this, SIGNAL(itemExpandStateSaveRequested(RootItem*)));
|
||||||
|
|
||||||
root->start(freshly_activated);
|
root->start(freshly_activated);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -726,7 +727,7 @@ bool FeedsModel::emptyAllBins() {
|
||||||
|
|
||||||
void FeedsModel::loadActivatedServiceAccounts() {
|
void FeedsModel::loadActivatedServiceAccounts() {
|
||||||
// Iterate all globally available feed "service plugins".
|
// Iterate all globally available feed "service plugins".
|
||||||
foreach (ServiceEntryPoint *entry_point, qApp->feedServices()) {
|
foreach (const ServiceEntryPoint *entry_point, qApp->feedServices()) {
|
||||||
// Load all stored root nodes from the entry point and add those to the model.
|
// Load all stored root nodes from the entry point and add those to the model.
|
||||||
QList<ServiceRoot*> roots = entry_point->initializeSubtree();
|
QList<ServiceRoot*> roots = entry_point->initializeSubtree();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -212,6 +212,10 @@ class FeedsModel : public QAbstractItemModel {
|
||||||
// Emitted if any item requested that any view should expand it.
|
// Emitted if any item requested that any view should expand it.
|
||||||
void itemExpandRequested(QList<RootItem*> items, bool expand);
|
void itemExpandRequested(QList<RootItem*> items, bool expand);
|
||||||
|
|
||||||
|
// Emitted if any item requested that its expand states should be explicitly saved.
|
||||||
|
// NOTE: Normally expand states are saved when application quits.
|
||||||
|
void itemExpandStateSaveRequested(RootItem *subtree_root);
|
||||||
|
|
||||||
// Emitted when there is a need of reloading of displayed messages.
|
// Emitted when there is a need of reloading of displayed messages.
|
||||||
void reloadMessageListRequested(bool mark_selected_messages_read);
|
void reloadMessageListRequested(bool mark_selected_messages_read);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
|
|
||||||
|
|
||||||
FormAbout::FormAbout(QWidget *parent) : QDialog(parent), m_ui(new Ui::FormAbout) {
|
FormAbout::FormAbout(QWidget *parent) : QDialog(parent), m_ui(new Ui::FormAbout()) {
|
||||||
m_ui->setupUi(this);
|
m_ui->setupUi(this);
|
||||||
|
|
||||||
// Set flags and attributes.
|
// Set flags and attributes.
|
||||||
|
|
@ -54,7 +54,6 @@ FormAbout::FormAbout(QWidget *parent) : QDialog(parent), m_ui(new Ui::FormAbout)
|
||||||
|
|
||||||
FormAbout::~FormAbout() {
|
FormAbout::~FormAbout() {
|
||||||
qDebug("Destroying FormAbout instance.");
|
qDebug("Destroying FormAbout instance.");
|
||||||
delete m_ui;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FormAbout::loadSettingsAndPaths() {
|
void FormAbout::loadSettingsAndPaths() {
|
||||||
|
|
|
||||||
2
src/gui/dialogs/formabout.h
Normal file → Executable file
2
src/gui/dialogs/formabout.h
Normal file → Executable file
|
|
@ -41,7 +41,7 @@ class FormAbout : public QDialog {
|
||||||
void loadLicenseAndInformation();
|
void loadLicenseAndInformation();
|
||||||
void loadSettingsAndPaths();
|
void loadSettingsAndPaths();
|
||||||
|
|
||||||
Ui::FormAbout *m_ui;
|
QScopedPointer<Ui::FormAbout> m_ui;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FORMABOUT_H
|
#endif // FORMABOUT_H
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,7 @@ QList<QAction*> FormMain::allActions() {
|
||||||
actions << m_ui->m_actionServiceEdit;
|
actions << m_ui->m_actionServiceEdit;
|
||||||
actions << m_ui->m_actionServiceDelete;
|
actions << m_ui->m_actionServiceDelete;
|
||||||
actions << m_ui->m_actionAddFeedIntoSelectedAccount;
|
actions << m_ui->m_actionAddFeedIntoSelectedAccount;
|
||||||
|
actions << m_ui->m_actionAddCategoryIntoSelectedAccount;
|
||||||
actions << m_ui->m_actionViewSelectedItemsNewspaperMode;
|
actions << m_ui->m_actionViewSelectedItemsNewspaperMode;
|
||||||
actions << m_ui->m_actionSelectNextItem;
|
actions << m_ui->m_actionSelectNextItem;
|
||||||
actions << m_ui->m_actionSelectPreviousItem;
|
actions << m_ui->m_actionSelectPreviousItem;
|
||||||
|
|
@ -185,28 +186,39 @@ void FormMain::updateAddItemMenu() {
|
||||||
root_menu->setIcon(activated_root->icon());
|
root_menu->setIcon(activated_root->icon());
|
||||||
root_menu->setToolTip(activated_root->description());
|
root_menu->setToolTip(activated_root->description());
|
||||||
|
|
||||||
QList<QAction*> root_actions = activated_root->addItemMenu();
|
QList<QAction*> specific_root_actions = activated_root->addItemMenu();
|
||||||
|
|
||||||
if (root_actions.isEmpty()) {
|
if (activated_root->supportsCategoryAdding()) {
|
||||||
QAction *no_action = new QAction(qApp->icons()->fromTheme(QSL("dialog-error")),
|
QAction *action_new_category = new QAction(qApp->icons()->fromTheme(QSL("folder-category")),
|
||||||
tr("No possible actions"),
|
tr("Add new category"),
|
||||||
m_ui->m_menuAddItem);
|
m_ui->m_menuAddItem);
|
||||||
no_action->setEnabled(false);
|
root_menu->addAction(action_new_category);
|
||||||
root_menu->addAction(no_action);
|
connect(action_new_category, SIGNAL(triggered()), activated_root, SLOT(addNewCategory()));
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
root_menu->addActions(root_actions);
|
if (activated_root->supportsFeedAdding()) {
|
||||||
|
QAction *action_new_feed = new QAction(qApp->icons()->fromTheme(QSL("folder-feed")),
|
||||||
|
tr("Add new feed"),
|
||||||
|
m_ui->m_menuAddItem);
|
||||||
|
root_menu->addAction(action_new_feed);
|
||||||
|
connect(action_new_feed, SIGNAL(triggered()), activated_root, SLOT(addNewFeed()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!specific_root_actions.isEmpty()) {
|
||||||
|
if (!root_menu->isEmpty()) {
|
||||||
|
root_menu->addSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
|
root_menu->addActions(specific_root_actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ui->m_menuAddItem->addMenu(root_menu);
|
m_ui->m_menuAddItem->addMenu(root_menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_ui->m_menuAddItem->isEmpty()) {
|
if (!m_ui->m_menuAddItem->isEmpty()) {
|
||||||
QAction *no_action = new QAction(qApp->icons()->fromTheme(QSL("dialog-error")),
|
m_ui->m_menuAddItem->addSeparator();
|
||||||
tr("No accounts activated"),
|
m_ui->m_menuAddItem->addAction(m_ui->m_actionAddCategoryIntoSelectedAccount);
|
||||||
m_ui->m_menuAddItem);
|
m_ui->m_menuAddItem->addAction(m_ui->m_actionAddFeedIntoSelectedAccount);
|
||||||
no_action->setEnabled(false);
|
|
||||||
m_ui->m_menuAddItem->addAction(no_action);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -386,7 +398,8 @@ void FormMain::setupIcons() {
|
||||||
m_ui->m_actionServiceAdd->setIcon(icon_theme_factory->fromTheme(QSL("item-new")));
|
m_ui->m_actionServiceAdd->setIcon(icon_theme_factory->fromTheme(QSL("item-new")));
|
||||||
m_ui->m_actionServiceEdit->setIcon(icon_theme_factory->fromTheme(QSL("item-edit")));
|
m_ui->m_actionServiceEdit->setIcon(icon_theme_factory->fromTheme(QSL("item-edit")));
|
||||||
m_ui->m_actionServiceDelete->setIcon(icon_theme_factory->fromTheme(QSL("item-remove")));
|
m_ui->m_actionServiceDelete->setIcon(icon_theme_factory->fromTheme(QSL("item-remove")));
|
||||||
m_ui->m_actionAddFeedIntoSelectedAccount->setIcon(icon_theme_factory->fromTheme(QSL("item-new")));
|
m_ui->m_actionAddFeedIntoSelectedAccount->setIcon(icon_theme_factory->fromTheme(QSL("folder-feed")));
|
||||||
|
m_ui->m_actionAddCategoryIntoSelectedAccount->setIcon(icon_theme_factory->fromTheme(QSL("folder-category")));
|
||||||
|
|
||||||
// Setup icons for underlying components: opened web browsers...
|
// Setup icons for underlying components: opened web browsers...
|
||||||
foreach (WebBrowser *browser, WebBrowser::runningWebBrowsers()) {
|
foreach (WebBrowser *browser, WebBrowser::runningWebBrowsers()) {
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,6 @@
|
||||||
<addaction name="m_actionUpdateSelectedItems"/>
|
<addaction name="m_actionUpdateSelectedItems"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="m_menuAddItem"/>
|
<addaction name="m_menuAddItem"/>
|
||||||
<addaction name="m_actionAddFeedIntoSelectedAccount"/>
|
|
||||||
<addaction name="m_actionEditSelectedItem"/>
|
<addaction name="m_actionEditSelectedItem"/>
|
||||||
<addaction name="m_actionDeleteSelectedItem"/>
|
<addaction name="m_actionDeleteSelectedItem"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
|
|
@ -790,6 +789,14 @@
|
||||||
<string notr="true"/>
|
<string notr="true"/>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="m_actionAddCategoryIntoSelectedAccount">
|
||||||
|
<property name="text">
|
||||||
|
<string>Add new category into selected account</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
|
|
|
||||||
|
|
@ -63,8 +63,8 @@ void DiscoverFeedsButton::linkTriggered(QAction *action) {
|
||||||
QString url = action->property("url").toString();
|
QString url = action->property("url").toString();
|
||||||
ServiceRoot *root = static_cast<ServiceRoot*>(action->property("root").value<void*>());
|
ServiceRoot *root = static_cast<ServiceRoot*>(action->property("root").value<void*>());
|
||||||
|
|
||||||
if (root->supportsFeedAddingByUrl()) {
|
if (root->supportsFeedAdding()) {
|
||||||
root->addFeedByUrl(url);
|
root->addNewFeed(url);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
qApp->showGuiMessage(tr("Not supported"),
|
qApp->showGuiMessage(tr("Not supported"),
|
||||||
|
|
@ -81,7 +81,7 @@ void DiscoverFeedsButton::fillMenu() {
|
||||||
QMenu *root_menu = menu()->addMenu(root->icon(), root->title());
|
QMenu *root_menu = menu()->addMenu(root->icon(), root->title());
|
||||||
|
|
||||||
foreach (const QString &url, m_addresses) {
|
foreach (const QString &url, m_addresses) {
|
||||||
if (root->supportsFeedAddingByUrl()) {
|
if (root->supportsFeedAdding()) {
|
||||||
QAction *url_action = root_menu->addAction(root->icon(), url);
|
QAction *url_action = root_menu->addAction(root->icon(), url);
|
||||||
|
|
||||||
url_action->setProperty("url", url);
|
url_action->setProperty("url", url);
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ FeedMessageViewer::~FeedMessageViewer() {
|
||||||
void FeedMessageViewer::saveSize() {
|
void FeedMessageViewer::saveSize() {
|
||||||
Settings *settings = qApp->settings();
|
Settings *settings = qApp->settings();
|
||||||
|
|
||||||
m_feedsView->saveExpandedStates();
|
m_feedsView->saveAllExpandStates();
|
||||||
|
|
||||||
// Store offsets of splitters.
|
// Store offsets of splitters.
|
||||||
settings->setValue(GROUP(GUI), GUI::SplitterFeeds, QString(m_feedSplitter->saveState().toBase64()));
|
settings->setValue(GROUP(GUI), GUI::SplitterFeeds, QString(m_feedSplitter->saveState().toBase64()));
|
||||||
|
|
@ -257,6 +257,8 @@ void FeedMessageViewer::createConnections() {
|
||||||
// Toolbar forwardings.
|
// Toolbar forwardings.
|
||||||
connect(form_main->m_ui->m_actionAddFeedIntoSelectedAccount, SIGNAL(triggered()),
|
connect(form_main->m_ui->m_actionAddFeedIntoSelectedAccount, SIGNAL(triggered()),
|
||||||
m_feedsView, SLOT(addFeedIntoSelectedAccount()));
|
m_feedsView, SLOT(addFeedIntoSelectedAccount()));
|
||||||
|
connect(form_main->m_ui->m_actionAddCategoryIntoSelectedAccount, SIGNAL(triggered()),
|
||||||
|
m_feedsView, SLOT(addCategoryIntoSelectedAccount()));
|
||||||
connect(form_main->m_ui->m_actionCleanupDatabase,
|
connect(form_main->m_ui->m_actionCleanupDatabase,
|
||||||
SIGNAL(triggered()), this, SLOT(showDbCleanupAssistant()));
|
SIGNAL(triggered()), this, SLOT(showDbCleanupAssistant()));
|
||||||
connect(form_main->m_ui->m_actionSwitchImportanceOfSelectedMessages,
|
connect(form_main->m_ui->m_actionSwitchImportanceOfSelectedMessages,
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ FeedsView::FeedsView(QWidget *parent)
|
||||||
// Connections.
|
// Connections.
|
||||||
connect(m_sourceModel, SIGNAL(requireItemValidationAfterDragDrop(QModelIndex)), this, SLOT(validateItemAfterDragDrop(QModelIndex)));
|
connect(m_sourceModel, SIGNAL(requireItemValidationAfterDragDrop(QModelIndex)), this, SLOT(validateItemAfterDragDrop(QModelIndex)));
|
||||||
connect(m_sourceModel, SIGNAL(itemExpandRequested(QList<RootItem*>,bool)), this, SLOT(onItemExpandRequested(QList<RootItem*>,bool)));
|
connect(m_sourceModel, SIGNAL(itemExpandRequested(QList<RootItem*>,bool)), this, SLOT(onItemExpandRequested(QList<RootItem*>,bool)));
|
||||||
|
connect(m_sourceModel, SIGNAL(itemExpandStateSaveRequested(RootItem*)), this, SLOT(onItemExpandStateSaveRequested(RootItem*)));
|
||||||
connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(saveSortState(int,Qt::SortOrder)));
|
connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(saveSortState(int,Qt::SortOrder)));
|
||||||
|
|
||||||
setModel(m_proxyModel);
|
setModel(m_proxyModel);
|
||||||
|
|
@ -100,23 +101,29 @@ RootItem *FeedsView::selectedItem() const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FeedsView::saveExpandedStates() {
|
void FeedsView::onItemExpandStateSaveRequested(RootItem *item) {
|
||||||
Settings *settings = qApp->settings();
|
saveExpandStates(item);
|
||||||
QList<RootItem*> expandable_items;
|
}
|
||||||
|
|
||||||
expandable_items.append(sourceModel()->rootItem()->getSubTree(RootItemKind::Category | RootItemKind::ServiceRoot));
|
void FeedsView::saveAllExpandStates() {
|
||||||
|
saveExpandStates(sourceModel()->rootItem());
|
||||||
|
}
|
||||||
|
|
||||||
|
void FeedsView::saveExpandStates(RootItem *item) {
|
||||||
|
Settings *settings = qApp->settings();
|
||||||
|
QList<RootItem*> items = item->getSubTree(RootItemKind::Category | RootItemKind::ServiceRoot);
|
||||||
|
|
||||||
// Iterate all categories and save their expand statuses.
|
// Iterate all categories and save their expand statuses.
|
||||||
foreach (RootItem *item, expandable_items) {
|
foreach (RootItem *item, items) {
|
||||||
QString setting_name = QString::number(item->kind()) + QL1S("-") + QString::number(qHash(item->title())) + QL1S("-") + QString::number(item->id());
|
const QString setting_name = item->hashCode();
|
||||||
|
|
||||||
settings->setValue(GROUP(Categories),
|
settings->setValue(GROUP(CategoriesExpandStates),
|
||||||
setting_name,
|
setting_name,
|
||||||
isExpanded(model()->mapFromSource(sourceModel()->indexForItem(item))));
|
isExpanded(model()->mapFromSource(sourceModel()->indexForItem(item))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FeedsView::loadExpandedStates() {
|
void FeedsView::loadAllExpandStates() {
|
||||||
Settings *settings = qApp->settings();
|
Settings *settings = qApp->settings();
|
||||||
QList<RootItem*> expandable_items;
|
QList<RootItem*> expandable_items;
|
||||||
|
|
||||||
|
|
@ -124,10 +131,10 @@ void FeedsView::loadExpandedStates() {
|
||||||
|
|
||||||
// Iterate all categories and save their expand statuses.
|
// Iterate all categories and save their expand statuses.
|
||||||
foreach (RootItem *item, expandable_items) {
|
foreach (RootItem *item, expandable_items) {
|
||||||
QString setting_name = QString::number(item->kind()) + QL1S("-") + QString::number(qHash(item->title())) + QL1S("-") + QString::number(item->id());
|
const QString setting_name = item->hashCode();
|
||||||
|
|
||||||
setExpanded(model()->mapFromSource(sourceModel()->indexForItem(item)),
|
setExpanded(model()->mapFromSource(sourceModel()->indexForItem(item)),
|
||||||
settings->value(GROUP(Categories), setting_name, item->childCount() > 0).toBool());
|
settings->value(GROUP(CategoriesExpandStates), setting_name, item->childCount() > 0).toBool());
|
||||||
}
|
}
|
||||||
|
|
||||||
sortByColumn(qApp->settings()->value(GROUP(GUI), SETTING(GUI::DefaultSortColumnFeeds)).toInt(),
|
sortByColumn(qApp->settings()->value(GROUP(GUI), SETTING(GUI::DefaultSortColumnFeeds)).toInt(),
|
||||||
|
|
@ -140,8 +147,8 @@ void FeedsView::addFeedIntoSelectedAccount() {
|
||||||
if (selected != NULL) {
|
if (selected != NULL) {
|
||||||
ServiceRoot *root = selected->getParentServiceRoot();
|
ServiceRoot *root = selected->getParentServiceRoot();
|
||||||
|
|
||||||
if (root->supportsFeedAddingByUrl()) {
|
if (root->supportsFeedAdding()) {
|
||||||
root->addFeedByUrl();
|
root->addNewFeed();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
qApp->showGuiMessage(tr("Not supported"),
|
qApp->showGuiMessage(tr("Not supported"),
|
||||||
|
|
@ -152,6 +159,24 @@ void FeedsView::addFeedIntoSelectedAccount() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FeedsView::addCategoryIntoSelectedAccount() {
|
||||||
|
RootItem *selected = selectedItem();
|
||||||
|
|
||||||
|
if (selected != NULL) {
|
||||||
|
ServiceRoot *root = selected->getParentServiceRoot();
|
||||||
|
|
||||||
|
if (root->supportsCategoryAdding()) {
|
||||||
|
root->addNewCategory();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
qApp->showGuiMessage(tr("Not supported"),
|
||||||
|
tr("Selected account does not support adding of new categories."),
|
||||||
|
QSystemTrayIcon::Warning,
|
||||||
|
qApp->mainForm(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FeedsView::expandCollapseCurrentItem() {
|
void FeedsView::expandCollapseCurrentItem() {
|
||||||
if (selectionModel()->selectedRows().size() == 1) {
|
if (selectionModel()->selectedRows().size() == 1) {
|
||||||
QModelIndex index = selectionModel()->selectedRows().at(0);
|
QModelIndex index = selectionModel()->selectedRows().at(0);
|
||||||
|
|
|
||||||
|
|
@ -58,11 +58,12 @@ class FeedsView : public QTreeView {
|
||||||
RootItem *selectedItem() const;
|
RootItem *selectedItem() const;
|
||||||
|
|
||||||
// Saves/loads expand states of all nodes (feeds/categories) of the list to/from settings.
|
// Saves/loads expand states of all nodes (feeds/categories) of the list to/from settings.
|
||||||
void saveExpandedStates();
|
void saveAllExpandStates();
|
||||||
void loadExpandedStates();
|
void loadAllExpandStates();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void addFeedIntoSelectedAccount();
|
void addFeedIntoSelectedAccount();
|
||||||
|
void addCategoryIntoSelectedAccount();
|
||||||
void expandCollapseCurrentItem();
|
void expandCollapseCurrentItem();
|
||||||
|
|
||||||
// Feed updating.
|
// Feed updating.
|
||||||
|
|
@ -106,6 +107,7 @@ class FeedsView : public QTreeView {
|
||||||
void saveSortState(int column, Qt::SortOrder order);
|
void saveSortState(int column, Qt::SortOrder order);
|
||||||
void validateItemAfterDragDrop(const QModelIndex &source_index);
|
void validateItemAfterDragDrop(const QModelIndex &source_index);
|
||||||
void onItemExpandRequested(const QList<RootItem*> &items, bool exp);
|
void onItemExpandRequested(const QList<RootItem*> &items, bool exp);
|
||||||
|
void onItemExpandStateSaveRequested(RootItem *item);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Initializes context menus.
|
// Initializes context menus.
|
||||||
|
|
@ -117,6 +119,8 @@ class FeedsView : public QTreeView {
|
||||||
// Sets up appearance of this widget.
|
// Sets up appearance of this widget.
|
||||||
void setupAppearance();
|
void setupAppearance();
|
||||||
|
|
||||||
|
void saveExpandStates(RootItem *item);
|
||||||
|
|
||||||
// Handle selections.
|
// Handle selections.
|
||||||
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
|
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ WidgetWithStatus::WidgetWithStatus(QWidget *parent)
|
||||||
m_btnStatus = new PlainToolButton(this);
|
m_btnStatus = new PlainToolButton(this);
|
||||||
m_btnStatus->setFocusPolicy(Qt::NoFocus);
|
m_btnStatus->setFocusPolicy(Qt::NoFocus);
|
||||||
|
|
||||||
|
m_iconProgress = qApp->icons()->fromTheme(QSL("item-sync"));
|
||||||
m_iconInformation = qApp->icons()->fromTheme(QSL("dialog-information"));
|
m_iconInformation = qApp->icons()->fromTheme(QSL("dialog-information"));
|
||||||
m_iconWarning = qApp->icons()->fromTheme(QSL("dialog-warning"));
|
m_iconWarning = qApp->icons()->fromTheme(QSL("dialog-warning"));
|
||||||
m_iconError = qApp->icons()->fromTheme(QSL("dialog-error"));
|
m_iconError = qApp->icons()->fromTheme(QSL("dialog-error"));
|
||||||
|
|
@ -52,6 +53,10 @@ void WidgetWithStatus::setStatus(WidgetWithStatus::StatusType status, const QStr
|
||||||
m_btnStatus->setIcon(m_iconInformation);
|
m_btnStatus->setIcon(m_iconInformation);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Progress:
|
||||||
|
m_btnStatus->setIcon(m_iconProgress);
|
||||||
|
break;
|
||||||
|
|
||||||
case Warning:
|
case Warning:
|
||||||
m_btnStatus->setIcon(m_iconWarning);
|
m_btnStatus->setIcon(m_iconWarning);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
4
src/gui/widgetwithstatus.h
Normal file → Executable file
4
src/gui/widgetwithstatus.h
Normal file → Executable file
|
|
@ -33,7 +33,8 @@ class WidgetWithStatus : public QWidget {
|
||||||
Information,
|
Information,
|
||||||
Warning,
|
Warning,
|
||||||
Error,
|
Error,
|
||||||
Ok
|
Ok,
|
||||||
|
Progress
|
||||||
};
|
};
|
||||||
|
|
||||||
// Constructors and destructors.
|
// Constructors and destructors.
|
||||||
|
|
@ -53,6 +54,7 @@ class WidgetWithStatus : public QWidget {
|
||||||
PlainToolButton *m_btnStatus;
|
PlainToolButton *m_btnStatus;
|
||||||
QHBoxLayout *m_layout;
|
QHBoxLayout *m_layout;
|
||||||
|
|
||||||
|
QIcon m_iconProgress;
|
||||||
QIcon m_iconInformation;
|
QIcon m_iconInformation;
|
||||||
QIcon m_iconWarning;
|
QIcon m_iconWarning;
|
||||||
QIcon m_iconError;
|
QIcon m_iconError;
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,7 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
// Load activated accounts.
|
// Load activated accounts.
|
||||||
qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->loadActivatedServiceAccounts();
|
qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->loadActivatedServiceAccounts();
|
||||||
qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->loadExpandedStates();
|
qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->loadAllExpandStates();
|
||||||
|
|
||||||
// Setup single-instance behavior.
|
// Setup single-instance behavior.
|
||||||
QObject::connect(&application, SIGNAL(messageReceived(QString)), &application, SLOT(processExecutionMessage(QString)));
|
QObject::connect(&application, SIGNAL(messageReceived(QString)), &application, SLOT(processExecutionMessage(QString)));
|
||||||
|
|
|
||||||
|
|
@ -290,7 +290,7 @@ DKEY Browser::QueueTabs = "queue_tabs";
|
||||||
DVALUE(bool) Browser::QueueTabsDef = true;
|
DVALUE(bool) Browser::QueueTabsDef = true;
|
||||||
|
|
||||||
// Categories.
|
// Categories.
|
||||||
DKEY Categories::ID = "categories_expand_states";
|
DKEY CategoriesExpandStates::ID = "categories_expand_states";
|
||||||
|
|
||||||
Settings::Settings(const QString &file_name, Format format, const SettingsProperties::SettingsType &status, QObject *parent)
|
Settings::Settings(const QString &file_name, Format format, const SettingsProperties::SettingsType &status, QObject *parent)
|
||||||
: QSettings(file_name, format, parent), m_initializationStatus(status) {
|
: QSettings(file_name, format, parent), m_initializationStatus(status) {
|
||||||
|
|
|
||||||
|
|
@ -322,7 +322,7 @@ namespace Browser {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Categories.
|
// Categories.
|
||||||
namespace Categories {
|
namespace CategoriesExpandStates {
|
||||||
KEY ID;
|
KEY ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,10 @@ RootItem::~RootItem() {
|
||||||
qDeleteAll(m_childItems);
|
qDeleteAll(m_childItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString RootItem::hashCode() const {
|
||||||
|
return QString::number(kind()) + QL1S("-") + QString::number(id());
|
||||||
|
}
|
||||||
|
|
||||||
QList<QAction*> RootItem::contextMenu() {
|
QList<QAction*> RootItem::contextMenu() {
|
||||||
return QList<QAction*>();
|
return QList<QAction*>();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,8 @@ class RootItem : public QObject {
|
||||||
// /* Members to override.
|
// /* Members to override.
|
||||||
/////////////////////////////////////////
|
/////////////////////////////////////////
|
||||||
|
|
||||||
|
virtual QString hashCode() const;
|
||||||
|
|
||||||
// Returns list of specific actions which can be done with the item.
|
// Returns list of specific actions which can be done with the item.
|
||||||
// Do not include general actions here like actions: Mark as read, Update, ...
|
// Do not include general actions here like actions: Mark as read, Update, ...
|
||||||
// NOTE: Ownership of returned actions is not switched to caller, free them when needed.
|
// NOTE: Ownership of returned actions is not switched to caller, free them when needed.
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ class ServiceEntryPoint {
|
||||||
// point from persistent DB.
|
// point from persistent DB.
|
||||||
// Returns list of root nodes which will be afterwards added
|
// Returns list of root nodes which will be afterwards added
|
||||||
// to the global feed model.
|
// to the global feed model.
|
||||||
virtual QList<ServiceRoot*> initializeSubtree() = 0;
|
virtual QList<ServiceRoot*> initializeSubtree() const = 0;
|
||||||
|
|
||||||
// Can this service account be added just once?
|
// Can this service account be added just once?
|
||||||
// NOTE: This is true particularly for "standard" service
|
// NOTE: This is true particularly for "standard" service
|
||||||
|
|
|
||||||
|
|
@ -122,10 +122,14 @@ void ServiceRoot::requestFeedReadFilterReload() {
|
||||||
emit readFeedsFilterInvalidationRequested();
|
emit readFeedsFilterInvalidationRequested();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServiceRoot::requestItemExpand(const QList<RootItem *> &items, bool expand) {
|
void ServiceRoot::requestItemExpand(const QList<RootItem*> &items, bool expand) {
|
||||||
emit itemExpandRequested(items, expand);
|
emit itemExpandRequested(items, expand);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ServiceRoot::requestItemExpandStateSave(RootItem *subtree_root) {
|
||||||
|
emit itemExpandStateSaveRequested(subtree_root);
|
||||||
|
}
|
||||||
|
|
||||||
void ServiceRoot::requestItemReassignment(RootItem *item, RootItem *new_parent) {
|
void ServiceRoot::requestItemReassignment(RootItem *item, RootItem *new_parent) {
|
||||||
emit itemReassignmentRequested(item, new_parent);
|
emit itemReassignmentRequested(item, new_parent);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,8 @@ class ServiceRoot : public RootItem {
|
||||||
bool deleteViaGui();
|
bool deleteViaGui();
|
||||||
bool markAsReadUnread(ReadStatus status);
|
bool markAsReadUnread(ReadStatus status);
|
||||||
|
|
||||||
virtual bool supportsFeedAddingByUrl() const = 0;
|
virtual bool supportsFeedAdding() const = 0;
|
||||||
|
virtual bool supportsCategoryAdding() const = 0;
|
||||||
|
|
||||||
// Returns list of specific actions for "Add new item" main window menu.
|
// Returns list of specific actions for "Add new item" main window menu.
|
||||||
// So typical list of returned actions could look like:
|
// So typical list of returned actions could look like:
|
||||||
|
|
@ -151,6 +152,7 @@ class ServiceRoot : public RootItem {
|
||||||
void requestReloadMessageList(bool mark_selected_messages_read);
|
void requestReloadMessageList(bool mark_selected_messages_read);
|
||||||
void requestFeedReadFilterReload();
|
void requestFeedReadFilterReload();
|
||||||
void requestItemExpand(const QList<RootItem*> &items, bool expand);
|
void requestItemExpand(const QList<RootItem*> &items, bool expand);
|
||||||
|
void requestItemExpandStateSave(RootItem *subtree_root);
|
||||||
void requestItemReassignment(RootItem *item, RootItem *new_parent);
|
void requestItemReassignment(RootItem *item, RootItem *new_parent);
|
||||||
void requestItemRemoval(RootItem *item);
|
void requestItemRemoval(RootItem *item);
|
||||||
|
|
||||||
|
|
@ -159,7 +161,8 @@ class ServiceRoot : public RootItem {
|
||||||
void setAccountId(int account_id);
|
void setAccountId(int account_id);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
virtual void addFeedByUrl(const QString &url = QString()) = 0;
|
virtual void addNewFeed(const QString &url = QString()) = 0;
|
||||||
|
virtual void addNewCategory() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Takes lists of feeds/categories and assembles them into the tree structure.
|
// Takes lists of feeds/categories and assembles them into the tree structure.
|
||||||
|
|
@ -172,6 +175,7 @@ class ServiceRoot : public RootItem {
|
||||||
void readFeedsFilterInvalidationRequested();
|
void readFeedsFilterInvalidationRequested();
|
||||||
void reloadMessageListRequested(bool mark_selected_messages_read);
|
void reloadMessageListRequested(bool mark_selected_messages_read);
|
||||||
void itemExpandRequested(QList<RootItem*> items, bool expand);
|
void itemExpandRequested(QList<RootItem*> items, bool expand);
|
||||||
|
void itemExpandStateSaveRequested(RootItem *subtree_root);
|
||||||
|
|
||||||
void itemReassignmentRequested(RootItem *item, RootItem *new_parent);
|
void itemReassignmentRequested(RootItem *item, RootItem *new_parent);
|
||||||
void itemRemovalRequested(RootItem *item);
|
void itemRemovalRequested(RootItem *item);
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,10 @@ FormStandardImportExport::FormStandardImportExport(StandardServiceRoot *service_
|
||||||
m_ui->setupUi(this);
|
m_ui->setupUi(this);
|
||||||
m_model = new FeedsImportExportModel(m_ui->m_treeFeeds);
|
m_model = new FeedsImportExportModel(m_ui->m_treeFeeds);
|
||||||
|
|
||||||
|
connect(m_model, SIGNAL(parsingStarted()), this, SLOT(onParsingStarted()));
|
||||||
|
connect(m_model, SIGNAL(parsingFinished(int,int,bool)), this, SLOT(onParsingFinished(int,int,bool)));
|
||||||
|
connect(m_model, SIGNAL(parsingProgress(int,int)), this, SLOT(onParsingProgress(int,int)));
|
||||||
|
|
||||||
setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint);
|
setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint);
|
||||||
|
|
||||||
m_ui->m_lblSelectFile->setStatus(WidgetWithStatus::Error, tr("No file is selected."), tr("No file is selected."));
|
m_ui->m_lblSelectFile->setStatus(WidgetWithStatus::Error, tr("No file is selected."), tr("No file is selected."));
|
||||||
|
|
@ -54,6 +58,7 @@ FormStandardImportExport::~FormStandardImportExport() {
|
||||||
|
|
||||||
void FormStandardImportExport::setMode(const FeedsImportExportModel::Mode &mode) {
|
void FormStandardImportExport::setMode(const FeedsImportExportModel::Mode &mode) {
|
||||||
m_model->setMode(mode);
|
m_model->setMode(mode);
|
||||||
|
m_ui->m_progressBar->setVisible(false);
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case FeedsImportExportModel::Export: {
|
case FeedsImportExportModel::Export: {
|
||||||
|
|
@ -100,6 +105,41 @@ void FormStandardImportExport::selectFile() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FormStandardImportExport::onParsingStarted() {
|
||||||
|
m_ui->m_lblResult->setStatus(WidgetWithStatus::Progress, tr("Parsing data..."), tr("Parsing data..."));
|
||||||
|
m_ui->m_btnSelectFile->setEnabled(false);
|
||||||
|
m_ui->m_progressBar->setValue(0);
|
||||||
|
m_ui->m_progressBar->setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FormStandardImportExport::onParsingFinished(int count_failed, int count_succeeded, bool parsing_error) {
|
||||||
|
Q_UNUSED(count_failed)
|
||||||
|
Q_UNUSED(count_succeeded)
|
||||||
|
|
||||||
|
m_ui->m_progressBar->setVisible(false);
|
||||||
|
m_ui->m_progressBar->setValue(0);
|
||||||
|
m_model->checkAllItems();
|
||||||
|
|
||||||
|
if (!parsing_error) {
|
||||||
|
m_ui->m_lblResult->setStatus(WidgetWithStatus::Ok, tr("Feeds were loaded."), tr("Feeds were loaded."));
|
||||||
|
m_ui->m_groupFeeds->setEnabled(true);
|
||||||
|
m_ui->m_btnSelectFile->setEnabled(true);
|
||||||
|
m_ui->m_treeFeeds->setModel(m_model);
|
||||||
|
m_ui->m_treeFeeds->expandAll();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_ui->m_lblResult->setStatus(WidgetWithStatus::Error, tr("Error, file is not well-formed. Select another file."),
|
||||||
|
tr("Error occurred. File is not well-formed. Select another file."));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ui->m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!parsing_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FormStandardImportExport::onParsingProgress(int completed, int total) {
|
||||||
|
m_ui->m_progressBar->setMaximum(total);
|
||||||
|
m_ui->m_progressBar->setValue(completed);
|
||||||
|
}
|
||||||
|
|
||||||
void FormStandardImportExport::selectExportFile() {
|
void FormStandardImportExport::selectExportFile() {
|
||||||
QString filter_opml20 = tr("OPML 2.0 files (*.opml)");
|
QString filter_opml20 = tr("OPML 2.0 files (*.opml)");
|
||||||
QString filter_txt_url_per_line = tr("TXT files (one URL per line) (*.txt)");
|
QString filter_txt_url_per_line = tr("TXT files (one URL per line) (*.txt)");
|
||||||
|
|
@ -162,7 +202,6 @@ void FormStandardImportExport::selectImportFile() {
|
||||||
|
|
||||||
m_ui->m_lblSelectFile->setStatus(WidgetWithStatus::Ok, QDir::toNativeSeparators(selected_file), tr("File is selected."));
|
m_ui->m_lblSelectFile->setStatus(WidgetWithStatus::Ok, QDir::toNativeSeparators(selected_file), tr("File is selected."));
|
||||||
parseImportFile(selected_file);
|
parseImportFile(selected_file);
|
||||||
m_model->checkAllItems();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -179,15 +218,13 @@ void FormStandardImportExport::parseImportFile(const QString &file_name) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parsing_result;
|
|
||||||
|
|
||||||
switch (m_conversionType) {
|
switch (m_conversionType) {
|
||||||
case OPML20:
|
case OPML20:
|
||||||
parsing_result = m_model->importAsOPML20(input_data);
|
m_model->importAsOPML20(input_data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TXTUrlPerLine:
|
case TXTUrlPerLine:
|
||||||
parsing_result = m_model->importAsTxtURLPerLine(input_data);
|
m_model->importAsTxtURLPerLine(input_data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// TODO: V celém kódu nově zavést pořádně všude const, i v lokálních metodových proměnných
|
// TODO: V celém kódu nově zavést pořádně všude const, i v lokálních metodových proměnných
|
||||||
|
|
@ -198,19 +235,6 @@ void FormStandardImportExport::parseImportFile(const QString &file_name) {
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parsing_result) {
|
|
||||||
m_ui->m_lblResult->setStatus(WidgetWithStatus::Ok, tr("Feeds were loaded."), tr("Feeds were loaded."));
|
|
||||||
m_ui->m_groupFeeds->setEnabled(true);
|
|
||||||
m_ui->m_treeFeeds->setModel(m_model);
|
|
||||||
m_ui->m_treeFeeds->expandAll();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
m_ui->m_lblResult->setStatus(WidgetWithStatus::Error, tr("Error, file is not well-formed. Select another file."),
|
|
||||||
tr("Error occurred. File is not well-formed. Select another file."));
|
|
||||||
}
|
|
||||||
|
|
||||||
m_ui->m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(parsing_result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FormStandardImportExport::performAction() {
|
void FormStandardImportExport::performAction() {
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,10 @@ class FormStandardImportExport : public QDialog {
|
||||||
void performAction();
|
void performAction();
|
||||||
void selectFile();
|
void selectFile();
|
||||||
|
|
||||||
|
void onParsingStarted();
|
||||||
|
void onParsingFinished(int count_failed, int count_succeeded, bool parsing_error);
|
||||||
|
void onParsingProgress(int completed, int total);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void selectExportFile();
|
void selectExportFile();
|
||||||
void selectImportFile();
|
void selectImportFile();
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,13 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="1" column="0" colspan="2">
|
||||||
|
<widget class="QProgressBar" name="m_progressBar">
|
||||||
|
<property name="value">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
|
||||||
|
|
@ -282,7 +282,9 @@ void StandardFeed::fetchMetadataForItself() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QPair<StandardFeed*,QNetworkReply::NetworkError> StandardFeed::guessFeed(const QString &url, const QString &username, const QString &password) {
|
QPair<StandardFeed*,QNetworkReply::NetworkError> StandardFeed::guessFeed(const QString &url,
|
||||||
|
const QString &username,
|
||||||
|
const QString &password) {
|
||||||
QPair<StandardFeed*,QNetworkReply::NetworkError> result; result.first = NULL;
|
QPair<StandardFeed*,QNetworkReply::NetworkError> result; result.first = NULL;
|
||||||
|
|
||||||
QByteArray feed_contents;
|
QByteArray feed_contents;
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,9 @@ class StandardFeed : public Feed {
|
||||||
// Returns pointer to guessed feed (if at least partially
|
// Returns pointer to guessed feed (if at least partially
|
||||||
// guessed) and retrieved error/status code from network layer
|
// guessed) and retrieved error/status code from network layer
|
||||||
// or NULL feed.
|
// or NULL feed.
|
||||||
static QPair<StandardFeed*,QNetworkReply::NetworkError> guessFeed(const QString &url, const QString &username, const QString &password);
|
static QPair<StandardFeed*,QNetworkReply::NetworkError> guessFeed(const QString &url,
|
||||||
|
const QString &username = QString(),
|
||||||
|
const QString &password = QString());
|
||||||
|
|
||||||
// Converts particular feed type to string.
|
// Converts particular feed type to string.
|
||||||
static QString typeToString(Type type);
|
static QString typeToString(Type type);
|
||||||
|
|
|
||||||
|
|
@ -154,19 +154,22 @@ bool FeedsImportExportModel::exportToOMPL20(QByteArray &result) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FeedsImportExportModel::importAsOPML20(const QByteArray &data) {
|
void FeedsImportExportModel::importAsOPML20(const QByteArray &data) {
|
||||||
|
emit parsingStarted();
|
||||||
|
|
||||||
QDomDocument opml_document;
|
QDomDocument opml_document;
|
||||||
|
|
||||||
if (!opml_document.setContent(data)) {
|
if (!opml_document.setContent(data)) {
|
||||||
return false;
|
emit parsingFinished(0, 0, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opml_document.documentElement().isNull() || opml_document.documentElement().tagName() != QSL("opml") ||
|
if (opml_document.documentElement().isNull() || opml_document.documentElement().tagName() != QSL("opml") ||
|
||||||
opml_document.documentElement().elementsByTagName(QSL("body")).size() != 1) {
|
opml_document.documentElement().elementsByTagName(QSL("body")).size() != 1) {
|
||||||
// This really is not an OPML file.
|
// This really is not an OPML file.
|
||||||
return false;
|
emit parsingFinished(0, 0, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int completed = 0, total = 0;
|
||||||
StandardServiceRoot *root_item = new StandardServiceRoot();
|
StandardServiceRoot *root_item = new StandardServiceRoot();
|
||||||
QStack<RootItem*> model_items; model_items.push(root_item);
|
QStack<RootItem*> model_items; model_items.push(root_item);
|
||||||
QStack<QDomElement> elements_to_process; elements_to_process.push(opml_document.documentElement().elementsByTagName(QSL("body")).at(0).toElement());
|
QStack<QDomElement> elements_to_process; elements_to_process.push(opml_document.documentElement().elementsByTagName(QSL("body")).at(0).toElement());
|
||||||
|
|
@ -175,7 +178,10 @@ bool FeedsImportExportModel::importAsOPML20(const QByteArray &data) {
|
||||||
RootItem *active_model_item = model_items.pop();
|
RootItem *active_model_item = model_items.pop();
|
||||||
QDomElement active_element = elements_to_process.pop();
|
QDomElement active_element = elements_to_process.pop();
|
||||||
|
|
||||||
for (int i = 0; i < active_element.childNodes().size(); i++) {
|
int current_count = active_element.childNodes().size();
|
||||||
|
total += current_count;
|
||||||
|
|
||||||
|
for (int i = 0; i < current_count; i++) {
|
||||||
QDomNode child = active_element.childNodes().at(i);
|
QDomNode child = active_element.childNodes().at(i);
|
||||||
|
|
||||||
if (child.isElement()) {
|
if (child.isElement()) {
|
||||||
|
|
@ -242,6 +248,8 @@ bool FeedsImportExportModel::importAsOPML20(const QByteArray &data) {
|
||||||
elements_to_process.push(child_element);
|
elements_to_process.push(child_element);
|
||||||
model_items.push(new_category);
|
model_items.push(new_category);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit parsingProgress(++completed, total);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -250,8 +258,7 @@ bool FeedsImportExportModel::importAsOPML20(const QByteArray &data) {
|
||||||
emit layoutAboutToBeChanged();
|
emit layoutAboutToBeChanged();
|
||||||
setRootItem(root_item);
|
setRootItem(root_item);
|
||||||
emit layoutChanged();
|
emit layoutChanged();
|
||||||
|
emit parsingFinished(0, completed, false);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FeedsImportExportModel::exportToTxtURLPerLine(QByteArray &result) {
|
bool FeedsImportExportModel::exportToTxtURLPerLine(QByteArray &result) {
|
||||||
|
|
@ -262,32 +269,49 @@ bool FeedsImportExportModel::exportToTxtURLPerLine(QByteArray &result) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FeedsImportExportModel::importAsTxtURLPerLine(const QByteArray &data) {
|
void FeedsImportExportModel::importAsTxtURLPerLine(const QByteArray &data) {
|
||||||
|
emit parsingStarted();
|
||||||
|
|
||||||
|
int completed = 0, succeded = 0, failed = 0;
|
||||||
StandardServiceRoot *root_item = new StandardServiceRoot();
|
StandardServiceRoot *root_item = new StandardServiceRoot();
|
||||||
|
QList<QByteArray> urls = data.split('\n');
|
||||||
|
|
||||||
foreach (const QByteArray &url, data.split('\n')) {
|
foreach (const QByteArray &url, urls) {
|
||||||
if (!url.isEmpty()) {
|
if (!url.isEmpty()) {
|
||||||
|
QPair<StandardFeed*,QNetworkReply::NetworkError> guessed = StandardFeed::guessFeed(url);
|
||||||
|
|
||||||
StandardFeed *feed = new StandardFeed();
|
if (guessed.second == QNetworkReply::NoError) {
|
||||||
|
guessed.first->setUrl(url);
|
||||||
|
root_item->appendChild(guessed.first);
|
||||||
|
succeded++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
StandardFeed *feed = new StandardFeed();
|
||||||
|
|
||||||
// TODO: co guessovat ten feed?
|
feed->setUrl(url);
|
||||||
|
feed->setTitle(url);
|
||||||
|
feed->setCreationDate(QDateTime::currentDateTime());
|
||||||
|
feed->setIcon(qApp->icons()->fromTheme(QSL("folder-feed")));
|
||||||
|
feed->setEncoding(DEFAULT_FEED_ENCODING);
|
||||||
|
root_item->appendChild(feed);
|
||||||
|
failed++;
|
||||||
|
}
|
||||||
|
|
||||||
feed->setUrl(url);
|
qApp->processEvents();
|
||||||
feed->setTitle(url);
|
|
||||||
feed->setCreationDate(QDateTime::currentDateTime());
|
|
||||||
feed->setIcon(qApp->icons()->fromTheme(QSL("folder-feed")));
|
|
||||||
feed->setEncoding(DEFAULT_FEED_ENCODING);
|
|
||||||
|
|
||||||
root_item->appendChild(feed);
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
qWarning("Detected empty URL when parsing input TXT (one URL per line) data.");
|
||||||
|
failed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit parsingProgress(++completed, urls.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now, XML is processed and we have result in form of pointer item structure.
|
// Now, XML is processed and we have result in form of pointer item structure.
|
||||||
emit layoutAboutToBeChanged();
|
emit layoutAboutToBeChanged();
|
||||||
setRootItem(root_item);
|
setRootItem(root_item);
|
||||||
emit layoutChanged();
|
emit layoutChanged();
|
||||||
|
emit parsingFinished(failed, succeded, false);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FeedsImportExportModel::Mode FeedsImportExportModel::mode() const {
|
FeedsImportExportModel::Mode FeedsImportExportModel::mode() const {
|
||||||
|
|
|
||||||
|
|
@ -60,12 +60,12 @@ class FeedsImportExportModel : public QAbstractItemModel {
|
||||||
// Exports to OPML 2.0
|
// Exports to OPML 2.0
|
||||||
// NOTE: http://dev.opml.org/spec2.html
|
// NOTE: http://dev.opml.org/spec2.html
|
||||||
bool exportToOMPL20(QByteArray &result);
|
bool exportToOMPL20(QByteArray &result);
|
||||||
bool importAsOPML20(const QByteArray &data);
|
void importAsOPML20(const QByteArray &data);
|
||||||
|
|
||||||
// Exports to plain text format
|
// Exports to plain text format
|
||||||
// where there is one feed URL per line.
|
// where there is one feed URL per line.
|
||||||
bool exportToTxtURLPerLine(QByteArray &result);
|
bool exportToTxtURLPerLine(QByteArray &result);
|
||||||
bool importAsTxtURLPerLine(const QByteArray &data);
|
void importAsTxtURLPerLine(const QByteArray &data);
|
||||||
|
|
||||||
Mode mode() const;
|
Mode mode() const;
|
||||||
void setMode(const Mode &mode);
|
void setMode(const Mode &mode);
|
||||||
|
|
@ -74,8 +74,15 @@ class FeedsImportExportModel : public QAbstractItemModel {
|
||||||
void checkAllItems();
|
void checkAllItems();
|
||||||
void uncheckAllItems();
|
void uncheckAllItems();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
// These signals are emitted when user selects some data
|
||||||
|
// to be imported/parsed into the model.
|
||||||
|
void parsingStarted();
|
||||||
|
void parsingProgress(int completed, int total);
|
||||||
|
void parsingFinished(int count_failed, int count_succeeded, bool parsing_error);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QHash<RootItem*, Qt::CheckState> m_checkStates;
|
QHash<RootItem*,Qt::CheckState> m_checkStates;
|
||||||
RootItem *m_rootItem;
|
RootItem *m_rootItem;
|
||||||
|
|
||||||
bool m_recursiveChange;
|
bool m_recursiveChange;
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,7 @@ ServiceRoot *StandardServiceEntryPoint::createNewRoot() {
|
||||||
|
|
||||||
if (query.exec()) {
|
if (query.exec()) {
|
||||||
StandardServiceRoot *root = new StandardServiceRoot();
|
StandardServiceRoot *root = new StandardServiceRoot();
|
||||||
|
root->setId(id_to_assign);
|
||||||
root->setAccountId(id_to_assign);
|
root->setAccountId(id_to_assign);
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
@ -85,7 +86,7 @@ ServiceRoot *StandardServiceEntryPoint::createNewRoot() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<ServiceRoot*> StandardServiceEntryPoint::initializeSubtree() {
|
QList<ServiceRoot*> StandardServiceEntryPoint::initializeSubtree() const {
|
||||||
// Check DB if standard account is enabled.
|
// Check DB if standard account is enabled.
|
||||||
QSqlDatabase database = qApp->database()->connection(QSL("StandardServiceEntryPoint"), DatabaseFactory::FromSettings);
|
QSqlDatabase database = qApp->database()->connection(QSL("StandardServiceEntryPoint"), DatabaseFactory::FromSettings);
|
||||||
QSqlQuery query(database);
|
QSqlQuery query(database);
|
||||||
|
|
@ -98,6 +99,7 @@ QList<ServiceRoot*> StandardServiceEntryPoint::initializeSubtree() {
|
||||||
if (query.exec()) {
|
if (query.exec()) {
|
||||||
while (query.next()) {
|
while (query.next()) {
|
||||||
StandardServiceRoot *root = new StandardServiceRoot();
|
StandardServiceRoot *root = new StandardServiceRoot();
|
||||||
|
root->setId(query.value(0).toInt());
|
||||||
root->setAccountId(query.value(0).toInt());
|
root->setAccountId(query.value(0).toInt());
|
||||||
roots.append(root);
|
roots.append(root);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ class StandardServiceEntryPoint : public ServiceEntryPoint {
|
||||||
QString code();
|
QString code();
|
||||||
|
|
||||||
ServiceRoot *createNewRoot();
|
ServiceRoot *createNewRoot();
|
||||||
QList<ServiceRoot*> initializeSubtree();
|
QList<ServiceRoot*> initializeSubtree() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // STANDARDSERVICEENTRYPOINT_H
|
#endif // STANDARDSERVICEENTRYPOINT_H
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@
|
||||||
StandardServiceRoot::StandardServiceRoot(RootItem *parent)
|
StandardServiceRoot::StandardServiceRoot(RootItem *parent)
|
||||||
: ServiceRoot(parent), m_recycleBin(new StandardRecycleBin(this)),
|
: ServiceRoot(parent), m_recycleBin(new StandardRecycleBin(this)),
|
||||||
m_actionExportFeeds(NULL), m_actionImportFeeds(NULL), m_serviceMenu(QList<QAction*>()),
|
m_actionExportFeeds(NULL), m_actionImportFeeds(NULL), m_serviceMenu(QList<QAction*>()),
|
||||||
m_addItemMenu(QList<QAction*>()), m_feedContextMenu(QList<QAction*>()), m_actionFeedFetchMetadata(NULL) {
|
m_feedContextMenu(QList<QAction*>()), m_actionFeedFetchMetadata(NULL) {
|
||||||
|
|
||||||
setTitle(qApp->system()->getUsername() + QL1S("@") + QL1S(APP_LOW_NAME));
|
setTitle(qApp->system()->getUsername() + QL1S("@") + QL1S(APP_LOW_NAME));
|
||||||
setIcon(StandardServiceEntryPoint().icon());
|
setIcon(StandardServiceEntryPoint().icon());
|
||||||
|
|
@ -57,7 +57,6 @@ StandardServiceRoot::StandardServiceRoot(RootItem *parent)
|
||||||
|
|
||||||
StandardServiceRoot::~StandardServiceRoot() {
|
StandardServiceRoot::~StandardServiceRoot() {
|
||||||
qDeleteAll(m_serviceMenu);
|
qDeleteAll(m_serviceMenu);
|
||||||
qDeleteAll(m_addItemMenu);
|
|
||||||
qDeleteAll(m_feedContextMenu);
|
qDeleteAll(m_feedContextMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -125,11 +124,15 @@ bool StandardServiceRoot::markAsReadUnread(RootItem::ReadStatus status) {
|
||||||
return ServiceRoot::markAsReadUnread(status);
|
return ServiceRoot::markAsReadUnread(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StandardServiceRoot::supportsFeedAddingByUrl() const {
|
bool StandardServiceRoot::supportsFeedAdding() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StandardServiceRoot::addFeedByUrl(const QString &url) {
|
bool StandardServiceRoot::supportsCategoryAdding() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StandardServiceRoot::addNewFeed(const QString &url) {
|
||||||
QPointer<FormStandardFeedDetails> form_pointer = new FormStandardFeedDetails(this, qApp->mainForm());
|
QPointer<FormStandardFeedDetails> form_pointer = new FormStandardFeedDetails(this, qApp->mainForm());
|
||||||
form_pointer.data()->exec(NULL, NULL, url);
|
form_pointer.data()->exec(NULL, NULL, url);
|
||||||
delete form_pointer.data();
|
delete form_pointer.data();
|
||||||
|
|
@ -300,7 +303,7 @@ void StandardServiceRoot::checkArgumentsForFeedAdding() {
|
||||||
|
|
||||||
void StandardServiceRoot::checkArgumentForFeedAdding(const QString &argument) {
|
void StandardServiceRoot::checkArgumentForFeedAdding(const QString &argument) {
|
||||||
if (argument.startsWith(QL1S("feed:"))) {
|
if (argument.startsWith(QL1S("feed:"))) {
|
||||||
addFeedByUrl(argument);
|
addNewFeed(argument);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -441,18 +444,7 @@ QStringList StandardServiceRoot::textualFeedIds(const QList<Feed*> &feeds) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QAction*> StandardServiceRoot::addItemMenu() {
|
QList<QAction*> StandardServiceRoot::addItemMenu() {
|
||||||
if (m_addItemMenu.isEmpty()) {
|
return QList<QAction*>();
|
||||||
QAction *action_new_category = new QAction(qApp->icons()->fromTheme("folder-category"), tr("Add new category"), this);
|
|
||||||
connect(action_new_category, SIGNAL(triggered()), this, SLOT(addNewCategory()));
|
|
||||||
|
|
||||||
QAction *action_new_feed = new QAction(qApp->icons()->fromTheme("folder-feed"), tr("Add new feed"), this);
|
|
||||||
connect(action_new_feed, SIGNAL(triggered()), this, SLOT(addFeedByUrl()));
|
|
||||||
|
|
||||||
m_addItemMenu.append(action_new_category);
|
|
||||||
m_addItemMenu.append(action_new_feed);
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_addItemMenu;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QAction*> StandardServiceRoot::serviceMenu() {
|
QList<QAction*> StandardServiceRoot::serviceMenu() {
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,8 @@ class StandardServiceRoot : public ServiceRoot {
|
||||||
|
|
||||||
bool markAsReadUnread(ReadStatus status);
|
bool markAsReadUnread(ReadStatus status);
|
||||||
|
|
||||||
bool supportsFeedAddingByUrl() const;
|
bool supportsFeedAdding() const;
|
||||||
|
bool supportsCategoryAdding() const;
|
||||||
|
|
||||||
QVariant data(int column, int role) const;
|
QVariant data(int column, int role) const;
|
||||||
Qt::ItemFlags additionalFlags() const;
|
Qt::ItemFlags additionalFlags() const;
|
||||||
|
|
@ -100,7 +101,7 @@ class StandardServiceRoot : public ServiceRoot {
|
||||||
void checkArgumentForFeedAdding(const QString &argument);
|
void checkArgumentForFeedAdding(const QString &argument);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void addFeedByUrl(const QString &url = QString());
|
void addNewFeed(const QString &url = QString());
|
||||||
void addNewCategory();
|
void addNewCategory();
|
||||||
void importFeeds();
|
void importFeeds();
|
||||||
void exportFeeds();
|
void exportFeeds();
|
||||||
|
|
@ -119,7 +120,6 @@ class StandardServiceRoot : public ServiceRoot {
|
||||||
QAction *m_actionImportFeeds;
|
QAction *m_actionImportFeeds;
|
||||||
|
|
||||||
QList<QAction*> m_serviceMenu;
|
QList<QAction*> m_serviceMenu;
|
||||||
QList<QAction*> m_addItemMenu;
|
|
||||||
QList<QAction*> m_feedContextMenu;
|
QList<QAction*> m_feedContextMenu;
|
||||||
|
|
||||||
QAction *m_actionFeedFetchMetadata;
|
QAction *m_actionFeedFetchMetadata;
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,13 @@ TtRssCategory::TtRssCategory(const QSqlRecord &record) : Category(NULL) {
|
||||||
TtRssCategory::~TtRssCategory() {
|
TtRssCategory::~TtRssCategory() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString TtRssCategory::hashCode() const {
|
||||||
|
return
|
||||||
|
QString::number(kind()) + QL1S("-") +
|
||||||
|
QString::number(const_cast<TtRssCategory*>(this)->getParentServiceRoot()->accountId()) + QL1S("-") +
|
||||||
|
QString::number(customId());
|
||||||
|
}
|
||||||
|
|
||||||
TtRssServiceRoot *TtRssCategory::serviceRoot() {
|
TtRssServiceRoot *TtRssCategory::serviceRoot() {
|
||||||
return qobject_cast<TtRssServiceRoot*>(getParentServiceRoot());
|
return qobject_cast<TtRssServiceRoot*>(getParentServiceRoot());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,8 @@ class TtRssCategory : public Category {
|
||||||
explicit TtRssCategory(const QSqlRecord &record);
|
explicit TtRssCategory(const QSqlRecord &record);
|
||||||
virtual ~TtRssCategory();
|
virtual ~TtRssCategory();
|
||||||
|
|
||||||
|
QString hashCode() const;
|
||||||
|
|
||||||
TtRssServiceRoot *serviceRoot();
|
TtRssServiceRoot *serviceRoot();
|
||||||
|
|
||||||
bool markAsReadUnread(ReadStatus status);
|
bool markAsReadUnread(ReadStatus status);
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,13 @@ TtRssFeed::TtRssFeed(const QSqlRecord &record) : Feed(NULL), m_totalCount(0), m_
|
||||||
TtRssFeed::~TtRssFeed() {
|
TtRssFeed::~TtRssFeed() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString TtRssFeed::hashCode() const {
|
||||||
|
return
|
||||||
|
QString::number(kind()) + QL1S("-") +
|
||||||
|
QString::number(const_cast<TtRssFeed*>(this)->getParentServiceRoot()->accountId()) + QL1S("-") +
|
||||||
|
QString::number(customId());
|
||||||
|
}
|
||||||
|
|
||||||
TtRssServiceRoot *TtRssFeed::serviceRoot() {
|
TtRssServiceRoot *TtRssFeed::serviceRoot() {
|
||||||
return qobject_cast<TtRssServiceRoot*>(getParentServiceRoot());
|
return qobject_cast<TtRssServiceRoot*>(getParentServiceRoot());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,8 @@ class TtRssFeed : public Feed {
|
||||||
explicit TtRssFeed(const QSqlRecord &record);
|
explicit TtRssFeed(const QSqlRecord &record);
|
||||||
virtual ~TtRssFeed();
|
virtual ~TtRssFeed();
|
||||||
|
|
||||||
|
QString hashCode() const;
|
||||||
|
|
||||||
TtRssServiceRoot *serviceRoot();
|
TtRssServiceRoot *serviceRoot();
|
||||||
|
|
||||||
QVariant data(int column, int role) const;
|
QVariant data(int column, int role) const;
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ ServiceRoot *TtRssServiceEntryPoint::createNewRoot() {
|
||||||
return new_root;
|
return new_root;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<ServiceRoot*> TtRssServiceEntryPoint::initializeSubtree() {
|
QList<ServiceRoot*> TtRssServiceEntryPoint::initializeSubtree() const {
|
||||||
// Check DB if standard account is enabled.
|
// Check DB if standard account is enabled.
|
||||||
QSqlDatabase database = qApp->database()->connection(QSL("TtRssServiceEntryPoint"), DatabaseFactory::FromSettings);
|
QSqlDatabase database = qApp->database()->connection(QSL("TtRssServiceEntryPoint"), DatabaseFactory::FromSettings);
|
||||||
QSqlQuery query(database);
|
QSqlQuery query(database);
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ class TtRssServiceEntryPoint : public ServiceEntryPoint {
|
||||||
QString code();
|
QString code();
|
||||||
|
|
||||||
ServiceRoot *createNewRoot();
|
ServiceRoot *createNewRoot();
|
||||||
QList<ServiceRoot*> initializeSubtree();
|
QList<ServiceRoot*> initializeSubtree() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TTRSSSERVICEENTRYPOINT_H
|
#endif // TTRSSSERVICEENTRYPOINT_H
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,7 @@
|
||||||
|
|
||||||
TtRssServiceRoot::TtRssServiceRoot(RootItem *parent)
|
TtRssServiceRoot::TtRssServiceRoot(RootItem *parent)
|
||||||
: ServiceRoot(parent), m_recycleBin(new TtRssRecycleBin(this)),
|
: ServiceRoot(parent), m_recycleBin(new TtRssRecycleBin(this)),
|
||||||
m_actionSyncIn(NULL), m_serviceMenu(QList<QAction*>()), m_addItemMenu(QList<QAction*>()),
|
m_actionSyncIn(NULL), m_serviceMenu(QList<QAction*>()), m_network(new TtRssNetworkFactory) {
|
||||||
m_network(new TtRssNetworkFactory) {
|
|
||||||
setIcon(TtRssServiceEntryPoint().icon());
|
setIcon(TtRssServiceEntryPoint().icon());
|
||||||
setCreationDate(QDateTime::currentDateTime());
|
setCreationDate(QDateTime::currentDateTime());
|
||||||
}
|
}
|
||||||
|
|
@ -111,17 +110,25 @@ bool TtRssServiceRoot::markAsReadUnread(RootItem::ReadStatus status) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TtRssServiceRoot::supportsFeedAddingByUrl() const {
|
bool TtRssServiceRoot::supportsFeedAdding() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TtRssServiceRoot::addFeedByUrl(const QString &url) {
|
bool TtRssServiceRoot::supportsCategoryAdding() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TtRssServiceRoot::addNewFeed(const QString &url) {
|
||||||
QPointer<FormEditFeed> form_pointer = new FormEditFeed(this, qApp->mainForm());
|
QPointer<FormEditFeed> form_pointer = new FormEditFeed(this, qApp->mainForm());
|
||||||
|
|
||||||
form_pointer.data()->execForAdd(url);
|
form_pointer.data()->execForAdd(url);
|
||||||
delete form_pointer.data();
|
delete form_pointer.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TtRssServiceRoot::addNewCategory() {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
bool TtRssServiceRoot::canBeEdited() {
|
bool TtRssServiceRoot::canBeEdited() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -153,14 +160,7 @@ QVariant TtRssServiceRoot::data(int column, int role) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QAction*> TtRssServiceRoot::addItemMenu() {
|
QList<QAction*> TtRssServiceRoot::addItemMenu() {
|
||||||
if (m_addItemMenu.isEmpty()) {
|
return QList<QAction*>();
|
||||||
QAction *action_new_feed = new QAction(qApp->icons()->fromTheme("folder-feed"), tr("Add new feed"), this);
|
|
||||||
connect(action_new_feed, SIGNAL(triggered()), this, SLOT(addFeedByUrl()));
|
|
||||||
|
|
||||||
m_addItemMenu.append(action_new_feed);
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_addItemMenu;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RecycleBin *TtRssServiceRoot::recycleBin() {
|
RecycleBin *TtRssServiceRoot::recycleBin() {
|
||||||
|
|
@ -581,6 +581,7 @@ void TtRssServiceRoot::syncIn() {
|
||||||
RootItem *new_tree = feed_cats_response.feedsCategories(true, m_network->url());
|
RootItem *new_tree = feed_cats_response.feedsCategories(true, m_network->url());
|
||||||
|
|
||||||
// Purge old data from SQL and clean all model items.
|
// Purge old data from SQL and clean all model items.
|
||||||
|
requestItemExpandStateSave(this);
|
||||||
removeOldFeedTree(false);
|
removeOldFeedTree(false);
|
||||||
cleanAllItems();
|
cleanAllItems();
|
||||||
|
|
||||||
|
|
@ -602,7 +603,17 @@ void TtRssServiceRoot::syncIn() {
|
||||||
|
|
||||||
itemChanged(all_items);
|
itemChanged(all_items);
|
||||||
requestReloadMessageList(true);
|
requestReloadMessageList(true);
|
||||||
requestItemExpand(all_items, true);
|
|
||||||
|
// Now we must refresh expand states.
|
||||||
|
QList<RootItem*> items_to_expand;
|
||||||
|
|
||||||
|
foreach (RootItem *item, all_items) {
|
||||||
|
if (qApp->settings()->value(GROUP(CategoriesExpandStates), item->hashCode(), item->childCount() > 0).toBool()) {
|
||||||
|
items_to_expand.append(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
requestItemExpand(items_to_expand, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
setIcon(original_icon);
|
setIcon(original_icon);
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,8 @@ class TtRssServiceRoot : public ServiceRoot {
|
||||||
|
|
||||||
bool markAsReadUnread(ReadStatus status);
|
bool markAsReadUnread(ReadStatus status);
|
||||||
|
|
||||||
bool supportsFeedAddingByUrl() const;
|
bool supportsFeedAdding() const;
|
||||||
|
bool supportsCategoryAdding() const;
|
||||||
|
|
||||||
QVariant data(int column, int role) const;
|
QVariant data(int column, int role) const;
|
||||||
|
|
||||||
|
|
@ -85,7 +86,8 @@ class TtRssServiceRoot : public ServiceRoot {
|
||||||
void completelyRemoveAllData();
|
void completelyRemoveAllData();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void addFeedByUrl(const QString &url = QString());
|
void addNewFeed(const QString &url = QString());
|
||||||
|
void addNewCategory();
|
||||||
void syncIn();
|
void syncIn();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -105,7 +107,6 @@ class TtRssServiceRoot : public ServiceRoot {
|
||||||
|
|
||||||
QAction *m_actionSyncIn;
|
QAction *m_actionSyncIn;
|
||||||
QList<QAction*> m_serviceMenu;
|
QList<QAction*> m_serviceMenu;
|
||||||
QList<QAction*> m_addItemMenu;
|
|
||||||
|
|
||||||
TtRssNetworkFactory *m_network;
|
TtRssNetworkFactory *m_network;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue