1 /*
2 * Copyright (C) 2013-2015 Ofer Kashayov <oferkv@live.com>
3 * This file is part of Phototonic Image Viewer.
4 *
5 * Phototonic is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * Phototonic 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 Phototonic. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "DirCompleter.h"
20 #include "Phototonic.h"
21 #include "Settings.h"
22 #include "CopyMoveDialog.h"
23 #include "ResizeDialog.h"
24 #include "CropDialog.h"
25 #include "ColorsDialog.h"
26 #include "ExternalAppsDialog.h"
27 #include "ProgressDialog.h"
28 #include "ImagePreview.h"
29 #include "FileListWidget.h"
30 #include "RenameDialog.h"
31 #include "Trashcan.h"
32 #include "MessageBox.h"
33
Phototonic(QStringList argumentsList,int filesStartAt,QWidget * parent)34 Phototonic::Phototonic(QStringList argumentsList, int filesStartAt, QWidget *parent) : QMainWindow(parent) {
35 Settings::appSettings = new QSettings("phototonic", "phototonic");
36 setDockOptions(QMainWindow::AllowNestedDocks);
37 readSettings();
38 createThumbsViewer();
39 createActions();
40 createMenus();
41 createToolBars();
42 createStatusBar();
43 createFileSystemDock();
44 createBookmarksDock();
45 createImagePreviewDock();
46 createImageTagsDock();
47 createImageViewer();
48 updateExternalApps();
49 loadShortcuts();
50 setupDocks();
51
52 connect(qApp, SIGNAL(focusChanged(QWidget * , QWidget * )), this, SLOT(updateActions()));
53
54 restoreGeometry(Settings::appSettings->value(Settings::optionGeometry).toByteArray());
55 restoreState(Settings::appSettings->value(Settings::optionWindowState).toByteArray());
56 defaultApplicationIcon = QIcon(":/images/phototonic.png");
57 setWindowIcon(defaultApplicationIcon);
58
59 stackedLayout = new QStackedLayout;
60 QWidget *stackedLayoutWidget = new QWidget;
61 stackedLayout->addWidget(thumbsViewer);
62 stackedLayout->addWidget(imageViewer);
63 stackedLayoutWidget->setLayout(stackedLayout);
64 setCentralWidget(stackedLayoutWidget);
65 processStartupArguments(argumentsList, filesStartAt);
66
67 copyMoveToDialog = nullptr;
68 colorsDialog = nullptr;
69 cropDialog = nullptr;
70 initComplete = true;
71 thumbsViewer->isBusy = false;
72 currentHistoryIdx = -1;
73 needHistoryRecord = true;
74 interfaceDisabled = false;
75
76 refreshThumbs(true);
77 if (Settings::layoutMode == ThumbViewWidget) {
78 thumbsViewer->setFocus(Qt::OtherFocusReason);
79 }
80 }
81
processStartupArguments(QStringList argumentsList,int filesStartAt)82 void Phototonic::processStartupArguments(QStringList argumentsList, int filesStartAt) {
83 if (argumentsList.size() > filesStartAt) {
84 QFileInfo firstArgument(argumentsList.at(filesStartAt));
85 if (firstArgument.isDir()) {
86 Settings::currentDirectory = argumentsList.at(filesStartAt);
87 } else if (argumentsList.size() > filesStartAt + 1) {
88 loadStartupFileList(argumentsList, filesStartAt);
89 return;
90 } else {
91 Settings::currentDirectory = firstArgument.absolutePath();
92 QString cliFileName = Settings::currentDirectory + QDir::separator() + firstArgument.fileName();
93 loadImageFromCliArguments(cliFileName);
94 QTimer::singleShot(1000, this, SLOT(updateIndexByViewerImage()));
95 }
96 } else {
97 if (Settings::startupDir == Settings::SpecifiedDir) {
98 Settings::currentDirectory = Settings::specifiedStartDir;
99 } else if (Settings::startupDir == Settings::RememberLastDir) {
100 Settings::currentDirectory = Settings::appSettings->value(Settings::optionLastDir).toString();
101 }
102 }
103 selectCurrentViewDir();
104 }
105
getDefaultWindowIcon()106 QIcon &Phototonic::getDefaultWindowIcon() {
107 return defaultApplicationIcon;
108 }
109
loadStartupFileList(QStringList argumentsList,int filesStartAt)110 void Phototonic::loadStartupFileList(QStringList argumentsList, int filesStartAt) {
111 Settings::filesList.clear();
112 for (int i = filesStartAt; i < argumentsList.size(); i++) {
113 QFile currentFileFullPath(argumentsList[i]);
114 QFileInfo currentFileInfo(currentFileFullPath);
115
116 if (!Settings::filesList.contains(currentFileInfo.absoluteFilePath())) {
117 Settings::filesList << currentFileInfo.absoluteFilePath();
118 }
119 }
120 fileSystemTree->clearSelection();
121 fileListWidget->setItemSelected(fileListWidget->itemAt(0, 0), true);
122 Settings::isFileListLoaded = true;
123 }
124
event(QEvent * event)125 bool Phototonic::event(QEvent *event) {
126 if (event->type() == QEvent::ActivationChange ||
127 (Settings::layoutMode == ThumbViewWidget && event->type() == QEvent::MouseButtonRelease)) {
128 thumbsViewer->loadVisibleThumbs();
129 }
130
131 return QMainWindow::event(event);
132 }
133
createThumbsViewer()134 void Phototonic::createThumbsViewer() {
135 metadataCache = new MetadataCache;
136 thumbsViewer = new ThumbsViewer(this, metadataCache);
137 thumbsViewer->thumbsSortFlags = (QDir::SortFlags) Settings::appSettings->value(
138 Settings::optionThumbsSortFlags).toInt();
139 thumbsViewer->thumbsSortFlags |= QDir::IgnoreCase;
140
141 connect(thumbsViewer->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
142 this, SLOT(updateActions()));
143
144 imageInfoDock = new QDockWidget(tr("Image Info"), this);
145 imageInfoDock->setObjectName("Image Info");
146 imageInfoDock->setWidget(thumbsViewer->infoView);
147 connect(imageInfoDock->toggleViewAction(), SIGNAL(triggered()), this, SLOT(setImageInfoDockVisibility()));
148 connect(imageInfoDock, SIGNAL(visibilityChanged(bool)), this, SLOT(setImageInfoDockVisibility()));
149 }
150
addMenuSeparator(QWidget * widget)151 void Phototonic::addMenuSeparator(QWidget *widget) {
152 QAction *separator = new QAction(this);
153 separator->setSeparator(true);
154 widget->addAction(separator);
155 }
156
createImageViewer()157 void Phototonic::createImageViewer() {
158 imageViewer = new ImageViewer(this, metadataCache);
159 connect(saveAction, SIGNAL(triggered()), imageViewer, SLOT(saveImage()));
160 connect(saveAsAction, SIGNAL(triggered()), imageViewer, SLOT(saveImageAs()));
161 connect(copyImageAction, SIGNAL(triggered()), imageViewer, SLOT(copyImage()));
162 connect(pasteImageAction, SIGNAL(triggered()), imageViewer, SLOT(pasteImage()));
163 connect(cropToSelectionAction, SIGNAL(triggered()), imageViewer, SLOT(cropToSelection()));
164 imageViewer->ImagePopUpMenu = new QMenu();
165
166 // Widget actions
167 imageViewer->addAction(slideShowAction);
168 imageViewer->addAction(nextImageAction);
169 imageViewer->addAction(prevImageAction);
170 imageViewer->addAction(firstImageAction);
171 imageViewer->addAction(lastImageAction);
172 imageViewer->addAction(randomImageAction);
173 imageViewer->addAction(zoomInAction);
174 imageViewer->addAction(zoomOutAction);
175 imageViewer->addAction(origZoomAction);
176 imageViewer->addAction(resetZoomAction);
177 imageViewer->addAction(rotateRightAction);
178 imageViewer->addAction(rotateLeftAction);
179 imageViewer->addAction(freeRotateRightAction);
180 imageViewer->addAction(freeRotateLeftAction);
181 imageViewer->addAction(flipHorizontalAction);
182 imageViewer->addAction(flipVerticalAction);
183 imageViewer->addAction(cropAction);
184 imageViewer->addAction(cropToSelectionAction);
185 imageViewer->addAction(resizeAction);
186 imageViewer->addAction(saveAction);
187 imageViewer->addAction(saveAsAction);
188 imageViewer->addAction(copyImageAction);
189 imageViewer->addAction(pasteImageAction);
190 imageViewer->addAction(deleteAction);
191 imageViewer->addAction(deletePermanentlyAction);
192 imageViewer->addAction(renameAction);
193 imageViewer->addAction(CloseImageAction);
194 imageViewer->addAction(fullScreenAction);
195 imageViewer->addAction(settingsAction);
196 imageViewer->addAction(mirrorDisabledAction);
197 imageViewer->addAction(mirrorDualAction);
198 imageViewer->addAction(mirrorTripleAction);
199 imageViewer->addAction(mirrorDualVerticalAction);
200 imageViewer->addAction(mirrorQuadAction);
201 imageViewer->addAction(keepTransformAction);
202 imageViewer->addAction(keepZoomAction);
203 imageViewer->addAction(refreshAction);
204 imageViewer->addAction(colorsAction);
205 imageViewer->addAction(moveRightAction);
206 imageViewer->addAction(moveLeftAction);
207 imageViewer->addAction(moveUpAction);
208 imageViewer->addAction(moveDownAction);
209 imageViewer->addAction(showClipboardAction);
210 imageViewer->addAction(copyToAction);
211 imageViewer->addAction(moveToAction);
212 imageViewer->addAction(resizeAction);
213 imageViewer->addAction(viewImageAction);
214 imageViewer->addAction(exitAction);
215 imageViewer->addAction(showViewerToolbarAction);
216 imageViewer->addAction(externalAppsAction);
217
218 // Actions
219 addMenuSeparator(imageViewer->ImagePopUpMenu);
220 imageViewer->ImagePopUpMenu->addAction(nextImageAction);
221 imageViewer->ImagePopUpMenu->addAction(prevImageAction);
222 imageViewer->ImagePopUpMenu->addAction(firstImageAction);
223 imageViewer->ImagePopUpMenu->addAction(lastImageAction);
224 imageViewer->ImagePopUpMenu->addAction(randomImageAction);
225 imageViewer->ImagePopUpMenu->addAction(slideShowAction);
226
227 addMenuSeparator(imageViewer->ImagePopUpMenu);
228 zoomSubMenu = new QMenu(tr("Zoom"));
229 zoomSubMenuAction = new QAction(tr("Zoom"), this);
230 zoomSubMenuAction->setIcon(QIcon::fromTheme("edit-find", QIcon(":/images/zoom.png")));
231 zoomSubMenuAction->setMenu(zoomSubMenu);
232 imageViewer->ImagePopUpMenu->addAction(zoomSubMenuAction);
233 zoomSubMenu->addAction(zoomInAction);
234 zoomSubMenu->addAction(zoomOutAction);
235 zoomSubMenu->addAction(origZoomAction);
236 zoomSubMenu->addAction(resetZoomAction);
237 addMenuSeparator(zoomSubMenu);
238 zoomSubMenu->addAction(keepZoomAction);
239
240 MirroringSubMenu = new QMenu(tr("Mirroring"));
241 mirrorSubMenuAction = new QAction(tr("Mirroring"), this);
242 mirrorSubMenuAction->setMenu(MirroringSubMenu);
243 mirroringActionGroup = new QActionGroup(this);
244 mirroringActionGroup->addAction(mirrorDisabledAction);
245 mirroringActionGroup->addAction(mirrorDualAction);
246 mirroringActionGroup->addAction(mirrorTripleAction);
247 mirroringActionGroup->addAction(mirrorDualVerticalAction);
248 mirroringActionGroup->addAction(mirrorQuadAction);
249 MirroringSubMenu->addActions(mirroringActionGroup->actions());
250
251 transformSubMenu = new QMenu(tr("Transform"));
252 transformSubMenuAction = new QAction(tr("Transform"), this);
253 transformSubMenuAction->setMenu(transformSubMenu);
254 imageViewer->ImagePopUpMenu->addAction(resizeAction);
255 imageViewer->ImagePopUpMenu->addAction(cropToSelectionAction);
256 imageViewer->ImagePopUpMenu->addAction(transformSubMenuAction);
257 transformSubMenu->addAction(colorsAction);
258 transformSubMenu->addAction(rotateRightAction);
259 transformSubMenu->addAction(rotateLeftAction);
260 transformSubMenu->addAction(freeRotateRightAction);
261 transformSubMenu->addAction(freeRotateLeftAction);
262 transformSubMenu->addAction(flipHorizontalAction);
263 transformSubMenu->addAction(flipVerticalAction);
264 transformSubMenu->addAction(cropAction);
265
266 addMenuSeparator(transformSubMenu);
267 transformSubMenu->addAction(keepTransformAction);
268 imageViewer->ImagePopUpMenu->addAction(mirrorSubMenuAction);
269
270 addMenuSeparator(imageViewer->ImagePopUpMenu);
271 imageViewer->ImagePopUpMenu->addAction(copyToAction);
272 imageViewer->ImagePopUpMenu->addAction(moveToAction);
273 imageViewer->ImagePopUpMenu->addAction(saveAction);
274 imageViewer->ImagePopUpMenu->addAction(saveAsAction);
275 imageViewer->ImagePopUpMenu->addAction(renameAction);
276 imageViewer->ImagePopUpMenu->addAction(deleteAction);
277 imageViewer->ImagePopUpMenu->addAction(deletePermanentlyAction);
278 imageViewer->ImagePopUpMenu->addAction(openWithMenuAction);
279
280 addMenuSeparator(imageViewer->ImagePopUpMenu);
281 viewSubMenu = new QMenu(tr("View"));
282 viewSubMenuAction = new QAction(tr("View"), this);
283 viewSubMenuAction->setMenu(viewSubMenu);
284 imageViewer->ImagePopUpMenu->addAction(viewSubMenuAction);
285 viewSubMenu->addAction(fullScreenAction);
286 viewSubMenu->addAction(showClipboardAction);
287 viewSubMenu->addAction(showViewerToolbarAction);
288 viewSubMenu->addAction(refreshAction);
289 imageViewer->ImagePopUpMenu->addAction(copyImageAction);
290 imageViewer->ImagePopUpMenu->addAction(pasteImageAction);
291 imageViewer->ImagePopUpMenu->addAction(CloseImageAction);
292 imageViewer->ImagePopUpMenu->addAction(exitAction);
293
294 addMenuSeparator(imageViewer->ImagePopUpMenu);
295 imageViewer->ImagePopUpMenu->addAction(settingsAction);
296
297 imageViewer->setContextMenuPolicy(Qt::DefaultContextMenu);
298 Settings::isFullScreen = Settings::appSettings->value(Settings::optionFullScreenMode).toBool();
299 fullScreenAction->setChecked(Settings::isFullScreen);
300 thumbsViewer->imagePreview->setImageViewer(imageViewer);
301 }
302
createActions()303 void Phototonic::createActions() {
304 thumbsGoToTopAction = new QAction(tr("Top"), this);
305 thumbsGoToTopAction->setObjectName("thumbsGoTop");
306 thumbsGoToTopAction->setIcon(QIcon::fromTheme("go-top", QIcon(":/images/top.png")));
307 connect(thumbsGoToTopAction, SIGNAL(triggered()), this, SLOT(goTop()));
308
309 thumbsGoToBottomAction = new QAction(tr("Bottom"), this);
310 thumbsGoToBottomAction->setObjectName("thumbsGoBottom");
311 thumbsGoToBottomAction->setIcon(QIcon::fromTheme("go-bottom", QIcon(":/images/bottom.png")));
312 connect(thumbsGoToBottomAction, SIGNAL(triggered()), this, SLOT(goBottom()));
313
314 CloseImageAction = new QAction(tr("Close Viewer"), this);
315 CloseImageAction->setObjectName("closeImage");
316 connect(CloseImageAction, SIGNAL(triggered()), this, SLOT(hideViewer()));
317
318 fullScreenAction = new QAction(tr("Full Screen"), this);
319 fullScreenAction->setObjectName("fullScreen");
320 fullScreenAction->setCheckable(true);
321 connect(fullScreenAction, SIGNAL(triggered()), this, SLOT(toggleFullScreen()));
322
323 settingsAction = new QAction(tr("Preferences"), this);
324 settingsAction->setObjectName("settings");
325 settingsAction->setIcon(QIcon::fromTheme("preferences-system", QIcon(":/images/settings.png")));
326 connect(settingsAction, SIGNAL(triggered()), this, SLOT(showSettings()));
327
328 exitAction = new QAction(tr("Exit"), this);
329 exitAction->setObjectName("exit");
330 connect(exitAction, SIGNAL(triggered()), this, SLOT(close()));
331
332 thumbsZoomInAction = new QAction(tr("Enlarge Thumbnails"), this);
333 thumbsZoomInAction->setObjectName("thumbsZoomIn");
334 connect(thumbsZoomInAction, SIGNAL(triggered()), this, SLOT(thumbsZoomIn()));
335 thumbsZoomInAction->setIcon(QIcon::fromTheme("zoom-in", QIcon(":/images/zoom_in.png")));
336 if (thumbsViewer->thumbSize == THUMB_SIZE_MAX) {
337 thumbsZoomInAction->setEnabled(false);
338 }
339
340 thumbsZoomOutAction = new QAction(tr("Shrink Thumbnails"), this);
341 thumbsZoomOutAction->setObjectName("thumbsZoomOut");
342 connect(thumbsZoomOutAction, SIGNAL(triggered()), this, SLOT(thumbsZoomOut()));
343 thumbsZoomOutAction->setIcon(QIcon::fromTheme("zoom-out", QIcon(":/images/zoom_out.png")));
344 if (thumbsViewer->thumbSize == THUMB_SIZE_MIN) {
345 thumbsZoomOutAction->setEnabled(false);
346 }
347
348 cutAction = new QAction(tr("Cut"), this);
349 cutAction->setObjectName("cut");
350 cutAction->setIcon(QIcon::fromTheme("edit-cut", QIcon(":/images/cut.png")));
351 connect(cutAction, SIGNAL(triggered()), this, SLOT(cutThumbs()));
352 cutAction->setEnabled(false);
353
354 copyAction = new QAction(tr("Copy"), this);
355 copyAction->setObjectName("copy");
356 copyAction->setIcon(QIcon::fromTheme("edit-copy", QIcon(":/images/copy.png")));
357 connect(copyAction, SIGNAL(triggered()), this, SLOT(copyThumbs()));
358 copyAction->setEnabled(false);
359
360 copyToAction = new QAction(tr("Copy to..."), this);
361 copyToAction->setObjectName("copyTo");
362 connect(copyToAction, SIGNAL(triggered()), this, SLOT(copyImagesTo()));
363
364 moveToAction = new QAction(tr("Move to..."), this);
365 moveToAction->setObjectName("moveTo");
366 connect(moveToAction, SIGNAL(triggered()), this, SLOT(moveImagesTo()));
367
368 deleteAction = new QAction(tr("Move to Trash"), this);
369 deleteAction->setObjectName("moveToTrash");
370 deleteAction->setIcon(style()->standardIcon(QStyle::SP_TrashIcon));
371 connect(deleteAction, SIGNAL(triggered()), this, SLOT(deleteOperation()));
372
373 deletePermanentlyAction = new QAction(tr("Delete"), this);
374 deletePermanentlyAction->setObjectName("delete");
375 deletePermanentlyAction->setIcon(QIcon::fromTheme("edit-delete", QIcon(":/images/delete.png")));
376 connect(deletePermanentlyAction, SIGNAL(triggered()), this, SLOT(deletePermanentlyOperation()));
377
378 saveAction = new QAction(tr("Save"), this);
379 saveAction->setObjectName("save");
380 saveAction->setIcon(QIcon::fromTheme("document-save", QIcon(":/images/save.png")));
381
382 saveAsAction = new QAction(tr("Save As"), this);
383 saveAsAction->setObjectName("saveAs");
384 saveAsAction->setIcon(QIcon::fromTheme("document-save-as", QIcon(":/images/save_as.png")));
385
386 copyImageAction = new QAction(tr("Copy Image"), this);
387 copyImageAction->setObjectName("copyImage");
388 pasteImageAction = new QAction(tr("Paste Image"), this);
389 pasteImageAction->setObjectName("pasteImage");
390
391 renameAction = new QAction(tr("Rename"), this);
392 renameAction->setObjectName("rename");
393 connect(renameAction, SIGNAL(triggered()), this, SLOT(rename()));
394
395 removeMetadataAction = new QAction(tr("Remove Metadata"), this);
396 removeMetadataAction->setObjectName("removeMetadata");
397 connect(removeMetadataAction, SIGNAL(triggered()), this, SLOT(removeMetadata()));
398
399 selectAllAction = new QAction(tr("Select All"), this);
400 selectAllAction->setObjectName("selectAll");
401 connect(selectAllAction, SIGNAL(triggered()), this, SLOT(selectAllThumbs()));
402
403 aboutAction = new QAction(tr("About"), this);
404 aboutAction->setObjectName("about");
405 connect(aboutAction, SIGNAL(triggered()), this, SLOT(about()));
406
407 // Sort actions
408 sortByNameAction = new QAction(tr("Sort by Name"), this);
409 sortByNameAction->setObjectName("name");
410 sortByTimeAction = new QAction(tr("Sort by Time"), this);
411 sortByTimeAction->setObjectName("time");
412 sortBySizeAction = new QAction(tr("Sort by Size"), this);
413 sortBySizeAction->setObjectName("size");
414 sortByTypeAction = new QAction(tr("Sort by Type"), this);
415 sortByTypeAction->setObjectName("type");
416 sortReverseAction = new QAction(tr("Reverse Order"), this);
417 sortReverseAction->setObjectName("reverse");
418 sortByNameAction->setCheckable(true);
419 sortByTimeAction->setCheckable(true);
420 sortBySizeAction->setCheckable(true);
421 sortByTypeAction->setCheckable(true);
422 sortReverseAction->setCheckable(true);
423 connect(sortByNameAction, SIGNAL(triggered()), this, SLOT(sortThumbnails()));
424 connect(sortByTimeAction, SIGNAL(triggered()), this, SLOT(sortThumbnails()));
425 connect(sortBySizeAction, SIGNAL(triggered()), this, SLOT(sortThumbnails()));
426 connect(sortByTypeAction, SIGNAL(triggered()), this, SLOT(sortThumbnails()));
427 connect(sortReverseAction, SIGNAL(triggered()), this, SLOT(sortThumbnails()));
428
429 if (thumbsViewer->thumbsSortFlags & QDir::Time) {
430 sortByTimeAction->setChecked(true);
431 } else if (thumbsViewer->thumbsSortFlags & QDir::Size) {
432 sortBySizeAction->setChecked(true);
433 } else if (thumbsViewer->thumbsSortFlags & QDir::Type) {
434 sortByTypeAction->setChecked(true);
435 } else {
436 sortByNameAction->setChecked(true);
437 }
438 sortReverseAction->setChecked(thumbsViewer->thumbsSortFlags & QDir::Reversed);
439
440 showHiddenFilesAction = new QAction(tr("Show Hidden Files"), this);
441 showHiddenFilesAction->setObjectName("showHidden");
442 showHiddenFilesAction->setCheckable(true);
443 showHiddenFilesAction->setChecked(Settings::showHiddenFiles);
444 connect(showHiddenFilesAction, SIGNAL(triggered()), this, SLOT(showHiddenFiles()));
445
446 smallToolbarIconsAction = new QAction(tr("Small Toolbar Icons"), this);
447 smallToolbarIconsAction->setObjectName("smallToolbarIcons");
448 smallToolbarIconsAction->setCheckable(true);
449 smallToolbarIconsAction->setChecked(Settings::smallToolbarIcons);
450 connect(smallToolbarIconsAction, SIGNAL(triggered()), this, SLOT(setToolbarIconSize()));
451
452 lockDocksAction = new QAction(tr("Hide Dock Title Bars"), this);
453 lockDocksAction->setObjectName("lockDocks");
454 lockDocksAction->setCheckable(true);
455 lockDocksAction->setChecked(Settings::hideDockTitlebars);
456 connect(lockDocksAction, SIGNAL(triggered()), this, SLOT(lockDocks()));
457
458 showViewerToolbarAction = new QAction(tr("Show Toolbar"), this);
459 showViewerToolbarAction->setObjectName("showViewerToolbars");
460 showViewerToolbarAction->setCheckable(true);
461 showViewerToolbarAction->setChecked(Settings::showViewerToolbar);
462 connect(showViewerToolbarAction, SIGNAL(triggered()), this, SLOT(toggleImageViewerToolbar()));
463
464 refreshAction = new QAction(tr("Reload"), this);
465 refreshAction->setObjectName("refresh");
466 refreshAction->setIcon(QIcon::fromTheme("view-refresh", QIcon(":/images/refresh.png")));
467 connect(refreshAction, SIGNAL(triggered()), this, SLOT(reload()));
468
469 includeSubDirectoriesAction = new QAction(tr("Include Sub-directories"), this);
470 includeSubDirectoriesAction->setObjectName("subFolders");
471 includeSubDirectoriesAction->setIcon(QIcon(":/images/tree.png"));
472 includeSubDirectoriesAction->setCheckable(true);
473 connect(includeSubDirectoriesAction, SIGNAL(triggered()), this, SLOT(setIncludeSubDirs()));
474
475 pasteAction = new QAction(tr("Paste Here"), this);
476 pasteAction->setObjectName("paste");
477 pasteAction->setIcon(QIcon::fromTheme("edit-paste", QIcon(":/images/paste.png")));
478 connect(pasteAction, SIGNAL(triggered()), this, SLOT(pasteThumbs()));
479 pasteAction->setEnabled(false);
480
481 createDirectoryAction = new QAction(tr("New Directory"), this);
482 createDirectoryAction->setObjectName("createDir");
483 connect(createDirectoryAction, SIGNAL(triggered()), this, SLOT(createSubDirectory()));
484 createDirectoryAction->setIcon(QIcon::fromTheme("folder-new", QIcon(":/images/new_folder.png")));
485
486 goBackAction = new QAction(tr("Back"), this);
487 goBackAction->setObjectName("goBack");
488 goBackAction->setIcon(QIcon::fromTheme("go-previous", QIcon(":/images/back.png")));
489 connect(goBackAction, SIGNAL(triggered()), this, SLOT(goBack()));
490 goBackAction->setEnabled(false);
491
492 goFrwdAction = new QAction(tr("Forward"), this);
493 goFrwdAction->setObjectName("goFrwd");
494 goFrwdAction->setIcon(QIcon::fromTheme("go-next", QIcon(":/images/next.png")));
495 connect(goFrwdAction, SIGNAL(triggered()), this, SLOT(goForward()));
496 goFrwdAction->setEnabled(false);
497
498 goUpAction = new QAction(tr("Go Up"), this);
499 goUpAction->setObjectName("up");
500 goUpAction->setIcon(QIcon::fromTheme("go-up", QIcon(":/images/up.png")));
501 connect(goUpAction, SIGNAL(triggered()), this, SLOT(goUp()));
502
503 goHomeAction = new QAction(tr("Home"), this);
504 goHomeAction->setObjectName("home");
505 connect(goHomeAction, SIGNAL(triggered()), this, SLOT(goHome()));
506 goHomeAction->setIcon(QIcon::fromTheme("go-home", QIcon(":/images/home.png")));
507
508 slideShowAction = new QAction(tr("Slide Show"), this);
509 slideShowAction->setObjectName("toggleSlideShow");
510 connect(slideShowAction, SIGNAL(triggered()), this, SLOT(toggleSlideShow()));
511 slideShowAction->setIcon(QIcon::fromTheme("media-playback-start", QIcon(":/images/play.png")));
512
513 nextImageAction = new QAction(tr("Next Image"), this);
514 nextImageAction->setObjectName("nextImage");
515 nextImageAction->setIcon(QIcon::fromTheme("go-next", QIcon(":/images/next.png")));
516 connect(nextImageAction, SIGNAL(triggered()), this, SLOT(loadNextImage()));
517
518 prevImageAction = new QAction(tr("Previous Image"), this);
519 prevImageAction->setObjectName("prevImage");
520 prevImageAction->setIcon(QIcon::fromTheme("go-previous", QIcon(":/images/back.png")));
521 connect(prevImageAction, SIGNAL(triggered()), this, SLOT(loadPreviousImage()));
522
523 firstImageAction = new QAction(tr("First Image"), this);
524 firstImageAction->setObjectName("firstImage");
525 firstImageAction->setIcon(QIcon::fromTheme("go-first", QIcon(":/images/first.png")));
526 connect(firstImageAction, SIGNAL(triggered()), this, SLOT(loadFirstImage()));
527
528 lastImageAction = new QAction(tr("Last Image"), this);
529 lastImageAction->setObjectName("lastImage");
530 lastImageAction->setIcon(QIcon::fromTheme("go-last", QIcon(":/images/last.png")));
531 connect(lastImageAction, SIGNAL(triggered()), this, SLOT(loadLastImage()));
532
533 randomImageAction = new QAction(tr("Random Image"), this);
534 randomImageAction->setObjectName("randomImage");
535 connect(randomImageAction, SIGNAL(triggered()), this, SLOT(loadRandomImage()));
536
537 viewImageAction = new QAction(tr("View Image"), this);
538 viewImageAction->setObjectName("open");
539 viewImageAction->setIcon(QIcon::fromTheme("document-open", QIcon(":/images/open.png")));
540 connect(viewImageAction, SIGNAL(triggered()), this, SLOT(viewImage()));
541
542 showClipboardAction = new QAction(tr("Load Clipboard"), this);
543 showClipboardAction->setObjectName("showClipboard");
544 showClipboardAction->setIcon(QIcon::fromTheme("insert-image", QIcon(":/images/new.png")));
545 connect(showClipboardAction, SIGNAL(triggered()), this, SLOT(newImage()));
546
547 openWithSubMenu = new QMenu(tr("Open With..."));
548 openWithMenuAction = new QAction(tr("Open With..."), this);
549 openWithMenuAction->setObjectName("openWithMenu");
550 openWithMenuAction->setMenu(openWithSubMenu);
551 externalAppsAction = new QAction(tr("External Applications"), this);
552 externalAppsAction->setIcon(QIcon::fromTheme("preferences-other", QIcon(":/images/settings.png")));
553 externalAppsAction->setObjectName("chooseApp");
554 connect(externalAppsAction, SIGNAL(triggered()), this, SLOT(chooseExternalApp()));
555
556 addBookmarkAction = new QAction(tr("Add Bookmark"), this);
557 addBookmarkAction->setObjectName("addBookmark");
558 addBookmarkAction->setIcon(QIcon(":/images/new_bookmark.png"));
559 connect(addBookmarkAction, SIGNAL(triggered()), this, SLOT(addNewBookmark()));
560
561 removeBookmarkAction = new QAction(tr("Delete Bookmark"), this);
562 removeBookmarkAction->setObjectName("deleteBookmark");
563 removeBookmarkAction->setIcon(QIcon::fromTheme("edit-delete", QIcon(":/images/delete.png")));
564
565 zoomOutAction = new QAction(tr("Zoom Out"), this);
566 zoomOutAction->setObjectName("zoomOut");
567 connect(zoomOutAction, SIGNAL(triggered()), this, SLOT(zoomOut()));
568 zoomOutAction->setIcon(QIcon::fromTheme("zoom-out", QIcon(":/images/zoom_out.png")));
569
570 zoomInAction = new QAction(tr("Zoom In"), this);
571 zoomInAction->setObjectName("zoomIn");
572 connect(zoomInAction, SIGNAL(triggered()), this, SLOT(zoomIn()));
573 zoomInAction->setIcon(QIcon::fromTheme("zoom-in", QIcon(":/images/zoom_out.png")));
574
575 resetZoomAction = new QAction(tr("Reset Zoom"), this);
576 resetZoomAction->setObjectName("resetZoom");
577 resetZoomAction->setIcon(QIcon::fromTheme("zoom-fit-best", QIcon(":/images/zoom.png")));
578 connect(resetZoomAction, SIGNAL(triggered()), this, SLOT(resetZoom()));
579
580 origZoomAction = new QAction(tr("Original Size"), this);
581 origZoomAction->setObjectName("origZoom");
582 origZoomAction->setIcon(QIcon::fromTheme("zoom-original", QIcon(":/images/zoom1.png")));
583 connect(origZoomAction, SIGNAL(triggered()), this, SLOT(origZoom()));
584
585 keepZoomAction = new QAction(tr("Keep Zoom"), this);
586 keepZoomAction->setObjectName("keepZoom");
587 keepZoomAction->setCheckable(true);
588 connect(keepZoomAction, SIGNAL(triggered()), this, SLOT(keepZoom()));
589
590 rotateLeftAction = new QAction(tr("Rotate 90 degree CCW"), this);
591 rotateLeftAction->setObjectName("rotateLeft");
592 rotateLeftAction->setIcon(QIcon::fromTheme("object-rotate-left", QIcon(":/images/rotate_left.png")));
593 connect(rotateLeftAction, SIGNAL(triggered()), this, SLOT(rotateLeft()));
594
595 rotateRightAction = new QAction(tr("Rotate 90 degree CW"), this);
596 rotateRightAction->setObjectName("rotateRight");
597 rotateRightAction->setIcon(QIcon::fromTheme("object-rotate-right", QIcon(":/images/rotate_right.png")));
598 connect(rotateRightAction, SIGNAL(triggered()), this, SLOT(rotateRight()));
599
600 flipHorizontalAction = new QAction(tr("Flip Horizontally"), this);
601 flipHorizontalAction->setObjectName("flipH");
602 flipHorizontalAction->setIcon(QIcon::fromTheme("object-flip-horizontal", QIcon(":/images/flipH.png")));
603 connect(flipHorizontalAction, SIGNAL(triggered()), this, SLOT(flipHorizontal()));
604
605 flipVerticalAction = new QAction(tr("Flip Vertically"), this);
606 flipVerticalAction->setObjectName("flipV");
607 flipVerticalAction->setIcon(QIcon::fromTheme("object-flip-vertical", QIcon(":/images/flipV.png")));
608 connect(flipVerticalAction, SIGNAL(triggered()), this, SLOT(flipVertical()));
609
610 cropAction = new QAction(tr("Cropping"), this);
611 cropAction->setObjectName("crop");
612 cropAction->setIcon(QIcon(":/images/crop.png"));
613 connect(cropAction, SIGNAL(triggered()), this, SLOT(cropImage()));
614
615 cropToSelectionAction = new QAction(tr("Crop to Selection"), this);
616 cropToSelectionAction->setObjectName("cropToSelection");
617 cropToSelectionAction->setIcon(QIcon(":/images/crop.png"));
618
619 resizeAction = new QAction(tr("Scale Image"), this);
620 resizeAction->setObjectName("resize");
621 resizeAction->setIcon(QIcon::fromTheme("transform-scale", QIcon(":/images/scale.png")));
622 connect(resizeAction, SIGNAL(triggered()), this, SLOT(scaleImage()));
623
624 freeRotateLeftAction = new QAction(tr("Rotate 1 degree CCW"), this);
625 freeRotateLeftAction->setObjectName("freeRotateLeft");
626 connect(freeRotateLeftAction, SIGNAL(triggered()), this, SLOT(freeRotateLeft()));
627
628 freeRotateRightAction = new QAction(tr("Rotate 1 degree CW"), this);
629 freeRotateRightAction->setObjectName("freeRotateRight");
630 connect(freeRotateRightAction, SIGNAL(triggered()), this, SLOT(freeRotateRight()));
631
632 colorsAction = new QAction(tr("Colors"), this);
633 colorsAction->setObjectName("colors");
634 connect(colorsAction, SIGNAL(triggered()), this, SLOT(showColorsDialog()));
635 colorsAction->setIcon(QIcon(":/images/colors.png"));
636
637 mirrorDisabledAction = new QAction(tr("Disable Mirror"), this);
638 mirrorDisabledAction->setObjectName("mirrorDisabled");
639 mirrorDualAction = new QAction(tr("Dual Mirror"), this);
640 mirrorDualAction->setObjectName("mirrorDual");
641 mirrorTripleAction = new QAction(tr("Triple Mirror"), this);
642 mirrorTripleAction->setObjectName("mirrorTriple");
643 mirrorDualVerticalAction = new QAction(tr("Dual Vertical Mirror"), this);
644 mirrorDualVerticalAction->setObjectName("mirrorVDual");
645 mirrorQuadAction = new QAction(tr("Quad Mirror"), this);
646 mirrorQuadAction->setObjectName("mirrorQuad");
647
648 mirrorDisabledAction->setCheckable(true);
649 mirrorDualAction->setCheckable(true);
650 mirrorTripleAction->setCheckable(true);
651 mirrorDualVerticalAction->setCheckable(true);
652 mirrorQuadAction->setCheckable(true);
653 connect(mirrorDisabledAction, SIGNAL(triggered()), this, SLOT(setMirrorDisabled()));
654 connect(mirrorDualAction, SIGNAL(triggered()), this, SLOT(setMirrorDual()));
655 connect(mirrorTripleAction, SIGNAL(triggered()), this, SLOT(setMirrorTriple()));
656 connect(mirrorDualVerticalAction, SIGNAL(triggered()), this, SLOT(setMirrorVDual()));
657 connect(mirrorQuadAction, SIGNAL(triggered()), this, SLOT(setMirrorQuad()));
658 mirrorDisabledAction->setChecked(true);
659
660 keepTransformAction = new QAction(tr("Keep Transformations"), this);
661 keepTransformAction->setObjectName("keepTransform");
662 keepTransformAction->setCheckable(true);
663 connect(keepTransformAction, SIGNAL(triggered()), this, SLOT(keepTransformClicked()));
664
665 moveLeftAction = new QAction(tr("Move Image Left"), this);
666 moveLeftAction->setObjectName("moveLeft");
667 connect(moveLeftAction, SIGNAL(triggered()), this, SLOT(moveLeft()));
668 moveRightAction = new QAction(tr("Move Image Right"), this);
669 moveRightAction->setObjectName("moveRight");
670 connect(moveRightAction, SIGNAL(triggered()), this, SLOT(moveRight()));
671 moveUpAction = new QAction(tr("Move Image Up"), this);
672 moveUpAction->setObjectName("moveUp");
673 connect(moveUpAction, SIGNAL(triggered()), this, SLOT(moveUp()));
674 moveDownAction = new QAction(tr("Move Image Down"), this);
675 moveDownAction->setObjectName("moveDown");
676 connect(moveDownAction, SIGNAL(triggered()), this, SLOT(moveDown()));
677
678 invertSelectionAction = new QAction(tr("Invert Selection"), this);
679 invertSelectionAction->setObjectName("invertSelection");
680 connect(invertSelectionAction, SIGNAL(triggered()), thumbsViewer, SLOT(invertSelection()));
681
682 filterImagesFocusAction = new QAction(tr("Filter by Name"), this);
683 filterImagesFocusAction->setObjectName("filterImagesFocus");
684 connect(filterImagesFocusAction, SIGNAL(triggered()), this, SLOT(filterImagesFocus()));
685 setPathFocusAction = new QAction(tr("Edit Current Path"), this);
686 setPathFocusAction->setObjectName("setPathFocus");
687 connect(setPathFocusAction, SIGNAL(triggered()), this, SLOT(setPathFocus()));
688 }
689
createMenus()690 void Phototonic::createMenus() {
691 fileMenu = menuBar()->addMenu(tr("&File"));
692 fileMenu->addAction(includeSubDirectoriesAction);
693 fileMenu->addAction(createDirectoryAction);
694 fileMenu->addAction(showClipboardAction);
695 fileMenu->addAction(addBookmarkAction);
696 fileMenu->addSeparator();
697 fileMenu->addAction(exitAction);
698
699 editMenu = menuBar()->addMenu(tr("&Edit"));
700 editMenu->addAction(cutAction);
701 editMenu->addAction(copyAction);
702 editMenu->addAction(copyToAction);
703 editMenu->addAction(moveToAction);
704 editMenu->addAction(pasteAction);
705 editMenu->addAction(renameAction);
706 editMenu->addAction(removeMetadataAction);
707 editMenu->addAction(deleteAction);
708 editMenu->addAction(deletePermanentlyAction);
709 editMenu->addSeparator();
710 editMenu->addAction(selectAllAction);
711 editMenu->addAction(invertSelectionAction);
712 addAction(filterImagesFocusAction);
713 addAction(setPathFocusAction);
714 editMenu->addSeparator();
715 editMenu->addAction(externalAppsAction);
716 editMenu->addAction(settingsAction);
717
718 goMenu = menuBar()->addMenu(tr("&Go"));
719 goMenu->addAction(goBackAction);
720 goMenu->addAction(goFrwdAction);
721 goMenu->addAction(goUpAction);
722 goMenu->addAction(goHomeAction);
723 goMenu->addSeparator();
724 goMenu->addAction(prevImageAction);
725 goMenu->addAction(nextImageAction);
726 goMenu->addSeparator();
727 goMenu->addAction(thumbsGoToTopAction);
728 goMenu->addAction(thumbsGoToBottomAction);
729
730 viewMenu = menuBar()->addMenu(tr("&View"));
731 viewMenu->addAction(slideShowAction);
732 viewMenu->addSeparator();
733
734 viewMenu->addAction(thumbsZoomInAction);
735 viewMenu->addAction(thumbsZoomOutAction);
736 sortMenu = viewMenu->addMenu(tr("Thumbnails Sorting"));
737 sortTypesGroup = new QActionGroup(this);
738 sortTypesGroup->addAction(sortByNameAction);
739 sortTypesGroup->addAction(sortByTimeAction);
740 sortTypesGroup->addAction(sortBySizeAction);
741 sortTypesGroup->addAction(sortByTypeAction);
742 sortMenu->addActions(sortTypesGroup->actions());
743 sortMenu->addSeparator();
744 sortMenu->addAction(sortReverseAction);
745 viewMenu->addSeparator();
746
747 viewMenu->addAction(showHiddenFilesAction);
748 viewMenu->addSeparator();
749 viewMenu->addAction(refreshAction);
750
751 // thumbs viewer context menu
752 thumbsViewer->addAction(viewImageAction);
753 thumbsViewer->addAction(openWithMenuAction);
754 thumbsViewer->addAction(cutAction);
755 thumbsViewer->addAction(copyAction);
756 thumbsViewer->addAction(pasteAction);
757 addMenuSeparator(thumbsViewer);
758 thumbsViewer->addAction(copyToAction);
759 thumbsViewer->addAction(moveToAction);
760 thumbsViewer->addAction(renameAction);
761 thumbsViewer->addAction(removeMetadataAction);
762 thumbsViewer->addAction(deleteAction);
763 thumbsViewer->addAction(deletePermanentlyAction);
764 addMenuSeparator(thumbsViewer);
765 thumbsViewer->addAction(selectAllAction);
766 thumbsViewer->addAction(invertSelectionAction);
767 thumbsViewer->setContextMenuPolicy(Qt::ActionsContextMenu);
768 menuBar()->setVisible(true);
769 }
770
createToolBars()771 void Phototonic::createToolBars() {
772 /* Edit */
773 editToolBar = addToolBar(tr("Edit Toolbar"));
774 editToolBar->setObjectName("Edit");
775 editToolBar->addAction(cutAction);
776 editToolBar->addAction(copyAction);
777 editToolBar->addAction(pasteAction);
778 editToolBar->addAction(deleteAction);
779 editToolBar->addAction(deletePermanentlyAction);
780 editToolBar->addAction(showClipboardAction);
781 connect(editToolBar->toggleViewAction(), SIGNAL(triggered()), this, SLOT(setEditToolBarVisibility()));
782
783 /* Navigation */
784 goToolBar = addToolBar(tr("Navigation Toolbar"));
785 goToolBar->setObjectName("Navigation");
786 goToolBar->addAction(goBackAction);
787 goToolBar->addAction(goFrwdAction);
788 goToolBar->addAction(goUpAction);
789 goToolBar->addAction(goHomeAction);
790 goToolBar->addAction(refreshAction);
791
792 /* path bar */
793 pathLineEdit = new QLineEdit;
794 pathLineEdit->setCompleter(new DirCompleter(pathLineEdit));
795 pathLineEdit->setMinimumWidth(200);
796 pathLineEdit->setMaximumWidth(600);
797 connect(pathLineEdit, SIGNAL(returnPressed()), this, SLOT(goPathBarDir()));
798 goToolBar->addWidget(pathLineEdit);
799 goToolBar->addAction(includeSubDirectoriesAction);
800 connect(goToolBar->toggleViewAction(), SIGNAL(triggered()), this, SLOT(setGoToolBarVisibility()));
801
802 /* View */
803 viewToolBar = addToolBar(tr("View Toolbar"));
804 viewToolBar->setObjectName("View");
805 viewToolBar->addAction(thumbsZoomInAction);
806 viewToolBar->addAction(thumbsZoomOutAction);
807 viewToolBar->addAction(slideShowAction);
808
809 /* filter bar */
810 QAction *filterAct = new QAction(tr("Filter"), this);
811 filterAct->setIcon(QIcon::fromTheme("edit-find", QIcon(":/images/zoom.png")));
812 connect(filterAct, SIGNAL(triggered()), this, SLOT(setThumbsFilter()));
813 filterLineEdit = new QLineEdit;
814 filterLineEdit->setMinimumWidth(100);
815 filterLineEdit->setMaximumWidth(200);
816 connect(filterLineEdit, SIGNAL(returnPressed()), this, SLOT(setThumbsFilter()));
817 connect(filterLineEdit, SIGNAL(textChanged(
818 const QString&)), this, SLOT(clearThumbsFilter()));
819 filterLineEdit->setClearButtonEnabled(true);
820 filterLineEdit->addAction(filterAct, QLineEdit::LeadingPosition);
821
822 viewToolBar->addSeparator();
823 viewToolBar->addWidget(filterLineEdit);
824 viewToolBar->addAction(settingsAction);
825 connect(viewToolBar->toggleViewAction(), SIGNAL(triggered()), this, SLOT(setViewToolBarVisibility()));
826
827 /* image */
828 imageToolBar = new QToolBar(tr("Image Toolbar"));
829 imageToolBar->setObjectName("Image");
830 imageToolBar->addAction(prevImageAction);
831 imageToolBar->addAction(nextImageAction);
832 imageToolBar->addAction(firstImageAction);
833 imageToolBar->addAction(lastImageAction);
834 imageToolBar->addAction(slideShowAction);
835 imageToolBar->addSeparator();
836 imageToolBar->addAction(saveAction);
837 imageToolBar->addAction(saveAsAction);
838 imageToolBar->addAction(deleteAction);
839 imageToolBar->addAction(deletePermanentlyAction);
840 imageToolBar->addSeparator();
841 imageToolBar->addAction(zoomInAction);
842 imageToolBar->addAction(zoomOutAction);
843 imageToolBar->addAction(resetZoomAction);
844 imageToolBar->addAction(origZoomAction);
845 imageToolBar->addSeparator();
846 imageToolBar->addAction(resizeAction);
847 imageToolBar->addAction(rotateRightAction);
848 imageToolBar->addAction(rotateLeftAction);
849 imageToolBar->addAction(flipHorizontalAction);
850 imageToolBar->addAction(flipVerticalAction);
851 imageToolBar->addAction(cropAction);
852 imageToolBar->addAction(colorsAction);
853 imageToolBar->setVisible(false);
854 connect(imageToolBar->toggleViewAction(), SIGNAL(triggered()), this, SLOT(setImageToolBarVisibility()));
855
856 setToolbarIconSize();
857 }
858
setToolbarIconSize()859 void Phototonic::setToolbarIconSize() {
860 if (initComplete) {
861 Settings::smallToolbarIcons = smallToolbarIconsAction->isChecked();
862 }
863 int iconSize = Settings::smallToolbarIcons ? 16 : 24;
864 QSize iconQSize(iconSize, iconSize);
865
866 editToolBar->setIconSize(iconQSize);
867 goToolBar->setIconSize(iconQSize);
868 viewToolBar->setIconSize(iconQSize);
869 imageToolBar->setIconSize(iconQSize);
870 }
871
createStatusBar()872 void Phototonic::createStatusBar() {
873 statusLabel = new QLabel(tr("Initializing..."));
874 statusBar()->addWidget(statusLabel);
875
876 busyMovie = new QMovie(":/images/busy.gif");
877 busyLabel = new QLabel(this);
878 busyLabel->setMovie(busyMovie);
879 statusBar()->addWidget(busyLabel);
880 busyLabel->setVisible(false);
881
882 statusBar()->setStyleSheet("QStatusBar::item { border: 0px solid black }; ");
883 }
884
onFileListSelected()885 void Phototonic::onFileListSelected() {
886 if (initComplete && fileListWidget->itemAt(0, 0)->isSelected()) {
887 Settings::isFileListLoaded = true;
888 fileSystemTree->clearSelection();
889 refreshThumbs(true);
890 }
891 }
892
createFileSystemDock()893 void Phototonic::createFileSystemDock() {
894 fileSystemDock = new QDockWidget(tr("File System"), this);
895 fileSystemDock->setObjectName("File System");
896
897 fileListWidget = new FileListWidget(fileSystemDock);
898 connect(fileListWidget, SIGNAL(itemSelectionChanged()), this, SLOT(onFileListSelected()));
899
900 fileSystemTree = new FileSystemTree(fileSystemDock);
901 fileSystemTree->addAction(createDirectoryAction);
902 fileSystemTree->addAction(renameAction);
903 fileSystemTree->addAction(deleteAction);
904 fileSystemTree->addAction(deletePermanentlyAction);
905 addMenuSeparator(fileSystemTree);
906 fileSystemTree->addAction(pasteAction);
907 addMenuSeparator(fileSystemTree);
908 fileSystemTree->addAction(openWithMenuAction);
909 fileSystemTree->addAction(addBookmarkAction);
910 fileSystemTree->setContextMenuPolicy(Qt::ActionsContextMenu);
911
912 connect(fileSystemTree, SIGNAL(clicked(
913 const QModelIndex&)), this, SLOT(goSelectedDir(
914 const QModelIndex &)));
915
916 connect(fileSystemTree->fileSystemModel, SIGNAL(rowsRemoved(
917 const QModelIndex &, int, int)),
918 this, SLOT(checkDirState(
919 const QModelIndex &, int, int)));
920
921 connect(fileSystemTree, SIGNAL(dropOp(Qt::KeyboardModifiers, bool, QString)),
922 this, SLOT(dropOp(Qt::KeyboardModifiers, bool, QString)));
923
924 fileSystemTree->setCurrentIndex(fileSystemTree->fileSystemModel->index(QDir::currentPath()));
925
926 connect(fileSystemTree->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
927 this, SLOT(updateActions()));
928
929 QVBoxLayout *mainLayout = new QVBoxLayout;
930 mainLayout->setContentsMargins(0, 0, 0, 0);
931 mainLayout->setSpacing(0);
932 mainLayout->addWidget(fileListWidget);
933 mainLayout->addWidget(fileSystemTree);
934
935 QWidget *fileSystemTreeMainWidget = new QWidget(fileSystemDock);
936 fileSystemTreeMainWidget->setLayout(mainLayout);
937
938 fileSystemDock->setWidget(fileSystemTreeMainWidget);
939 connect(fileSystemDock->toggleViewAction(), SIGNAL(triggered()), this, SLOT(setFileSystemDockVisibility()));
940 connect(fileSystemDock, SIGNAL(visibilityChanged(bool)), this, SLOT(setFileSystemDockVisibility()));
941 addDockWidget(Qt::LeftDockWidgetArea, fileSystemDock);
942 }
943
createBookmarksDock()944 void Phototonic::createBookmarksDock() {
945 bookmarksDock = new QDockWidget(tr("Bookmarks"), this);
946 bookmarksDock->setObjectName("Bookmarks");
947 bookmarks = new BookMarks(bookmarksDock);
948 bookmarksDock->setWidget(bookmarks);
949
950 connect(bookmarksDock->toggleViewAction(), SIGNAL(triggered()), this, SLOT(setBookmarksDockVisibility()));
951 connect(bookmarksDock, SIGNAL(visibilityChanged(bool)), this, SLOT(setBookmarksDockVisibility()));
952 connect(bookmarks, SIGNAL(itemClicked(QTreeWidgetItem * , int)),
953 this, SLOT(bookmarkClicked(QTreeWidgetItem * , int)));
954 connect(removeBookmarkAction, SIGNAL(triggered()), bookmarks, SLOT(removeBookmark()));
955 connect(bookmarks, SIGNAL(dropOp(Qt::KeyboardModifiers, bool, QString)),
956 this, SLOT(dropOp(Qt::KeyboardModifiers, bool, QString)));
957
958 addDockWidget(Qt::LeftDockWidgetArea, bookmarksDock);
959
960 bookmarks->addAction(pasteAction);
961 bookmarks->addAction(removeBookmarkAction);
962 bookmarks->setContextMenuPolicy(Qt::ActionsContextMenu);
963 }
964
createImagePreviewDock()965 void Phototonic::createImagePreviewDock() {
966 imagePreviewDock = new QDockWidget(tr("Preview"), this);
967 imagePreviewDock->setObjectName("ImagePreview");
968 imagePreviewDock->setWidget(thumbsViewer->imagePreview);
969 connect(imagePreviewDock->toggleViewAction(), SIGNAL(triggered()), this, SLOT(setImagePreviewDockVisibility()));
970 connect(imagePreviewDock, SIGNAL(visibilityChanged(bool)), this, SLOT(setImagePreviewDockVisibility()));
971 addDockWidget(Qt::RightDockWidgetArea, imagePreviewDock);
972 }
973
createImageTagsDock()974 void Phototonic::createImageTagsDock() {
975 tagsDock = new QDockWidget(tr("Tags"), this);
976 tagsDock->setObjectName("Tags");
977 thumbsViewer->imageTags = new ImageTags(tagsDock, thumbsViewer, metadataCache);
978 tagsDock->setWidget(thumbsViewer->imageTags);
979
980 connect(tagsDock->toggleViewAction(), SIGNAL(triggered()), this, SLOT(setTagsDockVisibility()));
981 connect(tagsDock, SIGNAL(visibilityChanged(bool)), this, SLOT(setTagsDockVisibility()));
982 connect(thumbsViewer->imageTags, SIGNAL(reloadThumbs()), this, SLOT(onReloadThumbs()));
983 connect(thumbsViewer->imageTags->removeTagAction, SIGNAL(triggered()), this, SLOT(deleteOperation()));
984 }
985
sortThumbnails()986 void Phototonic::sortThumbnails() {
987 thumbsViewer->thumbsSortFlags = QDir::IgnoreCase;
988
989 if (sortByNameAction->isChecked()) {
990 thumbsViewer->thumbsSortFlags |= QDir::Name;
991 } else if (sortByTimeAction->isChecked()) {
992 thumbsViewer->thumbsSortFlags |= QDir::Time;
993 } else if (sortBySizeAction->isChecked()) {
994 thumbsViewer->thumbsSortFlags |= QDir::Size;
995 } else if (sortByTypeAction->isChecked()) {
996 thumbsViewer->thumbsSortFlags |= QDir::Type;
997 }
998
999 if (sortReverseAction->isChecked()) {
1000 thumbsViewer->thumbsSortFlags |= QDir::Reversed;
1001 }
1002 refreshThumbs(false);
1003 }
1004
reload()1005 void Phototonic::reload() {
1006 if (Settings::layoutMode == ThumbViewWidget) {
1007 refreshThumbs(false);
1008 } else {
1009 imageViewer->reload();
1010 }
1011 }
1012
setIncludeSubDirs()1013 void Phototonic::setIncludeSubDirs() {
1014 Settings::includeSubDirectories = includeSubDirectoriesAction->isChecked();
1015 refreshThumbs(false);
1016 }
1017
refreshThumbs(bool scrollToTop)1018 void Phototonic::refreshThumbs(bool scrollToTop) {
1019 thumbsViewer->setNeedToScroll(scrollToTop);
1020 QTimer::singleShot(0, this, SLOT(onReloadThumbs()));
1021 }
1022
showHiddenFiles()1023 void Phototonic::showHiddenFiles() {
1024 Settings::showHiddenFiles = showHiddenFilesAction->isChecked();
1025 fileSystemTree->setModelFlags();
1026 refreshThumbs(false);
1027 }
1028
toggleImageViewerToolbar()1029 void Phototonic::toggleImageViewerToolbar() {
1030 imageToolBar->setVisible(showViewerToolbarAction->isChecked());
1031 addToolBar(imageToolBar);
1032 Settings::showViewerToolbar = showViewerToolbarAction->isChecked();
1033 }
1034
about()1035 void Phototonic::about() {
1036 MessageBox messageBox(this);
1037 messageBox.about();
1038 }
1039
filterImagesFocus()1040 void Phototonic::filterImagesFocus() {
1041 if (Settings::layoutMode == ThumbViewWidget) {
1042 if (!viewToolBar->isVisible()) {
1043 viewToolBar->setVisible(true);
1044 }
1045 setViewToolBarVisibility();
1046 filterLineEdit->setFocus(Qt::OtherFocusReason);
1047 filterLineEdit->selectAll();
1048 }
1049 }
1050
setPathFocus()1051 void Phototonic::setPathFocus() {
1052 if (Settings::layoutMode == ThumbViewWidget) {
1053 if (!goToolBar->isVisible()) {
1054 goToolBar->setVisible(true);
1055 }
1056 setGoToolBarVisibility();
1057 pathLineEdit->setFocus(Qt::OtherFocusReason);
1058 pathLineEdit->selectAll();
1059 }
1060 }
1061
cleanupSender()1062 void Phototonic::cleanupSender() {
1063 delete QObject::sender();
1064 }
1065
externalAppError()1066 void Phototonic::externalAppError() {
1067 MessageBox msgBox(this);
1068 msgBox.critical(tr("Error"), tr("Failed to start external application."));
1069 }
1070
runExternalApp()1071 void Phototonic::runExternalApp() {
1072 QString execCommand;
1073 QString selectedFileNames("");
1074 execCommand = Settings::externalApps[((QAction *) sender())->text()];
1075
1076 if (Settings::layoutMode == ImageViewWidget) {
1077 if (imageViewer->isNewImage()) {
1078 showNewImageWarning();
1079 return;
1080 }
1081
1082 execCommand += " \"" + imageViewer->viewerImageFullPath + "\"";
1083 } else {
1084 if (QApplication::focusWidget() == fileSystemTree) {
1085 selectedFileNames += " \"" + getSelectedPath() + "\"";
1086 } else {
1087
1088 QModelIndexList selectedIdxList = thumbsViewer->selectionModel()->selectedIndexes();
1089 if (selectedIdxList.size() < 1) {
1090 setStatus(tr("Invalid selection."));
1091 return;
1092 }
1093
1094 selectedFileNames += " ";
1095 for (int tn = selectedIdxList.size() - 1; tn >= 0; --tn) {
1096 selectedFileNames += "\"" +
1097 thumbsViewer->thumbsViewerModel->item(selectedIdxList[tn].row())->data(
1098 thumbsViewer->FileNameRole).toString();
1099 if (tn)
1100 selectedFileNames += "\" ";
1101 }
1102 }
1103
1104 execCommand += selectedFileNames;
1105 }
1106
1107 QProcess *externalProcess = new QProcess();
1108 connect(externalProcess, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(cleanupSender()));
1109 connect(externalProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(externalAppError()));
1110 externalProcess->start(execCommand);
1111 }
1112
updateExternalApps()1113 void Phototonic::updateExternalApps() {
1114 int actionNumber = 0;
1115 QMapIterator<QString, QString> externalAppsIterator(Settings::externalApps);
1116
1117 QList<QAction *> actionList = openWithSubMenu->actions();
1118 if (!actionList.empty()) {
1119
1120 for (int i = 0; i < actionList.size(); ++i) {
1121 QAction *action = actionList.at(i);
1122 if (action->isSeparator()) {
1123 break;
1124 }
1125
1126 openWithSubMenu->removeAction(action);
1127 imageViewer->removeAction(action);
1128 delete action;
1129 }
1130
1131 openWithSubMenu->clear();
1132 }
1133
1134 while (externalAppsIterator.hasNext()) {
1135 ++actionNumber;
1136 externalAppsIterator.next();
1137 QAction *extAppAct = new QAction(externalAppsIterator.key(), this);
1138 if (actionNumber < 10) {
1139 extAppAct->setShortcut(QKeySequence("Alt+" + QString::number(actionNumber)));
1140 }
1141 extAppAct->setIcon(QIcon::fromTheme(externalAppsIterator.key()));
1142 connect(extAppAct, SIGNAL(triggered()), this, SLOT(runExternalApp()));
1143 openWithSubMenu->addAction(extAppAct);
1144 imageViewer->addAction(extAppAct);
1145 }
1146
1147 openWithSubMenu->addSeparator();
1148 openWithSubMenu->addAction(externalAppsAction);
1149 }
1150
chooseExternalApp()1151 void Phototonic::chooseExternalApp() {
1152 ExternalAppsDialog *externalAppsDialog = new ExternalAppsDialog(this);
1153
1154 if (Settings::slideShowActive) {
1155 toggleSlideShow();
1156 }
1157 imageViewer->setCursorHiding(false);
1158
1159 externalAppsDialog->exec();
1160 updateExternalApps();
1161 delete (externalAppsDialog);
1162
1163 if (isFullScreen()) {
1164 imageViewer->setCursorHiding(true);
1165 }
1166 }
1167
showSettings()1168 void Phototonic::showSettings() {
1169 if (Settings::slideShowActive) {
1170 toggleSlideShow();
1171 }
1172
1173 imageViewer->setCursorHiding(false);
1174
1175 SettingsDialog *settingsDialog = new SettingsDialog(this);
1176 if (settingsDialog->exec()) {
1177 imageViewer->setBackgroundColor();
1178 thumbsViewer->setThumbColors();
1179 thumbsViewer->imagePreview->setBackgroundColor();
1180 Settings::imageZoomFactor = 1.0;
1181 imageViewer->imageInfoLabel->setVisible(Settings::showImageName);
1182
1183 if (Settings::layoutMode == ImageViewWidget) {
1184 imageViewer->reload();
1185 needThumbsRefresh = true;
1186 } else {
1187 refreshThumbs(false);
1188 }
1189
1190 if (!Settings::setWindowIcon) {
1191 setWindowIcon(defaultApplicationIcon);
1192 }
1193 writeSettings();
1194 }
1195
1196 if (isFullScreen()) {
1197 imageViewer->setCursorHiding(true);
1198 }
1199 delete settingsDialog;
1200 }
1201
toggleFullScreen()1202 void Phototonic::toggleFullScreen() {
1203 if (fullScreenAction->isChecked()) {
1204 shouldMaximize = isMaximized();
1205 showFullScreen();
1206 Settings::isFullScreen = true;
1207 imageViewer->setCursorHiding(true);
1208 } else {
1209 showNormal();
1210 if (shouldMaximize) {
1211 showMaximized();
1212 }
1213 imageViewer->setCursorHiding(false);
1214 Settings::isFullScreen = false;
1215 }
1216 }
1217
selectAllThumbs()1218 void Phototonic::selectAllThumbs() {
1219 thumbsViewer->selectAll();
1220 }
1221
copyOrCutThumbs(bool isCopyOperation)1222 void Phototonic::copyOrCutThumbs(bool isCopyOperation) {
1223 Settings::copyCutIndexList = thumbsViewer->selectionModel()->selectedIndexes();
1224 copyCutThumbsCount = Settings::copyCutIndexList.size();
1225
1226 Settings::copyCutFileList.clear();
1227 for (int thumb = 0; thumb < copyCutThumbsCount; ++thumb) {
1228 Settings::copyCutFileList.append(thumbsViewer->thumbsViewerModel->item(Settings::copyCutIndexList[thumb].
1229 row())->data(thumbsViewer->FileNameRole).toString());
1230 }
1231
1232 Settings::isCopyOperation = isCopyOperation;
1233 pasteAction->setEnabled(true);
1234
1235 QString state = QString((Settings::isCopyOperation ? tr("Copied") : tr("Cut")) + " " +
1236 tr("%n image(s) to clipboard", "", copyCutThumbsCount));
1237 setStatus(state);
1238 }
1239
cutThumbs()1240 void Phototonic::cutThumbs() {
1241 copyOrCutThumbs(false);
1242 }
1243
copyThumbs()1244 void Phototonic::copyThumbs() {
1245 copyOrCutThumbs(true);
1246 }
1247
copyImagesTo()1248 void Phototonic::copyImagesTo() {
1249 copyOrMoveImages(false);
1250 }
1251
moveImagesTo()1252 void Phototonic::moveImagesTo() {
1253 copyOrMoveImages(true);
1254 }
1255
copyOrMoveImages(bool isMoveOperation)1256 void Phototonic::copyOrMoveImages(bool isMoveOperation) {
1257 if (Settings::slideShowActive) {
1258 toggleSlideShow();
1259 }
1260 imageViewer->setCursorHiding(false);
1261
1262 copyMoveToDialog = new CopyMoveToDialog(this, getSelectedPath(), isMoveOperation);
1263 if (copyMoveToDialog->exec()) {
1264 if (Settings::layoutMode == ThumbViewWidget) {
1265 if (copyMoveToDialog->copyOp) {
1266 copyThumbs();
1267 } else {
1268 cutThumbs();
1269 }
1270
1271 pasteThumbs();
1272 } else {
1273 if (imageViewer->isNewImage()) {
1274 showNewImageWarning();
1275 if (isFullScreen()) {
1276 imageViewer->setCursorHiding(true);
1277 }
1278
1279 return;
1280 }
1281
1282 QFileInfo fileInfo = QFileInfo(imageViewer->viewerImageFullPath);
1283 QString fileName = fileInfo.fileName();
1284 QString destFile = copyMoveToDialog->selectedPath + QDir::separator() + fileInfo.fileName();
1285
1286 int result = CopyMoveDialog::copyOrMoveFile(copyMoveToDialog->copyOp, fileName,
1287 imageViewer->viewerImageFullPath,
1288 destFile, copyMoveToDialog->selectedPath);
1289
1290 if (!result) {
1291 MessageBox msgBox(this);
1292 msgBox.critical(tr("Error"), tr("Failed to copy or move image."));
1293 } else {
1294 if (!copyMoveToDialog->copyOp) {
1295 int currentRow = thumbsViewer->getCurrentRow();
1296 thumbsViewer->thumbsViewerModel->removeRow(currentRow);
1297 loadCurrentImage(currentRow);
1298 }
1299 }
1300 }
1301 }
1302
1303 bookmarks->reloadBookmarks();
1304 delete (copyMoveToDialog);
1305 copyMoveToDialog = 0;
1306
1307 if (isFullScreen()) {
1308 imageViewer->setCursorHiding(true);
1309 }
1310 }
1311
thumbsZoomIn()1312 void Phototonic::thumbsZoomIn() {
1313 if (thumbsViewer->thumbSize < THUMB_SIZE_MAX) {
1314 thumbsViewer->thumbSize += THUMB_SIZE_MIN;
1315 thumbsZoomOutAction->setEnabled(true);
1316 if (thumbsViewer->thumbSize == THUMB_SIZE_MAX)
1317 thumbsZoomInAction->setEnabled(false);
1318 refreshThumbs(false);
1319 }
1320 }
1321
thumbsZoomOut()1322 void Phototonic::thumbsZoomOut() {
1323 if (thumbsViewer->thumbSize > THUMB_SIZE_MIN) {
1324 thumbsViewer->thumbSize -= THUMB_SIZE_MIN;
1325 thumbsZoomInAction->setEnabled(true);
1326 if (thumbsViewer->thumbSize == THUMB_SIZE_MIN)
1327 thumbsZoomOutAction->setEnabled(false);
1328 refreshThumbs(false);
1329 }
1330 }
1331
zoomOut()1332 void Phototonic::zoomOut() {
1333 if (Settings::imageZoomFactor <= 4.0 && Settings::imageZoomFactor > 0.25) {
1334 Settings::imageZoomFactor -= 0.25;
1335 } else if (Settings::imageZoomFactor <= 8.0 && Settings::imageZoomFactor >= 4.0) {
1336 Settings::imageZoomFactor -= 0.50;
1337 } else if (Settings::imageZoomFactor <= 16.0 && Settings::imageZoomFactor >= 8.0) {
1338 Settings::imageZoomFactor -= 1.0;
1339 } else {
1340 imageViewer->setFeedback(tr("Minimum zoom"));
1341 return;
1342 }
1343
1344 imageViewer->tempDisableResize = false;
1345 imageViewer->resizeImage();
1346 imageViewer->setFeedback(tr("Zoom %1%").arg(QString::number(Settings::imageZoomFactor * 100)));
1347 }
1348
zoomIn()1349 void Phototonic::zoomIn() {
1350 if (Settings::imageZoomFactor < 4.0 && Settings::imageZoomFactor >= 0.25) {
1351 Settings::imageZoomFactor += 0.25;
1352 } else if (Settings::imageZoomFactor < 8.0 && Settings::imageZoomFactor >= 4.0) {
1353 Settings::imageZoomFactor += 0.50;
1354 } else if (Settings::imageZoomFactor < 16.0 && Settings::imageZoomFactor >= 8.0) {
1355 Settings::imageZoomFactor += 1.00;
1356 } else {
1357 imageViewer->setFeedback(tr("Maximum zoom"));
1358 return;
1359 }
1360
1361 imageViewer->tempDisableResize = false;
1362 imageViewer->resizeImage();
1363 imageViewer->setFeedback(tr("Zoom %1%").arg(QString::number(Settings::imageZoomFactor * 100)));
1364 }
1365
resetZoom()1366 void Phototonic::resetZoom() {
1367 Settings::imageZoomFactor = 1.0;
1368 imageViewer->tempDisableResize = false;
1369 imageViewer->resizeImage();
1370 imageViewer->setFeedback(tr("Zoom Reset"));
1371 }
1372
origZoom()1373 void Phototonic::origZoom() {
1374 Settings::imageZoomFactor = 1.0;
1375 imageViewer->tempDisableResize = true;
1376 imageViewer->resizeImage();
1377 imageViewer->setFeedback(tr("Original Size"));
1378 }
1379
keepZoom()1380 void Phototonic::keepZoom() {
1381 Settings::keepZoomFactor = keepZoomAction->isChecked();
1382 if (Settings::keepZoomFactor) {
1383 imageViewer->setFeedback(tr("Zoom Locked"));
1384 } else {
1385 imageViewer->setFeedback(tr("Zoom Unlocked"));
1386 }
1387 }
1388
keepTransformClicked()1389 void Phototonic::keepTransformClicked() {
1390 Settings::keepTransform = keepTransformAction->isChecked();
1391
1392 if (Settings::keepTransform) {
1393 imageViewer->setFeedback(tr("Transformations Locked"));
1394 if (cropDialog) {
1395 cropDialog->applyCrop(0);
1396 }
1397 } else {
1398 Settings::cropLeftPercent = Settings::cropTopPercent = Settings::cropWidthPercent = Settings::cropHeightPercent = 0;
1399 imageViewer->setFeedback(tr("Transformations Unlocked"));
1400 }
1401
1402 imageViewer->refresh();
1403 }
1404
rotateLeft()1405 void Phototonic::rotateLeft() {
1406 Settings::rotation -= 90;
1407 if (Settings::rotation < 0)
1408 Settings::rotation = 270;
1409 imageViewer->refresh();
1410 imageViewer->setFeedback(tr("Rotation %1°").arg(QString::number(Settings::rotation)));
1411 }
1412
rotateRight()1413 void Phototonic::rotateRight() {
1414 Settings::rotation += 90;
1415 if (Settings::rotation > 270)
1416 Settings::rotation = 0;
1417 imageViewer->refresh();
1418 imageViewer->setFeedback(tr("Rotation %1°").arg(QString::number(Settings::rotation)));
1419 }
1420
flipVertical()1421 void Phototonic::flipVertical() {
1422 Settings::flipV = !Settings::flipV;
1423 imageViewer->refresh();
1424 imageViewer->setFeedback(Settings::flipV ? tr("Flipped Vertically") : tr("Unflipped Vertically"));
1425 }
1426
flipHorizontal()1427 void Phototonic::flipHorizontal() {
1428 Settings::flipH = !Settings::flipH;
1429 imageViewer->refresh();
1430 imageViewer->setFeedback(Settings::flipH ? tr("Flipped Horizontally") : tr("Unflipped Horizontally"));
1431 }
1432
cropImage()1433 void Phototonic::cropImage() {
1434 if (Settings::slideShowActive) {
1435 toggleSlideShow();
1436 }
1437
1438 if (!cropDialog) {
1439 cropDialog = new CropDialog(this, imageViewer);
1440 connect(cropDialog, SIGNAL(accepted()), this, SLOT(cleanupCropDialog()));
1441 connect(cropDialog, SIGNAL(rejected()), this, SLOT(cleanupCropDialog()));
1442 }
1443
1444 cropDialog->show();
1445 setInterfaceEnabled(false);
1446 cropDialog->applyCrop(0);
1447 }
1448
scaleImage()1449 void Phototonic::scaleImage() {
1450 if (Settings::slideShowActive) {
1451 toggleSlideShow();
1452 }
1453
1454 if (Settings::layoutMode == ThumbViewWidget && thumbsViewer->selectionModel()->selectedIndexes().size() < 1) {
1455 setStatus(tr("No selection"));
1456 return;
1457 }
1458
1459 resizeDialog = new ResizeDialog(this, imageViewer);
1460 connect(resizeDialog, SIGNAL(accepted()), this, SLOT(cleanupResizeDialog()));
1461 connect(resizeDialog, SIGNAL(rejected()), this, SLOT(cleanupResizeDialog()));
1462
1463 resizeDialog->show();
1464 setInterfaceEnabled(false);
1465 }
1466
freeRotateLeft()1467 void Phototonic::freeRotateLeft() {
1468 --Settings::rotation;
1469 if (Settings::rotation < 0)
1470 Settings::rotation = 359;
1471 imageViewer->refresh();
1472 imageViewer->setFeedback(tr("Rotation %1°").arg(QString::number(Settings::rotation)));
1473 }
1474
freeRotateRight()1475 void Phototonic::freeRotateRight() {
1476 ++Settings::rotation;
1477 if (Settings::rotation > 360)
1478 Settings::rotation = 1;
1479 imageViewer->refresh();
1480 imageViewer->setFeedback(tr("Rotation %1°").arg(QString::number(Settings::rotation)));
1481 }
1482
showColorsDialog()1483 void Phototonic::showColorsDialog() {
1484 if (Settings::slideShowActive) {
1485 toggleSlideShow();
1486 }
1487
1488 if (!colorsDialog) {
1489 colorsDialog = new ColorsDialog(this, imageViewer);
1490 connect(colorsDialog, SIGNAL(accepted()), this, SLOT(cleanupColorsDialog()));
1491 connect(colorsDialog, SIGNAL(rejected()), this, SLOT(cleanupColorsDialog()));
1492 }
1493
1494 Settings::colorsActive = true;
1495 colorsDialog->show();
1496 colorsDialog->applyColors(0);
1497 setInterfaceEnabled(false);
1498 }
1499
moveRight()1500 void Phototonic::moveRight() {
1501 imageViewer->keyMoveEvent(ImageViewer::MoveRight);
1502 }
1503
moveLeft()1504 void Phototonic::moveLeft() {
1505 imageViewer->keyMoveEvent(ImageViewer::MoveLeft);
1506 }
1507
moveUp()1508 void Phototonic::moveUp() {
1509 imageViewer->keyMoveEvent(ImageViewer::MoveUp);
1510 }
1511
moveDown()1512 void Phototonic::moveDown() {
1513 imageViewer->keyMoveEvent(ImageViewer::MoveDown);
1514 }
1515
setMirrorDisabled()1516 void Phototonic::setMirrorDisabled() {
1517 imageViewer->mirrorLayout = ImageViewer::LayNone;
1518 imageViewer->refresh();
1519 imageViewer->setFeedback(tr("Mirroring Disabled"));
1520 }
1521
setMirrorDual()1522 void Phototonic::setMirrorDual() {
1523 imageViewer->mirrorLayout = ImageViewer::LayDual;
1524 imageViewer->refresh();
1525 imageViewer->setFeedback(tr("Mirroring: Dual"));
1526 }
1527
setMirrorTriple()1528 void Phototonic::setMirrorTriple() {
1529 imageViewer->mirrorLayout = ImageViewer::LayTriple;
1530 imageViewer->refresh();
1531 imageViewer->setFeedback(tr("Mirroring: Triple"));
1532 }
1533
setMirrorVDual()1534 void Phototonic::setMirrorVDual() {
1535 imageViewer->mirrorLayout = ImageViewer::LayVDual;
1536 imageViewer->refresh();
1537 imageViewer->setFeedback(tr("Mirroring: Dual Vertical"));
1538 }
1539
setMirrorQuad()1540 void Phototonic::setMirrorQuad() {
1541 imageViewer->mirrorLayout = ImageViewer::LayQuad;
1542 imageViewer->refresh();
1543 imageViewer->setFeedback(tr("Mirroring: Quad"));
1544 }
1545
isValidPath(QString & path)1546 bool Phototonic::isValidPath(QString &path) {
1547 QDir checkPath(path);
1548 if (!checkPath.exists() || !checkPath.isReadable()) {
1549 return false;
1550 }
1551 return true;
1552 }
1553
pasteThumbs()1554 void Phototonic::pasteThumbs() {
1555 if (!copyCutThumbsCount) {
1556 return;
1557 }
1558
1559 QString destDir;
1560 if (copyMoveToDialog) {
1561 destDir = copyMoveToDialog->selectedPath;
1562 } else {
1563 if (QApplication::focusWidget() == bookmarks) {
1564 if (bookmarks->currentItem()) {
1565 destDir = bookmarks->currentItem()->toolTip(0);
1566 }
1567 } else {
1568 destDir = getSelectedPath();
1569 }
1570 }
1571
1572 if (!isValidPath(destDir)) {
1573 MessageBox msgBox(this);
1574 msgBox.critical(tr("Error"), tr("Can not copy or move to ") + destDir);
1575 selectCurrentViewDir();
1576 return;
1577 }
1578
1579 bool pasteInCurrDir = (Settings::currentDirectory == destDir);
1580 QFileInfo fileInfo;
1581 if (!Settings::isCopyOperation && pasteInCurrDir) {
1582 for (int thumb = 0; thumb < Settings::copyCutFileList.size(); ++thumb) {
1583 fileInfo = QFileInfo(Settings::copyCutFileList[thumb]);
1584 if (fileInfo.absolutePath() == destDir) {
1585 MessageBox msgBox(this);
1586 msgBox.critical(tr("Error"), tr("Can not move to the same directory"));
1587 return;
1588 }
1589 }
1590 }
1591
1592 CopyMoveDialog *copyMoveDialog = new CopyMoveDialog(this);
1593 copyMoveDialog->exec(thumbsViewer, destDir, pasteInCurrDir);
1594 if (pasteInCurrDir) {
1595 for (int thumb = 0; thumb < Settings::copyCutFileList.size(); ++thumb) {
1596 thumbsViewer->addThumb(Settings::copyCutFileList[thumb]);
1597 }
1598 } else {
1599 int row = copyMoveDialog->latestRow;
1600 if (thumbsViewer->thumbsViewerModel->rowCount()) {
1601 if (row >= thumbsViewer->thumbsViewerModel->rowCount()) {
1602 row = thumbsViewer->thumbsViewerModel->rowCount() - 1;
1603 }
1604
1605 thumbsViewer->setCurrentRow(row);
1606 thumbsViewer->selectThumbByRow(row);
1607 }
1608 }
1609
1610 QString state = QString((Settings::isCopyOperation ? tr("Copied") : tr("Moved")) + " " +
1611 tr("%n image(s)", "", copyMoveDialog->nFiles));
1612 setStatus(state);
1613 delete (copyMoveDialog);
1614 selectCurrentViewDir();
1615
1616 copyCutThumbsCount = 0;
1617 Settings::copyCutIndexList.clear();
1618 Settings::copyCutFileList.clear();
1619 pasteAction->setEnabled(false);
1620
1621 thumbsViewer->loadVisibleThumbs();
1622 }
1623
loadCurrentImage(int currentRow)1624 void Phototonic::loadCurrentImage(int currentRow) {
1625 bool wrapImageListTmp = Settings::wrapImageList;
1626 Settings::wrapImageList = false;
1627
1628 if (currentRow == thumbsViewer->thumbsViewerModel->rowCount()) {
1629 thumbsViewer->setCurrentRow(currentRow - 1);
1630 }
1631
1632 if (thumbsViewer->getNextRow() < 0 && currentRow > 0) {
1633 imageViewer->loadImage(thumbsViewer->thumbsViewerModel->item(currentRow - 1)->
1634 data(thumbsViewer->FileNameRole).toString());
1635 } else {
1636 if (thumbsViewer->thumbsViewerModel->rowCount() == 0) {
1637 hideViewer();
1638 refreshThumbs(true);
1639 return;
1640 }
1641
1642 if (currentRow > (thumbsViewer->thumbsViewerModel->rowCount() - 1))
1643 currentRow = thumbsViewer->thumbsViewerModel->rowCount() - 1;
1644
1645 imageViewer->loadImage(thumbsViewer->thumbsViewerModel->item(currentRow)->
1646 data(thumbsViewer->FileNameRole).toString());
1647 }
1648
1649 Settings::wrapImageList = wrapImageListTmp;
1650 thumbsViewer->setImageViewerWindowTitle();
1651 }
1652
deleteImages(bool trash)1653 void Phototonic::deleteImages(bool trash) {
1654 // Deleting selected thumbnails
1655 if (thumbsViewer->selectionModel()->selectedIndexes().size() < 1) {
1656 setStatus(tr("No selection"));
1657 return;
1658 }
1659
1660 if (Settings::deleteConfirm) {
1661 MessageBox msgBox(this);
1662 msgBox.setText(trash ? tr("Move selected images to the trash?") : tr("Permanently delete selected images?"));
1663 msgBox.setWindowTitle(trash ? tr("Move to Trash") : tr("Delete images"));
1664 msgBox.setIcon(MessageBox::Warning);
1665 msgBox.setStandardButtons(MessageBox::Yes | MessageBox::Cancel);
1666 msgBox.setDefaultButton(MessageBox::Yes);
1667 msgBox.setButtonText(MessageBox::Yes, tr("Yes"));
1668 msgBox.setButtonText(MessageBox::Cancel, tr("Cancel"));
1669
1670 if (msgBox.exec() != MessageBox::Yes) {
1671 return;
1672 }
1673 }
1674
1675 ProgressDialog *progressDialog = new ProgressDialog(this);
1676 progressDialog->show();
1677
1678 int deleteFilesCount = 0;
1679 bool deleteOk;
1680 QList<int> rows;
1681 int row;
1682 QModelIndexList indexesList;
1683 while ((indexesList = thumbsViewer->selectionModel()->selectedIndexes()).size()) {
1684 QString fileNameFullPath = thumbsViewer->thumbsViewerModel->item(
1685 indexesList.first().row())->data(thumbsViewer->FileNameRole).toString();
1686 progressDialog->opLabel->setText("Deleting " + fileNameFullPath);
1687 QString deleteError;
1688 if (trash) {
1689 deleteOk = Trash::moveToTrash(fileNameFullPath, deleteError) == Trash::Success;
1690 } else {
1691 QFile fileToRemove(fileNameFullPath);
1692 deleteOk = fileToRemove.remove();
1693 if (!deleteOk) {
1694 deleteError = fileToRemove.errorString();
1695 }
1696 }
1697
1698 ++deleteFilesCount;
1699 if (deleteOk) {
1700 row = indexesList.first().row();
1701 rows << row;
1702 thumbsViewer->thumbsViewerModel->removeRow(row);
1703 } else {
1704 MessageBox msgBox(this);
1705 msgBox.critical(tr("Error"),
1706 (trash ? tr("Failed to move image to the trash.") : tr("Failed to delete image.")) + "\n" +
1707 deleteError);
1708 break;
1709 }
1710
1711 Settings::filesList.removeOne(fileNameFullPath);
1712
1713 if (progressDialog->abortOp) {
1714 break;
1715 }
1716 }
1717
1718 if (thumbsViewer->thumbsViewerModel->rowCount() && rows.count()) {
1719 qSort(rows.begin(), rows.end());
1720 row = rows.at(0);
1721
1722 if (row >= thumbsViewer->thumbsViewerModel->rowCount()) {
1723 row = thumbsViewer->thumbsViewerModel->rowCount() - 1;
1724 }
1725
1726 thumbsViewer->setCurrentRow(row);
1727 thumbsViewer->selectThumbByRow(row);
1728 }
1729
1730 progressDialog->close();
1731 delete (progressDialog);
1732
1733 QString state = QString(tr("Deleted") + " " + tr("%n image(s)", "", deleteFilesCount));
1734 setStatus(state);
1735 }
1736
deleteFromViewer(bool trash)1737 void Phototonic::deleteFromViewer(bool trash) {
1738 if (imageViewer->isNewImage()) {
1739 showNewImageWarning();
1740 return;
1741 }
1742
1743 if (Settings::slideShowActive) {
1744 toggleSlideShow();
1745 }
1746 imageViewer->setCursorHiding(false);
1747
1748 bool ok;
1749 QFileInfo fileInfo = QFileInfo(imageViewer->viewerImageFullPath);
1750 QString fileName = fileInfo.fileName();
1751
1752 bool deleteConfirmed = true;
1753 if (Settings::deleteConfirm) {
1754 MessageBox msgBox(this);
1755 msgBox.setText(trash ? tr("Move %1 to the trash").arg(fileName) : tr("Permanently delete %1").arg(fileName));
1756 msgBox.setWindowTitle(trash ? tr("Move to Trash") : tr("Delete images"));
1757 msgBox.setIcon(MessageBox::Warning);
1758 msgBox.setStandardButtons(MessageBox::Yes | MessageBox::Cancel);
1759 msgBox.setDefaultButton(MessageBox::Yes);
1760 msgBox.setButtonText(MessageBox::Yes, tr("Yes"));
1761 msgBox.setButtonText(MessageBox::Cancel, tr("Cancel"));
1762
1763 if (msgBox.exec() != MessageBox::Yes) {
1764 deleteConfirmed = false;
1765 }
1766 }
1767
1768 if (deleteConfirmed) {
1769 int currentRow = thumbsViewer->getCurrentRow();
1770
1771 QString trashError;
1772 ok = trash ? (Trash::moveToTrash(imageViewer->viewerImageFullPath, trashError) == Trash::Success)
1773 : QFile::remove(imageViewer->viewerImageFullPath);
1774 if (ok) {
1775 thumbsViewer->thumbsViewerModel->removeRow(currentRow);
1776 imageViewer->setFeedback(tr("Deleted ") + fileName);
1777 } else {
1778 MessageBox msgBox(this);
1779 msgBox.critical(tr("Error"), trash ? trashError : tr("Failed to delete image"));
1780 if (isFullScreen()) {
1781 imageViewer->setCursorHiding(true);
1782 }
1783 return;
1784 }
1785
1786 loadCurrentImage(currentRow);
1787 }
1788 if (isFullScreen()) {
1789 imageViewer->setCursorHiding(true);
1790 }
1791 }
1792
1793 // Main delete operation
deleteOperation()1794 void Phototonic::deleteOperation() {
1795 if (QApplication::focusWidget() == thumbsViewer->imageTags->tagsTree) {
1796 thumbsViewer->imageTags->removeTag();
1797 return;
1798 }
1799
1800 if (QApplication::focusWidget() == bookmarks) {
1801 bookmarks->removeBookmark();
1802 return;
1803 }
1804
1805 if (QApplication::focusWidget() == fileSystemTree) {
1806 deleteDirectory(true);
1807 return;
1808 }
1809
1810 if (Settings::layoutMode == ImageViewWidget) {
1811 deleteFromViewer(true);
1812 return;
1813 }
1814
1815 deleteImages(true);
1816 }
1817
deletePermanentlyOperation()1818 void Phototonic::deletePermanentlyOperation() {
1819 if (QApplication::focusWidget() == fileSystemTree) {
1820 deleteDirectory(false);
1821 return;
1822 }
1823
1824 if (Settings::layoutMode == ImageViewWidget) {
1825 deleteFromViewer(false);
1826 return;
1827 }
1828
1829 deleteImages(false);
1830 }
1831
goTo(QString path)1832 void Phototonic::goTo(QString path) {
1833 Settings::isFileListLoaded = false;
1834 fileListWidget->clearSelection();
1835 thumbsViewer->setNeedToScroll(true);
1836 fileSystemTree->setCurrentIndex(fileSystemTree->fileSystemModel->index(path));
1837 Settings::currentDirectory = path;
1838 refreshThumbs(true);
1839 }
1840
goSelectedDir(const QModelIndex & idx)1841 void Phototonic::goSelectedDir(const QModelIndex &idx) {
1842 Settings::isFileListLoaded = false;
1843 fileListWidget->clearSelection();
1844 thumbsViewer->setNeedToScroll(true);
1845 Settings::currentDirectory = getSelectedPath();
1846 refreshThumbs(true);
1847 fileSystemTree->expand(idx);
1848 }
1849
goPathBarDir()1850 void Phototonic::goPathBarDir() {
1851 thumbsViewer->setNeedToScroll(true);
1852
1853 QDir checkPath(pathLineEdit->text());
1854 if (!checkPath.exists() || !checkPath.isReadable()) {
1855 MessageBox msgBox(this);
1856 msgBox.critical(tr("Error"), tr("Invalid Path:") + " " + pathLineEdit->text());
1857 pathLineEdit->setText(Settings::currentDirectory);
1858 return;
1859 }
1860
1861 Settings::currentDirectory = pathLineEdit->text();
1862 refreshThumbs(true);
1863 selectCurrentViewDir();
1864 }
1865
bookmarkClicked(QTreeWidgetItem * item,int col)1866 void Phototonic::bookmarkClicked(QTreeWidgetItem *item, int col) {
1867 goTo(item->toolTip(col));
1868 }
1869
setThumbsFilter()1870 void Phototonic::setThumbsFilter() {
1871 thumbsViewer->filterString = filterLineEdit->text();
1872 refreshThumbs(true);
1873 }
1874
clearThumbsFilter()1875 void Phototonic::clearThumbsFilter() {
1876 if (filterLineEdit->text() == "") {
1877 thumbsViewer->filterString = filterLineEdit->text();
1878 refreshThumbs(true);
1879 }
1880 }
1881
goBack()1882 void Phototonic::goBack() {
1883 if (currentHistoryIdx > 0) {
1884 needHistoryRecord = false;
1885 goTo(pathHistoryList.at(--currentHistoryIdx));
1886 goFrwdAction->setEnabled(true);
1887 if (currentHistoryIdx == 0)
1888 goBackAction->setEnabled(false);
1889 }
1890 }
1891
goForward()1892 void Phototonic::goForward() {
1893
1894 if (currentHistoryIdx < pathHistoryList.size() - 1) {
1895 needHistoryRecord = false;
1896 goTo(pathHistoryList.at(++currentHistoryIdx));
1897 if (currentHistoryIdx == (pathHistoryList.size() - 1))
1898 goFrwdAction->setEnabled(false);
1899 }
1900 }
1901
goUp()1902 void Phototonic::goUp() {
1903 QFileInfo fileInfo = QFileInfo(Settings::currentDirectory);
1904 goTo(fileInfo.dir().absolutePath());
1905 }
1906
goHome()1907 void Phototonic::goHome() {
1908 goTo(QDir::homePath());
1909 }
1910
setCopyCutActions(bool setEnabled)1911 void Phototonic::setCopyCutActions(bool setEnabled) {
1912 cutAction->setEnabled(setEnabled);
1913 copyAction->setEnabled(setEnabled);
1914 }
1915
updateActions()1916 void Phototonic::updateActions() {
1917 if (QApplication::focusWidget() == thumbsViewer) {
1918 bool hasSelectedItems = thumbsViewer->selectionModel()->selectedIndexes().size() > 0;
1919 setCopyCutActions(hasSelectedItems);
1920 } else if (QApplication::focusWidget() == bookmarks) {
1921 setCopyCutActions(false);
1922 } else if (QApplication::focusWidget() == fileSystemTree) {
1923 setCopyCutActions(false);
1924 } else if (Settings::layoutMode == ImageViewWidget || QApplication::focusWidget() == imageViewer->scrollArea) {
1925 setCopyCutActions(false);
1926 } else {
1927 setCopyCutActions(false);
1928 }
1929
1930 if (Settings::layoutMode == ImageViewWidget && !interfaceDisabled) {
1931 setViewerKeyEventsEnabled(true);
1932 fullScreenAction->setEnabled(true);
1933 CloseImageAction->setEnabled(true);
1934 } else {
1935 if (QApplication::focusWidget() == imageViewer->scrollArea) {
1936 setViewerKeyEventsEnabled(true);
1937 fullScreenAction->setEnabled(false);
1938 CloseImageAction->setEnabled(false);
1939 } else {
1940 setViewerKeyEventsEnabled(false);
1941 fullScreenAction->setEnabled(false);
1942 CloseImageAction->setEnabled(false);
1943 }
1944 }
1945 }
1946
writeSettings()1947 void Phototonic::writeSettings() {
1948 if (Settings::layoutMode == ThumbViewWidget) {
1949 Settings::appSettings->setValue(Settings::optionGeometry, saveGeometry());
1950 Settings::appSettings->setValue(Settings::optionWindowState, saveState());
1951 }
1952
1953 Settings::appSettings->setValue(Settings::optionThumbsSortFlags, (int) thumbsViewer->thumbsSortFlags);
1954 Settings::appSettings->setValue(Settings::optionThumbsZoomLevel, thumbsViewer->thumbSize);
1955 Settings::appSettings->setValue(Settings::optionFullScreenMode, (bool) Settings::isFullScreen);
1956 Settings::appSettings->setValue(Settings::optionViewerBackgroundColor, Settings::viewerBackgroundColor);
1957 Settings::appSettings->setValue(Settings::optionThumbsBackgroundColor, Settings::thumbsBackgroundColor);
1958 Settings::appSettings->setValue(Settings::optionThumbsTextColor, Settings::thumbsTextColor);
1959 Settings::appSettings->setValue(Settings::optionThumbsPagesReadCount, (int) Settings::thumbsPagesReadCount);
1960 Settings::appSettings->setValue(Settings::optionEnableAnimations, (bool) Settings::enableAnimations);
1961 Settings::appSettings->setValue(Settings::optionExifRotationEnabled, (bool) Settings::exifRotationEnabled);
1962 Settings::appSettings->setValue(Settings::optionExifThumbRotationEnabled,
1963 (bool) Settings::exifThumbRotationEnabled);
1964 Settings::appSettings->setValue(Settings::optionReverseMouseBehavior, (bool) Settings::reverseMouseBehavior);
1965 Settings::appSettings->setValue(Settings::optionDeleteConfirm, (bool) Settings::deleteConfirm);
1966 Settings::appSettings->setValue(Settings::optionShowHiddenFiles, (bool) Settings::showHiddenFiles);
1967 Settings::appSettings->setValue(Settings::optionWrapImageList, (bool) Settings::wrapImageList);
1968 Settings::appSettings->setValue(Settings::optionImageZoomFactor, Settings::imageZoomFactor);
1969 Settings::appSettings->setValue(Settings::optionShouldMaximize, (bool) isMaximized());
1970 Settings::appSettings->setValue(Settings::optionDefaultSaveQuality, Settings::defaultSaveQuality);
1971 Settings::appSettings->setValue(Settings::optionSlideShowDelay, Settings::slideShowDelay);
1972 Settings::appSettings->setValue(Settings::optionSlideShowRandom, (bool) Settings::slideShowRandom);
1973 Settings::appSettings->setValue(Settings::optionEditToolBarVisible, (bool) editToolBarVisible);
1974 Settings::appSettings->setValue(Settings::optionGoToolBarVisible, (bool) goToolBarVisible);
1975 Settings::appSettings->setValue(Settings::optionViewToolBarVisible, (bool) viewToolBarVisible);
1976 Settings::appSettings->setValue(Settings::optionImageToolBarVisible, (bool) imageToolBarVisible);
1977 Settings::appSettings->setValue(Settings::optionFileSystemDockVisible, (bool) Settings::fileSystemDockVisible);
1978 Settings::appSettings->setValue(Settings::optionImageInfoDockVisible, (bool) Settings::imageInfoDockVisible);
1979 Settings::appSettings->setValue(Settings::optionBookmarksDockVisible, (bool) Settings::bookmarksDockVisible);
1980 Settings::appSettings->setValue(Settings::optionTagsDockVisible, (bool) Settings::tagsDockVisible);
1981 Settings::appSettings->setValue(Settings::optionImagePreviewDockVisible, (bool) Settings::imagePreviewDockVisible);
1982 Settings::appSettings->setValue(Settings::optionStartupDir, (int) Settings::startupDir);
1983 Settings::appSettings->setValue(Settings::optionSpecifiedStartDir, Settings::specifiedStartDir);
1984 Settings::appSettings->setValue(Settings::optionThumbsBackgroundImage, Settings::thumbsBackgroundImage);
1985 Settings::appSettings->setValue(Settings::optionLastDir,
1986 Settings::startupDir == Settings::RememberLastDir ? Settings::currentDirectory
1987 : "");
1988 Settings::appSettings->setValue(Settings::optionShowImageName, (bool) Settings::showImageName);
1989 Settings::appSettings->setValue(Settings::optionSmallToolbarIcons, (bool) Settings::smallToolbarIcons);
1990 Settings::appSettings->setValue(Settings::optionHideDockTitlebars, (bool) Settings::hideDockTitlebars);
1991 Settings::appSettings->setValue(Settings::optionShowViewerToolbar, (bool) Settings::showViewerToolbar);
1992 Settings::appSettings->setValue(Settings::optionSetWindowIcon, (bool) Settings::setWindowIcon);
1993
1994 /* Action shortcuts */
1995 Settings::appSettings->beginGroup(Settings::optionShortcuts);
1996 QMapIterator<QString, QAction *> shortcutsIterator(Settings::actionKeys);
1997 while (shortcutsIterator.hasNext()) {
1998 shortcutsIterator.next();
1999 Settings::appSettings->setValue(shortcutsIterator.key(), shortcutsIterator.value()->shortcut().toString());
2000 }
2001 Settings::appSettings->endGroup();
2002
2003 /* External apps */
2004 Settings::appSettings->beginGroup(Settings::optionExternalApps);
2005 Settings::appSettings->remove("");
2006 QMapIterator<QString, QString> eaIter(Settings::externalApps);
2007 while (eaIter.hasNext()) {
2008 eaIter.next();
2009 Settings::appSettings->setValue(eaIter.key(), eaIter.value());
2010 }
2011 Settings::appSettings->endGroup();
2012
2013 /* save bookmarks */
2014 int idx = 0;
2015 Settings::appSettings->beginGroup(Settings::optionCopyMoveToPaths);
2016 Settings::appSettings->remove("");
2017 QSetIterator<QString> pathsIter(Settings::bookmarkPaths);
2018 while (pathsIter.hasNext()) {
2019 Settings::appSettings->setValue("path" + QString::number(++idx), pathsIter.next());
2020 }
2021 Settings::appSettings->endGroup();
2022
2023 /* save known Tags */
2024 idx = 0;
2025 Settings::appSettings->beginGroup(Settings::optionKnownTags);
2026 Settings::appSettings->remove("");
2027 QSetIterator<QString> tagsIter(Settings::knownTags);
2028 while (tagsIter.hasNext()) {
2029 Settings::appSettings->setValue("tag" + QString::number(++idx), tagsIter.next());
2030 }
2031 Settings::appSettings->endGroup();
2032 }
2033
readSettings()2034 void Phototonic::readSettings() {
2035 initComplete = false;
2036 needThumbsRefresh = false;
2037
2038 if (!Settings::appSettings->contains(Settings::optionThumbsZoomLevel)) {
2039 resize(800, 600);
2040 Settings::appSettings->setValue(Settings::optionThumbsSortFlags, (int) 0);
2041 Settings::appSettings->setValue(Settings::optionThumbsZoomLevel, (int) 200);
2042 Settings::appSettings->setValue(Settings::optionFullScreenMode, (bool) false);
2043 Settings::appSettings->setValue(Settings::optionViewerBackgroundColor, QColor(25, 25, 25));
2044 Settings::appSettings->setValue(Settings::optionThumbsBackgroundColor, QColor(200, 200, 200));
2045 Settings::appSettings->setValue(Settings::optionThumbsTextColor, QColor(25, 25, 25));
2046 Settings::appSettings->setValue(Settings::optionThumbsPagesReadCount, (int) 2);
2047 Settings::appSettings->setValue(Settings::optionViewerZoomOutFlags, (int) 1);
2048 Settings::appSettings->setValue(Settings::optionViewerZoomInFlags, (int) 0);
2049 Settings::appSettings->setValue(Settings::optionWrapImageList, (bool) false);
2050 Settings::appSettings->setValue(Settings::optionImageZoomFactor, (float) 1.0);
2051 Settings::appSettings->setValue(Settings::optionDefaultSaveQuality, (int) 90);
2052 Settings::appSettings->setValue(Settings::optionEnableAnimations, (bool) true);
2053 Settings::appSettings->setValue(Settings::optionExifRotationEnabled, (bool) true);
2054 Settings::appSettings->setValue(Settings::optionExifThumbRotationEnabled, (bool) false);
2055 Settings::appSettings->setValue(Settings::optionReverseMouseBehavior, (bool) false);
2056 Settings::appSettings->setValue(Settings::optionDeleteConfirm, (bool) true);
2057 Settings::appSettings->setValue(Settings::optionShowHiddenFiles, (bool) false);
2058 Settings::appSettings->setValue(Settings::optionSlideShowDelay, (int) 5);
2059 Settings::appSettings->setValue(Settings::optionSlideShowRandom, (bool) false);
2060 Settings::appSettings->setValue(Settings::optionEditToolBarVisible, (bool) true);
2061 Settings::appSettings->setValue(Settings::optionGoToolBarVisible, (bool) true);
2062 Settings::appSettings->setValue(Settings::optionViewToolBarVisible, (bool) true);
2063 Settings::appSettings->setValue(Settings::optionImageToolBarVisible, (bool) false);
2064 Settings::appSettings->setValue(Settings::optionFileSystemDockVisible, (bool) true);
2065 Settings::appSettings->setValue(Settings::optionBookmarksDockVisible, (bool) true);
2066 Settings::appSettings->setValue(Settings::optionTagsDockVisible, (bool) true);
2067 Settings::appSettings->setValue(Settings::optionImagePreviewDockVisible, (bool) true);
2068 Settings::appSettings->setValue(Settings::optionImageInfoDockVisible, (bool) true);
2069 Settings::appSettings->setValue(Settings::optionShowImageName, (bool) false);
2070 Settings::appSettings->setValue(Settings::optionSmallToolbarIcons, (bool) false);
2071 Settings::appSettings->setValue(Settings::optionHideDockTitlebars, (bool) false);
2072 Settings::appSettings->setValue(Settings::optionShowViewerToolbar, (bool) false);
2073 Settings::appSettings->setValue(Settings::optionSmallToolbarIcons, (bool) true);
2074 Settings::bookmarkPaths.insert(QDir::homePath());
2075 const QString picturesLocation = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
2076 if (!picturesLocation.isEmpty()) {
2077 Settings::bookmarkPaths.insert(picturesLocation);
2078 }
2079 }
2080
2081 Settings::viewerBackgroundColor = Settings::appSettings->value(
2082 Settings::optionViewerBackgroundColor).value<QColor>();
2083 Settings::enableAnimations = Settings::appSettings->value(Settings::optionEnableAnimations).toBool();
2084 Settings::exifRotationEnabled = Settings::appSettings->value(Settings::optionExifRotationEnabled).toBool();
2085 Settings::exifThumbRotationEnabled = Settings::appSettings->value(
2086 Settings::optionExifThumbRotationEnabled).toBool();
2087 Settings::reverseMouseBehavior = Settings::appSettings->value(Settings::optionReverseMouseBehavior).toBool();
2088 Settings::deleteConfirm = Settings::appSettings->value(Settings::optionDeleteConfirm).toBool();
2089 Settings::showHiddenFiles = Settings::appSettings->value(Settings::optionShowHiddenFiles).toBool();
2090 Settings::wrapImageList = Settings::appSettings->value(Settings::optionWrapImageList).toBool();
2091 Settings::imageZoomFactor = Settings::appSettings->value(Settings::optionImageZoomFactor).toFloat();
2092 Settings::zoomOutFlags = Settings::appSettings->value(Settings::optionViewerZoomOutFlags).toUInt();
2093 Settings::zoomInFlags = Settings::appSettings->value(Settings::optionViewerZoomInFlags).toUInt();
2094 Settings::rotation = 0;
2095 Settings::keepTransform = false;
2096 shouldMaximize = Settings::appSettings->value(Settings::optionShouldMaximize).toBool();
2097 Settings::flipH = false;
2098 Settings::flipV = false;
2099 Settings::defaultSaveQuality = Settings::appSettings->value(Settings::optionDefaultSaveQuality).toInt();
2100 Settings::slideShowDelay = Settings::appSettings->value(Settings::optionSlideShowDelay).toInt();
2101 Settings::slideShowRandom = Settings::appSettings->value(Settings::optionSlideShowRandom).toBool();
2102 Settings::slideShowActive = false;
2103 editToolBarVisible = Settings::appSettings->value(Settings::optionEditToolBarVisible).toBool();
2104 goToolBarVisible = Settings::appSettings->value(Settings::optionGoToolBarVisible).toBool();
2105 viewToolBarVisible = Settings::appSettings->value(Settings::optionViewToolBarVisible).toBool();
2106 imageToolBarVisible = Settings::appSettings->value(Settings::optionImageToolBarVisible).toBool();
2107 Settings::fileSystemDockVisible = Settings::appSettings->value(Settings::optionFileSystemDockVisible).toBool();
2108 Settings::bookmarksDockVisible = Settings::appSettings->value(Settings::optionBookmarksDockVisible).toBool();
2109 Settings::tagsDockVisible = Settings::appSettings->value(Settings::optionTagsDockVisible).toBool();
2110 Settings::imagePreviewDockVisible = Settings::appSettings->value(Settings::optionImagePreviewDockVisible).toBool();
2111 Settings::imageInfoDockVisible = Settings::appSettings->value(Settings::optionImageInfoDockVisible).toBool();
2112 Settings::startupDir = (Settings::StartupDir) Settings::appSettings->value(Settings::optionStartupDir).toInt();
2113 Settings::specifiedStartDir = Settings::appSettings->value(Settings::optionSpecifiedStartDir).toString();
2114 Settings::thumbsBackgroundImage = Settings::appSettings->value(Settings::optionThumbsBackgroundImage).toString();
2115 Settings::showImageName = Settings::appSettings->value(Settings::optionShowImageName).toBool();
2116 Settings::smallToolbarIcons = Settings::appSettings->value(Settings::optionSmallToolbarIcons).toBool();
2117 Settings::hideDockTitlebars = Settings::appSettings->value(Settings::optionHideDockTitlebars).toBool();
2118 Settings::showViewerToolbar = Settings::appSettings->value(Settings::optionShowViewerToolbar).toBool();
2119 Settings::setWindowIcon = Settings::appSettings->value(Settings::optionSetWindowIcon).toBool();
2120
2121 /* read external apps */
2122 Settings::appSettings->beginGroup(Settings::optionExternalApps);
2123 QStringList extApps = Settings::appSettings->childKeys();
2124 for (int i = 0; i < extApps.size(); ++i) {
2125 Settings::externalApps[extApps.at(i)] = Settings::appSettings->value(extApps.at(i)).toString();
2126 }
2127 Settings::appSettings->endGroup();
2128
2129 /* read bookmarks */
2130 Settings::appSettings->beginGroup(Settings::optionCopyMoveToPaths);
2131 QStringList paths = Settings::appSettings->childKeys();
2132 for (int i = 0; i < paths.size(); ++i) {
2133 Settings::bookmarkPaths.insert(Settings::appSettings->value(paths.at(i)).toString());
2134 }
2135 Settings::appSettings->endGroup();
2136
2137 /* read known tags */
2138 Settings::appSettings->beginGroup(Settings::optionKnownTags);
2139 QStringList tags = Settings::appSettings->childKeys();
2140 for (int i = 0; i < tags.size(); ++i) {
2141 Settings::knownTags.insert(Settings::appSettings->value(tags.at(i)).toString());
2142 }
2143 Settings::appSettings->endGroup();
2144
2145 Settings::isFileListLoaded = false;
2146 }
2147
setupDocks()2148 void Phototonic::setupDocks() {
2149
2150 addDockWidget(Qt::RightDockWidgetArea, imageInfoDock);
2151 addDockWidget(Qt::RightDockWidgetArea, tagsDock);
2152
2153 menuBar()->addMenu(createPopupMenu())->setText(tr("Window"));
2154 menuBar()->addSeparator();
2155 helpMenu = menuBar()->addMenu(tr("&Help"));
2156 helpMenu->addAction(aboutAction);
2157
2158 fileSystemDockOrigWidget = fileSystemDock->titleBarWidget();
2159 bookmarksDockOrigWidget = bookmarksDock->titleBarWidget();
2160 imagePreviewDockOrigWidget = imagePreviewDock->titleBarWidget();
2161 tagsDockOrigWidget = tagsDock->titleBarWidget();
2162 imageInfoDockOrigWidget = imageInfoDock->titleBarWidget();
2163 fileSystemDockEmptyWidget = new QWidget;
2164 bookmarksDockEmptyWidget = new QWidget;
2165 imagePreviewDockEmptyWidget = new QWidget;
2166 tagsDockEmptyWidget = new QWidget;
2167 imageInfoDockEmptyWidget = new QWidget;
2168 lockDocks();
2169 }
2170
lockDocks()2171 void Phototonic::lockDocks() {
2172 if (initComplete)
2173 Settings::hideDockTitlebars = lockDocksAction->isChecked();
2174
2175 if (Settings::hideDockTitlebars) {
2176 fileSystemDock->setTitleBarWidget(fileSystemDockEmptyWidget);
2177 bookmarksDock->setTitleBarWidget(bookmarksDockEmptyWidget);
2178 imagePreviewDock->setTitleBarWidget(imagePreviewDockEmptyWidget);
2179 tagsDock->setTitleBarWidget(tagsDockEmptyWidget);
2180 imageInfoDock->setTitleBarWidget(imageInfoDockEmptyWidget);
2181 } else {
2182 fileSystemDock->setTitleBarWidget(fileSystemDockOrigWidget);
2183 bookmarksDock->setTitleBarWidget(bookmarksDockOrigWidget);
2184 imagePreviewDock->setTitleBarWidget(imagePreviewDockOrigWidget);
2185 tagsDock->setTitleBarWidget(tagsDockOrigWidget);
2186 imageInfoDock->setTitleBarWidget(imageInfoDockOrigWidget);
2187 }
2188 }
2189
createPopupMenu()2190 QMenu *Phototonic::createPopupMenu() {
2191 QMenu *extraActsMenu = QMainWindow::createPopupMenu();
2192 extraActsMenu->addSeparator();
2193 extraActsMenu->addAction(smallToolbarIconsAction);
2194 extraActsMenu->addAction(lockDocksAction);
2195 return extraActsMenu;
2196 }
2197
loadShortcuts()2198 void Phototonic::loadShortcuts() {
2199 // Add customizable key shortcut actions
2200 Settings::actionKeys[thumbsGoToTopAction->objectName()] = thumbsGoToTopAction;
2201 Settings::actionKeys[thumbsGoToBottomAction->objectName()] = thumbsGoToBottomAction;
2202 Settings::actionKeys[CloseImageAction->objectName()] = CloseImageAction;
2203 Settings::actionKeys[fullScreenAction->objectName()] = fullScreenAction;
2204 Settings::actionKeys[settingsAction->objectName()] = settingsAction;
2205 Settings::actionKeys[exitAction->objectName()] = exitAction;
2206 Settings::actionKeys[thumbsZoomInAction->objectName()] = thumbsZoomInAction;
2207 Settings::actionKeys[thumbsZoomOutAction->objectName()] = thumbsZoomOutAction;
2208 Settings::actionKeys[cutAction->objectName()] = cutAction;
2209 Settings::actionKeys[copyAction->objectName()] = copyAction;
2210 Settings::actionKeys[nextImageAction->objectName()] = nextImageAction;
2211 Settings::actionKeys[prevImageAction->objectName()] = prevImageAction;
2212 Settings::actionKeys[deletePermanentlyAction->objectName()] = deletePermanentlyAction;
2213 Settings::actionKeys[deleteAction->objectName()] = deleteAction;
2214 Settings::actionKeys[saveAction->objectName()] = saveAction;
2215 Settings::actionKeys[saveAsAction->objectName()] = saveAsAction;
2216 Settings::actionKeys[keepTransformAction->objectName()] = keepTransformAction;
2217 Settings::actionKeys[keepZoomAction->objectName()] = keepZoomAction;
2218 Settings::actionKeys[showClipboardAction->objectName()] = showClipboardAction;
2219 Settings::actionKeys[copyImageAction->objectName()] = copyImageAction;
2220 Settings::actionKeys[pasteImageAction->objectName()] = pasteImageAction;
2221 Settings::actionKeys[renameAction->objectName()] = renameAction;
2222 Settings::actionKeys[refreshAction->objectName()] = refreshAction;
2223 Settings::actionKeys[pasteAction->objectName()] = pasteAction;
2224 Settings::actionKeys[goBackAction->objectName()] = goBackAction;
2225 Settings::actionKeys[goFrwdAction->objectName()] = goFrwdAction;
2226 Settings::actionKeys[slideShowAction->objectName()] = slideShowAction;
2227 Settings::actionKeys[firstImageAction->objectName()] = firstImageAction;
2228 Settings::actionKeys[lastImageAction->objectName()] = lastImageAction;
2229 Settings::actionKeys[randomImageAction->objectName()] = randomImageAction;
2230 Settings::actionKeys[viewImageAction->objectName()] = viewImageAction;
2231 Settings::actionKeys[zoomOutAction->objectName()] = zoomOutAction;
2232 Settings::actionKeys[zoomInAction->objectName()] = zoomInAction;
2233 Settings::actionKeys[resetZoomAction->objectName()] = resetZoomAction;
2234 Settings::actionKeys[origZoomAction->objectName()] = origZoomAction;
2235 Settings::actionKeys[rotateLeftAction->objectName()] = rotateLeftAction;
2236 Settings::actionKeys[rotateRightAction->objectName()] = rotateRightAction;
2237 Settings::actionKeys[freeRotateLeftAction->objectName()] = freeRotateLeftAction;
2238 Settings::actionKeys[freeRotateRightAction->objectName()] = freeRotateRightAction;
2239 Settings::actionKeys[flipHorizontalAction->objectName()] = flipHorizontalAction;
2240 Settings::actionKeys[flipVerticalAction->objectName()] = flipVerticalAction;
2241 Settings::actionKeys[cropAction->objectName()] = cropAction;
2242 Settings::actionKeys[cropToSelectionAction->objectName()] = cropToSelectionAction;
2243 Settings::actionKeys[colorsAction->objectName()] = colorsAction;
2244 Settings::actionKeys[mirrorDisabledAction->objectName()] = mirrorDisabledAction;
2245 Settings::actionKeys[mirrorDualAction->objectName()] = mirrorDualAction;
2246 Settings::actionKeys[mirrorTripleAction->objectName()] = mirrorTripleAction;
2247 Settings::actionKeys[mirrorDualVerticalAction->objectName()] = mirrorDualVerticalAction;
2248 Settings::actionKeys[mirrorQuadAction->objectName()] = mirrorQuadAction;
2249 Settings::actionKeys[moveDownAction->objectName()] = moveDownAction;
2250 Settings::actionKeys[moveUpAction->objectName()] = moveUpAction;
2251 Settings::actionKeys[moveRightAction->objectName()] = moveRightAction;
2252 Settings::actionKeys[moveLeftAction->objectName()] = moveLeftAction;
2253 Settings::actionKeys[copyToAction->objectName()] = copyToAction;
2254 Settings::actionKeys[moveToAction->objectName()] = moveToAction;
2255 Settings::actionKeys[goUpAction->objectName()] = goUpAction;
2256 Settings::actionKeys[resizeAction->objectName()] = resizeAction;
2257 Settings::actionKeys[filterImagesFocusAction->objectName()] = filterImagesFocusAction;
2258 Settings::actionKeys[setPathFocusAction->objectName()] = setPathFocusAction;
2259 Settings::actionKeys[invertSelectionAction->objectName()] = invertSelectionAction;
2260 Settings::actionKeys[includeSubDirectoriesAction->objectName()] = includeSubDirectoriesAction;
2261 Settings::actionKeys[createDirectoryAction->objectName()] = createDirectoryAction;
2262 Settings::actionKeys[addBookmarkAction->objectName()] = addBookmarkAction;
2263 Settings::actionKeys[removeMetadataAction->objectName()] = removeMetadataAction;
2264 Settings::actionKeys[externalAppsAction->objectName()] = externalAppsAction;
2265 Settings::actionKeys[goHomeAction->objectName()] = goHomeAction;
2266 Settings::actionKeys[sortByNameAction->objectName()] = sortByNameAction;
2267 Settings::actionKeys[sortBySizeAction->objectName()] = sortBySizeAction;
2268 Settings::actionKeys[sortByTimeAction->objectName()] = sortByTimeAction;
2269 Settings::actionKeys[sortByTypeAction->objectName()] = sortByTypeAction;
2270 Settings::actionKeys[sortReverseAction->objectName()] = sortReverseAction;
2271 Settings::actionKeys[showHiddenFilesAction->objectName()] = showHiddenFilesAction;
2272 Settings::actionKeys[showViewerToolbarAction->objectName()] = showViewerToolbarAction;
2273
2274 Settings::appSettings->beginGroup(Settings::optionShortcuts);
2275 QStringList groupKeys = Settings::appSettings->childKeys();
2276
2277 if (groupKeys.size()) {
2278 if (groupKeys.contains(thumbsGoToTopAction->text())) {
2279 QMapIterator<QString, QAction *> key(Settings::actionKeys);
2280 while (key.hasNext()) {
2281 key.next();
2282 if (groupKeys.contains(key.value()->text())) {
2283 key.value()->setShortcut(Settings::appSettings->value(key.value()->text()).toString());
2284 Settings::appSettings->remove(key.value()->text());
2285 Settings::appSettings->setValue(key.key(), key.value()->shortcut().toString());
2286 }
2287 }
2288 } else {
2289 for (int i = 0; i < groupKeys.size(); ++i) {
2290 if (Settings::actionKeys.value(groupKeys.at(i)))
2291 Settings::actionKeys.value(groupKeys.at(i))->setShortcut
2292 (Settings::appSettings->value(groupKeys.at(i)).toString());
2293 }
2294 }
2295 } else {
2296 thumbsGoToTopAction->setShortcut(QKeySequence("Ctrl+Home"));
2297 thumbsGoToBottomAction->setShortcut(QKeySequence("Ctrl+End"));
2298 CloseImageAction->setShortcut(Qt::Key_Escape);
2299 fullScreenAction->setShortcut(QKeySequence("Alt+Return"));
2300 settingsAction->setShortcut(QKeySequence("Ctrl+P"));
2301 exitAction->setShortcut(QKeySequence("Ctrl+Q"));
2302 cutAction->setShortcut(QKeySequence("Ctrl+X"));
2303 copyAction->setShortcut(QKeySequence("Ctrl+C"));
2304 deleteAction->setShortcut(QKeySequence("Del"));
2305 deletePermanentlyAction->setShortcut(QKeySequence("Shift+Del"));
2306 saveAction->setShortcut(QKeySequence("Ctrl+S"));
2307 copyImageAction->setShortcut(QKeySequence("Ctrl+Shift+C"));
2308 pasteImageAction->setShortcut(QKeySequence("Ctrl+Shift+V"));
2309 renameAction->setShortcut(QKeySequence("F2"));
2310 refreshAction->setShortcut(QKeySequence("F5"));
2311 pasteAction->setShortcut(QKeySequence("Ctrl+V"));
2312 goBackAction->setShortcut(QKeySequence("Alt+Left"));
2313 goFrwdAction->setShortcut(QKeySequence("Alt+Right"));
2314 goUpAction->setShortcut(QKeySequence("Alt+Up"));
2315 slideShowAction->setShortcut(QKeySequence("Ctrl+W"));
2316 nextImageAction->setShortcut(QKeySequence("PgDown"));
2317 prevImageAction->setShortcut(QKeySequence("PgUp"));
2318 firstImageAction->setShortcut(QKeySequence("Home"));
2319 lastImageAction->setShortcut(QKeySequence("End"));
2320 randomImageAction->setShortcut(QKeySequence("Ctrl+D"));
2321 viewImageAction->setShortcut(QKeySequence("Return"));
2322 zoomOutAction->setShortcut(QKeySequence("-"));
2323 zoomInAction->setShortcut(QKeySequence("+"));
2324 resetZoomAction->setShortcut(QKeySequence("*"));
2325 origZoomAction->setShortcut(QKeySequence("/"));
2326 rotateLeftAction->setShortcut(QKeySequence("Ctrl+Left"));
2327 rotateRightAction->setShortcut(QKeySequence("Ctrl+Right"));
2328 freeRotateLeftAction->setShortcut(QKeySequence("Ctrl+Shift+Left"));
2329 freeRotateRightAction->setShortcut(QKeySequence("Ctrl+Shift+Right"));
2330 flipHorizontalAction->setShortcut(QKeySequence("Ctrl+Down"));
2331 flipVerticalAction->setShortcut(QKeySequence("Ctrl+Up"));
2332 cropAction->setShortcut(QKeySequence("Ctrl+G"));
2333 cropToSelectionAction->setShortcut(QKeySequence("Ctrl+R"));
2334 colorsAction->setShortcut(QKeySequence("Ctrl+O"));
2335 mirrorDisabledAction->setShortcut(QKeySequence("Ctrl+1"));
2336 mirrorDualAction->setShortcut(QKeySequence("Ctrl+2"));
2337 mirrorTripleAction->setShortcut(QKeySequence("Ctrl+3"));
2338 mirrorDualVerticalAction->setShortcut(QKeySequence("Ctrl+4"));
2339 mirrorQuadAction->setShortcut(QKeySequence("Ctrl+5"));
2340 moveDownAction->setShortcut(QKeySequence("Down"));
2341 moveUpAction->setShortcut(QKeySequence("Up"));
2342 moveLeftAction->setShortcut(QKeySequence("Left"));
2343 moveRightAction->setShortcut(QKeySequence("Right"));
2344 copyToAction->setShortcut(QKeySequence("Ctrl+Y"));
2345 moveToAction->setShortcut(QKeySequence("Ctrl+M"));
2346 resizeAction->setShortcut(QKeySequence("Ctrl+I"));
2347 filterImagesFocusAction->setShortcut(QKeySequence("Ctrl+F"));
2348 setPathFocusAction->setShortcut(QKeySequence("Ctrl+L"));
2349 keepTransformAction->setShortcut(QKeySequence("Ctrl+K"));
2350 showHiddenFilesAction->setShortcut(QKeySequence("Ctrl+H"));
2351 }
2352
2353 Settings::appSettings->endGroup();
2354 }
2355
closeEvent(QCloseEvent * event)2356 void Phototonic::closeEvent(QCloseEvent *event) {
2357 thumbsViewer->abort();
2358 writeSettings();
2359 hide();
2360 if (!QApplication::clipboard()->image().isNull()) {
2361 QApplication::clipboard()->clear();
2362 }
2363 event->accept();
2364 }
2365
setStatus(QString state)2366 void Phototonic::setStatus(QString state) {
2367 statusLabel->setText(" " + state + " ");
2368 }
2369
mouseDoubleClickEvent(QMouseEvent * event)2370 void Phototonic::mouseDoubleClickEvent(QMouseEvent *event) {
2371 if (interfaceDisabled) {
2372 return;
2373 }
2374
2375 if (event->button() == Qt::LeftButton) {
2376 if (Settings::layoutMode == ImageViewWidget) {
2377 if (Settings::reverseMouseBehavior) {
2378 fullScreenAction->setChecked(!(fullScreenAction->isChecked()));
2379 toggleFullScreen();
2380 event->accept();
2381 } else if (CloseImageAction->isEnabled()) {
2382 hideViewer();
2383 event->accept();
2384 }
2385 } else {
2386 if (QApplication::focusWidget() == thumbsViewer->imagePreview->scrollArea) {
2387 viewImage();
2388 }
2389 }
2390 }
2391 }
2392
mousePressEvent(QMouseEvent * event)2393 void Phototonic::mousePressEvent(QMouseEvent *event) {
2394 if (interfaceDisabled) {
2395 return;
2396 }
2397
2398 if (Settings::layoutMode == ImageViewWidget) {
2399 if (event->button() == Qt::MiddleButton) {
2400
2401 if (event->modifiers() == Qt::ShiftModifier) {
2402 origZoom();
2403 event->accept();
2404 return;
2405 }
2406 if (event->modifiers() == Qt::ControlModifier) {
2407 resetZoom();
2408 event->accept();
2409 return;
2410 }
2411
2412 if (Settings::reverseMouseBehavior && CloseImageAction->isEnabled()) {
2413 hideViewer();
2414 event->accept();
2415 } else {
2416 fullScreenAction->setChecked(!(fullScreenAction->isChecked()));
2417 toggleFullScreen();
2418 event->accept();
2419 }
2420 }
2421 } else if (QApplication::focusWidget() == thumbsViewer->imagePreview->scrollArea) {
2422 if (event->button() == Qt::MiddleButton) {
2423 viewImage();
2424 }
2425 }
2426 }
2427
newImage()2428 void Phototonic::newImage() {
2429 if (Settings::layoutMode == ThumbViewWidget) {
2430 showViewer();
2431 }
2432
2433 imageViewer->loadImage("");
2434 }
2435
setDocksVisibility(bool visible)2436 void Phototonic::setDocksVisibility(bool visible) {
2437 fileSystemDock->setVisible(visible ? Settings::fileSystemDockVisible : false);
2438 bookmarksDock->setVisible(visible ? Settings::bookmarksDockVisible : false);
2439 imagePreviewDock->setVisible(visible ? Settings::imagePreviewDockVisible : false);
2440 tagsDock->setVisible(visible ? Settings::tagsDockVisible : false);
2441 imageInfoDock->setVisible(visible ? Settings::imageInfoDockVisible : false);
2442
2443 menuBar()->setVisible(visible);
2444 menuBar()->setDisabled(!visible);
2445 statusBar()->setVisible(visible);
2446
2447 editToolBar->setVisible(visible ? editToolBarVisible : false);
2448 goToolBar->setVisible(visible ? goToolBarVisible : false);
2449 viewToolBar->setVisible(visible ? viewToolBarVisible : false);
2450 imageToolBar->setVisible(visible ? imageToolBarVisible : Settings::showViewerToolbar);
2451 addToolBar(imageToolBar);
2452
2453 setContextMenuPolicy(Qt::PreventContextMenu);
2454 }
2455
viewImage()2456 void Phototonic::viewImage() {
2457 if (Settings::layoutMode == ImageViewWidget) {
2458 hideViewer();
2459 return;
2460 }
2461
2462 if (QApplication::focusWidget() == fileSystemTree) {
2463 goSelectedDir(fileSystemTree->getCurrentIndex());
2464 return;
2465 } else if (QApplication::focusWidget() == thumbsViewer
2466 || QApplication::focusWidget() == thumbsViewer->imagePreview->scrollArea
2467 || QApplication::focusWidget() == imageViewer->scrollArea) {
2468 QModelIndex selectedImageIndex;
2469 QModelIndexList selectedIndexes = thumbsViewer->selectionModel()->selectedIndexes();
2470 if (selectedIndexes.size() > 0) {
2471 selectedImageIndex = selectedIndexes.first();
2472 } else {
2473 if (thumbsViewer->thumbsViewerModel->rowCount() == 0) {
2474 setStatus(tr("No images"));
2475 return;
2476 }
2477
2478 selectedImageIndex = thumbsViewer->thumbsViewerModel->indexFromItem(
2479 thumbsViewer->thumbsViewerModel->item(0));
2480 thumbsViewer->selectionModel()->select(selectedImageIndex, QItemSelectionModel::Toggle);
2481 thumbsViewer->setCurrentRow(0);
2482 }
2483
2484 loadSelectedThumbImage(selectedImageIndex);
2485 return;
2486 } else if (QApplication::focusWidget() == filterLineEdit) {
2487 setThumbsFilter();
2488 return;
2489 } else if (QApplication::focusWidget() == pathLineEdit) {
2490 goPathBarDir();
2491 return;
2492 }
2493 }
2494
setEditToolBarVisibility()2495 void Phototonic::setEditToolBarVisibility() {
2496 editToolBarVisible = editToolBar->isVisible();
2497 }
2498
setGoToolBarVisibility()2499 void Phototonic::setGoToolBarVisibility() {
2500 goToolBarVisible = goToolBar->isVisible();
2501 }
2502
setViewToolBarVisibility()2503 void Phototonic::setViewToolBarVisibility() {
2504 viewToolBarVisible = viewToolBar->isVisible();
2505 }
2506
setImageToolBarVisibility()2507 void Phototonic::setImageToolBarVisibility() {
2508 imageToolBarVisible = imageToolBar->isVisible();
2509 }
2510
setFileSystemDockVisibility()2511 void Phototonic::setFileSystemDockVisibility() {
2512 if (Settings::layoutMode != ImageViewWidget) {
2513 Settings::fileSystemDockVisible = fileSystemDock->isVisible();
2514 }
2515 }
2516
setBookmarksDockVisibility()2517 void Phototonic::setBookmarksDockVisibility() {
2518 if (Settings::layoutMode != ImageViewWidget) {
2519 Settings::bookmarksDockVisible = bookmarksDock->isVisible();
2520 }
2521 }
2522
setImagePreviewDockVisibility()2523 void Phototonic::setImagePreviewDockVisibility() {
2524 if (Settings::layoutMode != ImageViewWidget) {
2525 Settings::imagePreviewDockVisible = imagePreviewDock->isVisible();
2526 }
2527 }
2528
setTagsDockVisibility()2529 void Phototonic::setTagsDockVisibility() {
2530 if (Settings::layoutMode != ImageViewWidget) {
2531 Settings::tagsDockVisible = tagsDock->isVisible();
2532 }
2533 }
2534
setImageInfoDockVisibility()2535 void Phototonic::setImageInfoDockVisibility() {
2536 if (Settings::layoutMode != ImageViewWidget) {
2537 Settings::imageInfoDockVisible = imageInfoDock->isVisible();
2538 }
2539 }
2540
showViewer()2541 void Phototonic::showViewer() {
2542 if (Settings::layoutMode == ThumbViewWidget) {
2543 Settings::layoutMode = ImageViewWidget;
2544 Settings::appSettings->setValue("Geometry", saveGeometry());
2545 Settings::appSettings->setValue("WindowState", saveState());
2546
2547 stackedLayout->setCurrentWidget(imageViewer);
2548 setDocksVisibility(false);
2549
2550 if (Settings::isFullScreen) {
2551 shouldMaximize = isMaximized();
2552 showFullScreen();
2553 imageViewer->setCursorHiding(true);
2554 QApplication::processEvents();
2555 }
2556 imageViewer->setFocus(Qt::OtherFocusReason);
2557 }
2558 }
2559
showBusyAnimation(bool busy)2560 void Phototonic::showBusyAnimation(bool busy) {
2561 static int busyStatus = 0;
2562
2563 if (busy) {
2564 ++busyStatus;
2565 } else {
2566 --busyStatus;
2567 }
2568
2569 if (busyStatus > 0) {
2570 busyMovie->start();
2571 busyLabel->setVisible(true);
2572 } else {
2573 busyLabel->setVisible(false);
2574 busyMovie->stop();
2575 busyStatus = 0;
2576 }
2577 }
2578
loadSelectedThumbImage(const QModelIndex & idx)2579 void Phototonic::loadSelectedThumbImage(const QModelIndex &idx) {
2580 thumbsViewer->setCurrentRow(idx.row());
2581 showViewer();
2582 imageViewer->loadImage(
2583 thumbsViewer->thumbsViewerModel->item(idx.row())->data(thumbsViewer->FileNameRole).toString());
2584 thumbsViewer->setImageViewerWindowTitle();
2585 }
2586
loadImageFromCliArguments(QString cliFileName)2587 void Phototonic::loadImageFromCliArguments(QString cliFileName) {
2588 QFile imageFile(cliFileName);
2589 if (!imageFile.exists()) {
2590 MessageBox msgBox(this);
2591 msgBox.critical(tr("Error"), tr("Failed to open file %1, file not found.").arg(cliFileName));
2592 return;
2593 }
2594
2595 showViewer();
2596 imageViewer->loadImage(cliFileName);
2597 setWindowTitle(cliFileName + " - Phototonic");
2598 }
2599
toggleSlideShow()2600 void Phototonic::toggleSlideShow() {
2601 if (Settings::slideShowActive) {
2602 Settings::slideShowActive = false;
2603 slideShowAction->setText(tr("Slide Show"));
2604 imageViewer->setFeedback(tr("Slide show stopped"));
2605
2606 SlideShowTimer->stop();
2607 delete SlideShowTimer;
2608 slideShowAction->setIcon(QIcon::fromTheme("media-playback-start", QIcon(":/images/play.png")));
2609 } else {
2610 if (thumbsViewer->thumbsViewerModel->rowCount() <= 0) {
2611 return;
2612 }
2613
2614 if (Settings::layoutMode == ThumbViewWidget) {
2615 QModelIndexList indexesList = thumbsViewer->selectionModel()->selectedIndexes();
2616 if (indexesList.size() != 1) {
2617 thumbsViewer->setCurrentRow(0);
2618 } else {
2619 thumbsViewer->setCurrentRow(indexesList.first().row());
2620 }
2621
2622 showViewer();
2623 }
2624
2625 Settings::slideShowActive = true;
2626
2627 SlideShowTimer = new QTimer(this);
2628 connect(SlideShowTimer, SIGNAL(timeout()), this, SLOT(slideShowHandler()));
2629 SlideShowTimer->start(Settings::slideShowDelay * 1000);
2630
2631 slideShowAction->setText(tr("Stop Slide Show"));
2632 imageViewer->setFeedback(tr("Slide show started"));
2633 slideShowAction->setIcon(QIcon::fromTheme("media-playback-stop", QIcon(":/images/stop.png")));
2634
2635 slideShowHandler();
2636 }
2637 }
2638
slideShowHandler()2639 void Phototonic::slideShowHandler() {
2640 if (Settings::slideShowActive) {
2641 if (Settings::slideShowRandom) {
2642 loadRandomImage();
2643 } else {
2644 int currentRow = thumbsViewer->getCurrentRow();
2645 imageViewer->loadImage(
2646 thumbsViewer->thumbsViewerModel->item(currentRow)->data(thumbsViewer->FileNameRole).toString());
2647 thumbsViewer->setImageViewerWindowTitle();
2648
2649 if (thumbsViewer->getNextRow() > 0) {
2650 thumbsViewer->setCurrentRow(thumbsViewer->getNextRow());
2651 } else {
2652 if (Settings::wrapImageList) {
2653 thumbsViewer->setCurrentRow(0);
2654 } else {
2655 toggleSlideShow();
2656 }
2657 }
2658 }
2659 }
2660 }
2661
loadNextImage()2662 void Phototonic::loadNextImage() {
2663 if (thumbsViewer->thumbsViewerModel->rowCount() <= 0) {
2664 return;
2665 }
2666
2667 int nextThumb = thumbsViewer->getNextRow();
2668 if (nextThumb < 0) {
2669 if (Settings::wrapImageList) {
2670 nextThumb = 0;
2671 } else {
2672 return;
2673 }
2674 }
2675
2676 if (Settings::layoutMode == ImageViewWidget) {
2677 imageViewer->loadImage(
2678 thumbsViewer->thumbsViewerModel->item(nextThumb)->data(thumbsViewer->FileNameRole).toString());
2679 }
2680
2681 thumbsViewer->setCurrentRow(nextThumb);
2682 thumbsViewer->setImageViewerWindowTitle();
2683
2684 if (Settings::layoutMode == ThumbViewWidget) {
2685 thumbsViewer->selectThumbByRow(nextThumb);
2686 }
2687 }
2688
loadPreviousImage()2689 void Phototonic::loadPreviousImage() {
2690 if (thumbsViewer->thumbsViewerModel->rowCount() <= 0) {
2691 return;
2692 }
2693
2694 int previousThumb = thumbsViewer->getPrevRow();
2695 if (previousThumb < 0) {
2696 if (Settings::wrapImageList) {
2697 previousThumb = thumbsViewer->getLastRow();
2698 } else {
2699 return;
2700 }
2701 }
2702
2703 if (Settings::layoutMode == ImageViewWidget) {
2704 imageViewer->loadImage(
2705 thumbsViewer->thumbsViewerModel->item(previousThumb)->data(thumbsViewer->FileNameRole).toString());
2706 }
2707
2708 thumbsViewer->setCurrentRow(previousThumb);
2709 thumbsViewer->setImageViewerWindowTitle();
2710
2711 if (Settings::layoutMode == ThumbViewWidget) {
2712 thumbsViewer->selectThumbByRow(previousThumb);
2713 }
2714 }
2715
loadFirstImage()2716 void Phototonic::loadFirstImage() {
2717 if (thumbsViewer->thumbsViewerModel->rowCount() <= 0) {
2718 return;
2719 }
2720
2721 imageViewer->loadImage(thumbsViewer->thumbsViewerModel->item(0)->data(thumbsViewer->FileNameRole).toString());
2722 thumbsViewer->setCurrentRow(0);
2723 thumbsViewer->setImageViewerWindowTitle();
2724
2725 if (Settings::layoutMode == ThumbViewWidget) {
2726 thumbsViewer->selectThumbByRow(0);
2727 }
2728 }
2729
loadLastImage()2730 void Phototonic::loadLastImage() {
2731 if (thumbsViewer->thumbsViewerModel->rowCount() <= 0) {
2732 return;
2733 }
2734
2735 int lastRow = thumbsViewer->getLastRow();
2736 imageViewer->loadImage(thumbsViewer->thumbsViewerModel->item(lastRow)->data(thumbsViewer->FileNameRole).toString());
2737 thumbsViewer->setCurrentRow(lastRow);
2738 thumbsViewer->setImageViewerWindowTitle();
2739
2740 if (Settings::layoutMode == ThumbViewWidget) {
2741 thumbsViewer->selectThumbByRow(lastRow);
2742 }
2743 }
2744
loadRandomImage()2745 void Phototonic::loadRandomImage() {
2746 if (thumbsViewer->thumbsViewerModel->rowCount() <= 0) {
2747 return;
2748 }
2749
2750 int randomRow = thumbsViewer->getRandomRow();
2751 imageViewer->loadImage(
2752 thumbsViewer->thumbsViewerModel->item(randomRow)->data(thumbsViewer->FileNameRole).toString());
2753 thumbsViewer->setCurrentRow(randomRow);
2754 thumbsViewer->setImageViewerWindowTitle();
2755
2756 if (Settings::layoutMode == ThumbViewWidget) {
2757 thumbsViewer->selectThumbByRow(randomRow);
2758 }
2759 }
2760
setViewerKeyEventsEnabled(bool enabled)2761 void Phototonic::setViewerKeyEventsEnabled(bool enabled) {
2762 moveLeftAction->setEnabled(enabled);
2763 moveRightAction->setEnabled(enabled);
2764 moveUpAction->setEnabled(enabled);
2765 moveDownAction->setEnabled(enabled);
2766 }
2767
updateIndexByViewerImage()2768 void Phototonic::updateIndexByViewerImage() {
2769 if (thumbsViewer->thumbsViewerModel->rowCount() > 0 &&
2770 thumbsViewer->setCurrentIndexByName(imageViewer->viewerImageFullPath)) {
2771 thumbsViewer->selectCurrentIndex();
2772 }
2773 }
2774
hideViewer()2775 void Phototonic::hideViewer() {
2776 if (isFullScreen()) {
2777 showNormal();
2778 if (shouldMaximize) {
2779 showMaximized();
2780 }
2781 imageViewer->setCursorHiding(false);
2782 }
2783
2784 restoreGeometry(Settings::appSettings->value(Settings::optionGeometry).toByteArray());
2785 restoreState(Settings::appSettings->value(Settings::optionWindowState).toByteArray());
2786
2787 Settings::layoutMode = ThumbViewWidget;
2788 stackedLayout->setCurrentWidget(thumbsViewer);
2789
2790 setDocksVisibility(true);
2791 while (QApplication::overrideCursor()) {
2792 QApplication::restoreOverrideCursor();
2793 }
2794
2795 if (Settings::slideShowActive) {
2796 toggleSlideShow();
2797 }
2798
2799 setThumbsViewerWindowTitle();
2800
2801 for (int i = 0; i <= 10 && qApp->hasPendingEvents(); ++i) {
2802 QApplication::processEvents();
2803 }
2804
2805 if (needThumbsRefresh) {
2806 needThumbsRefresh = false;
2807 refreshThumbs(true);
2808 } else {
2809 if (thumbsViewer->thumbsViewerModel->rowCount() > 0) {
2810 if (thumbsViewer->setCurrentIndexByName(imageViewer->viewerImageFullPath)) {
2811 thumbsViewer->selectCurrentIndex();
2812 }
2813 }
2814
2815 thumbsViewer->loadVisibleThumbs();
2816 }
2817
2818 imageViewer->clearImage();
2819 thumbsViewer->setFocus(Qt::OtherFocusReason);
2820 setContextMenuPolicy(Qt::DefaultContextMenu);
2821 }
2822
goBottom()2823 void Phototonic::goBottom() {
2824 thumbsViewer->scrollToBottom();
2825 }
2826
goTop()2827 void Phototonic::goTop() {
2828 thumbsViewer->scrollToTop();
2829 }
2830
dropOp(Qt::KeyboardModifiers keyMods,bool dirOp,QString copyMoveDirPath)2831 void Phototonic::dropOp(Qt::KeyboardModifiers keyMods, bool dirOp, QString copyMoveDirPath) {
2832 QApplication::restoreOverrideCursor();
2833 Settings::isCopyOperation = (keyMods == Qt::ControlModifier);
2834 QString destDir;
2835
2836 if (QObject::sender() == fileSystemTree) {
2837 destDir = getSelectedPath();
2838 } else if (QObject::sender() == bookmarks) {
2839 if (bookmarks->currentItem()) {
2840 destDir = bookmarks->currentItem()->toolTip(0);
2841 } else {
2842 addBookmark(copyMoveDirPath);
2843 return;
2844 }
2845 } else {
2846 // Unknown sender
2847 return;
2848 }
2849
2850 MessageBox msgBox(this);
2851 if (!isValidPath(destDir)) {
2852 msgBox.critical(tr("Error"), tr("Can not move or copy images to this directory."));
2853 selectCurrentViewDir();
2854 return;
2855 }
2856
2857 if (destDir == Settings::currentDirectory) {
2858 msgBox.critical(tr("Error"), tr("Destination directory is the same as the source directory."));
2859 return;
2860 }
2861
2862 if (dirOp) {
2863 QString dirOnly = copyMoveDirPath.right(
2864 copyMoveDirPath.size() - copyMoveDirPath.lastIndexOf(QDir::separator()) - 1);
2865
2866 QString question = tr("Move directory %1 to %2?").arg(dirOnly).arg(destDir);
2867
2868 MessageBox moveDirMessageBox(this);
2869 moveDirMessageBox.setText(question);
2870 moveDirMessageBox.setWindowTitle(tr("Move directory"));
2871 moveDirMessageBox.setIcon(MessageBox::Warning);
2872 moveDirMessageBox.setStandardButtons(MessageBox::Yes | MessageBox::Cancel);
2873 moveDirMessageBox.setDefaultButton(MessageBox::Cancel);
2874 moveDirMessageBox.setButtonText(MessageBox::Yes, tr("Move Directory"));
2875 moveDirMessageBox.setButtonText(MessageBox::Cancel, tr("Cancel"));
2876 int ret = moveDirMessageBox.exec();
2877
2878 if (ret == MessageBox::Yes) {
2879 QFile dir(copyMoveDirPath);
2880 bool moveOk = dir.rename(destDir + QDir::separator() + dirOnly);
2881 if (!moveOk) {
2882 moveDirMessageBox.critical(tr("Error"), tr("Failed to move directory."));
2883 }
2884 setStatus(tr("Directory moved"));
2885 }
2886 } else {
2887 CopyMoveDialog *copyMoveDialog = new CopyMoveDialog(this);
2888 Settings::copyCutIndexList = thumbsViewer->selectionModel()->selectedIndexes();
2889 copyMoveDialog->exec(thumbsViewer, destDir, false);
2890
2891 if (!Settings::isCopyOperation) {
2892 int row = copyMoveDialog->latestRow;
2893 if (thumbsViewer->thumbsViewerModel->rowCount()) {
2894 if (row >= thumbsViewer->thumbsViewerModel->rowCount()) {
2895 row = thumbsViewer->thumbsViewerModel->rowCount() - 1;
2896 }
2897
2898 thumbsViewer->setCurrentRow(row);
2899 thumbsViewer->selectThumbByRow(row);
2900 }
2901 }
2902
2903 QString stateString = QString((Settings::isCopyOperation ? tr("Copied") : tr("Moved")) + " " +
2904 tr("%n image(s)", "", copyMoveDialog->nFiles));
2905 setStatus(stateString);
2906 delete (copyMoveDialog);
2907 }
2908
2909 thumbsViewer->loadVisibleThumbs();
2910 }
2911
selectCurrentViewDir()2912 void Phototonic::selectCurrentViewDir() {
2913 QModelIndex idx = fileSystemTree->fileSystemModel->index(Settings::currentDirectory);
2914 if (idx.isValid()) {
2915 fileSystemTree->setCurrentIndex(idx);
2916 }
2917 }
2918
checkDirState(const QModelIndex &,int,int)2919 void Phototonic::checkDirState(const QModelIndex &, int, int) {
2920 if (!initComplete) {
2921 return;
2922 }
2923
2924 if (thumbsViewer->isBusy) {
2925 thumbsViewer->abort();
2926 }
2927
2928 if (!QDir().exists(Settings::currentDirectory)) {
2929 Settings::currentDirectory.clear();
2930 QTimer::singleShot(0, this, SLOT(onReloadThumbs()));
2931 }
2932 }
2933
addPathHistoryRecord(QString dir)2934 void Phototonic::addPathHistoryRecord(QString dir) {
2935 if (!needHistoryRecord) {
2936 needHistoryRecord = true;
2937 return;
2938 }
2939
2940 if (pathHistoryList.size() && dir == pathHistoryList.at(currentHistoryIdx)) {
2941 return;
2942 }
2943
2944 pathHistoryList.insert(++currentHistoryIdx, dir);
2945
2946 // Need to clear irrelevant items from list
2947 if (currentHistoryIdx != pathHistoryList.size() - 1) {
2948 goFrwdAction->setEnabled(false);
2949 for (int i = pathHistoryList.size() - 1; i > currentHistoryIdx; --i) {
2950 pathHistoryList.removeAt(i);
2951 }
2952 }
2953 }
2954
onReloadThumbs()2955 void Phototonic::onReloadThumbs() {
2956 if (thumbsViewer->isBusy || !initComplete) {
2957 thumbsViewer->abort();
2958 QTimer::singleShot(0, this, SLOT(onReloadThumbs()));
2959 return;
2960 }
2961
2962 if (!Settings::isFileListLoaded) {
2963 if (Settings::currentDirectory.isEmpty()) {
2964 Settings::currentDirectory = getSelectedPath();
2965 if (Settings::currentDirectory.isEmpty()) {
2966 return;
2967 }
2968 }
2969
2970 QDir checkPath(Settings::currentDirectory);
2971 if (!checkPath.exists() || !checkPath.isReadable()) {
2972 MessageBox msgBox(this);
2973 msgBox.critical(tr("Error"), tr("Failed to open directory ") + Settings::currentDirectory);
2974 setStatus(tr("No directory selected"));
2975 return;
2976 }
2977
2978 thumbsViewer->infoView->clear();
2979 thumbsViewer->imagePreview->clear();
2980 if (Settings::setWindowIcon && Settings::layoutMode == Phototonic::ThumbViewWidget) {
2981 setWindowIcon(defaultApplicationIcon);
2982 }
2983 pathLineEdit->setText(Settings::currentDirectory);
2984 addPathHistoryRecord(Settings::currentDirectory);
2985 if (currentHistoryIdx > 0) {
2986 goBackAction->setEnabled(true);
2987 }
2988 }
2989
2990 if (Settings::layoutMode == ThumbViewWidget) {
2991 setThumbsViewerWindowTitle();
2992 }
2993
2994 thumbsViewer->reLoad();
2995 }
2996
setThumbsViewerWindowTitle()2997 void Phototonic::setThumbsViewerWindowTitle() {
2998
2999 if (Settings::isFileListLoaded) {
3000 setWindowTitle(tr("Files List") + " - Phototonic");
3001 } else {
3002 setWindowTitle(Settings::currentDirectory + " - Phototonic");
3003 }
3004 }
3005
renameDir()3006 void Phototonic::renameDir() {
3007 QModelIndexList selectedDirs = fileSystemTree->selectionModel()->selectedRows();
3008 QFileInfo dirInfo = QFileInfo(fileSystemTree->fileSystemModel->filePath(selectedDirs[0]));
3009
3010 bool renameOk;
3011 QString title = tr("Rename") + " " + dirInfo.completeBaseName();
3012 QString newDirName = QInputDialog::getText(this, title,
3013 tr("New name:"), QLineEdit::Normal, dirInfo.completeBaseName(),
3014 &renameOk);
3015
3016 if (!renameOk) {
3017 selectCurrentViewDir();
3018 return;
3019 }
3020
3021 if (newDirName.isEmpty()) {
3022 MessageBox msgBox(this);
3023 msgBox.critical(tr("Error"), tr("Invalid name entered."));
3024 selectCurrentViewDir();
3025 return;
3026 }
3027
3028 QFile dir(dirInfo.absoluteFilePath());
3029 QString newFullPathName = dirInfo.absolutePath() + QDir::separator() + newDirName;
3030 renameOk = dir.rename(newFullPathName);
3031 if (!renameOk) {
3032 MessageBox msgBox(this);
3033 msgBox.critical(tr("Error"), tr("Failed to rename directory."));
3034 selectCurrentViewDir();
3035 return;
3036 }
3037
3038 if (Settings::currentDirectory == dirInfo.absoluteFilePath()) {
3039 fileSystemTree->setCurrentIndex(fileSystemTree->fileSystemModel->index(newFullPathName));
3040 } else {
3041 selectCurrentViewDir();
3042 }
3043 }
3044
rename()3045 void Phototonic::rename() {
3046 if (QApplication::focusWidget() == fileSystemTree) {
3047 renameDir();
3048 return;
3049 }
3050
3051 if (Settings::layoutMode == ImageViewWidget) {
3052 if (imageViewer->isNewImage()) {
3053 showNewImageWarning();
3054 return;
3055 }
3056
3057 if (thumbsViewer->thumbsViewerModel->rowCount() > 0) {
3058 if (thumbsViewer->setCurrentIndexByName(imageViewer->viewerImageFullPath))
3059 thumbsViewer->selectCurrentIndex();
3060 }
3061 }
3062
3063 QString selectedImageFileName = thumbsViewer->getSingleSelectionFilename();
3064 if (selectedImageFileName.isEmpty()) {
3065 setStatus(tr("Invalid selection"));
3066 return;
3067 }
3068
3069 if (Settings::slideShowActive) {
3070 toggleSlideShow();
3071 }
3072 imageViewer->setCursorHiding(false);
3073
3074 QFile currentFileFullPath(selectedImageFileName);
3075 QFileInfo currentFileInfo(currentFileFullPath);
3076 int renameConfirmed;
3077
3078 RenameDialog *renameDialog = new RenameDialog(this);
3079 renameDialog->setModal(true);
3080 renameDialog->setFileName(currentFileInfo.fileName());
3081 renameConfirmed = renameDialog->exec();
3082
3083 QString newFileName = renameDialog->getFileName();
3084 delete (renameDialog);
3085
3086 if (renameConfirmed && newFileName.isEmpty()) {
3087 MessageBox msgBox(this);
3088 msgBox.critical(tr("Error"), tr("No name entered."));
3089 renameConfirmed = 0;
3090 }
3091
3092 if (renameConfirmed) {
3093 QString newFileNameFullPath = currentFileInfo.absolutePath() + QDir::separator() + newFileName;
3094 if (currentFileFullPath.rename(newFileNameFullPath)) {
3095 QModelIndexList indexesList = thumbsViewer->selectionModel()->selectedIndexes();
3096 thumbsViewer->thumbsViewerModel->item(indexesList.first().row())->setData(newFileNameFullPath,
3097 thumbsViewer->FileNameRole);
3098 thumbsViewer->thumbsViewerModel->item(indexesList.first().row())->setData(newFileName, Qt::DisplayRole);
3099
3100 imageViewer->setInfo(newFileName);
3101 imageViewer->viewerImageFullPath = newFileNameFullPath;
3102
3103 if (Settings::filesList.contains(currentFileInfo.absoluteFilePath())) {
3104 Settings::filesList.replace(Settings::filesList.indexOf(currentFileInfo.absoluteFilePath()),
3105 newFileNameFullPath);
3106 }
3107
3108 if (Settings::layoutMode == ImageViewWidget) {
3109 thumbsViewer->setImageViewerWindowTitle();
3110 }
3111 } else {
3112 MessageBox msgBox(this);
3113 msgBox.critical(tr("Error"), tr("Failed to rename image."));
3114 }
3115 }
3116
3117 if (isFullScreen()) {
3118 imageViewer->setCursorHiding(true);
3119 }
3120 }
3121
removeMetadata()3122 void Phototonic::removeMetadata() {
3123
3124 QModelIndexList indexList = thumbsViewer->selectionModel()->selectedIndexes();
3125 QStringList fileList;
3126 copyCutThumbsCount = indexList.size();
3127
3128 for (int thumb = 0; thumb < copyCutThumbsCount; ++thumb) {
3129 fileList.append(thumbsViewer->thumbsViewerModel->item(indexList[thumb].
3130 row())->data(thumbsViewer->FileNameRole).toString());
3131 }
3132
3133 if (fileList.isEmpty()) {
3134 setStatus(tr("Invalid selection"));
3135 return;
3136 }
3137
3138 if (Settings::slideShowActive) {
3139 toggleSlideShow();
3140 }
3141
3142 MessageBox msgBox(this);
3143 msgBox.setText(tr("Permanently remove all Exif metadata from selected images?"));
3144 msgBox.setWindowTitle(tr("Remove Metadata"));
3145 msgBox.setIcon(MessageBox::Warning);
3146 msgBox.setStandardButtons(MessageBox::Yes | MessageBox::Cancel);
3147 msgBox.setDefaultButton(MessageBox::Cancel);
3148 msgBox.setButtonText(MessageBox::Yes, tr("Remove Metadata"));
3149 msgBox.setButtonText(MessageBox::Cancel, tr("Cancel"));
3150 int ret = msgBox.exec();
3151
3152 if (ret == MessageBox::Yes) {
3153 for (int file = 0; file < fileList.size(); ++file) {
3154 Exiv2::Image::AutoPtr image;
3155 try {
3156 image = Exiv2::ImageFactory::open(fileList[file].toStdString());
3157 image->clearMetadata();
3158 image->writeMetadata();
3159 metadataCache->removeImage(fileList[file]);
3160 }
3161 catch (Exiv2::Error &error) {
3162 msgBox.critical(tr("Error"), tr("Failed to remove Exif metadata."));
3163 return;
3164 }
3165 }
3166
3167 QItemSelection dummy;
3168 thumbsViewer->onSelectionChanged(dummy);
3169 QString state = QString(tr("Metadata removed from selected images"));
3170 setStatus(state);
3171 }
3172 }
3173
deleteDirectory(bool trash)3174 void Phototonic::deleteDirectory(bool trash) {
3175 bool removeDirectoryOk;
3176 QModelIndexList selectedDirs = fileSystemTree->selectionModel()->selectedRows();
3177 QString deletePath = fileSystemTree->fileSystemModel->filePath(selectedDirs[0]);
3178 QModelIndex idxAbove = fileSystemTree->indexAbove(selectedDirs[0]);
3179 QFileInfo dirInfo = QFileInfo(deletePath);
3180 QString question = (trash ? tr("Move directory %1 to the trash?") : tr(
3181 "Permanently delete the directory %1 and all of its contents?")).arg(
3182 dirInfo.completeBaseName());
3183
3184 MessageBox msgBox(this);
3185 msgBox.setText(question);
3186 msgBox.setWindowTitle(tr("Delete directory"));
3187 msgBox.setIcon(MessageBox::Warning);
3188 msgBox.setStandardButtons(MessageBox::Yes | MessageBox::Cancel);
3189 msgBox.setDefaultButton(MessageBox::Cancel);
3190 msgBox.setButtonText(MessageBox::Yes, trash ? tr("OK") : tr("Delete Directory"));
3191 msgBox.setButtonText(MessageBox::Cancel, tr("Cancel"));
3192 int ret = msgBox.exec();
3193
3194 QString trashError;
3195 if (ret == MessageBox::Yes) {
3196 if (trash) {
3197 removeDirectoryOk = Trash::moveToTrash(deletePath, trashError) == Trash::Success;
3198 } else {
3199 removeDirectoryOk = removeDirectoryOperation(deletePath);
3200 }
3201 } else {
3202 selectCurrentViewDir();
3203 return;
3204 }
3205
3206 if (!removeDirectoryOk) {
3207 msgBox.critical(tr("Error"), trash ? tr("Failed to move directory to the trash: %1").arg(trashError)
3208 : tr("Failed to delete directory."));
3209 selectCurrentViewDir();
3210 return;
3211 }
3212
3213 QString state = QString(tr("Removed \"%1\"").arg(deletePath));
3214 setStatus(state);
3215
3216 if (Settings::currentDirectory == deletePath) {
3217 if (idxAbove.isValid()) {
3218 fileSystemTree->setCurrentIndex(idxAbove);
3219 }
3220 } else {
3221 selectCurrentViewDir();
3222 }
3223 }
3224
createSubDirectory()3225 void Phototonic::createSubDirectory() {
3226 QModelIndexList selectedDirs = fileSystemTree->selectionModel()->selectedRows();
3227 QFileInfo dirInfo = QFileInfo(fileSystemTree->fileSystemModel->filePath(selectedDirs[0]));
3228
3229 bool ok;
3230 QString newDirName = QInputDialog::getText(this, tr("New Sub directory"),
3231 tr("New directory name:"), QLineEdit::Normal, "", &ok);
3232
3233 if (!ok) {
3234 selectCurrentViewDir();
3235 return;
3236 }
3237
3238 if (newDirName.isEmpty()) {
3239 MessageBox msgBox(this);
3240 msgBox.critical(tr("Error"), tr("Invalid name entered."));
3241 selectCurrentViewDir();
3242 return;
3243 }
3244
3245 QDir dir(dirInfo.absoluteFilePath());
3246 ok = dir.mkdir(dirInfo.absoluteFilePath() + QDir::separator() + newDirName);
3247
3248 if (!ok) {
3249 MessageBox msgBox(this);
3250 msgBox.critical(tr("Error"), tr("Failed to create new directory."));
3251 selectCurrentViewDir();
3252 return;
3253 }
3254
3255 setStatus(tr("Created %1").arg(newDirName));
3256 fileSystemTree->expand(selectedDirs[0]);
3257 }
3258
getSelectedPath()3259 QString Phototonic::getSelectedPath() {
3260 QModelIndexList selectedDirs = fileSystemTree->selectionModel()->selectedRows();
3261 if (selectedDirs.size() && selectedDirs[0].isValid()) {
3262 QFileInfo dirInfo = QFileInfo(fileSystemTree->fileSystemModel->filePath(selectedDirs[0]));
3263 return dirInfo.absoluteFilePath();
3264 } else
3265 return "";
3266 }
3267
wheelEvent(QWheelEvent * event)3268 void Phototonic::wheelEvent(QWheelEvent *event) {
3269 if (Settings::layoutMode == ImageViewWidget) {
3270 if (event->modifiers() == Qt::ControlModifier) {
3271 if (event->delta() < 0) {
3272 zoomOut();
3273 } else {
3274 zoomIn();
3275 }
3276 } else if (nextImageAction->isEnabled()) {
3277 if (event->delta() < 0) {
3278 loadNextImage();
3279 } else {
3280 loadPreviousImage();
3281 }
3282 }
3283 event->accept();
3284 } else if (event->modifiers() == Qt::ControlModifier && QApplication::focusWidget() == thumbsViewer) {
3285 if (event->delta() < 0) {
3286 thumbsZoomOut();
3287 } else {
3288 thumbsZoomIn();
3289 }
3290 }
3291 }
3292
showNewImageWarning()3293 void Phototonic::showNewImageWarning() {
3294 MessageBox msgBox(this);
3295 msgBox.warning(tr("Warning"), tr("Cannot perform action with temporary image."));
3296 }
3297
removeDirectoryOperation(QString dirToDelete)3298 bool Phototonic::removeDirectoryOperation(QString dirToDelete) {
3299 bool removeDirOk;
3300 QDir dir(dirToDelete);
3301
3302 Q_FOREACH(QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden |
3303 QDir::AllDirs | QDir::Files, QDir::DirsFirst)) {
3304 if (info.isDir()) {
3305 removeDirOk = removeDirectoryOperation(info.absoluteFilePath());
3306 } else {
3307 removeDirOk = QFile::remove(info.absoluteFilePath());
3308 }
3309
3310 if (!removeDirOk) {
3311 return removeDirOk;
3312 }
3313 }
3314 removeDirOk = dir.rmdir(dirToDelete);
3315 return removeDirOk;
3316 }
3317
cleanupCropDialog()3318 void Phototonic::cleanupCropDialog() {
3319 setInterfaceEnabled(true);
3320 }
3321
cleanupResizeDialog()3322 void Phototonic::cleanupResizeDialog() {
3323 delete resizeDialog;
3324 resizeDialog = 0;
3325 setInterfaceEnabled(true);
3326 }
3327
cleanupColorsDialog()3328 void Phototonic::cleanupColorsDialog() {
3329 Settings::colorsActive = false;
3330 setInterfaceEnabled(true);
3331 }
3332
setInterfaceEnabled(bool enable)3333 void Phototonic::setInterfaceEnabled(bool enable) {
3334 // actions
3335 colorsAction->setEnabled(enable);
3336 renameAction->setEnabled(enable);
3337 removeMetadataAction->setEnabled(enable);
3338 cropAction->setEnabled(enable);
3339 resizeAction->setEnabled(enable);
3340 CloseImageAction->setEnabled(enable);
3341 nextImageAction->setEnabled(enable);
3342 prevImageAction->setEnabled(enable);
3343 firstImageAction->setEnabled(enable);
3344 lastImageAction->setEnabled(enable);
3345 randomImageAction->setEnabled(enable);
3346 slideShowAction->setEnabled(enable);
3347 copyToAction->setEnabled(enable);
3348 moveToAction->setEnabled(enable);
3349 deleteAction->setEnabled(enable);
3350 deletePermanentlyAction->setEnabled(enable);
3351 settingsAction->setEnabled(enable);
3352 viewImageAction->setEnabled(enable);
3353
3354 // other
3355 thumbsViewer->setEnabled(enable);
3356 fileSystemTree->setEnabled(enable);
3357 bookmarks->setEnabled(enable);
3358 thumbsViewer->imageTags->setEnabled(enable);
3359 menuBar()->setEnabled(enable);
3360 editToolBar->setEnabled(enable);
3361 goToolBar->setEnabled(enable);
3362 viewToolBar->setEnabled(enable);
3363 interfaceDisabled = !enable;
3364
3365 if (enable) {
3366 if (isFullScreen()) {
3367 imageViewer->setCursorHiding(true);
3368 }
3369 } else {
3370 imageViewer->setCursorHiding(false);
3371 }
3372 }
3373
addNewBookmark()3374 void Phototonic::addNewBookmark() {
3375 addBookmark(getSelectedPath());
3376 }
3377
addBookmark(QString path)3378 void Phototonic::addBookmark(QString path) {
3379 Settings::bookmarkPaths.insert(path);
3380 bookmarks->reloadBookmarks();
3381 }
3382