Fix random error when remove word from bookmark. Fix show all bookmark feature.
[mdictionary] / src / mdictionary / gui / MainWindow.cpp
1 /*******************************************************************************
2
3     This file is part of mDictionary.
4
5     mDictionary 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     mDictionary 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 mDictionary.  If not, see <http://www.gnu.org/licenses/>.
17
18     Copyright 2010 Comarch S.A.
19
20 *******************************************************************************/
21
22 /*! \file MainWindow.cpp
23     \brief Implements interface for GUI
24
25     \author Mateusz Półrola <mateusz.polrola@comarch.pl>
26 */
27
28 #include "MainWindow.h"
29 #include <QtGui>
30 #ifdef Q_WS_MAEMO_5
31     #include <QMaemo5InformationBox>
32 #endif
33
34
35 MainWindow::MainWindow(Backbone *backbone, QWidget *parent):
36     GUIInterface(parent) {
37
38     this->backbone = backbone;
39
40
41     initializeUI();
42
43     connectBackbone();
44     connectSearchBar();
45     connectWordList();
46     connectTranslationWidget();
47     connectDictManager();
48     connectMenu();
49     connectBookmarksWidget();
50
51     setExactSearch(false);
52
53     setMinimumSize(750, 400);
54
55     showMaximized();
56
57     searchBarWidget->setFocus();
58 }
59
60 MainWindow::~MainWindow() {
61 }
62
63
64 void MainWindow::initializeUI() {
65
66     #ifdef Q_WS_MAEMO_5
67         setAttribute(Qt::WA_Maemo5StackedWindow);
68     #endif
69
70
71     /*translationWidget is another stacked window, so we don't add it to
72       layout, only create it with this widget as parent
73       it must be created as first object in main window, otherwise sometimes
74       when app starts in maemo, when trying to set stacked window attribute
75       it segfaults*/
76     translationWidget = new TranslationWidget(this);
77
78
79
80
81     setWindowIcon(QIcon(":/icons/64x64/mdictionary.png"));
82     setWindowTitle("mDictionary");
83
84     mainLayout = new QVBoxLayout();
85     QWidget* w = new QWidget();
86     w->setLayout(mainLayout);
87     setCentralWidget(w);
88
89     menuBar = new QMenuBar();
90     setMenuBar(menuBar);
91
92     notifyManager = new NotifyManager(this);
93
94     initializeSearchWidgets();
95
96     initializeMenu();
97 }
98
99 void MainWindow::initializeSearchWidgets() {
100     searchBarWidget = new SearchBarWidget();
101
102     wordListWidget = new WordListWidget();
103
104     welcomeScreenWidget = new WelcomeScreenWidget();
105
106     #ifdef Q_WS_MAEMO_5
107         //At start we set widget as welcome screen widget
108         mainLayout->addWidget(welcomeScreenWidget);
109         mainLayout->addWidget(searchBarWidget, 0, Qt::AlignBottom);
110     #else
111         translationWidget->hide();
112         //we add word list and welcome screen to splitter
113         splitter = new QSplitter(Qt::Horizontal);
114         splitter->addWidget(wordListWidget);
115         splitter->addWidget(welcomeScreenWidget);
116         splitter->setStretchFactor(1, 150);
117
118         mainLayout->addWidget(splitter, 1);
119
120         mainLayout->addWidget(searchBarWidget,0, Qt::AlignBottom);
121     #endif
122 }
123
124 void MainWindow::initializeMenu() {
125     initializeMenuWidgets();
126
127 #ifdef Q_WS_MAEMO_5
128     menuWidget = new MenuWidget(this);
129
130     menuWidget->addSubMenu(tr("Settings"), settingsWidget);
131     menuWidget->addSubMenu(tr("Dictionaries"), dictManagerWidget);
132     menuWidget->addSubMenu(tr("Bookmarks"), bookmarksWidget);
133     menuWidget->addSubMenu(tr("About"), aboutWidget);
134
135     menuBar->addAction(menuWidget);
136
137     connect(menuWidget, SIGNAL(setApplicationMenu(QWidget*)),
138             notifyManager, SLOT(setMenu(QWidget*)));
139 #else
140     dictionariesAction = menuBar->addAction(tr("&Dictionaries"));
141     connect(dictionariesAction, SIGNAL(triggered()),
142             dictManagerWidget, SLOT(show()));
143
144     settingsAction = menuBar->addAction(tr("&Settings"));
145     connect(settingsAction, SIGNAL(triggered()),
146             settingsWidget, SLOT(show()));
147
148     QMenu* m = menuBar->addMenu(tr("&Bookmarks"));
149     bookmarksShowAllAction = new QAction(tr("Show all"), m);
150
151     bookmarksRemoveAllAction = new QAction(tr("Remove all"), m);
152
153     m->addAction(bookmarksShowAllAction);
154     m->addAction(bookmarksRemoveAllAction);
155
156     aboutAction = menuBar->addAction(tr("&About"));
157     connect(aboutAction, SIGNAL(triggered()),
158             aboutWidget, SLOT(show()));
159
160 #endif
161 }
162
163 void MainWindow::initializeMenuWidgets() {
164     dictManagerWidget = new DictManagerWidget(this);
165     dictManagerWidget->hide();
166
167     settingsWidget = new SettingsWidget(this);
168     settingsWidget->hide();
169
170     connect(settingsWidget, SIGNAL(notify(Notify::NotifyType,QString)),
171             this, SLOT(showNotification(Notify::NotifyType,QString)));
172
173     bookmarksWidget = new BookmarksWidget(this);
174     bookmarksWidget->hide();
175
176     aboutWidget = new AboutWidget(this);
177     aboutWidget->hide();
178 }
179
180 void MainWindow::closeEvent(QCloseEvent *event) {
181     //request to stop all searches and close app
182     Q_EMIT quit();
183     event->accept();
184 }
185
186 bool MainWindow::isInExactSearch() {
187     return _exactSearch;
188 }
189
190 void MainWindow::setExactSearch(bool exact) {
191     _exactSearch = exact;
192 }
193
194 void MainWindow::setExactSearchString(QString word) {
195     searchString = word;
196 }
197
198 void MainWindow::wordListReady() {
199     //gets results from backbone
200     QMultiHash<QString, Translation*> backboneResult = backbone->result();
201     QHash<QString, QList<Translation*> > searchResult;
202
203     #ifdef Q_WS_MAEMO_5
204         hideWelcomeScreen();
205     #endif
206
207     //if nothing was found
208     if(backboneResult.count() == 0) {
209         showNotification(Notify::Info, tr("Can't find any matching words"));
210
211         //show empty list to remove results of old search
212         Q_EMIT showWordList(searchResult);
213     }
214     else {
215         //find translations of the same key word
216         QMultiHash<QString, Translation*>::iterator i;
217         for(i = backboneResult.begin(); i != backboneResult.end(); i++) {
218             searchResult[i.key()].push_back(i.value());
219         }
220
221         //show search results
222         Q_EMIT showWordList(searchResult);
223
224
225         if(isInExactSearch()) {
226             QList<Translation*> exactTranslation;
227             if(checkExactSearch(searchResult, exactTranslation)) {
228                 Q_EMIT searchTranslations(exactTranslation);
229             }
230             else {
231                 showNotification(Notify::Info,
232                            tr("Can't find exactly matching word"));
233             }
234
235             setExactSearch(false);
236         }
237     }
238     wordListWidget->setFocus();
239 }
240
241 bool MainWindow::checkExactSearch(
242         QHash<QString, QList<Translation *> > searchResult,
243         QList<Translation *> &found) {
244
245     bool foundExactMatch = false;
246     QHash<QString, QList<Translation*> >::iterator j;
247     for(j = searchResult.begin(); j != searchResult.end(); j++) {
248         if(j.key().toLower() == searchString.toLower()
249             && !foundExactMatch) {
250             found = j.value();
251             return true;
252         }
253     }
254     return false;
255 }
256
257 void MainWindow::translationsReady() {
258     #ifndef Q_WS_MAEMO_5
259         hideWelcomeScreen();
260     #endif
261
262     Q_EMIT showTranslation(backbone->xmls());
263     wordListWidget->setFocus();
264     #ifdef Q_WS_MAEMO_5
265         notifyManager->screenChanged();
266     #endif
267 }
268
269
270 void MainWindow::hideWelcomeScreen() {
271 #ifdef Q_WS_MAEMO_5
272     //switch welcome screen with word list
273     if(!wordListWidget->isVisible()) {
274         mainLayout->removeWidget(welcomeScreenWidget);
275         welcomeScreenWidget->deleteLater();
276
277         mainLayout->insertWidget(0, wordListWidget);
278     }
279 #else
280     //switch welcome screen with translation widget
281     if(!translationWidget->isVisible()) {
282         splitter->insertWidget(1,translationWidget);
283         splitter->setStretchFactor(1, 150);
284         welcomeScreenWidget->deleteLater();
285     }
286 #endif
287 }
288
289 QList<CommonDictInterface*> MainWindow::getPlugins() {
290     return backbone->getPlugins();
291 }
292
293 QHash<CommonDictInterface*, bool> MainWindow::getDictionaries() {
294     return backbone->getDictionaries();
295 }
296
297 /**/
298 void MainWindow::search(QString word) {
299     setExactSearch(false);
300     searchBarWidget->search(word);
301     #ifdef Q_WS_MAEMO_5
302     if(translationWidget->isVisible()) {
303             translationWidget->hide();
304             update();
305         }
306     #endif
307 }
308
309 void MainWindow::searchExact(QString word) {
310     setExactSearch(true);
311     searchBarWidget->search(word);
312 }
313
314 void MainWindow::searchDelay(QString word) {
315     searchBarWidget->searchDelay(word);
316 }
317
318
319
320
321
322 void MainWindow::searchingInterrupted() {
323     //make sure to unset exact search mode
324     setExactSearch(false);
325 }
326
327 void MainWindow::addToHistory(QList<Translation *> trans) {
328     if(trans.count() > 0) {
329         backbone->history()->add(trans[0]->key());
330     }
331 }
332
333 void MainWindow::historyNext() {
334     if(backbone->history()->nextAvailable()) {
335         QString next = backbone->history()->next();
336         #ifndef Q_WS_MAEMO_5
337             setExactSearch(true);
338         #endif
339         searchDelay(next);
340     }
341 }
342
343 void MainWindow::historyPrev() {
344     if(backbone->history()->prevAvailable()) {
345         #ifndef Q_WS_MAEMO_5
346             setExactSearch(true);
347         #endif
348         QString prev = backbone->history()->previous();
349         searchDelay(prev);
350     }
351 }
352
353 void MainWindow::disableMenu() {
354     #ifdef Q_WS_MAEMO_5
355         if(menuBar->actions().contains(menuWidget)) {
356               menuBar->removeAction(menuWidget);
357         }
358     #else
359         menuBar->setEnabled(false);
360     #endif
361 }
362
363 void MainWindow::enableMenu() {
364     #ifdef Q_WS_MAEMO_5
365         if(!menuBar->actions().contains(menuWidget)) {
366             menuBar->addAction(menuWidget);
367         }
368     #else
369         menuBar->setEnabled(true);
370     #endif
371 }
372
373 void MainWindow::showHistory(QPoint p) {
374     HistoryListDialog historyDialog(backbone->history()->list(), this );// searchBarWidget);
375     #ifndef Q_WS_MAEMO_5
376         p.setX(p.x() - historyDialog.sizeHint().width() + 5);
377         p.setY(p.y() - historyDialog.sizeHint().height()- 10); //- 80);
378         historyDialog.move(p);
379     #endif
380
381     if(historyDialog.exec() == QDialog::Accepted) {
382         backbone->history()->setCurrentElement(historyDialog.selectedRow());
383         searchExact(historyDialog.selectedWord());
384     }
385 }
386
387 void MainWindow::setSettings(Settings *s) {
388     backbone->setSettings(s);
389 }
390
391 Settings* MainWindow::settings() {
392     return backbone->settings();
393 }
394
395
396 void MainWindow::showNotification(Notify::NotifyType type, QString text) {
397     notifyManager->showNotification(type, text);
398 }
399
400 void MainWindow::connectBackbone() {
401
402     connect(this, SIGNAL(searchWordList(QString)),
403             this, SIGNAL(setBusy()));
404
405     connect(this, SIGNAL(searchTranslations(QList<Translation*>)),
406             this, SIGNAL(setBusy()));
407
408     connect(this, SIGNAL(stopSearching()),
409             this, SIGNAL(setIdle()));
410
411     connect(this, SIGNAL(searchWordList(QString)),
412             this, SLOT(setExactSearchString(QString)));
413
414     connect(this, SIGNAL(searchTranslations(QList<Translation*>)),
415             this, SLOT(addToHistory(QList<Translation*>)));
416
417
418
419     connect(this, SIGNAL(quit()),
420             backbone, SLOT(quit()));
421
422     connect(this, SIGNAL(searchWordList(QString)),
423             backbone, SLOT(search(QString)));
424
425     connect(this, SIGNAL(searchTranslations(QList<Translation*>)),
426             backbone, SLOT(searchXml(QList<Translation*>)));
427
428     connect(this, SIGNAL(stopSearching()),
429             backbone, SLOT(stopSearching()));
430
431     connect(this, SIGNAL(stopSearching()),
432             this, SLOT(searchingInterrupted()));
433
434     connect(this, SIGNAL(addNewDictionary(CommonDictInterface*)),
435             backbone, SLOT(addDictionary(CommonDictInterface*)));
436
437     connect(this, SIGNAL(removeDictionary(CommonDictInterface*)),
438             backbone, SLOT(removeDictionary(CommonDictInterface*)));
439
440     connect(this, SIGNAL(selectedDictionaries(QList<CommonDictInterface*>)),
441             backbone, SLOT(selectedDictionaries(QList<CommonDictInterface*>)));
442
443
444     connect(backbone, SIGNAL(ready()),
445             this, SIGNAL(setIdle()));
446
447     connect(backbone, SIGNAL(xmlReady()),
448             this, SIGNAL(setIdle()));
449
450
451     connect(backbone, SIGNAL(ready()),
452             this, SLOT(wordListReady()));
453
454     connect(backbone, SIGNAL(xmlReady()),
455             this, SLOT(translationsReady()));
456
457     connect(backbone, SIGNAL(searchCanceled()),
458             this, SIGNAL(setIdle()));
459
460     connect(backbone, SIGNAL(notify(Notify::NotifyType,QString)),
461             this, SLOT(showNotification(Notify::NotifyType,QString)));
462
463     connect(backbone, SIGNAL(closeOk()),
464             this, SLOT(close()));
465
466     connect(backbone, SIGNAL(bookmarkMode()),
467             this, SIGNAL(bookmarkMode()));
468
469
470     //connect(wordListWidget, SIGNAL(addBookmark(QList<Translation*>)),
471     //       this, SIGNAL(setBusy()));
472
473     //connect(backbone, SIGNAL(bookmarkReady()),
474     //        this, SIGNAL(setIdle()));
475 }
476
477 void MainWindow::connectSearchBar() {
478     connect(searchBarWidget, SIGNAL(searchForTranslations(QString)),
479             this, SIGNAL(searchWordList(QString)));
480
481     connect(searchBarWidget, SIGNAL(stopSearching()),
482             this, SIGNAL(stopSearching()));
483
484     connect(this, SIGNAL(setBusy()),
485             searchBarWidget, SLOT(setBusy()));
486
487     connect(this, SIGNAL(setIdle()),
488             searchBarWidget, SLOT(setIdle()));
489
490     connect(searchBarWidget, SIGNAL(historyNext()),
491             this, SLOT(historyNext()));
492
493     connect(searchBarWidget, SIGNAL(historyPrev()),
494             this, SLOT(historyPrev()));
495
496     connect(searchBarWidget, SIGNAL(historyShow(QPoint)),
497             this, SLOT(showHistory(QPoint)));
498
499     connect(searchBarWidget, SIGNAL(refreshHistoryButtons()),
500             backbone->history(), SLOT(refreshStatus()));
501
502     connect(backbone->history(), SIGNAL(historyChanged(bool,bool,bool)),
503             searchBarWidget, SLOT(updateHistoryButtons(bool,bool,bool)));
504 }
505
506 void MainWindow::connectWordList() {
507     connect(this,
508             SIGNAL(showWordList(QHash<QString, QList<Translation*> >)),
509             wordListWidget,
510             SLOT(showSearchResults(QHash<QString,QList<Translation*> >)));
511
512     connect(wordListWidget, SIGNAL(showTranslation(QList<Translation*>)),
513             this, SIGNAL(searchTranslations(QList<Translation*>)));
514
515
516
517
518     connect(this, SIGNAL(setBusy()),
519             wordListWidget, SLOT(lockList()));
520
521     connect(this, SIGNAL(setIdle()),
522             wordListWidget, SLOT(unlockList()));
523
524     connect(this, SIGNAL(bookmarkMode()),
525             wordListWidget, SLOT(bookmarkModeActive()));
526
527     connect(wordListWidget, SIGNAL(addBookmark(QList<Translation*>)),
528             backbone, SLOT(addBookmark(QList<Translation*>)));
529
530     connect(wordListWidget, SIGNAL(removeBookmark(QList<Translation*>)),
531             backbone, SLOT(removeBookmark(QList<Translation*>)));
532 }
533
534 void MainWindow::connectTranslationWidget() {
535     connect(this, SIGNAL(showTranslation(QStringList)),
536             translationWidget, SLOT(show(QStringList)));
537
538      #ifdef Q_WS_MAEMO_5
539         connect(translationWidget, SIGNAL(search(QString)),
540                 this, SLOT(search(QString)));
541
542         connect(translationWidget, SIGNAL(notify(Notify::NotifyType, QString)),
543                 this, SLOT(showNotification(Notify::NotifyType,QString)));
544     #else
545         connect(translationWidget, SIGNAL(search(QString)),
546                 this, SLOT(searchExact(QString)));
547     #endif
548
549 }
550
551 void MainWindow::connectDictManager() {
552     connect(dictManagerWidget, SIGNAL(addDictionary(CommonDictInterface*)),
553             this, SIGNAL(addNewDictionary(CommonDictInterface*)));
554
555     connect(dictManagerWidget, SIGNAL(removeDictionary(CommonDictInterface*)),
556             this, SIGNAL(removeDictionary(CommonDictInterface*)));
557
558     connect(dictManagerWidget,
559             SIGNAL(selectedDictionaries(QList<CommonDictInterface*>)),
560             this, SIGNAL(selectedDictionaries(QList<CommonDictInterface*>)));
561 }
562
563 void MainWindow::connectMenu() {
564     connect(this, SIGNAL(setBusy()),
565             this, SLOT(disableMenu()));
566
567     connect(this, SIGNAL(setIdle()),
568             this, SLOT(enableMenu()));
569 }
570
571
572 void MainWindow::connectBookmarksWidget() {
573     #ifdef Q_WS_MAEMO_5
574         //after removing bookmarks we search for them once again to clear the words list
575         connect(bookmarksWidget, SIGNAL(removeAllBookmarks()),
576                 this, SLOT(removeBookmarks()));
577
578
579         connect(bookmarksWidget, SIGNAL(showAllBookmarks()),
580                 menuWidget, SLOT(hideMenu()));
581
582         connect(bookmarksWidget, SIGNAL(showAllBookmarks()),
583                 backbone, SLOT(fetchBookmarks()));
584
585
586     #else
587         connect(bookmarksRemoveAllAction, SIGNAL(triggered()),
588                 this, SLOT(removeBookmarks()));
589         connect(bookmarksShowAllAction, SIGNAL(triggered()),
590                 backbone, SLOT(fetchBookmarks()));
591
592     #endif
593 }
594
595
596 void MainWindow::removeBookmarks() {
597     QWidget* par;
598     #ifdef Q_WS_MAEMO_5
599         par = bookmarksWidget;
600     #else
601         par = this;
602     #endif
603     if(QMessageBox::question(par, tr("Delete all bookmarks"),
604              tr("Do you want to delete all bookmarks? (This action cannot be revoked, and will clear current word list)"),
605              QMessageBox::Yes, QMessageBox::Cancel) == QMessageBox::Yes) {
606         backbone->removeAllBookmarks();
607         ((WordListWidget*)wordListWidget)->clear();
608     }
609 }