More small Symbian fixes.
[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
38 #ifdef DORIAN_TEST_MODEL
39 #   include "modeltest.h"
40 #endif
41
42 const int PROGRESS_HEIGHT = 17;
43 static const char *DORIAN_VERSION =
44 #include "pkg/version.txt"
45 ;
46
47 MainWindow::MainWindow(QWidget *parent):
48     AdopterWindow(parent), view(0), preventBlankingTimer(-1)
49 {
50     Trace t("MainWindow::MainWindow");
51 #ifdef Q_WS_MAEMO_5
52     setAttribute(Qt::WA_Maemo5StackedWindow, true);
53 #endif
54     setWindowTitle("Dorian");
55
56     // Central widget. Must be an intermediate, because the book view widget
57     // can be re-parented later
58     QFrame *central = new QFrame(this);
59     QVBoxLayout *layout = new QVBoxLayout(central);
60     layout->setMargin(0);
61     central->setLayout(layout);
62     setCentralWidget(central);
63
64     // Book view
65     view = new BookView(central);
66     view->show();
67     layout->addWidget(view);
68
69     // Progress
70     progress = new Progress(central);
71
72     // Settings dialog
73     settings = new QDialog(this);
74
75     // Tool bar actions
76
77 #ifdef Q_OS_SYMBIAN
78     fullScreenAction = addToolBarAction(this, SLOT(showBig()),
79                                         "view-fullscreen", tr("Full screen"));
80 #endif
81
82     chaptersAction = addToolBarAction(this, SLOT(showChapters()),
83                                       "chapters", tr("Chapters"));
84     bookmarksAction = addToolBarAction(this, SLOT(showBookmarks()),
85                                        "bookmarks", tr("Bookmarks"));
86     infoAction = addToolBarAction(this, SLOT(showInfo()),
87                                   "info", tr("Book info"));
88     libraryAction = addToolBarAction(this, SLOT(showLibrary()),
89                                      "library", tr("Library"));
90
91 #ifdef Q_WS_MAEMO_5
92     settingsAction = menuBar()->addAction(tr("Settings"));
93     connect(settingsAction, SIGNAL(triggered()), this, SLOT(showSettings()));
94     devToolsAction = menuBar()->addAction(tr("Developer"));
95     connect(devToolsAction, SIGNAL(triggered()), this, SLOT(showDevTools()));
96     QAction *aboutAction = menuBar()->addAction(tr("About"));
97     connect(aboutAction, SIGNAL(triggered()), this, SLOT(about()));
98 #else
99     settingsAction = addToolBarAction(this, SLOT(showSettings()),
100                                       "preferences-system", tr("Settings"));
101     devToolsAction = addToolBarAction(this, SLOT(showDevTools()),
102                                       "developer", tr("Developer"));
103     addToolBarAction(this, SLOT(about()), "about", tr("About"));
104 #endif // Q_WS_MAEMO_5
105
106 #ifndef Q_OS_SYMBIAN
107     addToolBarSpace();
108     fullScreenAction = addToolBarAction(this, SLOT(showBig()),
109                                         "view-fullscreen", tr("Full screen"));
110 #endif
111
112     // Buttons on top of the book view
113     previousButton = new TranslucentButton("back", this);
114     nextButton = new TranslucentButton("forward", this);
115
116     // Handle model changes
117     connect(Library::instance(), SIGNAL(nowReadingChanged()),
118             this, SLOT(onCurrentBookChanged()));
119
120     // Load library, upgrade it if needed
121     libraryProgress = new QProgressDialog(tr("Upgrading library"), "", 0, 0, this);
122     libraryProgress->reset();
123     libraryProgress->setMinimumDuration(0);
124     libraryProgress->setWindowModality(Qt::WindowModal);
125     libraryProgress->setCancelButton(0);
126     Library *library = Library::instance();
127     connect(library, SIGNAL(beginUpgrade(int)), this, SLOT(onBeginUpgrade(int)));
128     connect(library, SIGNAL(upgrading(const QString &)),
129             this, SLOT(onUpgrading(const QString &)));
130     connect(library, SIGNAL(endUpgrade()), this, SLOT(onEndUpgrade()));
131     connect(library, SIGNAL(beginLoad(int)), this, SLOT(onBeginLoad(int)));
132     connect(library, SIGNAL(loading(const QString &)),
133             this, SLOT(onLoading(const QString &)));
134     connect(library, SIGNAL(endLoad()), this, SLOT(onEndLoad()));
135     library->upgrade();
136     library->load();
137
138     // Load book on command line, or load last read book, or load default book
139     if (QCoreApplication::arguments().size() == 2) {
140         QString path = QCoreApplication::arguments()[1];
141         library->add(path);
142         QModelIndex index = library->find(path);
143         if (index.isValid()) {
144             library->setNowReading(index);
145         }
146     } else {
147         QModelIndex index = library->nowReading();
148         if (index.isValid()) {
149             library->setNowReading(index);
150         } else {
151             if (!library->rowCount()) {
152                 library->add(":/books/2BR02B.epub");
153             }
154             library->setNowReading(library->index(0));
155         }
156     }
157
158     // Handle loading book parts
159     connect(view, SIGNAL(partLoadStart(int)), this, SLOT(onPartLoadStart()));
160     connect(view, SIGNAL(partLoadEnd(int)), this, SLOT(onPartLoadEnd(int)));
161
162     // Handle progress
163     connect(view, SIGNAL(progress(qreal)), progress, SLOT(setProgress(qreal)));
164
165     // Shadow window for full screen reading
166     fullScreenWindow = new FullScreenWindow(this);
167     connect(fullScreenWindow, SIGNAL(restore()), this, SLOT(showRegular()));
168
169     // Handle settings changes
170     Settings *settings = Settings::instance();
171     connect(settings, SIGNAL(valueChanged(const QString &)),
172             this, SLOT(onSettingsChanged(const QString &)));
173     settings->setValue("orientation", settings->value("orientation"));
174     settings->setValue("lightson", settings->value("lightson"));
175     settings->setValue("usevolumekeys", settings->value("usevolumekeys"));
176
177     // Handle book view buttons
178     connect(nextButton, SIGNAL(triggered()), this, SLOT(goToNextPage()));
179     connect(previousButton, SIGNAL(triggered()), this, SLOT(goToPreviousPage()));
180
181 #ifdef DORIAN_TEST_MODEL
182     (void)new ModelTest(Library::instance(), this);
183 #endif
184 }
185
186 MainWindow::~MainWindow()
187 {
188 }
189
190 void MainWindow::onCurrentBookChanged()
191 {
192     setCurrentBook(Library::instance()->nowReading());
193 }
194
195 void MainWindow::showRegular()
196 {
197     Trace t("MainWindow::showRegular");
198     fullScreenWindow->hide();
199     fullScreenWindow->leaveChildren();
200
201     QList<QWidget *> otherChildren;
202     otherChildren << progress << previousButton << nextButton;
203     takeChildren(view, otherChildren);
204     QRect geo = geometry();
205     progress->setGeometry(0, 0, geo.width(), PROGRESS_HEIGHT);
206 #if defined(Q_WS_MAEMO_5)
207     previousButton->setGeometry(0,
208         geo.height() - toolBar->height() - TranslucentButton::pixels,
209         TranslucentButton::pixels, TranslucentButton::pixels);
210     nextButton->setGeometry(geo.width() - TranslucentButton::pixels, 0,
211         TranslucentButton::pixels, TranslucentButton::pixels);
212 #elif defined(Q_OS_SYMBIAN)
213     previousButton->setGeometry(0, geo.height() - TranslucentButton::pixels,
214         TranslucentButton::pixels, TranslucentButton::pixels);
215     nextButton->setGeometry(geo.width() - TranslucentButton::pixels,
216         0, TranslucentButton::pixels, TranslucentButton::pixels);
217 #else
218     previousButton->setGeometry(0, geo.height() - TranslucentButton::pixels,
219         TranslucentButton::pixels, TranslucentButton::pixels);
220     nextButton->setGeometry(geo.width() - TranslucentButton::pixels - 25,
221         toolBar->height(), TranslucentButton::pixels, TranslucentButton::pixels);
222 #endif // Q_WS_MAEMO_5
223     qDebug() << "previousButton geometry" << previousButton->geometry();
224     progress->flash();
225     nextButton->show();
226     previousButton->show();
227     nextButton->flash(1500);
228     previousButton->flash(1500);
229 }
230
231 void MainWindow::showBig()
232 {
233     Trace t("MainWindow::showBig");
234     leaveChildren();
235     QList<QWidget *> otherChildren;
236     otherChildren << progress << nextButton << previousButton;
237     QRect screen = QApplication::desktop()->screenGeometry();
238     progress->setGeometry(0, 0, screen.width(), PROGRESS_HEIGHT);
239 #if defined(Q_WS_MAEMO_5)
240     nextButton->setGeometry(screen.width() - TranslucentButton::pixels, 0,
241         TranslucentButton::pixels, TranslucentButton::pixels);
242 #else
243     nextButton->setGeometry(screen.width() - TranslucentButton::pixels - 25, 0,
244                             TranslucentButton::pixels, TranslucentButton::pixels);
245 #endif // Q_WS_MAEMO_5
246     previousButton->setGeometry(0, screen.height() - TranslucentButton::pixels,
247         TranslucentButton::pixels, TranslucentButton::pixels);
248
249     fullScreenWindow->takeChildren(view, otherChildren);
250     fullScreenWindow->showFullScreen();
251     progress->flash();
252     nextButton->flash(1500);
253     previousButton->flash(1500);
254 }
255
256 void MainWindow::setCurrentBook(const QModelIndex &current)
257 {
258     mCurrent = current;
259     Book *book = Library::instance()->book(current);
260     view->setBook(book);
261     setWindowTitle(book? book->shortName(): tr("Dorian"));
262 }
263
264 void MainWindow::showLibrary()
265 {
266     (new LibraryDialog(this))->show();
267 }
268
269 void MainWindow::showSettings()
270 {
271     (new SettingsWindow(this))->show();
272 }
273
274 void MainWindow::showInfo()
275 {
276     if (mCurrent.isValid()) {
277         (new InfoDialog(Library::instance()->book(mCurrent), this, false))->
278                 exec();
279     }
280 }
281
282 void MainWindow::showDevTools()
283 {
284     (new DevTools())->exec();
285 }
286
287 void MainWindow::showBookmarks()
288 {
289     Book *book = Library::instance()->book(mCurrent);
290     if (book) {
291         BookmarksDialog *bookmarks = new BookmarksDialog(book, this);
292         bookmarks->setWindowModality(Qt::WindowModal);
293         connect(bookmarks, SIGNAL(addBookmark()), this, SLOT(onAddBookmark()));
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()
366 {
367     Trace t("MainWindow:onAddBookmark");
368     view->addBookmark();
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(), 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(DORIAN_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