Abstract out progress dialog.
[dorian] / mainwindow.cpp
1 #include <QtGui>
2 #include <QtDebug>
3 #include <QDir>
4 #include <QApplication>
5 #include <QFileInfo>
6 #include <QStringList>
7 #include <QWebView>
8 #include <QWebFrame>
9
10 #ifdef Q_WS_MAEMO_5
11 #   include <QtMaemo5/QMaemo5InformationBox>
12 #   include <QtDBus>
13 #   include <QtGui/QX11Info>
14 #   include <X11/Xlib.h>
15 #   include <X11/Xatom.h>
16 #   include <mce/mode-names.h>
17 #   include <mce/dbus-names.h>
18 #endif // Q_WS_MAEMO_5
19
20 #include "bookview.h"
21 #include "book.h"
22 #include "library.h"
23 #include "infodialog.h"
24 #include "librarydialog.h"
25 #include "devtools.h"
26 #include "mainwindow.h"
27 #include "settingswindow.h"
28 #include "bookmarksdialog.h"
29 #include "settings.h"
30 #include "chaptersdialog.h"
31 #include "fullscreenwindow.h"
32 #include "trace.h"
33 #include "bookfinder.h"
34 #include "progress.h"
35 #include "dyalog.h"
36 #include "translucentbutton.h"
37 #include "platform.h"
38 #include "progressdialog.h"
39
40 #ifdef DORIAN_TEST_MODEL
41 #   include "modeltest.h"
42 #endif
43
44 const int DORIAN_PROGRESS_HEIGHT = 17;
45
46 MainWindow::MainWindow(QWidget *parent):
47     AdopterWindow(parent), view(0), preventBlankingTimer(-1)
48 {
49     Trace t("MainWindow::MainWindow");
50 #ifdef Q_WS_MAEMO_5
51     setAttribute(Qt::WA_Maemo5StackedWindow, true);
52 #endif
53     setWindowTitle("Dorian");
54
55     // Central widget. Must be an intermediate, because the book view widget
56     // can be re-parented later
57     QFrame *central = new QFrame(this);
58     QVBoxLayout *layout = new QVBoxLayout(central);
59     layout->setMargin(0);
60     central->setLayout(layout);
61     setCentralWidget(central);
62
63     // Book view
64     view = new BookView(central);
65     view->show();
66     layout->addWidget(view);
67
68     // Progress
69     progress = new Progress(central);
70
71     // Settings dialog
72     settings = new QDialog(this);
73
74     // Tool bar actions
75
76 #ifdef Q_OS_SYMBIAN
77     fullScreenAction = addToolBarAction(this, SLOT(showBig()),
78                                         "view-fullscreen", tr("Full screen"));
79 #endif
80
81     chaptersAction = addToolBarAction(this, SLOT(showChapters()),
82                                       "chapters", tr("Chapters"));
83     bookmarksAction = addToolBarAction(this, SLOT(showBookmarks()),
84                                        "bookmarks", tr("Bookmarks"));
85     infoAction = addToolBarAction(this, SLOT(showInfo()),
86                                   "info", tr("Book info"));
87     libraryAction = addToolBarAction(this, SLOT(showLibrary()),
88                                      "library", tr("Library"));
89
90 #ifdef Q_WS_MAEMO_5
91     settingsAction = menuBar()->addAction(tr("Settings"));
92     connect(settingsAction, SIGNAL(triggered()), this, SLOT(showSettings()));
93     devToolsAction = menuBar()->addAction(tr("Developer"));
94     connect(devToolsAction, SIGNAL(triggered()), this, SLOT(showDevTools()));
95     QAction *aboutAction = menuBar()->addAction(tr("About"));
96     connect(aboutAction, SIGNAL(triggered()), this, SLOT(about()));
97 #else
98     settingsAction = addToolBarAction(this, SLOT(showSettings()),
99                                       "preferences-system", tr("Settings"));
100     devToolsAction = addToolBarAction(this, SLOT(showDevTools()),
101                                       "developer", tr("Developer"));
102     addToolBarAction(this, SLOT(about()), "about", tr("About"));
103 #endif // Q_WS_MAEMO_5
104
105 #ifndef Q_OS_SYMBIAN
106     addToolBarSpace();
107     fullScreenAction = addToolBarAction(this, SLOT(showBig()),
108                                         "view-fullscreen", tr("Full screen"));
109 #endif
110
111     // Buttons on top of the book view
112     previousButton = new TranslucentButton("back", this);
113     nextButton = new TranslucentButton("forward", this);
114
115     // Handle model changes
116     connect(Library::instance(), SIGNAL(nowReadingChanged()),
117             this, SLOT(onCurrentBookChanged()));
118
119     // Load library, upgrade it if needed
120     libraryProgress = new ProgressDialog(tr("Upgrading library"), this);
121     libraryProgress->reset();
122     libraryProgress->setMinimumDuration(0);
123     libraryProgress->setWindowModality(Qt::WindowModal);
124     libraryProgress->setCancelButton(0);
125     Library *library = Library::instance();
126     connect(library, SIGNAL(beginUpgrade(int)), this, SLOT(onBeginUpgrade(int)));
127     connect(library, SIGNAL(upgrading(const QString &)),
128             this, SLOT(onUpgrading(const QString &)));
129     connect(library, SIGNAL(endUpgrade()), this, SLOT(onEndUpgrade()));
130     connect(library, SIGNAL(beginLoad(int)), this, SLOT(onBeginLoad(int)));
131     connect(library, SIGNAL(loading(const QString &)),
132             this, SLOT(onLoading(const QString &)));
133     connect(library, SIGNAL(endLoad()), this, SLOT(onEndLoad()));
134     library->upgrade();
135     library->load();
136
137     // Load book on command line, or load last read book, or load default book
138     if (QCoreApplication::arguments().size() == 2) {
139         QString path = QCoreApplication::arguments()[1];
140         library->add(path);
141         QModelIndex index = library->find(path);
142         if (index.isValid()) {
143             library->setNowReading(index);
144         }
145     } else {
146         QModelIndex index = library->nowReading();
147         if (index.isValid()) {
148             library->setNowReading(index);
149         } else {
150             if (!library->rowCount()) {
151                 library->add(":/books/2BR02B.epub");
152             }
153             library->setNowReading(library->index(0));
154         }
155     }
156
157     // Handle loading book parts
158     connect(view, SIGNAL(partLoadStart(int)), this, SLOT(onPartLoadStart()));
159     connect(view, SIGNAL(partLoadEnd(int)), this, SLOT(onPartLoadEnd(int)));
160
161     // Handle progress
162     connect(view, SIGNAL(progress(qreal)), progress, SLOT(setProgress(qreal)));
163
164     // Shadow window for full screen reading
165     fullScreenWindow = new FullScreenWindow(this);
166     connect(fullScreenWindow, SIGNAL(restore()), this, SLOT(showRegular()));
167
168     // Handle settings changes
169     Settings *settings = Settings::instance();
170     connect(settings, SIGNAL(valueChanged(const QString &)),
171             this, SLOT(onSettingsChanged(const QString &)));
172     settings->setValue("orientation", settings->value("orientation"));
173     settings->setValue("lightson", settings->value("lightson"));
174     settings->setValue("usevolumekeys", settings->value("usevolumekeys"));
175
176     // Handle book view buttons
177     connect(nextButton, SIGNAL(triggered()), this, SLOT(goToNextPage()));
178     connect(previousButton, SIGNAL(triggered()), this, SLOT(goToPreviousPage()));
179
180 #ifdef DORIAN_TEST_MODEL
181     (void)new ModelTest(Library::instance(), this);
182 #endif
183 }
184
185 MainWindow::~MainWindow()
186 {
187 }
188
189 void MainWindow::onCurrentBookChanged()
190 {
191     setCurrentBook(Library::instance()->nowReading());
192 }
193
194 void MainWindow::showRegular()
195 {
196     Trace t("MainWindow::showRegular");
197     fullScreenWindow->hide();
198     fullScreenWindow->leaveChildren();
199
200     QList<QWidget *> otherChildren;
201     otherChildren << progress << previousButton << nextButton;
202     takeChildren(view, otherChildren);
203     QRect geo = geometry();
204     progress->setGeometry(0, 0, geo.width(), DORIAN_PROGRESS_HEIGHT);
205 #if defined(Q_WS_MAEMO_5)
206     previousButton->setGeometry(0,
207         geo.height() - toolBar->height() - TranslucentButton::pixels,
208         TranslucentButton::pixels, TranslucentButton::pixels);
209     nextButton->setGeometry(geo.width() - TranslucentButton::pixels, 0,
210         TranslucentButton::pixels, TranslucentButton::pixels);
211 #elif defined(Q_OS_SYMBIAN)
212     previousButton->setGeometry(0, geo.height() - TranslucentButton::pixels,
213         TranslucentButton::pixels, TranslucentButton::pixels);
214     nextButton->setGeometry(geo.width() - TranslucentButton::pixels,
215         0, TranslucentButton::pixels, TranslucentButton::pixels);
216 #else
217     previousButton->setGeometry(0, geo.height() - TranslucentButton::pixels,
218         TranslucentButton::pixels, TranslucentButton::pixels);
219     nextButton->setGeometry(geo.width() - TranslucentButton::pixels - 25,
220         toolBar->height(), TranslucentButton::pixels, TranslucentButton::pixels);
221 #endif // Q_WS_MAEMO_5
222     qDebug() << "previousButton geometry" << previousButton->geometry();
223     progress->flash();
224     nextButton->show();
225     previousButton->show();
226     nextButton->flash(1500);
227     previousButton->flash(1500);
228 }
229
230 void MainWindow::showBig()
231 {
232     Trace t("MainWindow::showBig");
233     leaveChildren();
234     QList<QWidget *> otherChildren;
235     otherChildren << progress << nextButton << previousButton;
236     QRect screen = QApplication::desktop()->screenGeometry();
237     progress->setGeometry(0, 0, screen.width(), DORIAN_PROGRESS_HEIGHT);
238 #if defined(Q_WS_MAEMO_5)
239     nextButton->setGeometry(screen.width() - TranslucentButton::pixels, 0,
240         TranslucentButton::pixels, TranslucentButton::pixels);
241 #else
242     nextButton->setGeometry(screen.width() - TranslucentButton::pixels - 25, 0,
243                             TranslucentButton::pixels, TranslucentButton::pixels);
244 #endif // Q_WS_MAEMO_5
245     previousButton->setGeometry(0, screen.height() - TranslucentButton::pixels,
246         TranslucentButton::pixels, TranslucentButton::pixels);
247
248     fullScreenWindow->takeChildren(view, otherChildren);
249     fullScreenWindow->showFullScreen();
250     progress->flash();
251     nextButton->flash(1500);
252     previousButton->flash(1500);
253 }
254
255 void MainWindow::setCurrentBook(const QModelIndex &current)
256 {
257     mCurrent = current;
258     Book *book = Library::instance()->book(current);
259     view->setBook(book);
260     setWindowTitle(book? book->shortName(): tr("Dorian"));
261 }
262
263 void MainWindow::showLibrary()
264 {
265     (new LibraryDialog(this))->show();
266 }
267
268 void MainWindow::showSettings()
269 {
270     (new SettingsWindow(this))->show();
271 }
272
273 void MainWindow::showInfo()
274 {
275     if (mCurrent.isValid()) {
276         (new InfoDialog(Library::instance()->book(mCurrent), this, false))->
277                 exec();
278     }
279 }
280
281 void MainWindow::showDevTools()
282 {
283     (new DevTools())->exec();
284 }
285
286 void MainWindow::showBookmarks()
287 {
288     Book *book = Library::instance()->book(mCurrent);
289     if (book) {
290         BookmarksDialog *bookmarks = new BookmarksDialog(book, this);
291         bookmarks->setWindowModality(Qt::WindowModal);
292         connect(bookmarks, SIGNAL(addBookmark(const QString &)),
293                 this, SLOT(onAddBookmark(const QString &)));
294         connect(bookmarks, SIGNAL(goToBookmark(int)),
295                 this, SLOT(onGoToBookmark(int)));
296         bookmarks->show();
297     }
298 }
299
300 void MainWindow::closeEvent(QCloseEvent *event)
301 {
302     Trace t("MainWindow::closeEvent");
303     view->setLastBookmark();
304     event->accept();
305 }
306
307 void MainWindow::onSettingsChanged(const QString &key)
308 {
309 #ifdef Q_WS_MAEMO_5
310     if (key == "orientation") {
311         QString value = Settings::instance()->value(key).toString();
312         qDebug() << "MainWindow::onSettingsChanged: orientation" << value;
313         if (value == "portrait") {
314             setAttribute(Qt::WA_Maemo5LandscapeOrientation, false);
315             setAttribute(Qt::WA_Maemo5PortraitOrientation, true);
316         } else {
317             setAttribute(Qt::WA_Maemo5PortraitOrientation, false);
318             setAttribute(Qt::WA_Maemo5LandscapeOrientation, true);
319         }
320     } else if (key == "lightson") {
321         bool enable = Settings::instance()->value(key, false).toBool();
322         qDebug() << "MainWindow::onSettingsChanged: lightson:" << enable;
323         killTimer(preventBlankingTimer);
324         if (enable) {
325             preventBlankingTimer = startTimer(29 * 1000);
326         }
327     } else if (key == "usevolumekeys") {
328         bool value = Settings::instance()->value(key).toBool();
329         qDebug() << "MainWindow::onSettingsChanged: usevolumekeys" << value;
330         grabZoomKeys(value);
331         fullScreenWindow->grabZoomKeys(value);
332     }
333 #else
334     Q_UNUSED(key);
335 #endif // Q_WS_MAEMO_5
336 }
337
338 void MainWindow::onPartLoadStart()
339 {
340     Trace t("MainWindow::onPartLoadStart");
341 #ifdef Q_WS_MAEMO_5
342     setAttribute(Qt::WA_Maemo5ShowProgressIndicator, true);
343 #endif
344 }
345
346 void MainWindow::onPartLoadEnd(int index)
347 {
348     Trace t("MainWindow::onPartLoadEnd");
349     bool enablePrevious = false;
350     bool enableNext = false;
351     Book *book = Library::instance()->book(mCurrent);
352     if (book) {
353         if (index > 0) {
354             enablePrevious = true;
355         }
356         if (index < (book->parts.size() - 1)) {
357             enableNext = true;
358         }
359     }
360 #ifdef Q_WS_MAEMO_5
361     setAttribute(Qt::WA_Maemo5ShowProgressIndicator, false);
362 #endif // Q_WS_MAEMO_5
363 }
364
365 void MainWindow::onAddBookmark(const QString &note)
366 {
367     Trace t("MainWindow:onAddBookmark");
368     view->addBookmark(note);
369 }
370
371 void MainWindow::onGoToBookmark(int index)
372 {
373     Trace t("MainWindow::onGoToBookmark");
374     Book *book = Library::instance()->book(mCurrent);
375     view->goToBookmark(book->bookmarks()[index]);
376 }
377
378 void MainWindow::showChapters()
379 {
380     Book *book = Library::instance()->book(mCurrent);
381     if (book) {
382         ChaptersDialog *chapters = new ChaptersDialog(book, this);
383         chapters->setWindowModality(Qt::WindowModal);
384         connect(chapters, SIGNAL(goToChapter(int)),
385                 this, SLOT(onGoToChapter(int)));
386         chapters->show();
387     }
388 }
389
390 void MainWindow::onGoToChapter(int index)
391 {
392     Trace t("MainWindow::onGoToChapter");
393
394     Book *book = Library::instance()->book(mCurrent);
395     if (book) {
396         int partIndex = book->partFromChapter(index);
397         if (partIndex != -1) {
398             view->goToBookmark(Book::Bookmark(partIndex, 0));
399         }
400     }
401 }
402
403 void MainWindow::timerEvent(QTimerEvent *event)
404 {
405     if (event->timerId() == preventBlankingTimer) {
406 #ifdef Q_WS_MAEMO_5
407         QDBusInterface mce(MCE_SERVICE, MCE_REQUEST_PATH,
408                            MCE_REQUEST_IF, QDBusConnection::systemBus());
409         mce.call(MCE_PREVENT_BLANK_REQ);
410 #endif // Q_WS_MAEMO_5
411         qDebug() << "MainWindow::timerEvent: Prevent display blanking";
412     }
413     AdopterWindow::timerEvent(event);
414 }
415
416 void MainWindow::resizeEvent(QResizeEvent *e)
417 {
418     Trace t("MainWindow::resizeEvent");
419     progress->setGeometry(QRect(0, 0, e->size().width(), DORIAN_PROGRESS_HEIGHT));
420 #if defined(Q_WS_MAEMO_5)
421     previousButton->setGeometry(0,
422         e->size().height() - toolBar->height() - TranslucentButton::pixels,
423         TranslucentButton::pixels, TranslucentButton::pixels);
424     nextButton->setGeometry(e->size().width() - TranslucentButton::pixels, 0,
425         TranslucentButton::pixels, TranslucentButton::pixels);
426 #elif defined(Q_OS_SYMBIAN)
427     previousButton->setGeometry(0, e->size().height() - TranslucentButton::pixels,
428         TranslucentButton::pixels, TranslucentButton::pixels);
429     nextButton->setGeometry(e->size().width() - TranslucentButton::pixels,
430         0, TranslucentButton::pixels, TranslucentButton::pixels);
431 #else
432     previousButton->setGeometry(0, e->size().height() - TranslucentButton::pixels,
433         TranslucentButton::pixels, TranslucentButton::pixels);
434     nextButton->setGeometry(e->size().width() - TranslucentButton::pixels - 25,
435         toolBar->height(), TranslucentButton::pixels, TranslucentButton::pixels);
436 #endif // Q_WS_MAEMO_5
437     qDebug() << "previousButton geometry" << previousButton->geometry();
438     previousButton->flash(1500);
439     nextButton->flash(1500);
440     QMainWindow::resizeEvent(e);
441 }
442
443 void MainWindow::about()
444 {
445     Dyalog *aboutDialog = new Dyalog(this, false);
446     aboutDialog->setWindowTitle(tr("About Dorian"));
447     QLabel *label = new QLabel(aboutDialog);
448     label->setTextFormat(Qt::RichText);
449     label->setOpenExternalLinks(true);
450     label->setWordWrap(true);
451     label->setText(tr("<b>Dorian %1</b><br><br>Copyright &copy; 2010 "
452         "Akos Polster &lt;akos@pipacs.com&gt;<br>"
453         "Licensed under GNU General Public License, Version 3<br>"
454         "Source code: <a href='https://garage.maemo.org/projects/dorian/'>"
455         "garage.maemo.org/projects/dorian</a>").arg(Platform::version()));
456     aboutDialog->addWidget(label);
457     aboutDialog->addStretch();
458     aboutDialog->show();
459 }
460
461
462 void MainWindow::goToNextPage()
463 {
464     nextButton->flash(1500);
465     previousButton->flash(1500);
466     view->goNextPage();
467 }
468
469 void MainWindow::goToPreviousPage()
470 {
471     nextButton->flash(1500);
472     previousButton->flash(1500);
473     view->goPreviousPage();
474 }
475
476 void MainWindow::onBeginUpgrade(int total)
477 {
478     libraryProgress->setVisible(total > 0);
479     libraryProgress->setWindowTitle(tr("Upgrading library"));
480     libraryProgress->setMaximum(total);
481 }
482
483 void MainWindow::onUpgrading(const QString &path)
484 {
485     libraryProgress->setLabelText(tr("Upgrading %1").
486                                   arg(QFileInfo(path).fileName()));
487     libraryProgress->setValue(libraryProgress->value() + 1);
488 }
489
490 void MainWindow::onEndUpgrade()
491 {
492     libraryProgress->hide();
493     libraryProgress->reset();
494 }
495
496
497 void MainWindow::onBeginLoad(int total)
498 {
499     libraryProgress->setVisible(total > 0);
500     libraryProgress->setWindowTitle(tr("Loading library"));
501     libraryProgress->setMaximum(total);
502 }
503
504 void MainWindow::onLoading(const QString &path)
505 {
506     libraryProgress->setLabelText(tr("Loading %1").
507                                   arg(QFileInfo(path).fileName()));
508     libraryProgress->setValue(libraryProgress->value() + 1);
509 }
510
511 void MainWindow::onEndLoad()
512 {
513     libraryProgress->hide();
514     libraryProgress->reset();
515 }
516