51384d6b59ca8e8a18ea3ad82864b18c88627d9c
[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     wordListWidget->setFocus();
236 }
237
238 bool MainWindow::checkExactSearch(
239         QHash<QString, QList<Translation *> > searchResult,
240         QList<Translation *> &found) {
241
242     bool foundExactMatch = false;
243     QHash<QString, QList<Translation*> >::iterator j;
244     for(j = searchResult.begin(); j != searchResult.end(); j++) {
245         if(j.key().toLower() == searchString.toLower()
246             && !foundExactMatch) {
247             found = j.value();
248             return true;
249         }
250     }
251     return false;
252 }
253
254 void MainWindow::translationsReady() {
255     #ifndef Q_WS_MAEMO_5
256         hideWelcomeScreen();
257     #endif
258
259     Q_EMIT showTranslation(backbone->xmls());
260     wordListWidget->setFocus();
261     #ifdef Q_WS_MAEMO_5
262         notifyManager->screenChanged();
263     #endif
264 }
265
266
267 void MainWindow::hideWelcomeScreen() {
268 #ifdef Q_WS_MAEMO_5
269     //switch welcome screen with word list
270     if(!wordListWidget->isVisible()) {
271         mainLayout->removeWidget(welcomeScreenWidget);
272         welcomeScreenWidget->deleteLater();
273
274         mainLayout->insertWidget(0, wordListWidget);
275     }
276 #else
277     //switch welcome screen with translation widget
278     if(!translationWidget->isVisible()) {
279         splitter->insertWidget(1,translationWidget);
280         splitter->setStretchFactor(1, 150);
281         welcomeScreenWidget->deleteLater();
282     }
283 #endif
284 }
285
286 QList<CommonDictInterface*> MainWindow::getPlugins() {
287     return backbone->getPlugins();
288 }
289
290 QHash<CommonDictInterface*, bool> MainWindow::getDictionaries() {
291     return backbone->getDictionaries();
292 }
293
294
295 void MainWindow::search(QString word) {
296     setExactSearch(false);
297     searchBarWidget->search(word);
298     #ifdef Q_WS_MAEMO_5
299     if(translationWidget->isVisible()) {
300             translationWidget->hide();
301             update();
302         }
303     #endif
304 }
305
306 void MainWindow::searchExact(QString word) {
307     setExactSearch(true);
308     searchBarWidget->search(word);
309 }
310
311 void MainWindow::searchDelay(QString word) {
312     searchBarWidget->searchDelay(word);
313 }
314
315
316
317
318
319 void MainWindow::searchingInterrupted() {
320     //make sure to unset exact search mode
321     setExactSearch(false);
322 }
323
324 void MainWindow::addToHistory(QList<Translation *> trans) {
325     if(trans.count() > 0) {
326         backbone->history()->add(trans[0]->key());
327     }
328 }
329
330 void MainWindow::historyNext() {
331     if(backbone->history()->nextAvailable()) {
332         QString next = backbone->history()->next();
333         #ifndef Q_WS_MAEMO_5
334             setExactSearch(true);
335         #endif
336         searchDelay(next);
337     }
338 }
339
340 void MainWindow::historyPrev() {
341     if(backbone->history()->prevAvailable()) {
342         #ifndef Q_WS_MAEMO_5
343             setExactSearch(true);
344         #endif
345         QString prev = backbone->history()->previous();
346         searchDelay(prev);
347     }
348 }
349
350 void MainWindow::disableMenu() {
351     #ifdef Q_WS_MAEMO_5
352         if(menuBar->actions().contains(menuWidget)) {
353               menuBar->removeAction(menuWidget);
354         }
355     #else
356         menuBar->setEnabled(false);
357     #endif
358 }
359
360 void MainWindow::enableMenu() {
361     #ifdef Q_WS_MAEMO_5
362         if(!menuBar->actions().contains(menuWidget)) {
363             menuBar->addAction(menuWidget);
364         }
365     #else
366         menuBar->setEnabled(true);
367     #endif
368 }
369
370 void MainWindow::showHistory(QPoint p) {
371
372     HistoryListDialog historyDialog(backbone->history()->list(), searchBarWidget);
373
374     #ifndef Q_WS_MAEMO_5
375         QPoint newPos = mapFromGlobal(p);
376         newPos.setY(searchBarWidget->pos().y() -
377                     historyDialog.sizeHint().height());
378         newPos.setX(width() - historyDialog.sizeHint().width());
379
380         historyDialog.move(newPos);
381     #endif
382
383     if(historyDialog.exec() == QDialog::Accepted) {
384         backbone->history()->setCurrentElement(historyDialog.selectedRow());
385         searchExact(historyDialog.selectedWord());
386     }
387 }
388
389 void MainWindow::setSettings(Settings *s) {
390     backbone->setSettings(s);
391 }
392
393 Settings* MainWindow::settings() {
394     return backbone->settings();
395 }
396
397
398 void MainWindow::showNotification(Notify::NotifyType type, QString text) {
399     notifyManager->showNotification(type, text);
400 }
401
402 void MainWindow::connectBackbone() {
403
404     connect(this, SIGNAL(searchWordList(QString)),
405             this, SIGNAL(setBusy()));
406
407     connect(this, SIGNAL(searchTranslations(QList<Translation*>)),
408             this, SIGNAL(setBusy()));
409
410     connect(this, SIGNAL(stopSearching()),
411             this, SIGNAL(setIdle()));
412
413     connect(this, SIGNAL(searchWordList(QString)),
414             this, SLOT(setExactSearchString(QString)));
415
416     connect(this, SIGNAL(searchTranslations(QList<Translation*>)),
417             this, SLOT(addToHistory(QList<Translation*>)));
418
419
420
421     connect(this, SIGNAL(quit()),
422             backbone, SLOT(quit()));
423
424     connect(this, SIGNAL(searchWordList(QString)),
425             backbone, SLOT(search(QString)));
426
427     connect(this, SIGNAL(searchTranslations(QList<Translation*>)),
428             backbone, SLOT(searchXml(QList<Translation*>)));
429
430     connect(this, SIGNAL(stopSearching()),
431             backbone, SLOT(stopSearching()));
432
433     connect(this, SIGNAL(stopSearching()),
434             this, SLOT(searchingInterrupted()));
435
436     connect(this, SIGNAL(addNewDictionary(CommonDictInterface*)),
437             backbone, SLOT(addDictionary(CommonDictInterface*)));
438
439     connect(this, SIGNAL(removeDictionary(CommonDictInterface*)),
440             backbone, SLOT(removeDictionary(CommonDictInterface*)));
441
442     connect(this, SIGNAL(selectedDictionaries(QList<CommonDictInterface*>)),
443             backbone, SLOT(selectedDictionaries(QList<CommonDictInterface*>)));
444
445
446     connect(backbone, SIGNAL(ready()),
447             this, SIGNAL(setIdle()));
448
449     connect(backbone, SIGNAL(xmlReady()),
450             this, SIGNAL(setIdle()));
451
452
453     connect(backbone, SIGNAL(ready()),
454             this, SLOT(wordListReady()));
455
456     connect(backbone, SIGNAL(xmlReady()),
457             this, SLOT(translationsReady()));
458
459     connect(backbone, SIGNAL(searchCanceled()),
460             this, SIGNAL(setIdle()));
461
462     connect(backbone, SIGNAL(notify(Notify::NotifyType,QString)),
463             this, SLOT(showNotification(Notify::NotifyType,QString)));
464
465     connect(backbone, SIGNAL(closeOk()),
466             this, SLOT(close()));
467
468
469     //connect(wordListWidget, SIGNAL(addBookmark(QList<Translation*>)),
470     //       this, SIGNAL(setBusy()));
471
472     //connect(backbone, SIGNAL(bookmarkReady()),
473     //        this, SIGNAL(setIdle()));
474 }
475
476 void MainWindow::connectSearchBar() {
477     connect(searchBarWidget, SIGNAL(searchForTranslations(QString)),
478             this, SIGNAL(searchWordList(QString)));
479
480     connect(searchBarWidget, SIGNAL(stopSearching()),
481             this, SIGNAL(stopSearching()));
482
483     connect(this, SIGNAL(setBusy()),
484             searchBarWidget, SLOT(setBusy()));
485
486     connect(this, SIGNAL(setIdle()),
487             searchBarWidget, SLOT(setIdle()));
488
489     connect(searchBarWidget, SIGNAL(historyNext()),
490             this, SLOT(historyNext()));
491
492     connect(searchBarWidget, SIGNAL(historyPrev()),
493             this, SLOT(historyPrev()));
494
495     connect(searchBarWidget, SIGNAL(historyShow(QPoint)),
496             this, SLOT(showHistory(QPoint)));
497
498     connect(searchBarWidget, SIGNAL(refreshHistoryButtons()),
499             backbone->history(), SLOT(refreshStatus()));
500
501     connect(backbone->history(), SIGNAL(historyChanged(bool,bool,bool)),
502             searchBarWidget, SLOT(updateHistoryButtons(bool,bool,bool)));
503 }
504
505 void MainWindow::connectWordList() {
506     connect(this,
507             SIGNAL(showWordList(QHash<QString, QList<Translation*> >)),
508             wordListWidget,
509             SLOT(showSearchResults(QHash<QString,QList<Translation*> >)));
510
511     connect(wordListWidget, SIGNAL(showTranslation(QList<Translation*>)),
512             this, SIGNAL(searchTranslations(QList<Translation*>)));
513
514
515
516
517     connect(this, SIGNAL(setBusy()),
518             wordListWidget, SLOT(lockList()));
519
520     connect(this, SIGNAL(setIdle()),
521             wordListWidget, SLOT(unlockList()));
522
523     connect(wordListWidget, SIGNAL(addBookmark(QList<Translation*>)),
524             backbone, SLOT(addBookmark(QList<Translation*>)));
525
526     connect(wordListWidget, SIGNAL(removeBookmark(QList<Translation*>)),
527             backbone, SLOT(removeBookmark(QList<Translation*>)));
528 }
529
530 void MainWindow::connectTranslationWidget() {
531     connect(this, SIGNAL(showTranslation(QStringList)),
532             translationWidget, SLOT(show(QStringList)));
533
534      #ifdef Q_WS_MAEMO_5
535         connect(translationWidget, SIGNAL(search(QString)),
536                 this, SLOT(search(QString)));
537
538         connect(translationWidget, SIGNAL(notify(Notify::NotifyType, QString)),
539                 this, SLOT(showNotification(Notify::NotifyType,QString)));
540     #else
541         connect(translationWidget, SIGNAL(search(QString)),
542                 this, SLOT(searchExact(QString)));
543     #endif
544
545 }
546
547 void MainWindow::connectDictManager() {
548     connect(dictManagerWidget, SIGNAL(addDictionary(CommonDictInterface*)),
549             this, SIGNAL(addNewDictionary(CommonDictInterface*)));
550
551     connect(dictManagerWidget, SIGNAL(removeDictionary(CommonDictInterface*)),
552             this, SIGNAL(removeDictionary(CommonDictInterface*)));
553
554     connect(dictManagerWidget,
555             SIGNAL(selectedDictionaries(QList<CommonDictInterface*>)),
556             this, SIGNAL(selectedDictionaries(QList<CommonDictInterface*>)));
557 }
558
559 void MainWindow::connectMenu() {
560     connect(this, SIGNAL(setBusy()),
561             this, SLOT(disableMenu()));
562
563     connect(this, SIGNAL(setIdle()),
564             this, SLOT(enableMenu()));
565 }
566
567
568 void MainWindow::connectBookmarksWidget() {
569     #ifdef Q_WS_MAEMO_5
570         //after removing bookmarks we search for them once again to clear the words list
571         connect(bookmarksWidget, SIGNAL(removeAllBookmarks()),
572                 this, SLOT(removeBookmarks()));
573
574
575         connect(bookmarksWidget, SIGNAL(showAllBookmarks()),
576                 menuWidget, SLOT(hideMenu()));
577
578         connect(bookmarksWidget, SIGNAL(showAllBookmarks()),
579                 backbone, SLOT(fetchBookmarks()));
580
581
582     #else
583         connect(bookmarksRemoveAllAction, SIGNAL(triggered()),
584                 this, SLOT(removeBookmarks()));
585         connect(bookmarksShowAllAction, SIGNAL(triggered()),
586                 backbone, SLOT(fetchBookmarks()));
587
588     #endif
589 }
590
591
592 void MainWindow::removeBookmarks() {
593     QWidget* par;
594     #ifdef Q_WS_MAEMO_5
595         par = bookmarksWidget;
596     #else
597         par = this;
598     #endif
599     if(QMessageBox::question(par, tr("Delete all bookmarks"),
600              tr("Do you want to delete all bookmarks? (This action cannot be revoked, and will clear current word list)"),
601              QMessageBox::Yes, QMessageBox::Cancel) == QMessageBox::Yes) {
602         backbone->removeAllBookmarks();
603         ((WordListWidget*)wordListWidget)->clear();
604     }
605
606
607 }