diff --git a/DEPENDENCIES b/DEPENDENCIES index 1fe7a930a9..4ee45d3636 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -1,67 +1,68 @@ Dependency Status Version Project URL Remarks TODO ---------- ------ ------- ----------- ------- ---- CMake X >= 3.0.0 http://www.cmake.org > 3.1.0 hightly recommended. ECM X >= 1.7.0 https://cgit.kde.org/extra-cmake-modules.git/ Qt5::Core X >= 5.6.0 http://code.qt.io/cgit/qt/qtbase.git/ Qt5::Gui X >= 5.6.0 http://code.qt.io/cgit/qt/qtbase.git/ Qt5::Widgets X >= 5.6.0 http://code.qt.io/cgit/qt/qtbase.git/ Qt5::Network X >= 5.6.0 http://code.qt.io/cgit/qt/qtbase.git/ Qt5::Sql X >= 5.6.0 http://code.qt.io/cgit/qt/qtbase.git/ Including Qt5::Sqlite and Qt5::Mysql plugins. Qt5::Xml X >= 5.6.0 http://code.qt.io/cgit/qt/qtbase.git/ Qt5::Concurrent X >= 5.6.0 http://code.qt.io/cgit/qt/qtbase.git/ Qt5::PrintSupport X >= 5.6.0 http://code.qt.io/cgit/qt/qtbase.git/ Qt5::Svg X >= 5.6.0 http://code.qt.io/cgit/qt/qtsvg.git/ Qt5::XmlPatterns X >= 5.6.0 http://code.qt.io/cgit/qt/qtxmlpatterns.git/ -Qt5::WebKitWidgets X >= 5.6.0 http://code.qt.io/cgit/qt/qtwebkit.git/ +Qt5::WebKitWidgets X >= 5.6.0 http://code.qt.io/cgit/qt/qtwebkit.git/ To render web contents Still the default while transitional stage. +Qt5::WebView opt >= 5.6.0 http://code.qt.io/cgit/qt/qtwebview.git/ To render web contents (ENABLE_QWEBENGINE=on). To replace QWebKitWidgets. Must be the default in the future. Qt5::X11Extras opt >= 5.6.0 http://code.qt.io/cgit/qt/qtx11extras.git/ For color management support under Linux. Qt5::DBus opt >= 5.6.0 http://code.qt.io/cgit/qt/qtbase.git/ Optional: only for Linux Desktop. Qt5::OpenGL opt >= 5.6.0 http://code.qt.io/cgit/qt/qtbase.git/ For Presentation tool. Qt5::Test opt >= 5.6.0 http://code.qt.io/cgit/qt/qtbase.git/ To compile test codes (BUILD_TESTING=on). KF5::Config X >= 5.5.0 https://cgit.kde.org/kconfig.git/about/ KF5::XmlGui X >= 5.5.0 https://cgit.kde.org/kxmlgui.git/about/ KF5::I18n X >= 5.5.0 https://cgit.kde.org/ki18n.git/about/ KF5::WindowSystem X >= 5.5.0 https://cgit.kde.org/kwindowsystem.git/about/ KF5::Service X >= 5.5.0 https://cgit.kde.org/kservice.git/about/ TODO: make optional for Linux desktop (DFileOperations). KF5::Solid X >= 5.5.0 https://cgit.kde.org/solid.git/about/ KF5::CoreAddons X >= 5.5.0 https://cgit.kde.org/kcoreaddons.git/about/ Needs for KAboutData. KF5::NotifyConfig opt >= 5.5.0 https://cgit.kde.org/knotifyconfig.git/about/ For Linux desktop application notify configuration. KF5::Notifications opt >= 5.5.0 https://cgit.kde.org/knotifications.git/about/ For Linux desktop notifications integrations. KF5::ThreadWeaver opt >= 5.5.0 https://cgit.kde.org/threadweaver.git/about/ For panorama tool. KF5::IconThemes opt >= 5.5.0 https://cgit.kde.org/kiconthemes.git/about/ Optional: only for Linux Desktop (KIconDialog) KF5::FileMetaData opt >= 5.5.0 https://cgit.kde.org/kfilemetadata.git/about/ KDE files indexer (ENABLE_KFILEMETADATASUPPORT=on) Still experimental, disabled by default. Implementation from KDE side very unstable. KF5::AkonadiContact opt >= 17.12.1 https://cgit.kde.org/akonadi-contacts.git/about/ KDE Mail contacts (ENABLE_AKONADICONTACTSUPPORT=on) Still experimental, disabled by default. Need testing. KF5::CalendarCore opt >= 17.12.1 https://cgit.kde.org/kcalcore.git/about/ For calendar tool to setup ical special events. KF5::KIO opt >= 5.5.0 https://cgit.kde.org/kio.git/about/ Optional: only for Linux Desktop libopencv X >= 3.1 http://opencv.willowgarage.com Both versions supported using a cmake flag. libpthread X >= 2.0.0 http://www.gnu.org/software/hurd/libpthread.html For DNG converter. libtiff X >= 4.0 http://www.remotesensing.org/libtiff For DImg image loader. libpng X >= 1.6 http://www.libpng.org/pub/png/libpng.html For DImg image loader. libjpeg X >= 6b http://www.ijg.org jpeglib >= 8.0 hightly recommended for RawEngine. libboost X >= 1.55.0 http://www.boost.org/doc/libs For Versionning support. liblcms X >= 2.x http://www.littlecms.com For Color Management support. libexpat X >= 2.1.0 http://expat.sourceforge.net For DNG converter. libexiv2 X >= 0.26 http://www.exiv2.org Metadata low level management. 0.24 deprecated. libxml2 opt >= 2.7.0 http://xmlsoft.org For HtmlGallery tool. libxslt opt >= 1.1.0 http://xmlsoft.org/XSLT For HtmlGallery tool. libqtav opt >= 1.12.0 http://www.qtav.org To play video and audio (ENABLE_MEDIAPLAYER=on) libffmpeg opt >= 3.3.x http://www.ffmpeg.org To play video and audio (ENABLE_MEDIAPLAYER=on) libavformat, libavutil, libavcodec used to extract video metadata. Flex opt >= 2.5.0 http://flex.sourceforge.net For Panorama tool. Bison opt >= 2.5.0 http://www.gnu.org/software/bison/bison.html For Panorama tool. libmesa opt >= 11.0 http://www.mesa3d.org For Presentation tools (Linux only). libmediawiki opt >= 5.5.0 https://cgit.kde.org/libmediawiki.git/about/ For MediaWiki tool (DIGIKAMSC_COMPILE_LIBMEDIAWIKI=on) libkvkontakte opt >= 4.70.0 https://cgit.kde.org/libkvkontatke.git/about/ For Vkontakte tool (DIGIKAMSC_COMPILE_LIBKVKONTAKTE=on) libksane opt >= 5.0.0 https://cgit.kde.org/libksane.git/about/ Digital scanner (DIGIKAMSC_COMPILE_LIBKSANE=on). libjpasper opt >= 1.900.1 http://www.ece.uvic.ca/~mdadams/jasper For JPEG-2000 support. libmarble opt >= 0.21.80 https://cgit.kde.org/marble.git/about/ For geolocation support. libeigen3 opt >= 3.2 http://eigen.tuxfamily.org For Refocus tool. See if Clapack from OpenCV can be used instead. liblensfun opt >= 0.2.8 http://lensfun.sourceforge.net For LensCorrection tool. liblqr-1 opt >= 0.4.2 http://liblqr.wikidot.com For Liquid rescale tool. libgphoto2 opt >= 2.5 http://www.gphoto.org Digital camera drivers support. Need libusb-1. libgomp opt >= 5.0 https://gcc.gnu.org/onlinedocs/libgomp OpenMP support for RawEngine. diff --git a/NEWS b/NEWS index e9cc4a5de9..91bbb9bbcb 100644 --- a/NEWS +++ b/NEWS @@ -1,246 +1,247 @@ digiKam 6.0.0 - Release date: 2018-xx-xx ***************************************************************************************************** NEW FEATURES: ImageEditor : New clone tool to replace old CImg in-painting tool. ImageEditor : Add Web services Import and Export tools. Showfoto : Add Web services Import and Export tools. LightTable : Add Web services Import and Export tools. Database : Similarity database has been moved to a dedicated file to not bloat core database with computed finger-prints. This will speed-up query in core database in case of Similarity feature is used. Database : New video metadata parser based on ffmpeg to populate database. Search : Add video support to find files based on properties registered on database. General : Add QWebEngine support. General : Update internal Libraw to last 0.18.12. General : Fix all Krazy static analyzer reports. Tags : Add possibility to merge tags by drag & drop. HTML Gallery : New Vanilla theme to emulate export to HTML from Adobe LightRoom. HTML Gallery : New Blue Frame theme. HTML Gallery : New Kiosk-Mode theme. ***************************************************************************************************** BUGFIXES: 001 ==> 172650 - No export tools available. 002 ==> 149591 - The export menu is blank. 003 ==> 300424 - Export tools not detected. 004 ==> 327743 - MediaWiki export not displayed. 005 ==> 348146 - Export tools configuration module. 006 ==> 243275 - Crashing when calling configuration. 007 ==> 257134 - Crashes when entering its settings. 008 ==> 230666 - Crash during start. 009 ==> 306698 - Crashes after update to KDE. 010 ==> 207640 - Crashes immediately at startup, sometimes at closing. 011 ==> 245628 - Crash when enabling/disabling Facebook import/export. 012 ==> 097317 - sigsegv [New Thread 1100241184 (LWP 5665)]. 013 ==> 245776 - Crashes when selecting Settings. 014 ==> 245775 - Crashes even without export tools installed. 015 ==> 254283 - Crash as soon as i click settings. 016 ==> 255733 - crash when reopening configuration dialog. 017 ==> 262050 - Crash after new install and scan to mysql database. 018 ==> 263871 - Crashed after searching for duplicates. 019 ==> 268242 - Crashes after I clicked on 'Settings'. 020 ==> 276882 - Add export tool buttons to toolbar. 021 ==> 284801 - Export to picasaweb crashes. 022 ==> 277669 - Crash after files moved. 023 ==> 281250 - Crash after disabling Export tools. 024 ==> 202637 - Crash trying to start export tool. 025 ==> 306693 - after update to KDE host application crashes on startup. 026 ==> 282781 - Crashes when reopening configuration dialog after disabling export tools. 027 ==> 285499 - Crash when settings window opened. 028 ==> 297629 - Crashed when importing from Nikon P7000. 029 ==> 303338 - Crashes when clicking "send to" button. 030 ==> 307619 - Refuses to load Export tools. 031 ==> 311812 - Export tools not loading, SO version not defined. 032 ==> 313186 - Crashes on attempt to use the "Send to" menu. 033 ==> 313356 - Crashed when clicking the "send to" button. 034 ==> 313577 - Crashes when pressing the "send to" button. 035 ==> 313890 - Crash when clicking "Send to...". 036 ==> 315033 - Crashes on pressing Send To... button. 037 ==> 315914 - The facebook tool crashes everytime on initialization. 038 ==> 326556 - Export tools are not loaded when starting host application for second time. 039 ==> 095175 - crash on loading, signal 11 SIGSEGV. 040 ==> 175844 - Crashes at startup loading Export tools. 041 ==> 306511 - Crash during start. 042 ==> 234021 - Crash on loading. 043 ==> 219772 - Opening the application causes crash. 044 ==> 294173 - Crash after Image resize start. 045 ==> 306881 - Crashed when attempting to open Export tools. 046 ==> 306495 - Crash changing settings linux ubuntu lucid. 047 ==> 306497 - Crash after changing settings segmentation fault possible 2nd report? 048 ==> 185470 - "Import from facebook" is listed twice in import menu. 049 ==> 334045 - MediaWiki option not available in Export menu when plugin activated. 050 ==> 142112 - Can't save on my webspace with ShowFoto. 051 ==> 167417 - Showfoto cannot save files of CIFS mount. 052 ==> 125164 - Flickr export tool should respect host application selection. 053 ==> 238927 - Host application quits when uploading to Flickr. 054 ==> 326740 - Selection of tools is set to default after each update. 055 ==> 233063 - Add progress indicator when moving or copy files [patch]. 056 ==> 361829 - Rotated MP4 video with "Orientation" flag are not played back in the correct rotation angle. 057 ==> 329854 - digiKam doesn't rotate video thumbnail. 058 ==> 376661 - When importing ~200,000 video files Digikam crashes in about 2-5 seconds of starting. 059 ==> 377072 - Cannot read video metadata. 060 ==> 374453 - Extract right video date from MP4 files metadata. 061 ==> 377177 - Geolocation / GPS information doesn't appear in video metadata. 062 ==> 383588 - Imported video files have time shifted exactly 2 hours later. 063 ==> 380847 - MP4 video not importing with correct date. 064 ==> 373682 - geolocalisation filter does not take care of the videos geolocalisation tags. 065 ==> 340925 - digiKam crash when start it. 066 ==> 331506 - digiKam crashes on startup. 067 ==> 335816 - Crash when trying to add a big collection. 068 ==> 353295 - digiKam repeatedly crashes while importing pictures. 069 ==> 341433 - Crash when opening digiKam application. 070 ==> 375562 - digiKam crashes while scanning images into sqlite database. 071 ==> 334782 - Crash while doing nothing. 072 ==> 362672 - Crash on start of digiKam. 073 ==> 341023 - Crash after startup during check for updated images. 074 ==> 386891 - Crashed while adding pictures. 075 ==> 342666 - digiKam crashes during find new items. 076 ==> 341274 - digiKam crash on startup. 077 ==> 343708 - Crash when scanning album. 078 ==> 332721 - Crash when reading a certain MP4 video file. 079 ==> 343736 - Crashes when rebuilding thumbnails from database. 080 ==> 346356 - digiKam crashes when adding 90.000 pictures to library. 081 ==> 343714 - digiKam crash when scanning for new items. 082 ==> 341091 - digiKam crashes when updating the MySQL database of a a hudge photo collection. 083 ==> 340879 - digiKam crashes after getting unexpected but reasonable output from libexiv2. 084 ==> 342712 - Crash on collection scanning. 085 ==> 356704 - digiKam still crashes while scanning a new photo directory and subdirs. 086 ==> 339269 - Segfault when opening a folder that contains unknown file types (mov, avi, xcf). 087 ==> 364635 - digiKam crashes on startup. 088 ==> 357356 - digiKam crash on startup while scanning photos. 089 ==> 341554 - digiKam crashed by Data-Import from NFS. 090 ==> 345457 - digiKam crashes at "loading tools". 091 ==> 349635 - Crash of digiKam - moving album. 092 ==> 342604 - digiKam crash. 093 ==> 331450 - Signal 8 on album opening. 094 ==> 342030 - digiKam crashes when checking an AVI video file using exiv2. 095 ==> 352777 - Crash during scan. 096 ==> 352944 - digiKam crashes on start. 097 ==> 343643 - digiKam crashes while perform initial scanning of custom photo folder. 098 ==> 342000 - digiKam crash when opening folder with Videos (Album or SD Card import). 099 ==> 353447 - digiKam crashes when scanning files. 100 ==> 346807 - Crashes on startup. 101 ==> 364639 - digiKam crashed while opening database. 102 ==> 341504 - Crash while using application. 103 ==> 367691 - Searching for pictures crashes at 30% every time. 104 ==> 334604 - Crash after changing disk partions. 105 ==> 351689 - Crash on opening digiKam. 106 ==> 149267 - digiKam crashes after finding avi and so on. 107 ==> 170387 - Add movies management. 108 ==> 369629 - digiKam does not use GPS data from video files. 109 ==> 367880 - Nexus 5X videos show up upside-down in digiKam. 110 ==> 330116 - digiKam does not take care about GPS info stored in MP4 video files. 111 ==> 339150 - digikam crashes when trying to display video file. 112 ==> 344406 - Crash at start. 113 ==> 339909 - digiKam Segmentation Fault on open. 114 ==> 343231 - Crash at scanning for new fotos. 115 ==> 340373 - Crash on scanning video directory. 116 ==> 134679 - Video and audio files are not imported. 117 ==> 375357 - No video preview. 118 ==> 261773 - Batch renaming does not complete when MP4 video file is processed. 119 ==> 185915 - Album View: "Created" time of video set to "00:00". 120 ==> 303218 - digiKam import crashes when you select video files. 121 ==> 374241 - Bad video date rename. 122 ==> 375646 - Be able to scan only photo, not video and audio. 123 ==> 262499 - Cannot rename .AVI files. 124 ==> 199261 - Import avi movies from sdcard wrong date and no thumbnail. 125 ==> 181521 - NEF's in descending order, AVI in ascending order in import from SD-card. 126 ==> 392019 - Two persons can point to the same face tag in pictures. 127 ==> 392013 - Metadata explorer does not show XMP face rectangles. 128 ==> 389508 - Dates Side Menu Is Not Updated Automatically After Exif Date Change [patch]. 129 ==> 331864 - Merge Tags with same name when moving to same hierarchy level. 130 ==> 347302 - Reassign name to face. 131 ==> 391747 - BQM Tool "Remove Metadata" doesn't remove all metadata from image. 132 ==> 285683 - Already imported pictures not recognized after daylight savings time. 133 ==> 392309 - Icons are pixelated when my display scale factor is 1.2 134 ==> 392405 - Function 'getImageIdsFromArea' argument order different. 135 ==> 386224 - Metadata is not updated when moving tags. 136 ==> 370245 - Be able to rename tags which have been setted in pictures. 137 ==> 374470 - Deleted tags are not removed from file metadata. 138 ==> 374516 - Persons metadata are not updated after a tag removed. 139 ==> 392436 - Count Files in directory. 140 ==> 363859 - digiKam core port from QWebKit to QWebEngine [patch]. 141 ==> 392427 - Cannot add collection on network drive. 142 ==> 392022 - Position of a face tag appears on top of bottom of the list, instead of being sorted alphabetically. 143 ==> 372763 - Rename does not give options on Conflict. 144 ==> 391533 - Feature request: add "NOT" tag matching condition in "Filters" panel. 145 ==> 381222 - digiKam crash on fuzzy search. 146 ==> 386275 - Crash caused by QtAV. 147 ==> 372342 - Face tag area is very short [patch]. 148 ==> 391348 - People Side Menu Shows Only Faces Not People Tagged Images. 149 ==> 385630 - Views Requiring Maps Takes ~30s to Launch. 150 ==> 192908 - Allow to split icon-view in order to show multiple albums at the same time. 151 ==> 339088 - GIT master: crash when clicking through images in preview, with face recognition running in background. 152 ==> 341605 - Crash if I attempt to use left-sidebar tags tab. 153 ==> 227266 - Handle Video Date from metadata. 154 ==> 227259 - Needs to Edit Video Date. 155 ==> 373284 - digiKam crashed with SIGSEGV in QSortFilterProxyModel::parent(). 156 ==> 384807 - digikam 5.7.0 AppImage bundle : provide a more recent ffmpeg version for video support. 157 ==> 391835 - Deleted pictures still appear in group. 158 ==> 387483 - Elegant theme: Selected frame colors swapped [patch]. 159 ==> 375424 - Thumbnails are not being removed from AlbumsView after moving the images to Trash. 160 ==> 368796 - Problem with Exif-tags: ImageDescription and UserComment. 161 ==> 392417 - AppImage (5.9.0-01-x86-64) does not support "--install" cli parameter. 162 ==> 392922 - digikam-6.0.0 fail to start. 163 ==> 391399 - Not possible to add location bookmarks in Digikam >5.6.0. 164 ==> 380876 - Tags in Digikam DB maintained after being removed from file and file re-scanned. 165 ==> 392017 - Merging, renaming and removing face tags. 166 ==> 352711 - Externally removed tags are not removed from digiKam. 167 ==> 393108 - Tags not always visible when selecting multiple pictures in a group. 168 ==> 392656 - Selecting a root album for face scan doesn't include subfolders, but rather scans an unexpected album set. 169 ==> 329438 - Rename function with Date & Time does not work with NTFS. 170 ==> 376473 - Can"t set empty IPTC country code when using metadata templates. 171 ==> 380289 - Cannot write to Albums residing on NFS. 172 ==> 384465 - With Compact Flash Card Created date in thumbnails is wrong. 173 ==> 381958 - Cannot add additional collection. 174 ==> 383747 - "Rotate only by setting a flag" Changes Image Instead. 175 ==> 387977 - No icon only view of "Extras sidebar": sidebar taking up a lot of space. 176 ==> 277502 - All versions of version set always displayed in Album view [patch]. 177 ==> 393283 - Caption not updating Exif.Image.ImageDescription field. 178 ==> 391060 - Crashes on undo of very large tif. 179 ==> 366305 - Add a message at startup about the lack of temporary space to perform Undo operations. 180 ==> 366391 - Rotating an image seems to forget to reset the orientation flag. 181 ==> 393654 - Not able to select gpx file. 182 ==> 367596 - Sub-folder count images but don't show them (unsupported JPEG file?). 183 ==> 379922 - Digikam won't remove tags set by Windows Explorer. 184 ==> 379081 - GPS data are in file but geolocation indicator is not shown and map view empty. 185 ==> 354819 - Specific pictures not showing up in digikam. 186 ==> 393855 - MySQL/MariaDB upgrade fails. 187 ==> 384603 - Camera Creation Date not set from EXIF data. 188 ==> 386959 - Properties view: wrong creation date [patch]. 189 ==> 393970 - No mts video thumbnails. 190 ==> 393728 - Reread metadata from Video uses sidecar only. 191 ==> 393925 - UpdateSchemaFromV7ToV9 fails due to duplicate key in album_2. 192 ==> 393773 - showfoto crashes when geotagging. 193 ==> 388199 - No context menu to copy coordinates from map. 194 ==> 393399 - Windows defender freaks out in windows 10 and Edge. 195 ==> 392134 - SIGSEGV While Scanning Faces [patch]. 196 ==> 394168 - OSM Search Yields No Results. 197 ==> 377719 - Cannot rename file with overwrite [patch]. 198 ==> 388002 - remove kio related legacy [patch] 199 ==> 394242 - Import settings unneccesarily asks to overwrite image database, and crashes when I decline. 200 ==> 394278 - A slideshow theme for kiosk mode. 201 ==> 340389 - digiKam crashes while editing pictures for color balancing on OSX [patch]. 202 ==> 394413 - Unify group handling [patch]. 203 ==> 394573 - Revers geodata from open street map does not work. 204 ==> 394590 - Feature request: being able to filter on all metadatas fields. 205 ==> 394671 - Distortion on Panasonic DMC-LX15. 206 ==> 393205 - Advanced rename very slow. 207 ==> 382474 - Thumbnail regeneration. 208 ==> 394865 - digikam suspicious crash on exit. 209 ==> 390541 - Tooltip background cannot be changed. 210 ==> 391521 - "Tool-tip" box difficult to read due to default color scheme. 211 ==> 377849 - Albums disappear when the network is interrupted. 212 ==> 394988 - PgDown and PgUp hardcoded in preview mode. 213 ==> 366312 - Efficient photo tagging workflow got lost in transition from 4.x to 5. 214 ==> 395093 - Being able to export a list of paths from a selection of thumbnails. 215 ==> 395144 - When zooming in preview, face tags show on wrong places. -216 ==> +216 ==> 275671 - Scan single image for faces. +217 ==> diff --git a/core/app/main/digikamapp.cpp b/core/app/main/digikamapp.cpp index c72836ae30..3cd8eb645f 100644 --- a/core/app/main/digikamapp.cpp +++ b/core/app/main/digikamapp.cpp @@ -1,931 +1,932 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2002-16-10 * Description : main digiKam interface implementation * * Copyright (C) 2002-2005 by Renchi Raju * Copyright (C) 2006 by Tom Albers * Copyright (C) 2009-2012 by Andi Clemens * Copyright (C) 2013 by Michael G. Hansen * Copyright (C) 2014-2015 by Mohamed_Anwer * Copyright (C) 2002-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. * * ============================================================ */ #include "digikamapp.h" #include "digikamapp_p.h" namespace Digikam { DigikamApp* DigikamApp::m_instance = 0; DigikamApp::DigikamApp() : DXmlGuiWindow(0), d(new Private) { setObjectName(QLatin1String("Digikam")); setConfigGroupName(ApplicationSettings::instance()->generalConfigGroupName()); setFullScreenOptions(FS_ALBUMGUI); setXMLFile(QLatin1String("digikamui5.rc")); m_instance = this; d->config = KSharedConfig::openConfig(); KConfigGroup group = d->config->group(configGroupName()); #ifdef HAVE_DBUS new DigikamAdaptor(this); QDBusConnection::sessionBus().registerObject(QLatin1String("/Digikam"), this); QDBusConnection::sessionBus().registerService(QLatin1String("org.kde.digikam-") + QString::number(QCoreApplication::instance()->applicationPid())); #endif // collection scan if (!CollectionScanner::databaseInitialScanDone()) { ScanController::instance()->completeCollectionScanDeferFiles(); } if (ApplicationSettings::instance()->getShowSplashScreen() && !qApp->isSessionRestored()) { d->splashScreen = new DSplashScreen(); d->splashScreen->show(); } else { // Windows need here QCoreApplication::processEvents(). qApp->processEvents(); } if (d->splashScreen) { d->splashScreen->setMessage(i18n("Initializing...")); } // ensure creation AlbumManager::instance(); LoadingCacheInterface::initialize(); IccSettings::instance()->loadAllProfilesProperties(); MetadataSettings::instance(); DMetadataSettings::instance(); ProgressManager::instance(); ThumbnailLoadThread::setDisplayingWidget(this); DIO::instance(); // creation of the engine on first use - when drawing - // can take considerable time and cause a noticeable hang in the UI thread. QFontMetrics fm(font()); fm.width(QLatin1String("a")); connect(ApplicationSettings::instance(), SIGNAL(setupChanged()), this, SLOT(slotSetupChanged())); connect(IccSettings::instance(), SIGNAL(settingsChanged()), this, SLOT(slotColorManagementOptionsChanged())); d->cameraMenu = new QMenu(this); d->usbMediaMenu = new QMenu(this); d->cardReaderMenu = new QMenu(this); d->quickImportMenu = new QMenu(this); d->cameraList = new CameraList(this, QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1String("/cameras.xml")); connect(d->cameraList, SIGNAL(signalCameraAdded(CameraType*)), this, SLOT(slotCameraAdded(CameraType*))); connect(d->cameraList, SIGNAL(signalCameraRemoved(QAction*)), this, SLOT(slotCameraRemoved(QAction*))); d->modelCollection = new DigikamModelCollection; // This manager must be created after collection setup and before accelerators setup. d->tagsActionManager = new TagsActionMngr(this); // First create everything, then connect. // Otherwise some items may send signals and the slots can try // to access items which were not created yet. setupView(); setupAccelerators(); setupActions(); setupStatusBar(); initGui(); setupViewConnections(); applyMainWindowSettings(group); slotColorManagementOptionsChanged(); // Check ICC profiles repository availability if (d->splashScreen) { d->splashScreen->setMessage(i18n("Checking ICC repository...")); } d->validIccPath = SetupICC::iccRepositoryIsValid(); // Read albums from database if (d->splashScreen) { d->splashScreen->setMessage(i18n("Reading database...")); } AlbumManager::instance()->startScan(); // Setting the initial menu options after all tools have been loaded QList albumList = AlbumManager::instance()->currentAlbums(); d->view->slotAlbumSelected(albumList); // preload additional windows preloadWindows(); readFullScreenSettings(group); #ifdef HAVE_KFILEMETADATA // Create BalooWrap object, because it need to register a listener // to update digiKam data when changes in Baloo occur BalooWrap* const baloo = BalooWrap::instance(); Q_UNUSED(baloo); #endif //HAVE_KFILEMETADATA setAutoSaveSettings(group, true); LoadSaveThread::setInfoProvider(new DatabaseLoadSaveFileInfoProvider); setupSelectToolsAction(); } DigikamApp::~DigikamApp() { ProgressManager::instance()->slotAbortAll(); ImageAttributesWatch::shutDown(); // Close and delete image editor instance. if (ImageWindow::imageWindowCreated()) { // Delete after close ImageWindow::imageWindow()->setAttribute(Qt::WA_DeleteOnClose, true); // close the window ImageWindow::imageWindow()->close(); } // Close and delete light table instance. if (LightTableWindow::lightTableWindowCreated()) { LightTableWindow::lightTableWindow()->setAttribute(Qt::WA_DeleteOnClose, true); LightTableWindow::lightTableWindow()->close(); } // Close and delete Batch Queue Manager instance. if (QueueMgrWindow::queueManagerWindowCreated()) { QueueMgrWindow::queueManagerWindow()->setAttribute(Qt::WA_DeleteOnClose, true); QueueMgrWindow::queueManagerWindow()->close(); } if (TagsManager::isCreated()) { TagsManager::instance()->close(); } if (MetadataHubMngr::isCreated()) { delete MetadataHubMngr::internalPtr; } #ifdef HAVE_KFILEMETADATA if (BalooWrap::isCreated()) { BalooWrap::internalPtr.clear(); } #endif if (ExpoBlendingManager::isCreated()) { delete ExpoBlendingManager::internalPtr; } #ifdef HAVE_PANORAMA if (PanoManager::isCreated()) { delete PanoManager::internalPtr; } #endif delete d->view; ApplicationSettings::instance()->setRecurseAlbums(d->recurseAlbumsAction->isChecked()); ApplicationSettings::instance()->setRecurseTags(d->recurseTagsAction->isChecked()); ApplicationSettings::instance()->setShowThumbbar(d->showBarAction->isChecked()); ApplicationSettings::instance()->saveSettings(); ScanController::instance()->shutDown(); AlbumManager::instance()->cleanUp(); ImageAttributesWatch::cleanUp(); ThumbnailLoadThread::cleanUp(); AlbumThumbnailLoader::instance()->cleanUp(); LoadingCacheInterface::cleanUp(); DIO::cleanUp(); DMediaServerMngr::instance()->saveAtShutdown(); // close database server if (ApplicationSettings::instance()->getDbEngineParameters().internalServer) { DatabaseServerStarter::instance()->stopServerManagerProcess(); } AlbumManager::instance()->removeFakeConnection(); m_instance = 0; delete d->modelCollection; delete d; } DigikamApp* DigikamApp::instance() { return m_instance; } DigikamView* DigikamApp::view() const { return d->view; } void DigikamApp::show() { // Remove Splashscreen. if (d->splashScreen) { d->splashScreen->finish(this); delete d->splashScreen; d->splashScreen = 0; } // Display application window. KMainWindow::show(); // Report errors from ICC repository path. if (!d->validIccPath) { QString message = i18n("

The ICC profiles folder seems to be invalid.

" "

If you want to try setting it again, choose \"Yes\" here, otherwise " "choose \"No\", and the \"Color Management\" feature " "will be disabled until you solve this issue.

