6511bd994ac9ff95a7759ae5a31317c7fde1d0ac
[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 #ifdef Q_WS_MAC
43 #   define ICON_PREFIX ":/icons/mac/"
44 #else
45 #   define ICON_PREFIX ":/icons/"
46 #endif
47
48 const int PROGRESS_HEIGHT = 17;
49 static const char *DORIAN_VERSION =
50 #include "pkg/version.txt"
51 ;
52
53 MainWindow::MainWindow(QWidget *parent):
54     AdopterWindow(parent), view(0), preventBlankingTimer(-1)
55 {
56     Trace t("MainWindow::MainWindow");
57 #ifdef Q_WS_MAEMO_5
58     setAttribute(Qt::WA_Maemo5StackedWindow, true);
59 #endif
60     setWindowTitle("Dorian");
61
62     // Central widget. Must be an intermediate, because the book view widget
63     // can be re-parented later
64     QFrame *central = new QFrame(this);
65     QVBoxLayout *layout = new QVBoxLayout(central);
66     layout->setMargin(0);
67     central->setLayout(layout);
68     setCentralWidget(central);
69
70     // Book view
71     view = new BookView(central);
72     view->show();
73     layout->addWidget(view);
74
75     // Progress
76     progress = new Progress(central);
77
78     // Settings dialog
79     settings = new QDialog(this);
80
81     // Tool bar actions
82
83     chaptersAction = addToolBarAction(this, SLOT(showChapters()),
84                                       "chapters", tr("Chapters"));
85     bookmarksAction = addToolBarAction(this, SLOT(showBookmarks()),
86                                        "bookmarks", tr("Bookmarks"));
87     infoAction = addToolBarAction(this, SLOT(showInfo()),
88                                   "info", tr("Book info"));
89     libraryAction = addToolBarAction(this, SLOT(showLibrary()),
90                                      "library", tr("Library"));
91
92 #ifdef Q_WS_MAEMO_5
93     settingsAction = menuBar()->addAction(tr("Settings"));
94     connect(settingsAction, SIGNAL(triggered()), this, SLOT(showSettings()));
95     devToolsAction = menuBar()->addAction(tr("Developer"));
96     connect(devToolsAction, SIGNAL(triggered()), this, SLOT(showDevTools()));
97     QAction *aboutAction = menuBar()->addAction(tr("About"));
98     connect(aboutAction, SIGNAL(triggered()), this, SLOT(about()));
99 #else
100     settingsAction = addToolBarAction(this, SLOT(showSettings()),
101                                       "preferences-system", tr("Settings"));
102     devToolsAction = addToolBarAction(this, SLOT(showDevTools()),
103                                       "developer", tr("Developer"));
104     addToolBarAction(this, SLOT(about()), "about", tr("About"));
105 #endif // Q_WS_MAEMO_5
106
107     addToolBarSpace();
108     fullScreenAction = addToolBarAction(this, SLOT(showBig()),
109                                         "view-fullscreen", tr("Full screen"));
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 book on command line, or load last read book, or load default book
120     Library *library = Library::instance();
121     if (QCoreApplication::arguments().size() == 2) {
122         QString path = QCoreApplication::arguments()[1];
123         library->add(path);
124         QModelIndex index = library->find(path);
125         if (index.isValid()) {
126             library->setNowReading(index);
127         }
128     }
129     else {
130         QModelIndex index = library->nowReading();
131         if (index.isValid()) {
132             library->setNowReading(index);
133         }
134         else {
135             if (!library->rowCount()) {
136                 library->add(":/books/2BR02B.epub");
137             }
138             library->setNowReading(library->index(0));
139         }
140     }
141
142     // Handle loading book parts
143     connect(view, SIGNAL(partLoadStart(int)), this, SLOT(onPartLoadStart()));
144     connect(view, SIGNAL(partLoadEnd(int)), this, SLOT(onPartLoadEnd(int)));
145
146     // Handle progress
147     connect(view, SIGNAL(progress(qreal)), progress, SLOT(setProgress(qreal)));
148
149     // Shadow window for full screen reading
150     fullScreenWindow = new FullScreenWindow(this);
151     connect(fullScreenWindow, SIGNAL(restore()), this, SLOT(showRegular()));
152
153     // Handle settings changes
154     Settings *settings = Settings::instance();
155     connect(settings, SIGNAL(valueChanged(const QString &)),
156             this, SLOT(onSettingsChanged(const QString &)));
157     settings->setValue("orientation", settings->value("orientation"));
158     settings->setValue("lightson", settings->value("lightson"));
159     settings->setValue("usevolumekeys", settings->value("usevolumekeys"));
160
161     // Handle book view buttons
162     connect(nextButton, SIGNAL(triggered()), this, SLOT(goToNextPage()));
163     connect(previousButton, SIGNAL(triggered()), this, SLOT(goToPreviousPage()));
164
165 #ifdef DORIAN_TEST_MODEL
166     (void)new ModelTest(Library::instance(), this);
167 #endif
168 }
169
170 MainWindow::~MainWindow()
171 {
172 }
173
174 void MainWindow::onCurrentBookChanged()
175 {
176     setCurrentBook(Library::instance()->nowReading());
177 }
178
179 void MainWindow::showRegular()
180 {
181     Trace t("MainWindow::showRegular");
182     fullScreenWindow->hide();
183     fullScreenWindow->leaveChildren();
184
185     QList<QWidget *> otherChildren;
186     otherChildren << progress << previousButton << nextButton;
187     takeChildren(view, otherChildren);
188     QRect geo = geometry();
189     progress->setGeometry(0, 0, geo.width(), PROGRESS_HEIGHT);
190 #if defined(Q_WS_MAEMO_5)
191     previousButton->setGeometry(0,
192         geo.height() - toolBar->height() - TranslucentButton::pixels,
193         TranslucentButton::pixels, TranslucentButton::pixels);
194     nextButton->setGeometry(geo.width() - TranslucentButton::pixels, 0,
195         TranslucentButton::pixels, TranslucentButton::pixels);
196 #elif defined(Q_OS_SYMBIAN)
197     previousButton->setGeometry(0, geo.height() - TranslucentButton::pixels,
198         TranslucentButton::pixels, TranslucentButton::pixels);
199     nextButton->setGeometry(geo.width() - TranslucentButton::pixels,
200         0, TranslucentButton::pixels, TranslucentButton::pixels);
201 #else
202     previousButton->setGeometry(0, geo.height() - TranslucentButton::pixels,
203         TranslucentButton::pixels, TranslucentButton::pixels);
204     nextButton->setGeometry(geo.width() - TranslucentButton::pixels - 25,
205         toolBar->height(), TranslucentButton::pixels, TranslucentButton::pixels);
206 #endif // Q_WS_MAEMO_5
207     qDebug() << "previousButton geometry" << previousButton->geometry();
208     progress->flash();
209     nextButton->show();
210     previousButton->show();
211     nextButton->flash(1500);
212     previousButton->flash(1500);
213 }
214
215 void MainWindow::showBig()
216 {
217     Trace t("MainWindow::showBig");
218     leaveChildren();
219     QList<QWidget *> otherChildren;
220     otherChildren << progress << nextButton << previousButton;
221     QRect screen = QApplication::desktop()->screenGeometry();
222     progress->setGeometry(0, 0, screen.width(), PROGRESS_HEIGHT);
223 #if defined(Q_WS_MAEMO_5)
224     nextButton->setGeometry(screen.width() - TranslucentButton::pixels, 0,
225         TranslucentButton::pixels, TranslucentButton::pixels);
226 #else
227     nextButton->setGeometry(screen.width() - TranslucentButton::pixels - 25, 0,
228                             TranslucentButton::pixels, TranslucentButton::pixels);
229 #endif // Q_WS_MAEMO_5
230     previousButton->setGeometry(0, screen.height() - TranslucentButton::pixels,
231         TranslucentButton::pixels, TranslucentButton::pixels);
232
233     fullScreenWindow->takeChildren(view, otherChildren);
234     fullScreenWindow->showFullScreen();
235     progress->flash();
236     nextButton->flash(1500);
237     previousButton->flash(1500);
238 }
239
240 void MainWindow::setCurrentBook(const QModelIndex &current)
241 {
242     mCurrent = current;
243     Book *book = Library::instance()->book(current);
244     view->setBook(book);
245     setWindowTitle(book? book->shortName(): tr("Dorian"));
246 }
247
248 void MainWindow::showLibrary()
249 {
250     (new LibraryDialog(this))->show();
251 }
252
253 void MainWindow::showSettings()
254 {
255     (new SettingsWindow(this))->show();
256 }
257
258 void MainWindow::showInfo()
259 {
260     if (mCurrent.isValid()) {
261         (new InfoDialog(Library::instance()->book(mCurrent), this, false))->
262                 exec();
263     }
264 }
265
266 void MainWindow::showDevTools()
267 {
268     (new DevTools())->exec();
269 }
270
271 void MainWindow::showBookmarks()
272 {
273     Book *book = Library::instance()->book(mCurrent);
274     if (book) {
275         BookmarksDialog *bookmarks = new BookmarksDialog(book, this);
276         bookmarks->setWindowModality(Qt::WindowModal);
277         connect(bookmarks, SIGNAL(addBookmark()), this, SLOT(onAddBookmark()));
278         connect(bookmarks, SIGNAL(goToBookmark(int)),
279                 this, SLOT(onGoToBookmark(int)));
280         bookmarks->show();
281     }
282 }
283
284 void MainWindow::closeEvent(QCloseEvent *event)
285 {
286     Trace t("MainWindow::closeEvent");
287     view->setLastBookmark();
288     event->accept();
289 }
290
291 void MainWindow::onSettingsChanged(const QString &key)
292 {
293 #ifdef Q_WS_MAEMO_5
294     if (key == "orientation") {
295         QString value = Settings::instance()->value(key).toString();
296         qDebug() << "MainWindow::onSettingsChanged: orientation" << value;
297         if (value == "portrait") {
298             setAttribute(Qt::WA_Maemo5LandscapeOrientation, false);
299             setAttribute(Qt::WA_Maemo5PortraitOrientation, true);
300         }
301         else {
302             setAttribute(Qt::WA_Maemo5PortraitOrientation, false);
303             setAttribute(Qt::WA_Maemo5LandscapeOrientation, true);
304         }
305     } else if (key == "lightson") {
306         bool enable = Settings::instance()->value(key, false).toBool();
307         qDebug() << "MainWindow::onSettingsChanged: lightson:" << enable;
308         killTimer(preventBlankingTimer);
309         if (enable) {
310             preventBlankingTimer = startTimer(29 * 1000);
311         }
312     } else if (key == "usevolumekeys") {
313         bool value = Settings::instance()->value(key).toBool();
314         qDebug() << "MainWindow::onSettingsChanged: usevolumekeys" << value;
315         grabZoomKeys(value);
316         fullScreenWindow->grabZoomKeys(value);
317     }
318 #else
319     Q_UNUSED(key);
320 #endif // Q_WS_MAEMO_5
321 }
322
323 void MainWindow::onPartLoadStart()
324 {
325     Trace t("MainWindow::onPartLoadStart");
326 #ifdef Q_WS_MAEMO_5
327     setAttribute(Qt::WA_Maemo5ShowProgressIndicator, true);
328 #endif
329 }
330
331 void MainWindow::onPartLoadEnd(int index)
332 {
333     Trace t("MainWindow::onPartLoadEnd");
334     bool enablePrevious = false;
335     bool enableNext = false;
336     Book *book = Library::instance()->book(mCurrent);
337     if (book) {
338         if (index > 0) {
339             enablePrevious = true;
340         }
341         if (index < (book->parts.size() - 1)) {
342             enableNext = true;
343         }
344     }
345 #ifdef Q_WS_MAEMO_5
346     setAttribute(Qt::WA_Maemo5ShowProgressIndicator, false);
347 #endif // Q_WS_MAEMO_5
348 }
349
350 void MainWindow::onAddBookmark()
351 {
352     Trace t("MainWindow:onAddBookmark");
353     view->addBookmark();
354 }
355
356 void MainWindow::onGoToBookmark(int index)
357 {
358     Trace t("MainWindow::onGoToBookmark");
359     Book *book = Library::instance()->book(mCurrent);
360     view->goToBookmark(book->bookmarks()[index]);
361 }
362
363 void MainWindow::showChapters()
364 {
365     Book *book = Library::instance()->book(mCurrent);
366     if (book) {
367         ChaptersDialog *chapters = new ChaptersDialog(book, this);
368         chapters->setWindowModality(Qt::WindowModal);
369         connect(chapters, SIGNAL(goToChapter(int)),
370                 this, SLOT(onGoToChapter(int)));
371         chapters->show();
372     }
373 }
374
375 void MainWindow::onGoToChapter(int index)
376 {
377     Trace t("MainWindow::onGoToChapter");
378
379     Book *book = Library::instance()->book(mCurrent);
380     if (book) {
381         int partIndex = book->partFromChapter(index);
382         if (partIndex != -1) {
383             view->goToBookmark(Book::Bookmark(partIndex, 0));
384         }
385     }
386 }
387
388 void MainWindow::timerEvent(QTimerEvent *event)
389 {
390     if (event->timerId() == preventBlankingTimer) {
391 #ifdef Q_WS_MAEMO_5
392         QDBusInterface mce(MCE_SERVICE, MCE_REQUEST_PATH,
393                            MCE_REQUEST_IF, QDBusConnection::systemBus());
394         mce.call(MCE_PREVENT_BLANK_REQ);
395 #endif // Q_WS_MAEMO_5
396         qDebug() << "MainWindow::timerEvent: Prevent display blanking";
397     }
398 }
399
400 void MainWindow::resizeEvent(QResizeEvent *e)
401 {
402     Trace t("MainWindow::resizeEvent");
403     progress->setGeometry(QRect(0, 0, e->size().width(), PROGRESS_HEIGHT));
404 #if defined(Q_WS_MAEMO_5)
405     previousButton->setGeometry(0,
406         e->size().height() - toolBar->height() - TranslucentButton::pixels,
407         TranslucentButton::pixels, TranslucentButton::pixels);
408     nextButton->setGeometry(e->size().width() - TranslucentButton::pixels, 0,
409         TranslucentButton::pixels, TranslucentButton::pixels);
410 #elif defined(Q_OS_SYMBIAN)
411     previousButton->setGeometry(0, e->size().height() - TranslucentButton::pixels,
412         TranslucentButton::pixels, TranslucentButton::pixels);
413     nextButton->setGeometry(e->size().width() - TranslucentButton::pixels,
414         0, TranslucentButton::pixels, TranslucentButton::pixels);
415 #else
416     previousButton->setGeometry(0, e->size().height() - TranslucentButton::pixels,
417         TranslucentButton::pixels, TranslucentButton::pixels);
418     nextButton->setGeometry(e->size().width() - TranslucentButton::pixels - 25,
419         toolBar->height(), TranslucentButton::pixels, TranslucentButton::pixels);
420 #endif // Q_WS_MAEMO_5
421     qDebug() << "previousButton geometry" << previousButton->geometry();
422     previousButton->flash(1500);
423     nextButton->flash(1500);
424     QMainWindow::resizeEvent(e);
425 }
426
427 void MainWindow::about()
428 {
429     Dyalog *aboutDialog = new Dyalog(this);
430     aboutDialog->setWindowTitle(tr("About Dorian"));
431     QLabel *label = new QLabel(aboutDialog);
432     label->setTextFormat(Qt::RichText);
433     label->setOpenExternalLinks(true);
434     label->setWordWrap(true);
435     label->setText(tr("<b>Dorian %1</b><br><br>Copyright &copy; 2010 "
436         "Akos Polster &lt;akos@pipacs.com&gt;<br>"
437         "Licensed under GNU General Public License, Version 3<br>"
438         "Source code: <a href='https://garage.maemo.org/projects/dorian/'>"
439         "garage.maemo.org/projects/dorian</a>").arg(DORIAN_VERSION));
440     aboutDialog->addWidget(label);
441     aboutDialog->addStretch();
442     aboutDialog->show();
443 }
444
445
446 void MainWindow::goToNextPage()
447 {
448     nextButton->flash(1500);
449     previousButton->flash(1500);
450     view->goNextPage();
451 }
452
453 void MainWindow::goToPreviousPage()
454 {
455     nextButton->flash(1500);
456     previousButton->flash(1500);
457     view->goPreviousPage();
458 }