2 * This file is a part of QComicBook.
4 * Copyright (C) 2005-2006 Pawel Stolowski <yogin@linux.bydg.org>
6 * QComicBook is free software; you can redestribute it and/or modify it
7 * under terms of GNU General Public License by Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY. See GPL for more details.
14 #include "bookmarks.h"
15 #include "comicmain.h"
20 #include "imgarchivesink.h"
21 #include "imgsinkfactory.h"
22 #include "aboutdialog.h"
23 #include "cbsettings.h"
25 #include "helpbrowser.h"
26 #include "cbconfigdialog.h"
27 #include "statusbar.h"
28 #include "thumbnailswin.h"
29 #include "thumbnailsview.h"
30 #include "thumbnailloader.h"
31 #include "bookmarkmanager.h"
33 #include "archiverdialog.h"
34 #include "suparchwin.h"
35 #include "imlibimage.h"
38 #include <qpopupmenu.h>
39 #include <qstringlist.h>
41 #include <qfiledialog.h>
42 #include <qfileinfo.h>
44 #include <qmessagebox.h>
47 #include <jumptopagewin.h>
49 #include <qdragobject.h>
52 using namespace QComicBook;
53 using namespace Utility;
55 ComicMainWindow::ComicMainWindow(QWidget *parent): QMainWindow(parent, NULL, WType_TopLevel|WDestructiveClose), sink(NULL), currpage(0), prevpage(-1), nextpage(-1), spreading(false), stripping(false), edit_menu(NULL)
58 setIcon(Icons::get(ICON_APPICON).pixmap(QIconSet::Small, true));
59 setMinimumSize(320, 200);
61 setAcceptDrops(true); //???
63 cfg = &ComicBookSettings::instance();
65 setGeometry(cfg->geometry());
70 setupComicImageView();
71 setupThumbnailsWindow();
74 if (cfg->editSupport())
77 setupNavigationMenu();
83 lastdir = cfg->lastDir();
84 recentfiles = new History(10);
85 *recentfiles = cfg->recentlyOpened();
86 setRecentFilesMenu(*recentfiles);
88 cfg->restoreDockLayout(this);
90 enableComicBookActions(false);
93 ComicMainWindow::~ComicMainWindow()
95 if (cfg->cacheThumbnails())
96 ImgDirSink::removeThumbnails(cfg->thumbnailsAge());
107 void ComicMainWindow::setupActions()
109 openArchiveAction = new QAction(Icons::get(ICON_OPENARCH), tr("Open archive"), CTRL+Key_O, this);
110 openDirAction = new QAction(Icons::get(ICON_OPENDIR), tr("Open directory"), CTRL+Key_D, this);
111 openNextAction = new QAction(tr("Open next"), CTRL+Key_N, this);
112 openPrevAction = new QAction(tr("Open previous"), CTRL+Key_P, this);
113 fullScreenAction = new QAction(tr("&Fullscreen"), Key_F11, this);
114 nextPageAction = new QAction(Icons::get(ICON_NEXTPAGE), tr("Next page"), Key_PageDown, this);
115 forwardPageAction = new QAction(Icons::get(ICON_FORWARD), tr("5 pages forward"), QKeySequence(), this);
116 backwardPageAction = new QAction(Icons::get (ICON_BACKWARD), tr("5 pages backward"), QKeySequence(), this);
117 jumpDownAction = new QAction(QString::null, Key_Space, this);
118 jumpUpAction = new QAction(QString::null, Key_Backspace, this);
119 prevPageAction = new QAction(Icons::get(ICON_PREVPAGE), tr("&Previous page"), Key_PageUp, this);
120 pageTopAction = new QAction(Icons::get(ICON_PAGETOP), tr("Page top"), Key_Home, this);
121 pageBottomAction = new QAction(Icons::get(ICON_PAGEBOTTOM), tr("Page bottom"), Key_End, this);
122 firstPageAction = new QAction(tr("First page"), CTRL+Key_Home, this);
123 lastPageAction = new QAction(tr("Last page"), CTRL+Key_End, this);
124 scrollRightAction = new QAction(tr("Scroll right"), Key_Right, this);
125 scrollLeftAction = new QAction(tr("Scroll left"), Key_Left, this);
126 scrollRightFastAction = new QAction(tr("Fast scroll right"), SHIFT+Key_Right, this);
127 scrollLeftFastAction = new QAction(tr("Fast scroll left"), SHIFT+Key_Left, this);
128 scrollUpAction = new QAction(tr("Scroll up"), Key_Up, this);
129 scrollDownAction = new QAction(tr("Scroll down"), Key_Down, this);
130 scrollUpFastAction = new QAction(tr("Fast scroll up"), SHIFT+Key_Up, this);
131 scrollDownFastAction = new QAction(tr("Fast scroll down"), SHIFT+Key_Down, this);
132 quitAction = new QAction(tr("Quit"), CTRL+Key_Q, this);
134 QActionGroup *scaleActions = new QActionGroup(this);
135 fitWidthAction = new QAction(Icons::get(ICON_FITWIDTH), tr("Fit width"), ALT+Key_W, scaleActions);
136 fitWidthAction->setToggleAction(true);
137 fitHeightAction = new QAction(Icons::get(ICON_FITHEIGHT), tr("Fit height"), ALT+Key_H, scaleActions);
138 fitHeightAction->setToggleAction(true);
139 wholePageAction = new QAction(Icons::get(ICON_WHOLEPAGE), tr("Whole page"), ALT+Key_A, scaleActions);
140 wholePageAction->setToggleAction(true);
141 originalSizeAction = new QAction(Icons::get(ICON_ORGSIZE), tr("Original size"), ALT+Key_O, scaleActions);
142 originalSizeAction->setToggleAction(true);
143 bestFitAction = new QAction(Icons::get(ICON_BESTFIT), tr("Best fit"), ALT+Key_B, scaleActions);
144 bestFitAction->setToggleAction(true);
145 mangaModeAction = new QAction(Icons::get(ICON_JAPANESE), tr("Japanese mode"), CTRL+Key_J, this);
146 mangaModeAction->setToggleAction(true);
147 twoPagesAction = new QAction(Icons::get(ICON_TWOPAGES), tr("Two pages"), CTRL+Key_T, this);
148 twoPagesAction->setToggleAction(true);
149 stripModeAction = new QAction(Icons::get(ICON_STRIPMODE), tr("Strip Mode"), QKeySequence(), this);
150 stripModeAction->setToggleAction(true);
151 rotateRightAction = new QAction(Icons::get(ICON_ROTRIGHT), tr("Rotate right"), QKeySequence(), this);
152 rotateLeftAction = new QAction(Icons::get(ICON_ROTLEFT), tr("Rotate left"), QKeySequence(), this);
153 rotateResetAction = new QAction(tr("No rotation"), QKeySequence(), this);
154 togglePreserveRotationAction = new QAction(tr("Preserve rotation"), QKeySequence(), this);
155 togglePreserveRotationAction->setToggleAction(true);
156 showInfoAction = new QAction(Icons::get(ICON_INFO), tr("Info"), ALT+Key_I, this);
157 exitFullScreenAction = new QAction(QString::null, Key_Escape, this);
158 toggleStatusbarAction = new QAction(tr("Statusbar"), QKeySequence(), this);
159 toggleStatusbarAction->setToggleAction(true);
160 toggleThumbnailsAction = new QAction(Icons::get(ICON_THUMBNAILS), tr("Thumbnails"), ALT+Key_T, this);
161 toggleThumbnailsAction->setToggleAction(true);
162 toggleToolbarAction = new QAction(tr("Toolbar"), QKeySequence(), this);
163 toggleToolbarAction->setToggleAction(true);
165 connect(openArchiveAction, SIGNAL(activated()), this, SLOT(browseArchive()));
166 connect(openDirAction, SIGNAL(activated()), this, SLOT(browseDirectory()));
167 connect(openNextAction, SIGNAL(activated()), this, SLOT(openNext()));
168 connect(openPrevAction, SIGNAL(activated()), this, SLOT(openPrevious()));
169 connect(showInfoAction, SIGNAL(activated()), this, SLOT(showInfo()));
170 connect(exitFullScreenAction, SIGNAL(activated()), this, SLOT(exitFullscreen()));
171 connect(nextPageAction, SIGNAL(activated()), this, SLOT(nextPage()));
172 connect(forwardPageAction, SIGNAL(activated()), this, SLOT(forwardPages()));
173 connect(firstPageAction, SIGNAL(activated()), this, SLOT(firstPage()));
174 connect(lastPageAction, SIGNAL(activated()), this, SLOT(lastPage()));
175 connect(backwardPageAction, SIGNAL(activated()), this, SLOT(backwardPages()));
176 connect(quitAction, SIGNAL(activated()), this, SLOT(close()));
179 void ComicMainWindow::setupComicImageView()
181 view = new ComicImageView(this, cfg->pageSize(), cfg->background());
182 setCentralWidget(view);
184 view->setSmallCursor(cfg->smallCursor());
185 connect(cfg, SIGNAL(backgroundChanged(const QColor&)), view, SLOT(setBackground(const QColor&)));
186 connect(cfg, SIGNAL(cursorChanged(bool)), view, SLOT(setSmallCursor(bool)));
187 connect(cfg, SIGNAL(stripMaxChanged(int)), this, SLOT(setStripMax(int)));
188 connect(fullScreenAction, SIGNAL(activated()), this, SLOT(toggleFullScreen()));
189 connect(pageTopAction, SIGNAL(activated()), view, SLOT(scrollToTop()));
190 connect(pageBottomAction, SIGNAL(activated()), view, SLOT(scrollToBottom()));
191 connect(scrollRightAction, SIGNAL(activated()), view, SLOT(scrollRight()));
192 connect(scrollLeftAction, SIGNAL(activated()), view, SLOT(scrollLeft()));
193 connect(scrollRightFastAction, SIGNAL(activated()), view, SLOT(scrollRightFast()));
194 connect(scrollLeftFastAction, SIGNAL(activated()), view, SLOT(scrollLeftFast()));
195 connect(scrollUpAction, SIGNAL(activated()), view, SLOT(scrollUp()));
196 connect(scrollDownAction, SIGNAL(activated()), view, SLOT(scrollDown()));
197 connect(scrollUpFastAction, SIGNAL(activated()), view, SLOT(scrollUpFast()));
198 connect(scrollDownFastAction, SIGNAL(activated()), view, SLOT(scrollDownFast()));
199 connect(fitWidthAction, SIGNAL(activated()), view, SLOT(setSizeFitWidth()));
200 connect(fitHeightAction, SIGNAL(activated()), view, SLOT(setSizeFitHeight()));
201 connect(wholePageAction, SIGNAL(activated()), view, SLOT(setSizeWholePage()));
202 connect(originalSizeAction, SIGNAL(activated()), view, SLOT(setSizeOriginal()));
203 connect(bestFitAction, SIGNAL(activated()), view, SLOT(setSizeBestFit()));
204 connect(mangaModeAction, SIGNAL(toggled(bool)), this, SLOT(toggleJapaneseMode(bool)));
205 connect(twoPagesAction, SIGNAL(toggled(bool)), this, SLOT(toggleTwoPages(bool)));
206 connect(stripModeAction, SIGNAL(toggled(bool)), this, SLOT(toggleStripMode(bool)));
207 connect(prevPageAction, SIGNAL(activated()), this, SLOT(prevPage()));
208 connect(rotateRightAction, SIGNAL(activated()), view, SLOT(rotateRight()));
209 connect(rotateLeftAction, SIGNAL(activated()), view, SLOT(rotateLeft()));
210 connect(rotateResetAction, SIGNAL(activated()), view, SLOT(resetRotation()));
211 connect(jumpDownAction, SIGNAL(activated()), view, SLOT(jumpDown()));
212 connect(jumpUpAction, SIGNAL(activated()), view, SLOT(jumpUp()));
213 if (cfg->continuousScrolling())
215 connect(view, SIGNAL(bottomReached()), this, SLOT(nextPage()));
216 connect(view, SIGNAL(topReached()), this, SLOT(prevPageBottom()));
218 connect(view, SIGNAL(doubleClick()), this, SLOT(nextPage()));
219 view->enableScrollbars(cfg->scrollbarsVisible());
220 QAction *which = originalSizeAction;
221 switch (cfg->pageSize())
223 case FitWidth: which = fitWidthAction; break;
224 case FitHeight: which = fitHeightAction; break;
225 case BestFit: which = bestFitAction; break;
226 case WholePage: which = wholePageAction; break;
227 case Original: which = originalSizeAction; break;
232 void ComicMainWindow::setupThumbnailsWindow()
234 thumbswin = new ThumbnailsWindow(QDockWindow::InDock, this);
235 moveDockWindow(thumbswin, Qt::DockLeft); //initial position of thumbnails window
236 connect(thumbswin, SIGNAL(requestedPage(int, bool)), this, SLOT(jumpToPage(int, bool)));
237 connect(thumbswin, SIGNAL(visibilityChanged(bool)), this, SLOT(thumbnailsVisibilityChanged(bool)));
238 connect(thumbswin, SIGNAL(visibilityChanged(bool)), toggleThumbnailsAction, SLOT(setOn(bool)));
239 connect(toggleThumbnailsAction, SIGNAL(toggled(bool)), thumbswin, SLOT(setShown(bool)));
242 void ComicMainWindow::setupToolbar()
244 toolbar = new QToolBar(tr("Toolbar"), this);
245 openArchiveAction->addTo(toolbar);
246 openDirAction->addTo(toolbar);
247 toolbar->addSeparator();
248 showInfoAction->addTo(toolbar);
249 toggleThumbnailsAction->addTo(toolbar);
250 toolbar->addSeparator();
251 twoPagesAction->addTo(toolbar);
252 stripModeAction->addTo(toolbar);
253 mangaModeAction->addTo(toolbar);
254 toolbar->addSeparator();
255 prevPageAction->addTo(toolbar);
256 nextPageAction->addTo(toolbar);
257 backwardPageAction->addTo(toolbar);
258 forwardPageAction->addTo(toolbar);
259 pageTopAction->addTo(toolbar);
260 pageBottomAction->addTo(toolbar);
261 toolbar->addSeparator();
262 originalSizeAction->addTo(toolbar);
263 fitWidthAction->addTo(toolbar);
264 fitHeightAction->addTo(toolbar);
265 wholePageAction->addTo(toolbar);
266 bestFitAction->addTo(toolbar);
267 toolbar->addSeparator();
268 rotateRightAction->addTo(toolbar);
269 rotateLeftAction->addTo(toolbar);
270 connect(toggleToolbarAction, SIGNAL(toggled(bool)), toolbar, SLOT(setShown(bool)));
271 connect(toolbar, SIGNAL(visibilityChanged(bool)), this, SLOT(toolbarVisibilityChanged(bool)));
274 void ComicMainWindow::setupFileMenu()
276 file_menu = new QPopupMenu(this);
277 openArchiveAction->addTo(file_menu);
278 openDirAction->addTo(file_menu);
279 openNextAction->addTo(file_menu);
280 openPrevAction->addTo(file_menu);
281 recent_menu = new QPopupMenu(this);
282 file_menu->insertItem(tr("Recently opened"), recent_menu);
283 connect(recent_menu, SIGNAL(activated(int)), this, SLOT(recentSelected(int)));
284 file_menu->insertSeparator();
285 //create_id = file_menu->insertItem(tr("Create archive"), this, SLOT(createArchive()));
286 //file_menu->insertSeparator();
287 showInfoAction->addTo(file_menu);
288 file_menu->insertSeparator();
289 close_id = file_menu->insertItem(tr("Close"), this, SLOT(closeSink()));
290 file_menu->insertSeparator();
291 quitAction->addTo(file_menu);
292 menuBar()->insertItem(tr("&File"), file_menu);
295 void ComicMainWindow::setupEditMenu()
297 edit_menu = new QPopupMenu(this);
298 gimp_id = edit_menu->insertItem(tr("Open with Gimp"), this, SLOT(openWithGimp()));
299 //edit_menu->insertItem(tr("Open with Kolour Paint"), this, SLOT(openWithGimp()));
300 //edit_menu->insertItem(tr("Open with ImageMagick"), this, SLOT(openWithGimp()));
301 edit_menu->insertSeparator();
302 reload_id = edit_menu->insertItem(tr("Reload page"), this, SLOT(reloadPage()));
303 menuBar()->insertItem(tr("&Edit"), edit_menu);
306 void ComicMainWindow::setupViewMenu()
308 view_menu = new QPopupMenu(this);
309 view_menu->setCheckable(true);
310 originalSizeAction->addTo(view_menu);
311 fitWidthAction->addTo(view_menu);
312 fitHeightAction->addTo(view_menu);
313 wholePageAction->addTo(view_menu);
314 bestFitAction->addTo(view_menu);
315 view_menu->insertSeparator();
316 rotateRightAction->addTo(view_menu);
317 rotateLeftAction->addTo(view_menu);
318 rotateResetAction->addTo(view_menu);
319 togglePreserveRotationAction->addTo(view_menu);
320 view_menu->insertSeparator();
321 twoPagesAction->addTo(view_menu);
322 stripModeAction->addTo(view_menu);
323 mangaModeAction->addTo(view_menu);
324 toggleThumbnailsAction->addTo(view_menu);
325 menuBar()->insertItem(tr("&View"), view_menu);
328 void ComicMainWindow::setupNavigationMenu()
330 navi_menu = new QPopupMenu(this);
331 nextPageAction->addTo(navi_menu);
332 prevPageAction->addTo(navi_menu);
333 navi_menu->insertSeparator();
334 forwardPageAction->addTo(navi_menu);
335 backwardPageAction->addTo(navi_menu);
336 navi_menu->insertSeparator();
337 jumpto_id = navi_menu->insertItem(tr("Jump to page..."), this, SLOT(showJumpToPage()));
338 firstPageAction->addTo(navi_menu);
339 lastPageAction->addTo(navi_menu);
340 navi_menu->insertSeparator();
341 pageTopAction->addTo(navi_menu);
342 pageBottomAction->addTo(navi_menu);
343 navi_menu->insertSeparator();
344 contscr_id = navi_menu->insertItem(tr("Continuous scrolling"), this, SLOT(toggleContinousScroll()));
345 twoPagesAction->setOn(cfg->twoPagesMode());
346 stripModeAction->setOn(cfg->stripMode());
347 mangaModeAction->setOn(cfg->japaneseMode());
348 navi_menu->setItemChecked(contscr_id, cfg->continuousScrolling());
349 menuBar()->insertItem(tr("&Navigation"), navi_menu);
352 void ComicMainWindow::setupBookmarksMenu()
354 bookmarks_menu = new QPopupMenu(this);
355 bookmarks = new Bookmarks(bookmarks_menu);
356 menuBar()->insertItem(tr("&Bookmarks"), bookmarks_menu);
357 setbookmark_id = bookmarks_menu->insertItem(Icons::get(ICON_BOOKMARK), tr("Set bookmark for this comicbook"), this, SLOT(setBookmark()));
358 rmvbookmark_id = bookmarks_menu->insertItem(tr("Remove bookmark for this comicbook"), this, SLOT(removeBookmark()));
359 bookmarks_menu->insertItem(tr("Manage bookmarks"), this, SLOT(openBookmarksManager()));
360 bookmarks_menu->insertSeparator();
362 connect(bookmarks_menu, SIGNAL(activated(int)), this, SLOT(bookmarkSelected(int)));
365 void ComicMainWindow::setupSettingsMenu()
367 settings_menu = new QPopupMenu(this);
368 scrv_id = settings_menu->insertItem(tr("Scrollbars"), this, SLOT(toggleScrollbars()));
369 settings_menu->setItemChecked(scrv_id, cfg->scrollbarsVisible());
370 toggleToolbarAction->addTo(settings_menu);
371 toggleStatusbarAction->addTo(settings_menu);
372 settings_menu->insertSeparator();
373 fullScreenAction->addTo(settings_menu);
374 settings_menu->insertSeparator();
375 settings_menu->insertItem(Icons::get(ICON_SETTINGS), tr("Configure QComicBook"), this, SLOT(showConfigDialog()));
376 menuBar()->insertItem(tr("&Settings"), settings_menu);
379 void ComicMainWindow::setupHelpMenu()
381 QPopupMenu *help_menu = new QPopupMenu(this);
382 help_menu->insertItem(tr("System information"), this, SLOT(showSysInfo()));
383 help_menu->insertSeparator();
384 help_menu->insertItem(tr("Index"), this, SLOT(showHelp()));
385 help_menu->insertItem(tr("About"), this, SLOT(showAbout()));
386 menuBar()->insertItem(tr("&Help"), help_menu);
389 void ComicMainWindow::setupStatusbar()
391 statusbar = new StatusBar(this);
392 connect(toggleStatusbarAction, SIGNAL(toggled(bool)), statusbar, SLOT(setShown(bool)));
393 toggleStatusbarAction->setOn(cfg->showStatusbar());
394 statusbar->setShown(cfg->showStatusbar());
397 void ComicMainWindow::setupContextMenu()
399 QPopupMenu *cmenu = view->contextMenu();
400 pageinfo = new QLabel(cmenu);
401 pageinfo->setMargin(3);
402 pageinfo->setAlignment(Qt::AlignHCenter);
403 pageinfo->setFrameStyle(QFrame::Box | QFrame::Raised);
404 nextPageAction->addTo(cmenu);
405 prevPageAction->addTo(cmenu);
406 cmenu->insertSeparator();
407 fitWidthAction->addTo(cmenu);
408 fitHeightAction->addTo(cmenu);
409 wholePageAction->addTo(cmenu);
410 originalSizeAction->addTo(cmenu);
411 bestFitAction->addTo(cmenu);
412 cmenu->insertSeparator();
413 rotateRightAction->addTo(cmenu);
414 rotateLeftAction->addTo(cmenu);
415 rotateResetAction->addTo(cmenu);
416 cmenu->insertSeparator();
417 twoPagesAction->addTo(cmenu);
418 stripModeAction->addTo(cmenu);
419 mangaModeAction->addTo(cmenu);
420 cmenu->insertSeparator();
421 fullScreenAction->addTo(cmenu);
422 cmenu->insertSeparator();
423 cmenu->insertItem(pageinfo);
426 void ComicMainWindow::enableComicBookActions(bool f)
430 const bool x = f && sink && sink->supportsNext();
431 file_menu->setItemEnabled(close_id, f);
432 file_menu->setItemEnabled(create_id, f);
433 showInfoAction->setEnabled(f);
434 openNextAction->setEnabled(x);
435 openPrevAction->setEnabled(x);
441 edit_menu->setItemEnabled(gimp_id, f);
442 edit_menu->setItemEnabled(reload_id, f);
447 rotateRightAction->setEnabled(f);
448 rotateLeftAction->setEnabled(f);
449 rotateResetAction->setEnabled(f);
453 lastPageAction->setEnabled(f);
454 firstPageAction->setEnabled(f);
455 navi_menu->setItemEnabled(jumpto_id, f);
456 nextPageAction->setEnabled(f);
457 prevPageAction->setEnabled(f);
458 backwardPageAction->setEnabled(f);
459 forwardPageAction->setEnabled(f);
460 pageTopAction->setEnabled(f);
461 pageBottomAction->setEnabled(f);
465 bookmarks_menu->setItemEnabled(setbookmark_id, f);
466 bookmarks_menu->setItemEnabled(rmvbookmark_id, f);
469 void ComicMainWindow::dragEnterEvent(QDragEnterEvent *e)
471 e->accept(QUriDrag::canDecode(e));
474 void ComicMainWindow::dropEvent(QDropEvent *e)
477 if (QUriDrag::decodeLocalFiles(e, files))
481 void ComicMainWindow::keyPressEvent(QKeyEvent *e)
483 if ((e->key()>=Qt::Key_1) && (e->key()<=Qt::Key_9))
486 showJumpToPage(e->text());
489 QMainWindow::keyPressEvent(e);
492 void ComicMainWindow::closeEvent(QCloseEvent *e)
494 return (!cfg->confirmExit() || confirmExit()) ? e->accept() : e->ignore();
497 bool ComicMainWindow::confirmExit()
499 return QMessageBox::question(this, tr("Leave QComicBook?"), tr("Do you really want to quit QComicBook?"), QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes;
502 void ComicMainWindow::thumbnailsVisibilityChanged(bool f)
506 int max = sink->numOfImages();
507 for (int i=0; i<max; i++)
508 if (!thumbswin->view()->isLoaded(i))
509 sink->requestThumbnail(i);
513 void ComicMainWindow::toolbarVisibilityChanged(bool f)
515 toggleToolbarAction->setOn(f);
518 void ComicMainWindow::toggleScrollbars()
520 bool f = settings_menu->isItemChecked(scrv_id);
521 settings_menu->setItemChecked(scrv_id, !f);
522 view->enableScrollbars(!f);
525 void ComicMainWindow::toggleContinousScroll()
527 bool f = navi_menu->isItemChecked(contscr_id);
528 navi_menu->setItemChecked(contscr_id, !f);
531 view->disconnect(SIGNAL(bottomReached()), this);
532 view->disconnect(SIGNAL(topReached()), this);
535 { connect(view, SIGNAL(bottomReached()), this, SLOT(nextPage()));
536 connect(view, SIGNAL(topReached()), this, SLOT(prevPageBottom()));
540 void ComicMainWindow::toggleTwoPages(bool f)
542 twoPagesAction->setOn(f);
543 jumpToPage(currpage, true);
546 void ComicMainWindow::toggleStripMode(bool f)
548 stripModeAction->setOn(f);
549 jumpToPage(currpage, true);
552 void ComicMainWindow::setStripMax(int sm)
554 jumpToPage(currpage, true);
557 void ComicMainWindow::toggleJapaneseMode(bool f)
559 mangaModeAction->setOn(f);
560 if (twoPagesAction->isOn())
561 jumpToPage(currpage, true);
564 void ComicMainWindow::reloadPage()
567 jumpToPage(currpage, true);
570 void ComicMainWindow::updateCaption()
572 QString c = "QComicBook";
574 c += " - " + sink->getName();
578 void ComicMainWindow::setRecentFilesMenu(const History &hist)
580 QStringList list = hist.getAll();
581 recent_menu->clear();
582 for (QStringList::const_iterator it = list.begin(); it != list.end(); it++)
583 recent_menu->insertItem(*it);
586 void ComicMainWindow::recentSelected(int id)
588 const QString &fname = recent_menu->text(id);
589 if (fname != QString::null)
591 QFileInfo finfo(fname);
594 recentfiles->remove(fname);
595 recent_menu->removeItem(id);
601 void ComicMainWindow::sinkReady(const QString &path)
603 statusbar->setShown(toggleStatusbarAction->isOn() && !(isFullScreen() && cfg->fullScreenHideStatusbar())); //applies back user's statusbar&toolbar preferences
604 //toolbar->setShown(toggleToolbarAction->isOn() && !(isFullScreen() && cfg->fullScreenHideToolbar()));
606 recentfiles->append(path);
607 setRecentFilesMenu(*recentfiles);
609 enableComicBookActions(true);
611 statusbar->setName(sink->getFullName());
613 thumbswin->view()->setPages(sink->numOfImages());
616 // request thumbnails for all pages
617 if (thumbswin->isVisible())
618 sink->requestThumbnails(0, sink->numOfImages());
620 jumpToPage(currpage, true);
622 const bool hasdesc = (sink->getDescription().count() > 0);
623 showInfoAction->setDisabled(!hasdesc);
625 if (hasdesc && cfg->autoInfo())
629 void ComicMainWindow::sinkError(int code)
631 statusbar->setShown(toggleStatusbarAction->isOn() && !(isFullScreen() && cfg->fullScreenHideStatusbar())); //applies back user's statusbar&toolbar preferences
632 //toolbar->setShown(toggleToolbarAction->isOn() && !(isFullScreen() && cfg->fullScreenHideToolbar()));
637 case SINKERR_EMPTY: msg = tr("no images found"); break;
638 case SINKERR_UNKNOWNFILE: msg = tr("unknown archive"); break;
639 case SINKERR_ACCESS: msg = tr("can't access directory"); break;
640 case SINKERR_NOTFOUND: msg = tr("file/directory not found"); break;
641 case SINKERR_NOTSUPPORTED: msg = tr("archive not supported"); break;
642 case SINKERR_ARCHEXIT: msg = tr("archive extractor exited with error"); break;
645 QMessageBox::critical(this, "QComicBook error", "Error opening comicbook: " + msg,
646 QMessageBox::Ok, QMessageBox::NoButton);
650 void ComicMainWindow::browseDirectory()
652 const QString dir = QFileDialog::getExistingDirectory(lastdir, this,
653 NULL, tr("Choose a directory") );
658 void ComicMainWindow::browseArchive()
660 const QString file = QFileDialog::getOpenFileName(lastdir,
661 "Archives (" + ImgArchiveSink::supportedOpenExtensions() + ");;All files (*)",
662 this, NULL, tr("Choose a file") );
667 void ComicMainWindow::open(const QString &path, int page)
669 const QFileInfo f(path);
670 const QString fullname = f.absFilePath();
672 if (sink && sink->getFullName() == fullname) //trying to open same dir?
675 lastdir = f.dirPath(true);
680 ImlibImage::setCacheSize(cfg->cacheSize()*1024*1024);
682 sink = ImgSinkFactory::instance().createImgSink(path);
683 sink->thumbnailLoader().setReciever(thumbswin);
684 sink->thumbnailLoader().setUseCache(cfg->cacheThumbnails());
686 connect(sink, SIGNAL(sinkReady(const QString&)), this, SLOT(sinkReady(const QString&)));
687 connect(sink, SIGNAL(sinkError(int)), this, SLOT(sinkError(int)));
688 connect(sink, SIGNAL(progress(int, int)), statusbar, SLOT(setProgress(int, int)));
690 statusbar->setShown(true); //ensures status bar is visible when opening regardless of user settings
692 sink->open(fullname);
695 void ComicMainWindow::openNext()
697 if (sink && sink->supportsNext())
699 QString fname = sink->getNext();
700 if (!fname.isEmpty())
705 void ComicMainWindow::openPrevious()
707 if (sink && sink->supportsNext())
709 QString fname = sink->getPrevious();
710 if (!fname.isEmpty())
715 void ComicMainWindow::toggleFullScreen()
723 if (cfg->fullScreenHideMenu())
725 if (cfg->fullScreenHideStatusbar())
727 /*if (cfg->fullScreenHideToolbar())
733 void ComicMainWindow::exitFullscreen()
738 if (toggleStatusbarAction->isOn())
740 /*if (toggleToolbarAction->isOn())
746 void ComicMainWindow::nextPage()
750 int savedpage = currpage;
753 jumpToPage(nextpage);
757 if (!spreading && twoPagesAction->isOn() && cfg->twoPagesStep())
759 if (currpage < sink->numOfImages() - 2) //do not change pages if last two pages are visible
760 jumpToPage(currpage + 2);
764 jumpToPage(currpage + 1);
767 if (currpage != savedpage)
768 prevpage = savedpage;
772 void ComicMainWindow::prevPage()
775 jumpToPage(prevpage);
777 if (!spreading && twoPagesAction->isOn() && cfg->twoPagesStep())
778 jumpToPage(currpage - 2);
780 jumpToPage(currpage - 1);
783 void ComicMainWindow::prevPageBottom()
788 view->scrollToBottom();
792 void ComicMainWindow::firstPage()
797 void ComicMainWindow::lastPage()
800 jumpToPage(sink->numOfImages() - (twoPagesAction->isOn() && cfg->twoPagesStep() ? 2 : 1));
803 void ComicMainWindow::forwardPages()
805 jumpToPage(currpage + 5*(nextpage-currpage));
808 void ComicMainWindow::backwardPages()
810 jumpToPage(currpage - 5*(nextpage-currpage));
813 void ComicMainWindow::jumpToPage(int n, bool force)
817 if (n >= sink->numOfImages())
818 n = sink->numOfImages()-1;
821 if ((n != currpage) || force)
824 int result1, result2;
825 ImlibImage *img1, *img2;
826 ImlibImageList list[2];
828 const bool preserveangle = togglePreserveRotationAction->isOn();
830 img1 = sink->getImage(currpage = n, result1);
832 if (img1->getFormat() == STRIP_FORMAT && stripModeAction->isOn())
834 nextpage = buildStripList(n, img1, list, twoPagesAction->isOn());
835 jumpToStrip(n, list, twoPagesAction->isOn());
839 if (twoPagesAction->isOn())
841 // If the first page is a spread and we consider spreads as
842 // two pages, skip loading a second page and mark this
843 if (img1->getFormat() == SPREAD_FORMAT && cfg->twoPagesSpread())
852 img2 = sink->getImage(currpage + (++page_off), result2);
854 if (result2 == 0 && img2->getFormat() == STRIP_FORMAT && stripModeAction->isOn()) {
855 list[0].append(img1);
856 nextpage = buildStripList(currpage+page_off, img2, &(list[1]), false);
857 jumpToStrip(n, list, true);
863 // If the second page is a spread, and we consider spreads as
864 // two pages, there are two possible ways of handling the lone
865 // first page: either we display it alone, or we display it
866 // with the next non-spread page as second page.
868 // This works fine for comics which have sequences such
869 // as "p04 p04-05 p05", i.e. both the single pages and
870 // the spreads are available. Since there is no easy
871 // way to autodetect the situation, we have to make it
872 // an user-settable option.
873 if (result2 == 0 && img2->getFormat() == SPREAD_FORMAT && cfg->twoPagesSpread())
875 if (cfg->twoPagesSkip())
877 int save_page_off = page_off;
878 while (result2 == 0 && img2->getFormat() == SPREAD_FORMAT)
881 img2 = sink->getImage(currpage + (++page_off), result2);
884 page_off = save_page_off - 1; // Reset counter for next page
887 { // Stop at spreads:
891 --page_off; // Reset counter for next page
897 if (mangaModeAction->isOn())
899 view->setImage(img2, img1, preserveangle);
900 statusbar->setImageInfo(img2, img1);
904 view->setImage(img1, img2, preserveangle);
905 statusbar->setImageInfo(img1, img2);
910 view->setImage(img1, preserveangle);
911 statusbar->setImageInfo(img1);
912 if (cfg->preloadPages())
913 sink->preload(currpage + 1);
918 view->setImage(img1, preserveangle);
919 statusbar->setImageInfo(img1);
921 if (mangaModeAction->isOn())
922 view->ensureVisible(view->imageWidth(), 0);
923 const QString page = tr("Page") + " " + QString::number(currpage + 1) + "/" + QString::number(sink->numOfImages());
924 pageinfo->setText(page);
925 statusbar->setPage(currpage + 1, sink->numOfImages());
926 thumbswin->view()->scrollToPage(currpage);
927 if (cfg->preloadPages())
929 if (!twoPagesAction->isOn())
931 sink->preload(currpage + 1);
935 sink->preload(currpage + 3);
936 sink->preload(currpage + 2);
939 nextpage = currpage + (++page_off);
943 int ComicMainWindow::buildStripList(int n, ImlibImage *img1, ImlibImageList *list, bool twoPages)
948 int stripmax = cfg->stripMax();
950 list[0].append(img1);
952 img2 = sink->getImage(n + (++page_off), result2) ;
953 while (result2 == 0 && img2->getFormat() == STRIP_FORMAT && list[0].count() < stripmax) {
954 list[0].append(img2) ;
955 img2 = sink->getImage(n + (++page_off), result2) ;
958 // If we are displaying two pages, start filling the second side
959 if (twoPages && result2 == 0)
961 list[1].append(img2) ;
962 // ... which is a strip collection if the first strip is a strip
963 if (img2->getFormat() == STRIP_FORMAT)
965 img2 = sink->getImage(n + (++page_off), result2) ;
966 while (result2 == 0 && img2->getFormat() == STRIP_FORMAT && list[1].count() < stripmax) {
967 list[1].append(img2) ;
968 img2 = sink->getImage(n + (++page_off), result2) ;
973 return (n + page_off);
976 void ComicMainWindow::jumpToStrip(int n, ImlibImageList *list, bool twoPages)
978 const bool preserveangle = togglePreserveRotationAction->isOn();
981 ImlibImage *img1, *img2;
983 img1 = list[0].at(0);
987 img2 = list[1].at(0);
988 if (mangaModeAction->isOn())
990 view->setImage(list[1], list[0], preserveangle);
991 statusbar->setImageInfo(img2, img1);
995 view->setImage(list[0], list[1], preserveangle);
996 statusbar->setImageInfo(img1, img2);
1001 view->setImage(list[0], preserveangle);
1002 statusbar->setImageInfo(img1);
1004 if (mangaModeAction->isOn())
1005 view->ensureVisible(view->imageWidth(), 0);
1006 const QString page = tr("Page") + " " + QString::number(currpage + 1) + "/" + QString::number(sink->numOfImages());
1007 pageinfo->setText(page);
1008 statusbar->setPage(currpage + 1, sink->numOfImages());
1009 thumbswin->view()->scrollToPage(currpage);
1012 void ComicMainWindow::showInfo()
1016 ComicBookInfo *i = new ComicBookInfo(this, *sink, cfg->infoFont());
1021 void ComicMainWindow::showSysInfo()
1023 SupportedArchivesWindow *win = new SupportedArchivesWindow(this);
1027 void ComicMainWindow::createArchive()
1031 ArchiverDialog *win = new ArchiverDialog(this, sink);
1037 void ComicMainWindow::showAbout()
1039 AboutDialog *win = new AboutDialog(this, "About QComicBook",
1040 "QComicBook " VERSION " - comic book viewer for GNU/Linux\n"
1041 "(c)by Pawel Stolowski 2005-2006\n"
1042 "released under terms of GNU General Public License\n\n"
1043 "http://linux.bydg.org/~yogin\n"
1044 "pawel.stolowski@wp.pl", QPixmap(DATADIR "qcomicbook-splash.png"));
1048 void ComicMainWindow::showHelp()
1050 const QString helpdir = HelpBrowser::getLocaleHelpDir(DATADIR "/help");
1051 if (!cfg->useInternalBrowser() && cfg->externalBrowser() != QString::null)
1053 QProcess *proc = new QProcess(this);
1054 proc->addArgument(cfg->externalBrowser());
1055 proc->addArgument(helpdir + "/index.html");
1056 connect(proc, SIGNAL(processExited()), proc, SLOT(deleteLater()));
1059 proc->deleteLater();
1060 cfg->useInternalBrowser(true);
1063 if (cfg->useInternalBrowser())
1065 HelpBrowser *help = new HelpBrowser(tr("QComicBook Help"), helpdir);
1070 void ComicMainWindow::showConfigDialog()
1072 ComicBookCfgDialog *d = new ComicBookCfgDialog(this, cfg);
1076 void ComicMainWindow::showJumpToPage(const QString &number)
1080 JumpToPageWindow *win = new JumpToPageWindow(this, number.toInt(), sink->numOfImages());
1081 connect(win, SIGNAL(pageSelected(int)), this, SLOT(jumpToPage(int)));
1086 void ComicMainWindow::closeSink()
1088 enableComicBookActions(false);
1092 /*if (typeid(*sink) == typeid(ImgArchiveSink) && cfg->editSupport() && sink->hasModifiedFiles())
1094 if (QMessageBox::warning(this, tr("Create archive?"),
1095 tr("Warning! Some files were modified in this comic book\nDo you want to create new archive file?"),
1096 QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
1098 ArchiverDialog *win = new ArchiverDialog(this, sink);
1104 sink->deleteLater();
1108 thumbswin->view()->clear();
1113 void ComicMainWindow::setBookmark()
1116 bookmarks->set(sink->getFullName(), currpage);
1119 void ComicMainWindow::removeBookmark()
1121 if (sink && bookmarks->exists(sink->getFullName()) && QMessageBox::question(this, tr("Removing bookmark"),
1122 tr("Do you really want to remove bookmark\nfor this comic book?"),
1123 QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
1124 bookmarks->remove(sink->getFullName());
1127 void ComicMainWindow::openBookmarksManager()
1129 BookmarkManager *win = new BookmarkManager(this, bookmarks);
1133 void ComicMainWindow::openWithGimp()
1137 QProcess *proc = new QProcess(this);
1138 proc->addArgument("gimp-remote");
1139 proc->addArgument(sink->getFullFileName(currpage));
1140 connect(proc, SIGNAL(processExited()), proc, SLOT(deleteLater()));
1143 proc->deleteLater();
1147 void ComicMainWindow::bookmarkSelected(int id)
1150 if (bookmarks->get(id, b))
1152 if (b.getName() != QString::null)
1154 QString fname = b.getName();
1155 if (sink && fname == sink->getFullName()) //is this comicbook already opened?
1157 jumpToPage(b.getPage(), true); //if so, just jump to bookmarked page
1161 QFileInfo finfo(fname);
1162 if (!finfo.exists())
1164 if (QMessageBox::question(this, tr("Comic book not found"),
1165 tr("Selected bookmark points to\nnon-existing comic book\nDo you want to remove it?"),
1166 QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
1167 bookmarks->remove(id);
1170 open(fname, b.getPage());
1175 void ComicMainWindow::saveSettings()
1177 cfg->geometry(frameGeometry());
1178 cfg->saveDockLayout(this);
1179 cfg->scrollbarsVisible(settings_menu->isItemChecked(scrv_id));
1180 cfg->twoPagesMode(twoPagesAction->isOn());
1181 cfg->stripMode(stripModeAction->isOn());
1182 cfg->japaneseMode(mangaModeAction->isOn());
1183 cfg->continuousScrolling(navi_menu->isItemChecked(contscr_id));
1184 cfg->lastDir(lastdir);
1185 cfg->recentlyOpened(*recentfiles);
1186 cfg->pageSize(view->getSize());
1187 cfg->showStatusbar(toggleStatusbarAction->isOn());