1 /*******************************************************************************
2 **
3 ** Photivo
4 **
5 ** Copyright (C) 2011-2013 Bernd Schoeler <brjohn@brother-john.net>
6 ** Copyright (C) 2011-2013 Michael Munzert <mail@mm-log.com>
7 ** Copyright (C) 2013 Alexander Tzyganenko <tz@fast-report.com>
8 **
9 ** This file is part of Photivo.
10 **
11 ** Photivo is free software: you can redistribute it and/or modify
12 ** it under the terms of the GNU General Public License version 3
13 ** as published by the Free Software Foundation.
14 **
15 ** Photivo is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ** GNU General Public License for more details.
19 **
20 ** You should have received a copy of the GNU General Public License
21 ** along with Photivo. If not, see <http://www.gnu.org/licenses/>.
22 **
23 *******************************************************************************/
24
25 #include "ptFileMgrWindow.h"
26 #include "ptGraphicsSceneEmitter.h"
27 #include "ptRowGridThumbnailLayouter.h"
28 #include "ptColumnGridThumbnailLayouter.h"
29 #include "../ptDefines.h"
30 #include "../ptSettings.h"
31 #include "../ptTheme.h"
32 #include "../ptImageHelper.h"
33 #include "../ptMessageBox.h"
34 #include "../ptImage8.h"
35 #include <QVBoxLayout>
36 #include <QFontMetrics>
37 #include <QList>
38 #include <QDir>
39 #include <QMenu>
40 #include <QAction>
41 #include <QLabel>
42 #include <QScrollBar>
43 #include <QFileDialog>
44 #include <cassert>
45
46 extern void CB_MenuFileOpen(const short HaveFile);
47
48 extern ptSettings* Settings;
49 extern ptTheme* Theme;
50 extern QString ImageFileToOpen;
51 extern short InStartup;
52 extern QString SaveBitmapPattern;
53
54 //------------------------------------------------------------------------------
55 /*!
56 Creates a ptFileMgrWindow instance.
57 \param parent
58 The file manager’s parent window.
59 */
ptFileMgrWindow(QWidget * parent)60 ptFileMgrWindow::ptFileMgrWindow(QWidget* parent)
61 : QWidget(parent),
62 FDataModel(new ptFileMgrDM(this)), // setup data model first because several UI elements need it
63 FIsFirstShow(true),
64 FThumbCount(-1),
65 FThumbListIdx(0)
66 {
67 // Main UI init
68 setupUi(this);
69 setMouseTracking(true);
70
71 ptGraphicsSceneEmitter::ConnectThumbnailAction(
72 this, SLOT(execThumbnailAction(ptThumbnailAction,QString)));
73 ptGraphicsSceneEmitter::ConnectFocusChanged(this, SLOT(thumbFocusChanged()));
74
75 //-------------------------------------
76
77 // sidebar
78 FMSidebar->setVisible(Settings->GetInt("FileMgrShowSidebar"));
79
80 // Folder list
81 #ifdef Q_OS_WIN
82 DirListLabel->setText(tr("Folders"));
83 #else
84 DirListLabel->setText(tr("Directories"));
85 #endif
86 m_DirList->setModel(FDataModel->dirModel());
87 connect(m_DirList, SIGNAL(activated(QModelIndex)), this, SLOT(changeListDir(QModelIndex)));
88
89
90 #ifdef Q_OS_WIN
91 QString BookmarkTooltip = tr("Bookmark current folder (Ctrl+B)");
92 #else
93 QString BookmarkTooltip = tr("Bookmark current directory (Ctrl+B)");
94 #endif
95
96 // bookmark list in sidebar
97 FTagList = new ptTagList(this);
98 FTagList->setModel(FDataModel->tagModel());
99 connect(FDataModel->tagModel(), SIGNAL(itemChanged(QStandardItem*)),
100 this, SLOT(bookmarkDataChanged(QStandardItem*)));
101 m_TagPaneLayout->addWidget(FTagList);
102 connect(FTagList, SIGNAL(activated(QModelIndex)), this, SLOT(changeToBookmark(QModelIndex)));
103 m_AddBookmarkButton->setToolTip(BookmarkTooltip);
104 connect(m_AddBookmarkButton, SIGNAL(clicked()), this, SLOT(bookmarkCurrentDir()));
105
106 //-------------------------------------
107
108 //bookmark menu
109 FTagMenu = new QMenu(this);
110 FTagMenu->hide();
111 FTagMenu->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
112 FTagMenu->setObjectName("FMTagMenu");
113
114 QLabel* label = new QLabel("<b>" + tr("Bookmarks") + "</b>", FTagMenu);
115 QToolButton* addButton = new QToolButton(FTagMenu);
116 addButton->setIcon(QIcon(Theme->IconAddBookmark));
117 addButton->setToolTip(BookmarkTooltip);
118 connect(addButton, SIGNAL(clicked()), this, SLOT(bookmarkCurrentDir()));
119
120 QHBoxLayout* headerLayout = new QHBoxLayout();
121 headerLayout->setContentsMargins(0,0,0,0);
122 headerLayout->addWidget(addButton);
123 headerLayout->addWidget(label);
124
125 FTagMenuList = new ptTagList(FTagMenu);
126 FTagMenuList->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
127 FTagMenuList->setModel(FDataModel->tagModel());
128 connect(FTagMenuList, SIGNAL(activated(QModelIndex)),
129 this, SLOT(changeToBookmarkFromMenu(QModelIndex)));
130
131 QVBoxLayout* layout = new QVBoxLayout(FTagMenu);
132 layout->addLayout(headerLayout);
133 layout->addWidget(FTagMenuList);
134 FTagMenu->setLayout(layout);
135
136 //-------------------------------------
137
138 // Setup the graphics view/scene
139 FFilesScene = new QGraphicsScene(m_FilesView);
140 FFilesScene->setStickyFocus(true);
141 FFilesScene->installEventFilter(this);
142 m_FilesView->setOptimizationFlags(QGraphicsView::DontSavePainterState);
143 m_FilesView->installEventFilter(this);
144 m_FilesView->verticalScrollBar()->installEventFilter(this);
145 m_FilesView->horizontalScrollBar()->installEventFilter(this);
146 m_FilesView->setScene(FFilesScene);
147 FDataModel->connectThumbGen(this, SLOT(receiveThumb(uint,TThumbPtr)));
148 setLayouter((ptThumbnailLayout)Settings->GetInt("FileMgrThumbLayoutType"));
149
150 FPathBar = new ptPathBar(m_PathContainer);
151 FPathBar->setObjectName("FMPathBar");
152 connect(FPathBar, SIGNAL(changedPath(QString)), this, SLOT(changeDir(QString)));
153 m_PathLayout->addWidget(FPathBar);
154 m_Progressbar->hide();
155
156 //-------------------------------------
157
158 // construct the image view
159 FImageView = new ptImageView(FMImageViewPane);
160 FImageView->installEventFilter(this);
161 FMImageViewPane->setVisible((bool)Settings->GetInt("FileMgrShowImageView"));
162
163 //-------------------------------------
164
165 // Filemgr main splitter layout
166 if (Settings->m_IniSettings->contains("FileMgrMainSplitter")) {
167 FMMainSplitter->restoreState(
168 Settings->m_IniSettings->value("FileMgrMainSplitter").toByteArray());
169 } else {
170 FMMainSplitter->setSizes(QList<int>() << 150 << 500 << 500);
171 }
172 FMMainSplitter->setStretchFactor(1,1);
173
174 // sidebar splitter layout
175 if (Settings->m_IniSettings->contains("FileMgrSidebarSplitter")) {
176 FMSidebarSplitter->restoreState(
177 Settings->m_IniSettings->value("FileMgrSidebarSplitter").toByteArray());
178 } else {
179 FMSidebarSplitter->setSizes(QList<int>() << 400 << 400);
180 }
181 FMSidebarSplitter->setStretchFactor(1,1);
182
183 //-------------------------------------
184
185 constructContextMenu();
186 }
187
188 //------------------------------------------------------------------------------
189 /*! Destroys a \c ptFileMgrWindow instance. */
~ptFileMgrWindow()190 ptFileMgrWindow::~ptFileMgrWindow() {
191 Settings->SetValue("LastFileMgrLocation", FDataModel->currentDir());
192 Settings->m_IniSettings->
193 setValue("FileMgrMainSplitter", FMMainSplitter->saveState());
194 Settings->m_IniSettings->
195 setValue("FileMgrSidebarSplitter", FMSidebarSplitter->saveState());
196
197 DelAndNull(FLayouter);
198 DelAndNull(FPathBar);
199
200 // Make sure to destroy all thumbnail related things before the singletons!
201 ptGraphicsSceneEmitter::DestroyInstance();
202
203 // context menu actions
204 DelAndNull(FVerticalThumbsAct);
205 DelAndNull(FHorizontalThumbsAct);
206 DelAndNull(FDetailedThumbsAct);
207 DelAndNull(FDirThumbsAct);
208 DelAndNull(FThumbLayoutGroupAct);
209 DelAndNull(FToggleSidebarAct);
210 DelAndNull(FToggleImageViewAct);
211 DelAndNull(FCloseFileMgrAct);
212 DelAndNull(FSaveThumbAct);
213
214 DelAndNull(FImageView);
215 }
216
217 //------------------------------------------------------------------------------
setLayouter(const ptThumbnailLayout layout)218 void ptFileMgrWindow::setLayouter(const ptThumbnailLayout layout) {
219 bool RestartThumbnailer = false;
220 if (!InStartup) {
221 if ((ptThumbnailLayout)Settings->GetInt("FileMgrThumbLayoutType") == layout)
222 return;
223 RestartThumbnailer = FDataModel->thumbGenRunning();
224 FDataModel->abortThumbGen();
225 DelAndNull(FLayouter);
226 Settings->SetValue("FileMgrThumbLayoutType", layout);
227 }
228
229 switch (layout) {
230 case tlVerticalByRow:
231 m_FilesView->setAlignment(Qt::AlignHCenter | Qt::AlignTop);
232 FLayouter = new ptRowGridThumbnailLayouter(m_FilesView);
233 break;
234
235 case tlHorizontalByColumn:
236 m_FilesView->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
237 FLayouter = new ptColumnGridThumbnailLayouter(m_FilesView);
238 break;
239
240 case tlDetailedList:
241 m_FilesView->setAlignment(Qt::AlignHCenter | Qt::AlignTop);
242 //TODO: re-enable m_Layouter = new ptDetailedThumbnailLayouter(m_FilesView);
243 break;
244
245 default:
246 assert(!"Unhandled thumbnail layouter type!");
247 break;
248 }
249
250 if (RestartThumbnailer) {
251 this->displayThumbnails();
252 } else {
253 this->layoutAll();
254 }
255 }
256
257 //------------------------------------------------------------------------------
changeListDir(const QModelIndex & index)258 void ptFileMgrWindow::changeListDir(const QModelIndex& index) {
259 FDataModel->dirModel()->ChangeDir(index);
260 displayThumbnails(FDataModel->dirModel()->absolutePath(), FDataModel->dirModel()->pathType());
261 }
262
263 //------------------------------------------------------------------------------
changeToBookmark(const QModelIndex & index)264 void ptFileMgrWindow::changeToBookmark(const QModelIndex& index) {
265 changeDir(FDataModel->tagModel()->path(index));
266 }
267
268 //------------------------------------------------------------------------------
changeToBookmarkFromMenu(const QModelIndex & index)269 void ptFileMgrWindow::changeToBookmarkFromMenu(const QModelIndex& index) {
270 FTagMenu->hide();
271 changeToBookmark(index);
272 }
273
274 //------------------------------------------------------------------------------
changeDir(const QString & path)275 void ptFileMgrWindow::changeDir(const QString& path) {
276 FDataModel->dirModel()->ChangeAbsoluteDir(path);
277 displayThumbnails(path, FDataModel->dirModel()->pathType());
278 }
279
280 //------------------------------------------------------------------------------
281 /*!
282 Creates or refreshes the thumbnail display.
283 \param path
284 The path to the desired directory. Must be an absolute path. \c path can be
285 empty. Then it defaults to the currently set thumbnail directory.
286 \param fsoType
287 Only relevant on Windows to indicate if the folder is “My Computer”. If that is
288 the case, set to \c fsoRoot. Then \c path will be ignored and no thumbnails
289 displayed. Do \b not use as a general flag to prevent thumbnail display!
290 */
291 #ifdef Q_OS_UNIX
292 // Linux does not need parameter fsoType. Disable compiler warning.
293 #pragma GCC diagnostic push
294 #pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
295 #endif
displayThumbnails(QString path,ptFSOType fsoType)296 void ptFileMgrWindow::displayThumbnails(QString path /*= ""*/, ptFSOType fsoType /*= fsoDir*/) {
297 if (path.isEmpty()) {
298 path = FDataModel->dirModel()->absolutePath();
299 fsoType = FDataModel->dirModel()->pathType();
300 }
301
302 #ifdef Q_OS_WIN
303 if (fsoType == fsoRoot) {
304 // We are in “My Computer”
305 path = MyComputerIdString;
306 }
307 #endif
308
309 m_FilesView->horizontalScrollBar()->setValue(0);
310 m_FilesView->verticalScrollBar()->setValue(0);
311 FThumbListIdx = 0;
312 FThumbCount = FDataModel->setThumDir(path);
313 FThumbsReceived = 0;
314 FPathBar->setPath(path);
315
316 if (FThumbCount == 0) {
317 // setting scene to null dimensions disappears unneeded scrollbars
318 FFilesScene->setSceneRect(0,0,0,0);
319
320 } else {
321 FLayouter->LazyInit(FThumbCount);
322 this->initProgressbar();
323 FDataModel->populateThumbs(FFilesScene); // non-blocking, returns almost immediately
324 this->layoutAll();
325 }
326 }
327 #ifdef Q_OS_UNIX
328 #pragma GCC diagnostic pop
329 #endif
330
331 //------------------------------------------------------------------------------
332 // Slot to receive thumbnail images from the generator and dispatch them to their thumb group.
333 // Also updates the progress bar.
receiveThumb(uint AReceiverId,TThumbPtr AImage)334 void ptFileMgrWindow::receiveThumb(uint AReceiverId, TThumbPtr AImage) {
335 for (ptGraphicsThumbGroup* hThumbGroup: *FDataModel->thumbGroupList()) {
336 if (hThumbGroup->id() == AReceiverId) {
337 hThumbGroup->addImage(AImage);
338 ++FThumbsReceived;
339 this->updateProgressbar();
340 break;
341 }
342 }
343 }
344
345 //------------------------------------------------------------------------------
346 // Sets progress bar range to current FThumbCount, shows the progressbar and hides the path bar.
initProgressbar()347 void ptFileMgrWindow::initProgressbar() {
348 m_Progressbar->setValue(0);
349 m_Progressbar->setMaximum(FThumbCount);
350 m_Progressbar->show();
351 m_PathContainer->hide();
352 }
353
354 //------------------------------------------------------------------------------
355 // Updates the progress bar’s value. Switches display back to path bar when last thumbnail is reached.
updateProgressbar()356 void ptFileMgrWindow::updateProgressbar() {
357 if (FThumbsReceived < FThumbCount) {
358 m_Progressbar->setValue(FThumbsReceived);
359 } else {
360 m_Progressbar->hide();
361 m_PathContainer->show();
362
363 FFilesScene->setFocus();
364 }
365 }
366
367 //------------------------------------------------------------------------------
layoutAll()368 void ptFileMgrWindow::layoutAll() {
369 FLayouter->Init(FDataModel->thumbGroupList()->count(), m_FilesView->font());
370 QListIterator<ptGraphicsThumbGroup*> i(*FDataModel->thumbGroupList());
371
372 while (i.hasNext()) {
373 FLayouter->Layout(i.next());
374 }
375 }
376
377 //------------------------------------------------------------------------------
showEvent(QShowEvent * event)378 void ptFileMgrWindow::showEvent(QShowEvent* event) {
379 if (FIsFirstShow) {
380 // Execute once when the file manager is opened for the first time.
381
382 // Theme and layout stuff (wouldn’t work in constructor)
383 updateTheme();
384
385 // set initally selected directory
386 QString lastDir = Settings->GetString("LastFileMgrLocation");
387 ptFSOType lastDirType = fsoDir;
388 #ifdef Q_OS_WIN
389 if (lastDir == MyComputerIdString || lastDir.isEmpty()) {
390 lastDir = MyComputerIdString;
391 lastDirType = fsoRoot;
392 } else {
393 #endif
394 if (lastDir.isEmpty() || !QDir(lastDir).exists()) {
395 // dir from ini is broken, default to homePath
396 lastDir = QDir::homePath();
397 }
398 #ifdef Q_OS_WIN
399 }
400 #endif
401 FDataModel->dirModel()->ChangeAbsoluteDir(lastDir);
402 FDataModel->setCurrentDir(lastDir);
403 FPathBar->setPath(lastDir);
404
405 // First call base class showEvent, then start thumbnail loading to ensure
406 // the file manager is visible before ressource heavy actions begin.
407 QWidget::showEvent(event);
408 if (!InStartup) {
409 this->displayThumbnails(lastDir, lastDirType);
410 }
411
412 FIsFirstShow = false;
413 return;
414 }
415
416 focusThumbnail(FDataModel->focusedThumb());
417 if (!event->spontaneous()) {
418 QWidget::showEvent(event);
419 // Thumbnails are cleared to free memory when the fm window is closed,
420 // i.e. we need to refresh the display when opening it again.
421 // temporarily disabled. should become a user option
422 // displayThumbnails();
423 }
424 }
425
426 //------------------------------------------------------------------------------
eventFilter(QObject * obj,QEvent * event)427 bool ptFileMgrWindow::eventFilter(QObject* obj, QEvent* event) {
428 if (obj == m_FilesView && event->type() == QEvent::Resize) {
429 // Resize event: Rearrange thumbnails when size of viewport changes
430 layoutAll();
431 return false; // handle event further
432 }
433
434
435 else if ((obj == qobject_cast<QObject*>(m_FilesView->verticalScrollBar()) ||
436 obj == qobject_cast<QObject*>(m_FilesView->horizontalScrollBar())) &&
437 event->type() == QEvent::Wheel)
438 { // Wheel event
439 int dir = ((QWheelEvent*)event)->delta() > 0 ? -1 : 1;
440 if (m_FilesView->verticalScrollBar()->isVisible()) {
441 m_FilesView->verticalScrollBar()->setValue(
442 m_FilesView->verticalScrollBar()->value() + FLayouter->Step()*dir);
443
444 } else if (m_FilesView->horizontalScrollBar()->isVisible()) {
445 m_FilesView->horizontalScrollBar()->setValue(
446 m_FilesView->horizontalScrollBar()->value() + FLayouter->Step()*dir);
447 }
448 return true; // prevent further event handling
449 }
450
451
452 else if (obj == FFilesScene && (event->type() == QEvent::GraphicsSceneDragEnter ||
453 event->type() == QEvent::GraphicsSceneDrop))
454 { // Make sure drag&drop events are passed on to MainWindow
455 event->ignore();
456 return true;
457 }
458
459
460 else if (obj == FFilesScene && event->type() == QEvent::KeyPress) {
461 // Keyboard navigation in thumbnail list
462 int newIdx = FLayouter->MoveIndex(FDataModel->focusedThumb(), (QKeyEvent*)event);
463 if (newIdx >= 0) {
464 focusThumbnail(newIdx);
465 return true;
466 }
467 }
468
469
470 // unhandled events fall through to here
471 // make sure parent event filters are executed
472 return QWidget::eventFilter(obj, event);
473 }
474
475 //------------------------------------------------------------------------------
focusThumbnail(int index)476 void ptFileMgrWindow::focusThumbnail(int index) {
477 if (index >= 0) {
478 // focus new thumb
479 ptGraphicsThumbGroup* thumb = FDataModel->moveFocus(index);
480 FFilesScene->setFocusItem(thumb);
481 m_FilesView->ensureVisible(thumb, 0, 0);
482 m_FilesView->setFocus();
483
484 // if a different thumb is focused update ImageView
485 if (thumb->fsoType() == fsoFile) {
486 this->loadForImageView(thumb->fullPath());
487 }
488
489 } else {
490 FFilesScene->clearFocus();
491 }
492 }
493
494 //------------------------------------------------------------------------------
loadForImageView(const QString & AFilePath)495 void ptFileMgrWindow::loadForImageView(const QString& AFilePath) {
496 if (FImageView->isVisible()) {
497 FImageView->showImage(AFilePath);
498 }
499 }
500
501 //------------------------------------------------------------------------------
thumbFocusChanged()502 void ptFileMgrWindow::thumbFocusChanged() {
503 focusThumbnail(FDataModel->focusedThumb(FFilesScene->focusItem()));
504 }
505
506 //------------------------------------------------------------------------------
saveThumbnail()507 void ptFileMgrWindow::saveThumbnail() {
508 int hThumbIdx = FDataModel->focusedThumb();
509
510 if (hThumbIdx > -1 && (hThumbIdx < FDataModel->thumbGroupList()->count())) {
511 QString hFileName = FDataModel->thumbGroupList()->at(hThumbIdx)->fullPath();
512 auto hImage = FDataModel->getThumb(hFileName, Settings->GetInt("FileMgrThumbSaveSize"));
513
514 if (!hImage) {
515 ptMessageBox::warning(0, QObject::tr("Error"), QObject::tr("Thumbnail could not be saved."));
516 return;
517 }
518
519 QFileInfo hPathInfo(hFileName);
520 QString hSuggestedFileName = hPathInfo.dir().path() + "/" + hPathInfo.completeBaseName() + "-thumb.jpg";
521
522 auto hOutputName = QFileDialog::getSaveFileName(nullptr,
523 QObject::tr("Save File"),
524 hSuggestedFileName,
525 SaveBitmapPattern);
526
527 if (hOutputName.isEmpty()) {
528 return; // Operation cancelled.
529 }
530
531 if (!(hImage->DumpImage(hOutputName.toLocal8Bit().data(), true))) {
532 ptMessageBox::warning(0, QObject::tr("Error"), QObject::tr("Thumbnail could not be saved."));
533 }
534
535 if (!ptImageHelper::TransferExif(hFileName, hOutputName)) {
536 ptMessageBox::warning(0, QObject::tr("Exif error"), QObject::tr("Exif data could not be written."));
537 }
538 }
539 }
540
541 //------------------------------------------------------------------------------
execThumbnailAction(const ptThumbnailAction action,const QString location)542 void ptFileMgrWindow::execThumbnailAction(const ptThumbnailAction action, const QString location) {
543 if (action == tnaLoadImage) {
544 closeWindow();
545 ImageFileToOpen = location;
546 CB_MenuFileOpen(1);
547
548 } else if (action == tnaChangeDir) {
549 FDataModel->dirModel()->ChangeAbsoluteDir(location);
550 displayThumbnails(location, FDataModel->dirModel()->pathType());
551
552 } else if (action == tnaViewImage) {
553 this->loadForImageView(location);
554 }
555 }
556
557 //------------------------------------------------------------------------------
558 /*! Updates the file manager’s visual appearance. Call this once every time Photivo’s theme changes. */
updateTheme()559 void ptFileMgrWindow::updateTheme() {
560 // Update file manager window appearance
561 setStyle(Theme->style());
562 setStyleSheet(Theme->stylesheet());
563
564 // Thumbgroups don’t need to be updated because Photivo theme can only be changed
565 // while fm is closed = thumbnail display cleared
566 }
567
568 //------------------------------------------------------------------------------
closeWindow()569 void ptFileMgrWindow::closeWindow() {
570 // File manager can’t close its window itself. That’s handled by the main window.
571 // Signal tells main window to perform necessary closing actions.
572 // FM internal cleanup is done in ptFileMgrWindow::hideEvent().
573 emit fileMgrWindowClosed();
574 }
575
576 //------------------------------------------------------------------------------
hideEvent(QHideEvent *)577 void ptFileMgrWindow::hideEvent(QHideEvent* /*event*/) {
578 // temporarily disabled. should become a user-option
579 // if (!event->spontaneous()) {
580 // event->accept();
581 // // free memory occupied by thumbnails and thumb cache
582 // // clear() includes stopping thumbnail generation
583 // FDataModel->clear();
584 // FImageView->clear();
585 // this->clearScene();
586 // } else {
587 // event->ignore();
588 // }
589 }
590
591 //------------------------------------------------------------------------------
clearScene()592 void ptFileMgrWindow::clearScene() {
593 FDataModel->thumbGroupList()->clear();
594 FFilesScene->clear();
595 }
596
597 //------------------------------------------------------------------------------
keyPressEvent(QKeyEvent * event)598 void ptFileMgrWindow::keyPressEvent(QKeyEvent* event) {
599 // Esc: close file manager
600 if (event->key() == Qt::Key_Escape && event->modifiers() == Qt::NoModifier) {
601 closeWindow();
602 }
603 // Ctrl+M: close file manager
604 else if (event->key() == Qt::Key_M && event->modifiers() == Qt::ControlModifier) {
605 closeWindow();
606 }
607 // F5: refresh thumbnails
608 else if (event->key() == Qt::Key_F5 && event->modifiers() == Qt::NoModifier) {
609 displayThumbnails();
610 }
611 // Shift+F5: clear cache and refresh thumbnails
612 else if (event->key() == Qt::Key_F5 && event->modifiers() == Qt::ShiftModifier) {
613 FDataModel->clear();
614 displayThumbnails();
615 }
616 // Ctrl+B: bookmark current folder
617 else if (event->key() == Qt::Key_B && event->modifiers() == Qt::ControlModifier) {
618 bookmarkCurrentDir();
619 }
620 // F11: toggles fullscreen (handled by main window)
621 else if (event->key() == Qt::Key_F11 && event->modifiers() == Qt::NoModifier) {
622 event->ignore();
623 }
624 // Alt+1: vertical thumbnail view
625 else if (event->key() == Qt::Key_1 && event->modifiers() == Qt::AltModifier) {
626 setLayouter(tlVerticalByRow);
627 }
628 // Alt+2: horizontal thumbnail view
629 else if (event->key() == Qt::Key_2 && event->modifiers() == Qt::AltModifier) {
630 setLayouter(tlHorizontalByColumn);
631 }
632 // Alt+3: detailed thumbnail view
633 //TODO: re-enable else if (event->key() == Qt::Key_3 && event->modifiers() == Qt::AltModifier) {
634 // setLayouter(tlDetailedList);
635 // }
636 // F3: toggles: ImageView
637 else if (event->key() == Qt::Key_F3 && event->modifiers() == Qt::NoModifier) {
638 toggleImageView();
639 }
640 // F4: toggles sidebar
641 else if (event->key() == Qt::Key_F4 && event->modifiers() == Qt::NoModifier) {
642 toggleSidebar();
643 }
644
645 else if (event->modifiers() == Qt::NoModifier) {
646 // Keyboard actions for image viewer
647 switch (event->key()) {
648 case Qt::Key_1: FImageView->zoomIn(); break;
649 case Qt::Key_2: FImageView->zoom100(); break;
650 case Qt::Key_3: FImageView->zoomOut(); break;
651 case Qt::Key_4: FImageView->zoomFit(); break;
652 default: break;
653 }
654 }
655 }
656
657 //------------------------------------------------------------------------------
constructContextMenu()658 void ptFileMgrWindow::constructContextMenu() {
659 // Actions for thumbnail view submenu
660 FVerticalThumbsAct = new QAction(tr("&Vertical") + "\t" + tr("Alt+1"), this);
661 FVerticalThumbsAct->setCheckable(true);
662 connect(FVerticalThumbsAct, SIGNAL(triggered()), this, SLOT(verticalThumbs()));
663
664 FHorizontalThumbsAct = new QAction(tr("&Horizontal") + "\t" + tr("Alt+2"), this);
665 FHorizontalThumbsAct->setCheckable(true);
666 connect(FHorizontalThumbsAct, SIGNAL(triggered()), this, SLOT(horizontalThumbs()));
667
668 FDetailedThumbsAct = new QAction(tr("&Details") + "\t" + tr("Alt+3"), this);
669 FDetailedThumbsAct->setCheckable(true);
670 connect(FDetailedThumbsAct, SIGNAL(triggered()), this, SLOT(detailedThumbs()));
671
672 #ifdef Q_OS_WIN
673 FDirThumbsAct = new QAction(tr("Show &folder thumbnails"), this);
674 #else
675 FDirThumbsAct = new QAction(tr("Show &directory thumbnails"), this);
676 #endif
677 FDirThumbsAct->setCheckable(true);
678 connect(FDirThumbsAct, SIGNAL(triggered()), this, SLOT(toggleDirThumbs()));
679
680 FThumbLayoutGroupAct = new QActionGroup(this);
681 FThumbLayoutGroupAct->setExclusive(true);
682 FThumbLayoutGroupAct->addAction(FVerticalThumbsAct);
683 FThumbLayoutGroupAct->addAction(FHorizontalThumbsAct);
684 //TODO: re-enable ac_ThumbLayoutGroup->addAction(ac_DetailedThumbs);
685
686 // actions for main context menu
687 FToggleImageViewAct = new QAction(tr("Show &image preview") + "\t" + tr("F3"), this);
688 FToggleImageViewAct->setCheckable(true);
689 connect(FToggleImageViewAct, SIGNAL(triggered()), this, SLOT(toggleImageView()));
690
691 FToggleSidebarAct = new QAction(tr("Show &sidebar") + "\t" + tr("F4"), this);
692 FToggleSidebarAct->setCheckable(true);
693 connect(FToggleSidebarAct, SIGNAL(triggered()), this, SLOT(toggleSidebar()));
694
695 FSaveThumbAct = new QAction(tr("&Save thumbnail"), this);
696 connect(FSaveThumbAct, SIGNAL(triggered()), this, SLOT(saveThumbnail()));
697
698 FCloseFileMgrAct = new QAction(tr("&Close file manager") + "\t" + tr("Esc"), this);
699 connect(FCloseFileMgrAct, SIGNAL(triggered()), this, SLOT(closeWindow()));
700
701 FToggleShowRAWsAct = new QAction(tr("Show RAWs"), this);
702 FToggleShowRAWsAct->setCheckable(true);
703 connect(FToggleShowRAWsAct, SIGNAL(triggered()), this, SLOT(toggleShowRAWs()));
704
705 FToggleShowBitmapsAct = new QAction(tr("Show bitmaps"), this);
706 FToggleShowBitmapsAct->setCheckable(true);
707 connect(FToggleShowBitmapsAct, SIGNAL(triggered()), this, SLOT(toggleShowBitmaps()));
708 }
709
710 //------------------------------------------------------------------------------
contextMenuEvent(QContextMenuEvent * event)711 void ptFileMgrWindow::contextMenuEvent(QContextMenuEvent* event) {
712 ptThumbnailLayout currLayout = (ptThumbnailLayout)Settings->GetInt("FileMgrThumbLayoutType");
713
714 // thumbnail view submenu
715 QMenu MenuThumbLayout(tr("Thumbnail &view"));
716 MenuThumbLayout.setPalette(Theme->menuPalette());
717 MenuThumbLayout.setStyle(Theme->style());
718 MenuThumbLayout.addActions(FThumbLayoutGroupAct->actions());
719 MenuThumbLayout.addSeparator();
720 MenuThumbLayout.addAction(FDirThumbsAct);
721 FVerticalThumbsAct->setChecked(currLayout == tlVerticalByRow);
722 FHorizontalThumbsAct->setChecked(currLayout == tlHorizontalByColumn);
723 FDetailedThumbsAct->setChecked(currLayout == tlDetailedList);
724 FDirThumbsAct->setChecked(Settings->GetInt("FileMgrShowDirThumbs"));
725
726 // main context menu
727 QMenu Menu(NULL);
728 Menu.setPalette(Theme->menuPalette());
729 Menu.setStyle(Theme->style());
730 Menu.addMenu(&MenuThumbLayout);
731
732 Menu.addSeparator();
733 Menu.addAction(FToggleImageViewAct);
734 FToggleImageViewAct->setChecked(FMImageViewPane->isVisible());
735 Menu.addAction(FToggleSidebarAct);
736 FToggleSidebarAct->setChecked(FMSidebar->isVisible());
737
738 Menu.addSeparator();
739 Menu.addAction(FToggleShowRAWsAct);
740 FToggleShowRAWsAct->setChecked(Settings->GetInt("FileMgrShowRAWs"));
741 Menu.addAction(FToggleShowBitmapsAct);
742 FToggleShowBitmapsAct->setChecked(Settings->GetInt("FileMgrShowBitmaps"));
743
744 Menu.addSeparator();
745 Menu.addAction(FSaveThumbAct);
746
747 Menu.addSeparator();
748 Menu.addAction(FCloseFileMgrAct);
749
750 Menu.exec(event->globalPos());
751 }
752
753 //------------------------------------------------------------------------------
verticalThumbs()754 void ptFileMgrWindow::verticalThumbs() {
755 setLayouter(tlVerticalByRow);
756 }
757
758 //------------------------------------------------------------------------------
horizontalThumbs()759 void ptFileMgrWindow::horizontalThumbs() {
760 setLayouter(tlHorizontalByColumn);
761 }
762
763 //------------------------------------------------------------------------------
detailedThumbs()764 void ptFileMgrWindow::detailedThumbs() {
765 setLayouter(tlDetailedList);
766 }
767
768 //------------------------------------------------------------------------------
toggleSidebar()769 void ptFileMgrWindow::toggleSidebar() {
770 FMSidebar->setVisible(!FMSidebar->isVisible());
771 Settings->SetValue("FileMgrShowSidebar", (int)FMSidebar->isVisible());
772 }
773
774 //------------------------------------------------------------------------------
toggleImageView()775 void ptFileMgrWindow::toggleImageView() {
776 FMImageViewPane->setVisible(!FMImageViewPane->isVisible());
777 Settings->SetValue("FileMgrShowImageView", (int)FMImageViewPane->isVisible());
778 }
779
780 //------------------------------------------------------------------------------
toggleDirThumbs()781 void ptFileMgrWindow::toggleDirThumbs() {
782 Settings->SetValue("FileMgrShowDirThumbs", 1 - Settings->GetInt("FileMgrShowDirThumbs"));
783 displayThumbnails();
784 }
785
toggleShowRAWs()786 void ptFileMgrWindow::toggleShowRAWs() {
787 Settings->SetValue("FileMgrShowRAWs", 1 - Settings->GetInt("FileMgrShowRAWs"));
788 displayThumbnails();
789 }
790
toggleShowBitmaps()791 void ptFileMgrWindow::toggleShowBitmaps() {
792 Settings->SetValue("FileMgrShowBitmaps", 1 - Settings->GetInt("FileMgrShowBitmaps"));
793 displayThumbnails();
794 }
795
796 //------------------------------------------------------------------------------
bookmarkCurrentDir()797 void ptFileMgrWindow::bookmarkCurrentDir() {
798 FDataModel->tagModel()->appendRow(QDir::toNativeSeparators(FDataModel->currentDir()),
799 FDataModel->currentDir());
800 if (FTagMenu->isVisible()) {
801 adjustBookmarkMenuSize();
802 }
803 }
804
805 //------------------------------------------------------------------------------
on_m_BookmarkButton_clicked()806 void ptFileMgrWindow::on_m_BookmarkButton_clicked() {
807 FTagMenu->move(m_BookmarkButton->mapToGlobal(QPoint(0, m_BookmarkButton->height())));
808 FTagMenu->setPalette(Theme->menuPalette());
809 FTagMenu->setStyle(Theme->style());
810 FTagMenu->show(); // must be first or adjust size won’t work correctly
811 adjustBookmarkMenuSize();
812
813 FTagMenuList->setFocus();
814 }
815
816 //------------------------------------------------------------------------------
adjustBookmarkMenuSize()817 void ptFileMgrWindow::adjustBookmarkMenuSize() {
818 QSize MenuSize(0, 0);
819 QPoint MenuTopleft = m_BookmarkButton->mapTo(this, QPoint(0, m_BookmarkButton->height()));
820 QSize MaxSize((this->width() - MenuTopleft.x()) * 0.85,
821 (this->height() - MenuTopleft.y()) * 0.85);
822
823 QFontMetrics metrics(FTagMenuList->font());
824 for (int i = 0; i < FDataModel->tagModel()->rowCount(); i++) {
825 QModelIndex curIndex = FDataModel->tagModel()->index(i, 0);
826 int width = metrics.width(curIndex.data().toString());
827 if (width > MenuSize.width()) MenuSize.setWidth(width);
828 MenuSize.setHeight(MenuSize.height() + FTagMenuList->visualRect(curIndex).height());
829 }
830
831 FTagMenu->setFixedSize(qBound(150,
832 MenuSize.width() + 20 + FTagMenuList->verticalScrollBar()->width(),
833 MaxSize.width()),
834 qBound(FTagMenuList->y() + 50,
835 MenuSize.height() + FTagMenuList->y() + 30,
836 MaxSize.height()) );
837 }
838
839 //------------------------------------------------------------------------------
bookmarkDataChanged(QStandardItem *)840 void ptFileMgrWindow::bookmarkDataChanged(QStandardItem*) {
841 if (FTagMenu->isVisible()) {
842 adjustBookmarkMenuSize();
843 }
844 }
845
846