"); if (QMessageBox::warning(this, qApp->applicationName(), message, QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { if (!setupICC()) { d->config->group(QLatin1String("Color Management")).writeEntry(QLatin1String("EnableCM"), false); d->config->sync(); } } else { d->config->group(QLatin1String("Color Management")).writeEntry(QLatin1String("EnableCM"), false); d->config->sync(); } } // Init album icon view zoom factor. slotThumbSizeChanged(ApplicationSettings::instance()->getDefaultIconSize()); slotZoomSliderChanged(ApplicationSettings::instance()->getDefaultIconSize()); d->autoShowZoomToolTip = true; // Enable finished the collection scan as deferred process if (ApplicationSettings::instance()->getScanAtStart() || !CollectionScanner::databaseInitialScanDone()) { NewItemsFinder* const tool = new NewItemsFinder(NewItemsFinder::ScanDeferredFiles); QTimer::singleShot(1000, tool, SLOT(start())); } if (ApplicationSettings::instance()->getCleanAtStart()) { DbCleaner* const tool = new DbCleaner(false,false); QTimer::singleShot(1000, tool, SLOT(start())); } // Start the Media Server if necessary DMediaServerMngr::instance()->loadAtStartup(); } void DigikamApp::restoreSession() { //TODO: show and restore ImageEditor, Lighttable, and Batch Queue Manager main windows if (qApp->isSessionRestored()) { int n = 1; while (KMainWindow::canBeRestored(n)) { const QString className = KMainWindow::classNameOfToplevel(n); if (className == QLatin1String(Digikam::DigikamApp::staticMetaObject.className())) { restore(n, false); break; } ++n; } } } void DigikamApp::closeEvent(QCloseEvent* e) { // may show a progress dialog to finish actions FileActionMngr::instance()->requestShutDown(); // may show a progress dialog to apply pending metadata if (MetadataHubMngr::isCreated()) MetadataHubMngr::instance()->requestShutDown(); DXmlGuiWindow::closeEvent(e); e->accept(); } bool DigikamApp::queryClose() { bool ret = true; if (ImageWindow::imageWindowCreated()) { ret &= ImageWindow::imageWindow()->queryClose(); } if (QueueMgrWindow::queueManagerWindowCreated()) { ret &= QueueMgrWindow::queueManagerWindow()->queryClose(); } return ret; } void DigikamApp::enableZoomPlusAction(bool val) { d->zoomPlusAction->setEnabled(val); } void DigikamApp::enableZoomMinusAction(bool val) { d->zoomMinusAction->setEnabled(val); } void DigikamApp::enableAlbumBackwardHistory(bool enable) { d->backwardActionMenu->setEnabled(enable); } void DigikamApp::enableAlbumForwardHistory(bool enable) { d->forwardActionMenu->setEnabled(enable); } void DigikamApp::slotAboutToShowBackwardMenu() { d->backwardActionMenu->menu()->clear(); QStringList titles; d->view->getBackwardHistory(titles); for (int i = 0; i < titles.size(); ++i) { QAction* const action = d->backwardActionMenu->menu()->addAction(titles.at(i), d->backwardSignalMapper, SLOT(map())); d->backwardSignalMapper->setMapping(action, i + 1); } } void DigikamApp::slotAboutToShowForwardMenu() { d->forwardActionMenu->menu()->clear(); QStringList titles; d->view->getForwardHistory(titles); for (int i = 0; i < titles.size(); ++i) { QAction* const action = d->forwardActionMenu->menu()->addAction(titles.at(i), d->forwardSignalMapper, SLOT(map())); d->forwardSignalMapper->setMapping(action, i + 1); } } void DigikamApp::slotAlbumSelected(Album* album) { if (album) { PAlbum* const palbum = dynamic_cast(album); if (album->type() != Album::PHYSICAL || !palbum) { // Rules if not Physical album. d->deleteAction->setEnabled(false); d->renameAction->setEnabled(false); d->addImagesAction->setEnabled(false); d->propsEditAction->setEnabled(false); d->openInFileManagerAction->setEnabled(false); d->newAction->setEnabled(false); d->addFoldersAction->setEnabled(false); d->writeAlbumMetadataAction->setEnabled(true); d->readAlbumMetadataAction->setEnabled(true); d->pasteItemsAction->setEnabled(!album->isRoot()); // Special case if Tag album. bool enabled = (album->type() == Album::TAG) && !album->isRoot(); d->newTagAction->setEnabled(enabled); d->deleteTagAction->setEnabled(enabled); d->editTagAction->setEnabled(enabled); } else { // Rules if Physical album. // We have either the abstract root album, // the album root album for collection base dirs, or normal albums. bool isRoot = palbum->isRoot(); bool isAlbumRoot = palbum->isAlbumRoot(); bool isNormalAlbum = !isRoot && !isAlbumRoot; d->deleteAction->setEnabled(isNormalAlbum); d->renameAction->setEnabled(isNormalAlbum); d->addImagesAction->setEnabled(isNormalAlbum || isAlbumRoot); d->propsEditAction->setEnabled(isNormalAlbum); d->openInFileManagerAction->setEnabled(isNormalAlbum || isAlbumRoot); d->newAction->setEnabled(isNormalAlbum || isAlbumRoot); d->addFoldersAction->setEnabled(isNormalAlbum || isAlbumRoot); d->writeAlbumMetadataAction->setEnabled(isNormalAlbum || isAlbumRoot); d->readAlbumMetadataAction->setEnabled(isNormalAlbum || isAlbumRoot); d->pasteItemsAction->setEnabled(isNormalAlbum || isAlbumRoot); } } else { // Rules if no current album. d->deleteAction->setEnabled(false); d->renameAction->setEnabled(false); d->addImagesAction->setEnabled(false); d->propsEditAction->setEnabled(false); d->openInFileManagerAction->setEnabled(false); d->newAction->setEnabled(false); d->addFoldersAction->setEnabled(false); d->writeAlbumMetadataAction->setEnabled(false); d->readAlbumMetadataAction->setEnabled(false); d->pasteItemsAction->setEnabled(false); d->newTagAction->setEnabled(false); d->deleteTagAction->setEnabled(false); d->editTagAction->setEnabled(false); } } void DigikamApp::slotImageSelected(const ImageInfoList& selection, const ImageInfoList& listAll) { int numImagesWithGrouped = listAll.count(); int numImagesWithoutGrouped = d->view->allUrls(false).count(); ImageInfoList selectionWithoutGrouped = d->view->selectedInfoList(true, false); QString statusBarSelectionText; QString statusBarSelectionToolTip; switch (selection.count()) { case 0: { if (numImagesWithGrouped == numImagesWithoutGrouped) { statusBarSelectionText = i18np("No item selected (%1 item)", "No item selected (%1 items)", numImagesWithoutGrouped); break; } statusBarSelectionText = i18np("No item selected (%1 [%2] item)", "No item selected (%1 [%2] items)", numImagesWithoutGrouped, numImagesWithGrouped); statusBarSelectionToolTip = i18np("No item selected (%1 item. With grouped items: %2)", "No item selected (%1 items. With grouped items: %2)", numImagesWithoutGrouped, numImagesWithGrouped); break; } default: { if (numImagesWithGrouped == numImagesWithoutGrouped) { statusBarSelectionText = i18n("%1/%2 items selected", selection.count(), numImagesWithoutGrouped); break; } if (selectionWithoutGrouped.count() > 1) { if (selection.count() == selectionWithoutGrouped.count()) { statusBarSelectionText = i18n("%1/%2 [%3] items selected", selectionWithoutGrouped.count(), numImagesWithoutGrouped, numImagesWithGrouped); statusBarSelectionToolTip = i18n("%1/%2 items selected. Total with grouped items: %3", selectionWithoutGrouped.count(), numImagesWithoutGrouped, numImagesWithGrouped); } else { statusBarSelectionText = i18n("%1/%2 [%3/%4] items selected", selectionWithoutGrouped.count(), numImagesWithoutGrouped, selection.count(), numImagesWithGrouped); statusBarSelectionToolTip = i18n("%1/%2 items selected. With grouped items: %3/%4", selectionWithoutGrouped.count(), numImagesWithoutGrouped, selection.count(), numImagesWithGrouped); } break; } #if __GNUC__ >= 7 // krazy:exclude=cpp // no break; is completely intentional, arriving here is equivalent to case 1: [[fallthrough]]; #endif } case 1: { slotSetCheckedExifOrientationAction(selectionWithoutGrouped.first()); int index = listAll.indexOf(selection.first()) + 1; if (numImagesWithGrouped == numImagesWithoutGrouped) { statusBarSelectionText = selection.first().fileUrl().fileName() + i18n(" (%1 of %2)", index, numImagesWithoutGrouped); } else { int indexWithoutGrouped = d->view->allInfo(false).indexOf(selectionWithoutGrouped.first()) + 1; statusBarSelectionText = selection.first().fileUrl().fileName() + i18n(" (%1 of %2 [%3])", indexWithoutGrouped, numImagesWithoutGrouped, numImagesWithGrouped); statusBarSelectionToolTip = selection.first().fileUrl().fileName() + i18n(" (%1 of %2. Total with grouped items: %3)", indexWithoutGrouped, numImagesWithoutGrouped, numImagesWithGrouped); } break; } } d->statusLabel->setAdjustedText(statusBarSelectionText); d->statusLabel->setToolTip(statusBarSelectionToolTip); } void DigikamApp::slotSelectionChanged(int selectionCount) { // The preview can either be activated when only one image is selected, // or if multiple images are selected, but one image is the 'current image'. bool hasAtLeastCurrent =(selectionCount == 1) || ( (selectionCount > 0) && d->view->hasCurrentItem()); d->imagePreviewAction->setEnabled(hasAtLeastCurrent); d->imageViewAction->setEnabled(hasAtLeastCurrent); + d->imageScanForFacesAction->setEnabled(selectionCount > 0); d->imageFindSimilarAction->setEnabled(selectionCount == 1); d->imageRenameAction->setEnabled(selectionCount > 0); d->imageLightTableAction->setEnabled(selectionCount > 0); d->imageAddLightTableAction->setEnabled(selectionCount > 0); d->imageAddCurrentQueueAction->setEnabled((selectionCount > 0) && !QueueMgrWindow::queueManagerWindow()->isBusy()); d->imageAddNewQueueAction->setEnabled((selectionCount > 0) && !QueueMgrWindow::queueManagerWindow()->isBusy()); d->imageWriteMetadataAction->setEnabled(selectionCount > 0); d->imageReadMetadataAction->setEnabled(selectionCount > 0); d->imageDeleteAction->setEnabled(selectionCount > 0); d->imageRotateActionMenu->setEnabled(selectionCount > 0); d->imageFlipActionMenu->setEnabled(selectionCount > 0); d->imageExifOrientationActionMenu->setEnabled(selectionCount > 0); d->slideShowSelectionAction->setEnabled(selectionCount > 0); d->moveSelectionToAlbumAction->setEnabled(selectionCount > 0); d->cutItemsAction->setEnabled(selectionCount > 0); d->copyItemsAction->setEnabled(selectionCount > 0); m_metadataEditAction->setEnabled(selectionCount > 0); d->openWithAction->setEnabled(selectionCount > 0); d->imageAutoExifActionMenu->setEnabled(selectionCount > 0); #ifdef HAVE_MARBLE m_geolocationEditAction->setEnabled(selectionCount > 0); #endif if (selectionCount > 0) { d->imageWriteMetadataAction->setText(i18np("Write Metadata to File", "Write Metadata to Selected Files", selectionCount)); d->imageReadMetadataAction->setText(i18np("Reread Metadata From File", "Reread Metadata From Selected Files", selectionCount)); slotResetExifOrientationActions(); } } void DigikamApp::slotExit() { close(); } void DigikamApp::slotDBStat() { showDigikamDatabaseStat(); } void DigikamApp::slotRecurseAlbums(bool checked) { d->view->setRecurseAlbums(checked); } void DigikamApp::slotRecurseTags(bool checked) { d->view->setRecurseTags(checked); } void DigikamApp::slotZoomSliderChanged(int size) { d->view->setThumbSize(size); } void DigikamApp::slotThumbSizeChanged(int size) { d->zoomBar->setThumbsSize(size); if (!fullScreenIsActive() && d->autoShowZoomToolTip) { d->zoomBar->triggerZoomTrackerToolTip(); } } void DigikamApp::slotZoomChanged(double zoom) { double zmin = d->view->zoomMin(); double zmax = d->view->zoomMax(); d->zoomBar->setZoom(zoom, zmin, zmax); if (!fullScreenIsActive() && d->autoShowZoomToolTip) { d->zoomBar->triggerZoomTrackerToolTip(); } } void DigikamApp::slotToggleShowBar() { d->view->toggleShowBar(d->showBarAction->isChecked()); } void DigikamApp::moveEvent(QMoveEvent*) { emit signalWindowHasMoved(); } void DigikamApp::slotTransformAction() { if (sender()->objectName() == QLatin1String("rotate_ccw")) { d->view->imageTransform(MetaEngineRotation::Rotate270); } else if (sender()->objectName() == QLatin1String("rotate_cw")) { d->view->imageTransform(MetaEngineRotation::Rotate90); } else if (sender()->objectName() == QLatin1String("flip_horizontal")) { d->view->imageTransform(MetaEngineRotation::FlipHorizontal); } else if (sender()->objectName() == QLatin1String("flip_vertical")) { d->view->imageTransform(MetaEngineRotation::FlipVertical); } else if (sender()->objectName() == QLatin1String("image_transform_exif")) { // special value for FileActionMngr d->view->imageTransform(MetaEngineRotation::NoTransformation); } } void DigikamApp::slotResetExifOrientationActions() { d->imageSetExifOrientation1Action->setChecked(false); d->imageSetExifOrientation2Action->setChecked(false); d->imageSetExifOrientation3Action->setChecked(false); d->imageSetExifOrientation4Action->setChecked(false); d->imageSetExifOrientation5Action->setChecked(false); d->imageSetExifOrientation6Action->setChecked(false); d->imageSetExifOrientation7Action->setChecked(false); d->imageSetExifOrientation8Action->setChecked(false); } void DigikamApp::slotSetCheckedExifOrientationAction(const ImageInfo& info) { //DMetadata meta(info.fileUrl().toLocalFile()); //int orientation = (meta.isEmpty()) ? 0 : meta.getImageOrientation(); int orientation = info.orientation(); switch (orientation) { case 1: d->imageSetExifOrientation1Action->setChecked(true); break; case 2: d->imageSetExifOrientation2Action->setChecked(true); break; case 3: d->imageSetExifOrientation3Action->setChecked(true); break; case 4: d->imageSetExifOrientation4Action->setChecked(true); break; case 5: d->imageSetExifOrientation5Action->setChecked(true); break; case 6: d->imageSetExifOrientation6Action->setChecked(true); break; case 7: d->imageSetExifOrientation7Action->setChecked(true); break; case 8: d->imageSetExifOrientation8Action->setChecked(true); break; default: slotResetExifOrientationActions(); break; } } QMenu* DigikamApp::slideShowMenu() const { return d->slideShowAction; } void DigikamApp::showSideBars(bool visible) { visible ? d->view->showSideBars() : d->view->hideSideBars(); } void DigikamApp::slotToggleLeftSideBar() { d->view->toggleLeftSidebar(); } void DigikamApp::slotToggleRightSideBar() { d->view->toggleRightSidebar(); } void DigikamApp::slotPreviousLeftSideBarTab() { d->view->previousLeftSideBarTab(); } void DigikamApp::slotNextLeftSideBarTab() { d->view->nextLeftSideBarTab(); } void DigikamApp::slotNextRightSideBarTab() { d->view->nextRightSideBarTab(); } void DigikamApp::slotPreviousRightSideBarTab() { d->view->previousRightSideBarTab(); } void DigikamApp::showThumbBar(bool visible) { view()->toggleShowBar(visible); } bool DigikamApp::thumbbarVisibility() const { return d->showBarAction->isChecked(); } void DigikamApp::slotSwitchedToPreview() { d->imagePreviewAction->setChecked(true); d->zoomBar->setBarMode(DZoomBar::PreviewZoomCtrl); toggleShowBar(); } void DigikamApp::slotSwitchedToIconView() { d->zoomBar->setBarMode(DZoomBar::ThumbsSizeCtrl); d->imageIconViewAction->setChecked(true); toggleShowBar(); } void DigikamApp::slotSwitchedToMapView() { //TODO: Link to map view's zoom actions d->zoomBar->setBarMode(DZoomBar::ThumbsSizeCtrl); #ifdef HAVE_MARBLE d->imageMapViewAction->setChecked(true); #endif // HAVE_MARBLE toggleShowBar(); } void DigikamApp::slotSwitchedToTableView() { d->zoomBar->setBarMode(DZoomBar::ThumbsSizeCtrl); d->imageTableViewAction->setChecked(true); toggleShowBar(); } void DigikamApp::slotSwitchedToTrashView() { d->zoomBar->setBarMode(DZoomBar::ThumbsSizeCtrl); // TODO: disable all other views toggleShowBar(); } void DigikamApp::customizedFullScreenMode(bool set) { toolBarMenuAction()->setEnabled(!set); showMenuBarAction()->setEnabled(!set); showStatusBarAction()->setEnabled(!set); set ? d->showBarAction->setEnabled(false) : toggleShowBar(); d->view->toggleFullScreen(set); } void DigikamApp::toggleShowBar() { switch (d->view->viewMode()) { case StackedView::PreviewImageMode: case StackedView::MediaPlayerMode: d->showBarAction->setEnabled(true); break; default: d->showBarAction->setEnabled(false); break; } } void DigikamApp::slotComponentsInfo() { showDigikamComponentsInfo(); } void DigikamApp::slotToggleColorManagedView() { if (!IccSettings::instance()->isEnabled()) { return; } bool cmv = !IccSettings::instance()->settings().useManagedPreviews; IccSettings::instance()->setUseManagedPreviews(cmv); } void DigikamApp::slotColorManagementOptionsChanged() { ICCSettingsContainer settings = IccSettings::instance()->settings(); d->viewCMViewAction->blockSignals(true); d->viewCMViewAction->setEnabled(settings.enableCM); d->viewCMViewAction->setChecked(settings.useManagedPreviews); d->viewCMViewAction->blockSignals(false); } } // namespace Digikam diff --git a/core/app/main/digikamapp_p.h b/core/app/main/digikamapp_p.h index 724fadb66e..d76534740c 100644 --- a/core/app/main/digikamapp_p.h +++ b/core/app/main/digikamapp_p.h @@ -1,461 +1,463 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2007-31-01 * Description : main digiKam interface implementation * * Copyright (C) 2007-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_APP_PRIVATE_H #define DIGIKAM_APP_PRIVATE_H // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include #include #include #include #include #include // Local includes #include "digikam_config.h" #include "digikam_debug.h" #include "albummanager.h" #include "applicationsettings.h" #include "cameralist.h" #include "cameratype.h" #include "cameranamehelper.h" #include "dsplashscreen.h" #include "dzoombar.h" #include "digikamview.h" #include "metadatastatusbar.h" #include "imagepropertiestab.h" #include "importui.h" #include "setup.h" #include "actioncategorizedview.h" #include "drawdecoder.h" #include "dlayoutbox.h" #include "album.h" #include "coredb.h" #include "albummodel.h" #include "albumselectdialog.h" #include "albumthumbnailloader.h" #include "dbinfoiface.h" #include "imagegps.h" #include "categorizeditemmodel.h" #include "collectionscanner.h" #include "collectionmanager.h" #include "componentsinfo.h" #include "coredbthumbinfoprovider.h" #include "dio.h" #include "dlogoaction.h" #include "fileactionmngr.h" #include "filterstatusbar.h" #include "iccsettings.h" #include "imageattributeswatch.h" #include "imageinfo.h" #include "imagewindow.h" #include "lighttablewindow.h" #include "queuemgrwindow.h" #include "loadingcache.h" #include "loadingcacheinterface.h" #include "loadsavethread.h" #include "metaengine_rotation.h" #include "scancontroller.h" #include "setupeditor.h" #include "setupicc.h" #include "thememanager.h" #include "thumbnailloadthread.h" #include "thumbnailsize.h" #include "dmetadata.h" #include "tagscache.h" #include "tagsactionmngr.h" #include "databaseserverstarter.h" #include "metadatasettings.h" #include "statusbarprogresswidget.h" #include "dbmigrationdlg.h" #include "progressmanager.h" #include "progressview.h" #include "maintenancedlg.h" #include "maintenancemngr.h" #include "newitemsfinder.h" #include "dbcleaner.h" #include "tagsmanager.h" #include "imagesortsettings.h" #include "metadatahubmngr.h" #include "metadataedit.h" #include "expoblendingmanager.h" #include "calwizard.h" #include "mailwizard.h" #include "advprintwizard.h" #include "dfiledialog.h" #include "dmediaservermngr.h" #include "dmediaserverdlg.h" #include "dbwindow.h" #include "fbwindow.h" #include "flickrwindow.h" #include "gswindow.h" #include "imageshackwindow.h" #include "imgurwindow.h" #include "piwigowindow.h" #include "rajcewindow.h" #include "smugwindow.h" #include "yfwindow.h" #ifdef HAVE_MEDIAWIKI # include "mediawikiwindow.h" #endif #ifdef HAVE_VKONTAKTE # include "vkwindow.h" #endif #ifdef HAVE_KIO # include "ftexportwindow.h" # include "ftimportwindow.h" #endif #ifdef HAVE_MARBLE # include "geolocationedit.h" #endif #ifdef HAVE_HTMLGALLERY # include "htmlwizard.h" #endif #ifdef HAVE_DBUS # include "digikamadaptor.h" #endif #ifdef HAVE_PANORAMA # include "panomanager.h" #endif #ifdef HAVE_MEDIAPLAYER # include "vidslidewizard.h" #endif #ifdef HAVE_KFILEMETADATA # include "baloowrap.h" #endif class KToolBarPopupAction; namespace Digikam { class SearchTextBar; class FilterStatusBar; class TagsActionMngr; class DAdjustableLabel; class ProgressEntry { public: explicit ProgressEntry() : progress(0), canCancel(false) { } QString message; float progress; bool canCancel; }; // ------------------------------------------------------------------------------ class DigikamApp::Private { public: explicit Private() : autoShowZoomToolTip(false), validIccPath(true), cameraMenu(0), usbMediaMenu(0), cardReaderMenu(0), quickImportMenu(0), config(0), newAction(0), moveSelectionToAlbumAction(0), deleteAction(0), renameAction(0), imageDeletePermanentlyAction(0), imageDeletePermanentlyDirectlyAction(0), imageTrashDirectlyAction(0), backwardActionMenu(0), forwardActionMenu(0), addImagesAction(0), propsEditAction(0), addFoldersAction(0), openInFileManagerAction(0), refreshAction(0), writeAlbumMetadataAction(0), readAlbumMetadataAction(0), browseTagsAction(0), openTagMngrAction(0), newTagAction(0), deleteTagAction(0), editTagAction(0), assignTagAction(0), imageViewSelectionAction(0), imagePreviewAction(0), #ifdef HAVE_MARBLE imageMapViewAction(0), #endif // HAVE_MARBLE imageTableViewAction(0), imageIconViewAction(0), imageLightTableAction(0), imageAddLightTableAction(0), imageAddCurrentQueueAction(0), imageAddNewQueueAction(0), imageViewAction(0), imageWriteMetadataAction(0), imageReadMetadataAction(0), + imageScanForFacesAction(0), imageFindSimilarAction(0), imageSetExifOrientation1Action(0), imageSetExifOrientation2Action(0), imageSetExifOrientation3Action(0), imageSetExifOrientation4Action(0), imageSetExifOrientation5Action(0), imageSetExifOrientation6Action(0), imageSetExifOrientation7Action(0), imageSetExifOrientation8Action(0), imageRenameAction(0), imageRotateActionMenu(0), imageFlipActionMenu(0), imageAutoExifActionMenu(0), imageDeleteAction(0), imageExifOrientationActionMenu(0), openWithAction(0), ieAction(0), ltAction(0), cutItemsAction(0), copyItemsAction(0), pasteItemsAction(0), selectAllAction(0), selectNoneAction(0), selectInvertAction(0), zoomPlusAction(0), zoomMinusAction(0), zoomFitToWindowAction(0), zoomTo100percents(0), imageSortAction(0), imageSortOrderAction(0), imageSeparationAction(0), imageSeparationSortOrderAction(0), albumSortAction(0), recurseAlbumsAction(0), recurseTagsAction(0), showBarAction(0), viewCMViewAction(0), slideShowAction(0), slideShowAllAction(0), slideShowSelectionAction(0), slideShowRecursiveAction(0), bqmAction(0), maintenanceAction(0), qualityAction(0), advSearchAction(0), addCameraSeparatorAction(0), quitAction(0), tipAction(0), backwardSignalMapper(0), forwardSignalMapper(0), manualCameraActionGroup(0), solidCameraActionGroup(0), solidUsmActionGroup(0), exifOrientationActionGroup(0), eventLoop(0), metadataStatusBar(0), filterStatusBar(0), splashScreen(0), view(0), cameraList(0), tagsActionManager(0), zoomBar(0), statusLabel(0), modelCollection(0) { } bool autoShowZoomToolTip; bool validIccPath; QMenu* cameraMenu; QMenu* usbMediaMenu; QMenu* cardReaderMenu; QMenu* quickImportMenu; QHash cameraAppearanceTimes; KSharedConfig::Ptr config; // Album Actions QAction* newAction; QAction* moveSelectionToAlbumAction; QAction* deleteAction; QAction* renameAction; QAction* imageDeletePermanentlyAction; QAction* imageDeletePermanentlyDirectlyAction; QAction* imageTrashDirectlyAction; KToolBarPopupAction* backwardActionMenu; KToolBarPopupAction* forwardActionMenu; QAction* addImagesAction; QAction* propsEditAction; QAction* addFoldersAction; QAction* openInFileManagerAction; QAction* refreshAction; QAction* writeAlbumMetadataAction; QAction* readAlbumMetadataAction; // Tag Actions QAction* browseTagsAction; QAction* openTagMngrAction; QAction* newTagAction; QAction* deleteTagAction; QAction* editTagAction; QAction* assignTagAction; // Image Actions KSelectAction* imageViewSelectionAction; QAction* imagePreviewAction; #ifdef HAVE_MARBLE QAction* imageMapViewAction; #endif // HAVE_MARBLE QAction* imageTableViewAction; QAction* imageIconViewAction; QAction* imageLightTableAction; QAction* imageAddLightTableAction; QAction* imageAddCurrentQueueAction; QAction* imageAddNewQueueAction; QAction* imageViewAction; QAction* imageWriteMetadataAction; QAction* imageReadMetadataAction; + QAction* imageScanForFacesAction; QAction* imageFindSimilarAction; QAction* imageSetExifOrientation1Action; QAction* imageSetExifOrientation2Action; QAction* imageSetExifOrientation3Action; QAction* imageSetExifOrientation4Action; QAction* imageSetExifOrientation5Action; QAction* imageSetExifOrientation6Action; QAction* imageSetExifOrientation7Action; QAction* imageSetExifOrientation8Action; QAction* imageRenameAction; QMenu* imageRotateActionMenu; QMenu* imageFlipActionMenu; QAction* imageAutoExifActionMenu; QAction* imageDeleteAction; QMenu* imageExifOrientationActionMenu; QAction* openWithAction; QAction* ieAction; QAction* ltAction; // Edit Actions QAction* cutItemsAction; QAction* copyItemsAction; QAction* pasteItemsAction; QAction* selectAllAction; QAction* selectNoneAction; QAction* selectInvertAction; // View Actions QAction* zoomPlusAction; QAction* zoomMinusAction; QAction* zoomFitToWindowAction; QAction* zoomTo100percents; KSelectAction* imageSortAction; KSelectAction* imageSortOrderAction; KSelectAction* imageSeparationAction; KSelectAction* imageSeparationSortOrderAction; KSelectAction* albumSortAction; QAction* recurseAlbumsAction; QAction* recurseTagsAction; QAction* showBarAction; QAction* viewCMViewAction; // Tools Actions QMenu* slideShowAction; QAction* slideShowAllAction; QAction* slideShowSelectionAction; QAction* slideShowRecursiveAction; QAction* bqmAction; QAction* maintenanceAction; QAction* qualityAction; QAction* advSearchAction; // Application Actions QAction* addCameraSeparatorAction; QAction* quitAction; QAction* tipAction; QSignalMapper* backwardSignalMapper; QSignalMapper* forwardSignalMapper; QActionGroup* manualCameraActionGroup; QActionGroup* solidCameraActionGroup; QActionGroup* solidUsmActionGroup; QActionGroup* exifOrientationActionGroup; QMap > cameraUIMap; QEventLoop* eventLoop; QString solidErrorMessage; MetadataStatusBar* metadataStatusBar; FilterStatusBar* filterStatusBar; DSplashScreen* splashScreen; DigikamView* view; CameraList* cameraList; TagsActionMngr* tagsActionManager; DZoomBar* zoomBar; DAdjustableLabel* statusLabel; DigikamModelCollection* modelCollection; }; } // namespace Digikam #endif // DIGIKAM_APP_PRIVATE_H diff --git a/core/app/main/digikamapp_setup.cpp b/core/app/main/digikamapp_setup.cpp index c48160928c..d43bcb8f00 100644 --- a/core/app/main/digikamapp_setup.cpp +++ b/core/app/main/digikamapp_setup.cpp @@ -1,1099 +1,1106 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2002-16-10 * Description : main digiKam interface implementation - Internal setup * * Copyright (C) 2002-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. * * ============================================================ */ #include "digikamapp.h" #include "digikamapp_p.h" namespace Digikam { void DigikamApp::rebuild() { QString file = xmlFile(); if (!file.isEmpty()) { setXMLGUIBuildDocument(QDomDocument()); loadStandardsXmlFile(); setXMLFile(file, true); } } void DigikamApp::setupView() { if (d->splashScreen) { d->splashScreen->setMessage(i18n("Initializing Main View...")); } d->view = new DigikamView(this, d->modelCollection); setCentralWidget(d->view); d->view->applySettings(); } void DigikamApp::setupViewConnections() { connect(d->view, SIGNAL(signalAlbumSelected(Album*)), this, SLOT(slotAlbumSelected(Album*))); connect(d->view, SIGNAL(signalSelectionChanged(int)), this, SLOT(slotSelectionChanged(int))); connect(d->view, SIGNAL(signalImageSelected(ImageInfoList,ImageInfoList)), this, SLOT(slotImageSelected(ImageInfoList,ImageInfoList))); connect(d->view, SIGNAL(signalSwitchedToPreview()), this, SLOT(slotSwitchedToPreview())); connect(d->view, SIGNAL(signalSwitchedToIconView()), this, SLOT(slotSwitchedToIconView())); connect(d->view, SIGNAL(signalSwitchedToMapView()), this, SLOT(slotSwitchedToMapView())); connect(d->view, SIGNAL(signalSwitchedToTableView()), this, SLOT(slotSwitchedToTableView())); connect(d->view, SIGNAL(signalSwitchedToTrashView()), this, SLOT(slotSwitchedToTrashView())); } void DigikamApp::setupStatusBar() { d->statusLabel = new DAdjustableLabel(statusBar()); d->statusLabel->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); statusBar()->addWidget(d->statusLabel, 80); //------------------------------------------------------------------------------ d->metadataStatusBar = new MetadataStatusBar(statusBar()); statusBar()->addWidget(d->metadataStatusBar, 50); //------------------------------------------------------------------------------ d->filterStatusBar = new FilterStatusBar(statusBar()); statusBar()->addWidget(d->filterStatusBar, 50); d->view->connectIconViewFilter(d->filterStatusBar); //------------------------------------------------------------------------------ ProgressView* const view = new ProgressView(statusBar(), this); view->hide(); StatusbarProgressWidget* const littleProgress = new StatusbarProgressWidget(view, statusBar()); littleProgress->show(); statusBar()->addPermanentWidget(littleProgress); //------------------------------------------------------------------------------ d->zoomBar = new DZoomBar(statusBar()); d->zoomBar->setZoomToFitAction(d->zoomFitToWindowAction); d->zoomBar->setZoomTo100Action(d->zoomTo100percents); d->zoomBar->setZoomPlusAction(d->zoomPlusAction); d->zoomBar->setZoomMinusAction(d->zoomMinusAction); d->zoomBar->setBarMode(DZoomBar::ThumbsSizeCtrl); statusBar()->addPermanentWidget(d->zoomBar); //------------------------------------------------------------------------------ connect(d->zoomBar, SIGNAL(signalZoomSliderChanged(int)), this, SLOT(slotZoomSliderChanged(int))); connect(this, SIGNAL(signalWindowHasMoved()), d->zoomBar, SLOT(slotUpdateTrackerPos())); connect(d->zoomBar, SIGNAL(signalZoomValueEdited(double)), d->view, SLOT(setZoomFactor(double))); connect(d->view, SIGNAL(signalZoomChanged(double)), this, SLOT(slotZoomChanged(double))); connect(d->view, SIGNAL(signalThumbSizeChanged(int)), this, SLOT(slotThumbSizeChanged(int))); } void DigikamApp::setupActions() { KActionCollection* const ac = actionCollection(); d->solidCameraActionGroup = new QActionGroup(this); connect(d->solidCameraActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(slotOpenSolidCamera(QAction*))); d->solidUsmActionGroup = new QActionGroup(this); connect(d->solidUsmActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(slotOpenSolidUsmDevice(QAction*))); d->manualCameraActionGroup = new QActionGroup(this); connect(d->manualCameraActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(slotOpenManualCamera(QAction*))); // ----------------------------------------------------------------- d->backwardActionMenu = new KToolBarPopupAction(QIcon::fromTheme(QLatin1String("go-previous")), i18n("&Back"), this); d->backwardActionMenu->setEnabled(false); ac->addAction(QLatin1String("album_back"), d->backwardActionMenu); ac->setDefaultShortcut(d->backwardActionMenu, Qt::ALT+Qt::Key_Left); connect(d->backwardActionMenu->menu(), SIGNAL(aboutToShow()), this, SLOT(slotAboutToShowBackwardMenu())); // we are using a signal mapper to identify which of a bunch of actions was triggered d->backwardSignalMapper = new QSignalMapper(this); // connect mapper to view connect(d->backwardSignalMapper, SIGNAL(mapped(int)), d->view, SLOT(slotAlbumHistoryBack(int))); // connect action to mapper connect(d->backwardActionMenu, SIGNAL(triggered()), d->backwardSignalMapper, SLOT(map())); // inform mapper about number of steps d->backwardSignalMapper->setMapping(d->backwardActionMenu, 1); // ----------------------------------------------------------------- d->forwardActionMenu = new KToolBarPopupAction(QIcon::fromTheme(QLatin1String("go-next")), i18n("Forward"), this); d->forwardActionMenu->setEnabled(false); ac->addAction(QLatin1String("album_forward"), d->forwardActionMenu); ac->setDefaultShortcut(d->forwardActionMenu, Qt::ALT+Qt::Key_Right); connect(d->forwardActionMenu->menu(), SIGNAL(aboutToShow()), this, SLOT(slotAboutToShowForwardMenu())); d->forwardSignalMapper = new QSignalMapper(this); connect(d->forwardSignalMapper, SIGNAL(mapped(int)), d->view, SLOT(slotAlbumHistoryForward(int))); connect(d->forwardActionMenu, SIGNAL(triggered()), d->forwardSignalMapper, SLOT(map())); d->forwardSignalMapper->setMapping(d->forwardActionMenu, 1); // ----------------------------------------------------------------- d->refreshAction = new QAction(QIcon::fromTheme(QLatin1String("view-refresh")), i18n("Refresh"), this); d->refreshAction->setWhatsThis(i18n("Refresh the current contents.")); connect(d->refreshAction, SIGNAL(triggered()), d->view, SLOT(slotRefresh())); ac->addAction(QLatin1String("view_refresh"), d->refreshAction); ac->setDefaultShortcut(d->refreshAction, Qt::Key_F5); // ----------------------------------------------------------------- QSignalMapper* const browseActionsMapper = new QSignalMapper(this); connect(browseActionsMapper, SIGNAL(mapped(QWidget*)), d->view, SLOT(slotLeftSideBarActivate(QWidget*))); foreach(SidebarWidget* const leftWidget, d->view->leftSidebarWidgets()) { QString actionName = QLatin1String("browse_") + leftWidget->objectName() .remove(QLatin1Char(' ')) .remove(QLatin1String("Sidebar")) .remove(QLatin1String("FolderView")) .remove(QLatin1String("View")).toLower(); qCDebug(DIGIKAM_GENERAL_LOG) << actionName; QAction* const action = new QAction(leftWidget->getIcon(), leftWidget->getCaption(), this); ac->addAction(actionName, action); ac->setDefaultShortcut(action, QKeySequence(leftWidget->property("Shortcut").toInt())); connect(action, SIGNAL(triggered()), browseActionsMapper, SLOT(map())); browseActionsMapper->setMapping(action, leftWidget); } // ----------------------------------------------------------------- d->newAction = new QAction(QIcon::fromTheme(QLatin1String("folder-new")), i18n("&New..."), this); d->newAction->setWhatsThis(i18n("Creates a new empty Album in the collection.")); connect(d->newAction, SIGNAL(triggered()), d->view, SLOT(slotNewAlbum())); ac->addAction(QLatin1String("album_new"), d->newAction); ac->setDefaultShortcuts(d->newAction, QList() << Qt::CTRL + Qt::Key_N); // ----------------------------------------------------------------- d->moveSelectionToAlbumAction = new QAction(QIcon::fromTheme(QLatin1String("folder-new")), i18n("&Move to Album..."), this); d->moveSelectionToAlbumAction->setWhatsThis(i18n("Move selected images into an album.")); connect(d->moveSelectionToAlbumAction, SIGNAL(triggered()), d->view, SLOT(slotMoveSelectionToAlbum())); ac->addAction(QLatin1String("move_selection_to_album"), d->moveSelectionToAlbumAction); // ----------------------------------------------------------------- d->deleteAction = new QAction(QIcon::fromTheme(QLatin1String("edit-delete")), i18n("Delete Album"), this); connect(d->deleteAction, SIGNAL(triggered()), d->view, SLOT(slotDeleteAlbum())); ac->addAction(QLatin1String("album_delete"), d->deleteAction); // ----------------------------------------------------------------- d->renameAction = new QAction(QIcon::fromTheme(QLatin1String("document-edit")), i18n("Rename..."), this); connect(d->renameAction, SIGNAL(triggered()), d->view, SLOT(slotRenameAlbum())); ac->addAction(QLatin1String("album_rename"), d->renameAction); ac->setDefaultShortcut(d->renameAction, Qt::SHIFT + Qt::Key_F2); // ----------------------------------------------------------------- d->propsEditAction = new QAction(QIcon::fromTheme(QLatin1String("configure")), i18n("Properties"), this); d->propsEditAction->setWhatsThis(i18n("Edit album properties and collection information.")); connect(d->propsEditAction, SIGNAL(triggered()), d->view, SLOT(slotAlbumPropsEdit())); ac->addAction(QLatin1String("album_propsEdit"), d->propsEditAction); ac->setDefaultShortcut(d->propsEditAction, Qt::ALT + Qt::Key_Return); // ----------------------------------------------------------------- d->writeAlbumMetadataAction = new QAction(QIcon::fromTheme(QLatin1String("document-edit")), i18n("Write Metadata to Files"), this); d->writeAlbumMetadataAction->setWhatsThis(i18n("Updates metadata of files in the current " "album with the contents of digiKam database " "(file metadata will be overwritten with data from " "the database).")); connect(d->writeAlbumMetadataAction, SIGNAL(triggered()), d->view, SLOT(slotAlbumWriteMetadata())); ac->addAction(QLatin1String("album_write_metadata"), d->writeAlbumMetadataAction); // ----------------------------------------------------------------- d->readAlbumMetadataAction = new QAction(QIcon::fromTheme(QLatin1String("edit-redo")), i18n("Reread Metadata From Files"), this); d->readAlbumMetadataAction->setWhatsThis(i18n("Updates the digiKam database from the metadata " "of the files in the current album " "(information in the database will be overwritten with data from " "the files' metadata).")); connect(d->readAlbumMetadataAction, SIGNAL(triggered()), d->view, SLOT(slotAlbumReadMetadata())); ac->addAction(QLatin1String("album_read_metadata"), d->readAlbumMetadataAction); // ----------------------------------------------------------------- d->openInFileManagerAction = new QAction(QIcon::fromTheme(QLatin1String("folder-open")), i18n("Open in File Manager"), this); connect(d->openInFileManagerAction, SIGNAL(triggered()), d->view, SLOT(slotAlbumOpenInFileManager())); ac->addAction(QLatin1String("album_openinfilemanager"), d->openInFileManagerAction); // ----------------------------------------------------------- d->openTagMngrAction = new QAction(QIcon::fromTheme(QLatin1String("tag")), i18n("Tag Manager"), this); connect(d->openTagMngrAction, SIGNAL(triggered()), d->view, SLOT(slotOpenTagsManager())); ac->addAction(QLatin1String("open_tag_mngr"), d->openTagMngrAction); // ----------------------------------------------------------- d->newTagAction = new QAction(QIcon::fromTheme(QLatin1String("tag-new")), i18nc("new tag", "N&ew..."), this); connect(d->newTagAction, SIGNAL(triggered()), d->view, SLOT(slotNewTag())); ac->addAction(QLatin1String("tag_new"), d->newTagAction); // ----------------------------------------------------------- d->editTagAction = new QAction(QIcon::fromTheme(QLatin1String("tag-properties")), i18n("Properties"), this); connect(d->editTagAction, SIGNAL(triggered()), d->view, SLOT(slotEditTag())); ac->addAction(QLatin1String("tag_edit"), d->editTagAction); // ----------------------------------------------------------- d->deleteTagAction = new QAction(QIcon::fromTheme(QLatin1String("user-trash")), i18n("Delete"), this); connect(d->deleteTagAction, SIGNAL(triggered()), d->view, SLOT(slotDeleteTag())); ac->addAction(QLatin1String("tag_delete"), d->deleteTagAction); // ----------------------------------------------------------- d->assignTagAction = new QAction(QIcon::fromTheme(QLatin1String("tag-new")), i18n("Assign Tag"), this); connect(d->assignTagAction, SIGNAL(triggered()), d->view, SLOT(slotAssignTag())); ac->addAction(QLatin1String("tag_assign"), d->assignTagAction); ac->setDefaultShortcut(d->assignTagAction, Qt::Key_T); // ----------------------------------------------------------- d->imageViewSelectionAction = new KSelectAction(QIcon::fromTheme(QLatin1String("view-preview")), i18n("Views"), this); ac->addAction(QLatin1String("view_selection"), d->imageViewSelectionAction); d->imageIconViewAction = new QAction(QIcon::fromTheme(QLatin1String("view-list-icons")), i18nc("@action Go to thumbnails (icon) view", "Thumbnails"), this); d->imageIconViewAction->setCheckable(true); ac->addAction(QLatin1String("icon_view"), d->imageIconViewAction); connect(d->imageIconViewAction, SIGNAL(triggered()), d->view, SLOT(slotIconView())); d->imageViewSelectionAction->addAction(d->imageIconViewAction); d->imagePreviewAction = new QAction(QIcon::fromTheme(QLatin1String("view-preview")), i18nc("View the selected image", "Preview"), this); d->imagePreviewAction->setCheckable(true); ac->addAction(QLatin1String("image_view"), d->imagePreviewAction); ac->setDefaultShortcut(d->imagePreviewAction, Qt::Key_F3); connect(d->imagePreviewAction, SIGNAL(triggered()), d->view, SLOT(slotImagePreview())); d->imageViewSelectionAction->addAction(d->imagePreviewAction); #ifdef HAVE_MARBLE d->imageMapViewAction = new QAction(QIcon::fromTheme(QLatin1String("globe")), i18nc("@action Switch to map view", "Map"), this); d->imageMapViewAction->setCheckable(true); ac->addAction(QLatin1String("map_view"), d->imageMapViewAction); connect(d->imageMapViewAction, SIGNAL(triggered()), d->view, SLOT(slotMapWidgetView())); d->imageViewSelectionAction->addAction(d->imageMapViewAction); #endif // HAVE_MARBLE d->imageTableViewAction = new QAction(QIcon::fromTheme(QLatin1String("view-list-details")), i18nc("@action Switch to table view", "Table"), this); d->imageTableViewAction->setCheckable(true); ac->addAction(QLatin1String("table_view"), d->imageTableViewAction); connect(d->imageTableViewAction, SIGNAL(triggered()), d->view, SLOT(slotTableView())); d->imageViewSelectionAction->addAction(d->imageTableViewAction); // ----------------------------------------------------------- d->imageViewAction = new QAction(QIcon::fromTheme(QLatin1String("quickopen-file")), i18n("Open..."), this); d->imageViewAction->setWhatsThis(i18n("Open the selected item.")); connect(d->imageViewAction, SIGNAL(triggered()), d->view, SLOT(slotImageEdit())); ac->addAction(QLatin1String("image_edit"), d->imageViewAction); ac->setDefaultShortcut(d->imageViewAction, Qt::Key_F4); d->openWithAction = new QAction(QIcon::fromTheme(QLatin1String("preferences-desktop-filetype-association")), i18n("Open With Default Application"), this); d->openWithAction->setWhatsThis(i18n("Open the selected item with default assigned application.")); connect(d->openWithAction, SIGNAL(triggered()), d->view, SLOT(slotFileWithDefaultApplication())); ac->addAction(QLatin1String("open_with_default_application"), d->openWithAction); ac->setDefaultShortcut(d->openWithAction, Qt::META + Qt::Key_F4); d->ieAction = new QAction(QIcon::fromTheme(QLatin1String("document-edit")), i18n("Image Editor"), this); d->ieAction->setWhatsThis(i18n("Open the image editor.")); connect(d->ieAction, SIGNAL(triggered()), d->view, SLOT(slotEditor())); ac->addAction(QLatin1String("imageeditor"), d->ieAction); // ----------------------------------------------------------- d->ltAction = new QAction(QIcon::fromTheme(QLatin1String("lighttable")), i18n("Light Table"), this); connect(d->ltAction, SIGNAL(triggered()), d->view, SLOT(slotLightTable())); ac->addAction(QLatin1String("light_table"), d->ltAction); ac->setDefaultShortcut(d->ltAction, Qt::Key_L); d->imageLightTableAction = new QAction(QIcon::fromTheme(QLatin1String("lighttable")), i18n("Place onto Light Table"), this); d->imageLightTableAction->setWhatsThis(i18n("Place the selected items on the light table thumbbar.")); connect(d->imageLightTableAction, SIGNAL(triggered()), d->view, SLOT(slotImageLightTable())); ac->addAction(QLatin1String("image_lighttable"), d->imageLightTableAction); ac->setDefaultShortcut(d->imageLightTableAction, Qt::CTRL+Qt::Key_L); d->imageAddLightTableAction = new QAction(QIcon::fromTheme(QLatin1String("list-add")), i18n("Add to Light Table"), this); d->imageAddLightTableAction->setWhatsThis(i18n("Add selected items to the light table thumbbar.")); connect(d->imageAddLightTableAction, SIGNAL(triggered()), d->view, SLOT(slotImageAddToLightTable())); ac->addAction(QLatin1String("image_add_to_lighttable"), d->imageAddLightTableAction); ac->setDefaultShortcut(d->imageAddLightTableAction, Qt::SHIFT+Qt::CTRL+Qt::Key_L); // ----------------------------------------------------------- d->bqmAction = new QAction(QIcon::fromTheme(QLatin1String("run-build")), i18n("Batch Queue Manager"), this); connect(d->bqmAction, SIGNAL(triggered()), d->view, SLOT(slotQueueMgr())); ac->addAction(QLatin1String("queue_manager"), d->bqmAction); ac->setDefaultShortcut(d->bqmAction, Qt::Key_B); d->imageAddCurrentQueueAction = new QAction(QIcon::fromTheme(QLatin1String("go-up")), i18n("Add to Current Queue"), this); d->imageAddCurrentQueueAction->setWhatsThis(i18n("Add selected items to current queue from batch manager.")); connect(d->imageAddCurrentQueueAction, SIGNAL(triggered()), d->view, SLOT(slotImageAddToCurrentQueue())); ac->addAction(QLatin1String("image_add_to_current_queue"), d->imageAddCurrentQueueAction); ac->setDefaultShortcut(d->imageAddCurrentQueueAction, Qt::CTRL+Qt::Key_B); d->imageAddNewQueueAction = new QAction(QIcon::fromTheme(QLatin1String("list-add")), i18n("Add to New Queue"), this); d->imageAddNewQueueAction->setWhatsThis(i18n("Add selected items to a new queue from batch manager.")); connect(d->imageAddNewQueueAction, SIGNAL(triggered()), d->view, SLOT(slotImageAddToNewQueue())); ac->addAction(QLatin1String("image_add_to_new_queue"), d->imageAddNewQueueAction); ac->setDefaultShortcut(d->imageAddNewQueueAction, Qt::SHIFT+Qt::CTRL+Qt::Key_B); // ----------------------------------------------------------------- d->quickImportMenu->setTitle(i18nc("@action Import photos from camera", "Import")); d->quickImportMenu->setIcon(QIcon::fromTheme(QLatin1String("camera-photo"))); ac->addAction(QLatin1String("import_auto"), d->quickImportMenu->menuAction()); // ----------------------------------------------------------------- d->imageWriteMetadataAction = new QAction(QIcon::fromTheme(QLatin1String("document-edit")), i18n("Write Metadata to Selected Files"), this); d->imageWriteMetadataAction->setWhatsThis(i18n("Updates metadata of files in the current " "album with the contents of digiKam database " "(file metadata will be overwritten with data from " "the database).")); connect(d->imageWriteMetadataAction, SIGNAL(triggered()), d->view, SLOT(slotImageWriteMetadata())); ac->addAction(QLatin1String("image_write_metadata"), d->imageWriteMetadataAction); // ----------------------------------------------------------------- d->imageReadMetadataAction = new QAction(QIcon::fromTheme(QLatin1String("edit-redo")), i18n("Reread Metadata From Selected Files"), this); d->imageReadMetadataAction->setWhatsThis(i18n("Updates the digiKam database from the metadata " "of the files in the current album " "(information in the database will be overwritten with data from " "the files' metadata).")); connect(d->imageReadMetadataAction, SIGNAL(triggered()), d->view, SLOT(slotImageReadMetadata())); ac->addAction(QLatin1String("image_read_metadata"), d->imageReadMetadataAction); // ----------------------------------------------------------- + d->imageScanForFacesAction = new QAction(QIcon::fromTheme(QLatin1String("list-add-user")), i18n("Scan for Faces"), this); + connect(d->imageScanForFacesAction, SIGNAL(triggered()), d->view, SLOT(slotImageScanForFaces())); + ac->addAction(QLatin1String("image_scan_for_faces"), d->imageScanForFacesAction); + + // ----------------------------------------------------------- + d->imageFindSimilarAction = new QAction(QIcon::fromTheme(QLatin1String("tools-wizard")), i18n("Find Similar..."), this); d->imageFindSimilarAction->setWhatsThis(i18n("Find similar images using selected item as reference.")); connect(d->imageFindSimilarAction, SIGNAL(triggered()), d->view, SLOT(slotImageFindSimilar())); ac->addAction(QLatin1String("image_find_similar"), d->imageFindSimilarAction); // ----------------------------------------------------------- d->imageRenameAction = new QAction(QIcon::fromTheme(QLatin1String("document-edit")), i18n("Rename..."), this); d->imageRenameAction->setWhatsThis(i18n("Change the filename of the currently selected item.")); connect(d->imageRenameAction, SIGNAL(triggered()), d->view, SLOT(slotImageRename())); ac->addAction(QLatin1String("image_rename"), d->imageRenameAction); ac->setDefaultShortcut(d->imageRenameAction, Qt::Key_F2); // ----------------------------------------------------------- // Pop up dialog to ask user whether to move to trash d->imageDeleteAction = new QAction(QIcon::fromTheme(QLatin1String("user-trash")), i18nc("Non-pluralized", "Move to Trash"), this); connect(d->imageDeleteAction, SIGNAL(triggered()), d->view, SLOT(slotImageDelete())); ac->addAction(QLatin1String("image_delete"), d->imageDeleteAction); ac->setDefaultShortcut(d->imageDeleteAction, Qt::Key_Delete); // ----------------------------------------------------------- // Pop up dialog to ask user whether to permanently delete // FIXME: This action is never used?? How can someone delete a album directly, without moving it to the trash first? // This is especially important when deleting from a different partition or from a net source. // Also note that we use the wrong icon for the default album delete action, which should have a trashcan icon instead // of a red cross, it confuses users. d->imageDeletePermanentlyAction = new QAction(QIcon::fromTheme(QLatin1String("edit-delete")), i18n("Delete Permanently"), this); connect(d->imageDeletePermanentlyAction, SIGNAL(triggered()), d->view, SLOT(slotImageDeletePermanently())); ac->addAction(QLatin1String("image_delete_permanently"), d->imageDeletePermanentlyAction); ac->setDefaultShortcut(d->imageDeletePermanentlyAction, Qt::SHIFT+Qt::Key_Delete); // ----------------------------------------------------------- // These two actions are hidden, no menu entry, no toolbar entry, no shortcut. // Power users may add them. d->imageDeletePermanentlyDirectlyAction = new QAction(QIcon::fromTheme(QLatin1String("edit-delete")), i18n("Delete permanently without confirmation"), this); connect(d->imageDeletePermanentlyDirectlyAction, SIGNAL(triggered()), d->view, SLOT(slotImageDeletePermanentlyDirectly())); ac->addAction(QLatin1String("image_delete_permanently_directly"), d->imageDeletePermanentlyDirectlyAction); // ----------------------------------------------------------- d->imageTrashDirectlyAction = new QAction(QIcon::fromTheme(QLatin1String("user-trash")), i18n("Move to trash without confirmation"), this); connect(d->imageTrashDirectlyAction, SIGNAL(triggered()), d->view, SLOT(slotImageTrashDirectly())); ac->addAction(QLatin1String("image_trash_directly"), d->imageTrashDirectlyAction); // ----------------------------------------------------------------- d->albumSortAction = new KSelectAction(i18n("&Sort Albums"), this); d->albumSortAction->setWhatsThis(i18n("Sort Albums in tree-view.")); connect(d->albumSortAction, SIGNAL(triggered(int)), d->view, SLOT(slotSortAlbums(int))); ac->addAction(QLatin1String("album_sort"), d->albumSortAction); // Use same list order as in applicationsettings enum QStringList sortActionList; sortActionList.append(i18n("By Folder")); sortActionList.append(i18n("By Category")); sortActionList.append(i18n("By Date")); d->albumSortAction->setItems(sortActionList); // ----------------------------------------------------------- d->recurseAlbumsAction = new QAction(i18n("Include Album Sub-Tree"), this); d->recurseAlbumsAction->setCheckable(true); d->recurseAlbumsAction->setWhatsThis(i18n("Activate this option to show all sub-albums below " "the current album.")); connect(d->recurseAlbumsAction, SIGNAL(toggled(bool)), this, SLOT(slotRecurseAlbums(bool))); ac->addAction(QLatin1String("albums_recursive"), d->recurseAlbumsAction); d->recurseTagsAction = new QAction(i18n("Include Tag Sub-Tree"), this); d->recurseTagsAction->setCheckable(true); d->recurseTagsAction->setWhatsThis(i18n("Activate this option to show all images marked by the given tag " "and all its sub-tags.")); connect(d->recurseTagsAction, SIGNAL(toggled(bool)), this, SLOT(slotRecurseTags(bool))); ac->addAction(QLatin1String("tags_recursive"), d->recurseTagsAction); // ----------------------------------------------------------- d->imageSortAction = new KSelectAction(i18n("&Sort Items"), this); d->imageSortAction->setWhatsThis(i18n("The value by which the images in one album are sorted in the thumbnail view")); QSignalMapper* const imageSortMapper = new QSignalMapper(this); connect(imageSortMapper, SIGNAL(mapped(int)), d->view, SLOT(slotSortImages(int))); ac->addAction(QLatin1String("image_sort"), d->imageSortAction); // map to ImageSortSettings enum QAction* const sortByNameAction = d->imageSortAction->addAction(i18n("By Name")); QAction* const sortByPathAction = d->imageSortAction->addAction(i18n("By Path")); QAction* const sortByDateAction = d->imageSortAction->addAction(i18n("By Date")); QAction* const sortByFileSizeAction = d->imageSortAction->addAction(i18n("By File Size")); QAction* const sortByRatingAction = d->imageSortAction->addAction(i18n("By Rating")); QAction* const sortByImageSizeAction = d->imageSortAction->addAction(i18n("By Image Size")); QAction* const sortByAspectRatioAction = d->imageSortAction->addAction(i18n("By Aspect Ratio")); QAction* const sortBySimilarityAction = d->imageSortAction->addAction(i18n("By Similarity")); // activate the sort by similarity if the fuzzy search sidebar is active. Deactivate at start. sortBySimilarityAction->setEnabled(false); connect(d->view, SIGNAL(signalFuzzySidebarActive(bool)), sortBySimilarityAction, SLOT(setEnabled(bool))); connect(sortByNameAction, SIGNAL(triggered()), imageSortMapper, SLOT(map())); connect(sortByPathAction, SIGNAL(triggered()), imageSortMapper, SLOT(map())); connect(sortByDateAction, SIGNAL(triggered()), imageSortMapper, SLOT(map())); connect(sortByFileSizeAction, SIGNAL(triggered()), imageSortMapper, SLOT(map())); connect(sortByRatingAction, SIGNAL(triggered()), imageSortMapper, SLOT(map())); connect(sortByImageSizeAction, SIGNAL(triggered()), imageSortMapper, SLOT(map())); connect(sortByAspectRatioAction, SIGNAL(triggered()), imageSortMapper, SLOT(map())); connect(sortBySimilarityAction, SIGNAL(triggered()), imageSortMapper, SLOT(map())); imageSortMapper->setMapping(sortByNameAction, (int)ImageSortSettings::SortByFileName); imageSortMapper->setMapping(sortByPathAction, (int)ImageSortSettings::SortByFilePath); imageSortMapper->setMapping(sortByDateAction, (int)ImageSortSettings::SortByCreationDate); imageSortMapper->setMapping(sortByFileSizeAction, (int)ImageSortSettings::SortByFileSize); imageSortMapper->setMapping(sortByRatingAction, (int)ImageSortSettings::SortByRating); imageSortMapper->setMapping(sortByImageSizeAction, (int)ImageSortSettings::SortByImageSize); imageSortMapper->setMapping(sortByAspectRatioAction, (int)ImageSortSettings::SortByAspectRatio); imageSortMapper->setMapping(sortBySimilarityAction, (int)ImageSortSettings::SortBySimilarity); // ----------------------------------------------------------- d->imageSortOrderAction = new KSelectAction(i18n("Item Sort &Order"), this); d->imageSortOrderAction->setWhatsThis(i18n("Defines whether images are sorted in ascending or descending manner.")); QSignalMapper* const imageSortOrderMapper = new QSignalMapper(this); connect(imageSortOrderMapper, SIGNAL(mapped(int)), d->view, SLOT(slotSortImagesOrder(int))); ac->addAction(QLatin1String("image_sort_order"), d->imageSortOrderAction); QAction* const sortAscendingAction = d->imageSortOrderAction->addAction(QIcon::fromTheme(QLatin1String("view-sort-ascending")), i18n("Ascending")); QAction* const sortDescendingAction = d->imageSortOrderAction->addAction(QIcon::fromTheme(QLatin1String("view-sort-descending")), i18n("Descending")); connect(sortAscendingAction, SIGNAL(triggered()), imageSortOrderMapper, SLOT(map())); connect(sortDescendingAction, SIGNAL(triggered()), imageSortOrderMapper, SLOT(map())); imageSortOrderMapper->setMapping(sortAscendingAction, (int)ImageSortSettings::AscendingOrder); imageSortOrderMapper->setMapping(sortDescendingAction, (int)ImageSortSettings::DescendingOrder); // ----------------------------------------------------------- d->imageSeparationAction = new KSelectAction(i18n("Separate Items"), this); d->imageSeparationAction->setWhatsThis(i18n("The categories in which the images in the thumbnail view are displayed")); QSignalMapper* const imageSeparationMapper = new QSignalMapper(this); connect(imageSeparationMapper, SIGNAL(mapped(int)), d->view, SLOT(slotSeparateImages(int))); ac->addAction(QLatin1String("image_separation"), d->imageSeparationAction); // map to ImageSortSettings enum QAction* const noCategoriesAction = d->imageSeparationAction->addAction(i18n("Flat List")); QAction* const separateByAlbumAction = d->imageSeparationAction->addAction(i18n("By Album")); QAction* const separateByFormatAction = d->imageSeparationAction->addAction(i18n("By Format")); connect(noCategoriesAction, SIGNAL(triggered()), imageSeparationMapper, SLOT(map())); connect(separateByAlbumAction, SIGNAL(triggered()), imageSeparationMapper, SLOT(map())); connect(separateByFormatAction, SIGNAL(triggered()), imageSeparationMapper, SLOT(map())); imageSeparationMapper->setMapping(noCategoriesAction, (int)ImageSortSettings::OneCategory); imageSeparationMapper->setMapping(separateByAlbumAction, (int)ImageSortSettings::CategoryByAlbum); imageSeparationMapper->setMapping(separateByFormatAction, (int)ImageSortSettings::CategoryByFormat); // ----------------------------------------------------------------- d->imageSeparationSortOrderAction = new KSelectAction(i18n("Item Separation Order"), this); d->imageSeparationSortOrderAction->setWhatsThis(i18n("The sort order of the groups of separated items")); QSignalMapper* const imageSeparationSortOrderMapper = new QSignalMapper(this); connect(imageSeparationSortOrderMapper, SIGNAL(mapped(int)), d->view, SLOT(slotImageSeparationSortOrder(int))); ac->addAction(QLatin1String("image_separation_sort_order"), d->imageSeparationSortOrderAction); QAction* const sortSeparationsAscending = d->imageSeparationSortOrderAction->addAction(QIcon::fromTheme(QLatin1String("view-sort-ascending")), i18n("Ascending")); QAction* const sortSeparationsDescending = d->imageSeparationSortOrderAction->addAction(QIcon::fromTheme(QLatin1String("view-sort-descending")), i18n("Descending")); connect(sortSeparationsAscending, SIGNAL(triggered()), imageSeparationSortOrderMapper, SLOT(map())); connect(sortSeparationsDescending, SIGNAL(triggered()), imageSeparationSortOrderMapper, SLOT(map())); imageSeparationSortOrderMapper->setMapping(sortSeparationsAscending, (int)ImageSortSettings::AscendingOrder); imageSeparationSortOrderMapper->setMapping(sortSeparationsDescending, (int)ImageSortSettings::DescendingOrder); // ----------------------------------------------------------------- setupImageTransformActions(); setupExifOrientationActions(); createMetadataEditAction(); createGeolocationEditAction(); createExportActions(); createImportActions(); // ----------------------------------------------------------------- d->selectAllAction = new QAction(i18n("Select All"), this); connect(d->selectAllAction, SIGNAL(triggered()), d->view, SLOT(slotSelectAll())); ac->addAction(QLatin1String("selectAll"), d->selectAllAction); ac->setDefaultShortcut(d->selectAllAction, Qt::CTRL+Qt::Key_A); // ----------------------------------------------------------------- d->selectNoneAction = new QAction(i18n("Select None"), this); connect(d->selectNoneAction, SIGNAL(triggered()), d->view, SLOT(slotSelectNone())); ac->addAction(QLatin1String("selectNone"), d->selectNoneAction); ac->setDefaultShortcut(d->selectNoneAction, Qt::CTRL+Qt::SHIFT+Qt::Key_A); // ----------------------------------------------------------------- d->selectInvertAction = new QAction(i18n("Invert Selection"), this); connect(d->selectInvertAction, SIGNAL(triggered()), d->view, SLOT(slotSelectInvert())); ac->addAction(QLatin1String("selectInvert"), d->selectInvertAction); ac->setDefaultShortcut(d->selectInvertAction, Qt::CTRL+Qt::Key_I); // ----------------------------------------------------------- d->showBarAction = new QAction(QIcon::fromTheme(QLatin1String("view-choose")), i18n("Show Thumbbar"), this); d->showBarAction->setCheckable(true); connect(d->showBarAction, SIGNAL(triggered()), this, SLOT(slotToggleShowBar())); ac->addAction(QLatin1String("showthumbs"), d->showBarAction); ac->setDefaultShortcut(d->showBarAction, Qt::CTRL+Qt::Key_T); // Provides a menu entry that allows showing/hiding the toolbar(s) setStandardToolBarMenuEnabled(true); // Provides a menu entry that allows showing/hiding the statusbar createStandardStatusBarAction(); // Standard 'Configure' menu actions createSettingsActions(); // ----------------------------------------------------------- d->zoomPlusAction = buildStdAction(StdZoomInAction, d->view, SLOT(slotZoomIn()), this); QKeySequence keysPlus(d->zoomPlusAction->shortcut()[0], Qt::Key_Plus); ac->addAction(QLatin1String("album_zoomin"), d->zoomPlusAction); ac->setDefaultShortcut(d->zoomPlusAction, keysPlus); // ----------------------------------------------------------- d->zoomMinusAction = buildStdAction(StdZoomOutAction, d->view, SLOT(slotZoomOut()), this); QKeySequence keysMinus(d->zoomMinusAction->shortcut()[0], Qt::Key_Minus); ac->addAction(QLatin1String("album_zoomout"), d->zoomMinusAction); ac->setDefaultShortcut(d->zoomMinusAction, keysMinus); // ----------------------------------------------------------- d->zoomTo100percents = new QAction(QIcon::fromTheme(QLatin1String("zoom-original")), i18n("Zoom to 100%"), this); connect(d->zoomTo100percents, SIGNAL(triggered()), d->view, SLOT(slotZoomTo100Percents())); ac->addAction(QLatin1String("album_zoomto100percents"), d->zoomTo100percents); ac->setDefaultShortcut(d->zoomTo100percents, Qt::CTRL + Qt::Key_Period); // ----------------------------------------------------------- d->zoomFitToWindowAction = new QAction(QIcon::fromTheme(QLatin1String("zoom-fit-best")), i18n("Fit to &Window"), this); connect(d->zoomFitToWindowAction, SIGNAL(triggered()), d->view, SLOT(slotFitToWindow())); ac->addAction(QLatin1String("album_zoomfit2window"), d->zoomFitToWindowAction); ac->setDefaultShortcut(d->zoomFitToWindowAction, Qt::ALT + Qt::CTRL + Qt::Key_E); // ----------------------------------------------------------- createFullScreenAction(QLatin1String("full_screen")); createSidebarActions(); // ----------------------------------------------------------- d->slideShowAction = new QMenu(i18n("Slideshow"), this); d->slideShowAction->setIcon(QIcon::fromTheme(QLatin1String("view-presentation"))); ac->addAction(QLatin1String("slideshow"), d->slideShowAction->menuAction()); d->slideShowAllAction = new QAction(i18n("All"), this); connect(d->slideShowAllAction, SIGNAL(triggered()), d->view, SLOT(slotSlideShowAll())); ac->addAction(QLatin1String("slideshow_all"), d->slideShowAllAction); ac->setDefaultShortcut(d->slideShowAllAction, Qt::Key_F9); d->slideShowAction->addAction(d->slideShowAllAction); d->slideShowSelectionAction = new QAction(i18n("Selection"), this); connect(d->slideShowSelectionAction, SIGNAL(triggered()), d->view, SLOT(slotSlideShowSelection())); ac->addAction(QLatin1String("slideshow_selected"), d->slideShowSelectionAction); ac->setDefaultShortcut(d->slideShowSelectionAction, Qt::ALT+Qt::Key_F9); d->slideShowAction->addAction(d->slideShowSelectionAction); d->slideShowRecursiveAction = new QAction(i18n("With All Sub-Albums"), this); connect(d->slideShowRecursiveAction, SIGNAL(triggered()), d->view, SLOT(slotSlideShowRecursive())); ac->addAction(QLatin1String("slideshow_recursive"), d->slideShowRecursiveAction); ac->setDefaultShortcut(d->slideShowRecursiveAction, Qt::SHIFT+Qt::Key_F9); d->slideShowAction->addAction(d->slideShowRecursiveAction); createPresentationAction(); // ----------------------------------------------------------- d->viewCMViewAction = new QAction(QIcon::fromTheme(QLatin1String("video-display")), i18n("Color-Managed View"), this); d->viewCMViewAction->setCheckable(true); connect(d->viewCMViewAction, SIGNAL(triggered()), this, SLOT(slotToggleColorManagedView())); ac->addAction(QLatin1String("color_managed_view"), d->viewCMViewAction); ac->setDefaultShortcut(d->viewCMViewAction, Qt::Key_F12); // ----------------------------------------------------------- d->quitAction = buildStdAction(StdQuitAction, this, SLOT(slotExit()), this); ac->addAction(QLatin1String("app_exit"), d->quitAction); // ----------------------------------------------------------- createHelpActions(); // ----------------------------------------------------------- QAction* const findAction = new QAction(QIcon::fromTheme(QLatin1String("edit-find")), i18n("Search..."), this); connect(findAction, SIGNAL(triggered()), d->view, SLOT(slotNewKeywordSearch())); ac->addAction(QLatin1String("search_quick"), findAction); ac->setDefaultShortcut(findAction, Qt::CTRL+Qt::Key_F); // ----------------------------------------------------------- d->advSearchAction = new QAction(QIcon::fromTheme(QLatin1String("edit-find")), i18n("Advanced Search..."), this); connect(d->advSearchAction, SIGNAL(triggered()), d->view, SLOT(slotNewAdvancedSearch())); ac->addAction(QLatin1String("search_advanced"), d->advSearchAction); ac->setDefaultShortcut(d->advSearchAction, Qt::CTRL+Qt::ALT+Qt::Key_F); // ----------------------------------------------------------- QAction* const duplicatesAction = new QAction(QIcon::fromTheme(QLatin1String("tools-wizard")), i18n("Find Duplicates..."), this); connect(duplicatesAction, SIGNAL(triggered()), d->view, SLOT(slotNewDuplicatesSearch())); ac->addAction(QLatin1String("find_duplicates"), duplicatesAction); ac->setDefaultShortcut(duplicatesAction, Qt::CTRL+Qt::Key_D); // ----------------------------------------------------------- #ifdef HAVE_MYSQLSUPPORT QAction* const databaseMigrationAction = new QAction(QIcon::fromTheme(QLatin1String("network-server-database")), i18n("Database Migration..."), this); connect(databaseMigrationAction, SIGNAL(triggered()), this, SLOT(slotDatabaseMigration())); ac->addAction(QLatin1String("database_migration"), databaseMigrationAction); #endif // ----------------------------------------------------------- d->maintenanceAction = new QAction(QIcon::fromTheme(QLatin1String("run-build-prune")), i18n("Maintenance..."), this); connect(d->maintenanceAction, SIGNAL(triggered()), this, SLOT(slotMaintenance())); ac->addAction(QLatin1String("maintenance"), d->maintenanceAction); createExpoBlendingAction(); createPanoramaAction(); createHtmlGalleryAction(); createCalendarAction(); createVideoSlideshowAction(); createSendByMailAction(); createPrintCreatorAction(); createMediaServerAction(); // ----------------------------------------------------------- QAction* const cameraAction = new QAction(i18n("Add Camera Manually..."), this); connect(cameraAction, SIGNAL(triggered()), this, SLOT(slotSetupCamera())); ac->addAction(QLatin1String("camera_add"), cameraAction); // ----------------------------------------------------------- // Load Cameras -- do this before the createGUI so that the cameras // are plugged into the toolbar at startup if (d->splashScreen) { d->splashScreen->setMessage(i18n("Loading cameras...")); } loadCameras(); // Load Themes populateThemes(); createGUI(xmlFile()); cleanupActions(); // NOTE: see bug #252130 and #283281 : we need to disable these actions when BQM is running. // These connections must be done after loading color theme else theme menu cannot be plugged to Settings menu, connect(QueueMgrWindow::queueManagerWindow(), SIGNAL(signalBqmIsBusy(bool)), d->bqmAction, SLOT(setDisabled(bool))); connect(QueueMgrWindow::queueManagerWindow(), SIGNAL(signalBqmIsBusy(bool)), d->imageAddCurrentQueueAction, SLOT(setDisabled(bool))); connect(QueueMgrWindow::queueManagerWindow(), SIGNAL(signalBqmIsBusy(bool)), d->imageAddNewQueueAction, SLOT(setDisabled(bool))); } void DigikamApp::setupAccelerators() { KActionCollection* const ac = actionCollection(); // Action are added by tag in ui.rc XML file QAction* const escapeAction = new QAction(i18n("Exit Preview Mode"), this); ac->addAction(QLatin1String("exit_preview_mode"), escapeAction); ac->setDefaultShortcut(escapeAction, Qt::Key_Escape); connect(escapeAction, SIGNAL(triggered()), this, SIGNAL(signalEscapePressed())); QAction* const nextImageAction = new QAction(i18n("Next Image"), this); nextImageAction->setIcon(QIcon::fromTheme(QLatin1String("go-next"))); ac->addAction(QLatin1String("next_image"), nextImageAction); ac->setDefaultShortcut(nextImageAction, Qt::Key_Space); connect(nextImageAction, SIGNAL(triggered()), this, SIGNAL(signalNextItem())); QAction* const previousImageAction = new QAction(i18n("Previous Image"), this); previousImageAction->setIcon(QIcon::fromTheme(QLatin1String("go-previous"))); ac->addAction(QLatin1String("previous_image"), previousImageAction); ac->setDefaultShortcuts(previousImageAction, QList() << Qt::Key_Backspace << Qt::SHIFT+Qt::Key_Space); connect(previousImageAction, SIGNAL(triggered()), this, SIGNAL(signalPrevItem())); QAction* const firstImageAction = new QAction(i18n("First Image"), this); ac->addAction(QLatin1String("first_image"), firstImageAction); ac->setDefaultShortcuts(firstImageAction, QList() << Qt::CTRL + Qt::Key_Home); connect(firstImageAction, SIGNAL(triggered()), this, SIGNAL(signalFirstItem())); QAction* const lastImageAction = new QAction(i18n("Last Image"), this); ac->addAction(QLatin1String("last_image"), lastImageAction); ac->setDefaultShortcuts(lastImageAction, QList() << Qt::CTRL + Qt::Key_End); connect(lastImageAction, SIGNAL(triggered()), this, SIGNAL(signalLastItem())); d->cutItemsAction = new QAction(i18n("Cu&t"), this); d->cutItemsAction->setIcon(QIcon::fromTheme(QLatin1String("edit-cut"))); d->cutItemsAction->setWhatsThis(i18n("Cut selection to clipboard")); ac->addAction(QLatin1String("cut_album_selection"), d->cutItemsAction); // NOTE: shift+del keyboard shortcut must not be assigned to Cut action // else the shortcut for Delete permanently collides with secondary shortcut of Cut ac->setDefaultShortcut(d->cutItemsAction, Qt::CTRL + Qt::Key_X); connect(d->cutItemsAction, SIGNAL(triggered()), this, SIGNAL(signalCutAlbumItemsSelection())); d->copyItemsAction = buildStdAction(StdCopyAction, this, SIGNAL(signalCopyAlbumItemsSelection()), this); ac->addAction(QLatin1String("copy_album_selection"), d->copyItemsAction); d->pasteItemsAction = buildStdAction(StdPasteAction, this, SIGNAL(signalPasteAlbumItemsSelection()), this); ac->addAction(QLatin1String("paste_album_selection"), d->pasteItemsAction); // Labels shortcuts must be registered here to be saved in XML GUI files if user customize it. d->tagsActionManager->registerLabelsActions(ac); QAction* const editTitles = new QAction(i18n("Edit Titles"), this); ac->addAction(QLatin1String("edit_titles"), editTitles); ac->setDefaultShortcut(editTitles, Qt::META + Qt::Key_T); connect(editTitles, SIGNAL(triggered()), d->view, SLOT(slotRightSideBarActivateTitles())); QAction* const editComments = new QAction(i18n("Edit Comments"), this); ac->addAction(QLatin1String("edit_comments"), editComments); ac->setDefaultShortcut(editComments, Qt::META + Qt::Key_C); connect(editComments, SIGNAL(triggered()), d->view, SLOT(slotRightSideBarActivateComments())); QAction* const assignedTags = new QAction(i18n("Show Assigned Tags"), this); ac->addAction(QLatin1String("assigned _tags"), assignedTags); ac->setDefaultShortcut(assignedTags, Qt::META + Qt::Key_A); connect(assignedTags, SIGNAL(triggered()), d->view, SLOT(slotRightSideBarActivateAssignedTags())); } void DigikamApp::setupExifOrientationActions() { KActionCollection* const ac = actionCollection(); QSignalMapper* const exifOrientationMapper = new QSignalMapper(d->view); connect(exifOrientationMapper, SIGNAL(mapped(int)), d->view, SLOT(slotImageExifOrientation(int))); d->imageExifOrientationActionMenu = new QMenu(i18n("Adjust Exif Orientation Tag"), this); ac->addAction(QLatin1String("image_set_exif_orientation"), d->imageExifOrientationActionMenu->menuAction()); d->imageSetExifOrientation1Action = new QAction(i18nc("normal exif orientation", "Normal"), this); d->imageSetExifOrientation1Action->setCheckable(true); d->imageSetExifOrientation2Action = new QAction(i18n("Flipped Horizontally"), this); d->imageSetExifOrientation2Action->setCheckable(true); d->imageSetExifOrientation3Action = new QAction(i18n("Rotated Upside Down"), this); d->imageSetExifOrientation3Action->setCheckable(true); d->imageSetExifOrientation4Action = new QAction(i18n("Flipped Vertically"), this); d->imageSetExifOrientation4Action->setCheckable(true); d->imageSetExifOrientation5Action = new QAction(i18n("Rotated Right / Horiz. Flipped"), this); d->imageSetExifOrientation5Action->setCheckable(true); d->imageSetExifOrientation6Action = new QAction(i18n("Rotated Right"), this); d->imageSetExifOrientation6Action->setCheckable(true); d->imageSetExifOrientation7Action = new QAction(i18n("Rotated Right / Vert. Flipped"), this); d->imageSetExifOrientation7Action->setCheckable(true); d->imageSetExifOrientation8Action = new QAction(i18n("Rotated Left"), this); d->imageSetExifOrientation8Action->setCheckable(true); d->exifOrientationActionGroup = new QActionGroup(d->imageExifOrientationActionMenu); d->exifOrientationActionGroup->addAction(d->imageSetExifOrientation1Action); d->exifOrientationActionGroup->addAction(d->imageSetExifOrientation2Action); d->exifOrientationActionGroup->addAction(d->imageSetExifOrientation3Action); d->exifOrientationActionGroup->addAction(d->imageSetExifOrientation4Action); d->exifOrientationActionGroup->addAction(d->imageSetExifOrientation5Action); d->exifOrientationActionGroup->addAction(d->imageSetExifOrientation6Action); d->exifOrientationActionGroup->addAction(d->imageSetExifOrientation7Action); d->exifOrientationActionGroup->addAction(d->imageSetExifOrientation8Action); d->imageSetExifOrientation1Action->setChecked(true); ac->addAction(QLatin1String("image_set_exif_orientation_normal"), d->imageSetExifOrientation1Action); ac->addAction(QLatin1String("image_set_exif_orientation_flipped_horizontal"), d->imageSetExifOrientation2Action); ac->addAction(QLatin1String("image_set_exif_orientation_rotated_upside_down"), d->imageSetExifOrientation3Action); ac->addAction(QLatin1String("image_set_exif_orientation_flipped_vertically"), d->imageSetExifOrientation4Action); ac->addAction(QLatin1String("image_set_exif_orientation_rotated_right_hor_flipped"), d->imageSetExifOrientation5Action); ac->addAction(QLatin1String("image_set_exif_orientation_rotated_right"), d->imageSetExifOrientation6Action); ac->addAction(QLatin1String("image_set_exif_orientation_rotated_right_ver_flipped"), d->imageSetExifOrientation7Action); ac->addAction(QLatin1String("image_set_exif_orientation_rotated_left"), d->imageSetExifOrientation8Action); d->imageExifOrientationActionMenu->addAction(d->imageSetExifOrientation1Action); d->imageExifOrientationActionMenu->addAction(d->imageSetExifOrientation2Action); d->imageExifOrientationActionMenu->addAction(d->imageSetExifOrientation3Action); d->imageExifOrientationActionMenu->addAction(d->imageSetExifOrientation4Action); d->imageExifOrientationActionMenu->addAction(d->imageSetExifOrientation5Action); d->imageExifOrientationActionMenu->addAction(d->imageSetExifOrientation6Action); d->imageExifOrientationActionMenu->addAction(d->imageSetExifOrientation7Action); d->imageExifOrientationActionMenu->addAction(d->imageSetExifOrientation8Action); connect(d->imageSetExifOrientation1Action, SIGNAL(triggered()), exifOrientationMapper, SLOT(map())); connect(d->imageSetExifOrientation2Action, SIGNAL(triggered()), exifOrientationMapper, SLOT(map())); connect(d->imageSetExifOrientation3Action, SIGNAL(triggered()), exifOrientationMapper, SLOT(map())); connect(d->imageSetExifOrientation4Action, SIGNAL(triggered()), exifOrientationMapper, SLOT(map())); connect(d->imageSetExifOrientation5Action, SIGNAL(triggered()), exifOrientationMapper, SLOT(map())); connect(d->imageSetExifOrientation6Action, SIGNAL(triggered()), exifOrientationMapper, SLOT(map())); connect(d->imageSetExifOrientation7Action, SIGNAL(triggered()), exifOrientationMapper, SLOT(map())); connect(d->imageSetExifOrientation8Action, SIGNAL(triggered()), exifOrientationMapper, SLOT(map())); exifOrientationMapper->setMapping(d->imageSetExifOrientation1Action, 1); exifOrientationMapper->setMapping(d->imageSetExifOrientation2Action, 2); exifOrientationMapper->setMapping(d->imageSetExifOrientation3Action, 3); exifOrientationMapper->setMapping(d->imageSetExifOrientation4Action, 4); exifOrientationMapper->setMapping(d->imageSetExifOrientation5Action, 5); exifOrientationMapper->setMapping(d->imageSetExifOrientation6Action, 6); exifOrientationMapper->setMapping(d->imageSetExifOrientation7Action, 7); exifOrientationMapper->setMapping(d->imageSetExifOrientation8Action, 8); } void DigikamApp::setupImageTransformActions() { KActionCollection* const ac = actionCollection(); d->imageRotateActionMenu = new QMenu(i18n("Rotate"), this); d->imageRotateActionMenu->setIcon(QIcon::fromTheme(QLatin1String("object-rotate-right"))); QAction* const left = ac->addAction(QLatin1String("rotate_ccw")); left->setText(i18nc("rotate image left", "Left")); ac->setDefaultShortcut(left, Qt::SHIFT+Qt::CTRL+Qt::Key_Left); connect(left, SIGNAL(triggered(bool)), this, SLOT(slotTransformAction())); d->imageRotateActionMenu->addAction(left); QAction* const right = ac->addAction(QLatin1String("rotate_cw")); right->setText(i18nc("rotate image right", "Right")); ac->setDefaultShortcut(right, Qt::SHIFT+Qt::CTRL+Qt::Key_Right); connect(right, SIGNAL(triggered(bool)), this, SLOT(slotTransformAction())); d->imageRotateActionMenu->addAction(right); ac->addAction(QLatin1String("image_rotate"), d->imageRotateActionMenu->menuAction()); // ----------------------------------------------------------------------------------- d->imageFlipActionMenu = new QMenu(i18n("Flip"), this); d->imageFlipActionMenu->setIcon(QIcon::fromTheme(QLatin1String("flip-horizontal"))); QAction* const hori = ac->addAction(QLatin1String("flip_horizontal")); hori->setText(i18n("Horizontally")); ac->setDefaultShortcut(hori, Qt::CTRL+Qt::Key_Asterisk); connect(hori, SIGNAL(triggered(bool)), this, SLOT(slotTransformAction())); d->imageFlipActionMenu->addAction(hori); QAction* const verti = ac->addAction(QLatin1String("flip_vertical")); verti->setText(i18n("Vertically")); ac->setDefaultShortcut(verti, Qt::CTRL+Qt::Key_Slash); connect(verti, SIGNAL(triggered(bool)), this, SLOT(slotTransformAction())); d->imageFlipActionMenu->addAction(verti); ac->addAction(QLatin1String("image_flip"), d->imageFlipActionMenu->menuAction()); // ----------------------------------------------------------------------------------- d->imageAutoExifActionMenu = new QAction(i18n("Auto Rotate/Flip Using Exif Information"), this); connect(d->imageAutoExifActionMenu, SIGNAL(triggered(bool)), this, SLOT(slotTransformAction())); ac->addAction(QLatin1String("image_transform_exif"), d->imageAutoExifActionMenu); } void DigikamApp::populateThemes() { if (d->splashScreen) { d->splashScreen->setMessage(i18n("Loading themes...")); } ThemeManager::instance()->setThemeMenuAction(new QMenu(i18n("&Themes"), this)); ThemeManager::instance()->registerThemeActions(this); ThemeManager::instance()->setCurrentTheme(ApplicationSettings::instance()->getCurrentTheme()); connect(ThemeManager::instance(), SIGNAL(signalThemeChanged()), this, SLOT(slotThemeChanged())); } void DigikamApp::preloadWindows() { if (d->splashScreen) { d->splashScreen->setMessage(i18n("Loading tools...")); } QueueMgrWindow::queueManagerWindow(); ImageWindow::imageWindow(); LightTableWindow::lightTableWindow(); d->tagsActionManager->registerTagsActionCollections(); } void DigikamApp::initGui() { // Initialize Actions --------------------------------------- d->deleteAction->setEnabled(false); d->renameAction->setEnabled(false); d->addImagesAction->setEnabled(false); d->propsEditAction->setEnabled(false); d->openInFileManagerAction->setEnabled(false); d->imageViewAction->setEnabled(false); d->imagePreviewAction->setEnabled(false); d->imageLightTableAction->setEnabled(false); d->imageAddLightTableAction->setEnabled(false); + d->imageScanForFacesAction->setEnabled(false); d->imageFindSimilarAction->setEnabled(false); d->imageRenameAction->setEnabled(false); d->imageDeleteAction->setEnabled(false); d->imageExifOrientationActionMenu->setEnabled(false); d->openWithAction->setEnabled(false); d->slideShowSelectionAction->setEnabled(false); m_metadataEditAction->setEnabled(false); d->imageAutoExifActionMenu->setEnabled(false); #ifdef HAVE_MARBLE m_geolocationEditAction->setEnabled(false); #endif d->albumSortAction->setCurrentItem((int)ApplicationSettings::instance()->getAlbumSortRole()); d->imageSortAction->setCurrentItem((int)ApplicationSettings::instance()->getImageSortOrder()); d->imageSortOrderAction->setCurrentItem((int)ApplicationSettings::instance()->getImageSorting()); d->imageSeparationAction->setCurrentItem((int)ApplicationSettings::instance()->getImageSeparationMode()-1); // no action for enum 0 d->imageSeparationSortOrderAction->setCurrentItem((int)ApplicationSettings::instance()->getImageSeparationSortOrder()); d->recurseAlbumsAction->setChecked(ApplicationSettings::instance()->getRecurseAlbums()); d->recurseTagsAction->setChecked(ApplicationSettings::instance()->getRecurseTags()); d->showBarAction->setChecked(ApplicationSettings::instance()->getShowThumbbar()); showMenuBarAction()->setChecked(!menuBar()->isHidden()); // NOTE: workaround for bug #171080 slotSwitchedToIconView(); } } // namespace Digikam diff --git a/core/app/main/digikamui5.rc b/core/app/main/digikamui5.rc index da7d66c82b..cc80c8e0b6 100644 --- a/core/app/main/digikamui5.rc +++ b/core/app/main/digikamui5.rc @@ -1,227 +1,228 @@ - + &Browse &Album T&ag &Item + &Edit &View &Tools I&mport &Export &Settings &Help Main Toolbar diff --git a/core/app/views/digikamview.cpp b/core/app/views/digikamview.cpp index c51a5e6ebf..da052115ae 100644 --- a/core/app/views/digikamview.cpp +++ b/core/app/views/digikamview.cpp @@ -1,2766 +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(signalEditItem()), - this, SLOT(slotImageEdit())); - 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(signalSlideShow()), - this, SLOT(slotSlideShowAll())); - connect(d->stackedview, SIGNAL(signalSlideShowCurrent()), this, SLOT(slotSlideShowManualFromCurrent())); connect(d->stackedview, SIGNAL(signalZoomFactorChanged(double)), this, SLOT(slotZoomFactorChanged(double))); - connect(d->stackedview, SIGNAL(signalInsert2LightTable()), - this, SLOT(slotImageAddToLightTable())); - - connect(d->stackedview, SIGNAL(signalInsert2QueueMgr()), - this, SLOT(slotImageAddToCurrentQueue())); - - connect(d->stackedview, SIGNAL(signalFindSimilar()), - this, SLOT(slotImageFindSimilar())); - 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) { slotLeftSideBarActivate(d->fuzzySearchSideBar); d->fuzzySearchSideBar->newDuplicatesSearch(albums); } void DigikamView::slotNewDuplicatesSearch(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) { titles[i] = d->userPresentableAlbumTitle(titles.at(i)); } } void DigikamView::getForwardHistory(QStringList& titles) { d->albumHistory->getForwardHistory(titles); 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) { 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 6c3010d612..f5756451bf 100644 --- a/core/app/views/digikamview.h +++ b/core/app/views/digikamview.h @@ -1,340 +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 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); // 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/imagepreviewview.cpp b/core/app/views/imagepreviewview.cpp index fa045715e4..25c1fe8711 100644 --- a/core/app/views/imagepreviewview.cpp +++ b/core/app/views/imagepreviewview.cpp @@ -1,576 +1,577 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2006-21-12 * Description : a embedded view to show the image preview widget. * * Copyright (C) 2006-2018 by Gilles Caulier * Copyright (C) 2009-2012 by Andi Clemens * Copyright (C) 2010-2011 by Aditya Bhatt * * 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 "imagepreviewview.h" // Qt includes #include #include #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "digikam_debug.h" #include "digikam_config.h" #include "imagepreviewviewitem.h" #include "applicationsettings.h" #include "contextmenuhelper.h" #include "ddragobjects.h" #include "digikamapp.h" #include "dimg.h" #include "dimgpreviewitem.h" #include "imageinfo.h" #include "fileactionmngr.h" #include "metadatasettings.h" #include "regionframeitem.h" #include "tagspopupmenu.h" #include "thememanager.h" #include "previewlayout.h" #include "previewsettings.h" #include "tagscache.h" #include "imagetagpair.h" #include "albummanager.h" #include "facegroup.h" namespace Digikam { class ImagePreviewView::Private { public: explicit Private() { fullSize = 0; scale = 1.0; item = 0; isValid = false; rotationLock = false; toolBar = 0; prevAction = 0; nextAction = 0; rotLeftAction = 0; rotRightAction = 0; mode = ImagePreviewView::IconViewPreview; faceGroup = 0; peopleToggleAction = 0; addPersonAction = 0; forgetFacesAction = 0; fullscreenAction = 0; currAlbum = 0; } bool fullSize; double scale; bool isValid; bool rotationLock; ImagePreviewView::Mode mode; ImagePreviewViewItem* item; QAction* prevAction; QAction* nextAction; QAction* rotLeftAction; QAction* rotRightAction; QToolBar* toolBar; FaceGroup* faceGroup; QAction* peopleToggleAction; QAction* addPersonAction; QAction* forgetFacesAction; QAction* fullscreenAction; Album* currAlbum; }; -ImagePreviewView::ImagePreviewView(QWidget* const parent, Mode mode, Album* currAlbum) +ImagePreviewView::ImagePreviewView(QWidget* const parent, Mode mode, Album* const currAlbum) : GraphicsDImgView(parent), d(new Private()) { d->mode = mode; d->item = new ImagePreviewViewItem(); d->currAlbum = currAlbum; setItem(d->item); d->faceGroup = new FaceGroup(this); d->faceGroup->setShowOnHover(true); d->item->setFaceGroup(d->faceGroup); connect(d->item, SIGNAL(loaded()), this, SLOT(imageLoaded())); connect(d->item, SIGNAL(loadingFailed()), this, SLOT(imageLoadingFailed())); connect(d->item, SIGNAL(imageChanged()), this, SLOT(slotUpdateFaces())); connect(d->item, SIGNAL(showContextMenu(QGraphicsSceneContextMenuEvent*)), this, SLOT(slotShowContextMenu(QGraphicsSceneContextMenuEvent*))); // set default zoom layout()->fitToWindow(); // ------------------------------------------------------------ installPanIcon(); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); // ------------------------------------------------------------ d->prevAction = new QAction(QIcon::fromTheme(QLatin1String("go-previous")), i18nc("go to previous image", "Back"), this); d->nextAction = new QAction(QIcon::fromTheme(QLatin1String("go-next")), i18nc("go to next image", "Forward"), this); d->rotLeftAction = new QAction(QIcon::fromTheme(QLatin1String("object-rotate-left")), i18nc("@info:tooltip", "Rotate Left"), this); d->rotRightAction = new QAction(QIcon::fromTheme(QLatin1String("object-rotate-right")), i18nc("@info:tooltip", "Rotate Right"), this); d->addPersonAction = new QAction(QIcon::fromTheme(QLatin1String("list-add-user")), i18n("Add a Face Tag"), this); d->forgetFacesAction = new QAction(QIcon::fromTheme(QLatin1String("list-remove-user")), i18n("Clear all faces on this image"), this); d->peopleToggleAction = new QAction(QIcon::fromTheme(QLatin1String("im-user")), i18n("Show Face Tags"), this); d->peopleToggleAction->setCheckable(true); d->fullscreenAction = new QAction(QIcon::fromTheme(QLatin1String("media-playback-start")), i18n("Show Fullscreen"), this); d->toolBar = new QToolBar(this); if (mode == IconViewPreview) { d->toolBar->addAction(d->prevAction); d->toolBar->addAction(d->nextAction); } d->toolBar->addAction(d->rotLeftAction); d->toolBar->addAction(d->rotRightAction); d->toolBar->addAction(d->peopleToggleAction); d->toolBar->addAction(d->addPersonAction); d->toolBar->addAction(d->fullscreenAction); connect(d->prevAction, SIGNAL(triggered()), this, SIGNAL(toPreviousImage())); connect(d->nextAction, SIGNAL(triggered()), this, SIGNAL(toNextImage())); connect(d->rotLeftAction, SIGNAL(triggered()), this, SLOT(slotRotateLeft())); connect(d->rotRightAction, SIGNAL(triggered()), this, SLOT(slotRotateRight())); connect(d->peopleToggleAction, SIGNAL(toggled(bool)), d->faceGroup, SLOT(setVisible(bool))); connect(d->addPersonAction, SIGNAL(triggered()), d->faceGroup, SLOT(addFace())); connect(d->forgetFacesAction, SIGNAL(triggered()), d->faceGroup, SLOT(rejectAll())); connect(d->fullscreenAction, SIGNAL(triggered()), this, SIGNAL(signalSlideShowCurrent())); // ------------------------------------------------------------ connect(this, SIGNAL(toNextImage()), this, SIGNAL(signalNextItem())); connect(this, SIGNAL(toPreviousImage()), this, SIGNAL(signalPrevItem())); connect(this, SIGNAL(activated()), this, SIGNAL(signalEscapePreview())); connect(ThemeManager::instance(), SIGNAL(signalThemeChanged()), this, SLOT(slotThemeChanged())); connect(ApplicationSettings::instance(), SIGNAL(setupChanged()), this, SLOT(slotSetupChanged())); slotSetupChanged(); } ImagePreviewView::~ImagePreviewView() { delete d->item; delete d; } void ImagePreviewView::reload() { previewItem()->reload(); } void ImagePreviewView::imageLoaded() { emit signalPreviewLoaded(true); d->rotLeftAction->setEnabled(true); d->rotRightAction->setEnabled(true); d->faceGroup->setInfo(d->item->imageInfo()); } void ImagePreviewView::imageLoadingFailed() { emit signalPreviewLoaded(false); d->rotLeftAction->setEnabled(false); d->rotRightAction->setEnabled(false); d->faceGroup->setInfo(ImageInfo()); } void ImagePreviewView::setImageInfo(const ImageInfo& info, const ImageInfo& previous, const ImageInfo& next) { d->faceGroup->aboutToSetInfo(info); d->item->setImageInfo(info); d->prevAction->setEnabled(!previous.isNull()); d->nextAction->setEnabled(!next.isNull()); QStringList previewPaths; if (next.category() == DatabaseItem::Image) { previewPaths << next.filePath(); } if (previous.category() == DatabaseItem::Image) { previewPaths << previous.filePath(); } d->item->setPreloadPaths(previewPaths); } ImageInfo ImagePreviewView::getImageInfo() const { return d->item->imageInfo(); } bool ImagePreviewView::acceptsMouseClick(QMouseEvent* e) { if (!GraphicsDImgView::acceptsMouseClick(e)) { return false; } return d->faceGroup->acceptsMouseClick(mapToScene(e->pos())); } void ImagePreviewView::enterEvent(QEvent* e) { d->faceGroup->enterEvent(e); } void ImagePreviewView::leaveEvent(QEvent* e) { d->faceGroup->leaveEvent(e); } void ImagePreviewView::showEvent(QShowEvent* e) { GraphicsDImgView::showEvent(e); d->faceGroup->setVisible(d->peopleToggleAction->isChecked()); } void ImagePreviewView::slotShowContextMenu(QGraphicsSceneContextMenuEvent* event) { ImageInfo info = d->item->imageInfo(); if (info.isNull()) { return; } event->accept(); QList idList; idList << info.id(); // -------------------------------------------------------- QMenu popmenu(this); ContextMenuHelper cmHelper(&popmenu); cmHelper.addAction(QLatin1String("full_screen")); cmHelper.addAction(QLatin1String("options_show_menubar")); cmHelper.addSeparator(); // -------------------------------------------------------- if (d->mode == IconViewPreview) { cmHelper.addAction(d->prevAction, true); cmHelper.addAction(d->nextAction, true); cmHelper.addSeparator(); } // -------------------------------------------------------- cmHelper.addAction(d->peopleToggleAction, true); cmHelper.addAction(d->addPersonAction, true); cmHelper.addAction(d->forgetFacesAction, true); cmHelper.addSeparator(); // -------------------------------------------------------- cmHelper.addOpenAndNavigateActions(idList); cmHelper.addSeparator(); // -------------------------------------------------------- + cmHelper.addAction(QLatin1String("image_scan_for_faces")); cmHelper.addAction(QLatin1String("image_find_similar")); if (d->mode == IconViewPreview) { cmHelper.addStandardActionLightTable(); } cmHelper.addQueueManagerMenu(); cmHelper.addSeparator(); // -------------------------------------------------------- cmHelper.addAction(QLatin1String("image_rotate")); cmHelper.addStandardActionItemDelete(this, SLOT(slotDeleteItem())); cmHelper.addSeparator(); // -------------------------------------------------------- if (d->mode == IconViewPreview && d->currAlbum) { cmHelper.addStandardActionThumbnail(idList, d->currAlbum); } cmHelper.addAssignTagsMenu(idList); cmHelper.addRemoveTagsMenu(idList); cmHelper.addLabelsAction(); // special action handling -------------------------------- connect(&cmHelper, SIGNAL(signalAssignTag(int)), this, SLOT(slotAssignTag(int))); connect(&cmHelper, SIGNAL(signalPopupTagsView()), this, SIGNAL(signalPopupTagsView())); connect(&cmHelper, SIGNAL(signalRemoveTag(int)), this, SLOT(slotRemoveTag(int))); connect(&cmHelper, SIGNAL(signalAssignPickLabel(int)), this, SLOT(slotAssignPickLabel(int))); connect(&cmHelper, SIGNAL(signalAssignColorLabel(int)), this, SLOT(slotAssignColorLabel(int))); connect(&cmHelper, SIGNAL(signalAssignRating(int)), this, SLOT(slotAssignRating(int))); connect(&cmHelper, SIGNAL(signalAddToExistingQueue(int)), this, SIGNAL(signalAddToExistingQueue(int))); connect(&cmHelper, SIGNAL(signalGotoTag(int)), this, SIGNAL(signalGotoTagAndItem(int))); connect(&cmHelper, SIGNAL(signalGotoAlbum(ImageInfo)), this, SIGNAL(signalGotoAlbumAndItem(ImageInfo))); connect(&cmHelper, SIGNAL(signalGotoDate(ImageInfo)), this, SIGNAL(signalGotoDateAndItem(ImageInfo))); cmHelper.exec(event->screenPos()); } void ImagePreviewView::slotAssignTag(int tagID) { FileActionMngr::instance()->assignTag(d->item->imageInfo(), tagID); } void ImagePreviewView::slotRemoveTag(int tagID) { FileActionMngr::instance()->removeTag(d->item->imageInfo(), tagID); } void ImagePreviewView::slotAssignPickLabel(int pickId) { FileActionMngr::instance()->assignPickLabel(d->item->imageInfo(), pickId); } void ImagePreviewView::slotAssignColorLabel(int colorId) { FileActionMngr::instance()->assignColorLabel(d->item->imageInfo(), colorId); } void ImagePreviewView::slotAssignRating(int rating) { FileActionMngr::instance()->assignRating(d->item->imageInfo(), rating); } void ImagePreviewView::slotThemeChanged() { QPalette plt(palette()); plt.setColor(backgroundRole(), qApp->palette().color(QPalette::Base)); setPalette(plt); } void ImagePreviewView::slotSetupChanged() { previewItem()->setPreviewSettings(ApplicationSettings::instance()->getPreviewSettings()); d->toolBar->setVisible(ApplicationSettings::instance()->getPreviewShowIcons()); setShowText(ApplicationSettings::instance()->getPreviewShowIcons()); // pass auto-suggest? } void ImagePreviewView::slotRotateLeft() { if (d->rotationLock) return; d->rotationLock = true; /** * Setting lock won't allow mouse hover events in ImagePreviewViewItem class */ d->item->setAcceptHoverEvents(false); /** * aboutToSetInfo will delete all face tags from FaceGroup storage */ d->faceGroup->aboutToSetInfo(ImageInfo()); FileActionMngr::instance()->transform(QList() << d->item->imageInfo(), MetaEngineRotation::Rotate270); } void ImagePreviewView::slotRotateRight() { if (d->rotationLock) return; d->rotationLock = true; /** * Setting lock won't allow mouse hover events in ImagePreviewViewItem class */ d->item->setAcceptHoverEvents(false); /** * aboutToSetInfo will delete all face tags from FaceGroup storage */ d->faceGroup->aboutToSetInfo(ImageInfo()); FileActionMngr::instance()->transform(QList() << d->item->imageInfo(), MetaEngineRotation::Rotate90); } void ImagePreviewView::slotDeleteItem() { emit signalDeleteItem(); } void Digikam::ImagePreviewView::slotUpdateFaces() { //d->faceGroup->aboutToSetInfo(ImageInfo()); d->faceGroup->aboutToSetInfoAfterRotate(ImageInfo()); d->item->setAcceptHoverEvents(true); /** * Release rotation lock after rotation */ d->rotationLock = false; } void ImagePreviewView::dragMoveEvent(QDragMoveEvent* e) { if (DTagListDrag::canDecode(e->mimeData())) { e->accept(); return; } e->ignore(); } void ImagePreviewView::dragEnterEvent(QDragEnterEvent* e) { if (DTagListDrag::canDecode(e->mimeData())) { e->accept(); return; } e->ignore(); } void ImagePreviewView::dropEvent(QDropEvent* e) { if (DTagListDrag::canDecode(e->mimeData())) { QList tagIDs; if (!DTagListDrag::decode(e->mimeData(), tagIDs)) { return; } QMenu popMenu(this); QAction* const assignToThisAction = popMenu.addAction(QIcon::fromTheme(QLatin1String("tag")), i18n("Assign Tags to &This Item")); popMenu.addSeparator(); popMenu.addAction(QIcon::fromTheme(QLatin1String("dialog-cancel")), i18n("&Cancel")); popMenu.setMouseTracking(true); QAction* const choice = popMenu.exec(this->mapToGlobal(e->pos())); if (choice == assignToThisAction) { FileActionMngr::instance()->assignTags(d->item->imageInfo(), tagIDs); } } e->accept(); return; } void ImagePreviewView::mousePressEvent(QMouseEvent* e) { if (e->button() == Qt::LeftButton && QApplication::keyboardModifiers() == Qt::ControlModifier) { d->faceGroup->addFace(); } GraphicsDImgView::mousePressEvent(e); } } // namespace Digikam diff --git a/core/app/views/imagepreviewview.h b/core/app/views/imagepreviewview.h index 348e4264f7..af897276d9 100644 --- a/core/app/views/imagepreviewview.h +++ b/core/app/views/imagepreviewview.h @@ -1,137 +1,132 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2006-21-12 * Description : a embedded view to show the image preview widget. * * Copyright (C) 2006-2018 by Gilles Caulier * Copyright (C) 2009-2012 by Andi Clemens * Copyright (C) 2010-2011 by Aditya Bhatt * * 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_IMAGE_PREVIEW_VIEW_H #define DIGIKAM_IMAGE_PREVIEW_VIEW_H // Local includes #include "graphicsdimgview.h" #include "imageinfo.h" class QPixmap; class QDragMoveEvent; class QDropEvent; class QDragEnterEvent; namespace Digikam { class Album; class LoadingDescription; class ImagePreviewView : public GraphicsDImgView { Q_OBJECT public: enum Mode { IconViewPreview, LightTablePreview }; public: - explicit ImagePreviewView(QWidget* const parent, Mode mode=IconViewPreview, Album* currAlbum = 0); + explicit ImagePreviewView(QWidget* const parent, Mode mode=IconViewPreview, Album* const currAlbum = 0); ~ImagePreviewView(); void setImageInfo(const ImageInfo& info = ImageInfo(), const ImageInfo& previous = ImageInfo(), const ImageInfo& next = ImageInfo()); ImageInfo getImageInfo() const; void reload(); void setImagePath(const QString& path=QString()); void setPreviousNextPaths(const QString& previous, const QString& next); Q_SIGNALS: void signalNextItem(); void signalPrevItem(); void signalDeleteItem(); - void signalEditItem(); void signalPreviewLoaded(bool success); void signalEscapePreview(); void signalSlideShowCurrent(); - void signalSlideShow(); - void signalInsert2LightTable(); - void signalInsert2QueueMgr(); - void signalFindSimilar(); void signalAddToExistingQueue(int); void signalGotoAlbumAndItem(const ImageInfo&); void signalGotoDateAndItem(const ImageInfo&); void signalGotoTagAndItem(int); void signalPopupTagsView(); protected: bool acceptsMouseClick(QMouseEvent* e); void mousePressEvent(QMouseEvent* e); void enterEvent(QEvent* e); void leaveEvent(QEvent* e); void showEvent(QShowEvent* e); void dropEvent(QDropEvent* e); void dragMoveEvent(QDragMoveEvent* e); void dragEnterEvent(QDragEnterEvent* e); private Q_SLOTS: void imageLoaded(); void imageLoadingFailed(); void slotAssignTag(int tagID); void slotRemoveTag(int tagID); void slotAssignRating(int rating); void slotAssignPickLabel(int pickId); void slotAssignColorLabel(int colorId); void slotThemeChanged(); void slotSetupChanged(); void slotRotateLeft(); void slotRotateRight(); void slotDeleteItem(); /** * @brief slotUpdateFaces - after applying some transformation on * image, update face tags position */ void slotUpdateFaces(); void slotShowContextMenu(QGraphicsSceneContextMenuEvent* event); private: class Private; Private* const d; }; } // namespace Digikam #endif // DIGIKAM_IMAGE_PREVIEW_VIEW_H diff --git a/core/app/views/stackedview.cpp b/core/app/views/stackedview.cpp index d5c5f7da30..697b2ce35a 100644 --- a/core/app/views/stackedview.cpp +++ b/core/app/views/stackedview.cpp @@ -1,592 +1,577 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2006-06-13 * Description : A widget stack to embedded album content view * or the current image preview. * * Copyright (C) 2006-2018 by Gilles Caulier * Copyright (C) 2013 by Michael G. Hansen * Copyright (C) 2015 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 "stackedview.h" // Qt includes #include #include // KDE includes #include // Local includes #include "digikam_config.h" #include "digikam_debug.h" #include "applicationsettings.h" #include "digikamimageview.h" #include "digikamview.h" #include "imagealbummodel.h" #include "imagealbumfiltermodel.h" #include "imagepreviewview.h" #include "imagethumbnailbar.h" #include "loadingcacheinterface.h" #include "previewlayout.h" #include "welcomepageview.h" #include "thumbbardock.h" #include "tableview.h" #include "trashview.h" #include "dimg.h" #ifdef HAVE_MEDIAPLAYER # include "mediaplayerview.h" #endif //HAVE_MEDIAPLAYER #ifdef HAVE_MARBLE # include "mapwidgetview.h" #endif // HAVE_MARBLE namespace Digikam { class StackedView::Private { public: explicit Private() { dockArea = 0; splitter = 0; thumbBar = 0; thumbBarDock = 0; imageIconView = 0; imagePreviewView = 0; welcomePageView = 0; needUpdateBar = false; syncingSelection = false; tableView = 0; trashView = 0; #ifdef HAVE_MEDIAPLAYER mediaPlayerView = 0; #endif //HAVE_MEDIAPLAYER #ifdef HAVE_MARBLE mapWidgetView = 0; #endif // HAVE_MARBLE } bool needUpdateBar; bool syncingSelection; QMainWindow* dockArea; QSplitter* splitter; DigikamImageView* imageIconView; ImageThumbnailBar* thumbBar; ImagePreviewView* imagePreviewView; ThumbBarDock* thumbBarDock; WelcomePageView* welcomePageView; TableView* tableView; TrashView* trashView; #ifdef HAVE_MEDIAPLAYER MediaPlayerView* mediaPlayerView; #endif //HAVE_MEDIAPLAYER #ifdef HAVE_MARBLE MapWidgetView* mapWidgetView; #endif // HAVE_MARBLE }; StackedView::StackedView(QWidget* const parent) : QStackedWidget(parent), d(new Private) { d->imageIconView = new DigikamImageView(this); d->imagePreviewView = new ImagePreviewView(this); d->thumbBarDock = new ThumbBarDock(); d->thumbBar = new ImageThumbnailBar(d->thumbBarDock); d->thumbBar->setModelsFiltered(d->imageIconView->imageModel(), d->imageIconView->imageFilterModel()); d->thumbBar->installOverlays(); d->thumbBarDock->setWidget(d->thumbBar); d->thumbBarDock->setObjectName(QLatin1String("mainwindow_thumbbar")); d->welcomePageView = new WelcomePageView(this); d->tableView = new TableView(d->imageIconView->getSelectionModel(), d->imageIconView->imageFilterModel(), this); d->tableView->setObjectName(QLatin1String("mainwindow_tableview")); d->trashView = new TrashView(this); #ifdef HAVE_MARBLE d->mapWidgetView = new MapWidgetView(d->imageIconView->getSelectionModel(), d->imageIconView->imageFilterModel(), this, MapWidgetView::ApplicationDigikam ); d->mapWidgetView->setObjectName(QLatin1String("mainwindow_mapwidgetview")); #endif // HAVE_MARBLE #ifdef HAVE_MEDIAPLAYER d->mediaPlayerView = new MediaPlayerView(this); #endif //HAVE_MEDIAPLAYER insertWidget(IconViewMode, d->imageIconView); insertWidget(PreviewImageMode, d->imagePreviewView); insertWidget(WelcomePageMode, d->welcomePageView); insertWidget(TableViewMode, d->tableView); insertWidget(TrashViewMode, d->trashView); #ifdef HAVE_MARBLE insertWidget(MapWidgetMode, d->mapWidgetView); #endif // HAVE_MARBLE #ifdef HAVE_MEDIAPLAYER insertWidget(MediaPlayerMode, d->mediaPlayerView); #endif //HAVE_MEDIAPLAYER setViewMode(IconViewMode); setAttribute(Qt::WA_DeleteOnClose); readSettings(); // ----------------------------------------------------------------- connect(d->imagePreviewView, SIGNAL(signalPopupTagsView()), this, SIGNAL(signalPopupTagsView())); connect(d->imagePreviewView, SIGNAL(signalGotoAlbumAndItem(ImageInfo)), this, SIGNAL(signalGotoAlbumAndItem(ImageInfo))); connect(d->imagePreviewView, SIGNAL(signalGotoDateAndItem(ImageInfo)), this, SIGNAL(signalGotoDateAndItem(ImageInfo))); connect(d->imagePreviewView, SIGNAL(signalGotoTagAndItem(int)), this, SIGNAL(signalGotoTagAndItem(int))); connect(d->imagePreviewView, SIGNAL(signalNextItem()), this, SIGNAL(signalNextItem())); connect(d->imagePreviewView, SIGNAL(signalPrevItem()), this, SIGNAL(signalPrevItem())); - connect(d->imagePreviewView, SIGNAL(signalEditItem()), - this, SIGNAL(signalEditItem())); - connect(d->imagePreviewView, SIGNAL(signalDeleteItem()), this, SIGNAL(signalDeleteItem())); connect(d->imagePreviewView, SIGNAL(signalEscapePreview()), this, SIGNAL(signalEscapePreview())); - connect(d->imagePreviewView, SIGNAL(signalSlideShow()), - this, SIGNAL(signalSlideShow())); - connect(d->imagePreviewView, SIGNAL(signalSlideShowCurrent()), this, SIGNAL(signalSlideShowCurrent())); connect(d->imagePreviewView->layout(), SIGNAL(zoomFactorChanged(double)), this, SLOT(slotZoomFactorChanged(double))); - connect(d->imagePreviewView, SIGNAL(signalInsert2LightTable()), - this, SIGNAL(signalInsert2LightTable())); - - connect(d->imagePreviewView, SIGNAL(signalInsert2QueueMgr()), - this, SIGNAL(signalInsert2QueueMgr())); - - connect(d->imagePreviewView, SIGNAL(signalFindSimilar()), - this, SIGNAL(signalFindSimilar())); - connect(d->imagePreviewView, SIGNAL(signalAddToExistingQueue(int)), this, SIGNAL(signalAddToExistingQueue(int))); connect(d->thumbBar, SIGNAL(selectionChanged()), this, SLOT(slotThumbBarSelectionChanged())); connect(d->imageIconView, SIGNAL(selectionChanged()), this, SLOT(slotIconViewSelectionChanged())); connect(d->thumbBarDock, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), d->thumbBar, SLOT(slotDockLocationChanged(Qt::DockWidgetArea))); connect(d->imagePreviewView, SIGNAL(signalPreviewLoaded(bool)), this, SLOT(slotPreviewLoaded(bool))); #ifdef HAVE_MEDIAPLAYER connect(d->mediaPlayerView, SIGNAL(signalNextItem()), this, SIGNAL(signalNextItem())); connect(d->mediaPlayerView, SIGNAL(signalPrevItem()), this, SIGNAL(signalPrevItem())); connect(d->mediaPlayerView, SIGNAL(signalEscapePreview()), this, SIGNAL(signalEscapePreview())); #endif //HAVE_MEDIAPLAYER } StackedView::~StackedView() { delete d; } void StackedView::readSettings() { ApplicationSettings* settings = ApplicationSettings::instance(); bool showThumbbar = settings->getShowThumbbar(); d->thumbBarDock->setShouldBeVisible(showThumbbar); } void StackedView::setDockArea(QMainWindow* dockArea) { // Attach the thumbbar dock to the given dock area and place it initially on top. d->dockArea = dockArea; d->thumbBarDock->setParent(d->dockArea); d->dockArea->addDockWidget(Qt::TopDockWidgetArea, d->thumbBarDock); d->thumbBarDock->setFloating(false); } ThumbBarDock* StackedView::thumbBarDock() const { return d->thumbBarDock; } ImageThumbnailBar* StackedView::thumbBar() const { return d->thumbBar; } void StackedView::slotEscapePreview() { #ifdef HAVE_MEDIAPLAYER if (viewMode() == MediaPlayerMode) { d->mediaPlayerView->escapePreview(); } #endif //HAVE_MEDIAPLAYER } DigikamImageView* StackedView::imageIconView() const { return d->imageIconView; } ImagePreviewView* StackedView::imagePreviewView() const { return d->imagePreviewView; } #ifdef HAVE_MARBLE MapWidgetView* StackedView::mapWidgetView() const { return d->mapWidgetView; } #endif // HAVE_MARBLE TableView* StackedView::tableView() const { return d->tableView; } TrashView* StackedView::trashView() const { return d->trashView; } #ifdef HAVE_MEDIAPLAYER MediaPlayerView* StackedView::mediaPlayerView() const { return d->mediaPlayerView; } #endif //HAVE_MEDIAPLAYER bool StackedView::isInSingleFileMode() const { return currentIndex() == PreviewImageMode || currentIndex() == MediaPlayerMode; } bool StackedView::isInMultipleFileMode() const { return (currentIndex() == IconViewMode || currentIndex() == MapWidgetMode || currentIndex() == TableViewMode); } bool StackedView::isInAbstractMode() const { return currentIndex() == WelcomePageMode; } void StackedView::setPreviewItem(const ImageInfo& info, const ImageInfo& previous, const ImageInfo& next) { if (info.isNull()) { if (viewMode() == MediaPlayerMode) { #ifdef HAVE_MEDIAPLAYER d->mediaPlayerView->setCurrentItem(); #endif //HAVE_MEDIAPLAYER } else if (viewMode() == PreviewImageMode) { d->imagePreviewView->setImageInfo(); } } else { if (info.category() == DatabaseItem::Audio || info.category() == DatabaseItem::Video || DImg::isAnimatedImage(info.fileUrl().toLocalFile()) // Special case for animated image as GIF or NMG ) { // Stop image viewer if (viewMode() == PreviewImageMode) { d->imagePreviewView->setImageInfo(); } #ifdef HAVE_MEDIAPLAYER setViewMode(MediaPlayerMode); d->mediaPlayerView->setCurrentItem(info.fileUrl(), !previous.isNull(), !next.isNull()); #endif //HAVE_MEDIAPLAYER } else // Static image or Raw image. { // Stop media player if running... if (viewMode() == MediaPlayerMode) { #ifdef HAVE_MEDIAPLAYER d->mediaPlayerView->setCurrentItem(); #endif //HAVE_MEDIAPLAYER } d->imagePreviewView->setImageInfo(info, previous, next); // NOTE: No need to toggle immediately in PreviewImageMode here, // because we will receive a signal for that when the image preview will be loaded. // This will prevent a flicker effect with the old image preview loaded in stack. } // do not touch the selection, only adjust current info QModelIndex currentIndex = d->thumbBar->imageSortFilterModel()->indexForImageInfo(info); d->thumbBar->selectionModel()->setCurrentIndex(currentIndex, QItemSelectionModel::NoUpdate); } } StackedView::StackedViewMode StackedView::viewMode() const { return StackedViewMode(indexOf(currentWidget())); } void StackedView::setViewMode(const StackedViewMode mode) { qCDebug(DIGIKAM_GENERAL_LOG) << "Stacked View Mode : " << mode; if ((mode < StackedViewModeFirst) || (mode > StackedViewModeLast)) { return; } if (mode == PreviewImageMode || mode == MediaPlayerMode) { d->thumbBarDock->restoreVisibility(); syncSelection(d->imageIconView, d->thumbBar); } else { d->thumbBarDock->hide(); } if (mode == IconViewMode || mode == WelcomePageMode || mode == MapWidgetMode || mode == TableViewMode) { setPreviewItem(); setCurrentIndex(mode); } else { setCurrentIndex(mode); } #ifdef HAVE_MARBLE d->mapWidgetView->setActive(mode == MapWidgetMode); #endif // HAVE_MARBLE d->tableView->slotSetActive(mode == TableViewMode); if (mode == IconViewMode) { d->imageIconView->setFocus(); } #ifdef HAVE_MARBLE else if (mode == MapWidgetMode) { d->mapWidgetView->setFocus(); } #endif // HAVE_MARBLE else if (mode == TableViewMode) { d->tableView->setFocus(); } emit signalViewModeChanged(); } void StackedView::syncSelection(ImageCategorizedView* from, ImageCategorizedView* to) { ImageSortFilterModel* const fromModel = from->imageSortFilterModel(); ImageSortFilterModel* const toModel = to->imageSortFilterModel(); QModelIndex currentIndex = toModel->indexForImageInfo(from->currentInfo()); // sync selection QItemSelection selection = from->selectionModel()->selection(); QItemSelection newSelection; foreach(const QItemSelectionRange& range, selection) { QModelIndex topLeft = toModel->indexForImageInfo(fromModel->imageInfo(range.topLeft())); QModelIndex bottomRight = toModel->indexForImageInfo(fromModel->imageInfo(range.bottomRight())); newSelection.select(topLeft, bottomRight); } d->syncingSelection = true; if (currentIndex.isValid()) { // set current info to->setCurrentIndex(currentIndex); } to->selectionModel()->select(newSelection, QItemSelectionModel::ClearAndSelect); d->syncingSelection = false; } void StackedView::slotThumbBarSelectionChanged() { if (currentIndex() != PreviewImageMode && currentIndex() != MediaPlayerMode) { return; } if (d->syncingSelection) { return; } syncSelection(d->thumbBar, d->imageIconView); } void StackedView::slotIconViewSelectionChanged() { if (currentIndex() != IconViewMode) { return; } if (d->syncingSelection) { return; } syncSelection(d->imageIconView, d->thumbBar); } void StackedView::previewLoaded() { emit signalViewModeChanged(); } void StackedView::slotZoomFactorChanged(double z) { if (viewMode() == PreviewImageMode) { emit signalZoomFactorChanged(z); } } void StackedView::increaseZoom() { d->imagePreviewView->layout()->increaseZoom(); } void StackedView::decreaseZoom() { d->imagePreviewView->layout()->decreaseZoom(); } void StackedView::zoomTo100Percents() { d->imagePreviewView->layout()->setZoomFactor(1.0, QPoint()); } void StackedView::fitToWindow() { d->imagePreviewView->layout()->fitToWindow(); } void StackedView::toggleFitToWindowOr100() { d->imagePreviewView->layout()->toggleFitToWindowOr100(); } bool StackedView::maxZoom() { return d->imagePreviewView->layout()->atMaxZoom(); } bool StackedView::minZoom() { return d->imagePreviewView->layout()->atMinZoom(); } void StackedView::setZoomFactor(double z) { // Giving a null anchor means to use the current view center d->imagePreviewView->layout()->setZoomFactor(z, QPoint()); } void StackedView::setZoomFactorSnapped(double z) { d->imagePreviewView->layout()->setZoomFactor(z, QPoint(), SinglePhotoPreviewLayout::SnapZoomFactor); } double StackedView::zoomFactor() { return d->imagePreviewView->layout()->zoomFactor(); } double StackedView::zoomMin() { return d->imagePreviewView->layout()->minZoomFactor(); } double StackedView::zoomMax() { return d->imagePreviewView->layout()->maxZoomFactor(); } void StackedView::slotPreviewLoaded(bool) { setViewMode(StackedView::PreviewImageMode); previewLoaded(); } } // namespace Digikam diff --git a/core/app/views/stackedview.h b/core/app/views/stackedview.h index d2a6a51613..f2f08db529 100644 --- a/core/app/views/stackedview.h +++ b/core/app/views/stackedview.h @@ -1,175 +1,170 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2006-06-13 * Description : A widget stack to embedded album content view * or the current image preview. * * Copyright (C) 2006-2018 by Gilles Caulier * Copyright (C) 2013 by Michael G. Hansen * * 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_STACKED_VIEW_H #define DIGIKAM_STACKED_VIEW_H // Qt includes #include #include // Local includes #include "digikam_config.h" #include "digikam_export.h" #include "imageinfo.h" #include "thumbbardock.h" namespace Digikam { class DigikamImageView; class ImageCategorizedView; class ImagePreviewView; class ImageThumbnailBar; class TableView; class TrashView; #ifdef HAVE_MEDIAPLAYER class MediaPlayerView; #endif //HAVE_MEDIAPLAYER #ifdef HAVE_MARBLE class MapWidgetView; #endif // HAVE_MARBLE class StackedView : public QStackedWidget { Q_OBJECT public: enum StackedViewMode { StackedViewModeFirst = 0, IconViewMode = 0, PreviewImageMode = 1, WelcomePageMode = 2, TableViewMode = 3, TrashViewMode = 4, MapWidgetMode = 5, MediaPlayerMode = 6, StackedViewModeLast = 6 }; public: explicit StackedView(QWidget* const parent=0); ~StackedView(); /* Attach the thumbnail dock widget to the specified QMainWindow. */ void setDockArea(QMainWindow*); ThumbBarDock* thumbBarDock() const; ImageThumbnailBar* thumbBar() const; DigikamImageView* imageIconView() const; ImagePreviewView* imagePreviewView() const; TableView* tableView() const; TrashView* trashView() const; #ifdef HAVE_MEDIAPLAYER MediaPlayerView* mediaPlayerView() const; #endif //HAVE_MEDIAPLAYER #ifdef HAVE_MARBLE MapWidgetView* mapWidgetView() const; #endif // HAVE_MARBLE /** * Single-file mode is image preview or media player, * multi-file is icon view or map, * abstract modes do not handle files (welcome page) */ bool isInSingleFileMode() const; bool isInMultipleFileMode() const; bool isInAbstractMode() const; void setPreviewItem(const ImageInfo& info = ImageInfo(), const ImageInfo& previous = ImageInfo(), const ImageInfo& next = ImageInfo()); StackedViewMode viewMode() const; void setViewMode(const StackedViewMode mode); void previewLoaded(); void increaseZoom(); void decreaseZoom(); void fitToWindow(); void toggleFitToWindowOr100(); void zoomTo100Percents(); bool maxZoom(); bool minZoom(); void setZoomFactor(double z); void setZoomFactorSnapped(double z); double zoomFactor(); double zoomMin(); double zoomMax(); Q_SIGNALS: void signalNextItem(); void signalPrevItem(); - void signalEditItem(); void signalDeleteItem(); void signalViewModeChanged(); void signalEscapePreview(); - void signalSlideShow(); void signalSlideShowCurrent(); void signalZoomFactorChanged(double); - void signalInsert2LightTable(); - void signalInsert2QueueMgr(); - void signalFindSimilar(); void signalPopupTagsView(); void signalAddToExistingQueue(int); void signalGotoAlbumAndItem(const ImageInfo&); void signalGotoDateAndItem(const ImageInfo&); void signalGotoTagAndItem(int); public Q_SLOTS: void slotEscapePreview(); private Q_SLOTS: void slotPreviewLoaded(bool); void slotZoomFactorChanged(double); void slotThumbBarSelectionChanged(); void slotIconViewSelectionChanged(); private: void readSettings(); void syncSelection(ImageCategorizedView* from, ImageCategorizedView* to); private: class Private; Private* const d; }; } // namespace Digikam #endif // DIGIKAM_STACKED_VIEW_H diff --git a/core/libs/rawengine/libraw/COPYRIGHT b/core/libs/rawengine/libraw/COPYRIGHT old mode 100755 new mode 100644 diff --git a/core/libs/rawengine/libraw/Changelog.txt b/core/libs/rawengine/libraw/Changelog.txt old mode 100755 new mode 100644 diff --git a/core/libs/rawengine/libraw/LICENSE.CDDL b/core/libs/rawengine/libraw/LICENSE.CDDL old mode 100755 new mode 100644 diff --git a/core/libs/rawengine/libraw/LICENSE.LGPL b/core/libs/rawengine/libraw/LICENSE.LGPL old mode 100755 new mode 100644 diff --git a/core/utilities/facemanagement/facescansettings.h b/core/utilities/facemanagement/facescansettings.h index 01dd95e754..3b647d1501 100644 --- a/core/utilities/facemanagement/facescansettings.h +++ b/core/utilities/facemanagement/facescansettings.h @@ -1,89 +1,91 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2010-10-09 * Description : Face scan settings * * Copyright (C) 2010-2012 by Marcel Wiesweg * Copyright (C) 2012-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_FACE_SCAN_SETTINGS_H #define DIGIKAM_FACE_SCAN_SETTINGS_H // Local includes #include "album.h" +#include "imageinfo.h" #include "recognitiondatabase.h" namespace Digikam { -class Album; - class FaceScanSettings { public: enum ScanTask { Detect, DetectAndRecognize, RecognizeMarkedFaces, RetrainAll, BenchmarkDetection, BenchmarkRecognition }; // for detect and recognize enum AlreadyScannedHandling { Skip, Merge, Rescan }; public: explicit FaceScanSettings() { useFullCpu = false; accuracy = 80; task = Detect; alreadyScannedHandling = Skip; recognizeAlgorithm = RecognitionDatabase::RecognizeAlgorithm::DNN; } // processing power bool useFullCpu; // detection double accuracy; // albums to scan AlbumList albums; + // image infos to scan + ImageInfoList infos; + ScanTask task; AlreadyScannedHandling alreadyScannedHandling; RecognitionDatabase::RecognizeAlgorithm recognizeAlgorithm; }; } // namespace Digikam #endif // DIGIKAM_FACE_SCAN_SETTINGS_H diff --git a/core/utilities/import/views/importpreviewview.h b/core/utilities/import/views/importpreviewview.h index abc02fb94a..ad985388bc 100644 --- a/core/utilities/import/views/importpreviewview.h +++ b/core/utilities/import/views/importpreviewview.h @@ -1,123 +1,118 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2012-14-07 * Description : An embedded view to show the cam item preview widget. * * Copyright (C) 2012 by Islam Wazery * * 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 IMPORTPREVIEWVIEW_H #define IMPORTPREVIEWVIEW_H // Local includes #include "graphicsdimgview.h" #include "camiteminfo.h" namespace Digikam { class ImportPreviewView : public GraphicsDImgView { Q_OBJECT public: enum Mode { IconViewPreview }; public: explicit ImportPreviewView(QWidget* const parent, Mode mode = IconViewPreview); ~ImportPreviewView(); void setCamItemInfo(const CamItemInfo& info = CamItemInfo(), const CamItemInfo& previous = CamItemInfo(), const CamItemInfo& next = CamItemInfo()); CamItemInfo getCamItemInfo() const; void reload(); void setCamItemPath(const QString& path = QString()); void setPreviousNextPaths(const QString& previous, const QString& next); void showContextMenu(const CamItemInfo& info, QGraphicsSceneContextMenuEvent* event); private: QString identifyCategoryforMime(QString mime); Q_SIGNALS: void signalNextItem(); void signalPrevItem(); void signalDeleteItem(); - void signalEditItem(); void signalPreviewLoaded(bool success); void signalEscapePreview(); - //void signalSlideShow(); - //void signalInsert2LightTable(); - //void signalInsert2QueueMgr(); - //void signalFindSimilar(); //void signalAddToExistingQueue(int); //void signalGotoFolderAndItem(const CamItemInfo&); //void signalGotoDateAndItem(const CamItemInfo&); //void signalGotoTagAndItem(int); //void signalPopupTagsView(); void signalAssignPickLabel(int); void signalAssignColorLabel(int); void signalAssignRating(int); protected: bool acceptsMouseClick(QMouseEvent* e); void enterEvent(QEvent* e); void leaveEvent(QEvent* e); void showEvent(QShowEvent* e); private Q_SLOTS: void camItemLoaded(); void camItemLoadingFailed(); //TODO: Implement Tags and Labels in Import Tool //void slotAssignTag(int tagID); //void slotRemoveTag(int tagID); //void slotAssignPickLabel(int pickId); //void slotAssignColorLabel(int colorId); void slotThemeChanged(); void slotSetupChanged(); void slotRotateLeft(); void slotRotateRight(); void slotDeleteItem(); private: class Private; Private* const d; }; } // namespace Digikam #endif // IMPORTPREVIEWVIEW_H diff --git a/core/utilities/import/views/importstackedview.cpp b/core/utilities/import/views/importstackedview.cpp index 0e74f9f4a1..b8222d2213 100644 --- a/core/utilities/import/views/importstackedview.cpp +++ b/core/utilities/import/views/importstackedview.cpp @@ -1,529 +1,517 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2012-05-07 * Description : QStackedWidget to handle different types of views * (icon view, image preview, media view) * * Copyright (C) 2012 by Islam Wazery * Copyright (C) 2012-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. * * ============================================================ */ #include "importstackedview.h" // Qt includes #include // Local includes #include "digikam_debug.h" #include "previewlayout.h" #include "importsettings.h" namespace Digikam { class MediaPlayerView; class ImportStackedView::Private { public: explicit Private() { dockArea = 0; splitter = 0; thumbBar = 0; thumbBarDock = 0; importIconView = 0; importPreviewView = 0; #ifdef HAVE_MARBLE mapWidgetView = 0; #endif // HAVE_MARBLE #ifdef HAVE_MEDIAPLAYER mediaPlayerView = 0; #endif // HAVE_MEDIAPLAYER syncingSelection = false; } QMainWindow* dockArea; QSplitter* splitter; ImportThumbnailBar* thumbBar; ThumbBarDock* thumbBarDock; ImportIconView* importIconView; ImportPreviewView* importPreviewView; #ifdef HAVE_MARBLE MapWidgetView* mapWidgetView; #endif // HAVE_MARBLE #ifdef HAVE_MEDIAPLAYER MediaPlayerView* mediaPlayerView; // Reuse of albumgui mediaplayer view. #endif // HAVE_MEDIAPLAYER bool syncingSelection; }; ImportStackedView::ImportStackedView(QWidget* const parent) : QStackedWidget(parent), d(new Private) { d->importIconView = new ImportIconView(this); d->importPreviewView = new ImportPreviewView(this); d->thumbBarDock = new ThumbBarDock(); d->thumbBar = new ImportThumbnailBar(d->thumbBarDock); d->thumbBar->setModelsFiltered(d->importIconView->importImageModel(), d->importIconView->importFilterModel()); d->thumbBar->installOverlays(); d->thumbBarDock->setWidget(d->thumbBar); d->thumbBarDock->setObjectName(QLatin1String("import_thumbbar")); #ifdef HAVE_MARBLE // TODO refactor MapWidgetView not to require the models on startup? d->mapWidgetView = new MapWidgetView(d->importIconView->getSelectionModel(), d->importIconView->importFilterModel(), this, MapWidgetView::ApplicationImportUI); d->mapWidgetView->setObjectName(QLatin1String("import_mapwidgetview")); #endif // HAVE_MARBLE #ifdef HAVE_MEDIAPLAYER d->mediaPlayerView = new MediaPlayerView(this); #endif //HAVE_MEDIAPLAYER insertWidget(PreviewCameraMode, d->importIconView); insertWidget(PreviewImageMode, d->importPreviewView); #ifdef HAVE_MARBLE insertWidget(MapWidgetMode, d->mapWidgetView); #endif // HAVE_MARBLE #ifdef HAVE_MEDIAPLAYER insertWidget(MediaPlayerMode, d->mediaPlayerView); #endif //HAVE_MEDIAPLAYER setAttribute(Qt::WA_DeleteOnClose); readSettings(); // ----------------------------------------------------------------- //FIXME: connect(d->importPreviewView, SIGNAL(signalPopupTagsView()), //d->importIconView, SIGNAL(signalPopupTagsView())); //connect(d->importPreviewView, SIGNAL(signalGotoFolderAndItem(CamItemInfo)), //this, SIGNAL(signalGotoFolderAndItem(CamItemInfo))); //connect(d->importPreviewView, SIGNAL(signalGotoDateAndItem(CamItemInfo)), //this, SIGNAL(signalGotoDateAndItem(CamItemInfo))); //FIXME: connect(d->importPreviewView, SIGNAL(signalGotoTagAndItem(int)), //this, SIGNAL(signalGotoTagAndItem(int))); connect(d->importPreviewView, SIGNAL(signalNextItem()), this, SIGNAL(signalNextItem())); connect(d->importPreviewView, SIGNAL(signalPrevItem()), this, SIGNAL(signalPrevItem())); - //connect(d->importPreviewView, SIGNAL(signalEditItem()), - //this, SIGNAL(signalEditItem())); - //FIXME: connect(d->importPreviewView, SIGNAL(signalDeleteItem()), //this, SIGNAL(signalDeleteItem())); connect(d->importPreviewView, SIGNAL(signalEscapePreview()), this, SIGNAL(signalEscapePreview())); // A workaround to assign pickLabel, colorLabel, and rating in the preview view. connect(d->importPreviewView, SIGNAL(signalAssignPickLabel(int)), d->importIconView, SLOT(assignPickLabelToSelected(int))); connect(d->importPreviewView, SIGNAL(signalAssignColorLabel(int)), d->importIconView, SLOT(assignColorLabelToSelected(int))); connect(d->importPreviewView, SIGNAL(signalAssignRating(int)), d->importIconView, SLOT(assignRatingToSelected(int))); connect(d->importPreviewView->layout(), SIGNAL(zoomFactorChanged(double)), this, SLOT(slotZoomFactorChanged(double))); - //FIXME: connect(d->importPreviewView, SIGNAL(signalInsert2LightTable()), - //this, SIGNAL(signalInsert2LightTable())); - - //FIXME: connect(d->importPreviewView, SIGNAL(signalInsert2QueueMgr()), - //this, SIGNAL(signalInsert2QueueMgr())); - - //FIXME: connect(d->importPreviewView, SIGNAL(signalFindSimilar()), - //this, SIGNAL(signalFindSimilar())); - //FIXME: connect(d->importPreviewView, SIGNAL(signalAddToExistingQueue(int)), //this, SIGNAL(signalAddToExistingQueue(int))); connect(d->thumbBar, SIGNAL(selectionChanged()), this, SLOT(slotThumbBarSelectionChanged())); connect(d->importIconView, SIGNAL(selectionChanged()), this, SLOT(slotIconViewSelectionChanged())); connect(d->thumbBarDock, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), d->thumbBar, SLOT(slotDockLocationChanged(Qt::DockWidgetArea))); connect(d->importPreviewView, SIGNAL(signalPreviewLoaded(bool)), this, SLOT(slotPreviewLoaded(bool))); #ifdef HAVE_MEDIAPLAYER connect(d->mediaPlayerView, SIGNAL(signalNextItem()), this, SIGNAL(signalNextItem())); connect(d->mediaPlayerView, SIGNAL(signalPrevItem()), this, SIGNAL(signalPrevItem())); connect(d->mediaPlayerView, SIGNAL(signalEscapePreview()), this, SIGNAL(signalEscapePreview())); #endif //HAVE_MEDIAPLAYER } ImportStackedView::~ImportStackedView() { delete d; } void ImportStackedView::readSettings() { ImportSettings* const settings = ImportSettings::instance(); bool showThumbbar = settings->getShowThumbbar(); d->thumbBarDock->setShouldBeVisible(showThumbbar); } void ImportStackedView::setDockArea(QMainWindow* dockArea) { // Attach the thumbbar dock to the given dock area and place it initially on top. d->dockArea = dockArea; d->thumbBarDock->setParent(d->dockArea); d->dockArea->addDockWidget(Qt::TopDockWidgetArea, d->thumbBarDock); d->thumbBarDock->setFloating(false); } ThumbBarDock* ImportStackedView::thumbBarDock() const { return d->thumbBarDock; } ImportThumbnailBar* ImportStackedView::thumbBar() const { return d->thumbBar; } void ImportStackedView::slotEscapePreview() { #ifdef HAVE_MEDIAPLAYER if (viewMode() == MediaPlayerMode) { d->mediaPlayerView->escapePreview(); } #endif //HAVE_MEDIAPLAYER } ImportIconView* ImportStackedView::importIconView() const { return d->importIconView; } ImportPreviewView* ImportStackedView::importPreviewView() const { return d->importPreviewView; } #ifdef HAVE_MARBLE MapWidgetView* ImportStackedView::mapWidgetView() const { return d->mapWidgetView; } #endif // HAVE_MARBLE #ifdef HAVE_MEDIAPLAYER MediaPlayerView* ImportStackedView::mediaPlayerView() const { return d->mediaPlayerView; } #endif //HAVE_MEDIAPLAYER bool ImportStackedView::isInSingleFileMode() const { return currentIndex() == PreviewImageMode || currentIndex() == MediaPlayerMode; } bool ImportStackedView::isInMultipleFileMode() const { return currentIndex() == PreviewCameraMode || currentIndex() == MapWidgetMode; } void ImportStackedView::setPreviewItem(const CamItemInfo& info, const CamItemInfo& previous, const CamItemInfo& next) { if (info.isNull()) { if (viewMode() == MediaPlayerMode) { #ifdef HAVE_MEDIAPLAYER d->mediaPlayerView->setCurrentItem(); #endif //HAVE_MEDIAPLAYER } else if (viewMode() == PreviewImageMode) { d->importPreviewView->setCamItemInfo(); } } else { if (identifyCategoryforMime(info.mime) == QLatin1String("audio") || identifyCategoryforMime(info.mime) == QLatin1String("video")) { // Stop image viewer if (viewMode() == PreviewImageMode) { d->importPreviewView->setCamItemInfo(); } #ifdef HAVE_MEDIAPLAYER setViewMode(MediaPlayerMode); d->mediaPlayerView->setCurrentItem(info.url(), !previous.isNull(), !next.isNull()); #endif //HAVE_MEDIAPLAYER } else { // Stop media player if running... if (viewMode() == MediaPlayerMode) { #ifdef HAVE_MEDIAPLAYER d->mediaPlayerView->setCurrentItem(); #endif //HAVE_MEDIAPLAYER } d->importPreviewView->setCamItemInfo(info, previous, next); // NOTE: No need to toggle immediately in PreviewImageMode here, // because we will receive a signal for that when the image preview will be loaded. // This will prevent a flicker effect with the old image preview loaded in stack. } // do not touch the selection, only adjust current info QModelIndex currentIndex = d->thumbBar->importSortFilterModel()->indexForCamItemInfo(info); d->thumbBar->selectionModel()->setCurrentIndex(currentIndex, QItemSelectionModel::NoUpdate); } } QString ImportStackedView::identifyCategoryforMime(const QString& mime) const { return mime.split(QLatin1Char('/')).at(0); } ImportStackedView::StackedViewMode ImportStackedView::viewMode() const { return (StackedViewMode)(indexOf(currentWidget())); } void ImportStackedView::setViewMode(const StackedViewMode mode) { if (mode != PreviewCameraMode && mode != PreviewImageMode && mode != MediaPlayerMode && mode != MapWidgetMode) { return; } if (mode == PreviewImageMode || mode == MediaPlayerMode) { d->thumbBarDock->restoreVisibility(); syncSelection(d->importIconView, d->thumbBar); } else { d->thumbBarDock->hide(); } if (mode == PreviewCameraMode || mode == MapWidgetMode) { setPreviewItem(); setCurrentIndex(mode); } else { setCurrentIndex(mode); } #ifdef HAVE_MARBLE d->mapWidgetView->setActive(mode == MapWidgetMode); #endif // HAVE_MARBLE if (mode == PreviewCameraMode) { d->importIconView->setFocus(); } #ifdef HAVE_MARBLE else if (mode == MapWidgetMode) { d->mapWidgetView->setFocus(); } #endif // HAVE_MARBLE emit signalViewModeChanged(); } void ImportStackedView::syncSelection(ImportCategorizedView* const from, ImportCategorizedView* const to) { ImportSortFilterModel* const fromModel = from->importSortFilterModel(); ImportSortFilterModel* const toModel = to->importSortFilterModel(); QModelIndex currentIndex = toModel->indexForCamItemInfo(from->currentInfo()); // sync selection QItemSelection selection = from->selectionModel()->selection(); QItemSelection newSelection; foreach(const QItemSelectionRange& range, selection) { QModelIndex topLeft = toModel->indexForCamItemInfo(fromModel->camItemInfo(range.topLeft())); QModelIndex bottomRight = toModel->indexForCamItemInfo(fromModel->camItemInfo(range.bottomRight())); newSelection.select(topLeft, bottomRight); } d->syncingSelection = true; if (currentIndex.isValid()) { // set current info to->setCurrentIndex(currentIndex); } to->selectionModel()->select(newSelection, QItemSelectionModel::ClearAndSelect); d->syncingSelection = false; } void ImportStackedView::slotThumbBarSelectionChanged() { if (currentIndex() != PreviewImageMode && currentIndex() != MediaPlayerMode) { return; } if (d->syncingSelection) { return; } syncSelection(d->thumbBar, d->importIconView); } void ImportStackedView::slotIconViewSelectionChanged() { if (currentIndex() != PreviewCameraMode) { return; } if (d->syncingSelection) { return; } syncSelection(d->importIconView, d->thumbBar); } void ImportStackedView::previewLoaded() { emit signalViewModeChanged(); } void ImportStackedView::slotZoomFactorChanged(double z) { if (viewMode() == PreviewImageMode) { emit signalZoomFactorChanged(z); } } void ImportStackedView::increaseZoom() { d->importPreviewView->layout()->increaseZoom(); } void ImportStackedView::decreaseZoom() { d->importPreviewView->layout()->decreaseZoom(); } void ImportStackedView::zoomTo100Percents() { d->importPreviewView->layout()->setZoomFactor(1.0); } void ImportStackedView::fitToWindow() { d->importPreviewView->layout()->fitToWindow(); } void ImportStackedView::toggleFitToWindowOr100() { d->importPreviewView->layout()->toggleFitToWindowOr100(); } bool ImportStackedView::maxZoom() const { return d->importPreviewView->layout()->atMaxZoom(); } bool ImportStackedView::minZoom() const { return d->importPreviewView->layout()->atMinZoom(); } void ImportStackedView::setZoomFactor(double z) { // Giving a null anchor means to use the current view center d->importPreviewView->layout()->setZoomFactor(z, QPoint()); } void ImportStackedView::setZoomFactorSnapped(double z) { d->importPreviewView->layout()->setZoomFactor(z, QPoint(), SinglePhotoPreviewLayout::SnapZoomFactor); } double ImportStackedView::zoomFactor() const { return d->importPreviewView->layout()->zoomFactor(); } double ImportStackedView::zoomMin() const { return d->importPreviewView->layout()->minZoomFactor(); } double ImportStackedView::zoomMax() const { return d->importPreviewView->layout()->maxZoomFactor(); } void ImportStackedView::slotPreviewLoaded(bool) { setViewMode(ImportStackedView::PreviewImageMode); previewLoaded(); } } // namespace Digikam diff --git a/core/utilities/import/views/importstackedview.h b/core/utilities/import/views/importstackedview.h index 91dbfb8d0d..f24ba60b69 100644 --- a/core/utilities/import/views/importstackedview.h +++ b/core/utilities/import/views/importstackedview.h @@ -1,160 +1,158 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2012-05-07 * Description : QStackedWidget to handle different types of views * (icon view, items preview, media view) * * Copyright (C) 2012 by Islam Wazery * Copyright (C) 2012-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 IMPORTSTACKEDVIEW_H #define IMPORTSTACKEDVIEW_H // Qt inclueds #include // Local includes #include "digikam_config.h" #include "importthumbnailbar.h" #include "importpreviewview.h" #include "thumbbardock.h" #include "camiteminfo.h" #include "importiconview.h" #include "digikam_export.h" #ifdef HAVE_MEDIAPLAYER #include "mediaplayerview.h" #endif //HAVE_MEDIAPLAYER #ifdef HAVE_MARBLE #include "mapwidgetview.h" #endif // HAVE_MARBLE namespace Digikam { class DIGIKAM_EXPORT ImportStackedView : public QStackedWidget { Q_OBJECT public: enum StackedViewMode { PreviewCameraMode = 0, // previewing the set of items on the camera PreviewImageMode, #ifdef HAVE_MARBLE MapWidgetMode, MediaPlayerMode #else MediaPlayerMode, MapWidgetMode #endif // HAVE_MARBLE }; public: explicit ImportStackedView(QWidget*const parent = 0); ~ImportStackedView(); void setDockArea(QMainWindow*); ThumbBarDock* thumbBarDock() const; ImportThumbnailBar* thumbBar() const; ImportIconView* importIconView() const; ImportPreviewView* importPreviewView() const; #ifdef HAVE_MARBLE MapWidgetView* mapWidgetView() const; #endif // HAVE_MARBLE #ifdef HAVE_MEDIAPLAYER MediaPlayerView* mediaPlayerView() const; #endif //HAVE_MEDIAPLAYER bool isInSingleFileMode() const; bool isInMultipleFileMode() const; //FIXME: bool isInAbstractMode() const; void setPreviewItem(const CamItemInfo& info = CamItemInfo(), const CamItemInfo& previous = CamItemInfo(), const CamItemInfo& next = CamItemInfo()); StackedViewMode viewMode() const; void setViewMode(const StackedViewMode mode); void previewLoaded(); void increaseZoom(); void decreaseZoom(); void fitToWindow(); void toggleFitToWindowOr100(); void zoomTo100Percents(); void setZoomFactor(double z); void setZoomFactorSnapped(double z); bool maxZoom() const; bool minZoom() const; double zoomFactor() const; double zoomMin() const; double zoomMax() const; Q_SIGNALS: void signalNextItem(); void signalPrevItem(); - //FIXME: void signalEditItem(); void signalViewModeChanged(); void signalEscapePreview(); - //FIXME: void signalSlideShow(); void signalZoomFactorChanged(double); //FIXME: void signalGotoAlbumAndItem(const CamItemInfo&); //FIXME: void signalGotoDateAndItem(const CamItemInfo&); //FIXME: void signalGotoTagAndItem(int); public Q_SLOTS: void slotEscapePreview(); private Q_SLOTS: void slotPreviewLoaded(bool); void slotZoomFactorChanged(double); void slotThumbBarSelectionChanged(); void slotIconViewSelectionChanged(); private: void readSettings(); void syncSelection(ImportCategorizedView* const from, ImportCategorizedView* const to); /// Used to return the category for a specified camera item. QString identifyCategoryforMime(const QString& mime) const; private: class Private; Private* const d; }; } // namespace Digikam #endif // IMPORTSTACKEDVIEW_H diff --git a/core/utilities/import/views/importview.cpp b/core/utilities/import/views/importview.cpp index 0eb1fa96f2..9177119d1b 100644 --- a/core/utilities/import/views/importview.cpp +++ b/core/utilities/import/views/importview.cpp @@ -1,864 +1,861 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2012-26-07 * Description : Main view for import tool * * Copyright (C) 2012 by Islam Wazery * Copyright (C) 2012-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. * * ============================================================ */ #include "importview.h" // Qt includes #include #include #include // Local includes #include "digikam_debug.h" #include "digikam_config.h" #include "digikam_globals.h" #include "dmessagebox.h" #include "importui.h" #include "importiconview.h" #include "thumbnailsize.h" #include "fileactionmngr.h" #include "importsettings.h" #include "sidebar.h" #include "dzoombar.h" #include "camitemsortsettings.h" #ifdef HAVE_MARBLE #include "mapwidgetview.h" #endif // HAVE_MARBLE namespace Digikam { class ImportView::Private { public: explicit Private() : needDispatchSelection(false), thumbSize(ThumbnailSize::Medium), dockArea(0), splitter(0), selectionTimer(0), thumbSizeTimer(0), parent(0), iconView(0), #ifdef HAVE_MARBLE mapView(0), #endif // HAVE_MARBLE stackedView(0), lastViewMode(ImportStackedView::PreviewCameraMode) //FIXME: filterWidget(0) { } void addPageUpDownActions(ImportView* const q, QWidget* const w); public: bool needDispatchSelection; int thumbSize; QMainWindow* dockArea; SidebarSplitter* splitter; QTimer* selectionTimer; QTimer* thumbSizeTimer; ImportUI* parent; ImportIconView* iconView; #ifdef HAVE_MARBLE MapWidgetView* mapView; #endif // HAVE_MARBLE ImportStackedView* stackedView; ImportStackedView::StackedViewMode lastViewMode; //FIXME: FilterSideBarWidget* filterWidget; QString optionAlbumViewPrefix; }; void ImportView::Private::addPageUpDownActions(ImportView* 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())); } ImportView::ImportView(ImportUI* const ui, QWidget* const parent) : DHBox(parent), d(new Private) { d->parent = static_cast(ui); d->splitter = new SidebarSplitter; d->splitter->setFrameStyle(QFrame::NoFrame); d->splitter->setFrameShadow(QFrame::Plain); d->splitter->setFrameShape(QFrame::NoFrame); d->splitter->setOpaqueResize(false); d->splitter->setParent(this); // The dock area where the thumbnail bar is allowed to go. // TODO qmainwindow here, wtf? d->dockArea = new QMainWindow(this, Qt::Widget); d->splitter->addWidget(d->dockArea); d->stackedView = new ImportStackedView(d->dockArea); d->stackedView->setViewMode(ImportStackedView::PreviewCameraMode); // call here, because the models need to be set first.. d->dockArea->setCentralWidget(d->stackedView); d->stackedView->setDockArea(d->dockArea); d->iconView = d->stackedView->importIconView(); #ifdef HAVE_MARBLE d->mapView = d->stackedView->mapWidgetView(); #endif // HAVE_MARBLE d->addPageUpDownActions(this, d->stackedView->importPreviewView()); d->addPageUpDownActions(this, d->stackedView->thumbBar()); #ifdef HAVE_MEDIAPLAYER d->addPageUpDownActions(this, d->stackedView->mediaPlayerView()); #endif //HAVE_MEDIAPLAYER 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); setupConnections(); loadViewState(); } ImportView::~ImportView() { saveViewState(); delete d; } void ImportView::applySettings() { //refreshView(); } void ImportView::refreshView() { //d->rightSideBar->refreshTagsView(); } void ImportView::setupConnections() { // -- ImportUI connections ---------------------------------- connect(d->parent, SIGNAL(signalEscapePressed()), this, SLOT(slotEscapePreview())); connect(d->parent, SIGNAL(signalEscapePressed()), d->stackedView, SLOT(slotEscapePreview())); // Preview items while download. connect(d->parent, SIGNAL(signalPreviewRequested(CamItemInfo,bool)), this, SLOT(slotTogglePreviewMode(CamItemInfo,bool))); // -- 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(CamItemInfo,bool)), this, SLOT(slotTogglePreviewMode(CamItemInfo,bool))); connect(d->iconView, SIGNAL(zoomOutStep()), this, SLOT(slotZoomOut())); connect(d->iconView, SIGNAL(zoomInStep()), this, SLOT(slotZoomIn())); // -- Preview image widget Connections ------------------------ connect(d->stackedView, SIGNAL(signalNextItem()), this, SLOT(slotNextItem())); connect(d->stackedView, SIGNAL(signalPrevItem()), this, SLOT(slotPrevItem())); - //connect(d->stackedView, SIGNAL(signalEditItem()), - //this, SLOT(slotImageEdit())); - connect(d->stackedView, SIGNAL(signalViewModeChanged()), this, SLOT(slotViewModeChanged())); connect(d->stackedView, SIGNAL(signalEscapePreview()), this, SLOT(slotEscapePreview())); connect(d->stackedView, SIGNAL(signalZoomFactorChanged(double)), this, SLOT(slotZoomFactorChanged(double))); // -- 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()) ); // -- Import Settings ---------------- //connect(ImportSettings::instance(), SIGNAL(setupChanged()), //this, SLOT(slotSidebarTabTitleStyleChanged())); } /* void ImportView::connectIconViewFilter(FilterStatusBar* 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 ImportView::slotPopupFiltersView() { d->rightSideBar->setActiveTab(d->filterWidget); d->filterWidget->setFocusToTextFilter(); } */ void ImportView::loadViewState() { //TODO: d->filterWidget->loadState(); KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group("Import MainWindow"); // Restore the splitter d->splitter->restoreState(group); // Restore the thumbnail bar dock. QByteArray thumbbarState; thumbbarState = group.readEntry("ThumbbarState", thumbbarState); d->dockArea->restoreState(QByteArray::fromBase64(thumbbarState)); #ifdef HAVE_MARBLE d->mapView->loadState(); #endif // HAVE_MARBLE } void ImportView::saveViewState() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group("Import MainWindow"); //TODO: 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("ThumbbarState", d->dockArea->saveState().toBase64()); #ifdef HAVE_MARBLE d->mapView->saveState(); #endif // HAVE_MARBLE } CamItemInfo ImportView::camItemInfo(const QString& folder, const QString& file) const { return d->iconView->camItemInfo(folder, file); } CamItemInfo& ImportView::camItemInfoRef(const QString& folder, const QString& file) const { return d->iconView->camItemInfoRef(folder, file); } bool ImportView::hasImage(const CamItemInfo& info) const { return d->iconView->importImageModel()->hasImage(info); } QList ImportView::allUrls() const { return d->iconView->urls(); } QList ImportView::selectedUrls() const { return d->iconView->selectedUrls(); } QList ImportView::selectedCamItemInfos() const { return d->iconView->selectedCamItemInfos(); } QList ImportView::allItems() const { return d->iconView->camItemInfos(); } void ImportView::setSelectedCamItemInfos(const CamItemInfoList& infos) const { d->iconView->setSelectedCamItemInfos(infos); } int ImportView::downloadedCamItemInfos() const { QList infos = d->iconView->camItemInfos(); int numberOfDownloaded = 0; foreach(const CamItemInfo& info, infos) { if (info.downloaded == CamItemInfo::DownloadedYes) { ++numberOfDownloaded; } } return numberOfDownloaded; } bool ImportView::isSelected(const QUrl& url) const { QList urlsList = selectedUrls(); foreach(const QUrl& selected, urlsList) { if (url == selected) { return true; } } return false; } void ImportView::slotFirstItem() { d->iconView->toFirstIndex(); } void ImportView::slotPrevItem() { d->iconView->toPreviousIndex(); } void ImportView::slotNextItem() { d->iconView->toNextIndex(); } void ImportView::slotLastItem() { d->iconView->toLastIndex(); } void ImportView::slotSelectItemByUrl(const QUrl& url) { d->iconView->toIndex(url); } void ImportView::slotImageSelected() { // delay to slotDispatchImageSelected d->needDispatchSelection = true; d->selectionTimer->start(); emit signalSelectionChanged(d->iconView->numberOfSelectedIndexes()); } void ImportView::slotDispatchImageSelected() { if (d->needDispatchSelection) { // the list of CamItemInfos of currently selected items, currentItem first // since the iconView tracks the changes also while we are in map widget mode, // we can still pull the data from the iconView const CamItemInfoList list = d->iconView->selectedCamItemInfosCurrentFirst(); const CamItemInfoList allImages = d->iconView->camItemInfos(); if (list.isEmpty()) { d->stackedView->setPreviewItem(); emit signalImageSelected(list, allImages); emit signalNewSelection(false); emit signalNoCurrentItem(); } else { CamItemInfo previousInfo; CamItemInfo nextInfo; if (d->stackedView->viewMode() != ImportStackedView::MapWidgetMode) { previousInfo = d->iconView->previousInfo(list.first()); nextInfo = d->iconView->nextInfo(list.first()); } if ( (d->stackedView->viewMode() != ImportStackedView::PreviewCameraMode) && (d->stackedView->viewMode() != ImportStackedView::MapWidgetMode) ) { d->stackedView->setPreviewItem(list.first(), previousInfo, nextInfo); } emit signalImageSelected(list, allImages); emit signalNewSelection(true); } d->needDispatchSelection = false; } } double ImportView::zoomMin() const { return d->stackedView->zoomMin(); } double ImportView::zoomMax() const { return d->stackedView->zoomMax(); } void ImportView::setZoomFactor(double zoom) { d->stackedView->setZoomFactorSnapped(zoom); } void ImportView::slotZoomFactorChanged(double zoom) { toggleZoomActions(); emit signalZoomChanged(zoom); } void ImportView::setThumbSize(int size) { if (d->stackedView->viewMode() == ImportStackedView::PreviewImageMode) { double z = DZoomBar::zoomFromSize(size, zoomMin(), zoomMax()); setZoomFactor(z); } else if (d->stackedView->viewMode() == ImportStackedView::PreviewCameraMode) { 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(); } } ThumbnailSize ImportView::thumbnailSize() const { return ThumbnailSize(d->thumbSize); } void ImportView::slotThumbSizeEffect() { d->iconView->setThumbnailSize(ThumbnailSize(d->thumbSize)); toggleZoomActions(); ImportSettings::instance()->setDefaultIconSize(d->thumbSize); } void ImportView::toggleZoomActions() { if (d->stackedView->viewMode() == ImportStackedView::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 (d->stackedView->viewMode() == ImportStackedView::PreviewCameraMode) { 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 ImportView::slotZoomIn() { if (d->stackedView->viewMode() == ImportStackedView::PreviewCameraMode) { setThumbSize(d->thumbSize + ThumbnailSize::Step); toggleZoomActions(); emit signalThumbSizeChanged(d->thumbSize); } else if (d->stackedView->viewMode() == ImportStackedView::PreviewImageMode) { d->stackedView->increaseZoom(); } } void ImportView::slotZoomOut() { if (d->stackedView->viewMode() == ImportStackedView::PreviewCameraMode) { setThumbSize(d->thumbSize - ThumbnailSize::Step); toggleZoomActions(); emit signalThumbSizeChanged(d->thumbSize); } else if (d->stackedView->viewMode() == ImportStackedView::PreviewImageMode) { d->stackedView->decreaseZoom(); } } void ImportView::slotZoomTo100Percents() { if (d->stackedView->viewMode() == ImportStackedView::PreviewImageMode) { d->stackedView->toggleFitToWindowOr100(); } } void ImportView::slotFitToWindow() { if (d->stackedView->viewMode() == ImportStackedView::PreviewCameraMode) { int nts = d->iconView->fitToWidthIcons(); setThumbSize(nts); toggleZoomActions(); emit signalThumbSizeChanged(d->thumbSize); } else if (d->stackedView->viewMode() == ImportStackedView::PreviewImageMode) { d->stackedView->fitToWindow(); } } void ImportView::slotEscapePreview() { if (d->stackedView->viewMode() == ImportStackedView::PreviewCameraMode) //TODO: || d->stackedView->viewMode() == ImportStackedView::WelcomePageMode) { return; } // pass a null camera item info, because we want to fall back to the old // view mode slotTogglePreviewMode(CamItemInfo(), false); } void ImportView::slotMapWidgetView() { d->stackedView->setViewMode(ImportStackedView::MapWidgetMode); } void ImportView::slotIconView() { if (d->stackedView->viewMode() == ImportStackedView::PreviewImageMode) { emit signalThumbSizeChanged(d->iconView->thumbnailSize().size()); } // and switch to icon view d->stackedView->setViewMode(ImportStackedView::PreviewCameraMode); // make sure the next/previous buttons are updated slotImageSelected(); } void ImportView::slotImagePreview() { const int currentPreviewMode = d->stackedView->viewMode(); CamItemInfo currentInfo; if (currentPreviewMode == ImportStackedView::PreviewCameraMode) { currentInfo = d->iconView->currentInfo(); } #ifdef HAVE_MARBLE //TODO: Implement MapWidget else if (currentPreviewMode == ImportStackedView::MapWidgetMode) { currentInfo = d->mapView->currentCamItemInfo(); } #endif // HAVE_MARBLE slotTogglePreviewMode(currentInfo, false); } /** * @brief This method toggles between IconView/MapWidgetView and ImportPreview modes, depending on the context. */ void ImportView::slotTogglePreviewMode(const CamItemInfo& info, bool downloadPreview) { if (!d->parent->cameraUseUMSDriver()) { return; } if ( (d->stackedView->viewMode() == ImportStackedView::PreviewCameraMode || d->stackedView->viewMode() == ImportStackedView::MapWidgetMode || downloadPreview) && !info.isNull() ) { d->lastViewMode = d->stackedView->viewMode(); CamItemInfo previous = CamItemInfo(); if (!downloadPreview) { previous = d->iconView->previousInfo(info); } d->stackedView->setPreviewItem(info, previous, d->iconView->nextInfo(info)); } else { // go back to either CameraViewMode or MapWidgetMode d->stackedView->setViewMode(d->lastViewMode); } if(!downloadPreview) { // make sure the next/previous buttons are updated slotImageSelected(); } } void ImportView::slotViewModeChanged() { toggleZoomActions(); switch (d->stackedView->viewMode()) { case ImportStackedView::PreviewCameraMode: emit signalSwitchedToIconView(); emit signalThumbSizeChanged(d->iconView->thumbnailSize().size()); break; case ImportStackedView::PreviewImageMode: emit signalSwitchedToPreview(); slotZoomFactorChanged(d->stackedView->zoomFactor()); break; /* TODO case ImportStackedView::WelcomePageMode: emit signalSwitchedToIconView(); break; */ case ImportStackedView::MediaPlayerMode: emit signalSwitchedToPreview(); break; case ImportStackedView::MapWidgetMode: emit signalSwitchedToMapView(); //TODO: connect map view's zoom buttons to main status bar zoom buttons break; } } //TODO: Delete or implement this. void ImportView::slotImageRename() { d->iconView->rename(); } void ImportView::slotSelectAll() { d->iconView->selectAll(); } void ImportView::slotSelectNone() { d->iconView->clearSelection(); } void ImportView::slotSelectInvert() { d->iconView->invertSelection(); } void ImportView::slotSortImagesBy(int sortBy) { ImportSettings* const settings = ImportSettings::instance(); if (!settings) { return; } settings->setImageSortBy(sortBy); d->iconView->importFilterModel()->setSortRole((CamItemSortSettings::SortRole) sortBy); } void ImportView::slotSortImagesOrder(int order) { ImportSettings* const settings = ImportSettings::instance(); if (!settings) { return; } settings->setImageSortOrder(order); d->iconView->importFilterModel()->setSortOrder((CamItemSortSettings::SortOrder) order); } void ImportView::slotSeparateImages(int categoryMode) { ImportSettings* const settings = ImportSettings::instance(); if (!settings) { return; } settings->setImageSeparationMode(categoryMode); d->iconView->importFilterModel()->setCategorizationMode((CamItemSortSettings::CategorizationMode) categoryMode); } void ImportView::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 ImportView::scrollTo(const QString& folder, const QString& file) { CamItemInfo info = camItemInfo(folder, file); QModelIndex index = d->iconView->importFilterModel()->indexForCamItemInfo(info); d->iconView->scrollToRelaxed(index); d->iconView->setSelectedCamItemInfos(CamItemInfoList() << info); } void ImportView::slotImageChangeFailed(const QString& message, const QStringList& fileNames) { if (fileNames.isEmpty()) { return; } DMessageBox::showInformationList(QMessageBox::Critical, qApp->activeWindow(), qApp->applicationName(), message, fileNames); } bool ImportView::hasCurrentItem() const { // We should actually get this directly from the selection model, // but the iconView is fine for now. return !d->iconView->currentInfo().isNull(); } /* void ImportView::slotImageExifOrientation(int orientation) { FileActionMngr::instance()->setExifOrientation(d->iconView->selectedCamItemInfos(), orientation); } */ ImportFilterModel* ImportView::importFilterModel() const { return d->iconView->importFilterModel(); } ImportStackedView::StackedViewMode ImportView::viewMode() const { return d->stackedView->viewMode(); } void ImportView::toggleFullScreen(bool set) { d->stackedView->importPreviewView()->toggleFullScreen(set); } void ImportView::updateIconView() { d->iconView->viewport()->update(); } } // namespace Digikam diff --git a/core/utilities/lighttable/lighttableview.cpp b/core/utilities/lighttable/lighttableview.cpp index 8fc3f34e6b..80fb7b9376 100644 --- a/core/utilities/lighttable/lighttableview.cpp +++ b/core/utilities/lighttable/lighttableview.cpp @@ -1,478 +1,472 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2007-03-05 * Description : a widget to display 2 preview image on * lightable to compare pictures. * * Copyright (C) 2007-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. * * ============================================================ */ #include "lighttableview.h" // Qt includes #include #include #include // Local includes #include "digikam_debug.h" #include "dimg.h" #include "dzoombar.h" #include "thumbnailsize.h" #include "lighttablepreview.h" #include "previewlayout.h" #include "dimgpreviewitem.h" namespace Digikam { class LightTableView::Private { public: explicit Private() : syncPreview(false), grid(0), leftFrame(0), rightFrame(0), leftPreview(0), rightPreview(0) { } bool syncPreview; QGridLayout* grid; // These labels are used to draw a frame around preview views to identify easily which item has the focus. QLabel* leftFrame; QLabel* rightFrame; LightTablePreview* leftPreview; LightTablePreview* rightPreview; }; LightTableView::LightTableView(QWidget* const parent) : QFrame(parent), d(new Private) { setAttribute(Qt::WA_DeleteOnClose); setFrameStyle(QFrame::NoFrame); setLineWidth(0); d->grid = new QGridLayout(); setLayout(d->grid); d->leftFrame = new QLabel(this); d->leftPreview = new LightTablePreview(this); QVBoxLayout* const llay = new QVBoxLayout(d->leftFrame); llay->addWidget(d->leftPreview); llay->setContentsMargins(3, 3, 3, 3); llay->setSpacing(0); d->rightFrame = new QLabel(this); d->rightPreview = new LightTablePreview(this); QVBoxLayout* const rlay = new QVBoxLayout(d->rightFrame); rlay->addWidget(d->rightPreview); rlay->setContentsMargins(3, 3, 3, 3); rlay->setSpacing(0); d->grid->addWidget(d->leftFrame, 0, 0, 1, 1); d->grid->addWidget(d->rightFrame, 0, 1, 1, 1); d->grid->setColumnStretch(0, 10); d->grid->setColumnStretch(1, 10); d->grid->setRowStretch(0, 10); // Left panel connections ------------------------------------------------ connect(d->leftPreview, SIGNAL(signalPopupTagsView()), this, SIGNAL(signalLeftPopupTagsView())); connect(d->leftPreview->layout(), SIGNAL(zoomFactorChanged(double)), this, SLOT(slotLeftZoomFactorChanged(double))); connect(d->leftPreview, SIGNAL(contentsMoving(int,int)), this, SLOT(slotLeftContentsMoved(int,int))); - connect(d->leftPreview, SIGNAL(signalSlideShow()), - this, SIGNAL(signalSlideShow())); - connect(d->leftPreview, SIGNAL(signalSlideShowCurrent()), this, SIGNAL(signalLeftSlideShowCurrent())); connect(d->leftPreview, SIGNAL(signalDroppedItems(ImageInfoList)), this, SIGNAL(signalLeftDroppedItems(ImageInfoList))); connect(d->leftPreview, SIGNAL(signalPreviewLoaded(bool)), this, SLOT(slotLeftPreviewLoaded(bool))); connect(d->leftPreview, SIGNAL(leftButtonClicked()), this, SIGNAL(signalLeftPanelLeftButtonClicked())); connect(d->leftPreview, SIGNAL(signalDeleteItem()), this, SLOT(slotDeleteLeftItem())); // Right panel connections ------------------------------------------------ connect(d->rightPreview, SIGNAL(signalPopupTagsView()), this, SIGNAL(signalRightPopupTagsView())); connect(d->rightPreview->layout(), SIGNAL(zoomFactorChanged(double)), this, SLOT(slotRightZoomFactorChanged(double))); connect(d->rightPreview, SIGNAL(contentsMoving(int,int)), this, SLOT(slotRightContentsMoved(int,int))); connect(d->rightPreview, SIGNAL(signalDroppedItems(ImageInfoList)), this, SIGNAL(signalRightDroppedItems(ImageInfoList))); - connect(d->rightPreview, SIGNAL(signalSlideShow()), - this, SIGNAL(signalSlideShow())); - connect(d->rightPreview, SIGNAL(signalSlideShowCurrent()), this, SIGNAL(signalRightSlideShowCurrent())); connect(d->rightPreview, SIGNAL(signalPreviewLoaded(bool)), this, SLOT(slotRightPreviewLoaded(bool))); connect(d->rightPreview, SIGNAL(leftButtonClicked()), this, SIGNAL(signalRightPanelLeftButtonClicked())); connect(d->rightPreview, SIGNAL(signalDeleteItem()), this, SLOT(slotDeleteRightItem())); } LightTableView::~LightTableView() { delete d; } void LightTableView::setPreviewSettings(const PreviewSettings& settings) { d->leftPreview->previewItem()->setPreviewSettings(settings); d->rightPreview->previewItem()->setPreviewSettings(settings); } void LightTableView::setSyncPreview(bool sync) { d->syncPreview = sync; // Left panel like a reference to resync preview. if (d->syncPreview) { slotLeftZoomFactorChanged(d->leftPreview->layout()->zoomFactor()); slotLeftContentsMoved(d->leftPreview->contentsX(), d->leftPreview->contentsY()); } } void LightTableView::setNavigateByPair(bool b) { d->leftPreview->setDragAndDropEnabled(!b); d->rightPreview->setDragAndDropEnabled(!b); } void LightTableView::slotDecreaseLeftZoom() { d->leftPreview->layout()->decreaseZoom(); } void LightTableView::slotIncreaseLeftZoom() { d->leftPreview->layout()->increaseZoom(); } void LightTableView::slotDecreaseRightZoom() { d->rightPreview->layout()->decreaseZoom(); } void LightTableView::slotIncreaseRightZoom() { d->rightPreview->layout()->increaseZoom(); } void LightTableView::setLeftZoomFactor(double z) { d->leftPreview->layout()->setZoomFactor(z); } void LightTableView::setRightZoomFactor(double z) { d->rightPreview->layout()->setZoomFactor(z); } void LightTableView::slotLeftZoomTo100() { d->leftPreview->layout()->toggleFitToWindowOr100(); } void LightTableView::slotRightZoomTo100() { d->rightPreview->layout()->toggleFitToWindowOr100(); } void LightTableView::slotLeftFitToWindow() { d->leftPreview->layout()->fitToWindow(); } void LightTableView::slotRightFitToWindow() { d->rightPreview->layout()->fitToWindow(); } double LightTableView::leftZoomMax() const { return d->leftPreview->layout()->maxZoomFactor(); } double LightTableView::leftZoomMin() const { return d->leftPreview->layout()->minZoomFactor(); } bool LightTableView::leftMaxZoom() const { return d->leftPreview->layout()->atMaxZoom(); } bool LightTableView::leftMinZoom() const { return d->leftPreview->layout()->atMinZoom(); } double LightTableView::rightZoomMax() const { return d->rightPreview->layout()->maxZoomFactor(); } double LightTableView::rightZoomMin() const { return d->rightPreview->layout()->minZoomFactor(); } bool LightTableView::rightMaxZoom() const { return d->rightPreview->layout()->atMaxZoom(); } bool LightTableView::rightMinZoom() const { return d->rightPreview->layout()->atMinZoom(); } void LightTableView::slotLeftZoomSliderChanged(int size) { double zmin = d->leftPreview->layout()->minZoomFactor(); double zmax = d->leftPreview->layout()->maxZoomFactor(); double z = DZoomBar::zoomFromSize(size, zmin, zmax); d->leftPreview->layout()->setZoomFactorSnapped(z); } void LightTableView::slotRightZoomSliderChanged(int size) { double zmin = d->rightPreview->layout()->minZoomFactor(); double zmax = d->rightPreview->layout()->maxZoomFactor(); double z = DZoomBar::zoomFromSize(size, zmin, zmax); d->rightPreview->layout()->setZoomFactorSnapped(z); } void LightTableView::leftReload() { d->leftPreview->previewItem()->reload(); } void LightTableView::rightReload() { d->rightPreview->previewItem()->reload(); } void LightTableView::slotLeftContentsMoved(int x, int y) { if (d->syncPreview && !leftPreviewLoading()) { d->rightPreview->blockSignals(true); d->rightPreview->setContentsPos(x, y); d->rightPreview->blockSignals(false); } } void LightTableView::slotRightContentsMoved(int x, int y) { if (d->syncPreview && !rightPreviewLoading()) { d->leftPreview->blockSignals(true); d->leftPreview->setContentsPos(x, y); d->leftPreview->blockSignals(false); } } void LightTableView::slotLeftZoomFactorChanged(double zoom) { if (d->syncPreview && !leftPreviewLoading()) { d->rightPreview->layout()->blockSignals(true); d->rightPreview->blockSignals(true); setRightZoomFactor(zoom); emit signalRightZoomFactorChanged(zoom); d->rightPreview->blockSignals(false); d->rightPreview->layout()->blockSignals(false); } emit signalLeftZoomFactorChanged(zoom); } void LightTableView::slotRightZoomFactorChanged(double zoom) { if (d->syncPreview && !rightPreviewLoading()) { d->leftPreview->layout()->blockSignals(true); d->leftPreview->blockSignals(true); setLeftZoomFactor(zoom); emit signalLeftZoomFactorChanged(zoom); d->leftPreview->blockSignals(false); d->leftPreview->layout()->blockSignals(false); } emit signalRightZoomFactorChanged(zoom); } ImageInfo LightTableView::leftImageInfo() const { return d->leftPreview->getImageInfo(); } ImageInfo LightTableView::rightImageInfo() const { return d->rightPreview->getImageInfo(); } void LightTableView::setLeftImageInfo(const ImageInfo& info) { d->leftPreview->setImageInfo(info); if (info.isNull()) { d->leftPreview->showDragAndDropMessage(); } } void LightTableView::setRightImageInfo(const ImageInfo& info) { d->rightPreview->setImageInfo(info); if (info.isNull()) { d->rightPreview->showDragAndDropMessage(); } } void LightTableView::slotLeftPreviewLoaded(bool success) { checkForSyncPreview(); slotRightContentsMoved(d->rightPreview->contentsX(), d->rightPreview->contentsY()); emit signalLeftPreviewLoaded(success); } void LightTableView::slotRightPreviewLoaded(bool success) { checkForSyncPreview(); slotLeftContentsMoved(d->leftPreview->contentsX(), d->leftPreview->contentsY()); emit signalRightPreviewLoaded(success); } void LightTableView::checkForSyncPreview() { if (!d->leftPreview->getImageInfo().isNull() && !d->rightPreview->getImageInfo().isNull() && d->leftPreview->previewItem()->image().size() == d->rightPreview->previewItem()->image().size()) { d->syncPreview = true; } else { d->syncPreview = false; } emit signalToggleOnSyncPreview(d->syncPreview); } void LightTableView::checkForSelection(const ImageInfo& info) { QString selected = QString::fromUtf8("QLabel { background-color: %1; }") .arg(qApp->palette().color(QPalette::Highlight).name()); QString notSelected = QString::fromUtf8("QLabel { background-color: %1; }") .arg(qApp->palette().color(QPalette::Base).name()); if (info.isNull()) { d->leftFrame->setStyleSheet(notSelected); d->rightFrame->setStyleSheet(notSelected); return; } if (!d->leftPreview->getImageInfo().isNull()) { bool onLeft = (d->leftPreview->getImageInfo() == info); d->leftFrame->setStyleSheet(onLeft ? selected : notSelected); } if (!d->rightPreview->getImageInfo().isNull()) { bool onRight = (d->rightPreview->getImageInfo() == info); d->rightFrame->setStyleSheet(onRight ? selected : notSelected); } } void LightTableView::slotDeleteLeftItem() { emit signalDeleteItem(d->leftPreview->getImageInfo()); } void LightTableView::slotDeleteRightItem() { emit signalDeleteItem(d->rightPreview->getImageInfo()); } bool LightTableView::leftPreviewLoading() const { return (d->leftPreview->previewItem()->state() == DImgPreviewItem::Loading); } bool LightTableView::rightPreviewLoading() const { return (d->rightPreview->previewItem()->state() == DImgPreviewItem::Loading); } void LightTableView::toggleFullScreen(bool set) { d->leftPreview->toggleFullScreen(set); d->rightPreview->toggleFullScreen(set); } } // namespace Digikam diff --git a/core/utilities/lighttable/lighttableview.h b/core/utilities/lighttable/lighttableview.h index 67c933dd87..0232853333 100644 --- a/core/utilities/lighttable/lighttableview.h +++ b/core/utilities/lighttable/lighttableview.h @@ -1,150 +1,149 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2007-03-05 * Description : a widget to display 2 preview image on * lightable to compare pictures. * * Copyright (C) 2007-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_LIGHT_TABLE_VIEW_H #define DIGIKAM_LIGHT_TABLE_VIEW_H // Qt includes #include #include // Local includes #include "imageinfo.h" namespace Digikam { class PreviewSettings; class LightTableView : public QFrame { Q_OBJECT public: explicit LightTableView(QWidget* const parent = 0); ~LightTableView(); void setSyncPreview(bool sync); void setNavigateByPair(bool b); void setLeftImageInfo(const ImageInfo& info = ImageInfo()); void setRightImageInfo(const ImageInfo& info = ImageInfo()); ImageInfo leftImageInfo() const; ImageInfo rightImageInfo() const; void setPreviewSettings(const PreviewSettings& settings); void checkForSelection(const ImageInfo& info); void toggleFullScreen(bool set); double leftZoomMax() const; double leftZoomMin() const; double rightZoomMax() const; double rightZoomMin() const; bool leftMaxZoom() const; bool leftMinZoom() const; bool rightMaxZoom() const; bool rightMinZoom() const; void leftReload(); void rightReload(); Q_SIGNALS: void signalLeftPreviewLoaded(bool); void signalRightPreviewLoaded(bool); void signalLeftZoomFactorChanged(double); void signalRightZoomFactorChanged(double); void signalLeftDroppedItems(const ImageInfoList&); void signalRightDroppedItems(const ImageInfoList&); void signalLeftPanelLeftButtonClicked(); void signalRightPanelLeftButtonClicked(); void signalLeftPopupTagsView(); void signalRightPopupTagsView(); void signalLeftSlideShowCurrent(); void signalRightSlideShowCurrent(); - void signalSlideShow(); void signalDeleteItem(const ImageInfo&); void signalEditItem(const ImageInfo&); void signalToggleOnSyncPreview(bool); public Q_SLOTS: void slotDecreaseLeftZoom(); void slotIncreaseLeftZoom(); void slotLeftZoomSliderChanged(int); void setLeftZoomFactor(double z); void slotLeftFitToWindow(); void slotLeftZoomTo100(); void slotDecreaseRightZoom(); void slotIncreaseRightZoom(); void slotRightZoomSliderChanged(int); void setRightZoomFactor(double z); void slotRightFitToWindow(); void slotRightZoomTo100(); private Q_SLOTS: void slotLeftContentsMoved(int, int); void slotRightContentsMoved(int, int); void slotLeftZoomFactorChanged(double); void slotRightZoomFactorChanged(double); void slotLeftPreviewLoaded(bool); void slotRightPreviewLoaded(bool); void slotDeleteLeftItem(); void slotDeleteRightItem(); private : void checkForSyncPreview(); /// To not sync right panel during left loading bool leftPreviewLoading() const; /// To not sync left panel during right loading. bool rightPreviewLoading() const; private : class Private; Private* const d; }; } // namespace Digikam #endif // DIGIKAM_LIGHT_TABLE_VIEW_H diff --git a/core/utilities/lighttable/lighttablewindow.cpp b/core/utilities/lighttable/lighttablewindow.cpp index dddedcb679..11cd98b039 100644 --- a/core/utilities/lighttable/lighttablewindow.cpp +++ b/core/utilities/lighttable/lighttablewindow.cpp @@ -1,2081 +1,2078 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2007-03-05 * Description : digiKam light table GUI * * Copyright (C) 2007-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. * * ============================================================ */ #include "lighttablewindow.h" #include "lighttablewindow_p.h" // Qt includes #include #include #include #include #include #include #include #include // KDE includes #include #include // Local includes #include "drawdecoder.h" #include "digikam_debug.h" #include "componentsinfo.h" #include "digikamapp.h" #include "thememanager.h" #include "dimg.h" #include "dio.h" #include "dmetadata.h" #include "dfileoperations.h" #include "metadatasettings.h" #include "metadataedit.h" #include "applicationsettings.h" #include "albummanager.h" #include "loadingcacheinterface.h" #include "deletedialog.h" #include "iccsettings.h" #include "imagewindow.h" #include "imagegps.h" #include "imagedescedittab.h" #include "presentationmngr.h" #include "slideshowbuilder.h" #include "slideshow.h" #include "setup.h" #include "syncjob.h" #include "lighttablepreview.h" #include "albummodel.h" #include "albumfiltermodel.h" #include "coredbchangesets.h" #include "collectionscanner.h" #include "scancontroller.h" #include "tagsactionmngr.h" #include "thumbbardock.h" #include "thumbnailsize.h" #include "thumbnailloadthread.h" #include "dexpanderbox.h" #include "dbinfoiface.h" #include "calwizard.h" #include "expoblendingmanager.h" #include "mailwizard.h" #include "advprintwizard.h" #include "dmediaserverdlg.h" #include "dbwindow.h" #include "fbwindow.h" #include "flickrwindow.h" #include "gswindow.h" #include "imageshackwindow.h" #include "imgurwindow.h" #include "piwigowindow.h" #include "rajcewindow.h" #include "smugwindow.h" #include "yfwindow.h" #ifdef HAVE_MEDIAWIKI # include "mediawikiwindow.h" #endif #ifdef HAVE_VKONTAKTE # include "vkwindow.h" #endif #ifdef HAVE_KIO # include "ftexportwindow.h" # include "ftimportwindow.h" #endif #ifdef HAVE_MARBLE # include "geolocationedit.h" #endif #ifdef HAVE_HTMLGALLERY # include "htmlwizard.h" #endif #ifdef HAVE_PANORAMA # include "panomanager.h" #endif #ifdef HAVE_MEDIAPLAYER # include "vidslidewizard.h" #endif namespace Digikam { LightTableWindow* LightTableWindow::m_instance = 0; LightTableWindow* LightTableWindow::lightTableWindow() { if (!m_instance) { new LightTableWindow(); } return m_instance; } bool LightTableWindow::lightTableWindowCreated() { return m_instance; } LightTableWindow::LightTableWindow() : DXmlGuiWindow(0), d(new Private) { setConfigGroupName(QLatin1String("LightTable Settings")); setXMLFile(QLatin1String("lighttablewindowui5.rc")); m_instance = this; setWindowFlags(Qt::Window); setCaption(i18n("Light Table")); // We don't want to be deleted on close setAttribute(Qt::WA_DeleteOnClose, false); setFullScreenOptions(FS_LIGHTTABLE); // -- Build the GUI ------------------------------- setupUserArea(); setupActions(); setupStatusBar(); // ------------------------------------------------ setupConnections(); slotColorManagementOptionsChanged(); readSettings(); d->leftSideBar->populateTags(); d->rightSideBar->populateTags(); applySettings(); setAutoSaveSettings(configGroupName(), true); } LightTableWindow::~LightTableWindow() { m_instance = 0; delete d->thumbView; delete d->rightSideBar; delete d->leftSideBar; delete d; } void LightTableWindow::readSettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(configGroupName()); d->hSplitter->restoreState(group, QLatin1String("Horizontal Splitter State")); d->barViewDock->setShouldBeVisible(group.readEntry(QLatin1String("Show Thumbbar"), true)); d->navigateByPairAction->setChecked(group.readEntry(QLatin1String("Navigate By Pair"), false)); slotToggleNavigateByPair(); d->leftSideBar->setConfigGroup(KConfigGroup(&group, QLatin1String("Left Sidebar"))); d->leftSideBar->loadState(); d->rightSideBar->setConfigGroup(KConfigGroup(&group, QLatin1String("Right Sidebar"))); d->rightSideBar->loadState(); readFullScreenSettings(group); } void LightTableWindow::writeSettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(configGroupName()); d->hSplitter->saveState(group, QLatin1String("Horizontal Splitter State")); group.writeEntry(QLatin1String("Show Thumbbar"), d->barViewDock->shouldBeVisible()); group.writeEntry(QLatin1String("Navigate By Pair"), d->navigateByPairAction->isChecked()); group.writeEntry(QLatin1String("Clear On Close"), d->clearOnCloseAction->isChecked()); d->leftSideBar->setConfigGroup(KConfigGroup(&group, QLatin1String("Left Sidebar"))); d->leftSideBar->saveState(); d->rightSideBar->setConfigGroup(KConfigGroup(&group, QLatin1String("Right Sidebar"))); d->rightSideBar->saveState(); config->sync(); } void LightTableWindow::applySettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(configGroupName()); d->autoLoadOnRightPanel = group.readEntry(QLatin1String("Auto Load Right Panel"), true); d->autoSyncPreview = group.readEntry(QLatin1String("Auto Sync Preview"), true); d->clearOnCloseAction->setChecked(group.readEntry(QLatin1String("Clear On Close"), false)); slotApplicationSettingsChanged(); // Restore full screen Mode readFullScreenSettings(group); // NOTE: Image orientation settings in thumbbar is managed by image model. refreshView(); } void LightTableWindow::refreshView() { d->leftSideBar->refreshTagsView(); d->rightSideBar->refreshTagsView(); } void LightTableWindow::closeEvent(QCloseEvent* e) { if (!e) { return; } if (d->clearOnCloseAction->isChecked()) { slotClearItemsList(); } // There is one nasty habit with the thumbnail bar if it is floating: it // doesn't close when the parent window does, so it needs to be manually // closed. If the light table is opened again, its original state needs to // be restored. // This only needs to be done when closing a visible window and not when // destroying a closed window, since the latter case will always report that // the thumbnail bar isn't visible. if (isVisible()) { d->barViewDock->hide(); } writeSettings(); DXmlGuiWindow::closeEvent(e); e->accept(); } void LightTableWindow::showEvent(QShowEvent*) { // Restore the visibility of the thumbbar and start autosaving again. d->barViewDock->restoreVisibility(); } void LightTableWindow::setupUserArea() { QWidget* const mainW = new QWidget(this); d->hSplitter = new SidebarSplitter(Qt::Horizontal, mainW); QHBoxLayout* const hlay = new QHBoxLayout(mainW); // The left sidebar d->leftSideBar = new ImagePropertiesSideBarDB(mainW, d->hSplitter, Qt::LeftEdge, true); // The central preview is wrapped in a KMainWindow so that the thumbnail // bar can float around it. KMainWindow* const viewContainer = new KMainWindow(mainW, Qt::Widget); d->hSplitter->addWidget(viewContainer); d->previewView = new LightTableView(viewContainer); viewContainer->setCentralWidget(d->previewView); // The right sidebar. d->rightSideBar = new ImagePropertiesSideBarDB(mainW, d->hSplitter, Qt::RightEdge, true); hlay->addWidget(d->leftSideBar); hlay->addWidget(d->hSplitter); hlay->addWidget(d->rightSideBar); hlay->setSpacing(0); hlay->setContentsMargins(QMargins()); hlay->setStretchFactor(d->hSplitter, 10); d->hSplitter->setFrameStyle(QFrame::NoFrame); d->hSplitter->setFrameShadow(QFrame::Plain); d->hSplitter->setFrameShape(QFrame::NoFrame); d->hSplitter->setOpaqueResize(false); d->hSplitter->setStretchFactor(1, 10); // set previewview+thumbbar container default size to max. // The thumb bar is placed in a detachable/dockable widget. d->barViewDock = new ThumbBarDock(viewContainer, Qt::Tool); d->barViewDock->setObjectName(QLatin1String("lighttable_thumbbar")); d->thumbView = new LightTableThumbBar(d->barViewDock); d->barViewDock->setWidget(d->thumbView); viewContainer->addDockWidget(Qt::TopDockWidgetArea, d->barViewDock); d->barViewDock->setFloating(false); // Restore the previous state. This doesn't emit the proper signals to the // dock widget, so it has to be manually reinitialized. viewContainer->setAutoSaveSettings(QLatin1String("LightTable Thumbbar"), true); connect(d->barViewDock, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), d->thumbView, SLOT(slotDockLocationChanged(Qt::DockWidgetArea))); d->barViewDock->reInitialize(); setCentralWidget(mainW); } void LightTableWindow::setupStatusBar() { d->leftZoomBar = new DZoomBar(statusBar()); d->leftZoomBar->setZoomToFitAction(d->leftZoomFitToWindowAction); d->leftZoomBar->setZoomTo100Action(d->leftZoomTo100percents); d->leftZoomBar->setZoomPlusAction(d->leftZoomPlusAction); d->leftZoomBar->setZoomMinusAction(d->leftZoomMinusAction); d->leftZoomBar->setBarMode(DZoomBar::PreviewZoomCtrl); d->leftZoomBar->setEnabled(false); statusBar()->addWidget(d->leftZoomBar, 1); d->leftFileName = new DAdjustableLabel(statusBar()); d->leftFileName->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); statusBar()->addWidget(d->leftFileName, 10); d->statusProgressBar = new StatusProgressBar(statusBar()); d->statusProgressBar->setAlignment(Qt::AlignCenter); statusBar()->addWidget(d->statusProgressBar, 10); d->rightFileName = new DAdjustableLabel(statusBar()); d->rightFileName->setAlignment(Qt::AlignRight | Qt::AlignVCenter); statusBar()->addWidget(d->rightFileName, 10); d->rightZoomBar = new DZoomBar(statusBar()); d->rightZoomBar->setZoomToFitAction(d->rightZoomFitToWindowAction); d->rightZoomBar->setZoomTo100Action(d->rightZoomTo100percents); d->rightZoomBar->setZoomPlusAction(d->rightZoomPlusAction); d->rightZoomBar->setZoomMinusAction(d->rightZoomMinusAction); d->rightZoomBar->setBarMode(DZoomBar::PreviewZoomCtrl); d->rightZoomBar->setEnabled(false); statusBar()->addWidget(d->rightZoomBar, 1); } void LightTableWindow::setupConnections() { connect(ApplicationSettings::instance(), SIGNAL(setupChanged()), this, SLOT(slotApplicationSettingsChanged())); connect(ThemeManager::instance(), SIGNAL(signalThemeChanged()), this, SLOT(slotThemeChanged())); connect(IccSettings::instance(), SIGNAL(settingsChanged()), this, SLOT(slotColorManagementOptionsChanged())); // Thumbs bar connections --------------------------------------- connect(d->thumbView, SIGNAL(signalSetItemOnLeftPanel(ImageInfo)), this, SLOT(slotSetItemOnLeftPanel(ImageInfo))); connect(d->thumbView, SIGNAL(signalSetItemOnRightPanel(ImageInfo)), this, SLOT(slotSetItemOnRightPanel(ImageInfo))); connect(d->thumbView, SIGNAL(signalRemoveItem(ImageInfo)), this, SLOT(slotRemoveItem(ImageInfo))); connect(d->thumbView, SIGNAL(signalEditItem(ImageInfo)), this, SLOT(slotEditItem(ImageInfo))); connect(d->thumbView, SIGNAL(signalClearAll()), this, SLOT(slotClearItemsList())); connect(d->thumbView, SIGNAL(signalDroppedItems(QList)), this, SLOT(slotThumbbarDroppedItems(QList))); connect(d->thumbView, SIGNAL(currentChanged(ImageInfo)), this, SLOT(slotItemSelected(ImageInfo))); connect(d->thumbView, SIGNAL(signalContentChanged()), this, SLOT(slotRefreshStatusBar())); // Zoom bars connections ----------------------------------------- connect(d->leftZoomBar, SIGNAL(signalZoomSliderChanged(int)), d->previewView, SLOT(slotLeftZoomSliderChanged(int))); connect(d->leftZoomBar, SIGNAL(signalZoomValueEdited(double)), d->previewView, SLOT(setLeftZoomFactor(double))); connect(d->rightZoomBar, SIGNAL(signalZoomSliderChanged(int)), d->previewView, SLOT(slotRightZoomSliderChanged(int))); connect(d->rightZoomBar, SIGNAL(signalZoomValueEdited(double)), d->previewView, SLOT(setRightZoomFactor(double))); // View connections --------------------------------------------- connect(d->previewView, SIGNAL(signalLeftPopupTagsView()), d->leftSideBar, SLOT(slotPopupTagsView())); connect(d->previewView, SIGNAL(signalRightPopupTagsView()), d->rightSideBar, SLOT(slotPopupTagsView())); connect(d->previewView, SIGNAL(signalLeftZoomFactorChanged(double)), this, SLOT(slotLeftZoomFactorChanged(double))); connect(d->previewView, SIGNAL(signalRightZoomFactorChanged(double)), this, SLOT(slotRightZoomFactorChanged(double))); connect(d->previewView, SIGNAL(signalEditItem(ImageInfo)), this, SLOT(slotEditItem(ImageInfo))); connect(d->previewView, SIGNAL(signalDeleteItem(ImageInfo)), this, SLOT(slotDeleteItem(ImageInfo))); - connect(d->previewView, SIGNAL(signalSlideShow()), - this, SLOT(slotSlideShowAll())); - connect(d->previewView, SIGNAL(signalLeftSlideShowCurrent()), this, SLOT(slotLeftSlideShowManualFromCurrent())); connect(d->previewView, SIGNAL(signalRightSlideShowCurrent()), this, SLOT(slotRightSlideShowManualFromCurrent())); connect(d->previewView, SIGNAL(signalLeftDroppedItems(ImageInfoList)), this, SLOT(slotLeftDroppedItems(ImageInfoList))); connect(d->previewView, SIGNAL(signalRightDroppedItems(ImageInfoList)), this, SLOT(slotRightDroppedItems(ImageInfoList))); connect(d->previewView, SIGNAL(signalToggleOnSyncPreview(bool)), this, SLOT(slotToggleOnSyncPreview(bool))); connect(d->previewView, SIGNAL(signalLeftPreviewLoaded(bool)), this, SLOT(slotLeftPreviewLoaded(bool))); connect(d->previewView, SIGNAL(signalRightPreviewLoaded(bool)), this, SLOT(slotRightPreviewLoaded(bool))); connect(d->previewView, SIGNAL(signalLeftPanelLeftButtonClicked()), this, SLOT(slotLeftPanelLeftButtonClicked())); connect(d->previewView, SIGNAL(signalRightPanelLeftButtonClicked()), this, SLOT(slotRightPanelLeftButtonClicked())); connect(this, SIGNAL(signalWindowHasMoved()), d->leftZoomBar, SLOT(slotUpdateTrackerPos())); connect(this, SIGNAL(signalWindowHasMoved()), d->rightZoomBar, SLOT(slotUpdateTrackerPos())); // -- FileWatch connections ------------------------------ LoadingCacheInterface::connectToSignalFileChanged(this, SLOT(slotFileChanged(QString))); } void LightTableWindow::setupActions() { // -- Standard 'File' menu actions --------------------------------------------- KActionCollection* const ac = actionCollection(); d->backwardAction = buildStdAction(StdBackAction, this, SLOT(slotBackward()), this); ac->addAction(QLatin1String("lighttable_backward"), d->backwardAction); ac->setDefaultShortcuts(d->backwardAction, QList() << Qt::Key_PageUp << Qt::Key_Backspace); d->forwardAction = buildStdAction(StdForwardAction, this, SLOT(slotForward()), this); ac->addAction(QLatin1String("lighttable_forward"), d->forwardAction); ac->setDefaultShortcuts(d->forwardAction, QList() << Qt::Key_PageDown << Qt::Key_Space); d->forwardAction->setEnabled(false); d->firstAction = new QAction(QIcon::fromTheme(QLatin1String("go-first")), i18n("&First"), this); d->firstAction->setEnabled(false); connect(d->firstAction, SIGNAL(triggered()), this, SLOT(slotFirst())); ac->addAction(QLatin1String("lighttable_first"), d->firstAction); ac->setDefaultShortcuts(d->firstAction, QList() << Qt::CTRL + Qt::Key_Home); d->lastAction = new QAction(QIcon::fromTheme(QLatin1String("go-last")), i18n("&Last"), this); d->lastAction->setEnabled(false); connect(d->lastAction, SIGNAL(triggered()), this, SLOT(slotLast())); ac->addAction(QLatin1String("lighttable_last"), d->lastAction); ac->setDefaultShortcuts(d->lastAction, QList() << Qt::CTRL + Qt::Key_End); d->setItemLeftAction = new QAction(QIcon::fromTheme(QLatin1String("go-previous")), i18n("On left"), this); d->setItemLeftAction->setEnabled(false); d->setItemLeftAction->setWhatsThis(i18n("Show item on left panel")); connect(d->setItemLeftAction, SIGNAL(triggered()), this, SLOT(slotSetItemLeft())); ac->addAction(QLatin1String("lighttable_setitemleft"), d->setItemLeftAction); ac->setDefaultShortcut(d->setItemLeftAction, Qt::CTRL + Qt::Key_L); d->setItemRightAction = new QAction(QIcon::fromTheme(QLatin1String("go-next")), i18n("On right"), this); d->setItemRightAction->setEnabled(false); d->setItemRightAction->setWhatsThis(i18n("Show item on right panel")); connect(d->setItemRightAction, SIGNAL(triggered()), this, SLOT(slotSetItemRight())); ac->addAction(QLatin1String("lighttable_setitemright"), d->setItemRightAction); ac->setDefaultShortcut(d->setItemRightAction, Qt::CTRL + Qt::Key_R); d->editItemAction = new QAction(QIcon::fromTheme(QLatin1String("document-edit")), i18n("Edit"), this); d->editItemAction->setEnabled(false); connect(d->editItemAction, SIGNAL(triggered()), this, SLOT(slotEditItem())); ac->addAction(QLatin1String("lighttable_edititem"), d->editItemAction); ac->setDefaultShortcut(d->editItemAction, Qt::Key_F4); QAction* const openWithAction = new QAction(QIcon::fromTheme(QLatin1String("preferences-desktop-filetype-association")), i18n("Open With Default Application"), this); openWithAction->setWhatsThis(i18n("Open the item with default assigned application.")); connect(openWithAction, SIGNAL(triggered()), this, SLOT(slotFileWithDefaultApplication())); ac->addAction(QLatin1String("open_with_default_application"), openWithAction); ac->setDefaultShortcut(openWithAction, Qt::META + Qt::Key_F4); d->removeItemAction = new QAction(QIcon::fromTheme(QLatin1String("list-remove")), i18n("Remove item from LightTable"), this); d->removeItemAction->setEnabled(false); connect(d->removeItemAction, SIGNAL(triggered()), this, SLOT(slotRemoveItem())); ac->addAction(QLatin1String("lighttable_removeitem"), d->removeItemAction); ac->setDefaultShortcut(d->removeItemAction, Qt::CTRL + Qt::Key_K); d->clearListAction = new QAction(QIcon::fromTheme(QLatin1String("edit-clear")), i18n("Remove all items from LightTable"), this); d->clearListAction->setEnabled(false); connect(d->clearListAction, SIGNAL(triggered()), this, SLOT(slotClearItemsList())); ac->addAction(QLatin1String("lighttable_clearlist"), d->clearListAction); ac->setDefaultShortcut(d->clearListAction, Qt::CTRL + Qt::SHIFT + Qt::Key_K); d->fileDeleteAction = new QAction(QIcon::fromTheme(QLatin1String("user-trash")), i18nc("Non-pluralized", "Move to Trash"), this); d->fileDeleteAction->setEnabled(false); connect(d->fileDeleteAction, SIGNAL(triggered()), this, SLOT(slotDeleteItem())); ac->addAction(QLatin1String("lighttable_filedelete"), d->fileDeleteAction); ac->setDefaultShortcut(d->fileDeleteAction, Qt::Key_Delete); d->fileDeleteFinalAction = new QAction(QIcon::fromTheme(QLatin1String("edit-delete")), i18n("Delete immediately"), this); d->fileDeleteFinalAction->setEnabled(false); connect(d->fileDeleteFinalAction, SIGNAL(triggered()), this, SLOT(slotDeleteFinalItem())); ac->addAction(QLatin1String("lighttable_filefinaldelete"), d->fileDeleteFinalAction); ac->setDefaultShortcut(d->fileDeleteFinalAction, Qt::SHIFT + Qt::Key_Delete); QAction* const closeAction = buildStdAction(StdCloseAction, this, SLOT(close()), this); ac->addAction(QLatin1String("lighttable_close"), closeAction); // -- Standard 'View' menu actions --------------------------------------------- d->syncPreviewAction = new QAction(QIcon::fromTheme(QLatin1String("view-split-left-right")), i18n("Synchronize"), this); d->syncPreviewAction->setEnabled(false); d->syncPreviewAction->setCheckable(true); d->syncPreviewAction->setWhatsThis(i18n("Synchronize preview from left and right panels")); connect(d->syncPreviewAction, SIGNAL(triggered()), this, SLOT(slotToggleSyncPreview())); ac->addAction(QLatin1String("lighttable_syncpreview"), d->syncPreviewAction); ac->setDefaultShortcut(d->syncPreviewAction, Qt::CTRL + Qt::SHIFT + Qt::Key_Y); d->navigateByPairAction = new QAction(QIcon::fromTheme(QLatin1String("system-run")), i18n("By Pair"), this); d->navigateByPairAction->setEnabled(false); d->navigateByPairAction->setCheckable(true); d->navigateByPairAction->setWhatsThis(i18n("Navigate by pairs with all items")); connect(d->navigateByPairAction, SIGNAL(triggered()), this, SLOT(slotToggleNavigateByPair())); ac->addAction(QLatin1String("lighttable_navigatebypair"), d->navigateByPairAction); ac->setDefaultShortcut(d->navigateByPairAction, Qt::CTRL + Qt::SHIFT + Qt::Key_P); d->clearOnCloseAction = new QAction(QIcon::fromTheme(QLatin1String("edit-clear")), i18n("Clear On Close"), this); d->clearOnCloseAction->setEnabled(true); d->clearOnCloseAction->setCheckable(true); d->clearOnCloseAction->setToolTip(i18n("Clear light table when it is closed")); d->clearOnCloseAction->setWhatsThis(i18n("Remove all images from the light table when it is closed")); ac->addAction(QLatin1String("lighttable_clearonclose"), d->clearOnCloseAction); ac->setDefaultShortcut(d->clearOnCloseAction, Qt::CTRL + Qt::SHIFT + Qt::Key_C); d->showBarAction = d->barViewDock->getToggleAction(this); ac->addAction(QLatin1String("lighttable_showthumbbar"), d->showBarAction); ac->setDefaultShortcut(d->showBarAction, Qt::CTRL + Qt::Key_T); createFullScreenAction(QLatin1String("lighttable_fullscreen")); createSidebarActions(); d->slideShowAction = new QAction(QIcon::fromTheme(QLatin1String("view-presentation")), i18n("Slideshow"), this); connect(d->slideShowAction, SIGNAL(triggered()), this, SLOT(slotSlideShowAll())); ac->addAction(QLatin1String("lighttable_slideshow"), d->slideShowAction); ac->setDefaultShortcut(d->slideShowAction, Qt::Key_F9); createPresentationAction(); // -- Standard 'Tools' menu actions ------------------------ createMetadataEditAction(); createGeolocationEditAction(); createHtmlGalleryAction(); createPanoramaAction(); createExpoBlendingAction(); createCalendarAction(); createVideoSlideshowAction(); createSendByMailAction(); createPrintCreatorAction(); createMediaServerAction(); createExportActions(); createImportActions(); // Left Panel Zoom Actions d->leftZoomPlusAction = buildStdAction(StdZoomInAction, d->previewView, SLOT(slotIncreaseLeftZoom()), this); d->leftZoomPlusAction->setEnabled(false); QKeySequence leftKeysPlus(d->leftZoomPlusAction->shortcut()[0], Qt::Key_Plus); ac->addAction(QLatin1String("lighttable_zoomplus_left"), d->leftZoomPlusAction); ac->setDefaultShortcut(d->leftZoomPlusAction, leftKeysPlus); d->leftZoomMinusAction = buildStdAction(StdZoomOutAction, d->previewView, SLOT(slotDecreaseLeftZoom()), this); d->leftZoomMinusAction->setEnabled(false); QKeySequence leftKeysMinus(d->leftZoomMinusAction->shortcut()[0], Qt::Key_Minus); ac->addAction(QLatin1String("lighttable_zoomminus_left"), d->leftZoomMinusAction); ac->setDefaultShortcut(d->leftZoomMinusAction, leftKeysMinus); d->leftZoomTo100percents = new QAction(QIcon::fromTheme(QLatin1String("zoom-original")), i18n("Zoom to 100%"), this); connect(d->leftZoomTo100percents, SIGNAL(triggered()), d->previewView, SLOT(slotLeftZoomTo100())); ac->addAction(QLatin1String("lighttable_zoomto100percents_left"), d->leftZoomTo100percents); ac->setDefaultShortcut(d->leftZoomTo100percents, Qt::CTRL + Qt::Key_Period); d->leftZoomFitToWindowAction = new QAction(QIcon::fromTheme(QLatin1String("zoom-fit-best")), i18n("Fit to &Window"), this); connect(d->leftZoomFitToWindowAction, SIGNAL(triggered()), d->previewView, SLOT(slotLeftFitToWindow())); ac->addAction(QLatin1String("lighttable_zoomfit2window_left"), d->leftZoomFitToWindowAction); ac->setDefaultShortcut(d->leftZoomFitToWindowAction, Qt::ALT + Qt::CTRL + Qt::Key_E); // Right Panel Zoom Actions d->rightZoomPlusAction = buildStdAction(StdZoomInAction, d->previewView, SLOT(slotIncreaseRightZoom()), this); d->rightZoomPlusAction->setEnabled(false); QKeySequence rightKeysPlus(d->rightZoomPlusAction->shortcut()[0], Qt::SHIFT + Qt::CTRL + Qt::Key_Plus, Qt::SHIFT + Qt::Key_Plus); ac->addAction(QLatin1String("lighttable_zoomplus_right"), d->rightZoomPlusAction); ac->setDefaultShortcut(d->rightZoomPlusAction, rightKeysPlus); d->rightZoomMinusAction = buildStdAction(StdZoomOutAction, d->previewView, SLOT(slotDecreaseRightZoom()), this); d->rightZoomMinusAction->setEnabled(false); QKeySequence rightKeysMinus(d->rightZoomMinusAction->shortcut()[0], Qt::SHIFT + Qt::CTRL + Qt::Key_Minus, Qt::SHIFT + Qt::Key_Minus); ac->addAction(QLatin1String("lighttable_zoomminus_right"), d->rightZoomMinusAction); ac->setDefaultShortcut(d->rightZoomMinusAction, rightKeysMinus); d->rightZoomTo100percents = new QAction(QIcon::fromTheme(QLatin1String("zoom-original")), i18n("Zoom to 100%"), this); connect(d->rightZoomTo100percents, SIGNAL(triggered()), d->previewView, SLOT(slotRightZoomTo100())); ac->addAction(QLatin1String("lighttable_zoomto100percents_right"), d->rightZoomTo100percents); ac->setDefaultShortcut(d->rightZoomTo100percents, Qt::SHIFT + Qt::CTRL + Qt::Key_Period); d->rightZoomFitToWindowAction = new QAction(QIcon::fromTheme(QLatin1String("zoom-fit-best")), i18n("Fit to &Window"), this); connect(d->rightZoomFitToWindowAction, SIGNAL(triggered()), d->previewView, SLOT(slotRightFitToWindow())); ac->addAction(QLatin1String("lighttable_zoomfit2window_right"), d->rightZoomFitToWindowAction); ac->setDefaultShortcut(d->rightZoomFitToWindowAction, Qt::SHIFT + Qt::CTRL + Qt::Key_E); // ----------------------------------------------------------- d->viewCMViewAction = new QAction(QIcon::fromTheme(QLatin1String("video-display")), i18n("Color-Managed View"), this); d->viewCMViewAction->setCheckable(true); connect(d->viewCMViewAction, SIGNAL(triggered()), this, SLOT(slotToggleColorManagedView())); ac->addAction(QLatin1String("color_managed_view"), d->viewCMViewAction); ac->setDefaultShortcut(d->viewCMViewAction, Qt::Key_F12); // ----------------------------------------------------------------------------- ThemeManager::instance()->registerThemeActions(this); // Standard 'Help' menu actions createHelpActions(); // Provides a menu entry that allows showing/hiding the toolbar(s) setStandardToolBarMenuEnabled(true); // Provides a menu entry that allows showing/hiding the statusbar createStandardStatusBarAction(); // Standard 'Configure' menu actions createSettingsActions(); // -- Keyboard-only actions ---------------------------------------------------- d->addPageUpDownActions(this, this); QAction* const altBackwardAction = new QAction(i18n("Previous Image"), this); ac->addAction(QLatin1String("lighttable_backward_shift_space"), altBackwardAction); ac->setDefaultShortcut(altBackwardAction, Qt::SHIFT + Qt::Key_Space); connect(altBackwardAction, SIGNAL(triggered()), this, SLOT(slotBackward())); // Labels shortcuts must be registered here to be saved in XML GUI files if user customize it. TagsActionMngr::defaultManager()->registerLabelsActions(ac); QAction* const editTitlesRight = new QAction(i18n("Edit Titles on the Right"), this); ac->addAction(QLatin1String("edit_titles_right"), editTitlesRight); ac->setDefaultShortcut(editTitlesRight, Qt::META + Qt::Key_T); connect(editTitlesRight, SIGNAL(triggered()), this, SLOT(slotRightSideBarActivateTitles())); QAction* const editCommentsRight = new QAction(i18n("Edit Comments on the Right"), this); ac->addAction(QLatin1String("edit_comments_right"), editCommentsRight); ac->setDefaultShortcut(editCommentsRight, Qt::META + Qt::Key_C); connect(editCommentsRight, SIGNAL(triggered()), this, SLOT(slotRightSideBarActivateComments())); QAction* const editTitlesLeft = new QAction(i18n("Edit Titles on the Left"), this); ac->addAction(QLatin1String("edit_titles_left"), editTitlesLeft); ac->setDefaultShortcut(editTitlesLeft, Qt::SHIFT + Qt::META + Qt::Key_T); connect(editTitlesLeft, SIGNAL(triggered()), this, SLOT(slotLeftSideBarActivateTitles())); QAction* const editCommentsLeft = new QAction(i18n("Edit Comments on the Left"), this); ac->addAction(QLatin1String("edit_comments_left"), editCommentsLeft); ac->setDefaultShortcut(editCommentsLeft, Qt::SHIFT + Qt::META + Qt::Key_C); connect(editCommentsLeft, SIGNAL(triggered()), this, SLOT(slotLeftSideBarActivateComments())); QAction* const assignedTagsRight = new QAction(i18n("Show Assigned Tags on the Right"), this); ac->addAction(QLatin1String("assigned _tags_right"), assignedTagsRight); ac->setDefaultShortcut(assignedTagsRight, Qt::META + Qt::Key_A); connect(assignedTagsRight, SIGNAL(triggered()), this, SLOT(slotRightSideBarActivateAssignedTags())); QAction* const assignedTagsLeft = new QAction(i18n("Show Assigned Tags on the Left"), this); ac->addAction(QLatin1String("assigned _tags_left"), assignedTagsLeft); ac->setDefaultShortcut(assignedTagsLeft, Qt::SHIFT + Qt::META + Qt::Key_A); connect(assignedTagsLeft, SIGNAL(triggered()), this, SLOT(slotLeftSideBarActivateAssignedTags())); // --------------------------------------------------------------------------------- createGUI(xmlFile()); cleanupActions(); showMenuBarAction()->setChecked(!menuBar()->isHidden()); // NOTE: workaround for bug #171080 } // Deal with items dropped onto the thumbbar (e.g. from the Album view) void LightTableWindow::slotThumbbarDroppedItems(const QList& list) { // Setting the third parameter of loadImageInfos to true // means that the images are added to the presently available images. loadImageInfos(ImageInfoList() << list, ImageInfo(), true); } // We get here either // - via CTRL+L (from the albumview) // a) digikamapp.cpp: CTRL+key_L leads to slotImageLightTable()) // b) digikamview.cpp: void DigikamView::slotImageLightTable() // calls d->iconView->insertToLightTable(list, info); // c) albumiconview.cpp: AlbumIconView::insertToLightTable // calls ltview->loadImageInfos(list, current); // - via drag&drop, i.e. calls issued by the ...Dropped... routines void LightTableWindow::loadImageInfos(const ImageInfoList& list, const ImageInfo& givenImageInfoCurrent, bool addTo) { // Clear all items before adding new images to the light table. qCDebug(DIGIKAM_GENERAL_LOG) << "Clearing LT" << (!addTo); if (!addTo) { slotClearItemsList(); } ImageInfoList l = list; ImageInfo imageInfoCurrent = givenImageInfoCurrent; if (imageInfoCurrent.isNull() && !l.isEmpty()) { imageInfoCurrent = l.first(); } d->thumbView->setItems(l); QModelIndex index = d->thumbView->findItemByInfo(imageInfoCurrent); if (index.isValid()) { d->thumbView->setCurrentIndex(index); } else { d->thumbView->setCurrentWhenAvailable(imageInfoCurrent.id()); } } bool LightTableWindow::isEmpty() const { return (d->thumbView->countItems() == 0); } void LightTableWindow::slotRefreshStatusBar() { d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode, i18np("%1 item on Light Table", "%1 items on Light Table", d->thumbView->countItems())); } void LightTableWindow::slotFileChanged(const QString& path) { QUrl url = QUrl::fromLocalFile(path); // NOTE: Thumbbar handle change through ImageCategorizedView if (!d->previewView->leftImageInfo().isNull()) { if (d->previewView->leftImageInfo().fileUrl() == url) { d->previewView->leftReload(); d->leftSideBar->itemChanged(d->previewView->leftImageInfo()); } } if (!d->previewView->rightImageInfo().isNull()) { if (d->previewView->rightImageInfo().fileUrl() == url) { d->previewView->rightReload(); d->rightSideBar->itemChanged(d->previewView->rightImageInfo()); } } } void LightTableWindow::slotLeftPanelLeftButtonClicked() { if (d->navigateByPairAction->isChecked()) { return; } d->thumbView->setCurrentInfo(d->previewView->leftImageInfo()); } void LightTableWindow::slotRightPanelLeftButtonClicked() { // With navigate by pair option, only the left panel can be selected. if (d->navigateByPairAction->isChecked()) { return; } d->thumbView->setCurrentInfo(d->previewView->rightImageInfo()); } void LightTableWindow::slotLeftPreviewLoaded(bool b) { d->leftZoomBar->setEnabled(b); d->leftFileName->setAdjustedText(); if (b) { d->leftFileName->setAdjustedText(d->previewView->leftImageInfo().name()); d->previewView->checkForSelection(d->thumbView->currentInfo()); d->thumbView->setOnLeftPanel(d->previewView->leftImageInfo()); QModelIndex index = d->thumbView->findItemByInfo(d->previewView->leftImageInfo()); if (d->navigateByPairAction->isChecked() && index.isValid()) { QModelIndex next = d->thumbView->nextIndex(index); if (next.isValid()) { d->thumbView->setOnRightPanel(d->thumbView->findItemByIndex(next)); slotSetItemOnRightPanel(d->thumbView->findItemByIndex(next)); } else { QModelIndex first = d->thumbView->firstIndex(); slotSetItemOnRightPanel(first.isValid() ? d->thumbView->findItemByIndex(first) : ImageInfo()); } } } } void LightTableWindow::slotRightPreviewLoaded(bool b) { d->rightZoomBar->setEnabled(b); d->rightFileName->setAdjustedText(); if (b) { d->rightFileName->setAdjustedText(d->previewView->rightImageInfo().name()); d->previewView->checkForSelection(d->thumbView->currentInfo()); d->thumbView->setOnRightPanel(d->previewView->rightImageInfo()); QModelIndex index = d->thumbView->findItemByInfo(d->previewView->rightImageInfo()); if (index.isValid()) { d->thumbView->setOnRightPanel(d->thumbView->findItemByIndex(index)); } } } void LightTableWindow::slotItemSelected(const ImageInfo& info) { bool hasInfo = !info.isNull(); d->setItemLeftAction->setEnabled(hasInfo); d->setItemRightAction->setEnabled(hasInfo); d->editItemAction->setEnabled(hasInfo); d->removeItemAction->setEnabled(hasInfo); d->clearListAction->setEnabled(hasInfo); d->fileDeleteAction->setEnabled(hasInfo); d->fileDeleteFinalAction->setEnabled(hasInfo); d->backwardAction->setEnabled(hasInfo); d->forwardAction->setEnabled(hasInfo); d->firstAction->setEnabled(hasInfo); d->lastAction->setEnabled(hasInfo); d->syncPreviewAction->setEnabled(hasInfo); d->navigateByPairAction->setEnabled(hasInfo); d->slideShowAction->setEnabled(hasInfo); if (hasInfo) { QModelIndex curr = d->thumbView->findItemByInfo(info); if (curr.isValid()) { if (!d->thumbView->previousIndex(curr).isValid()) { d->firstAction->setEnabled(false); } if (!d->thumbView->nextIndex(curr).isValid()) { d->lastAction->setEnabled(false); } if (d->navigateByPairAction->isChecked()) { d->setItemLeftAction->setEnabled(false); d->setItemRightAction->setEnabled(false); d->thumbView->setOnLeftPanel(info); slotSetItemOnLeftPanel(info); } else if (d->autoLoadOnRightPanel && !d->thumbView->isOnLeftPanel(info)) { d->thumbView->setOnRightPanel(info); slotSetItemOnRightPanel(info); } } } d->previewView->checkForSelection(info); } // Deal with one (or more) items dropped onto the left panel void LightTableWindow::slotLeftDroppedItems(const ImageInfoList& list) { ImageInfo info = list.first(); // add the image to the existing images loadImageInfos(list, info, true); // We will check if first item from list is already stored in thumbbar // Note that the thumbbar stores all ImageInfo reference // in memory for preview object. QModelIndex index = d->thumbView->findItemByInfo(info); if (index.isValid()) { slotSetItemOnLeftPanel(info); } } // Deal with one (or more) items dropped onto the right panel void LightTableWindow::slotRightDroppedItems(const ImageInfoList& list) { ImageInfo info = list.first(); // add the image to the existing images loadImageInfos(list, info, true); // We will check if first item from list is already stored in thumbbar // Note that the thumbbar stores all ImageInfo reference // in memory for preview object. QModelIndex index = d->thumbView->findItemByInfo(info); if (index.isValid()) { slotSetItemOnRightPanel(info); // Make this item the current one. d->thumbView->setCurrentInfo(info); } } // Set the images for the left and right panel. void LightTableWindow::setLeftRightItems(const ImageInfoList& list, bool addTo) { ImageInfoList l = list; if (l.count() == 0) { return; } ImageInfo info = l.first(); QModelIndex index = d->thumbView->findItemByInfo(info); if (l.count() == 1 && !addTo) { // Just one item; this is used for the left panel. d->thumbView->setOnLeftPanel(info); slotSetItemOnLeftPanel(info); d->thumbView->setCurrentInfo(info); return; } if (index.isValid()) { // The first item is used for the left panel. if (!addTo) { d->thumbView->setOnLeftPanel(info); slotSetItemOnLeftPanel(info); } // The subsequent item is used for the right panel. QModelIndex next = d->thumbView->nextIndex(index); if (next.isValid() && !addTo) { ImageInfo nextInf = d->thumbView->findItemByIndex(next); d->thumbView->setOnRightPanel(nextInf); slotSetItemOnRightPanel(nextInf); if (!d->navigateByPairAction->isChecked()) { d->thumbView->setCurrentInfo(nextInf); } } // If navigate by pairs is active, the left panel item is selected. // (Fixes parts of bug #150296) if (d->navigateByPairAction->isChecked()) { d->thumbView->setCurrentInfo(info); } } } void LightTableWindow::slotSetItemLeft() { if (!d->thumbView->currentInfo().isNull()) { slotSetItemOnLeftPanel(d->thumbView->currentInfo()); } } void LightTableWindow::slotSetItemRight() { if (!d->thumbView->currentInfo().isNull()) { slotSetItemOnRightPanel(d->thumbView->currentInfo()); } } void LightTableWindow::slotSetItemOnLeftPanel(const ImageInfo& info) { d->previewView->setLeftImageInfo(info); if (!info.isNull()) { d->leftSideBar->itemChanged(info); } else { d->leftSideBar->slotNoCurrentItem(); } } void LightTableWindow::slotSetItemOnRightPanel(const ImageInfo& info) { d->previewView->setRightImageInfo(info); if (!info.isNull()) { d->rightSideBar->itemChanged(info); } else { d->rightSideBar->slotNoCurrentItem(); } } void LightTableWindow::slotClearItemsList() { if (!d->previewView->leftImageInfo().isNull()) { d->previewView->setLeftImageInfo(); d->leftSideBar->slotNoCurrentItem(); } if (!d->previewView->rightImageInfo().isNull()) { d->previewView->setRightImageInfo(); d->rightSideBar->slotNoCurrentItem(); } d->thumbView->clear(); } void LightTableWindow::slotDeleteItem() { deleteItem(false); } void LightTableWindow::slotDeleteItem(const ImageInfo& info) { deleteItem(info, false); } void LightTableWindow::slotDeleteFinalItem() { deleteItem(true); } void LightTableWindow::slotDeleteFinalItem(const ImageInfo& info) { deleteItem(info, true); } void LightTableWindow::deleteItem(bool permanently) { if (!d->thumbView->currentInfo().isNull()) { deleteItem(d->thumbView->currentInfo(), permanently); } } void LightTableWindow::deleteItem(const ImageInfo& info, bool permanently) { QUrl u = info.fileUrl(); PAlbum* const palbum = AlbumManager::instance()->findPAlbum(u.adjusted(QUrl::RemoveFilename)); if (!palbum) { return; } qCDebug(DIGIKAM_GENERAL_LOG) << "Item to delete: " << u; bool useTrash; bool preselectDeletePermanently = permanently; DeleteDialog dialog(this); QList urlList; urlList.append(u); if (!dialog.confirmDeleteList(urlList, DeleteDialogMode::Files, preselectDeletePermanently ? DeleteDialogMode::NoChoiceDeletePermanently : DeleteDialogMode::NoChoiceTrash)) { return; } useTrash = !dialog.shouldDelete(); DIO::del(info, useTrash); } void LightTableWindow::slotRemoveItem() { if (!d->thumbView->currentInfo().isNull()) { slotRemoveItem(d->thumbView->currentInfo()); } } void LightTableWindow::slotRemoveItem(const ImageInfo& info) { /* if (!d->previewView->leftImageInfo().isNull()) { if (d->previewView->leftImageInfo() == info) { d->previewView->setLeftImageInfo(); d->leftSideBar->slotNoCurrentItem(); } } if (!d->previewView->rightImageInfo().isNull()) { if (d->previewView->rightImageInfo() == info) { d->previewView->setRightImageInfo(); d->rightSideBar->slotNoCurrentItem(); } } d->thumbView->removeItemByInfo(info); d->thumbView->setSelected(d->thumbView->currentItem()); */ // When either the image from the left or right panel is removed, // there are various situations to account for. // To describe them, 4 images A B C D are used // and the subscript _L and _ R mark the currently // active item on the left and right panel ImageInfo new_linfo; ImageInfo new_rinfo; bool leftPanelActive = false; ImageInfo curr_linfo = d->previewView->leftImageInfo(); ImageInfo curr_rinfo = d->previewView->rightImageInfo(); qint64 infoId = info.id(); // First determine the next images to the current left and right image: ImageInfo next_linfo; ImageInfo next_rinfo; if (!curr_linfo.isNull()) { QModelIndex index = d->thumbView->findItemByInfo(curr_linfo); if (index.isValid()) { QModelIndex next = d->thumbView->nextIndex(index); if (next.isValid()) { next_linfo = d->thumbView->findItemByIndex(next); } } } if (!curr_rinfo.isNull()) { QModelIndex index = d->thumbView->findItemByInfo(curr_rinfo); if (index.isValid()) { QModelIndex next = d->thumbView->nextIndex(index); if (next.isValid()) { next_rinfo = d->thumbView->findItemByIndex(next); } } } d->thumbView->removeItemByInfo(info); // Make sure that next_linfo and next_rinfo are still available: if (!d->thumbView->findItemByInfo(next_linfo).isValid()) { next_linfo = ImageInfo(); } if (!d->thumbView->findItemByInfo(next_rinfo).isValid()) { next_rinfo = ImageInfo(); } // removal of the left panel item? if (!curr_linfo.isNull()) { if (curr_linfo.id() == infoId) { leftPanelActive = true; // Delete the item A_L of the left panel: // 1) A_L B_R C D -> B_L C_R D // 2) A_L B C_R D -> B C_L D_R // 3) A_L B C D_R -> B_R C D_L // 4) A_L B_R -> A_L // some more corner cases: // 5) A B_L C_R D -> A C_L D_R // 6) A B_L C_R -> A_R C_L // 7) A_LR B C D -> B_L C_R D (does not yet work) // I.e. in 3) we wrap around circularly. // When removing the left panel image, // put the right panel image into the left panel. // Check if this one is not the same (i.e. also removed). if (!curr_rinfo.isNull()) { if (curr_rinfo.id() != infoId) { new_linfo = curr_rinfo; // Set the right panel to the next image: new_rinfo = next_rinfo; // set the right panel active, but not in pair mode if (!d->navigateByPairAction->isChecked()) { leftPanelActive = false; } } } } } // removal of the right panel item? if (!curr_rinfo.isNull()) { if (curr_rinfo.id() == infoId) { // Leave the left panel as the current one new_linfo = curr_linfo; // Set the right panel to the next image new_rinfo = next_rinfo; } } // Now we deal with the corner cases, where no left or right item exists. // If the right panel would be set, but not the left-one, then swap if (new_linfo.isNull() && !new_rinfo.isNull()) { new_linfo = new_rinfo; new_rinfo = ImageInfo(); leftPanelActive = true; } if (new_linfo.isNull()) { if (d->thumbView->countItems() > 0) { QModelIndex first = d->thumbView->firstIndex(); new_linfo = d->thumbView->findItemByIndex(first); } } // Make sure that new_linfo and new_rinfo exist. // This addresses a crash occurring if the last image is removed // in the navigate by pairs mode. if (!d->thumbView->findItemByInfo(new_linfo).isValid()) { new_linfo = ImageInfo(); } if (!d->thumbView->findItemByInfo(new_rinfo).isValid()) { new_rinfo = ImageInfo(); } // no right item defined? if (new_rinfo.isNull()) { // If there are at least two items, we can find reasonable right image. if (d->thumbView->countItems() > 1) { // See if there is an item next to the left one: QModelIndex index = d->thumbView->findItemByInfo(new_linfo); QModelIndex next; if (index.isValid()) { next = d->thumbView->nextIndex(index); } if (next.isValid()) { new_rinfo = d->thumbView->findItemByIndex(next); } else { // If there is no item to the right of new_linfo // then we can choose the first item for new_rinfo // (as we made sure that there are at least two items) QModelIndex first = d->thumbView->firstIndex(); new_rinfo = d->thumbView->findItemByIndex(first); } } } // Check if left and right are set to the same if (!new_linfo.isNull() && !new_rinfo.isNull()) { if (new_linfo.id() == new_rinfo.id()) { // Only keep the left one new_rinfo = ImageInfo(); } } // If the right panel would be set, but not the left-one, then swap // (note that this has to be done here again!) if (new_linfo.isNull() && !new_rinfo.isNull()) { new_linfo = new_rinfo; new_rinfo = ImageInfo(); leftPanelActive = true; } // set the image for the left panel if (!new_linfo.isNull()) { d->thumbView->setOnLeftPanel(new_linfo); slotSetItemOnLeftPanel(new_linfo); // make this the selected item if the left was active before if (leftPanelActive) { d->thumbView->setCurrentInfo(new_linfo); } } else { d->previewView->setLeftImageInfo(); d->leftSideBar->slotNoCurrentItem(); } // set the image for the right panel if (!new_rinfo.isNull()) { d->thumbView->setOnRightPanel(new_rinfo); slotSetItemOnRightPanel(new_rinfo); // make this the selected item if the left was active before if (!leftPanelActive) { d->thumbView->setCurrentInfo(new_rinfo); } } else { d->previewView->setRightImageInfo(); d->rightSideBar->slotNoCurrentItem(); } } void LightTableWindow::slotEditItem() { if (!d->thumbView->currentInfo().isNull()) { slotEditItem(d->thumbView->currentInfo()); } } void LightTableWindow::slotEditItem(const ImageInfo& info) { ImageWindow* const im = ImageWindow::imageWindow(); ImageInfoList list = d->thumbView->allImageInfos(); im->loadImageInfos(list, info, i18n("Light Table")); if (im->isHidden()) { im->show(); } else { im->raise(); } im->setFocus(); } void LightTableWindow::slotPresentation() { PresentationMngr* const mngr = new PresentationMngr(this); foreach(const ImageInfo& info, d->thumbView->allImageInfos()) { mngr->addFile(info.fileUrl(), info.comment()); qApp->processEvents(); } mngr->showConfigDialog(); } void LightTableWindow::slotSlideShowAll() { SlideShowBuilder* const builder = new SlideShowBuilder(d->thumbView->allImageInfos()); d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode, i18n("Preparing slideshow. Please wait...")); connect(builder, SIGNAL(signalComplete(SlideShowSettings)), this, SLOT(slotSlideShowBuilderComplete(SlideShowSettings))); builder->run(); } void LightTableWindow::slotLeftSlideShowManualFromCurrent() { slotSlideShowManualFrom(d->previewView->leftImageInfo()); d->fromLeftPreview = true; } void LightTableWindow::slotRightSlideShowManualFromCurrent() { slotSlideShowManualFrom(d->previewView->rightImageInfo()); d->fromLeftPreview = false; } void LightTableWindow::slotSlideShowManualFrom(const ImageInfo& info) { SlideShowBuilder* const builder = new SlideShowBuilder(d->thumbView->allImageInfos()); builder->setOverrideStartFrom(info); builder->setAutoPlayEnabled(false); d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode, i18n("Preparing slideshow. Please wait...")); connect(builder, SIGNAL(signalComplete(SlideShowSettings)), this, SLOT(slotSlideShowBuilderComplete(SlideShowSettings))); builder->run(); } void LightTableWindow::slotSlideShowBuilderComplete(const SlideShowSettings& settings) { SlideShow* const slide = new SlideShow(settings); TagsActionMngr::defaultManager()->registerActionsToWidget(slide); d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode, QString()); slotRefreshStatusBar(); if (settings.imageUrl.isValid()) { slide->setCurrentItem(settings.imageUrl); } else if (settings.startWithCurrent) { slide->setCurrentItem(d->thumbView->currentInfo().fileUrl()); } connect(slide, SIGNAL(signalRatingChanged(QUrl,int)), d->thumbView, SLOT(slotRatingChanged(QUrl,int))); connect(slide, SIGNAL(signalColorLabelChanged(QUrl,int)), d->thumbView, SLOT(slotColorLabelChanged(QUrl,int))); connect(slide, SIGNAL(signalPickLabelChanged(QUrl,int)), d->thumbView, SLOT(slotPickLabelChanged(QUrl,int))); connect(slide, SIGNAL(signalToggleTag(QUrl,int)), d->thumbView, SLOT(slotToggleTag(QUrl,int))); connect(slide, SIGNAL(signalLastItemUrl(QUrl)), this, SLOT(slotSlideShowLastItemUrl(QUrl))); slide->show(); } void LightTableWindow::slotSlideShowLastItemUrl(const QUrl& url) { if (d->fromLeftPreview && !d->navigateByPairAction->isChecked()) { d->thumbView->blockSignals(true); d->thumbView->setCurrentUrl(url); d->thumbView->blockSignals(false); slotSetItemLeft(); } else { d->thumbView->setCurrentUrl(url); } } void LightTableWindow::slotSetup() { Setup::execDialog(this); } void LightTableWindow::slotLeftZoomFactorChanged(double zoom) { double zmin = d->previewView->leftZoomMin(); double zmax = d->previewView->leftZoomMax(); d->leftZoomBar->setZoom(zoom, zmin, zmax); d->leftZoomPlusAction->setEnabled(!d->previewView->leftMaxZoom()); d->leftZoomMinusAction->setEnabled(!d->previewView->leftMinZoom()); } void LightTableWindow::slotRightZoomFactorChanged(double zoom) { double zmin = d->previewView->rightZoomMin(); double zmax = d->previewView->rightZoomMax(); d->rightZoomBar->setZoom(zoom, zmin, zmax); d->rightZoomPlusAction->setEnabled(!d->previewView->rightMaxZoom()); d->rightZoomMinusAction->setEnabled(!d->previewView->rightMinZoom()); } void LightTableWindow::slotToggleSyncPreview() { d->previewView->setSyncPreview(d->syncPreviewAction->isChecked()); } void LightTableWindow::slotToggleOnSyncPreview(bool t) { d->syncPreviewAction->setEnabled(t); if (!t) { d->syncPreviewAction->setChecked(false); } else { if (d->autoSyncPreview) { d->syncPreviewAction->setChecked(true); } } } void LightTableWindow::slotBackward() { d->thumbView->toPreviousIndex(); } void LightTableWindow::slotForward() { d->thumbView->toNextIndex(); } void LightTableWindow::slotFirst() { d->thumbView->toFirstIndex(); } void LightTableWindow::slotLast() { d->thumbView->toLastIndex(); } void LightTableWindow::slotToggleNavigateByPair() { d->thumbView->setNavigateByPair(d->navigateByPairAction->isChecked()); d->previewView->setNavigateByPair(d->navigateByPairAction->isChecked()); slotItemSelected(d->thumbView->currentInfo()); } void LightTableWindow::slotComponentsInfo() { showDigikamComponentsInfo(); } void LightTableWindow::slotDBStat() { showDigikamDatabaseStat(); } void LightTableWindow::slotApplicationSettingsChanged() { d->leftSideBar->setStyle(ApplicationSettings::instance()->getSidebarTitleStyle()); d->rightSideBar->setStyle(ApplicationSettings::instance()->getSidebarTitleStyle()); /// @todo Which part of the settings has to be reloaded? // d->rightSideBar->applySettings(); d->previewView->setPreviewSettings(ApplicationSettings::instance()->getPreviewSettings()); } void LightTableWindow::moveEvent(QMoveEvent* e) { Q_UNUSED(e) emit signalWindowHasMoved(); } void LightTableWindow::toggleTag(int tagID) { d->thumbView->toggleTag(tagID); } void LightTableWindow::slotAssignPickLabel(int pickId) { d->thumbView->slotAssignPickLabel(pickId); } void LightTableWindow::slotAssignColorLabel(int colorId) { d->thumbView->slotAssignColorLabel(colorId); } void LightTableWindow::slotAssignRating(int rating) { d->thumbView->slotAssignRating(rating); } void LightTableWindow::slotThemeChanged() { d->previewView->checkForSelection(d->previewView->leftImageInfo()); d->previewView->checkForSelection(d->previewView->rightImageInfo()); } void LightTableWindow::showSideBars(bool visible) { if (visible) { d->leftSideBar->restore(); d->rightSideBar->restore(); } else { d->leftSideBar->backup(); d->rightSideBar->backup(); } } void LightTableWindow::slotToggleLeftSideBar() { d->leftSideBar->isExpanded() ? d->leftSideBar->shrink() : d->leftSideBar->expand(); } void LightTableWindow::slotToggleRightSideBar() { d->rightSideBar->isExpanded() ? d->rightSideBar->shrink() : d->rightSideBar->expand(); } void LightTableWindow::slotPreviousLeftSideBarTab() { d->leftSideBar->activePreviousTab(); } void LightTableWindow::slotNextLeftSideBarTab() { d->leftSideBar->activeNextTab(); } void LightTableWindow::slotPreviousRightSideBarTab() { d->rightSideBar->activePreviousTab(); } void LightTableWindow::slotNextRightSideBarTab() { d->rightSideBar->activeNextTab(); } void LightTableWindow::customizedFullScreenMode(bool set) { showStatusBarAction()->setEnabled(!set); toolBarMenuAction()->setEnabled(!set); showMenuBarAction()->setEnabled(!set); d->showBarAction->setEnabled(!set); d->previewView->toggleFullScreen(set); } void LightTableWindow::slotFileWithDefaultApplication() { if (!d->thumbView->currentInfo().isNull()) { DFileOperations::openFilesWithDefaultApplication(QList() << d->thumbView->currentInfo().fileUrl()); } } void LightTableWindow::slotRightSideBarActivateTitles() { d->rightSideBar->setActiveTab(d->rightSideBar->imageDescEditTab()); d->rightSideBar->imageDescEditTab()->setFocusToTitlesEdit(); } void LightTableWindow::slotRightSideBarActivateComments() { d->rightSideBar->setActiveTab(d->rightSideBar->imageDescEditTab()); d->rightSideBar->imageDescEditTab()->setFocusToCommentsEdit(); } void LightTableWindow::slotRightSideBarActivateAssignedTags() { d->rightSideBar->setActiveTab(d->rightSideBar->imageDescEditTab()); d->rightSideBar->imageDescEditTab()->activateAssignedTagsButton(); } void LightTableWindow::slotLeftSideBarActivateTitles() { d->leftSideBar->setActiveTab(d->leftSideBar->imageDescEditTab()); d->leftSideBar->imageDescEditTab()->setFocusToTitlesEdit(); } void LightTableWindow::slotLeftSideBarActivateComments() { d->leftSideBar->setActiveTab(d->leftSideBar->imageDescEditTab()); d->leftSideBar->imageDescEditTab()->setFocusToCommentsEdit(); } void LightTableWindow::slotLeftSideBarActivateAssignedTags() { d->leftSideBar->setActiveTab(d->leftSideBar->imageDescEditTab()); d->leftSideBar->imageDescEditTab()->activateAssignedTagsButton(); } void LightTableWindow::slotToggleColorManagedView() { if (!IccSettings::instance()->isEnabled()) { return; } bool cmv = !IccSettings::instance()->settings().useManagedPreviews; IccSettings::instance()->setUseManagedPreviews(cmv); } void LightTableWindow::slotColorManagementOptionsChanged() { ICCSettingsContainer settings = IccSettings::instance()->settings(); d->viewCMViewAction->blockSignals(true); d->viewCMViewAction->setEnabled(settings.enableCM); d->viewCMViewAction->setChecked(settings.useManagedPreviews); d->viewCMViewAction->blockSignals(false); } void LightTableWindow::slotEditGeolocation() { #ifdef HAVE_MARBLE ImageInfoList infos = d->thumbView->allImageInfos(); if (infos.isEmpty()) { return; } TagModel* const tagModel = new TagModel(AbstractAlbumModel::IgnoreRootAlbum, this); TagPropertiesFilterModel* const filterModel = new TagPropertiesFilterModel(this); filterModel->setSourceAlbumModel(tagModel); filterModel->sort(0); QPointer dialog = new GeolocationEdit(filterModel, new DBInfoIface(this, d->thumbView->allUrls()), QApplication::activeWindow()); dialog->setItems(ImageGPS::infosToItems(infos)); dialog->exec(); delete dialog; // Refresh Database with new metadata from files. foreach(const ImageInfo& inf, infos) { ScanController::instance()->scannedInfo(inf.fileUrl().toLocalFile()); } #endif } void LightTableWindow::slotEditMetadata() { if (d->thumbView->currentInfo().isNull()) { return; } QUrl url = d->thumbView->currentInfo().fileUrl(); QPointer dialog = new MetadataEditDialog(QApplication::activeWindow(), QList() << url); dialog->exec(); delete dialog; // Refresh Database with new metadata from file. CollectionScanner scanner; scanner.scanFile(url.toLocalFile(), CollectionScanner::Rescan); } void LightTableWindow::slotImportFromScanner() { #ifdef HAVE_KSANE m_ksaneAction->activate(DigikamApp::instance()->scannerTargetPlace(), configGroupName()); connect(m_ksaneAction, SIGNAL(signalImportedImage(QUrl)), this, SLOT(slotImportedImagefromScanner(QUrl))); #endif } void LightTableWindow::slotImportedImagefromScanner(const QUrl& url) { ImageInfo info = ScanController::instance()->scannedInfo(url.toLocalFile()); loadImageInfos(ImageInfoList() << info, info, true); } void LightTableWindow::slotHtmlGallery() { #ifdef HAVE_HTMLGALLERY QPointer w = new HTMLWizard(this, new DBInfoIface(this, d->thumbView->allUrls())); w->exec(); delete w; #endif } void LightTableWindow::slotCalendar() { QPointer w = new CalWizard(d->thumbView->allUrls(), this); w->exec(); delete w; } void LightTableWindow::slotPanorama() { #ifdef HAVE_PANORAMA PanoManager::instance()->checkBinaries(); PanoManager::instance()->setItemsList(d->thumbView->allUrls()); PanoManager::instance()->run(); #endif } void LightTableWindow::slotExpoBlending() { ExpoBlendingManager::instance()->checkBinaries(); ExpoBlendingManager::instance()->setItemsList(d->thumbView->allUrls()); ExpoBlendingManager::instance()->run(); } void LightTableWindow::slotVideoSlideshow() { #ifdef HAVE_MEDIAPLAYER QPointer w = new VidSlideWizard(this, new DBInfoIface(this, d->thumbView->allUrls())); w->exec(); delete w; #endif } void LightTableWindow::slotSendByMail() { QPointer w = new MailWizard(this, new DBInfoIface(this, d->thumbView->allUrls())); w->exec(); delete w; } void LightTableWindow::slotPrintCreator() { QPointer w = new AdvPrintWizard(this, new DBInfoIface(this, d->thumbView->allUrls())); w->exec(); delete w; } void LightTableWindow::slotMediaServer() { DBInfoIface* const iface = new DBInfoIface(this, QList(), ApplicationSettings::Tools); // NOTE: We overwrite the default albums chooser object name for load save check items state between sessions. // The goal is not mix these settings with other export tools. iface->setObjectName(QLatin1String("SetupMediaServerIface")); QPointer w = new DMediaServerDlg(this, iface); w->exec(); delete w; } void LightTableWindow::slotExportTool() { QAction* const tool = dynamic_cast(sender()); if (tool == m_exportDropboxAction) { QPointer w = new DBWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportFacebookAction) { QPointer w = new FbWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportFlickrAction) { QPointer w = new FlickrWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportGdriveAction) { QPointer w = new GSWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this, QLatin1String("googledriveexport")); w->exec(); delete w; } else if (tool == m_exportGphotoAction) { QPointer w = new GSWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this, QLatin1String("googlephotoexport")); w->exec(); delete w; } else if (tool == m_exportImageshackAction) { QPointer w = new ImageShackWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportImgurAction) { QPointer w = new ImgurWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportPiwigoAction) { QPointer w = new PiwigoWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportRajceAction) { QPointer w = new RajceWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportSmugmugAction) { QPointer w = new SmugWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportYandexfotkiAction) { QPointer w = new YFWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } #ifdef HAVE_MEDIAWIKI else if (tool == m_exportMediawikiAction) { QPointer w = new MediaWikiWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } #endif #ifdef HAVE_VKONTAKTE else if (tool == m_exportVkontakteAction) { QPointer w = new VKWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } #endif #ifdef HAVE_KIO else if (tool == m_exportFileTransferAction) { QPointer w = new FTExportWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } #endif } void LightTableWindow::slotImportTool() { QAction* const tool = dynamic_cast(sender()); if (tool == m_importGphotoAction) { QPointer w = new GSWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this, QLatin1String("googlephotoimport")); w->exec(); delete w; } else if (tool == m_importSmugmugAction) { QPointer w = new SmugWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this, true); w->exec(); delete w; } #ifdef HAVE_KIO else if (tool == m_importFileTransferAction) { QPointer w = new FTImportWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } #endif } } // namespace Digikam diff --git a/core/utilities/maintenance/facesdetector.cpp b/core/utilities/maintenance/facesdetector.cpp index 07e12f517d..aa06e71669 100644 --- a/core/utilities/maintenance/facesdetector.cpp +++ b/core/utilities/maintenance/facesdetector.cpp @@ -1,390 +1,399 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2010-07-18 * Description : batch face detection * * Copyright (C) 2010 by Aditya Bhatt * Copyright (C) 2010-2018 by Gilles Caulier * 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 "facesdetector.h" // Qt includes #include #include #include #include #include #include #include // KDE includes #include #include // Local includes #include "recognitiondatabase.h" #include "digikam_debug.h" #include "coredb.h" #include "album.h" #include "albummanager.h" #include "facepipeline.h" #include "facescansettings.h" #include "imageinfo.h" #include "imageinfojob.h" namespace Digikam { class BenchmarkMessageDisplay : public QWidget { public: explicit BenchmarkMessageDisplay(const QString& richText) : QWidget(0) { setAttribute(Qt::WA_DeleteOnClose); QVBoxLayout* const vbox = new QVBoxLayout; QTextEdit* const edit = new QTextEdit; vbox->addWidget(edit, 1); QPushButton* const okButton = new QPushButton(i18n("OK")); vbox->addWidget(okButton, 0, Qt::AlignRight); setLayout(vbox); connect(okButton, SIGNAL(clicked()), this, SLOT(close())); edit->setHtml(richText); QApplication::clipboard()->setText(edit->toPlainText()); resize(500, 400); show(); raise(); } }; // -------------------------------------------------------------------------- class FacesDetector::Private { public: explicit Private() : benchmark(false), - total(0), - progressValue(0), - currentProgressChunk(0), - currentScheduled(0), - currentFinished(0) + useImageInfos(false) { } bool benchmark; - - int total; + bool useImageInfos; AlbumPointerList<> albumTodoList; + ImageInfoList infoTodoList; ImageInfoJob albumListing; FacePipeline pipeline; - QMap relativeProgressValue; - double progressValue; - double currentProgressChunk; - int currentScheduled; - int currentFinished; }; FacesDetector::FacesDetector(const FaceScanSettings& settings, ProgressItem* const parent) : MaintenanceTool(QLatin1String("FacesDetector"), parent), d(new Private) { setLabel(i18n("Updating faces database.")); ProgressManager::addProgressItem(this); if (settings.task == FaceScanSettings::RetrainAll) { // clear all training data in the database RecognitionDatabase().clearAllTraining(QLatin1String("digikam")); d->pipeline.plugRetrainingDatabaseFilter(); d->pipeline.plugTrainer(); d->pipeline.construct(); } else if (settings.task == FaceScanSettings::BenchmarkDetection) { d->benchmark = true; d->pipeline.plugDatabaseFilter(FacePipeline::ScanAll); d->pipeline.plugPreviewLoader(); if (settings.useFullCpu) { d->pipeline.plugParallelFaceDetectors(); } else { d->pipeline.plugFaceDetector(); } d->pipeline.plugDetectionBenchmarker(); d->pipeline.construct(); } else if (settings.task == FaceScanSettings::BenchmarkRecognition) { d->benchmark = true; d->pipeline.plugRetrainingDatabaseFilter(); d->pipeline.plugFaceRecognizer(); d->pipeline.plugRecognitionBenchmarker(); d->pipeline.construct(); } else if ((settings.task == FaceScanSettings::DetectAndRecognize) || (settings.task == FaceScanSettings::Detect)) { FacePipeline::FilterMode filterMode; FacePipeline::WriteMode writeMode; if (settings.alreadyScannedHandling == FaceScanSettings::Skip) { filterMode = FacePipeline::SkipAlreadyScanned; writeMode = FacePipeline::NormalWrite; } else if (settings.alreadyScannedHandling == FaceScanSettings::Rescan) { filterMode = FacePipeline::ScanAll; writeMode = FacePipeline::OverwriteUnconfirmed; } else // FaceScanSettings::Merge { filterMode = FacePipeline::ScanAll; writeMode = FacePipeline::NormalWrite; } d->pipeline.plugDatabaseFilter(filterMode); d->pipeline.plugPreviewLoader(); if (settings.useFullCpu) { d->pipeline.plugParallelFaceDetectors(); } else { d->pipeline.plugFaceDetector(); } if (settings.task == FaceScanSettings::DetectAndRecognize) { //d->pipeline.plugRerecognizingDatabaseFilter(); qCDebug(DIGIKAM_GENERAL_LOG) << "recognize algorithm: " << (int)settings.recognizeAlgorithm; d->pipeline.plugFaceRecognizer(); d->pipeline.activeFaceRecognizer(settings.recognizeAlgorithm); } d->pipeline.plugDatabaseWriter(writeMode); d->pipeline.setDetectionAccuracy(settings.accuracy); d->pipeline.construct(); } else // FaceScanSettings::RecognizeMarkedFaces { d->pipeline.plugRerecognizingDatabaseFilter(); d->pipeline.plugFaceRecognizer(); d->pipeline.activeFaceRecognizer(settings.recognizeAlgorithm); d->pipeline.plugDatabaseWriter(FacePipeline::NormalWrite); d->pipeline.setDetectionAccuracy(settings.accuracy); d->pipeline.construct(); } connect(&d->albumListing, SIGNAL(signalItemsInfo(ImageInfoList)), this, SLOT(slotItemsInfo(ImageInfoList))); connect(&d->albumListing, SIGNAL(signalCompleted()), this, SLOT(slotContinueAlbumListing())); connect(&d->pipeline, SIGNAL(finished()), this, SLOT(slotContinueAlbumListing())); connect(&d->pipeline, SIGNAL(processed(FacePipelinePackage)), this, SLOT(slotShowOneDetected(FacePipelinePackage))); connect(&d->pipeline, SIGNAL(skipped(QList)), this, SLOT(slotImagesSkipped(QList))); connect(this, SIGNAL(progressItemCanceled(ProgressItem*)), this, SLOT(slotCancel())); - if (settings.albums.isEmpty() || settings.task == FaceScanSettings::RetrainAll) + if ((settings.albums.isEmpty() && settings.infos.isEmpty()) || + settings.task == FaceScanSettings::RetrainAll) { d->albumTodoList = AlbumManager::instance()->allPAlbums(); } - else + else if (!settings.albums.isEmpty()) { d->albumTodoList = settings.albums; } + else + { + d->infoTodoList = settings.infos; + d->useImageInfos = true; + } } FacesDetector::~FacesDetector() { delete d; } void FacesDetector::slotStart() { MaintenanceTool::slotStart(); setThumbnail(QIcon::fromTheme(QLatin1String("edit-image-face-show")).pixmap(22)); + + if (d->useImageInfos) + { + int total = d->infoTodoList.count(); + qCDebug(DIGIKAM_GENERAL_LOG) << "Total is" << total; + + setTotalItems(total); + + return slotItemsInfo(d->infoTodoList); + } + setUsesBusyIndicator(true); // get total count, cached by AlbumManager - QMap palbumCounts, talbumCounts; + QMap palbumCounts; + QMap talbumCounts; bool hasPAlbums = false; bool hasTAlbums = false; foreach(Album* const album, d->albumTodoList) { if (album->type() == Album::PHYSICAL) { hasPAlbums = true; } else { hasTAlbums = true; } } palbumCounts = AlbumManager::instance()->getPAlbumsCount(); talbumCounts = AlbumManager::instance()->getTAlbumsCount(); if (palbumCounts.isEmpty() && hasPAlbums) { QApplication::setOverrideCursor(Qt::WaitCursor); palbumCounts = CoreDbAccess().db()->getNumberOfImagesInAlbums(); QApplication::restoreOverrideCursor(); } if (talbumCounts.isEmpty() && hasTAlbums) { QApplication::setOverrideCursor(Qt::WaitCursor); talbumCounts = CoreDbAccess().db()->getNumberOfImagesInTags(); QApplication::restoreOverrideCursor(); } - // first, we use the relativeProgressValue map to store absolute counts + // first, we use the progressValueMap map to store absolute counts + + QMap progressValueMap; foreach(Album* const album, d->albumTodoList) { if (album->type() == Album::PHYSICAL) { - d->relativeProgressValue[album] = palbumCounts.value(album->id()); + progressValueMap[album] = palbumCounts.value(album->id()); } else { // this is possibly broken of course because we do not know if images have multiple tags, // but there's no better solution without expensive operation - d->relativeProgressValue[album] = talbumCounts.value(album->id()); + progressValueMap[album] = talbumCounts.value(album->id()); } } // second, calculate (approximate) overall sum - d->total = 0; + int total = 0; - foreach(double count, d->relativeProgressValue) + foreach(int count, progressValueMap) { - d->total += (int)count; + total += count; } - d->total = qMax(1, d->total); - qCDebug(DIGIKAM_GENERAL_LOG) << "Total is" << d->total; - - // third, break absolute to relative values - - for (QMap::iterator it = d->relativeProgressValue.begin() ; it != d->relativeProgressValue.end() ; ++it) - { - it.value() /= double(d->total); - } + total = qMax(1, total); + qCDebug(DIGIKAM_GENERAL_LOG) << "Total is" << total; setUsesBusyIndicator(false); - setTotalItems(d->total); + setTotalItems(total); slotContinueAlbumListing(); } void FacesDetector::slotContinueAlbumListing() { + if (d->useImageInfos) + { + return slotDone(); + } + qCDebug(DIGIKAM_GENERAL_LOG) << d->albumListing.isRunning() << !d->pipeline.hasFinished(); // we get here by the finished signal from both, and want both to have finished to continue if (d->albumListing.isRunning() || !d->pipeline.hasFinished()) { return; } // list can have null pointer if album was deleted recently Album* album = 0; do { if (d->albumTodoList.isEmpty()) { return slotDone(); } album = d->albumTodoList.takeFirst(); } while (!album); d->albumListing.allItemsFromAlbum(album); } void FacesDetector::slotItemsInfo(const ImageInfoList& items) { d->pipeline.process(items); } void FacesDetector::slotDone() { if (d->benchmark) { new BenchmarkMessageDisplay(d->pipeline.benchmarkResult()); } // Switch on scanned for faces flag on digiKam config file. KSharedConfig::openConfig()->group("General Settings").writeEntry("Face Scanner First Run", true); MaintenanceTool::slotDone(); } void FacesDetector::slotCancel() { d->pipeline.shutDown(); MaintenanceTool::slotCancel(); } void FacesDetector::slotImagesSkipped(const QList& infos) { advance(infos.size()); } void FacesDetector::slotShowOneDetected(const FacePipelinePackage& /*package*/) { advance(1); } } // namespace Digikam