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