Fix navigation in twoPagesSpread mode
[qcomicbook-oblomov] / src / comicmain.cpp
1 /*
2  * This file is a part of QComicBook.
3  *
4  * Copyright (C) 2005-2006 Pawel Stolowski <yogin@linux.bydg.org>
5  *
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.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY. See GPL for more details.
11  */
12
13 #include "config.h"
14 #include "bookmarks.h"
15 #include "comicmain.h"
16 #include "icons.h"
17 #include "cbicons.h"
18 #include "cbinfo.h"
19 #include "imgview.h"
20 #include "imgarchivesink.h"
21 #include "imgsinkfactory.h"
22 #include "aboutdialog.h"
23 #include "cbsettings.h"
24 #include "history.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"
32 #include "miscutil.h"
33 #include "archiverdialog.h"
34 #include "suparchwin.h"
35 #include "imlibimage.h"
36 #include <qimage.h>
37 #include <qmenubar.h>
38 #include <qpopupmenu.h>
39 #include <qstringlist.h>
40 #include <qaction.h>
41 #include <qfiledialog.h>
42 #include <qfileinfo.h>
43 #include <qtoolbar.h>
44 #include <qmessagebox.h>
45 #include <qlabel.h>
46 #include <qframe.h>
47 #include <jumptopagewin.h>
48 #include <qprocess.h>
49 #include <qdragobject.h>
50 #include <typeinfo>
51
52 using namespace QComicBook;
53 using namespace Utility;
54
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)
56 {
57         updateCaption();
58         setIcon(Icons::get(ICON_APPICON).pixmap(QIconSet::Small, true));
59         setMinimumSize(320, 200);
60
61         setAcceptDrops(true); //???
62
63         cfg = &ComicBookSettings::instance();
64
65         setGeometry(cfg->geometry());
66
67         setupActions();
68         setupToolbar();
69         setupStatusbar();
70         setupComicImageView();
71         setupThumbnailsWindow();
72
73         setupFileMenu();  
74         if (cfg->editSupport())
75               setupEditMenu();
76         setupViewMenu();
77         setupNavigationMenu();
78         setupBookmarksMenu();
79         setupSettingsMenu();
80         setupHelpMenu();
81         setupContextMenu();    
82
83         lastdir = cfg->lastDir();
84         recentfiles = new History(10);
85         *recentfiles = cfg->recentlyOpened();
86         setRecentFilesMenu(*recentfiles);
87
88         cfg->restoreDockLayout(this);
89
90         enableComicBookActions(false);
91 }
92
93 ComicMainWindow::~ComicMainWindow()
94 {
95         if (cfg->cacheThumbnails())
96                 ImgDirSink::removeThumbnails(cfg->thumbnailsAge());
97
98         saveSettings();        
99
100         delete recentfiles;
101         delete bookmarks;
102
103         if (sink)
104                 delete sink;
105 }
106
107 void ComicMainWindow::setupActions()
108 {
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);
133
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);
164
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()));
177 }
178
179 void ComicMainWindow::setupComicImageView()
180 {
181         view = new ComicImageView(this, cfg->pageSize(), cfg->background());
182         setCentralWidget(view);
183         view->setFocus();
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())
214         {
215                 connect(view, SIGNAL(bottomReached()), this, SLOT(nextPage()));
216                 connect(view, SIGNAL(topReached()), this, SLOT(prevPageBottom()));
217         }
218         connect(view, SIGNAL(doubleClick()), this, SLOT(nextPage()));
219         view->enableScrollbars(cfg->scrollbarsVisible());
220         QAction *which = originalSizeAction;
221         switch (cfg->pageSize())
222         {
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;
228         }
229         which->setOn(true);
230 }
231
232 void ComicMainWindow::setupThumbnailsWindow()
233 {
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)));       
240 }
241
242 void ComicMainWindow::setupToolbar()
243 {
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)));
272 }
273
274 void ComicMainWindow::setupFileMenu()
275 {
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);   
293 }
294
295 void ComicMainWindow::setupEditMenu()
296 {
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);
304 }
305
306 void ComicMainWindow::setupViewMenu()
307 {
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);     
326 }
327
328 void ComicMainWindow::setupNavigationMenu()
329 {
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);
350 }
351
352 void ComicMainWindow::setupBookmarksMenu()
353 {
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();
361         bookmarks->load();
362         connect(bookmarks_menu, SIGNAL(activated(int)), this, SLOT(bookmarkSelected(int)));
363 }
364
365 void ComicMainWindow::setupSettingsMenu()
366 {
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);
377 }
378
379 void ComicMainWindow::setupHelpMenu()
380 {
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);
387 }
388
389 void ComicMainWindow::setupStatusbar()
390 {
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());
395 }
396
397 void ComicMainWindow::setupContextMenu()
398 {
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);
424 }
425
426 void ComicMainWindow::enableComicBookActions(bool f)
427 {
428         //
429         // file menu
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);
436
437         //
438         // edit menu
439         if (edit_menu)
440         {
441                 edit_menu->setItemEnabled(gimp_id, f);
442                 edit_menu->setItemEnabled(reload_id, f);
443         }
444         
445         //
446         // view menu
447         rotateRightAction->setEnabled(f);
448         rotateLeftAction->setEnabled(f);
449         rotateResetAction->setEnabled(f);
450
451         //
452         // navigation menu
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);
462
463         //
464         // bookmarks menu
465         bookmarks_menu->setItemEnabled(setbookmark_id, f);
466         bookmarks_menu->setItemEnabled(rmvbookmark_id, f);
467 }
468
469 void ComicMainWindow::dragEnterEvent(QDragEnterEvent *e)
470 {
471         e->accept(QUriDrag::canDecode(e));
472 }
473
474 void ComicMainWindow::dropEvent(QDropEvent *e)
475 {
476         QStringList files;
477         if (QUriDrag::decodeLocalFiles(e, files))
478                 open(files[0], 0);
479 }
480
481 void ComicMainWindow::keyPressEvent(QKeyEvent *e)
482 {
483         if ((e->key()>=Qt::Key_1) && (e->key()<=Qt::Key_9))
484         {
485                 e->accept();
486                 showJumpToPage(e->text());
487         }
488         else
489                 QMainWindow::keyPressEvent(e);
490 }
491
492 void ComicMainWindow::closeEvent(QCloseEvent *e)
493 {
494         return (!cfg->confirmExit() || confirmExit()) ? e->accept() : e->ignore();
495 }
496
497 bool ComicMainWindow::confirmExit()
498 {
499         return QMessageBox::question(this, tr("Leave QComicBook?"), tr("Do you really want to quit QComicBook?"), QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes;
500 }
501
502 void ComicMainWindow::thumbnailsVisibilityChanged(bool f)
503 {
504         if (f && sink)
505         {
506                 int max = sink->numOfImages();
507                 for (int i=0; i<max; i++)
508                         if (!thumbswin->view()->isLoaded(i))
509                                 sink->requestThumbnail(i);
510         }
511 }
512
513 void ComicMainWindow::toolbarVisibilityChanged(bool f)
514 {
515         toggleToolbarAction->setOn(f);
516 }
517
518 void ComicMainWindow::toggleScrollbars()
519 {
520         bool f = settings_menu->isItemChecked(scrv_id);
521         settings_menu->setItemChecked(scrv_id, !f);
522         view->enableScrollbars(!f);
523 }
524
525 void ComicMainWindow::toggleContinousScroll()
526 {
527         bool f = navi_menu->isItemChecked(contscr_id);
528         navi_menu->setItemChecked(contscr_id, !f);
529         if (f)
530         {
531                 view->disconnect(SIGNAL(bottomReached()), this);
532                 view->disconnect(SIGNAL(topReached()), this);
533         }
534         else
535         {       connect(view, SIGNAL(bottomReached()), this, SLOT(nextPage()));
536                 connect(view, SIGNAL(topReached()), this, SLOT(prevPageBottom()));
537         }
538 }
539
540 void ComicMainWindow::toggleTwoPages(bool f)
541 {
542         twoPagesAction->setOn(f);
543         jumpToPage(currpage, true);
544 }
545
546 void ComicMainWindow::toggleStripMode(bool f)
547 {
548         stripModeAction->setOn(f);
549         jumpToPage(currpage, true);
550 }
551
552 void ComicMainWindow::setStripMax(int sm)
553 {
554         jumpToPage(currpage, true);
555 }
556
557 void ComicMainWindow::toggleJapaneseMode(bool f)
558 {
559         mangaModeAction->setOn(f);
560         if (twoPagesAction->isOn())
561                 jumpToPage(currpage, true);
562 }
563
564 void ComicMainWindow::reloadPage()
565 {
566         if (sink)
567                 jumpToPage(currpage, true);
568 }
569
570 void ComicMainWindow::updateCaption()
571 {
572         QString c = "QComicBook";
573         if (sink)
574                 c += " - " + sink->getName();
575         setCaption(c);
576 }
577
578 void ComicMainWindow::setRecentFilesMenu(const History &hist)
579 {
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);
584 }
585
586 void ComicMainWindow::recentSelected(int id)
587 {
588         const QString &fname = recent_menu->text(id);
589         if (fname != QString::null)
590         {
591                 QFileInfo finfo(fname);
592                 if (!finfo.exists())
593                 {
594                         recentfiles->remove(fname);
595                         recent_menu->removeItem(id);
596                 }
597                 open(fname, 0);
598         }
599 }
600
601 void ComicMainWindow::sinkReady(const QString &path)
602 {
603         statusbar->setShown(toggleStatusbarAction->isOn() && !(isFullScreen() && cfg->fullScreenHideStatusbar())); //applies back user's statusbar&toolbar preferences
604         //toolbar->setShown(toggleToolbarAction->isOn() && !(isFullScreen() && cfg->fullScreenHideToolbar()));
605
606         recentfiles->append(path);
607         setRecentFilesMenu(*recentfiles);
608
609         enableComicBookActions(true);
610         updateCaption();
611         statusbar->setName(sink->getFullName());
612
613         thumbswin->view()->setPages(sink->numOfImages());
614
615         //
616         // request thumbnails for all pages
617         if (thumbswin->isVisible())
618                 sink->requestThumbnails(0, sink->numOfImages());
619
620         jumpToPage(currpage, true);
621
622         const bool hasdesc = (sink->getDescription().count() > 0);
623         showInfoAction->setDisabled(!hasdesc);
624
625         if (hasdesc && cfg->autoInfo())
626                 showInfo();
627 }
628
629 void ComicMainWindow::sinkError(int code)
630 {
631         statusbar->setShown(toggleStatusbarAction->isOn() && !(isFullScreen() && cfg->fullScreenHideStatusbar())); //applies back user's statusbar&toolbar preferences
632         //toolbar->setShown(toggleToolbarAction->isOn() && !(isFullScreen() && cfg->fullScreenHideToolbar()));
633
634         QString msg;
635         switch (code)
636         {
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;
643                 default: break;
644         }
645         QMessageBox::critical(this, "QComicBook error", "Error opening comicbook: " + msg, 
646                         QMessageBox::Ok, QMessageBox::NoButton);
647         closeSink();
648 }
649
650 void ComicMainWindow::browseDirectory()
651 {
652         const QString dir = QFileDialog::getExistingDirectory(lastdir, this, 
653                         NULL, tr("Choose a directory") );
654         if (!dir.isEmpty())
655                 open(dir, 0);
656 }
657
658 void ComicMainWindow::browseArchive()
659 {
660         const QString file = QFileDialog::getOpenFileName(lastdir,
661                         "Archives (" + ImgArchiveSink::supportedOpenExtensions() + ");;All files (*)",
662                         this, NULL, tr("Choose a file") );
663         if (!file.isEmpty())
664                 open(file, 0);
665 }
666
667 void ComicMainWindow::open(const QString &path, int page)
668 {
669         const QFileInfo f(path);
670         const QString fullname = f.absFilePath();
671
672         if (sink && sink->getFullName() == fullname) //trying to open same dir?
673                 return;
674
675         lastdir = f.dirPath(true);
676         currpage = page;
677
678         closeSink();
679
680         ImlibImage::setCacheSize(cfg->cacheSize()*1024*1024);
681
682         sink = ImgSinkFactory::instance().createImgSink(path);
683         sink->thumbnailLoader().setReciever(thumbswin);
684         sink->thumbnailLoader().setUseCache(cfg->cacheThumbnails());
685
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)));
689
690         statusbar->setShown(true); //ensures status bar is visible when opening regardless of user settings
691
692         sink->open(fullname);
693 }
694
695 void ComicMainWindow::openNext()
696 {
697         if (sink && sink->supportsNext())
698         {
699                 QString fname = sink->getNext();
700                 if (!fname.isEmpty())
701                         open(fname, 0);
702         }
703 }
704
705 void ComicMainWindow::openPrevious()
706 {
707         if (sink && sink->supportsNext())
708         {
709                 QString fname = sink->getPrevious();
710                 if (!fname.isEmpty())
711                         open(fname, 0);
712         }
713 }
714
715 void ComicMainWindow::toggleFullScreen()
716 {
717         if (isFullScreen())
718         {
719                 exitFullscreen();
720         }
721         else
722         {
723                 if (cfg->fullScreenHideMenu())
724                         menuBar()->hide();
725                 if (cfg->fullScreenHideStatusbar())
726                         statusbar->hide();
727                 /*if (cfg->fullScreenHideToolbar())
728                         toolbar->hide();*/
729                 showFullScreen();
730         }
731 }
732
733 void ComicMainWindow::exitFullscreen()
734 {
735         if (isFullScreen())
736         {
737                 menuBar()->show();
738                 if (toggleStatusbarAction->isOn())
739                         statusbar->show();
740                 /*if (toggleToolbarAction->isOn())
741                         toolbar->show();*/
742                 showNormal();
743         }
744 }
745
746 void ComicMainWindow::nextPage()
747 {
748         if (sink)
749         {
750                 int savedpage = currpage;
751                 if (nextpage != -1)
752                 {
753                         jumpToPage(nextpage);
754                 }
755                 else
756                 {
757                         if (!spreading && twoPagesAction->isOn() && cfg->twoPagesStep())
758                         {
759                                 if (currpage < sink->numOfImages() - 2) //do not change pages if last two pages are visible
760                                         jumpToPage(currpage + 2);
761                         }
762                         else
763                         {
764                                 jumpToPage(currpage + 1);
765                         }
766                 }
767                 if (currpage != savedpage)
768                         prevpage = savedpage;
769         }
770 }
771
772 void ComicMainWindow::prevPage()
773 {
774         if (prevpage != -1)
775                 jumpToPage(prevpage);
776         else
777                 if (!spreading && twoPagesAction->isOn() && cfg->twoPagesStep())
778                         jumpToPage(currpage - 2);
779                 else
780                         jumpToPage(currpage - 1);
781 }
782
783 void ComicMainWindow::prevPageBottom()
784 {
785         if (currpage > 0)
786         {
787                 prevPage();
788                 view->scrollToBottom();
789         }
790 }
791
792 void ComicMainWindow::firstPage()
793 {
794         jumpToPage(0);
795 }
796
797 void ComicMainWindow::lastPage()
798 {
799         if (sink)
800                 jumpToPage(sink->numOfImages() - (twoPagesAction->isOn() && cfg->twoPagesStep() ? 2 : 1));
801 }
802
803 void ComicMainWindow::forwardPages()
804 {
805         jumpToPage(currpage + 5*(nextpage-currpage));
806 }
807
808 void ComicMainWindow::backwardPages()
809 {
810         jumpToPage(currpage - 5*(nextpage-currpage));
811 }
812
813 void ComicMainWindow::jumpToPage(int n, bool force)
814 {
815         if (!sink)
816                 return;
817         if (n >= sink->numOfImages())
818                 n = sink->numOfImages()-1;
819         if (n < 0)
820                 n = 0;
821         if ((n != currpage) || force)
822         {
823                 prevpage = -1;
824                 int result1, result2;
825                 ImlibImage *img1, *img2;
826                 ImlibImageList list[2];
827                 int page_off = 0;
828                 const bool preserveangle = togglePreserveRotationAction->isOn();
829
830                 img1 = sink->getImage(currpage = n, result1);
831
832                 if (img1->getFormat() == STRIP_FORMAT && stripModeAction->isOn())
833                 {
834                         nextpage = buildStripList(n, img1, list, twoPagesAction->isOn());
835                         jumpToStrip(n, list, twoPagesAction->isOn());
836                         return;
837                 }
838
839                 if (twoPagesAction->isOn())
840                 {
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())
844                         {
845                                 result2 = 1;
846                                 spreading = true;
847                         }
848                         else
849                         {
850                                 spreading = false;
851
852                                 img2 = sink->getImage(currpage + (++page_off), result2);
853
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);
858                                         return;
859                                 }
860                         }
861
862
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.
867                         //
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())
874                         {
875                                 if (cfg->twoPagesSkip())
876                                 { // Skip spreads:
877                                         int save_page_off = page_off;
878                                         while (result2 == 0 && img2->getFormat() == SPREAD_FORMAT)
879                                         {
880                                                 delete img2;
881                                                 img2 = sink->getImage(currpage + (++page_off), result2);
882                                                 spreading = true;
883                                         }
884                                         page_off = save_page_off - 1; // Reset counter for next page
885                                 }
886                                 else
887                                 { // Stop at spreads:
888                                         result2 = 1;
889                                         spreading = true;
890                                         delete img2;
891                                         --page_off; // Reset counter for next page
892                                 }
893                         }
894
895                         if (result2 == 0)
896                         {
897                                 if (mangaModeAction->isOn())
898                                 {
899                                         view->setImage(img2, img1, preserveangle);
900                                         statusbar->setImageInfo(img2, img1);
901                                 }
902                                 else
903                                 {
904                                         view->setImage(img1, img2, preserveangle);
905                                         statusbar->setImageInfo(img1, img2);
906                                 }
907                         }
908                         else
909                         {
910                                 view->setImage(img1, preserveangle);
911                                 statusbar->setImageInfo(img1);
912                                 if (cfg->preloadPages())
913                                         sink->preload(currpage + 1);
914                         }
915                 }
916                 else
917                 {
918                         view->setImage(img1, preserveangle);
919                         statusbar->setImageInfo(img1);
920                 }
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())
928                 {
929                         if (!twoPagesAction->isOn())
930                         {
931                                 sink->preload(currpage + 1);
932                         }
933                         else
934                         {
935                                 sink->preload(currpage + 3);
936                                 sink->preload(currpage + 2);
937                         }
938                 }
939                 nextpage = currpage + (++page_off);
940         }
941 }
942
943 int ComicMainWindow::buildStripList(int n, ImlibImage *img1, ImlibImageList *list, bool twoPages)
944 {
945         ImlibImage *img2;
946         int page_off = 0;
947         int result2;
948         int stripmax = cfg->stripMax();
949
950         list[0].append(img1);
951
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) ;
956         }
957
958         // If we are displaying two pages, start filling the second side
959         if (twoPages && result2 == 0)
960         {
961                 list[1].append(img2) ;
962                 // ... which is a strip collection if the first strip is a strip
963                 if (img2->getFormat() == STRIP_FORMAT)
964                 {
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) ;
969                         }
970                 }
971
972         }
973         return (n + page_off);
974 }
975
976 void ComicMainWindow::jumpToStrip(int n, ImlibImageList *list, bool twoPages)
977 {
978         const bool preserveangle = togglePreserveRotationAction->isOn();
979
980         // Temporary
981         ImlibImage *img1, *img2;
982
983         img1 = list[0].at(0);
984
985         if (twoPages)
986         {
987                 img2 = list[1].at(0);
988                 if (mangaModeAction->isOn())
989                 {
990                         view->setImage(list[1], list[0], preserveangle);
991                         statusbar->setImageInfo(img2, img1);
992                 }
993                 else
994                 {
995                         view->setImage(list[0], list[1], preserveangle);
996                         statusbar->setImageInfo(img1, img2);
997                 }
998         }
999         else
1000         {
1001                 view->setImage(list[0], preserveangle);
1002                 statusbar->setImageInfo(img1);
1003         }
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);
1010 }
1011
1012 void ComicMainWindow::showInfo()
1013 {
1014         if (sink)
1015         {
1016                 ComicBookInfo *i = new ComicBookInfo(this, *sink, cfg->infoFont());
1017                 i->show();
1018         }
1019 }
1020
1021 void ComicMainWindow::showSysInfo()
1022 {
1023         SupportedArchivesWindow *win = new SupportedArchivesWindow(this);
1024         win->show();
1025 }
1026
1027 void ComicMainWindow::createArchive()
1028 {
1029         if (sink)
1030         {
1031                 ArchiverDialog *win = new ArchiverDialog(this, sink);
1032                 win->exec();
1033                 delete win;
1034         }
1035 }
1036
1037 void ComicMainWindow::showAbout()
1038 {
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"));
1045         win->show();
1046 }
1047
1048 void ComicMainWindow::showHelp()
1049 {
1050         const QString helpdir = HelpBrowser::getLocaleHelpDir(DATADIR "/help");
1051         if (!cfg->useInternalBrowser() && cfg->externalBrowser() != QString::null)
1052         {
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()));
1057                 if (!proc->start())
1058                 {
1059                         proc->deleteLater();
1060                         cfg->useInternalBrowser(true);
1061                 }
1062         }
1063         if (cfg->useInternalBrowser())
1064         {
1065                 HelpBrowser *help = new HelpBrowser(tr("QComicBook Help"), helpdir);
1066                 help->show();
1067         }
1068 }
1069
1070 void ComicMainWindow::showConfigDialog()
1071 {
1072         ComicBookCfgDialog *d = new ComicBookCfgDialog(this, cfg);
1073         d->show();
1074 }
1075
1076 void ComicMainWindow::showJumpToPage(const QString &number)
1077 {
1078         if (sink)
1079         {
1080                 JumpToPageWindow *win = new JumpToPageWindow(this, number.toInt(), sink->numOfImages());
1081                 connect(win, SIGNAL(pageSelected(int)), this, SLOT(jumpToPage(int)));
1082                 win->show();
1083         }
1084 }
1085
1086 void ComicMainWindow::closeSink()
1087 {
1088         enableComicBookActions(false);
1089
1090         if (sink)
1091         {
1092                 /*if (typeid(*sink) == typeid(ImgArchiveSink) && cfg->editSupport() && sink->hasModifiedFiles()) 
1093                 {
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)
1097                         {
1098                                 ArchiverDialog *win = new ArchiverDialog(this, sink);
1099                                 win->exec();
1100                                 delete win;
1101                         }
1102
1103                 }*/
1104                 sink->deleteLater();
1105                 sink = NULL;
1106         }
1107         view->clear();
1108         thumbswin->view()->clear();
1109         updateCaption();
1110         statusbar->clear();
1111 }
1112
1113 void ComicMainWindow::setBookmark()
1114 {
1115         if (sink)
1116                 bookmarks->set(sink->getFullName(), currpage);
1117 }
1118
1119 void ComicMainWindow::removeBookmark()
1120 {
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());
1125 }
1126
1127 void ComicMainWindow::openBookmarksManager()
1128 {
1129         BookmarkManager *win = new BookmarkManager(this, bookmarks);
1130         win->show();
1131 }
1132
1133 void ComicMainWindow::openWithGimp()
1134 {
1135         if (!sink)
1136                 return;
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()));
1141         if (!proc->start())
1142         {
1143                 proc->deleteLater();
1144         }
1145 }
1146
1147 void ComicMainWindow::bookmarkSelected(int id)
1148 {
1149         Bookmark b;
1150         if (bookmarks->get(id, b))
1151         {
1152                 if (b.getName() != QString::null)
1153                 {
1154                         QString fname = b.getName();
1155                         if (sink && fname == sink->getFullName()) //is this comicbook already opened?
1156                         {
1157                                 jumpToPage(b.getPage(), true); //if so, just jump to bookmarked page
1158                                 return;
1159                         }
1160
1161                         QFileInfo finfo(fname);
1162                         if (!finfo.exists())
1163                         {
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);
1168                                 return;
1169                         }
1170                         open(fname, b.getPage());
1171                 }
1172         }
1173 }
1174
1175 void ComicMainWindow::saveSettings()
1176 {
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());
1188
1189         bookmarks->save();        
1190 }
1191