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