diff --git a/core/app/views/digikamview.cpp b/core/app/views/digikamview.cpp index da052115ae..a9cb03648f 100644 --- a/core/app/views/digikamview.cpp +++ b/core/app/views/digikamview.cpp @@ -1,2780 +1,2780 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2002-16-10 * Description : implementation of album view interface. * * Copyright (C) 2002-2005 by Renchi Raju * Copyright (C) 2002-2018 by Gilles Caulier * Copyright (C) 2009-2011 by Johannes Wienke * Copyright (C) 2010-2011 by Andi Clemens * Copyright (C) 2011-2013 by Michael G. Hansen * Copyright (C) 2014-2015 by Mohamed_Anwer * Copyright (C) 2017 by Simon Frei * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "digikamview.h" // Qt includes #include #include #include #include // KDE includes #include // Local includes #include "albumhistory.h" #include "albumlabelstreeview.h" #include "coredbsearchxml.h" #include "digikam_config.h" #include "digikam_debug.h" #include "digikam_globals.h" #include "digikamapp.h" #include "digikamimageview.h" #include "dmessagebox.h" #include "dzoombar.h" #include "dtrashitemmodel.h" #include "facescansettings.h" #include "facesdetector.h" #include "fileactionmngr.h" #include "fileactionprogress.h" #include "filtersidebarwidget.h" #include "filterstatusbar.h" #include "imagealbummodel.h" #include "imagedescedittab.h" #include "imagepreviewview.h" #include "imagepropertiessidebardb.h" #include "imagepropertiesversionstab.h" #include "imagethumbnailbar.h" #include "imageviewutilities.h" #include "leftsidebarwidgets.h" #include "loadingcacheinterface.h" #include "metadatahub.h" #include "metadatasettings.h" #include "metadatasynchronizer.h" #include "newitemsfinder.h" #include "presentationmngr.h" #include "queuemgrwindow.h" #include "scancontroller.h" #include "setup.h" #include "sidebar.h" #include "slideshow.h" #include "slideshowbuilder.h" #include "statusprogressbar.h" #include "tableview.h" #include "tagmodificationhelper.h" #include "tagsactionmngr.h" #include "tagscache.h" #include "tagsmanager.h" #include "thumbsgenerator.h" #include "trashview.h" #include "versionmanagersettings.h" #include "contextmenuhelper.h" #ifdef HAVE_MEDIAPLAYER # include "mediaplayerview.h" #endif //HAVE_MEDIAPLAYER #ifdef HAVE_MARBLE # include "mapwidgetview.h" #endif // HAVE_MARBLE namespace Digikam { class DigikamView::Private { public: explicit Private() : needDispatchSelection(false), useAlbumHistory(false), initialAlbumID(0), thumbSize(ThumbnailSize::Medium), dockArea(0), splitter(0), selectionTimer(0), thumbSizeTimer(0), albumFolderSideBar(0), tagViewSideBar(0), labelsSideBar(0), dateViewSideBar(0), timelineSideBar(0), searchSideBar(0), fuzzySearchSideBar(0), #ifdef HAVE_MARBLE gpsSearchSideBar(0), mapView(0), #endif // HAVE_MARBLE peopleSideBar(0), parent(0), iconView(0), tableView(0), trashView(0), utilities(0), albumManager(0), albumHistory(0), stackedview(0), lastViewMode(StackedView::IconViewMode), albumModificationHelper(0), tagModificationHelper(0), searchModificationHelper(0), leftSideBar(0), rightSideBar(0), filterWidget(0), optionAlbumViewPrefix(QLatin1String("AlbumView")), modelCollection(0), labelsSearchHandler(0) { } QString userPresentableAlbumTitle(const QString& album) const; void addPageUpDownActions(DigikamView* const q, QWidget* const w); public: bool needDispatchSelection; bool useAlbumHistory; int initialAlbumID; int thumbSize; QMainWindow* dockArea; SidebarSplitter* splitter; QTimer* selectionTimer; QTimer* thumbSizeTimer; // left side bar AlbumFolderViewSideBarWidget* albumFolderSideBar; TagViewSideBarWidget* tagViewSideBar; LabelsSideBarWidget* labelsSideBar; DateFolderViewSideBarWidget* dateViewSideBar; TimelineSideBarWidget* timelineSideBar; SearchSideBarWidget* searchSideBar; FuzzySearchSideBarWidget* fuzzySearchSideBar; #ifdef HAVE_MARBLE GPSSearchSideBarWidget* gpsSearchSideBar; MapWidgetView* mapView; #endif // HAVE_MARBLE PeopleSideBarWidget* peopleSideBar; DigikamApp* parent; DigikamImageView* iconView; TableView* tableView; TrashView* trashView; ImageViewUtilities* utilities; AlbumManager* albumManager; AlbumHistory* albumHistory; StackedView* stackedview; StackedView::StackedViewMode lastViewMode; AlbumModificationHelper* albumModificationHelper; TagModificationHelper* tagModificationHelper; SearchModificationHelper* searchModificationHelper; Sidebar* leftSideBar; ImagePropertiesSideBarDB* rightSideBar; FilterSideBarWidget* filterWidget; QString optionAlbumViewPrefix; QList leftSideBarWidgets; DigikamModelCollection* modelCollection; AlbumLabelsSearchHandler* labelsSearchHandler; }; QString DigikamView::Private::userPresentableAlbumTitle(const QString& title) const { if (title == SAlbum::getTemporaryHaarTitle(DatabaseSearch::HaarSketchSearch)) { return i18n("Fuzzy Sketch Search"); } else if (title == SAlbum::getTemporaryHaarTitle(DatabaseSearch::HaarImageSearch)) { return i18n("Fuzzy Image Search"); } else if (title == SAlbum::getTemporaryTitle(DatabaseSearch::MapSearch)) { return i18n("Map Search"); } else if (title == SAlbum::getTemporaryTitle(DatabaseSearch::AdvancedSearch) || title == SAlbum::getTemporaryTitle(DatabaseSearch::KeywordSearch)) { return i18n("Last Search"); } else if (title == SAlbum::getTemporaryTitle(DatabaseSearch::TimeLineSearch)) { return i18n("Timeline"); } return title; } void DigikamView::Private::addPageUpDownActions(DigikamView* const q, QWidget* const w) { defineShortcut(w, Qt::Key_PageDown, q, SLOT(slotNextItem())); defineShortcut(w, Qt::Key_Down, q, SLOT(slotNextItem())); defineShortcut(w, Qt::Key_Right, q, SLOT(slotNextItem())); defineShortcut(w, Qt::Key_PageUp, q, SLOT(slotPrevItem())); defineShortcut(w, Qt::Key_Up, q, SLOT(slotPrevItem())); defineShortcut(w, Qt::Key_Left, q, SLOT(slotPrevItem())); } // ------------------------------------------------------------------------------------------- DigikamView::DigikamView(QWidget* const parent, DigikamModelCollection* const modelCollection) : DHBox(parent), d(new Private) { qRegisterMetaType("SlideShowSettings"); d->parent = static_cast(parent); d->modelCollection = modelCollection; d->albumManager = AlbumManager::instance(); d->albumModificationHelper = new AlbumModificationHelper(this, this); d->tagModificationHelper = new TagModificationHelper(this, this); d->searchModificationHelper = new SearchModificationHelper(this, this); d->splitter = new SidebarSplitter; d->splitter->setFrameStyle( QFrame::NoFrame ); d->splitter->setFrameShadow( QFrame::Plain ); d->splitter->setFrameShape( QFrame::NoFrame ); d->splitter->setOpaqueResize(false); d->leftSideBar = new Sidebar(this, d->splitter, Qt::LeftEdge); d->leftSideBar->setObjectName(QLatin1String("Digikam Left Sidebar")); d->splitter->setParent(this); // The dock area where the thumbnail bar is allowed to go. d->dockArea = new QMainWindow(this, Qt::Widget); d->splitter->addWidget(d->dockArea); d->stackedview = new StackedView(d->dockArea); d->dockArea->setCentralWidget(d->stackedview); d->stackedview->setDockArea(d->dockArea); d->iconView = d->stackedview->imageIconView(); #ifdef HAVE_MARBLE d->mapView = d->stackedview->mapWidgetView(); #endif // HAVE_MARBLE d->tableView = d->stackedview->tableView(); d->trashView = d->stackedview->trashView(); d->utilities = d->iconView->utilities(); d->addPageUpDownActions(this, d->stackedview->imagePreviewView()); d->addPageUpDownActions(this, d->stackedview->thumbBar()); #ifdef HAVE_MEDIAPLAYER d->addPageUpDownActions(this, d->stackedview->mediaPlayerView()); #endif //HAVE_MEDIAPLAYER d->rightSideBar = new ImagePropertiesSideBarDB(this, d->splitter, Qt::RightEdge, true); d->rightSideBar->setObjectName(QLatin1String("Digikam Right Sidebar")); // album folder view d->albumFolderSideBar = new AlbumFolderViewSideBarWidget(d->leftSideBar, d->modelCollection->getAlbumModel(), d->albumModificationHelper); d->leftSideBarWidgets << d->albumFolderSideBar; connect(d->albumFolderSideBar, SIGNAL(signalFindDuplicates(PAlbum*)), this, SLOT(slotNewDuplicatesSearch(PAlbum*))); // Tags sidebar tab contents. d->tagViewSideBar = new TagViewSideBarWidget(d->leftSideBar, d->modelCollection->getTagModel()); d->leftSideBarWidgets << d->tagViewSideBar; connect(d->tagViewSideBar, SIGNAL(signalFindDuplicates(QList)), this, SLOT(slotNewDuplicatesSearch(QList))); // Labels sidebar d->labelsSideBar = new LabelsSideBarWidget(d->leftSideBar); d->leftSideBarWidgets << d->labelsSideBar; d->labelsSearchHandler = new AlbumLabelsSearchHandler(d->labelsSideBar->labelsTree()); // date view d->dateViewSideBar = new DateFolderViewSideBarWidget(d->leftSideBar, d->modelCollection->getDateAlbumModel(), d->iconView->imageAlbumFilterModel()); d->leftSideBarWidgets << d->dateViewSideBar; // timeline side bar d->timelineSideBar = new TimelineSideBarWidget(d->leftSideBar, d->modelCollection->getSearchModel(), d->searchModificationHelper); d->leftSideBarWidgets << d->timelineSideBar; // Search sidebar tab contents. d->searchSideBar = new SearchSideBarWidget(d->leftSideBar, d->modelCollection->getSearchModel(), d->searchModificationHelper); d->leftSideBarWidgets << d->searchSideBar; // Fuzzy search d->fuzzySearchSideBar = new FuzzySearchSideBarWidget(d->leftSideBar, d->modelCollection->getSearchModel(), d->searchModificationHelper); d->leftSideBarWidgets << d->fuzzySearchSideBar; connect(d->fuzzySearchSideBar,SIGNAL(signalActive(bool)), this, SIGNAL(signalFuzzySidebarActive(bool))); #ifdef HAVE_MARBLE d->gpsSearchSideBar = new GPSSearchSideBarWidget(d->leftSideBar, d->modelCollection->getSearchModel(), d->searchModificationHelper, d->iconView->imageFilterModel(), d->iconView->getSelectionModel()); d->leftSideBarWidgets << d->gpsSearchSideBar; #endif // HAVE_MARBLE // People Sidebar d->peopleSideBar = new PeopleSideBarWidget(d->leftSideBar, d->modelCollection->getTagFacesModel(), d->searchModificationHelper); connect(d->peopleSideBar, SIGNAL(requestFaceMode(bool)), d->iconView, SLOT(setFaceMode(bool))); connect(d->peopleSideBar, SIGNAL(signalFindDuplicates(QList)), this, SLOT(slotNewDuplicatesSearch(QList))); d->leftSideBarWidgets << d->peopleSideBar; foreach(SidebarWidget* const leftWidget, d->leftSideBarWidgets) { d->leftSideBar->appendTab(leftWidget, leftWidget->getIcon(), leftWidget->getCaption()); connect(leftWidget, SIGNAL(requestActiveTab(SidebarWidget*)), this, SLOT(slotLeftSideBarActivate(SidebarWidget*))); } // add only page up and down to work correctly with QCompleter defineShortcut(d->rightSideBar->imageDescEditTab(), Qt::Key_PageDown, this, SLOT(slotNextItem())); defineShortcut(d->rightSideBar->imageDescEditTab(), Qt::Key_PageUp, this, SLOT(slotPrevItem())); // Tags Filter sidebar tab contents. d->filterWidget = new FilterSideBarWidget(d->rightSideBar, d->modelCollection->getTagFilterModel()); d->rightSideBar->appendTab(d->filterWidget, QIcon::fromTheme(QLatin1String("view-filter")), i18n("Filters")); // Versions sidebar overlays d->rightSideBar->getFiltersHistoryTab()->addOpenAlbumAction(d->iconView->imageModel()); d->rightSideBar->getFiltersHistoryTab()->addShowHideOverlay(); d->selectionTimer = new QTimer(this); d->selectionTimer->setSingleShot(true); d->selectionTimer->setInterval(75); d->thumbSizeTimer = new QTimer(this); d->thumbSizeTimer->setSingleShot(true); d->thumbSizeTimer->setInterval(300); d->albumHistory = new AlbumHistory(); slotSidebarTabTitleStyleChanged(); setupConnections(); connect(d->rightSideBar->imageDescEditTab()->getNewTagEdit(), SIGNAL(taggingActionFinished()), this, SLOT(slotFocusAndNextImage())); connect(d->rightSideBar, SIGNAL(signalSetupMetadataFilters(int)), this, SLOT(slotSetupMetadataFilters(int))); } DigikamView::~DigikamView() { saveViewState(); delete d->labelsSearchHandler; delete d->albumHistory; delete d; } void DigikamView::applySettings() { foreach(SidebarWidget* const sidebarWidget, d->leftSideBarWidgets) { sidebarWidget->applySettings(); } d->iconView->imageFilterModel()->setVersionImageFilterSettings(VersionImageFilterSettings(ApplicationSettings::instance()->getVersionManagerSettings())); refreshView(); } void DigikamView::refreshView() { d->rightSideBar->refreshTagsView(); } void DigikamView::setupConnections() { // -- DigikamApp connections ---------------------------------- connect(d->parent, SIGNAL(signalEscapePressed()), this, SLOT(slotEscapePreview())); connect(d->parent, SIGNAL(signalEscapePressed()), d->stackedview, SLOT(slotEscapePreview())); connect(d->parent, SIGNAL(signalNextItem()), this, SLOT(slotNextItem())); connect(d->parent, SIGNAL(signalPrevItem()), this, SLOT(slotPrevItem())); connect(d->parent, SIGNAL(signalFirstItem()), this, SLOT(slotFirstItem())); connect(d->parent, SIGNAL(signalLastItem()), this, SLOT(slotLastItem())); connect(d->parent, SIGNAL(signalCutAlbumItemsSelection()), d->iconView, SLOT(cut())); connect(d->parent, SIGNAL(signalCopyAlbumItemsSelection()), d->iconView, SLOT(copy())); connect(d->parent, SIGNAL(signalPasteAlbumItemsSelection()), this, SLOT(slotImagePaste())); // -- AlbumManager connections -------------------------------- connect(d->albumManager, SIGNAL(signalAlbumCurrentChanged(QList)), this, SLOT(slotAlbumSelected(QList))); connect(d->albumManager, SIGNAL(signalAllAlbumsLoaded()), this, SLOT(slotAllAlbumsLoaded())); connect(d->albumManager, SIGNAL(signalAlbumsCleared()), this, SLOT(slotAlbumsCleared())); // -- IconView Connections ------------------------------------- connect(d->iconView->model(), SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(slotImageSelected())); connect(d->iconView->model(), SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(slotImageSelected())); connect(d->iconView->model(), SIGNAL(layoutChanged()), this, SLOT(slotImageSelected())); connect(d->iconView, SIGNAL(selectionChanged()), this, SLOT(slotImageSelected())); connect(d->iconView, SIGNAL(previewRequested(ImageInfo)), this, SLOT(slotTogglePreviewMode(ImageInfo))); connect(d->iconView, SIGNAL(fullscreenRequested(ImageInfo)), this, SLOT(slotSlideShowManualFrom(ImageInfo))); connect(d->iconView, SIGNAL(zoomOutStep()), this, SLOT(slotZoomOut())); connect(d->iconView, SIGNAL(zoomInStep()), this, SLOT(slotZoomIn())); connect(d->iconView, SIGNAL(signalShowContextMenu(QContextMenuEvent*,QList)), this, SLOT(slotShowContextMenu(QContextMenuEvent*,QList))); connect(d->iconView, SIGNAL(signalShowContextMenuOnInfo(QContextMenuEvent*,ImageInfo,QList,ImageFilterModel*)), this, SLOT(slotShowContextMenuOnInfo(QContextMenuEvent*,ImageInfo,QList,ImageFilterModel*))); connect(d->iconView, SIGNAL(signalShowGroupContextMenu(QContextMenuEvent*,QList,ImageFilterModel*)), this, SLOT(slotShowGroupContextMenu(QContextMenuEvent*,QList,ImageFilterModel*))); // -- TableView Connections ----------------------------------- connect(d->tableView, SIGNAL(signalPreviewRequested(ImageInfo)), this, SLOT(slotTogglePreviewMode(ImageInfo))); connect(d->tableView, SIGNAL(signalZoomOutStep()), this, SLOT(slotZoomOut())); connect(d->tableView, SIGNAL(signalZoomInStep()), this, SLOT(slotZoomIn())); connect(d->tableView, SIGNAL(signalShowContextMenu(QContextMenuEvent*,QList)), this, SLOT(slotShowContextMenu(QContextMenuEvent*,QList))); connect(d->tableView, SIGNAL(signalShowContextMenuOnInfo(QContextMenuEvent*,ImageInfo,QList,ImageFilterModel*)), this, SLOT(slotShowContextMenuOnInfo(QContextMenuEvent*,ImageInfo,QList,ImageFilterModel*))); // TableView::signalItemsChanged is emitted when something changes in the model that // DigikamView should care about, not only the selection. connect(d->tableView, SIGNAL(signalItemsChanged()), this, SLOT(slotImageSelected())); // -- Trash View Connections ---------------------------------- connect(d->trashView, SIGNAL(selectionChanged()), this, SLOT(slotImageSelected())); // -- Sidebar Connections ------------------------------------- connect(d->leftSideBar, SIGNAL(signalChangedTab(QWidget*)), this, SLOT(slotLeftSidebarChangedTab(QWidget*))); connect(d->rightSideBar, SIGNAL(signalFirstItem()), this, SLOT(slotFirstItem())); connect(d->rightSideBar, SIGNAL(signalNextItem()), this, SLOT(slotNextItem())); connect(d->rightSideBar, SIGNAL(signalPrevItem()), this, SLOT(slotPrevItem())); connect(d->rightSideBar, SIGNAL(signalLastItem()), this, SLOT(slotLastItem())); connect(this, SIGNAL(signalNoCurrentItem()), d->rightSideBar, SLOT(slotNoCurrentItem())); #ifdef HAVE_MARBLE connect(d->gpsSearchSideBar, SIGNAL(signalMapSoloItems(QList,QString)), d->iconView->imageFilterModel(), SLOT(setIdWhitelist(QList,QString))); #endif // HAVE_MARBLE // -- Filter Bars Connections --------------------------------- ImageAlbumFilterModel* const model = d->iconView->imageAlbumFilterModel(); connect(d->filterWidget, SIGNAL(signalTagFilterChanged(QList,QList,ImageFilterSettings::MatchingCondition,bool,QList,QList)), d->iconView->imageFilterModel(), SLOT(setTagFilter(QList,QList,ImageFilterSettings::MatchingCondition,bool,QList,QList))); connect(d->filterWidget, SIGNAL(signalRatingFilterChanged(int,ImageFilterSettings::RatingCondition,bool)), model, SLOT(setRatingFilter(int,ImageFilterSettings::RatingCondition,bool))); connect(d->filterWidget, SIGNAL(signalSearchTextFilterChanged(SearchTextFilterSettings)), model, SLOT(setTextFilter(SearchTextFilterSettings))); connect(model, SIGNAL(filterMatchesForText(bool)), d->filterWidget, SLOT(slotFilterMatchesForText(bool))); connect(d->filterWidget, SIGNAL(signalMimeTypeFilterChanged(int)), model, SLOT(setMimeTypeFilter(int))); connect(d->filterWidget, SIGNAL(signalGeolocationFilterChanged(ImageFilterSettings::GeolocationCondition)), model, SLOT(setGeolocationFilter(ImageFilterSettings::GeolocationCondition))); // -- Preview image widget Connections ------------------------ connect(d->stackedview, SIGNAL(signalNextItem()), this, SLOT(slotNextItem())); connect(d->stackedview, SIGNAL(signalPrevItem()), this, SLOT(slotPrevItem())); connect(d->stackedview, SIGNAL(signalDeleteItem()), this, SLOT(slotImageDelete())); connect(d->stackedview, SIGNAL(signalViewModeChanged()), this, SLOT(slotViewModeChanged())); connect(d->stackedview, SIGNAL(signalEscapePreview()), this, SLOT(slotEscapePreview())); connect(d->stackedview, SIGNAL(signalSlideShowCurrent()), this, SLOT(slotSlideShowManualFromCurrent())); connect(d->stackedview, SIGNAL(signalZoomFactorChanged(double)), this, SLOT(slotZoomFactorChanged(double))); connect(d->stackedview, SIGNAL(signalAddToExistingQueue(int)), this, SLOT(slotImageAddToExistingQueue(int))); connect(d->stackedview, SIGNAL(signalGotoAlbumAndItem(ImageInfo)), this, SLOT(slotGotoAlbumAndItem(ImageInfo))); connect(d->stackedview, SIGNAL(signalGotoDateAndItem(ImageInfo)), this, SLOT(slotGotoDateAndItem(ImageInfo))); connect(d->stackedview, SIGNAL(signalGotoTagAndItem(int)), this, SLOT(slotGotoTagAndItem(int))); connect(d->stackedview, SIGNAL(signalPopupTagsView()), d->rightSideBar, SLOT(slotPopupTagsView())); // -- FileActionMngr progress --------------- connect(FileActionMngr::instance(), SIGNAL(signalImageChangeFailed(QString,QStringList)), this, SLOT(slotImageChangeFailed(QString,QStringList))); // -- timers --------------- connect(d->selectionTimer, SIGNAL(timeout()), this, SLOT(slotDispatchImageSelected())); connect(d->thumbSizeTimer, SIGNAL(timeout()), this, SLOT(slotThumbSizeEffect()) ); // -- Album Settings ---------------- connect(ApplicationSettings::instance(), SIGNAL(setupChanged()), this, SLOT(slotSidebarTabTitleStyleChanged())); // -- Album History ----------------- connect(this, SIGNAL(signalAlbumSelected(Album*)), d->albumHistory, SLOT(slotAlbumSelected())); connect(this, SIGNAL(signalImageSelected(ImageInfoList,ImageInfoList)), d->albumHistory, SLOT(slotImageSelected(ImageInfoList))); connect(d->iconView, SIGNAL(currentChanged(ImageInfo)), d->albumHistory, SLOT(slotCurrentChange(ImageInfo))); connect(d->iconView->imageModel(), SIGNAL(imageInfosAdded(QList)), d->albumHistory, SLOT(slotAlbumCurrentChanged())); connect(d->albumHistory, SIGNAL(signalSetCurrent(qlonglong)), this, SLOT(slotSetCurrentWhenAvailable(qlonglong))); connect(d->albumHistory, SIGNAL(signalSetSelectedInfos(QList)), d->iconView, SLOT(setSelectedImageInfos(QList))); connect(d->albumManager, SIGNAL(signalAlbumDeleted(Album*)), d->albumHistory, SLOT(slotAlbumDeleted(Album*))); connect(d->albumManager, SIGNAL(signalAlbumsCleared()), d->albumHistory, SLOT(slotAlbumsCleared())); // -- Image versions ---------------- connect(d->rightSideBar->getFiltersHistoryTab(), SIGNAL(imageSelected(ImageInfo)), d->iconView, SLOT(hintAt(ImageInfo))); connect(d->rightSideBar->getFiltersHistoryTab(), SIGNAL(actionTriggered(ImageInfo)), this, SLOT(slotGotoAlbumAndItem(ImageInfo))); } void DigikamView::connectIconViewFilter(FilterStatusBar* const filterbar) { ImageAlbumFilterModel* const model = d->iconView->imageAlbumFilterModel(); connect(model, SIGNAL(filterMatches(bool)), filterbar, SLOT(slotFilterMatches(bool))); connect(model, SIGNAL(filterSettingsChanged(ImageFilterSettings)), filterbar, SLOT(slotFilterSettingsChanged(ImageFilterSettings))); connect(filterbar, SIGNAL(signalResetFilters()), d->filterWidget, SLOT(slotResetFilters())); connect(filterbar, SIGNAL(signalPopupFiltersView()), this, SLOT(slotPopupFiltersView())); } void DigikamView::slotPopupFiltersView() { d->rightSideBar->setActiveTab(d->filterWidget); d->filterWidget->setFocusToTextFilter(); } void DigikamView::loadViewState() { foreach(SidebarWidget* const widget, d->leftSideBarWidgets) { widget->loadState(); } d->filterWidget->loadState(); KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(QLatin1String("MainWindow")); // Restore the splitter d->splitter->restoreState(group); // Restore the thumbnail bar dock. QByteArray thumbbarState; thumbbarState = group.readEntry(QLatin1String("ThumbbarState"), thumbbarState); d->dockArea->restoreState(QByteArray::fromBase64(thumbbarState)); d->initialAlbumID = group.readEntry(QLatin1String("InitialAlbumID"), 0); #ifdef HAVE_MARBLE d->mapView->loadState(); #endif // HAVE_MARBLE d->tableView->loadState(); d->rightSideBar->loadState(); } void DigikamView::saveViewState() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(QLatin1String("MainWindow")); foreach(SidebarWidget* const widget, d->leftSideBarWidgets) { widget->saveState(); } d->filterWidget->saveState(); // Save the splitter states. d->splitter->saveState(group); // Save the position and size of the thumbnail bar. The thumbnail bar dock // needs to be closed explicitly, because when it is floating and visible // (when the user is in image preview mode) when the layout is saved, it // also reappears when restoring the view, while it should always be hidden. d->stackedview->thumbBarDock()->close(); group.writeEntry(QLatin1String("ThumbbarState"), d->dockArea->saveState().toBase64()); QList albumList = AlbumManager::instance()->currentAlbums(); Album* album = 0; if(!albumList.isEmpty()) { album = albumList.first(); } if (album) { group.writeEntry(QLatin1String("InitialAlbumID"), album->globalID()); } else { group.writeEntry(QLatin1String("InitialAlbumID"), 0); } #ifdef HAVE_MARBLE d->mapView->saveState(); #endif // HAVE_MARBLE d->tableView->saveState(); d->rightSideBar->saveState(); } QList DigikamView::leftSidebarWidgets() const { return d->leftSideBarWidgets; } QList DigikamView::allUrls(bool grouping) const { /// @todo This functions seems not to be used anywhere right now return allInfo(grouping).toImageUrlList(); } QList DigikamView::selectedUrls(bool grouping) const { return selectedInfoList(grouping).toImageUrlList(); } QList DigikamView::selectedUrls(const ApplicationSettings::OperationType type) const { return selectedInfoList(type).toImageUrlList(); } void DigikamView::showSideBars() { d->leftSideBar->restore(); d->rightSideBar->restore(); } void DigikamView::hideSideBars() { d->leftSideBar->backup(); d->rightSideBar->backup(); } void DigikamView::toggleLeftSidebar() { d->leftSideBar->isExpanded() ? d->leftSideBar->shrink() : d->leftSideBar->expand(); } void DigikamView::toggleRightSidebar() { d->rightSideBar->isExpanded() ? d->rightSideBar->shrink() : d->rightSideBar->expand(); } void DigikamView::previousLeftSideBarTab() { d->leftSideBar->activePreviousTab(); } void DigikamView::nextLeftSideBarTab() { d->leftSideBar->activeNextTab(); } void DigikamView::previousRightSideBarTab() { d->rightSideBar->activePreviousTab(); } void DigikamView::nextRightSideBarTab() { d->rightSideBar->activeNextTab(); } void DigikamView::slotFirstItem() { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->slotGoToRow(0, false); break; default: // all other views are tied to IconView's selection model d->iconView->toFirstIndex(); } } void DigikamView::slotPrevItem() { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->slotGoToRow(-1, true); break; default: // all other views are tied to IconView's selection model d->iconView->toPreviousIndex(); } } void DigikamView::slotNextItem() { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->slotGoToRow(1, true); break; default: // all other views are tied to IconView's selection model d->iconView->toNextIndex(); } } void DigikamView::slotLastItem() { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->slotGoToRow(-1, false); break; default: // all other views are tied to IconView's selection model d->iconView->toLastIndex(); } } void DigikamView::slotSelectItemByUrl(const QUrl& url) { /// @todo This functions seems not to be used anywhere right now /// @todo Adapt to TableView d->iconView->toIndex(url); } void DigikamView::slotAllAlbumsLoaded() { disconnect(d->albumManager, SIGNAL(signalAllAlbumsLoaded()), this, SLOT(slotAllAlbumsLoaded())); loadViewState(); d->leftSideBar->loadState(); d->rightSideBar->loadState(); d->rightSideBar->populateTags(); // now that all albums have been loaded, activate the albumHistory d->useAlbumHistory = true; Album* const album = d->albumManager->findAlbum(d->initialAlbumID); d->albumManager->setCurrentAlbums(QList() << album); } void DigikamView::slotSortAlbums(int role) { ApplicationSettings* const settings = ApplicationSettings::instance(); if (!settings) { return; } settings->setAlbumSortRole((ApplicationSettings::AlbumSortRole) role); settings->saveSettings(); //A dummy way to force the tree view to resort if the album sort role changed PAlbum* const albumBeforeSorting = d->albumFolderSideBar->currentAlbum(); settings->setAlbumSortChanged(true); d->albumFolderSideBar->doSaveState(); d->albumFolderSideBar->doLoadState(); d->albumFolderSideBar->doSaveState(); d->albumFolderSideBar->doLoadState(); settings->setAlbumSortChanged(false); if (d->leftSideBar->getActiveTab() == d->albumFolderSideBar) { d->albumFolderSideBar->setCurrentAlbum(albumBeforeSorting); } } void DigikamView::slotNewAlbum() { // TODO use the selection model of the view instead d->albumModificationHelper->slotAlbumNew(d->albumFolderSideBar->currentAlbum()); } void DigikamView::slotDeleteAlbum() { d->albumModificationHelper->slotAlbumDelete(d->albumFolderSideBar->currentAlbum()); } void DigikamView::slotRenameAlbum() { d->albumModificationHelper->slotAlbumRename(d->albumFolderSideBar->currentAlbum()); } void DigikamView::slotNewTag() { QList talbums = AlbumManager::instance()->currentTAlbums(); if (!talbums.isEmpty()) d->tagModificationHelper->slotTagNew(talbums.first()); } void DigikamView::slotDeleteTag() { QList talbums = AlbumManager::instance()->currentTAlbums(); if (!talbums.isEmpty()) d->tagModificationHelper->slotTagDelete(talbums.first()); } void DigikamView::slotEditTag() { QList talbums = AlbumManager::instance()->currentTAlbums(); if (!talbums.isEmpty()) d->tagModificationHelper->slotTagEdit(talbums.first()); } void DigikamView::slotOpenTagsManager() { TagsManager* const tagMngr = TagsManager::instance(); tagMngr->show(); tagMngr->activateWindow(); tagMngr->raise(); } void DigikamView::slotAssignTag() { d->rightSideBar->setActiveTab(d->rightSideBar->imageDescEditTab()); d->rightSideBar->imageDescEditTab()->setFocusToNewTagEdit(); } void DigikamView::slotNewKeywordSearch() { slotLeftSideBarActivate(d->searchSideBar); d->searchSideBar->newKeywordSearch(); } void DigikamView::slotNewAdvancedSearch() { slotLeftSideBarActivate(d->searchSideBar); d->searchSideBar->newAdvancedSearch(); } void DigikamView::slotNewDuplicatesSearch(PAlbum* album) { slotLeftSideBarActivate(d->fuzzySearchSideBar); d->fuzzySearchSideBar->newDuplicatesSearch(album); } -void DigikamView::slotNewDuplicatesSearch(QList albums) +void DigikamView::slotNewDuplicatesSearch(const QList& albums) { slotLeftSideBarActivate(d->fuzzySearchSideBar); d->fuzzySearchSideBar->newDuplicatesSearch(albums); } -void DigikamView::slotNewDuplicatesSearch(QList albums) +void DigikamView::slotNewDuplicatesSearch(const QList& albums) { slotLeftSideBarActivate(d->fuzzySearchSideBar); d->fuzzySearchSideBar->newDuplicatesSearch(albums); } void DigikamView::slotAlbumsCleared() { emit signalAlbumSelected(0); } void DigikamView::slotAlbumHistoryBack(int steps) { QList albums; QWidget* widget = 0; d->albumHistory->back(albums, &widget, steps); changeAlbumFromHistory(albums, widget); } void DigikamView::slotAlbumHistoryForward(int steps) { QList albums; QWidget* widget = 0; d->albumHistory->forward(albums, &widget, steps); changeAlbumFromHistory(albums , widget); } // TODO update, use SideBarWidget instead of QWidget void DigikamView::changeAlbumFromHistory(QList album, QWidget* const widget) { if (!(album.isEmpty()) && widget) { // TODO update, temporary casting until signature is changed SidebarWidget* const sideBarWidget = dynamic_cast(widget); if (sideBarWidget) { sideBarWidget->changeAlbumFromHistory(album); slotLeftSideBarActivate(sideBarWidget); if (sideBarWidget == d->labelsSideBar) { d->labelsSearchHandler->restoreSelectionFromHistory(d->albumHistory->neededLabels()); } } d->parent->enableAlbumBackwardHistory(d->useAlbumHistory && !d->albumHistory->isBackwardEmpty()); d->parent->enableAlbumForwardHistory(d->useAlbumHistory && !d->albumHistory->isForwardEmpty()); } } void DigikamView::clearHistory() { d->albumHistory->clearHistory(); d->parent->enableAlbumBackwardHistory(false); d->parent->enableAlbumForwardHistory(false); } void DigikamView::getBackwardHistory(QStringList& titles) { d->albumHistory->getBackwardHistory(titles); - for (int i = 0; i < titles.size(); ++i) + for (int i = 0 ; i < titles.size() ; ++i) { titles[i] = d->userPresentableAlbumTitle(titles.at(i)); } } void DigikamView::getForwardHistory(QStringList& titles) { d->albumHistory->getForwardHistory(titles); - for (int i = 0; i < titles.size(); ++i) + for (int i = 0 ; i < titles.size() ; ++i) { titles[i] = d->userPresentableAlbumTitle(titles.at(i)); } } void DigikamView::slotGotoAlbumAndItem(const ImageInfo& imageInfo) { qCDebug(DIGIKAM_GENERAL_LOG) << "going to " << imageInfo; emit signalNoCurrentItem(); PAlbum* const album = AlbumManager::instance()->findPAlbum(imageInfo.albumId()); d->albumFolderSideBar->setCurrentAlbum(album); slotLeftSideBarActivate(d->albumFolderSideBar); // Set the activate item url to find in the Album View after // all items have be reloaded. slotSetCurrentWhenAvailable(imageInfo.id()); // And finally toggle album manager to handle album history and // reload all items. d->albumManager->setCurrentAlbums(QList() << album); } void DigikamView::slotGotoDateAndItem(const ImageInfo& imageInfo) { QDate date = imageInfo.dateTime().date(); emit signalNoCurrentItem(); // Change to Date Album view. // Note, that this also opens the side bar if it is closed; this is // considered as a feature, because it highlights that the view was changed. slotLeftSideBarActivate(d->dateViewSideBar); // Set the activate item url to find in the Album View after // all items have be reloaded. slotSetCurrentWhenAvailable(imageInfo.id()); // Change the year and month of the iconItem (day is unused). d->dateViewSideBar->gotoDate(date); } void DigikamView::slotGotoTagAndItem(int tagID) { // FIXME: Arnd: don't know yet how to get the iconItem passed through ... // then we would know how to use the following ... // KURL url( iconItem->imageInfo()->kurl() ); // url.cleanPath(); emit signalNoCurrentItem(); // Change to Tag Folder view. // Note, that this also opens the side bar if it is closed; this is // considered as a feature, because it highlights that the view was changed. slotLeftSideBarActivate(d->tagViewSideBar); // Set the current tag in the tag folder view. // TODO this slot should use a TAlbum pointer directly TAlbum* const tag = AlbumManager::instance()->findTAlbum(tagID); if (tag) { d->tagViewSideBar->setCurrentAlbum(tag); } else { qCDebug(DIGIKAM_GENERAL_LOG) << "Could not find a tag album for tag id " << tagID; } // Set the activate item url to find in the Tag View after // all items have be reloaded. // FIXME: see above // d->iconView->setAlbumItemToFind(url); } void DigikamView::slotSelectAlbum(const QUrl& url) { PAlbum* const album = d->albumManager->findPAlbum(url); if (!album) { qCWarning(DIGIKAM_GENERAL_LOG) << "Unable to find album for " << url; return; } slotLeftSideBarActivate(d->albumFolderSideBar); d->albumFolderSideBar->setCurrentAlbum(album); } -void DigikamView::slotAlbumSelected(QList albums) +void DigikamView::slotAlbumSelected(const QList& albums) { emit signalNoCurrentItem(); emit signalAlbumSelected(0); if (albums.isEmpty() || !albums.first()) { d->iconView->openAlbum(QList()); #ifdef HAVE_MARBLE d->mapView->openAlbum(0); #endif // HAVE_MARBLE slotTogglePreviewMode(ImageInfo()); return; } Album* const album = albums.first(); emit signalAlbumSelected(album); if (d->useAlbumHistory && !d->labelsSearchHandler->isRestoringSelectionFromHistory()) { if (!(d->leftSideBar->getActiveTab() == d->labelsSideBar)) { d->albumHistory->addAlbums(albums, d->leftSideBar->getActiveTab()); } else { if (albums.first()->isUsedByLabelsTree()) { d->albumHistory->addAlbums(albums, d->leftSideBar->getActiveTab(), d->labelsSideBar->selectedLabels()); } } } d->parent->enableAlbumBackwardHistory(d->useAlbumHistory && !d->albumHistory->isBackwardEmpty()); d->parent->enableAlbumForwardHistory(d->useAlbumHistory && !d->albumHistory->isForwardEmpty()); d->iconView->openAlbum(albums); if (album->isRoot()) { d->stackedview->setViewMode(StackedView::WelcomePageMode); } else if (album->isTrashAlbum()) { PAlbum* const palbum = d->albumManager->findPAlbum(album->parent()->id()); if (palbum) { QUrl url = palbum->fileUrl(); url = url.adjusted(QUrl::StripTrailingSlash); d->trashView->model()->loadItemsForCollection(url.toLocalFile()); d->filterWidget->setEnabled(false); d->stackedview->setViewMode(StackedView::TrashViewMode); } } else { switch (viewMode()) { case StackedView::PreviewImageMode: case StackedView::MediaPlayerMode: case StackedView::WelcomePageMode: case StackedView::TrashViewMode: slotTogglePreviewMode(ImageInfo()); break; default: break; } d->filterWidget->setEnabled(true); } } void DigikamView::slotAlbumOpenInFileManager() { Album* const album = d->albumManager->currentAlbums().first(); if (!album || album->type() != Album::PHYSICAL) { return; } if (album->isRoot()) { QMessageBox::critical(this, qApp->applicationName(), i18n("Cannot open the root album. It is not a physical location.")); return; } PAlbum* const palbum = dynamic_cast(album); if (palbum) { QDesktopServices::openUrl(QUrl::fromLocalFile(palbum->folderPath())); } } void DigikamView::slotRefresh() { switch (viewMode()) { case StackedView::PreviewImageMode: d->stackedview->imagePreviewView()->reload(); break; #ifdef HAVE_MEDIAPLAYER case StackedView::MediaPlayerMode: d->stackedview->mediaPlayerView()->reload(); break; #endif //HAVE_MEDIAPLAYER default: Album* const album = currentAlbum(); if (!album) return; // force reloading of thumbnails LoadingCacheInterface::cleanThumbnailCache(); ThumbsGenerator* const tool = new ThumbsGenerator(true, album->id()); tool->start(); // if physical album, schedule a collection scan of current album's path if (album->type() == Album::PHYSICAL) { NewItemsFinder* const tool = new NewItemsFinder(NewItemsFinder::ScheduleCollectionScan, QStringList() << static_cast(album)->folderPath()); connect(tool, SIGNAL(signalComplete()), this, SLOT(slotAlbumRefreshComplete())); tool->start(); } break; } } void DigikamView::slotAlbumRefreshComplete() { // force reload. Should normally not be necessary, but we may have bugs qlonglong currentId = currentInfo().id(); d->iconView->imageAlbumModel()->refresh(); if (currentId != -1) { slotSetCurrentWhenAvailable(currentId); } } void DigikamView::slotImageSelected() { // delay to slotDispatchImageSelected d->needDispatchSelection = true; d->selectionTimer->start(); switch (viewMode()) { case StackedView::TableViewMode: emit signalSelectionChanged(d->tableView->numberOfSelectedItems()); break; default: emit signalSelectionChanged(d->iconView->numberOfSelectedIndexes()); } } void DigikamView::slotDispatchImageSelected() { if (viewMode() == StackedView::TrashViewMode) { d->rightSideBar->itemChanged(d->trashView->lastSelectedItemUrl()); return; } if (d->needDispatchSelection) { // the list of ImageInfos of currently selected items, currentItem first const ImageInfoList list = selectedInfoList(true, true); const ImageInfoList allImages = allInfo(true); if (list.isEmpty()) { d->stackedview->setPreviewItem(); emit signalImageSelected(list, allImages); emit signalNoCurrentItem(); } else { d->rightSideBar->itemChanged(list); ImageInfo previousInfo; ImageInfo nextInfo; if (viewMode() == StackedView::TableViewMode) { previousInfo = d->tableView->previousInfo(); nextInfo = d->tableView->nextInfo(); } else { previousInfo = d->iconView->previousInfo(list.first()); nextInfo = d->iconView->nextInfo(list.first()); } if ((viewMode() != StackedView::IconViewMode) && (viewMode() != StackedView::MapWidgetMode) && (viewMode() != StackedView::TableViewMode) ) { d->stackedview->setPreviewItem(list.first(), previousInfo, nextInfo); } emit signalImageSelected(list, allImages); } d->needDispatchSelection = false; } } double DigikamView::zoomMin() const { return d->stackedview->zoomMin(); } double DigikamView::zoomMax() const { return d->stackedview->zoomMax(); } void DigikamView::setZoomFactor(double zoom) { d->stackedview->setZoomFactorSnapped(zoom); } void DigikamView::slotZoomFactorChanged(double zoom) { toggleZoomActions(); emit signalZoomChanged(zoom); } void DigikamView::setThumbSize(int size) { if (viewMode() == StackedView::PreviewImageMode) { double z = DZoomBar::zoomFromSize(size, zoomMin(), zoomMax()); setZoomFactor(z); } else if ( (viewMode() == StackedView::IconViewMode) || (viewMode() == StackedView::TableViewMode) || (viewMode() == StackedView::TrashViewMode)) { if (size > ThumbnailSize::maxThumbsSize()) { d->thumbSize = ThumbnailSize::maxThumbsSize(); } else if (size < ThumbnailSize::Small) { d->thumbSize = ThumbnailSize::Small; } else { d->thumbSize = size; } emit signalThumbSizeChanged(d->thumbSize); d->thumbSizeTimer->start(); } } void DigikamView::slotThumbSizeEffect() { d->iconView->setThumbnailSize(ThumbnailSize(d->thumbSize)); d->tableView->setThumbnailSize(ThumbnailSize(d->thumbSize)); d->trashView->setThumbnailSize(ThumbnailSize(d->thumbSize)); toggleZoomActions(); ApplicationSettings::instance()->setDefaultIconSize(d->thumbSize); } void DigikamView::toggleZoomActions() { if (viewMode() == StackedView::PreviewImageMode) { d->parent->enableZoomMinusAction(true); d->parent->enableZoomPlusAction(true); if (d->stackedview->maxZoom()) { d->parent->enableZoomPlusAction(false); } if (d->stackedview->minZoom()) { d->parent->enableZoomMinusAction(false); } } else if ((viewMode() == StackedView::IconViewMode) || (viewMode() == StackedView::TableViewMode)) { d->parent->enableZoomMinusAction(true); d->parent->enableZoomPlusAction(true); if (d->thumbSize >= ThumbnailSize::maxThumbsSize()) { d->parent->enableZoomPlusAction(false); } if (d->thumbSize <= ThumbnailSize::Small) { d->parent->enableZoomMinusAction(false); } } else { d->parent->enableZoomMinusAction(false); d->parent->enableZoomPlusAction(false); } } void DigikamView::slotZoomIn() { if ( (viewMode() == StackedView::IconViewMode) || (viewMode() == StackedView::TableViewMode) ) { setThumbSize(d->thumbSize + ThumbnailSize::Step); toggleZoomActions(); emit signalThumbSizeChanged(d->thumbSize); } else if (viewMode() == StackedView::PreviewImageMode) { d->stackedview->increaseZoom(); } } void DigikamView::slotZoomOut() { if ( (viewMode() == StackedView::IconViewMode) || (viewMode() == StackedView::TableViewMode) ) { setThumbSize(d->thumbSize - ThumbnailSize::Step); toggleZoomActions(); emit signalThumbSizeChanged(d->thumbSize); } else if (viewMode() == StackedView::PreviewImageMode) { d->stackedview->decreaseZoom(); } } void DigikamView::slotZoomTo100Percents() { if (viewMode() == StackedView::PreviewImageMode) { d->stackedview->toggleFitToWindowOr100(); } } void DigikamView::slotFitToWindow() { if (viewMode() == StackedView::TableViewMode) { /// @todo We should choose an appropriate thumbnail size here } else if (viewMode() == StackedView::IconViewMode) { int nts = d->iconView->fitToWidthIcons(); qCDebug(DIGIKAM_GENERAL_LOG) << "new thumb size = " << nts; setThumbSize(nts); toggleZoomActions(); emit signalThumbSizeChanged(d->thumbSize); } else if (viewMode() == StackedView::PreviewImageMode) { d->stackedview->fitToWindow(); } } void DigikamView::slotAlbumPropsEdit() { d->albumModificationHelper->slotAlbumEdit(d->albumManager->currentPAlbum()); } void DigikamView::slotAlbumWriteMetadata() { Album* const album = d->albumManager->currentAlbums().first(); if (!album) { return; } MetadataSynchronizer* const tool = new MetadataSynchronizer(AlbumList() << album, MetadataSynchronizer::WriteFromDatabaseToFile); tool->start(); } void DigikamView::slotAlbumReadMetadata() { Album* const album = d->albumManager->currentAlbums().first(); if (!album) { return; } MetadataSynchronizer* const tool = new MetadataSynchronizer(AlbumList() << album, MetadataSynchronizer::ReadFromFileToDatabase); tool->start(); } void DigikamView::slotImageWriteMetadata() { const ImageInfoList selected = selectedInfoList(ApplicationSettings::Metadata); MetadataSynchronizer* const tool = new MetadataSynchronizer(selected, MetadataSynchronizer::WriteFromDatabaseToFile); tool->start(); } void DigikamView::slotImageReadMetadata() { const ImageInfoList selected = selectedInfoList(ApplicationSettings::Metadata); MetadataSynchronizer* const tool = new MetadataSynchronizer(selected, MetadataSynchronizer::ReadFromFileToDatabase); tool->start(); } // ---------------------------------------------------------------- void DigikamView::slotEscapePreview() { if (viewMode() == StackedView::IconViewMode || viewMode() == StackedView::MapWidgetMode || viewMode() == StackedView::TableViewMode || viewMode() == StackedView::WelcomePageMode) { return; } // pass a null image info, because we want to fall back to the old // view mode slotTogglePreviewMode(ImageInfo()); } void DigikamView::slotMapWidgetView() { d->stackedview->setViewMode(StackedView::MapWidgetMode); } void DigikamView::slotTableView() { d->stackedview->setViewMode(StackedView::TableViewMode); } void DigikamView::slotIconView() { if (viewMode() == StackedView::PreviewImageMode) { emit signalThumbSizeChanged(d->thumbSize); } // and switch to icon view d->stackedview->setViewMode(StackedView::IconViewMode); // make sure the next/previous buttons are updated slotImageSelected(); } void DigikamView::slotImagePreview() { slotTogglePreviewMode(currentInfo()); } /** * @brief This method toggles between AlbumView/MapWidgetView and ImagePreview modes, depending on the context. */ void DigikamView::slotTogglePreviewMode(const ImageInfo& info) { if ( (viewMode() == StackedView::IconViewMode || viewMode() == StackedView::TableViewMode || viewMode() == StackedView::MapWidgetMode) && !info.isNull() ) { if (info.isLocationAvailable()) { d->lastViewMode = viewMode(); if (viewMode() == StackedView::IconViewMode) { d->stackedview->setPreviewItem(info, d->iconView->previousInfo(info), d->iconView->nextInfo(info)); } else { d->stackedview->setPreviewItem(info, ImageInfo(), ImageInfo()); } } else { QModelIndex index = d->iconView->indexForInfo(info); d->iconView->showIndexNotification(index, i18nc("@info", "The storage location of this image
is currently not available
")); } } else { // go back to either AlbumViewMode or MapWidgetMode d->stackedview->setViewMode( d->lastViewMode ); } // make sure the next/previous buttons are updated slotImageSelected(); } void DigikamView::slotViewModeChanged() { toggleZoomActions(); switch (viewMode()) { case StackedView::IconViewMode: emit signalSwitchedToIconView(); emit signalThumbSizeChanged(d->thumbSize); break; case StackedView::PreviewImageMode: emit signalSwitchedToPreview(); slotZoomFactorChanged(d->stackedview->zoomFactor()); break; case StackedView::WelcomePageMode: emit signalSwitchedToIconView(); break; case StackedView::MediaPlayerMode: emit signalSwitchedToPreview(); break; case StackedView::MapWidgetMode: emit signalSwitchedToMapView(); //TODO: connect map view's zoom buttons to main status bar zoom buttons break; case StackedView::TableViewMode: emit signalSwitchedToTableView(); emit signalThumbSizeChanged(d->thumbSize); break; case StackedView::TrashViewMode: emit signalSwitchedToTrashView(); break; } } void DigikamView::slotImageFindSimilar() { const ImageInfo current = currentInfo(); if (!current.isNull()) { d->fuzzySearchSideBar->newSimilarSearch(current); slotLeftSideBarActivate(d->fuzzySearchSideBar); } } void DigikamView::slotImageScanForFaces() { FaceScanSettings settings; settings.accuracy = ApplicationSettings::instance()->getFaceDetectionAccuracy(); settings.recognizeAlgorithm = RecognitionDatabase::RecognizeAlgorithm::LBP; settings.task = FaceScanSettings::DetectAndRecognize; settings.alreadyScannedHandling = FaceScanSettings::Rescan; settings.infos = selectedInfoList(ApplicationSettings::Tools); FacesDetector* const tool = new FacesDetector(settings); connect(tool, SIGNAL(signalComplete()), this, SLOT(slotRefreshImagePreview())); tool->start(); } void DigikamView::slotRefreshImagePreview() { if (viewMode() == StackedView::PreviewImageMode) { d->stackedview->imagePreviewView()->reload(); } } void DigikamView::slotEditor() { const ImageInfoList imageInfoList = selectedInfoList(ApplicationSettings::Tools); ImageInfo singleInfo = currentInfo(); if (singleInfo.isNull() && !imageInfoList.isEmpty()) { singleInfo = imageInfoList.first(); } Album* const current = currentAlbum(); d->utilities->openInfos(singleInfo, imageInfoList, current); } void DigikamView::slotFileWithDefaultApplication() { d->utilities->openInfosWithDefaultApplication(selectedInfoList(ApplicationSettings::Tools)); } void DigikamView::slotLightTable() { bool grouping = selectedNeedGroupResolving(ApplicationSettings::LightTable); const ImageInfoList selectedList = selectedInfoList(false, grouping); if (selectedList.isEmpty()) { grouping = allNeedGroupResolving(ApplicationSettings::LightTable); } const ImageInfoList allInfoList = allInfo(grouping); const ImageInfo currentImageInfo = currentInfo(); d->utilities->insertToLightTableAuto(allInfoList, selectedList, currentImageInfo); } void DigikamView::slotQueueMgr() { bool grouping = selectedNeedGroupResolving(ApplicationSettings::BQM); ImageInfoList imageInfoList = selectedInfoList(false, grouping); ImageInfo singleInfo = currentInfo(); if (singleInfo.isNull() && !imageInfoList.isEmpty()) { singleInfo = imageInfoList.first(); } if (singleInfo.isNull()) { grouping = allNeedGroupResolving(ApplicationSettings::BQM); const ImageInfoList allItems = allInfo(grouping); if (!allItems.isEmpty()) { singleInfo = allItems.first(); } } d->utilities->insertToQueueManager(imageInfoList, singleInfo, true); } void DigikamView::slotImageEdit() { // Where is the difference to slotEditor? slotEditor(); } void DigikamView::slotImageLightTable() { const ImageInfoList selectedList = selectedInfoList(ApplicationSettings::LightTable); const ImageInfo currentImageInfo = currentInfo(); // replace images in light table d->utilities->insertToLightTable(selectedList, currentImageInfo, false); } void DigikamView::slotImageAddToLightTable() { const ImageInfoList selectedList = selectedInfoList(ApplicationSettings::LightTable); const ImageInfo currentImageInfo = currentInfo(); // add to images in light table d->utilities->insertToLightTable(selectedList, currentImageInfo, true); } void DigikamView::slotImageAddToCurrentQueue() { const ImageInfoList selectedList = selectedInfoList(ApplicationSettings::BQM); const ImageInfo currentImageInfo = currentInfo(); d->utilities->insertToQueueManager(selectedList, currentImageInfo, false); } void DigikamView::slotImageAddToNewQueue() { const bool newQueue = QueueMgrWindow::queueManagerWindowCreated() && !QueueMgrWindow::queueManagerWindow()->queuesMap().isEmpty(); const ImageInfoList selectedList = selectedInfoList(ApplicationSettings::BQM); const ImageInfo currentImageInfo = currentInfo(); d->utilities->insertToQueueManager(selectedList, currentImageInfo, newQueue); } void DigikamView::slotImageAddToExistingQueue(int queueid) { const ImageInfoList selectedList = selectedInfoList(ApplicationSettings::BQM); const ImageInfo currentImageInfo = currentInfo(); if (!selectedList.isEmpty()) { d->utilities->insertSilentToQueueManager(selectedList, currentImageInfo, queueid); } } void DigikamView::slotImageRename() { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->rename(); break; default: d->iconView->rename(); } } void DigikamView::slotImageDelete() { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->slotDeleteSelected(ImageViewUtilities::DeleteUseTrash); break; default: d->iconView->deleteSelected(ImageViewUtilities::DeleteUseTrash); } } void DigikamView::slotImageDeletePermanently() { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->slotDeleteSelected(ImageViewUtilities::DeletePermanently); break; default: d->iconView->deleteSelected(ImageViewUtilities::DeletePermanently); } } void DigikamView::slotImageDeletePermanentlyDirectly() { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->slotDeleteSelectedWithoutConfirmation(ImageViewUtilities::DeletePermanently); break; default: d->iconView->deleteSelectedDirectly(ImageViewUtilities::DeletePermanently); } } void DigikamView::slotImageTrashDirectly() { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->slotDeleteSelectedWithoutConfirmation(ImageViewUtilities::DeleteUseTrash); break; default: d->iconView->deleteSelectedDirectly(ImageViewUtilities::DeleteUseTrash); } } void DigikamView::slotSelectAll() { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->selectAll(); break; default: d->iconView->selectAll(); } } void DigikamView::slotSelectNone() { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->clearSelection(); break; default: d->iconView->clearSelection(); } } void DigikamView::slotSelectInvert() { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->invertSelection(); break; default: d->iconView->invertSelection(); } } void DigikamView::slotSortImages(int sortRole) { ApplicationSettings* const settings = ApplicationSettings::instance(); if (!settings) { return; } settings->setImageSortOrder(sortRole); d->iconView->imageFilterModel()->setSortRole((ImageSortSettings::SortRole) sortRole); settings->emitSetupChanged(); } void DigikamView::slotSortImagesOrder(int order) { ApplicationSettings* const settings = ApplicationSettings::instance(); if (!settings) { return; } settings->setImageSorting(order); d->iconView->imageFilterModel()->setSortOrder((ImageSortSettings::SortOrder) order); settings->emitSetupChanged(); } void DigikamView::slotSeparateImages(int categoryMode) { ApplicationSettings* const settings = ApplicationSettings::instance(); if (!settings) { return; } settings->setImageSeparationMode(categoryMode); d->iconView->imageFilterModel()->setCategorizationMode((ImageSortSettings::CategorizationMode) categoryMode); } void DigikamView::slotImageSeparationSortOrder(int order) { ApplicationSettings* const settings = ApplicationSettings::instance(); if (!settings) { return; } settings->setImageSeparationSortOrder(order); d->iconView->imageFilterModel()->setCategorizationSortOrder((ImageSortSettings::SortOrder) order); } void DigikamView::slotMoveSelectionToAlbum() { d->utilities->createNewAlbumForInfos(selectedInfoList(false, true), currentAlbum()); } void DigikamView::slotImagePaste() { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->slotPaste(); break; default: d->iconView->paste(); } } void DigikamView::slotLeftSidebarChangedTab(QWidget* w) { // TODO update, temporary cast SidebarWidget* const widget = dynamic_cast(w); foreach(SidebarWidget* const sideBarWidget, d->leftSideBarWidgets) { bool active = (widget && (widget == sideBarWidget)); sideBarWidget->setActive(active); } } void DigikamView::toggleTag(int tagID) { ImageInfoList tagToRemove, tagToAssign; const ImageInfoList selectedList = selectedInfoList(ApplicationSettings::Metadata); foreach(const ImageInfo& info, selectedList) { if (info.tagIds().contains(tagID)) tagToRemove.append(info); else tagToAssign.append(info); } FileActionMngr::instance()->assignTag(tagToAssign, tagID); FileActionMngr::instance()->removeTag(tagToRemove, tagID); } void DigikamView::slotAssignPickLabel(int pickId) { FileActionMngr::instance()->assignPickLabel(selectedInfoList(ApplicationSettings::Metadata), pickId); } void DigikamView::slotAssignColorLabel(int colorId) { FileActionMngr::instance()->assignColorLabel(selectedInfoList(ApplicationSettings::Metadata), colorId); } void DigikamView::slotAssignRating(int rating) { FileActionMngr::instance()->assignRating(selectedInfoList(ApplicationSettings::Metadata), rating); } void DigikamView::slotAssignTag(int tagID) { FileActionMngr::instance()->assignTags(selectedInfoList(ApplicationSettings::Metadata), QList() << tagID); } void DigikamView::slotRemoveTag(int tagID) { FileActionMngr::instance()->removeTags(selectedInfoList(ApplicationSettings::Metadata), QList() << tagID); } void DigikamView::slotSlideShowAll() { slideShow(allInfo(ApplicationSettings::Slideshow)); } void DigikamView::slotSlideShowSelection() { slideShow(selectedInfoList(ApplicationSettings::Slideshow)); } void DigikamView::slotSlideShowRecursive() { QList albumList = AlbumManager::instance()->currentAlbums(); Album* album = 0; if (!albumList.isEmpty()) { album = albumList.first(); } if (album) { SlideShowBuilder* const builder = new SlideShowBuilder(album); connect(builder, SIGNAL(signalComplete(SlideShowSettings)), this, SLOT(slotSlideShowBuilderComplete(SlideShowSettings))); builder->run(); } } void DigikamView::slotSlideShowManualFromCurrent() { slotSlideShowManualFrom(currentInfo()); } void DigikamView::slotSlideShowManualFrom(const ImageInfo& info) { SlideShowBuilder* const builder = new SlideShowBuilder(allInfo(ApplicationSettings::Slideshow)); builder->setOverrideStartFrom(info); builder->setAutoPlayEnabled(false); connect(builder, SIGNAL(signalComplete(SlideShowSettings)), this, SLOT(slotSlideShowBuilderComplete(SlideShowSettings))); builder->run(); } void DigikamView::presentation() { PresentationMngr* const mngr = new PresentationMngr(this); foreach(const ImageInfo& info, selectedInfoList(ApplicationSettings::Slideshow)) { mngr->addFile(info.fileUrl(), info.comment()); qApp->processEvents(); } mngr->showConfigDialog(); } void DigikamView::slideShow(const ImageInfoList& infoList) { SlideShowBuilder* const builder = new SlideShowBuilder(infoList); connect(builder, SIGNAL(signalComplete(SlideShowSettings)), this, SLOT(slotSlideShowBuilderComplete(SlideShowSettings))); builder->run(); } void DigikamView::slotSlideShowBuilderComplete(const SlideShowSettings& settings) { SlideShow* const slide = new SlideShow(settings); TagsActionMngr::defaultManager()->registerActionsToWidget(slide); if (settings.imageUrl.isValid()) { slide->setCurrentItem(settings.imageUrl); } else if (settings.startWithCurrent) { slide->setCurrentItem(currentInfo().fileUrl()); } connect(slide, SIGNAL(signalRatingChanged(QUrl,int)), this, SLOT(slotRatingChanged(QUrl,int))); connect(slide, SIGNAL(signalColorLabelChanged(QUrl,int)), this, SLOT(slotColorLabelChanged(QUrl,int))); connect(slide, SIGNAL(signalPickLabelChanged(QUrl,int)), this, SLOT(slotPickLabelChanged(QUrl,int))); connect(slide, SIGNAL(signalToggleTag(QUrl,int)), this, SLOT(slotToggleTag(QUrl,int))); connect(slide, SIGNAL(signalLastItemUrl(QUrl)), d->iconView, SLOT(setCurrentUrl(QUrl))); slide->show(); } void DigikamView::toggleShowBar(bool b) { d->stackedview->thumbBarDock()->showThumbBar(b); // See bug #319876 : force to reload current view mode to set thumbbar visibility properly. d->stackedview->setViewMode(viewMode()); } void DigikamView::setRecurseAlbums(bool recursive) { d->iconView->imageAlbumModel()->setRecurseAlbums(recursive); } void DigikamView::setRecurseTags(bool recursive) { d->iconView->imageAlbumModel()->setRecurseTags(recursive); } void DigikamView::slotSidebarTabTitleStyleChanged() { d->leftSideBar->setStyle(ApplicationSettings::instance()->getSidebarTitleStyle()); d->rightSideBar->setStyle(ApplicationSettings::instance()->getSidebarTitleStyle()); /// @todo Which settings actually have to be reloaded? // d->rightSideBar->applySettings(); } void DigikamView::slotImageChangeFailed(const QString& message, const QStringList& fileNames) { if (fileNames.isEmpty()) { return; } DMessageBox::showInformationList(QMessageBox::Critical, qApp->activeWindow(), qApp->applicationName(), message, fileNames); } void DigikamView::slotLeftSideBarActivateAlbums() { d->leftSideBar->setActiveTab(d->albumFolderSideBar); } void DigikamView::slotLeftSideBarActivateTags() { d->leftSideBar->setActiveTab(d->tagViewSideBar); } void DigikamView::slotLeftSideBarActivate(SidebarWidget* widget) { d->leftSideBar->setActiveTab(widget); } void DigikamView::slotLeftSideBarActivate(QWidget* widget) { slotLeftSideBarActivate(static_cast(widget)); } void DigikamView::slotRightSideBarActivateTitles() { d->rightSideBar->setActiveTab(d->rightSideBar->imageDescEditTab()); d->rightSideBar->imageDescEditTab()->setFocusToTitlesEdit(); } void DigikamView::slotRightSideBarActivateComments() { d->rightSideBar->setActiveTab(d->rightSideBar->imageDescEditTab()); d->rightSideBar->imageDescEditTab()->setFocusToCommentsEdit(); } void DigikamView::slotRightSideBarActivateAssignedTags() { d->rightSideBar->setActiveTab(d->rightSideBar->imageDescEditTab()); d->rightSideBar->imageDescEditTab()->activateAssignedTagsButton(); } void DigikamView::slotRatingChanged(const QUrl& url, int rating) { rating = qMin(RatingMax, qMax(RatingMin, rating)); ImageInfo info = ImageInfo::fromUrl(url); if (!info.isNull()) { FileActionMngr::instance()->assignRating(info, rating); } } void DigikamView::slotColorLabelChanged(const QUrl& url, int color) { ImageInfo info = ImageInfo::fromUrl(url); if (!info.isNull()) { FileActionMngr::instance()->assignColorLabel(info, color); } } void DigikamView::slotPickLabelChanged(const QUrl& url, int pick) { ImageInfo info = ImageInfo::fromUrl(url); if (!info.isNull()) { FileActionMngr::instance()->assignPickLabel(info, pick); } } void DigikamView::slotToggleTag(const QUrl& url, int tagID) { ImageInfo info = ImageInfo::fromUrl(url); if (!info.isNull()) { if (info.tagIds().contains(tagID)) FileActionMngr::instance()->removeTag(info, tagID); else FileActionMngr::instance()->assignTag(info, tagID); } } bool DigikamView::hasCurrentItem() const { return !currentInfo().isNull(); } void DigikamView::slotFocusAndNextImage() { //slot is called on pressing "return" a second time after assigning a tag d->stackedview->currentWidget()->setFocus(); //select next image, since the user is probably done tagging the current image slotNextItem(); } void DigikamView::slotImageExifOrientation(int orientation) { FileActionMngr::instance()->setExifOrientation( selectedInfoList(ApplicationSettings::Metadata), orientation); } void DigikamView::imageTransform(MetaEngineRotation::TransformationAction transform) { FileActionMngr::instance()->transform( selectedInfoList(ApplicationSettings::Metadata), transform); } ImageInfo DigikamView::currentInfo() const { switch (viewMode()) { case StackedView::TableViewMode: return d->tableView->currentInfo(); #ifdef HAVE_MARBLE case StackedView::MapWidgetMode: return d->mapView->currentImageInfo(); #endif // HAVE_MARBLE case StackedView::MediaPlayerMode: case StackedView::PreviewImageMode: case StackedView::IconViewMode: // all of these modes use the same selection model and data as the IconViewMode return d->iconView->currentInfo(); default: return ImageInfo(); } } Album* DigikamView::currentAlbum() const { switch (viewMode()) { case StackedView::TableViewMode: return d->tableView->currentAlbum(); case StackedView::PreviewImageMode: case StackedView::MediaPlayerMode: case StackedView::MapWidgetMode: case StackedView::IconViewMode: // all of these modes use the same selection model and data as the IconViewMode return d->iconView->currentAlbum(); default: return 0; } } ImageInfoList DigikamView::selectedInfoList(const bool currentFirst, const bool grouping) const { switch (viewMode()) { case StackedView::TableViewMode: if (currentFirst) { return d->tableView->selectedImageInfosCurrentFirst(grouping); } return d->tableView->selectedImageInfos(grouping); case StackedView::PreviewImageMode: case StackedView::MediaPlayerMode: case StackedView::MapWidgetMode: case StackedView::IconViewMode: // all of these modes use the same selection model and data as the IconViewMode if (currentFirst) { return d->iconView->selectedImageInfosCurrentFirst(grouping); } return d->iconView->selectedImageInfos(grouping); default: return QList(); } } ImageInfoList DigikamView::selectedInfoList(const ApplicationSettings::OperationType type, const bool currentFirst) const { return selectedInfoList(currentFirst, selectedNeedGroupResolving(type)); } ImageInfoList DigikamView::allInfo(const bool grouping) const { switch (viewMode()) { case StackedView::TableViewMode: return d->tableView->allImageInfos(grouping); case StackedView::MapWidgetMode: case StackedView::PreviewImageMode: case StackedView::MediaPlayerMode: case StackedView::IconViewMode: // all of these modes use the same selection model and data as the IconViewMode return d->iconView->allImageInfos(grouping); default: return QList(); } } ImageInfoList DigikamView::allInfo(const ApplicationSettings::OperationType type) const { return allInfo(allNeedGroupResolving(type)); } bool DigikamView::allNeedGroupResolving(const ApplicationSettings::OperationType type) const { switch (viewMode()) { case StackedView::TableViewMode: return d->tableView->allNeedGroupResolving(type); case StackedView::MapWidgetMode: case StackedView::PreviewImageMode: case StackedView::MediaPlayerMode: case StackedView::IconViewMode: // all of these modes use the same selection model and data as the IconViewMode return d->iconView->allNeedGroupResolving(type); default: return false; } } bool DigikamView::selectedNeedGroupResolving(const ApplicationSettings::OperationType type) const { switch (viewMode()) { case StackedView::TableViewMode: return d->tableView->selectedNeedGroupResolving(type); case StackedView::MapWidgetMode: case StackedView::PreviewImageMode: case StackedView::MediaPlayerMode: case StackedView::IconViewMode: // all of these modes use the same selection model and data as the IconViewMode return d->iconView->selectedNeedGroupResolving(type); default: return false; } } QUrl DigikamView::currentUrl() const { const ImageInfo cInfo = currentInfo(); return cInfo.fileUrl(); } void DigikamView::slotSetCurrentWhenAvailable(const qlonglong id) { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->slotSetCurrentWhenAvailable(id); break; default: d->iconView->setCurrentWhenAvailable(id); } } void DigikamView::slotAwayFromSelection() { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->slotAwayFromSelection(); break; default: d->iconView->awayFromSelection(); } } StackedView::StackedViewMode DigikamView::viewMode() const { return d->stackedview->viewMode(); } void DigikamView::slotSetupMetadataFilters(int tab) { Setup::execMetadataFilters(this, tab); } void DigikamView::toggleFullScreen(bool set) { d->stackedview->imagePreviewView()->toggleFullScreen(set); } void DigikamView::setToolsIconView(DCategorizedView* const view) { d->rightSideBar->appendTab(view, QIcon::fromTheme(QLatin1String("document-edit")), i18n("Tools")); } void DigikamView::slotShowContextMenu(QContextMenuEvent* event, const QList& extraGroupingActions) { Album* const album = currentAlbum(); if (!album || album->isRoot() || (album->type() != Album::PHYSICAL && album->type() != Album::TAG) ) { return; } QMenu menu(this); ContextMenuHelper cmHelper(&menu); cmHelper.addAction(QLatin1String("full_screen")); cmHelper.addAction(QLatin1String("options_show_menubar")); cmHelper.addSeparator(); // -------------------------------------------------------- cmHelper.addStandardActionPaste(this, SLOT(slotImagePaste())); // -------------------------------------------------------- if (!extraGroupingActions.isEmpty()) { cmHelper.addSeparator(); cmHelper.addGroupMenu(QList(), extraGroupingActions); } cmHelper.exec(event->globalPos()); } void DigikamView::slotShowContextMenuOnInfo(QContextMenuEvent* event, const ImageInfo& info, const QList& extraGroupingActions, ImageFilterModel* imageFilterModel) { QList selectedImageIds = selectedInfoList(true, true).toImageIdList(); // -------------------------------------------------------- QMenu menu(this); ContextMenuHelper cmHelper(&menu); cmHelper.setImageFilterModel(imageFilterModel); cmHelper.addAction(QLatin1String("full_screen")); cmHelper.addAction(QLatin1String("options_show_menubar")); cmHelper.addSeparator(); // -------------------------------------------------------- QAction* const viewAction = new QAction(i18nc("View the selected image", "Preview"), this); viewAction->setIcon(QIcon::fromTheme(QLatin1String("view-preview"))); viewAction->setEnabled(selectedImageIds.count() == 1); cmHelper.addAction(viewAction); cmHelper.addOpenAndNavigateActions(selectedImageIds); cmHelper.addSeparator(); // -------------------------------------------------------- cmHelper.addAction(QLatin1String("image_scan_for_faces")); cmHelper.addAction(QLatin1String("image_find_similar")); cmHelper.addStandardActionLightTable(); cmHelper.addQueueManagerMenu(); cmHelper.addSeparator(); // -------------------------------------------------------- cmHelper.addAction(QLatin1String("image_rotate")); cmHelper.addAction(QLatin1String("cut_album_selection")); cmHelper.addAction(QLatin1String("copy_album_selection")); cmHelper.addAction(QLatin1String("paste_album_selection")); cmHelper.addAction(QLatin1String("image_rename")); cmHelper.addStandardActionItemDelete(this, SLOT(slotImageDelete()), selectedImageIds.count()); cmHelper.addSeparator(); // -------------------------------------------------------- cmHelper.addStandardActionThumbnail(selectedImageIds, currentAlbum()); cmHelper.addAssignTagsMenu(selectedImageIds); cmHelper.addRemoveTagsMenu(selectedImageIds); cmHelper.addLabelsAction(); if (d->leftSideBar->getActiveTab() != d->peopleSideBar) { cmHelper.addSeparator(); cmHelper.addGroupMenu(selectedImageIds, extraGroupingActions); } // special action handling -------------------------------- connect(&cmHelper, SIGNAL(signalAssignColorLabel(int)), this, SLOT(slotAssignColorLabel(int))); connect(&cmHelper, SIGNAL(signalAssignPickLabel(int)), this, SLOT(slotAssignPickLabel(int))); connect(&cmHelper, SIGNAL(signalAssignRating(int)), this, SLOT(slotAssignRating(int))); connect(&cmHelper, SIGNAL(signalAssignTag(int)), this, SLOT(slotAssignTag(int))); connect(&cmHelper, SIGNAL(signalRemoveTag(int)), this, SLOT(slotRemoveTag(int))); connect(&cmHelper, SIGNAL(signalPopupTagsView()), d->rightSideBar, SLOT(slotPopupTagsView())); connect(&cmHelper, SIGNAL(signalGotoTag(int)), this, SLOT(slotGotoTagAndItem(int))); connect(&cmHelper, SIGNAL(signalGotoTag(int)), d->albumHistory, SLOT(slotClearSelectTAlbum(int))); connect(&cmHelper, SIGNAL(signalGotoAlbum(ImageInfo)), this, SLOT(slotGotoAlbumAndItem(ImageInfo))); connect(&cmHelper, SIGNAL(signalGotoAlbum(ImageInfo)), d->albumHistory, SLOT(slotClearSelectPAlbum(ImageInfo))); connect(&cmHelper, SIGNAL(signalGotoDate(ImageInfo)), this, SLOT(slotGotoDateAndItem(ImageInfo))); connect(&cmHelper, SIGNAL(signalSetThumbnail(ImageInfo)), this, SLOT(slotSetAsAlbumThumbnail(ImageInfo))); connect(&cmHelper, SIGNAL(signalAddToExistingQueue(int)), this, SLOT(slotImageAddToExistingQueue(int))); connect(&cmHelper, SIGNAL(signalCreateGroup()), this, SLOT(slotCreateGroupFromSelection())); connect(&cmHelper, SIGNAL(signalCreateGroupByTime()), this, SLOT(slotCreateGroupByTimeFromSelection())); connect(&cmHelper, SIGNAL(signalCreateGroupByFilename()), this, SLOT(slotCreateGroupByFilenameFromSelection())); connect(&cmHelper, SIGNAL(signalRemoveFromGroup()), this, SLOT(slotRemoveSelectedFromGroup())); connect(&cmHelper, SIGNAL(signalUngroup()), this, SLOT(slotUngroupSelected())); // -------------------------------------------------------- QAction* const choice = cmHelper.exec(event->globalPos()); if (choice && (choice == viewAction)) { slotTogglePreviewMode(info); } } void DigikamView::slotShowGroupContextMenu(QContextMenuEvent* event, const QList& selectedInfos, ImageFilterModel* imageFilterModel) { QList selectedImageIDs; foreach(const ImageInfo& info, selectedInfos) { selectedImageIDs << info.id(); } QMenu popmenu(this); ContextMenuHelper cmhelper(&popmenu); cmhelper.setImageFilterModel(imageFilterModel); cmhelper.addGroupActions(selectedImageIDs); // special action handling -------------------------------- connect(&cmhelper, SIGNAL(signalCreateGroup()), this, SLOT(slotCreateGroupFromSelection())); connect(&cmhelper, SIGNAL(signalCreateGroupByTime()), this, SLOT(slotCreateGroupByTimeFromSelection())); connect(&cmhelper, SIGNAL(signalCreateGroupByFilename()), this, SLOT(slotCreateGroupByFilenameFromSelection())); connect(&cmhelper, SIGNAL(signalUngroup()), this, SLOT(slotUngroupSelected())); connect(&cmhelper, SIGNAL(signalRemoveFromGroup()), this, SLOT(slotRemoveSelectedFromGroup())); cmhelper.exec(event->globalPos()); } void DigikamView::slotSetAsAlbumThumbnail(const ImageInfo& info) { d->utilities->setAsAlbumThumbnail(currentAlbum(), info); } void DigikamView::slotCreateGroupFromSelection() { FileActionMngr::instance()->addToGroup(currentInfo(), selectedInfoList(false, true)); } void DigikamView::slotCreateGroupByTimeFromSelection() { d->utilities->createGroupByTimeFromInfoList(selectedInfoList(false, true)); } void DigikamView::slotCreateGroupByFilenameFromSelection() { d->utilities->createGroupByFilenameFromInfoList(selectedInfoList(false, true)); } void DigikamView::slotRemoveSelectedFromGroup() { FileActionMngr::instance()->removeFromGroup(selectedInfoList(false, true)); } void DigikamView::slotUngroupSelected() { FileActionMngr::instance()->ungroup(selectedInfoList(false, true)); } } // namespace Digikam diff --git a/core/app/views/digikamview.h b/core/app/views/digikamview.h index f5756451bf..efbcd8c627 100644 --- a/core/app/views/digikamview.h +++ b/core/app/views/digikamview.h @@ -1,343 +1,343 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2002-16-10 * Description : implementation of album view interface. * * Copyright (C) 2002-2005 by Renchi Raju * Copyright (C) 2002-2018 by Gilles Caulier * Copyright (C) 2009-2011 by Johannes Wienke * Copyright (C) 2010-2011 by Andi Clemens * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_VIEW_H #define DIGIKAM_VIEW_H // Qt includes #include #include // Local includes #include "applicationsettings.h" #include "metaengine_rotation.h" #include "digikam_config.h" #include "searchtextbar.h" #include "imageinfo.h" #include "digikammodelcollection.h" #include "sidebarwidget.h" #include "stackedview.h" #include "dlayoutbox.h" namespace Digikam { class AlbumIconItem; class Album; class PAlbum; class TAlbum; class BatchSyncMetadata; class FilterStatusBar; class SlideShowSettings; class DCategorizedView; class ImageFilterModel; class DigikamView : public DHBox { Q_OBJECT public: explicit DigikamView(QWidget* const parent, DigikamModelCollection* const modelCollection); ~DigikamView(); void applySettings(); void refreshView(); void clearHistory(); void getForwardHistory(QStringList& titles); void getBackwardHistory(QStringList& titles); void showSideBars(); void hideSideBars(); void toggleLeftSidebar(); void toggleRightSidebar(); void previousLeftSideBarTab(); void nextLeftSideBarTab(); void previousRightSideBarTab(); void nextRightSideBarTab(); void setToolsIconView(DCategorizedView* const view); void setThumbSize(int size); void toggleShowBar(bool); void setRecurseAlbums(bool recursive); void setRecurseTags(bool recursive); void imageTransform(MetaEngineRotation::TransformationAction transform); void connectIconViewFilter(FilterStatusBar* const filter); QUrl currentUrl() const; bool hasCurrentItem() const; ImageInfo currentInfo() const; Album* currentAlbum() const; /** * Get currently selected items. By default only the first images in groups are * given, while all can be obtained by setting the grouping parameter to true. * Given an operation, it will be determined from settings/user query whether * only the first or all items in a group are returned. * Ideally only the latter (giving an operation) is used. */ QList selectedUrls(bool grouping = false) const; QList selectedUrls(const ApplicationSettings::OperationType type) const; ImageInfoList selectedInfoList(const bool currentFirst = false, const bool grouping = false) const; ImageInfoList selectedInfoList(const ApplicationSettings::OperationType type, const bool currentFirst = false) const; /** * Get all items in the current view. * Whether only the first or all grouped items are returned is determined * as described above. */ QList allUrls(bool grouping = false) const; ImageInfoList allInfo(const bool grouping = false) const; ImageInfoList allInfo(const ApplicationSettings::OperationType type) const; /** * Query whether the operation to be performed on currently selected or all * all items in the currently active view should be performed on all * grouped items or just the first. */ bool allNeedGroupResolving(const ApplicationSettings::OperationType type) const; bool selectedNeedGroupResolving(const ApplicationSettings::OperationType type) const; double zoomMin() const; double zoomMax() const; void presentation(); void toggleTag(int tagID); void toggleFullScreen(bool set); QList leftSidebarWidgets() const; StackedView::StackedViewMode viewMode() const; Q_SIGNALS: void signalAlbumSelected(Album*); void signalImageSelected(const ImageInfoList& selectedImage, const ImageInfoList& allImages); void signalNoCurrentItem(); void signalSelectionChanged(int numberOfSelectedItems); void signalThumbSizeChanged(int); void signalZoomChanged(double); void signalSwitchedToPreview(); void signalSwitchedToIconView(); void signalSwitchedToMapView(); void signalSwitchedToTableView(); void signalSwitchedToTrashView(); void signalGotoAlbumAndItem(const ImageInfo&); void signalGotoDateAndItem(AlbumIconItem*); void signalGotoTagAndItem(int tagID); void signalChangedTab(QWidget*); void signalFuzzySidebarActive(bool active); public Q_SLOTS: void setZoomFactor(double zoom); // View Action slots void slotZoomIn(); void slotZoomOut(); void slotZoomTo100Percents(); void slotFitToWindow(); void slotSlideShowAll(); void slotSlideShowSelection(); void slotSlideShowRecursive(); void slotSlideShowManualFromCurrent(); void slotSlideShowManualFrom(const ImageInfo& info); // Album action slots void slotRefresh(); void slotNewAlbum(); void slotSortAlbums(int role); void slotDeleteAlbum(); void slotRenameAlbum(); void slotAlbumPropsEdit(); void slotAlbumOpenInFileManager(); void slotAlbumHistoryBack(int steps=1); void slotAlbumHistoryForward(int steps=1); void slotAlbumWriteMetadata(); void slotAlbumReadMetadata(); - void slotAlbumSelected(QList albums); + void slotAlbumSelected(const QList& albums); void slotGotoAlbumAndItem(const ImageInfo& imageInfo); void slotGotoDateAndItem(const ImageInfo& imageInfo); void slotGotoTagAndItem(int tagID); void slotSelectAlbum(const QUrl& url); void slotSetCurrentWhenAvailable(const qlonglong id); void slotSetAsAlbumThumbnail(const ImageInfo& info); // Tag action slots void slotNewTag(); void slotDeleteTag(); void slotEditTag(); void slotOpenTagsManager(); void slotAssignTag(); // Search action slots void slotNewKeywordSearch(); void slotNewAdvancedSearch(); - void slotNewDuplicatesSearch(PAlbum* album=0); - void slotNewDuplicatesSearch(QList albums); - void slotNewDuplicatesSearch(QList albums); + void slotNewDuplicatesSearch(PAlbum* album); + void slotNewDuplicatesSearch(const QList& albums); + void slotNewDuplicatesSearch(const QList& albums); // Image action slots void slotImageLightTable(); void slotImageAddToLightTable(); void slotImageAddToCurrentQueue(); void slotImageAddToNewQueue(); void slotImageAddToExistingQueue(int); void slotImagePreview(); void slotMapWidgetView(); void slotTableView(); void slotIconView(); void slotImageEdit(); void slotImageFindSimilar(); void slotImageScanForFaces(); void slotImageExifOrientation(int orientation); void slotImageRename(); void slotImageDelete(); void slotImageDeletePermanently(); void slotImageDeletePermanentlyDirectly(); void slotImageTrashDirectly(); void slotImageWriteMetadata(); void slotImageReadMetadata(); void slotSelectAll(); void slotSelectNone(); void slotSelectInvert(); void slotSortImages(int order); void slotSortImagesOrder(int order); void slotSeparateImages(int mode); void slotImageSeparationSortOrder(int order); void slotMoveSelectionToAlbum(); void slotImagePaste(); void slotAssignPickLabel(int pickId); void slotAssignColorLabel(int colorId); void slotAssignRating(int rating); void slotAssignTag(int tagID); void slotRemoveTag(int tagID); // Tools action slots. void slotEditor(); void slotLightTable(); void slotQueueMgr(); void slotFileWithDefaultApplication(); void slotLeftSideBarActivate(QWidget* widget); void slotLeftSideBarActivate(SidebarWidget* widget); void slotLeftSideBarActivateAlbums(); void slotLeftSideBarActivateTags(); void slotRightSideBarActivateTitles(); void slotRightSideBarActivateComments(); void slotRightSideBarActivateAssignedTags(); void slotFocusAndNextImage(); void slotCreateGroupFromSelection(); void slotCreateGroupByTimeFromSelection(); void slotCreateGroupByFilenameFromSelection(); void slotRemoveSelectedFromGroup(); void slotUngroupSelected(); private: void toggleZoomActions(); void setupConnections(); void loadViewState(); void saveViewState(); void changeAlbumFromHistory(QList album, QWidget* const widget); void slideShow(const ImageInfoList& infoList); private Q_SLOTS: void slotAllAlbumsLoaded(); void slotAlbumsCleared(); void slotImageSelected(); void slotTogglePreviewMode(const ImageInfo& info); void slotDispatchImageSelected(); void slotLeftSidebarChangedTab(QWidget* w); void slotFirstItem(); void slotPrevItem(); void slotNextItem(); void slotLastItem(); void slotSelectItemByUrl(const QUrl&); void slotAwayFromSelection(); void slotViewModeChanged(); void slotEscapePreview(); void slotSlideShowBuilderComplete(const SlideShowSettings& settings); void slotThumbSizeEffect(); void slotZoomFactorChanged(double); void slotSidebarTabTitleStyleChanged(); void slotImageChangeFailed(const QString& message, const QStringList& fileNames); void slotRatingChanged(const QUrl&, int); void slotColorLabelChanged(const QUrl&, int); void slotPickLabelChanged(const QUrl&, int); void slotToggleTag(const QUrl&, int); void slotPopupFiltersView(); void slotSetupMetadataFilters(int); void slotAlbumRefreshComplete(); void slotRefreshImagePreview(); void slotShowContextMenu(QContextMenuEvent* event, const QList& extraGroupingActions = QList()); void slotShowContextMenuOnInfo(QContextMenuEvent* event, const ImageInfo& info, const QList& extraGroupingActions = QList(), ImageFilterModel* imageFilterModel = 0); void slotShowGroupContextMenu(QContextMenuEvent* event, const QList& selectedInfos, ImageFilterModel* imageFilterModel = 0); private: class Private; Private* const d; }; } // namespace Digikam #endif // DIGIKAM_VIEW_H diff --git a/core/app/views/leftsidebarwidgets.cpp b/core/app/views/leftsidebarwidgets.cpp index 7e0e14bf06..932f583d5f 100644 --- a/core/app/views/leftsidebarwidgets.cpp +++ b/core/app/views/leftsidebarwidgets.cpp @@ -1,1501 +1,1501 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2000-12-05 * Description : left sidebar widgets * * Copyright (C) 2009-2010 by Johannes Wienke * Copyright (C) 2010-2018 by Gilles Caulier * Copyright (C) 2012 by Andi Clemens * Copyright (C) 2014 by Mohamed_Anwer * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "leftsidebarwidgets.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "digikam_debug.h" #include "albummanager.h" #include "albummodificationhelper.h" #include "albumselectiontreeview.h" #include "applicationsettings.h" #include "datefolderview.h" #include "editablesearchtreeview.h" #include "fuzzysearchview.h" #include "searchfolderview.h" #include "searchtabheader.h" #include "searchtextbar.h" #include "coredbsearchxml.h" #include "tagfolderview.h" #include "timelinewidget.h" #include "facescandialog.h" #include "facesdetector.h" #include "tagsmanager.h" #include "albumlabelstreeview.h" #include "coredb.h" #include "dexpanderbox.h" namespace Digikam { class AlbumFolderViewSideBarWidget::Private { public: explicit Private() : albumModificationHelper(0), albumFolderView(0), searchTextBar(0) { } AlbumModificationHelper* albumModificationHelper; AlbumSelectionTreeView* albumFolderView; SearchTextBar* searchTextBar; }; AlbumFolderViewSideBarWidget::AlbumFolderViewSideBarWidget(QWidget* const parent, AlbumModel* const model, AlbumModificationHelper* const albumModificationHelper) : SidebarWidget(parent), d(new Private) { setObjectName(QLatin1String("AlbumFolderView Sidebar")); setProperty("Shortcut", Qt::META + Qt::CTRL + Qt::Key_F1); d->albumModificationHelper = albumModificationHelper; QVBoxLayout* const layout = new QVBoxLayout(this); d->albumFolderView = new AlbumSelectionTreeView(this, model, d->albumModificationHelper); d->albumFolderView->setObjectName(QLatin1String("AlbumFolderView")); d->albumFolderView->setConfigGroup(getConfigGroup()); d->albumFolderView->setExpandNewCurrentItem(true); d->albumFolderView->setAlbumManagerCurrentAlbum(true); d->searchTextBar = new SearchTextBar(this, QLatin1String("DigikamViewFolderSearchBar")); d->searchTextBar->setHighlightOnResult(true); d->searchTextBar->setModel(model, AbstractAlbumModel::AlbumIdRole, AbstractAlbumModel::AlbumTitleRole); d->searchTextBar->setFilterModel(d->albumFolderView->albumFilterModel()); layout->addWidget(d->albumFolderView); layout->addWidget(d->searchTextBar); // setup connection connect(d->albumFolderView, SIGNAL(signalFindDuplicates(PAlbum*)), this, SIGNAL(signalFindDuplicates(PAlbum*))); } AlbumFolderViewSideBarWidget::~AlbumFolderViewSideBarWidget() { delete d; } void AlbumFolderViewSideBarWidget::setActive(bool active) { if (active) { AlbumManager::instance()->setCurrentAlbums(QList() << d->albumFolderView->currentAlbum()); } } void AlbumFolderViewSideBarWidget::doLoadState() { d->albumFolderView->loadState(); } void AlbumFolderViewSideBarWidget::doSaveState() { d->albumFolderView->saveState(); } void AlbumFolderViewSideBarWidget::applySettings() { ApplicationSettings* const settings = ApplicationSettings::instance(); d->albumFolderView->setEnableToolTips(settings->getShowAlbumToolTips()); } void AlbumFolderViewSideBarWidget::changeAlbumFromHistory(QList album) { d->albumFolderView->setCurrentAlbums(album); } AlbumPointer AlbumFolderViewSideBarWidget::currentAlbum() const { return AlbumPointer (d->albumFolderView->currentAlbum()); } void AlbumFolderViewSideBarWidget::setCurrentAlbum(PAlbum* album) { // Change the current album in list view. d->albumFolderView->setCurrentAlbums(QList() << album); } const QIcon AlbumFolderViewSideBarWidget::getIcon() { return QIcon::fromTheme(QLatin1String("folder-pictures")); } const QString AlbumFolderViewSideBarWidget::getCaption() { return i18n("Albums"); } // ----------------------------------------------------------------------------- class TagViewSideBarWidget::Private { public: enum TagsSource { NoTags = 0, ExistingTags }; public: explicit Private() : openTagMngr(0), tagSearchBar(0), tagFolderView(0), btnGroup(0), noTagsBtn(0), tagsBtn(0), noTagsWasChecked(false), ExistingTagsWasChecked(false) { } public: QPushButton* openTagMngr; SearchTextBar* tagSearchBar; TagFolderView* tagFolderView; QButtonGroup* btnGroup; QRadioButton* noTagsBtn; QRadioButton* tagsBtn; bool noTagsWasChecked; bool ExistingTagsWasChecked; QString noTagsSearchXml; static const QString configTagsSourceEntry; }; const QString TagViewSideBarWidget::Private::configTagsSourceEntry(QLatin1String("TagsSource")); TagViewSideBarWidget::TagViewSideBarWidget(QWidget* const parent, TagModel* const model) : SidebarWidget(parent), d(new Private) { setObjectName(QLatin1String("TagView Sidebar")); setProperty("Shortcut", Qt::META + Qt::CTRL + Qt::Key_F2); QVBoxLayout* const layout = new QVBoxLayout(this); d->openTagMngr = new QPushButton( i18n("Open Tag Manager")); d->noTagsBtn = new QRadioButton(i18n("No Tags"), this); d->tagsBtn = new QRadioButton(i18n("Existing Tags"), this); d->btnGroup = new QButtonGroup(this); d->btnGroup->addButton(d->noTagsBtn); d->btnGroup->addButton(d->tagsBtn); d->btnGroup->setId(d->noTagsBtn, 0); d->btnGroup->setId(d->tagsBtn, 1); d->btnGroup->setExclusive(true); d->tagFolderView = new TagFolderView(this, model); d->tagFolderView->setConfigGroup(getConfigGroup()); d->tagFolderView->setExpandNewCurrentItem(true); d->tagFolderView->setAlbumManagerCurrentAlbum(true); d->tagSearchBar = new SearchTextBar(this, QLatin1String("DigikamViewTagSearchBar")); d->tagSearchBar->setHighlightOnResult(true); d->tagSearchBar->setModel(model, AbstractAlbumModel::AlbumIdRole, AbstractAlbumModel::AlbumTitleRole); d->tagSearchBar->setFilterModel(d->tagFolderView->albumFilterModel()); layout->addWidget(d->openTagMngr); layout->addWidget(d->noTagsBtn); layout->addWidget(d->tagsBtn); layout->addWidget(d->tagFolderView); layout->addWidget(d->tagSearchBar); connect(d->openTagMngr, SIGNAL(clicked()), this,SLOT(slotOpenTagManager())); connect(d->tagFolderView, SIGNAL(signalFindDuplicates(QList)), this, SIGNAL(signalFindDuplicates(QList))); connect(d->btnGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotToggleTagsSelection(int))); } TagViewSideBarWidget::~TagViewSideBarWidget() { delete d; } void TagViewSideBarWidget::setActive(bool active) { if (active) { if(d->noTagsBtn->isChecked()) { setNoTagsAlbum(); } else { AlbumManager::instance()->setCurrentAlbums(d->tagFolderView->selectedTags()); } } } void TagViewSideBarWidget::doLoadState() { KConfigGroup group = getConfigGroup(); bool noTagsBtnWasChecked = group.readEntry(d->configTagsSourceEntry, false); d->noTagsBtn->setChecked(noTagsBtnWasChecked); d->tagsBtn->setChecked(!noTagsBtnWasChecked); d->noTagsWasChecked = noTagsBtnWasChecked; d->ExistingTagsWasChecked = !noTagsBtnWasChecked; d->tagFolderView->loadState(); d->tagFolderView->setDisabled(noTagsBtnWasChecked); } void TagViewSideBarWidget::doSaveState() { KConfigGroup group = getConfigGroup(); group.writeEntry(d->configTagsSourceEntry, d->noTagsBtn->isChecked()); d->tagFolderView->saveState(); group.sync(); } void TagViewSideBarWidget::applySettings() { } void TagViewSideBarWidget::changeAlbumFromHistory(QList album) { if (album.first()->type() == Album::TAG) { d->tagsBtn->setChecked(true); d->tagFolderView->setEnabled(true); d->ExistingTagsWasChecked = true; d->noTagsWasChecked = false; d->tagFolderView->setCurrentAlbums(album); } else { d->noTagsBtn->setChecked(true); d->tagFolderView->setDisabled(true); d->noTagsWasChecked = true; d->ExistingTagsWasChecked = false; } } AlbumPointer TagViewSideBarWidget::currentAlbum() const { return AlbumPointer (d->tagFolderView->currentAlbum()); } void TagViewSideBarWidget::setNoTagsAlbum() { if (d->noTagsSearchXml.isEmpty()) { SearchXmlWriter writer; writer.setFieldOperator((SearchXml::standardFieldOperator())); writer.writeGroup(); writer.writeField(QLatin1String("notag"), SearchXml::Equal); writer.finishField(); writer.finishGroup(); writer.finish(); d->noTagsSearchXml = writer.xml(); } QString title = SAlbum::getTemporaryTitle(DatabaseSearch::AdvancedSearch); SAlbum* album = AlbumManager::instance()->findSAlbum(title); int id; if (album) { id = album->id(); CoreDbAccess().db()->updateSearch(id,DatabaseSearch::AdvancedSearch, SAlbum::getTemporaryTitle(DatabaseSearch::AdvancedSearch), d->noTagsSearchXml); } else { id = CoreDbAccess().db()->addSearch(DatabaseSearch::AdvancedSearch, SAlbum::getTemporaryTitle(DatabaseSearch::AdvancedSearch), d->noTagsSearchXml); } album = new SAlbum(i18n("No Tags Album"), id); if (album) { AlbumManager::instance()->setCurrentAlbums(QList() << album); } } const QIcon TagViewSideBarWidget::getIcon() { return QIcon::fromTheme(QLatin1String("tag")); } const QString TagViewSideBarWidget::getCaption() { return i18n("Tags"); } void TagViewSideBarWidget::setCurrentAlbum(TAlbum* album) { d->tagFolderView->setCurrentAlbums(QList() << album); } void TagViewSideBarWidget::slotOpenTagManager() { TagsManager* const tagMngr = TagsManager::instance(); tagMngr->show(); tagMngr->activateWindow(); tagMngr->raise(); } void TagViewSideBarWidget::slotToggleTagsSelection(int radioClicked) { switch (Private::TagsSource(radioClicked)) { case Private::NoTags: { if (!d->noTagsWasChecked) { setNoTagsAlbum(); d->tagFolderView->setDisabled(true); d->noTagsWasChecked = d->noTagsBtn->isChecked(); d->ExistingTagsWasChecked = d->tagsBtn->isChecked(); } break; } case Private::ExistingTags: { if (!d->ExistingTagsWasChecked) { d->tagFolderView->setEnabled(true); setActive(true); d->noTagsWasChecked = d->noTagsBtn->isChecked(); d->ExistingTagsWasChecked = d->tagsBtn->isChecked(); } break; } } } // ----------------------------------------------------------------------------- class LabelsSideBarWidget::Private { public: explicit Private() : labelsTree(0) { } AlbumLabelsTreeView* labelsTree; }; LabelsSideBarWidget::LabelsSideBarWidget(QWidget* const parent) : SidebarWidget(parent), d(new Private) { setObjectName(QLatin1String("Labels Sidebar")); setProperty("Shortcut", Qt::META + Qt::CTRL + Qt::Key_F3); QVBoxLayout* const layout = new QVBoxLayout(this); d->labelsTree = new AlbumLabelsTreeView(this); d->labelsTree->setConfigGroup(getConfigGroup()); layout->addWidget(d->labelsTree); } LabelsSideBarWidget::~LabelsSideBarWidget() { delete d; } AlbumLabelsTreeView *LabelsSideBarWidget::labelsTree() { return d->labelsTree; } void LabelsSideBarWidget::setActive(bool active) { if (active) { d->labelsTree->setCurrentAlbum(); } } void LabelsSideBarWidget::applySettings() { } void LabelsSideBarWidget::changeAlbumFromHistory(QList album) { Q_UNUSED(album); } void LabelsSideBarWidget::doLoadState() { d->labelsTree->doLoadState(); } void LabelsSideBarWidget::doSaveState() { d->labelsTree->doSaveState(); } const QIcon LabelsSideBarWidget::getIcon() { return QIcon::fromTheme(QLatin1String("folder-favorites")); } const QString LabelsSideBarWidget::getCaption() { return i18n("Labels"); } QHash > LabelsSideBarWidget::selectedLabels() { return d->labelsTree->selectedLabels(); } // ----------------------------------------------------------------------------- class DateFolderViewSideBarWidget::Private { public: explicit Private() : dateFolderView(0) { } DateFolderView* dateFolderView; }; DateFolderViewSideBarWidget::DateFolderViewSideBarWidget(QWidget* const parent, DateAlbumModel* const model, ImageAlbumFilterModel* const imageFilterModel) : SidebarWidget(parent), d(new Private) { setObjectName(QLatin1String("DateFolderView Sidebar")); setProperty("Shortcut", Qt::META + Qt::CTRL + Qt::Key_F4); QVBoxLayout* const layout = new QVBoxLayout(this); d->dateFolderView = new DateFolderView(this, model); d->dateFolderView->setConfigGroup(getConfigGroup()); d->dateFolderView->setImageModel(imageFilterModel); layout->addWidget(d->dateFolderView); } DateFolderViewSideBarWidget::~DateFolderViewSideBarWidget() { delete d; } void DateFolderViewSideBarWidget::setActive(bool active) { d->dateFolderView->setActive(active); } void DateFolderViewSideBarWidget::doLoadState() { d->dateFolderView->loadState(); } void DateFolderViewSideBarWidget::doSaveState() { d->dateFolderView->saveState(); } void DateFolderViewSideBarWidget::applySettings() { } void DateFolderViewSideBarWidget::changeAlbumFromHistory(QList album) { d->dateFolderView->changeAlbumFromHistory(dynamic_cast(album.first())); } AlbumPointer DateFolderViewSideBarWidget::currentAlbum() const { return d->dateFolderView->currentAlbum(); } void DateFolderViewSideBarWidget::gotoDate(const QDate& date) { d->dateFolderView->gotoDate(date); } const QIcon DateFolderViewSideBarWidget::getIcon() { return QIcon::fromTheme(QLatin1String("view-calendar-list")); } const QString DateFolderViewSideBarWidget::getCaption() { return i18n("Dates"); } // ----------------------------------------------------------------------------- class TimelineSideBarWidget::Private { public: explicit Private() : scaleBG(0), cursorCountLabel(0), scrollBar(0), timer(0), resetButton(0), saveButton(0), timeUnitCB(0), nameEdit(0), cursorDateLabel(0), searchDateBar(0), timeLineFolderView(0), timeLineWidget(0), searchModificationHelper(0) { } static const QString configHistogramTimeUnitEntry; static const QString configHistogramScaleEntry; static const QString configCursorPositionEntry; QButtonGroup* scaleBG; QLabel* cursorCountLabel; QScrollBar* scrollBar; QTimer* timer; QToolButton* resetButton; QToolButton* saveButton; QComboBox* timeUnitCB; QLineEdit* nameEdit; DAdjustableLabel* cursorDateLabel; SearchTextBar* searchDateBar; EditableSearchTreeView* timeLineFolderView; TimeLineWidget* timeLineWidget; SearchModificationHelper* searchModificationHelper; AlbumPointer currentTimelineSearch; }; const QString TimelineSideBarWidget::Private::configHistogramTimeUnitEntry(QLatin1String("Histogram TimeUnit")); const QString TimelineSideBarWidget::Private::configHistogramScaleEntry(QLatin1String("Histogram Scale")); const QString TimelineSideBarWidget::Private::configCursorPositionEntry(QLatin1String("Cursor Position")); // -------------------------------------------------------- TimelineSideBarWidget::TimelineSideBarWidget(QWidget* const parent, SearchModel* const searchModel, SearchModificationHelper* const searchModificationHelper) : SidebarWidget(parent), d(new Private) { setObjectName(QLatin1String("TimeLine Sidebar")); setProperty("Shortcut", Qt::META + Qt::CTRL + Qt::Key_F5); d->searchModificationHelper = searchModificationHelper; d->timer = new QTimer(this); setAttribute(Qt::WA_DeleteOnClose); const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); QVBoxLayout* const vlay = new QVBoxLayout(this); QFrame* const panel = new QFrame(this); panel->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); panel->setLineWidth(1); QGridLayout* const grid = new QGridLayout(panel); // --------------------------------------------------------------- QWidget* const hbox1 = new QWidget(panel); QHBoxLayout* const hlay = new QHBoxLayout(hbox1); QLabel* const label1 = new QLabel(i18n("Time Unit:"), hbox1); d->timeUnitCB = new QComboBox(hbox1); d->timeUnitCB->addItem(i18n("Day"), TimeLineWidget::Day); d->timeUnitCB->addItem(i18n("Week"), TimeLineWidget::Week); d->timeUnitCB->addItem(i18n("Month"), TimeLineWidget::Month); d->timeUnitCB->addItem(i18n("Year"), TimeLineWidget::Year); d->timeUnitCB->setCurrentIndex((int)TimeLineWidget::Month); d->timeUnitCB->setFocusPolicy(Qt::NoFocus); d->timeUnitCB->setWhatsThis(i18n("

