1 | /* |
2 | Gwenview: an image viewer |
3 | Copyright 2007 Aurélien Gâteau <agateau@kde.org> |
4 | |
5 | This program is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU General Public License |
7 | as published by the Free Software Foundation; either version 2 |
8 | of the License, or (at your option) any later version. |
9 | |
10 | This program is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | GNU General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU General Public License |
16 | along with this program; if not, write to the Free Software |
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
18 | |
19 | */ |
20 | #include "mainwindow.moc" |
21 | #include <config-gwenview.h> |
22 | |
23 | // Qt |
24 | #include <QApplication> |
25 | #include <QDateTime> |
26 | #include <QDesktopWidget> |
27 | #include <QLabel> |
28 | #include <QPushButton> |
29 | #include <QShortcut> |
30 | #include <QSlider> |
31 | #include <QSplitter> |
32 | #include <QStackedWidget> |
33 | #include <QTimer> |
34 | #include <QUndoGroup> |
35 | #include <QVBoxLayout> |
36 | |
37 | // KDE |
38 | #include <KIO/NetAccess> |
39 | #include <KActionCategory> |
40 | #include <KActionCollection> |
41 | #include <KAction> |
42 | #include <KApplication> |
43 | #include <KDirLister> |
44 | #include <KEditToolBar> |
45 | #include <KFileDialog> |
46 | #include <KFileItem> |
47 | #include <KLocale> |
48 | #include <KMenuBar> |
49 | #include <KMessageBox> |
50 | #include <KNotificationRestrictions> |
51 | #include <KProtocolManager> |
52 | #include <KLinkItemSelectionModel> |
53 | #include <KRecentFilesAction> |
54 | #include <KStatusBar> |
55 | #include <KStandardDirs> |
56 | #include <KStandardGuiItem> |
57 | #include <KStandardShortcut> |
58 | #include <KToggleFullScreenAction> |
59 | #include <KToolBar> |
60 | #include <KUrl> |
61 | #include <KUrlNavigator> |
62 | #include <KXMLGUIFactory> |
63 | #include <KWindowSystem> |
64 | |
65 | // Local |
66 | #include "configdialog.h" |
67 | #include "documentinfoprovider.h" |
68 | #include "viewmainpage.h" |
69 | #include "fileopscontextmanageritem.h" |
70 | #include "folderviewcontextmanageritem.h" |
71 | #include "fullscreencontent.h" |
72 | #include "gvcore.h" |
73 | #include "imageopscontextmanageritem.h" |
74 | #include "infocontextmanageritem.h" |
75 | #ifdef KIPI_FOUND |
76 | #include "kipiexportaction.h" |
77 | #include "kipiinterface.h" |
78 | #endif |
79 | #ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE |
80 | #include "semanticinfocontextmanageritem.h" |
81 | #endif |
82 | #include "preloader.h" |
83 | #include "savebar.h" |
84 | #include "sidebar.h" |
85 | #include "splitter.h" |
86 | #include "startmainpage.h" |
87 | #include "thumbnailviewhelper.h" |
88 | #include "browsemainpage.h" |
89 | #include <lib/hud/hudbuttonbox.h> |
90 | #include <lib/archiveutils.h> |
91 | #include <lib/contextmanager.h> |
92 | #include <lib/disabledactionshortcutmonitor.h> |
93 | #include <lib/document/documentfactory.h> |
94 | #include <lib/documentonlyproxymodel.h> |
95 | #include <lib/eventwatcher.h> |
96 | #include <lib/gvdebug.h> |
97 | #include <lib/gwenviewconfig.h> |
98 | #include <lib/mimetypeutils.h> |
99 | #include <lib/print/printhelper.h> |
100 | #include <lib/slideshow.h> |
101 | #include <lib/signalblocker.h> |
102 | #include <lib/semanticinfo/sorteddirmodel.h> |
103 | #include <lib/thumbnailprovider/thumbnailprovider.h> |
104 | #include <lib/thumbnailview/thumbnailbarview.h> |
105 | #include <lib/thumbnailview/thumbnailview.h> |
106 | #include <lib/urlutils.h> |
107 | |
108 | namespace Gwenview |
109 | { |
110 | |
111 | #undef ENABLE_LOG |
112 | #undef LOG |
113 | //#define ENABLE_LOG |
114 | #ifdef ENABLE_LOG |
115 | #define LOG(x) kDebug() << x |
116 | #else |
117 | #define LOG(x) ; |
118 | #endif |
119 | |
120 | static const int BROWSE_PRELOAD_DELAY = 1000; |
121 | static const int VIEW_PRELOAD_DELAY = 100; |
122 | |
123 | static const char* BROWSE_MODE_SIDE_BAR_GROUP = "SideBar-BrowseMode" ; |
124 | static const char* VIEW_MODE_SIDE_BAR_GROUP = "SideBar-ViewMode" ; |
125 | static const char* FULLSCREEN_MODE_SIDE_BAR_GROUP = "SideBar-FullScreenMode" ; |
126 | static const char* SIDE_BAR_IS_VISIBLE_KEY = "IsVisible" ; |
127 | |
128 | static const char* SESSION_CURRENT_PAGE_KEY = "Page" ; |
129 | static const char* SESSION_URL_KEY = "Url" ; |
130 | |
131 | enum MainPageId { |
132 | StartMainPageId, |
133 | BrowseMainPageId, |
134 | ViewMainPageId |
135 | }; |
136 | |
137 | struct MainWindowState |
138 | { |
139 | bool mToolBarVisible; |
140 | Qt::WindowStates mWindowState; |
141 | }; |
142 | |
143 | /* |
144 | |
145 | Layout of the main window looks like this: |
146 | |
147 | .-mCentralSplitter-----------------------------. |
148 | |.-mSideBar--. .-mContentWidget---------------.| |
149 | || | |.-mSaveBar-------------------.|| |
150 | || | || ||| |
151 | || | |'----------------------------'|| |
152 | || | |.-mViewStackedWidget---------.|| |
153 | || | || ||| |
154 | || | || ||| |
155 | || | || ||| |
156 | || | || ||| |
157 | || | |'----------------------------'|| |
158 | |'-----------' '------------------------------'| |
159 | '----------------------------------------------' |
160 | |
161 | */ |
162 | struct MainWindow::Private |
163 | { |
164 | GvCore* mGvCore; |
165 | MainWindow* q; |
166 | QSplitter* mCentralSplitter; |
167 | QWidget* mContentWidget; |
168 | ViewMainPage* mViewMainPage; |
169 | KUrlNavigator* mUrlNavigator; |
170 | ThumbnailView* mThumbnailView; |
171 | ThumbnailView* mActiveThumbnailView; |
172 | DocumentInfoProvider* mDocumentInfoProvider; |
173 | ThumbnailViewHelper* mThumbnailViewHelper; |
174 | QPointer<ThumbnailProvider> mThumbnailProvider; |
175 | BrowseMainPage* mBrowseMainPage; |
176 | StartMainPage* mStartMainPage; |
177 | SideBar* mSideBar; |
178 | QStackedWidget* mViewStackedWidget; |
179 | FullScreenContent* mFullScreenContent; |
180 | SaveBar* mSaveBar; |
181 | bool mStartSlideShowWhenDirListerCompleted; |
182 | SlideShow* mSlideShow; |
183 | Preloader* mPreloader; |
184 | bool mPreloadDirectionIsForward; |
185 | #ifdef KIPI_FOUND |
186 | KIPIInterface* mKIPIInterface; |
187 | #endif |
188 | |
189 | QActionGroup* mViewModeActionGroup; |
190 | KRecentFilesAction* mFileOpenRecentAction; |
191 | KAction* mBrowseAction; |
192 | KAction* mViewAction; |
193 | KAction* mGoUpAction; |
194 | KAction* mGoToPreviousAction; |
195 | KAction* mGoToNextAction; |
196 | KAction* mGoToFirstAction; |
197 | KAction* mGoToLastAction; |
198 | KToggleAction* mToggleSideBarAction; |
199 | KToggleFullScreenAction* mFullScreenAction; |
200 | KAction* mToggleSlideShowAction; |
201 | KToggleAction* mShowMenuBarAction; |
202 | #ifdef KIPI_FOUND |
203 | KIPIExportAction* mKIPIExportAction; |
204 | #endif |
205 | |
206 | SortedDirModel* mDirModel; |
207 | DocumentOnlyProxyModel* mThumbnailBarModel; |
208 | KLinkItemSelectionModel* mThumbnailBarSelectionModel; |
209 | ContextManager* mContextManager; |
210 | |
211 | MainWindowState mStateBeforeFullScreen; |
212 | |
213 | QString mCaption; |
214 | |
215 | MainPageId mCurrentMainPageId; |
216 | |
217 | QDateTime mFullScreenLeftAt; |
218 | KNotificationRestrictions* mNotificationRestrictions; |
219 | |
220 | void setupContextManager() |
221 | { |
222 | mContextManager = new ContextManager(mDirModel, q); |
223 | connect(mContextManager, SIGNAL(selectionChanged()), |
224 | q, SLOT(slotSelectionChanged())); |
225 | connect(mContextManager, SIGNAL(currentDirUrlChanged(KUrl)), |
226 | q, SLOT(slotCurrentDirUrlChanged(KUrl))); |
227 | } |
228 | |
229 | void setupWidgets() |
230 | { |
231 | mFullScreenContent = new FullScreenContent(q); |
232 | connect(mContextManager, SIGNAL(currentUrlChanged(KUrl)), mFullScreenContent, SLOT(setCurrentUrl(KUrl))); |
233 | |
234 | mCentralSplitter = new Splitter(Qt::Horizontal, q); |
235 | q->setCentralWidget(mCentralSplitter); |
236 | |
237 | // Left side of splitter |
238 | mSideBar = new SideBar(mCentralSplitter); |
239 | EventWatcher::install(mSideBar, QList<QEvent::Type>() << QEvent::Show << QEvent::Hide, |
240 | q, SLOT(updateToggleSideBarAction())); |
241 | |
242 | // Right side of splitter |
243 | mContentWidget = new QWidget(mCentralSplitter); |
244 | |
245 | mSaveBar = new SaveBar(mContentWidget, q->actionCollection()); |
246 | connect(mContextManager, SIGNAL(currentUrlChanged(KUrl)), mSaveBar, SLOT(setCurrentUrl(KUrl))); |
247 | mViewStackedWidget = new QStackedWidget(mContentWidget); |
248 | QVBoxLayout* layout = new QVBoxLayout(mContentWidget); |
249 | layout->addWidget(mSaveBar); |
250 | layout->addWidget(mViewStackedWidget); |
251 | layout->setMargin(0); |
252 | layout->setSpacing(0); |
253 | //// |
254 | |
255 | mStartSlideShowWhenDirListerCompleted = false; |
256 | mSlideShow = new SlideShow(q); |
257 | connect(mContextManager, SIGNAL(currentUrlChanged(KUrl)), mSlideShow, SLOT(setCurrentUrl(KUrl))); |
258 | |
259 | setupThumbnailView(mViewStackedWidget); |
260 | setupViewMainPage(mViewStackedWidget); |
261 | setupStartMainPage(mViewStackedWidget); |
262 | mViewStackedWidget->addWidget(mBrowseMainPage); |
263 | mViewStackedWidget->addWidget(mViewMainPage); |
264 | mViewStackedWidget->addWidget(mStartMainPage); |
265 | mViewStackedWidget->setCurrentWidget(mBrowseMainPage); |
266 | |
267 | mCentralSplitter->setStretchFactor(0, 0); |
268 | mCentralSplitter->setStretchFactor(1, 1); |
269 | |
270 | connect(mSaveBar, SIGNAL(requestSaveAll()), |
271 | mGvCore, SLOT(saveAll())); |
272 | connect(mSaveBar, SIGNAL(goToUrl(KUrl)), |
273 | q, SLOT(goToUrl(KUrl))); |
274 | |
275 | connect(mSlideShow, SIGNAL(goToUrl(KUrl)), |
276 | q, SLOT(goToUrl(KUrl))); |
277 | } |
278 | |
279 | void setupThumbnailView(QWidget* parent) |
280 | { |
281 | Q_ASSERT(mContextManager); |
282 | mBrowseMainPage = new BrowseMainPage(parent, q->actionCollection(), mGvCore); |
283 | |
284 | mThumbnailView = mBrowseMainPage->thumbnailView(); |
285 | mThumbnailView->setSelectionModel(mContextManager->selectionModel()); |
286 | mUrlNavigator = mBrowseMainPage->urlNavigator(); |
287 | |
288 | mDocumentInfoProvider = new DocumentInfoProvider(mDirModel); |
289 | mThumbnailView->setDocumentInfoProvider(mDocumentInfoProvider); |
290 | |
291 | mThumbnailViewHelper = new ThumbnailViewHelper(mDirModel, q->actionCollection()); |
292 | connect(mContextManager, SIGNAL(currentDirUrlChanged(KUrl)), |
293 | mThumbnailViewHelper, SLOT(setCurrentDirUrl(KUrl))); |
294 | mThumbnailView->setThumbnailViewHelper(mThumbnailViewHelper); |
295 | |
296 | mThumbnailBarSelectionModel = new KLinkItemSelectionModel(mThumbnailBarModel, mContextManager->selectionModel(), q); |
297 | |
298 | // Connect thumbnail view |
299 | connect(mThumbnailView, SIGNAL(indexActivated(QModelIndex)), |
300 | q, SLOT(slotThumbnailViewIndexActivated(QModelIndex))); |
301 | |
302 | // Connect delegate |
303 | QAbstractItemDelegate* delegate = mThumbnailView->itemDelegate(); |
304 | connect(delegate, SIGNAL(saveDocumentRequested(KUrl)), |
305 | mGvCore, SLOT(save(KUrl))); |
306 | connect(delegate, SIGNAL(rotateDocumentLeftRequested(KUrl)), |
307 | mGvCore, SLOT(rotateLeft(KUrl))); |
308 | connect(delegate, SIGNAL(rotateDocumentRightRequested(KUrl)), |
309 | mGvCore, SLOT(rotateRight(KUrl))); |
310 | connect(delegate, SIGNAL(showDocumentInFullScreenRequested(KUrl)), |
311 | q, SLOT(showDocumentInFullScreen(KUrl))); |
312 | connect(delegate, SIGNAL(setDocumentRatingRequested(KUrl,int)), |
313 | mGvCore, SLOT(setRating(KUrl,int))); |
314 | |
315 | // Connect url navigator |
316 | connect(mUrlNavigator, SIGNAL(urlChanged(KUrl)), |
317 | q, SLOT(openDirUrl(KUrl))); |
318 | } |
319 | |
320 | void setupViewMainPage(QWidget* parent) |
321 | { |
322 | mViewMainPage = new ViewMainPage(parent, mSlideShow, q->actionCollection(), mGvCore); |
323 | connect(mViewMainPage, SIGNAL(captionUpdateRequested(QString)), |
324 | q, SLOT(setCaption(QString))); |
325 | connect(mViewMainPage, SIGNAL(completed()), |
326 | q, SLOT(slotPartCompleted())); |
327 | connect(mViewMainPage, SIGNAL(previousImageRequested()), |
328 | q, SLOT(goToPrevious())); |
329 | connect(mViewMainPage, SIGNAL(nextImageRequested()), |
330 | q, SLOT(goToNext())); |
331 | |
332 | setupThumbnailBar(mViewMainPage->thumbnailBar()); |
333 | } |
334 | |
335 | void setupThumbnailBar(ThumbnailView* bar) |
336 | { |
337 | Q_ASSERT(mThumbnailBarModel); |
338 | Q_ASSERT(mThumbnailBarSelectionModel); |
339 | Q_ASSERT(mDocumentInfoProvider); |
340 | Q_ASSERT(mThumbnailViewHelper); |
341 | bar->setModel(mThumbnailBarModel); |
342 | bar->setSelectionModel(mThumbnailBarSelectionModel); |
343 | bar->setDocumentInfoProvider(mDocumentInfoProvider); |
344 | bar->setThumbnailViewHelper(mThumbnailViewHelper); |
345 | } |
346 | |
347 | void setupStartMainPage(QWidget* parent) |
348 | { |
349 | mStartMainPage = new StartMainPage(parent, mGvCore); |
350 | connect(mStartMainPage, SIGNAL(urlSelected(KUrl)), |
351 | q, SLOT(slotStartMainPageUrlSelected(KUrl))); |
352 | } |
353 | |
354 | void installDisabledActionShortcutMonitor(QAction* action, const char* slot) |
355 | { |
356 | DisabledActionShortcutMonitor* monitor = new DisabledActionShortcutMonitor(action, q); |
357 | connect(monitor, SIGNAL(activated()), q, slot); |
358 | } |
359 | |
360 | void setupActions() |
361 | { |
362 | KActionCollection* actionCollection = q->actionCollection(); |
363 | KActionCategory* file = new KActionCategory(i18nc("@title actions category" , "File" ), actionCollection); |
364 | KActionCategory* view = new KActionCategory(i18nc("@title actions category - means actions changing smth in interface" , "View" ), actionCollection); |
365 | |
366 | file->addAction(KStandardAction::Save, q, SLOT(saveCurrent())); |
367 | file->addAction(KStandardAction::SaveAs, q, SLOT(saveCurrentAs())); |
368 | file->addAction(KStandardAction::Open, q, SLOT(openFile())); |
369 | mFileOpenRecentAction = KStandardAction::openRecent(q, SLOT(openUrl(KUrl)), q); |
370 | file->addAction("file_open_recent" , mFileOpenRecentAction); |
371 | file->addAction(KStandardAction::Print, q, SLOT(print())); |
372 | file->addAction(KStandardAction::Quit, KApplication::kApplication(), SLOT(closeAllWindows())); |
373 | |
374 | KAction* action = file->addAction("reload" , q, SLOT(reload())); |
375 | action->setText(i18nc("@action reload the currently viewed image" , "Reload" )); |
376 | action->setIcon(KIcon("view-refresh" )); |
377 | action->setShortcut(Qt::Key_F5); |
378 | |
379 | mBrowseAction = view->addAction("browse" ); |
380 | mBrowseAction->setText(i18nc("@action:intoolbar Switch to file list" , "Browse" )); |
381 | mBrowseAction->setToolTip(i18nc("@info:tooltip" , "Browse folders for images" )); |
382 | mBrowseAction->setCheckable(true); |
383 | mBrowseAction->setIcon(KIcon("view-list-icons" )); |
384 | mBrowseAction->setShortcut(Qt::Key_Escape); |
385 | connect(mViewMainPage, SIGNAL(goToBrowseModeRequested()), |
386 | mBrowseAction, SLOT(trigger())); |
387 | |
388 | mViewAction = view->addAction("view" ); |
389 | mViewAction->setText(i18nc("@action:intoolbar Switch to image view" , "View" )); |
390 | mViewAction->setToolTip(i18nc("@info:tooltip" , "View selected images" )); |
391 | mViewAction->setIcon(KIcon("view-preview" )); |
392 | mViewAction->setCheckable(true); |
393 | |
394 | mViewModeActionGroup = new QActionGroup(q); |
395 | mViewModeActionGroup->addAction(mBrowseAction); |
396 | mViewModeActionGroup->addAction(mViewAction); |
397 | |
398 | connect(mViewModeActionGroup, SIGNAL(triggered(QAction*)), |
399 | q, SLOT(setActiveViewModeAction(QAction*))); |
400 | |
401 | mFullScreenAction = static_cast<KToggleFullScreenAction*>(view->addAction(KStandardAction::FullScreen, q, SLOT(toggleFullScreen(bool)))); |
402 | KShortcut shortcut = mFullScreenAction->shortcut(); |
403 | if (shortcut.alternate().isEmpty()) { |
404 | shortcut.setAlternate(Qt::Key_F11); |
405 | } |
406 | mFullScreenAction->setShortcut(shortcut); |
407 | connect(mViewMainPage, SIGNAL(toggleFullScreenRequested()), |
408 | mFullScreenAction, SLOT(trigger())); |
409 | |
410 | KAction* leaveFullScreenAction = view->addAction("leave_fullscreen" , q, SLOT(leaveFullScreen())); |
411 | leaveFullScreenAction->setIcon(KIcon("view-restore" )); |
412 | leaveFullScreenAction->setPriority(QAction::LowPriority); |
413 | leaveFullScreenAction->setText(i18nc("@action" , "Leave Fullscreen Mode" )); |
414 | |
415 | mGoToPreviousAction = view->addAction("go_previous" , q, SLOT(goToPrevious())); |
416 | mGoToPreviousAction->setPriority(QAction::LowPriority); |
417 | mGoToPreviousAction->setIcon(KIcon("media-skip-backward" )); |
418 | mGoToPreviousAction->setText(i18nc("@action Go to previous image" , "Previous" )); |
419 | mGoToPreviousAction->setToolTip(i18nc("@info:tooltip" , "Go to previous image" )); |
420 | mGoToPreviousAction->setShortcut(Qt::Key_Backspace); |
421 | installDisabledActionShortcutMonitor(mGoToPreviousAction, SLOT(showFirstDocumentReached())); |
422 | |
423 | mGoToNextAction = view->addAction("go_next" , q, SLOT(goToNext())); |
424 | mGoToNextAction->setPriority(QAction::LowPriority); |
425 | mGoToNextAction->setIcon(KIcon("media-skip-forward" )); |
426 | mGoToNextAction->setText(i18nc("@action Go to next image" , "Next" )); |
427 | mGoToNextAction->setToolTip(i18nc("@info:tooltip" , "Go to next image" )); |
428 | mGoToNextAction->setShortcut(Qt::Key_Space); |
429 | installDisabledActionShortcutMonitor(mGoToNextAction, SLOT(showLastDocumentReached())); |
430 | |
431 | mGoToFirstAction = view->addAction("go_first" , q, SLOT(goToFirst())); |
432 | mGoToFirstAction->setPriority(QAction::LowPriority); |
433 | mGoToFirstAction->setText(i18nc("@action Go to first image" , "First" )); |
434 | mGoToFirstAction->setToolTip(i18nc("@info:tooltip" , "Go to first image" )); |
435 | mGoToFirstAction->setShortcut(Qt::Key_Home); |
436 | |
437 | mGoToLastAction = view->addAction("go_last" , q, SLOT(goToLast())); |
438 | mGoToLastAction->setPriority(QAction::LowPriority); |
439 | mGoToLastAction->setText(i18nc("@action Go to last image" , "Last" )); |
440 | mGoToLastAction->setToolTip(i18nc("@info:tooltip" , "Go to last image" )); |
441 | mGoToLastAction->setShortcut(Qt::Key_End); |
442 | |
443 | mPreloadDirectionIsForward = true; |
444 | |
445 | mGoUpAction = view->addAction(KStandardAction::Up, q, SLOT(goUp())); |
446 | |
447 | action = view->addAction("go_start_page" , q, SLOT(showStartMainPage())); |
448 | action->setPriority(QAction::LowPriority); |
449 | action->setIcon(KIcon("go-home" )); |
450 | action->setText(i18nc("@action" , "Start Page" )); |
451 | action->setToolTip(i18nc("@info:tooltip" , "Open the start page" )); |
452 | |
453 | mToggleSideBarAction = view->add<KToggleAction>("toggle_sidebar" ); |
454 | connect(mToggleSideBarAction, SIGNAL(toggled(bool)), |
455 | q, SLOT(toggleSideBar(bool))); |
456 | mToggleSideBarAction->setIcon(KIcon("view-sidetree" )); |
457 | mToggleSideBarAction->setShortcut(Qt::Key_F4); |
458 | mToggleSideBarAction->setText(i18nc("@action" , "Sidebar" )); |
459 | connect(mBrowseMainPage->toggleSideBarButton(), SIGNAL(clicked()), |
460 | mToggleSideBarAction, SLOT(trigger())); |
461 | connect(mViewMainPage->toggleSideBarButton(), SIGNAL(clicked()), |
462 | mToggleSideBarAction, SLOT(trigger())); |
463 | |
464 | mToggleSlideShowAction = view->addAction("toggle_slideshow" , q, SLOT(toggleSlideShow())); |
465 | q->updateSlideShowAction(); |
466 | connect(mSlideShow, SIGNAL(stateChanged(bool)), |
467 | q, SLOT(updateSlideShowAction())); |
468 | |
469 | mShowMenuBarAction = static_cast<KToggleAction*>(view->addAction(KStandardAction::ShowMenubar, q, SLOT(toggleMenuBar()))); |
470 | |
471 | view->addAction(KStandardAction::KeyBindings, q->guiFactory(), |
472 | SLOT(configureShortcuts())); |
473 | |
474 | view->addAction(KStandardAction::Preferences, q, |
475 | SLOT(showConfigDialog())); |
476 | |
477 | view->addAction(KStandardAction::ConfigureToolbars, q, |
478 | SLOT(configureToolbars())); |
479 | |
480 | #ifdef KIPI_FOUND |
481 | mKIPIExportAction = new KIPIExportAction(q); |
482 | actionCollection->addAction("kipi_export" , mKIPIExportAction); |
483 | #endif |
484 | } |
485 | |
486 | void setupUndoActions() |
487 | { |
488 | // There is no KUndoGroup similar to KUndoStack. This code basically |
489 | // does the same as KUndoStack, but for the KUndoGroup actions. |
490 | QUndoGroup* undoGroup = DocumentFactory::instance()->undoGroup(); |
491 | QAction* action; |
492 | KActionCollection* actionCollection = q->actionCollection(); |
493 | KActionCategory* edit = new KActionCategory(i18nc("@title actions category - means actions changing smth in interface" , "Edit" ), actionCollection); |
494 | |
495 | action = undoGroup->createRedoAction(actionCollection); |
496 | action->setObjectName(KStandardAction::name(KStandardAction::Redo)); |
497 | action->setIcon(KIcon("edit-redo" )); |
498 | action->setIconText(i18n("Redo" )); |
499 | action->setShortcuts(KStandardShortcut::redo()); |
500 | edit->addAction(action->objectName(), action); |
501 | |
502 | action = undoGroup->createUndoAction(actionCollection); |
503 | action->setObjectName(KStandardAction::name(KStandardAction::Undo)); |
504 | action->setIcon(KIcon("edit-undo" )); |
505 | action->setIconText(i18n("Undo" )); |
506 | action->setShortcuts(KStandardShortcut::undo()); |
507 | edit->addAction(action->objectName(), action); |
508 | } |
509 | |
510 | void setupContextManagerItems() |
511 | { |
512 | Q_ASSERT(mContextManager); |
513 | KActionCollection* actionCollection = q->actionCollection(); |
514 | |
515 | // Create context manager items |
516 | FolderViewContextManagerItem* folderViewItem = new FolderViewContextManagerItem(mContextManager); |
517 | connect(folderViewItem, SIGNAL(urlChanged(KUrl)), |
518 | q, SLOT(openDirUrl(KUrl))); |
519 | |
520 | InfoContextManagerItem* infoItem = new InfoContextManagerItem(mContextManager); |
521 | |
522 | #ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE |
523 | SemanticInfoContextManagerItem* semanticInfoItem = 0; |
524 | semanticInfoItem = new SemanticInfoContextManagerItem(mContextManager, actionCollection, mViewMainPage); |
525 | #endif |
526 | |
527 | ImageOpsContextManagerItem* imageOpsItem = |
528 | new ImageOpsContextManagerItem(mContextManager, q); |
529 | |
530 | FileOpsContextManagerItem* fileOpsItem = new FileOpsContextManagerItem(mContextManager, mThumbnailView, actionCollection, q); |
531 | |
532 | // Fill sidebar |
533 | SideBarPage* page; |
534 | page = new SideBarPage(i18n("Folders" )); |
535 | page->setObjectName(QLatin1String("folders" )); |
536 | page->addWidget(folderViewItem->widget()); |
537 | page->layout()->setMargin(0); |
538 | mSideBar->addPage(page); |
539 | |
540 | page = new SideBarPage(i18n("Information" )); |
541 | page->setObjectName(QLatin1String("information" )); |
542 | page->addWidget(infoItem->widget()); |
543 | #ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE |
544 | if (semanticInfoItem) { |
545 | page->addWidget(semanticInfoItem->widget()); |
546 | } |
547 | #endif |
548 | mSideBar->addPage(page); |
549 | |
550 | page = new SideBarPage(i18n("Operations" )); |
551 | page->setObjectName(QLatin1String("operations" )); |
552 | page->addWidget(imageOpsItem->widget()); |
553 | page->addWidget(fileOpsItem->widget()); |
554 | page->addStretch(); |
555 | mSideBar->addPage(page); |
556 | } |
557 | |
558 | void initDirModel() |
559 | { |
560 | mDirModel->setKindFilter( |
561 | MimeTypeUtils::KIND_DIR |
562 | | MimeTypeUtils::KIND_ARCHIVE |
563 | | MimeTypeUtils::KIND_RASTER_IMAGE |
564 | | MimeTypeUtils::KIND_SVG_IMAGE |
565 | | MimeTypeUtils::KIND_VIDEO); |
566 | |
567 | connect(mDirModel, SIGNAL(rowsInserted(QModelIndex,int,int)), |
568 | q, SLOT(slotDirModelNewItems())); |
569 | |
570 | connect(mDirModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), |
571 | q, SLOT(updatePreviousNextActions())); |
572 | connect(mDirModel, SIGNAL(modelReset()), |
573 | q, SLOT(updatePreviousNextActions())); |
574 | |
575 | connect(mDirModel->dirLister(), SIGNAL(completed()), |
576 | q, SLOT(slotDirListerCompleted())); |
577 | } |
578 | |
579 | void setupThumbnailBarModel() |
580 | { |
581 | mThumbnailBarModel = new DocumentOnlyProxyModel(q); |
582 | mThumbnailBarModel->setSourceModel(mDirModel); |
583 | } |
584 | |
585 | bool indexIsDirOrArchive(const QModelIndex& index) const |
586 | { |
587 | Q_ASSERT(index.isValid()); |
588 | KFileItem item = mDirModel->itemForIndex(index); |
589 | return ArchiveUtils::fileItemIsDirOrArchive(item); |
590 | } |
591 | |
592 | void goTo(const QModelIndex& index) |
593 | { |
594 | if (!index.isValid()) { |
595 | return; |
596 | } |
597 | mThumbnailView->setCurrentIndex(index); |
598 | mThumbnailView->scrollTo(index); |
599 | } |
600 | |
601 | void goTo(int offset) |
602 | { |
603 | mPreloadDirectionIsForward = offset > 0; |
604 | QModelIndex index = mContextManager->selectionModel()->currentIndex(); |
605 | index = mDirModel->index(index.row() + offset, 0); |
606 | if (index.isValid() && !indexIsDirOrArchive(index)) { |
607 | goTo(index); |
608 | } |
609 | } |
610 | |
611 | void goToFirstDocument() |
612 | { |
613 | QModelIndex index; |
614 | for (int row = 0;; ++row) { |
615 | index = mDirModel->index(row, 0); |
616 | if (!index.isValid()) { |
617 | return; |
618 | } |
619 | |
620 | if (!indexIsDirOrArchive(index)) { |
621 | break; |
622 | } |
623 | } |
624 | goTo(index); |
625 | } |
626 | |
627 | void goToLastDocument() |
628 | { |
629 | QModelIndex index = mDirModel->index(mDirModel->rowCount() - 1, 0); |
630 | goTo(index); |
631 | } |
632 | |
633 | void setupFullScreenContent() |
634 | { |
635 | mFullScreenContent->init(q->actionCollection(), mViewMainPage, mSlideShow); |
636 | setupThumbnailBar(mFullScreenContent->thumbnailBar()); |
637 | } |
638 | |
639 | inline void setActionEnabled(const char* name, bool enabled) |
640 | { |
641 | QAction* action = q->actionCollection()->action(name); |
642 | if (action) { |
643 | action->setEnabled(enabled); |
644 | } else { |
645 | kWarning() << "Action" << name << "not found" ; |
646 | } |
647 | } |
648 | |
649 | void setActionsDisabledOnStartMainPageEnabled(bool enabled) |
650 | { |
651 | mBrowseAction->setEnabled(enabled); |
652 | mViewAction->setEnabled(enabled); |
653 | mToggleSideBarAction->setEnabled(enabled); |
654 | mFullScreenAction->setEnabled(enabled); |
655 | mToggleSlideShowAction->setEnabled(enabled); |
656 | |
657 | setActionEnabled("reload" , enabled); |
658 | setActionEnabled("go_start_page" , enabled); |
659 | setActionEnabled("add_folder_to_places" , enabled); |
660 | } |
661 | |
662 | void updateActions() |
663 | { |
664 | bool isRasterImage = false; |
665 | bool canSave = false; |
666 | bool isModified = false; |
667 | const KUrl url = mContextManager->currentUrl(); |
668 | |
669 | if (url.isValid()) { |
670 | isRasterImage = mContextManager->currentUrlIsRasterImage(); |
671 | canSave = isRasterImage; |
672 | isModified = DocumentFactory::instance()->load(url)->isModified(); |
673 | if (mCurrentMainPageId != ViewMainPageId) { |
674 | // Saving only makes sense if exactly one image is selected |
675 | QItemSelection selection = mThumbnailView->selectionModel()->selection(); |
676 | QModelIndexList indexList = selection.indexes(); |
677 | if (indexList.count() != 1) { |
678 | canSave = false; |
679 | } |
680 | } |
681 | } |
682 | |
683 | KActionCollection* actionCollection = q->actionCollection(); |
684 | actionCollection->action("file_save" )->setEnabled(canSave && isModified); |
685 | actionCollection->action("file_save_as" )->setEnabled(canSave); |
686 | actionCollection->action("file_print" )->setEnabled(isRasterImage); |
687 | } |
688 | |
689 | const char* sideBarConfigGroupName() const |
690 | { |
691 | const char* name = 0; |
692 | switch (mCurrentMainPageId) { |
693 | case StartMainPageId: |
694 | GV_WARN_AND_RETURN_VALUE(BROWSE_MODE_SIDE_BAR_GROUP, "mCurrentMainPageId == 'StartMainPageId'" ); |
695 | break; |
696 | case BrowseMainPageId: |
697 | name = BROWSE_MODE_SIDE_BAR_GROUP; |
698 | break; |
699 | case ViewMainPageId: |
700 | name = mViewMainPage->isFullScreenMode() |
701 | ? FULLSCREEN_MODE_SIDE_BAR_GROUP |
702 | : VIEW_MODE_SIDE_BAR_GROUP; |
703 | break; |
704 | } |
705 | return name; |
706 | } |
707 | |
708 | void loadSideBarConfig() |
709 | { |
710 | static QMap<const char*, bool> defaultVisibility; |
711 | if (defaultVisibility.isEmpty()) { |
712 | defaultVisibility[BROWSE_MODE_SIDE_BAR_GROUP] = true; |
713 | defaultVisibility[VIEW_MODE_SIDE_BAR_GROUP] = true; |
714 | defaultVisibility[FULLSCREEN_MODE_SIDE_BAR_GROUP] = false; |
715 | } |
716 | |
717 | const char* name = sideBarConfigGroupName(); |
718 | KConfigGroup group(KGlobal::config(), name); |
719 | mSideBar->setVisible(group.readEntry(SIDE_BAR_IS_VISIBLE_KEY, defaultVisibility[name])); |
720 | mSideBar->setCurrentPage(GwenviewConfig::sideBarPage()); |
721 | q->updateToggleSideBarAction(); |
722 | } |
723 | |
724 | void saveSideBarConfig() const |
725 | { |
726 | KConfigGroup group(KGlobal::config(), sideBarConfigGroupName()); |
727 | group.writeEntry(SIDE_BAR_IS_VISIBLE_KEY, mSideBar->isVisible()); |
728 | GwenviewConfig::setSideBarPage(mSideBar->currentPage()); |
729 | } |
730 | |
731 | void setScreenSaverEnabled(bool enabled) |
732 | { |
733 | // Always delete mNotificationRestrictions, it does not hurt |
734 | delete mNotificationRestrictions; |
735 | if (!enabled) { |
736 | mNotificationRestrictions = new KNotificationRestrictions(KNotificationRestrictions::ScreenSaver, q); |
737 | } else { |
738 | mNotificationRestrictions = 0; |
739 | } |
740 | } |
741 | |
742 | void assignThumbnailProviderToThumbnailView(ThumbnailView* thumbnailView) |
743 | { |
744 | GV_RETURN_IF_FAIL(thumbnailView); |
745 | if (mActiveThumbnailView) { |
746 | mActiveThumbnailView->setThumbnailProvider(0); |
747 | } |
748 | thumbnailView->setThumbnailProvider(mThumbnailProvider); |
749 | mActiveThumbnailView = thumbnailView; |
750 | if (mActiveThumbnailView->isVisible()) { |
751 | mThumbnailProvider->stop(); |
752 | mActiveThumbnailView->generateThumbnailsForItems(); |
753 | } |
754 | } |
755 | |
756 | void autoAssignThumbnailProvider() |
757 | { |
758 | if (mCurrentMainPageId == ViewMainPageId) { |
759 | if (q->windowState() & Qt::WindowFullScreen) { |
760 | assignThumbnailProviderToThumbnailView(mFullScreenContent->thumbnailBar()); |
761 | } else { |
762 | assignThumbnailProviderToThumbnailView(mViewMainPage->thumbnailBar()); |
763 | } |
764 | } else if (mCurrentMainPageId == BrowseMainPageId) { |
765 | assignThumbnailProviderToThumbnailView(mThumbnailView); |
766 | } else if (mCurrentMainPageId == StartMainPageId) { |
767 | assignThumbnailProviderToThumbnailView(mStartMainPage->recentFoldersView()); |
768 | } |
769 | } |
770 | }; |
771 | |
772 | MainWindow::MainWindow() |
773 | : KXmlGuiWindow(), |
774 | d(new MainWindow::Private) |
775 | { |
776 | d->q = this; |
777 | d->mCurrentMainPageId = StartMainPageId; |
778 | d->mDirModel = new SortedDirModel(this); |
779 | d->setupContextManager(); |
780 | d->setupThumbnailBarModel(); |
781 | d->mGvCore = new GvCore(this, d->mDirModel); |
782 | d->mPreloader = new Preloader(this); |
783 | d->mNotificationRestrictions = 0; |
784 | d->mThumbnailProvider = new ThumbnailProvider(); |
785 | d->mActiveThumbnailView = 0; |
786 | d->initDirModel(); |
787 | d->setupWidgets(); |
788 | d->setupActions(); |
789 | d->setupUndoActions(); |
790 | d->setupContextManagerItems(); |
791 | d->setupFullScreenContent(); |
792 | d->updateActions(); |
793 | updatePreviousNextActions(); |
794 | d->mSaveBar->initActionDependentWidgets(); |
795 | |
796 | createGUI(); |
797 | loadConfig(); |
798 | |
799 | connect(DocumentFactory::instance(), SIGNAL(modifiedDocumentListChanged()), |
800 | SLOT(slotModifiedDocumentListChanged())); |
801 | |
802 | #ifdef KIPI_FOUND |
803 | d->mKIPIInterface = new KIPIInterface(this); |
804 | d->mKIPIExportAction->setKIPIInterface(d->mKIPIInterface); |
805 | #endif |
806 | setAutoSaveSettings(); |
807 | } |
808 | |
809 | MainWindow::~MainWindow() |
810 | { |
811 | if (GwenviewConfig::deleteThumbnailCacheOnExit()) { |
812 | const QString dir = ThumbnailProvider::thumbnailBaseDir(); |
813 | if (QFile::exists(dir)) { |
814 | KIO::NetAccess::del(KUrl::fromPath(dir), this); |
815 | } |
816 | } |
817 | delete d->mThumbnailProvider; |
818 | delete d; |
819 | } |
820 | |
821 | ContextManager* MainWindow::contextManager() const |
822 | { |
823 | return d->mContextManager; |
824 | } |
825 | |
826 | ViewMainPage* MainWindow::viewMainPage() const |
827 | { |
828 | return d->mViewMainPage; |
829 | } |
830 | |
831 | void MainWindow::setCaption(const QString& caption) |
832 | { |
833 | // Keep a trace of caption to use it in slotModifiedDocumentListChanged() |
834 | d->mCaption = caption; |
835 | KXmlGuiWindow::setCaption(caption); |
836 | } |
837 | |
838 | void MainWindow::setCaption(const QString& caption, bool modified) |
839 | { |
840 | d->mCaption = caption; |
841 | KXmlGuiWindow::setCaption(caption, modified); |
842 | } |
843 | |
844 | void MainWindow::slotModifiedDocumentListChanged() |
845 | { |
846 | d->updateActions(); |
847 | |
848 | // Update caption |
849 | QList<KUrl> list = DocumentFactory::instance()->modifiedDocumentList(); |
850 | bool modified = list.count() > 0; |
851 | setCaption(d->mCaption, modified); |
852 | } |
853 | |
854 | void MainWindow::setInitialUrl(const KUrl& _url) |
855 | { |
856 | Q_ASSERT(_url.isValid()); |
857 | KUrl url = UrlUtils::fixUserEnteredUrl(_url); |
858 | if (url.protocol() == "http" || url.protocol() == "https" ) { |
859 | d->mGvCore->addUrlToRecentUrls(url); |
860 | } |
861 | if (UrlUtils::urlIsDirectory(url)) { |
862 | d->mBrowseAction->trigger(); |
863 | openDirUrl(url); |
864 | } else { |
865 | d->mViewAction->trigger(); |
866 | d->mViewMainPage->openUrl(url); |
867 | d->mContextManager->setUrlToSelect(url); |
868 | } |
869 | } |
870 | |
871 | void MainWindow::startSlideShow() |
872 | { |
873 | d->mViewAction->trigger(); |
874 | // We need to wait until we have listed all images in the dirlister to |
875 | // start the slideshow because the SlideShow objects needs an image list to |
876 | // work. |
877 | d->mStartSlideShowWhenDirListerCompleted = true; |
878 | } |
879 | |
880 | void MainWindow::setActiveViewModeAction(QAction* action) |
881 | { |
882 | if (d->mCurrentMainPageId != StartMainPageId) { |
883 | d->saveSideBarConfig(); |
884 | } |
885 | if (action == d->mViewAction) { |
886 | d->mCurrentMainPageId = ViewMainPageId; |
887 | // Switching to view mode |
888 | d->mViewStackedWidget->setCurrentWidget(d->mViewMainPage); |
889 | if (d->mViewMainPage->isEmpty()) { |
890 | openSelectedDocuments(); |
891 | } |
892 | d->mPreloadDirectionIsForward = true; |
893 | QTimer::singleShot(VIEW_PRELOAD_DELAY, this, SLOT(preloadNextUrl())); |
894 | } else { |
895 | d->mCurrentMainPageId = BrowseMainPageId; |
896 | // Switching to browse mode |
897 | d->mViewStackedWidget->setCurrentWidget(d->mBrowseMainPage); |
898 | if (!d->mViewMainPage->isEmpty() |
899 | && KProtocolManager::supportsListing(d->mViewMainPage->url())) { |
900 | // Reset the view to spare resources, but don't do it if we can't |
901 | // browse the url, otherwise if the user starts Gwenview this way: |
902 | // gwenview http://example.com/example.png |
903 | // and switch to browse mode, switching back to view mode won't bring |
904 | // his image back. |
905 | d->mViewMainPage->reset(); |
906 | } |
907 | setCaption(QString()); |
908 | } |
909 | d->loadSideBarConfig(); |
910 | d->autoAssignThumbnailProvider(); |
911 | |
912 | emit viewModeChanged(); |
913 | } |
914 | |
915 | void MainWindow::slotThumbnailViewIndexActivated(const QModelIndex& index) |
916 | { |
917 | if (!index.isValid()) { |
918 | return; |
919 | } |
920 | |
921 | KFileItem item = d->mDirModel->itemForIndex(index); |
922 | if (item.isDir()) { |
923 | // Item is a dir, open it |
924 | openDirUrl(item.url()); |
925 | } else { |
926 | QString protocol = ArchiveUtils::protocolForMimeType(item.mimetype()); |
927 | if (!protocol.isEmpty()) { |
928 | // Item is an archive, tweak url then open it |
929 | KUrl url = item.url(); |
930 | url.setProtocol(protocol); |
931 | openDirUrl(url); |
932 | } else { |
933 | // Item is a document, switch to view mode |
934 | d->mViewAction->trigger(); |
935 | } |
936 | } |
937 | } |
938 | |
939 | static bool indexRowLessThan(const QModelIndex& i1, const QModelIndex& i2) |
940 | { |
941 | return i1.row() < i2.row(); |
942 | } |
943 | |
944 | void MainWindow::openSelectedDocuments() |
945 | { |
946 | if (d->mCurrentMainPageId != ViewMainPageId) { |
947 | return; |
948 | } |
949 | |
950 | QModelIndex currentIndex = d->mThumbnailView->currentIndex(); |
951 | if (!currentIndex.isValid()) { |
952 | return; |
953 | } |
954 | |
955 | int count = 0; |
956 | |
957 | KUrl::List urls; |
958 | KUrl currentUrl; |
959 | QModelIndex firstDocumentIndex; |
960 | QModelIndexList list = d->mThumbnailView->selectionModel()->selectedIndexes(); |
961 | // Make 'list' follow the same order as 'mThumbnailView' |
962 | qSort(list.begin(), list.end(), indexRowLessThan); |
963 | |
964 | Q_FOREACH(const QModelIndex& index, list) { |
965 | KFileItem item = d->mDirModel->itemForIndex(index); |
966 | if (!item.isNull() && !ArchiveUtils::fileItemIsDirOrArchive(item)) { |
967 | KUrl url = item.url(); |
968 | if (!firstDocumentIndex.isValid()) { |
969 | firstDocumentIndex = index; |
970 | } |
971 | urls << url; |
972 | if (index == currentIndex) { |
973 | currentUrl = url; |
974 | } |
975 | ++count; |
976 | if (count == ViewMainPage::MaxViewCount) { |
977 | break; |
978 | } |
979 | } |
980 | } |
981 | if (urls.isEmpty()) { |
982 | // No image to display |
983 | return; |
984 | } |
985 | if (currentUrl.isEmpty()) { |
986 | // Current index is not selected, or it is not a document: set |
987 | // firstDocumentIndex as current |
988 | GV_RETURN_IF_FAIL(firstDocumentIndex.isValid()); |
989 | d->mThumbnailView->selectionModel()->setCurrentIndex(firstDocumentIndex, QItemSelectionModel::Current); |
990 | currentUrl = urls.first(); |
991 | } |
992 | |
993 | d->mViewMainPage->openUrls(urls, currentUrl); |
994 | } |
995 | |
996 | void MainWindow::goUp() |
997 | { |
998 | if (d->mCurrentMainPageId == BrowseMainPageId) { |
999 | KUrl url = d->mContextManager->currentDirUrl(); |
1000 | url = url.upUrl(); |
1001 | openDirUrl(url); |
1002 | } else { |
1003 | d->mBrowseAction->trigger(); |
1004 | } |
1005 | } |
1006 | |
1007 | void MainWindow::showStartMainPage() |
1008 | { |
1009 | if (d->mCurrentMainPageId != StartMainPageId) { |
1010 | d->saveSideBarConfig(); |
1011 | d->mCurrentMainPageId = StartMainPageId; |
1012 | } |
1013 | d->setActionsDisabledOnStartMainPageEnabled(false); |
1014 | |
1015 | d->mSideBar->hide(); |
1016 | d->mViewStackedWidget->setCurrentWidget(d->mStartMainPage); |
1017 | |
1018 | d->updateActions(); |
1019 | updatePreviousNextActions(); |
1020 | d->mContextManager->setCurrentDirUrl(KUrl()); |
1021 | d->mContextManager->setCurrentUrl(KUrl()); |
1022 | |
1023 | d->autoAssignThumbnailProvider(); |
1024 | } |
1025 | |
1026 | void MainWindow::slotStartMainPageUrlSelected(const KUrl& url) |
1027 | { |
1028 | d->setActionsDisabledOnStartMainPageEnabled(true); |
1029 | |
1030 | if (d->mBrowseAction->isChecked()) { |
1031 | // Silently uncheck the action so that setInitialUrl() does the right thing |
1032 | SignalBlocker blocker(d->mBrowseAction); |
1033 | d->mBrowseAction->setChecked(false); |
1034 | } |
1035 | |
1036 | setInitialUrl(url); |
1037 | } |
1038 | |
1039 | void MainWindow::openDirUrl(const KUrl& url) |
1040 | { |
1041 | const KUrl currentUrl = d->mContextManager->currentDirUrl(); |
1042 | |
1043 | if (url.equals(currentUrl, KUrl::CompareWithoutTrailingSlash)) { |
1044 | return; |
1045 | } |
1046 | |
1047 | if (url.isParentOf(currentUrl)) { |
1048 | // Keep first child between url and currentUrl selected |
1049 | // If currentPath is "/home/user/photos/2008/event" |
1050 | // and wantedPath is "/home/user/photos" |
1051 | // pathToSelect should be "/home/user/photos/2008" |
1052 | |
1053 | // To anyone considering using KUrl::toLocalFile() instead of |
1054 | // KUrl::path() here. Please don't, using KUrl::path() is the right |
1055 | // thing to do here. |
1056 | const QString currentPath = QDir::cleanPath(currentUrl.path(KUrl::RemoveTrailingSlash)); |
1057 | const QString wantedPath = QDir::cleanPath(url.path(KUrl::RemoveTrailingSlash)); |
1058 | const QChar separator('/'); |
1059 | const int slashCount = wantedPath.count(separator); |
1060 | const QString pathToSelect = currentPath.section(separator, 0, slashCount + 1); |
1061 | KUrl urlToSelect = url; |
1062 | urlToSelect.setPath(pathToSelect); |
1063 | d->mContextManager->setUrlToSelect(urlToSelect); |
1064 | } |
1065 | d->mThumbnailProvider->stop(); |
1066 | d->mContextManager->setCurrentDirUrl(url); |
1067 | d->mGvCore->addUrlToRecentFolders(url); |
1068 | d->mViewMainPage->reset(); |
1069 | } |
1070 | |
1071 | void MainWindow::toggleSideBar(bool on) |
1072 | { |
1073 | d->mSideBar->setVisible(on); |
1074 | } |
1075 | |
1076 | void MainWindow::updateToggleSideBarAction() |
1077 | { |
1078 | SignalBlocker blocker(d->mToggleSideBarAction); |
1079 | bool visible = d->mSideBar->isVisible(); |
1080 | d->mToggleSideBarAction->setChecked(visible); |
1081 | |
1082 | QString text; |
1083 | if (QApplication::isRightToLeft()) { |
1084 | text = QString::fromUtf8(visible ? "▮→" : "▮←" ); |
1085 | } else { |
1086 | text = QString::fromUtf8(visible ? "▮←" : "▮→" ); |
1087 | } |
1088 | QString toolTip = visible ? i18nc("@info:tooltip" , "Hide sidebar" ) : i18nc("@info:tooltip" , "Show sidebar" ); |
1089 | |
1090 | QList<QToolButton*> lst; |
1091 | lst << d->mBrowseMainPage->toggleSideBarButton() |
1092 | << d->mViewMainPage->toggleSideBarButton(); |
1093 | Q_FOREACH(QToolButton * button, lst) { |
1094 | button->setText(text); |
1095 | button->setToolTip(toolTip); |
1096 | } |
1097 | } |
1098 | |
1099 | void MainWindow::slotPartCompleted() |
1100 | { |
1101 | d->updateActions(); |
1102 | KUrl url = d->mViewMainPage->url(); |
1103 | // remember the opened file |
1104 | if (!url.isEmpty()) { |
1105 | d->mFileOpenRecentAction->addUrl(url); |
1106 | } |
1107 | if (!KProtocolManager::supportsListing(url)) { |
1108 | return; |
1109 | } |
1110 | |
1111 | KUrl dirUrl = url; |
1112 | dirUrl.setFileName(QString()); |
1113 | if (dirUrl.equals(d->mContextManager->currentDirUrl(), KUrl::CompareWithoutTrailingSlash)) { |
1114 | QModelIndex index = d->mDirModel->indexForUrl(url); |
1115 | QItemSelectionModel* selectionModel = d->mThumbnailView->selectionModel(); |
1116 | if (index.isValid() && !selectionModel->isSelected(index)) { |
1117 | // FIXME: QGV Reactivating this line prevents navigation to prev/next image |
1118 | //selectionModel->select(index, QItemSelectionModel::SelectCurrent); |
1119 | } |
1120 | } else { |
1121 | d->mContextManager->setCurrentDirUrl(dirUrl); |
1122 | d->mGvCore->addUrlToRecentFolders(dirUrl); |
1123 | } |
1124 | } |
1125 | |
1126 | void MainWindow::slotSelectionChanged() |
1127 | { |
1128 | if (d->mCurrentMainPageId == ViewMainPageId) { |
1129 | // The user selected a new file in the thumbnail view, since the |
1130 | // document view is visible, let's show it |
1131 | openSelectedDocuments(); |
1132 | } else { |
1133 | // No document view, we need to load the document to set the undo group |
1134 | // of document factory to the correct QUndoStack |
1135 | QModelIndex index = d->mThumbnailView->currentIndex(); |
1136 | KFileItem item; |
1137 | if (index.isValid()) { |
1138 | item = d->mDirModel->itemForIndex(index); |
1139 | } |
1140 | QUndoGroup* undoGroup = DocumentFactory::instance()->undoGroup(); |
1141 | if (!item.isNull() && !ArchiveUtils::fileItemIsDirOrArchive(item)) { |
1142 | KUrl url = item.url(); |
1143 | Document::Ptr doc = DocumentFactory::instance()->load(url); |
1144 | undoGroup->addStack(doc->undoStack()); |
1145 | undoGroup->setActiveStack(doc->undoStack()); |
1146 | } else { |
1147 | undoGroup->setActiveStack(0); |
1148 | } |
1149 | } |
1150 | |
1151 | // Update UI |
1152 | d->updateActions(); |
1153 | updatePreviousNextActions(); |
1154 | |
1155 | // Start preloading |
1156 | int preloadDelay = d->mCurrentMainPageId == ViewMainPageId ? VIEW_PRELOAD_DELAY : BROWSE_PRELOAD_DELAY; |
1157 | QTimer::singleShot(preloadDelay, this, SLOT(preloadNextUrl())); |
1158 | } |
1159 | |
1160 | void MainWindow::slotCurrentDirUrlChanged(const KUrl& url) |
1161 | { |
1162 | if (url.isValid()) { |
1163 | d->mUrlNavigator->setLocationUrl(url); |
1164 | d->mGoUpAction->setEnabled(url.path() != "/" ); |
1165 | } else { |
1166 | d->mGoUpAction->setEnabled(false); |
1167 | } |
1168 | } |
1169 | |
1170 | void MainWindow::slotDirModelNewItems() |
1171 | { |
1172 | if (d->mThumbnailView->selectionModel()->hasSelection()) { |
1173 | updatePreviousNextActions(); |
1174 | } |
1175 | } |
1176 | |
1177 | void MainWindow::slotDirListerCompleted() |
1178 | { |
1179 | if (d->mStartSlideShowWhenDirListerCompleted) { |
1180 | d->mStartSlideShowWhenDirListerCompleted = false; |
1181 | QTimer::singleShot(0, d->mToggleSlideShowAction, SLOT(trigger())); |
1182 | } |
1183 | if (d->mThumbnailView->selectionModel()->hasSelection()) { |
1184 | updatePreviousNextActions(); |
1185 | } else if (!d->mContextManager->urlToSelect().isValid()) { |
1186 | d->goToFirstDocument(); |
1187 | } |
1188 | d->mThumbnailView->scrollToSelectedIndex(); |
1189 | d->mViewMainPage->thumbnailBar()->scrollToSelectedIndex(); |
1190 | } |
1191 | |
1192 | void MainWindow::goToPrevious() |
1193 | { |
1194 | d->goTo(-1); |
1195 | } |
1196 | |
1197 | void MainWindow::goToNext() |
1198 | { |
1199 | d->goTo(1); |
1200 | } |
1201 | |
1202 | void MainWindow::goToFirst() |
1203 | { |
1204 | d->goToFirstDocument(); |
1205 | } |
1206 | |
1207 | void MainWindow::goToLast() |
1208 | { |
1209 | d->goToLastDocument(); |
1210 | } |
1211 | |
1212 | void MainWindow::goToUrl(const KUrl& url) |
1213 | { |
1214 | if (d->mCurrentMainPageId == ViewMainPageId) { |
1215 | d->mViewMainPage->openUrl(url); |
1216 | } |
1217 | KUrl dirUrl = url; |
1218 | dirUrl.setFileName("" ); |
1219 | if (!dirUrl.equals(d->mContextManager->currentDirUrl(), KUrl::CompareWithoutTrailingSlash)) { |
1220 | d->mContextManager->setCurrentDirUrl(dirUrl); |
1221 | d->mGvCore->addUrlToRecentFolders(dirUrl); |
1222 | } |
1223 | d->mContextManager->setUrlToSelect(url); |
1224 | } |
1225 | |
1226 | void MainWindow::updatePreviousNextActions() |
1227 | { |
1228 | bool hasPrevious; |
1229 | bool hasNext; |
1230 | QModelIndex currentIndex = d->mContextManager->selectionModel()->currentIndex(); |
1231 | if (currentIndex.isValid() && !d->indexIsDirOrArchive(currentIndex)) { |
1232 | int row = currentIndex.row(); |
1233 | QModelIndex prevIndex = d->mDirModel->index(row - 1, 0); |
1234 | QModelIndex nextIndex = d->mDirModel->index(row + 1, 0); |
1235 | hasPrevious = prevIndex.isValid() && !d->indexIsDirOrArchive(prevIndex); |
1236 | hasNext = nextIndex.isValid() && !d->indexIsDirOrArchive(nextIndex); |
1237 | } else { |
1238 | hasPrevious = false; |
1239 | hasNext = false; |
1240 | } |
1241 | |
1242 | d->mGoToPreviousAction->setEnabled(hasPrevious); |
1243 | d->mGoToNextAction->setEnabled(hasNext); |
1244 | d->mGoToFirstAction->setEnabled(hasPrevious); |
1245 | d->mGoToLastAction->setEnabled(hasNext); |
1246 | } |
1247 | |
1248 | void MainWindow::leaveFullScreen() |
1249 | { |
1250 | if (d->mFullScreenAction->isChecked()) { |
1251 | d->mFullScreenAction->trigger(); |
1252 | } |
1253 | } |
1254 | |
1255 | void MainWindow::toggleFullScreen(bool checked) |
1256 | { |
1257 | setUpdatesEnabled(false); |
1258 | d->saveSideBarConfig(); |
1259 | if (checked) { |
1260 | // Save MainWindow config now, this way if we quit while in |
1261 | // fullscreen, we are sure latest MainWindow changes are remembered. |
1262 | saveMainWindowSettings(autoSaveConfigGroup()); |
1263 | resetAutoSaveSettings(); |
1264 | |
1265 | // Save state |
1266 | d->mStateBeforeFullScreen.mToolBarVisible = toolBar()->isVisible(); |
1267 | d->mStateBeforeFullScreen.mWindowState = windowState(); |
1268 | |
1269 | // Go full screen |
1270 | setWindowState(windowState() | Qt::WindowFullScreen); |
1271 | menuBar()->hide(); |
1272 | toolBar()->hide(); |
1273 | |
1274 | QApplication::setPalette(d->mGvCore->palette(GvCore::FullScreenPalette)); |
1275 | d->mFullScreenContent->setFullScreenMode(true); |
1276 | d->mBrowseMainPage->setFullScreenMode(true); |
1277 | d->mViewMainPage->setFullScreenMode(true); |
1278 | d->mSaveBar->setFullScreenMode(true); |
1279 | d->setScreenSaverEnabled(false); |
1280 | |
1281 | // HACK: Only load sidebar config now, because it looks at |
1282 | // ViewMainPage fullScreenMode property to determine the sidebar |
1283 | // config group. |
1284 | d->loadSideBarConfig(); |
1285 | } else { |
1286 | setAutoSaveSettings(); |
1287 | |
1288 | // Back to normal |
1289 | QApplication::setPalette(d->mGvCore->palette(GvCore::NormalPalette)); |
1290 | d->mFullScreenContent->setFullScreenMode(false); |
1291 | d->mBrowseMainPage->setFullScreenMode(false); |
1292 | d->mViewMainPage->setFullScreenMode(false); |
1293 | d->mSlideShow->stop(); |
1294 | d->mSaveBar->setFullScreenMode(false); |
1295 | setWindowState(d->mStateBeforeFullScreen.mWindowState); |
1296 | menuBar()->setVisible(d->mShowMenuBarAction->isChecked()); |
1297 | toolBar()->setVisible(d->mStateBeforeFullScreen.mToolBarVisible); |
1298 | |
1299 | d->setScreenSaverEnabled(true); |
1300 | |
1301 | // Keep this after mViewMainPage->setFullScreenMode(false). |
1302 | // See call to loadSideBarConfig() above. |
1303 | d->loadSideBarConfig(); |
1304 | |
1305 | // See resizeEvent |
1306 | d->mFullScreenLeftAt = QDateTime::currentDateTime(); |
1307 | } |
1308 | setUpdatesEnabled(true); |
1309 | d->autoAssignThumbnailProvider(); |
1310 | } |
1311 | |
1312 | void MainWindow::saveCurrent() |
1313 | { |
1314 | d->mGvCore->save(d->mContextManager->currentUrl()); |
1315 | } |
1316 | |
1317 | void MainWindow::saveCurrentAs() |
1318 | { |
1319 | d->mGvCore->saveAs(d->mContextManager->currentUrl()); |
1320 | } |
1321 | |
1322 | void MainWindow::reload() |
1323 | { |
1324 | if (d->mCurrentMainPageId == ViewMainPageId) { |
1325 | d->mViewMainPage->reload(); |
1326 | } else { |
1327 | d->mBrowseMainPage->reload(); |
1328 | } |
1329 | } |
1330 | |
1331 | void MainWindow::openFile() |
1332 | { |
1333 | KUrl dirUrl = d->mContextManager->currentDirUrl(); |
1334 | |
1335 | KFileDialog dialog(dirUrl, QString(), this); |
1336 | dialog.setCaption(i18nc("@title:window" , "Open Image" )); |
1337 | const QStringList mimeFilter = MimeTypeUtils::imageMimeTypes(); |
1338 | dialog.setMimeFilter(mimeFilter); |
1339 | dialog.setOperationMode(KFileDialog::Opening); |
1340 | if (!dialog.exec()) { |
1341 | return; |
1342 | } |
1343 | |
1344 | openUrl(dialog.selectedUrl()); |
1345 | } |
1346 | |
1347 | void MainWindow::openUrl(const KUrl& url) |
1348 | { |
1349 | d->setActionsDisabledOnStartMainPageEnabled(true); |
1350 | d->mViewAction->trigger(); |
1351 | d->mViewMainPage->openUrl(url); |
1352 | d->mContextManager->setUrlToSelect(url); |
1353 | } |
1354 | |
1355 | void MainWindow::showDocumentInFullScreen(const KUrl& url) |
1356 | { |
1357 | d->mViewMainPage->openUrl(url); |
1358 | d->mContextManager->setUrlToSelect(url); |
1359 | d->mFullScreenAction->trigger(); |
1360 | } |
1361 | |
1362 | void MainWindow::toggleSlideShow() |
1363 | { |
1364 | if (d->mSlideShow->isRunning()) { |
1365 | d->mSlideShow->stop(); |
1366 | } else { |
1367 | if (!d->mViewAction->isChecked()) { |
1368 | d->mViewAction->trigger(); |
1369 | } |
1370 | if (!d->mFullScreenAction->isChecked()) { |
1371 | d->mFullScreenAction->trigger(); |
1372 | } |
1373 | QList<KUrl> list; |
1374 | for (int pos = 0; pos < d->mDirModel->rowCount(); ++pos) { |
1375 | QModelIndex index = d->mDirModel->index(pos, 0); |
1376 | KFileItem item = d->mDirModel->itemForIndex(index); |
1377 | MimeTypeUtils::Kind kind = MimeTypeUtils::fileItemKind(item); |
1378 | switch (kind) { |
1379 | case MimeTypeUtils::KIND_SVG_IMAGE: |
1380 | case MimeTypeUtils::KIND_RASTER_IMAGE: |
1381 | case MimeTypeUtils::KIND_VIDEO: |
1382 | list << item.url(); |
1383 | break; |
1384 | default: |
1385 | break; |
1386 | } |
1387 | } |
1388 | d->mSlideShow->start(list); |
1389 | } |
1390 | updateSlideShowAction(); |
1391 | } |
1392 | |
1393 | void MainWindow::updateSlideShowAction() |
1394 | { |
1395 | if (d->mSlideShow->isRunning()) { |
1396 | d->mToggleSlideShowAction->setText(i18n("Stop Slideshow" )); |
1397 | d->mToggleSlideShowAction->setIcon(KIcon("media-playback-pause" )); |
1398 | } else { |
1399 | d->mToggleSlideShowAction->setText(i18n("Start Slideshow" )); |
1400 | d->mToggleSlideShowAction->setIcon(KIcon("media-playback-start" )); |
1401 | } |
1402 | } |
1403 | |
1404 | bool MainWindow::queryClose() |
1405 | { |
1406 | saveConfig(); |
1407 | d->saveSideBarConfig(); |
1408 | QList<KUrl> list = DocumentFactory::instance()->modifiedDocumentList(); |
1409 | if (list.size() == 0) { |
1410 | return true; |
1411 | } |
1412 | |
1413 | KGuiItem yes(i18n("Save All Changes" ), "document-save-all" ); |
1414 | KGuiItem no(i18n("Discard Changes" )); |
1415 | QString msg = i18np("One image has been modified." , "%1 images have been modified." , list.size()) |
1416 | + '\n' |
1417 | + i18n("If you quit now, your changes will be lost." ); |
1418 | int answer = KMessageBox::warningYesNoCancel( |
1419 | this, |
1420 | msg, |
1421 | QString() /* caption */, |
1422 | yes, |
1423 | no); |
1424 | |
1425 | switch (answer) { |
1426 | case KMessageBox::Yes: |
1427 | d->mGvCore->saveAll(); |
1428 | // We need to wait a bit because the DocumentFactory is notified about |
1429 | // saved documents through a queued connection. |
1430 | qApp->processEvents(); |
1431 | return DocumentFactory::instance()->modifiedDocumentList().isEmpty(); |
1432 | |
1433 | case KMessageBox::No: |
1434 | return true; |
1435 | |
1436 | default: // cancel |
1437 | return false; |
1438 | } |
1439 | } |
1440 | |
1441 | void MainWindow::showConfigDialog() |
1442 | { |
1443 | ConfigDialog dialog(this); |
1444 | connect(&dialog, SIGNAL(settingsChanged(QString)), SLOT(loadConfig())); |
1445 | dialog.exec(); |
1446 | } |
1447 | |
1448 | void MainWindow::toggleMenuBar() |
1449 | { |
1450 | if (!d->mFullScreenAction->isChecked()) { |
1451 | menuBar()->setVisible(d->mShowMenuBarAction->isChecked()); |
1452 | } |
1453 | } |
1454 | |
1455 | void MainWindow::loadConfig() |
1456 | { |
1457 | d->mDirModel->setBlackListedExtensions(GwenviewConfig::blackListedExtensions()); |
1458 | d->mDirModel->adjustKindFilter(MimeTypeUtils::KIND_VIDEO, GwenviewConfig::listVideos()); |
1459 | |
1460 | d->mFileOpenRecentAction->loadEntries(KConfigGroup(KGlobal::config(), "Recent Files" )); |
1461 | d->mStartMainPage->loadConfig(); |
1462 | d->mViewMainPage->loadConfig(); |
1463 | d->mBrowseMainPage->loadConfig(); |
1464 | } |
1465 | |
1466 | void MainWindow::saveConfig() |
1467 | { |
1468 | d->mFileOpenRecentAction->saveEntries(KConfigGroup(KGlobal::config(), "Recent Files" )); |
1469 | d->mViewMainPage->saveConfig(); |
1470 | d->mBrowseMainPage->saveConfig(); |
1471 | } |
1472 | |
1473 | void MainWindow::print() |
1474 | { |
1475 | if (!d->mContextManager->currentUrlIsRasterImage()) { |
1476 | return; |
1477 | } |
1478 | |
1479 | Document::Ptr doc = DocumentFactory::instance()->load(d->mContextManager->currentUrl()); |
1480 | PrintHelper printHelper(this); |
1481 | printHelper.print(doc); |
1482 | } |
1483 | |
1484 | void MainWindow::preloadNextUrl() |
1485 | { |
1486 | static bool disablePreload = qgetenv("GV_MAX_UNREFERENCED_IMAGES" ) == "0" ; |
1487 | if (disablePreload) { |
1488 | kDebug() << "Preloading disabled" ; |
1489 | return; |
1490 | } |
1491 | QItemSelection selection = d->mThumbnailView->selectionModel()->selection(); |
1492 | if (selection.size() != 1) { |
1493 | return; |
1494 | } |
1495 | |
1496 | QModelIndexList indexList = selection.indexes(); |
1497 | if (indexList.isEmpty()) { |
1498 | return; |
1499 | } |
1500 | |
1501 | QModelIndex index = indexList.at(0); |
1502 | if (!index.isValid()) { |
1503 | return; |
1504 | } |
1505 | |
1506 | if (d->mCurrentMainPageId == ViewMainPageId) { |
1507 | // If we are in view mode, preload the next url, otherwise preload the |
1508 | // selected one |
1509 | int offset = d->mPreloadDirectionIsForward ? 1 : -1; |
1510 | index = d->mDirModel->sibling(index.row() + offset, index.column(), index); |
1511 | if (!index.isValid()) { |
1512 | return; |
1513 | } |
1514 | } |
1515 | |
1516 | KFileItem item = d->mDirModel->itemForIndex(index); |
1517 | if (!ArchiveUtils::fileItemIsDirOrArchive(item)) { |
1518 | KUrl url = item.url(); |
1519 | if (url.isLocalFile()) { |
1520 | QSize size = d->mViewStackedWidget->size(); |
1521 | d->mPreloader->preload(url, size); |
1522 | } |
1523 | } |
1524 | } |
1525 | |
1526 | QSize MainWindow::sizeHint() const |
1527 | { |
1528 | return KXmlGuiWindow::sizeHint().expandedTo(QSize(750, 500)); |
1529 | } |
1530 | |
1531 | void MainWindow::showEvent(QShowEvent *event) |
1532 | { |
1533 | // We need to delay initializing the action state until the menu bar has |
1534 | // been initialized, that's why it's done only in the showEvent() |
1535 | d->mShowMenuBarAction->setChecked(menuBar()->isVisible()); |
1536 | KXmlGuiWindow::showEvent(event); |
1537 | } |
1538 | |
1539 | void MainWindow::resizeEvent(QResizeEvent* event) |
1540 | { |
1541 | KXmlGuiWindow::resizeEvent(event); |
1542 | // This is a small hack to execute code after leaving fullscreen, and after |
1543 | // the window has been resized back to its former size. |
1544 | if (d->mFullScreenLeftAt.isValid() && d->mFullScreenLeftAt.secsTo(QDateTime::currentDateTime()) < 2) { |
1545 | if (d->mCurrentMainPageId == BrowseMainPageId) { |
1546 | d->mThumbnailView->scrollToSelectedIndex(); |
1547 | } |
1548 | d->mFullScreenLeftAt = QDateTime(); |
1549 | } |
1550 | } |
1551 | |
1552 | void MainWindow::setDistractionFreeMode(bool value) |
1553 | { |
1554 | d->mFullScreenContent->setDistractionFreeMode(value); |
1555 | } |
1556 | |
1557 | void MainWindow::saveProperties(KConfigGroup& group) |
1558 | { |
1559 | group.writeEntry(SESSION_CURRENT_PAGE_KEY, int(d->mCurrentMainPageId)); |
1560 | group.writeEntry(SESSION_URL_KEY, d->mContextManager->currentUrl()); |
1561 | } |
1562 | |
1563 | void MainWindow::readProperties(const KConfigGroup& group) |
1564 | { |
1565 | MainPageId pageId = MainPageId(group.readEntry(SESSION_CURRENT_PAGE_KEY, int(StartMainPageId))); |
1566 | if (pageId == StartMainPageId) { |
1567 | d->mCurrentMainPageId = StartMainPageId; |
1568 | showStartMainPage(); |
1569 | } else if (pageId == BrowseMainPageId) { |
1570 | d->mBrowseAction->trigger(); |
1571 | } else { |
1572 | d->mViewAction->trigger(); |
1573 | } |
1574 | KUrl url = group.readEntry(SESSION_URL_KEY, KUrl()); |
1575 | if (!url.isValid()) { |
1576 | kWarning() << "Invalid url!" ; |
1577 | return; |
1578 | } |
1579 | goToUrl(url); |
1580 | } |
1581 | |
1582 | void MainWindow::showFirstDocumentReached() |
1583 | { |
1584 | if (d->mCurrentMainPageId != ViewMainPageId) { |
1585 | return; |
1586 | } |
1587 | HudButtonBox* dlg = new HudButtonBox; |
1588 | dlg->setText(i18n("You reached the first document, what do you want to do?" )); |
1589 | dlg->addButton(i18n("Stay There" )); |
1590 | dlg->addAction(d->mGoToLastAction, i18n("Go to the Last Document" )); |
1591 | dlg->addAction(d->mBrowseAction, i18n("Go Back to the Document List" )); |
1592 | dlg->addCountDown(15000); |
1593 | d->mViewMainPage->showMessageWidget(dlg, Qt::AlignCenter); |
1594 | } |
1595 | |
1596 | void MainWindow::showLastDocumentReached() |
1597 | { |
1598 | if (d->mCurrentMainPageId != ViewMainPageId) { |
1599 | return; |
1600 | } |
1601 | HudButtonBox* dlg = new HudButtonBox; |
1602 | dlg->setText(i18n("You reached the last document, what do you want to do?" )); |
1603 | dlg->addButton(i18n("Stay There" )); |
1604 | dlg->addAction(d->mGoToFirstAction, i18n("Go to the First Document" )); |
1605 | dlg->addAction(d->mBrowseAction, i18n("Go Back to the Document List" )); |
1606 | dlg->addCountDown(15000); |
1607 | d->mViewMainPage->showMessageWidget(dlg, Qt::AlignCenter); |
1608 | } |
1609 | |
1610 | } // namespace |
1611 | |