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