Select the histogram time unit.

" "

You can change the graph decade to zoom in or zoom out over time.

")); QWidget* const scaleBox = new QWidget(hbox1); QHBoxLayout* const hlay2 = new QHBoxLayout(scaleBox); d->scaleBG = new QButtonGroup(scaleBox); d->scaleBG->setExclusive(true); scaleBox->setWhatsThis( i18n("

Select the histogram scale.

" "

If the date's maximal counts are small, you can use the linear scale.

" "

Logarithmic scale can be used when the maximal counts are big; " "if it is used, all values (small and large) will be visible on the " "graph.

")); QToolButton* const linHistoButton = new QToolButton(scaleBox); linHistoButton->setToolTip( i18n( "Linear" ) ); linHistoButton->setIcon(QIcon::fromTheme(QLatin1String("view-object-histogram-linear"))); linHistoButton->setCheckable(true); d->scaleBG->addButton(linHistoButton, TimeLineWidget::LinScale); QToolButton* const logHistoButton = new QToolButton(scaleBox); logHistoButton->setToolTip( i18n( "Logarithmic" ) ); logHistoButton->setIcon(QIcon::fromTheme(QLatin1String("view-object-histogram-logarithmic"))); logHistoButton->setCheckable(true); d->scaleBG->addButton(logHistoButton, TimeLineWidget::LogScale); hlay2->setContentsMargins(QMargins()); hlay2->setSpacing(0); hlay2->addWidget(linHistoButton); hlay2->addWidget(logHistoButton); hlay->setContentsMargins(QMargins()); hlay->setSpacing(spacing); hlay->addWidget(label1); hlay->addWidget(d->timeUnitCB); hlay->addItem(new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Minimum)); hlay->addWidget(scaleBox); // --------------------------------------------------------------- d->timeLineWidget = new TimeLineWidget(panel); d->scrollBar = new QScrollBar(panel); d->scrollBar->setOrientation(Qt::Horizontal); d->scrollBar->setMinimum(0); d->scrollBar->setSingleStep(1); d->cursorDateLabel = new DAdjustableLabel(panel); d->cursorCountLabel = new QLabel(panel); d->cursorCountLabel->setAlignment(Qt::AlignRight); // --------------------------------------------------------------- DHBox* const hbox2 = new DHBox(panel); hbox2->setContentsMargins(QMargins()); hbox2->setSpacing(spacing); d->resetButton = new QToolButton(hbox2); d->resetButton->setIcon(QIcon::fromTheme(QLatin1String("document-revert"))); d->resetButton->setToolTip(i18n("Clear current selection")); d->resetButton->setWhatsThis(i18n("If you press this button, the current date selection on the time-line will be cleared.")); d->nameEdit = new QLineEdit(hbox2); d->nameEdit->setClearButtonEnabled(true); d->nameEdit->setWhatsThis(i18n("Enter the name of the current dates search to save in the " "\"Searches\" view")); d->saveButton = new QToolButton(hbox2); d->saveButton->setIcon(QIcon::fromTheme(QLatin1String("document-save"))); d->saveButton->setEnabled(false); d->saveButton->setToolTip(i18n("Save current selection to a new virtual Album")); d->saveButton->setWhatsThis(i18n("If you press this button, the dates selected on the time-line will be " "saved to a new search virtual Album using the name set on the left.")); // --------------------------------------------------------------- grid->addWidget(hbox1, 0, 0, 1, 4); grid->addWidget(d->cursorDateLabel, 1, 0, 1, 3); grid->addWidget(d->cursorCountLabel, 1, 3, 1, 1); grid->addWidget(d->timeLineWidget, 2, 0, 1, 4); grid->addWidget(d->scrollBar, 3, 0, 1, 4); grid->addWidget(hbox2, 4, 0, 1, 4); grid->setColumnStretch(2, 10); grid->setContentsMargins(spacing, spacing, spacing, spacing); grid->setSpacing(spacing); // --------------------------------------------------------------- d->timeLineFolderView = new EditableSearchTreeView(this, searchModel, searchModificationHelper); d->timeLineFolderView->setConfigGroup(getConfigGroup()); d->timeLineFolderView->filteredModel()->listTimelineSearches(); d->timeLineFolderView->filteredModel()->setListTemporarySearches(false); d->timeLineFolderView->setAlbumManagerCurrentAlbum(false); d->searchDateBar = new SearchTextBar(this, QLatin1String("TimeLineViewSearchDateBar")); d->searchDateBar->setModel(d->timeLineFolderView->filteredModel(), AbstractAlbumModel::AlbumIdRole, AbstractAlbumModel::AlbumTitleRole); d->searchDateBar->setFilterModel(d->timeLineFolderView->albumFilterModel()); vlay->addWidget(panel); vlay->addWidget(d->timeLineFolderView); vlay->addItem(new QSpacerItem(spacing, spacing, QSizePolicy::Minimum, QSizePolicy::Minimum)); vlay->addWidget(d->searchDateBar); vlay->setContentsMargins(QMargins()); vlay->setSpacing(0); // --------------------------------------------------------------- connect(AlbumManager::instance(), SIGNAL(signalDatesMapDirty(QMap)), d->timeLineWidget, SLOT(slotDatesMap(QMap))); connect(d->timeLineFolderView, SIGNAL(currentAlbumChanged(Album*)), this, SLOT(slotAlbumSelected(Album*))); connect(d->timeUnitCB, SIGNAL(activated(int)), this, SLOT(slotTimeUnitChanged(int))); connect(d->scaleBG, SIGNAL(buttonReleased(int)), this, SLOT(slotScaleChanged(int))); connect(d->timeLineWidget, SIGNAL(signalDateMapChanged()), this, SLOT(slotInit())); connect(d->timeLineWidget, SIGNAL(signalCursorPositionChanged()), this, SLOT(slotCursorPositionChanged())); connect(d->timeLineWidget, SIGNAL(signalSelectionChanged()), this, SLOT(slotSelectionChanged())); connect(d->timeLineWidget, SIGNAL(signalRefDateTimeChanged()), this, SLOT(slotRefDateTimeChanged())); connect(d->timer, SIGNAL(timeout()), this, SLOT(slotUpdateCurrentDateSearchAlbum())); connect(d->resetButton, SIGNAL(clicked()), this, SLOT(slotResetSelection())); connect(d->saveButton, SIGNAL(clicked()), this, SLOT(slotSaveSelection())); connect(d->scrollBar, SIGNAL(valueChanged(int)), this, SLOT(slotScrollBarValueChanged(int))); connect(d->nameEdit, SIGNAL(textChanged(QString)), this, SLOT(slotCheckAboutSelection())); connect(d->nameEdit, SIGNAL(returnPressed()), d->saveButton, SLOT(animateClick())); } TimelineSideBarWidget::~TimelineSideBarWidget() { delete d; } void TimelineSideBarWidget::slotInit() { // Date Maps are loaded from AlbumManager to TimeLineWidget after than GUI is initialized. // AlbumManager query Date KIO slave to stats items from database and it can take a while. // We waiting than TimeLineWidget is ready before to set last config from users. loadState(); disconnect(d->timeLineWidget, SIGNAL(signalDateMapChanged()), this, SLOT(slotInit())); connect(d->timeLineWidget, SIGNAL(signalDateMapChanged()), this, SLOT(slotCursorPositionChanged())); } void TimelineSideBarWidget::setActive(bool active) { if (active) { if (!d->currentTimelineSearch) { d->currentTimelineSearch = d->timeLineFolderView->currentAlbum(); } if (d->currentTimelineSearch) { AlbumManager::instance()->setCurrentAlbums(QList() << d->currentTimelineSearch); } else { slotUpdateCurrentDateSearchAlbum(); } } } void TimelineSideBarWidget::doLoadState() { KConfigGroup group = getConfigGroup(); d->timeUnitCB->setCurrentIndex(group.readEntry(d->configHistogramTimeUnitEntry, (int)TimeLineWidget::Month)); slotTimeUnitChanged(d->timeUnitCB->currentIndex()); int id = group.readEntry(d->configHistogramScaleEntry, (int)TimeLineWidget::LinScale); if (d->scaleBG->button(id)) { d->scaleBG->button(id)->setChecked(true); } slotScaleChanged(d->scaleBG->checkedId()); QDateTime now = QDateTime::currentDateTime(); d->timeLineWidget->setCursorDateTime(group.readEntry(d->configCursorPositionEntry, now)); d->timeLineWidget->setCurrentIndex(d->timeLineWidget->indexForCursorDateTime()); d->timeLineFolderView->loadState(); } void TimelineSideBarWidget::doSaveState() { KConfigGroup group = getConfigGroup(); group.writeEntry(d->configHistogramTimeUnitEntry, d->timeUnitCB->currentIndex()); group.writeEntry(d->configHistogramScaleEntry, d->scaleBG->checkedId()); group.writeEntry(d->configCursorPositionEntry, d->timeLineWidget->cursorDateTime()); d->timeLineFolderView->saveState(); group.sync(); } void TimelineSideBarWidget::applySettings() { // nothing to do here right now } void TimelineSideBarWidget::changeAlbumFromHistory(QList album) { d->timeLineFolderView->setCurrentAlbums(album); } const QIcon TimelineSideBarWidget::getIcon() { return QIcon::fromTheme(QLatin1String("player-time")); } const QString TimelineSideBarWidget::getCaption() { return i18n("Timeline"); } void TimelineSideBarWidget::slotRefDateTimeChanged() { d->scrollBar->blockSignals(true); d->scrollBar->setMaximum(d->timeLineWidget->totalIndex()-1); d->scrollBar->setValue(d->timeLineWidget->indexForRefDateTime()-1); d->scrollBar->blockSignals(false); } void TimelineSideBarWidget::slotTimeUnitChanged(int mode) { d->timeLineWidget->setTimeUnit((TimeLineWidget::TimeUnit)mode); } void TimelineSideBarWidget::slotScrollBarValueChanged(int val) { d->timeLineWidget->setCurrentIndex(val); } void TimelineSideBarWidget::slotScaleChanged(int mode) { d->timeLineWidget->setScaleMode((TimeLineWidget::ScaleMode)mode); } void TimelineSideBarWidget::slotCursorPositionChanged() { QString txt; int val = d->timeLineWidget->cursorInfo(txt); d->cursorDateLabel->setAdjustedText(txt); d->cursorCountLabel->setText((val == 0) ? i18n("no item") : i18np("1 item", "%1 items", val)); } void TimelineSideBarWidget::slotSelectionChanged() { d->timer->setSingleShot(true); d->timer->start(500); } /** Called from d->timer event.*/ void TimelineSideBarWidget::slotUpdateCurrentDateSearchAlbum() { slotCheckAboutSelection(); int totalCount = 0; DateRangeList dateRanges = d->timeLineWidget->selectedDateRange(totalCount); d->currentTimelineSearch = d->searchModificationHelper-> slotCreateTimeLineSearch(SAlbum::getTemporaryTitle(DatabaseSearch::TimeLineSearch), dateRanges, true); d->timeLineFolderView->setCurrentAlbum(0); // "temporary" search is not listed in view } void TimelineSideBarWidget::slotSaveSelection() { QString name = d->nameEdit->text(); int totalCount = 0; DateRangeList dateRanges = d->timeLineWidget->selectedDateRange(totalCount); d->currentTimelineSearch = d->searchModificationHelper->slotCreateTimeLineSearch(name, dateRanges); } void TimelineSideBarWidget::slotAlbumSelected(Album* album) { if (d->currentTimelineSearch == album) { return; } SAlbum* const salbum = dynamic_cast(album); if (!salbum) { return; } d->currentTimelineSearch = salbum; AlbumManager::instance()->setCurrentAlbums(QList() << salbum); SearchXmlReader reader(salbum->query()); // The timeline query consists of groups, with two date time fields each DateRangeList list; while (!reader.atEnd()) { // read groups if (reader.readNext() == SearchXml::Group) { QDateTime start, end; int numberOfFields = 0; while (!reader.atEnd()) { // read fields reader.readNext(); if (reader.isEndElement()) { break; } if (reader.isFieldElement()) { if (numberOfFields == 0) { start = reader.valueToDateTime(); } else if (numberOfFields == 1) { end = reader.valueToDateTime(); } ++numberOfFields; } } if (numberOfFields) { list << DateRange(start, end); } } } d->timeLineWidget->setSelectedDateRange(list); } void TimelineSideBarWidget::slotResetSelection() { d->timeLineWidget->slotResetSelection(); slotCheckAboutSelection(); AlbumManager::instance()->setCurrentAlbums(QList()); } void TimelineSideBarWidget::slotCheckAboutSelection() { int totalCount = 0; DateRangeList list = d->timeLineWidget->selectedDateRange(totalCount); if (!list.isEmpty()) { d->nameEdit->setEnabled(true); if (!d->nameEdit->text().isEmpty()) { d->saveButton->setEnabled(true); } } else { d->nameEdit->setEnabled(false); d->saveButton->setEnabled(false); } } // ----------------------------------------------------------------------------- class SearchSideBarWidget::Private { public: explicit Private() : searchSearchBar(0), searchTreeView(0), searchTabHeader(0) { } SearchTextBar* searchSearchBar; NormalSearchTreeView* searchTreeView; SearchTabHeader* searchTabHeader; }; SearchSideBarWidget::SearchSideBarWidget(QWidget* const parent, SearchModel* const searchModel, SearchModificationHelper* const searchModificationHelper) : SidebarWidget(parent), d(new Private) { setObjectName(QLatin1String("Search Sidebar")); setProperty("Shortcut", Qt::META + Qt::CTRL + Qt::Key_F6); QVBoxLayout* const layout = new QVBoxLayout(this); d->searchTabHeader = new SearchTabHeader(this); d->searchTreeView = new NormalSearchTreeView(this, searchModel, searchModificationHelper); d->searchTreeView->setConfigGroup(getConfigGroup()); d->searchTreeView->filteredModel()->listNormalSearches(); d->searchTreeView->filteredModel()->setListTemporarySearches(true); d->searchTreeView->setAlbumManagerCurrentAlbum(true); d->searchSearchBar = new SearchTextBar(this, QLatin1String("DigikamViewSearchSearchBar")); d->searchSearchBar->setModel(d->searchTreeView->filteredModel(), AbstractAlbumModel::AlbumIdRole, AbstractAlbumModel::AlbumTitleRole); d->searchSearchBar->setFilterModel(d->searchTreeView->albumFilterModel()); layout->addWidget(d->searchTabHeader); layout->addWidget(d->searchTreeView); layout->setStretchFactor(d->searchTreeView, 1); layout->addWidget(d->searchSearchBar); connect(d->searchTreeView, SIGNAL(newSearch()), d->searchTabHeader, SLOT(newAdvancedSearch())); connect(d->searchTreeView, SIGNAL(editSearch(SAlbum*)), d->searchTabHeader, SLOT(editSearch(SAlbum*))); connect(d->searchTreeView, SIGNAL(currentAlbumChanged(Album*)), d->searchTabHeader, SLOT(selectedSearchChanged(Album*))); connect(d->searchTabHeader, SIGNAL(searchShallBeSelected(QList)), d->searchTreeView, SLOT(setCurrentAlbums(QList))); } SearchSideBarWidget::~SearchSideBarWidget() { delete d; } void SearchSideBarWidget::setActive(bool active) { if (active) { AlbumManager::instance()->setCurrentAlbums(QList() << d->searchTreeView->currentAlbum()); } } void SearchSideBarWidget::doLoadState() { d->searchTreeView->loadState(); } void SearchSideBarWidget::doSaveState() { d->searchTreeView->saveState(); } void SearchSideBarWidget::applySettings() { } void SearchSideBarWidget::changeAlbumFromHistory(QList album) { d->searchTreeView->setCurrentAlbums(album); } const QIcon SearchSideBarWidget::getIcon() { return QIcon::fromTheme(QLatin1String("edit-find")); } const QString SearchSideBarWidget::getCaption() { return i18nc("Avanced search images, access stored searches", "Search"); } void SearchSideBarWidget::newKeywordSearch() { d->searchTabHeader->newKeywordSearch(); } void SearchSideBarWidget::newAdvancedSearch() { d->searchTabHeader->newAdvancedSearch(); } // ----------------------------------------------------------------------------- class FuzzySearchSideBarWidget::Private { public: explicit Private() : fuzzySearchView(0), searchModificationHelper(0) { } FuzzySearchView* fuzzySearchView; SearchModificationHelper* searchModificationHelper; }; FuzzySearchSideBarWidget::FuzzySearchSideBarWidget(QWidget* const parent, SearchModel* const searchModel, SearchModificationHelper* const searchModificationHelper) : SidebarWidget(parent), d(new Private) { setObjectName(QLatin1String("Fuzzy Search Sidebar")); setProperty("Shortcut", Qt::META + Qt::CTRL + Qt::Key_F7); d->fuzzySearchView = new FuzzySearchView(searchModel, searchModificationHelper, this); d->fuzzySearchView->setConfigGroup(getConfigGroup()); QVBoxLayout* const layout = new QVBoxLayout(this); layout->addWidget(d->fuzzySearchView); } FuzzySearchSideBarWidget::~FuzzySearchSideBarWidget() { delete d; } void FuzzySearchSideBarWidget::setActive(bool active) { d->fuzzySearchView->setActive(active); if (active) { AlbumManager::instance()->setCurrentAlbums(QList() << d->fuzzySearchView->currentAlbum()); } emit signalActive(active); } void FuzzySearchSideBarWidget::doLoadState() { d->fuzzySearchView->loadState(); } void FuzzySearchSideBarWidget::doSaveState() { d->fuzzySearchView->saveState(); } void FuzzySearchSideBarWidget::applySettings() { } void FuzzySearchSideBarWidget::changeAlbumFromHistory(QList album) { SAlbum* const salbum = dynamic_cast(album.first()); d->fuzzySearchView->setCurrentAlbum(salbum); } const QIcon FuzzySearchSideBarWidget::getIcon() { return QIcon::fromTheme(QLatin1String("tools-wizard")); } const QString FuzzySearchSideBarWidget::getCaption() { return i18nc("Fuzzy Search images, as dupplicates, sketch, searches by similarities", "Similarity"); } void FuzzySearchSideBarWidget::newDuplicatesSearch(PAlbum* album) { d->fuzzySearchView->newDuplicatesSearch(album); } -void FuzzySearchSideBarWidget::newDuplicatesSearch(QList albums) +void FuzzySearchSideBarWidget::newDuplicatesSearch(const QList& albums) { d->fuzzySearchView->newDuplicatesSearch(albums); } -void FuzzySearchSideBarWidget::newDuplicatesSearch(QList albums) +void FuzzySearchSideBarWidget::newDuplicatesSearch(const QList& albums) { d->fuzzySearchView->newDuplicatesSearch(albums); } void FuzzySearchSideBarWidget::newSimilarSearch(const ImageInfo& imageInfo) { if (imageInfo.isNull()) { return; } d->fuzzySearchView->setImageInfo(imageInfo); } // ----------------------------------------------------------------------------- #ifdef HAVE_MARBLE class GPSSearchSideBarWidget::Private { public: explicit Private() : gpsSearchView(0) { } GPSSearchView* gpsSearchView; }; GPSSearchSideBarWidget::GPSSearchSideBarWidget(QWidget* const parent, SearchModel* const searchModel, SearchModificationHelper* const searchModificationHelper, ImageFilterModel* const imageFilterModel, QItemSelectionModel* const itemSelectionModel) : SidebarWidget(parent), d(new Private) { setObjectName(QLatin1String("GPS Search Sidebar")); setProperty("Shortcut", Qt::META + Qt::CTRL + Qt::Key_F8); d->gpsSearchView = new GPSSearchView(this, searchModel, searchModificationHelper, imageFilterModel, itemSelectionModel); d->gpsSearchView->setConfigGroup(getConfigGroup()); QScrollArea* const scrollArea = new QScrollArea(this); QVBoxLayout* const layout = new QVBoxLayout(this); layout->addWidget(scrollArea); scrollArea->setWidget(d->gpsSearchView); scrollArea->setWidgetResizable(true); connect(d->gpsSearchView, SIGNAL(signalMapSoloItems(QList,QString)), this, SIGNAL(signalMapSoloItems(QList,QString))); } GPSSearchSideBarWidget::~GPSSearchSideBarWidget() { delete d; } void GPSSearchSideBarWidget::setActive(bool active) { d->gpsSearchView->setActive(active); } void GPSSearchSideBarWidget::doLoadState() { d->gpsSearchView->loadState(); } void GPSSearchSideBarWidget::doSaveState() { d->gpsSearchView->saveState(); } void GPSSearchSideBarWidget::applySettings() { } void GPSSearchSideBarWidget::changeAlbumFromHistory(QList album) { d->gpsSearchView->changeAlbumFromHistory(dynamic_cast(album.first())); } const QIcon GPSSearchSideBarWidget::getIcon() { return QIcon::fromTheme(QLatin1String("globe")); } const QString GPSSearchSideBarWidget::getCaption() { return i18nc("Search images on a map", "Map"); } #endif // HAVE_MARBLE // ----------------------------------------------------------------------------- class PeopleSideBarWidget::Private : public TagViewSideBarWidget::Private { public: explicit Private() { personIcon = 0; textLabel = 0; rescanButton = 0; searchModificationHelper = 0; } QLabel* personIcon; QLabel* textLabel; QPushButton* rescanButton; SearchModificationHelper* searchModificationHelper; }; PeopleSideBarWidget::PeopleSideBarWidget(QWidget* const parent, TagModel* const model, SearchModificationHelper* const searchModificationHelper) : SidebarWidget(parent), d(new Private) { setObjectName(QLatin1String("People Sidebar")); setProperty("Shortcut", Qt::META + Qt::CTRL + Qt::Key_F9); d->searchModificationHelper = searchModificationHelper; QVBoxLayout* const layout = new QVBoxLayout; QHBoxLayout* const hlay = new QHBoxLayout; d->tagFolderView = new TagFolderView(this, model); d->tagFolderView->setConfigGroup(getConfigGroup()); d->tagFolderView->setExpandNewCurrentItem(true); d->tagFolderView->setAlbumManagerCurrentAlbum(true); d->tagFolderView->setShowDeleteFaceTagsAction(true); d->tagFolderView->filteredModel()->listOnlyTagsWithProperty(TagPropertyName::person()); d->tagFolderView->filteredModel()->setFilterBehavior(AlbumFilterModel::StrictFiltering); d->tagSearchBar = new SearchTextBar(this, QLatin1String("DigikamViewPeopleSearchBar")); d->tagSearchBar->setHighlightOnResult(true); d->tagSearchBar->setModel(d->tagFolderView->filteredModel(), AbstractAlbumModel::AlbumIdRole, AbstractAlbumModel::AlbumTitleRole); d->tagSearchBar->setFilterModel(d->tagFolderView->albumFilterModel()); d->rescanButton = new QPushButton; d->rescanButton->setText(i18n("Scan collection for faces")); d->personIcon = new QLabel; d->personIcon->setPixmap(QIcon::fromTheme(QLatin1String("edit-image-face-show")).pixmap(48)); d->textLabel = new QLabel(i18n("People Tags")); hlay->addWidget(d->personIcon); hlay->addWidget(d->textLabel); layout->addLayout(hlay); layout->addWidget(d->rescanButton); layout->addWidget(d->tagFolderView); layout->addWidget(d->tagSearchBar); setLayout(layout); connect(d->tagFolderView, SIGNAL(signalFindDuplicates(QList)), this, SIGNAL(signalFindDuplicates(QList))); connect(d->rescanButton, SIGNAL(pressed()), this, SLOT(slotScanForFaces()) ); } PeopleSideBarWidget::~PeopleSideBarWidget() { delete d; } void PeopleSideBarWidget::slotInit() { loadState(); } void PeopleSideBarWidget::setActive(bool active) { emit requestFaceMode(active); if (active) { d->tagFolderView->setCurrentAlbums(QList() << d->tagFolderView->currentAlbum()); } } void PeopleSideBarWidget::doLoadState() { d->tagFolderView->loadState(); } void PeopleSideBarWidget::doSaveState() { d->tagFolderView->saveState(); } void PeopleSideBarWidget::applySettings() { } void PeopleSideBarWidget::changeAlbumFromHistory(QList album) { d->tagFolderView->setCurrentAlbums(album); } void PeopleSideBarWidget::slotScanForFaces() { FaceScanDialog dialog; if (dialog.exec() == QDialog::Accepted) { FacesDetector* const tool = new FacesDetector(dialog.settings()); tool->start(); } } const QIcon PeopleSideBarWidget::getIcon() { return QIcon::fromTheme(QLatin1String("edit-image-face-show")); } const QString PeopleSideBarWidget::getCaption() { return i18nc("Browse images sorted by depicted people", "People"); } } // namespace Digikam diff --git a/core/app/views/leftsidebarwidgets.h b/core/app/views/leftsidebarwidgets.h index 42568f87ae..4639a734ab 100644 --- a/core/app/views/leftsidebarwidgets.h +++ b/core/app/views/leftsidebarwidgets.h @@ -1,425 +1,425 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2000-12-05 * Description : left sidebar widgets * * Copyright (C) 2009-2010 by Johannes Wienke * Copyright (C) 2010-2018 by Gilles Caulier * Copyright (C) 2014 by Mohamed_Anwer * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_LEFT_SIDE_BAR_WIDGETS_H #define DIGIKAM_LEFT_SIDE_BAR_WIDGETS_H // KDE includes #include // Local includes #include "digikam_config.h" #include "albummodel.h" #include "albummodificationhelper.h" #include "imagealbumfiltermodel.h" #include "searchmodificationhelper.h" #include "sidebarwidget.h" #include "imagefiltermodel.h" #include "albumlabelstreeview.h" #ifdef HAVE_MARBLE # include "gpssearchview.h" #endif // HAVE_MARBLE namespace Digikam { template class AlbumPointer; /** * SideBarWidget for the folder view. * * @author jwienke */ class AlbumFolderViewSideBarWidget : public SidebarWidget { Q_OBJECT public: explicit AlbumFolderViewSideBarWidget(QWidget* const parent, AlbumModel* const model, AlbumModificationHelper* const albumModificationHelper); virtual ~AlbumFolderViewSideBarWidget(); void setActive(bool active); void doLoadState(); void doSaveState(); void applySettings(); void changeAlbumFromHistory(QList album); const QIcon getIcon(); const QString getCaption(); AlbumPointer currentAlbum() const; public Q_SLOTS: void setCurrentAlbum(PAlbum* album); Q_SIGNALS: - void signalFindDuplicates(PAlbum*); + void signalFindDuplicates(PAlbum* album); private: class Private; Private* const d; }; // ----------------------------------------------------------------------------------------- /** * SideBarWidget for the tag view. * * @author jwienke */ class TagViewSideBarWidget : public SidebarWidget { Q_OBJECT public: explicit TagViewSideBarWidget(QWidget* const parent, TagModel* const model); virtual ~TagViewSideBarWidget(); void setActive(bool active); void doLoadState(); void doSaveState(); void applySettings(); void changeAlbumFromHistory(QList album); const QIcon getIcon(); const QString getCaption(); AlbumPointer currentAlbum() const; private: void setNoTagsAlbum(); public Q_SLOTS: void setCurrentAlbum(TAlbum* album); void slotOpenTagManager(); void slotToggleTagsSelection(int radioClicked); Q_SIGNALS: - void signalFindDuplicates(QList albums); + void signalFindDuplicates(const QList& albums); public: // Declared as public due to use by Private class Private; private: Private* const d; }; // ----------------------------------------------------------------------------------------- /** * SideBarWidget for the Labels. * * @author Mohamed_Anwer */ class LabelsSideBarWidget : public SidebarWidget { Q_OBJECT public: explicit LabelsSideBarWidget(QWidget* const parent); virtual ~LabelsSideBarWidget(); AlbumLabelsTreeView* labelsTree(); void setActive(bool active); void applySettings(); void changeAlbumFromHistory(QList album); void doLoadState(); void doSaveState(); const QIcon getIcon(); const QString getCaption(); QHash > selectedLabels(); private: class Private; Private* const d; }; // ----------------------------------------------------------------------------------------- /** * SideBarWidget for the date folder view. * * @author jwienke */ class DateFolderViewSideBarWidget : public SidebarWidget { Q_OBJECT public: explicit DateFolderViewSideBarWidget(QWidget* const parent, DateAlbumModel* const model, ImageAlbumFilterModel* const imageFilterModel); virtual ~DateFolderViewSideBarWidget(); void setActive(bool active); void doLoadState(); void doSaveState(); void applySettings(); void changeAlbumFromHistory(QList album); const QIcon getIcon(); const QString getCaption(); AlbumPointer currentAlbum() const; void gotoDate(const QDate& date); private: class Private; Private* const d; }; // ----------------------------------------------------------------------------------------- /** * SideBarWidget for the date folder view. * * @author jwienke */ class TimelineSideBarWidget : public SidebarWidget { Q_OBJECT public: explicit TimelineSideBarWidget(QWidget* const parent, SearchModel* const searchModel, SearchModificationHelper* const searchModificationHelper); virtual ~TimelineSideBarWidget(); void setActive(bool active); void doLoadState(); void doSaveState(); void applySettings(); void changeAlbumFromHistory(QList album); const QIcon getIcon(); const QString getCaption(); private Q_SLOTS: void slotInit(); void slotScrollBarValueChanged(int); void slotRefDateTimeChanged(); void slotScaleChanged(int); void slotTimeUnitChanged(int); void slotCursorPositionChanged(); void slotSelectionChanged(); void slotResetSelection(); void slotSaveSelection(); void slotUpdateCurrentDateSearchAlbum(); void slotAlbumSelected(Album*); void slotCheckAboutSelection(); private: class Private; Private* const d; }; // ----------------------------------------------------------------------------------------- /** * SideBarWidget for the search. * * @author jwienke */ class SearchSideBarWidget : public SidebarWidget { Q_OBJECT public: explicit SearchSideBarWidget(QWidget* const parent, SearchModel* const searchModel, SearchModificationHelper* const searchModificationHelper); virtual ~SearchSideBarWidget(); void setActive(bool active); void doLoadState(); void doSaveState(); void applySettings(); void changeAlbumFromHistory(QList album); const QIcon getIcon(); const QString getCaption(); void newKeywordSearch(); void newAdvancedSearch(); private: class Private; Private* const d; }; // ----------------------------------------------------------------------------------------- /** * SideBarWidget for the fuzzy search. * * @author jwienke */ class FuzzySearchSideBarWidget : public SidebarWidget { Q_OBJECT public: explicit FuzzySearchSideBarWidget(QWidget* const parent, SearchModel* const searchModel, SearchModificationHelper* const searchModificationHelper); virtual ~FuzzySearchSideBarWidget(); void setActive(bool active); void doLoadState(); void doSaveState(); void applySettings(); void changeAlbumFromHistory(QList album); const QIcon getIcon(); const QString getCaption(); void newDuplicatesSearch(PAlbum* album); - void newDuplicatesSearch(QList albums); - void newDuplicatesSearch(QList albums); + void newDuplicatesSearch(const QList& albums); + void newDuplicatesSearch(const QList& albums); void newSimilarSearch(const ImageInfo& imageInfo); Q_SIGNALS: void signalActive(bool); private: class Private; Private* const d; }; // ----------------------------------------------------------------------------------------- #ifdef HAVE_MARBLE /** * SideBarWidget for the gps search. * * @author jwienke */ class GPSSearchSideBarWidget : public SidebarWidget { Q_OBJECT public: explicit GPSSearchSideBarWidget(QWidget* const parent, SearchModel* const searchModel, SearchModificationHelper* const searchModificationHelper, ImageFilterModel* const imageFilterModel, QItemSelectionModel* const itemSelectionModel); virtual ~GPSSearchSideBarWidget(); void setActive(bool active); void doLoadState(); void doSaveState(); void applySettings(); void changeAlbumFromHistory(QList album); const QIcon getIcon(); const QString getCaption(); Q_SIGNALS: void signalMapSoloItems(const QList&, const QString&); private: class Private; Private* const d; }; #endif // HAVE_MARBLE // ----------------------------------------------------------------------------------------- /** * SideBarWidget for People * * @author Aditya Bhatt */ class PeopleSideBarWidget : public SidebarWidget { Q_OBJECT public: explicit PeopleSideBarWidget(QWidget* const parent, TagModel* const tagModel, SearchModificationHelper* const searchModificationHelper); virtual ~PeopleSideBarWidget(); void setActive(bool active); void doLoadState(); void doSaveState(); void applySettings(); void changeAlbumFromHistory(QList album); const QIcon getIcon(); const QString getCaption(); private Q_SLOTS: void slotInit(); void slotScanForFaces(); Q_SIGNALS: void requestFaceMode(bool on); - void signalFindDuplicates(QList); + void signalFindDuplicates(const QList& albums); private: class Private; Private* const d; }; } // namespace Digikam #endif // DIGIKAM_LEFT_SIDE_BAR_WIDGETS_H diff --git a/core/libs/album/albummanager.h b/core/libs/album/albummanager.h index 63823c9aeb..3f8029f8ba 100644 --- a/core/libs/album/albummanager.h +++ b/core/libs/album/albummanager.h @@ -1,913 +1,913 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2004-06-15 * Description : Albums manager interface. * * Copyright (C) 2004 by Renchi Raju * Copyright (C) 2006-2018 by Gilles Caulier * Copyright (C) 2006-2011 by Marcel Wiesweg * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ /** @file albummanager.h */ #ifndef DIGIKAM_ALBUM_MANAGER_H #define DIGIKAM_ALBUM_MANAGER_H // Qt includes #include #include #include #include #include // Local includes #include "album.h" #include "coredbalbuminfo.h" #include "dbengineparameters.h" #include "digikam_export.h" #include "imagelisterrecord.h" class QDate; namespace Digikam { class FAlbum; class CollectionLocation; class AlbumChangeset; class TagChangeset; class SearchChangeset; class CollectionImageChangeset; class ImageTagChangeset; /** * \class AlbumManager * * AlbumManager manages albums: does listing of albums and controls the lifetime of it. * For PAlbums and TAlbums, the listing is done by reading the db directly and * building the hierarchy of the albums. For DAlbums, since the listing takes * time, the work is delegated to a dbjob. Interested frontend entities can * connect to the albummanager to receive notifications of new Albums, when * Albums are deleted and when the current album is changed. * * Additional operations are provided for: creating/deleting/rename Albums, * updating icons and moving Albums. * */ class DIGIKAM_EXPORT AlbumManager : public QObject { Q_OBJECT public: /** * A convenience function to get the instance of the AlbumManager */ static AlbumManager* instance(); /** @name Library path And Scanning */ //@{ /** * Initialize. Informs the user about failures. * Returns true on success, false on failure. * A return value of false during startup indicates termination of the program * (user is informed) */ bool setDatabase(const DbEngineParameters& params, bool priority, const QString& suggestedAlbumRoot = QString()); /** * Some checks for settings done in first run wizard in case of QSlite Database. */ static void checkDatabaseDirsAfterFirstRun(const QString& dbPath, const QString& albumPath); /** * Sets new database when chosen by the user in setup. * Handles user notification about problems. * Call this instead of setDatabase when digiKam is up and running. */ void changeDatabase(const DbEngineParameters& params); /** * Stop ongoing operations, prepare for application shutdown */ void cleanUp(); /** * Checks if the given database path is equal to the current one */ bool databaseEqual(const DbEngineParameters& parameters) const; /** * starts scanning the libraryPath and listing the albums. If the * libraryPath has not changed since the last scan, then nothing happens * @see setLibraryPath * @see refresh */ void startScan(); /** * This is similar to startScan, except that it assumes you have run * startScan at least once. It checks the database to see if any new albums * have been added and updates them accordingly. Use this when a change in the * filesystem is detected (but the album library path hasn't changed) * @see startScan */ void refresh(); /** * Ensures that valid item counts for physical and tag albums are available */ void prepareItemCounts(); //@} /** @name List of Albums and current Album */ //@{ /** * @return a list of all PAlbums */ AlbumList allPAlbums() const; /** * @return a list of all TAlbums */ AlbumList allTAlbums() const; /** * @return a list of all SAlbums */ AlbumList allSAlbums() const; /** * @return a list of all DAlbums */ AlbumList allDAlbums() const; /** * @return a list of all FAlbums */ AlbumList allFAlbums() const; /** * set current album to @p albums. It's similar to setCurrentAlbum, * but supports multiple selected albums */ void setCurrentAlbums(QList albums); /** * @returns current albums, previously set up by setCurrentAlbums */ AlbumList currentAlbums() const; /** * @returns the current PAlbum or null if no one is selected */ PAlbum* currentPAlbum() const; /** * @returns the current TAlbum or null if no one is selected */ QList currentTAlbums() const; /** * @returns the current FAlbum or null if no one is selected */ FAlbum* currentFAlbum() const; //@} /** @name Finding Albums */ //@{ /** * Given a complete file url (kde url with file protocol), it will try to find * a PAlbum corresponding to it. * \warning This should not be used, unless really necessary * @return PAlbum corresponding to supplied @p url * @param url the url we need to check */ PAlbum* findPAlbum(const QUrl& url) const; /** * @return a PAlbum with given ID * @param id the id for the PAlbum */ PAlbum* findPAlbum(int id) const; /** * @return a TAlbum with given ID * @param id the id for the TAlbum */ TAlbum* findTAlbum(int id) const; /** * @return a SAlbum with given ID * @param id the id for the SAlbum */ SAlbum* findSAlbum(int id) const; /** * @return a DAlbum with given ID * @param id the id for the DAlbum */ DAlbum* findDAlbum(int id) const; /** * @return a FAlbum with given name * @param name the name for the FAlbum (name of the person which the FAlbum corresponds to */ FAlbum* findFAlbum(const QString& name) const; /** * @return a Album with the given globalID * @param gid the global id for the album */ Album* findAlbum(int gid) const; /** * @return a Album with the given type and id * @param id the id for the album (not the global id) */ Album* findAlbum(Album::Type type, int id) const; /** * @return a TAlbum with given tag path, or 0 if not found * @param tagPath the tag path ("People/Friend/John") */ TAlbum* findTAlbum(const QString& tagPath) const; /** * @return a SAlbum with given name, or 0 if not found * @param name the name of the search */ SAlbum* findSAlbum(const QString& name) const; /** * @return SAlbums with given type, empty list if not found * @param searchType the type of the search */ QList< SAlbum* > findSAlbumsBySearchType(int searchType) const; //@} /** @name Operations on PAlbum */ //@{ /** * Create a new PAlbum with supplied properties as a child of the parent * This is equivalent to creating a new folder on the disk with supplied * name in the parent's folder path. Also the supplied attributes are written * out to the database * \note the signalAlbumAdded will be fired before this function returns. Its * recommended to connect to that signal to get notification of new album added * @return the newly created PAlbum or 0 if it fails * @param parent The parent album under which to create the new Album. * Parent must not be root. Otherwise, use the other variants of this method. * If parent is root, the albumRootPath must be supplied. * @param name the name of the new album * @param caption the caption for the new album * @param date the date for the new album * @param errMsg this will contain the error message describing why the * operation failed */ PAlbum* createPAlbum(PAlbum* parent, const QString& name, const QString& caption, const QDate& date, const QString& category, QString& errMsg); /** * Overloaded method. Here you can supply an albumRootPath which must * correspond to an available collection location. */ PAlbum* createPAlbum(const QString& albumRootPath, const QString& name, const QString& caption, const QDate& date, const QString& category, QString& errMsg); /** * Overloaded method. Here you can supply a collection location (which * must be available). * * @param location the collection for the new album */ PAlbum* createPAlbum(const CollectionLocation& location, const QString& name, const QString& caption, const QDate& date, const QString& category, QString& errMsg); /** * Renames a PAlbum. This is equivalent to actually renaming the corresponding * folder on the disk. * @return true if the operation succeeds, false otherwise * @param album the Album which should be renamed * @param newName the new name for the album * @param errMsg this will contain the error message describing why the * operation failed */ bool renamePAlbum(PAlbum* album, const QString& newName, QString& errMsg); /** * Update the icon for an album. The @p icon is the name (and not full path) * of the file in the album * @return true if the operation succeeds, false otherwise * @param album the album for which icon should be changed * @param iconID the filename of the new icon * @param errMsg if the operation fails, this will contain the error message * describing why the operation failed */ bool updatePAlbumIcon(PAlbum* album, qlonglong iconID, QString& errMsg); /** * Returns the id of the item with the given filename in * the given PAlbum. * @param album The albumId in which we search the item. * @param fileName The name of the item file. * @return The item id or -1 if not existent. */ qlonglong getItemFromAlbum(PAlbum* album, const QString& fileName); //@} /** * @return A hash with the titles for all album IDs. */ QHash albumTitles() const; /** @name Operations on TAlbum */ //@{ /** * Create a new TAlbum with supplied properties as a child of the parent * The tag is added to the database * \note the signalAlbumAdded will be fired before this function returns. Its * recommended to connect to that signal to get notification of new album added * @return the newly created TAlbum or 0 if it fails * @param parent the parent album under which to create the new Album * @param name the name of the new album * @param iconkde the iconkde for the new album (this is a filename which * kde iconloader can load up * @param errMsg this will contain the error message describing why the * operation failed */ TAlbum* createTAlbum(TAlbum* parent, const QString& name, const QString& iconkde, QString& errMsg); /** * A list of tag paths is supplied. * If no corresponding TAlbum exists, a new one will be created. * @param tagPaths A list of tag paths * @returns A list of all TAlbums for the list (already existing or newly created) */ AlbumList findOrCreateTAlbums(const QStringList& tagPaths); /** * Delete a TAlbum. * The tag is removed from the database * \note the signalAlbumDeleted will be fired before this function returns. Its * recommended to connect to that signal to get notification of album deletes * @return true if the operation succeeds or false otherwise * @param album the TAlbum to delete * @param errMsg this will contain the error message describing why the * @param askUser ask user to write metadata to images * operation failed */ bool deleteTAlbum(TAlbum* album, QString& errMsg, bool askUser = true); /** * Renames a TAlbum. * This updates the tag name in the database * @return true if the operation succeeds, false otherwise * @param album the Album which should be renamed * @param name the new name for the album * @param errMsg this will contain the error message describing why the * operation failed */ bool renameTAlbum(TAlbum* album, const QString& name, QString& errMsg); /** * Move a TAlbum to a new parent. * This updates the tag parent ID in the database * @return true if the operation succeeds, false otherwise * @param album the Album which should be moved * @param newParent the Parent Album to which album should be moved * @param errMsg this will contain the error message describing why the * operation failed */ bool moveTAlbum(TAlbum* album, TAlbum* newParent, QString& errMsg); /** * Merge a TAlbum to a TAlbum. * This updates the image tags in the database * @return true if the operation succeeds, false otherwise * @param album the Album which should be merged * @param destAlbum the Album to which album should be merged * @param dialog show dialog to ask the user if he wants to merge * @param errMsg this will contain the error message describing why the * operation failed */ bool mergeTAlbum(TAlbum* album, TAlbum* destAlbum, bool dialog, QString& errMsg); /** * Update the icon for a TAlbum. * @return true if the operation succeeds, false otherwise * @param album the album for which icon should be changed * @param iconKDE a simple filename which can be loaded by KIconLoader * @param iconID id of the icon image file * @param errMsg this will contain the error message describing why the * operation failed * \note if iconKDE is not empty then iconID is used. So if you want to set * the icon to a file which can be loaded by KIconLoader, pass it in as * iconKDE. otherwise pass a null QString to iconKDE and set iconID */ bool updateTAlbumIcon(TAlbum* album, const QString& iconKDE, qlonglong iconID, QString& errMsg); /** * Get a list of recently assigned tags (only last 6 tags are listed) * @return the list of recently assigned TAlbums * @param includeInternal include internal tags in the returned list, or skip them */ AlbumList getRecentlyAssignedTags(bool includeInternal = false) const; /** * @return A list with the tag paths for a list of tag IDs. * @param tagIDs list of tag album IDs * @param leadingSlash if true return tags with a leading slash * @param includeInternal include internal tags in the returned list, or skip them */ QStringList tagPaths(const QList& tagIDs, bool leadingSlash=true, bool includeInternal = false) const; /** * @return A list with the tag names for a list of tag IDs. * @param tagIDs list of tag album IDs */ QStringList tagNames(const QList& tagIDs, bool includeInternal = false) const; /** * @return A hash with the tag paths for all tag IDs. */ QHash tagPaths(bool leadingSlash=true, bool includeInternal = false) const; /** * @return A hash with the tag names for all tag IDs. */ QHash tagNames(bool includeInternal = false) const; /** * Returns a list of TAlbums which have the given property, * or the given property/value combination. */ AlbumList findTagsWithProperty(const QString& property); AlbumList findTagsWithProperty(const QString& property, const QString& value); /** * TODO */ QList subTags(int tagId, bool recursive = false); //@} /** @name Operations on SAlbum */ //@{ /** * Create a new SAlbum with supplied url. If an existing SAlbum with same name * exists this function will return a pointer to that album, instead of creating * a new one. A newly created search album is added to the database. For an * existing SAlbum, the url is updated and written out to the database * \note the signalAlbumAdded will be fired before this function returns. Its * recommended to connect to that signal to get notification of new album added * @return the newly created SAlbum or an existing SAlbum with same name * @param name name for the new search * @param type the type of the search * @param query search query to use */ SAlbum* createSAlbum(const QString& name, DatabaseSearch::Type type, const QString& query); /** * Update the url for a SAlbum * @return true if the operation succeeds, false otherwise * @param album the album to update * @param changedQuery the new query data of the album * @param changedName a new name, or null to keep the current name * @param type a new type, or UndefinedType to keep the current type */ bool updateSAlbum(SAlbum* album, const QString& changedQuery, const QString& changedName = QString(), DatabaseSearch::Type type = DatabaseSearch::UndefinedType); /** * Delete a SAlbum from the database * \note the signalAlbumDeleted will be fired before this function returns. Its * recommended to connect to that signal to get notification of album deletes * @return true if the operation succeeds, false otherwise * @param album the album to delete */ bool deleteSAlbum(SAlbum* album); //@} /** @name Operations on TAlbum */ //@{ /** * Create a new FAlbum with supplied properties as a child of the parent * The person is added to the database * \note the signalAlbumAdded will be fired before this function returns. Its * recommended to connect to that signal to get notification of new album added * @return the newly created FAlbum or 0 if it fails * @param parent the parent album under which to create the new FAlbum * @param name the name of the new album * @param iconkde the iconkde for the new album (this is a filename which * kde iconloader can load up * @param errMsg this will contain the error message describing why the * operation failed */ FAlbum* createFAlbum(FAlbum* parent, const QString& name, const QString& iconkde, QString& errMsg); /** * Delete a FAlbum. * The person is removed from the database * \note the signalAlbumDeleted will be fired before this function returns. Its * recommended to connect to that signal to get notification of album deletes * @return true if the operation succeeds or false otherwise * @param album the FAlbum to delete * @param errMsg this will contain the error message describing why the * operation failed */ bool deleteFAlbum(FAlbum* album, QString& errMsg); /** * Renames a FAlbum. * This updates the person name in the database * @return true if the operation succeeds, false otherwise * @param album the Album which should be renamed * @param name the new name for the album * @param errMsg this will contain the error message describing why the * operation failed */ bool renameFAlbum(FAlbum* album, const QString& name, QString& errMsg); /** * Update the icon for a FAlbum. * @return true if the operation succeeds, false otherwise * @param album the album for which icon should be changed * @param iconKDE a simple filename which can be loaded by KIconLoader * @param iconID id of the icon image file * @param errMsg this will contain the error message describing why the * operation failed * \note if iconKDE is not empty then iconID is used. So if you want to set * the icon to a file which can be loaded by KIconLoader, pass it in as * iconKDE. otherwise pass a null QString to iconKDE and set iconID */ bool updateFAlbumIcon(FAlbum* album, const QString& iconKDE, qlonglong iconID, QString& errMsg); /** * @return A list with the name paths for a list of tag names. * @param names list of tag album names * @param leadingSlash if true return name paths with a leading slash */ QStringList namePaths(const QList& tagNames, bool leadingSlash=true) const; //@} /** @name Accessors to counting maps */ //@{ /** * Returns the latest count for PAlbums as also emitted via * signalPAlbumsDirty. * * @return count map for PAlbums */ QMap getPAlbumsCount() const; /** * Returns the latest count for TAlbums as also emitted via * signalTAlbumsDirty. * * @return count map for TAlbums */ QMap getTAlbumsCount() const; /** * Returns the latest count for DAlbums as also emitted via * signalDAlbumsDirty. * * @return count map for DAlbums */ QMap getDAlbumsCount() const; /** * Returns the latest count for faces as also emitted via * signalFaceCountsDirty. * * @return count map for faces (confirmed and unconfirmed combined) */ QMap getFaceCount() const; /** * Returns if the given album is currently being moved, that is, * if this album is in between signalAlbumAboutToBeMoved and * signalAlbumMoved. In this case, you can preserve state of such an album * because the object is guaranteed not to be deleted, even if * signalAlbumAboutToBeDeleted is emitted. */ bool isMovingAlbum(Album* album) const; bool isShowingOnlyAvailableAlbums() const; void setShowOnlyAvailableAlbums(bool onlyAvailable); void removeWatchedPAlbums(const PAlbum* const album); void addFakeConnection(); void removeFakeConnection(); //@} Q_SIGNALS: /// An album is about to be added to the given parent (0 if album is root) /// after the item given by prev (prev is 0 if parent has no children yet) void signalAlbumAboutToBeAdded(Album* album, Album* parent, Album* prev); /// The album has been added. void signalAlbumAdded(Album* album); /// The album is about to be deleted, but is still fully valid. void signalAlbumAboutToBeDeleted(Album* album); /// The album is deleted, but the object can still be accessed. void signalAlbumDeleted(Album* album); /// The album is deleted, the object can no longer be accessed. /// For identification purposes, the former album pointer is passed. void signalAlbumHasBeenDeleted(quintptr); void signalAlbumsCleared(); - void signalAlbumCurrentChanged(QList album); + void signalAlbumCurrentChanged(const QList& albums); void signalAllAlbumsLoaded(); void signalAllDAlbumsLoaded(); void signalAlbumIconChanged(Album* album); void signalAlbumRenamed(Album* album); void signalAlbumNewPath(Album* album); void signalSearchUpdated(SAlbum* album); /// Indicates that an album is about to be moved. Signals for deleting and adding will be /// sent afterwards, but the album object is guaranteed not to be deleted until after signalAlbumMoved. void signalAlbumAboutToBeMoved(Album* album); /// Emitted when the album is moved to its new parent. After signalAlbumAboutToBeMoved, /// all four signals for first deleting and then adding will have been sent. void signalAlbumMoved(Album* album); void signalPAlbumsDirty(const QMap&); void signalTAlbumsDirty(const QMap&); void signalDAlbumsDirty(const QMap&); void signalFaceCountsDirty(const QMap&); void signalDatesMapDirty(const QMap&); void signalTagPropertiesChanged(TAlbum* album); void signalAlbumsUpdated(int type); void signalUpdateDuplicatesAlbums(const QList& modifiedAlbums, const QList& deletedImages); // Signals a change in this property. Please note that affected albums may appear or disappear after this signal has been emitted. void signalShowOnlyAvailableAlbumsChanged(bool showsOnlyAvailableAlbums); private Q_SLOTS: void slotDatesJobResult(); void slotDatesJobData(const QMap& datesStatMap); void slotAlbumsJobResult(); void slotAlbumsJobData(const QMap& albumsStatMap); void slotTagsJobResult(); void slotTagsJobData(const QMap& tagsStatMap); void slotPeopleJobResult(); void slotPeopleJobData(const QMap >& facesStatMap); void slotCollectionLocationStatusChanged(const CollectionLocation&, int); void slotCollectionLocationPropertiesChanged(const CollectionLocation& location); void slotAlbumChange(const AlbumChangeset& changeset); void slotTagChange(const TagChangeset& changeset); void slotSearchChange(const SearchChangeset& changeset); void slotCollectionImageChange(const CollectionImageChangeset& changeset); void slotImageTagChange(const ImageTagChangeset& changeset); void slotImagesDeleted(const QList& imageIds); /** * Scan albums directly from database and creates new PAlbums * It only creates those PAlbums which haven't already been * created. */ void scanPAlbums(); void updateChangedPAlbums(); /** * Scan tags directly from database and creates new TAlbums * It only creates those TAlbums which haven't already been * created. */ void scanTAlbums(); /** * Scan searches directly from database and creates new SAlbums * It only creates those SAlbums which haven't already been * created. */ void scanSAlbums(); /** * Scan dates from the database (via IOSlave) and * updates the DAlbums. */ void scanDAlbumsScheduled(); void scanDAlbums(); void getAlbumItemsCount(); void getTagItemsCount(); void tagItemsCount(); void personItemsCount(); private: friend class AlbumManagerCreator; AlbumManager(); ~AlbumManager(); /** * Checks whether an Album has a direct child with the given name. * * @param parent album to check children for * @param title title to search for * @return true if there is a child with name, else * false */ void askUserForWriteChangedTAlbumToFiles(TAlbum* const album); void askUserForWriteChangedTAlbumToFiles(const QList& imageIds); bool hasDirectChildAlbumWithTitle(Album* parent, const QString& title); bool handleCollectionStatusChange(const CollectionLocation& location, int oldStatus); void insertPAlbum(PAlbum* album, PAlbum* parent); void removePAlbum(PAlbum* album); void insertTAlbum(TAlbum* album, TAlbum* parent); void removeTAlbum(TAlbum* album); void updateAlbumPathHash(); void notifyAlbumDeletion(Album* album); void addAlbumRoot(const CollectionLocation& location); void removeAlbumRoot(const CollectionLocation& location); void addGuardedPointer(Album* a, Album** pointer); void removeGuardedPointer(Album* a, Album** pointer); void changeGuardedPointer(Album* oldAlbum, Album* a, Album** pointer); void invalidateGuardedPointers(Album* album); static AlbumManager* internalInstance; public: // Declared public because it used in ChangingDB class. class Private; private: Private* const d; template friend class AlbumPointer; friend class Album; }; // ------------------------------------------------------------------------------------ /** * You can use AlbumPointer to store a guarded pointer to Album * or one of the subclasses (use template parameter). * The pointer will be set to 0 when the album object is deleted. */ template class AlbumPointer { public: AlbumPointer() : album(0) { } AlbumPointer(T* const a) // krazy:exclude=explicit : album(a) { AlbumManager::instance()->addGuardedPointer(album, &album); } AlbumPointer(const AlbumPointer& p) // krazy:exclude=explicit : album(p.album) { AlbumManager::instance()->addGuardedPointer(album, &album); } ~AlbumPointer() { AlbumManager::instance()->removeGuardedPointer(album, &album); } AlbumPointer& operator=(T* const a) { Album* const oldAlbum = album; album = a; AlbumManager::instance()->changeGuardedPointer(oldAlbum, album, &album); return *this; } AlbumPointer& operator=(const AlbumPointer& p) { Album* const oldAlbum = album; album = p.album; AlbumManager::instance()->changeGuardedPointer(oldAlbum, album, &album); return *this; } T* operator->() const { return static_cast(const_cast(album)); } T& operator*() const { return *static_cast(const_cast(album)); } operator T* () const { return static_cast(const_cast(album)); } bool operator!() const { return !album; } private: friend class AlbumManager; Album* album; }; // ------------------------------------------------------------------------------------ template class AlbumPointerList : public QList > { public: AlbumPointerList() { } explicit AlbumPointerList(const AlbumPointerList& list) : QList >(list) { } explicit AlbumPointerList(const QList& list) { operator=(list); } AlbumPointerList& operator=(const AlbumPointerList& list) { return QList >::operator=(list); } AlbumPointerList& operator=(const QList& list) { foreach(T* const t, list) { this->append(AlbumPointer(t)); } return *this; } }; } // namespace Digikam Q_DECLARE_METATYPE(Digikam::AlbumPointer<>) Q_DECLARE_METATYPE(Digikam::AlbumPointer) Q_DECLARE_METATYPE(Digikam::AlbumPointer) Q_DECLARE_METATYPE(Digikam::AlbumPointer) Q_DECLARE_METATYPE(Digikam::AlbumPointer) Q_DECLARE_METATYPE(QList) #endif // DIGIKAM_ALBUM_MANAGER_H diff --git a/core/libs/tags/tagfolderview.h b/core/libs/tags/tagfolderview.h index 5f6f4e333b..f68f696c50 100644 --- a/core/libs/tags/tagfolderview.h +++ b/core/libs/tags/tagfolderview.h @@ -1,151 +1,151 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2005-03-22 * Description : tags folder view. * * Copyright (C) 2005-2006 by Joern Ahrens * Copyright (C) 2006-2018 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_TAG_FOLDER_VIEW_H #define DIGIKAM_TAG_FOLDER_VIEW_H // Qt includes #include // Local includes #include "albumtreeview.h" namespace Digikam { class ContextMenuHelper; class TagFolderView: public TagTreeView { Q_OBJECT public: /** * Constructor. * * @param parent parent for Qt's parent child mechanism * @param model tag model to display */ TagFolderView(QWidget* const parent, Digikam::TagModel* const model); /** * Destructor. */ virtual ~TagFolderView(); /** * Define whether to show the "find duplicate" action in context menus * or not. * * @param show if true the action to find duplicate images in * the tag album is displayed */ void setShowFindDuplicateAction(bool show); /** * Define whether to show the "Delete People Tags" action in context menus * or not. * * @param show if true the action to delete people tags in * the tag album is displayed */ void setShowDeleteFaceTagsAction(bool show); Q_SIGNALS: - void signalFindDuplicates(QList); + void signalFindDuplicates(const QList& albums); protected: QString contextMenuTitle() const; /** * Hook method to add custom actions to the generated context menu. * * The default implementation adds actions to reset the tag icon and to * find duplicates in a tag album. If you want to use these actions, * remember to call this class' implementation of this method and * the handleCustomContextMenuAction in your derived class. * * @param cmh helper object to create the context menu * @param album tag on which the context menu will be created. May be null if * it is requested on no tag entry */ virtual void addCustomContextMenuActions(ContextMenuHelper& cmh, Album* album); /** * Hook method to handle the custom context menu actions that were added * with addCustomContextMenuActions. * * @param action the action that was chosen by the user, may be null if none * of the custom actions were selected * @param album the tag on which the context menu was requested. May be null * if there was no */ virtual void handleCustomContextMenuAction(QAction* action, AlbumPointer album); /** * Reimplement contextMenuEvent from AbstractAlbumTree to support multiple * selection * * @param event context menu event triggered by right click */ void contextMenuEvent(QContextMenuEvent* event); /** * Implementation of AddCustomContextMenuActions(see above) that handle * multiple selection. If only one element is selected, only * AddCustomContextMenuActions is called * * @param cmh - helper object to create context menu * @param albums - vector of selected albums to be used on menu actions */ virtual void setContexMenuItems(ContextMenuHelper& cmh, QList< TAlbum* > albums); private Q_SLOTS: void slotTagNewFromABCMenu(const QString& personName); /** * @brief slotExpandNode - expands recursively selected nodes */ void slotExpandNode(); /** * @brief slotCollapseNode - collapse recursively selected nodes */ void slotCollapseNode(); private: class Private; Private* const d; }; } // namespace Digikam #endif // DIGIKAM_TAG_FOLDER_VIEW_H diff --git a/core/utilities/fuzzysearch/findduplicatesview.cpp b/core/utilities/fuzzysearch/findduplicatesview.cpp index d8dc571d5a..f8ba866787 100644 --- a/core/utilities/fuzzysearch/findduplicatesview.cpp +++ b/core/utilities/fuzzysearch/findduplicatesview.cpp @@ -1,555 +1,555 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2008-05-19 * Description : Find Duplicates View. * * Copyright (C) 2016-2017 by Mario Frank * Copyright (C) 2008-2018 by Gilles Caulier * Copyright (C) 2008-2012 by Marcel Wiesweg * Copyright (C) 2009-2012 by Andi Clemens * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "findduplicatesview.h" // Qt includes #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "digikam_debug.h" #include "album.h" #include "coredb.h" #include "albummanager.h" #include "albumselectors.h" #include "coredbaccess.h" #include "coredbbackend.h" #include "findduplicatesalbum.h" #include "findduplicatesalbumitem.h" #include "duplicatesfinder.h" #include "fingerprintsgenerator.h" #include "applicationsettings.h" #include "haariface.h" #include "squeezedcombobox.h" #include "drangebox.h" namespace Digikam { class FindDuplicatesView::Private { public: explicit Private() { includeAlbumsLabel = 0; listView = 0; scanDuplicatesBtn = 0; updateFingerPrtBtn = 0; progressItem = 0; similarityLabel = 0; similarityRange = 0; restrictResultsLabel = 0; albumTagRelationLabel = 0; searchResultRestriction = 0; albumTagRelation = 0; albumSelectors = 0; settings = 0; active = false; } QLabel* includeAlbumsLabel; QLabel* similarityLabel; QLabel* restrictResultsLabel; QLabel* albumTagRelationLabel; DIntRangeBox* similarityRange; SqueezedComboBox* searchResultRestriction; SqueezedComboBox* albumTagRelation; QPushButton* scanDuplicatesBtn; QPushButton* updateFingerPrtBtn; FindDuplicatesAlbum* listView; ProgressItem* progressItem; AlbumSelectors* albumSelectors; ApplicationSettings* settings; bool active; }; FindDuplicatesView::FindDuplicatesView(QWidget* const parent) : QWidget(parent), d(new Private) { setAttribute(Qt::WA_DeleteOnClose); d->settings = ApplicationSettings::instance(); const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); // --------------------------------------------------------------- d->listView = new FindDuplicatesAlbum(); d->listView->setSortingEnabled(false); d->updateFingerPrtBtn = new QPushButton(i18n("Update fingerprints")); d->updateFingerPrtBtn->setIcon(QIcon::fromTheme(QLatin1String("run-build"))); d->updateFingerPrtBtn->setWhatsThis(i18n("Use this button to update all image fingerprints.")); d->scanDuplicatesBtn = new QPushButton(i18n("Find duplicates")); d->scanDuplicatesBtn->setIcon(QIcon::fromTheme(QLatin1String("edit-find"))); d->scanDuplicatesBtn->setWhatsThis(i18n("Use this button to scan the selected albums for " "duplicate items.")); // --------------------------------------------------------------- d->albumSelectors = new AlbumSelectors(i18nc("@label", "Search in:"), QLatin1String("Find Duplicates View")); // --------------------------------------------------------------- d->similarityRange = new DIntRangeBox(); d->similarityRange->setSuffix(QLatin1String("%")); if (d->settings) { d->similarityRange->setRange(d->settings->getMinimumSimilarityBound(), 100); d->similarityRange->setInterval(d->settings->getDuplicatesSearchLastMinSimilarity(), d->settings->getDuplicatesSearchLastMaxSimilarity()); } else { d->similarityRange->setRange(40, 100); d->similarityRange->setInterval(40, 100); } d->similarityLabel = new QLabel(i18n("Similarity range:")); d->similarityLabel->setBuddy(d->similarityRange); d->restrictResultsLabel = new QLabel(i18n("Restriction:")); d->restrictResultsLabel->setBuddy(d->searchResultRestriction); d->searchResultRestriction = new SqueezedComboBox(); d->searchResultRestriction->addSqueezedItem(i18nc("@label:listbox", "None"), HaarIface::DuplicatesSearchRestrictions::None); d->searchResultRestriction->addSqueezedItem(i18nc("@label:listbox", "Restrict to reference album"), HaarIface::DuplicatesSearchRestrictions::SameAlbum); d->searchResultRestriction->addSqueezedItem(i18nc("@label:listbox", "Exclude reference album"), HaarIface::DuplicatesSearchRestrictions::DifferentAlbum); d->searchResultRestriction->setToolTip(i18n("Use this option to restrict the duplicate search " "with some criteria, as to limit search to the album " "of reference image, or to exclude the album of " "reference image of the search.")); // Load the last choice from application settings. HaarIface::DuplicatesSearchRestrictions restrictions = d->settings ? (HaarIface::DuplicatesSearchRestrictions) d->settings->getDuplicatesSearchRestrictions() : HaarIface::DuplicatesSearchRestrictions::None; d->searchResultRestriction->setCurrentIndex(d->searchResultRestriction->findData(restrictions)); d->albumTagRelationLabel = new QLabel(i18n("Restrict to:")); d->albumTagRelationLabel->setBuddy(d->albumTagRelation); d->albumTagRelation = new SqueezedComboBox(); d->albumTagRelation->addSqueezedItem(i18nc("@label:listbox", "Only selected tab") , HaarIface::AlbumTagRelation::NoMix); d->albumTagRelation->addSqueezedItem(i18nc("@label:listbox", "One of"), HaarIface::AlbumTagRelation::Union); d->albumTagRelation->addSqueezedItem(i18nc("@label:listbox", "Both"), HaarIface::AlbumTagRelation::Intersection); d->albumTagRelation->addSqueezedItem(i18nc("@label:listbox", "Albums but not tags"), HaarIface::AlbumTagRelation::AlbumExclusive); d->albumTagRelation->addSqueezedItem(i18nc("@label:listbox", "Tags but not albums"), HaarIface::AlbumTagRelation::TagExclusive); d->albumTagRelation->setCurrentIndex(ApplicationSettings::instance()->getDuplicatesAlbumTagRelation()); d->albumTagRelation->setToolTip(i18n("Use this option to decide about the relation of the selected albums and tags.
" "One of means that the images are either in the selected albums or tags.
" "Both means that the images are both in the selected albums and tags.
" "Albums but not tags means that images must be in the selected albums but not tags.
" "Tags but not albums means that images must be in the selected tags but not albums.
" "Only selected tab means that only the selected tab is used.")); // Load the last choice from application settings. HaarIface::AlbumTagRelation relation = d->settings ? (HaarIface::AlbumTagRelation) d->settings->getDuplicatesAlbumTagRelation() : HaarIface::AlbumTagRelation::NoMix; d->albumTagRelation->setCurrentIndex(d->albumTagRelation->findData(relation)); // --------------------------------------------------------------- QGridLayout* const mainLayout = new QGridLayout(); mainLayout->addWidget(d->listView, 0, 0, 1, -1); mainLayout->addWidget(d->albumTagRelationLabel, 1, 0, 1, 2); mainLayout->addWidget(d->albumTagRelation, 1, 2, 1, -1); mainLayout->addWidget(d->albumSelectors, 2, 0, 1, -1); mainLayout->addWidget(d->similarityLabel, 3, 0, 1, 1); mainLayout->addWidget(d->similarityRange, 3, 2, 1, 1); mainLayout->addWidget(d->restrictResultsLabel, 4, 0, 1, 2); mainLayout->addWidget(d->searchResultRestriction, 4, 2, 1, -1); mainLayout->addWidget(d->updateFingerPrtBtn, 5, 0, 1, -1); mainLayout->addWidget(d->scanDuplicatesBtn, 6, 0, 1, -1); mainLayout->setRowStretch(0, 10); mainLayout->setColumnStretch(2, 10); mainLayout->setContentsMargins(spacing, spacing, spacing, spacing); mainLayout->setSpacing(spacing); setLayout(mainLayout); // --------------------------------------------------------------- connect(d->updateFingerPrtBtn, SIGNAL(clicked()), this, SLOT(slotUpdateFingerPrints())); connect(d->scanDuplicatesBtn, SIGNAL(clicked()), this, SLOT(slotFindDuplicates())); connect(d->listView, SIGNAL(itemSelectionChanged()), this, SLOT(slotDuplicatesAlbumActived())); connect(d->albumSelectors, SIGNAL(signalSelectionChanged()), this, SLOT(slotCheckForValidSettings())); connect(AlbumManager::instance(), SIGNAL(signalAllAlbumsLoaded()), this, SLOT(populateTreeView())); connect(AlbumManager::instance(), SIGNAL(signalAllAlbumsLoaded()), this, SLOT(initAlbumUpdateConnections())); connect(d->settings, SIGNAL(setupChanged()), this, SLOT(slotApplicationSettingsChanged())); } FindDuplicatesView::~FindDuplicatesView() { d->albumSelectors->saveState(); delete d; } void FindDuplicatesView::initAlbumUpdateConnections() { connect(AlbumManager::instance(), SIGNAL(signalAlbumAdded(Album*)), this, SLOT(slotAlbumAdded(Album*))); connect(AlbumManager::instance(), SIGNAL(signalAlbumDeleted(Album*)), this, SLOT(slotAlbumDeleted(Album*))); connect(AlbumManager::instance(), SIGNAL(signalSearchUpdated(SAlbum*)), this, SLOT(slotSearchUpdated(SAlbum*))); connect(AlbumManager::instance(), SIGNAL(signalAlbumsCleared()), this, SLOT(slotClear())); connect(AlbumManager::instance(),SIGNAL(signalUpdateDuplicatesAlbums(QList,QList)), this,SLOT(slotUpdateDuplicates(QList,QList))); } void FindDuplicatesView::setActive(bool val) { d->active = val; } void FindDuplicatesView::populateTreeView() { const AlbumList& aList = AlbumManager::instance()->allSAlbums(); for (AlbumList::const_iterator it = aList.constBegin() ; it != aList.constEnd() ; ++it) { SAlbum* const salbum = dynamic_cast(*it); if (salbum && salbum->isDuplicatesSearch() && !salbum->extraData(this)) { FindDuplicatesAlbumItem* const item = new FindDuplicatesAlbumItem(d->listView, salbum); salbum->setExtraData(this, item); } } d->listView->setSortingEnabled(true); d->listView->sortByColumn(1, Qt::DescendingOrder); d->listView->resizeColumnToContents(0); d->albumSelectors->loadState(); d->listView->selectFirstItem(); } QList FindDuplicatesView::currentFindDuplicatesAlbums() const { QList selectedItems = d->listView->selectedItems(); if (selectedItems.isEmpty()) { QTreeWidgetItem* const item = d->listView->firstItem(); if (item) { selectedItems << item; } } QList albumList; foreach(QTreeWidgetItem* const item, selectedItems) { FindDuplicatesAlbumItem* const albumItem = dynamic_cast(item); if (albumItem) { albumList << albumItem->album(); } } return albumList; } void FindDuplicatesView::slotAlbumAdded(Album* a) { if (!a || a->type() != Album::SEARCH) { return; } SAlbum* const salbum = static_cast(a); if (!salbum->isDuplicatesSearch()) { return; } if (!d->active) { qCDebug(DIGIKAM_GENERAL_LOG) << "Duplicates view is not active, returning"; return; } if (!salbum->extraData(this)) { FindDuplicatesAlbumItem* const item = new FindDuplicatesAlbumItem(d->listView, salbum); salbum->setExtraData(this, item); } d->similarityRange->setInterval(d->settings->getDuplicatesSearchLastMinSimilarity(), d->settings->getDuplicatesSearchLastMaxSimilarity()); } void FindDuplicatesView::slotAlbumDeleted(Album* a) { if (!a || a->type() != Album::SEARCH) { return; } SAlbum* const album = static_cast(a); FindDuplicatesAlbumItem* const item = static_cast(album->extraData(this)); if (item) { a->removeExtraData(this); delete item; } d->similarityRange->setInterval(d->settings->getDuplicatesSearchLastMinSimilarity(), d->settings->getDuplicatesSearchLastMaxSimilarity()); } void FindDuplicatesView::slotSearchUpdated(SAlbum* a) { if (!a->isDuplicatesSearch()) { return; } slotAlbumDeleted(a); slotAlbumAdded(a); } void FindDuplicatesView::slotClear() { for (QTreeWidgetItemIterator it(d->listView) ; *it ; ++it) { SAlbum* const salbum = static_cast(*it)->album(); if (salbum) { salbum->removeExtraData(this); } } d->listView->clear(); } void FindDuplicatesView::enableControlWidgets(bool val) { d->searchResultRestriction->setEnabled(val); d->updateFingerPrtBtn->setEnabled(val); d->scanDuplicatesBtn->setEnabled(val); d->albumTagRelation->setEnabled(val); d->similarityRange->setEnabled(val); d->albumSelectors->setEnabled(val); d->albumTagRelationLabel->setEnabled(val); d->restrictResultsLabel->setEnabled(val); d->similarityLabel->setEnabled(val); } void FindDuplicatesView::slotFindDuplicates() { d->albumSelectors->saveState(); slotClear(); enableControlWidgets(false); AlbumList albums; AlbumList tags; if (d->albumTagRelation->itemData(d->albumTagRelation->currentIndex()).toInt() == HaarIface::AlbumTagRelation::NoMix) { if (d->albumSelectors->typeSelection() == AlbumSelectors::AlbumType::PhysAlbum) { albums = d->albumSelectors->selectedAlbums(); } else if (d->albumSelectors->typeSelection() == AlbumSelectors::AlbumType::TagsAlbum) { tags = d->albumSelectors->selectedTags(); } } else { albums = d->albumSelectors->selectedAlbums(); tags = d->albumSelectors->selectedTags(); } DuplicatesFinder* const finder = new DuplicatesFinder(albums, tags, d->albumTagRelation->itemData(d->albumTagRelation->currentIndex()).toInt(), d->similarityRange->minValue(), d->similarityRange->maxValue(), d->searchResultRestriction->itemData(d->searchResultRestriction->currentIndex()).toInt()); connect(finder, SIGNAL(signalComplete()), this, SLOT(slotComplete())); finder->start(); } void FindDuplicatesView::slotUpdateDuplicates(const QList& sAlbumsToRebuild, const QList& deletedImages) { d->listView->updateDuplicatesAlbumItems(sAlbumsToRebuild, deletedImages); } void FindDuplicatesView::slotApplicationSettingsChanged() { d->similarityRange->setRange(d->settings->getMinimumSimilarityBound(), 100); } void FindDuplicatesView::slotComplete() { enableControlWidgets(true); slotCheckForValidSettings(); populateTreeView(); } void FindDuplicatesView::slotDuplicatesAlbumActived() { QList albums; foreach(QTreeWidgetItem* const item, d->listView->selectedItems()) { FindDuplicatesAlbumItem* const albumItem = dynamic_cast(item); if (albumItem) { albums << albumItem->album(); } } if (!albums.isEmpty()) { AlbumManager::instance()->setCurrentAlbums(QList() << albums); } } void FindDuplicatesView::slotCheckForValidSettings() { bool valid = d->albumSelectors->selectedAlbums().count() || d->albumSelectors->selectedTags().count(); d->scanDuplicatesBtn->setEnabled(valid); } void FindDuplicatesView::slotUpdateFingerPrints() { FingerPrintsGenerator* const tool = new FingerPrintsGenerator(false); tool->start(); } void FindDuplicatesView::slotSetSelectedAlbum(PAlbum* album) { if (!album) { return; } resetAlbumsAndTags(); // @ODD : Why is singleton set to true? resetAlbumsAndTags already clears the selection. d->albumSelectors->setAlbumSelected(album, true); d->albumSelectors->setTypeSelection(AlbumSelectors::AlbumType::PhysAlbum); slotCheckForValidSettings(); } -void FindDuplicatesView::slotSetSelectedAlbums(QList albums) +void FindDuplicatesView::slotSetSelectedAlbums(const QList& albums) { // @ODD : Why is singleton set to true? resetAlbumsAndTags already clears the selection. resetAlbumsAndTags(); foreach(PAlbum* const album, albums) { d->albumSelectors->setAlbumSelected(album, false); } d->albumSelectors->setTypeSelection(AlbumSelectors::AlbumType::PhysAlbum); slotCheckForValidSettings(); } -void FindDuplicatesView::slotSetSelectedAlbums(QList albums) +void FindDuplicatesView::slotSetSelectedAlbums(const QList& albums) { resetAlbumsAndTags(); foreach(TAlbum* const album, albums) { d->albumSelectors->setTagSelected(album, false); } d->albumSelectors->setTypeSelection(AlbumSelectors::AlbumType::TagsAlbum); slotCheckForValidSettings(); } void FindDuplicatesView::resetAlbumsAndTags() { d->albumSelectors->resetSelection(); slotCheckForValidSettings(); } } // namespace Digikam diff --git a/core/utilities/fuzzysearch/findduplicatesview.h b/core/utilities/fuzzysearch/findduplicatesview.h index d89118e8d8..23b6ddfbd7 100644 --- a/core/utilities/fuzzysearch/findduplicatesview.h +++ b/core/utilities/fuzzysearch/findduplicatesview.h @@ -1,95 +1,95 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2008-05-19 * Description : Find Duplicates View. * * Copyright (C) 2016-2017 by Mario Frank * Copyright (C) 2008-2018 by Gilles Caulier * Copyright (C) 2008-2012 by Marcel Wiesweg * Copyright (C) 2009 by Andi Clemens * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_FIND_DUPLICATES_VIEW_H #define DIGIKAM_FIND_DUPLICATES_VIEW_H // Qt includes #include class QTreeWidgetItem; namespace Digikam { class Album; class SAlbum; class PAlbum; class TAlbum; class FindDuplicatesView : public QWidget { Q_OBJECT public: explicit FindDuplicatesView(QWidget* const parent = 0); virtual ~FindDuplicatesView(); QList currentFindDuplicatesAlbums() const; void setActive(bool val); public Q_SLOTS: void slotSetSelectedAlbum(PAlbum* album); - void slotSetSelectedAlbums(QList albums); - void slotSetSelectedAlbums(QList albums); + void slotSetSelectedAlbums(const QList& albums); + void slotSetSelectedAlbums(const QList& albums); private Q_SLOTS: void initAlbumUpdateConnections(); void populateTreeView(); void slotAlbumAdded(Album* a); void slotAlbumDeleted(Album* a); void slotSearchUpdated(SAlbum* a); void slotClear(); void slotFindDuplicates(); void slotUpdateDuplicates(const QList& sAlbumsToRebuild, const QList& deletedImages); void slotDuplicatesAlbumActived(); void slotComplete(); void slotUpdateFingerPrints(); void slotCheckForValidSettings(); void slotApplicationSettingsChanged(); private: void enableControlWidgets(bool); void updateAlbumsBox(); void updateTagsBox(); void resetAlbumsAndTags(); private: class Private; Private* const d; }; } // namespace Digikam #endif // DIGIKAM_FIND_DUPLICATES_VIEW_H diff --git a/core/utilities/fuzzysearch/fuzzysearchview.cpp b/core/utilities/fuzzysearch/fuzzysearchview.cpp index b82a9020b3..777f45b1b3 100644 --- a/core/utilities/fuzzysearch/fuzzysearchview.cpp +++ b/core/utilities/fuzzysearch/fuzzysearchview.cpp @@ -1,1138 +1,1138 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2008-05-19 * Description : Fuzzy search sidebar tab contents. * * Copyright (C) 2016-2018 by Mario Frank * Copyright (C) 2008-2018 by Gilles Caulier * Copyright (C) 2008-2012 by Marcel Wiesweg * Copyright (C) 2012 by Andi Clemens * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "fuzzysearchview.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "dlayoutbox.h" #include "digikam_debug.h" #include "album.h" #include "coredb.h" #include "coredbalbuminfo.h" #include "albummanager.h" #include "albummodel.h" #include "albumselectors.h" #include "coredbaccess.h" #include "ddragobjects.h" #include "editablesearchtreeview.h" #include "findduplicatesview.h" #include "haariface.h" #include "imageinfo.h" #include "imagelister.h" #include "searchmodificationhelper.h" #include "searchtextbar.h" #include "coredbsearchxml.h" #include "sketchwidget.h" #include "thumbnailloadthread.h" #include "thumbnailsize.h" #include "dhuesaturationselect.h" #include "dcolorvalueselector.h" #include "dexpanderbox.h" #include "applicationsettings.h" #include "drangebox.h" #include "similaritydbaccess.h" #include "similaritydb.h" namespace Digikam { class FuzzySearchView::Private { public: enum FuzzySearchTab { DUPLICATES = 0, SIMILARS, SKETCH }; public: explicit Private() : // initially be active to update sketch panel when the search list is restored active(false), fingerprintsChecked(false), resetButton(0), saveBtnSketch(0), undoBtnSketch(0), redoBtnSketch(0), saveBtnImage(0), penSize(0), resultsSketch(0), similarityRange(0), imageWidget(0), timerSketch(0), timerImage(0), folderView(0), nameEditSketch(0), nameEditImage(0), tabWidget(0), hsSelector(0), vSelector(0), labelFile(0), labelFolder(0), searchFuzzyBar(0), searchTreeView(0), sketchWidget(0), thumbLoadThread(0), findDuplicatesPanel(0), imageSAlbum(0), sketchSAlbum(0), fuzzySearchAlbumSelectors(0), sketchSearchAlbumSelectors(0), searchModel(0), searchModificationHelper(0), settings(0) { } static const QString configTabEntry; static const QString configPenSketchSizeEntry; static const QString configResultSketchItemsEntry; static const QString configPenSketchHueEntry; static const QString configPenSketchSaturationEntry; static const QString configPenSkethValueEntry; static const QString configSimilarsThresholdEntry; static const QString configSimilarsMaxThresholdEntry; bool active; bool fingerprintsChecked; QColor selColor; QToolButton* resetButton; QToolButton* saveBtnSketch; QToolButton* undoBtnSketch; QToolButton* redoBtnSketch; QToolButton* saveBtnImage; QSpinBox* penSize; QSpinBox* resultsSketch; DIntRangeBox* similarityRange; QLabel* imageWidget; QTimer* timerSketch; QTimer* timerImage; DVBox* folderView; QLineEdit* nameEditSketch; QLineEdit* nameEditImage; QTabWidget* tabWidget; DHueSaturationSelector* hsSelector; DColorValueSelector* vSelector; DAdjustableLabel* labelFile; DAdjustableLabel* labelFolder; ImageInfo imageInfo; QUrl imageUrl; SearchTextBar* searchFuzzyBar; EditableSearchTreeView* searchTreeView; SketchWidget* sketchWidget; ThumbnailLoadThread* thumbLoadThread; FindDuplicatesView* findDuplicatesPanel; AlbumPointer imageSAlbum; AlbumPointer sketchSAlbum; AlbumSelectors* fuzzySearchAlbumSelectors; AlbumSelectors* sketchSearchAlbumSelectors; SearchModel* searchModel; SearchModificationHelper* searchModificationHelper; ApplicationSettings* settings; }; const QString FuzzySearchView::Private::configTabEntry(QLatin1String("FuzzySearch Tab")); const QString FuzzySearchView::Private::configPenSketchSizeEntry(QLatin1String("Pen Sketch Size")); const QString FuzzySearchView::Private::configResultSketchItemsEntry(QLatin1String("Result Sketch items")); const QString FuzzySearchView::Private::configPenSketchHueEntry(QLatin1String("Pen Sketch Hue")); const QString FuzzySearchView::Private::configPenSketchSaturationEntry(QLatin1String("Pen Sketch Saturation")); const QString FuzzySearchView::Private::configPenSkethValueEntry(QLatin1String("Pen Sketch Value")); const QString FuzzySearchView::Private::configSimilarsThresholdEntry(QLatin1String("Similars Threshold")); const QString FuzzySearchView::Private::configSimilarsMaxThresholdEntry(QLatin1String("Similars Maximum Threshold")); // -------------------------------------------------------- FuzzySearchView::FuzzySearchView(SearchModel* const searchModel, SearchModificationHelper* const searchModificationHelper, QWidget* const parent) : QScrollArea(parent), StateSavingObject(this), d(new Private) { d->settings = ApplicationSettings::instance(); const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); d->thumbLoadThread = ThumbnailLoadThread::defaultThread(); d->searchModel = searchModel; d->searchModificationHelper = searchModificationHelper; setWidgetResizable(true); setAttribute(Qt::WA_DeleteOnClose); setAcceptDrops(true); viewport()->setAcceptDrops(true); // --------------------------------------------------------------- QWidget* const imagePanel = setupFindSimilarPanel(); QWidget* const sketchPanel = setupSketchPanel(); d->findDuplicatesPanel = new FindDuplicatesView(); d->tabWidget = new QTabWidget(); d->tabWidget->insertTab(Private::DUPLICATES, d->findDuplicatesPanel, i18n("Duplicates")); d->tabWidget->insertTab(Private::SIMILARS, imagePanel, i18n("Image")); d->tabWidget->insertTab(Private::SKETCH, sketchPanel, i18n("Sketch")); // --------------------------------------------------------------- d->folderView = new DVBox(); d->searchTreeView = new EditableSearchTreeView(d->folderView, searchModel, searchModificationHelper); d->searchTreeView->filteredModel()->listHaarSearches(); d->searchTreeView->filteredModel()->setListTemporarySearches(true); d->searchTreeView->setAlbumManagerCurrentAlbum(true); d->searchFuzzyBar = new SearchTextBar(d->folderView, QLatin1String("FuzzySearchViewSearchFuzzyBar")); d->searchFuzzyBar->setModel(d->searchTreeView->filteredModel(), AbstractAlbumModel::AlbumIdRole, AbstractAlbumModel::AlbumTitleRole); d->searchFuzzyBar->setFilterModel(d->searchTreeView->albumFilterModel()); d->folderView->setContentsMargins(QMargins()); d->folderView->setSpacing(spacing); // --------------------------------------------------------------- QWidget* const mainWidget = new QWidget(this); QVBoxLayout* const mainLayout = new QVBoxLayout(); mainLayout->addWidget(d->tabWidget); mainLayout->addWidget(d->folderView); mainLayout->setContentsMargins(QMargins()); mainLayout->setSpacing(0); mainWidget->setLayout(mainLayout); setWidget(mainWidget); // --------------------------------------------------------------- d->timerSketch = new QTimer(this); d->timerSketch->setSingleShot(true); d->timerSketch->setInterval(500); d->timerImage = new QTimer(this); d->timerImage->setSingleShot(true); d->timerImage->setInterval(500); // --------------------------------------------------------------- setupConnections(); // --------------------------------------------------------------- slotCheckNameEditSketchConditions(); slotCheckNameEditImageConditions(); } QWidget* FuzzySearchView::setupFindSimilarPanel() const { const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); DHBox* const imageBox = new DHBox(); d->imageWidget = new QLabel(imageBox); d->imageWidget->setFixedSize(256, 256); d->imageWidget->setText(i18n("

