1 /* ============================================================
2 *
3 * This file is a part of digiKam project
4 * https://www.digikam.org
5 *
6 * Date : 2007-03-05
7 * Description : digiKam light table GUI
8 *
9 * Copyright (C) 2007-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
10 *
11 * This program is free software; you can redistribute it
12 * and/or modify it under the terms of the GNU General
13 * Public License as published by the Free Software Foundation;
14 * either version 2, or (at your option)
15 * any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * ============================================================ */
23
24 #include "lighttablewindow_p.h"
25
26 namespace Digikam
27 {
28
29 LightTableWindow* LightTableWindow::m_instance = nullptr;
30
lightTableWindow()31 LightTableWindow* LightTableWindow::lightTableWindow()
32 {
33 if (!m_instance)
34 {
35 new LightTableWindow();
36 }
37
38 return m_instance;
39 }
40
lightTableWindowCreated()41 bool LightTableWindow::lightTableWindowCreated()
42 {
43 return m_instance;
44 }
45
LightTableWindow()46 LightTableWindow::LightTableWindow()
47 : DXmlGuiWindow(nullptr),
48 d (new Private)
49 {
50 setObjectName(QLatin1String("Light Table"));
51 setConfigGroupName(QLatin1String("LightTable Settings"));
52 setXMLFile(QLatin1String("lighttablewindowui5.rc"));
53
54 m_instance = this;
55
56 setWindowFlags(Qt::Window);
57 setCaption(i18n("Light Table"));
58
59 // We don't want to be deleted on close
60
61 setAttribute(Qt::WA_DeleteOnClose, false);
62 setFullScreenOptions(FS_LIGHTTABLE);
63
64 // -- Build the GUI -------------------------------
65
66 setupUserArea();
67 setupActions();
68 setupStatusBar();
69
70 // ------------------------------------------------
71
72 setupConnections();
73 slotColorManagementOptionsChanged();
74
75 readSettings();
76
77 d->leftSideBar->populateTags();
78 d->rightSideBar->populateTags();
79
80 applySettings();
81 setAutoSaveSettings(configGroupName(), true);
82 }
83
~LightTableWindow()84 LightTableWindow::~LightTableWindow()
85 {
86 m_instance = nullptr;
87
88 delete d->thumbView;
89 delete d->rightSideBar;
90 delete d->leftSideBar;
91 delete d;
92 }
93
refreshView()94 void LightTableWindow::refreshView()
95 {
96 d->leftSideBar->refreshTagsView();
97 d->rightSideBar->refreshTagsView();
98 }
99
closeEvent(QCloseEvent * e)100 void LightTableWindow::closeEvent(QCloseEvent* e)
101 {
102 if (!e)
103 {
104 return;
105 }
106
107 if (d->clearOnCloseAction->isChecked())
108 {
109 slotClearItemsList();
110 }
111
112 // There is one nasty habit with the thumbnail bar if it is floating: it
113 // doesn't close when the parent window does, so it needs to be manually
114 // closed. If the light table is opened again, its original state needs to
115 // be restored.
116 // This only needs to be done when closing a visible window and not when
117 // destroying a closed window, since the latter case will always report that
118 // the thumbnail bar isn't visible.
119
120 if (isVisible())
121 {
122 d->barViewDock->hide();
123 }
124
125 writeSettings();
126
127 DXmlGuiWindow::closeEvent(e);
128 }
129
showEvent(QShowEvent *)130 void LightTableWindow::showEvent(QShowEvent*)
131 {
132 // Restore the visibility of the thumbbar and start autosaving again.
133
134 d->barViewDock->restoreVisibility();
135 }
136
137 /**
138 * Deal with items dropped onto the thumbbar (e.g. from the Album view)
139 */
slotThumbbarDroppedItems(const QList<ItemInfo> & list)140 void LightTableWindow::slotThumbbarDroppedItems(const QList<ItemInfo>& list)
141 {
142 // Setting the third parameter of loadItemInfos to true
143 // means that the images are added to the presently available images.
144
145 loadItemInfos(ItemInfoList(list), ItemInfo(), true);
146 }
147
148 /**
149 * We get here either
150 * - via CTRL+L (from the albumview)
151 * a) digikamapp.cpp: CTRL+key_L leads to slotImageLightTable())
152 * b) digikamview.cpp: void ItemIconView::slotImageLightTable()
153 * calls d->iconView->insertToLightTable(list, info);
154 * c) albumiconview.cpp: AlbumIconView::insertToLightTable
155 * calls ltview->loadItemInfos(list, current);
156 * - via drag&drop, i.e. calls issued by the ...Dropped... routines
157 */
loadItemInfos(const ItemInfoList & list,const ItemInfo & givenItemInfoCurrent,bool addTo)158 void LightTableWindow::loadItemInfos(const ItemInfoList& list,
159 const ItemInfo& givenItemInfoCurrent,
160 bool addTo)
161 {
162 // Clear all items before adding new images to the light table.
163
164 qCDebug(DIGIKAM_GENERAL_LOG) << "Clearing LT" << (!addTo);
165
166 if (!addTo)
167 {
168 slotClearItemsList();
169 }
170
171 ItemInfoList l = list;
172 ItemInfo imageInfoCurrent = givenItemInfoCurrent;
173
174 if (imageInfoCurrent.isNull() && !l.isEmpty())
175 {
176 imageInfoCurrent = l.first();
177 }
178
179 d->thumbView->setItems(l);
180
181 QModelIndex index = d->thumbView->findItemByInfo(imageInfoCurrent);
182
183 if (index.isValid())
184 {
185 d->thumbView->setCurrentIndex(index);
186 }
187 else
188 {
189 d->thumbView->setCurrentWhenAvailable(imageInfoCurrent.id());
190 }
191 }
192
isEmpty() const193 bool LightTableWindow::isEmpty() const
194 {
195 return (d->thumbView->countItems() == 0);
196 }
197
slotRefreshStatusBar()198 void LightTableWindow::slotRefreshStatusBar()
199 {
200 d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode,
201 i18np("%1 item on Light Table",
202 "%1 items on Light Table",
203 d->thumbView->countItems()));
204 }
205
slotFileChanged(const QString & path)206 void LightTableWindow::slotFileChanged(const QString& path)
207 {
208 QUrl url = QUrl::fromLocalFile(path);
209
210 // NOTE: Thumbbar handle change through ItemCategorizedView
211
212 if (!d->previewView->leftItemInfo().isNull())
213 {
214 if (d->previewView->leftItemInfo().fileUrl() == url)
215 {
216 d->previewView->leftReload();
217 d->leftSideBar->itemChanged(d->previewView->leftItemInfo());
218 }
219 }
220
221 if (!d->previewView->rightItemInfo().isNull())
222 {
223 if (d->previewView->rightItemInfo().fileUrl() == url)
224 {
225 d->previewView->rightReload();
226 d->rightSideBar->itemChanged(d->previewView->rightItemInfo());
227 }
228 }
229 }
230
slotLeftPanelLeftButtonClicked()231 void LightTableWindow::slotLeftPanelLeftButtonClicked()
232 {
233 if (d->navigateByPairAction->isChecked())
234 {
235 return;
236 }
237
238 d->thumbView->setCurrentInfo(d->previewView->leftItemInfo());
239 }
240
slotRightPanelLeftButtonClicked()241 void LightTableWindow::slotRightPanelLeftButtonClicked()
242 {
243 // With navigate by pair option, only the left panel can be selected.
244
245 if (d->navigateByPairAction->isChecked())
246 {
247 return;
248 }
249
250 d->thumbView->setCurrentInfo(d->previewView->rightItemInfo());
251 }
252
slotLeftPreviewLoaded(bool b)253 void LightTableWindow::slotLeftPreviewLoaded(bool b)
254 {
255 d->leftZoomBar->setEnabled(b);
256 d->leftFileName->setAdjustedText();
257
258 if (b)
259 {
260 d->leftFileName->setAdjustedText(d->previewView->leftItemInfo().name());
261 d->previewView->checkForSelection(d->thumbView->currentInfo());
262 d->thumbView->setOnLeftPanel(d->previewView->leftItemInfo());
263
264 QModelIndex index = d->thumbView->findItemByInfo(d->previewView->leftItemInfo());
265
266 if (d->navigateByPairAction->isChecked() && index.isValid())
267 {
268 QModelIndex next = d->thumbView->nextIndex(index);
269
270 if (next.isValid())
271 {
272 d->thumbView->setOnRightPanel(d->thumbView->findItemByIndex(next));
273 slotSetItemOnRightPanel(d->thumbView->findItemByIndex(next));
274 }
275 else
276 {
277 QModelIndex first = d->thumbView->firstIndex();
278 slotSetItemOnRightPanel(first.isValid() ? d->thumbView->findItemByIndex(first) : ItemInfo());
279 }
280 }
281 }
282 }
283
slotRightPreviewLoaded(bool b)284 void LightTableWindow::slotRightPreviewLoaded(bool b)
285 {
286 d->rightZoomBar->setEnabled(b);
287 d->rightFileName->setAdjustedText();
288
289 if (b)
290 {
291 d->rightFileName->setAdjustedText(d->previewView->rightItemInfo().name());
292 d->previewView->checkForSelection(d->thumbView->currentInfo());
293 d->thumbView->setOnRightPanel(d->previewView->rightItemInfo());
294
295 QModelIndex index = d->thumbView->findItemByInfo(d->previewView->rightItemInfo());
296
297 if (index.isValid())
298 {
299 d->thumbView->setOnRightPanel(d->thumbView->findItemByIndex(index));
300 }
301 }
302 }
303
slotItemSelected(const ItemInfo & info)304 void LightTableWindow::slotItemSelected(const ItemInfo& info)
305 {
306 bool hasInfo = !info.isNull();
307
308 d->setItemLeftAction->setEnabled(hasInfo);
309 d->setItemRightAction->setEnabled(hasInfo);
310 d->editItemAction->setEnabled(hasInfo);
311 d->removeItemAction->setEnabled(hasInfo);
312 d->clearListAction->setEnabled(hasInfo);
313 d->fileDeleteAction->setEnabled(hasInfo);
314 d->fileDeleteFinalAction->setEnabled(hasInfo);
315 d->backwardAction->setEnabled(hasInfo);
316 d->forwardAction->setEnabled(hasInfo);
317 d->firstAction->setEnabled(hasInfo);
318 d->lastAction->setEnabled(hasInfo);
319 d->syncPreviewAction->setEnabled(hasInfo);
320 d->navigateByPairAction->setEnabled(hasInfo);
321
322 if (hasInfo)
323 {
324 QModelIndex curr = d->thumbView->findItemByInfo(info);
325
326 if (curr.isValid())
327 {
328 if (!d->thumbView->previousIndex(curr).isValid())
329 {
330 d->firstAction->setEnabled(false);
331 }
332
333 if (!d->thumbView->nextIndex(curr).isValid())
334 {
335 d->lastAction->setEnabled(false);
336 }
337
338 if (d->navigateByPairAction->isChecked())
339 {
340 d->setItemLeftAction->setEnabled(false);
341 d->setItemRightAction->setEnabled(false);
342
343 d->thumbView->setOnLeftPanel(info);
344 slotSetItemOnLeftPanel(info);
345 }
346 else if (d->autoLoadOnRightPanel && !d->thumbView->isOnLeftPanel(info))
347 {
348 d->thumbView->setOnRightPanel(info);
349 slotSetItemOnRightPanel(info);
350 }
351 }
352 }
353
354 d->previewView->checkForSelection(info);
355 }
356
357 /**
358 * Deal with one (or more) items dropped onto the left panel
359 */
slotLeftDroppedItems(const ItemInfoList & list)360 void LightTableWindow::slotLeftDroppedItems(const ItemInfoList& list)
361 {
362 ItemInfo info = list.first();
363
364 // add the image to the existing images
365
366 loadItemInfos(list, info, true);
367
368 // We will check if first item from list is already stored in thumbbar
369 // Note that the thumbbar stores all ItemInfo reference
370 // in memory for preview object.
371
372 QModelIndex index = d->thumbView->findItemByInfo(info);
373
374 if (index.isValid())
375 {
376 slotSetItemOnLeftPanel(info);
377 }
378 }
379
380 /**
381 * Deal with one (or more) items dropped onto the right panel
382 */
slotRightDroppedItems(const ItemInfoList & list)383 void LightTableWindow::slotRightDroppedItems(const ItemInfoList& list)
384 {
385 ItemInfo info = list.first();
386
387 // add the image to the existing images
388
389 loadItemInfos(list, info, true);
390
391 // We will check if first item from list is already stored in thumbbar
392 // Note that the thumbbar stores all ItemInfo reference
393 // in memory for preview object.
394
395 QModelIndex index = d->thumbView->findItemByInfo(info);
396
397 if (index.isValid())
398 {
399 slotSetItemOnRightPanel(info);
400
401 // Make this item the current one.
402
403 d->thumbView->setCurrentInfo(info);
404 }
405 }
406
407 /**
408 * Set the images for the left and right panel.
409 */
setLeftRightItems(const ItemInfoList & list,bool addTo)410 void LightTableWindow::setLeftRightItems(const ItemInfoList& list, bool addTo)
411 {
412 ItemInfoList l = list;
413
414 if (l.count() == 0)
415 {
416 return;
417 }
418
419 ItemInfo info = l.first();
420 QModelIndex index = d->thumbView->findItemByInfo(info);
421
422 if ((l.count() == 1) && !addTo)
423 {
424 // Just one item; this is used for the left panel.
425
426 d->thumbView->setOnLeftPanel(info);
427 slotSetItemOnLeftPanel(info);
428 d->thumbView->setCurrentInfo(info);
429
430 return;
431 }
432
433 if (index.isValid())
434 {
435 // The first item is used for the left panel.
436
437 if (!addTo)
438 {
439 d->thumbView->setOnLeftPanel(info);
440 slotSetItemOnLeftPanel(info);
441 }
442
443 // The subsequent item is used for the right panel.
444
445 QModelIndex next = d->thumbView->nextIndex(index);
446
447 if (next.isValid() && !addTo)
448 {
449 ItemInfo nextInf = d->thumbView->findItemByIndex(next);
450 d->thumbView->setOnRightPanel(nextInf);
451 slotSetItemOnRightPanel(nextInf);
452
453 if (!d->navigateByPairAction->isChecked())
454 {
455 d->thumbView->setCurrentInfo(nextInf);
456 }
457 }
458
459 // If navigate by pairs is active, the left panel item is selected.
460 // (Fixes parts of bug #150296)
461
462 if (d->navigateByPairAction->isChecked())
463 {
464 d->thumbView->setCurrentInfo(info);
465 }
466 }
467 }
468
slotSetItemLeft()469 void LightTableWindow::slotSetItemLeft()
470 {
471 if (!d->thumbView->currentInfo().isNull())
472 {
473 slotSetItemOnLeftPanel(d->thumbView->currentInfo());
474 }
475 }
476
slotSetItemRight()477 void LightTableWindow::slotSetItemRight()
478 {
479 if (!d->thumbView->currentInfo().isNull())
480 {
481 slotSetItemOnRightPanel(d->thumbView->currentInfo());
482 }
483 }
484
slotSetItemOnLeftPanel(const ItemInfo & info)485 void LightTableWindow::slotSetItemOnLeftPanel(const ItemInfo& info)
486 {
487 d->previewView->setLeftItemInfo(info);
488
489 if (!info.isNull())
490 {
491 d->leftSideBar->itemChanged(info);
492 }
493 else
494 {
495 d->leftSideBar->slotNoCurrentItem();
496 }
497 }
498
slotSetItemOnRightPanel(const ItemInfo & info)499 void LightTableWindow::slotSetItemOnRightPanel(const ItemInfo& info)
500 {
501 d->previewView->setRightItemInfo(info);
502
503 if (!info.isNull())
504 {
505 d->rightSideBar->itemChanged(info);
506 }
507 else
508 {
509 d->rightSideBar->slotNoCurrentItem();
510 }
511 }
512
slotClearItemsList()513 void LightTableWindow::slotClearItemsList()
514 {
515 if (!d->previewView->leftItemInfo().isNull())
516 {
517 d->previewView->setLeftItemInfo();
518 d->leftSideBar->slotNoCurrentItem();
519 }
520
521 if (!d->previewView->rightItemInfo().isNull())
522 {
523 d->previewView->setRightItemInfo();
524 d->rightSideBar->slotNoCurrentItem();
525 }
526
527 d->thumbView->clear();
528 }
529
slotDeleteItem()530 void LightTableWindow::slotDeleteItem()
531 {
532 deleteItem(false);
533 }
534
slotDeleteItem(const ItemInfo & info)535 void LightTableWindow::slotDeleteItem(const ItemInfo& info)
536 {
537 deleteItem(info, false);
538 }
539
slotDeleteFinalItem()540 void LightTableWindow::slotDeleteFinalItem()
541 {
542 deleteItem(true);
543 }
544
slotDeleteFinalItem(const ItemInfo & info)545 void LightTableWindow::slotDeleteFinalItem(const ItemInfo& info)
546 {
547 deleteItem(info, true);
548 }
549
deleteItem(bool permanently)550 void LightTableWindow::deleteItem(bool permanently)
551 {
552 if (!d->thumbView->currentInfo().isNull())
553 {
554 deleteItem(d->thumbView->currentInfo(), permanently);
555 }
556 }
557
deleteItem(const ItemInfo & info,bool permanently)558 void LightTableWindow::deleteItem(const ItemInfo& info, bool permanently)
559 {
560 QUrl u = info.fileUrl();
561 PAlbum* const palbum = AlbumManager::instance()->findPAlbum(u.adjusted(QUrl::RemoveFilename));
562
563 if (!palbum)
564 {
565 return;
566 }
567
568 qCDebug(DIGIKAM_GENERAL_LOG) << "Item to delete: " << u;
569
570 bool useTrash;
571 bool preselectDeletePermanently = permanently;
572
573 DeleteDialog dialog(this);
574
575 QList<QUrl> urlList;
576 urlList.append(u);
577
578 if (!dialog.confirmDeleteList(urlList, DeleteDialogMode::Files, preselectDeletePermanently ?
579 DeleteDialogMode::NoChoiceDeletePermanently : DeleteDialogMode::NoChoiceTrash))
580 {
581 return;
582 }
583
584 useTrash = !dialog.shouldDelete();
585
586 DIO::del(info, useTrash);
587 }
588
slotRemoveItem()589 void LightTableWindow::slotRemoveItem()
590 {
591 if (!d->thumbView->currentInfo().isNull())
592 {
593 slotRemoveItem(d->thumbView->currentInfo());
594 }
595 }
596
slotRemoveItem(const ItemInfo & info)597 void LightTableWindow::slotRemoveItem(const ItemInfo& info)
598 {
599 /*
600 if (!d->previewView->leftItemInfo().isNull())
601 {
602 if (d->previewView->leftItemInfo() == info)
603 {
604 d->previewView->setLeftItemInfo();
605 d->leftSideBar->slotNoCurrentItem();
606 }
607 }
608
609 if (!d->previewView->rightItemInfo().isNull())
610 {
611 if (d->previewView->rightItemInfo() == info)
612 {
613 d->previewView->setRightItemInfo();
614 d->rightSideBar->slotNoCurrentItem();
615 }
616 }
617
618 d->thumbView->removeItemByInfo(info);
619 d->thumbView->setSelected(d->thumbView->currentItem());
620 */
621
622 // When either the image from the left or right panel is removed,
623 // there are various situations to account for.
624 // To describe them, 4 images A B C D are used
625 // and the subscript _L and _ R mark the currently
626 // active item on the left and right panel
627
628 ItemInfo new_linfo;
629 ItemInfo new_rinfo;
630 bool leftPanelActive = false;
631 ItemInfo curr_linfo = d->previewView->leftItemInfo();
632 ItemInfo curr_rinfo = d->previewView->rightItemInfo();
633 qint64 infoId = info.id();
634
635 // First determine the next images to the current left and right image:
636
637 ItemInfo next_linfo;
638 ItemInfo next_rinfo;
639
640 if (!curr_linfo.isNull())
641 {
642 QModelIndex index = d->thumbView->findItemByInfo(curr_linfo);
643
644 if (index.isValid())
645 {
646 QModelIndex next = d->thumbView->nextIndex(index);
647
648 if (next.isValid())
649 {
650 next_linfo = d->thumbView->findItemByIndex(next);
651 }
652 }
653 }
654
655 if (!curr_rinfo.isNull())
656 {
657 QModelIndex index = d->thumbView->findItemByInfo(curr_rinfo);
658
659 if (index.isValid())
660 {
661 QModelIndex next = d->thumbView->nextIndex(index);
662
663 if (next.isValid())
664 {
665 next_rinfo = d->thumbView->findItemByIndex(next);
666 }
667 }
668 }
669
670 d->thumbView->removeItemByInfo(info);
671
672 // Make sure that next_linfo and next_rinfo are still available:
673
674 if (!d->thumbView->findItemByInfo(next_linfo).isValid())
675 {
676 next_linfo = ItemInfo();
677 }
678
679 if (!d->thumbView->findItemByInfo(next_rinfo).isValid())
680 {
681 next_rinfo = ItemInfo();
682 }
683
684 // removal of the left panel item?
685
686 if (!curr_linfo.isNull())
687 {
688 if (curr_linfo.id() == infoId)
689 {
690 leftPanelActive = true;
691
692 // Delete the item A_L of the left panel:
693 // 1) A_L B_R C D -> B_L C_R D
694 // 2) A_L B C_R D -> B C_L D_R
695 // 3) A_L B C D_R -> B_R C D_L
696 // 4) A_L B_R -> A_L
697 // some more corner cases:
698 // 5) A B_L C_R D -> A C_L D_R
699 // 6) A B_L C_R -> A_R C_L
700 // 7) A_LR B C D -> B_L C_R D (does not yet work)
701 // I.e. in 3) we wrap around circularly.
702
703 // When removing the left panel image,
704 // put the right panel image into the left panel.
705 // Check if this one is not the same (i.e. also removed).
706
707 if (!curr_rinfo.isNull())
708 {
709 if (curr_rinfo.id() != infoId)
710 {
711 new_linfo = curr_rinfo;
712
713 // Set the right panel to the next image:
714
715 new_rinfo = next_rinfo;
716
717 // set the right panel active, but not in pair mode
718
719 if (!d->navigateByPairAction->isChecked())
720 {
721 leftPanelActive = false;
722 }
723 }
724 }
725 }
726 }
727
728 // removal of the right panel item?
729
730 if (!curr_rinfo.isNull())
731 {
732 if (curr_rinfo.id() == infoId)
733 {
734 // Leave the left panel as the current one
735
736 new_linfo = curr_linfo;
737
738 // Set the right panel to the next image
739
740 new_rinfo = next_rinfo;
741 }
742 }
743
744 // Now we deal with the corner cases, where no left or right item exists.
745 // If the right panel would be set, but not the left-one, then swap
746
747 if (new_linfo.isNull() && !new_rinfo.isNull())
748 {
749 new_linfo = new_rinfo;
750 new_rinfo = ItemInfo();
751 leftPanelActive = true;
752 }
753
754 if (new_linfo.isNull())
755 {
756 if (d->thumbView->countItems() > 0)
757 {
758 QModelIndex first = d->thumbView->firstIndex();
759 new_linfo = d->thumbView->findItemByIndex(first);
760 }
761 }
762
763 // Make sure that new_linfo and new_rinfo exist.
764 // This addresses a crash occurring if the last image is removed
765 // in the navigate by pairs mode.
766
767 if (!d->thumbView->findItemByInfo(new_linfo).isValid())
768 {
769 new_linfo = ItemInfo();
770 }
771
772 if (!d->thumbView->findItemByInfo(new_rinfo).isValid())
773 {
774 new_rinfo = ItemInfo();
775 }
776
777 // no right item defined?
778
779 if (new_rinfo.isNull())
780 {
781 // If there are at least two items, we can find reasonable right image.
782
783 if (d->thumbView->countItems() > 1)
784 {
785 // See if there is an item next to the left one:
786
787 QModelIndex index = d->thumbView->findItemByInfo(new_linfo);
788 QModelIndex next;
789
790 if (index.isValid())
791 {
792 next = d->thumbView->nextIndex(index);
793 }
794
795 if (next.isValid())
796 {
797 new_rinfo = d->thumbView->findItemByIndex(next);
798 }
799 else
800 {
801 // If there is no item to the right of new_linfo
802 // then we can choose the first item for new_rinfo
803 // (as we made sure that there are at least two items)
804
805 QModelIndex first = d->thumbView->firstIndex();
806 new_rinfo = d->thumbView->findItemByIndex(first);
807 }
808 }
809 }
810
811 // Check if left and right are set to the same
812
813 if (!new_linfo.isNull() && !new_rinfo.isNull())
814 {
815 if (new_linfo.id() == new_rinfo.id())
816 {
817 // Only keep the left one
818
819 new_rinfo = ItemInfo();
820 }
821 }
822
823 // If the right panel would be set, but not the left-one, then swap
824 // (note that this has to be done here again!)
825
826 if (new_linfo.isNull() && !new_rinfo.isNull())
827 {
828 new_linfo = new_rinfo;
829 new_rinfo = ItemInfo();
830 leftPanelActive = true;
831 }
832
833 // set the image for the left panel
834
835 if (!new_linfo.isNull())
836 {
837 d->thumbView->setOnLeftPanel(new_linfo);
838 slotSetItemOnLeftPanel(new_linfo);
839
840 // make this the selected item if the left was active before
841
842 if (leftPanelActive)
843 {
844 d->thumbView->setCurrentInfo(new_linfo);
845 }
846 }
847 else
848 {
849 d->previewView->setLeftItemInfo();
850 d->leftSideBar->slotNoCurrentItem();
851 }
852
853 // set the image for the right panel
854
855 if (!new_rinfo.isNull())
856 {
857 d->thumbView->setOnRightPanel(new_rinfo);
858 slotSetItemOnRightPanel(new_rinfo);
859
860 // make this the selected item if the left was active before
861
862 if (!leftPanelActive)
863 {
864 d->thumbView->setCurrentInfo(new_rinfo);
865 }
866 }
867 else
868 {
869 d->previewView->setRightItemInfo();
870 d->rightSideBar->slotNoCurrentItem();
871 }
872 }
873
slotLeftZoomFactorChanged(double zoom)874 void LightTableWindow::slotLeftZoomFactorChanged(double zoom)
875 {
876 double zmin = d->previewView->leftZoomMin();
877 double zmax = d->previewView->leftZoomMax();
878 d->leftZoomBar->setZoom(zoom, zmin, zmax);
879
880 d->leftZoomPlusAction->setEnabled(!d->previewView->leftMaxZoom());
881 d->leftZoomMinusAction->setEnabled(!d->previewView->leftMinZoom());
882 }
883
slotRightZoomFactorChanged(double zoom)884 void LightTableWindow::slotRightZoomFactorChanged(double zoom)
885 {
886 double zmin = d->previewView->rightZoomMin();
887 double zmax = d->previewView->rightZoomMax();
888 d->rightZoomBar->setZoom(zoom, zmin, zmax);
889
890 d->rightZoomPlusAction->setEnabled(!d->previewView->rightMaxZoom());
891 d->rightZoomMinusAction->setEnabled(!d->previewView->rightMinZoom());
892 }
893
slotToggleSyncPreview()894 void LightTableWindow::slotToggleSyncPreview()
895 {
896 d->previewView->setSyncPreview(d->syncPreviewAction->isChecked());
897 }
898
slotToggleOnSyncPreview(bool t)899 void LightTableWindow::slotToggleOnSyncPreview(bool t)
900 {
901 d->syncPreviewAction->setEnabled(t);
902
903 if (!t)
904 {
905 d->syncPreviewAction->setChecked(false);
906 }
907 else
908 {
909 if (d->autoSyncPreview)
910 {
911 d->syncPreviewAction->setChecked(true);
912 }
913 }
914 }
915
slotBackward()916 void LightTableWindow::slotBackward()
917 {
918 d->thumbView->toPreviousIndex();
919 }
920
slotForward()921 void LightTableWindow::slotForward()
922 {
923 d->thumbView->toNextIndex();
924 }
925
slotFirst()926 void LightTableWindow::slotFirst()
927 {
928 d->thumbView->toFirstIndex();
929 }
930
slotLast()931 void LightTableWindow::slotLast()
932 {
933 d->thumbView->toLastIndex();
934 }
935
slotToggleNavigateByPair()936 void LightTableWindow::slotToggleNavigateByPair()
937 {
938 d->thumbView->setNavigateByPair(d->navigateByPairAction->isChecked());
939 d->previewView->setNavigateByPair(d->navigateByPairAction->isChecked());
940 slotItemSelected(d->thumbView->currentInfo());
941 }
942
slotComponentsInfo()943 void LightTableWindow::slotComponentsInfo()
944 {
945 showDigikamComponentsInfo();
946 }
947
slotDBStat()948 void LightTableWindow::slotDBStat()
949 {
950 showDigikamDatabaseStat();
951 }
952
slotOnlineVersionCheck()953 void LightTableWindow::slotOnlineVersionCheck()
954 {
955 Setup::onlineVersionCheck();
956 }
957
moveEvent(QMoveEvent * e)958 void LightTableWindow::moveEvent(QMoveEvent* e)
959 {
960 Q_UNUSED(e)
961 emit signalWindowHasMoved();
962 }
963
toggleTag(int tagID)964 void LightTableWindow::toggleTag(int tagID)
965 {
966 d->thumbView->toggleTag(tagID);
967 }
968
slotAssignPickLabel(int pickId)969 void LightTableWindow::slotAssignPickLabel(int pickId)
970 {
971 d->thumbView->slotAssignPickLabel(pickId);
972 }
973
slotAssignColorLabel(int colorId)974 void LightTableWindow::slotAssignColorLabel(int colorId)
975 {
976 d->thumbView->slotAssignColorLabel(colorId);
977 }
978
slotAssignRating(int rating)979 void LightTableWindow::slotAssignRating(int rating)
980 {
981 d->thumbView->slotAssignRating(rating);
982 }
983
showSideBars(bool visible)984 void LightTableWindow::showSideBars(bool visible)
985 {
986 if (visible)
987 {
988 d->leftSideBar->restore();
989 d->rightSideBar->restore();
990 }
991 else
992 {
993 d->leftSideBar->backup();
994 d->rightSideBar->backup();
995 }
996 }
997
slotToggleLeftSideBar()998 void LightTableWindow::slotToggleLeftSideBar()
999 {
1000 d->leftSideBar->isExpanded() ? d->leftSideBar->shrink()
1001 : d->leftSideBar->expand();
1002 }
1003
slotToggleRightSideBar()1004 void LightTableWindow::slotToggleRightSideBar()
1005 {
1006 d->rightSideBar->isExpanded() ? d->rightSideBar->shrink()
1007 : d->rightSideBar->expand();
1008 }
1009
slotPreviousLeftSideBarTab()1010 void LightTableWindow::slotPreviousLeftSideBarTab()
1011 {
1012 d->leftSideBar->activePreviousTab();
1013 }
1014
slotNextLeftSideBarTab()1015 void LightTableWindow::slotNextLeftSideBarTab()
1016 {
1017 d->leftSideBar->activeNextTab();
1018 }
1019
slotPreviousRightSideBarTab()1020 void LightTableWindow::slotPreviousRightSideBarTab()
1021 {
1022 d->rightSideBar->activePreviousTab();
1023 }
1024
slotNextRightSideBarTab()1025 void LightTableWindow::slotNextRightSideBarTab()
1026 {
1027 d->rightSideBar->activeNextTab();
1028 }
1029
customizedFullScreenMode(bool set)1030 void LightTableWindow::customizedFullScreenMode(bool set)
1031 {
1032 showStatusBarAction()->setEnabled(!set);
1033 toolBarMenuAction()->setEnabled(!set);
1034 showMenuBarAction()->setEnabled(!set);
1035 d->showBarAction->setEnabled(!set);
1036
1037 d->previewView->toggleFullScreen(set);
1038 }
1039
slotFileWithDefaultApplication()1040 void LightTableWindow::slotFileWithDefaultApplication()
1041 {
1042 if (!d->thumbView->currentInfo().isNull())
1043 {
1044 DFileOperations::openFilesWithDefaultApplication(QList<QUrl>() << d->thumbView->currentInfo().fileUrl());
1045 }
1046 }
1047
slotRightSideBarActivateTitles()1048 void LightTableWindow::slotRightSideBarActivateTitles()
1049 {
1050 d->rightSideBar->setActiveTab(d->rightSideBar->imageDescEditTab());
1051 d->rightSideBar->imageDescEditTab()->setFocusToTitlesEdit();
1052 }
1053
slotRightSideBarActivateComments()1054 void LightTableWindow::slotRightSideBarActivateComments()
1055 {
1056 d->rightSideBar->setActiveTab(d->rightSideBar->imageDescEditTab());
1057 d->rightSideBar->imageDescEditTab()->setFocusToCommentsEdit();
1058 }
1059
slotRightSideBarActivateAssignedTags()1060 void LightTableWindow::slotRightSideBarActivateAssignedTags()
1061 {
1062 d->rightSideBar->setActiveTab(d->rightSideBar->imageDescEditTab());
1063 d->rightSideBar->imageDescEditTab()->activateAssignedTagsButton();
1064 }
1065
slotLeftSideBarActivateTitles()1066 void LightTableWindow::slotLeftSideBarActivateTitles()
1067 {
1068 d->leftSideBar->setActiveTab(d->leftSideBar->imageDescEditTab());
1069 d->leftSideBar->imageDescEditTab()->setFocusToTitlesEdit();
1070 }
1071
slotLeftSideBarActivateComments()1072 void LightTableWindow::slotLeftSideBarActivateComments()
1073 {
1074 d->leftSideBar->setActiveTab(d->leftSideBar->imageDescEditTab());
1075 d->leftSideBar->imageDescEditTab()->setFocusToCommentsEdit();
1076 }
1077
slotLeftSideBarActivateAssignedTags()1078 void LightTableWindow::slotLeftSideBarActivateAssignedTags()
1079 {
1080 d->leftSideBar->setActiveTab(d->leftSideBar->imageDescEditTab());
1081 d->leftSideBar->imageDescEditTab()->activateAssignedTagsButton();
1082 }
1083
slotToggleColorManagedView()1084 void LightTableWindow::slotToggleColorManagedView()
1085 {
1086 if (!IccSettings::instance()->isEnabled())
1087 {
1088 return;
1089 }
1090
1091 bool cmv = !IccSettings::instance()->settings().useManagedPreviews;
1092 IccSettings::instance()->setUseManagedPreviews(cmv);
1093 }
1094
infoIface(DPluginAction * const ac)1095 DInfoInterface* LightTableWindow::infoIface(DPluginAction* const ac)
1096 {
1097 ApplicationSettings::OperationType aset = ApplicationSettings::Unspecified;
1098
1099 switch (ac->actionCategory())
1100 {
1101 case DPluginAction::GenericExport:
1102 case DPluginAction::GenericImport:
1103 aset = ApplicationSettings::ImportExport;
1104 break;
1105
1106 case DPluginAction::GenericMetadata:
1107 aset = ApplicationSettings::Metadata;
1108 break;
1109
1110 case DPluginAction::GenericTool:
1111 aset = ApplicationSettings::Tools;
1112 break;
1113
1114 case DPluginAction::GenericView:
1115 aset = ApplicationSettings::Slideshow;
1116 break;
1117
1118 default:
1119 break;
1120 }
1121
1122 DBInfoIface* const iface = new DBInfoIface(this, d->thumbView->allUrls(), aset);
1123
1124 connect(iface, SIGNAL(signalImportedImage(QUrl)),
1125 this, SLOT(slotImportedImagefromScanner(QUrl)));
1126
1127 return iface;
1128 }
1129
1130 } // namespace Digikam
1131