915cf2d8012100b5a58eb58d5cc0a178bba57125
[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         mainLayout->addWidget(searchBarWidget, 0, Qt::AlignBottom);
120     #endif
121 }
122
123 void MainWindow::initializeMenu() {
124     initializeMenuWidgets();
125
126 #ifdef Q_WS_MAEMO_5
127     menuWidget = new MenuWidget(this);
128
129     menuWidget->addSubMenu(tr("Settings"), settingsWidget);
130     menuWidget->addSubMenu(tr("Dictionaries"), dictManagerWidget);
131     menuWidget->addSubMenu(tr("Bookmarks"), bookmarksWidget);
132     menuWidget->addSubMenu(tr("About"), aboutWidget);
133
134     menuBar->addAction(menuWidget);
135
136     connect(menuWidget, SIGNAL(setApplicationMenu(QWidget*)),
137             notifyManager, SLOT(setMenu(QWidget*)));
138 #else
139     dictionariesAction = menuBar->addAction(tr("&Dictionaries"));
140     connect(dictionariesAction, SIGNAL(triggered()),
141             dictManagerWidget, SLOT(show()));
142
143     settingsAction = menuBar->addAction(tr("&Settings"));
144     connect(settingsAction, SIGNAL(triggered()),
145             settingsWidget, SLOT(show()));
146
147     QMenu* m = menuBar->addMenu(tr("&Bookmarks"));
148     bookmarksShowAllAction = new QAction(tr("Show all"), m);
149
150     bookmarksRemoveAllAction = new QAction(tr("Remove all"), m);
151
152     m->addAction(bookmarksShowAllAction);
153     m->addAction(bookmarksRemoveAllAction);
154
155     aboutAction = menuBar->addAction(tr("&About"));
156     connect(aboutAction, SIGNAL(triggered()),
157             aboutWidget, SLOT(show()));
158
159 #endif
160 }
161
162 void MainWindow::initializeMenuWidgets() {
163     dictManagerWidget = new DictManagerWidget(this);
164     dictManagerWidget->hide();
165
166     settingsWidget = new SettingsWidget(this);
167     settingsWidget->hide();
168
169     connect(settingsWidget, SIGNAL(notify(Notify::NotifyType,QString)),
170             this, SLOT(showNotification(Notify::NotifyType,QString)));
171
172     bookmarksWidget = new BookmarksWidget(this);
173     bookmarksWidget->hide();
174
175     aboutWidget = new AboutWidget(this);
176     aboutWidget->hide();
177 }
178
179 void MainWindow::closeEvent(QCloseEvent *event) {
180     //request to stop all searches and close app
181     Q_EMIT quit();
182     event->accept();
183 }
184
185 bool MainWindow::isInExactSearch() {
186     return _exactSearch;
187 }
188
189 void MainWindow::setExactSearch(bool exact) {
190     _exactSearch = exact;
191 }
192
193 void MainWindow::setExactSearchString(QString word) {
194     searchString = word;
195 }
196
197 void MainWindow::wordListReady() {
198     //gets results from backbone
199     QMultiHash<QString, Translation*> backboneResult = backbone->result();
200     QHash<QString, QList<Translation*> > searchResult;
201
202     #ifdef Q_WS_MAEMO_5
203         hideWelcomeScreen();
204     #endif
205
206     //if nothing was found
207     if(backboneResult.count() == 0) {
208         showNotification(Notify::Info, tr("Can't find any matching words"));
209
210         //show empty list to remove results of old search
211         Q_EMIT showWordList(searchResult);
212     }
213     else {
214         //find translations of the same key word
215         QMultiHash<QString, Translation*>::iterator i;
216         for(i = backboneResult.begin(); i != backboneResult.end(); i++) {
217             searchResult[i.key()].push_back(i.value());
218         }
219
220         //show search results
221         Q_EMIT showWordList(searchResult);
222
223
224         if(isInExactSearch()) {
225             QList<Translation*> exactTranslation;
226             if(checkExactSearch(searchResult, exactTranslation)) {
227                 Q_EMIT searchTranslations(exactTranslation);
228             }
229             else {
230                 showNotification(Notify::Info,
231                            tr("Can't find exactly matching word"));
232             }
233
234             setExactSearch(false);
235         }
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
375     HistoryListDialog historyDialog(backbone->history()->list(), searchBarWidget);
376
377     #ifndef Q_WS_MAEMO_5
378         QPoint newPos = mapFromGlobal(p);
379         newPos.setY(searchBarWidget->pos().y() -
380                     historyDialog.sizeHint().height());
381         newPos.setX(width() - historyDialog.sizeHint().width());
382
383         historyDialog.move(newPos);
384     #endif
385
386     if(historyDialog.exec() == QDialog::Accepted) {
387         backbone->history()->setCurrentElement(historyDialog.selectedRow());
388         searchExact(historyDialog.selectedWord());
389     }
390 }
391
392 void MainWindow::setSettings(Settings *s) {
393     backbone->setSettings(s);
394 }
395
396 Settings* MainWindow::settings() {
397     return backbone->settings();
398 }
399
400
401 void MainWindow::showNotification(Notify::NotifyType type, QString text) {
402     notifyManager->showNotification(type, text);
403 }
404
405 void MainWindow::connectBackbone() {
406
407     connect(this, SIGNAL(searchWordList(QString)),
408             this, SIGNAL(setBusy()));
409
410     connect(this, SIGNAL(searchTranslations(QList<Translation*>)),
411             this, SIGNAL(setBusy()));
412
413     connect(this, SIGNAL(stopSearching()),
414             this, SIGNAL(setIdle()));
415
416     connect(this, SIGNAL(searchWordList(QString)),
417             this, SLOT(setExactSearchString(QString)));
418
419     connect(this, SIGNAL(searchTranslations(QList<Translation*>)),
420             this, SLOT(addToHistory(QList<Translation*>)));
421
422
423
424     connect(this, SIGNAL(quit()),
425             backbone, SLOT(quit()));
426
427     connect(this, SIGNAL(searchWordList(QString)),
428             backbone, SLOT(search(QString)));
429
430     connect(this, SIGNAL(searchTranslations(QList<Translation*>)),
431             backbone, SLOT(searchXml(QList<Translation*>)));
432
433     connect(this, SIGNAL(stopSearching()),
434             backbone, SLOT(stopSearching()));
435
436     connect(this, SIGNAL(stopSearching()),
437             this, SLOT(searchingInterrupted()));
438
439     connect(this, SIGNAL(addNewDictionary(CommonDictInterface*)),
440             backbone, SLOT(addDictionary(CommonDictInterface*)));
441
442     connect(this, SIGNAL(removeDictionary(CommonDictInterface*)),
443             backbone, SLOT(removeDictionary(CommonDictInterface*)));
444
445     connect(this, SIGNAL(selectedDictionaries(QList<CommonDictInterface*>)),
446             backbone, SLOT(selectedDictionaries(QList<CommonDictInterface*>)));
447
448
449     connect(backbone, SIGNAL(ready()),
450             this, SIGNAL(setIdle()));
451
452     connect(backbone, SIGNAL(xmlReady()),
453             this, SIGNAL(setIdle()));
454
455
456     connect(backbone, SIGNAL(ready()),
457             this, SLOT(wordListReady()));
458
459     connect(backbone, SIGNAL(xmlReady()),
460             this, SLOT(translationsReady()));
461
462     connect(backbone, SIGNAL(searchCanceled()),
463             this, SIGNAL(setIdle()));
464
465     connect(backbone, SIGNAL(notify(Notify::NotifyType,QString)),
466             this, SLOT(showNotification(Notify::NotifyType,QString)));
467
468     connect(backbone, SIGNAL(closeOk()),
469             this, SLOT(close()));
470
471
472     //connect(wordListWidget, SIGNAL(addBookmark(QList<Translation*>)),
473     //       this, SIGNAL(setBusy()));
474
475     //connect(backbone, SIGNAL(bookmarkReady()),
476     //        this, SIGNAL(setIdle()));
477 }
478
479 void MainWindow::connectSearchBar() {
480     connect(searchBarWidget, SIGNAL(searchForTranslations(QString)),
481             this, SIGNAL(searchWordList(QString)));
482
483     connect(searchBarWidget, SIGNAL(stopSearching()),
484             this, SIGNAL(stopSearching()));
485
486     connect(this, SIGNAL(setBusy()),
487             searchBarWidget, SLOT(setBusy()));
488
489     connect(this, SIGNAL(setIdle()),
490             searchBarWidget, SLOT(setIdle()));
491
492     connect(searchBarWidget, SIGNAL(historyNext()),
493             this, SLOT(historyNext()));
494
495     connect(searchBarWidget, SIGNAL(historyPrev()),
496             this, SLOT(historyPrev()));
497
498     connect(searchBarWidget, SIGNAL(historyShow(QPoint)),
499             this, SLOT(showHistory(QPoint)));
500
501     connect(searchBarWidget, SIGNAL(refreshHistoryButtons()),
502             backbone->history(), SLOT(refreshStatus()));
503
504     connect(backbone->history(), SIGNAL(historyChanged(bool,bool,bool)),
505             searchBarWidget, SLOT(updateHistoryButtons(bool,bool,bool)));
506 }
507
508 void MainWindow::connectWordList() {
509     connect(this,
510             SIGNAL(showWordList(QHash<QString, QList<Translation*> >)),
511             wordListWidget,
512             SLOT(showSearchResults(QHash<QString,QList<Translation*> >)));
513
514     connect(wordListWidget, SIGNAL(showTranslation(QList<Translation*>)),
515             this, SIGNAL(searchTranslations(QList<Translation*>)));
516
517
518
519
520     connect(this, SIGNAL(setBusy()),
521             wordListWidget, SLOT(lockList()));
522
523     connect(this, SIGNAL(setIdle()),
524             wordListWidget, SLOT(unlockList()));
525
526     connect(wordListWidget, SIGNAL(addBookmark(QList<Translation*>)),
527             backbone, SLOT(addBookmark(QList<Translation*>)));
528
529     connect(wordListWidget, SIGNAL(removeBookmark(QList<Translation*>)),
530             backbone, SLOT(removeBookmark(QList<Translation*>)));
531 }
532
533 void MainWindow::connectTranslationWidget() {
534     connect(this, SIGNAL(showTranslation(QStringList)),
535             translationWidget, SLOT(show(QStringList)));
536
537      #ifdef Q_WS_MAEMO_5
538         connect(translationWidget, SIGNAL(search(QString)),
539                 this, SLOT(search(QString)));
540
541         connect(translationWidget, SIGNAL(notify(Notify::NotifyType, QString)),
542                 this, SLOT(showNotification(Notify::NotifyType,QString)));
543     #else
544         connect(translationWidget, SIGNAL(search(QString)),
545                 this, SLOT(searchExact(QString)));
546     #endif
547
548 }
549
550 void MainWindow::connectDictManager() {
551     connect(dictManagerWidget, SIGNAL(addDictionary(CommonDictInterface*)),
552             this, SIGNAL(addNewDictionary(CommonDictInterface*)));
553
554     connect(dictManagerWidget, SIGNAL(removeDictionary(CommonDictInterface*)),
555             this, SIGNAL(removeDictionary(CommonDictInterface*)));
556
557     connect(dictManagerWidget,
558             SIGNAL(selectedDictionaries(QList<CommonDictInterface*>)),
559             this, SIGNAL(selectedDictionaries(QList<CommonDictInterface*>)));
560 }
561
562 void MainWindow::connectMenu() {
563     connect(this, SIGNAL(setBusy()),
564             this, SLOT(disableMenu()));
565
566     connect(this, SIGNAL(setIdle()),
567             this, SLOT(enableMenu()));
568 }
569
570
571 void MainWindow::connectBookmarksWidget() {
572     #ifdef Q_WS_MAEMO_5
573         //after removing bookmarks we search for them once again to clear the words list
574         connect(bookmarksWidget, SIGNAL(removeAllBookmarks()),
575                 this, SLOT(removeBookmarks()));
576
577
578         connect(bookmarksWidget, SIGNAL(showAllBookmarks()),
579                 menuWidget, SLOT(hideMenu()));
580
581         connect(bookmarksWidget, SIGNAL(showAllBookmarks()),
582                 backbone, SLOT(fetchBookmarks()));
583
584
585     #else
586         connect(bookmarksRemoveAllAction, SIGNAL(triggered()),
587                 this, SLOT(removeBookmarks()));
588         connect(bookmarksShowAllAction, SIGNAL(triggered()),
589                 backbone, SLOT(fetchBookmarks()));
590
591     #endif
592 }
593
594
595 void MainWindow::removeBookmarks() {
596     QWidget* par;
597     #ifdef Q_WS_MAEMO_5
598         par = bookmarksWidget;
599     #else
600         par = this;
601     #endif
602     if(QMessageBox::question(par, tr("Delete all bookmarks"),
603              tr("Do you want to delete all bookmarks? (This action cannot be revoked, and will clear current word list)"),
604              QMessageBox::Yes, QMessageBox::Cancel) == QMessageBox::Yes) {
605         backbone->removeAllBookmarks();
606         ((WordListWidget*)wordListWidget)->clear();
607     }
608
609
610 }