1 /* ============================================================
2 * QuiteRSS is a open-source cross-platform RSS/Atom news feeds reader
3 * Copyright (C) 2011-2020 QuiteRSS Team <quiterssteam@gmail.com>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 * ============================================================ */
18 #include "mainwindow.h"
19 
20 #include "common.h"
21 #include "mainapplication.h"
22 #include "database.h"
23 #include "aboutdialog.h"
24 #include "adblockmanager.h"
25 #include "adblockicon.h"
26 #include "addfeedwizard.h"
27 #include "addfolderdialog.h"
28 #include "cleanupwizard.h"
29 #include "customizetoolbardialog.h"
30 #include "feedpropertiesdialog.h"
31 #include "filterrulesdialog.h"
32 #include "newsfiltersdialog.h"
33 #include "webpage.h"
34 #include "settings.h"
35 
36 #if defined(Q_OS_WIN)
37 #include <windows.h>
38 #include <psapi.h>
39 #endif
40 #include <QMainWindow>
41 #include <QStatusBar>
42 #include <qzregexp.h>
43 
44 // ---------------------------------------------------------------------------
MainWindow(QWidget * parent)45 MainWindow::MainWindow(QWidget *parent)
46   : QMainWindow(parent)
47   , isMinimizeToTray_(true)
48   , currentNewsTab(NULL)
49   , isOpeningLink_(false)
50   , openNewsTab_(0)
51   , feedsFilterAction_(NULL)
52   , newsFilterAction_(NULL)
53   , newsView_(NULL)
54   , updateTimeCount_(0)
55 #if defined(HAVE_QT5) || defined(HAVE_PHONON)
56   , mediaPlayer_(NULL)
57 #endif
58   , updateAppDialog_(NULL)
59   , notificationWidget(NULL)
60   , feedIdOld_(-2)
61   , isStartImportFeed_(false)
62   , recountCategoryCountsOn_(false)
63   , optionsDialog_(NULL)
64 {
65   setObjectName("mainWindow");
66   setWindowTitle("QuiteRSS");
67   setContextMenuPolicy(Qt::CustomContextMenu);
68 
69   if (mainApp->analytics())
70     mainApp->analytics()->sendScreenview("MainWindow");
71 
72   db_ = QSqlDatabase::database();
73 
74   createFeedsWidget();
75   createToolBarNull();
76 
77   createActions();
78   createShortcut();
79   createMenu();
80   createToolBar();
81 
82   createStatusBar();
83   createTray();
84 
85   createTabBarWidget();
86   createCentralWidget();
87 
88   loadSettingsFeeds();
89 
90   setStyleSheet("QMainWindow::separator { width: 1px; }");
91 
92   loadSettings();
93 
94   addOurFeed();
95 
96   initUpdateFeeds();
97 
98   QTimer::singleShot(5000, this, SLOT(slotUpdateAppCheck()));
99 
100   connect(this, SIGNAL(signalShowNotification(bool)),
101           SLOT(showNotification(bool)), Qt::QueuedConnection);
102   connect(this, SIGNAL(signalPlaySoundNewNews()),
103           SLOT(slotPlaySoundNewNews()), Qt::QueuedConnection);
104 
105   connect(&timerLinkOpening_, SIGNAL(timeout()),
106           this, SLOT(slotTimerLinkOpening()));
107 
108   connect(mainApp->downloadManager(), SIGNAL(signalShowDownloads(bool)),
109           this, SLOT(showDownloadManager(bool)));
110   connect(mainApp->downloadManager(), SIGNAL(signalUpdateInfo(QString)),
111           this, SLOT(updateInfoDownloads(QString)));
112 
113   connect(&timerTrayOpenNotify, SIGNAL(timeout()), this, SLOT(slotTrayOpenNotifyTimer()));
114   timerTrayOpenNotify.setSingleShot(true);
115 
116   retranslateStrings();
117 
118   installEventFilter(this);
119 }
120 
121 // ---------------------------------------------------------------------------
~MainWindow()122 MainWindow::~MainWindow()
123 {
124 
125 }
126 
127 // ---------------------------------------------------------------------------
closeEvent(QCloseEvent * event)128 void MainWindow::closeEvent(QCloseEvent *event)
129 {
130   if (mainApp->isClosing())
131     return;
132 
133   if (closingTray_ && showTrayIcon_) {
134     event->ignore();
135     isOpeningLink_ = false;
136 
137     oldState = windowState();
138     emit signalPlaceToTray();
139   } else {
140 #if defined(Q_OS_MAC)
141     event->ignore();
142 #endif
143     quitApp();
144   }
145 }
146 
147 /** @brief Process quit application
148  *---------------------------------------------------------------------------*/
quitApp()149 void MainWindow::quitApp()
150 {
151   mainApp->setClosing();
152   isMinimizeToTray_ = true;
153   disconnect(this);
154   if (updateAppDialog_) {
155     updateAppDialog_->disconnectObjects();
156     updateAppDialog_->deleteLater();
157   }
158   if (optionsDialog_) {
159     optionsDialog_->close();
160   }
161 
162   mainApp->showClosingWidget();
163 
164   hide();
165   traySystem->hide();
166 
167   saveSettings();
168 
169   for (int i = 0; i < stackedWidget_->count(); i++) {
170     NewsTabWidget *widget = (NewsTabWidget*)stackedWidget_->widget(i);
171     widget->disconnectObjects();
172   }
173 
174   mainApp->networkManager()->disconnect(mainApp->networkManager());
175   mainApp->updateFeeds()->disconnectObjects();
176   emit signalQuitApp();
177 }
178 
179 // ---------------------------------------------------------------------------
eventFilter(QObject * obj,QEvent * event)180 bool MainWindow::eventFilter(QObject *obj, QEvent *event)
181 {
182   static int deactivateState = 0;
183 
184   if (obj == this) {
185     if (event->type() == QEvent::KeyPress) {
186       QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
187       if ((keyEvent->key() == Qt::Key_Up) ||
188           (keyEvent->key() == Qt::Key_Down) ||
189           (keyEvent->key() == Qt::Key_Left) ||
190           (keyEvent->key() == Qt::Key_Right)) {
191         QListIterator<QAction *> iter(listActions_);
192         while (iter.hasNext()) {
193           QAction *pAction = iter.next();
194           if (pAction->shortcut() == QKeySequence(keyEvent->key())) {
195             pAction->activate(QAction::Trigger);
196             break;
197           }
198         }
199       }
200     }
201   }
202 
203   if (obj == statusBar()) {
204     if (event->type() == QEvent::MouseButtonRelease) {
205       if (windowState() & Qt::WindowMaximized) {
206         QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
207         if ((mouseEvent->pos().x() > (statusBar()->width()-statusBar()->height())) &&
208             (mouseEvent->pos().y() > 0)) {
209           setFullScreen();
210         }
211       }
212     }
213     return false;
214   } else if (obj == categoriesLabel_) {
215     if (event->type() == QEvent::MouseButtonRelease) {
216       showNewsCategoriesTree();
217     }
218     return false;
219   } else if (obj == categoriesTree_) {
220     if (event->type() == QEvent::Show) {
221       recountCategoryCounts();
222     }
223   }
224   else if (event->type() == QEvent::WindowActivate) {
225     activationStateChangedTime_ = QDateTime::currentMSecsSinceEpoch();
226   }
227   // Process  open link in browser in background
228   else if (event->type() == QEvent::WindowDeactivate) {
229     if (isOpeningLink_ && openLinkInBackground_) {
230       isOpeningLink_ = false;
231       timerLinkOpening_.start(openingLinkTimeout_);
232       deactivateState = 1;
233     }
234     activationStateChangedTime_ = QDateTime::currentMSecsSinceEpoch();
235   }
236   // deactivation has painted
237   else if ((event->type() == QEvent::Paint) && (deactivateState == 1)) {
238     deactivateState = 2;
239   }
240   // deactivation in done. Reactivating
241   else if ((deactivateState == 2) && timerLinkOpening_.isActive()) {
242     deactivateState = 3;
243     if (!isActiveWindow()) {
244       setWindowState(windowState() & ~Qt::WindowActive);
245       show();
246       raise();
247       activateWindow();
248     }
249   }
250   // activating had painted
251   else if ((deactivateState == 3) && (event->type() == QEvent::Paint)) {
252     deactivateState = 0;
253   } else if (event->type() == QEvent::Hide) {
254     if (minimizingTray_  && showTrayIcon_ && !isMinimizeToTray_) {
255       emit signalPlaceToTray();
256     }
257   }
258 
259   // pass the event on to the parent class
260   return QMainWindow::eventFilter(obj, event);
261 }
262 
263 /** @brief Process send link to external browser in background
264  *---------------------------------------------------------------------------*/
slotTimerLinkOpening()265 void MainWindow::slotTimerLinkOpening()
266 {
267   timerLinkOpening_.stop();
268   if (!isActiveWindow()) {
269     setWindowState(windowState() & ~Qt::WindowActive);
270     show();
271     raise();
272     activateWindow();
273   }
274 }
275 
276 /** @brief Process changing window state
277  *---------------------------------------------------------------------------*/
changeEvent(QEvent * event)278 void MainWindow::changeEvent(QEvent *event)
279 {
280   if (event->type() == QEvent::WindowStateChange) {
281     isOpeningLink_ = false;
282     if (isMinimized()) {
283       oldState = ((QWindowStateChangeEvent*)event)->oldState();
284     } else {
285       oldState = windowState();
286     }
287   } else if (event->type() == QEvent::ActivationChange) {
288     if (isActiveWindow() && (behaviorIconTray_ == CHANGE_ICON_TRAY)) {
289       traySystem->setIcon(QIcon(":/images/quiterss128"));
290     }
291   } else if (event->type() == QEvent::LanguageChange) {
292     retranslateStrings();
293   }
294   QMainWindow::changeEvent(event);
295 }
296 
297 /** @brief Process placing to tray event
298  *---------------------------------------------------------------------------*/
slotPlaceToTray()299 void MainWindow::slotPlaceToTray()
300 {
301   isMinimizeToTray_ = true;
302   hide();
303 
304   if (emptyWorking_)
305     QTimer::singleShot(10000, this, SLOT(myEmptyWorkingSet()));
306   if (markReadMinimize_)
307     setFeedRead(currentNewsTab->type_, currentNewsTab->feedId_, FeedReadPlaceToTray, currentNewsTab);
308   if (clearStatusNew_)
309     QTimer::singleShot(0, this, SIGNAL(signalMarkAllFeedsOld()));
310   clearNotification(true);
311 
312   saveSettings();
313 
314   mainApp->updateFeeds()->saveMemoryDatabase();
315 
316   isMinimizeToTray_ = false;
317 }
318 
319 /** @brief Process tray event
320  *---------------------------------------------------------------------------*/
slotActivationTray(QSystemTrayIcon::ActivationReason reason)321 void MainWindow::slotActivationTray(QSystemTrayIcon::ActivationReason reason)
322 {
323   bool activated = false;
324 
325   switch (reason) {
326   case QSystemTrayIcon::Unknown:
327     break;
328   case QSystemTrayIcon::Context:
329     trayMenu_->activateWindow();
330     break;
331 
332   case QSystemTrayIcon::DoubleClick:
333   {
334     if (!singleClickTray_)
335     {
336       timerTrayOpenNotify.stop();
337 
338       if ((QDateTime::currentMSecsSinceEpoch() - activationStateChangedTime_ < 300) || isActiveWindow())
339       {
340         activated = true;
341       }
342 
343       showWindows(activated);
344     }
345 
346     break;
347   }
348 
349   case QSystemTrayIcon::Trigger:
350   {
351     if (singleClickTray_)
352     {
353       qint64 lastActiveChangeTime = QDateTime::currentMSecsSinceEpoch() - activationStateChangedTime_;
354 
355       if (isActiveWindow() ? (lastActiveChangeTime >= 200) : (lastActiveChangeTime < 200))
356       {
357         activated = true;
358       }
359 
360       showWindows(activated);
361     }
362     else
363     {
364       if (notificationWidget == NULL)
365       {
366         if (!timerTrayOpenNotify.isActive())
367         {
368           timerTrayOpenNotify.start(400);
369         }
370       }
371       else
372       {
373         delete notificationWidget;
374         notificationWidget = NULL;
375       }
376     }
377 
378     break;
379   }
380 
381   case QSystemTrayIcon::MiddleClick:
382     break;
383   }
384 }
slotTrayOpenNotifyTimer()385 void MainWindow::slotTrayOpenNotifyTimer()
386 {
387   emit signalShowNotification(true);
388 }
389 
390 /** @brief Show window on event
391  *---------------------------------------------------------------------------*/
showWindows(bool trayClick)392 void MainWindow::showWindows(bool trayClick)
393 {
394   if (!trayClick || isHidden()) {
395     if (oldState & Qt::WindowFullScreen) {
396       show();
397     } else if (oldState & Qt::WindowMaximized) {
398       showMaximized();
399     } else {
400       showNormal();
401       Settings settings;
402       restoreGeometry(settings.value("GeometryState").toByteArray());
403     }
404     activateWindow();
405   } else {
406     if (minimizingTray_)
407       emit signalPlaceToTray();
408     else
409       showMinimized();
410   }
411 }
412 // ---------------------------------------------------------------------------
createFeedsWidget()413 void MainWindow::createFeedsWidget()
414 {
415   feedsModel_ = new FeedsModel(this);
416 
417   feedsProxyModel_ = new FeedsProxyModel(feedsModel_);
418   feedsProxyModel_->setSourceModel(feedsModel_);
419 
420   feedsView_ = new FeedsView(this);
421   feedsView_->setModel(feedsProxyModel_);
422   feedsView_->setSourceModel(feedsModel_);
423   feedsModel_->setView(feedsView_);
424 
425   for (int i = 0; i < feedsView_->model()->columnCount(); ++i)
426     feedsView_->hideColumn(i);
427   feedsView_->showColumn(feedsView_->columnIndex("text"));
428 #ifdef HAVE_QT5
429   feedsView_->header()->setSectionResizeMode(feedsView_->columnIndex("text"), QHeaderView::Stretch);
430   feedsView_->header()->setSectionResizeMode(feedsView_->columnIndex("unread"), QHeaderView::ResizeToContents);
431   feedsView_->header()->setSectionResizeMode(feedsView_->columnIndex("undeleteCount"), QHeaderView::ResizeToContents);
432   feedsView_->header()->setSectionResizeMode(feedsView_->columnIndex("updated"), QHeaderView::ResizeToContents);
433 #else
434   feedsView_->header()->setResizeMode(feedsView_->columnIndex("text"), QHeaderView::Stretch);
435   feedsView_->header()->setResizeMode(feedsView_->columnIndex("unread"), QHeaderView::ResizeToContents);
436   feedsView_->header()->setResizeMode(feedsView_->columnIndex("undeleteCount"), QHeaderView::ResizeToContents);
437   feedsView_->header()->setResizeMode(feedsView_->columnIndex("updated"), QHeaderView::ResizeToContents);
438 #endif
439 
440   feedsToolBar_ = new QToolBar(this);
441   feedsToolBar_->setObjectName("feedsToolBar");
442   feedsToolBar_->setStyleSheet("QToolBar { border: none; padding: 0px; }");
443 
444   QHBoxLayout *feedsPanelLayout = new QHBoxLayout();
445   feedsPanelLayout->setMargin(2);
446   feedsPanelLayout->addWidget(feedsToolBar_, 1);
447 
448   feedsPanel_ = new QWidget(this);
449   feedsPanel_->setObjectName("feedsPanel_");
450   feedsPanel_->setStyleSheet(
451         QString("#feedsPanel_ {border-bottom: 1px solid %1;}").
452         arg(qApp->palette().color(QPalette::Dark).name()));
453   feedsPanel_->setLayout(feedsPanelLayout);
454 
455   findFeeds_ = new FindFeed(this);
456   QVBoxLayout *findFeedsLayout = new QVBoxLayout();
457   findFeedsLayout->setMargin(2);
458   findFeedsLayout->addWidget(findFeeds_);
459   findFeedsWidget_ = new QWidget(this);
460   findFeedsWidget_->hide();
461   findFeedsWidget_->setLayout(findFeedsLayout);
462 
463   categoriesTree_ = new CategoriesTreeWidget(this);
464 
465   categoriesLabel_ = new QLabel(this);
466   categoriesLabel_->setObjectName("categoriesLabel_");
467 
468   showCategoriesButton_ = new ToolButton(this);
469   showCategoriesButton_->setFocusPolicy(Qt::NoFocus);
470   showCategoriesButton_->setMaximumSize(16, 16);
471   showCategoriesButton_->setAutoRaise(true);
472 
473   QHBoxLayout *categoriesPanelLayout = new QHBoxLayout();
474   categoriesPanelLayout->setMargin(2);
475   categoriesPanelLayout->addSpacing(2);
476   categoriesPanelLayout->addWidget(categoriesLabel_, 1);
477   categoriesPanelLayout->addWidget(showCategoriesButton_);
478 
479   categoriesPanel_ = new QWidget(this);
480   categoriesPanel_->setObjectName("categoriesPanel_");
481   categoriesPanel_->setLayout(categoriesPanelLayout);
482 
483   QVBoxLayout *categoriesLayout = new QVBoxLayout();
484   categoriesLayout->setMargin(0);
485   categoriesLayout->setSpacing(0);
486   categoriesLayout->addWidget(categoriesPanel_);
487   categoriesLayout->addWidget(categoriesTree_, 1);
488 
489   categoriesWidget_ = new QWidget(this);
490   categoriesWidget_->setLayout(categoriesLayout);
491 
492   feedsSplitter_ = new QSplitter(Qt::Vertical);
493   feedsSplitter_->setChildrenCollapsible(false);
494   feedsSplitter_->setHandleWidth(1);
495   feedsSplitter_->setStyleSheet(
496         QString("QSplitter::handle {background: %1;}").
497         arg(qApp->palette().color(QPalette::Dark).name()));
498   feedsSplitter_->addWidget(feedsView_);
499   feedsSplitter_->addWidget(categoriesWidget_);
500   feedsSplitter_->setStretchFactor(0, 1);
501 
502 #define CATEGORIES_HEIGHT 210
503   QList <int> sizes;
504   sizes << QApplication::desktop()->height() << CATEGORIES_HEIGHT;
505   feedsSplitter_->setSizes(sizes);
506 
507   QVBoxLayout *feedsLayout = new QVBoxLayout();
508   feedsLayout->setMargin(0);
509   feedsLayout->setSpacing(0);
510   feedsLayout->addWidget(feedsPanel_);
511   feedsLayout->addWidget(findFeedsWidget_);
512   feedsLayout->addWidget(feedsSplitter_, 1);
513 
514   feedsWidget_ = new QFrame(this);
515   feedsWidget_->setFrameStyle(QFrame::NoFrame);
516   feedsWidget_->setLayout(feedsLayout);
517 
518   connect(feedsView_, SIGNAL(pressed(QModelIndex)),
519           this, SLOT(slotFeedClicked(QModelIndex)));
520   connect(feedsView_, SIGNAL(signalMiddleClicked()),
521           this, SLOT(slotOpenFeedNewTab()));
522   connect(feedsView_, SIGNAL(signalDoubleClicked()),
523           this, SLOT(slotGetFeed()));
524   connect(feedsView_, SIGNAL(pressKeyUp()), this, SLOT(slotFeedUpPressed()));
525   connect(feedsView_, SIGNAL(pressKeyDown()), this, SLOT(slotFeedDownPressed()));
526   connect(feedsView_, SIGNAL(pressKeyHome()), this, SLOT(slotFeedHomePressed()));
527   connect(feedsView_, SIGNAL(pressKeyEnd()), this, SLOT(slotFeedEndPressed()));
528   connect(feedsView_, SIGNAL(pressKeyPageUp()), this, SLOT(slotFeedPageUpPressed()));
529   connect(feedsView_, SIGNAL(pressKeyPageDown()), this, SLOT(slotFeedPageDownPressed()));
530   connect(feedsView_, SIGNAL(signalDropped(QModelIndex,int)),
531           this, SLOT(slotMoveIndex(QModelIndex,int)));
532   connect(feedsView_, SIGNAL(customContextMenuRequested(QPoint)),
533           this, SLOT(showContextMenuFeed(const QPoint &)));
534 
535   connect(findFeeds_, SIGNAL(textChanged(QString)),
536           this, SLOT(slotFindFeeds(QString)));
537   connect(findFeeds_, SIGNAL(signalSelectFind()),
538           this, SLOT(slotSelectFind()));
539   connect(findFeeds_, SIGNAL(returnPressed()),
540           this, SLOT(slotSelectFind()));
541   connect(findFeeds_, SIGNAL(signalVisible(bool)),
542           this, SLOT(findFeedVisible(bool)));
543 
544   connect(categoriesTree_, SIGNAL(itemPressed(QTreeWidgetItem*,int)),
545           this, SLOT(slotCategoriesClicked(QTreeWidgetItem*,int)));
546   connect(categoriesTree_, SIGNAL(signalMiddleClicked()),
547           this, SLOT(slotOpenCategoryNewTab()));
548   connect(categoriesTree_, SIGNAL(signalClearDeleted()),
549           this, SLOT(clearDeleted()));
550   connect(categoriesTree_, SIGNAL(signalMarkRead(QTreeWidgetItem*)),
551           this, SLOT(slotMarkReadCategory(QTreeWidgetItem*)));
552   connect(showCategoriesButton_, SIGNAL(clicked()),
553           this, SLOT(showNewsCategoriesTree()));
554   connect(feedsSplitter_, SIGNAL(splitterMoved(int,int)),
555           this, SLOT(feedsSplitterMoved(int,int)));
556 
557   categoriesLabel_->installEventFilter(this);
558   categoriesTree_->installEventFilter(this);
559 }
560 // ---------------------------------------------------------------------------
createToolBarNull()561 void MainWindow::createToolBarNull()
562 {
563   pushButtonNull_ = new QPushButton(this);
564   pushButtonNull_->setObjectName("pushButtonNull");
565   pushButtonNull_->setIcon(QIcon(":/images/images/triangleR.png"));
566   pushButtonNull_->setFixedWidth(6);
567   pushButtonNull_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
568   pushButtonNull_->setFocusPolicy(Qt::NoFocus);
569 }
570 // ---------------------------------------------------------------------------
createNewsTab(int index)571 void MainWindow::createNewsTab(int index)
572 {
573   currentNewsTab = (NewsTabWidget*)stackedWidget_->widget(index);
574   currentNewsTab->setSettings();
575   currentNewsTab->retranslateStrings();
576   currentNewsTab->setBrowserPosition();
577 
578   newsModel_ = currentNewsTab->newsModel_;
579   newsView_ = currentNewsTab->newsView_;
580 }
581 // ---------------------------------------------------------------------------
createStatusBar()582 void MainWindow::createStatusBar()
583 {
584 #if defined(HAVE_X11) || defined(Q_OS_MAC)
585   statusBar()->setStyleSheet(QString("QStatusBar::item {border-right: 1px solid %1;"
586                                      "margin: 1px;}").
587                              arg(qApp->palette().color(QPalette::Dark).name()));
588 #endif
589 
590   progressBar_ = new QProgressBar(this);
591   progressBar_->setObjectName("progressBar_");
592   progressBar_->setFormat("%p%");
593   progressBar_->setAlignment(Qt::AlignCenter);
594   progressBar_->setFixedWidth(100);
595   progressBar_->setFixedHeight(15);
596   progressBar_->setMinimum(0);
597   progressBar_->setMaximum(0);
598   progressBar_->setValue(0);
599   progressBar_->setVisible(false);
600 
601   QToolButton *stopUpdateButton_ = new QToolButton(progressBar_);
602   stopUpdateButton_->setFocusPolicy(Qt::NoFocus);
603   stopUpdateButton_->setToolButtonStyle(Qt::ToolButtonIconOnly);
604   stopUpdateButton_->setFixedSize(15, 15);
605   stopUpdateButton_->setCursor(Qt::ArrowCursor);
606   stopUpdateButton_->setDefaultAction(stopUpdateAct_);
607   stopUpdateButton_->setStyleSheet(
608         "QToolButton { border: none; padding: 0px; background: none; }"
609         "QToolButton:hover { background: rgba(150, 150, 150, 60) }"
610         );
611   stopUpdateButton_->move(progressBar_->rect().right() - stopUpdateButton_->sizeHint().width(),
612                           progressBar_->rect().top());
613 
614 
615   adblockIcon_ = new AdBlockIcon(this);
616 
617   QToolButton *loadImagesButton = new QToolButton(this);
618   loadImagesButton->setFocusPolicy(Qt::NoFocus);
619   loadImagesButton->setIconSize(QSize(16,16));
620   loadImagesButton->setDefaultAction(autoLoadImagesToggle_);
621   loadImagesButton->setStyleSheet("QToolButton { border: none; padding: 0px; background: none; }");
622 
623   QToolButton *fullScreenButton = new QToolButton(this);
624   fullScreenButton->setFocusPolicy(Qt::NoFocus);
625   loadImagesButton->setIconSize(QSize(16,16));
626   fullScreenButton->setDefaultAction(fullScreenAct_);
627   fullScreenButton->setStyleSheet("QToolButton { border: none; padding: 0px; background: none; }");
628   statusBar()->installEventFilter(this);
629 
630   statusBar()->addPermanentWidget(progressBar_);
631   statusUnread_ = new QLabel(this);
632   statusUnread_->hide();
633   statusBar()->addPermanentWidget(statusUnread_);
634   statusAll_ = new QLabel(this);
635   statusAll_->hide();
636   statusBar()->addPermanentWidget(statusAll_);
637   statusBar()->addPermanentWidget(adblockIcon_);
638   statusBar()->addPermanentWidget(loadImagesButton);
639   statusBar()->addPermanentWidget(fullScreenButton);
640   statusBar()->setVisible(true);
641 }
642 // ---------------------------------------------------------------------------
createTray()643 void MainWindow::createTray()
644 {
645   traySystem = new QSystemTrayIcon(QIcon(":/images/quiterss128"), this);
646   traySystem->setToolTip("QuiteRSS");
647 
648 #ifndef Q_OS_MAC
649   connect(traySystem,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
650           this, SLOT(slotActivationTray(QSystemTrayIcon::ActivationReason)));
651   connect(this, SIGNAL(signalPlaceToTray()),
652           this, SLOT(slotPlaceToTray()), Qt::QueuedConnection);
653 #endif
654 
655   createTrayMenu();
656 }
657 
658 /** @brief Create tabbar widget
659  *---------------------------------------------------------------------------*/
createTabBarWidget()660 void MainWindow::createTabBarWidget()
661 {
662   mainMenuButton_ = new ToolButton(this);
663   mainMenuButton_->setObjectName("mainMenuButton");
664   mainMenuButton_->setIcon(QIcon(":/images/menu"));
665 
666   tabBar_ = new TabBar();
667 
668   QHBoxLayout *tabBarLayout = new QHBoxLayout();
669   tabBarLayout->setContentsMargins(0, 0, 0, 0);
670   tabBarLayout->setSpacing(0);
671   tabBarLayout->addWidget(mainMenuButton_);
672   tabBarLayout->addSpacing(5);
673   tabBarLayout->addWidget(tabBar_, 1);
674 
675   tabBarWidget_ = new QWidget(this);
676   tabBarWidget_->setObjectName("tabBarWidget");
677   tabBarWidget_->setMinimumHeight(1);
678   tabBarWidget_->setLayout(tabBarLayout);
679 
680   connect(mainMenuButton_, SIGNAL(clicked()), this, SLOT(showMainMenu()));
681   connect(tabBar_, SIGNAL(closeTab(int)),
682           this, SLOT(slotCloseTab(int)));
683   connect(tabBar_, SIGNAL(currentChanged(int)),
684           this, SLOT(slotTabCurrentChanged(int)), Qt::QueuedConnection);
685   connect(tabBar_, SIGNAL(tabMoved(int,int)),
686           SLOT(slotTabMoved(int,int)));
687   connect(this, SIGNAL(signalSetCurrentTab(int,bool)),
688           SLOT(setCurrentTab(int,bool)), Qt::QueuedConnection);
689 
690   connect(closeTabAct_, SIGNAL(triggered()), tabBar_, SLOT(slotCloseTab()));
691   connect(closeOtherTabsAct_, SIGNAL(triggered()),
692           tabBar_, SLOT(slotCloseOtherTabs()));
693   connect(closeAllTabsAct_, SIGNAL(triggered()),
694           tabBar_, SLOT(slotCloseAllTab()));
695   connect(nextTabAct_, SIGNAL(triggered()), tabBar_, SLOT(slotNextTab()));
696   connect(prevTabAct_, SIGNAL(triggered()), tabBar_, SLOT(slotPrevTab()));
697 }
698 
createCentralWidget()699 void MainWindow::createCentralWidget()
700 {
701   stackedWidget_ = new QStackedWidget(this);
702   stackedWidget_->setObjectName("stackedWidget_");
703   stackedWidget_->setFrameStyle(QFrame::NoFrame);
704 
705   mainSplitter_ = new QSplitter(this);
706   mainSplitter_ ->setFrameStyle(QFrame::NoFrame);
707   mainSplitter_->setHandleWidth(1);
708   mainSplitter_->setStyleSheet(
709         QString("QSplitter::handle {background: qlineargradient("
710                 "x1: 0, y1: 0, x2: 0, y2: 1,"
711                 "stop: 0 %1, stop: 0.07 %2);}").
712         arg(feedsPanel_->palette().background().color().name()).
713         arg(qApp->palette().color(QPalette::Dark).name()));
714   mainSplitter_->setChildrenCollapsible(false);
715   mainSplitter_->addWidget(feedsWidget_);
716   mainSplitter_->addWidget(stackedWidget_);
717   mainSplitter_->setStretchFactor(1, 1);
718 
719 #define FEEDS_WIDTH 180
720   QList <int> sizes;
721   sizes << FEEDS_WIDTH << QApplication::desktop()->width();
722   mainSplitter_->setSizes(sizes);
723 
724   QHBoxLayout *mainLayout1 = new QHBoxLayout();
725   mainLayout1->addWidget(pushButtonNull_);
726   mainLayout1->addWidget(mainSplitter_, 1);
727 
728   QVBoxLayout *mainLayout = new QVBoxLayout();
729   mainLayout->setMargin(0);
730   mainLayout->setSpacing(0);
731   mainLayout->addWidget(tabBarWidget_);
732   mainLayout->addLayout(mainLayout1, 1);
733 
734   centralWidget_ = new QWidget(this);
735   centralWidget_->setLayout(mainLayout);
736 
737   setCentralWidget(centralWidget_);
738 }
739 
740 /** @brief Create actions for main menu and toolbar
741  *---------------------------------------------------------------------------*/
createActions()742 void MainWindow::createActions()
743 {
744   addAct_ = new QAction(this);
745   addAct_->setObjectName("newAct");
746   addAct_->setIcon(QIcon(":/images/add"));
747   this->addAction(addAct_);
748   connect(addAct_, SIGNAL(triggered()), this, SLOT(addFeed()));
749 
750   addFeedAct_ = new QAction(this);
751   addFeedAct_->setObjectName("addFeedAct");
752   addFeedAct_->setIcon(QIcon(":/images/feed"));
753   this->addAction(addFeedAct_);
754   connect(addFeedAct_, SIGNAL(triggered()), this, SLOT(addFeed()));
755 
756   addFeedTrayAct_ = new QAction(this);
757   addFeedTrayAct_->setIcon(QIcon(":/images/feed"));
758   connect(addFeedTrayAct_, SIGNAL(triggered()), this, SLOT(addFeed()));
759 
760   addFolderAct_ = new QAction(this);
761   addFolderAct_->setObjectName("addFolderAct");
762   addFolderAct_->setIcon(QIcon(":/images/folder"));
763   this->addAction(addFolderAct_);
764   connect(addFolderAct_, SIGNAL(triggered()), this, SLOT(addFolder()));
765 
766   openFeedNewTabAct_ = new QAction(this);
767   openFeedNewTabAct_->setObjectName("openNewTabAct");
768   this->addAction(openFeedNewTabAct_);
769   connect(openFeedNewTabAct_, SIGNAL(triggered()), this, SLOT(slotOpenFeedNewTab()));
770 
771   deleteFeedAct_ = new QAction(this);
772   deleteFeedAct_->setObjectName("deleteFeedAct");
773   deleteFeedAct_->setIcon(QIcon(":/images/delete"));
774   this->addAction(deleteFeedAct_);
775   connect(deleteFeedAct_, SIGNAL(triggered()), this, SLOT(deleteItemFeedsTree()));
776 
777   importFeedsAct_ = new QAction(this);
778   importFeedsAct_->setObjectName("importFeedsAct");
779   importFeedsAct_->setIcon(QIcon(":/images/importFeeds"));
780   this->addAction(importFeedsAct_);
781   connect(importFeedsAct_, SIGNAL(triggered()), this, SLOT(slotImportFeeds()));
782 
783   exportFeedsAct_ = new QAction(this);
784   exportFeedsAct_->setObjectName("exportFeedsAct");
785   exportFeedsAct_->setIcon(QIcon(":/images/exportFeeds"));
786   this->addAction(exportFeedsAct_);
787   connect(exportFeedsAct_, SIGNAL(triggered()), this, SLOT(slotExportFeeds()));
788 
789   createBackupAct_ = new QAction(this);
790   createBackupAct_->setObjectName("createBackupAct");
791   createBackupAct_->setIcon(QIcon(":/images/backup"));
792   this->addAction(createBackupAct_);
793   connect(createBackupAct_, SIGNAL(triggered()), this, SLOT(createBackup()));
794 
795   showMenuBarAct_ = new QAction(this);
796   showMenuBarAct_->setCheckable(true);
797   connect(showMenuBarAct_, SIGNAL(triggered()), this, SLOT(showMenuBar()));
798 
799   exitAct_ = new QAction(this);
800   exitAct_->setObjectName("exitAct");
801   this->addAction(exitAct_);
802   connect(exitAct_, SIGNAL(triggered()), this, SLOT(quitApp()));
803 
804   mainToolbarToggle_ = new QAction(this);
805   mainToolbarToggle_->setCheckable(true);
806   feedsToolbarToggle_ = new QAction(this);
807   feedsToolbarToggle_->setCheckable(true);
808   newsToolbarToggle_ = new QAction(this);
809   newsToolbarToggle_->setCheckable(true);
810   browserToolbarToggle_ = new QAction(this);
811   browserToolbarToggle_->setCheckable(true);
812   categoriesPanelToggle_ = new QAction(this);
813   categoriesPanelToggle_->setCheckable(true);
814   statusBarToggle_ = new QAction(this);
815   statusBarToggle_->setCheckable(true);
816 
817   connect(feedsToolbarToggle_, SIGNAL(toggled(bool)),
818           feedsPanel_, SLOT(setVisible(bool)));
819   connect(categoriesPanelToggle_, SIGNAL(toggled(bool)),
820           categoriesWidget_, SLOT(setVisible(bool)));
821   connect(statusBarToggle_, SIGNAL(toggled(bool)),
822           statusBar(), SLOT(setVisible(bool)));
823 
824   customizeMainToolbarAct_ = new QAction(this);
825   customizeMainToolbarAct_->setObjectName("customizeMainToolbarAct");
826   customizeMainToolbarAct2_ = new QAction(this);
827   connect(customizeMainToolbarAct2_, SIGNAL(triggered()),
828           this, SLOT(customizeMainToolbar()));
829 
830   toolBarLockAct_ = new QAction(this);
831   toolBarLockAct_->setCheckable(true);
832   toolBarHideAct_ = new QAction(this);
833 
834   customizeFeedsToolbarAct_ = new QAction(this);
835   customizeFeedsToolbarAct_->setObjectName("customizeFeedsToolbarAct");
836 
837   customizeNewsToolbarAct_ = new QAction(this);
838   customizeNewsToolbarAct_->setObjectName("customizeNewsToolbarAct");
839 
840   classicLayoutAct_ = new QAction(this);
841   classicLayoutAct_->setObjectName("classicLayoutAct_");
842   classicLayoutAct_->setIcon(QIcon(":/images/layout_classic"));
843   classicLayoutAct_->setCheckable(true);
844   classicLayoutAct_->setData(0);
845   newspaperLayoutAct_ = new QAction(this);
846   newspaperLayoutAct_->setObjectName("newspaperLayoutAct_");
847   newspaperLayoutAct_->setIcon(QIcon(":/images/layout_newspaper"));
848   newspaperLayoutAct_->setCheckable(true);
849   newspaperLayoutAct_->setData(1);
850   layoutToggle_ = new QAction(this);
851   layoutToggle_->setObjectName("layoutToggle");
852   layoutToggle_->setIcon(QIcon(":/images/layout_classic"));
853   this->addAction(layoutToggle_);
854   connect(layoutToggle_, SIGNAL(triggered()),
855           this, SLOT(setNewsLayout()));
856 
857   systemStyle_ = new QAction(this);
858   systemStyle_->setObjectName("systemStyle_");
859   systemStyle_->setCheckable(true);
860   system2Style_ = new QAction(this);
861   system2Style_->setObjectName("system2Style_");
862   system2Style_->setCheckable(true);
863   darkStyle_ = new QAction(this);
864   darkStyle_->setObjectName("darkStyle_");
865   darkStyle_->setCheckable(true);
866   greenStyle_ = new QAction(this);
867   greenStyle_->setObjectName("greenStyle_");
868   greenStyle_->setCheckable(true);
869   greenStyle_->setChecked(true);
870   orangeStyle_ = new QAction(this);
871   orangeStyle_->setObjectName("orangeStyle_");
872   orangeStyle_->setCheckable(true);
873   purpleStyle_ = new QAction(this);
874   purpleStyle_->setObjectName("purpleStyle_");
875   purpleStyle_->setCheckable(true);
876   pinkStyle_ = new QAction(this);
877   pinkStyle_->setObjectName("pinkStyle_");
878   pinkStyle_->setCheckable(true);
879   grayStyle_ = new QAction(this);
880   grayStyle_->setObjectName("grayStyle_");
881   grayStyle_->setCheckable(true);
882 
883   topBrowserPositionAct_ = new QAction(this);
884   topBrowserPositionAct_->setCheckable(true);
885   topBrowserPositionAct_->setData(TOP_POSITION);
886   bottomBrowserPositionAct_ = new QAction(this);
887   bottomBrowserPositionAct_->setCheckable(true);
888   bottomBrowserPositionAct_->setData(BOTTOM_POSITION);
889   rightBrowserPositionAct_ = new QAction(this);
890   rightBrowserPositionAct_->setCheckable(true);
891   rightBrowserPositionAct_->setData(RIGHT_POSITION);
892   leftBrowserPositionAct_ = new QAction(this);
893   leftBrowserPositionAct_->setCheckable(true);
894   leftBrowserPositionAct_->setData(LEFT_POSITION);
895 
896   autoLoadImagesToggle_ = new QAction(this);
897   autoLoadImagesToggle_->setObjectName("autoLoadImagesToggle");
898   autoLoadImagesToggle_->setIcon(QIcon(":/images/imagesOn"));
899   this->addAction(autoLoadImagesToggle_);
900 
901   printAct_ = new QAction(this);
902   printAct_->setObjectName("printAct");
903   printAct_->setIcon(QIcon(":/images/printer"));
904   this->addAction(printAct_);
905   connect(printAct_, SIGNAL(triggered()), this, SLOT(slotPrint()));
906   printPreviewAct_ = new QAction(this);
907   printPreviewAct_->setObjectName("printPreviewAct");
908   printPreviewAct_->setIcon(QIcon(":/images/printer"));
909   this->addAction(printPreviewAct_);
910   connect(printPreviewAct_, SIGNAL(triggered()), this, SLOT(slotPrintPreview()));
911 
912   savePageAsAct_ = new QAction(this);
913   savePageAsAct_->setObjectName("savePageAsAct");
914   savePageAsAct_->setIcon(QIcon(":/images/save_as"));
915   this->addAction(savePageAsAct_);
916   connect(savePageAsAct_, SIGNAL(triggered()), this, SLOT(slotSavePageAs()));
917 
918   savePageAsDescriptAct_ = new QAction(this);
919   savePageAsDescriptAct_->setObjectName("savePageAsDescriptAct");
920   savePageAsDescriptAct_->setIcon(QIcon(":/images/save_as"));
921   this->addAction(savePageAsDescriptAct_);
922   connect(savePageAsDescriptAct_, SIGNAL(triggered()),
923           this, SLOT(slotSavePageAsDescript()));
924 
925   zoomInAct_ = new QAction(this);
926   zoomInAct_->setObjectName("zoomInAct");
927   zoomInAct_->setIcon(QIcon(":/images/zoomIn"));
928   this->addAction(zoomInAct_);
929   zoomOutAct_ = new QAction(this);
930   zoomOutAct_->setObjectName("zoomOutAct");
931   zoomOutAct_->setIcon(QIcon(":/images/zoomOut"));
932   this->addAction(zoomOutAct_);
933   zoomTo100Act_ = new QAction(this);
934   zoomTo100Act_->setObjectName("zoomTo100Act");
935   this->addAction(zoomTo100Act_);
936 
937   updateFeedAct_ = new QAction(this);
938   updateFeedAct_->setObjectName("updateFeedAct");
939   updateFeedAct_->setIcon(QIcon(":/images/updateFeed"));
940   this->addAction(updateFeedAct_);
941   connect(updateFeedAct_, SIGNAL(triggered()), this, SLOT(slotGetFeed()));
942 
943   updateAllFeedsAct_ = new QAction(this);
944   updateAllFeedsAct_->setObjectName("updateAllFeedsAct");
945   updateAllFeedsAct_->setIcon(QIcon(":/images/updateAllFeeds"));
946   this->addAction(updateAllFeedsAct_);
947   connect(updateAllFeedsAct_, SIGNAL(triggered()), this, SLOT(slotGetAllFeeds()));
948 
949   stopUpdateAct_ = new QAction(this);
950   stopUpdateAct_->setObjectName("stopUpdateAct");
951   stopUpdateAct_->setIcon(QIcon(":/images/close"));
952   this->addAction(stopUpdateAct_);
953   connect(stopUpdateAct_, SIGNAL(triggered()), this, SLOT(slotStopUpdate()));
954 
955   markAllFeedsRead_ = new QAction(this);
956   markAllFeedsRead_->setObjectName("markAllFeedRead");
957   markAllFeedsRead_->setIcon(QIcon(":/images/markReadAll"));
958   this->addAction(markAllFeedsRead_);
959   connect(markAllFeedsRead_, SIGNAL(triggered()), this, SIGNAL(signalMarkAllFeedsRead()));
960 
961   indentationFeedsTreeAct_ = new QAction(this);
962   indentationFeedsTreeAct_->setCheckable(true);
963   connect(indentationFeedsTreeAct_, SIGNAL(triggered()),
964           this, SLOT(slotIndentationFeedsTree()));
965 
966   sortedByTitleFeedsTreeAct_ = new QAction(this);
967   connect(sortedByTitleFeedsTreeAct_, SIGNAL(triggered()),
968           this, SLOT(sortedByTitleFeedsTree()));
969 
970   collapseAllFoldersAct_ = new QAction(this);
971   collapseAllFoldersAct_->setObjectName("collapseAllFolderAct");
972   collapseAllFoldersAct_->setIcon(QIcon(":/images/bulletMinus"));
973   this->addAction(collapseAllFoldersAct_);
974   connect(collapseAllFoldersAct_, SIGNAL(triggered()),
975           feedsView_, SLOT(collapseAll()));
976 
977   expandAllFoldersAct_ = new QAction(this);
978   expandAllFoldersAct_->setObjectName("expandAllFolderAct");
979   expandAllFoldersAct_->setIcon(QIcon(":/images/bulletPlus"));
980   this->addAction(expandAllFoldersAct_);
981   connect(expandAllFoldersAct_, SIGNAL(triggered()),
982           feedsView_, SLOT(expandAll()));
983 
984   markNewsRead_ = new QAction(this);
985   markNewsRead_->setObjectName("markNewsRead");
986   markNewsRead_->setIcon(QIcon(":/images/markRead"));
987   this->addAction(markNewsRead_);
988 
989   markAllNewsRead_ = new QAction(this);
990   markAllNewsRead_->setObjectName("markAllNewsRead");
991   markAllNewsRead_->setIcon(QIcon(":/images/markReadAll"));
992   this->addAction(markAllNewsRead_);
993 
994   showDownloadManagerAct_ = new QAction(this);
995   showDownloadManagerAct_->setObjectName("showDownloadManagerAct");
996   showDownloadManagerAct_->setIcon(QIcon(":/images/download"));
997   this->addAction(showDownloadManagerAct_);
998   connect(showDownloadManagerAct_, SIGNAL(triggered()), this, SLOT(showDownloadManager()));
999 
1000   showCleanUpWizardAct_ = new QAction(this);
1001   showCleanUpWizardAct_->setObjectName("showCleanUpWizardAct");
1002   showCleanUpWizardAct_->setIcon(QIcon(":/images/cleanup"));
1003   this->addAction(showCleanUpWizardAct_);
1004   connect(showCleanUpWizardAct_, SIGNAL(triggered()), this, SLOT(cleanUp()));
1005 
1006   setNewsFiltersAct_ = new QAction(this);
1007   setNewsFiltersAct_->setObjectName("setNewsFiltersAct");
1008   setNewsFiltersAct_->setIcon(QIcon(":/images/filterOff"));
1009   this->addAction(setNewsFiltersAct_);
1010   connect(setNewsFiltersAct_, SIGNAL(triggered()), this, SLOT(showNewsFiltersDlg()));
1011   setFilterNewsAct_ = new QAction(this);
1012   setFilterNewsAct_->setObjectName("setFilterNewsAct");
1013   setFilterNewsAct_->setIcon(QIcon(":/images/filterOff"));
1014   this->addAction(setFilterNewsAct_);
1015   connect(setFilterNewsAct_, SIGNAL(triggered()), this, SLOT(showFilterRulesDlg()));
1016 
1017   optionsAct_ = new QAction(this);
1018   optionsAct_->setObjectName("optionsAct");
1019   optionsAct_->setIcon(QIcon(":/images/options"));
1020   this->addAction(optionsAct_);
1021   connect(optionsAct_, SIGNAL(triggered()), this, SLOT(showOptionDlg()));
1022 
1023   feedsFilter_ = new QAction(this);
1024   feedsFilter_->setObjectName("feedsFilter");
1025   feedsFilter_->setIcon(QIcon(":/images/filterOff"));
1026   this->addAction(feedsFilter_);
1027   filterFeedsAll_ = new QAction(this);
1028   filterFeedsAll_->setObjectName("filterFeedsAll_");
1029   filterFeedsAll_->setCheckable(true);
1030   filterFeedsAll_->setChecked(true);
1031   filterFeedsNew_ = new QAction(this);
1032   filterFeedsNew_->setObjectName("filterFeedsNew_");
1033   filterFeedsNew_->setCheckable(true);
1034   filterFeedsUnread_ = new QAction(this);
1035   filterFeedsUnread_->setObjectName("filterFeedsUnread_");
1036   filterFeedsUnread_->setCheckable(true);
1037   filterFeedsStarred_ = new QAction(this);
1038   filterFeedsStarred_->setObjectName("filterFeedsStarred_");
1039   filterFeedsStarred_->setCheckable(true);
1040   filterFeedsError_ = new QAction(this);
1041   filterFeedsError_->setObjectName("filterFeedsError_");
1042   filterFeedsError_->setCheckable(true);
1043 
1044   newsFilter_ = new QAction(this);
1045   newsFilter_->setObjectName("newsFilter");
1046   newsFilter_->setIcon(QIcon(":/images/filterOff"));
1047   this->addAction(newsFilter_);
1048   filterNewsAll_ = new QAction(this);
1049   filterNewsAll_->setObjectName("filterNewsAll_");
1050   filterNewsAll_->setCheckable(true);
1051   filterNewsAll_->setChecked(true);
1052   filterNewsNew_ = new QAction(this);
1053   filterNewsNew_->setObjectName("filterNewsNew_");
1054   filterNewsNew_->setCheckable(true);
1055   filterNewsUnread_ = new QAction(this);
1056   filterNewsUnread_->setObjectName("filterNewsUnread_");
1057   filterNewsUnread_->setCheckable(true);
1058   filterNewsStar_ = new QAction(this);
1059   filterNewsStar_->setObjectName("filterNewsStar_");
1060   filterNewsStar_->setCheckable(true);
1061   filterNewsNotStarred_ = new QAction(this);
1062   filterNewsNotStarred_->setObjectName("filterNewsNotStarred_");
1063   filterNewsNotStarred_->setCheckable(true);
1064   filterNewsUnreadStar_ = new QAction(this);
1065   filterNewsUnreadStar_->setObjectName("filterNewsUnreadStar_");
1066   filterNewsUnreadStar_->setCheckable(true);
1067   filterNewsLastDay_ = new QAction(this);
1068   filterNewsLastDay_->setObjectName("filterNewsLastDay_");
1069   filterNewsLastDay_->setCheckable(true);
1070   filterNewsLastWeek_ = new QAction(this);
1071   filterNewsLastWeek_->setObjectName("filterNewsLastWeek_");
1072   filterNewsLastWeek_->setCheckable(true);
1073 
1074   newsSortByColumnGroup_ = new QActionGroup(this);
1075   newsSortByColumnGroup_->setExclusive(true);
1076   connect(newsSortByColumnGroup_, SIGNAL(triggered(QAction*)),
1077           this, SLOT(setNewsSortByColumn()));
1078 
1079   newsSortOrderGroup_ = new QActionGroup(this);
1080   newsSortOrderGroup_->setExclusive(true);
1081   QStringList listAct;
1082   listAct << "sortOrderAsc" << "sortOrderDesc";
1083   foreach (QString actionStr, listAct) {
1084     QAction *newsSortOrderAct = new QAction(this);
1085     newsSortOrderAct->setObjectName(actionStr);
1086     newsSortOrderAct->setCheckable(true);
1087     newsSortOrderGroup_->addAction(newsSortOrderAct);
1088   }
1089   connect(newsSortOrderGroup_, SIGNAL(triggered(QAction*)),
1090           this, SLOT(setNewsSortByColumn()));
1091 
1092   aboutAct_ = new QAction(this);
1093   aboutAct_->setObjectName("AboutAct_");
1094   connect(aboutAct_, SIGNAL(triggered()), this, SLOT(slotShowAboutDlg()));
1095 
1096   updateAppAct_ = new QAction(this);
1097   updateAppAct_->setObjectName("UpdateApp_");
1098   connect(updateAppAct_, SIGNAL(triggered()), this, SLOT(slotShowUpdateAppDlg()));
1099 
1100   reportProblemAct_ = new QAction(this);
1101   reportProblemAct_->setObjectName("reportProblemAct_");
1102   connect(reportProblemAct_, SIGNAL(triggered()), this, SLOT(slotReportProblem()));
1103 
1104   openInBrowserAct_ = new QAction(this);
1105   openInBrowserAct_->setObjectName("openInBrowserAct");
1106   this->addAction(openInBrowserAct_);
1107 
1108   openInExternalBrowserAct_ = new QAction(this);
1109   openInExternalBrowserAct_->setObjectName("openInExternalBrowserAct");
1110   openInExternalBrowserAct_->setIcon(QIcon(":/images/openBrowser"));
1111   this->addAction(openInExternalBrowserAct_);
1112 
1113   openNewsNewTabAct_ = new QAction(this);
1114   openNewsNewTabAct_->setObjectName("openInNewTabAct");
1115   openNewsNewTabAct_->setIcon(QIcon(":/images/images/tab_go.png"));
1116   this->addAction(openNewsNewTabAct_);
1117   openNewsBackgroundTabAct_ = new QAction(this);
1118   openNewsBackgroundTabAct_->setObjectName("openInBackgroundTabAct");
1119   this->addAction(openNewsBackgroundTabAct_);
1120 
1121   markStarAct_ = new QAction(this);
1122   markStarAct_->setObjectName("markStarAct");
1123   markStarAct_->setIcon(QIcon(":/images/starOn"));
1124   this->addAction(markStarAct_);
1125 
1126   deleteNewsAct_ = new QAction(this);
1127   deleteNewsAct_->setObjectName("deleteNewsAct");
1128   deleteNewsAct_->setIcon(QIcon(":/images/delete"));
1129   this->addAction(deleteNewsAct_);
1130   deleteAllNewsAct_ = new QAction(this);
1131   deleteAllNewsAct_->setObjectName("deleteAllNewsAct");
1132   this->addAction(deleteAllNewsAct_);
1133 
1134   restoreNewsAct_ = new QAction(this);
1135   restoreNewsAct_->setObjectName("restoreNewsAct");
1136   restoreNewsAct_->setIcon(QIcon(":/images/images/arrow_turn_left.png"));
1137 
1138   restoreLastNewsAct_ = new QAction(this);
1139   restoreLastNewsAct_->setObjectName("restoreLastNewsAct");
1140   restoreLastNewsAct_->setIcon(QIcon(":/images/images/arrow_turn_left.png"));
1141   this->addAction(restoreLastNewsAct_);
1142   connect(restoreLastNewsAct_, SIGNAL(triggered()), this, SLOT(restoreLastNews()));
1143 
1144   markFeedRead_ = new QAction(this);
1145   markFeedRead_->setObjectName("markFeedRead");
1146   markFeedRead_->setIcon(QIcon(":/images/markRead"));
1147   this->addAction(markFeedRead_);
1148   connect(markFeedRead_, SIGNAL(triggered()), this, SLOT(markFeedRead()));
1149 
1150   feedProperties_ = new QAction(this);
1151   feedProperties_->setObjectName("feedProperties");
1152   feedProperties_->setIcon(QIcon(":/images/preferencesFeed"));
1153   this->addAction(feedProperties_);
1154   connect(feedProperties_, SIGNAL(triggered()), this, SLOT(showFeedPropertiesDlg()));
1155 
1156   feedKeyUpAct_ = new QAction(this);
1157   feedKeyUpAct_->setObjectName("feedKeyUp");
1158   connect(feedKeyUpAct_, SIGNAL(triggered()), this, SLOT(slotFeedPrevious()));
1159   this->addAction(feedKeyUpAct_);
1160 
1161   feedKeyDownAct_ = new QAction(this);
1162   feedKeyDownAct_->setObjectName("feedKeyDownAct");
1163   connect(feedKeyDownAct_, SIGNAL(triggered()), this, SLOT(slotFeedNext()));
1164   this->addAction(feedKeyDownAct_);
1165 
1166   newsKeyUpAct_ = new QAction(this);
1167   newsKeyUpAct_->setObjectName("newsKeyUpAct");
1168   this->addAction(newsKeyUpAct_);
1169   newsKeyDownAct_ = new QAction(this);
1170   newsKeyDownAct_->setObjectName("newsKeyDownAct");
1171   this->addAction(newsKeyDownAct_);
1172   newsKeyPageUpAct_ = new QAction(this);
1173   newsKeyPageUpAct_->setObjectName("newsKeyPageUpAct");
1174   this->addAction(newsKeyPageUpAct_);
1175   newsKeyPageDownAct_ = new QAction(this);
1176   newsKeyPageDownAct_->setObjectName("newsKeyPageDownAct");
1177   this->addAction(newsKeyPageDownAct_);
1178 
1179   switchFocusAct_ = new QAction(this);
1180   switchFocusAct_->setObjectName("switchFocusAct");
1181   connect(switchFocusAct_, SIGNAL(triggered()), this, SLOT(slotSwitchFocus()));
1182   this->addAction(switchFocusAct_);
1183   switchFocusPrevAct_ = new QAction(this);
1184   switchFocusPrevAct_->setObjectName("switchFocusPrevAct");
1185   connect(switchFocusPrevAct_, SIGNAL(triggered()), this, SLOT(slotSwitchPrevFocus()));
1186   this->addAction(switchFocusPrevAct_);
1187 
1188   feedsWidgetVisibleAct_ = new QAction(this);
1189   feedsWidgetVisibleAct_->setObjectName("visibleFeedsWidgetAct");
1190   feedsWidgetVisibleAct_->setCheckable(true);
1191   connect(feedsWidgetVisibleAct_, SIGNAL(triggered()), this, SLOT(slotVisibledFeedsWidget()));
1192   connect(pushButtonNull_, SIGNAL(clicked()), feedsWidgetVisibleAct_, SLOT(trigger()));
1193   this->addAction(feedsWidgetVisibleAct_);
1194 
1195   showUnreadCount_ = new QAction(this);
1196   showUnreadCount_->setData(feedsView_->columnIndex("unread"));
1197   showUnreadCount_->setCheckable(true);
1198   showUndeleteCount_ = new QAction(this);
1199   showUndeleteCount_->setData(feedsView_->columnIndex("undeleteCount"));
1200   showUndeleteCount_->setCheckable(true);
1201   showLastUpdated_ = new QAction(this);
1202   showLastUpdated_->setData(feedsView_->columnIndex("updated"));
1203   showLastUpdated_->setCheckable(true);
1204 
1205   openDescriptionNewsAct_ = new QAction(this);
1206   openDescriptionNewsAct_->setObjectName("openDescriptionNewsAct");
1207   connect(openDescriptionNewsAct_, SIGNAL(triggered()),
1208           this, SLOT(slotOpenNewsWebView()));
1209   this->addAction(openDescriptionNewsAct_);
1210 
1211   findTextAct_ = new QAction(this);
1212   findTextAct_->setObjectName("findTextAct");
1213   connect(findTextAct_, SIGNAL(triggered()),
1214           this, SLOT(findText()));
1215   this->addAction(findTextAct_);
1216 
1217   placeToTrayAct_ = new QAction(this);
1218   placeToTrayAct_->setObjectName("placeToTrayAct");
1219   connect(placeToTrayAct_, SIGNAL(triggered()), this, SLOT(slotPlaceToTray()));
1220   this->addAction(placeToTrayAct_);
1221 
1222   findFeedAct_ = new QAction(this);
1223   findFeedAct_->setObjectName("findFeedAct");
1224   findFeedAct_->setCheckable(true);
1225   findFeedAct_->setChecked(false);
1226   findFeedAct_->setIcon(QIcon(":/images/images/findFeed.png"));
1227   this->addAction(findFeedAct_);
1228   connect(findFeedAct_, SIGNAL(triggered(bool)),
1229           this, SLOT(findFeedVisible(bool)));
1230 
1231   fullScreenAct_ = new QAction(this);
1232   fullScreenAct_->setObjectName("fullScreenAct");
1233   fullScreenAct_->setIcon(QIcon(":/images/images/fullScreen.png"));
1234   this->addAction(fullScreenAct_);
1235   connect(fullScreenAct_, SIGNAL(triggered()),
1236           this, SLOT(setFullScreen()));
1237 
1238   stayOnTopAct_ = new QAction(this);
1239   stayOnTopAct_->setObjectName("stayOnTopAct");
1240   stayOnTopAct_->setCheckable(true);
1241   this->addAction(stayOnTopAct_);
1242   connect(stayOnTopAct_, SIGNAL(triggered()),
1243           this, SLOT(setStayOnTop()));
1244 
1245   newsLabelGroup_ = new QActionGroup(this);
1246   newsLabelGroup_->setExclusive(false);
1247   QSqlQuery q;
1248   q.exec("SELECT id, name, image FROM labels ORDER BY num");
1249   while (q.next()) {
1250     int idLabel = q.value(0).toInt();
1251     QString nameLabel = q.value(1).toString();
1252     QByteArray byteArray = q.value(2).toByteArray();
1253     QPixmap imageLabel;
1254     if (!byteArray.isNull())
1255       imageLabel.loadFromData(byteArray);
1256     QAction *action = new QAction(QIcon(imageLabel), nameLabel, this);
1257     action->setObjectName(QString("labelAction_%1").arg(idLabel));
1258     action->setCheckable(true);
1259     action->setData(idLabel);
1260     newsLabelGroup_->addAction(action);
1261   }
1262   this->addActions(newsLabelGroup_->actions());
1263 
1264   newsLabelAction_ = new QAction(this);
1265   newsLabelAction_->setObjectName("newsLabelAction");
1266   this->addAction(newsLabelAction_);
1267   if (newsLabelGroup_->actions().count()) {
1268     newsLabelAction_->setIcon(newsLabelGroup_->actions().at(0)->icon());
1269     newsLabelAction_->setToolTip(newsLabelGroup_->actions().at(0)->text());
1270     newsLabelAction_->setData(newsLabelGroup_->actions().at(0)->data());
1271   }
1272   connect(newsLabelAction_, SIGNAL(triggered()),
1273           this, SLOT(setDefaultLabelNews()));
1274   connect(newsLabelGroup_, SIGNAL(triggered(QAction*)),
1275           this, SLOT(setLabelNews(QAction*)));
1276 
1277   showLabelsMenuAct_ = new QAction(this);
1278   showLabelsMenuAct_->setObjectName("showLabelsMenuAct");
1279   this->addAction(showLabelsMenuAct_);
1280   connect(showLabelsMenuAct_, SIGNAL(triggered()),
1281           this, SLOT(slotShowLabelsMenu()));
1282 
1283   closeTabAct_ = new QAction(this);
1284   closeTabAct_->setObjectName("closeTabAct");
1285   this->addAction(closeTabAct_);
1286 
1287   closeOtherTabsAct_ = new QAction(this);
1288   closeOtherTabsAct_->setObjectName("closeOtherTabsAct");
1289   this->addAction(closeOtherTabsAct_);
1290 
1291   closeAllTabsAct_ = new QAction(this);
1292   closeAllTabsAct_->setObjectName("closeAllTabsAct");
1293   this->addAction(closeAllTabsAct_);
1294 
1295   nextTabAct_ = new QAction(this);
1296   nextTabAct_->setObjectName("nextTabAct");
1297   this->addAction(nextTabAct_);
1298 
1299   prevTabAct_ = new QAction(this);
1300   prevTabAct_->setObjectName("prevTabAct");
1301   this->addAction(prevTabAct_);
1302 
1303   reduceNewsListAct_ = new QAction(this);
1304   reduceNewsListAct_->setObjectName("reduceNewsListAct");
1305   this->addAction(reduceNewsListAct_);
1306   connect(reduceNewsListAct_, SIGNAL(triggered()),
1307           this, SLOT(reduceNewsList()));
1308   increaseNewsListAct_ = new QAction(this);
1309   increaseNewsListAct_->setObjectName("increaseNewsListAct");
1310   this->addAction(increaseNewsListAct_);
1311   connect(increaseNewsListAct_, SIGNAL(triggered()),
1312           this, SLOT(increaseNewsList()));
1313 
1314   nextUnreadNewsAct_ = new QAction(this);
1315   nextUnreadNewsAct_->setObjectName("nextUnreadNewsAct");
1316   nextUnreadNewsAct_->setIcon(QIcon(":/images/moveDown"));
1317   this->addAction(nextUnreadNewsAct_);
1318   connect(nextUnreadNewsAct_, SIGNAL(triggered()), this, SLOT(nextUnreadNews()));
1319   prevUnreadNewsAct_ = new QAction(this);
1320   prevUnreadNewsAct_->setObjectName("prevUnreadNewsAct");
1321   prevUnreadNewsAct_->setIcon(QIcon(":/images/moveUp"));
1322   this->addAction(prevUnreadNewsAct_);
1323   connect(prevUnreadNewsAct_, SIGNAL(triggered()), this, SLOT(prevUnreadNews()));
1324 
1325   openHomeFeedAct_ = new QAction(this);
1326   openHomeFeedAct_->setObjectName("openHomeFeedsAct");
1327   openHomeFeedAct_->setIcon(QIcon(":/images/homePage"));
1328   this->addAction(openHomeFeedAct_);
1329   connect(openHomeFeedAct_, SIGNAL(triggered()), this, SLOT(slotOpenHomeFeed()));
1330 
1331   copyLinkAct_ = new QAction(this);
1332   copyLinkAct_->setObjectName("copyLinkAct");
1333   copyLinkAct_->setIcon(QIcon(":/images/copy"));
1334   this->addAction(copyLinkAct_);
1335   connect(copyLinkAct_, SIGNAL(triggered()), this, SLOT(slotCopyLinkNews()));
1336 
1337   pageUpWebViewAct_ = new QAction(this);
1338   pageUpWebViewAct_->setObjectName("pageUpWebViewAct");
1339   this->addAction(pageUpWebViewAct_);
1340   connect(pageUpWebViewAct_, SIGNAL(triggered()),
1341           this, SLOT(slotPageUpWebView()));
1342   pageDownWebViewAct_ = new QAction(this);
1343   pageDownWebViewAct_->setObjectName("pageDownWebViewAct");
1344   this->addAction(pageDownWebViewAct_);
1345   connect(pageDownWebViewAct_, SIGNAL(triggered()),
1346           this, SLOT(slotPageDownWebView()));
1347 
1348   nextFolderAct_ = new QAction(this);
1349   nextFolderAct_->setObjectName("nextFolderAct");
1350   this->addAction(nextFolderAct_);
1351   connect(nextFolderAct_, SIGNAL(triggered()), this, SLOT(slotNextFolder()));
1352   prevFolderAct_ = new QAction(this);
1353   prevFolderAct_->setObjectName("prevFolderAct");
1354   this->addAction(prevFolderAct_);
1355   connect(prevFolderAct_, SIGNAL(triggered()), this, SLOT(slotPrevFolder()));
1356   expandFolderAct_ = new QAction(this);
1357   expandFolderAct_->setObjectName("expandFolderAct");
1358   this->addAction(expandFolderAct_);
1359   connect(expandFolderAct_, SIGNAL(triggered()), this, SLOT(slotExpandFolder()));
1360 
1361   settingPageLabelsAct_ = new QAction(this);
1362   settingPageLabelsAct_->setObjectName("settingPageLabelsAct");
1363   this->addAction(settingPageLabelsAct_);
1364   connect(settingPageLabelsAct_, SIGNAL(triggered()), this, SLOT(showSettingPageLabels()));
1365 
1366   backWebPageAct_ = new QAction(this);
1367   backWebPageAct_->setObjectName("backWebPageAct");
1368   forwardWebPageAct_ = new QAction(this);
1369   forwardWebPageAct_->setObjectName("forwardWebPageAct");
1370   reloadWebPageAct_ = new QAction(this);
1371   reloadWebPageAct_->setObjectName("reloadWebPageAct");
1372 
1373   shareGroup_ = new QActionGroup(this);
1374   shareGroup_->setExclusive(false);
1375 
1376   emailShareAct_ = new QAction(this);
1377   emailShareAct_->setObjectName("emailShareAct");
1378   emailShareAct_->setText("Email");
1379   emailShareAct_->setIcon(QIcon(":/images/images/email.png"));
1380   shareGroup_->addAction(emailShareAct_);
1381 
1382   evernoteShareAct_ = new QAction(this);
1383   evernoteShareAct_->setObjectName("evernoteShareAct");
1384   evernoteShareAct_->setText("Evernote");
1385   evernoteShareAct_->setIcon(QIcon(":/share/images/share/evernote.png"));
1386   shareGroup_->addAction(evernoteShareAct_);
1387 
1388   facebookShareAct_ = new QAction(this);
1389   facebookShareAct_->setObjectName("facebookShareAct");
1390   facebookShareAct_->setText("Facebook");
1391   facebookShareAct_->setIcon(QIcon(":/share/images/share/facebook.png"));
1392   shareGroup_->addAction(facebookShareAct_);
1393 
1394   livejournalShareAct_ = new QAction(this);
1395   livejournalShareAct_->setObjectName("livejournalShareAct");
1396   livejournalShareAct_->setText("LiveJournal");
1397   livejournalShareAct_->setIcon(QIcon(":/share/images/share/livejournal.png"));
1398   shareGroup_->addAction(livejournalShareAct_);
1399 
1400   pocketShareAct_ = new QAction(this);
1401   pocketShareAct_->setObjectName("pocketShareAct");
1402   pocketShareAct_->setText("Pocket");
1403   pocketShareAct_->setIcon(QIcon(":/share/images/share/pocket.png"));
1404   shareGroup_->addAction(pocketShareAct_);
1405 
1406   twitterShareAct_ = new QAction(this);
1407   twitterShareAct_->setObjectName("twitterShareAct");
1408   twitterShareAct_->setText("Twitter");
1409   twitterShareAct_->setIcon(QIcon(":/share/images/share/twitter.png"));
1410   shareGroup_->addAction(twitterShareAct_);
1411 
1412   vkShareAct_ = new QAction(this);
1413   vkShareAct_->setObjectName("vkShareAct");
1414   vkShareAct_->setText("VK");
1415   vkShareAct_->setIcon(QIcon(":/share/images/share/vk.png"));
1416   shareGroup_->addAction(vkShareAct_);
1417 
1418   linkedinShareAct_ = new QAction(this);
1419   linkedinShareAct_->setObjectName("linkedinShareAct");
1420   linkedinShareAct_->setText("LinkedIn");
1421   linkedinShareAct_->setIcon(QIcon(":/share/images/share/linkedin.png"));
1422   shareGroup_->addAction(linkedinShareAct_);
1423 
1424   bloggerShareAct_ = new QAction(this);
1425   bloggerShareAct_->setObjectName("bloggerShareAct");
1426   bloggerShareAct_->setText("Blogger");
1427   bloggerShareAct_->setIcon(QIcon(":/share/images/share/blogger.png"));
1428   shareGroup_->addAction(bloggerShareAct_);
1429 
1430   printfriendlyShareAct_ = new QAction(this);
1431   printfriendlyShareAct_->setObjectName("printfriendlyShareAct");
1432   printfriendlyShareAct_->setText("PrintFriendly");
1433   printfriendlyShareAct_->setIcon(QIcon(":/share/images/share/printfriendly.png"));
1434   shareGroup_->addAction(printfriendlyShareAct_);
1435 
1436   instapaperShareAct_ = new QAction(this);
1437   instapaperShareAct_->setObjectName("instapaperShareAct");
1438   instapaperShareAct_->setText("Instapaper");
1439   instapaperShareAct_->setIcon(QIcon(":/share/images/share/instapaper.png"));
1440   shareGroup_->addAction(instapaperShareAct_);
1441 
1442   redditShareAct_ = new QAction(this);
1443   redditShareAct_->setObjectName("redditShareAct");
1444   redditShareAct_->setText("Reddit");
1445   redditShareAct_->setIcon(QIcon(":/share/images/share/reddit.ico"));
1446   shareGroup_->addAction(redditShareAct_);
1447 
1448   hackerNewsShareAct_ = new QAction(this);
1449   hackerNewsShareAct_->setObjectName("hackerNewsShareAct");
1450   hackerNewsShareAct_->setText("HackerNews");
1451   hackerNewsShareAct_->setIcon(QIcon(":/share/images/share/hackernews.png"));
1452   shareGroup_->addAction(hackerNewsShareAct_);
1453 
1454   telegramShareAct_ = new QAction(this);
1455   telegramShareAct_->setObjectName("telegramShareAct");
1456   telegramShareAct_->setText("Telegram");
1457   telegramShareAct_->setIcon(QIcon(":/share/images/share/telegram.png"));
1458   shareGroup_->addAction(telegramShareAct_);
1459 
1460   viberShareAct_ = new QAction(this);
1461   viberShareAct_->setObjectName("viberShareAct");
1462   viberShareAct_->setText("Vider");
1463   viberShareAct_->setIcon(QIcon(":/share/images/share/viber.png"));
1464   shareGroup_->addAction(viberShareAct_);
1465 
1466   this->addActions(shareGroup_->actions());
1467   connect(shareGroup_, SIGNAL(triggered(QAction*)),
1468           this, SLOT(slotShareNews(QAction*)));
1469 
1470 
1471   connect(markNewsRead_, SIGNAL(triggered()),
1472           this, SLOT(markNewsRead()));
1473   connect(markAllNewsRead_, SIGNAL(triggered()),
1474           this, SLOT(markAllNewsRead()));
1475   connect(markStarAct_, SIGNAL(triggered()),
1476           this, SLOT(markNewsStar()));
1477   connect(deleteNewsAct_, SIGNAL(triggered()),
1478           this, SLOT(deleteNews()));
1479   connect(deleteAllNewsAct_, SIGNAL(triggered()),
1480           this, SLOT(deleteAllNewsList()));
1481   connect(restoreNewsAct_, SIGNAL(triggered()),
1482           this, SLOT(restoreNews()));
1483 
1484   connect(newsKeyUpAct_, SIGNAL(triggered()),
1485           this, SLOT(slotNewsUpPressed()));
1486   connect(newsKeyDownAct_, SIGNAL(triggered()),
1487           this, SLOT(slotNewsDownPressed()));
1488   connect(newsKeyPageUpAct_, SIGNAL(triggered()),
1489           this, SLOT(slotNewsPageUpPressed()));
1490   connect(newsKeyPageDownAct_, SIGNAL(triggered()),
1491           this, SLOT(slotNewsPageDownPressed()));
1492 
1493   connect(openInBrowserAct_, SIGNAL(triggered()),
1494           this, SLOT(openInBrowserNews()));
1495   connect(openInExternalBrowserAct_, SIGNAL(triggered()),
1496           this, SLOT(openInExternalBrowserNews()));
1497   connect(openNewsNewTabAct_, SIGNAL(triggered()),
1498           this, SLOT(slotOpenNewsNewTab()));
1499   connect(openNewsBackgroundTabAct_, SIGNAL(triggered()),
1500           this, SLOT(slotOpenNewsBackgroundTab()));
1501 }
1502 // ---------------------------------------------------------------------------
createShortcut()1503 void MainWindow::createShortcut()
1504 {
1505   addFeedAct_->setShortcut(QKeySequence(QKeySequence::New));
1506   listActions_.append(addFeedAct_);
1507   addFolderAct_->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_N));
1508   listActions_.append(addFolderAct_);
1509   listActions_.append(deleteFeedAct_);
1510   listActions_.append(createBackupAct_);
1511   exitAct_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));  // standart on other OS
1512   listActions_.append(exitAct_);
1513   updateFeedAct_->setShortcut(QKeySequence(Qt::Key_F5));
1514   listActions_.append(updateFeedAct_);
1515   updateAllFeedsAct_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_F5));
1516   listActions_.append(updateAllFeedsAct_);
1517   listActions_.append(stopUpdateAct_);
1518   listActions_.append(openHomeFeedAct_);
1519   listActions_.append(showDownloadManagerAct_);
1520   listActions_.append(showCleanUpWizardAct_);
1521   listActions_.append(setNewsFiltersAct_);
1522   listActions_.append(setFilterNewsAct_);
1523   optionsAct_->setShortcut(QKeySequence(Qt::Key_F8));
1524   listActions_.append(optionsAct_);
1525   deleteNewsAct_->setShortcut(QKeySequence(Qt::Key_Delete));
1526   listActions_.append(deleteNewsAct_);
1527   deleteAllNewsAct_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Delete));
1528   listActions_.append(deleteAllNewsAct_);
1529   feedProperties_->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_E));
1530   listActions_.append(feedProperties_);
1531   feedKeyUpAct_->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_Up));
1532   listActions_.append(feedKeyUpAct_);
1533   feedKeyDownAct_->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_Down));
1534   listActions_.append(feedKeyDownAct_);
1535   newsKeyUpAct_->setShortcut(QKeySequence(Qt::Key_Left));
1536   listActions_.append(newsKeyUpAct_);
1537   newsKeyDownAct_->setShortcut(QKeySequence(Qt::Key_Right));
1538   listActions_.append(newsKeyDownAct_);
1539   listActions_.append(newsKeyPageUpAct_);
1540   listActions_.append(newsKeyPageDownAct_);
1541 
1542   listActions_.append(nextUnreadNewsAct_);
1543   listActions_.append(prevUnreadNewsAct_);
1544 
1545   listActions_.append(nextFolderAct_);
1546   listActions_.append(prevFolderAct_);
1547 
1548   listActions_.append(importFeedsAct_);
1549   listActions_.append(exportFeedsAct_);
1550   listActions_.append(createBackupAct_);
1551   listActions_.append(autoLoadImagesToggle_);
1552   listActions_.append(markAllFeedsRead_);
1553   listActions_.append(markFeedRead_);
1554   listActions_.append(markNewsRead_);
1555   listActions_.append(markAllNewsRead_);
1556   listActions_.append(markStarAct_);
1557   listActions_.append(collapseAllFoldersAct_);
1558   listActions_.append(expandAllFoldersAct_);
1559   listActions_.append(expandFolderAct_);
1560 
1561   listActions_.append(openDescriptionNewsAct_);
1562   openDescriptionNewsAct_->setShortcut(QKeySequence(Qt::Key_Return));
1563   listActions_.append(openInBrowserAct_);
1564   openInBrowserAct_->setShortcut(QKeySequence(Qt::Key_Space));
1565   listActions_.append(openInExternalBrowserAct_);
1566   openInExternalBrowserAct_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_O));
1567   openNewsNewTabAct_->setShortcut(QKeySequence(Qt::Key_T));
1568   listActions_.append(openNewsNewTabAct_);
1569   openNewsBackgroundTabAct_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_T));
1570   listActions_.append(openNewsBackgroundTabAct_);
1571 
1572   switchFocusAct_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Tab));
1573   listActions_.append(switchFocusAct_);
1574   switchFocusPrevAct_->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Tab));
1575   listActions_.append(switchFocusPrevAct_);
1576 
1577   feedsWidgetVisibleAct_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_D));
1578   listActions_.append(feedsWidgetVisibleAct_);
1579 
1580   listActions_.append(placeToTrayAct_);
1581 
1582   zoomInAct_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Plus));
1583   listActions_.append(zoomInAct_);
1584   zoomOutAct_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Minus));
1585   listActions_.append(zoomOutAct_);
1586   zoomTo100Act_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_0));
1587   listActions_.append(zoomTo100Act_);
1588 
1589   printAct_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_P));
1590   listActions_.append(printAct_);
1591   printPreviewAct_->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_P));
1592   listActions_.append(printPreviewAct_);
1593 
1594   savePageAsAct_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_S));
1595   listActions_.append(savePageAsAct_);
1596   listActions_.append(savePageAsDescriptAct_);
1597 
1598   fullScreenAct_->setShortcut(QKeySequence(Qt::Key_F11));
1599   listActions_.append(fullScreenAct_);
1600 
1601   stayOnTopAct_->setShortcut(QKeySequence(Qt::Key_F10));
1602   listActions_.append(stayOnTopAct_);
1603 
1604   listActions_.append(layoutToggle_);
1605 
1606   closeTabAct_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_W));
1607   listActions_.append(closeTabAct_);
1608   listActions_.append(closeOtherTabsAct_);
1609   listActions_.append(closeAllTabsAct_);
1610   listActions_.append(nextTabAct_);
1611   listActions_.append(prevTabAct_);
1612 
1613   reduceNewsListAct_->setShortcut(QKeySequence(Qt::ALT+ Qt::Key_Up));
1614   listActions_.append(reduceNewsListAct_);
1615   increaseNewsListAct_->setShortcut(QKeySequence(Qt::ALT + Qt::Key_Down));
1616   listActions_.append(increaseNewsListAct_);
1617 
1618   restoreLastNewsAct_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Z));
1619   listActions_.append(restoreLastNewsAct_);
1620 
1621   findTextAct_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_F));
1622   listActions_.append(findTextAct_);
1623 
1624   listActions_.append(findFeedAct_);
1625 
1626   listActions_.append(copyLinkAct_);
1627 
1628   listActions_.append(backWebPageAct_);
1629   listActions_.append(forwardWebPageAct_);
1630   listActions_.append(reloadWebPageAct_);
1631   listActions_.append(pageUpWebViewAct_);
1632   listActions_.append(pageDownWebViewAct_);
1633 
1634   listActions_.append(shareGroup_->actions());
1635 
1636   // Actions for labels do add at the end
1637   listActions_.append(settingPageLabelsAct_);
1638   listActions_.append(showLabelsMenuAct_);
1639   listActions_.append(newsLabelGroup_->actions());
1640 
1641   loadActionShortcuts();
1642 }
1643 // ---------------------------------------------------------------------------
loadActionShortcuts()1644 void MainWindow::loadActionShortcuts()
1645 {
1646   Settings settings;
1647   settings.beginGroup("/Shortcuts");
1648 
1649   QListIterator<QAction *> iter(listActions_);
1650   while (iter.hasNext()) {
1651     QAction *pAction = iter.next();
1652     if (pAction->objectName().isEmpty())
1653       continue;
1654 
1655     listDefaultShortcut_.append(pAction->shortcut().toString());
1656 
1657     const QString& sKey = '/' + pAction->objectName();
1658     const QString& sValue = settings.value('/' + sKey, pAction->shortcut().toString()).toString();
1659     pAction->setShortcut(QKeySequence(sValue));
1660   }
1661 
1662   settings.endGroup();
1663 }
1664 // ---------------------------------------------------------------------------
saveActionShortcuts()1665 void MainWindow::saveActionShortcuts()
1666 {
1667   Settings settings;
1668   settings.beginGroup("/Shortcuts/");
1669 
1670   QListIterator<QAction *> iter(listActions_);
1671   while (iter.hasNext()) {
1672     QAction *pAction = iter.next();
1673     if (pAction->objectName().isEmpty())
1674       continue;
1675 
1676     const QString& sKey = '/' + pAction->objectName();
1677     const QString& sValue = QString(pAction->shortcut().toString());
1678     settings.setValue(sKey, sValue);
1679   }
1680 
1681   settings.endGroup();
1682 }
1683 // ---------------------------------------------------------------------------
createMenu()1684 void MainWindow::createMenu()
1685 {
1686   newMenu_ = new QMenu(this);
1687   newMenu_->addAction(addFeedAct_);
1688   newMenu_->addAction(addFolderAct_);
1689   addAct_->setMenu(newMenu_);
1690 
1691   fileMenu_ = new QMenu(this);
1692   fileMenu_->addAction(addAct_);
1693   fileMenu_->addSeparator();
1694   fileMenu_->addAction(importFeedsAct_);
1695   fileMenu_->addAction(exportFeedsAct_);
1696   fileMenu_->addSeparator();
1697   fileMenu_->addAction(createBackupAct_);
1698   fileMenu_->addSeparator();
1699 #ifndef Q_OS_MAC
1700   fileMenu_->addAction(showMenuBarAct_);
1701   fileMenu_->addSeparator();
1702 #endif
1703   fileMenu_->addAction(exitAct_);
1704 
1705   toolbarsMenu_ = new QMenu(this);
1706   toolbarsMenu_->addAction(mainToolbarToggle_);
1707   toolbarsMenu_->addAction(feedsToolbarToggle_);
1708   toolbarsMenu_->addAction(newsToolbarToggle_);
1709   toolbarsMenu_->addAction(browserToolbarToggle_);
1710   toolbarsMenu_->addAction(categoriesPanelToggle_);
1711   toolbarsMenu_->addAction(statusBarToggle_);
1712 
1713   customizeToolbarGroup_ = new QActionGroup(this);
1714   customizeToolbarGroup_->addAction(customizeMainToolbarAct_);
1715   customizeToolbarGroup_->addAction(customizeFeedsToolbarAct_);
1716   customizeToolbarGroup_->addAction(customizeNewsToolbarAct_);
1717   customizeToolbarMenu_ = new QMenu(this);
1718   customizeToolbarMenu_->addActions(customizeToolbarGroup_->actions());
1719 
1720   layoutGroup_ = new QActionGroup(this);
1721   layoutGroup_->addAction(classicLayoutAct_);
1722   layoutGroup_->addAction(newspaperLayoutAct_);
1723   layoutMenu_ = new QMenu(this);
1724   layoutMenu_->addActions(layoutGroup_->actions());
1725   layoutToggle_->setMenu(layoutMenu_);
1726 
1727   styleGroup_ = new QActionGroup(this);
1728   styleGroup_->addAction(systemStyle_);
1729   styleGroup_->addAction(system2Style_);
1730   styleGroup_->addAction(darkStyle_);
1731   styleGroup_->addAction(greenStyle_);
1732   styleGroup_->addAction(orangeStyle_);
1733   styleGroup_->addAction(purpleStyle_);
1734   styleGroup_->addAction(pinkStyle_);
1735   styleGroup_->addAction(grayStyle_);
1736 
1737   styleMenu_ = new QMenu(this);
1738   styleMenu_->addActions(styleGroup_->actions());
1739 
1740   browserPositionGroup_ = new QActionGroup(this);
1741   browserPositionGroup_->addAction(topBrowserPositionAct_);
1742   browserPositionGroup_->addAction(bottomBrowserPositionAct_);
1743   browserPositionGroup_->addAction(rightBrowserPositionAct_);
1744   browserPositionGroup_->addAction(leftBrowserPositionAct_);
1745 
1746   browserPositionMenu_ = new QMenu(this);
1747   browserPositionMenu_->addActions(browserPositionGroup_->actions());
1748 
1749   viewMenu_  = new QMenu(this);
1750   viewMenu_->addMenu(toolbarsMenu_);
1751   viewMenu_->addMenu(customizeToolbarMenu_);
1752   viewMenu_->addSeparator();
1753   viewMenu_->addMenu(layoutMenu_);
1754   viewMenu_->addMenu(browserPositionMenu_);
1755   viewMenu_->addMenu(styleMenu_);
1756   viewMenu_->addSeparator();
1757   viewMenu_->addAction(stayOnTopAct_);
1758   viewMenu_->addAction(fullScreenAct_);
1759 
1760   feedsFilterGroup_ = new QActionGroup(this);
1761   feedsFilterGroup_->setExclusive(true);
1762   feedsFilterGroup_->addAction(filterFeedsAll_);
1763   feedsFilterGroup_->addAction(filterFeedsNew_);
1764   feedsFilterGroup_->addAction(filterFeedsUnread_);
1765   feedsFilterGroup_->addAction(filterFeedsStarred_);
1766   feedsFilterGroup_->addAction(filterFeedsError_);
1767 
1768   feedsFilterMenu_ = new QMenu(this);
1769   feedsFilterMenu_->addActions(feedsFilterGroup_->actions());
1770   feedsFilterMenu_->insertSeparator(filterFeedsNew_);
1771 
1772   feedsFilter_->setMenu(feedsFilterMenu_);
1773 
1774   feedsColumnsGroup_ = new QActionGroup(this);
1775   feedsColumnsGroup_->setExclusive(false);
1776   feedsColumnsGroup_->addAction(showUnreadCount_);
1777   feedsColumnsGroup_->addAction(showUndeleteCount_);
1778   feedsColumnsGroup_->addAction(showLastUpdated_);
1779 
1780   feedsColumnsMenu_ = new QMenu(this);
1781   feedsColumnsMenu_->addActions(feedsColumnsGroup_->actions());
1782 
1783   feedMenu_ = new QMenu(this);
1784   feedMenu_->addAction(updateFeedAct_);
1785   feedMenu_->addAction(updateAllFeedsAct_);
1786   feedMenu_->addSeparator();
1787   feedMenu_->addAction(markFeedRead_);
1788   feedMenu_->addAction(markAllFeedsRead_);
1789   feedMenu_->addSeparator();
1790   feedMenu_->addAction(feedsFilter_);
1791   feedMenu_->addMenu(feedsColumnsMenu_);
1792   feedMenu_->addAction(sortedByTitleFeedsTreeAct_);
1793   feedMenu_->addAction(indentationFeedsTreeAct_);
1794   feedMenu_->addSeparator();
1795   feedMenu_->addAction(deleteFeedAct_);
1796   feedMenu_->addSeparator();
1797   feedMenu_->addAction(feedProperties_);
1798   feedMenu_->addSeparator();
1799 
1800   newsLabelMenu_ = new QMenu(this);
1801   newsLabelMenu_->addActions(newsLabelGroup_->actions());
1802   newsLabelMenuAction_ = new QAction(this);
1803   newsLabelMenuAction_->setIcon(QIcon(":/images/label_3"));
1804   newsLabelAction_->setMenu(newsLabelMenu_);
1805   newsLabelMenuAction_->setMenu(newsLabelMenu_);
1806 
1807   shareMenu_ = new QMenu(this);
1808   shareMenu_->addActions(shareGroup_->actions());
1809   shareMenuAct_ = new QAction(this);
1810   shareMenuAct_->setObjectName("shareMenuAct");
1811   shareMenuAct_->setIcon(QIcon(":/images/images/share.png"));
1812   shareMenuAct_->setMenu(shareMenu_);
1813   this->addAction(shareMenuAct_);
1814 
1815   newsFilterGroup_ = new QActionGroup(this);
1816   newsFilterGroup_->setExclusive(true);
1817   newsFilterGroup_->addAction(filterNewsAll_);
1818   newsFilterGroup_->addAction(filterNewsNew_);
1819   newsFilterGroup_->addAction(filterNewsUnread_);
1820   newsFilterGroup_->addAction(filterNewsStar_);
1821   newsFilterGroup_->addAction(filterNewsNotStarred_);
1822   newsFilterGroup_->addAction(filterNewsUnreadStar_);
1823   newsFilterGroup_->addAction(filterNewsLastDay_);
1824   newsFilterGroup_->addAction(filterNewsLastWeek_);
1825 
1826   newsFilterMenu_ = new QMenu(this);
1827   newsFilterMenu_->addActions(newsFilterGroup_->actions());
1828   newsFilterMenu_->insertSeparator(filterNewsNew_);
1829   newsFilterMenu_->insertSeparator(filterNewsLastDay_);
1830 
1831   newsFilter_->setMenu(newsFilterMenu_);
1832 
1833   newsSortByMenu_ = new QMenu(this);
1834   newsSortByMenu_->addSeparator();
1835   newsSortByMenu_->addActions(newsSortOrderGroup_->actions());
1836 
1837   newsMenu_ = new QMenu(this);
1838   newsMenu_->addAction(markNewsRead_);
1839   newsMenu_->addAction(markAllNewsRead_);
1840   newsMenu_->addSeparator();
1841   newsMenu_->addAction(markStarAct_);
1842   newsMenu_->addAction(newsLabelMenuAction_);
1843   newsMenu_->addAction(shareMenuAct_);
1844   newsMenu_->addSeparator();
1845   newsMenu_->addAction(newsFilter_);
1846   newsMenu_->addMenu(newsSortByMenu_);
1847   newsMenu_->addSeparator();
1848   newsMenu_->addAction(deleteNewsAct_);
1849   newsMenu_->addAction(deleteAllNewsAct_);
1850 
1851   browserZoomGroup_ = new QActionGroup(this);
1852   browserZoomGroup_->addAction(zoomInAct_);
1853   browserZoomGroup_->addAction(zoomOutAct_);
1854   browserZoomGroup_->addAction(zoomTo100Act_);
1855 
1856   browserZoomMenu_ = new QMenu(this);
1857   browserZoomMenu_->setIcon(QIcon(":/images/zoom"));
1858   browserZoomMenu_->addActions(browserZoomGroup_->actions());
1859   browserZoomMenu_->insertSeparator(zoomTo100Act_);
1860 
1861   browserMenu_ = new QMenu(this);
1862   browserMenu_->addAction(autoLoadImagesToggle_);
1863   browserMenu_->addMenu(browserZoomMenu_);
1864   browserMenu_->addSeparator();
1865   browserMenu_->addAction(printAct_);
1866   browserMenu_->addAction(printPreviewAct_);
1867   browserMenu_->addSeparator();
1868   browserMenu_->addAction(savePageAsAct_);
1869   browserMenu_->addSeparator();
1870   browserMenu_->addAction(tr("&AdBlock"), AdBlockManager::instance(), SLOT(showDialog()));
1871 
1872   toolsMenu_ = new QMenu(this);
1873   toolsMenu_->addAction(showDownloadManagerAct_);
1874   toolsMenu_->addSeparator();
1875   toolsMenu_->addAction(showCleanUpWizardAct_);
1876   toolsMenu_->addAction(setNewsFiltersAct_);
1877   toolsMenu_->addSeparator();
1878   toolsMenu_->addAction(optionsAct_);
1879 
1880   helpMenu_ = new QMenu(this);
1881   helpMenu_->addAction(updateAppAct_);
1882   helpMenu_->addSeparator();
1883   helpMenu_->addAction(reportProblemAct_);
1884   helpMenu_->addAction(aboutAct_);
1885 
1886 #ifndef Q_OS_MAC
1887   mainMenu_ = new QMenu(this);
1888   mainMenu_->addAction(addAct_);
1889   mainMenu_->addSeparator();
1890   mainMenu_->addAction(importFeedsAct_);
1891   mainMenu_->addAction(exportFeedsAct_);
1892   mainMenu_->addSeparator();
1893   mainMenu_->addAction(createBackupAct_);
1894   mainMenu_->addSeparator();
1895   mainMenu_->addMenu(viewMenu_);
1896   mainMenu_->addMenu(feedMenu_);
1897   mainMenu_->addMenu(newsMenu_);
1898   mainMenu_->addMenu(browserMenu_);
1899   mainMenu_->addSeparator();
1900   mainMenu_->addMenu(toolsMenu_);
1901   mainMenu_->addSeparator();
1902   mainMenu_->addMenu(helpMenu_);
1903   mainMenu_->addSeparator();
1904   mainMenu_->addAction(showMenuBarAct_);
1905   mainMenu_->addSeparator();
1906   mainMenu_->addAction(exitAct_);
1907 #endif
1908 
1909   menuBar()->addMenu(fileMenu_);
1910   menuBar()->addMenu(viewMenu_);
1911   menuBar()->addMenu(feedMenu_);
1912   menuBar()->addMenu(newsMenu_);
1913   menuBar()->addMenu(browserMenu_);
1914   menuBar()->addMenu(toolsMenu_);
1915   menuBar()->addMenu(helpMenu_);
1916 
1917   connect(customizeToolbarGroup_, SIGNAL(triggered(QAction*)),
1918           this, SLOT(showCustomizeToolbarDlg(QAction*)));
1919   connect(styleGroup_, SIGNAL(triggered(QAction*)),
1920           this, SLOT(setStyleApp(QAction*)));
1921   connect(browserPositionGroup_, SIGNAL(triggered(QAction*)),
1922           this, SLOT(setBrowserPosition(QAction*)));
1923   connect(feedsFilterGroup_, SIGNAL(triggered(QAction*)),
1924           this, SLOT(setFeedsFilter()));
1925   connect(feedsFilter_, SIGNAL(triggered()), this, SLOT(slotFeedsFilter()));
1926   connect(feedsColumnsGroup_, SIGNAL(triggered(QAction*)),
1927           this, SLOT(feedsColumnVisible(QAction*)));
1928   connect(feedMenu_, SIGNAL(aboutToShow()), this, SLOT(slotFeedMenuShow()));
1929   connect(newsLabelMenu_, SIGNAL(aboutToShow()), this, SLOT(getLabelNews()));
1930   connect(shareMenuAct_, SIGNAL(triggered()), this, SLOT(showMenuShareNews()));
1931   connect(newsFilterGroup_, SIGNAL(triggered(QAction*)),
1932           this, SLOT(setNewsFilter(QAction*)));
1933   connect(newsFilter_, SIGNAL(triggered()), this, SLOT(slotNewsFilter()));
1934   connect(newsSortByMenu_, SIGNAL(aboutToShow()),
1935           this, SLOT(showNewsSortByMenu()));
1936   connect(newsMenu_, SIGNAL(aboutToShow()), this, SLOT(showNewsMenu()));
1937   connect(browserZoomGroup_, SIGNAL(triggered(QAction*)),
1938           this, SLOT(browserZoom(QAction*)));
1939 }
1940 // ---------------------------------------------------------------------------
createToolBar()1941 void MainWindow::createToolBar()
1942 {
1943   mainToolbar_ = new QToolBar(this);
1944   mainToolbar_->setObjectName("ToolBar_General");
1945   mainToolbar_->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
1946   mainToolbar_->setContextMenuPolicy(Qt::CustomContextMenu);
1947   addToolBar(mainToolbar_);
1948 
1949   connect(mainToolbarToggle_, SIGNAL(toggled(bool)),
1950           mainToolbar_, SLOT(setVisible(bool)));
1951   connect(mainToolbar_, SIGNAL(customContextMenuRequested(QPoint)),
1952           this, SLOT(showContextMenuToolBar(const QPoint &)));
1953 
1954   connect(toolBarLockAct_, SIGNAL(toggled(bool)), this, SLOT(lockMainToolbar(bool)));
1955   connect(toolBarHideAct_, SIGNAL(triggered()), this, SLOT(hideMainToolbar()));
1956 }
1957 
1958 /** @brief Load settings from ini-file
1959  *---------------------------------------------------------------------------*/
loadSettings()1960 void MainWindow::loadSettings()
1961 {
1962   Settings settings;
1963   settings.beginGroup("Settings");
1964 
1965   showSplashScreen_ = settings.value("showSplashScreen", true).toBool();
1966   reopenFeedStartup_ = settings.value("reopenFeedStartup", true).toBool();
1967   openNewTabNextToActive_ = settings.value("openNewTabNextToActive", false).toBool();
1968 
1969   showTrayIcon_ = settings.value("showTrayIcon", true).toBool();
1970 #ifndef Q_OS_MAC
1971   startingTray_ = settings.value("startingTray", false).toBool();
1972   minimizingTray_ = settings.value("minimizingTray", true).toBool();
1973   closingTray_ = settings.value("closingTray", false).toBool();
1974 #else
1975   startingTray_ = false;
1976   minimizingTray_ = false;
1977   closingTray_ = false;
1978 #endif
1979   singleClickTray_ = settings.value("singleClickTray", false).toBool();
1980   clearStatusNew_ = settings.value("clearStatusNew", true).toBool();
1981   emptyWorking_ = settings.value("emptyWorking", true).toBool();
1982 
1983   QString fontFamily = settings.value("feedsFontFamily", qApp->font().family()).toString();
1984   int fontSize = settings.value("feedsFontSize", qApp->font().pointSize()).toInt();
1985   feedsView_->setFont(QFont(fontFamily, fontSize));
1986   feedsModel_->font_ = feedsView_->font();
1987 
1988   newsListFontFamily_ = settings.value("newsFontFamily", qApp->font().family()).toString();
1989   newsListFontSize_ = settings.value("newsFontSize", qApp->font().pointSize()).toInt();
1990   newsTitleFontFamily_ = settings.value("newsTitleFontFamily", qApp->font().family()).toString();
1991   newsTitleFontSize_ = settings.value("newsTitleFontSize", qApp->font().pointSize()+2).toInt();
1992   newsTextFontFamily_ = settings.value("newsTextFontFamily", qApp->font().family()).toString();
1993   newsTextFontSize_ = settings.value("newsTextFontSize", qApp->font().pointSize()+2).toInt();
1994   notificationFontFamily_ = settings.value("notificationFontFamily", qApp->font().family()).toString();
1995   notificationFontSize_ = settings.value("notificationFontSize", qApp->font().pointSize()).toInt();
1996 
1997   QString browserStandardFont = settings.value(
1998         "browserStandardFont", QWebSettings::globalSettings()->fontFamily(QWebSettings::StandardFont)).toString();
1999   QString browserFixedFont = settings.value(
2000         "browserFixedFont", QWebSettings::globalSettings()->fontFamily(QWebSettings::FixedFont)).toString();
2001   QString browserSerifFont = settings.value(
2002         "browserSerifFont", QWebSettings::globalSettings()->fontFamily(QWebSettings::SerifFont)).toString();
2003   QString browserSansSerifFont = settings.value(
2004         "browserSansSerifFont", QWebSettings::globalSettings()->fontFamily(QWebSettings::SansSerifFont)).toString();
2005   QString browserCursiveFont = settings.value(
2006         "browserCursiveFont", QWebSettings::globalSettings()->fontFamily(QWebSettings::CursiveFont)).toString();
2007   QString browserFantasyFont = settings.value(
2008         "browserFantasyFont", QWebSettings::globalSettings()->fontFamily(QWebSettings::FantasyFont)).toString();
2009   int browserDefaultFontSize = settings.value(
2010         "browserDefaultFontSize", QWebSettings::globalSettings()->fontSize(QWebSettings::DefaultFontSize)).toInt();
2011   int browserFixedFontSize = settings.value(
2012         "browserFixedFontSize", QWebSettings::globalSettings()->fontSize(QWebSettings::DefaultFixedFontSize)).toInt();
2013   int browserMinFontSize = settings.value(
2014         "browserMinFontSize", QWebSettings::globalSettings()->fontSize(QWebSettings::MinimumFontSize)).toInt();
2015   int browserMinLogFontSize = settings.value(
2016         "browserMinLogFontSize", QWebSettings::globalSettings()->fontSize(QWebSettings::MinimumLogicalFontSize)).toInt();
2017 
2018   QWebSettings::globalSettings()->setFontFamily(
2019         QWebSettings::StandardFont, browserStandardFont);
2020   QWebSettings::globalSettings()->setFontFamily(
2021         QWebSettings::FixedFont, browserFixedFont);
2022   QWebSettings::globalSettings()->setFontFamily(
2023         QWebSettings::SerifFont, browserSerifFont);
2024   QWebSettings::globalSettings()->setFontFamily(
2025         QWebSettings::SansSerifFont, browserSansSerifFont);
2026   QWebSettings::globalSettings()->setFontFamily(
2027         QWebSettings::CursiveFont, browserCursiveFont);
2028   QWebSettings::globalSettings()->setFontFamily(
2029         QWebSettings::FantasyFont, browserFantasyFont);
2030   QWebSettings::globalSettings()->setFontSize(
2031         QWebSettings::DefaultFontSize, browserDefaultFontSize);
2032   QWebSettings::globalSettings()->setFontSize(
2033         QWebSettings::DefaultFixedFontSize, browserFixedFontSize);
2034   QWebSettings::globalSettings()->setFontSize(
2035         QWebSettings::MinimumFontSize, browserMinFontSize);
2036   QWebSettings::globalSettings()->setFontSize(
2037         QWebSettings::MinimumLogicalFontSize, browserMinLogFontSize);
2038 
2039   updateFeedsEnable_ = settings.value("autoUpdatefeeds", false).toBool();
2040   updateFeedsInterval_ = settings.value("autoUpdatefeedsTime", 10).toInt();
2041   updateFeedsIntervalType_ = settings.value("autoUpdatefeedsInterval", 0).toInt();
2042 
2043   openingFeedAction_ = settings.value("openingFeedAction", 0).toInt();
2044   openNewsWebViewOn_ = settings.value("openNewsWebViewOn", true).toBool();
2045 
2046   markNewsReadOn_ = settings.value("markNewsReadOn", true).toBool();
2047   markCurNewsRead_ = settings.value("markCurNewsRead", true).toBool();
2048   markNewsReadTime_ = settings.value("markNewsReadTime", 0).toInt();
2049   markPrevNewsRead_= settings.value("markPrevNewsRead", false).toBool();
2050   markReadSwitchingFeed_ = settings.value("markReadSwitchingFeed", false).toBool();
2051   markReadClosingTab_ = settings.value("markReadClosingTab", false).toBool();
2052   markReadMinimize_ = settings.value("markReadMinimize", false).toBool();
2053 
2054   showDescriptionNews_ = settings.value("showDescriptionNews", true).toBool();
2055 
2056   formatDate_ = settings.value("formatData", "dd.MM.yy").toString();
2057   formatTime_ = settings.value("formatTime", "hh:mm").toString();
2058   feedsModel_->formatDate_ = formatDate_;
2059   feedsModel_->formatTime_ = formatTime_;
2060 
2061   alternatingRowColorsNews_ = settings.value("alternatingColorsNews", false).toBool();
2062   changeBehaviorActionNUN_ = settings.value("changeBehaviorActionNUN", false).toBool();
2063   simplifiedDateTime_ = settings.value("simplifiedDateTime", true).toBool();
2064   notDeleteStarred_ = settings.value("notDeleteStarred", false).toBool();
2065   notDeleteLabeled_ = settings.value("notDeleteLabeled", false).toBool();
2066   markIdenticalNewsRead_ = settings.value("markIdenticalNewsRead", true).toBool();
2067   avoidOldNews_ = settings.value("avoidOldNews", false).toBool();
2068   avoidedOldNewsDate_ = settings.value("avoidedOldNewsDate").toDate();
2069 
2070   mainNewsFilter_ = settings.value("mainNewsFilter", "filterNewsAll_").toString();
2071 
2072   cleanupOnShutdown_ = settings.value("cleanupOnShutdown", true).toBool();
2073   maxDayCleanUp_ = settings.value("maxDayClearUp", 30).toInt();
2074   maxNewsCleanUp_ = settings.value("maxNewsClearUp", 200).toInt();
2075   dayCleanUpOn_ = settings.value("dayClearUpOn", true).toBool();
2076   newsCleanUpOn_ = settings.value("newsClearUpOn", true).toBool();
2077   readCleanUp_ = settings.value("readClearUp", false).toBool();
2078   neverUnreadCleanUp_ = settings.value("neverUnreadClearUp", true).toBool();
2079   neverStarCleanUp_ = settings.value("neverStarClearUp", true).toBool();
2080   neverLabelCleanUp_ = settings.value("neverLabelClearUp", true).toBool();
2081   cleanUpDeleted_ = settings.value("cleanUpDeleted", false).toBool();
2082   optimizeDB_ = settings.value("optimizeDB", false).toBool();
2083 
2084   externalBrowserOn_ = settings.value("externalBrowserOn", 0).toInt();
2085   externalBrowser_ = settings.value("externalBrowser", "").toString();
2086   javaScriptEnable_ = settings.value("javaScriptEnable", true).toBool();
2087   pluginsEnable_ = settings.value("pluginsEnable", true).toBool();
2088   maxPagesInCache_ = settings.value("maxPagesInCache", 3).toInt();
2089   downloadLocation_ = settings.value("downloadLocation", "").toString();
2090   askDownloadLocation_ = settings.value("askDownloadLocation", true).toBool();
2091   defaultZoomPages_ = settings.value("defaultZoomPages", 100).toInt();
2092   autoLoadImages_ = settings.value("autoLoadImages", true).toBool();
2093 
2094   QWebSettings::globalSettings()->setAttribute(
2095         QWebSettings::JavascriptEnabled, javaScriptEnable_);
2096   QWebSettings::globalSettings()->setAttribute(
2097         QWebSettings::PluginsEnabled, pluginsEnable_);
2098   QWebSettings::globalSettings()->setMaximumPagesInCache(maxPagesInCache_);
2099 #if QT_VERSION >= 0x050e00
2100   QWebSettings::globalSettings()->setAttribute(
2101         QWebSettings::ErrorPageEnabled, false);
2102 #endif
2103   QWebSettings::globalSettings()->setOfflineStorageDefaultQuota(0);
2104   QWebSettings::globalSettings()->setOfflineStoragePath(mainApp->dataDir());
2105 
2106   soundNewNews_ = settings.value("soundNewNews", true).toBool();
2107   soundNotifyPath_ = settings.value("soundNotifyPath", mainApp->soundNotifyDefaultFile()).toString();
2108   showNotifyOn_ = settings.value("showNotifyOn", true).toBool();
2109   screenNotify_ = settings.value("screenNotify", 0).toInt();
2110   positionNotify_ = settings.value("positionNotify", 3).toInt();
2111   transparencyNotify_ = settings.value("transparencyNotify", 60).toInt();
2112   countShowNewsNotify_ = settings.value("countShowNewsNotify", 10).toInt();
2113   widthTitleNewsNotify_ = settings.value("widthTitleNewsNotify", 300).toInt();
2114   timeShowNewsNotify_ = settings.value("timeShowNewsNotify", 10).toInt();
2115   fullscreenModeNotify_ = settings.value("fullscreenModeNotify", true).toBool();
2116   showNotifyInactiveApp_ = settings.value("showNotifyInactiveApp", true).toBool();
2117   onlySelectedFeeds_ = settings.value("onlySelectedFeeds", false).toBool();
2118   showTitlesFeedsNotify_ = settings.value("showTitlesFeedsNotify", true).toBool();
2119   showIconFeedNotify_ = settings.value("showIconFeedNotify", false).toBool();
2120   showButtonMarkAllNotify_ = settings.value("showButtonMarkAllNotify", true).toBool();
2121   showButtonMarkReadNotify_ = settings.value("showButtonMarkReadNotify", true).toBool();
2122   showButtonExBrowserNotify_ = settings.value("showButtonExBrowserNotify", true).toBool();
2123   showButtonDeleteNotify_ = settings.value("showButtonDeleteNotify", true).toBool();
2124   closeNotify_ = settings.value("closeNotify", true).toBool();
2125 
2126   toolBarLockAct_->setChecked(settings.value("mainToolbarLock", true).toBool());
2127   lockMainToolbar(toolBarLockAct_->isChecked());
2128 
2129   mainToolbarToggle_->setChecked(settings.value("mainToolbarShow2", false).toBool());
2130   feedsToolbarToggle_->setChecked(settings.value("feedsToolbarShow2", true).toBool());
2131   newsToolbarToggle_->setChecked(settings.value("newsToolbarShow", true).toBool());
2132   browserToolbarToggle_->setChecked(settings.value("browserToolbarShow", true).toBool());
2133   categoriesPanelToggle_->setChecked(settings.value("categoriesPanelShow", true).toBool());
2134   categoriesWidget_->setVisible(categoriesPanelToggle_->isChecked());
2135   statusBarToggle_->setChecked(settings.value("statusBarShow", true).toBool());
2136 
2137   QString str = settings.value("mainToolBar",
2138                                "newAct,Separator,updateFeedAct,updateAllFeedsAct,"
2139                                "Separator,markFeedRead,Separator,autoLoadImagesToggle").toString();
2140 
2141   foreach (QString actionStr, str.split(",", QString::SkipEmptyParts)) {
2142     if (actionStr == "Separator") {
2143       mainToolbar_->addSeparator();
2144     } else {
2145       QListIterator<QAction *> iter(actions());
2146       while (iter.hasNext()) {
2147         QAction *pAction = iter.next();
2148         if (!pAction->icon().isNull()) {
2149           if (pAction->objectName() == actionStr) {
2150             mainToolbar_->addAction(pAction);
2151             break;
2152           }
2153         }
2154       }
2155     }
2156   }
2157 
2158   str = settings.value("feedsToolBar2",
2159                                "newAct,Separator,updateAllFeedsAct,markFeedRead,"
2160                                "Separator,feedsFilter,findFeedAct").toString();
2161 
2162   foreach (QString actionStr, str.split(",", QString::SkipEmptyParts)) {
2163     if (actionStr == "Separator") {
2164       feedsToolBar_->addSeparator();
2165     } else {
2166       QListIterator<QAction *> iter(actions());
2167       while (iter.hasNext()) {
2168         QAction *pAction = iter.next();
2169         if (!pAction->icon().isNull()) {
2170           if (pAction->objectName() == actionStr) {
2171             feedsToolBar_->addAction(pAction);
2172             break;
2173           }
2174         }
2175       }
2176     }
2177   }
2178 
2179   setToolBarStyle(settings.value("toolBarStyle", "toolBarStyleTuI_").toString());
2180   QString iconStr = settings.value("toolBarIconSize", "toolBarIconNormal_").toString();
2181   setToolBarIconSize(mainToolbar_, iconStr);
2182   iconStr = settings.value("feedsToolBarIconSize", "toolBarIconSmall_").toString();
2183   setToolBarIconSize(feedsToolBar_, iconStr);
2184 
2185   str = settings.value("styleApplication", "defaultStyle_").toString();
2186   QList<QAction*> listActions = styleGroup_->actions();
2187   foreach(QAction *action, listActions) {
2188     if (action->objectName() == str) {
2189       action->setChecked(true);
2190       break;
2191     }
2192   }
2193 
2194   showUnreadCount_->setChecked(settings.value("showUnreadCount", true).toBool());
2195   showUndeleteCount_->setChecked(settings.value("showUndeleteCount", false).toBool());
2196   showLastUpdated_->setChecked(settings.value("showLastUpdated", false).toBool());
2197   feedsColumnVisible(showUnreadCount_);
2198   feedsColumnVisible(showUndeleteCount_);
2199   feedsColumnVisible(showLastUpdated_);
2200 
2201   indentationFeedsTreeAct_->setChecked(settings.value("indentationFeedsTree", true).toBool());
2202   slotIndentationFeedsTree();
2203 
2204   newsLayout_ = settings.value("newsLayout", 0).toInt();
2205   switch (newsLayout_) {
2206   case 1:
2207     newspaperLayoutAct_->setChecked(true);
2208     layoutToggle_->setIcon(QIcon(":/images/layout_newspaper"));
2209     break;
2210   default:
2211     classicLayoutAct_->setChecked(true);
2212     layoutToggle_->setIcon(QIcon(":/images/layout_classic"));
2213   }
2214   connect(layoutGroup_, SIGNAL(triggered(QAction*)),
2215           this, SLOT(setNewsLayout(QAction*)));
2216 
2217   browserPosition_ = settings.value("browserPosition", BOTTOM_POSITION).toInt();
2218   switch (browserPosition_) {
2219   case TOP_POSITION:   topBrowserPositionAct_->setChecked(true); break;
2220   case RIGHT_POSITION: rightBrowserPositionAct_->setChecked(true); break;
2221   case LEFT_POSITION:  leftBrowserPositionAct_->setChecked(true); break;
2222   default: bottomBrowserPositionAct_->setChecked(true);
2223   }
2224 
2225   openLinkInBackground_ = settings.value("openLinkInBackground", true).toBool();
2226   openLinkInBackgroundEmbedded_ = settings.value("openLinkInBackgroundEmbedded", true).toBool();
2227   openingLinkTimeout_ = settings.value("openingLinkTimeout", 1000).toInt();
2228 
2229   stayOnTopAct_->setChecked(settings.value("stayOnTop", false).toBool());
2230   if (stayOnTopAct_->isChecked())
2231     setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
2232   else
2233     setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint);
2234 
2235   hideFeedsOpenTab_ = settings.value("hideFeedsOpenTab", false).toBool();
2236   showToggleFeedsTree_ = settings.value("showToggleFeedsTree", true).toBool();
2237   pushButtonNull_->setVisible(showToggleFeedsTree_);
2238 
2239   defaultIconFeeds_ = settings.value("defaultIconFeeds", false).toBool();
2240   feedsModel_->defaultIconFeeds_ = defaultIconFeeds_;
2241   feedsView_->autocollapseFolder_ =
2242       settings.value("autocollapseFolder", false).toBool();
2243 
2244 #ifndef Q_OS_MAC
2245   showMenuBarAct_->setChecked(settings.value("showMenuBar", false).toBool());
2246 #else
2247   showMenuBarAct_->setChecked(true);
2248 #endif
2249 
2250   settings.endGroup();
2251 
2252   settings.beginGroup("Color");
2253   QString windowTextColor = qApp->palette().brush(QPalette::WindowText).color().name();
2254   QString linkTextColor = qApp->palette().brush(QPalette::Link).color().name();
2255   feedsModel_->textColor_ = settings.value("feedsListTextColor", windowTextColor).toString();
2256   feedsModel_->backgroundColor_ = settings.value("feedsListBackgroundColor", "").toString();
2257   feedsView_->setStyleSheet(QString("#feedsView_ {background: %1;}").arg(feedsModel_->backgroundColor_));
2258   newsListTextColor_ = settings.value("newsListTextColor", windowTextColor).toString();
2259   newsListBackgroundColor_ = settings.value("newsListBackgroundColor", "").toString();
2260   newNewsTextColor_ = settings.value("newNewsTextColor", windowTextColor).toString();
2261   unreadNewsTextColor_ = settings.value("unreadNewsTextColor", windowTextColor).toString();
2262   focusedNewsTextColor_ = settings.value("focusedNewsTextColor", windowTextColor).toString();
2263   focusedNewsBGColor_ = settings.value("focusedNewsBGColor", "").toString();
2264   linkColor_ = settings.value("linkColor", "#0066CC").toString();
2265   titleColor_ = settings.value("titleColor", "#0066CC").toString();
2266   dateColor_ = settings.value("dateColor", "#666666").toString();
2267   authorColor_ = settings.value("authorColor", "#666666").toString();
2268   newsTextColor_ = settings.value("newsTextColor", "#000000").toString();
2269   newsTitleBackgroundColor_ = settings.value("newsTitleBackgroundColor", "#FFFFFF").toString();
2270   newsBackgroundColor_ = settings.value("newsBackgroundColor", "#FFFFFF").toString();
2271   feedsModel_->feedWithNewNewsColor_ = settings.value("feedWithNewNewsColor", linkTextColor).toString();
2272   feedsModel_->countNewsUnreadColor_ = settings.value("countNewsUnreadColor", linkTextColor).toString();
2273   feedsModel_->focusedFeedTextColor_ = settings.value("focusedFeedTextColor", windowTextColor).toString();
2274   feedsModel_->focusedFeedBGColor_ = settings.value("focusedFeedBGColor", "").toString();
2275   feedsModel_->feedDisabledUpdateColor_ = settings.value("feedDisabledUpdateColor", "#999999").toString();
2276   alternatingRowColors_ = settings.value("alternatingRowColors", qApp->palette().color(QPalette::AlternateBase).name()).toString();
2277   notifierTextColor_ = settings.value("notifierTextColor", windowTextColor).toString();
2278   notifierBackgroundColor_ = settings.value("notifierBackgroundColor", "#FFFFFF").toString();
2279   settings.endGroup();
2280 
2281   resize(800, 600);
2282   restoreGeometry(settings.value("GeometryState").toByteArray());
2283   restoreState(settings.value("ToolBarsState").toByteArray());
2284 
2285   if (!mainToolbarToggle_->isChecked())
2286     mainToolbar_->hide();
2287   if (!feedsToolbarToggle_->isChecked())
2288     feedsPanel_->hide();
2289   if (!statusBarToggle_->isChecked())
2290     statusBar()->hide();
2291 
2292   mainSplitter_->restoreState(settings.value("MainSplitterState").toByteArray());
2293   feedsWidgetVisibleAct_->setChecked(settings.value("FeedsWidgetVisible", true).toBool());
2294   slotVisibledFeedsWidget();
2295 
2296   feedsWidgetSplitterState_ = settings.value("FeedsWidgetSplitterState").toByteArray();
2297   bool showCategories = settings.value("NewsCategoriesTreeVisible", true).toBool();
2298   categoriesTree_->setVisible(showCategories);
2299   if (showCategories) {
2300     showCategoriesButton_->setIcon(QIcon(":/images/images/panel_hide.png"));
2301     showCategoriesButton_->setToolTip(tr("Hide Categories"));
2302     feedsSplitter_->restoreState(feedsWidgetSplitterState_);
2303   } else {
2304     showCategoriesButton_->setIcon(QIcon(":/images/images/panel_show.png"));
2305     showCategoriesButton_->setToolTip(tr("Show Categories"));
2306     QList <int> sizes;
2307     sizes << QApplication::desktop()->height() << 20;
2308     feedsSplitter_->setSizes(sizes);
2309   }
2310   bool expandCategories = settings.value("categoriesTreeExpanded", true).toBool();
2311   if (expandCategories)
2312     categoriesTree_->expandAll();
2313 
2314   showMenuBar();
2315 
2316   adblockIcon_->setEnabled(settings.value("AdBlock/enabled", true).toBool());
2317 }
2318 
2319 /** @brief Save settings in ini-file
2320  *---------------------------------------------------------------------------*/
saveSettings()2321 void MainWindow::saveSettings()
2322 {
2323   Settings settings;
2324   settings.beginGroup("Settings");
2325 
2326   settings.setValue("showSplashScreen", showSplashScreen_);
2327   settings.setValue("reopenFeedStartup", reopenFeedStartup_);
2328   settings.setValue("openNewTabNextToActive", openNewTabNextToActive_);
2329 
2330   settings.setValue("createLastFeed", mainApp->isSaveDataLastFeed());
2331 
2332   settings.setValue("showTrayIcon", showTrayIcon_);
2333   settings.setValue("startingTray", startingTray_);
2334   settings.setValue("minimizingTray", minimizingTray_);
2335   settings.setValue("closingTray", closingTray_);
2336   settings.setValue("behaviorIconTray", behaviorIconTray_);
2337   settings.setValue("singleClickTray", singleClickTray_);
2338   settings.setValue("clearStatusNew", clearStatusNew_);
2339   settings.setValue("emptyWorking", emptyWorking_);
2340 
2341   settings.setValue("langFileName", mainApp->language());
2342 
2343   QString fontFamily = feedsView_->font().family();
2344   settings.setValue("feedsFontFamily", fontFamily);
2345   int fontSize = feedsView_->font().pointSize();
2346   settings.setValue("feedsFontSize", fontSize);
2347 
2348   settings.setValue("newsFontFamily", newsListFontFamily_);
2349   settings.setValue("newsFontSize", newsListFontSize_);
2350   settings.setValue("newsTitleFontFamily", newsTitleFontFamily_);
2351   settings.setValue("newsTitleFontSize", newsTitleFontSize_);
2352   settings.setValue("newsTextFontFamily", newsTextFontFamily_);
2353   settings.setValue("newsTextFontSize", newsTextFontSize_);
2354   settings.setValue("notificationFontFamily", notificationFontFamily_);
2355   settings.setValue("notificationFontSize", notificationFontSize_);
2356 
2357   settings.setValue("autoUpdatefeeds", updateFeedsEnable_);
2358   settings.setValue("autoUpdatefeedsTime", updateFeedsInterval_);
2359   settings.setValue("autoUpdatefeedsInterval", updateFeedsIntervalType_);
2360 
2361   settings.setValue("openingFeedAction", openingFeedAction_);
2362   settings.setValue("openNewsWebViewOn", openNewsWebViewOn_);
2363 
2364   settings.setValue("markNewsReadOn", markNewsReadOn_);
2365   settings.setValue("markCurNewsRead", markCurNewsRead_);
2366   settings.setValue("markNewsReadTime", markNewsReadTime_);
2367   settings.setValue("markPrevNewsRead", markPrevNewsRead_);
2368   settings.setValue("markReadSwitchingFeed", markReadSwitchingFeed_);
2369   settings.setValue("markReadClosingTab", markReadClosingTab_);
2370   settings.setValue("markReadMinimize", markReadMinimize_);
2371 
2372   settings.setValue("showDescriptionNews", showDescriptionNews_);
2373 
2374   settings.setValue("formatData", formatDate_);
2375   settings.setValue("formatTime", formatTime_);
2376 
2377   settings.setValue("alternatingColorsNews", alternatingRowColorsNews_);
2378   settings.setValue("changeBehaviorActionNUN", changeBehaviorActionNUN_);
2379   settings.setValue("simplifiedDateTime", simplifiedDateTime_);
2380   settings.setValue("notDeleteStarred", notDeleteStarred_);
2381   settings.setValue("notDeleteLabeled", notDeleteLabeled_);
2382   settings.setValue("markIdenticalNewsRead", markIdenticalNewsRead_);
2383   settings.setValue("avoidOldNews", avoidOldNews_);
2384   settings.setValue("avoidedOldNewsDate", avoidedOldNewsDate_);
2385 
2386   settings.setValue("mainNewsFilter", mainNewsFilter_);
2387 
2388   settings.setValue("cleanupOnShutdown", cleanupOnShutdown_);
2389   settings.setValue("maxDayClearUp", maxDayCleanUp_);
2390   settings.setValue("maxNewsClearUp", maxNewsCleanUp_);
2391   settings.setValue("dayClearUpOn", dayCleanUpOn_);
2392   settings.setValue("newsClearUpOn", newsCleanUpOn_);
2393   settings.setValue("readClearUp", readCleanUp_);
2394   settings.setValue("neverUnreadClearUp", neverUnreadCleanUp_);
2395   settings.setValue("neverStarClearUp", neverStarCleanUp_);
2396   settings.setValue("neverLabelClearUp", neverLabelCleanUp_);
2397   settings.setValue("cleanUpDeleted", cleanUpDeleted_);
2398   settings.setValue("optimizeDB", optimizeDB_);
2399 
2400   settings.setValue("externalBrowserOn", externalBrowserOn_);
2401   settings.setValue("externalBrowser", externalBrowser_);
2402   settings.setValue("javaScriptEnable", javaScriptEnable_);
2403   settings.setValue("pluginsEnable", pluginsEnable_);
2404   settings.setValue("maxPagesInCache", maxPagesInCache_);
2405   settings.setValue("downloadLocation", downloadLocation_);
2406   settings.setValue("askDownloadLocation", askDownloadLocation_);
2407   settings.setValue("defaultZoomPages", defaultZoomPages_);
2408   settings.setValue("autoLoadImages", autoLoadImages_);
2409 
2410   settings.setValue("soundNewNews", soundNewNews_);
2411   settings.setValue("soundNotifyPath", soundNotifyPath_);
2412   settings.setValue("showNotifyOn", showNotifyOn_);
2413   settings.setValue("screenNotify", screenNotify_);
2414   settings.setValue("positionNotify", positionNotify_);
2415   settings.setValue("transparencyNotify", transparencyNotify_);
2416   settings.setValue("countShowNewsNotify", countShowNewsNotify_);
2417   settings.setValue("widthTitleNewsNotify", widthTitleNewsNotify_);
2418   settings.setValue("timeShowNewsNotify", timeShowNewsNotify_);
2419   settings.setValue("fullscreenModeNotify", fullscreenModeNotify_);
2420   settings.setValue("showNotifyInactiveApp", showNotifyInactiveApp_);
2421   settings.setValue("onlySelectedFeeds", onlySelectedFeeds_);
2422   settings.setValue("showTitlesFeedsNotify", showTitlesFeedsNotify_);
2423   settings.setValue("showIconFeedNotify", showIconFeedNotify_);
2424   settings.setValue("showButtonMarkAllNotify", showButtonMarkAllNotify_);
2425   settings.setValue("showButtonMarkReadNotify", showButtonMarkReadNotify_);
2426   settings.setValue("showButtonExBrowserNotify", showButtonExBrowserNotify_);
2427   settings.setValue("showButtonDeleteNotify", showButtonDeleteNotify_);
2428   settings.setValue("closeNotify", closeNotify_);
2429 
2430   settings.setValue("mainToolbarLock", toolBarLockAct_->isChecked());
2431 
2432   settings.setValue("mainToolbarShow2", mainToolbarToggle_->isChecked());
2433   settings.setValue("feedsToolbarShow2", feedsToolbarToggle_->isChecked());
2434   settings.setValue("newsToolbarShow", newsToolbarToggle_->isChecked());
2435   settings.setValue("browserToolbarShow", browserToolbarToggle_->isChecked());
2436   settings.setValue("categoriesPanelShow", categoriesPanelToggle_->isChecked());
2437   settings.setValue("statusBarShow", statusBarToggle_->isChecked());
2438 
2439   settings.setValue("styleApplication",
2440                     styleGroup_->checkedAction()->objectName());
2441 
2442   settings.setValue("showUnreadCount", showUnreadCount_->isChecked());
2443   settings.setValue("showUndeleteCount", showUndeleteCount_->isChecked());
2444   settings.setValue("showLastUpdated", showLastUpdated_->isChecked());
2445 
2446   settings.setValue("indentationFeedsTree", indentationFeedsTreeAct_->isChecked());
2447 
2448   settings.setValue("newsLayout", newsLayout_);
2449   settings.setValue("browserPosition", browserPosition_);
2450 
2451   settings.setValue("openLinkInBackground", openLinkInBackground_);
2452   settings.setValue("openLinkInBackgroundEmbedded", openLinkInBackgroundEmbedded_);
2453   settings.setValue("openingLinkTimeout", openingLinkTimeout_);
2454 
2455   settings.setValue("stayOnTop", stayOnTopAct_->isChecked());
2456 
2457   settings.setValue("hideFeedsOpenTab", hideFeedsOpenTab_);
2458   settings.setValue("showToggleFeedsTree", showToggleFeedsTree_);
2459 
2460   settings.setValue("defaultIconFeeds", defaultIconFeeds_);
2461   settings.setValue("autocollapseFolder", feedsView_->autocollapseFolder_);
2462 
2463   settings.setValue("showMenuBar", showMenuBarAct_->isChecked());
2464 
2465   settings.endGroup();
2466 
2467   settings.beginGroup("Color");
2468   settings.setValue("feedsListTextColor", feedsModel_->textColor_);
2469   settings.setValue("feedsListBackgroundColor", feedsModel_->backgroundColor_);
2470   settings.setValue("newsListTextColor", newsListTextColor_);
2471   settings.setValue("newsListBackgroundColor", newsListBackgroundColor_);
2472   settings.setValue("newNewsTextColor", newNewsTextColor_);
2473   settings.setValue("unreadNewsTextColor", unreadNewsTextColor_);
2474   settings.setValue("focusedNewsTextColor", focusedNewsTextColor_);
2475   settings.setValue("focusedNewsBGColor", focusedNewsBGColor_);
2476   settings.setValue("linkColor", linkColor_);
2477   settings.setValue("titleColor", titleColor_);
2478   settings.setValue("dateColor", dateColor_);
2479   settings.setValue("authorColor", authorColor_);
2480   settings.setValue("newsTextColor", newsTextColor_);
2481   settings.setValue("newsTitleBackgroundColor", newsTitleBackgroundColor_);
2482   settings.setValue("newsBackgroundColor", newsBackgroundColor_);
2483   settings.setValue("feedWithNewNewsColor", feedsModel_->feedWithNewNewsColor_);
2484   settings.setValue("countNewsUnreadColor", feedsModel_->countNewsUnreadColor_);
2485   settings.setValue("focusedFeedTextColor", feedsModel_->focusedFeedTextColor_);
2486   settings.setValue("focusedFeedBGColor", feedsModel_->focusedFeedBGColor_);
2487   settings.setValue("feedDisabledUpdateColor", feedsModel_->feedDisabledUpdateColor_);
2488   settings.setValue("alternatingRowColors", alternatingRowColors_);
2489   settings.setValue("notifierTextColor", notifierTextColor_);
2490   settings.setValue("notifierBackgroundColor", notifierBackgroundColor_);
2491   settings.endGroup();
2492 
2493   settings.setValue("GeometryState", saveGeometry());
2494   settings.setValue("ToolBarsState", saveState());
2495 
2496   settings.setValue("MainSplitterState", mainSplitter_->saveState());
2497   settings.setValue("FeedsWidgetVisible", showFeedsTabPermanent_);
2498 
2499   bool newsCategoriesTreeVisible = true;
2500   if (categoriesWidget_->height() <= (categoriesPanel_->height()+2)) {
2501     newsCategoriesTreeVisible = false;
2502     settings.setValue("FeedsWidgetSplitterState", feedsWidgetSplitterState_);
2503   } else {
2504     settings.setValue("FeedsWidgetSplitterState", feedsSplitter_->saveState());
2505   }
2506   settings.setValue("NewsCategoriesTreeVisible", newsCategoriesTreeVisible);
2507   settings.setValue("categoriesTreeExpanded", categoriesTree_->topLevelItem(CategoriesTreeWidget::LabelsItem)->isExpanded());
2508 
2509   if (stackedWidget_->count()) {
2510     NewsTabWidget *widget;
2511     if (currentNewsTab->type_ < NewsTabWidget::TabTypeWeb)
2512       widget = currentNewsTab;
2513     else
2514       widget = (NewsTabWidget*)stackedWidget_->widget(TAB_WIDGET_PERMANENT);
2515 
2516     widget->newsHeader_->saveStateColumns(widget);
2517     settings.setValue("NewsTabSplitterState",
2518                       widget->newsTabWidgetSplitter_->saveState());
2519   }
2520 
2521   NewsTabWidget *widget = (NewsTabWidget*)stackedWidget_->widget(TAB_WIDGET_PERMANENT);
2522   settings.setValue("feedSettings/currentId", widget->feedId_);
2523   settings.setValue("feedSettings/filterName",
2524                     feedsFilterGroup_->checkedAction()->objectName());
2525   settings.setValue("newsSettings/filterName",
2526                     newsFilterGroup_->checkedAction()->objectName());
2527 
2528   mainApp->cookieJar()->saveCookies();
2529   mainApp->c2fSaveSettings();
2530   AdBlockManager::instance()->save();
2531 }
2532 
showMainMenu()2533 void MainWindow::showMainMenu()
2534 {
2535 #ifndef Q_OS_MAC
2536   mainMenu_->popup(mainMenuButton_->mapToGlobal(QPoint(0, mainMenuButton_->height())));
2537 #endif
2538 }
2539 
2540 /** @brief Add feed to feed list
2541  *---------------------------------------------------------------------------*/
addFeed()2542 void MainWindow::addFeed()
2543 {
2544   int curFolderId = 0;
2545   QPersistentModelIndex curIndex = feedsView_->selectIndex();
2546   if (feedsModel_->isFolder(curIndex)) {
2547     curFolderId = feedsModel_->idByIndex(curIndex);
2548   } else {
2549     curFolderId = feedsModel_->paridByIndex(curIndex);
2550   }
2551 
2552   AddFeedWizard *addFeedWizard = new AddFeedWizard(this, curFolderId);
2553   addFeedWizard->show();
2554 
2555   int result = addFeedWizard->exec();
2556   if (result == QDialog::Rejected) {
2557     delete addFeedWizard;
2558     return;
2559   }
2560 
2561   emit faviconRequestUrl(addFeedWizard->htmlUrlString_, addFeedWizard->feedUrlString_);
2562 
2563   QList<int> categoriesList;
2564   categoriesList << addFeedWizard->feedParentId_;
2565   recountFeedCategories(categoriesList);
2566 
2567   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
2568   feedsView_->setCurrentIndex(QModelIndex());
2569   feedsModelReload();
2570   QModelIndex index = feedsProxyModel_->mapFromSource(addFeedWizard->feedId_);
2571   feedsView_->selectIdEn_ = true;
2572   feedsView_->setCurrentIndex(index);
2573   slotFeedClicked(index);
2574   QApplication::restoreOverrideCursor();
2575   slotUpdateFeed(addFeedWizard->feedId_, true, addFeedWizard->newCount_, false);
2576 
2577   delete addFeedWizard;
2578 }
2579 
2580 /** @brief Add folder to feed list
2581  *---------------------------------------------------------------------------*/
addFolder()2582 void MainWindow::addFolder()
2583 {
2584   int curFolderId = 0;
2585   QPersistentModelIndex curIndex = feedsView_->selectIndex();
2586   if (feedsModel_->isFolder(curIndex)) {
2587     curFolderId = feedsModel_->idByIndex(curIndex);
2588   } else {
2589     curFolderId = feedsModel_->paridByIndex(curIndex);
2590   }
2591 
2592   AddFolderDialog *addFolderDialog = new AddFolderDialog(this, curFolderId);
2593 
2594   if (addFolderDialog->exec() == QDialog::Rejected) {
2595     delete addFolderDialog;
2596     return;
2597   }
2598 
2599   QString folderText = addFolderDialog->nameFeedEdit_->text();
2600   int parentId = addFolderDialog->foldersTree_->currentItem()->text(1).toInt();
2601 
2602   QSqlQuery q;
2603 
2604   // Determine row number for folder
2605   int rowToParent = 0;
2606   q.exec(QString("SELECT count(id) FROM feeds WHERE parentId='%1'").
2607          arg(parentId));
2608   if (q.next()) rowToParent = q.value(0).toInt();
2609 
2610   // Add feed to DB
2611   q.prepare("INSERT INTO feeds(text, created, parentId, rowToParent) "
2612             "VALUES (:text, :feedCreateTime, :parentId, :rowToParent)");
2613   q.bindValue(":text", folderText);
2614   q.bindValue(":feedCreateTime",
2615               QLocale::c().toString(QDateTime::currentDateTimeUtc(), "yyyy-MM-ddTHH:mm:ss"));
2616   q.bindValue(":parentId", parentId);
2617   q.bindValue(":rowToParent", rowToParent);
2618   q.exec();
2619 
2620   delete addFolderDialog;
2621 
2622   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
2623   feedsModelReload();
2624   QApplication::restoreOverrideCursor();
2625 }
2626 
2627 /** @brief Delete feed list item with confirmation
2628  *---------------------------------------------------------------------------*/
deleteItemFeedsTree()2629 void MainWindow::deleteItemFeedsTree()
2630 {
2631   if (!feedsView_->selectIndex().isValid()) return;
2632 
2633   QMessageBox msgBox(this);
2634   msgBox.setIcon(QMessageBox::Question);
2635   msgBox.setWindowTitle(tr("Confirm Delete"));
2636   msgBox.setText(tr("Are you sure to delete selected elements?"));
2637   msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
2638   msgBox.setDefaultButton(QMessageBox::No);
2639 
2640   if (msgBox.exec() == QMessageBox::No) return;
2641 
2642   QModelIndex currentIndex = feedsProxyModel_->mapToSource(feedsView_->currentIndex());
2643   int feedIdCur = feedsModel_->idByIndex(currentIndex);
2644 
2645   QModelIndexList indexList = feedsView_->selectionModel()->selectedRows(0);
2646   if (indexList.count() <= 1) {
2647     indexList.clear();
2648     indexList.append(feedsProxyModel_->mapFromSource(feedsView_->selectIndex()));
2649   }
2650 
2651   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
2652 
2653   QList<int> idList;
2654   QList<int> parentIdList;
2655   for (int i = indexList.count()-1; i >= 0; --i) {
2656     QModelIndex index = feedsProxyModel_->mapToSource(indexList[i]);
2657     if (feedsModel_->isFolder(index)) {
2658       idList.append(feedsModel_->dataField(index, "id").toInt());
2659       int parentId = feedsModel_->dataField(index, "parentId").toInt();
2660       if (!parentIdList.contains(parentId)) {
2661         parentIdList.append(parentId);
2662       }
2663       indexList.removeAt(i);
2664     }
2665   }
2666   for (int i = indexList.count()-1; i >= 0; --i) {
2667     QModelIndex index = feedsProxyModel_->mapToSource(indexList[i]);
2668     int parentId = feedsModel_->dataField(index, "parentId").toInt();
2669     if (!idList.contains(parentId)) {
2670       idList.append(feedsModel_->dataField(index, "id").toInt());
2671       int parentId = feedsModel_->dataField(index, "parentId").toInt();
2672       if (!parentIdList.contains(parentId)) {
2673         parentIdList.append(parentId);
2674       }
2675     }
2676     indexList.removeAt(i);
2677   }
2678 
2679   db_.transaction();
2680   QSqlQuery q;
2681   QString idStr;
2682   QString feedIdStr;
2683   foreach (int feedId, idList) {
2684     if (idStr.isEmpty()) {
2685       idStr.append(QString("id='%1'").arg(feedId));
2686       feedIdStr.append(QString("feedId='%1'").arg(feedId));
2687     } else {
2688       idStr.append(QString(" OR id='%1'").arg(feedId));
2689       feedIdStr.append(QString(" OR feedId='%1'").arg(feedId));
2690     }
2691     QQueue<int> parentIds;
2692     parentIds.enqueue(feedId);
2693     while (!parentIds.empty()) {
2694       int parentId = parentIds.dequeue();
2695       q.exec(QString("SELECT id FROM feeds WHERE parentId='%1'").arg(parentId));
2696       while (q.next()) {
2697         int feedId = q.value(0).toInt();
2698 
2699         idStr.append(QString(" OR id='%1'").arg(feedId));
2700         feedIdStr.append(QString(" OR feedId='%1'").arg(feedId));
2701 
2702         parentIds.enqueue(feedId);
2703       }
2704     }
2705   }
2706   q.exec(QString("DELETE FROM feeds WHERE %1").arg(idStr));
2707   q.exec(QString("DELETE FROM news WHERE %1").arg(feedIdStr));
2708   db_.commit();
2709 
2710   // Correction row
2711   foreach (int parentId, parentIdList) {
2712     QList<int> idCorrectList;
2713     q.exec(QString("SELECT id FROM feeds WHERE parentId='%1' ORDER BY rowToParent").
2714            arg(parentId));
2715     while (q.next()) {
2716       idCorrectList << q.value(0).toInt();
2717     }
2718     for (int i = 0; i < idCorrectList.count(); i++) {
2719       q.exec(QString("UPDATE feeds SET rowToParent='%1' WHERE id=='%2'").
2720              arg(i).arg(idCorrectList.at(i)));
2721     }
2722   }
2723 
2724   recountFeedCategories(parentIdList);
2725   feedsModelReload();
2726   currentIndex = feedsProxyModel_->mapFromSource(feedIdCur);
2727   feedsView_->setCurrentIndex(currentIndex);
2728   slotFeedClicked(currentIndex);
2729 
2730   QApplication::restoreOverrideCursor();
2731 }
2732 
2733 /** @brief Import feeds from OPML-file
2734  *
2735  * Calls open file system dialog with filter *.opml.
2736  * Adds all feeds to DB include hierarchy, ignore duplicate feeds
2737  *---------------------------------------------------------------------------*/
slotImportFeeds()2738 void MainWindow::slotImportFeeds()
2739 {
2740   QString fileName = QFileDialog::getOpenFileName(this, tr("Select OPML-File"),
2741                                                   QDir::homePath(),
2742                                                   QString(tr("OPML-Files (*.%1 *.%2)"))
2743                                                   .arg("opml").arg("xml"));
2744 
2745   if (fileName.isNull()) {
2746     statusBar()->showMessage(tr("Import canceled"), 3000);
2747     return;
2748   }
2749 
2750   qDebug() << "import file:" << fileName;
2751 
2752   QFile file(fileName);
2753   if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
2754     statusBar()->showMessage(tr("Import: can't open a file"), 3000);
2755     return;
2756   }
2757 
2758   QByteArray xmlData = file.readAll();
2759   file.close();
2760 
2761   isStartImportFeed_ = true;
2762   emit signalImportFeeds(xmlData);
2763 }
2764 
2765 /** @brief Export feeds to OPML-file
2766  *---------------------------------------------------------------------------*/
slotExportFeeds()2767 void MainWindow::slotExportFeeds()
2768 {
2769   QString fileName = QFileDialog::getSaveFileName(this, tr("Select OPML-File"),
2770                                                   QDir::homePath(),
2771                                                   QString(tr("OPML-Files (*.%1)"))
2772                                                   .arg("opml"));
2773 
2774   if (fileName.isNull()) {
2775     statusBar()->showMessage(tr("Export canceled"), 3000);
2776     return;
2777   }
2778 
2779   QFile file(fileName);
2780   if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
2781     statusBar()->showMessage(tr("Export: can't open a file"), 3000);
2782     return;
2783   }
2784 
2785   QXmlStreamWriter xml(&file);
2786   xml.setAutoFormatting(true);
2787   xml.writeStartDocument();
2788   xml.writeStartElement("opml");
2789   xml.writeAttribute("version", "2.0");
2790   xml.writeStartElement("head");
2791   xml.writeTextElement("title", "QuiteRSS");
2792   xml.writeTextElement("dateModified", QDateTime::currentDateTime().toString());
2793   xml.writeEndElement(); // </head>
2794 
2795   xml.writeStartElement("body");
2796 
2797   // Create model and view for export
2798   // Expand the view to step on every item
2799   FeedsModel exportTreeModel(this);
2800   QTreeView exportTreeView;
2801   exportTreeView.setModel(&exportTreeModel);
2802   exportTreeModel.setView(feedsView_);
2803   exportTreeView.expandAll();
2804 
2805   QModelIndex index = exportTreeModel.index(0, 0);
2806   QStack<int> parentIdsStack;
2807   parentIdsStack.push(0);
2808   while (index.isValid()) {
2809     int feedId = exportTreeModel.idByIndex(index);
2810     int feedParId = exportTreeModel.paridByIndex(index);
2811 
2812     // Parent differs from previouse one - close folder
2813     while (feedParId != parentIdsStack.top()) {
2814       xml.writeEndElement();  // "outline" - folder finishes
2815       parentIdsStack.pop();
2816     }
2817 
2818     // Folder has found. Open it
2819     if (exportTreeModel.isFolder(index)) {
2820       parentIdsStack.push(feedId);
2821       xml.writeStartElement("outline");  // Folder starts
2822       xml.writeAttribute("text", exportTreeModel.dataField(index, "text").toString());
2823     }
2824     // Feed has found. Save it
2825     else {
2826       xml.writeEmptyElement("outline");
2827       xml.writeAttribute("text",    exportTreeModel.dataField(index, "text").toString());
2828       xml.writeAttribute("type",    "rss");
2829       xml.writeAttribute("htmlUrl", exportTreeModel.dataField(index, "htmlUrl").toString());
2830       xml.writeAttribute("xmlUrl",  exportTreeModel.dataField(index, "xmlUrl").toString());
2831     }
2832 
2833     index = exportTreeView.indexBelow(index);
2834   }
2835 
2836   xml.writeEndElement(); // </body>
2837 
2838   xml.writeEndElement(); // </opml>
2839   xml.writeEndDocument();
2840 
2841   file.close();
2842 }
2843 // ----------------------------------------------------------------------------
slotFeedsViewportUpdate()2844 void MainWindow::slotFeedsViewportUpdate()
2845 {
2846   feedsView_->viewport()->update();
2847 #ifdef HAVE_QT5
2848   feedsView_->header()->setSectionResizeMode(feedsView_->columnIndex("unread"), QHeaderView::ResizeToContents);
2849   feedsView_->header()->setSectionResizeMode(feedsView_->columnIndex("undeleteCount"), QHeaderView::ResizeToContents);
2850   feedsView_->header()->setSectionResizeMode(feedsView_->columnIndex("updated"), QHeaderView::ResizeToContents);
2851 #else
2852   feedsView_->header()->setResizeMode(feedsView_->columnIndex("unread"), QHeaderView::ResizeToContents);
2853   feedsView_->header()->setResizeMode(feedsView_->columnIndex("undeleteCount"), QHeaderView::ResizeToContents);
2854   feedsView_->header()->setResizeMode(feedsView_->columnIndex("updated"), QHeaderView::ResizeToContents);
2855 #endif
2856 }
2857 // ----------------------------------------------------------------------------
slotFeedCountsUpdate(FeedCountStruct counts)2858 void MainWindow::slotFeedCountsUpdate(FeedCountStruct counts)
2859 {
2860   QModelIndex index = feedsModel_->indexById(counts.feedId);
2861   if (index.isValid()) {
2862     QModelIndex indexUnread   = feedsModel_->indexSibling(index, "unread");
2863     QModelIndex indexNew      = feedsModel_->indexSibling(index, "newCount");
2864     QModelIndex indexUndelete = feedsModel_->indexSibling(index, "undeleteCount");
2865     feedsModel_->setData(indexUnread, counts.unreadCount);
2866     feedsModel_->setData(indexNew, counts.newCount);
2867     feedsModel_->setData(indexUndelete, counts.undeleteCount);
2868 
2869     if (!counts.updated.isEmpty()) {
2870       QModelIndex indexUpdated  = feedsModel_->indexSibling(index, "updated");
2871       feedsModel_->setData(indexUpdated, counts.updated);
2872     }
2873 
2874     if (!counts.lastBuildDate.isEmpty()) {
2875       QModelIndex indexLastBuildDate = feedsModel_->indexSibling(index, "lastBuildDate");
2876       feedsModel_->setData(indexLastBuildDate, counts.lastBuildDate);
2877     }
2878 
2879     if (!counts.htmlUrl.isEmpty()) {
2880       QModelIndex indexHtmlUrl = feedsModel_->indexSibling(index, "htmlUrl");
2881       feedsModel_->setData(indexHtmlUrl, counts.htmlUrl);
2882     }
2883 
2884     if (!counts.title.isEmpty()) {
2885       QModelIndex indexTitle = feedsModel_->indexSibling(index, "title");
2886       feedsModel_->setData(indexTitle, counts.title);
2887     }
2888   }
2889 
2890   if (isStartImportFeed_ && !counts.xmlUrl.isEmpty()) {
2891     emit faviconRequestUrl(counts.htmlUrl, counts.xmlUrl);
2892   }
2893 }
2894 
2895 /** @brief Recalculate counters for specified categories
2896  * @details Processing DB data. Model "reselect()" needed.
2897  * @param categoriesList - categories identifiers list for processing
2898  *---------------------------------------------------------------------------*/
recountFeedCategories(const QList<int> & categoriesList)2899 void MainWindow::recountFeedCategories(const QList<int> &categoriesList)
2900 {
2901   QSqlQuery q;
2902   QString qStr;
2903 
2904   foreach (int categoryIdStart, categoriesList) {
2905     if (categoryIdStart < 1) continue;
2906 
2907     int categoryId = categoryIdStart;
2908     // Process all parents
2909     while (0 < categoryId) {
2910       int unreadCount = -1;
2911       int undeleteCount = -1;
2912       int newCount = -1;
2913 
2914       // Calculate sum of all feeds with same parent
2915       qStr = QString("SELECT sum(unread), sum(undeleteCount), sum(newCount) "
2916                      "FROM feeds WHERE parentId=='%1'").arg(categoryId);
2917       q.exec(qStr);
2918       if (q.next()) {
2919         unreadCount   = q.value(0).toInt();
2920         undeleteCount = q.value(1).toInt();
2921         newCount = q.value(2).toInt();
2922       }
2923 
2924       if (unreadCount != -1) {
2925         qStr = QString("UPDATE feeds SET unread='%1', undeleteCount='%2', newCount='%3' WHERE id=='%4'").
2926             arg(unreadCount).arg(undeleteCount).arg(newCount).arg(categoryId);
2927         q.exec(qStr);
2928       }
2929 
2930       // go to next parent's parent
2931       qStr = QString("SELECT parentId FROM feeds WHERE id=='%1'").
2932           arg(categoryId);
2933       categoryId = 0;
2934       q.exec(qStr);
2935       if (q.next()) categoryId = q.value(0).toInt();
2936     }
2937   }
2938 }
2939 // ----------------------------------------------------------------------------
recountCategoryCounts()2940 void MainWindow::recountCategoryCounts()
2941 {
2942   if (recountCategoryCountsOn_) return;
2943 
2944   if (!categoriesTree_->isVisible() || !stackedWidget_->count()) return;
2945 
2946   recountCategoryCountsOn_ = true;
2947   emit signalRecountCategoryCounts();
2948 }
2949 
2950 /** @brief Process recalculating categories counters
2951  *----------------------------------------------------------------------------*/
slotRecountCategoryCounts(QList<int> deletedList,QList<int> starredList,QList<int> readList,QStringList labelList)2952 void MainWindow::slotRecountCategoryCounts(QList<int> deletedList, QList<int> starredList,
2953                                            QList<int> readList, QStringList labelList)
2954 {
2955   int allStarredCount = 0;
2956   int unreadStarredCount = 0;
2957   int deletedCount = 0;
2958   QMap<int,int> allCountList;
2959   QMap<int,int> unreadCountList;
2960   int allLabelCount = 0;
2961   int unreadLabelCount = 0;
2962   QFont font;
2963 
2964   QTreeWidgetItem *labelTreeItem = categoriesTree_->topLevelItem(CategoriesTreeWidget::LabelsItem);
2965   for (int i = 0; i < labelTreeItem->childCount(); i++) {
2966     int id = labelTreeItem->child(i)->text(2).toInt();
2967     allCountList.insert(id, 0);
2968     unreadCountList.insert(id, 0);
2969   }
2970 
2971   for (int i = 0; i < deletedList.count(); ++i) {
2972     if (deletedList.at(i) == 0) {
2973       if (starredList.at(i) == 1) {
2974         allStarredCount++;
2975         if (readList.at(i) == 0)
2976           unreadStarredCount++;
2977       }
2978       QString idString = labelList.at(i);
2979       if (!idString.isEmpty() && idString != ",") {
2980         QStringList idList = idString.split(",", QString::SkipEmptyParts);
2981         foreach (QString idStr, idList) {
2982           int id = idStr.toInt();
2983           if (allCountList.contains(id)) {
2984             allCountList[id]++;
2985             if (readList.at(i) == 0)
2986               unreadCountList[id]++;
2987           }
2988         }
2989       }
2990     } else if (deletedList.at(i) == 1) {
2991       deletedCount++;
2992     }
2993   }
2994 
2995   for (int i = 0; i < labelTreeItem->childCount(); i++) {
2996     int id = labelTreeItem->child(i)->text(2).toInt();
2997     QString countStr;
2998     if (!unreadCountList[id] && !allCountList[id])
2999       countStr = "";
3000     else
3001       countStr = QString("(%1/%2)").arg(unreadCountList[id]).arg(allCountList[id]);
3002     labelTreeItem->child(i)->setText(4, countStr);
3003     font = labelTreeItem->child(i)->font(0);
3004     if (unreadCountList[id])
3005       font.setBold(true);
3006     else
3007       font.setBold(false);
3008     labelTreeItem->child(i)->setFont(0, font);
3009 
3010     unreadLabelCount = unreadLabelCount + unreadCountList[id];
3011     allLabelCount = allLabelCount + allCountList[id];
3012   }
3013 
3014   QString countStr;
3015   if (!unreadStarredCount && !allStarredCount)
3016     countStr = "";
3017   else
3018     countStr = QString("(%1/%2)").arg(unreadStarredCount).arg(allStarredCount);
3019   categoriesTree_->topLevelItem(CategoriesTreeWidget::StarredItem)->setText(4, countStr);
3020   font = categoriesTree_->topLevelItem(CategoriesTreeWidget::StarredItem)->font(0);
3021   if (unreadStarredCount)
3022     font.setBold(true);
3023   else
3024     font.setBold(false);
3025   categoriesTree_->topLevelItem(CategoriesTreeWidget::StarredItem)->setFont(0, font);
3026 
3027   if (!deletedCount)
3028     countStr = "";
3029   else
3030     countStr = QString("(%1)").arg(deletedCount);
3031   categoriesTree_->topLevelItem(CategoriesTreeWidget::DeletedItem)->setText(4, countStr);
3032 
3033   if (!unreadLabelCount && !allLabelCount)
3034     countStr = "";
3035   else
3036     countStr = QString("(%1/%2)").arg(unreadLabelCount).arg(allLabelCount);
3037   categoriesTree_->topLevelItem(CategoriesTreeWidget::LabelsItem)->setText(4, countStr);
3038   font = categoriesTree_->topLevelItem(CategoriesTreeWidget::LabelsItem)->font(0);
3039   if (unreadLabelCount)
3040     font.setBold(true);
3041   else
3042     font.setBold(false);
3043   categoriesTree_->topLevelItem(CategoriesTreeWidget::LabelsItem)->setFont(0, font);
3044 
3045   NewsTabWidget *widget = (NewsTabWidget*)stackedWidget_->widget(stackedWidget_->currentIndex());
3046   if ((widget->type_ > NewsTabWidget::TabTypeFeed) && (widget->type_ < NewsTabWidget::TabTypeWeb)
3047       && categoriesTree_->currentIndex().isValid()) {
3048     int unreadCount = widget->getUnreadCount(categoriesTree_->currentItem()->text(4));
3049     int allCount = widget->newsModel_->rowCount();
3050     statusUnread_->setText(QString(" " + tr("Unread: %1") + " ").arg(unreadCount));
3051     statusAll_->setText(QString(" " + tr("All: %1") + " ").arg(allCount));
3052   }
3053 
3054   recountCategoryCountsOn_ = false;
3055 }
3056 
3057 /** @brief Update feed view
3058  *
3059  * Slot is called by UpdateDelayer after some delay
3060  * @param feedId Feed identifier to update
3061  * @param changed Flag indicating that feed is updated indeed
3062  *---------------------------------------------------------------------------*/
slotUpdateFeed(int feedId,bool changed,int newCount,bool finish)3063 void MainWindow::slotUpdateFeed(int feedId, bool changed, int newCount, bool finish)
3064 {
3065   if (finish) {
3066     emit signalShowNotification();
3067     progressBar_->hide();
3068     progressBar_->setMaximum(0);
3069     progressBar_->setValue(0);
3070     isStartImportFeed_ = false;
3071   }
3072 
3073   if (!changed) {
3074     emit signalNextUpdate(finish);
3075     return;
3076   }
3077 
3078   // Action after new news has arrived: tray, sound
3079   if (!isActiveWindow() && (newCount > 0) &&
3080       (behaviorIconTray_ == CHANGE_ICON_TRAY)) {
3081     traySystem->setIcon(QIcon(":/images/quiterss128_NewNews"));
3082   }
3083   emit signalRefreshInfoTray();
3084   if (newCount > 0)
3085     emit signalPlaySoundNewNews();
3086 
3087   // Manage notifications
3088   bool showNotify = true;
3089 
3090   if (showNotifyInactiveApp_)
3091   {
3092     showNotify = !isActiveWindow();
3093   }
3094 
3095   if (!showNotify)
3096   {
3097     clearNotification();
3098   }
3099 
3100   if (newCount > 0)
3101   {
3102     bool bAddRecentNews = !onlySelectedFeeds_ || idFeedsNotifyList_.contains(feedId);
3103     bool bAddNewNews = bAddRecentNews && showNotify;
3104 
3105     if (bAddNewNews)
3106     {
3107       int newFeedIdIndex = newNews.idFeedList_.indexOf(feedId);
3108 
3109       if (-1 < newFeedIdIndex)
3110       {
3111         newNews.cntNewsList_[newFeedIdIndex] = newCount;
3112       }
3113       else
3114       {
3115         newNews.idFeedList_.append(feedId);
3116         newNews.cntNewsList_.append(newCount);
3117       }
3118     }
3119 
3120     if (bAddRecentNews)
3121     {
3122       int recentFeedIdIndex = recentNews.idFeedList_.indexOf(feedId);
3123 
3124       if (-1 < recentFeedIdIndex)
3125       {
3126         recentNews.cntNewsList_[recentFeedIdIndex] += newCount;
3127       }
3128       else
3129       {
3130         recentNews.idFeedList_.append(feedId);
3131         recentNews.cntNewsList_.append(newCount);
3132       }
3133     }
3134   }
3135 
3136   recountCategoryCounts();
3137 
3138   emit signalNextUpdate(finish);
3139 }
3140 
3141 /** @brief Process updating news list
3142  *---------------------------------------------------------------------------*/
slotUpdateNews(int refresh)3143 void MainWindow::slotUpdateNews(int refresh)
3144 {
3145   int newsId = newsModel_->index(
3146         newsView_->currentIndex().row(), newsModel_->fieldIndex("id")).data(Qt::EditRole).toInt();
3147 
3148   newsModel_->select();
3149 
3150   if (newsModel_->rowCount() != 0) {
3151     while (newsModel_->canFetchMore())
3152       newsModel_->fetchMore();
3153   }
3154 
3155   currentNewsTab->loadNewspaper(refresh);
3156 
3157   QModelIndex index = newsModel_->index(0, newsModel_->fieldIndex("id"));
3158   QModelIndexList indexList = newsModel_->match(index, Qt::EditRole, newsId);
3159   if (indexList.count()) {
3160     int newsRow = indexList.first().row();
3161     newsView_->setCurrentIndex(newsModel_->index(newsRow, newsModel_->fieldIndex("title")));
3162   } else {
3163     currentNewsTab->currentNewsIdOld = newsId;
3164     currentNewsTab->hideWebContent();
3165   }
3166 }
3167 
3168 /** @brief Process click in feed tree
3169  *---------------------------------------------------------------------------*/
slotFeedClicked(QModelIndex index)3170 void MainWindow::slotFeedClicked(QModelIndex index)
3171 {
3172   if (feedsView_->selectionModel()->selectedRows(0).count() > 1) return;
3173 
3174   int feedIdCur = feedsModel_->idByIndex(feedsProxyModel_->mapToSource(index));
3175 
3176   if (stackedWidget_->count() && currentNewsTab->type_ < NewsTabWidget::TabTypeWeb) {
3177     currentNewsTab->newsHeader_->saveStateColumns(currentNewsTab);
3178   }
3179 
3180   // Search open tab containing this feed
3181   int indexTab = -1;
3182   for (int i = 0; i < stackedWidget_->count(); i++) {
3183     NewsTabWidget *widget = (NewsTabWidget*)stackedWidget_->widget(i);
3184     if (widget->feedId_ == feedIdCur) {
3185       indexTab = i;
3186       break;
3187     }
3188   }
3189 
3190   if (indexTab == -1) {
3191     if (tabBar_->currentIndex() != TAB_WIDGET_PERMANENT) {
3192       setFeedRead(currentNewsTab->type_, currentNewsTab->feedId_, FeedReadSwitchingTab, currentNewsTab);
3193 
3194       updateCurrentTab_ = false;
3195       tabBar_->setCurrentIndex(TAB_WIDGET_PERMANENT);
3196       updateCurrentTab_ = true;
3197       QModelIndex currentIndex = feedsProxyModel_->mapFromSource(feedIdCur);
3198       feedsView_->setCurrentIndex(currentIndex);
3199 
3200       currentNewsTab = (NewsTabWidget*)stackedWidget_->widget(TAB_WIDGET_PERMANENT);
3201       newsModel_ = currentNewsTab->newsModel_;
3202       newsView_ = currentNewsTab->newsView_;
3203     } else {
3204       if (stackedWidget_->count() && currentNewsTab->type_ != NewsTabWidget::TabTypeFeed) {
3205         setFeedRead(currentNewsTab->type_, currentNewsTab->feedId_, FeedReadSwitchingFeed, currentNewsTab);
3206       } else {
3207         // Mark previous feed Read while switching to another feed
3208         setFeedRead(NewsTabWidget::TabTypeFeed, feedIdOld_, FeedReadSwitchingFeed, 0, feedIdCur);
3209       }
3210 
3211       categoriesTree_->setCurrentIndex(QModelIndex());
3212     }
3213 
3214     slotFeedSelected(feedsModel_->indexById(feedIdCur));
3215     feedsView_->repaint();
3216   } else if (indexTab != -1) {
3217     tabBar_->setCurrentIndex(indexTab);
3218   }
3219   feedIdOld_ = feedIdCur;
3220 }
3221 
3222 /** @brief Process feed choosing
3223  *---------------------------------------------------------------------------*/
slotFeedSelected(QModelIndex index,bool createTab)3224 void MainWindow::slotFeedSelected(QModelIndex index, bool createTab)
3225 {
3226   int feedId = feedsModel_->idByIndex(index);
3227   int feedParId = feedsModel_->paridByIndex(index);
3228 
3229   // Open or create feed tab
3230   if (!stackedWidget_->count() || createTab) {
3231     NewsTabWidget *widget = new NewsTabWidget(this, NewsTabWidget::TabTypeFeed, feedId, feedParId);
3232     int indexTab = addTab(widget);
3233 
3234     createNewsTab(indexTab);
3235 
3236     if (indexTab == 0)
3237       currentNewsTab->closeButton_->setVisible(false);
3238     if (!index.isValid())
3239       currentNewsTab->setVisible(false);
3240 
3241     emit signalSetCurrentTab(indexTab);
3242   } else {
3243     currentNewsTab->type_ = NewsTabWidget::TabTypeFeed;
3244     currentNewsTab->feedId_ = feedId;
3245     currentNewsTab->feedParId_ = feedParId;
3246     currentNewsTab->setSettings(true, false);
3247     currentNewsTab->setVisible(index.isValid());
3248   }
3249   statusUnread_->setVisible(index.isValid());
3250   statusAll_->setVisible(index.isValid());
3251 
3252   // Set icon for tab has opened
3253   bool isFeed = (index.isValid() && feedsModel_->isFolder(index)) ? false : true;
3254 
3255   QPixmap iconTab;
3256   QByteArray byteArray = feedsModel_->dataField(index, "image").toByteArray();
3257   if (!isFeed) {
3258     iconTab.load(":/images/folder");
3259   } else {
3260     if (byteArray.isNull() || defaultIconFeeds_) {
3261       iconTab.load(":/images/feed");
3262     } else if (isFeed) {
3263       iconTab.loadFromData(QByteArray::fromBase64(byteArray));
3264     }
3265   }
3266   currentNewsTab->newsIconTitle_->setPixmap(iconTab);
3267 
3268   // Set title for tab has opened
3269   currentNewsTab->setTextTab(feedsModel_->dataField(index, "text").toString());
3270 
3271   feedProperties_->setEnabled(index.isValid());
3272 
3273   setNewsFilter(newsFilterGroup_->checkedAction(), false);
3274 
3275   // Search feed news that displayed before
3276   int newsRow = -1;
3277   if (openingFeedAction_ == 0) {
3278     QModelIndex feedIndex = feedsModel_->indexById(feedId);
3279     int newsIdCur = feedsModel_->dataField(feedIndex, "currentNews").toInt();
3280     QModelIndex index = newsModel_->index(0, newsModel_->fieldIndex("id"));
3281     QModelIndexList indexList = newsModel_->match(index, Qt::EditRole, newsIdCur);
3282 
3283     if (!indexList.isEmpty()) newsRow = indexList.first().row();
3284   } else if (openingFeedAction_ == 1) {
3285     newsRow = 0;
3286   } else if ((openingFeedAction_ == 3) || (openingFeedAction_ == 4)) {
3287     QModelIndex index = newsModel_->index(0, newsModel_->fieldIndex("read"));
3288     QModelIndexList indexList;
3289     if ((newsView_->header()->sortIndicatorOrder() == Qt::DescendingOrder) &&
3290         (openingFeedAction_ != 4))
3291       indexList = newsModel_->match(index, Qt::EditRole, 0, -1);
3292     else
3293       indexList = newsModel_->match(index, Qt::EditRole, 0);
3294 
3295     if (!indexList.isEmpty()) newsRow = indexList.last().row();
3296   }
3297 
3298   // Focus feed news that displayed before
3299   newsView_->setCurrentIndex(newsModel_->index(newsRow, newsModel_->fieldIndex("title")));
3300   if (newsRow == -1) newsView_->verticalScrollBar()->setValue(newsRow);
3301 
3302   if ((openingFeedAction_ != 2) && openNewsWebViewOn_) {
3303     currentNewsTab->slotNewsViewSelected(newsModel_->index(newsRow, newsModel_->fieldIndex("title")));
3304   } else {
3305     currentNewsTab->slotNewsViewSelected(newsModel_->index(-1, newsModel_->fieldIndex("title")));
3306     int newsId = newsModel_->index(newsRow, newsModel_->fieldIndex("id")).data(Qt::EditRole).toInt();
3307     QString qStr = QString("UPDATE feeds SET currentNews='%1' WHERE id=='%2'").arg(newsId).arg(feedId);
3308     mainApp->sqlQueryExec(qStr);
3309     QModelIndex feedIndex = feedsModel_->indexById(feedId);
3310     feedsModel_->setData(feedsModel_->indexSibling(feedIndex, "currentNews"), newsId);
3311   }
3312 }
3313 
3314 // ----------------------------------------------------------------------------
showOptionDlg(int index)3315 void MainWindow::showOptionDlg(int index)
3316 {
3317   static int pageIndex = 0;
3318   Settings settings;
3319 
3320   if (index != -1) pageIndex = index;
3321 
3322   if (optionsDialog_) {
3323     optionsDialog_->activateWindow();
3324     return;
3325   }
3326 
3327   optionsDialog_ = new OptionsDialog(this);
3328 
3329   settings.beginGroup("Settings");
3330   bool updateFeedsStartUp = settings.value("autoUpdatefeedsStartUp", false).toBool();
3331   settings.endGroup();
3332 
3333   optionsDialog_->showSplashScreen_->setChecked(showSplashScreen_);
3334   optionsDialog_->reopenFeedStartup_->setChecked(reopenFeedStartup_);
3335   optionsDialog_->openNewTabNextToActive_->setChecked(openNewTabNextToActive_);
3336   optionsDialog_->hideFeedsOpenTab_->setChecked(hideFeedsOpenTab_);
3337   optionsDialog_->showToggleFeedsTree_->setChecked(showToggleFeedsTree_);
3338   optionsDialog_->defaultIconFeeds_->setChecked(defaultIconFeeds_);
3339   optionsDialog_->autocollapseFolder_->setChecked(feedsView_->autocollapseFolder_);
3340   bool showCloseButtonTab = settings.value("Settings/showCloseButtonTab", true).toBool();
3341   optionsDialog_->showCloseButtonTab_->setChecked(showCloseButtonTab);
3342 
3343   bool updateCheckEnabled = settings.value("Settings/updateCheckEnabled", true).toBool();
3344   optionsDialog_->updateCheckEnabled_->setChecked(updateCheckEnabled);
3345   bool statisticsEnabled = settings.value("Settings/statisticsEnabled2", true).toBool();
3346   optionsDialog_->statisticsEnabled_->setChecked(statisticsEnabled);
3347 
3348   bool storeDBMemory_ = settings.value("Settings/storeDBMemory", true).toBool();
3349   optionsDialog_->storeDBMemory_->setChecked(storeDBMemory_);
3350   int saveDBMemFileInterval = settings.value("Settings/saveDBMemFileInterval", 30).toInt();
3351   optionsDialog_->saveDBMemFileInterval_->setValue(saveDBMemFileInterval);
3352 
3353   optionsDialog_->showTrayIconBox_->setChecked(showTrayIcon_);
3354   optionsDialog_->startingTray_->setChecked(startingTray_);
3355   optionsDialog_->minimizingTray_->setChecked(minimizingTray_);
3356   optionsDialog_->closingTray_->setChecked(closingTray_);
3357   optionsDialog_->setBehaviorIconTray(behaviorIconTray_);
3358   optionsDialog_->singleClickTray_->setChecked(singleClickTray_);
3359   optionsDialog_->clearStatusNew_->setChecked(clearStatusNew_);
3360   optionsDialog_->emptyWorking_->setChecked(emptyWorking_);
3361 
3362   optionsDialog_->setProxy(mainApp->networkProxy());
3363 
3364   int timeoutRequest = settings.value("Settings/timeoutRequest", 15).toInt();
3365   int numberRequests = settings.value("Settings/numberRequest", 10).toInt();
3366   int numberRepeats = settings.value("Settings/numberRepeats", 2).toInt();
3367   optionsDialog_->timeoutRequest_->setValue(timeoutRequest);
3368   optionsDialog_->numberRequests_->setValue(numberRequests);
3369   optionsDialog_->numberRepeats_->setValue(numberRepeats);
3370 
3371   optionsDialog_->embeddedBrowserOn_->setChecked(externalBrowserOn_ <= 0);
3372   optionsDialog_->externalBrowserOn_->setChecked(externalBrowserOn_ >= 1);
3373   optionsDialog_->defaultExternalBrowserOn_->setChecked((externalBrowserOn_ == 0) ||
3374                                                         (externalBrowserOn_ == 1));
3375   optionsDialog_->otherExternalBrowserOn_->setChecked((externalBrowserOn_ == -1) ||
3376                                                       (externalBrowserOn_ == 2));
3377   optionsDialog_->otherExternalBrowserEdit_->setText(externalBrowser_);
3378   optionsDialog_->autoLoadImages_->setChecked(autoLoadImages_);
3379   optionsDialog_->javaScriptEnable_->setChecked(javaScriptEnable_);
3380   optionsDialog_->pluginsEnable_->setChecked(pluginsEnable_);
3381   optionsDialog_->defaultZoomPages_->setValue(defaultZoomPages_);
3382   optionsDialog_->openLinkInBackground_->setChecked(openLinkInBackground_);
3383   optionsDialog_->openLinkInBackgroundEmbedded_->setChecked(openLinkInBackgroundEmbedded_);
3384   optionsDialog_->maxPagesInCache_->setValue(maxPagesInCache_);
3385 
3386   settings.beginGroup("Settings");
3387 
3388   QString userStyleBrowser = settings.value("userStyleBrowser", QString()).toString();
3389   optionsDialog_->userStyleBrowserEdit_->setText(userStyleBrowser);
3390 
3391   bool useDiskCache = settings.value("useDiskCache", true).toBool();
3392   optionsDialog_->diskCacheOn_->setChecked(useDiskCache);
3393   QString diskCacheDir = settings.value("dirDiskCache", mainApp->cacheDefaultDir()).toString();
3394   if (diskCacheDir.isEmpty()) diskCacheDir = mainApp->cacheDefaultDir();
3395   optionsDialog_->dirDiskCacheEdit_->setText(diskCacheDir);
3396   int maxDiskCache = settings.value("maxDiskCache", 50).toInt();
3397   optionsDialog_->maxDiskCache_->setValue(maxDiskCache);
3398 
3399   settings.endGroup();
3400 
3401   UseCookies useCookies = mainApp->cookieJar()->useCookies();
3402   optionsDialog_->saveCookies_->setChecked(useCookies == SaveCookies);
3403   optionsDialog_->deleteCookiesOnClose_->setChecked(useCookies == DeleteCookiesOnClose);
3404   optionsDialog_->blockCookies_->setChecked(useCookies == BlockCookies);
3405 
3406   optionsDialog_->downloadLocationEdit_->setText(downloadLocation_);
3407   optionsDialog_->askDownloadLocation_->setChecked(askDownloadLocation_);
3408 
3409   optionsDialog_->updateFeedsStartUp_->setChecked(updateFeedsStartUp);
3410   optionsDialog_->updateFeedsEnable_->setChecked(updateFeedsEnable_);
3411   optionsDialog_->updateIntervalType_->setCurrentIndex(updateFeedsIntervalType_+1);
3412   optionsDialog_->updateFeedsInterval_->setValue(updateFeedsInterval_);
3413 
3414   optionsDialog_->setOpeningFeed(openingFeedAction_);
3415   optionsDialog_->openNewsWebViewOn_->setChecked(openNewsWebViewOn_);
3416 
3417   optionsDialog_->markNewsReadOn_->setChecked(markNewsReadOn_);
3418   optionsDialog_->markCurNewsRead_->setChecked(markCurNewsRead_);
3419   optionsDialog_->markNewsReadTime_->setValue(markNewsReadTime_);
3420   optionsDialog_->markPrevNewsRead_->setChecked(markPrevNewsRead_);
3421   optionsDialog_->markReadSwitchingFeed_->setChecked(markReadSwitchingFeed_);
3422   optionsDialog_->markReadClosingTab_->setChecked(markReadClosingTab_);
3423   optionsDialog_->markReadMinimize_->setChecked(markReadMinimize_);
3424 
3425   optionsDialog_->showDescriptionNews_->setChecked(showDescriptionNews_);
3426 
3427   for (int i = 0; i < optionsDialog_->formatDate_->count(); i++) {
3428     if (optionsDialog_->formatDate_->itemData(i).toString() == formatDate_) {
3429       optionsDialog_->formatDate_->setCurrentIndex(i);
3430       break;
3431     }
3432   }
3433   for (int i = 0; i < optionsDialog_->formatTime_->count(); i++) {
3434     if (optionsDialog_->formatTime_->itemData(i).toString() == formatTime_) {
3435       optionsDialog_->formatTime_->setCurrentIndex(i);
3436       break;
3437     }
3438   }
3439 
3440   optionsDialog_->alternatingRowColorsNews_->setChecked(alternatingRowColorsNews_);
3441   optionsDialog_->changeBehaviorActionNUN_->setChecked(changeBehaviorActionNUN_);
3442   optionsDialog_->simplifiedDateTime_->setChecked(simplifiedDateTime_);
3443   optionsDialog_->notDeleteStarred_->setChecked(notDeleteStarred_);
3444   optionsDialog_->notDeleteLabeled_->setChecked(notDeleteLabeled_);
3445   optionsDialog_->markIdenticalNewsRead_->setChecked(markIdenticalNewsRead_);
3446   optionsDialog_->avoidedOldNewsDateOn_->setChecked(avoidOldNews_);
3447 
3448   if (!avoidedOldNewsDate_.isNull() && avoidedOldNewsDate_.isValid()) {
3449     optionsDialog_->avoidedOldNewsDate_->setSelectedDate(avoidedOldNewsDate_);
3450   } else {
3451     optionsDialog_->avoidedOldNewsDate_->setSelectedDate(QDate::currentDate());
3452   }
3453 
3454   for (int i = 0; i < optionsDialog_->mainNewsFilter_->count(); i++) {
3455     if (optionsDialog_->mainNewsFilter_->itemData(i).toString() == mainNewsFilter_) {
3456       optionsDialog_->mainNewsFilter_->setCurrentIndex(i);
3457       break;
3458     }
3459   }
3460 
3461   QString styleSheetNews = settings.value("Settings/styleSheetNews",
3462                                           mainApp->styleSheetNewsDefaultFile()).toString();
3463   optionsDialog_->styleSheetNewsEdit_->setText(styleSheetNews);
3464 
3465   optionsDialog_->cleanupOnShutdownBox_->setChecked(cleanupOnShutdown_);
3466   optionsDialog_->dayCleanUpOn_->setChecked(dayCleanUpOn_);
3467   optionsDialog_->maxDayCleanUp_->setValue(maxDayCleanUp_);
3468   optionsDialog_->newsCleanUpOn_->setChecked(newsCleanUpOn_);
3469   optionsDialog_->maxNewsCleanUp_->setValue(maxNewsCleanUp_);
3470   optionsDialog_->readCleanUp_->setChecked(readCleanUp_);
3471   optionsDialog_->neverUnreadCleanUp_->setChecked(neverUnreadCleanUp_);
3472   optionsDialog_->neverStarCleanUp_->setChecked(neverStarCleanUp_);
3473   optionsDialog_->neverLabelCleanUp_->setChecked(neverLabelCleanUp_);
3474   optionsDialog_->cleanUpDeleted_->setChecked(cleanUpDeleted_);
3475   optionsDialog_->optimizeDB_->setChecked(optimizeDB_);
3476 
3477   optionsDialog_->soundNotifyBox_->setChecked(soundNewNews_);
3478   optionsDialog_->editSoundNotifer_->setText(soundNotifyPath_);
3479   optionsDialog_->showNotifyOn_->setChecked(showNotifyOn_);
3480   optionsDialog_->screenNotify_->setCurrentIndex(screenNotify_+1);
3481   optionsDialog_->positionNotify_->setCurrentIndex(positionNotify_);
3482   optionsDialog_->transparencyNotify_->setValue(transparencyNotify_);
3483   optionsDialog_->countShowNewsNotify_->setValue(countShowNewsNotify_);
3484   optionsDialog_->widthTitleNewsNotify_->setValue(widthTitleNewsNotify_);
3485   optionsDialog_->timeShowNewsNotify_->setValue(timeShowNewsNotify_);
3486   optionsDialog_->fullscreenModeNotify_->setChecked(fullscreenModeNotify_);
3487   optionsDialog_->showNotifyInactiveApp_->setChecked(showNotifyInactiveApp_);
3488   optionsDialog_->onlySelectedFeeds_->setChecked(onlySelectedFeeds_);
3489   optionsDialog_->showTitlesFeedsNotify_->setChecked(showTitlesFeedsNotify_);
3490   optionsDialog_->showIconFeedNotify_->setChecked(showIconFeedNotify_);
3491   optionsDialog_->showButtonMarkAllNotify_->setChecked(showButtonMarkAllNotify_);
3492   optionsDialog_->showButtonMarkReadNotify_->setChecked(showButtonMarkReadNotify_);
3493   optionsDialog_->showButtonExBrowserNotify_->setChecked(showButtonExBrowserNotify_);
3494   optionsDialog_->showButtonDeleteNotify_->setChecked(showButtonDeleteNotify_);
3495   optionsDialog_->closeNotify_->setChecked(closeNotify_);
3496 
3497   optionsDialog_->setLanguage(mainApp->language());
3498 
3499   QString strFont = QString("%1, %2").
3500       arg(feedsView_->font().family()).
3501       arg(feedsView_->font().pointSize());
3502   optionsDialog_->fontsTree_->topLevelItem(0)->setText(2, strFont);
3503   strFont = QString("%1, %2").arg(newsListFontFamily_).arg(newsListFontSize_);
3504   optionsDialog_->fontsTree_->topLevelItem(1)->setText(2, strFont);
3505   strFont = QString("%1, %2").arg(newsTitleFontFamily_).arg(newsTitleFontSize_);
3506   optionsDialog_->fontsTree_->topLevelItem(2)->setText(2, strFont);
3507   strFont = QString("%1, %2").arg(newsTextFontFamily_).arg(newsTextFontSize_);
3508   optionsDialog_->fontsTree_->topLevelItem(3)->setText(2, strFont);
3509   strFont = QString("%1, %2").arg(notificationFontFamily_).arg(notificationFontSize_);
3510   optionsDialog_->fontsTree_->topLevelItem(4)->setText(2, strFont);
3511 
3512   settings.beginGroup("Settings");
3513   QString browserStandardFont = settings.value(
3514         "browserStandardFont", QWebSettings::globalSettings()->fontFamily(QWebSettings::StandardFont)).toString();
3515   QString browserFixedFont = settings.value(
3516         "browserFixedFont", QWebSettings::globalSettings()->fontFamily(QWebSettings::FixedFont)).toString();
3517   QString browserSerifFont = settings.value(
3518         "browserSerifFont", QWebSettings::globalSettings()->fontFamily(QWebSettings::SerifFont)).toString();
3519   QString browserSansSerifFont = settings.value(
3520         "browserSansSerifFont", QWebSettings::globalSettings()->fontFamily(QWebSettings::SansSerifFont)).toString();
3521   QString browserCursiveFont = settings.value(
3522         "browserCursiveFont", QWebSettings::globalSettings()->fontFamily(QWebSettings::CursiveFont)).toString();
3523   QString browserFantasyFont = settings.value(
3524         "browserFantasyFont", QWebSettings::globalSettings()->fontFamily(QWebSettings::FantasyFont)).toString();
3525   int browserDefaultFontSize = settings.value(
3526         "browserDefaultFontSize", QWebSettings::globalSettings()->fontSize(QWebSettings::DefaultFontSize)).toInt();
3527   int browserFixedFontSize = settings.value(
3528         "browserFixedFontSize", QWebSettings::globalSettings()->fontSize(QWebSettings::DefaultFixedFontSize)).toInt();
3529   int browserMinFontSize = settings.value(
3530         "browserMinFontSize", QWebSettings::globalSettings()->fontSize(QWebSettings::MinimumFontSize)).toInt();
3531   int browserMinLogFontSize = settings.value(
3532         "browserMinLogFontSize", QWebSettings::globalSettings()->fontSize(QWebSettings::MinimumLogicalFontSize)).toInt();
3533   settings.endGroup();
3534 
3535   optionsDialog_->browserStandardFont_->setCurrentFont(QFont(browserStandardFont));
3536   optionsDialog_->browserFixedFont_->setCurrentFont(QFont(browserFixedFont));
3537   optionsDialog_->browserSerifFont_->setCurrentFont(QFont(browserSerifFont));
3538   optionsDialog_->browserSansSerifFont_->setCurrentFont(QFont(browserSansSerifFont));
3539   optionsDialog_->browserCursiveFont_->setCurrentFont(QFont(browserCursiveFont));
3540   optionsDialog_->browserFantasyFont_->setCurrentFont(QFont(browserFantasyFont));
3541   optionsDialog_->browserDefaultFontSize_->setValue(browserDefaultFontSize);
3542   optionsDialog_->browserFixedFontSize_->setValue(browserFixedFontSize);
3543   optionsDialog_->browserMinFontSize_->setValue(browserMinFontSize);
3544   optionsDialog_->browserMinLogFontSize_->setValue(browserMinLogFontSize);
3545 
3546   QPixmap pixmapColor(14, 14);
3547   pixmapColor.fill(feedsModel_->textColor_);
3548   optionsDialog_->colorsTree_->topLevelItem(0)->setIcon(0, pixmapColor);
3549   optionsDialog_->colorsTree_->topLevelItem(0)->setText(1, feedsModel_->textColor_);
3550   if (feedsModel_->backgroundColor_.isEmpty())
3551     pixmapColor.fill(QColor(0, 0, 0, 0));
3552   else
3553     pixmapColor.fill(feedsModel_->backgroundColor_);
3554   optionsDialog_->colorsTree_->topLevelItem(1)->setIcon(0, pixmapColor);
3555   optionsDialog_->colorsTree_->topLevelItem(1)->setText(1, feedsModel_->backgroundColor_);
3556   pixmapColor.fill(newsListTextColor_);
3557   optionsDialog_->colorsTree_->topLevelItem(2)->setIcon(0, pixmapColor);
3558   optionsDialog_->colorsTree_->topLevelItem(2)->setText(1, newsListTextColor_);
3559 
3560   if (newsListBackgroundColor_.isEmpty())
3561     pixmapColor.fill(QColor(0, 0, 0, 0));
3562   else
3563     pixmapColor.fill(newsListBackgroundColor_);
3564   optionsDialog_->colorsTree_->topLevelItem(3)->setIcon(0, pixmapColor);
3565   optionsDialog_->colorsTree_->topLevelItem(3)->setText(1, newsListBackgroundColor_);
3566   pixmapColor.fill(focusedNewsTextColor_);
3567   optionsDialog_->colorsTree_->topLevelItem(4)->setIcon(0, pixmapColor);
3568   optionsDialog_->colorsTree_->topLevelItem(4)->setText(1, focusedNewsTextColor_);
3569   if (focusedNewsBGColor_.isEmpty())
3570     pixmapColor.fill(QColor(0, 0, 0, 0));
3571   else
3572     pixmapColor.fill(focusedNewsBGColor_);
3573   optionsDialog_->colorsTree_->topLevelItem(5)->setIcon(0, pixmapColor);
3574   optionsDialog_->colorsTree_->topLevelItem(5)->setText(1, focusedNewsBGColor_);
3575   pixmapColor.fill(linkColor_);
3576   optionsDialog_->colorsTree_->topLevelItem(6)->setIcon(0, pixmapColor);
3577   optionsDialog_->colorsTree_->topLevelItem(6)->setText(1, linkColor_);
3578   pixmapColor.fill(titleColor_);
3579   optionsDialog_->colorsTree_->topLevelItem(7)->setIcon(0, pixmapColor);
3580   optionsDialog_->colorsTree_->topLevelItem(7)->setText(1, titleColor_);
3581   pixmapColor.fill(dateColor_);
3582   optionsDialog_->colorsTree_->topLevelItem(8)->setIcon(0, pixmapColor);
3583   optionsDialog_->colorsTree_->topLevelItem(8)->setText(1, dateColor_);
3584   pixmapColor.fill(authorColor_);
3585   optionsDialog_->colorsTree_->topLevelItem(9)->setIcon(0, pixmapColor);
3586   optionsDialog_->colorsTree_->topLevelItem(9)->setText(1, authorColor_);
3587   pixmapColor.fill(newsTextColor_);
3588   optionsDialog_->colorsTree_->topLevelItem(10)->setIcon(0, pixmapColor);
3589   optionsDialog_->colorsTree_->topLevelItem(10)->setText(1, newsTextColor_);
3590   pixmapColor.fill(newsTitleBackgroundColor_);
3591   optionsDialog_->colorsTree_->topLevelItem(11)->setIcon(0, pixmapColor);
3592   optionsDialog_->colorsTree_->topLevelItem(11)->setText(1, newsTitleBackgroundColor_);
3593   pixmapColor.fill(newsBackgroundColor_);
3594   optionsDialog_->colorsTree_->topLevelItem(12)->setIcon(0, pixmapColor);
3595   optionsDialog_->colorsTree_->topLevelItem(12)->setText(1, newsBackgroundColor_);
3596   pixmapColor.fill(feedsModel_->feedWithNewNewsColor_);
3597   optionsDialog_->colorsTree_->topLevelItem(13)->setIcon(0, pixmapColor);
3598   optionsDialog_->colorsTree_->topLevelItem(13)->setText(1, feedsModel_->feedWithNewNewsColor_);
3599   pixmapColor.fill(feedsModel_->countNewsUnreadColor_);
3600   optionsDialog_->colorsTree_->topLevelItem(14)->setIcon(0, pixmapColor);
3601   optionsDialog_->colorsTree_->topLevelItem(14)->setText(1, feedsModel_->countNewsUnreadColor_);
3602 
3603   pixmapColor.fill(newNewsTextColor_);
3604   optionsDialog_->colorsTree_->topLevelItem(15)->setIcon(0, pixmapColor);
3605   optionsDialog_->colorsTree_->topLevelItem(15)->setText(1, newNewsTextColor_);
3606   pixmapColor.fill(unreadNewsTextColor_);
3607   optionsDialog_->colorsTree_->topLevelItem(16)->setIcon(0, pixmapColor);
3608   optionsDialog_->colorsTree_->topLevelItem(16)->setText(1, unreadNewsTextColor_);
3609 
3610   pixmapColor.fill(feedsModel_->focusedFeedTextColor_);
3611   optionsDialog_->colorsTree_->topLevelItem(17)->setIcon(0, pixmapColor);
3612   optionsDialog_->colorsTree_->topLevelItem(17)->setText(1, feedsModel_->focusedFeedTextColor_);
3613   if (feedsModel_->focusedFeedBGColor_.isEmpty())
3614     pixmapColor.fill(QColor(0, 0, 0, 0));
3615   else
3616     pixmapColor.fill(feedsModel_->focusedFeedBGColor_);
3617   optionsDialog_->colorsTree_->topLevelItem(18)->setIcon(0, pixmapColor);
3618   optionsDialog_->colorsTree_->topLevelItem(18)->setText(1, feedsModel_->focusedFeedBGColor_);
3619   pixmapColor.fill(feedsModel_->feedDisabledUpdateColor_);
3620   optionsDialog_->colorsTree_->topLevelItem(19)->setIcon(0, pixmapColor);
3621   optionsDialog_->colorsTree_->topLevelItem(19)->setText(1, feedsModel_->feedDisabledUpdateColor_);
3622 
3623   pixmapColor.fill(alternatingRowColors_);
3624   optionsDialog_->colorsTree_->topLevelItem(20)->setIcon(0, pixmapColor);
3625   optionsDialog_->colorsTree_->topLevelItem(20)->setText(1, alternatingRowColors_);
3626 
3627   pixmapColor.fill(notifierTextColor_);
3628   optionsDialog_->colorsTree_->topLevelItem(21)->setIcon(0, pixmapColor);
3629   optionsDialog_->colorsTree_->topLevelItem(21)->setText(1, notifierTextColor_);
3630   pixmapColor.fill(notifierBackgroundColor_);
3631   optionsDialog_->colorsTree_->topLevelItem(22)->setIcon(0, pixmapColor);
3632   optionsDialog_->colorsTree_->topLevelItem(22)->setText(1, notifierBackgroundColor_);
3633 
3634   NewsTabWidget *widget = (NewsTabWidget*)stackedWidget_->widget(TAB_WIDGET_PERMANENT);
3635   backWebPageAct_->setText(widget->webView_->page()->action(QWebPage::Back)->text());
3636   backWebPageAct_->setToolTip(widget->webView_->page()->action(QWebPage::Back)->toolTip() + " " + tr("(Browser)"));
3637   backWebPageAct_->setIcon(widget->webView_->page()->action(QWebPage::Back)->icon());
3638   backWebPageAct_->setShortcut(widget->webView_->page()->action(QWebPage::Back)->shortcut());
3639 
3640   forwardWebPageAct_->setText(widget->webView_->page()->action(QWebPage::Forward)->text());
3641   forwardWebPageAct_->setToolTip(widget->webView_->page()->action(QWebPage::Forward)->toolTip() + " " + tr("(Browser)"));
3642   forwardWebPageAct_->setIcon(widget->webView_->page()->action(QWebPage::Forward)->icon());
3643   forwardWebPageAct_->setShortcut(widget->webView_->page()->action(QWebPage::Forward)->shortcut());
3644 
3645   reloadWebPageAct_->setText(widget->webView_->page()->action(QWebPage::Reload)->text());
3646   reloadWebPageAct_->setToolTip(widget->webView_->page()->action(QWebPage::Reload)->toolTip() + " " + tr("(Browser)"));
3647   reloadWebPageAct_->setIcon(widget->webView_->page()->action(QWebPage::Reload)->icon());
3648   reloadWebPageAct_->setShortcut(widget->webView_->page()->action(QWebPage::Reload)->shortcut());
3649 
3650   optionsDialog_->loadActionShortcut(listActions_, &listDefaultShortcut_);
3651 
3652   // Display setting dialog
3653 
3654   optionsDialog_->setCurrentItem(pageIndex);
3655   int result = optionsDialog_->exec();
3656   pageIndex = optionsDialog_->currentIndex();
3657 
3658   if (result == QDialog::Rejected) {
3659     delete optionsDialog_;
3660     optionsDialog_ = NULL;
3661     return;
3662   }
3663 
3664   // Apply accepted settings
3665 
3666   foreach (QAction *action, listActions_) {
3667     QString objectName = action->objectName();
3668     if (objectName.contains("labelAction_")) {
3669       listActions_.removeOne(action);
3670       delete action;
3671     }
3672   }
3673   optionsDialog_->saveActionShortcut(listActions_, newsLabelGroup_);
3674   listActions_.append(newsLabelGroup_->actions());
3675   newsLabelMenu_->addActions(newsLabelGroup_->actions());
3676   this->addActions(newsLabelGroup_->actions());
3677   if (newsLabelGroup_->actions().count()) {
3678     newsLabelAction_->setIcon(newsLabelGroup_->actions().at(0)->icon());
3679     newsLabelAction_->setToolTip(newsLabelGroup_->actions().at(0)->text());
3680     newsLabelAction_->setData(newsLabelGroup_->actions().at(0)->data());
3681   }
3682 
3683   if (optionsDialog_->idLabels_.count()) {
3684     QTreeWidgetItem *labelTreeItem = categoriesTree_->topLevelItem(CategoriesTreeWidget::LabelsItem);
3685     while (labelTreeItem->childCount()) {
3686       labelTreeItem->removeChild(labelTreeItem->child(0));
3687     }
3688 
3689     bool closeTab = true;
3690     int indexTab = -1;
3691     int tabLabelId = -1;
3692     for (int i = 0; i < stackedWidget_->count(); i++) {
3693       NewsTabWidget *widget = (NewsTabWidget*)stackedWidget_->widget(i);
3694       if (widget->type_ == NewsTabWidget::TabTypeLabel) {
3695         indexTab = i;
3696         tabLabelId = widget->labelId_;
3697         break;
3698       }
3699     }
3700 
3701     QSqlQuery q;
3702     q.exec("SELECT id, name, image, currentNews, num, color_bg, color_text FROM labels ORDER BY num");
3703     while (q.next()) {
3704       int idLabel = q.value(0).toInt();
3705       QString nameLabel = q.value(1).toString();
3706       QByteArray byteArray = q.value(2).toByteArray();
3707       QString currentNews = q.value(3).toString();
3708       QPixmap imageLabel;
3709       if (!byteArray.isNull())
3710         imageLabel.loadFromData(byteArray);
3711       QStringList dataItem;
3712       dataItem << nameLabel << QString::number(NewsTabWidget::TabTypeLabel)
3713                << QString::number(idLabel) << currentNews;
3714       QTreeWidgetItem *childItem = new QTreeWidgetItem(dataItem);
3715       childItem->setIcon(0, QIcon(imageLabel));
3716       childItem->setData(0, CategoriesTreeWidget::ImageRole, q.value(2));
3717       childItem->setData(0, CategoriesTreeWidget::NumRole, q.value(4));
3718       childItem->setData(0, CategoriesTreeWidget::colorBgRole, q.value(5));
3719       childItem->setData(0, CategoriesTreeWidget::colorTextRole, q.value(6));
3720       labelTreeItem->addChild(childItem);
3721 
3722       if (idLabel == tabLabelId) {
3723         closeTab = false;
3724         NewsTabWidget *widget = (NewsTabWidget*)stackedWidget_->widget(indexTab);
3725         // Set icon and title for tab has opened
3726         widget->newsIconTitle_->setPixmap(imageLabel);
3727         widget->setTextTab(nameLabel);
3728       }
3729     }
3730 
3731     if (closeTab && (indexTab > 0) && (tabLabelId > 0)) {
3732       slotCloseTab(indexTab);
3733     }
3734     if ((tabBar_->currentIndex() == indexTab) && (indexTab > 0) && (tabLabelId == 0)) {
3735       slotUpdateNews(NewsTabWidget::RefreshWithPos);
3736     }
3737   }
3738 
3739   showSplashScreen_ = optionsDialog_->showSplashScreen_->isChecked();
3740   reopenFeedStartup_ = optionsDialog_->reopenFeedStartup_->isChecked();
3741   openNewTabNextToActive_ = optionsDialog_->openNewTabNextToActive_->isChecked();
3742   hideFeedsOpenTab_ = optionsDialog_->hideFeedsOpenTab_->isChecked();
3743   showToggleFeedsTree_ = optionsDialog_->showToggleFeedsTree_->isChecked();
3744   defaultIconFeeds_ = optionsDialog_->defaultIconFeeds_->isChecked();
3745   feedsModel_->defaultIconFeeds_ = defaultIconFeeds_;
3746   feedsView_->autocollapseFolder_ = optionsDialog_->autocollapseFolder_->isChecked();
3747 
3748   showCloseButtonTab = optionsDialog_->showCloseButtonTab_->isChecked();
3749   settings.setValue("Settings/showCloseButtonTab", showCloseButtonTab);
3750 
3751   pushButtonNull_->setVisible(showToggleFeedsTree_);
3752 
3753   updateCheckEnabled = optionsDialog_->updateCheckEnabled_->isChecked();
3754   settings.setValue("Settings/updateCheckEnabled", updateCheckEnabled);
3755   statisticsEnabled = optionsDialog_->statisticsEnabled_->isChecked();
3756   settings.setValue("Settings/statisticsEnabled2", statisticsEnabled);
3757 
3758   storeDBMemory_ = optionsDialog_->storeDBMemory_->isChecked();
3759   settings.setValue("Settings/storeDBMemory", storeDBMemory_);
3760   if (saveDBMemFileInterval != optionsDialog_->saveDBMemFileInterval_->value()) {
3761     saveDBMemFileInterval = optionsDialog_->saveDBMemFileInterval_->value();
3762     settings.setValue("Settings/saveDBMemFileInterval", saveDBMemFileInterval);
3763     mainApp->updateFeeds()->startSaveTimer();
3764   }
3765 
3766   showTrayIcon_ = optionsDialog_->showTrayIconBox_->isChecked();
3767   startingTray_ = optionsDialog_->startingTray_->isChecked();
3768   minimizingTray_ = optionsDialog_->minimizingTray_->isChecked();
3769   closingTray_ = optionsDialog_->closingTray_->isChecked();
3770   behaviorIconTray_ = optionsDialog_->behaviorIconTray();
3771   if (behaviorIconTray_ > CHANGE_ICON_TRAY) {
3772     emit signalRefreshInfoTray();
3773   } else {
3774     traySystem->setIcon(QIcon(":/images/quiterss128"));
3775   }
3776   singleClickTray_ = optionsDialog_->singleClickTray_->isChecked();
3777   clearStatusNew_ = optionsDialog_->clearStatusNew_->isChecked();
3778   emptyWorking_ = optionsDialog_->emptyWorking_->isChecked();
3779   if (showTrayIcon_) traySystem->show();
3780   else traySystem->hide();
3781 
3782   mainApp->proxySaveSettings(optionsDialog_->proxy());
3783 
3784   timeoutRequest = optionsDialog_->timeoutRequest_->value();
3785   numberRequests = optionsDialog_->numberRequests_->value();
3786   numberRepeats = optionsDialog_->numberRepeats_->value();
3787   settings.setValue("Settings/timeoutRequest", timeoutRequest);
3788   settings.setValue("Settings/numberRequest", numberRequests);
3789   settings.setValue("Settings/numberRepeats", numberRepeats);
3790 
3791   if (optionsDialog_->embeddedBrowserOn_->isChecked()) {
3792     if (optionsDialog_->defaultExternalBrowserOn_->isChecked())
3793       externalBrowserOn_ = 0;
3794     else
3795       externalBrowserOn_ = -1;
3796   } else {
3797     if (optionsDialog_->defaultExternalBrowserOn_->isChecked())
3798       externalBrowserOn_ = 1;
3799     else
3800       externalBrowserOn_ = 2;
3801   }
3802 
3803   externalBrowser_ = optionsDialog_->otherExternalBrowserEdit_->text();
3804   autoLoadImages_ = optionsDialog_->autoLoadImages_->isChecked();
3805   javaScriptEnable_ = optionsDialog_->javaScriptEnable_->isChecked();
3806   pluginsEnable_ = optionsDialog_->pluginsEnable_->isChecked();
3807   openLinkInBackground_ = optionsDialog_->openLinkInBackground_->isChecked();
3808   openLinkInBackgroundEmbedded_ = optionsDialog_->openLinkInBackgroundEmbedded_->isChecked();
3809   maxPagesInCache_ = optionsDialog_->maxPagesInCache_->value();
3810   defaultZoomPages_ = optionsDialog_->defaultZoomPages_->value();
3811 
3812   QWebSettings::globalSettings()->setAttribute(
3813         QWebSettings::JavascriptEnabled, javaScriptEnable_);
3814   QWebSettings::globalSettings()->setAttribute(
3815         QWebSettings::PluginsEnabled, pluginsEnable_);
3816   QWebSettings::globalSettings()->setMaximumPagesInCache(maxPagesInCache_);
3817 
3818   settings.beginGroup("Settings");
3819 
3820   userStyleBrowser = optionsDialog_->userStyleBrowserEdit_->text();
3821   settings.setValue("userStyleBrowser", userStyleBrowser);
3822 
3823   useDiskCache = optionsDialog_->diskCacheOn_->isChecked();
3824   settings.setValue("useDiskCache", useDiskCache);
3825   maxDiskCache = optionsDialog_->maxDiskCache_->value();
3826   settings.setValue("maxDiskCache", maxDiskCache);
3827 
3828   if (diskCacheDir != optionsDialog_->dirDiskCacheEdit_->text()) {
3829     Common::removePath(diskCacheDir);
3830   }
3831   diskCacheDir = optionsDialog_->dirDiskCacheEdit_->text();
3832   if (diskCacheDir.isEmpty()) diskCacheDir = mainApp->cacheDefaultDir();
3833   settings.setValue("dirDiskCache", diskCacheDir);
3834 
3835   settings.endGroup();
3836 
3837   mainApp->setDiskCache();
3838 
3839   useCookies = SaveCookies;
3840   if (optionsDialog_->deleteCookiesOnClose_->isChecked())
3841     useCookies = DeleteCookiesOnClose;
3842   else if (optionsDialog_->blockCookies_->isChecked())
3843     useCookies = BlockCookies;
3844   mainApp->cookieJar()->setUseCookies(useCookies);
3845 
3846   downloadLocation_ = optionsDialog_->downloadLocationEdit_->text();
3847   askDownloadLocation_ = optionsDialog_->askDownloadLocation_->isChecked();
3848 
3849   updateFeedsStartUp = optionsDialog_->updateFeedsStartUp_->isChecked();
3850   updateFeedsEnable_ = optionsDialog_->updateFeedsEnable_->isChecked();
3851   updateFeedsInterval_ = optionsDialog_->updateFeedsInterval_->value();
3852   updateFeedsIntervalType_ = optionsDialog_->updateIntervalType_->currentIndex()-1;
3853 
3854   int updateInterval = updateFeedsInterval_;
3855   if (updateFeedsIntervalType_ == 0)
3856     updateInterval = updateInterval*60;
3857   else if (updateFeedsIntervalType_ == 1)
3858     updateInterval = updateInterval*60*60;
3859   updateIntervalSec_ = updateInterval;
3860 
3861   openingFeedAction_ = optionsDialog_->getOpeningFeed();
3862   openNewsWebViewOn_ = optionsDialog_->openNewsWebViewOn_->isChecked();
3863 
3864   markNewsReadOn_ = optionsDialog_->markNewsReadOn_->isChecked();
3865   markCurNewsRead_ = optionsDialog_->markCurNewsRead_->isChecked();
3866   markNewsReadTime_ = optionsDialog_->markNewsReadTime_->value();
3867   markPrevNewsRead_ = optionsDialog_->markPrevNewsRead_->isChecked();
3868   markReadSwitchingFeed_ = optionsDialog_->markReadSwitchingFeed_->isChecked();
3869   markReadClosingTab_ = optionsDialog_->markReadClosingTab_->isChecked();
3870   markReadMinimize_ = optionsDialog_->markReadMinimize_->isChecked();
3871 
3872   showDescriptionNews_ = optionsDialog_->showDescriptionNews_->isChecked();
3873 
3874   formatDate_ = optionsDialog_->formatDate_->itemData(
3875         optionsDialog_->formatDate_->currentIndex()).toString();
3876   feedsModel_->formatDate_ = formatDate_;
3877   formatTime_ = optionsDialog_->formatTime_->itemData(
3878         optionsDialog_->formatTime_->currentIndex()).toString();
3879   feedsModel_->formatTime_ = formatTime_;
3880 
3881   alternatingRowColorsNews_ = optionsDialog_->alternatingRowColorsNews_->isChecked();
3882   changeBehaviorActionNUN_ = optionsDialog_->changeBehaviorActionNUN_->isChecked();
3883   simplifiedDateTime_ = optionsDialog_->simplifiedDateTime_->isChecked();
3884   notDeleteStarred_ = optionsDialog_->notDeleteStarred_->isChecked();
3885   notDeleteLabeled_ = optionsDialog_->notDeleteLabeled_->isChecked();
3886   markIdenticalNewsRead_ = optionsDialog_->markIdenticalNewsRead_->isChecked();
3887   avoidOldNews_ = optionsDialog_->avoidedOldNewsDateOn_->isChecked();
3888 
3889   if (!optionsDialog_->avoidedOldNewsDate_->selectedDate().isNull() && optionsDialog_->avoidedOldNewsDate_->selectedDate().isValid()) {
3890     avoidedOldNewsDate_ = optionsDialog_->avoidedOldNewsDate_->selectedDate();
3891   } else {
3892     avoidedOldNewsDate_ = QDate::currentDate();
3893   }
3894 
3895   mainNewsFilter_ = optionsDialog_->mainNewsFilter_->itemData(
3896         optionsDialog_->mainNewsFilter_->currentIndex()).toString();
3897 
3898   styleSheetNews = optionsDialog_->styleSheetNewsEdit_->text();
3899   if (styleSheetNews.isEmpty()) styleSheetNews = mainApp->styleSheetNewsDefaultFile();
3900   settings.setValue("Settings/styleSheetNews", styleSheetNews);
3901 
3902   cleanupOnShutdown_ = optionsDialog_->cleanupOnShutdownBox_->isChecked();
3903   dayCleanUpOn_ = optionsDialog_->dayCleanUpOn_->isChecked();
3904   maxDayCleanUp_ = optionsDialog_->maxDayCleanUp_->value();
3905   newsCleanUpOn_ = optionsDialog_->newsCleanUpOn_->isChecked();
3906   maxNewsCleanUp_ = optionsDialog_->maxNewsCleanUp_->value();
3907   readCleanUp_ = optionsDialog_->readCleanUp_->isChecked();
3908   neverUnreadCleanUp_ = optionsDialog_->neverUnreadCleanUp_->isChecked();
3909   neverStarCleanUp_ = optionsDialog_->neverStarCleanUp_->isChecked();
3910   neverLabelCleanUp_ = optionsDialog_->neverLabelCleanUp_->isChecked();
3911   cleanUpDeleted_ = optionsDialog_->cleanUpDeleted_->isChecked();
3912   optimizeDB_ = optionsDialog_->optimizeDB_->isChecked();
3913 
3914   soundNewNews_ = optionsDialog_->soundNotifyBox_->isChecked();
3915   soundNotifyPath_ = optionsDialog_->editSoundNotifer_->text();
3916   showNotifyOn_ = optionsDialog_->showNotifyOn_->isChecked();
3917   screenNotify_ = optionsDialog_->screenNotify_->currentIndex()-1;
3918   positionNotify_ = optionsDialog_->positionNotify_->currentIndex();
3919   transparencyNotify_ = optionsDialog_->transparencyNotify_->value();
3920   countShowNewsNotify_ = optionsDialog_->countShowNewsNotify_->value();
3921   widthTitleNewsNotify_ = optionsDialog_->widthTitleNewsNotify_->value();
3922   timeShowNewsNotify_ = optionsDialog_->timeShowNewsNotify_->value();
3923   fullscreenModeNotify_ = optionsDialog_->fullscreenModeNotify_->isChecked();
3924   showNotifyInactiveApp_ = optionsDialog_->showNotifyInactiveApp_->isChecked();
3925   onlySelectedFeeds_ = optionsDialog_->onlySelectedFeeds_->isChecked();
3926   showTitlesFeedsNotify_ = optionsDialog_->showTitlesFeedsNotify_->isChecked();
3927   showIconFeedNotify_ = optionsDialog_->showIconFeedNotify_->isChecked();
3928   showButtonMarkAllNotify_ = optionsDialog_->showButtonMarkAllNotify_->isChecked();
3929   showButtonMarkReadNotify_ = optionsDialog_->showButtonMarkReadNotify_->isChecked();
3930   showButtonExBrowserNotify_ = optionsDialog_->showButtonExBrowserNotify_->isChecked();
3931   showButtonDeleteNotify_ = optionsDialog_->showButtonDeleteNotify_->isChecked();
3932   closeNotify_ = optionsDialog_->closeNotify_->isChecked();
3933 
3934   mainApp->setLanguage(optionsDialog_->language());
3935   mainApp->setTranslateApplication();
3936 
3937   QFont font = feedsView_->font();
3938   font.setFamily(
3939         optionsDialog_->fontsTree_->topLevelItem(0)->text(2).section(", ", 0, 0));
3940   font.setPointSize(
3941         optionsDialog_->fontsTree_->topLevelItem(0)->text(2).section(", ", 1).toInt());
3942   feedsView_->setFont(font);
3943   feedsModel_->font_ = font;
3944 
3945   newsListFontFamily_ = optionsDialog_->fontsTree_->topLevelItem(1)->text(2).section(", ", 0, 0);
3946   newsListFontSize_ = optionsDialog_->fontsTree_->topLevelItem(1)->text(2).section(", ", 1).toInt();
3947   newsTitleFontFamily_ = optionsDialog_->fontsTree_->topLevelItem(2)->text(2).section(", ", 0, 0);
3948   newsTitleFontSize_ = optionsDialog_->fontsTree_->topLevelItem(2)->text(2).section(", ", 1).toInt();
3949   newsTextFontFamily_ = optionsDialog_->fontsTree_->topLevelItem(3)->text(2).section(", ", 0, 0);
3950   newsTextFontSize_ = optionsDialog_->fontsTree_->topLevelItem(3)->text(2).section(", ", 1).toInt();
3951   notificationFontFamily_ = optionsDialog_->fontsTree_->topLevelItem(4)->text(2).section(", ", 0, 0);
3952   notificationFontSize_ = optionsDialog_->fontsTree_->topLevelItem(4)->text(2).section(", ", 1).toInt();
3953 
3954   browserStandardFont = optionsDialog_->browserStandardFont_->currentFont().family();
3955   browserFixedFont = optionsDialog_->browserFixedFont_->currentFont().family();
3956   browserSerifFont = optionsDialog_->browserSerifFont_->currentFont().family();
3957   browserSansSerifFont = optionsDialog_->browserSansSerifFont_->currentFont().family();
3958   browserCursiveFont = optionsDialog_->browserCursiveFont_->currentFont().family();
3959   browserFantasyFont = optionsDialog_->browserFantasyFont_->currentFont().family();
3960   browserDefaultFontSize = optionsDialog_->browserDefaultFontSize_->value();
3961   browserFixedFontSize = optionsDialog_->browserFixedFontSize_->value();
3962   browserMinFontSize = optionsDialog_->browserMinFontSize_->value();
3963   browserMinLogFontSize = optionsDialog_->browserMinLogFontSize_->value();
3964 
3965   QWebSettings::globalSettings()->setFontFamily(
3966         QWebSettings::StandardFont, browserStandardFont);
3967   QWebSettings::globalSettings()->setFontFamily(
3968         QWebSettings::FixedFont, browserFixedFont);
3969   QWebSettings::globalSettings()->setFontFamily(
3970         QWebSettings::SerifFont, browserSerifFont);
3971   QWebSettings::globalSettings()->setFontFamily(
3972         QWebSettings::SansSerifFont, browserSansSerifFont);
3973   QWebSettings::globalSettings()->setFontFamily(
3974         QWebSettings::CursiveFont, browserCursiveFont);
3975   QWebSettings::globalSettings()->setFontFamily(
3976         QWebSettings::FantasyFont, browserFantasyFont);
3977   QWebSettings::globalSettings()->setFontSize(
3978         QWebSettings::DefaultFontSize, browserDefaultFontSize);
3979   QWebSettings::globalSettings()->setFontSize(
3980         QWebSettings::DefaultFixedFontSize, browserFixedFontSize);
3981   QWebSettings::globalSettings()->setFontSize(
3982         QWebSettings::MinimumFontSize, browserMinFontSize);
3983   QWebSettings::globalSettings()->setFontSize(
3984         QWebSettings::MinimumLogicalFontSize, browserMinLogFontSize);
3985 
3986   settings.beginGroup("Settings");
3987   settings.setValue("browserStandardFont", browserStandardFont);
3988   settings.setValue("browserFixedFont", browserFixedFont);
3989   settings.setValue("browserSerifFont", browserSerifFont);
3990   settings.setValue("browserSansSerifFont", browserSansSerifFont);
3991   settings.setValue("browserCursiveFont", browserCursiveFont);
3992   settings.setValue("browserFantasyFont", browserFantasyFont);
3993   settings.setValue("browserDefaultFontSize", browserDefaultFontSize);
3994   settings.setValue("browserFixedFontSize", browserFixedFontSize);
3995   settings.setValue("browserMinFontSize", browserMinFontSize);
3996   settings.setValue("browserMinLogFontSize", browserMinLogFontSize);
3997   settings.endGroup();
3998 
3999   feedsModel_->textColor_ = optionsDialog_->colorsTree_->topLevelItem(0)->text(1);
4000   feedsModel_->backgroundColor_ = optionsDialog_->colorsTree_->topLevelItem(1)->text(1);
4001   feedsView_->setStyleSheet(QString("#feedsView_ {background: %1;}").arg(feedsModel_->backgroundColor_));
4002   newsListTextColor_ = optionsDialog_->colorsTree_->topLevelItem(2)->text(1);
4003   newsListBackgroundColor_ = optionsDialog_->colorsTree_->topLevelItem(3)->text(1);
4004   focusedNewsTextColor_ = optionsDialog_->colorsTree_->topLevelItem(4)->text(1);
4005   focusedNewsBGColor_ = optionsDialog_->colorsTree_->topLevelItem(5)->text(1);
4006   linkColor_ = optionsDialog_->colorsTree_->topLevelItem(6)->text(1);
4007   titleColor_ = optionsDialog_->colorsTree_->topLevelItem(7)->text(1);
4008   dateColor_ = optionsDialog_->colorsTree_->topLevelItem(8)->text(1);
4009   authorColor_ = optionsDialog_->colorsTree_->topLevelItem(9)->text(1);
4010   newsTextColor_ = optionsDialog_->colorsTree_->topLevelItem(10)->text(1);
4011   newsTitleBackgroundColor_ = optionsDialog_->colorsTree_->topLevelItem(11)->text(1);
4012   newsBackgroundColor_ = optionsDialog_->colorsTree_->topLevelItem(12)->text(1);
4013   feedsModel_->feedWithNewNewsColor_ = optionsDialog_->colorsTree_->topLevelItem(13)->text(1);
4014   feedsModel_->countNewsUnreadColor_ = optionsDialog_->colorsTree_->topLevelItem(14)->text(1);
4015   newNewsTextColor_ = optionsDialog_->colorsTree_->topLevelItem(15)->text(1);
4016   unreadNewsTextColor_ = optionsDialog_->colorsTree_->topLevelItem(16)->text(1);
4017   feedsModel_->focusedFeedTextColor_ = optionsDialog_->colorsTree_->topLevelItem(17)->text(1);
4018   feedsModel_->focusedFeedBGColor_ = optionsDialog_->colorsTree_->topLevelItem(18)->text(1);
4019   feedsModel_->feedDisabledUpdateColor_ = optionsDialog_->colorsTree_->topLevelItem(19)->text(1);
4020   alternatingRowColors_ = optionsDialog_->colorsTree_->topLevelItem(20)->text(1);
4021   notifierTextColor_ = optionsDialog_->colorsTree_->topLevelItem(21)->text(1);
4022   notifierBackgroundColor_ = optionsDialog_->colorsTree_->topLevelItem(22)->text(1);
4023 
4024   delete optionsDialog_;
4025   optionsDialog_ = NULL;
4026 
4027   settings.beginGroup("Settings");
4028   settings.setValue("autoUpdatefeedsStartUp", updateFeedsStartUp);
4029   settings.endGroup();
4030 
4031   saveSettings();
4032   saveActionShortcuts();
4033   mainApp->reloadUserStyleBrowser();
4034 
4035   if (currentNewsTab != NULL) {
4036     if (currentNewsTab->type_ < NewsTabWidget::TabTypeWeb)
4037       currentNewsTab->newsHeader_->saveStateColumns(currentNewsTab);
4038     currentNewsTab->setSettings(false);
4039   }
4040 }
4041 
showSettingPageLabels()4042 void MainWindow::showSettingPageLabels()
4043 {
4044   showOptionDlg(5);
4045 }
4046 
4047 // ----------------------------------------------------------------------------
createTrayMenu()4048 void MainWindow::createTrayMenu()
4049 {
4050   trayMenu_ = new QMenu(this);
4051   showWindowAct_ = new QAction(this);
4052   connect(showWindowAct_, SIGNAL(triggered()), this, SLOT(showWindows()));
4053   QFont font_ = showWindowAct_->font();
4054   font_.setBold(true);
4055   showWindowAct_->setFont(font_);
4056   trayMenu_->addAction(showWindowAct_);
4057   trayMenu_->addAction(addFeedTrayAct_);
4058   trayMenu_->addAction(updateAllFeedsAct_);
4059   trayMenu_->addAction(markAllFeedsRead_);
4060   trayMenu_->addSeparator();
4061 
4062   trayMenu_->addAction(optionsAct_);
4063   trayMenu_->addSeparator();
4064 
4065   trayMenu_->addAction(exitAct_);
4066   traySystem->setContextMenu(trayMenu_);
4067 }
4068 
4069 /** @brief Free memory working set in Windows
4070  *---------------------------------------------------------------------------*/
myEmptyWorkingSet()4071 void MainWindow::myEmptyWorkingSet()
4072 {
4073 #if defined(Q_OS_WIN)
4074   if (isHidden())
4075     EmptyWorkingSet(GetCurrentProcess());
4076 #endif
4077 }
4078 // ----------------------------------------------------------------------------
initUpdateFeeds()4079 void MainWindow::initUpdateFeeds()
4080 {
4081   QSqlQuery q;
4082 
4083   if (onlySelectedFeeds_) {
4084     q.exec("SELECT feedId FROM feeds_ex WHERE value=1 AND name='showNotification'");
4085     while (q.next()) {
4086       idFeedsNotifyList_.append(q.value(0).toInt());
4087     }
4088   }
4089 
4090   q.exec("SELECT id, updateInterval, updateIntervalType FROM feeds WHERE xmlUrl != '' AND updateIntervalEnable == 1");
4091   while (q.next()) {
4092     int updateInterval = q.value(1).toInt();
4093     int updateIntervalType = q.value(2).toInt();
4094     if (updateIntervalType == 0)
4095       updateInterval = updateInterval*60;
4096     else if (updateIntervalType == 1)
4097       updateInterval = updateInterval*60*60;
4098 
4099     updateFeedsIntervalSec_.insert(q.value(0).toInt(), updateInterval);
4100     updateFeedsTimeCount_.insert(q.value(0).toInt(), 0);
4101   }
4102 
4103   int updateInterval = updateFeedsInterval_;
4104   if (updateFeedsIntervalType_ == 0)
4105     updateInterval = updateInterval*60;
4106   else if (updateFeedsIntervalType_ == 1)
4107     updateInterval = updateInterval*60*60;
4108   updateIntervalSec_ = updateInterval;
4109 
4110   updateFeedsTimer_ = new QTimer(this);
4111   connect(updateFeedsTimer_, SIGNAL(timeout()),
4112           this, SLOT(slotGetFeedsTimer()));
4113   updateFeedsTimer_->start(1000);
4114 }
4115 // ----------------------------------------------------------------------------
slotGetFeedsTimer()4116 void MainWindow::slotGetFeedsTimer()
4117 {
4118   if (updateFeedsEnable_) {
4119     updateTimeCount_++;
4120     if (updateTimeCount_ >= updateIntervalSec_) {
4121       updateTimeCount_ = 0;
4122 
4123       emit signalGetAllFeedsTimer();
4124     }
4125   } else {
4126     updateTimeCount_ = 0;
4127   }
4128 
4129   QMapIterator<int, int> iterator(updateFeedsTimeCount_);
4130   while (iterator.hasNext()) {
4131     iterator.next();
4132     int feedId = iterator.key();
4133     updateFeedsTimeCount_[feedId]++;
4134     if (updateFeedsTimeCount_[feedId] >= updateFeedsIntervalSec_[feedId]) {
4135       updateFeedsTimeCount_[feedId] = 0;
4136 
4137       emit signalGetFeedTimer(feedId);
4138     }
4139   }
4140 }
4141 /** @brief Process update feed action
4142  *---------------------------------------------------------------------------*/
slotGetFeed()4143 void MainWindow::slotGetFeed()
4144 {
4145   QModelIndexList indexList = feedsView_->selectionModel()->selectedRows(0);
4146   if (indexList.count() <= 1) {
4147     indexList.clear();
4148     indexList.append(feedsProxyModel_->mapFromSource(feedsView_->selectIndex()));
4149   }
4150   QList<int> idList;
4151   foreach (QModelIndex indexProxy, indexList) {
4152     QModelIndex index = feedsProxyModel_->mapToSource(indexProxy);
4153     if (feedsModel_->isFolder(index)) {
4154       QList<int> list = UpdateObject::getIdFeedsInList(db_, feedsModel_->dataField(index, "id").toInt());
4155       foreach (int idFeed, list) {
4156         if (!idList.contains(idFeed)) {
4157           idList.append(idFeed);
4158           index = feedsModel_->indexById(idFeed);
4159           if (!feedsModel_->dataField(index, "disableUpdate").toBool()) {
4160             emit signalGetFeed(feedsModel_->dataField(index, "id").toInt(),
4161                                feedsModel_->dataField(index, "xmlUrl").toString(),
4162                                feedsModel_->dataField(index, "lastBuildDate").toDateTime(),
4163                                feedsModel_->dataField(index, "authentication").toInt());
4164           }
4165         }
4166       }
4167 
4168     } else {
4169       int idFeed = feedsModel_->dataField(index, "id").toInt();
4170       if (!idList.contains(idFeed)) {
4171         idList.append(idFeed);
4172         emit signalGetFeed(feedsModel_->dataField(index, "id").toInt(),
4173                            feedsModel_->dataField(index, "xmlUrl").toString(),
4174                            feedsModel_->dataField(index, "lastBuildDate").toDateTime(),
4175                            feedsModel_->dataField(index, "authentication").toInt());
4176       }
4177     }
4178   }
4179 }
4180 
4181 /** @brief Process update all feeds action
4182  *---------------------------------------------------------------------------*/
slotGetAllFeeds()4183 void MainWindow::slotGetAllFeeds()
4184 {
4185   emit signalGetAllFeeds();
4186 }
4187 
slotStopUpdate()4188 void MainWindow::slotStopUpdate()
4189 {
4190   progressBar_->hide();
4191   emit signalStopUpdate();
4192 }
4193 
4194 /** @brief Show update progress bar after feed update has started
4195  *---------------------------------------------------------------------------*/
showProgressBar(int maximum)4196 void MainWindow::showProgressBar(int maximum)
4197 {
4198   if (maximum == 0) {
4199     isStartImportFeed_ = false;
4200     return;
4201   }
4202 
4203   Settings settings;
4204   settings.setValue("Flags/updatingFeeds", true);
4205 
4206   playSoundNewNews_ = false;
4207 
4208   progressBar_->setMaximum(maximum);
4209   progressBar_->show();
4210 }
slotSetValue(int value)4211 void MainWindow::slotSetValue(int value)
4212 {
4213   if (progressBar_->isVisible())
4214     progressBar_->setValue(progressBar_->maximum() - value);
4215 }
showMessageStatusBar(QString message,int timeout)4216 void MainWindow::showMessageStatusBar(QString message, int timeout)
4217 {
4218   statusBar()->showMessage(message, timeout);
4219 }
slotCountsStatusBar(int unreadCount,int allCount)4220 void MainWindow::slotCountsStatusBar(int unreadCount, int allCount)
4221 {
4222   statusUnread_->setText(QString(" " + tr("Unread: %1") + " ").arg(unreadCount));
4223   statusAll_->setText(QString(" " + tr("All: %1") + " ").arg(allCount));
4224 }
4225 // ----------------------------------------------------------------------------
slotVisibledFeedsWidget()4226 void MainWindow::slotVisibledFeedsWidget()
4227 {
4228   if (tabBar_->currentIndex() == TAB_WIDGET_PERMANENT) {
4229     showFeedsTabPermanent_ = feedsWidgetVisibleAct_->isChecked();
4230   }
4231 
4232   feedsWidget_->setVisible(feedsWidgetVisibleAct_->isChecked());
4233   updateIconToolBarNull(feedsWidgetVisibleAct_->isChecked());
4234 }
4235 // ----------------------------------------------------------------------------
updateIconToolBarNull(bool feedsWidgetVisible)4236 void MainWindow::updateIconToolBarNull(bool feedsWidgetVisible)
4237 {
4238   if (feedsWidgetVisible)
4239     pushButtonNull_->setIcon(QIcon(":/images/images/triangleR.png"));
4240   else
4241     pushButtonNull_->setIcon(QIcon(":/images/images/triangleL.png"));
4242 }
4243 
4244 /** @brief Update status of current feed or feed of current tab
4245  *---------------------------------------------------------------------------*/
slotUpdateStatus(int feedId,bool changed)4246 void MainWindow::slotUpdateStatus(int feedId, bool changed)
4247 {
4248   emit signalUpdateStatus(feedId, changed);
4249 }
4250 
4251 /** @brief Set filter for viewing feeds and categories
4252  * @param pAct Filter mode
4253  * @param clicked Flag to call function after user click or from programm code
4254  *    true  - user click
4255  *    false - programm call
4256  *----------------------------------------------------------------------------*/
setFeedsFilter(bool clicked)4257 void MainWindow::setFeedsFilter(bool clicked)
4258 {
4259   QList<int> idList;
4260   static bool setFilter = false;
4261 
4262   if (setFilter) return;
4263   setFilter = true;
4264 
4265   QAction* filterAct = feedsFilterGroup_->checkedAction();
4266 
4267   if (filterAct->objectName() == "filterFeedsNew_") {
4268     QModelIndex index = feedsProxyModel_->mapToSource(feedsView_->currentIndex());
4269     int newCount = feedsModel_->dataField(index, "newCount").toInt();
4270     if (!(clicked && !newCount)) {
4271       while (index.isValid()) {
4272         idList << feedsModel_->idByIndex(index);
4273         index = index.parent();
4274       }
4275     }
4276   } else if (filterAct->objectName() == "filterFeedsUnread_") {
4277     QModelIndex index = feedsProxyModel_->mapToSource(feedsView_->currentIndex());
4278     int unRead = feedsModel_->dataField(index, "unread").toInt();
4279     if (!(clicked && !unRead)) {
4280       while (index.isValid()) {
4281         idList << feedsModel_->idByIndex(index);
4282         index = index.parent();
4283       }
4284     }
4285   } else if (filterAct->objectName() == "filterFeedsStarred_") {
4286     QSqlQuery q;
4287     q.exec(QString("SELECT id, parentId FROM feeds WHERE label LIKE '%starred%'"));
4288     while (q.next()) {
4289       idList.append(q.value(0).toInt());
4290       int parentId = q.value(1).toInt();
4291       if (!idList.contains(parentId)) {
4292         while (parentId) {
4293           if (!idList.contains(parentId))
4294             idList.append(parentId);
4295           else break;
4296           QSqlQuery q1;
4297           q1.exec(QString("SELECT parentId FROM feeds WHERE id==%1").arg(parentId));
4298           if (q1.next()) parentId = q1.value(0).toInt();
4299         }
4300       }
4301     }
4302   } else if (filterAct->objectName() == "filterFeedsError_") {
4303     QSqlQuery q;
4304     q.exec(QString("SELECT id, parentId FROM feeds WHERE status!=0 AND status!=''"));
4305     while (q.next()) {
4306       idList.append(q.value(0).toInt());
4307       int parentId = q.value(1).toInt();
4308       if (!idList.contains(parentId)) {
4309         while (parentId) {
4310           if (!idList.contains(parentId))
4311             idList.append(parentId);
4312           else break;
4313           QSqlQuery q1;
4314           q1.exec(QString("SELECT parentId FROM feeds WHERE id==%1").arg(parentId));
4315           if (q1.next()) parentId = q1.value(0).toInt();
4316         }
4317       }
4318     }
4319   }
4320 
4321   if ((filterAct->objectName() == "filterFeedsNew_") ||
4322       (filterAct->objectName() == "filterFeedsUnread_")) {
4323     for (int i = 0; i < stackedWidget_->count(); i++) {
4324       if ((i == 0) && clicked && (stackedWidget_->currentIndex() == 0)) continue;
4325       NewsTabWidget *widget = (NewsTabWidget*)stackedWidget_->widget(i);
4326       if (!idList.contains(widget->feedId_)) {
4327         idList.append(widget->feedId_);
4328         QModelIndex index = feedsModel_->indexById(widget->feedId_).parent();
4329         while (index.isValid()) {
4330           int id = feedsModel_->idByIndex(index);
4331           if (!idList.contains(id))
4332             idList.append(id);
4333           index = index.parent();
4334         }
4335       }
4336     }
4337   }
4338 
4339   // Set filter
4340   feedsProxyModel_->setFilter(filterAct->objectName(), idList,
4341                               findFeeds_->findGroup_->checkedAction()->objectName(),
4342                               findFeeds_->text());
4343 
4344   feedsView_->restoreExpanded();
4345 
4346   feedsView_->clearSelection();
4347   feedsView_->setCurrentIndex(feedsView_->currentIndex());
4348 
4349   if (clicked && (tabBar_->currentIndex() == TAB_WIDGET_PERMANENT)) {
4350     slotFeedClicked(feedsView_->currentIndex());
4351   }
4352 
4353   if (filterAct->objectName() == "filterFeedsAll_") feedsFilter_->setIcon(QIcon(":/images/filterOff"));
4354   else feedsFilter_->setIcon(QIcon(":/images/filterOn"));
4355 
4356   // Store filter to enable it as "last used filter"
4357   if (filterAct->objectName() != "filterFeedsAll_")
4358     feedsFilterAction_ = filterAct;
4359 
4360   setFilter = false;
4361 }
4362 
4363 /** @brief Set filter for news list
4364  *---------------------------------------------------------------------------*/
setNewsFilter(QAction * pAct,bool clicked)4365 void MainWindow::setNewsFilter(QAction* pAct, bool clicked)
4366 {
4367   if (currentNewsTab == NULL) return;
4368   if (currentNewsTab->type_ >= NewsTabWidget::TabTypeWeb) {
4369     filterNewsAll_->setChecked(true);
4370     return;
4371   }
4372 
4373   QModelIndex index = newsView_->currentIndex();
4374   int feedId = currentNewsTab->feedId_;
4375   int newsId = newsModel_->index(
4376         index.row(), newsModel_->fieldIndex("id")).data(Qt::EditRole).toInt();
4377 
4378   // Hide news has marrked "Read"
4379   // read=1 - show regardless of filter
4380   // read=2 - don't display at all
4381   if (clicked) {
4382     QString qStr = QString("UPDATE news SET read=2 WHERE feedId='%1' AND read=1").
4383         arg(feedId);
4384     mainApp->sqlQueryExec(qStr);
4385   }
4386 
4387   // Create filter for category or for feed
4388   if (feedsModel_->isFolder(feedsModel_->indexById(feedId))) {
4389     newsFilterStr = QString("(%1) AND ").arg(getIdFeedsString(feedId));
4390   } else {
4391     newsFilterStr = QString("feedId=%1 AND ").arg(feedId);
4392   }
4393 
4394   // ... add filter from "filter"
4395   if (pAct->objectName() == "filterNewsAll_") {
4396     newsFilterStr.append("deleted = 0");
4397   } else if (pAct->objectName() == "filterNewsNew_") {
4398     newsFilterStr.append(QString("new = 1 AND deleted = 0"));
4399   } else if (pAct->objectName() == "filterNewsUnread_") {
4400     newsFilterStr.append(QString("read < 2 AND deleted = 0"));
4401   } else if (pAct->objectName() == "filterNewsStar_") {
4402     newsFilterStr.append(QString("starred = 1 AND deleted = 0"));
4403   } else if (pAct->objectName() == "filterNewsNotStarred_") {
4404     newsFilterStr.append(QString("starred = 0 AND deleted = 0"));
4405   } else if (pAct->objectName() == "filterNewsUnreadStar_") {
4406     newsFilterStr.append(QString("(read < 2 OR starred = 1) AND deleted = 0"));
4407   } else if (pAct->objectName() == "filterNewsLastDay_") {
4408     newsFilterStr.append(QString("(published >= datetime('now', '-1 day')) AND deleted = 0"));
4409   } else if (pAct->objectName() == "filterNewsLastWeek_") {
4410     newsFilterStr.append(QString("(published >= datetime('now', '-7 day')) AND deleted = 0"));
4411   }
4412 
4413   // ... add filter from "search"
4414   QString filterStr = newsFilterStr;
4415   QString objectName = currentNewsTab->findText_->findGroup_->checkedAction()->objectName();
4416   if (objectName != "findInBrowserAct") {
4417     QString findText = currentNewsTab->findText_->text();
4418     if (!findText.isEmpty()) {
4419       findText = findText.replace("'", "''").toUpper();
4420       if (objectName == "findTitleAct") {
4421         filterStr.append(
4422               QString(" AND UPPER(title) LIKE '%%1%'").arg(findText));
4423       } else if (objectName == "findAuthorAct") {
4424         filterStr.append(
4425               QString(" AND UPPER(author_name) LIKE '%%1%'").arg(findText));
4426       } else if (objectName == "findCategoryAct") {
4427         filterStr.append(
4428               QString(" AND UPPER(category) LIKE '%%1%'").arg(findText));
4429       } else if (objectName == "findContentAct") {
4430         filterStr.append(
4431               QString(" AND (UPPER(content) LIKE '%%1%' OR UPPER(description) LIKE '%%1%')").
4432               arg(findText));
4433       } else if (objectName == "findLinkAct") {
4434         filterStr.append(
4435               QString(" AND link_href LIKE '%%1%'").
4436               arg(findText));
4437       } else {
4438         filterStr.append(
4439               QString(" AND (UPPER(title) LIKE '%%1%' OR UPPER(author_name) LIKE '%%1%' "
4440                       "OR UPPER(category) LIKE '%%1%' OR UPPER(content) LIKE '%%1%' "
4441                       "OR UPPER(description) LIKE '%%1%')").
4442               arg(findText));
4443       }
4444     }
4445   }
4446 
4447   newsModel_->setFilter(filterStr);
4448   while (newsModel_->canFetchMore())
4449     newsModel_->fetchMore();
4450 
4451   if ((currentNewsTab->newsHeader_->sortIndicatorSection() == newsModel_->fieldIndex("read")) ||
4452       currentNewsTab->newsHeader_->sortIndicatorSection() == newsModel_->fieldIndex("starred")) {
4453     currentNewsTab->slotSort(currentNewsTab->newsHeader_->sortIndicatorSection(),
4454                              currentNewsTab->newsHeader_->sortIndicatorOrder());
4455   }
4456 
4457   currentNewsTab->loadNewspaper();
4458 
4459   // Set icon right before user click
4460   if (pAct->objectName() == "filterNewsAll_") newsFilter_->setIcon(QIcon(":/images/filterOff"));
4461   else newsFilter_->setIcon(QIcon(":/images/filterOn"));
4462 
4463   // Set focus on previous displayed feed, if user click has been
4464   if (clicked) {
4465     QModelIndex index = newsModel_->index(0, newsModel_->fieldIndex("id"));
4466     QModelIndexList indexList = newsModel_->match(index, Qt::EditRole, newsId);
4467     if (indexList.count()) {
4468       int newsRow = indexList.first().row();
4469       newsView_->setCurrentIndex(newsModel_->index(newsRow, newsModel_->fieldIndex("title")));
4470     } else {
4471       currentNewsTab->currentNewsIdOld = newsId;
4472       currentNewsTab->hideWebContent();
4473     }
4474   }
4475 
4476   // Store filter to enable it as "last used filter"
4477   if (pAct->objectName() != mainNewsFilter_)
4478     newsFilterAction_ = pAct;
4479 }
4480 
4481 /** @brief Mark feed Read while clicking on unfocused one
4482  *---------------------------------------------------------------------------*/
setFeedRead(int type,int feedId,FeedReedType feedReadType,NewsTabWidget * widgetTab,int idException)4483 void MainWindow::setFeedRead(int type, int feedId, FeedReedType feedReadType,
4484                              NewsTabWidget *widgetTab, int idException)
4485 {
4486   if ((type >= NewsTabWidget::TabTypeWeb) || (type == NewsTabWidget::TabTypeDel))
4487     return;
4488 
4489   if ((type == NewsTabWidget::TabTypeFeed) && (feedReadType != FeedReadSwitchingTab)) {
4490     if (feedId <= -1) return;
4491 
4492     QList<int> idNewsList;
4493     if (((feedReadType == FeedReadSwitchingFeed) && markReadSwitchingFeed_) ||
4494         ((feedReadType == FeedReadClosingTab) && markReadClosingTab_) ||
4495         ((feedReadType == FeedReadPlaceToTray) && markReadMinimize_)) {
4496       emit signalSetFeedRead(feedReadType, feedId, idException, idNewsList);
4497     } else {
4498       emit signalSetFeedRead(feedReadType, feedId, idException, idNewsList);
4499     }
4500   } else if (widgetTab) {
4501     int cnt = widgetTab->newsModel_->rowCount();
4502     if (cnt == 0) return;
4503 
4504     QList<int> idNewsList;
4505     for (int i = cnt-1; i >= 0; --i) {
4506       int newsId = widgetTab->newsModel_->index(i, widgetTab->newsModel_->fieldIndex("id")).data().toInt();
4507       idNewsList.append(newsId);
4508     }
4509     for (int i = 0; i < stackedWidget_->count(); i++) {
4510       NewsTabWidget *widget = (NewsTabWidget*)stackedWidget_->widget(i);
4511       if ((widget->type_ < NewsTabWidget::TabTypeWeb) &&
4512           !((feedReadType == FeedReadSwitchingFeed) && (i == TAB_WIDGET_PERMANENT))) {
4513         int row = widget->newsView_->currentIndex().row();
4514         int newsId = widget->newsModel_->index(row, widget->newsModel_->fieldIndex("id")).data().toInt();
4515         idNewsList.removeOne(newsId);
4516       }
4517     }
4518     emit signalSetFeedRead(FeedReadSwitchingTab, feedId, idException, idNewsList);
4519   }
4520 }
4521 
4522 /** @brief Mark feed read
4523  *---------------------------------------------------------------------------*/
markFeedRead()4524 void MainWindow::markFeedRead()
4525 {
4526   bool openFeed = false;
4527   bool isFolder = false;
4528 
4529   QModelIndexList indexList = feedsView_->selectionModel()->selectedRows(0);
4530   if (indexList.count() <= 1) {
4531     indexList.clear();
4532     indexList.append(feedsProxyModel_->mapFromSource(feedsView_->selectIndex()));
4533   }
4534   QList<int> idList;
4535   for (int i = indexList.count()-1; i >= 0; --i) {
4536     QModelIndex index = feedsProxyModel_->mapToSource(indexList[i]);
4537     if (feedsModel_->isFolder(index)) {
4538       idList.append(feedsModel_->dataField(index, "id").toInt());
4539       indexList.removeAt(i);
4540     }
4541   }
4542   for (int i = indexList.count()-1; i >= 0; --i) {
4543     QModelIndex index = feedsProxyModel_->mapToSource(indexList[i]);
4544     int parentId = feedsModel_->dataField(index, "parentId").toInt();
4545     if (!idList.contains(parentId)) {
4546       idList.append(feedsModel_->dataField(index, "id").toInt());
4547     }
4548     indexList.removeAt(i);
4549   }
4550   foreach (int id, idList) {
4551     bool openFeedT = false;
4552     QModelIndex index = feedsModel_->indexById(id);
4553     int parentId = feedsModel_->dataField(index, "parentId").toInt();
4554     if (currentNewsTab->feedId_ == id) {
4555       openFeedT = true;
4556       openFeed = true;
4557     }
4558     if (currentNewsTab->feedParId_ == id) {
4559       openFeed = true;
4560     }
4561     if (currentNewsTab->feedId_ == parentId) {
4562       openFeed = true;
4563       isFolder = true;
4564     }
4565     if (feedsModel_->isFolder(index)) {
4566       if (currentNewsTab->feedId_ == id) {
4567         isFolder = true;
4568       }
4569       QList<int> list = UpdateObject::getIdFeedsInList(db_, id);
4570       foreach (int id1, list) {
4571         QModelIndex index1 = feedsModel_->indexById(id1);
4572         QModelIndex indexUnread = feedsModel_->indexSibling(index1, "unread");
4573         QModelIndex indexNew    = feedsModel_->indexSibling(index1, "newCount");
4574         feedsModel_->setData(indexUnread, 0);
4575         feedsModel_->setData(indexNew, 0);
4576 
4577         if (!openFeed) {
4578           int parentId1 = feedsModel_->dataField(index1, "parentId").toInt();
4579           if ((currentNewsTab->feedId_ == id1) || (currentNewsTab->feedId_ == parentId1)) {
4580             openFeed = true;
4581           }
4582         }
4583       }
4584     }
4585 
4586     QModelIndex indexUnread = feedsModel_->indexSibling(index, "unread");
4587     QModelIndex indexNew    = feedsModel_->indexSibling(index, "newCount");
4588     feedsModel_->setData(indexUnread, 0);
4589     feedsModel_->setData(indexNew, 0);
4590     emit signalMarkFeedRead(id, feedsModel_->isFolder(index), openFeedT);
4591   }
4592 
4593   // Update feed view with focus
4594   if (openFeed) {
4595     if ((tabBar_->currentIndex() == TAB_WIDGET_PERMANENT) && !isFolder) {
4596       signalRefreshNewsView(1);
4597     } else {
4598       signalRefreshNewsView(0);
4599       recountCategoryCounts();
4600       emit signalSetFeedsFilter(true);
4601     }
4602   }
4603   // Update feeds view without focus
4604   else {
4605     recountCategoryCounts();
4606     emit signalSetFeedsFilter();
4607   }
4608 }
4609 
4610 /** @brief Refresh news view (After mark all feeds or one feed read)
4611  *---------------------------------------------------------------------------*/
slotRefreshNewsView(int nextUnread)4612 void MainWindow::slotRefreshNewsView(int nextUnread)
4613 {
4614   if (nextUnread == 1) {
4615     feedsView_->clearSelection();
4616     QModelIndex indexNextUnread =
4617         feedsView_->indexNextUnread(feedsView_->currentIndex());
4618     feedsView_->setCurrentIndex(indexNextUnread);
4619     slotFeedClicked(indexNextUnread);
4620   } else if ((tabBar_->currentIndex() == TAB_WIDGET_PERMANENT) && (nextUnread == -1)) {
4621     QModelIndex index = feedsProxyModel_->index(-1, "text");
4622     feedsView_->setCurrentIndex(index);
4623     slotFeedClicked(index);
4624   } else {
4625     int currentRow = newsView_->currentIndex().row();
4626 
4627     newsModel_->select();
4628 
4629     while (newsModel_->canFetchMore())
4630       newsModel_->fetchMore();
4631 
4632     currentNewsTab->loadNewspaper(NewsTabWidget::RefreshWithPos);
4633 
4634     newsView_->setCurrentIndex(newsModel_->index(currentRow, newsModel_->fieldIndex("title")));
4635   }
4636 }
4637 
4638 // ----------------------------------------------------------------------------
slotShowAboutDlg()4639 void MainWindow::slotShowAboutDlg()
4640 {
4641   AboutDialog *aboutDialog = new AboutDialog(mainApp->language(), this);
4642   aboutDialog->exec();
4643   delete aboutDialog;
4644 }
4645 
4646 /** @brief Call context menu of the feeds tree
4647  *----------------------------------------------------------------------------*/
showContextMenuFeed(const QPoint & pos)4648 void MainWindow::showContextMenuFeed(const QPoint &pos)
4649 {
4650   slotFeedMenuShow();
4651 
4652   QModelIndex index = feedsView_->indexAt(pos);
4653   if (index.isValid()) {
4654     QRect rectText = feedsView_->visualRect(index);
4655     if (pos.x() >= rectText.x()) {
4656       QMenu menu;
4657       menu.addAction(addAct_);
4658       menu.addSeparator();
4659       menu.addAction(openFeedNewTabAct_);
4660       menu.addSeparator();
4661       menu.addAction(updateFeedAct_);
4662       menu.addSeparator();
4663       menu.addAction(markFeedRead_);
4664       menu.addSeparator();
4665       menu.addAction(deleteFeedAct_);
4666       menu.addSeparator();
4667       menu.addAction(setFilterNewsAct_);
4668       menu.addAction(feedProperties_);
4669 
4670       menu.exec(feedsView_->viewport()->mapToGlobal(pos));
4671     }
4672   } else {
4673     QMenu menu;
4674     menu.addAction(addAct_);
4675 
4676     menu.exec(feedsView_->viewport()->mapToGlobal(pos));
4677   }
4678 
4679   index = feedsProxyModel_->mapToSource(feedsView_->currentIndex());
4680   feedsView_->selectId_ = feedsModel_->idByIndex(index);
4681 
4682   feedProperties_->setEnabled(feedsView_->selectIndex().isValid());
4683 }
4684 // ----------------------------------------------------------------------------
slotFeedMenuShow()4685 void MainWindow::slotFeedMenuShow()
4686 {
4687   feedProperties_->setEnabled(feedsView_->selectIndex().isValid());
4688 }
4689 // ----------------------------------------------------------------------------
loadSettingsFeeds()4690 void MainWindow::loadSettingsFeeds()
4691 {
4692   markCurNewsRead_ = false;
4693   Settings settings;
4694   behaviorIconTray_ = settings.value("Settings/behaviorIconTray", NEW_COUNT_ICON_TRAY).toInt();
4695 
4696   QString filterName = settings.value("feedSettings/filterName", "filterFeedsAll_").toString();
4697   QList<QAction*> listActions = feedsFilterGroup_->actions();
4698   foreach(QAction *action, listActions) {
4699     if (action->objectName() == filterName) {
4700       action->setChecked(true);
4701       break;
4702     }
4703   }
4704   filterName = settings.value("newsSettings/filterName", "filterNewsAll_").toString();
4705   listActions = newsFilterGroup_->actions();
4706   foreach(QAction *action, listActions) {
4707     if (action->objectName() == filterName) {
4708       action->setChecked(true);
4709       break;
4710     }
4711   }
4712 
4713   setFeedsFilter(false);
4714 }
4715 
4716 /** @brief Restore feeds state on application startup
4717  *---------------------------------------------------------------------------*/
restoreFeedsOnStartUp()4718 void MainWindow::restoreFeedsOnStartUp()
4719 {
4720   qApp->processEvents();
4721 
4722   //* Restore current feed
4723   QModelIndex feedIndex = QModelIndex();
4724   if (reopenFeedStartup_) {
4725     Settings settings;
4726     int feedId = settings.value("feedSettings/currentId", 0).toInt();
4727     feedIndex = feedsProxyModel_->mapFromSource(feedId);
4728   }
4729   feedsView_->setCurrentIndex(feedIndex);
4730   updateCurrentTab_ = false;
4731   slotFeedClicked(feedIndex);
4732   currentNewsTab->webView_->setFocus();
4733   updateCurrentTab_ = true;
4734 
4735   slotUpdateStatus(-1, false);
4736   recountCategoryCounts();
4737 
4738   // Open feeds in tabs
4739   QSqlQuery q;
4740   q.exec(QString("SELECT id, parentId FROM feeds WHERE displayOnStartup=1"));
4741   while (q.next()) {
4742     creatFeedTab(q.value(0).toInt(), q.value(1).toInt());
4743   }
4744 }
4745 // ----------------------------------------------------------------------------
slotFeedsFilter()4746 void MainWindow::slotFeedsFilter()
4747 {
4748   if (feedsFilterGroup_->checkedAction()->objectName() == "filterFeedsAll_") {
4749     if (feedsFilterAction_ != NULL) {
4750       feedsFilterAction_->setChecked(true);
4751       setFeedsFilter();
4752     } else {
4753       if (mainToolbar_->widgetForAction(feedsFilter_)) {
4754         QWidget *widget = mainToolbar_->widgetForAction(feedsFilter_);
4755         if (widget->underMouse()) {
4756           feedsFilterMenu_->popup(widget->mapToGlobal(QPoint(0, mainToolbar_->height()-1)));
4757         }
4758       }
4759       if (feedsToolBar_->widgetForAction(feedsFilter_)) {
4760         QWidget *widget = feedsToolBar_->widgetForAction(feedsFilter_);
4761         if (widget->underMouse()) {
4762           feedsFilterMenu_->popup(widget->mapToGlobal(QPoint(0, feedsToolBar_->height()-1)));
4763         }
4764       }
4765       if (currentNewsTab->newsToolBar_->widgetForAction(feedsFilter_)) {
4766         QWidget *widget = currentNewsTab->newsToolBar_->widgetForAction(feedsFilter_);
4767         if (widget->underMouse()) {
4768           feedsFilterMenu_->popup(widget->mapToGlobal(QPoint(0, currentNewsTab->newsToolBar_->height()-1)));
4769         }
4770       }
4771     }
4772   } else {
4773     filterFeedsAll_->setChecked(true);
4774     setFeedsFilter();
4775   }
4776 }
4777 // ----------------------------------------------------------------------------
slotNewsFilter()4778 void MainWindow::slotNewsFilter()
4779 {
4780   if (newsFilterGroup_->checkedAction()->objectName() == mainNewsFilter_) {
4781     if (newsFilterAction_ != NULL) {
4782       newsFilterAction_->setChecked(true);
4783       setNewsFilter(newsFilterAction_);
4784     } else {
4785       if (mainToolbar_->widgetForAction(newsFilter_)) {
4786         QWidget *widget = mainToolbar_->widgetForAction(newsFilter_);
4787         if (widget->underMouse()) {
4788           newsFilterMenu_->popup(widget->mapToGlobal(QPoint(0, mainToolbar_->height()-1)));
4789         }
4790       }
4791       if (feedsToolBar_->widgetForAction(newsFilter_)) {
4792         QWidget *widget = feedsToolBar_->widgetForAction(newsFilter_);
4793         if (widget->underMouse()) {
4794           newsFilterMenu_->popup(widget->mapToGlobal(QPoint(0, feedsToolBar_->height()-1)));
4795         }
4796       }
4797       if (currentNewsTab->newsToolBar_->widgetForAction(newsFilter_)) {
4798         QWidget *widget = currentNewsTab->newsToolBar_->widgetForAction(newsFilter_);
4799         if (widget->underMouse()) {
4800           newsFilterMenu_->popup(widget->mapToGlobal(QPoint(0, currentNewsTab->newsToolBar_->height()-1)));
4801         }
4802       }
4803     }
4804   } else {
4805     foreach(QAction *action, newsFilterGroup_->actions()) {
4806       if (action->objectName() == mainNewsFilter_) {
4807         action->setChecked(true);
4808         setNewsFilter(action);
4809         break;
4810       }
4811     }
4812   }
4813 }
4814 // ----------------------------------------------------------------------------
slotShowUpdateAppDlg()4815 void MainWindow::slotShowUpdateAppDlg()
4816 {
4817   UpdateAppDialog *updateAppDialog = new UpdateAppDialog(mainApp->language(), this);
4818   updateAppDialog->activateWindow();
4819   updateAppDialog->exec();
4820   delete updateAppDialog;
4821 }
4822 // ----------------------------------------------------------------------------
retranslateStrings()4823 void MainWindow::retranslateStrings()
4824 {
4825   QString str = statusUnread_->text();
4826   str = str.right(str.length() - str.indexOf(':') - 1).replace(" ", "");
4827   statusUnread_->setText(QString(" " + tr("Unread: %1") + " ").arg(str));
4828   str = statusAll_->text();
4829   str = str.right(str.length() - str.indexOf(':') - 1).replace(" ", "");
4830   statusAll_->setText(QString(" " + tr("All: %1") + " ").arg(str));
4831 
4832   str = traySystem->toolTip();
4833   QString info =
4834       "QuiteRSS\n" +
4835       QString(tr("New News: %1")).arg(str.section(": ", 1).section("\n", 0, 0)) +
4836       QString("\n") +
4837       QString(tr("Unread News: %1")).arg(str.section(": ", 2));
4838   traySystem->setToolTip(info);
4839 
4840   mainMenuButton_->setToolTip(tr("Menu"));
4841 
4842   addAct_->setText(tr("&Add"));
4843   addAct_->setToolTip(tr("Add New Feed"));
4844 
4845   addFeedAct_->setText(tr("&Feed..."));
4846   addFeedAct_->setToolTip(tr("Add New Feed"));
4847 
4848   addFeedTrayAct_->setText(tr("Add Feed..."));
4849 
4850   addFolderAct_->setText(tr("F&older..."));
4851   addFolderAct_->setToolTip(tr("Add New Folder"));
4852 
4853   openFeedNewTabAct_->setText(tr("Open in New Tab"));
4854 
4855   deleteFeedAct_->setText(tr("&Delete..."));
4856   deleteFeedAct_->setToolTip(tr("Delete Selected Feed"));
4857 
4858   importFeedsAct_->setText(tr("&Import Feeds..."));
4859   importFeedsAct_->setToolTip(tr("Import Feeds from OPML File"));
4860 
4861   exportFeedsAct_->setText(tr("&Export Feeds..."));
4862   exportFeedsAct_->setToolTip(tr("Export Feeds to OPML File"));
4863 
4864   createBackupAct_->setText(tr("&Create Backup..."));
4865   showMenuBarAct_->setText(tr("S&how Menu Bar"));
4866 
4867   exitAct_->setText(tr("E&xit"));
4868 
4869   updateFeedAct_->setText(tr("Update Feed"));
4870   updateFeedAct_->setToolTip(tr("Update Current Feed"));
4871 
4872   updateAllFeedsAct_->setText(tr("Update All"));
4873   updateAllFeedsAct_->setToolTip(tr("Update All Feeds"));
4874 
4875   stopUpdateAct_->setText(tr("Stop Update Feeds"));
4876   stopUpdateAct_->setToolTip(tr("Stop Update Feeds"));
4877 
4878   markAllFeedsRead_->setText(tr("Mark All Feeds Read"));
4879 
4880   markNewsRead_->setText(tr("Mark Read/Unread"));
4881   markNewsRead_->setToolTip(tr("Mark Current News Read/Unread"));
4882 
4883   markAllNewsRead_->setText(tr("Mark All News Read"));
4884   markAllNewsRead_->setToolTip(tr("Mark All News Read"));
4885 
4886   showDownloadManagerAct_->setText(tr("Downloads"));
4887 
4888   showCleanUpWizardAct_->setText(tr("Clean Up..."));
4889 
4890   setNewsFiltersAct_->setText(tr("News Filters..."));
4891   setFilterNewsAct_->setText(tr("Filter News..."));
4892 
4893   optionsAct_->setText(tr("Options..."));
4894   optionsAct_->setToolTip(tr("Open Options Dialog"));
4895 
4896   feedsFilter_->setText(tr("Filter Feeds"));
4897   filterFeedsAll_->setText(tr("Show All"));
4898   filterFeedsNew_->setText(tr("Show New"));
4899   filterFeedsUnread_->setText(tr("Show Unread"));
4900   filterFeedsStarred_->setText(tr("Show Starred Feeds"));
4901   filterFeedsError_->setText(tr("Show Not Working Feeds"));
4902 
4903   newsFilter_->setText(tr("Filter News"));
4904   filterNewsAll_->setText(tr("Show All"));
4905   filterNewsNew_->setText(tr("Show New"));
4906   filterNewsUnread_->setText(tr("Show Unread"));
4907   filterNewsStar_->setText(tr("Show Starred"));
4908   filterNewsNotStarred_->setText(tr("Show Not Starred"));
4909   filterNewsUnreadStar_->setText(tr("Show Unread or Starred"));
4910   filterNewsLastDay_->setText(tr("Show Last Day"));
4911   filterNewsLastWeek_->setText(tr("Show Last 7 Days"));
4912 
4913   aboutAct_ ->setText(tr("About..."));
4914   aboutAct_->setToolTip(tr("Show 'About' Dialog"));
4915 
4916   updateAppAct_->setText(tr("Check for Updates..."));
4917   reportProblemAct_->setText(tr("Report a Problem..."));
4918 
4919   openDescriptionNewsAct_->setText(tr("Open News"));
4920   openDescriptionNewsAct_->setToolTip(tr("Open News Description"));
4921   openInBrowserAct_->setText(tr("Open in Browser"));
4922   openInExternalBrowserAct_->setText(tr("Open in External Browser"));
4923   openInExternalBrowserAct_->setToolTip(tr("Open News in External Browser"));
4924   openNewsNewTabAct_->setText(tr("Open in New Tab"));
4925   openNewsNewTabAct_->setToolTip(tr("Open News in New Tab"));
4926   openNewsBackgroundTabAct_->setText(tr("Open in Background Tab"));
4927   openNewsBackgroundTabAct_->setToolTip(tr("Open News in Background Tab"));
4928   markStarAct_->setText(tr("Star"));
4929   markStarAct_->setToolTip(tr("Mark News Star"));
4930   deleteNewsAct_->setText(tr("Delete"));
4931   deleteNewsAct_->setToolTip(tr("Delete Selected News"));
4932   deleteAllNewsAct_->setText(tr("Delete All News"));
4933   deleteAllNewsAct_->setToolTip(tr("Delete All News from List"));
4934   restoreNewsAct_->setText(tr("Restore"));
4935   restoreNewsAct_->setToolTip(tr("Restore News"));
4936   copyLinkAct_->setText(tr("Copy Link"));
4937   copyLinkAct_->setToolTip(tr("Copy News Link"));
4938 
4939   restoreLastNewsAct_->setText(tr("Restore last deleted news"));
4940 
4941   markFeedRead_->setText(tr("Mark Read"));
4942   markFeedRead_->setToolTip(tr("Mark Feed Read"));
4943   feedProperties_->setText(tr("Properties"));
4944   feedProperties_->setToolTip(tr("Properties"));
4945 
4946   fileMenu_->setTitle(tr("&File"));
4947   viewMenu_->setTitle(tr("&View"));
4948   feedMenu_->setTitle(tr("Fee&ds"));
4949   newsMenu_->setTitle(tr("&News"));
4950   browserMenu_->setTitle(tr("&Browser"));
4951   toolsMenu_->setTitle(tr("&Tools"));
4952   helpMenu_->setTitle(tr("&Help"));
4953 
4954   mainToolbar_->setWindowTitle(tr("Main Toolbar"));
4955   customizeToolbarMenu_->setTitle(tr("Customize Toolbar"));
4956   customizeMainToolbarAct_->setText(tr("Main Toolbar..."));
4957   customizeMainToolbarAct2_->setText(tr("Customize Toolbar..."));
4958   customizeFeedsToolbarAct_->setText(tr("Feeds Toolbar..."));
4959   customizeNewsToolbarAct_->setText(tr("News Toolbar..."));
4960 
4961   toolBarLockAct_->setText(tr("Lock Toolbar"));
4962   toolBarHideAct_->setText(tr("Hide Toolbar"));
4963 
4964   layoutMenu_->setTitle(tr("Layout"));
4965   classicLayoutAct_->setText(tr("Classic"));
4966   newspaperLayoutAct_->setText(tr("Newspaper"));
4967   layoutToggle_->setText(tr("Layout"));
4968 
4969   styleMenu_->setTitle(tr("Application Style"));
4970   systemStyle_->setText(tr("System"));
4971   system2Style_->setText(tr("System2"));
4972   darkStyle_->setText(tr("Dark"));
4973   greenStyle_->setText(tr("Green"));
4974   orangeStyle_->setText(tr("Orange"));
4975   purpleStyle_->setText(tr("Purple"));
4976   pinkStyle_->setText(tr("Pink"));
4977   grayStyle_->setText(tr("Gray"));
4978 
4979   browserPositionMenu_->setTitle(tr("Browser Position"));
4980   topBrowserPositionAct_->setText(tr("Top"));
4981   bottomBrowserPositionAct_->setText(tr("Bottom"));
4982   rightBrowserPositionAct_->setText(tr("Right"));
4983   leftBrowserPositionAct_->setText(tr("Left"));
4984 
4985   showWindowAct_->setText(tr("Show Window"));
4986 
4987   feedKeyUpAct_->setText(tr("Previous Feed"));
4988   feedKeyDownAct_->setText(tr("Next Feed"));
4989   newsKeyUpAct_->setText(tr("Previous News"));
4990   newsKeyDownAct_->setText(tr("Next News"));
4991   newsKeyPageUpAct_->setText(tr("News Page Up"));
4992   newsKeyPageDownAct_->setText(tr("News Page Down"));
4993 
4994   nextUnreadNewsAct_->setText(tr("Next Unread News"));
4995   prevUnreadNewsAct_->setText(tr("Previous Unread News"));
4996 
4997   switchFocusAct_->setText(tr("Switch Focus to Next Panel"));
4998   switchFocusAct_->setToolTip(
4999         tr("Switch Focus to Next Panel (Tree Feeds, List News, Browser)"));
5000   switchFocusPrevAct_->setText(tr("Switch Focus to Previous Panel"));
5001   switchFocusPrevAct_->setToolTip(
5002         tr("Switch Focus to Previous Panel (Tree Feeds, Browser, List News)"));
5003 
5004   feedsWidgetVisibleAct_->setText(tr("Show/Hide Tree Feeds"));
5005 
5006   placeToTrayAct_->setText(tr("Minimize to Tray"));
5007   placeToTrayAct_->setToolTip(tr("Minimize Application to Tray"));
5008 
5009   feedsColumnsMenu_->setTitle(tr("Columns"));
5010   showUnreadCount_->setText(tr("Count Unread News"));
5011   showUndeleteCount_->setText(tr("Count All News"));
5012   showLastUpdated_->setText(tr("Last Update"));
5013 
5014   indentationFeedsTreeAct_->setText(tr("Show Indentation"));
5015 
5016   findFeedAct_->setText(tr("Search Feed"));
5017   findFeedAct_->setToolTip(tr("Search Feed"));
5018 
5019   browserZoomMenu_->setTitle(tr("Zoom"));
5020   zoomInAct_->setText(tr("Zoom In"));
5021   zoomInAct_->setToolTip(tr("Zoom in in browser"));
5022   zoomOutAct_->setText(tr("Zoom Out"));
5023   zoomOutAct_->setToolTip(tr("Zoom out in browser"));
5024   zoomTo100Act_->setText(tr("100%"));
5025   zoomTo100Act_->setToolTip(tr("Reset browser zoom"));
5026 
5027   printAct_->setText(tr("Print..."));
5028   printAct_->setToolTip(tr("Print Web Page"));
5029   printPreviewAct_->setText(tr("Print Preview..."));
5030   printPreviewAct_->setToolTip(tr("Preview Web Page"));
5031 
5032   pageUpWebViewAct_->setText(tr("Page up (Browser)"));
5033   pageDownWebViewAct_->setText(tr("Page down (Browser)"));
5034 
5035   savePageAsAct_->setText(tr("Save As..."));
5036   savePageAsAct_->setToolTip(tr("Save Page As..."));
5037   savePageAsDescriptAct_->setText(tr("Save page in database"));
5038   savePageAsDescriptAct_->setToolTip(tr("Save page in database instead of news description"));
5039 
5040   toolbarsMenu_->setTitle(tr("Show/Hide"));
5041   mainToolbarToggle_->setText(tr("Main Toolbar"));
5042   feedsToolbarToggle_->setText(tr("Feeds Toolbar"));
5043   newsToolbarToggle_->setText(tr("News Toolbar"));
5044   browserToolbarToggle_->setText(tr("Browser Toolbar"));
5045   categoriesPanelToggle_->setText(tr("Panel Categories"));
5046   statusBarToggle_->setText(tr("Status Bar"));
5047 
5048   fullScreenAct_->setText(tr("Full Screen"));
5049   fullScreenAct_->setToolTip(tr("Full Screen"));
5050 
5051   stayOnTopAct_->setText(tr("Stay On Top"));
5052   stayOnTopAct_->setToolTip(tr("Stay On Top"));
5053 
5054   categoriesLabel_->setText(tr("Categories"));
5055   if (categoriesTree_->isHidden())
5056     showCategoriesButton_->setToolTip(tr("Show Categories"));
5057   else
5058     showCategoriesButton_->setToolTip(tr("Hide Categories"));
5059 
5060   newsLabelMenuAction_->setText(tr("Label"));
5061   newsLabelAction_->setText(tr("Label"));
5062   showLabelsMenuAct_->setText(tr("Show labels menu"));
5063 
5064   closeTabAct_->setText(tr("Close Tab"));
5065   closeOtherTabsAct_->setText(tr("Close Other Tabs"));
5066   closeAllTabsAct_->setText(tr("Close All Tabs"));
5067   nextTabAct_->setText(tr("Switch to next tab"));
5068   prevTabAct_->setText(tr("Switch to previous tab"));
5069 
5070   categoriesTree_->topLevelItem(CategoriesTreeWidget::UnreadItem)->setText(0, tr("Unread"));
5071   categoriesTree_->topLevelItem(CategoriesTreeWidget::StarredItem)->setText(0, tr("Starred"));
5072   categoriesTree_->topLevelItem(CategoriesTreeWidget::DeletedItem)->setText(0, tr("Deleted"));
5073   categoriesTree_->topLevelItem(CategoriesTreeWidget::LabelsItem)->setText(0, tr("Labels"));
5074 
5075   reduceNewsListAct_->setText(tr("Decrease news list/increase browser"));
5076   increaseNewsListAct_->setText(tr("Increase news list/decrease browser"));
5077 
5078   findTextAct_->setText(tr("Find"));
5079 
5080   openHomeFeedAct_->setText(tr("Open Homepage Feed"));
5081   sortedByTitleFeedsTreeAct_->setText(tr("Sort by Name"));
5082   collapseAllFoldersAct_->setText(tr("Collapse All Folders"));
5083   expandAllFoldersAct_->setText(tr("Expand All Folders"));
5084   nextFolderAct_->setText(tr("Next Folder"));
5085   prevFolderAct_->setText(tr("Previous Folder"));
5086   expandFolderAct_->setText(tr("Expand Folder"));
5087 
5088   settingPageLabelsAct_->setText(tr("Setting Page: Labels"));
5089 
5090   shareMenuAct_->setText(tr("Share"));
5091 
5092   newsSortByMenu_->setTitle(tr("Sort By"));
5093   newsSortOrderGroup_->actions().at(0)->setText(tr("Ascending"));
5094   newsSortOrderGroup_->actions().at(1)->setText(tr("Descending"));
5095 
5096   QApplication::translate("QDialogButtonBox", "Close");
5097   QApplication::translate("QDialogButtonBox", "Cancel");
5098   QApplication::translate("QDialogButtonBox", "&Yes");
5099   QApplication::translate("QDialogButtonBox", "&No");
5100 
5101   QApplication::translate("QLineEdit", "&Undo");
5102   QApplication::translate("QLineEdit", "&Redo");
5103   QApplication::translate("QLineEdit", "Cu&t");
5104   QApplication::translate("QLineEdit", "&Copy");
5105   QApplication::translate("QLineEdit", "&Paste");
5106   QApplication::translate("QLineEdit", "Delete");
5107   QApplication::translate("QLineEdit", "Select All");
5108 
5109   QApplication::translate("QTextControl", "&Undo");
5110   QApplication::translate("QTextControl", "&Redo");
5111   QApplication::translate("QTextControl", "Cu&t");
5112   QApplication::translate("QTextControl", "&Copy");
5113   QApplication::translate("QTextControl", "&Paste");
5114   QApplication::translate("QTextControl", "Delete");
5115   QApplication::translate("QTextControl", "Select All");
5116   QApplication::translate("QTextControl", "Copy &Link Location");
5117 
5118   QApplication::translate("QAbstractSpinBox", "&Step up");
5119   QApplication::translate("QAbstractSpinBox", "Step &down");
5120   QApplication::translate("QAbstractSpinBox", "&Select All");
5121 
5122   QApplication::translate("QMultiInputContext", "Select IM");
5123 
5124   QApplication::translate("QWizard", "Cancel");
5125   QApplication::translate("QWizard", "< &Back");
5126   QApplication::translate("QWizard", "&Finish");
5127   QApplication::translate("QWizard", "&Next >");
5128 
5129   QSqlQuery q;
5130   q.exec("SELECT id, name FROM labels WHERE id <= 6");
5131   while (q.next()) {
5132     int idLabel = q.value(0).toInt();
5133     QString nameLabel = q.value(1).toString();
5134     QList<QTreeWidgetItem *> treeItems;
5135     treeItems = categoriesTree_->findItems(QString::number(idLabel),
5136                                            Qt::MatchFixedString|Qt::MatchRecursive,
5137                                            2);
5138     if (treeItems.count() && (nameLabels().at(idLabel-1) == nameLabel)) {
5139       treeItems.at(0)->setText(0, trNameLabels().at(idLabel-1));
5140       for (int i = 0; i < newsLabelGroup_->actions().count(); i++) {
5141         if (newsLabelGroup_->actions().at(i)->data().toInt() == idLabel) {
5142           newsLabelGroup_->actions().at(i)->setText(trNameLabels().at(idLabel-1));
5143           newsLabelGroup_->actions().at(i)->setToolTip(trNameLabels().at(idLabel-1));
5144           break;
5145         }
5146       }
5147       for (int i = 0; i < stackedWidget_->count(); i++) {
5148         NewsTabWidget *widget = (NewsTabWidget*)stackedWidget_->widget(i);
5149         if (widget->type_ == NewsTabWidget::TabTypeLabel) {
5150           if (widget->labelId_ == idLabel) {
5151             widget->setTextTab(trNameLabels().at(idLabel-1));
5152           }
5153         }
5154       }
5155     }
5156   }
5157 
5158   if (newsView_) {
5159     currentNewsTab->retranslateStrings();
5160   }
5161   findFeeds_->retranslateStrings();
5162   mainApp->downloadManager()->retranslateStrings();
5163   adblockIcon_->retranslateStrings();
5164   QApplication::translate("AdBlockCustomList", "Custom Rules");
5165 
5166 
5167   if ((mainApp->language() == "ar") || (mainApp->language() == "fa")) {
5168     QApplication::setLayoutDirection(Qt::RightToLeft);
5169     mainMenuButton_->setStyleSheet("#mainMenuButton { border: none; padding: 0px 5px 0px 0px; }");
5170   } else {
5171     QApplication::setLayoutDirection(Qt::LeftToRight);
5172     mainMenuButton_->setStyleSheet("#mainMenuButton { border: none; padding: 0px 0px 0px 5px; }");
5173   }
5174 
5175   /** Hack ltr <-> rtl**/
5176   int indexTab = tabBar_->addTab("");
5177   tabBar_->removeTab(indexTab);
5178 }
5179 // ----------------------------------------------------------------------------
setToolBarStyle(const QString & styleStr)5180 void MainWindow::setToolBarStyle(const QString &styleStr)
5181 {
5182   if (mainToolbar_->widgetForAction(addAct_))
5183     mainToolbar_->widgetForAction(addAct_)->setMinimumWidth(10);
5184   if (styleStr == "toolBarStyleI_") {
5185     mainToolbar_->setToolButtonStyle(Qt::ToolButtonIconOnly);
5186   } else if (styleStr == "toolBarStyleT_") {
5187     mainToolbar_->setToolButtonStyle(Qt::ToolButtonTextOnly);
5188   } else if (styleStr == "toolBarStyleTbI_") {
5189     mainToolbar_->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
5190   } else {
5191     mainToolbar_->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
5192     if (mainToolbar_->widgetForAction(addAct_))
5193       mainToolbar_->widgetForAction(addAct_)->setMinimumWidth(60);
5194   }
5195 }
5196 // ----------------------------------------------------------------------------
setToolBarIconSize(QToolBar * toolbar,const QString & iconSizeStr)5197 void MainWindow::setToolBarIconSize(QToolBar *toolbar, const QString &iconSizeStr)
5198 {
5199   if (iconSizeStr == "toolBarIconBig_") {
5200     toolbar->setIconSize(QSize(32, 32));
5201   } else if (iconSizeStr == "toolBarIconSmall_") {
5202     toolbar->setIconSize(QSize(18, 18));
5203   } else {
5204     toolbar->setIconSize(QSize(24, 24));
5205   }
5206 }
5207 
5208 /** @brief Call toolbar context menu
5209  *----------------------------------------------------------------------------*/
showContextMenuToolBar(const QPoint & pos)5210 void MainWindow::showContextMenuToolBar(const QPoint &pos)
5211 {
5212   QMenu menu;
5213   menu.addAction(customizeMainToolbarAct2_);
5214   menu.addSeparator();
5215   menu.addAction(toolBarLockAct_);
5216   menu.addAction(toolBarHideAct_);
5217 
5218   menu.exec(mainToolbar_->mapToGlobal(pos));
5219 }
5220 // ----------------------------------------------------------------------------
lockMainToolbar(bool lock)5221 void MainWindow::lockMainToolbar(bool lock)
5222 {
5223   mainToolbar_->setMovable(!lock);
5224 }
5225 // ----------------------------------------------------------------------------
hideMainToolbar()5226 void MainWindow::hideMainToolbar()
5227 {
5228   mainToolbarToggle_->setChecked(false);
5229   mainToolbar_->hide();
5230 }
5231 // ----------------------------------------------------------------------------
showFeedPropertiesDlg()5232 void MainWindow::showFeedPropertiesDlg()
5233 {
5234   if (!feedsView_->selectIndex().isValid()) {
5235     feedProperties_->setEnabled(false);
5236     return;
5237   }
5238 
5239   QPersistentModelIndex index = feedsView_->selectIndex();
5240   int feedId = feedsModel_->idByIndex(index);
5241   bool isFeed = (index.isValid() && feedsModel_->isFolder(index)) ? false : true;
5242 
5243   FeedPropertiesDialog *feedPropertiesDialog = new FeedPropertiesDialog(isFeed, this);
5244 
5245   FEED_PROPERTIES properties;
5246   FEED_PROPERTIES properties_tmp;
5247 
5248   QByteArray byteArray = feedsModel_->dataField(index, "image").toByteArray();
5249   if (!byteArray.isNull()) {
5250     QPixmap icon;
5251     icon.loadFromData(QByteArray::fromBase64(byteArray));
5252     feedPropertiesDialog->setWindowIcon(icon);
5253   } else if (isFeed) {
5254     feedPropertiesDialog->setWindowIcon(QPixmap(":/images/feed"));
5255   } else {
5256     feedPropertiesDialog->setWindowIcon(QPixmap(":/images/folder"));
5257   }
5258   properties.general.image = QByteArray::fromBase64(byteArray);
5259 
5260   QString str(feedPropertiesDialog->windowTitle() +
5261               " '" +
5262               feedsModel_->dataField(index, "text").toString() +
5263               "'");
5264   feedPropertiesDialog->setWindowTitle(str);
5265 
5266   properties.general.text =
5267       feedsModel_->dataField(index, "text").toString();
5268   properties.general.title =
5269       feedsModel_->dataField(index, "title").toString();
5270   properties.general.url =
5271       feedsModel_->dataField(index, "xmlUrl").toString();
5272   properties.general.homepage =
5273       feedsModel_->dataField(index, "htmlUrl").toString();
5274   properties.general.displayOnStartup =
5275       feedsModel_->dataField(index, "displayOnStartup").toInt();
5276   properties.display.displayEmbeddedImages =
5277       feedsModel_->dataField(index, "displayEmbeddedImages").toInt();
5278   properties.display.javaScriptEnable =
5279       feedsModel_->dataField(index, "javaScriptEnable").toInt();
5280   if (feedsModel_->dataField(index, "displayNews").toString().isEmpty())
5281     properties.display.displayNews = !showDescriptionNews_;
5282   else
5283     properties.display.displayNews =
5284         feedsModel_->dataField(index, "displayNews").toInt();
5285   properties.display.layoutDirection =
5286       feedsModel_->dataField(index, "layoutDirection").toInt();
5287 
5288   properties.general.disableUpdate =
5289       feedsModel_->dataField(index, "disableUpdate").toBool();
5290 
5291   if (feedsModel_->dataField(index, "updateIntervalEnable").isNull() ||
5292       (feedsModel_->dataField(index, "updateIntervalEnable").toInt() == -1)) {
5293     properties.general.updateEnable = updateFeedsEnable_;
5294     properties.general.updateInterval = updateFeedsInterval_;
5295     properties.general.intervalType = updateFeedsIntervalType_;
5296   } else {
5297     properties.general.updateEnable =
5298         feedsModel_->dataField(index, "updateIntervalEnable").toBool();
5299     properties.general.updateInterval =
5300         feedsModel_->dataField(index, "updateInterval").toInt();
5301     properties.general.intervalType =
5302         feedsModel_->dataField(index, "updateIntervalType").toInt();
5303   }
5304 
5305   if (feedsModel_->dataField(index, "label").toString().contains("starred"))
5306     properties.general.starred = true;
5307   else
5308     properties.general.starred = false;
5309 
5310   properties.general.duplicateNewsMode =
5311       feedsModel_->dataField(index, "duplicateNewsMode").toBool();
5312 
5313   properties.general.addSingleNewsAnyDateOn =
5314       feedsModel_->dataField(index, "addSingleNewsAnyDateOn").toBool();
5315 
5316   properties.general.avoidedOldSingleNewsDateOn =
5317       feedsModel_->dataField(index, "avoidedOldSingleNewsDateOn").toBool();
5318 
5319   properties.general.avoidedOldSingleNewsDate =
5320       feedsModel_->dataField(index, "avoidedOldSingleNewsDate").toDate();
5321 
5322   Settings settings;
5323   settings.beginGroup("NewsHeader");
5324   QString indexColumnsStr = settings.value("columns").toString();
5325   QStringList indexColumnsList = indexColumnsStr.split(",", QString::SkipEmptyParts);
5326   foreach (QString indexStr, indexColumnsList) {
5327     properties.columnDefault.columns.append(indexStr.toInt());
5328   }
5329   NewsTabWidget *widget = (NewsTabWidget*)stackedWidget_->widget(TAB_WIDGET_PERMANENT);
5330   int sortBy = settings.value("sortBy", widget->newsModel_->fieldIndex("published")).toInt();
5331   properties.columnDefault.sortBy = sortBy;
5332   int sortType = settings.value("sortOrder", Qt::DescendingOrder).toInt();
5333   properties.columnDefault.sortType = sortType;
5334   settings.endGroup();
5335 
5336   if (feedsModel_->dataField(index, "columns").toString().isEmpty()) {
5337     widget = (NewsTabWidget*)stackedWidget_->widget(TAB_WIDGET_PERMANENT);
5338     QListIterator<QAction *> iter(widget->newsHeader_->viewMenu_->actions());
5339     while (iter.hasNext()) {
5340       QAction *nextAction = iter.next();
5341       properties.column.indexList.append(nextAction->data().toInt());
5342       properties.column.nameList.append(nextAction->text());
5343       if (nextAction->isChecked())
5344         properties.column.columns.append(nextAction->data().toInt());
5345     }
5346     int section = widget->newsHeader_->sortIndicatorSection();
5347     properties.column.sortBy = section;
5348     if (widget->newsHeader_->sortIndicatorOrder() == Qt::AscendingOrder) {
5349       properties.column.sortType = 0;
5350     } else {
5351       properties.column.sortType = 1;
5352     }
5353   } else {
5354     widget = (NewsTabWidget*)stackedWidget_->widget(TAB_WIDGET_PERMANENT);
5355     QListIterator<QAction *> iter(widget->newsHeader_->viewMenu_->actions());
5356     while (iter.hasNext()) {
5357       QAction *nextAction = iter.next();
5358       properties.column.indexList.append(nextAction->data().toInt());
5359       properties.column.nameList.append(nextAction->text());
5360     }
5361     indexColumnsStr = feedsModel_->dataField(index, "columns").toString();
5362     indexColumnsList = indexColumnsStr.split(",", QString::SkipEmptyParts);
5363     foreach (QString indexStr, indexColumnsList) {
5364       properties.column.columns.append(indexStr.toInt());
5365     }
5366     properties.column.sortBy = feedsModel_->dataField(index, "sort").toInt();
5367     properties.column.sortType = feedsModel_->dataField(index, "sortType").toInt();
5368   }
5369 
5370   properties.authentication.on = false;
5371   if (feedsModel_->dataField(index, "authentication").toInt() == 1) {
5372     properties.authentication.on = true;
5373   }
5374   QUrl url(feedsModel_->dataField(index, "xmlUrl").toString());
5375   QSqlQuery q;
5376   q.prepare("SELECT username, password FROM passwords WHERE server=?");
5377   q.addBindValue(url.host());
5378   q.exec();
5379   if (q.next()) {
5380     properties.authentication.user = q.value(0).toString();
5381     properties.authentication.pass = QString::fromUtf8(QByteArray::fromBase64(q.value(1).toByteArray()));
5382   }
5383 
5384   properties.status.feedStatus = feedsModel_->dataField(index, "status").toString();
5385 
5386   QDateTime dtLocalTime = QDateTime::currentDateTime();
5387   QDateTime dtUTC = QDateTime(dtLocalTime.date(), dtLocalTime.time(), Qt::UTC);
5388   int nTimeShift = dtLocalTime.secsTo(dtUTC);
5389 
5390   QDateTime dt = QDateTime::fromString(
5391         feedsModel_->dataField(index, "created").toString(),
5392         Qt::ISODate);
5393   properties.status.createdTime = dt.addSecs(nTimeShift);
5394 
5395   dt = QDateTime::fromString(
5396         feedsModel_->dataField(index, "updated").toString(),
5397         Qt::ISODate);
5398   properties.status.lastUpdate = dt.addSecs(nTimeShift);
5399 
5400   dt = QDateTime::fromString(
5401         feedsModel_->dataField(index, "lastBuildDate").toString(),
5402         Qt::ISODate);
5403   properties.status.lastBuildDate = dt.addSecs(nTimeShift);
5404 
5405   properties.status.undeleteCount = feedsModel_->dataField(index, "undeleteCount").toInt();
5406   properties.status.newCount      = feedsModel_->dataField(index, "newCount").toInt();
5407   properties.status.unreadCount   = feedsModel_->dataField(index, "unread").toInt();
5408   properties.status.description   = feedsModel_->dataField(index, "description").toString();
5409 
5410   properties.status.feedsCount = 0;
5411   if (!isFeed) {
5412     QQueue<int> parentIds;
5413     parentIds.enqueue(feedId);
5414     while (!parentIds.empty()) {
5415       int parentId = parentIds.dequeue();
5416       q.exec(QString("SELECT id, xmlUrl FROM feeds WHERE parentId='%1'").arg(parentId));
5417       while (q.next()) {
5418         QString xmlUrl = q.value(1).toString();
5419         if (xmlUrl.isEmpty())
5420           parentIds.enqueue(q.value(0).toInt());
5421         else
5422           properties.status.feedsCount++;
5423       }
5424     }
5425   }
5426 
5427   feedPropertiesDialog->setFeedProperties(properties);
5428   properties_tmp = properties;
5429 
5430   int result = feedPropertiesDialog->exec();
5431   if (result == QDialog::Rejected) {
5432     delete feedPropertiesDialog;
5433     return;
5434   }
5435 
5436   if (!mainApp->storeDBMemory())
5437     db_.transaction();
5438 
5439   properties = feedPropertiesDialog->getFeedProperties();
5440   delete feedPropertiesDialog;
5441 
5442   index = feedsModel_->indexById(feedId);
5443 
5444   q.prepare("UPDATE feeds SET text = ?, xmlUrl = ?, displayOnStartup = ?, "
5445             "displayEmbeddedImages = ?, displayNews = ?, layoutDirection = ?, "
5446             "label = ?, duplicateNewsMode = ?, addSingleNewsAnyDateOn = ?, avoidedOldSingleNewsDateOn = ?, avoidedOldSingleNewsDate = ?,"
5447             " authentication = ?, disableUpdate = ?, "
5448             "javaScriptEnable = ? WHERE id == ?");
5449   q.addBindValue(properties.general.text);
5450   q.addBindValue(properties.general.url);
5451   q.addBindValue(properties.general.displayOnStartup);
5452   q.addBindValue(properties.display.displayEmbeddedImages);
5453   q.addBindValue(properties.display.displayNews);
5454   q.addBindValue(properties.display.layoutDirection);
5455   if (properties.general.starred)
5456     q.addBindValue("starred");
5457   else
5458     q.addBindValue("");
5459   q.addBindValue(properties.general.duplicateNewsMode ? 1 : 0);
5460   q.addBindValue(properties.general.addSingleNewsAnyDateOn ? 1 : 0);
5461   q.addBindValue(properties.general.avoidedOldSingleNewsDateOn ? 1 : 0);
5462   q.addBindValue(properties.general.avoidedOldSingleNewsDate);
5463   q.addBindValue(properties.authentication.on ? 1 : 0);
5464   q.addBindValue(properties.general.disableUpdate ? 1 : 0);
5465   q.addBindValue(properties.display.javaScriptEnable);
5466   q.addBindValue(feedId);
5467   q.exec();
5468 
5469 
5470   indexColumnsStr = "";
5471   if ((properties.column.columns != properties.columnDefault.columns) ||
5472       (properties.column.sortBy != properties.columnDefault.sortBy) ||
5473       (properties.column.sortType != properties.columnDefault.sortType)) {
5474     for (int i = 0; i < properties.column.columns.count(); ++i) {
5475       int index = properties.column.columns.at(i);
5476       indexColumnsStr.append(",");
5477       indexColumnsStr.append(QString::number(index));
5478     }
5479     indexColumnsStr.append(",");
5480   } else {
5481     properties.column.sortBy = 0;
5482     properties.column.sortType = 0;
5483   }
5484 
5485   q.prepare("UPDATE feeds SET columns = ?, sort = ?, sortType = ? WHERE id == ?");
5486   q.addBindValue(indexColumnsStr);
5487   q.addBindValue(properties.column.sortBy);
5488   q.addBindValue(properties.column.sortType);
5489   q.addBindValue(feedId);
5490   q.exec();
5491 
5492   QModelIndex indexColumns = feedsModel_->indexSibling(index, "columns");
5493   QModelIndex indexSort = feedsModel_->indexSibling(index, "sort");
5494   QModelIndex indexSortType = feedsModel_->indexSibling(index, "sortType");
5495   feedsModel_->setData(indexColumns, indexColumnsStr);
5496   feedsModel_->setData(indexSort, properties.column.sortBy);
5497   feedsModel_->setData(indexSortType, properties.column.sortType);
5498 
5499   if (!isFeed) {
5500     QQueue<int> parentIds;
5501     parentIds.enqueue(feedId);
5502     while (!parentIds.empty()) {
5503       int parentId = parentIds.dequeue();
5504       q.exec(QString("SELECT id, xmlUrl FROM feeds WHERE parentId='%1'").
5505              arg(parentId));
5506       while (q.next()) {
5507         int id = q.value(0).toInt();
5508         QString xmlUrl = q.value(1).toString();
5509 
5510         QSqlQuery q1;
5511         q1.prepare("UPDATE feeds SET columns = ?, sort = ?, sortType = ? WHERE id == ?");
5512         q1.addBindValue(indexColumnsStr);
5513         q1.addBindValue(properties.column.sortBy);
5514         q1.addBindValue(properties.column.sortType);
5515         q1.addBindValue(id);
5516         q1.exec();
5517 
5518         QPersistentModelIndex index1 = feedsModel_->indexById(id);
5519         indexColumns = feedsModel_->indexSibling(index1, "columns");
5520         indexSort = feedsModel_->indexSibling(index1, "sort");
5521         indexSortType = feedsModel_->indexSibling(index1, "sortType");
5522         feedsModel_->setData(indexColumns, indexColumnsStr);
5523         feedsModel_->setData(indexSort, properties.column.sortBy);
5524         feedsModel_->setData(indexSortType, properties.column.sortType);
5525 
5526         if (currentNewsTab->feedId_ == id)
5527           currentNewsTab->newsHeader_->setColumns(index1);
5528 
5529         if (xmlUrl.isEmpty())
5530           parentIds.enqueue(id);
5531       }
5532     }
5533   }
5534 
5535   if (currentNewsTab->feedId_ == feedId)
5536     currentNewsTab->newsHeader_->setColumns(index);
5537 
5538 
5539   if (!(!feedsModel_->dataField(index, "authentication").toInt() && !properties.authentication.on)) {
5540     q.prepare("SELECT * FROM passwords WHERE server=?");
5541     q.addBindValue(url.host());
5542     q.exec();
5543     if (q.next()) {
5544       q.prepare("UPDATE passwords SET username = ?, password = ? WHERE server=?");
5545       q.addBindValue(properties.authentication.user);
5546       q.addBindValue(properties.authentication.pass.toUtf8().toBase64());
5547       q.addBindValue(url.host());
5548       q.exec();
5549     } else if (properties.authentication.on) {
5550       q.prepare("INSERT INTO passwords (server, username, password) "
5551                 "VALUES (:server, :username, :password)");
5552       q.bindValue(":server", url.host());
5553       q.bindValue(":username", properties.authentication.user);
5554       q.bindValue(":password", properties.authentication.pass.toUtf8().toBase64());
5555       q.exec();
5556     }
5557   }
5558 
5559   QPersistentModelIndex indexText    = feedsModel_->indexSibling(index, "text");
5560   QPersistentModelIndex indexUrl     = feedsModel_->indexSibling(index, "xmlUrl");
5561   QPersistentModelIndex indexStartup = feedsModel_->indexSibling(index, "displayOnStartup");
5562   QModelIndex indexImages  = feedsModel_->indexSibling(index, "displayEmbeddedImages");
5563   QModelIndex indexNews    = feedsModel_->indexSibling(index, "displayNews");
5564   QModelIndex indexRTL     = feedsModel_->indexSibling(index, "layoutDirection");
5565   QModelIndex indexLabel   = feedsModel_->indexSibling(index, "label");
5566   QModelIndex indexDuplicate = feedsModel_->indexSibling(index, "duplicateNewsMode");
5567   QModelIndex indexaddSingleNewsAnyDateOn = feedsModel_->indexSibling(index, "addSingleNewsAnyDateOn");
5568   QModelIndex indexavoidedOldSingleNewsDateOn = feedsModel_->indexSibling(index, "avoidedOldSingleNewsDateOn");
5569   QModelIndex indexavoidedOldSingleNewsDate = feedsModel_->indexSibling(index, "avoidedOldSingleNewsDate");
5570   QModelIndex indexAuthentication = feedsModel_->indexSibling(index, "authentication");
5571   QModelIndex indexDisableUpdate = feedsModel_->indexSibling(index, "disableUpdate");
5572   QModelIndex indexJavaScript = feedsModel_->indexSibling(index, "javaScriptEnable");
5573   feedsModel_->setData(indexText, properties.general.text);
5574   feedsModel_->setData(indexUrl, properties.general.url);
5575   feedsModel_->setData(indexStartup, properties.general.displayOnStartup);
5576   feedsModel_->setData(indexImages, properties.display.displayEmbeddedImages);
5577   feedsModel_->setData(indexNews, properties.display.displayNews);
5578   feedsModel_->setData(indexRTL, properties.display.layoutDirection);
5579   feedsModel_->setData(indexLabel, properties.general.starred ? "starred" : "");
5580   feedsModel_->setData(indexDuplicate, properties.general.duplicateNewsMode ? 1 : 0);
5581   feedsModel_->setData(indexaddSingleNewsAnyDateOn, properties.general.addSingleNewsAnyDateOn ? 1 : 0);
5582   feedsModel_->setData(indexavoidedOldSingleNewsDateOn, properties.general.avoidedOldSingleNewsDateOn ? 1 : 0);
5583   feedsModel_->setData(indexavoidedOldSingleNewsDate, properties.general.avoidedOldSingleNewsDate);
5584   feedsModel_->setData(indexAuthentication, properties.authentication.on ? 1 : 0);
5585   feedsModel_->setData(indexDisableUpdate, properties.general.disableUpdate ? 1 : 0);
5586   feedsModel_->setData(indexJavaScript, properties.display.javaScriptEnable);
5587 
5588   if (!properties.general.updateEnable ||
5589       (properties.general.updateEnable != updateFeedsEnable_) ||
5590       (properties.general.updateInterval != updateFeedsInterval_) ||
5591       (properties.general.intervalType != updateFeedsIntervalType_)) {
5592     q.prepare("UPDATE feeds SET updateIntervalEnable = ?, updateInterval = ?, "
5593               "updateIntervalType = ? WHERE id == ?");
5594     q.addBindValue(properties.general.updateEnable ? 1 : 0);
5595     q.addBindValue(properties.general.updateInterval);
5596     q.addBindValue(properties.general.intervalType);
5597     q.addBindValue(feedId);
5598     q.exec();
5599 
5600     QPersistentModelIndex indexUpdateEnable   = feedsModel_->indexSibling(index, "updateIntervalEnable");
5601     QPersistentModelIndex indexUpdateInterval = feedsModel_->indexSibling(index, "updateInterval");
5602     QPersistentModelIndex indexIntervalType   = feedsModel_->indexSibling(index, "updateIntervalType");
5603     feedsModel_->setData(indexUpdateEnable, properties.general.updateEnable ? 1 : 0);
5604     feedsModel_->setData(indexUpdateInterval, properties.general.updateInterval);
5605     feedsModel_->setData(indexIntervalType, properties.general.intervalType);
5606 
5607     int updateInterval = properties.general.updateInterval;
5608     int updateIntervalType = properties.general.intervalType;
5609     if (updateIntervalType == 0)
5610       updateInterval = updateInterval*60;
5611     else if (updateIntervalType == 1)
5612       updateInterval = updateInterval*60*60;
5613 
5614     if (!isFeed) {
5615       QQueue<int> parentIds;
5616       parentIds.enqueue(feedId);
5617       while (!parentIds.empty()) {
5618         int parentId = parentIds.dequeue();
5619         q.exec(QString("SELECT id, xmlUrl FROM feeds WHERE parentId='%1'").
5620                arg(parentId));
5621         while (q.next()) {
5622           int id = q.value(0).toInt();
5623           QString xmlUrl = q.value(1).toString();
5624 
5625           QSqlQuery q1;
5626           q1.prepare("UPDATE feeds SET updateIntervalEnable = ?, updateInterval = ?, "
5627                      "updateIntervalType = ? WHERE id == ?");
5628           q1.addBindValue(properties.general.updateEnable ? 1 : 0);
5629           q1.addBindValue(properties.general.updateInterval);
5630           q1.addBindValue(properties.general.intervalType);
5631           q1.addBindValue(id);
5632           q1.exec();
5633 
5634           QPersistentModelIndex index1 = feedsModel_->indexById(id);
5635           indexUpdateEnable   = feedsModel_->indexSibling(index1, "updateIntervalEnable");
5636           indexUpdateInterval = feedsModel_->indexSibling(index1, "updateInterval");
5637           indexIntervalType   = feedsModel_->indexSibling(index1, "updateIntervalType");
5638           feedsModel_->setData(indexUpdateEnable, properties.general.updateEnable ? 1 : 0);
5639           feedsModel_->setData(indexUpdateInterval, properties.general.updateInterval);
5640           feedsModel_->setData(indexIntervalType, properties.general.intervalType);
5641 
5642           if (!xmlUrl.isEmpty()) {
5643             if (properties.general.updateEnable) {
5644               updateFeedsIntervalSec_.insert(id, updateInterval);
5645               updateFeedsTimeCount_.insert(id, 0);
5646             } else {
5647               updateFeedsIntervalSec_.remove(id);
5648               updateFeedsTimeCount_.remove(id);
5649             }
5650           } else {
5651             parentIds.enqueue(id);
5652           }
5653         }
5654       }
5655     } else {
5656       if (properties.general.updateEnable) {
5657         updateFeedsIntervalSec_.insert(feedId, updateInterval);
5658         updateFeedsTimeCount_.insert(feedId, 0);
5659       } else {
5660         updateFeedsIntervalSec_.remove(feedId);
5661         updateFeedsTimeCount_.remove(feedId);
5662       }
5663     }
5664   } else {
5665     q.prepare("UPDATE feeds SET updateIntervalEnable = -1 WHERE id == ?");
5666     q.addBindValue(feedId);
5667     q.exec();
5668 
5669     QPersistentModelIndex indexUpdateEnable = feedsModel_->indexSibling(index, "updateIntervalEnable");
5670     feedsModel_->setData(indexUpdateEnable, "-1");
5671 
5672     updateFeedsIntervalSec_.remove(feedId);
5673     updateFeedsTimeCount_.remove(feedId);
5674   }
5675 
5676   if (properties.general.image != properties_tmp.general.image) {
5677     q.prepare("UPDATE feeds SET image = ? WHERE id == ?");
5678     q.addBindValue(properties.general.image.toBase64());
5679     q.addBindValue(feedId);
5680     q.exec();
5681     slotIconFeedUpdate(feedId, properties.general.image);
5682   }
5683 
5684   if ((properties.display.layoutDirection  != properties_tmp.display.layoutDirection) &&
5685       !isFeed) {
5686     QQueue<int> parentIds;
5687     parentIds.enqueue(feedId);
5688     while (!parentIds.empty()) {
5689       int parentId = parentIds.dequeue();
5690       q.exec(QString("SELECT id, xmlUrl FROM feeds WHERE parentId='%1'").arg(parentId));
5691       while (q.next()) {
5692         int id = q.value(0).toInt();
5693         QString xmlUrl = q.value(1).toString();
5694 
5695         QSqlQuery q1;
5696         q1.prepare("UPDATE feeds SET layoutDirection = ? WHERE id == ?");
5697         q1.addBindValue(properties.display.layoutDirection);
5698         q1.addBindValue(id);
5699         q1.exec();
5700 
5701         QPersistentModelIndex index1 = feedsModel_->indexById(id);
5702         indexRTL = feedsModel_->indexSibling(index1, "layoutDirection");
5703         feedsModel_->setData(indexRTL, properties.display.layoutDirection);
5704 
5705         for (int i = 0; i < stackedWidget_->count(); i++) {
5706           NewsTabWidget *widget = (NewsTabWidget*)stackedWidget_->widget(i);
5707           if (widget->feedId_ == id) {
5708             widget->setSettings();
5709           }
5710         }
5711 
5712         if (xmlUrl.isEmpty())
5713           parentIds.enqueue(id);
5714       }
5715     }
5716   }
5717 
5718   for (int i = 0; i < stackedWidget_->count(); i++) {
5719     NewsTabWidget *widget = (NewsTabWidget*)stackedWidget_->widget(i);
5720     if (widget->feedId_ == feedId) {
5721       if (properties.general.text != properties_tmp.general.text) {
5722         widget->setTextTab(properties.general.text);
5723       }
5724       if ((properties.display.layoutDirection != properties_tmp.display.layoutDirection) ||
5725           (properties.display.javaScriptEnable != properties_tmp.display.javaScriptEnable)) {
5726         widget->setSettings();
5727       }
5728     }
5729   }
5730 
5731   if ((properties.general.disableUpdate != properties_tmp.general.disableUpdate) &&
5732       !isFeed) {
5733     QQueue<int> parentIds;
5734     parentIds.enqueue(feedId);
5735     while (!parentIds.empty()) {
5736       int parentId = parentIds.dequeue();
5737       q.exec(QString("SELECT id, xmlUrl FROM feeds WHERE parentId='%1'").arg(parentId));
5738       while (q.next()) {
5739         int id = q.value(0).toInt();
5740         QString xmlUrl = q.value(1).toString();
5741 
5742         QSqlQuery q1;
5743         q1.prepare("UPDATE feeds SET disableUpdate = ? WHERE id == ?");
5744         q1.addBindValue(properties.general.disableUpdate ? 1 : 0);
5745         q1.addBindValue(id);
5746         q1.exec();
5747 
5748         QPersistentModelIndex index1 = feedsModel_->indexById(id);
5749         indexDisableUpdate = feedsModel_->indexSibling(index1, "disableUpdate");
5750         feedsModel_->setData(indexDisableUpdate, properties.general.disableUpdate ? 1 : 0);
5751 
5752         if (xmlUrl.isEmpty())
5753           parentIds.enqueue(id);
5754       }
5755     }
5756   }
5757 
5758   if (!mainApp->storeDBMemory())
5759     db_.commit();
5760 }
5761 
5762 /** @brief Update tray information: icon and tooltip text
5763  *---------------------------------------------------------------------------*/
slotRefreshInfoTray(int newCount,int unreadCount)5764 void MainWindow::slotRefreshInfoTray(int newCount, int unreadCount)
5765 {
5766   if (!unreadCount)
5767     categoriesTree_->topLevelItem(CategoriesTreeWidget::UnreadItem)->setText(4, "");
5768   else
5769     categoriesTree_->topLevelItem(CategoriesTreeWidget::UnreadItem)->setText(4, QString("(%1)").arg(unreadCount));
5770   QFont font = categoriesTree_->topLevelItem(CategoriesTreeWidget::UnreadItem)->font(0);
5771   if (unreadCount)
5772     font.setBold(true);
5773   else
5774     font.setBold(false);
5775   categoriesTree_->topLevelItem(CategoriesTreeWidget::UnreadItem)->setFont(0, font);
5776 
5777   if (!showTrayIcon_) return;
5778 
5779   // Setting tooltip text
5780   QString info =
5781       "QuiteRSS\n" +
5782       QString(tr("New News: %1")).arg(newCount) +
5783       QString("\n") +
5784       QString(tr("Unread News: %1")).arg(unreadCount);
5785   traySystem->setToolTip(info);
5786 
5787   // Display new number or unread number of news
5788   if (behaviorIconTray_ > CHANGE_ICON_TRAY) {
5789     int trayCount = (behaviorIconTray_ == UNREAD_COUNT_ICON_TRAY) ? unreadCount : newCount;
5790     // Display icon with number
5791     if (trayCount != 0) {
5792       // Prepare number
5793       QString trayCountStr;
5794       QFont font("Consolas");
5795       if (trayCount > 99) {
5796         font.setBold(false);
5797         if (trayCount < 1000) {
5798           font.setPixelSize(60);
5799           trayCountStr = QString::number(trayCount);
5800         } else {
5801           font.setPixelSize(86);
5802           trayCountStr = "#";
5803         }
5804       } else {
5805         font.setBold(true);
5806         font.setPixelSize(90);
5807         trayCountStr = QString::number(trayCount);
5808       }
5809 
5810       // Draw icon, text above it, and set this icon to tray icon
5811       QPixmap icon(128, 128);
5812       icon.fill(Qt::transparent);
5813       QPainter trayPainter;
5814       trayPainter.begin(&icon);
5815       trayPainter.setRenderHint(QPainter::SmoothPixmapTransform, true);
5816       trayPainter.setRenderHint(QPainter::TextAntialiasing, true);
5817       QRect rectangle(0, 0, 128, 128);
5818       QLinearGradient gradient(rectangle.bottomLeft(), rectangle.topLeft());
5819       QColor color("#117C04");
5820       gradient.setColorAt(0, color.light());
5821       gradient.setColorAt(0.5, color);
5822       gradient.setColorAt(1, color.light());
5823       trayPainter.setBrush(gradient);
5824       trayPainter.drawRoundedRect(rectangle, 20, 20);
5825       trayPainter.setFont(font);
5826       trayPainter.setPen("#FFFFFF");
5827       trayPainter.drawText(rectangle, Qt::AlignVCenter | Qt::AlignHCenter,
5828                            trayCountStr);
5829       trayPainter.end();
5830       traySystem->setIcon(icon);
5831     }
5832     // Draw icon without number
5833     else {
5834       traySystem->setIcon(QIcon(":/images/quiterss128"));
5835     }
5836   }
5837 }
5838 
5839 /** @brief Prepare feed icon for storing in DB
5840  *---------------------------------------------------------------------------*/
slotIconFeedPreparing(QString feedUrl,QByteArray byteArray,QString format)5841 void MainWindow::slotIconFeedPreparing(QString feedUrl, QByteArray byteArray,
5842                                        QString format)
5843 {
5844   QPixmap icon;
5845   if (icon.loadFromData(byteArray)) {
5846     icon = icon.scaled(16, 16, Qt::IgnoreAspectRatio,
5847                        Qt::SmoothTransformation);
5848     QByteArray faviconData;
5849     QBuffer    buffer(&faviconData);
5850     buffer.open(QIODevice::WriteOnly);
5851     if (icon.save(&buffer, "ICO")) {
5852       emit signalIconFeedReady(feedUrl, faviconData);
5853     }
5854   } else if (icon.loadFromData(byteArray, format.toUtf8().data())) {
5855     icon = icon.scaled(16, 16, Qt::IgnoreAspectRatio,
5856                        Qt::SmoothTransformation);
5857     QByteArray faviconData;
5858     QBuffer    buffer(&faviconData);
5859     buffer.open(QIODevice::WriteOnly);
5860     if (icon.save(&buffer, "ICO")) {
5861       emit signalIconFeedReady(feedUrl, faviconData);
5862     }
5863   }
5864 }
5865 
5866 /** @brief Update feed icon in model and view
5867  *---------------------------------------------------------------------------*/
slotIconFeedUpdate(int feedId,QByteArray faviconData)5868 void MainWindow::slotIconFeedUpdate(int feedId, QByteArray faviconData)
5869 {
5870   QModelIndex index = feedsModel_->indexById(feedId);
5871   if (index.isValid()) {
5872     QModelIndex indexImage = feedsModel_->indexSibling(index, "image");
5873     feedsModel_->setData(indexImage, faviconData.toBase64());
5874     feedsView_->viewport()->update();
5875   }
5876 
5877   if (defaultIconFeeds_) return;
5878 
5879   for (int i = 0; i < stackedWidget_->count(); i++) {
5880     NewsTabWidget *widget = (NewsTabWidget*)stackedWidget_->widget(i);
5881     if (widget->feedId_ == feedId) {
5882       QPixmap iconTab;
5883       if (!faviconData.isNull()) {
5884         iconTab.loadFromData(faviconData);
5885       } else {
5886         iconTab.load(":/images/feed");
5887       }
5888       widget->newsIconTitle_->setPixmap(iconTab);
5889     }
5890   }
5891   if (currentNewsTab->type_ < NewsTabWidget::TabTypeWeb)
5892     currentNewsTab->newsView_->viewport()->update();
5893 }
5894 // ----------------------------------------------------------------------------
slotPlaySound(const QString & path)5895 void MainWindow::slotPlaySound(const QString &path)
5896 {
5897   QString soundPath = mainApp->absolutePath(path);
5898 
5899   if (!QFile::exists(soundPath)) {
5900     qWarning() << QString("Error playing sound: %1").arg(soundPath);
5901     return;
5902   }
5903 
5904   bool playing = false;
5905   Settings settings;
5906   bool useMediaPlayer = settings.value("Settings/useMediaPlayer", true).toBool();
5907 
5908   if (useMediaPlayer) {
5909 #ifdef HAVE_QT5
5910     if (mediaPlayer_ == NULL) {
5911       playlist_ = new QMediaPlaylist(this);
5912       mediaPlayer_ = new QMediaPlayer(this);
5913       mediaPlayer_->setPlaylist(playlist_);
5914       connect(mediaPlayer_, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),
5915               this, SLOT(mediaStatusChanged(QMediaPlayer::MediaStatus)));
5916       connect(mediaPlayer_, SIGNAL(error(QMediaPlayer::Error)),
5917               this, SLOT(mediaError(QMediaPlayer::Error)));
5918     }
5919 
5920     playlist_->addMedia(QUrl::fromLocalFile(soundPath));
5921     if (playlist_->currentIndex() == -1) {
5922       playlist_->setCurrentIndex(1);
5923       mediaPlayer_->play();
5924     }
5925 
5926     playing = true;
5927 #else
5928 #ifdef HAVE_PHONON
5929     if (mediaPlayer_ == NULL) {
5930       mediaPlayer_ = new Phonon::MediaObject(this);
5931       audioOutput_ = new Phonon::AudioOutput(Phonon::MusicCategory, this);
5932       Phonon::createPath(mediaPlayer_, audioOutput_);
5933       connect(mediaPlayer_, SIGNAL(stateChanged(Phonon::State,Phonon::State)),
5934               this, SLOT(mediaStateChanged(Phonon::State,Phonon::State)));
5935     }
5936 
5937     if (mediaPlayer_->state() == Phonon::ErrorState)
5938       mediaPlayer_->clear();
5939 
5940     if ((mediaPlayer_->state() != Phonon::PausedState) &&
5941         (mediaPlayer_->state() != Phonon::StoppedState)) {
5942       mediaPlayer_->enqueue(soundPath);
5943     }
5944     else {
5945       mediaPlayer_->setCurrentSource(soundPath);
5946     }
5947     mediaPlayer_->play();
5948 
5949     playing = true;
5950 #endif
5951 #endif
5952   }
5953 
5954   if (!playing) {
5955 #if defined(Q_OS_WIN) || defined(Q_OS_OS2)
5956     QSound::play(soundPath);
5957 #else
5958     QProcess::startDetached(QString("play %1").arg(soundPath));
5959 #endif
5960   }
5961 }
5962 
5963 #ifdef HAVE_QT5
mediaStatusChanged(QMediaPlayer::MediaStatus status)5964 void MainWindow::mediaStatusChanged(QMediaPlayer::MediaStatus status)
5965 {
5966   if (status == QMediaPlayer::EndOfMedia) {
5967     playlist_->removeMedia(0);
5968   }
5969 }
5970 
mediaError(QMediaPlayer::Error error)5971 void MainWindow::mediaError(QMediaPlayer::Error error)
5972 {
5973   QTextCodec *codec = QTextCodec::codecForLocale();
5974   qCritical() << QString("Error Media: %1 - %2").
5975                  arg(error).
5976                  arg(codec->toUnicode(mediaPlayer_->errorString().toUtf8()));
5977 }
5978 #endif
5979 
5980 #ifdef HAVE_PHONON
mediaStateChanged(Phonon::State newstate,Phonon::State)5981 void MainWindow::mediaStateChanged(Phonon::State newstate, Phonon::State)
5982 {
5983   if (newstate == Phonon::ErrorState) {
5984     QTextCodec *codec = QTextCodec::codecForLocale();
5985     qCritical() << QString("Error Phonon: %1 - %2").
5986                    arg(mediaPlayer_->errorType()).
5987                    arg(codec->toUnicode(mediaPlayer_->errorString().toUtf8()));
5988   }
5989 }
5990 #endif
5991 
slotPlaySoundNewNews()5992 void MainWindow::slotPlaySoundNewNews()
5993 {
5994   if (!playSoundNewNews_ && soundNewNews_) {
5995     slotPlaySound(soundNotifyPath_);
5996     playSoundNewNews_ = true;
5997   }
5998 }
5999 
6000 // ----------------------------------------------------------------------------
showNewsFiltersDlg(bool newFilter)6001 void MainWindow::showNewsFiltersDlg(bool newFilter)
6002 {
6003   NewsFiltersDialog *newsFiltersDialog = new NewsFiltersDialog(this);
6004   if (newFilter) {
6005     newsFiltersDialog->filtersTree_->setCurrentItem(
6006           newsFiltersDialog->filtersTree_->topLevelItem(
6007             newsFiltersDialog->filtersTree_->topLevelItemCount()-1));
6008   }
6009 
6010   newsFiltersDialog->exec();
6011 
6012   delete newsFiltersDialog;
6013 }
6014 // ----------------------------------------------------------------------------
showFilterRulesDlg()6015 void MainWindow::showFilterRulesDlg()
6016 {
6017   if (!feedsView_->selectIndex().isValid()) return;
6018 
6019   int feedId = feedsView_->selectId_;
6020 
6021   FilterRulesDialog *filterRulesDialog = new FilterRulesDialog(
6022         this, -1, feedId);
6023 
6024   QModelIndex index = feedsModel_->indexById(feedId);
6025   QString text = feedsModel_->dataField(index, "text").toString();
6026   filterRulesDialog->filterName_->setText(QString("'%1'").arg(text));
6027 
6028   int result = filterRulesDialog->exec();
6029   if (result == QDialog::Rejected) {
6030     delete filterRulesDialog;
6031     return;
6032   }
6033 
6034   delete filterRulesDialog;
6035 
6036   showNewsFiltersDlg(true);
6037 }
6038 // ----------------------------------------------------------------------------
slotUpdateAppCheck()6039 void MainWindow::slotUpdateAppCheck()
6040 {
6041   updateAppDialog_ = new UpdateAppDialog(mainApp->language(), this, false);
6042   connect(updateAppDialog_, SIGNAL(signalNewVersion(QString)),
6043           this, SLOT(slotNewVersion(QString)), Qt::QueuedConnection);
6044 }
6045 // ----------------------------------------------------------------------------
slotNewVersion(const QString & newVersion)6046 void MainWindow::slotNewVersion(const QString &newVersion)
6047 {
6048   updateAppDialog_->disconnectObjects();
6049   delete updateAppDialog_;
6050   updateAppDialog_ = NULL;
6051 
6052   if (!newVersion.isEmpty()) {
6053     traySystem->showMessage(tr("Check for updates"),
6054                             tr("A new version of QuiteRSS..."));
6055     connect(traySystem, SIGNAL(messageClicked()),
6056             this, SLOT(slotShowUpdateAppDlg()));
6057   }
6058 }
6059 
6060 /** @brief Process Key_Up in feeds tree
6061  *---------------------------------------------------------------------------*/
slotFeedUpPressed()6062 void MainWindow::slotFeedUpPressed()
6063 {
6064   QModelIndex indexBefore = feedsView_->currentIndex();
6065   QModelIndex indexAfter;
6066 
6067   // Jump to bottom in case of the most top index
6068   if (!indexBefore.isValid())
6069     indexAfter = feedsProxyModel_->index(feedsProxyModel_->rowCount()-1, "text");
6070   else
6071     indexAfter = feedsView_->indexAbove(indexBefore);
6072 
6073   // There is no "upper" index
6074   if (!indexAfter.isValid()) return;
6075 
6076   feedsView_->setCurrentIndex(indexAfter);
6077   slotFeedClicked(indexAfter);
6078 }
6079 
6080 /** @brief Process Key_Down in feeds tree
6081  *---------------------------------------------------------------------------*/
slotFeedDownPressed()6082 void MainWindow::slotFeedDownPressed()
6083 {
6084   QModelIndex indexBefore = feedsView_->currentIndex();
6085   QModelIndex indexAfter;
6086 
6087   // Jump to top in case of the most bottom index
6088   if (!indexBefore.isValid())
6089     indexAfter = feedsProxyModel_->index(0, "text");
6090   else
6091     indexAfter = feedsView_->indexBelow(indexBefore);
6092 
6093   // There is no "downer" index
6094   if (!indexAfter.isValid()) return;
6095 
6096   feedsView_->setCurrentIndex(indexAfter);
6097   slotFeedClicked(indexAfter);
6098 }
6099 
6100 /** @brief Process previous feed shortcut
6101  *---------------------------------------------------------------------------*/
slotFeedPrevious()6102 void MainWindow::slotFeedPrevious()
6103 {
6104   QModelIndex indexBefore = feedsView_->currentIndex();
6105   if (!indexBefore.isValid())
6106     indexBefore = feedsProxyModel_->index(feedsProxyModel_->rowCount()-1, feedsView_->columnIndex("text"));
6107 
6108   QModelIndex indexAfter = feedsView_->indexPrevious(indexBefore);
6109 
6110   // There is no "upper" index
6111   if (!indexAfter.isValid()) return;
6112   feedsView_->clearSelection();
6113 
6114   feedsView_->setCurrentIndex(indexAfter);
6115   slotFeedClicked(indexAfter);
6116 }
6117 
6118 /** @brief Process next feed shortcut
6119  *---------------------------------------------------------------------------*/
slotFeedNext()6120 void MainWindow::slotFeedNext()
6121 {
6122   QModelIndex indexBefore = feedsView_->currentIndex();
6123   if (!indexBefore.isValid())
6124     indexBefore = feedsProxyModel_->index(0, feedsView_->columnIndex("text"));
6125 
6126   QModelIndex indexAfter = feedsView_->indexNext(indexBefore);
6127 
6128   // There is no "downer" index
6129   if (!indexAfter.isValid()) return;
6130   feedsView_->clearSelection();
6131 
6132   feedsView_->setCurrentIndex(indexAfter);
6133   slotFeedClicked(indexAfter);
6134 }
6135 
6136 /** @brief Process Key_Home in feeds tree
6137  *---------------------------------------------------------------------------*/
slotFeedHomePressed()6138 void MainWindow::slotFeedHomePressed()
6139 {
6140   QModelIndex index = feedsProxyModel_->index(0, "text");
6141   feedsView_->setCurrentIndex(index);
6142   slotFeedClicked(index);
6143 }
6144 
6145 /** @brief Process Key_End in feeds tree
6146  *---------------------------------------------------------------------------*/
slotFeedEndPressed()6147 void MainWindow::slotFeedEndPressed()
6148 {
6149   QModelIndex index = feedsProxyModel_->index(feedsProxyModel_->rowCount()-1, "text");
6150   feedsView_->setCurrentIndex(index);
6151   slotFeedClicked(index);
6152 }
6153 
6154 /** @brief Process pressing PageUp-key in feeds tree
6155  *----------------------------------------------------------------------------*/
slotFeedPageUpPressed()6156 void MainWindow::slotFeedPageUpPressed()
6157 {
6158   int row = 0;
6159   QModelIndex index = feedsView_->currentIndex();
6160   if (index.isValid())
6161     row = index.row() - feedsView_->verticalScrollBar()->pageStep();
6162   if (row < 0)
6163     row = 0;
6164   index = feedsProxyModel_->index(row, "text");
6165 
6166   feedsView_->setCurrentIndex(index);
6167   slotFeedClicked(index);
6168 }
6169 
6170 /** @brief Process pressing PageDown-key in feeds tree
6171  *----------------------------------------------------------------------------*/
slotFeedPageDownPressed()6172 void MainWindow::slotFeedPageDownPressed()
6173 {
6174   int row = 0;
6175   QModelIndex index = feedsView_->currentIndex();
6176   if (index.isValid())
6177     row = index.row() + feedsView_->verticalScrollBar()->pageStep();
6178   if (row >= feedsProxyModel_->rowCount())
6179     row = feedsProxyModel_->rowCount()-1;
6180   index = feedsProxyModel_->index(row, "text");
6181 
6182   feedsView_->setCurrentIndex(index);
6183   slotFeedClicked(index);
6184 }
6185 
6186 /** @brief Set application style
6187  *---------------------------------------------------------------------------*/
setStyleApp(QAction * pAct)6188 void MainWindow::setStyleApp(QAction *pAct)
6189 {
6190   Settings settings;
6191 
6192   settings.setValue("Settings/styleApplication", pAct->objectName());
6193 
6194   QString fileName(mainApp->resourcesDir());
6195   if (pAct->objectName() == "systemStyle_") {
6196     fileName.append("/style/system.qss");
6197   } else if (pAct->objectName() == "system2Style_") {
6198     fileName.append("/style/system2.qss");
6199   } else if (pAct->objectName() == "darkStyle_") {
6200     fileName.append("/style/dark.qss");
6201   } else if (pAct->objectName() == "orangeStyle_") {
6202     fileName.append("/style/orange.qss");
6203   } else if (pAct->objectName() == "purpleStyle_") {
6204     fileName.append("/style/purple.qss");
6205   } else if (pAct->objectName() == "pinkStyle_") {
6206     fileName.append("/style/pink.qss");
6207   } else if (pAct->objectName() == "grayStyle_") {
6208     fileName.append("/style/gray.qss");
6209   } else {
6210     fileName.append("/style/green.qss");
6211   }
6212 
6213   QString userStyleBrowser = "";
6214   if (pAct->objectName() == "darkStyle_") {
6215     userStyleBrowser = mainApp->styleSheetWebDarkFile();
6216     feedsModel_->textColor_ = "#e1e0e1";
6217     newsListTextColor_ = "#e1e0e1";
6218     newsListBackgroundColor_ = "#464546";
6219     newNewsTextColor_ = "#e1e0e1";
6220     unreadNewsTextColor_ = "#e1e0e1";
6221     newsBackgroundColor_ = "#464546";
6222     newsTitleBackgroundColor_ = "#464546";
6223     titleColor_ = "#e1e0e1";
6224     newsTextColor_ = "#e1e0e1";
6225     dateColor_ = "#a5a5a5";
6226     authorColor_ = "#a5a5a5";
6227     notifierTextColor_ = "#e1e0e1";
6228     notifierBackgroundColor_ = "#464546";
6229     transparencyNotify_ = 40;
6230     alternatingRowColors_ = "#3a393a";
6231   } else {
6232     QString windowTextColor = qApp->palette().brush(QPalette::WindowText).color().name();
6233     feedsModel_->textColor_ = windowTextColor;
6234     newsListTextColor_ = windowTextColor;
6235     newsListBackgroundColor_ = "";
6236     newNewsTextColor_ = windowTextColor;
6237     unreadNewsTextColor_ = windowTextColor;
6238     newsBackgroundColor_ = "#FFFFFF";
6239     newsTitleBackgroundColor_ = "#FFFFFF";
6240     titleColor_ = "#0066CC";
6241     newsTextColor_ = "#000000";
6242     dateColor_ = "#666666";
6243     authorColor_ = "#666666";
6244     notifierTextColor_ = windowTextColor;
6245     notifierBackgroundColor_ = "#FFFFFF";
6246     transparencyNotify_ = 60;
6247     alternatingRowColors_ = qApp->palette().color(QPalette::AlternateBase).name();
6248   }
6249 
6250   settings.beginGroup("Settings");
6251   settings.setValue("userStyleBrowser", userStyleBrowser);
6252   settings.setValue("transparencyNotify", transparencyNotify_);
6253   settings.endGroup();
6254   settings.beginGroup("Color");
6255   settings.setValue("feedsListTextColor", feedsModel_->textColor_);
6256   settings.setValue("newsListTextColor", newsListTextColor_);
6257   settings.setValue("newsListBackgroundColor", newsListBackgroundColor_);
6258   settings.setValue("newNewsTextColor", newNewsTextColor_);
6259   settings.setValue("unreadNewsTextColor", unreadNewsTextColor_);
6260   settings.setValue("titleColor", titleColor_);
6261   settings.setValue("newsTextColor", newsTextColor_);
6262   settings.setValue("newsTitleBackgroundColor", newsTitleBackgroundColor_);
6263   settings.setValue("newsBackgroundColor", newsBackgroundColor_);
6264   settings.setValue("dateColor", dateColor_);
6265   settings.setValue("authorColor", authorColor_);
6266   settings.setValue("notifierTextColor", notifierTextColor_);
6267   settings.setValue("notifierBackgroundColor", notifierBackgroundColor_);
6268   settings.setValue("alternatingRowColors", alternatingRowColors_);
6269   settings.endGroup();
6270 
6271   QFile file(fileName);
6272   if (!file.open(QFile::ReadOnly)) {
6273     file.setFileName(":/style/systemStyle");
6274     file.open(QFile::ReadOnly);
6275   }
6276   qApp->setStyleSheet(QLatin1String(file.readAll()));
6277   file.close();
6278 
6279   mainSplitter_->setStyleSheet(
6280         QString("QSplitter::handle {background: qlineargradient("
6281                 "x1: 0, y1: 0, x2: 0, y2: 1,"
6282                 "stop: 0 %1, stop: 0.07 %2);}").
6283         arg(feedsPanel_->palette().background().color().name()).
6284         arg(qApp->palette().color(QPalette::Dark).name()));
6285 
6286   mainApp->reloadUserStyleBrowser();
6287   if (currentNewsTab != NULL) {
6288     if (currentNewsTab->type_ < NewsTabWidget::TabTypeWeb)
6289       currentNewsTab->newsHeader_->saveStateColumns(currentNewsTab);
6290     currentNewsTab->setSettings(false);
6291   }
6292 }
6293 
6294 /** Switch focus forward between feed tree, news list and browser
6295  *---------------------------------------------------------------------------*/
slotSwitchFocus()6296 void MainWindow::slotSwitchFocus()
6297 {
6298   if (feedsView_->hasFocus()) {
6299     newsView_->setFocus();
6300   } else if (newsView_->hasFocus()) {
6301     currentNewsTab->webView_->setFocus();
6302   } else {
6303     feedsView_->setFocus();
6304   }
6305 }
6306 
6307 /** @brief Switch focus backward between feed tree, news list and browser
6308  *---------------------------------------------------------------------------*/
slotSwitchPrevFocus()6309 void MainWindow::slotSwitchPrevFocus()
6310 {
6311   if (feedsView_->hasFocus()) {
6312     currentNewsTab->webView_->setFocus();
6313   } else if (currentNewsTab->webView_->hasFocus()) {
6314     newsView_->setFocus();
6315   } else {
6316     feedsView_->setFocus();
6317   }
6318 }
6319 
6320 /** @brief Open feed in a new tab
6321  *---------------------------------------------------------------------------*/
slotOpenFeedNewTab()6322 void MainWindow::slotOpenFeedNewTab()
6323 {
6324   if (stackedWidget_->count() && currentNewsTab->type_ < NewsTabWidget::TabTypeWeb) {
6325     setFeedRead(currentNewsTab->type_, currentNewsTab->feedId_, FeedReadSwitchingTab, currentNewsTab);
6326     currentNewsTab->newsHeader_->saveStateColumns(currentNewsTab);
6327     Settings settings;
6328     settings.setValue("NewsTabSplitterState", currentNewsTab->newsTabWidgetSplitter_->saveState());
6329   }
6330 
6331   QModelIndexList indexList = feedsView_->selectionModel()->selectedRows(0);
6332   if (indexList.count() <= 1) {
6333     indexList.clear();
6334     indexList.append(feedsProxyModel_->mapFromSource(feedsView_->selectIndex()));
6335   }
6336   QModelIndex index = indexList.takeFirst();
6337   feedsView_->selectIdEn_ = false;
6338   feedsView_->setCurrentIndex(index);
6339   slotFeedSelected(feedsProxyModel_->mapToSource(index), true);
6340 
6341   foreach (QModelIndex indexProxy, indexList) {
6342     QModelIndex index = feedsProxyModel_->mapToSource(indexProxy);
6343     creatFeedTab(feedsModel_->dataField(index, "id").toInt(),
6344                  feedsModel_->dataField(index, "parentId").toInt());
6345   }
6346 }
6347 
slotOpenCategoryNewTab()6348 void MainWindow::slotOpenCategoryNewTab()
6349 {
6350   slotCategoriesClicked(categoriesTree_->currentItem(), 0, true);
6351 }
6352 
6353 /** @brief Close tab with \a index
6354  *---------------------------------------------------------------------------*/
slotCloseTab(int index)6355 void MainWindow::slotCloseTab(int index)
6356 {
6357   if (index != 0) {
6358     NewsTabWidget *widget = (NewsTabWidget*)stackedWidget_->widget(index);
6359 
6360     setFeedRead(widget->type_, widget->feedId_, FeedReadClosingTab, widget);
6361 
6362     stackedWidget_->removeWidget(widget);
6363     tabBar_->removeTab(index);
6364     widget->disconnectObjects();
6365     widget->newsTitleLabel_->deleteLater();
6366     widget->deleteLater();
6367   }
6368 }
6369 
6370 /** @brief Switch to tab with index \a index
6371  *---------------------------------------------------------------------------*/
slotTabCurrentChanged(int index)6372 void MainWindow::slotTabCurrentChanged(int index)
6373 {
6374   if (!stackedWidget_->count()) return;
6375   if (tabBar_->closingTabState_ == TabBar::CloseTabOtherIndex) return;
6376 
6377   NewsTabWidget *widget = (NewsTabWidget*)stackedWidget_->widget(index);
6378 
6379   if ((widget->type_ == NewsTabWidget::TabTypeFeed) || (widget->type_ >= NewsTabWidget::TabTypeWeb))
6380     categoriesTree_->setCurrentIndex(QModelIndex());
6381   if (widget->type_ != NewsTabWidget::TabTypeFeed) {
6382     feedsView_->setCurrentIndex(QModelIndex());
6383     feedProperties_->setEnabled(false);
6384   }
6385 
6386   if (index == TAB_WIDGET_PERMANENT) {
6387     feedsWidgetVisibleAct_->setChecked(showFeedsTabPermanent_);
6388     slotVisibledFeedsWidget();
6389   } else {
6390     if (hideFeedsOpenTab_) {
6391       feedsWidgetVisibleAct_->setChecked(false);
6392       slotVisibledFeedsWidget();
6393     }
6394   }
6395 
6396   stackedWidget_->setCurrentIndex(index);
6397 
6398   if (!updateCurrentTab_) return;
6399 
6400   if ((tabBar_->closingTabState_ == TabBar::CloseTabIdle) && (currentNewsTab->type_ < NewsTabWidget::TabTypeWeb)) {
6401     setFeedRead(currentNewsTab->type_, currentNewsTab->feedId_, FeedReadSwitchingTab, currentNewsTab);
6402 
6403     currentNewsTab->newsHeader_->saveStateColumns(currentNewsTab);
6404     Settings settings;
6405     settings.setValue("NewsTabSplitterState", currentNewsTab->newsTabWidgetSplitter_->saveState());
6406   }
6407 
6408   if (widget->type_ == NewsTabWidget::TabTypeFeed) {
6409     if (widget->feedId_ == 0)
6410       widget->hide();
6411     currentNewsTab = (NewsTabWidget*)stackedWidget_->widget(index);
6412     currentNewsTab->setSettings(false);
6413     currentNewsTab->retranslateStrings();
6414     currentNewsTab->setBrowserPosition();
6415 
6416     newsModel_ = currentNewsTab->newsModel_;
6417     newsView_ = currentNewsTab->newsView_;
6418 
6419     QModelIndex feedIndex = feedsProxyModel_->mapFromSource(feedsModel_->indexById(widget->feedId_));
6420     feedsView_->setCurrentIndex(feedIndex);
6421     feedProperties_->setEnabled(feedIndex.isValid());
6422 
6423     setFeedsFilter(false);
6424 
6425     slotUpdateNews(NewsTabWidget::RefreshWithPos);
6426     if (widget->isVisible())
6427       newsView_->setFocus();
6428     else
6429       feedsView_->setFocus();
6430 
6431     statusUnread_->setVisible(widget->feedId_);
6432     statusAll_->setVisible(widget->feedId_);
6433   } else if (widget->type_ == NewsTabWidget::TabTypeWeb) {
6434     statusUnread_->setVisible(false);
6435     statusAll_->setVisible(false);
6436     currentNewsTab = widget;
6437     currentNewsTab->setSettings(false);
6438     currentNewsTab->retranslateStrings();
6439     currentNewsTab->webView_->setFocus();
6440   } else if (widget->type_ == NewsTabWidget::TabTypeDownloads) {
6441     statusUnread_->setVisible(false);
6442     statusAll_->setVisible(false);
6443     mainApp->downloadManager()->show();
6444     currentNewsTab = widget;
6445     currentNewsTab->retranslateStrings();
6446   } else {
6447     QList<QTreeWidgetItem *> treeItems;
6448     if (widget->type_ == NewsTabWidget::TabTypeLabel) {
6449       treeItems = categoriesTree_->findItems(QString::number(widget->labelId_),
6450                                              Qt::MatchFixedString|Qt::MatchRecursive,
6451                                              2);
6452     } else {
6453       treeItems = categoriesTree_->findItems(QString::number(widget->type_),
6454                                              Qt::MatchFixedString,
6455                                              1);
6456     }
6457     categoriesTree_->setCurrentItem(treeItems.at(0));
6458 
6459     currentNewsTab = (NewsTabWidget*)stackedWidget_->widget(index);
6460     currentNewsTab->setSettings(false);
6461     currentNewsTab->retranslateStrings();
6462     currentNewsTab->setBrowserPosition();
6463 
6464     newsModel_ = currentNewsTab->newsModel_;
6465     newsView_ = currentNewsTab->newsView_;
6466 
6467     slotUpdateNews(NewsTabWidget::RefreshWithPos);
6468     newsView_->setFocus();
6469 
6470     int unreadCount = widget->getUnreadCount(categoriesTree_->currentItem()->text(4));
6471     int allCount = widget->newsModel_->rowCount();
6472     statusUnread_->setText(QString(" " + tr("Unread: %1") + " ").arg(unreadCount));
6473     statusAll_->setText(QString(" " + tr("All: %1") + " ").arg(allCount));
6474 
6475     statusUnread_->setVisible(widget->type_ != NewsTabWidget::TabTypeDel);
6476     statusAll_->setVisible(true);
6477   }
6478 
6479   setTextTitle(widget->newsTitleLabel_->toolTip(), widget);
6480 }
6481 
6482 /** @brief Process tab moving
6483  *----------------------------------------------------------------------------*/
slotTabMoved(int fromIndex,int toIndex)6484 void MainWindow::slotTabMoved(int fromIndex, int toIndex)
6485 {
6486   stackedWidget_->insertWidget(toIndex, stackedWidget_->widget(fromIndex));
6487 }
6488 
6489 /** @brief Manage displaying columns in feed tree
6490  *---------------------------------------------------------------------------*/
feedsColumnVisible(QAction * action)6491 void MainWindow::feedsColumnVisible(QAction *action)
6492 {
6493   int idx = action->data().toInt();
6494   if (action->isChecked())
6495     feedsView_->showColumn(idx);
6496   else
6497     feedsView_->hideColumn(idx);
6498 }
6499 
setNewsLayout(QAction * action)6500 void MainWindow::setNewsLayout(QAction *action)
6501 {
6502   newsLayout_ = action->data().toInt();
6503   switch (newsLayout_) {
6504   case 1:
6505     layoutToggle_->setIcon(QIcon(":/images/layout_newspaper"));
6506     break;
6507   default:
6508     layoutToggle_->setIcon(QIcon(":/images/layout_classic"));
6509   }
6510   currentNewsTab->setNewsLayout();
6511 }
6512 
setNewsLayout()6513 void MainWindow::setNewsLayout()
6514 {
6515   if ((newsLayout_ + 1) >= layoutGroup_->actions().count())
6516     layoutGroup_->actions().at(0)->setChecked(true);
6517   else
6518     layoutGroup_->actions().at(newsLayout_ + 1)->setChecked(true);
6519   setNewsLayout(layoutGroup_->checkedAction());
6520 }
6521 
6522 /** @brief Set browser position
6523  *---------------------------------------------------------------------------*/
setBrowserPosition(QAction * action)6524 void MainWindow::setBrowserPosition(QAction *action)
6525 {
6526   browserPosition_ = action->data().toInt();
6527   currentNewsTab->setBrowserPosition();
6528 }
6529 
6530 /** @brief Create tab with browser only (without news list)
6531  *---------------------------------------------------------------------------*/
createWebTab(QUrl url)6532 QWebPage *MainWindow::createWebTab(QUrl url)
6533 {
6534   NewsTabWidget *widget = new NewsTabWidget(this, NewsTabWidget::TabTypeWeb);
6535   int indexTab = addTab(widget);
6536   widget->setTextTab(tr("Loading..."));
6537 
6538   if (openNewsTab_ == NEW_TAB_FOREGROUND) {
6539     currentNewsTab = widget;
6540     emit signalSetCurrentTab(indexTab);
6541   }
6542 
6543   widget->setSettings();
6544   widget->retranslateStrings();
6545 
6546   openNewsTab_ = 0;
6547 
6548   if (!url.isEmpty()) {
6549       widget->locationBar_->setText(url.toString());
6550       widget->webView_->load(url);
6551     }
6552 
6553   return widget->webView_->page();
6554 }
6555 // ----------------------------------------------------------------------------
creatFeedTab(int feedId,int feedParId)6556 void MainWindow::creatFeedTab(int feedId, int feedParId)
6557 {
6558   QSqlQuery q;
6559   q.exec(QString("SELECT text, image, currentNews, xmlUrl FROM feeds WHERE id=='%1'").
6560          arg(feedId));
6561 
6562   if (q.next()) {
6563     NewsTabWidget *widget = new NewsTabWidget(this, NewsTabWidget::TabTypeFeed, feedId, feedParId);
6564     addTab(widget);
6565     widget->setSettings();
6566     widget->retranslateStrings();
6567     widget->setBrowserPosition();
6568 
6569     bool isFeed = true;
6570     if (q.value(3).toString().isEmpty())
6571       isFeed = false;
6572 
6573     // Set icon and title for tab
6574     QPixmap iconTab;
6575     QByteArray byteArray = q.value(1).toByteArray();
6576     if (!isFeed) {
6577       iconTab.load(":/images/folder");
6578     } else {
6579       if (byteArray.isNull() || defaultIconFeeds_) {
6580         iconTab.load(":/images/feed");
6581       } else if (isFeed) {
6582         iconTab.loadFromData(QByteArray::fromBase64(byteArray));
6583       }
6584     }
6585     widget->newsIconTitle_->setPixmap(iconTab);
6586     widget->setTextTab(q.value(0).toString());
6587 
6588     QString feedIdFilter;
6589     if (feedsModel_->isFolder(feedsModel_->indexById(feedId))) {
6590       feedIdFilter = QString("(%1) AND ").arg(getIdFeedsString(feedId));
6591     } else {
6592       feedIdFilter = QString("feedId=%1 AND ").arg(feedId);
6593     }
6594 
6595     if (newsFilterGroup_->checkedAction()->objectName() == "filterNewsAll_") {
6596       feedIdFilter.append("deleted = 0");
6597     } else if (newsFilterGroup_->checkedAction()->objectName() == "filterNewsNew_") {
6598       feedIdFilter.append(QString("new = 1 AND deleted = 0"));
6599     } else if (newsFilterGroup_->checkedAction()->objectName() == "filterNewsUnread_") {
6600       feedIdFilter.append(QString("read < 2 AND deleted = 0"));
6601     } else if (newsFilterGroup_->checkedAction()->objectName() == "filterNewsStar_") {
6602       feedIdFilter.append(QString("starred = 1 AND deleted = 0"));
6603     } else if (newsFilterGroup_->checkedAction()->objectName() == "filterNewsNotStarred_") {
6604       feedIdFilter.append(QString("starred = 0 AND deleted = 0"));
6605     } else if (newsFilterGroup_->checkedAction()->objectName() == "filterNewsUnreadStar_") {
6606       feedIdFilter.append(QString("(read < 2 OR starred = 1) AND deleted = 0"));
6607     } else if (newsFilterGroup_->checkedAction()->objectName() == "filterNewsLastDay_") {
6608       feedIdFilter.append(QString("(published >= datetime('now', '-1 day')) AND deleted = 0"));
6609     } else if (newsFilterGroup_->checkedAction()->objectName() == "filterNewsLastWeek_") {
6610       feedIdFilter.append(QString("(published >= datetime('now', '-7 day')) AND deleted = 0"));
6611     }
6612     widget->newsModel_->setFilter(feedIdFilter);
6613 
6614     if (widget->newsModel_->rowCount() != 0) {
6615       while (widget->newsModel_->canFetchMore())
6616         widget->newsModel_->fetchMore();
6617     }
6618 
6619     currentNewsTab->loadNewspaper();
6620 
6621     // focus feed has displayed before
6622     int newsRow = -1;
6623     int newsId = widget->newsModel_->index(newsRow, widget->newsModel_->fieldIndex("id")).data(Qt::EditRole).toInt();
6624     if (openingFeedAction_ == 0) {
6625       QModelIndex index = newsModel_->index(0, newsModel_->fieldIndex("id"));
6626       QModelIndexList indexList = newsModel_->match(index, Qt::EditRole, newsId);
6627       if (indexList.count()) newsRow = indexList.first().row();
6628     } else if (openingFeedAction_ == 1) newsRow = 0;
6629 
6630     widget->newsView_->setCurrentIndex(widget->newsModel_->index(newsRow, widget->newsModel_->fieldIndex("title")));
6631     if (newsRow == -1) widget->newsView_->verticalScrollBar()->setValue(newsRow);
6632 
6633     if ((openingFeedAction_ < 2) && openNewsWebViewOn_) {
6634       widget->slotNewsViewSelected(widget->newsModel_->index(newsRow, widget->newsModel_->fieldIndex("title")));
6635     } else {
6636       widget->slotNewsViewSelected(widget->newsModel_->index(-1, widget->newsModel_->fieldIndex("title")));
6637       QSqlQuery q;
6638       QString qStr = QString("UPDATE feeds SET currentNews='%1' WHERE id=='%2'").
6639           arg(newsId).arg(feedId);
6640       q.exec(qStr);
6641     }
6642   }
6643 }
6644 
6645 /** @brief Open news using Enter key
6646  *---------------------------------------------------------------------------*/
slotOpenNewsWebView()6647 void MainWindow::slotOpenNewsWebView()
6648 {
6649   if (!newsView_->hasFocus()) return;
6650   currentNewsTab->slotNewsViewSelected(newsView_->currentIndex());
6651 }
6652 // ----------------------------------------------------------------------------
slotNewsUpPressed()6653 void MainWindow::slotNewsUpPressed()
6654 {
6655   currentNewsTab->slotNewsUpPressed();
6656 }
6657 // ----------------------------------------------------------------------------
slotNewsDownPressed()6658 void MainWindow::slotNewsDownPressed()
6659 {
6660   currentNewsTab->slotNewsDownPressed();
6661 }
6662 // ----------------------------------------------------------------------------
slotNewsPageUpPressed()6663 void MainWindow::slotNewsPageUpPressed()
6664 {
6665   currentNewsTab->slotNewsPageUpPressed();
6666 }
6667 // ----------------------------------------------------------------------------
slotNewsPageDownPressed()6668 void MainWindow::slotNewsPageDownPressed()
6669 {
6670   currentNewsTab->slotNewsPageDownPressed();
6671 }
6672 // ----------------------------------------------------------------------------
markNewsRead()6673 void MainWindow::markNewsRead()
6674 {
6675   currentNewsTab->markNewsRead();
6676 }
6677 // ----------------------------------------------------------------------------
markAllNewsRead()6678 void MainWindow::markAllNewsRead()
6679 {
6680   currentNewsTab->markAllNewsRead();
6681 }
6682 // ----------------------------------------------------------------------------
markNewsStar()6683 void MainWindow::markNewsStar()
6684 {
6685   currentNewsTab->markNewsStar();
6686 }
6687 // ----------------------------------------------------------------------------
deleteNews()6688 void MainWindow::deleteNews()
6689 {
6690   currentNewsTab->deleteNews();
6691 }
6692 // ----------------------------------------------------------------------------
deleteAllNewsList()6693 void MainWindow::deleteAllNewsList()
6694 {
6695   currentNewsTab->deleteAllNewsList();
6696 }
6697 // ----------------------------------------------------------------------------
restoreNews()6698 void MainWindow::restoreNews()
6699 {
6700   currentNewsTab->restoreNews();
6701 }
6702 // ----------------------------------------------------------------------------
openInBrowserNews()6703 void MainWindow::openInBrowserNews()
6704 {
6705   currentNewsTab->openInBrowserNews();
6706 }
6707 // ----------------------------------------------------------------------------
openInExternalBrowserNews()6708 void MainWindow::openInExternalBrowserNews()
6709 {
6710   currentNewsTab->openInExternalBrowserNews();
6711 }
6712 // ----------------------------------------------------------------------------
slotOpenNewsNewTab()6713 void MainWindow::slotOpenNewsNewTab()
6714 {
6715   openNewsTab_ = NEW_TAB_FOREGROUND;
6716   currentNewsTab->openNewsNewTab();
6717 }
6718 // ----------------------------------------------------------------------------
slotOpenNewsBackgroundTab()6719 void MainWindow::slotOpenNewsBackgroundTab()
6720 {
6721   openNewsTab_ = NEW_TAB_BACKGROUND;
6722   currentNewsTab->openNewsNewTab();
6723 }
6724 
6725 /** @brief Copy news URL-link
6726  *----------------------------------------------------------------------------*/
slotCopyLinkNews()6727 void MainWindow::slotCopyLinkNews()
6728 {
6729   currentNewsTab->slotCopyLinkNews();
6730 }
6731 
slotShowLabelsMenu()6732 void MainWindow::slotShowLabelsMenu()
6733 {
6734   currentNewsTab->showLabelsMenu();
6735 }
6736 // ----------------------------------------------------------------------------
slotPageUpWebView()6737 void MainWindow::slotPageUpWebView()
6738 {
6739   QKeyEvent keyEvent(QEvent::KeyPress, Qt::Key_PageUp, Qt::NoModifier);
6740   QApplication::sendEvent(currentNewsTab->webView_->page(), &keyEvent);
6741 }
6742 
slotPageDownWebView()6743 void MainWindow::slotPageDownWebView()
6744 {
6745   QKeyEvent keyEvent(QEvent::KeyPress, Qt::Key_PageDown, Qt::NoModifier);
6746   QApplication::sendEvent(currentNewsTab->webView_->page(), &keyEvent);
6747 }
6748 /** @brief Reload full model
6749  * @details Performs: reload model, reset proxy model, restore focus
6750  *---------------------------------------------------------------------------*/
feedsModelReload(bool checkFilter)6751 void MainWindow::feedsModelReload(bool checkFilter)
6752 {
6753   if (checkFilter) {
6754     if (feedsFilterGroup_->checkedAction()->objectName() != "filterFeedsAll_") {
6755       setFeedsFilter(false);
6756     }
6757     slotFeedsViewportUpdate();
6758     return;
6759   }
6760 
6761   int topRow = feedsView_->verticalScrollBar()->value();
6762   QModelIndex feedIndex = feedsProxyModel_->mapToSource(feedsView_->currentIndex());
6763   int feedId = feedsModel_->idByIndex(feedIndex);
6764 
6765   feedsView_->refresh();
6766 
6767   feedIndex = feedsProxyModel_->mapFromSource(feedId);
6768   feedsView_->selectIdEn_ = false;
6769   feedsView_->setCurrentIndex(feedIndex);
6770   feedsView_->verticalScrollBar()->setValue(topRow);
6771 }
6772 // ----------------------------------------------------------------------------
setCurrentTab(int index,bool updateCurrentTab)6773 void MainWindow::setCurrentTab(int index, bool updateCurrentTab)
6774 {
6775   updateCurrentTab_ = updateCurrentTab;
6776   tabBar_->setCurrentIndex(index);
6777   updateCurrentTab_ = true;
6778 }
6779 
6780 /** @brief Set focus to search field (CTRL+F)
6781  *---------------------------------------------------------------------------*/
findText()6782 void MainWindow::findText()
6783 {
6784   if (currentNewsTab->type_ < NewsTabWidget::TabTypeWeb) {
6785     if (!currentNewsTab->findText_->hasFocus())
6786       currentNewsTab->findText_->setFocus();
6787     else
6788       newsView_->setFocus();
6789   }
6790 }
6791 
6792 /** @brief Show notification on inbox news
6793  *---------------------------------------------------------------------------*/
showNotification(bool bShowRecentNews)6794 void MainWindow::showNotification(bool bShowRecentNews/*=false*/)
6795 {
6796   Settings settings;
6797   settings.setValue("Flags/updatingFeeds", false);
6798 
6799   bool showNotify = true;
6800 
6801   if (showNotifyInactiveApp_)
6802   {
6803     showNotify = !isActiveWindow();
6804   }
6805 
6806   NewNewsData& curNews = (bShowRecentNews ? recentNews : newNews);
6807 
6808   if (curNews.idFeedList_.isEmpty() || !showNotify || !showNotifyOn_)
6809   {
6810     clearNotification();
6811     return;
6812   }
6813 
6814   if (fullscreenModeNotify_) {
6815 #if defined(Q_OS_WIN)
6816     HWND hWnd = GetForegroundWindow();
6817     RECT appBounds;
6818     RECT rc;
6819     GetWindowRect(GetDesktopWindow(), &rc);
6820 
6821     if ((hWnd != GetDesktopWindow())
6822    #ifdef HAVE_QT5
6823        && (hWnd != GetShellWindow())
6824    #endif
6825        ) {
6826       GetWindowRect(hWnd, &appBounds);
6827       if ((rc.top == appBounds.top) && (rc.bottom == appBounds.bottom) &&
6828           (rc.left == appBounds.left) && (rc.right == appBounds.right)) {
6829         return;
6830       }
6831     }
6832 #endif
6833   }
6834 
6835   timerTrayOpenNotify.stop();
6836 
6837 
6838   if (notificationWidget != NULL)
6839   {
6840     delete notificationWidget;
6841   }
6842 
6843   notificationWidget = new NotificationWidget(curNews.idFeedList_, curNews.cntNewsList_,
6844                                               idColorList_, colorList_, this);
6845 
6846   if (!bShowRecentNews)
6847   {
6848     clearNotification();
6849   }
6850 
6851   connect(notificationWidget, SIGNAL(signalShow()), this, SLOT(showWindows()));
6852   connect(notificationWidget, SIGNAL(signalClose()),
6853           this, SLOT(deleteNotification()));
6854   connect(notificationWidget, SIGNAL(signalOpenNews(int, int)),
6855           this, SLOT(slotOpenNew(int, int)));
6856   connect(notificationWidget, SIGNAL(signalOpenExternalBrowser(QUrl)),
6857           this, SLOT(slotOpenNewBrowser(QUrl)));
6858   connect(notificationWidget, SIGNAL(signalMarkRead(int,int,int)),
6859           this, SLOT(slotMarkReadNewsInNotification(int,int,int)));
6860   connect(notificationWidget, SIGNAL(signalDeleteNews(int,int)),
6861           this, SLOT(slotDeleteNewsInNotification(int,int)));
6862   connect(notificationWidget, SIGNAL(signalMarkAllRead()),
6863           this, SLOT(slotMarkAllReadNewsInNotification()));
6864 
6865   notificationWidget->show();
6866 }
6867 
6868 /** @brief Delete notification widget
6869  *---------------------------------------------------------------------------*/
deleteNotification()6870 void MainWindow::deleteNotification()
6871 {
6872   notificationWidget->deleteLater();
6873   notificationWidget = NULL;
6874 }
6875 
clearNotification(bool bClearRecentNews)6876 void MainWindow::clearNotification(bool bClearRecentNews/*=false*/)
6877 {
6878   newNews.idFeedList_.clear();
6879   newNews.cntNewsList_.clear();
6880 
6881   if (bClearRecentNews)
6882   {
6883     recentNews.idFeedList_.clear();
6884     recentNews.cntNewsList_.clear();
6885 
6886     idColorList_.clear();
6887     colorList_.clear();
6888   }
6889 }
6890 
slotAddColorList(int id,const QString & color)6891 void MainWindow::slotAddColorList(int id, const QString &color)
6892 {
6893   if (idColorList_.indexOf(id) == -1)
6894   {
6895     idColorList_.append(id);
6896     colorList_.append(color);
6897   }
6898 }
6899 
6900 /** @brief Show news on click in notification window
6901  *---------------------------------------------------------------------------*/
slotOpenNew(int feedId,int newsId)6902 void MainWindow::slotOpenNew(int feedId, int newsId)
6903 {
6904   openingFeedAction_ = 0;
6905   openNewsWebViewOn_ = true;
6906 
6907   QSqlQuery q;
6908   q.exec(QString("UPDATE feeds SET currentNews='%1' WHERE id=='%2'").arg(newsId).arg(feedId));
6909 
6910   QModelIndex feedIndex = feedsModel_->indexById(feedId);
6911   feedsView_->setCurrentIndex(feedsProxyModel_->mapFromSource(feedIndex));
6912   feedsModel_->setData(feedsModel_->indexSibling(feedIndex, "currentNews"),
6913                            newsId);
6914 
6915   if (stackedWidget_->count() && currentNewsTab->type_ < NewsTabWidget::TabTypeWeb) {
6916     currentNewsTab->newsHeader_->saveStateColumns(currentNewsTab);
6917   }
6918 
6919   // Search open tab containing this feed
6920   int indexTab = -1;
6921   for (int i = 0; i < stackedWidget_->count(); i++) {
6922     NewsTabWidget *widget = (NewsTabWidget*)stackedWidget_->widget(i);
6923     if (widget->feedId_ == feedId) {
6924       indexTab = i;
6925       break;
6926     }
6927   }
6928 
6929   if (indexTab == -1) {
6930     if (tabBar_->currentIndex() != TAB_WIDGET_PERMANENT) {
6931       setFeedRead(currentNewsTab->type_, currentNewsTab->feedId_, FeedReadSwitchingTab, currentNewsTab);
6932 
6933       updateCurrentTab_ = false;
6934       tabBar_->setCurrentIndex(TAB_WIDGET_PERMANENT);
6935       updateCurrentTab_ = true;
6936 
6937       currentNewsTab = (NewsTabWidget*)stackedWidget_->widget(TAB_WIDGET_PERMANENT);
6938       newsModel_ = currentNewsTab->newsModel_;
6939       newsView_ = currentNewsTab->newsView_;
6940     } else {
6941       if (stackedWidget_->count() && currentNewsTab->type_ != NewsTabWidget::TabTypeFeed) {
6942         setFeedRead(currentNewsTab->type_, currentNewsTab->feedId_, FeedReadSwitchingFeed, currentNewsTab);
6943       } else {
6944         // Mark previous feed Read while switching to another feed
6945         setFeedRead(NewsTabWidget::TabTypeFeed, feedIdOld_, FeedReadSwitchingFeed, 0, feedId);
6946       }
6947 
6948       categoriesTree_->setCurrentIndex(QModelIndex());
6949     }
6950   } else {
6951     tabBar_->setCurrentIndex(indexTab);
6952   }
6953   slotFeedSelected(feedIndex);
6954   feedsView_->repaint();
6955   feedIdOld_ = feedId;
6956 
6957   Settings settings;
6958   openingFeedAction_ = settings.value("/Settings/openingFeedAction", 0).toInt();
6959   openNewsWebViewOn_ = settings.value("/Settings/openNewsWebViewOn", true).toBool();
6960   showWindows();
6961   newsView_->setFocus();
6962 }
6963 
6964 /** @brief Open news in external browser on click in notification window
6965  *---------------------------------------------------------------------------*/
slotOpenNewBrowser(const QUrl & url)6966 void MainWindow::slotOpenNewBrowser(const QUrl &url)
6967 {
6968   currentNewsTab->openUrl(url);
6969 }
6970 
slotMarkReadNewsInNotification(int feedId,int newsId,int read)6971 void MainWindow::slotMarkReadNewsInNotification(int feedId, int newsId, int read)
6972 {
6973   QSqlQuery q;
6974   bool showNews = false;
6975   if (currentNewsTab->type_ < NewsTabWidget::TabTypeWeb) {
6976     int cnt = newsModel_->rowCount();
6977     for (int i = 0; i < cnt; ++i) {
6978       if (newsId == newsModel_->index(i, newsModel_->fieldIndex("id")).data().toInt()) {
6979         if (read == 1) {
6980           if (newsModel_->index(i, newsModel_->fieldIndex("new")).data(Qt::EditRole).toInt() == 1) {
6981             newsModel_->setData(
6982                   newsModel_->index(i, newsModel_->fieldIndex("new")),
6983                   0);
6984             q.exec(QString("UPDATE news SET new=0 WHERE id=='%1'").arg(newsId));
6985           }
6986           if (newsModel_->index(i, newsModel_->fieldIndex("read")).data(Qt::EditRole).toInt() == 0) {
6987             newsModel_->setData(
6988                   newsModel_->index(i, newsModel_->fieldIndex("read")),
6989                   1);
6990             q.exec(QString("UPDATE news SET read=1 WHERE id=='%1'").arg(newsId));
6991           }
6992         } else {
6993           if (newsModel_->index(i, newsModel_->fieldIndex("read")).data(Qt::EditRole).toInt() != 0) {
6994             newsModel_->setData(
6995                   newsModel_->index(i, newsModel_->fieldIndex("read")),
6996                   0);
6997             q.exec(QString("UPDATE news SET read=0 WHERE id=='%1'").arg(newsId));
6998           }
6999         }
7000 
7001         newsView_->viewport()->update();
7002         showNews = true;
7003         break;
7004       }
7005     }
7006   }
7007 
7008   if (!showNews) {
7009     q.exec(QString("UPDATE news SET new=0, read='%1' WHERE id=='%2'").
7010            arg(read).arg(newsId));
7011   }
7012 
7013   slotUpdateStatus(feedId);
7014   recountCategoryCounts();
7015 }
7016 
slotDeleteNewsInNotification(int feedId,int newsId)7017 void MainWindow::slotDeleteNewsInNotification(int feedId, int newsId)
7018 {
7019   mainApp->sqlQueryExec(QString("UPDATE news SET new=0, read=2, deleted=1, deleteDate='%1' WHERE id=='%2'").
7020                arg(QDateTime::currentDateTime().toString(Qt::ISODate)).
7021                arg(newsId));
7022 
7023   if (currentNewsTab->type_ < NewsTabWidget::TabTypeWeb) {
7024     for (int i = 0; i < newsModel_->rowCount(); ++i) {
7025       if (newsId == newsModel_->index(i, newsModel_->fieldIndex("id")).data().toInt()) {
7026         newsModel_->setData(newsModel_->index(i, newsModel_->fieldIndex("new")), 0);
7027         newsModel_->setData(newsModel_->index(i, newsModel_->fieldIndex("read")), 2);
7028         newsModel_->setData(newsModel_->index(i, newsModel_->fieldIndex("deleted")), 1);
7029         newsModel_->setData(newsModel_->index(i, newsModel_->fieldIndex("deleteDate")),
7030                             QDateTime::currentDateTime().toString(Qt::ISODate));
7031 
7032         newsModel_->submitAll();
7033 
7034         while (newsModel_->canFetchMore())
7035           newsModel_->fetchMore();
7036 
7037         currentNewsTab->loadNewspaper(NewsTabWidget::RefreshWithPos);
7038 
7039         QModelIndex curIndex;
7040         if (i == newsModel_->rowCount())
7041           curIndex = newsModel_->index(i-1, newsModel_->fieldIndex("title"));
7042         else if (i > newsModel_->rowCount())
7043           curIndex = newsModel_->index(i-1, newsModel_->fieldIndex("title"));
7044         else
7045           curIndex = newsModel_->index(i, newsModel_->fieldIndex("title"));
7046         newsView_->setCurrentIndex(curIndex);
7047         currentNewsTab->slotNewsViewSelected(curIndex);
7048         break;
7049       }
7050     }
7051   }
7052 
7053   slotUpdateStatus(feedId);
7054   recountCategoryCounts();
7055 }
7056 
slotMarkAllReadNewsInNotification()7057 void MainWindow::slotMarkAllReadNewsInNotification()
7058 {
7059   if (NotificationWidget *notificationWidget = qobject_cast<NotificationWidget*>(sender())) {
7060     QList<int> idFeedList = notificationWidget->idFeedList();
7061     QList<int> idNewsList = notificationWidget->idNewsList();
7062 
7063     if (currentNewsTab->type_ < NewsTabWidget::TabTypeWeb) {
7064       for (int i = 0; i < newsModel_->rowCount(); ++i) {
7065         if (idNewsList.contains(newsModel_->index(i, newsModel_->fieldIndex("id")).data().toInt())) {
7066           newsModel_->setData(
7067                 newsModel_->index(i, newsModel_->fieldIndex("new")), 0);
7068           newsModel_->setData(
7069                 newsModel_->index(i, newsModel_->fieldIndex("read")), 1);
7070         }
7071       }
7072       newsView_->viewport()->update();
7073     }
7074 
7075     foreach (int newsId, idNewsList) {
7076       mainApp->sqlQueryExec(QString("UPDATE news SET new=0, read=1 WHERE id=='%1'").
7077                    arg(newsId));
7078     }
7079 
7080     foreach (int feedId, idFeedList) {
7081       slotUpdateStatus(feedId);
7082     }
7083     recountCategoryCounts();
7084   }
7085 }
7086 
7087 // ----------------------------------------------------------------------------
slotFindFeeds(QString)7088 void MainWindow::slotFindFeeds(QString)
7089 {
7090   if (!findFeedsWidget_->isVisible()) return;
7091 
7092   setFeedsFilter(false);
7093 }
7094 // ----------------------------------------------------------------------------
slotSelectFind()7095 void MainWindow::slotSelectFind()
7096 {
7097   slotFindFeeds(findFeeds_->text());
7098 }
7099 // ----------------------------------------------------------------------------
findFeedVisible(bool visible)7100 void MainWindow::findFeedVisible(bool visible)
7101 {
7102   findFeedsWidget_->setVisible(visible);
7103   if (visible) {
7104     findFeeds_->setFocus();
7105   } else {
7106     findFeedAct_->setChecked(false);
7107     findFeeds_->clear();
7108     // Call filter explicitly, because invisible widget don't calls it
7109     setFeedsFilter(false);
7110   }
7111 }
7112 
7113 /** @brief Totally remove news
7114  *---------------------------------------------------------------------------*/
cleanUp()7115 void MainWindow::cleanUp()
7116 {
7117   CleanUpWizard *cleanUpWizard = new CleanUpWizard(this);
7118   cleanUpWizard->exec();
7119   delete cleanUpWizard;
7120 }
7121 
7122 /** @brief Zooming in browser
7123  *---------------------------------------------------------------------------*/
browserZoom(QAction * action)7124 void MainWindow::browserZoom(QAction *action)
7125 {
7126   if (currentNewsTab->type_ == NewsTabWidget::TabTypeDownloads) return;
7127 
7128   if (action->objectName() == "zoomInAct") {
7129     if (currentNewsTab->webView_->zoomFactor() < 5.0)
7130       currentNewsTab->webView_->setZoomFactor(currentNewsTab->webView_->zoomFactor()+0.1);
7131   } else if (action->objectName() == "zoomOutAct") {
7132     if (currentNewsTab->webView_->zoomFactor() > 0.3)
7133       currentNewsTab->webView_->setZoomFactor(currentNewsTab->webView_->zoomFactor()-0.1);
7134   } else {
7135     currentNewsTab->webView_->setZoomFactor(1);
7136   }
7137 }
7138 
7139 /** @brief Call default e-mail application to report the problem
7140  *---------------------------------------------------------------------------*/
slotReportProblem()7141 void MainWindow::slotReportProblem()
7142 {
7143   QDesktopServices::openUrl(QUrl("https://github.com/QuiteRSS/quiterss/issues"));
7144 }
7145 
7146 /** @brief Print browser page
7147  *---------------------------------------------------------------------------*/
slotPrint(QWebFrame * frame)7148 void MainWindow::slotPrint(QWebFrame *frame)
7149 {
7150   if (currentNewsTab->type_ == NewsTabWidget::TabTypeDownloads) return;
7151 
7152   QPrinter printer;
7153   printer.setDocName(tr("Web Page"));
7154   QPrintDialog *printDlg = new QPrintDialog(&printer);
7155   if (!frame)
7156     connect(printDlg, SIGNAL(accepted(QPrinter*)), currentNewsTab->webView_, SLOT(print(QPrinter*)));
7157   else
7158     connect(printDlg, SIGNAL(accepted(QPrinter*)), frame, SLOT(print(QPrinter*)));
7159   printDlg->exec();
7160   printDlg->deleteLater();
7161 }
7162 
7163 /** @brief Call print preview dialog
7164  *---------------------------------------------------------------------------*/
slotPrintPreview(QWebFrame * frame)7165 void MainWindow::slotPrintPreview(QWebFrame *frame)
7166 {
7167   if (currentNewsTab->type_ == NewsTabWidget::TabTypeDownloads) return;
7168 
7169   QPrinter printer;
7170   printer.setDocName(tr("Web Page"));
7171   QPrintPreviewDialog *prevDlg = new QPrintPreviewDialog(&printer);
7172   prevDlg->setWindowFlags(prevDlg->windowFlags() | Qt::WindowMaximizeButtonHint);
7173   prevDlg->resize(650, 800);
7174   if (!frame)
7175     connect(prevDlg, SIGNAL(paintRequested(QPrinter*)), currentNewsTab->webView_, SLOT(print(QPrinter*)));
7176   else
7177     connect(prevDlg, SIGNAL(paintRequested(QPrinter*)), frame, SLOT(print(QPrinter*)));
7178   prevDlg->exec();
7179   prevDlg->deleteLater();
7180 }
7181 // ----------------------------------------------------------------------------
setFullScreen()7182 void MainWindow::setFullScreen()
7183 {
7184   if (!isFullScreen()) {
7185     // hide menu
7186     menuBar()->hide();
7187 #ifdef HAVE_X11
7188     show();
7189     raise();
7190     setWindowState(windowState() | Qt::WindowFullScreen);
7191 #else
7192     setWindowState(windowState() | Qt::WindowFullScreen);
7193 #endif
7194   } else {
7195     if (showMenuBarAct_->isChecked())
7196       menuBar()->show();
7197     setWindowState(windowState() & ~Qt::WindowFullScreen);
7198   }
7199 }
7200 // ----------------------------------------------------------------------------
setStayOnTop()7201 void MainWindow::setStayOnTop()
7202 {
7203   isMinimizeToTray_ = true;
7204 
7205   int state = windowState();
7206 
7207   if (stayOnTopAct_->isChecked())
7208     setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
7209   else
7210     setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint);
7211 
7212   if ((state & Qt::WindowFullScreen) || (state & Qt::WindowMaximized)) {
7213     Settings settings;
7214     restoreGeometry(settings.value("GeometryState").toByteArray());
7215   }
7216   setWindowState((Qt::WindowState)state);
7217   show();
7218 
7219   isMinimizeToTray_ = false;
7220 }
7221 
showMenuBar()7222 void MainWindow::showMenuBar()
7223 {
7224   if (showMenuBarAct_->isChecked()) {
7225     mainMenuButton_->hide();
7226     if (isFullScreen())
7227       menuBar()->hide();
7228     else
7229       menuBar()->show();
7230   } else {
7231     mainMenuButton_->show();
7232     menuBar()->hide();
7233   }
7234 }
7235 
7236 /** @brief Move index after drag&drop operations
7237  * @param indexWhat index that is moving
7238  * @param indexWhere index, where to move
7239  *---------------------------------------------------------------------------*/
slotMoveIndex(const QModelIndex & indexWhere,int how)7240 void MainWindow::slotMoveIndex(const QModelIndex &indexWhere, int how)
7241 {
7242   feedsView_->setCursor(Qt::WaitCursor);
7243 
7244   QModelIndexList indexList = feedsView_->selectionModel()->selectedRows(0);
7245   for (int i = 0; i < indexList.count(); i++) {
7246     QModelIndex indexWhat = feedsProxyModel_->mapToSource(indexList[i]);
7247     int feedIdWhat = feedsModel_->idByIndex(indexWhat);
7248     int feedParIdWhat = feedsModel_->paridByIndex(indexWhat);
7249     int feedIdWhere = feedsModel_->idByIndex(indexWhere);
7250     int feedParIdWhere = feedsModel_->paridByIndex(indexWhere);
7251 
7252     // Repair rowToParent
7253     QSqlQuery q;
7254     if (how == 2) {
7255       // Move to another folder
7256       QList<int> idList;
7257       q.exec(QString("SELECT id FROM feeds WHERE parentId='%1' ORDER BY rowToParent").
7258              arg(feedParIdWhat));
7259       while (q.next()) {
7260         if (feedIdWhat != q.value(0).toInt())
7261           idList << q.value(0).toInt();
7262       }
7263       for (int i = 0; i < idList.count(); i++) {
7264         q.exec(QString("UPDATE feeds SET rowToParent='%1' WHERE id=='%2'").
7265                arg(i).arg(idList.at(i)));
7266       }
7267 
7268       int rowToParent = 0;
7269       q.exec(QString("SELECT count(id) FROM feeds WHERE parentId='%1'").
7270              arg(feedIdWhere));
7271       if (q.next()) rowToParent = q.value(0).toInt();
7272 
7273       q.exec(QString("UPDATE feeds SET parentId='%1', rowToParent='%2' WHERE id=='%3'").
7274              arg(feedIdWhere).arg(rowToParent).arg(feedIdWhat));
7275 
7276       QList<int> categoriesList;
7277       categoriesList << feedParIdWhat << feedIdWhere;
7278       recountFeedCategories(categoriesList);
7279     } else if (feedParIdWhat == feedParIdWhere) {
7280       // Move inside folder
7281       QList<int> idList;
7282       q.exec(QString("SELECT id FROM feeds WHERE parentId='%1' ORDER BY rowToParent").
7283              arg(feedParIdWhat));
7284       while (q.next()) {
7285         idList << q.value(0).toInt();
7286       }
7287 
7288       int rowWhat = feedsModel_->dataField(indexWhat, "rowToParent").toInt();
7289       int rowWhere = feedsModel_->dataField(indexWhere, "rowToParent").toInt();
7290       if ((rowWhat < rowWhere) && (how != 1)) rowWhere--;
7291       else if (how == 1) rowWhere++;
7292       idList.insert(rowWhere, idList.takeAt(rowWhat));
7293 
7294       for (int i = 0; i < idList.count(); i++) {
7295         q.exec(QString("UPDATE feeds SET rowToParent='%1' WHERE id=='%2'").
7296                arg(i).arg(idList.at(i)));
7297       }
7298     } else {
7299       // Move in another folder beside feeds
7300       QList<int> idList;
7301       q.exec(QString("SELECT id FROM feeds WHERE parentId='%1' ORDER BY rowToParent").
7302              arg(feedParIdWhat));
7303       while (q.next()) {
7304         if (feedIdWhat != q.value(0).toInt())
7305           idList << q.value(0).toInt();
7306       }
7307       for (int i = 0; i < idList.count(); i++) {
7308         q.exec(QString("UPDATE feeds SET rowToParent='%1' WHERE id=='%2'").
7309                arg(i).arg(idList.at(i)));
7310       }
7311 
7312       //
7313 
7314       idList.clear();
7315       q.exec(QString("SELECT id FROM feeds WHERE parentId='%1' ORDER BY rowToParent").
7316              arg(feedParIdWhere));
7317       while (q.next()) {
7318         idList << q.value(0).toInt();
7319       }
7320 
7321       int rowWhere = feedsModel_->dataField(indexWhere, "rowToParent").toInt();
7322       if (how == 1) rowWhere++;
7323       idList.insert(rowWhere, feedIdWhat);
7324 
7325       for (int i = 0; i < idList.count(); i++) {
7326         q.exec(QString("UPDATE feeds SET rowToParent='%1' WHERE id=='%2'").
7327                arg(i).arg(idList.at(i)));
7328       }
7329 
7330       q.exec(QString("UPDATE feeds SET parentId='%1' WHERE id=='%2'").
7331              arg(feedParIdWhere).arg(feedIdWhat));
7332 
7333       QList<int> categoriesList;
7334       categoriesList << feedParIdWhat << feedParIdWhere;
7335       recountFeedCategories(categoriesList);
7336     }
7337   }
7338 
7339   feedsView_->refresh();
7340 
7341   feedsView_->setCurrentIndex(feedsProxyModel_->mapFromSource(feedIdOld_));
7342 
7343   feedsView_->setCursor(Qt::ArrowCursor);
7344 }
7345 
7346 /** @brief Process clicks in feeds tree
7347  * @param item Item that was clicked
7348  *---------------------------------------------------------------------------*/
slotCategoriesClicked(QTreeWidgetItem * item,int,bool createTab)7349 void MainWindow::slotCategoriesClicked(QTreeWidgetItem *item, int, bool createTab)
7350 {
7351   if (stackedWidget_->count() && currentNewsTab->type_ < NewsTabWidget::TabTypeWeb) {
7352     currentNewsTab->newsHeader_->saveStateColumns(currentNewsTab);
7353     Settings settings;
7354     settings.setValue("NewsTabSplitterState", currentNewsTab->newsTabWidgetSplitter_->saveState());
7355   }
7356 
7357   int type = item->text(1).toInt();
7358   NewsTabWidget::TabType tabType = static_cast<NewsTabWidget::TabType>(type);
7359 
7360   int indexTab = -1;
7361   if (!createTab) {
7362     for (int i = 0; i < stackedWidget_->count(); i++) {
7363       NewsTabWidget *widget = (NewsTabWidget*)stackedWidget_->widget(i);
7364       if (widget->type_ == tabType) {
7365         if (widget->type_ == NewsTabWidget::TabTypeLabel) {
7366           if (widget->labelId_ == item->text(2).toInt()) {
7367             indexTab = i;
7368             break;
7369           }
7370         }
7371         else {
7372           indexTab = i;
7373           break;
7374         }
7375       }
7376     }
7377   }
7378 
7379   if (indexTab == -1) {
7380     if (createTab) {
7381       setFeedRead(currentNewsTab->type_, currentNewsTab->feedId_,
7382                   FeedReadSwitchingTab, currentNewsTab);
7383 
7384       NewsTabWidget *widget = new NewsTabWidget(this, tabType);
7385       indexTab = addTab(widget);
7386       createNewsTab(indexTab);
7387     }
7388     else {
7389       feedsView_->setCurrentIndex(QModelIndex());
7390       feedProperties_->setEnabled(false);
7391 
7392       if (tabBar_->currentIndex() != TAB_WIDGET_PERMANENT) {
7393         setFeedRead(currentNewsTab->type_, currentNewsTab->feedId_,
7394                     FeedReadSwitchingTab, currentNewsTab);
7395 
7396         QModelIndex curIndex = categoriesTree_->currentIndex();
7397         updateCurrentTab_ = false;
7398         tabBar_->setCurrentIndex(TAB_WIDGET_PERMANENT);
7399         updateCurrentTab_ = true;
7400         categoriesTree_->setCurrentIndex(curIndex);
7401 
7402         currentNewsTab = (NewsTabWidget*)stackedWidget_->widget(TAB_WIDGET_PERMANENT);
7403         newsModel_ = currentNewsTab->newsModel_;
7404         newsView_ = currentNewsTab->newsView_;
7405       } else {
7406         setFeedRead(currentNewsTab->type_, currentNewsTab->feedId_,
7407                     FeedReadSwitchingFeed, currentNewsTab);
7408       }
7409 
7410       currentNewsTab->type_ = tabType;
7411       currentNewsTab->feedId_ = -1;
7412       currentNewsTab->feedParId_ = -1;
7413       currentNewsTab->setSettings(true, false);
7414       currentNewsTab->setVisible(true);
7415     }
7416 
7417     // Set icon and title of current tab
7418     currentNewsTab->newsIconTitle_->setPixmap(item->icon(0).pixmap(16,16));
7419     currentNewsTab->setTextTab(item->text(0));
7420 
7421     currentNewsTab->labelId_ = item->text(2).toInt();
7422 
7423     switch (type) {
7424     case NewsTabWidget::TabTypeUnread:
7425       currentNewsTab->categoryFilterStr_ = "feedId > 0 AND deleted = 0 AND read < 2";
7426       break;
7427     case NewsTabWidget::TabTypeStar:
7428       currentNewsTab->categoryFilterStr_ = "feedId > 0 AND deleted = 0 AND starred = 1";
7429       break;
7430     case NewsTabWidget::TabTypeDel:
7431       currentNewsTab->categoryFilterStr_ = "feedId > 0 AND deleted = 1";
7432       break;
7433     case NewsTabWidget::TabTypeLabel:
7434       if (currentNewsTab->labelId_ != 0) {
7435         currentNewsTab->categoryFilterStr_ =
7436             QString("feedId > 0 AND deleted = 0 AND label LIKE '%,%1,%'").
7437             arg(currentNewsTab->labelId_);
7438       } else {
7439         currentNewsTab->categoryFilterStr_ =
7440             QString("feedId > 0 AND deleted = 0 AND label!='' AND label!=','");
7441       }
7442       break;
7443     }
7444     // ... add filter from "search"
7445     QString filterStr = currentNewsTab->categoryFilterStr_;
7446     QString objectName = currentNewsTab->findText_->findGroup_->checkedAction()->objectName();
7447     if (objectName != "findInBrowserAct") {
7448       QString findText = currentNewsTab->findText_->text();
7449       if (!findText.isEmpty()) {
7450         findText = findText.replace("'", "''").toUpper();
7451         if (objectName == "findTitleAct") {
7452           filterStr.append(
7453                 QString(" AND UPPER(title) LIKE '%%1%'").arg(findText));
7454         } else if (objectName == "findAuthorAct") {
7455           filterStr.append(
7456                 QString(" AND UPPER(author_name) LIKE '%%1%'").arg(findText));
7457         } else if (objectName == "findCategoryAct") {
7458           filterStr.append(
7459                 QString(" AND UPPER(category) LIKE '%%1%'").arg(findText));
7460         } else if (objectName == "findContentAct") {
7461           filterStr.append(
7462                 QString(" AND (UPPER(content) LIKE '%%1%' OR UPPER(description) LIKE '%%1%')").
7463                 arg(findText));
7464         } else if (objectName == "findLinkAct") {
7465           filterStr.append(
7466                 QString(" AND link_href LIKE '%%1%'").
7467                 arg(findText));
7468         } else {
7469           filterStr.append(
7470                 QString(" AND (UPPER(title) LIKE '%%1%' OR UPPER(author_name) LIKE '%%1%' "
7471                         "OR UPPER(category) LIKE '%%1%' OR UPPER(content) LIKE '%%1%' "
7472                         "OR UPPER(description) LIKE '%%1%')").
7473                 arg(findText));
7474         }
7475       }
7476     }
7477     newsModel_->setFilter(filterStr);
7478 
7479     if (newsModel_->rowCount() != 0) {
7480       while (newsModel_->canFetchMore())
7481         newsModel_->fetchMore();
7482     }
7483 
7484     if (type == NewsTabWidget::TabTypeDel){
7485       currentNewsTab->newsHeader_->setSortIndicator(newsModel_->fieldIndex("deleteDate"),
7486                                                     Qt::DescendingOrder);
7487     } else {
7488       if ((currentNewsTab->newsHeader_->sortIndicatorSection() == newsModel_->fieldIndex("read")) ||
7489           currentNewsTab->newsHeader_->sortIndicatorSection() == newsModel_->fieldIndex("starred")) {
7490         currentNewsTab->slotSort(currentNewsTab->newsHeader_->sortIndicatorSection(),
7491                                  currentNewsTab->newsHeader_->sortIndicatorOrder());
7492       }
7493     }
7494 
7495     currentNewsTab->loadNewspaper();
7496 
7497     // Search previous displayed news of the feed
7498     int newsRow = -1;
7499     if (openingFeedAction_ == 0) {
7500       int newsIdCur = item->text(3).toInt();
7501       QModelIndex index = newsModel_->index(0, newsModel_->fieldIndex("id"));
7502       QModelIndexList indexList = newsModel_->match(index, Qt::EditRole, newsIdCur);
7503 
7504       if (!indexList.isEmpty()) newsRow = indexList.first().row();
7505     } else if (openingFeedAction_ == 1) {
7506       newsRow = 0;
7507     } else if (openingFeedAction_ == 3) {
7508       QModelIndex index = newsModel_->index(0, newsModel_->fieldIndex("read"));
7509       QModelIndexList indexList;
7510       if (newsView_->header()->sortIndicatorOrder() == Qt::DescendingOrder)
7511         indexList = newsModel_->match(index, Qt::EditRole, 0, -1);
7512       else
7513         indexList = newsModel_->match(index, Qt::EditRole, 0);
7514 
7515       if (!indexList.isEmpty()) newsRow = indexList.last().row();
7516     }
7517 
7518     // Display previous displayed news of the feed
7519     newsView_->setCurrentIndex(newsModel_->index(newsRow, newsModel_->fieldIndex("title")));
7520     if (newsRow == -1) newsView_->verticalScrollBar()->setValue(newsRow);
7521 
7522     if ((openingFeedAction_ != 2) && openNewsWebViewOn_) {
7523       currentNewsTab->slotNewsViewSelected(newsModel_->index(newsRow, newsModel_->fieldIndex("title")));
7524     } else {
7525       currentNewsTab->slotNewsViewSelected(newsModel_->index(-1, newsModel_->fieldIndex("title")));
7526     }
7527 
7528     if (createTab)
7529       emit signalSetCurrentTab(indexTab);
7530   } else {
7531     emit signalSetCurrentTab(indexTab, true);
7532   }
7533 
7534   int unreadCount = currentNewsTab->getUnreadCount(categoriesTree_->currentItem()->text(4));
7535   int allCount = currentNewsTab->newsModel_->rowCount();
7536   statusUnread_->setText(QString(" " + tr("Unread: %1") + " ").arg(unreadCount));
7537   statusAll_->setText(QString(" " + tr("All: %1") + " ").arg(allCount));
7538 
7539   statusUnread_->setVisible(currentNewsTab->type_ != NewsTabWidget::TabTypeDel);
7540   statusAll_->setVisible(true);
7541 }
7542 
clearDeleted()7543 void MainWindow::clearDeleted()
7544 {
7545   QSqlQuery q;
7546   q.exec("UPDATE news SET description='', content='', received='', "
7547          "author_name='', author_uri='', author_email='', "
7548          "category='', new='', read='', starred='', label='', "
7549          "deleteDate='', feedParentId='', deleted=2 WHERE deleted==1");
7550 
7551   if (currentNewsTab->type_ == NewsTabWidget::TabTypeDel) {
7552     currentNewsTab->newsModel_->select();
7553     currentNewsTab->slotNewsViewSelected(QModelIndex());
7554   }
7555 
7556   recountCategoryCounts();
7557 }
7558 
slotMarkReadCategory(QTreeWidgetItem * item)7559 void MainWindow::slotMarkReadCategory(QTreeWidgetItem *item)
7560 {
7561   int type = item->text(1).toInt();
7562   int labelId = item->text(2).toInt();
7563 
7564   if ((currentNewsTab->type_ == type) && (currentNewsTab->labelId_ == labelId)) {
7565     currentNewsTab->markAllNewsRead();
7566   }
7567   else {
7568     emit signalMarkReadCategory(type, labelId);
7569     recountCategoryCounts();
7570   }
7571 }
7572 
7573 /** @brief Show/Hide categories tree
7574  *---------------------------------------------------------------------------*/
showNewsCategoriesTree()7575 void MainWindow::showNewsCategoriesTree()
7576 {
7577   if (categoriesTree_->isHidden()) {
7578     showCategoriesButton_->setIcon(QIcon(":/images/images/panel_hide.png"));
7579     showCategoriesButton_->setToolTip(tr("Hide Categories"));
7580     categoriesTree_->show();
7581     feedsSplitter_->restoreState(feedsWidgetSplitterState_);
7582   } else {
7583     feedsWidgetSplitterState_ = feedsSplitter_->saveState();
7584     showCategoriesButton_->setIcon(QIcon(":/images/images/panel_show.png"));
7585     showCategoriesButton_->setToolTip(tr("Show Categories"));
7586     categoriesTree_->hide();
7587     QList <int> sizes;
7588     sizes << height() << 20;
7589     feedsSplitter_->setSizes(sizes);
7590   }
7591 }
7592 
7593 /** @brief Move splitter between feeds tree and categories tree
7594  *---------------------------------------------------------------------------*/
feedsSplitterMoved(int pos,int)7595 void MainWindow::feedsSplitterMoved(int pos, int)
7596 {
7597   if (categoriesTree_->isHidden()) {
7598     int height = pos + categoriesPanel_->height() + 2;
7599     if (height < feedsSplitter_->height()) {
7600       showCategoriesButton_->setIcon(QIcon(":/images/images/panel_hide.png"));
7601       showCategoriesButton_->setToolTip(tr("Hide Categories"));
7602       categoriesTree_->show();
7603       recountCategoryCounts();
7604     }
7605   }
7606 }
7607 
7608 /** @brief Set specified label for news
7609  *---------------------------------------------------------------------------*/
setLabelNews(QAction * action)7610 void MainWindow::setLabelNews(QAction *action)
7611 {
7612   if (currentNewsTab->type_ >= NewsTabWidget::TabTypeWeb) return;
7613 
7614   newsLabelAction_->setIcon(action->icon());
7615   newsLabelAction_->setToolTip(action->text());
7616   newsLabelAction_->setData(action->data());
7617 
7618   currentNewsTab->setLabelNews(action->data().toInt());
7619 }
7620 
7621 /** @brief Set last chosen label for news
7622  *---------------------------------------------------------------------------*/
setDefaultLabelNews()7623 void MainWindow::setDefaultLabelNews()
7624 {
7625   if (currentNewsTab->type_ >= NewsTabWidget::TabTypeWeb) return;
7626 
7627   currentNewsTab->setLabelNews(newsLabelAction_->data().toInt());
7628 }
7629 
7630 /** @brief Get Label that belong to current news
7631  *---------------------------------------------------------------------------*/
getLabelNews()7632 void MainWindow::getLabelNews()
7633 {
7634   for (int i = 0; i < newsLabelGroup_->actions().count(); i++) {
7635     newsLabelGroup_->actions().at(i)->setChecked(false);
7636   }
7637 
7638   if (currentNewsTab->type_ >= NewsTabWidget::TabTypeWeb) return;
7639 
7640   QList<QModelIndex> indexes = newsView_->selectionModel()->selectedRows(
7641         newsModel_->fieldIndex("label"));
7642   if (!indexes.count()) return;
7643 
7644   if (indexes.count() == 1) {
7645     QModelIndex index = indexes.at(0);
7646     QStringList strLabelIdList = index.data(Qt::EditRole).toString().split(",", QString::SkipEmptyParts);
7647     foreach (QString strLabelId, strLabelIdList) {
7648       for (int i = 0; i < newsLabelGroup_->actions().count(); i++) {
7649         if (newsLabelGroup_->actions().at(i)->data().toString() == strLabelId)
7650           newsLabelGroup_->actions().at(i)->setChecked(true);
7651       }
7652     }
7653   } else {
7654     for (int i = 0; i < newsLabelGroup_->actions().count(); i++) {
7655       bool check = false;
7656       QString strLabelId = newsLabelGroup_->actions().at(i)->data().toString();
7657       for (int y = indexes.count()-1; y >= 0; --y) {
7658         QModelIndex index = indexes.at(y);
7659         QString strIdLabels = index.data(Qt::EditRole).toString();
7660         if (!strIdLabels.contains(QString(",%1,").arg(strLabelId))) {
7661           check = false;
7662           break;
7663         }
7664         check = true;
7665       }
7666       newsLabelGroup_->actions().at(i)->setChecked(check);
7667     }
7668   }
7669 }
7670 
7671 /** @brief Add tab widget to tabs stack widget
7672  *---------------------------------------------------------------------------*/
addTab(NewsTabWidget * widget)7673 int MainWindow::addTab(NewsTabWidget *widget)
7674 {
7675   int indexTab;
7676   if (openNewTabNextToActive_) {
7677     if (stackedWidget_->count()) tabBar_->insertTab(tabBar_->currentIndex()+1, "");
7678     indexTab = stackedWidget_->insertWidget(stackedWidget_->currentIndex()+1, widget);
7679   }
7680   else {
7681     if (stackedWidget_->count()) tabBar_->addTab("");
7682     indexTab = stackedWidget_->addWidget(widget);
7683   }
7684   tabBar_->setTabButton(indexTab,
7685                         QTabBar::LeftSide,
7686                         widget->newsTitleLabel_);
7687 
7688   return indexTab;
7689 }
7690 
7691 // ----------------------------------------------------------------------------
reduceNewsList()7692 void MainWindow::reduceNewsList()
7693 {
7694   currentNewsTab->reduceNewsList();
7695 }
7696 // ----------------------------------------------------------------------------
increaseNewsList()7697 void MainWindow::increaseNewsList()
7698 {
7699   currentNewsTab->increaseNewsList();
7700 }
7701 
7702 /** @brief Save browser current page to file
7703  *---------------------------------------------------------------------------*/
slotSavePageAs()7704 void MainWindow::slotSavePageAs()
7705 {
7706   if (currentNewsTab->type_ == NewsTabWidget::TabTypeDownloads) return;
7707 
7708   QString fileName = currentNewsTab->webView_->title();
7709   if (newsLayout_ == 0) {
7710     if (fileName == "news_descriptions") {
7711       int row = currentNewsTab->newsView_->currentIndex().row();
7712       fileName = currentNewsTab->newsModel_->dataField(row, "title").toString();
7713     }
7714   } else {
7715     if (currentNewsTab->type_ == NewsTabWidget::TabTypeFeed) {
7716       QModelIndex feedIndex = feedsView_->currentIndex();
7717       feedIndex = feedsProxyModel_->mapToSource(feedIndex);
7718       fileName = feedsModel_->dataField(feedIndex, "text").toString();
7719     } else {
7720       fileName = categoriesTree_->currentItem()->text(0);
7721     }
7722   }
7723   QString title = fileName.trimmed();
7724 
7725   fileName = fileName.trimmed();
7726   fileName = fileName.replace(QzRegExp("[:\"]"), "_");
7727   fileName = QDir::toNativeSeparators(QDir::homePath() + "/" + fileName);
7728   fileName = QFileDialog::getSaveFileName(this, tr("Save As"),
7729                                           fileName,
7730                                           QString(tr("HTML-Files (*.%1)") + ";;" + tr("Text files (*.%2)"))
7731                                           .arg("html").arg("txt"));
7732   if (fileName.isNull()) return;
7733 
7734   QFile file(fileName);
7735   if (!file.open(QIODevice::WriteOnly)) {
7736     statusBar()->showMessage(tr("Save As: can't open a file"), 3000);
7737     return;
7738   }
7739   QFileInfo fileInfo(fileName);
7740   if (fileInfo.suffix() == "txt") {
7741     file.write(currentNewsTab->webView_->page()->mainFrame()->toPlainText().toUtf8());
7742   } else {
7743     QString html = currentNewsTab->webView_->page()->mainFrame()->toHtml();
7744     QzRegExp reg("news_descriptions", Qt::CaseInsensitive);
7745     html = html.replace(reg, title);
7746     reg.setPattern("<img class=\"quiterss-img\"[^>]+\\>");
7747     html = html.remove(reg);
7748     QTextCodec *codec = QTextCodec::codecForHtml(html.toUtf8(),
7749                                                  QTextCodec::codecForName("UTF-8"));
7750     file.write(codec->fromUnicode(html));
7751   }
7752   file.close();
7753 }
7754 
slotSavePageAsDescript()7755 void MainWindow::slotSavePageAsDescript()
7756 {
7757   currentNewsTab->savePageAsDescript();
7758 }
7759 
7760 /** @brief Restore last deleted news
7761  *---------------------------------------------------------------------------*/
restoreLastNews()7762 void MainWindow::restoreLastNews()
7763 {
7764   QSqlQuery q;
7765   q.exec("SELECT id, feedId FROM news WHERE deleted=1 AND deleteDate!='' ORDER BY deleteDate DESC");
7766   if (q.next()) {
7767     QModelIndex curIndex = newsView_->currentIndex();
7768     int newsIdCur = newsModel_->index(curIndex.row(), newsModel_->fieldIndex("id")).data().toInt();
7769 
7770     int newsId = q.value(0).toInt();
7771     int feedId = q.value(1).toInt();
7772     q.exec(QString("UPDATE news SET deleted=0, deleteDate='' WHERE id=='%1'").
7773            arg(newsId));
7774 
7775     newsModel_->select();
7776 
7777     while (newsModel_->canFetchMore())
7778       newsModel_->fetchMore();
7779 
7780     currentNewsTab->loadNewspaper(NewsTabWidget::RefreshWithPos);
7781 
7782     QModelIndex index = newsModel_->index(0, newsModel_->fieldIndex("id"));
7783     QModelIndexList indexList = newsModel_->match(index, Qt::EditRole, newsIdCur);
7784     if (indexList.count()) {
7785       int newsRow = indexList.first().row();
7786       newsView_->setCurrentIndex(newsModel_->index(newsRow, newsModel_->fieldIndex("title")));
7787     }
7788     slotUpdateStatus(feedId);
7789     recountCategoryCounts();
7790   }
7791 }
7792 
7793 /** @brief Switch to next unread news
7794  *---------------------------------------------------------------------------*/
nextUnreadNews()7795 void MainWindow::nextUnreadNews()
7796 {
7797   if (currentNewsTab->type_ >= NewsTabWidget::TabTypeWeb) return;
7798   newsView_->clearSelection();
7799 
7800   int newsRow = currentNewsTab->findUnreadNews(true);
7801 
7802   if (newsRow == -1) {
7803     if (currentNewsTab->type_ != NewsTabWidget::TabTypeFeed) return;
7804 
7805     QModelIndex indexPrevUnread = QModelIndex();
7806     if (feedsView_->currentIndex().isValid())
7807       indexPrevUnread = feedsView_->indexNextUnread(feedsView_->currentIndex(), 1);
7808     if (!indexPrevUnread.isValid()) {
7809       indexPrevUnread = feedsView_->indexNextUnread(QModelIndex(), 1);
7810     }
7811     if (indexPrevUnread.isValid()) {
7812       if (changeBehaviorActionNUN_)
7813         openingFeedAction_ = 4;
7814       else
7815         openingFeedAction_ = 3;
7816       feedsView_->clearSelection();
7817       feedsView_->setCurrentIndex(indexPrevUnread);
7818       slotFeedClicked(indexPrevUnread);
7819 
7820       if (tabBar_->currentIndex() != TAB_WIDGET_PERMANENT) {
7821         QModelIndex index = newsModel_->index(0, newsModel_->fieldIndex("read"));
7822         QModelIndexList indexList;
7823         if ((newsView_->header()->sortIndicatorOrder() == Qt::DescendingOrder) &&
7824             (openingFeedAction_ != 4))
7825           indexList = newsModel_->match(index, Qt::EditRole, 0, -1);
7826         else
7827           indexList = newsModel_->match(index, Qt::EditRole, 0);
7828 
7829         if (!indexList.isEmpty()) newsRow = indexList.last().row();
7830 
7831         // Focus feed news that displayed before
7832         newsView_->setCurrentIndex(newsModel_->index(newsRow, newsModel_->fieldIndex("title")));
7833         if (newsRow == -1) newsView_->verticalScrollBar()->setValue(newsRow);
7834 
7835         if (openNewsWebViewOn_) {
7836           currentNewsTab->slotNewsViewSelected(newsModel_->index(newsRow, newsModel_->fieldIndex("title")));
7837         }
7838       }
7839 
7840       Settings settings;
7841       openingFeedAction_ = settings.value("/Settings/openingFeedAction", 0).toInt();
7842     }
7843     return;
7844   }
7845 
7846   int value = newsView_->verticalScrollBar()->value();
7847   int pageStep = newsView_->verticalScrollBar()->pageStep();
7848   if (newsRow > (value + pageStep/2))
7849     newsView_->verticalScrollBar()->setValue(newsRow - pageStep/2);
7850 
7851   QModelIndex index = newsModel_->index(newsRow, newsModel_->fieldIndex("title"));
7852   newsView_->setCurrentIndex(index);
7853   currentNewsTab->slotNewsViewSelected(index);
7854 }
7855 
7856 /** @brief Switch to previous unread news
7857  *---------------------------------------------------------------------------*/
prevUnreadNews()7858 void MainWindow::prevUnreadNews()
7859 {
7860   if (currentNewsTab->type_ >= NewsTabWidget::TabTypeWeb) return;
7861   newsView_->clearSelection();
7862 
7863   int newsRow = currentNewsTab->findUnreadNews(false);
7864 
7865   int newsRowCur = newsView_->currentIndex().row();
7866   if ((newsRow >= newsRowCur) || (newsRow == -1)) {
7867     if (currentNewsTab->type_ != NewsTabWidget::TabTypeFeed) return;
7868 
7869     QModelIndex indexNextUnread =
7870         feedsView_->indexNextUnread(feedsView_->currentIndex(), 2);
7871     if (indexNextUnread.isValid()) {
7872       openingFeedAction_ = 3;
7873       feedsView_->clearSelection();
7874       feedsView_->setCurrentIndex(indexNextUnread);
7875       slotFeedClicked(indexNextUnread);
7876       Settings settings;
7877       openingFeedAction_ = settings.value("/Settings/openingFeedAction", 0).toInt();
7878     }
7879     return;
7880   }
7881 
7882   int value = newsView_->verticalScrollBar()->value();
7883   int pageStep = newsView_->verticalScrollBar()->pageStep();
7884   if (newsRow < (value + pageStep/2))
7885     newsView_->verticalScrollBar()->setValue(newsRow - pageStep/2);
7886 
7887   QModelIndex index = newsModel_->index(newsRow, newsModel_->fieldIndex("title"));
7888   newsView_->setCurrentIndex(index);
7889   currentNewsTab->slotNewsViewSelected(index);
7890 }
7891 
7892 /** @brief Get feeds ids list string of folder \a idFolder
7893  *---------------------------------------------------------------------------*/
getIdFeedsString(int idFolder,int idException)7894 QString MainWindow::getIdFeedsString(int idFolder, int idException)
7895 {
7896   QList<int> idList = UpdateObject::getIdFeedsInList(db_, idFolder);
7897   if (idList.count()) {
7898     QString str;
7899     foreach (int id, idList) {
7900       if (id == idException) continue;
7901       if (!str.isEmpty()) str.append(" OR ");
7902       str.append(QString("feedId=%1").arg(id));
7903     }
7904     return str;
7905   } else {
7906     return QString("feedId=-1");
7907   }
7908 }
7909 
7910 /** @brief Set application title
7911  *---------------------------------------------------------------------------*/
setTextTitle(const QString & text,NewsTabWidget * widget)7912 void MainWindow::setTextTitle(const QString &text, NewsTabWidget *widget)
7913 {
7914   if (currentNewsTab != widget) return;
7915 
7916   if (text.isEmpty()) setWindowTitle("QuiteRSS");
7917   else setWindowTitle(QString("%1 - QuiteRSS").arg(text));
7918 }
7919 
7920 /** @brief Enable|Disable indent in feeds tree
7921  *---------------------------------------------------------------------------*/
slotIndentationFeedsTree()7922 void MainWindow::slotIndentationFeedsTree()
7923 {
7924   feedsView_->setRootIsDecorated(indentationFeedsTreeAct_->isChecked());
7925 }
7926 
7927 // ----------------------------------------------------------------------------
customizeMainToolbar()7928 void MainWindow::customizeMainToolbar()
7929 {
7930   showCustomizeToolbarDlg(customizeMainToolbarAct2_);
7931 }
7932 // ----------------------------------------------------------------------------
showCustomizeToolbarDlg(QAction * action)7933 void MainWindow::showCustomizeToolbarDlg(QAction *action)
7934 {
7935   QToolBar *toolbar = mainToolbar_;
7936   if (action->objectName() == "customizeFeedsToolbarAct") {
7937     toolbar = feedsToolBar_;
7938   } else if (action->objectName() == "customizeNewsToolbarAct") {
7939     if (currentNewsTab->type_ == NewsTabWidget::TabTypeWeb) return;
7940     if (currentNewsTab->type_ == NewsTabWidget::TabTypeDownloads) return;
7941     toolbar = currentNewsTab->newsToolBar_;
7942   }
7943 
7944   CustomizeToolbarDialog *toolbarDlg = new CustomizeToolbarDialog(this, toolbar);
7945 
7946   toolbarDlg->exec();
7947 
7948   delete toolbarDlg;
7949 }
7950 
7951 /** @brief Process news sharing
7952  *---------------------------------------------------------------------------*/
slotShareNews(QAction * action)7953 void MainWindow::slotShareNews(QAction *action)
7954 {
7955   currentNewsTab->slotShareNews(action);
7956 }
7957 // ----------------------------------------------------------------------------
showMenuShareNews()7958 void MainWindow::showMenuShareNews()
7959 {
7960   if (mainToolbar_->widgetForAction(shareMenuAct_)) {
7961     QWidget *widget = mainToolbar_->widgetForAction(shareMenuAct_);
7962     if (widget->underMouse()) {
7963       shareMenu_->popup(widget->mapToGlobal(QPoint(0, mainToolbar_->height()-1)));
7964     }
7965   }
7966   if (feedsToolBar_->widgetForAction(shareMenuAct_)) {
7967     QWidget *widget = feedsToolBar_->widgetForAction(shareMenuAct_);
7968     if (widget->underMouse()) {
7969       shareMenu_->popup(widget->mapToGlobal(QPoint(0, feedsToolBar_->height()-1)));
7970     }
7971   }
7972   if (currentNewsTab->type_ < NewsTabWidget::TabTypeWeb) {
7973     if (currentNewsTab->newsToolBar_->widgetForAction(shareMenuAct_)) {
7974       QWidget *widget = currentNewsTab->newsToolBar_->widgetForAction(shareMenuAct_);
7975       if (widget->underMouse()) {
7976         shareMenu_->popup(widget->mapToGlobal(QPoint(0, currentNewsTab->newsToolBar_->height()-1)));
7977       }
7978     }
7979   }
7980   if (currentNewsTab->webToolBar_->widgetForAction(shareMenuAct_)) {
7981     QWidget *widget = currentNewsTab->webToolBar_->widgetForAction(shareMenuAct_);
7982     if (widget->underMouse()) {
7983       shareMenu_->popup(widget->mapToGlobal(QPoint(0, currentNewsTab->webToolBar_->height()-1)));
7984     }
7985   }
7986 }
7987 
7988 /** @brief Open feed home page in external browser
7989  *---------------------------------------------------------------------------*/
slotOpenHomeFeed()7990 void MainWindow::slotOpenHomeFeed()
7991 {
7992   QModelIndex index = feedsView_->currentIndex();
7993   if (!index.isValid()) return;
7994   index = feedsProxyModel_->mapToSource(index);
7995 
7996   QString homePage = feedsModel_->dataField(index, "htmlUrl").toString();
7997   QDesktopServices::openUrl(homePage);
7998 }
7999 
8000 /** @brief Sort feed and folders by title
8001  *---------------------------------------------------------------------------*/
sortedByTitleFeedsTree()8002 void MainWindow::sortedByTitleFeedsTree()
8003 {
8004   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
8005 
8006   QList<int> parentIdsPotential;
8007   parentIdsPotential << 0;
8008   while (!parentIdsPotential.empty()) {
8009     int parentId = parentIdsPotential.takeFirst();
8010 
8011     // Search children of parent <parentId>
8012     QSqlQuery q;
8013     q.prepare(QString("SELECT id, xmlUrl FROM feeds WHERE parentId=? ORDER BY text COLLATE LOCALE"));
8014     q.addBindValue(parentId);
8015     q.exec();
8016 
8017     // assing each child his <rowToParent>
8018     // ... store it in prospactive parent list
8019     int rowToParent = 0;
8020     while (q.next()) {
8021       int parentIdNew = q.value(0).toInt();
8022       QString xmlUrl = q.value(1).toString();
8023 
8024       QSqlQuery q2;
8025       q2.prepare("UPDATE feeds SET rowToParent=? WHERE id=?");
8026       q2.addBindValue(rowToParent);
8027       q2.addBindValue(parentIdNew);
8028       q2.exec();
8029 
8030       if (xmlUrl.isEmpty())
8031         parentIdsPotential << parentIdNew;
8032       ++rowToParent;
8033     }
8034   }
8035 
8036   feedsModelReload();
8037   QApplication::restoreOverrideCursor();
8038 }
8039 
8040 // ----------------------------------------------------------------------------
showNewsMenu()8041 void MainWindow::showNewsMenu()
8042 {
8043   if (currentNewsTab)
8044     newsSortByMenu_->setEnabled(currentNewsTab->type_ < NewsTabWidget::TabTypeWeb);
8045 }
8046 // ----------------------------------------------------------------------------
showNewsSortByMenu()8047 void MainWindow::showNewsSortByMenu()
8048 {
8049   if (currentNewsTab->type_ >= NewsTabWidget::TabTypeWeb) return;
8050 
8051   QListIterator<QAction *> iter(newsSortByColumnGroup_->actions());
8052   while (iter.hasNext()) {
8053     QAction *nextAction = iter.next();
8054     delete nextAction;
8055   }
8056 
8057   int section = currentNewsTab->newsHeader_->sortIndicatorSection();
8058   iter = currentNewsTab->newsHeader_->viewMenu_->actions();
8059   while (iter.hasNext()) {
8060     QAction *nextAction = iter.next();
8061     QAction *newsSortByColumnAct = new QAction(this);
8062     newsSortByColumnAct->setCheckable(true);
8063     newsSortByColumnAct->setText(nextAction->text());
8064     newsSortByColumnAct->setData(nextAction->data());
8065     if (nextAction->data().toInt() == section) {
8066       newsSortByColumnAct->setChecked(true);
8067     }
8068     newsSortByColumnGroup_->addAction(newsSortByColumnAct);
8069   }
8070   newsSortByMenu_->insertActions(newsSortByMenu_->actions().at(0),
8071                                  newsSortByColumnGroup_->actions());
8072 
8073   if (currentNewsTab->newsHeader_->sortIndicatorOrder() == Qt::AscendingOrder) {
8074     newsSortOrderGroup_->actions().at(0)->setChecked(true);
8075   } else {
8076     newsSortOrderGroup_->actions().at(1)->setChecked(true);
8077   }
8078 }
8079 // ----------------------------------------------------------------------------
setNewsSortByColumn()8080 void MainWindow::setNewsSortByColumn()
8081 {
8082   if (currentNewsTab->type_ >= NewsTabWidget::TabTypeWeb) return;
8083 
8084   int lIdx = newsSortByColumnGroup_->checkedAction()->data().toInt();
8085   if (newsSortOrderGroup_->actions().at(0)->isChecked()) {
8086     currentNewsTab->newsHeader_->setSortIndicator(lIdx, Qt::AscendingOrder);
8087   } else {
8088     currentNewsTab->newsHeader_->setSortIndicator(lIdx, Qt::DescendingOrder);
8089   }
8090 }
8091 // ----------------------------------------------------------------------------
slotPrevFolder()8092 void MainWindow::slotPrevFolder()
8093 {
8094   QModelIndex indexBefore = feedsView_->currentIndex();
8095   QModelIndex indexAfter;
8096 
8097   // Set to bottom folder, if there's no above folder
8098   if (!indexBefore.isValid())
8099     indexAfter = feedsView_->lastFolderInFolder(QModelIndex());
8100   else
8101     indexAfter = feedsView_->indexPreviousFolder(indexBefore);
8102 
8103   // there's no "upper" index
8104   if (!indexAfter.isValid()) return;
8105   feedsView_->clearSelection();
8106 
8107   feedsView_->setCurrentIndex(indexAfter);
8108   slotFeedClicked(indexAfter);
8109 }
8110 // ----------------------------------------------------------------------------
slotNextFolder()8111 void MainWindow::slotNextFolder()
8112 {
8113   QModelIndex indexBefore = feedsView_->currentIndex();
8114   QModelIndex indexAfter;
8115 
8116   // Set to top index, if there's no below index
8117   if (!indexBefore.isValid())
8118     indexAfter = feedsView_->firstFolderInFolder(QModelIndex());
8119   else
8120     indexAfter = feedsView_->indexNextFolder(indexBefore);
8121 
8122   // there's no "downer" index
8123   if (!indexAfter.isValid()) return;
8124   feedsView_->clearSelection();
8125 
8126   feedsView_->setCurrentIndex(indexAfter);
8127   slotFeedClicked(indexAfter);
8128 }
8129 // ----------------------------------------------------------------------------
slotExpandFolder()8130 void MainWindow::slotExpandFolder()
8131 {
8132   QModelIndex index = feedsView_->currentIndex();
8133   if (!feedsModel_->isFolder(index)) {
8134     index = feedsModel_->parent(index);
8135   }
8136   feedsView_->setExpanded(index, !feedsView_->isExpanded(index));
8137 }
8138 // ----------------------------------------------------------------------------
showDownloadManager(bool activate)8139 void MainWindow::showDownloadManager(bool activate)
8140 {
8141   int indexTab = -1;
8142   NewsTabWidget *widget;
8143   for (int i = 0; i < stackedWidget_->count(); i++) {
8144     widget = (NewsTabWidget*)stackedWidget_->widget(i);
8145     if (widget->type_ == NewsTabWidget::TabTypeDownloads) {
8146       indexTab = i;
8147       break;
8148     }
8149   }
8150 
8151   if (indexTab == -1) {
8152     widget = new NewsTabWidget(this, NewsTabWidget::TabTypeDownloads);
8153     indexTab = addTab(widget);
8154     QPixmap iconTab;
8155     iconTab.load(":/images/download");
8156     widget->newsIconTitle_->setPixmap(iconTab);
8157     widget->retranslateStrings();
8158   }
8159 
8160   if (activate) {
8161     currentNewsTab = widget;
8162     currentNewsTab->setTextTab(tr("Downloads"));
8163     statusUnread_->setVisible(false);
8164     statusAll_->setVisible(false);
8165     mainApp->downloadManager()->show();
8166     emit signalSetCurrentTab(indexTab);
8167   } else {
8168     widget->setTextTab(tr("Downloads"));
8169   }
8170 }
8171 // ----------------------------------------------------------------------------
updateInfoDownloads(const QString & text)8172 void MainWindow::updateInfoDownloads(const QString &text)
8173 {
8174   NewsTabWidget *widget;
8175   for (int i = 0; i < stackedWidget_->count(); i++) {
8176     widget = (NewsTabWidget*)stackedWidget_->widget(i);
8177     if (widget->type_ == NewsTabWidget::TabTypeDownloads) {
8178       widget->setTextTab(QString("%1 %2").arg(tr("Downloads")).arg(text));
8179       break;
8180     }
8181   }
8182 }
8183 
setStatusFeed(int feedId,QString status)8184 void MainWindow::setStatusFeed(int feedId, QString status)
8185 {
8186   QModelIndex index = feedsModel_->indexById(feedId);
8187   if (index.isValid()) {
8188     QModelIndex indexStatus = feedsModel_->indexSibling(index, "status");
8189     feedsModel_->setData(indexStatus, status);
8190     feedsView_->viewport()->update();
8191   }
8192 }
8193 
addOurFeed()8194 void MainWindow::addOurFeed()
8195 {
8196   if (mainApp->dbFileExists()) return;
8197 
8198   QPixmap icon(":/images/quiterss16");
8199   QByteArray iconData;
8200   QBuffer buffer(&iconData);
8201   buffer.open(QIODevice::WriteOnly);
8202   icon.save(&buffer, "PNG");
8203   buffer.close();
8204 
8205   QString xmlUrl = "https://quiterss.org/en/rss.xml";
8206   if (mainApp->language() == "ru")
8207     xmlUrl = "https://quiterss.org/ru/rss.xml";
8208 
8209   QSqlQuery q;
8210   q.prepare("INSERT INTO feeds(text, title, xmlUrl, htmlUrl, created, parentId, rowToParent, image) "
8211             "VALUES(?, ?, ?, ?, ?, ?, ?, ?)");
8212   q.addBindValue("QuiteRSS");
8213   q.addBindValue("QuiteRSS");
8214   q.addBindValue(xmlUrl);
8215   q.addBindValue("https://quiterss.org");
8216   q.addBindValue(QDateTime::currentDateTimeUtc().toString(Qt::ISODate));
8217   q.addBindValue(0);
8218   q.addBindValue(0);
8219   q.addBindValue(iconData.toBase64());
8220   q.exec();
8221 
8222   feedsModelReload();
8223 }
8224 
createBackup()8225 void MainWindow::createBackup()
8226 {
8227   QString backupDir(QDir::currentPath());
8228   Settings settings;
8229   backupDir = settings.value("Settings/backupDir", backupDir).toString();
8230   backupDir = QFileDialog::getExistingDirectory(this, tr("Choose Directory"),
8231                                                 backupDir,
8232                                                 QFileDialog::ShowDirsOnly |
8233                                                 QFileDialog::DontResolveSymlinks);
8234   if (!backupDir.isEmpty()) {
8235     settings.setValue("Settings/backupDir", backupDir);
8236 
8237     QFileInfo fileInfo;
8238     QString backupFileName;
8239     QString timeStr(QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss"));
8240 
8241     fileInfo.setFile(mainApp->dbFileName());
8242     backupFileName = QString("%1/%2_%3.bak").
8243         arg(backupDir).
8244         arg(fileInfo.fileName()).
8245         arg(timeStr);
8246     QFile::copy(mainApp->dbFileName(), backupFileName);
8247 
8248     fileInfo.setFile(settings.fileName());
8249     backupFileName = QString("%1/%2_%3.bak").
8250         arg(backupDir).
8251         arg(fileInfo.fileName()).
8252         arg(timeStr);
8253     QFile::copy(settings.fileName(), backupFileName);
8254   }
8255 }
8256 
webViewFullScreen(bool on)8257 void MainWindow::webViewFullScreen(bool on)
8258 {
8259   feedsWidget_->setVisible(!on);
8260   pushButtonNull_->setVisible(!on);
8261   tabBarWidget_->setVisible(!on);
8262   currentNewsTab->newsWidget_->setVisible(!on);
8263   currentNewsTab->webControlPanel_->setVisible(!on);
8264   pushButtonNull_->setVisible(!on);
8265   statusBar()->setVisible(!on);
8266   setFullScreen();
8267 }
8268