Drag & drop an image here
to perform similar
items search.

" "

You can also use the context menu
when browsing through your images.

")); d->imageWidget->setAlignment(Qt::AlignCenter); imageBox->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); imageBox->setLineWidth(1); // --------------------------------------------------------------- QLabel* const file = new QLabel(i18n("File:")); d->labelFile = new DAdjustableLabel(0); QLabel* const folder = new QLabel(i18n("Folder:")); d->labelFolder = new DAdjustableLabel(0); int hgt = fontMetrics().height() - 2; file->setMaximumHeight(hgt); folder->setMaximumHeight(hgt); d->labelFile->setMaximumHeight(hgt); d->labelFolder->setMaximumHeight(hgt); // --------------------------------------------------------------- d->fuzzySearchAlbumSelectors = new AlbumSelectors(i18nc("@label", "Search in albums:"), QLatin1String("Fuzzy Search View"), 0, AlbumSelectors::AlbumType::PhysAlbum); // --------------------------------------------------------------- QLabel* const resultsLabel = new QLabel(i18n("Similarity range:")); d->similarityRange = new DIntRangeBox(); d->similarityRange->setSuffix(QLatin1String("%")); if (d->settings) { d->similarityRange->setRange(d->settings->getMinimumSimilarityBound(), 100); d->similarityRange->setInterval(d->settings->getDuplicatesSearchLastMinSimilarity(), d->settings->getDuplicatesSearchLastMaxSimilarity()); } else { d->similarityRange->setRange(40, 100); d->similarityRange->setInterval(90, 100); } d->similarityRange->setWhatsThis(i18n("Select here the approximate similarity interval " "as a percentage. ")); // --------------------------------------------------------------- DHBox* const saveBox = new DHBox(); saveBox->setContentsMargins(QMargins()); saveBox->setSpacing(spacing); d->nameEditImage = new QLineEdit(saveBox); d->nameEditImage->setClearButtonEnabled(true); d->nameEditImage->setWhatsThis(i18n("Enter the name of the current similar image search to save in the " "\"Similarity Searches\" view.")); d->saveBtnImage = new QToolButton(saveBox); d->saveBtnImage->setIcon(QIcon::fromTheme(QLatin1String("document-save"))); d->saveBtnImage->setEnabled(false); d->saveBtnImage->setToolTip(i18n("Save current similar image search to a new virtual Album")); d->saveBtnImage->setWhatsThis(i18n("If you press this button, the current " "similar image search will be saved to a new search " "virtual album using name " "set on the left side.")); // --------------------------------------------------------------- QWidget* const mainWidget = new QWidget(); QGridLayout* const mainLayout = new QGridLayout(); mainLayout->addWidget(imageBox, 0, 0, 1, 6); mainLayout->addWidget(file, 1, 0, 1, 1); mainLayout->addWidget(d->labelFile, 1, 1, 1, 5); mainLayout->addWidget(folder, 2, 0, 1, 1); mainLayout->addWidget(d->labelFolder, 2, 1, 1, 5); mainLayout->addWidget(d->fuzzySearchAlbumSelectors, 3, 0, 1, -1); mainLayout->addWidget(resultsLabel, 4, 0, 1, 1); mainLayout->addWidget(d->similarityRange, 4, 2, 1, 1); mainLayout->addWidget(saveBox, 5, 0, 1, 6); mainLayout->setRowStretch(0, 10); mainLayout->setColumnStretch(1, 10); mainLayout->setContentsMargins(spacing, spacing, spacing, spacing); mainLayout->setSpacing(spacing); mainWidget->setLayout(mainLayout); return mainWidget; } QWidget* FuzzySearchView::setupSketchPanel() const { const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); DHBox* const drawingBox = new DHBox(); d->sketchWidget = new SketchWidget(drawingBox); drawingBox->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); drawingBox->setLineWidth(1); // --------------------------------------------------------------- QString tooltip(i18n("Set here the brush color used to draw sketch.")); d->hsSelector = new DHueSaturationSelector(); d->hsSelector->setMinimumSize(200, 96); d->hsSelector->setChooserMode(ChooserValue); d->hsSelector->setColorValue(255); d->hsSelector->setWhatsThis(tooltip); d->vSelector = new DColorValueSelector(); d->vSelector->setMinimumSize(26, 96); d->vSelector->setChooserMode(ChooserValue); d->vSelector->setIndent(false); d->vSelector->setWhatsThis(tooltip); // --------------------------------------------------------------- d->undoBtnSketch = new QToolButton(); d->undoBtnSketch->setAutoRepeat(true); d->undoBtnSketch->setIcon(QIcon::fromTheme(QLatin1String("edit-undo"))); d->undoBtnSketch->setToolTip(i18n("Undo last draw on sketch")); d->undoBtnSketch->setWhatsThis(i18n("Use this button to undo last drawing action on sketch.")); d->undoBtnSketch->setEnabled(false); d->redoBtnSketch = new QToolButton(); d->redoBtnSketch->setAutoRepeat(true); d->redoBtnSketch->setIcon(QIcon::fromTheme(QLatin1String("edit-redo"))); d->redoBtnSketch->setToolTip(i18n("Redo last draw on sketch")); d->redoBtnSketch->setWhatsThis(i18n("Use this button to redo last drawing action on sketch.")); d->redoBtnSketch->setEnabled(false); QLabel* const brushLabel = new QLabel(i18n("Pen:")); d->penSize = new QSpinBox(); d->penSize->setRange(1, 64); d->penSize->setSingleStep(1); d->penSize->setValue(10); d->penSize->setWhatsThis(i18n("Set here the brush size in pixels used to draw sketch.")); QLabel* const resultsLabel = new QLabel(i18n("Items:")); d->resultsSketch = new QSpinBox(); d->resultsSketch->setRange(1, 50); d->resultsSketch->setSingleStep(1); d->resultsSketch->setValue(10); d->resultsSketch->setWhatsThis(i18n("Set here the number of items to find using sketch.")); QGridLayout* const settingsLayout = new QGridLayout(); settingsLayout->addWidget(d->undoBtnSketch, 0, 0); settingsLayout->addWidget(d->redoBtnSketch, 0, 1); settingsLayout->addWidget(brushLabel, 0, 2); settingsLayout->addWidget(d->penSize, 0, 3); settingsLayout->addWidget(resultsLabel, 0, 5); settingsLayout->addWidget(d->resultsSketch, 0, 6); settingsLayout->setColumnStretch(4, 10); settingsLayout->setContentsMargins(QMargins()); settingsLayout->setSpacing(spacing); // --------------------------------------------------------------- d->sketchSearchAlbumSelectors = new AlbumSelectors(i18nc("@label", "Search in albums:"), QLatin1String("Sketch Search View"), 0, AlbumSelectors::AlbumType::PhysAlbum); // --------------------------------------------------------------- DHBox* const saveBox = new DHBox(); saveBox->setContentsMargins(QMargins()); saveBox->setSpacing(spacing); d->resetButton = new QToolButton(saveBox); d->resetButton->setIcon(QIcon::fromTheme(QLatin1String("document-revert"))); d->resetButton->setToolTip(i18n("Clear sketch")); d->resetButton->setWhatsThis(i18n("Use this button to clear sketch contents.")); d->nameEditSketch = new QLineEdit(saveBox); d->nameEditSketch->setClearButtonEnabled(true); d->nameEditSketch->setWhatsThis(i18n("Enter the name of the current sketch search to save in the " "\"Similarity Searches\" view.")); d->saveBtnSketch = new QToolButton(saveBox); d->saveBtnSketch->setIcon(QIcon::fromTheme(QLatin1String("document-save"))); d->saveBtnSketch->setEnabled(false); d->saveBtnSketch->setToolTip(i18n("Save current sketch search to a new virtual Album")); d->saveBtnSketch->setWhatsThis(i18n("If you press this button, the current sketch " "fuzzy search will be saved to a new search " "virtual album using the name " "set on the left side.")); // --------------------------------------------------------------- QWidget* const mainWidget = new QWidget; QGridLayout* const mainLayout = new QGridLayout(); mainLayout->addWidget(drawingBox, 0, 0, 1, 3); mainLayout->addWidget(d->hsSelector, 1, 0, 1, 2); mainLayout->addWidget(d->vSelector, 1, 2, 1, 1); mainLayout->addLayout(settingsLayout, 2, 0, 1, 3); mainLayout->addWidget(d->sketchSearchAlbumSelectors, 3, 0, 1, 3); mainLayout->addWidget(saveBox, 4, 0, 1, 3); mainLayout->setRowStretch(0, 10); mainLayout->setColumnStretch(1, 10); mainLayout->setContentsMargins(spacing, spacing, spacing, spacing); mainLayout->setSpacing(spacing); mainWidget->setLayout(mainLayout); return mainWidget; } void FuzzySearchView::setupConnections() { connect(d->settings, SIGNAL(setupChanged()), this, SLOT(slotApplicationSettingsChanged())); connect(d->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(slotTabChanged(int))); connect(d->searchTreeView, SIGNAL(currentAlbumChanged(Album*)), this, SLOT(slotAlbumSelected(Album*))); connect(d->hsSelector, SIGNAL(valueChanged(int,int)), this, SLOT(slotHSChanged(int,int))); connect(d->vSelector, SIGNAL(valueChanged(int)), this, SLOT(slotVChanged(int))); connect(d->penSize, SIGNAL(valueChanged(int)), d->sketchWidget, SLOT(setPenWidth(int))); connect(d->resultsSketch, SIGNAL(valueChanged(int)), this, SLOT(slotDirtySketch())); connect(d->sketchSearchAlbumSelectors, SIGNAL(signalSelectionChanged()), this, SLOT(slotDirtySketch())); connect(d->fuzzySearchAlbumSelectors, SIGNAL(signalSelectionChanged()), this, SLOT(slotFuzzyAlbumsChanged())); connect(d->similarityRange, SIGNAL(minChanged(int)), this, SLOT(slotMinLevelImageChanged(int))); connect(d->similarityRange, SIGNAL(maxChanged(int)), this, SLOT(slotMaxLevelImageChanged(int))); connect(d->resetButton, SIGNAL(clicked()), this, SLOT(slotClearSketch())); connect(d->sketchWidget, SIGNAL(signalPenSizeChanged(int)), d->penSize, SLOT(setValue(int))); connect(d->sketchWidget, SIGNAL(signalPenColorChanged(QColor)), this, SLOT(slotPenColorChanged(QColor))); connect(d->sketchWidget, SIGNAL(signalSketchChanged(QImage)), this, SLOT(slotDirtySketch())); connect(d->sketchWidget, SIGNAL(signalUndoRedoStateChanged(bool,bool)), this, SLOT(slotUndoRedoStateChanged(bool,bool))); connect(d->undoBtnSketch, SIGNAL(clicked()), d->sketchWidget, SLOT(slotUndo())); connect(d->redoBtnSketch, SIGNAL(clicked()), d->sketchWidget, SLOT(slotRedo())); connect(d->saveBtnSketch, SIGNAL(clicked()), this, SLOT(slotSaveSketchSAlbum())); connect(d->saveBtnImage, SIGNAL(clicked()), this, SLOT(slotSaveImageSAlbum())); connect(d->nameEditSketch, SIGNAL(textChanged(QString)), this, SLOT(slotCheckNameEditSketchConditions())); connect(d->nameEditSketch, SIGNAL(returnPressed()), d->saveBtnSketch, SLOT(animateClick())); connect(d->nameEditImage, SIGNAL(textChanged(QString)), this, SLOT(slotCheckNameEditImageConditions())); connect(d->nameEditImage, SIGNAL(returnPressed()), d->saveBtnImage, SLOT(animateClick())); connect(d->thumbLoadThread, SIGNAL(signalThumbnailLoaded(LoadingDescription,QPixmap)), this, SLOT(slotThumbnailLoaded(LoadingDescription,QPixmap))); connect(d->timerSketch, SIGNAL(timeout()), this, SLOT(slotTimerSketchDone())); connect(d->timerImage, SIGNAL(timeout()), this, SLOT(slotTimerImageDone())); } FuzzySearchView::~FuzzySearchView() { delete d->timerSketch; delete d->timerImage; delete d; } SAlbum* FuzzySearchView::currentAlbum() const { return d->searchTreeView->currentAlbum(); } void FuzzySearchView::setCurrentAlbum(SAlbum* const album) { d->searchTreeView->setCurrentAlbums(QList() << album); } void FuzzySearchView::newDuplicatesSearch(PAlbum* const album) { if (album) { d->findDuplicatesPanel->slotSetSelectedAlbum(album); } d->tabWidget->setCurrentIndex(Private::DUPLICATES); } -void FuzzySearchView::newDuplicatesSearch(QList const albums) +void FuzzySearchView::newDuplicatesSearch(const QList& albums) { if (!albums.isEmpty()) { d->findDuplicatesPanel->slotSetSelectedAlbums(albums); } d->tabWidget->setCurrentIndex(Private::DUPLICATES); } -void FuzzySearchView::newDuplicatesSearch(QList const albums) +void FuzzySearchView::newDuplicatesSearch(const QList& albums) { if (!albums.isEmpty()) { d->findDuplicatesPanel->slotSetSelectedAlbums(albums); } d->tabWidget->setCurrentIndex(Private::DUPLICATES); } void FuzzySearchView::setConfigGroup(const KConfigGroup& group) { StateSavingObject::setConfigGroup(group); d->searchTreeView->setConfigGroup(group); } void FuzzySearchView::doLoadState() { KConfigGroup group = getConfigGroup(); d->tabWidget->setCurrentIndex(group.readEntry(entryName(d->configTabEntry), (int)Private::DUPLICATES)); d->penSize->setValue(group.readEntry(entryName(d->configPenSketchSizeEntry), 10)); d->resultsSketch->setValue(group.readEntry(entryName(d->configResultSketchItemsEntry), 10)); d->hsSelector->setHue(group.readEntry(entryName(d->configPenSketchHueEntry), 180)); d->hsSelector->setSaturation(group.readEntry(entryName(d->configPenSketchSaturationEntry), 128)); d->vSelector->setValue(group.readEntry(entryName(d->configPenSkethValueEntry), 255)); d->similarityRange->setInterval(group.readEntry(entryName(d->configSimilarsThresholdEntry), 90), group.readEntry(entryName(d->configSimilarsMaxThresholdEntry), 100)); d->hsSelector->updateContents(); QColor col; col.setHsv(d->hsSelector->hue(), d->hsSelector->saturation(), d->vSelector->value()); setColor(col); d->sketchWidget->setPenWidth(d->penSize->value()); d->searchTreeView->loadState(); d->fuzzySearchAlbumSelectors->loadState(); d->sketchSearchAlbumSelectors->loadState(); } void FuzzySearchView::doSaveState() { KConfigGroup group = getConfigGroup(); group.writeEntry(entryName(d->configTabEntry), d->tabWidget->currentIndex()); group.writeEntry(entryName(d->configPenSketchSizeEntry), d->penSize->value()); group.writeEntry(entryName(d->configResultSketchItemsEntry), d->resultsSketch->value()); group.writeEntry(entryName(d->configPenSketchHueEntry), d->hsSelector->hue()); group.writeEntry(entryName(d->configPenSketchSaturationEntry), d->hsSelector->saturation()); group.writeEntry(entryName(d->configPenSkethValueEntry), d->vSelector->value()); group.writeEntry(entryName(d->configSimilarsThresholdEntry), d->similarityRange->minValue()); group.writeEntry(entryName(d->configSimilarsMaxThresholdEntry), d->similarityRange->maxValue()); d->searchTreeView->saveState(); group.sync(); d->fuzzySearchAlbumSelectors->saveState(); d->sketchSearchAlbumSelectors->saveState(); } void FuzzySearchView::setActive(bool val) { d->active = val; // at first occasion, warn if no fingerprints are available if (val && !d->fingerprintsChecked && isVisible()) { if (!SimilarityDbAccess().db()->hasFingerprints()) { QString msg = i18n("Image fingerprints have not yet been generated for your collection. " "The Similarity Search Tools will not be operational " "without pre-generated fingerprints. Please generate " "the fingerprints first."); QMessageBox::information(this, i18n("No Fingerprints"), msg); } d->fingerprintsChecked = true; } int tab = d->tabWidget->currentIndex(); if (val) { slotTabChanged(tab); } } void FuzzySearchView::slotTabChanged(int tab) { /** * Set a list with only one element, albummanager can set only multiple albums */ QList albums; switch (tab) { case Private::SIMILARS: { albums << d->imageSAlbum; AlbumManager::instance()->setCurrentAlbums(albums); d->folderView->setVisible(true); break; } case Private::SKETCH: { albums << d->sketchSAlbum; AlbumManager::instance()->setCurrentAlbums(albums); d->folderView->setVisible(true); break; } default: // DUPLICATES { d->findDuplicatesPanel->setActive(true); QList sAlbums = d->findDuplicatesPanel->currentFindDuplicatesAlbums(); foreach(SAlbum* const album, sAlbums) { albums << album; } AlbumManager::instance()->setCurrentAlbums(albums); d->folderView->setVisible(false); break; } } } void FuzzySearchView::slotAlbumSelected(Album* album) { qCDebug(DIGIKAM_GENERAL_LOG) << "Selected new album" << album; SAlbum* const salbum = dynamic_cast(album); if (!salbum || !salbum->isHaarSearch()) { qCDebug(DIGIKAM_GENERAL_LOG) << "Not a haar search, returning"; return; } if (!d->active) { qCDebug(DIGIKAM_GENERAL_LOG) << "Not active, returning"; return; } SearchXmlReader reader(salbum->query()); reader.readToFirstField(); QStringRef type = reader.attributes().value(QLatin1String("type")); QStringRef numResultsString = reader.attributes().value(QLatin1String("numberofresults")); QStringRef thresholdString = reader.attributes().value(QLatin1String("threshold")); QStringRef maxThresholdString = reader.attributes().value(QLatin1String("maxthreshold")); QStringRef sketchTypeString = reader.attributes().value(QLatin1String("sketchtype")); if (type == QLatin1String("imageid")) { setCurrentImage(reader.valueToLongLong()); d->imageSAlbum = salbum; d->tabWidget->setCurrentIndex((int)Private::SIMILARS); } else if (type == QLatin1String("signature")) { d->sketchSAlbum = salbum; d->tabWidget->setCurrentIndex((int)Private::SKETCH); if (reader.readToStartOfElement(QLatin1String("SketchImage"))) { d->sketchWidget->setSketchImageFromXML(reader); } } } void FuzzySearchView::slotApplicationSettingsChanged() { d->similarityRange->setRange(d->settings->getMinimumSimilarityBound(),100); } // Sketch Searches methods ----------------------------------------------------------------------- void FuzzySearchView::slotHSChanged(int h, int s) { QColor color; int val = d->selColor.value(); color.setHsv(h, s, val); setColor(color); } void FuzzySearchView::slotVChanged(int v) { QColor color; int hue = d->selColor.hue(); int sat = d->selColor.saturation(); color.setHsv(hue, sat, v); setColor(color); } void FuzzySearchView::slotPenColorChanged(const QColor& color) { slotHSChanged(color.hue(), color.saturation()); slotVChanged(color.value()); } void FuzzySearchView::setColor(QColor c) { if (c.isValid()) { d->selColor = c; // set values d->hsSelector->setValues(c.hue(), c.saturation()); d->vSelector->setValue(c.value()); // set colors d->hsSelector->blockSignals(true); d->hsSelector->setHue(c.hue()); d->hsSelector->setSaturation(c.saturation()); d->hsSelector->setColorValue(c.value()); d->hsSelector->updateContents(); d->hsSelector->blockSignals(false); d->hsSelector->repaint(); d->vSelector->blockSignals(true); d->vSelector->setHue(c.hue()); d->vSelector->setSaturation(c.saturation()); d->vSelector->setColorValue(c.value()); d->vSelector->updateContents(); d->vSelector->blockSignals(false); d->vSelector->repaint(); d->sketchWidget->setPenColor(c); } } void FuzzySearchView::slotUndoRedoStateChanged(bool hasUndo, bool hasRedo) { d->undoBtnSketch->setEnabled(hasUndo); d->redoBtnSketch->setEnabled(hasRedo); } void FuzzySearchView::slotSaveSketchSAlbum() { createNewFuzzySearchAlbumFromSketch(d->nameEditSketch->text()); } void FuzzySearchView::slotDirtySketch() { if (d->active) { d->timerSketch->start(); } } void FuzzySearchView::slotTimerSketchDone() { slotCheckNameEditSketchConditions(); createNewFuzzySearchAlbumFromSketch(SAlbum::getTemporaryHaarTitle(DatabaseSearch::HaarSketchSearch), true); } void FuzzySearchView::createNewFuzzySearchAlbumFromSketch(const QString& name, bool force) { AlbumManager::instance()->setCurrentAlbums(QList()); QList albums = d->sketchSearchAlbumSelectors->selectedAlbumIds(); d->sketchSAlbum = d->searchModificationHelper->createFuzzySearchFromSketch(name, d->sketchWidget, d->resultsSketch->value(), albums, force); d->searchTreeView->setCurrentAlbums(QList() << d->sketchSAlbum); } void FuzzySearchView::slotClearSketch() { d->sketchWidget->slotClear(); slotCheckNameEditSketchConditions(); AlbumManager::instance()->setCurrentAlbums(QList()); } void FuzzySearchView::slotCheckNameEditSketchConditions() { if (!d->sketchWidget->isClear()) { d->nameEditSketch->setEnabled(true); if (!d->nameEditSketch->text().isEmpty()) { d->saveBtnSketch->setEnabled(true); } } else { d->nameEditSketch->setEnabled(false); d->saveBtnSketch->setEnabled(false); } } // Similars Searches methods ---------------------------------------------------------------------- void FuzzySearchView::dragEnterEvent(QDragEnterEvent* e) { if (DItemDrag::canDecode(e->mimeData())) { e->acceptProposedAction(); } else if (e->mimeData()->hasUrls()) { QList urls = e->mimeData()->urls(); // If there is at least one URL and the URL is a local file. if (!urls.isEmpty()) { if (urls.first().isLocalFile()) { HaarIface haarIface; QString path = urls.first().toLocalFile(); const QImage image = haarIface.loadQImage(path); if (!image.isNull()) { e->acceptProposedAction(); } } } } } void FuzzySearchView::dropEvent(QDropEvent* e) { if (DItemDrag::canDecode(e->mimeData())) { QList urls; QList albumIDs; QList imageIDs; if (!DItemDrag::decode(e->mimeData(), urls, albumIDs, imageIDs)) { return; } if (imageIDs.isEmpty()) { return; } setImageInfo(ImageInfo(imageIDs.first())); e->acceptProposedAction(); } // Allow dropping urls and handle them as sketch search if the urls represent images. if (e->mimeData()->hasUrls()) { QList urls = e->mimeData()->urls(); // If there is at least one URL and the URL is a local file. if (!urls.isEmpty()) { if (urls.first().isLocalFile()) { HaarIface haarIface; QString path = urls.first().toLocalFile(); const QImage image = haarIface.loadQImage(path); if (!image.isNull()) { // Set a temporary image id d->imageInfo = ImageInfo(-1); d->imageUrl = urls.first(); d->imageWidget->setPixmap(QPixmap::fromImage(image).scaled(256, 256, Qt::KeepAspectRatio, Qt::SmoothTransformation)); AlbumManager::instance()->setCurrentAlbums(QList()); QString haarTitle = SAlbum::getTemporaryHaarTitle(DatabaseSearch::HaarImageSearch); QList albums = d->fuzzySearchAlbumSelectors->selectedAlbumIds(); d->imageSAlbum = d->searchModificationHelper->createFuzzySearchFromDropped(haarTitle, path, d->similarityRange->minValue() / 100.0, d->similarityRange->maxValue() / 100.0, albums, true); d->searchTreeView->setCurrentAlbums(QList() << d->imageSAlbum); d->labelFile->setAdjustedText(urls.first().fileName()); d->labelFolder->setAdjustedText(urls.first().adjusted(QUrl::RemoveFilename).toLocalFile()); e->acceptProposedAction(); } } } } } void FuzzySearchView::slotMaxLevelImageChanged(int /*newValue*/) { if (d->active) { d->timerImage->start(); } } void FuzzySearchView::slotMinLevelImageChanged(int /*newValue*/) { if (d->active) { d->timerImage->start(); } } void FuzzySearchView::slotFuzzyAlbumsChanged() { if (d->active) { d->timerImage->start(); } } void FuzzySearchView::slotTimerImageDone() { if (d->imageInfo.isNull() && d->imageInfo.id() == -1 && !d->imageUrl.isEmpty()) { AlbumManager::instance()->setCurrentAlbums(QList()); QString haarTitle = SAlbum::getTemporaryHaarTitle(DatabaseSearch::HaarImageSearch); QList albums = d->fuzzySearchAlbumSelectors->selectedAlbumIds(); d->imageSAlbum = d->searchModificationHelper->createFuzzySearchFromDropped(haarTitle, d->imageUrl.toLocalFile(), d->similarityRange->minValue() / 100.0, d->similarityRange->maxValue() / 100.0, albums, true); d->searchTreeView->setCurrentAlbums(QList() << d->imageSAlbum); return; } if (!d->imageInfo.isNull() && d->active) { setImageInfo(d->imageInfo); } } void FuzzySearchView::setCurrentImage(qlonglong imageid) { setCurrentImage(ImageInfo(imageid)); } void FuzzySearchView::setCurrentImage(const ImageInfo& info) { d->imageInfo = info; d->imageUrl = info.fileUrl(); d->labelFile->setAdjustedText(d->imageInfo.name()); d->labelFolder->setAdjustedText(d->imageInfo.fileUrl().adjusted(QUrl::RemoveFilename).toLocalFile()); d->thumbLoadThread->find(d->imageInfo.thumbnailIdentifier()); } void FuzzySearchView::setImageInfo(const ImageInfo& info) { setCurrentImage(info); slotCheckNameEditImageConditions(); createNewFuzzySearchAlbumFromImage(SAlbum::getTemporaryHaarTitle(DatabaseSearch::HaarImageSearch), true); d->tabWidget->setCurrentIndex((int)Private::SIMILARS); } void FuzzySearchView::slotThumbnailLoaded(const LoadingDescription& desc, const QPixmap& pix) { if (!d->imageInfo.isNull() && QUrl::fromLocalFile(desc.filePath) == d->imageInfo.fileUrl()) { d->imageWidget->setPixmap(pix.scaled(256, 256, Qt::KeepAspectRatio, Qt::SmoothTransformation)); } } void FuzzySearchView::createNewFuzzySearchAlbumFromImage(const QString& name, bool force) { AlbumManager::instance()->setCurrentAlbums(QList()); QList albums = d->fuzzySearchAlbumSelectors->selectedAlbumIds(); d->imageSAlbum = d->searchModificationHelper->createFuzzySearchFromImage(name, d->imageInfo, d->similarityRange->minValue() / 100.0, d->similarityRange->maxValue() / 100.0, albums, force); d->searchTreeView->setCurrentAlbums(QList() << d->imageSAlbum); } void FuzzySearchView::slotCheckNameEditImageConditions() { if (!d->imageInfo.isNull()) { d->nameEditImage->setEnabled(true); if (!d->nameEditImage->text().isEmpty()) { d->saveBtnImage->setEnabled(true); } } else { d->nameEditImage->setEnabled(false); d->saveBtnImage->setEnabled(false); } } void FuzzySearchView::slotSaveImageSAlbum() { createNewFuzzySearchAlbumFromImage(d->nameEditImage->text()); } } // namespace Digikam diff --git a/core/utilities/fuzzysearch/fuzzysearchview.h b/core/utilities/fuzzysearch/fuzzysearchview.h index 698d5bd5d3..fc4336496e 100644 --- a/core/utilities/fuzzysearch/fuzzysearchview.h +++ b/core/utilities/fuzzysearch/fuzzysearchview.h @@ -1,135 +1,135 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2008-05-19 * Description : Fuzzy search sidebar tab contents. * * Copyright (C) 2016-2018 by Mario Frank * Copyright (C) 2008-2018 by Gilles Caulier * Copyright (C) 2008-2012 by Marcel Wiesweg * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_FUZZY_SEARCH_VIEW_H #define DIGIKAM_FUZZY_SEARCH_VIEW_H // Qt includes #include // Local includs #include "statesavingobject.h" class QDragEnterEvent; class QDropEvent; class QPixmap; namespace Digikam { class Album; class FuzzySearchFolderView; class ImageInfo; class LoadingDescription; class SAlbum; class PAlbum; class TAlbum; class SearchModel; class SearchModificationHelper; class SearchTextBar; class FuzzySearchView : public QScrollArea, public StateSavingObject { Q_OBJECT public: explicit FuzzySearchView(SearchModel* const searchModel, SearchModificationHelper* const searchModificationHelper, QWidget* const parent = 0); virtual ~FuzzySearchView(); SAlbum* currentAlbum() const; void setCurrentAlbum(SAlbum* const album); void setActive(bool val); void setImageInfo(const ImageInfo& info); - void newDuplicatesSearch(PAlbum* const); - void newDuplicatesSearch(QList const); - void newDuplicatesSearch(QList const); + void newDuplicatesSearch(PAlbum* const album); + void newDuplicatesSearch(const QList& albums); + void newDuplicatesSearch(const QList& albums); virtual void setConfigGroup(const KConfigGroup& group); void doLoadState(); void doSaveState(); protected: void dragEnterEvent(QDragEnterEvent* e); void dropEvent(QDropEvent* e); private Q_SLOTS: void slotTabChanged(int); void slotHSChanged(int h, int s); void slotVChanged(int v); void slotPenColorChanged(const QColor&); void slotClearSketch(); void slotSaveSketchSAlbum(); void slotCheckNameEditSketchConditions(); void slotAlbumSelected(Album* album); void slotSaveImageSAlbum(); void slotCheckNameEditImageConditions(); void slotThumbnailLoaded(const LoadingDescription&, const QPixmap&); void slotDirtySketch(); void slotTimerSketchDone(); void slotUndoRedoStateChanged(bool, bool); void slotMinLevelImageChanged(int); void slotMaxLevelImageChanged(int); void slotFuzzyAlbumsChanged(); void slotTimerImageDone(); void slotApplicationSettingsChanged(); private: void setCurrentImage(qlonglong imageid); void setCurrentImage(const ImageInfo& info); void createNewFuzzySearchAlbumFromSketch(const QString& name, bool force = false); void createNewFuzzySearchAlbumFromImage(const QString& name, bool force = false); void setColor(QColor c); QWidget* setupFindSimilarPanel() const; QWidget* setupSketchPanel() const; void setupConnections(); private: class Private; Private* const d; }; } // namespace Digikam #endif // DIGIKAM_FUZZY_SEARCH_VIEW_H