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