diff --git a/NEWS b/NEWS index 6aaf0eb448..6ed16d28c9 100644 --- a/NEWS +++ b/NEWS @@ -1,519 +1,520 @@ digiKam 7.0.0-beta2 - Release date: 2020-01-26 ***************************************************************************************************** NEW FEATURES: FaceManagement: New Neural Network engine based on OpenCV Deep Learning module to detect and recognize faces. FaceManagement: Face Scan dialog contents is now simlified and embeded into left side-bar tab. SlideShow : Add new shuffle mode. HTMLGallery : Add new theme "Html5Responsive". General : Update internal libraw engine to last 201910 snapshot aka next 0.20.0 release (https://www.libraw.org/news/libraw-snapshot-201910) ***************************************************************************************************** BUGFIXES: 001 ==> 384401 - Various recognition algorithm improvements for face detection. 002 ==> 413701 - DigiKam 6.3.0 does not build against current plasma. 003 ==> 413748 - Broken theme on Windows 10 after Digikam update. 004 ==> 413738 - Video Preview changes VLC volume. 005 ==> 382311 - Photos in collapsed groups are incorrectly excluded if first photo in group does not match filter. 006 ==> 396337 - In tag filter view (or any other filitered view), grouped photos should not always have "group" thumbnail 007 ==> 413704 - Filters do not work on hidden grouped images. 007 ==> 413233 - Application crashes when click in Albums left panel. 008 ==> 413759 - Tarball is missing translations. 009 ==> 413879 - Buttons without theme colors. 010 ==> 392015 - Show "Unknown" faces in a more visible and preeminent place in the "People" list. 011 ==> 413837 - Reverse geolocation deletes previous tags from the picture. 012 ==> 376629 - Face tagging dropdown: "Add in persons" adds person not label. 013 ==> 413923 - The peoples list shows just one line of height (one name) when expanded for the first time. 014 ==> 413924 - The face rectangle behavior when show face tags is OFF. 015 ==> 341111 - MYSQL : deleting an image involves "too many" queries. 016 ==> 413938 - Metadata is not written to all pictures in a tag hierarchy. 017 ==> 413916 - Compile Error with lqr on neon. 018 ==> 413972 - align_image_stack and enfuse use only 1 CPU core if called by digiKam plugin, 4 CPU core on command line. 019 ==> 413981 - Refresh has no effect in Preview mode. 020 ==> 413985 - Can't move an album too far down - no treeview scrolling. 021 ==> 412678 - Renaming folder leads to an error. 022 ==> 303239 - GROUP : grouped images are found, but do not show in searches. 023 ==> 321339 - GROUP : suppress display of albums containing only grouped images. 024 ==> 289911 - 23HQ should be split from flickr uploader as a new export tool. 025 ==> 414112 - Rounding problems in Resize Image function. 026 ==> 414052 - Packaging error of digikam-6.4.0.tar.xz, archive file contains a huge number of unnecessary files. 027 ==> 404667 - Bug of proofing for illuminant A and color cast. 028 ==> 414247 - digikam: error while loading shared libraries: libcudart.so.8.0. 029 ==> 392758 - Slideshow with random pictures [patch]. 030 ==> 414300 - Buttons on either side completely unresponsive. 031 ==> 414320 - Performance regression when scanning directories with many sub-directories. 032 ==> 414284 - Improve Setup/Slideshow View Options Layout. 033 ==> 414420 - Date/time in sidecar files for Videos seems to be ignored by digikam. 034 ==> 414340 - RawTherapee plugin. 035 ==> 414473 - Importing problem with M2Ts video files. 036 ==> 414521 - File management is broken. 037 ==> 205406 - Add Javascript to scaling images in html gallery [patch]. 038 ==> 334680 - Allow to limit exported files by type-mime in html gallery. 039 ==> 092462 - Add a new option to limit amount of thumbnails per index page. 040 ==> 136389 - Add new option to show image date and time in html gallery. 041 ==> 305167 - Add back filenames in html gallery. 042 ==> 114216 - Add a new option to export and merge more than one album in html gallery. 043 ==> 414516 - digikam crash when double-clicking on Google Maps when editing geolocation. 044 ==> 414603 - Pictures sort by freehand - drag & drop. 045 ==> 414630 - Shortcut bug in caption (tag). 046 ==> 414484 - Cannot use Rawtherapee or Darktable for raw image import on Windows. 047 ==> 166577 - List of available cameras in search. 048 ==> 414637 - New option for search. 049 ==> 414401 - RawTherapee does not work as Raw Import Tool if both are AppImages. 050 ==> 412067 - I get a error message: "Error while opening the database". 051 ==> 414902 - After using the "healing clone" tool only preview is available from other tools. 052 ==> 402894 - Display of original image. 053 ==> 380345 - Batch converting RAW to JPEG saves as new version. 054 ==> 383716 - "Save Changes" button same as "Save As New Version" Button. 055 ==> 307374 - Wrong image count in album view with versioning. 056 ==> 412961 - All image versions remain visible. 057 ==> 399923 - Segmentation fault during face detection. 058 ==> 392651 - Digikam crashes when Face scanning reaches 29%. 059 ==> 397919 - Segmentation fault during maintenance. 060 ==> 365354 - MYSQL : Application crash on scanning for faces in large picture set. 061 ==> 391014 - Crashes on close. 062 ==> 387821 - Face Recognition and Finding crashs after reaching 50%. 063 ==> 414749 - Export google photos: error transmission date creation. 064 ==> 377127 - Wrong item count on years in Dates View. 065 ==> 350350 - Moving images notifies me moving finished when it did not finish yet. 066 ==> 342191 - digiKam keeps crashing after crash with face-detection and manual tagging at the same time. 067 ==> 309769 - Crash on startup: 'Program received signal SIGILL, Illegal instruction.' (libopencv_nonfree). 068 ==> 286418 - digikam crashed during face recognition. 069 ==> 402470 - Crashed While I Walked Away During Face Detection. 070 ==> 415046 - Facial Recognition crash during scan. 071 ==> 360477 - Crash when adding a new face tag. 072 ==> 351638 - digiKam crash after facemarking. 073 ==> 350599 - Crash after maintenance. 074 ==> 350549 - Massive memory usage when assigning a tag to a recognized face. 075 ==> 312243 - digiKam crash when detected face moved or resized. 076 ==> 329108 - Crash when running Scanning faces/Clear and rebuild all training data. 077 ==> 280958 - Removing non-faces crashes digiKam. 078 ==> 312289 - Face Scan Crash. 079 ==> 285444 - Crash when adding face tag. 080 ==> 328413 - Crash while tagging faces - no background detection in process. 081 ==> 303328 - digiKam crashes repeatedly while tagging faces. 082 ==> 307554 - digiKam crash when scanning faces. 083 ==> 301506 - Crash while Tagging and Grouping Faces. 084 ==> 309306 - Crash during face-recognition. 085 ==> 284137 - digiKam crashed while moving a face tag after rotating a picture. 086 ==> 299173 - Crash during face tagging. 087 ==> 328560 - Crash when attempting to exit digiKam after aborted face recognition. 088 ==> 323828 - Crash when assigning a name to a single unknown face. 089 ==> 344735 - Crash if I name a face. 090 ==> 275688 - Crash during face detection, whilst tagging. 091 ==> 322022 - Faces and crash. 092 ==> 326750 - digiKam sometimes crashes when tagging recogniced faces with names. 093 ==> 314877 - Face Scan Crash. 094 ==> 271791 - digiKam crashes when removing a "face image" from the current list when the list is not yet loaded completely. 095 ==> 270410 - digiKam crashes when confirming faces. 096 ==> 283197 - Crash during tagging faces. 097 ==> 326689 - digiKam crashes while tagging faces. 098 ==> 284398 - Crash while tagging persons. 099 ==> 334158 - digiKam crash while tagging faces. 100 ==> 321851 - Face scan crash but only on multithread. 101 ==> 308393 - Crash while scanning faces. 102 ==> 326570 - digiKam crashes while recognizing/tagging faces. 103 ==> 343014 - Crashed when select another tag (face tag management). 104 ==> 327699 - Crashing while face detection. 105 ==> 308645 - digiKam crashed when I clicked scan faces while another scan was already running. 106 ==> 287961 - Crash while face-tagging pictures and doing import. 107 ==> 317863 - digiKam crashes as detected faces are being assigned to people or being removed while face detection is running. 108 ==> 302354 - Crash finding again faces (probably a duplicate of 262596). 109 ==> 320861 - Crash when adding tag to photo of the face scan result. 110 ==> 326794 - Tagging faces crashed digiKam. 111 ==> 274850 - digiKam crash on face scanning. 112 ==> 283165 - Crash happened while running face recognition. 113 ==> 280521 - digiKam crashes when deselecting two pictures in in quick succession from the face view. 114 ==> 303304 - Crash during face detection. 115 ==> 329596 - digiKam crashes during face recognition. 116 ==> 298599 - digiKam crashed while scaning for faces in the background. 117 ==> 304360 - Crash during face tagging. 118 ==> 280620 - digiKam crashes when tagging multiple non-faces. 119 ==> 302437 - Crash when re-searching for faces. 120 ==> 274727 - Crash on scan of faces. 121 ==> 333582 - Scanning for faces crashes. 122 ==> 290826 - digiKam crashed while tagging faces. 123 ==> 289003 - Crash when trying to face-scan all images. 124 ==> 280618 - digiKam crashes when tagging multiple faces. 125 ==> 329651 - Face detection crashes when reaches 3 GB of Memory, the computer has 6GB and 2 are still free. 126 ==> 294452 - digiKam crash in "Scan collection for faces". 127 ==> 268102 - Crash when finding faces. 128 ==> 323823 - Crash while first face detection after update. 129 ==> 336236 - Crash while tagging faces on more than one image at same time. 130 ==> 279266 - digiKam crashes while trying to tag faces. 131 ==> 312442 - digiKam crashed when editing face tags. 132 ==> 275827 - digiKam crash whilst scanning for faces, starting to enter tag. 133 ==> 330828 - Crash while detecting faces. 134 ==> 324711 - Crash when scaning faces. 135 ==> 323654 - digiKam crashed while i was tagging faces. 136 ==> 283540 - digiKam crashes on entering people tages (face recognition). 137 ==> 277099 - digiKam crash when adding a tag to a face. 138 ==> 296281 - digiKam crashed while manually adding a face. 139 ==> 325526 - Crash while tagging faces. 140 ==> 275637 - Performing multiple scans and recognises causes crash. 141 ==> 289228 - Crash when detecting faces. 142 ==> 317413 - digiKam crashed while tagging faces. 143 ==> 334580 - Face detection crashes digiKam. 144 ==> 301781 - digiKam crashed while scanning photos for faces. 145 ==> 321273 - crash during face scan. 146 ==> 296784 - digiKam crashes while tagging faces. 147 ==> 285517 - digiKam crashed when tagging faces. 148 ==> 290818 - digiKam crash during face scanning. 149 ==> 271375 - digiKam crashed when unchecking face. 150 ==> 317290 - Crashes during face scan. 151 ==> 308575 - digiKam crashes while scanning for faces. 152 ==> 301832 - digiKam crashes a while after starting face detection scan. 153 ==> 300357 - digiKam crashes on Face Recognition scan. 154 ==> 309142 - Face Crash. 155 ==> 279781 - digiKam crashes while using face detection tool. 156 ==> 275387 - digiKam crashes on face recognition. 157 ==> 311934 - digiKam was crashing when I was face-tagging photos. 158 ==> 323428 - Crash while tagging a lot of faces at the same time. 159 ==> 262873 - digiKam crashes on scanning for faces. 160 ==> 280520 - Crash while running a face detection, and marking some of the faces. 161 ==> 322187 - Crash while 'detect and recognize faces'. 162 ==> 334337 - Crash when tagging faces in RAW picture files. 163 ==> 301856 - digiKam crashes during face tagging. 164 ==> 275541 - digiKam crashed while doing face recognition. 165 ==> 324093 - digiKam crashed when I clicked the check mark to assign an existing name to several selected face images. No background tasks were running. 166 ==> 286071 - Crash while adding face tags. 167 ==> 280901 - Crash when rejecting faces in different albums. 168 ==> 290891 - digiKam Crash while Face Recognition. 169 ==> 293418 - Crashes when scanning for faces. 170 ==> 273161 - digiKam: malloc(): smallbin double linked list corrupted. 171 ==> 268046 - Switch foto with face recognition. 172 ==> 277163 - digikam valgrind issues during face recognition testing. 173 ==> 302359 - Crash creating a tag while scanning faces. 174 ==> 307110 - digiKam crashes when manually adding face tags, then moving to next image. 175 ==> 339263 - digiKam crash. 176 ==> 379470 - Crash when performing face detection or recognition on large collection. 177 ==> 284154 - Crash upon exit. 178 ==> 392142 - Use Tensorflow for face and object recognition. 179 ==> 303501 - Double free or corruption during face tagging. 180 ==> 314646 - digikam crash when (tagging) scanning collection for faces. 181 ==> 317450 - Attempting to name a person while face tagging is in progress. 182 ==> 318640 - Face detection crash. 183 ==> 325385 - Face scan and using all processor cores. 184 ==> 325712 - Face tagging has massive memory leak. 185 ==> 326323 - Running Face Scan. 186 ==> 329164 - Changing face tags in an image causes digiKam to eat up all the virtual memory. 187 ==> 331912 - Face detection and recognition dos not work, tags and factags counts for one person are different, memory goes up and up without any result. 188 ==> 334509 - Person Detection. 189 ==> 337936 - Assigning a new person. 190 ==> 342144 - Face detection. 191 ==> 344661 - Face recognition makes digikam fill all the available memory. 192 ==> 345395 - Face Management the Memory and Swap growed to max. 193 ==> 365669 - Face Recognition improvement suggestion. 194 ==> 376901 - Face Recognition Algorithm Improvements. 195 ==> 338072 - digiKam face detection. 196 ==> 387870 - undefined reference to typeinfo for cv::face::FaceRecognizer. 197 ==> 327197 - When add one face tag in mainview/albums/one pictures view digikam and/or opencv fullfill the memory. 198 ==> 353859 - FaceEngine multi threaded ? 199 ==> 342004 - FacesEngine header and pkgconfig files not installed. 200 ==> 406838 - digiKam crashes while labeling unconfirmed faces. 201 ==> 409437 - Crash when doing any face detection. 202 ==> 404853 - digiKam faces engine fails to compile on PowerPC. 203 ==> 405625 - digiKam faces engine fails to compile on PowerPC with AltiVec enabled. 204 ==> 194401 - Face detection / recognition for digiKam for tags. 205 ==> 339823 - Detect and recognice faces crashes. 206 ==> 351077 - Crash during facial detection and recognition. 207 ==> 375317 - MYSQL: digikam crashes during face recognition. 208 ==> 299066 - digiKam crashed while tagging a large amount of people. 209 ==> 268761 - Segfault when tagging people without existing tag in preview mode. 210 ==> 374165 - Tag Change in Menu Person search crashes. 211 ==> 347753 - Surface freezes after some faces tagged. 212 ==> 375945 - Face detection not scanning my images. 213 ==> 343314 - Mass face tagging pictures when writing the tags into the files often crashes at the end of the writing. 214 ==> 345909 - digiKam crashed when face taging multiple photos. 215 ==> 401306 - digiKam doesn't compile with Opencv 4. 216 ==> 376766 - Face detection is using all CPU cores regardless of the checked option. 217 ==> 402320 - Memory hole (>1.5GB resident after 2 minutes) when detecting faces. 218 ==> 389031 - Scanning collection for faces causes produces lots of OpenCV errors. 219 ==> 325331 - MySQL : when adding a new face, tag is created with a new _Digikam_root_ tag in database. 220 ==> 262577 - Scanning collection for new faces (skip already scanned images) does not do anything. 221 ==> 330143 - "Detect and recognize faces" does no detection. 222 ==> 392527 - "Add A Face Tag" Dialogue Is Too Small. 223 ==> 372761 - Face Tag selection needs extra confirm now. 224 ==> 375418 - Glitch in face selection in album view. 225 ==> 281792 - When tagging with 'Return', too many faces are tagged. 226 ==> 282592 - Rejecting multiple faces at a time doesn't work properly. 227 ==> 376681 - Region Coordinates Are Sometimes inf / Large Numbers. 228 ==> 380251 - "Show only face tags..." not working properly. 229 ==> 326538 - When a picture is in portrait, face thumbnails are not rotated. 230 ==> 279208 - After the upgrade to Plasma and digiKam Faces Are Not Detected Anymore. 231 ==> 316856 - I suggest to extend face recognition to text-recognition system. 232 ==> 381378 - Face rectangle from XMP sidecar drawn incorrectly for EXIF rotated images. 233 ==> 326035 - Stepping through previews with "show face tags" enabled does not always show the tags. 234 ==> 326033 - Adding or changing face tag in preview window causes all tags on that preview to "hide". 235 ==> 265022 - UI's handling of People tags is confusing. 236 ==> 262180 - The toggle button to show/hide faces is difficult to see. 237 ==> 316161 - Reuse face tags from another picture. 238 ==> 412999 - Some photos downloaded in previous version of digikam no more recognized as already downloaded. 239 ==> 334215 - Cannot open RAW files from Sony A7R. 240 ==> 340595 - Convertion Sony A7 raw file turns to red the result. 241 ==> 307313 - digiKam uses wrong darkness/saturation values. 242 ==> 315156 - CR2 files from Canon PowerShot G1 X the colours are messed up. 243 ==> 332126 - LibRaw_r_LIBRARIES CMake Error: The following variables are used in this project, but they are set to NOTFOUND. 244 ==> 352996 - digiKam crashes while scanning for new files in Collection. 245 ==> 362779 - Can't decode PEF image from Pentax K-1 (36mp). 246 ==> 364063 - Crash on startup (related to crashing on conversion to DNG?). 247 ==> 221984 - Choosing manual WB does not allow user to tweak the previously selected WB setting. 248 ==> 182611 - Segfault with Samsung S85 RAW images. 249 ==> 178760 - Conversion of Canon .cr2 files broken as used in Darkroom. 250 ==> 364230 - Crash on startup. 251 ==> 244142 - digiKam crash. 252 ==> 362418 - Crashes on launch. 253 ==> 253091 - digiKam will not launch. 254 ==> 338075 - Tagging RAW images for Canon EOS-1Ds corrupts them. 255 ==> 205006 - On first run, digikam crashes while creating the index. 256 ==> 409148 - Sony A7r3 ARW files are displayed blurred in preview. 257 ==> 388339 - Crash when importing Pentax DNG file. 258 ==> 329230 - Crash when tuning a raw image. 259 ==> 253877 - digiKam Crash when loading. 260 ==> 134700 - CR2 thumbnails are not rotated. 261 ==> 090875 - Preview of RAW-Files in album. 262 ==> 143681 - Can't edit/view NEF anymore. 263 ==> 341024 - digiKam crash in a dir with only Canon Raw and JPEG files. 264 ==> 132695 - CR2 RAW files do not open. 265 ==> 339924 - RAW preview using embedded JPG. 266 ==> 142057 - Speed to view raw pictures. 267 ==> 187015 - Libraw breaks RW2 file handling. 268 ==> 126151 - Raw (NEF) thumbnail not correctly showed. 269 ==> 143244 - Error processing RAW files. 270 ==> 235321 - Tried to open X3F file. Was showing up in preview but crashed while opening in editor. 271 ==> 306843 - Raw-pics rotating. 272 ==> 149328 - Let RawEngine use raw decoding options when generating thumbnails. 273 ==> 150872 - Crash during during RAW conversion. 274 ==> 182013 - Sensitivity is not shown for rw2 files. 275 ==> 157619 - Let digiKam use preview images from raw files for more speed. 276 ==> 220322 - Crash when reading nef data: Warning: Exif tag Exif.NikonPreview.JPEGInterchangeFormatLength not encoded. 277 ==> 165176 - Previews of raw pics are not created when "create all previews new" is selected. 278 ==> 149086 - RAF-picture finepix not show in Imageeditor (thumbnails are displayed). 279 ==> 123950 - Crashing on raw files (.nef). 280 ==> 320049 - RawEngine is crashing on decoding some sigma raw files. 281 ==> 277707 - Easy way to convert Raw, to get same image as seen in preview. 282 ==> 146738 - Fuji *.RAF files aren't recognized as RAW files. 283 ==> 331397 - Preview and thumbnails colors are wrong for cr2. 284 ==> 210659 - Inconsistent Save / Save As handling in image editor after raw import. 285 ==> 155950 - Raw file open with action causes two instances. 286 ==> 337601 - digiKam crashed on closing after interrupted raw processing. 287 ==> 219748 - Image editor doesn't import raw images twice. 288 ==> 272725 - Some PEF/jpeg files not recognized as raw/non raw 289 ==> 154922 - Start to use libopenraw instead of libraw. 290 ==> 359949 - Bad canon raw file makes digikam to crash at startup. 291 ==> 101281 - EXIF info from RAW images not woking properly. 292 ==> 342233 - Crash when decoding pentax k-r raw photo. 293 ==> 139550 - Autocorrect levels for raw photos (which are shown too dark). 294 ==> 099437 - Incorrect Libraw option. 295 ==> 155156 - Raw file conversion crash single/batch mode. 296 ==> 146259 - Raw Converter won't convert to 16bit PNG. 297 ==> 151523 - RAW converter crashes on startup. 298 ==> 242479 - Crashes on appling refocus tool to raw image. 299 ==> 361678 - Dng Converter crashes when opening a raw file (*.NEF in my case). 300 ==> 382576 - DNG Image Converter crashed trying to convert a RAW image. 301 ==> 326268 - SONY SLT A58. 302 ==> 140087 - Sony Alpha Super SteadyShot Meta Info. 303 ==> 282116 - DNG Converter fails to convert Nikon NEF to DNG. 304 ==> 270457 - Crash when opening a NIKON-jpg with 1.3 MB. 305 ==> 135011 - Sort images by EXIF date seems buggy for Nikon (or not just Nikon?). 306 ==> 141249 - CANON EOS 5D not support. 307 ==> 240750 - DNG Converter produces black files (Canon 5D mkII) 308 ==> 361660 - DNG Image Converter crashes when converting Canon cr2 file. 309 ==> 211908 - TIF (RAW from Phase One and old Canon, not TIFF/EP) opens as thumbnail. 310 ==> 388222 - high RAM memory consumption of digiKam. 311 ==> 338249 - digiKam uses all free memory and gets terminated. 312 ==> 131277 - Memory leak in image editor. 313 ==> 252443 - digiKam leaves a zombie after quit. doesn't free memory. 314 ==> 321784 - Recreating fingerprints leaks memory. 315 ==> 381877 - digiKam start allocating all memory when scans a new collection. 316 ==> 098227 - Huge memory leak when downloading from camera. 317 ==> 330227 - Image quality sorter leaks memory. 318 ==> 412893 - Application windows are incorrectly magnified in macOS. 319 ==> 413656 - Manage Tags window appears with messed up double size graphics. 320 ==> 092783 - Usabilitiy of RAW file support. 321 ==> 158911 - digiKam crashes before RAW convert. 322 ==> 362870 - DNG Convert crash on convert NEF file. 323 ==> 367859 - DNG Converter crashed after trying to nconvert CR2 file. 324 ==> 369289 - DNG converter crashes when converting Olympus (.ORF) files. 325 ==> 407203 - Crash on trying to convert a .NEF file. 326 ==> 370623 - digiKam converter to DNG report an error while to process NEF image. 327 ==> 354364 - Crash of DNG converter. 328 ==> 338842 - Moving DNG images to another album corrupts DNG properties. 329 ==> 401849 - Cannot Save Current Search. 330 ==> 372972 - Find duplicates "search in drop down" only shows 1 item. 331 ==> 351521 - digiKam crashes when searching by date. 332 ==> 335978 - digiKam crashes when using timeline. 333 ==> 335052 - Crash on looking for duplicate. 334 ==> 333952 - Crashed when trying to search for duplicates. 335 ==> 218022 - Albums are sorted alphabetically within the month. 336 ==> 326495 - Calendar: higher flexibility in the layout. 337 ==> 281848 - Search for images with no goelocation. 338 ==> 283045 - Crash when searching with timeline. 339 ==> 281895 - digiKam crashed the selection date in the calendar. 340 ==> 280760 - Find duplicates should handle raw files more intelligently. 341 ==> 182029 - Duplicate item count not changed after duplicates deleted. 342 ==> 182043 - Duplicates search result in an inconsistent/broken state. 343 ==> 182492 - No photos are displayed when selecting a timeframe in the timeline. 344 ==> 140732 - Show all pictures of year when selecting year in date-tree. 345 ==> 240738 - Batch deletion of duplicate or similar files. 346 ==> 241536 - Reproducible crash when bilding fingerprint. 347 ==> 242438 - Crashes while creating fingerprints. 348 ==> 246500 - Fingerprint. 349 ==> 246635 - Crash when rebuilding fingerprints. 350 ==> 253382 - digiKam crashs creating fingerprints. 351 ==> 265670 - digiKam crashes when generating thumbnails and fingerprints in parallel. 352 ==> 265245 - Crash upon selecting certain month in timeline. 353 ==> 261418 - Improved handling of duplicate images. 354 ==> 263002 - Crash during browsing timeline. 355 ==> 147981 - Ability to move images to different albums from seach results. 356 ==> 149025 - Do not sort images in Search by album. 357 ==> 147407 - Root folders/years should display all child images. 358 ==> 155286 - Crash during duplicate search. 359 ==> 169404 - Color selector in fuzzy search is black. 360 ==> 214665 - Crash when cleaning duplicated images. 361 ==> 243136 - Fingerprints. 362 ==> 247550 - digiKam does not quit gracefully. 363 ==> 406228 - Getting random unextpected 'Database is locked' events. 364 ==> 409884 - digiKam Crash. 365 ==> 413944 - digiKam crashes while album browsing. 366 ==> 134817 - Introduce symlinks for album collection. 367 ==> 149983 - Show recursively sub-album images. 268 ==> 226770 - digiKam edit photo shift+space. 369 ==> 237161 - digiKam crashes on album viewing. 370 ==> 240436 - digiKam crashes when selecting a photo in an album. 371 ==> 291514 - Suggestions for improving face recognition performance. 372 ==> 271679 - digiKam detects but does not recognize faces. 373 ==> 292248 - Recognize faces does nothing. 374 ==> 321297 - Name not set on face recognition run. 375 ==> 314744 - Face do not recognize. 376 ==> 402021 - Face recognition not working. 377 ==> 392518 - Face recognition using the deep learning algo, dont move faces to Unconfirmed. 378 ==> 391671 - Face recognition fails giving a lot of addition effort to correct the errors. 379 ==> 392010 - Face recognition assigns faces to people without confirmation, leading to false positives. 380 ==> 277620 - Face recognition should propose the tagged name as default in the face identification page. 381 ==> 414308 - On a person, be able to view only the news found. 382 ==> 404167 - Improve confirmation process. 383 ==> 247571 - Crash while browsing in album view. 384 ==> 263209 - New Album crash. 385 ==> 275684 - Crash during tagging. 386 ==> 297044 - digiKam crashes when moving images to a new Album. 387 ==> 305108 - Crash during import of images. 388 ==> 317440 - digiKam crashes after deleting a tag. 389 ==> 335708 - Crash on image import. 390 ==> 337839 - I experience many crashes, without precise action. 391 ==> 339720 - Very slow tagging when missing Plasma icons have been used for tags. 392 ==> 343026 - Crashes when downloading. 393 ==> 361084 - Crash while importing. 394 ==> 117561 - Should store hashes of files if file is moved. 395 ==> 186920 - Too many open files. 396 ==> 135051 - digiKam crashes when building database from existing directory. 397 ==> 135689 - New folders not visible. 398 ==> 150181 - digiKam wants to delete the whole database (24.000Images) at startup when USB-Disk with the Photos is not connected. 399 ==> 194630 - digiKam fails to start ? after Plasma update. 400 ==> 202956 - Crashing on start up. 401 ==> 204071 - Just started digiKam and it crashed. 402 ==> 218726 - digiKam always crashes at startup with segmentation fault. 403 ==> 218860 - digiKam crashes when starting from krunner. 404 ==> 220172 - digiKam crash on scanning directories [mem2chunk_check, free_check, QHashData::free_helper]. 405 ==> 242305 - digiKam Crash. 406 ==> 242818 - digiKam crash at startup. 407 ==> 246065 - digiKam crashes at startup. 408 ==> 246534 - digiKam crashes at every start. 409 ==> 250418 - digiKam crashes on startup. 410 ==> 261624 - Moving an album from one collection to another doesn't update the source collection. 411 ==> 338171 - When automatic recognition guesses the same name for multiple faces in one picture, assigning a different name deletes all the face boxes except one. 412 ==> 392016 - Confirmed and unconfirmed faces look the same in a person's face list. 413 ==> 286452 - No way to scan untagged photos for faces, or scan ALL folders. 414 ==> 411732 - UI for assigning people tag is very fragile. 415 ==> 365668 - Face tagger allows text input when hovered over, then does crazy stuff. 416 ==> 413923 - The peoples list shows just one line of height (one name) when expanded for the first time. 417 ==> 326034 - Allow to add "unknown" face tags in Preview mode. 418 ==> 388649 - Face tag rectangle cursor sometimes disappear. 419 ==> 415560 - No default selection for Scan Collection. 420 ==> 415460 - JFIF files have APP0 marker after SOI where there should be APP1. 421 ==> 415582 - People Unknown faces does not decrease to zero. 422 ==> 415599 - Add date to help DNN face recognition for baby/kid/adult distinction. 423 ==> 415602 - How to erase faces rectangles for an album. 424 ==> 316897 - Face Detection improvements by colors filtering and using EXIF orientation. 425 ==> 088895 - Stops after a few percent with: Unknown event: 3. 426 ==> 091548 - Find duplicate images claims no album is selected although one is 427 ==> 101958 - Can not select duplicate images by clicking on a line instead of the select box of 6 pix square. 428 ==> 107095 - Double image removal: Use trashcan. 429 ==> 113557 - digiKam crashes during "Find Duplicate Images" with SIGSEGV. 430 ==> 117578 - Bad UI fpr searching duplicate images. 431 ==> 181698 - Cannot delete fuzzy searches. 432 ==> 181720 - Can't rename fuzzy searches. 433 ==> 183008 - Fuzzy image search requires two clicks to navigate back. 434 ==> 199045 - Find duplicates in a directory/directories. 435 ==> 199732 - Deleting duplicated images crashes digiKam. 436 ==> 222273 - Run fingerprint scan on new images. 437 ==> 231047 - Crash when updating fingerprints on a large photo collection (100GB). 438 ==> 235763 - Reproducible crash, when attempting to rebuild all fingerprints. 439 ==> 167168 - Timeline view shows redundant extra sections. 440 ==> 168004 - Timeline gives zero height column for dates with a single entry. 441 ==> 279674 - Incorporate "event view". 442 ==> 261216 - Debugging doesn´t work with installed. 443 ==> 109022 - Iphoto like calendar search. 444 ==> 109703 - Updating of calendar view in Date panel. 445 ==> 109705 - When quit date panel with day selected no images in other panels. 446 ==> 130230 - Wrong date in header using date-view. 447 ==> 213619 - Add a new view of albums based on due date. 448 ==> 375306 - Add 'Go to album' in search results. 449 ==> 128101 - Crash when selecting "Comments&Tags" tab, after selecting "Search" tab, with no search results selected. 450 ==> 146091 - Displaying raw photos by Tag or Date takes very long to load. 451 ==> 091372 - Make searching for multiple tags possible. 452 ==> 098846 - Searching photos with no tag. 453 ==> 113806 - Is it possible to have the size of the quick search window saved? 454 ==> 114848 - Search dialog: images not rotated correctly. 455 ==> 115536 - Quick search dialog box: wrong attached tips. 456 ==> 133294 - Advanced search dialog - combo box with tag names (when tag is to be matched) doesn't stretch with the dialog. 457 ==> 149555 - Always present search box instead of search by right-clicking and selecting simple or advanced search. 458 ==> 185106 - Advanced search is not saved/restored correctly. 459 ==> 120922 - Clicking on Advanced search crashes application. 460 ==> 141035 - Advanced Search gives error when trying to search by rating. 461 ==> 147429 - "and not" option in search function. 462 ==> 415489 - Win32 7.0.0 Beta 1 Crash On Opening Preview. 463 ==> 407540 - Missing EXIF parameter in DNG when converting Panasonic RW2 images. 464 ==> 399159 - Lenses name lost on converting to DNG. 465 ==> 118396 - Ability to search through image comments. 466 ==> 139283 - IPTC Caption comment in search function 467 ==> 155735 - Make it possible to seach on IPTC-text. 468 ==> 095584 - No indication of the end of download from camera. 469 ==> 179712 - Open image in embeded editor lead to digikam crash. 470 ==> 297293 - Option to use libnotify for non-blocking errors/message. 471 ==> 316928 - Servicing: statut of each servicing option should be searchable. 472 ==> 375521 - Progress bars waste useful space. 473 ==> 218583 - Showfoto customizing toolbar freerotation. 474 ==> 228879 - Geolocation Editor: Missing progress bar. 475 ==> 272158 - More user feedback about background operations. 476 ==> 301064 - Async task UI persists on leaving geolocation UI. 477 ==> 164600 - No picture in view pane. 478 ==> 297295 - Zooming: full picture thumbnail to show position. 479 ==> 160894 - Add new picLens like 3D view mode. 480 ==> 325530 - Preview and Editor return "Failed to Load Image" error when viewing JPEG (only) files. 481 ==> 256309 - Wish to save settings in batch queue manager. 482 ==> 271198 - Make queues saveable and use them as single action. 483 ==> 287407 - Save tools with settings in BQM. 484 ==> 318771 - Saved process don't remember settings in BQM. 485 ==> 320358 - Files randomly fail to process. 486 ==> 342433 - Crashes after tagging a few batches of photos. 487 ==> 171073 - Statistic of database, all pictures? 488 ==> 119228 - Storage of images on removable media. 489 ==> 144724 - Freezing by using NAS. 490 ==> 189362 - After moving the collection on a new HD, Digikam doesn't find it. 491 ==> 249375 - Crash when device with open window is removed. 492 ==> 272918 - digiKam crash after scanning ssh network drive. 493 ==> 275559 - digiKam crashes while browsing over NFS. 494 ==> 415679 - Faces are not recognized. 495 ==> 220903 - Duplicate records in ImageComments table after migration. 496 ==> 267800 - Keywords from IPTC-Metadata are not imported. 497 ==> 280678 - MIGRATION : cannot migrate from sqlite database. 498 ==> 301075 - MySQL : external database empty after migration. 499 ==> 328729 - digiKam crash while switching MySQL to SQLite 500 ==> 329849 - MIGRATION : db conversion fails. 501 ==> 361809 - Migration failed from SQLite to MySQL. 502 ==> 415700 - "Welcome to" screen still mentions v5.0. 503 ==> 415566 - Use existing face rectangles to improve recognition. -504 ==> +504 ==> 415603 - Add "Face Recognition" optional item in toolbar. +505 ==> diff --git a/core/app/views/stack/itemiconview.cpp b/core/app/views/stack/itemiconview.cpp index 6172e72aa4..28396e3dc1 100644 --- a/core/app/views/stack/itemiconview.cpp +++ b/core/app/views/stack/itemiconview.cpp @@ -1,2509 +1,2509 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2002-16-10 * Description : Item icon view interface - Core implementation. * * Copyright (C) 2002-2005 by Renchi Raju * Copyright (C) 2002-2020 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 "itemiconview_p.h" namespace Digikam { ItemIconView::ItemIconView(QWidget* const parent, DModelFactory* 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); const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); 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->leftSideBar->setContentsMargins(0, 0, spacing, 0); d->splitter->setParent(this); // The dock area where the thumbnail bar is allowed to go. d->dockArea = new QMainWindow(this, Qt::Widget); d->dockArea->setContentsMargins(QMargins()); d->splitter->addWidget(d->dockArea); DVBox* const vbox = new DVBox(d->dockArea); d->errorWidget = new DNotificationWidget(vbox); d->errorWidget->setCloseButtonVisible(true); d->errorWidget->setWordWrap(true); d->errorWidget->hide(); connect(d->leftSideBar, SIGNAL(signalChangedTab(QWidget*)), d->errorWidget, SLOT(animatedHide())); d->stackedview = new StackedView(vbox); d->dockArea->setCentralWidget(vbox); 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 ItemPropertiesSideBarDB(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))); connect(d->fuzzySearchSideBar, SIGNAL(signalNofificationError(QString,int)), this, SLOT(slotNofificationError(QString,int))); #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))); connect(d->peopleSideBar, SIGNAL(signalNofificationError(QString,int)), this, SLOT(slotNofificationError(QString,int))); 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))); } ItemIconView::~ItemIconView() { saveViewState(); delete d->labelsSearchHandler; delete d->albumHistory; delete d; } void ItemIconView::applySettings() { foreach (SidebarWidget* const sidebarWidget, d->leftSideBarWidgets) { sidebarWidget->applySettings(); } d->iconView->imageFilterModel()->setVersionItemFilterSettings(VersionItemFilterSettings(ApplicationSettings::instance()->getVersionManagerSettings())); refreshView(); } void ItemIconView::refreshView() { d->rightSideBar->refreshTagsView(); } void ItemIconView::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(ItemInfo)), this, SLOT(slotTogglePreviewMode(ItemInfo))); connect(d->iconView, SIGNAL(fullscreenRequested(ItemInfo)), this, SLOT(slotSlideShowManualFrom(ItemInfo))); 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*,ItemInfo,QList,ItemFilterModel*)), this, SLOT(slotShowContextMenuOnInfo(QContextMenuEvent*,ItemInfo,QList,ItemFilterModel*))); connect(d->iconView, SIGNAL(signalShowGroupContextMenu(QContextMenuEvent*,QList,ItemFilterModel*)), this, SLOT(slotShowGroupContextMenu(QContextMenuEvent*,QList,ItemFilterModel*))); // -- TableView Connections ----------------------------------- connect(d->tableView, SIGNAL(signalPreviewRequested(ItemInfo)), this, SLOT(slotTogglePreviewMode(ItemInfo))); 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*,ItemInfo,QList,ItemFilterModel*)), this, SLOT(slotShowContextMenuOnInfo(QContextMenuEvent*,ItemInfo,QList,ItemFilterModel*))); // TableView::signalItemsChanged is emitted when something changes in the model that // ItemIconView 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 --------------------------------- ItemAlbumFilterModel* const model = d->iconView->imageAlbumFilterModel(); connect(d->filterWidget, SIGNAL(signalTagFilterChanged(QList,QList,ItemFilterSettings::MatchingCondition,bool,QList,QList)), d->iconView->imageFilterModel(), SLOT(setTagFilter(QList,QList,ItemFilterSettings::MatchingCondition,bool,QList,QList))); connect(d->filterWidget, SIGNAL(signalRatingFilterChanged(int,ItemFilterSettings::RatingCondition,bool)), model, SLOT(setRatingFilter(int,ItemFilterSettings::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(ItemFilterSettings::GeolocationCondition)), model, SLOT(setGeolocationFilter(ItemFilterSettings::GeolocationCondition))); // -- Preview image widget Connections ------------------------ connect(d->stackedview, SIGNAL(signalNextItem()), this, SLOT(slotNextItem())); connect(d->stackedview, SIGNAL(signalPrevItem()), this, SLOT(slotPrevItem())); connect(d->stackedview, SIGNAL(signalDeleteItem()), this, SLOT(slotImageDelete())); connect(d->stackedview, SIGNAL(signalViewModeChanged()), this, SLOT(slotViewModeChanged())); connect(d->stackedview, SIGNAL(signalEscapePreview()), this, SLOT(slotEscapePreview())); connect(d->stackedview, SIGNAL(signalSlideShowCurrent()), this, SLOT(slotSlideShowManualFromCurrent())); connect(d->stackedview, SIGNAL(signalZoomFactorChanged(double)), this, SLOT(slotZoomFactorChanged(double))); connect(d->stackedview, SIGNAL(signalAddToExistingQueue(int)), this, SLOT(slotImageAddToExistingQueue(int))); connect(d->stackedview, SIGNAL(signalGotoAlbumAndItem(ItemInfo)), this, SLOT(slotGotoAlbumAndItem(ItemInfo))); connect(d->stackedview, SIGNAL(signalGotoDateAndItem(ItemInfo)), this, SLOT(slotGotoDateAndItem(ItemInfo))); 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(ItemInfoList,ItemInfoList)), d->albumHistory, SLOT(slotImageSelected(ItemInfoList))); connect(d->iconView, SIGNAL(currentChanged(ItemInfo)), d->albumHistory, SLOT(slotCurrentChange(ItemInfo))); 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(setSelectedItemInfos(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(ItemInfo)), d->iconView, SLOT(hintAt(ItemInfo))); connect(d->rightSideBar->getFiltersHistoryTab(), SIGNAL(actionTriggered(ItemInfo)), this, SLOT(slotGotoAlbumAndItem(ItemInfo))); } void ItemIconView::connectIconViewFilter(FilterStatusBar* const filterbar) { ItemAlbumFilterModel* const model = d->iconView->imageAlbumFilterModel(); connect(model, SIGNAL(filterMatches(bool)), filterbar, SLOT(slotFilterMatches(bool))); connect(model, SIGNAL(filterSettingsChanged(ItemFilterSettings)), filterbar, SLOT(slotFilterSettingsChanged(ItemFilterSettings))); connect(filterbar, SIGNAL(signalResetFilters()), d->filterWidget, SLOT(slotResetFilters())); connect(filterbar, SIGNAL(signalPopupFiltersView()), this, SLOT(slotPopupFiltersView())); } void ItemIconView::slotPopupFiltersView() { d->rightSideBar->setActiveTab(d->filterWidget); d->filterWidget->setFocusToTextFilter(); } void ItemIconView::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 ItemIconView::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 = nullptr; 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 ItemIconView::leftSidebarWidgets() const { return d->leftSideBarWidgets; } QList ItemIconView::allUrls(bool grouping) const { /// @todo This functions seems not to be used anywhere right now return allInfo(grouping).toImageUrlList(); } QList ItemIconView::selectedUrls(bool grouping) const { return selectedInfoList(false, grouping).toImageUrlList(); } QList ItemIconView::selectedUrls(const ApplicationSettings::OperationType type) const { return selectedInfoList(type).toImageUrlList(); } void ItemIconView::showSideBars() { d->leftSideBar->restore(); d->rightSideBar->restore(); } void ItemIconView::hideSideBars() { d->leftSideBar->backup(); d->rightSideBar->backup(); } void ItemIconView::toggleLeftSidebar() { d->leftSideBar->isExpanded() ? d->leftSideBar->shrink() : d->leftSideBar->expand(); } void ItemIconView::toggleRightSidebar() { d->rightSideBar->isExpanded() ? d->rightSideBar->shrink() : d->rightSideBar->expand(); } void ItemIconView::previousLeftSideBarTab() { d->leftSideBar->activePreviousTab(); } void ItemIconView::nextLeftSideBarTab() { d->leftSideBar->activeNextTab(); } void ItemIconView::previousRightSideBarTab() { d->rightSideBar->activePreviousTab(); } void ItemIconView::nextRightSideBarTab() { d->rightSideBar->activeNextTab(); } void ItemIconView::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 ItemIconView::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 ItemIconView::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 ItemIconView::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 ItemIconView::slotSelectItemByUrl(const QUrl& url) { /// @todo This functions seems not to be used anywhere right now /// @todo Adapt to TableView d->iconView->toIndex(url); } void ItemIconView::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 ItemIconView::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 ItemIconView::slotNewAlbum() { // TODO use the selection model of the view instead d->albumModificationHelper->slotAlbumNew(d->albumFolderSideBar->currentAlbum()); } void ItemIconView::slotDeleteAlbum() { d->albumModificationHelper->slotAlbumDelete(d->albumFolderSideBar->currentAlbum()); } void ItemIconView::slotRenameAlbum() { d->albumModificationHelper->slotAlbumRename(d->albumFolderSideBar->currentAlbum()); } void ItemIconView::slotNewTag() { QList talbums = AlbumManager::instance()->currentTAlbums(); if (!talbums.isEmpty()) d->tagModificationHelper->slotTagNew(talbums.first()); } void ItemIconView::slotDeleteTag() { QList talbums = AlbumManager::instance()->currentTAlbums(); if (!talbums.isEmpty()) d->tagModificationHelper->slotTagDelete(talbums.first()); } void ItemIconView::slotEditTag() { QList talbums = AlbumManager::instance()->currentTAlbums(); if (!talbums.isEmpty()) d->tagModificationHelper->slotTagEdit(talbums.first()); } void ItemIconView::slotOpenTagsManager() { TagsManager* const tagMngr = TagsManager::instance(); tagMngr->show(); tagMngr->activateWindow(); tagMngr->raise(); } void ItemIconView::slotAssignTag() { d->rightSideBar->setActiveTab(d->rightSideBar->imageDescEditTab()); d->rightSideBar->imageDescEditTab()->setFocusToNewTagEdit(); } void ItemIconView::slotNewKeywordSearch() { slotLeftSideBarActivate(d->searchSideBar); d->searchSideBar->newKeywordSearch(); } void ItemIconView::slotNewAdvancedSearch() { slotLeftSideBarActivate(d->searchSideBar); d->searchSideBar->newAdvancedSearch(); } void ItemIconView::slotNewDuplicatesSearch(PAlbum* album) { slotLeftSideBarActivate(d->fuzzySearchSideBar); d->fuzzySearchSideBar->newDuplicatesSearch(album); } void ItemIconView::slotNewDuplicatesSearch(const QList& albums) { slotLeftSideBarActivate(d->fuzzySearchSideBar); d->fuzzySearchSideBar->newDuplicatesSearch(albums); } void ItemIconView::slotNewDuplicatesSearch(const QList& albums) { slotLeftSideBarActivate(d->fuzzySearchSideBar); d->fuzzySearchSideBar->newDuplicatesSearch(albums); } void ItemIconView::slotAlbumsCleared() { emit signalAlbumSelected(nullptr); } void ItemIconView::slotAlbumHistoryBack(int steps) { QList albums; QWidget* widget = nullptr; d->albumHistory->back(albums, &widget, steps); changeAlbumFromHistory(albums, widget); } void ItemIconView::slotAlbumHistoryForward(int steps) { QList albums; QWidget* widget = nullptr; d->albumHistory->forward(albums, &widget, steps); changeAlbumFromHistory(albums , widget); } // TODO update, use SideBarWidget instead of QWidget void ItemIconView::changeAlbumFromHistory(const 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 ItemIconView::clearHistory() { d->albumHistory->clearHistory(); d->parent->enableAlbumBackwardHistory(false); d->parent->enableAlbumForwardHistory(false); } void ItemIconView::getBackwardHistory(QStringList& titles) { d->albumHistory->getBackwardHistory(titles); for (int i = 0 ; i < titles.size() ; ++i) { titles[i] = d->userPresentableAlbumTitle(titles.at(i)); } } void ItemIconView::getForwardHistory(QStringList& titles) { d->albumHistory->getForwardHistory(titles); for (int i = 0 ; i < titles.size() ; ++i) { titles[i] = d->userPresentableAlbumTitle(titles.at(i)); } } void ItemIconView::slotGotoAlbumAndItem(const ItemInfo& 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 ItemIconView::slotGotoDateAndItem(const ItemInfo& 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 ItemIconView::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 ItemIconView::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 ItemIconView::slotAlbumSelected(const QList& albums) { emit signalNoCurrentItem(); emit signalAlbumSelected(nullptr); if (albums.isEmpty() || !albums.first()) { d->iconView->openAlbum(QList()); #ifdef HAVE_MARBLE d->mapView->openAlbum(nullptr); #endif // HAVE_MARBLE slotTogglePreviewMode(ItemInfo()); 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) { slotTogglePreviewMode(ItemInfo()); QUrl url = palbum->fileUrl().adjusted(QUrl::StripTrailingSlash); d->trashView->model()->loadItemsForCollection(url.toLocalFile()); d->stackedview->setViewMode(StackedView::TrashViewMode); d->filterWidget->setEnabled(false); } } else { switch (viewMode()) { case StackedView::PreviewImageMode: case StackedView::MediaPlayerMode: case StackedView::WelcomePageMode: case StackedView::TrashViewMode: slotTogglePreviewMode(ItemInfo()); break; default: break; } d->filterWidget->setEnabled(true); } } void ItemIconView::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; } QList urls = selectedInfoList(true, true).toImageUrlList(); if (!urls.isEmpty()) { DFileOperations::openInFileManager(urls); } else { PAlbum* const palbum = dynamic_cast(album); if (palbum) { QUrl url(QUrl::fromLocalFile(palbum->folderPath())); DFileOperations::openInFileManager(QList() << url); } } } void ItemIconView::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 tool2 = new NewItemsFinder(NewItemsFinder::ScheduleCollectionScan, QStringList() << static_cast(album)->folderPath()); connect(tool2, SIGNAL(signalComplete()), this, SLOT(slotAlbumRefreshComplete())); tool2->start(); } break; } } void ItemIconView::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 ItemIconView::slotImageSelected() { // delay to slotDispatchImageSelected d->needDispatchSelection = true; d->selectionTimer->start(); switch (viewMode()) { case StackedView::TrashViewMode: emit signalTrashSelectionChanged(d->trashView->statusBarText()); break; case StackedView::TableViewMode: emit signalSelectionChanged(d->tableView->numberOfSelectedItems()); break; default: emit signalSelectionChanged(d->iconView->numberOfSelectedIndexes()); } } void ItemIconView::slotDispatchImageSelected() { if (viewMode() == StackedView::TrashViewMode) { d->rightSideBar->itemChanged(d->trashView->lastSelectedItemUrl()); return; } if (d->needDispatchSelection) { // the list of ItemInfos of currently selected items, currentItem first const ItemInfoList list = selectedInfoList(true, true); const ItemInfoList allImages = allInfo(true); if (list.isEmpty()) { d->stackedview->setPreviewItem(); emit signalImageSelected(list, allImages); emit signalNoCurrentItem(); } else { d->rightSideBar->itemChanged(list); ItemInfo previousInfo; ItemInfo 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 ItemIconView::zoomMin() const { return d->stackedview->zoomMin(); } double ItemIconView::zoomMax() const { return d->stackedview->zoomMax(); } void ItemIconView::setZoomFactor(double zoom) { d->stackedview->setZoomFactorSnapped(zoom); } void ItemIconView::slotZoomFactorChanged(double zoom) { toggleZoomActions(); emit signalZoomChanged(zoom); } void ItemIconView::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 ItemIconView::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 ItemIconView::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 ItemIconView::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 ItemIconView::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 ItemIconView::slotZoomTo100Percents() { if (viewMode() == StackedView::PreviewImageMode) { d->stackedview->toggleFitToWindowOr100(); } } void ItemIconView::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 ItemIconView::slotAlbumPropsEdit() { d->albumModificationHelper->slotAlbumEdit(d->albumManager->currentPAlbum()); } void ItemIconView::slotAlbumWriteMetadata() { Album* const album = d->albumManager->currentAlbums().first(); if (!album) { return; } MetadataSynchronizer* const tool = new MetadataSynchronizer(AlbumList() << album, MetadataSynchronizer::WriteFromDatabaseToFile); tool->start(); } void ItemIconView::slotAlbumReadMetadata() { Album* const album = d->albumManager->currentAlbums().first(); if (!album) { return; } MetadataSynchronizer* const tool = new MetadataSynchronizer(AlbumList() << album, MetadataSynchronizer::ReadFromFileToDatabase); tool->start(); } void ItemIconView::slotImageWriteMetadata() { const ItemInfoList selected = selectedInfoList(ApplicationSettings::Metadata); MetadataSynchronizer* const tool = new MetadataSynchronizer(selected, MetadataSynchronizer::WriteFromDatabaseToFile); tool->start(); } void ItemIconView::slotImageReadMetadata() { const ItemInfoList selected = selectedInfoList(ApplicationSettings::Metadata); MetadataSynchronizer* const tool = new MetadataSynchronizer(selected, MetadataSynchronizer::ReadFromFileToDatabase); tool->start(); } // ---------------------------------------------------------------- void ItemIconView::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(ItemInfo()); } void ItemIconView::slotMapWidgetView() { d->stackedview->setViewMode(StackedView::MapWidgetMode); } void ItemIconView::slotTableView() { d->stackedview->setViewMode(StackedView::TableViewMode); } void ItemIconView::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 ItemIconView::slotImagePreview() { slotTogglePreviewMode(currentInfo()); } /** * @brief This method toggles between AlbumView/MapWidgetView and ImagePreview modes, depending on the context. */ void ItemIconView::slotTogglePreviewMode(const ItemInfo& 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, ItemInfo(), ItemInfo()); } } 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 ItemIconView::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 ItemIconView::slotImageFindSimilar() { const ItemInfo current = currentInfo(); if (!current.isNull()) { d->fuzzySearchSideBar->newSimilarSearch(current); slotLeftSideBarActivate(d->fuzzySearchSideBar); } } void ItemIconView::slotImageScanForFaces() { FaceScanSettings settings; settings.accuracy = ApplicationSettings::instance()->getFaceDetectionAccuracy(); settings.recognizeAlgorithm = RecognitionDatabase::RecognizeAlgorithm::DNN; // Default now change to DNN - settings.task = FaceScanSettings::Detect; + 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 ItemIconView::slotRefreshImagePreview() { if (viewMode() == StackedView::PreviewImageMode) { d->stackedview->imagePreviewView()->reload(); } } void ItemIconView::slotImageRename() { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->rename(); break; default: d->iconView->rename(); } } void ItemIconView::slotImageDelete() { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->slotDeleteSelected(ItemViewUtilities::DeleteUseTrash); break; default: d->iconView->deleteSelected(ItemViewUtilities::DeleteUseTrash); } } void ItemIconView::slotImageDeletePermanently() { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->slotDeleteSelected(ItemViewUtilities::DeletePermanently); break; default: d->iconView->deleteSelected(ItemViewUtilities::DeletePermanently); } } void ItemIconView::slotImageDeletePermanentlyDirectly() { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->slotDeleteSelectedWithoutConfirmation(ItemViewUtilities::DeletePermanently); break; default: d->iconView->deleteSelectedDirectly(ItemViewUtilities::DeletePermanently); } } void ItemIconView::slotImageTrashDirectly() { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->slotDeleteSelectedWithoutConfirmation(ItemViewUtilities::DeleteUseTrash); break; default: d->iconView->deleteSelectedDirectly(ItemViewUtilities::DeleteUseTrash); } } void ItemIconView::slotSelectAll() { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->selectAll(); break; default: d->iconView->selectAll(); } } void ItemIconView::slotSelectNone() { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->clearSelection(); break; default: d->iconView->clearSelection(); } } void ItemIconView::slotSelectInvert() { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->invertSelection(); break; default: d->iconView->invertSelection(); } } void ItemIconView::slotSortImages(int sortRole) { ApplicationSettings* const settings = ApplicationSettings::instance(); if (!settings) { return; } settings->setImageSortOrder(sortRole); d->iconView->imageFilterModel()->setSortRole((ItemSortSettings::SortRole) sortRole); settings->emitSetupChanged(); } void ItemIconView::slotSortImagesOrder(int order) { ApplicationSettings* const settings = ApplicationSettings::instance(); if (!settings) { return; } settings->setImageSorting(order); d->iconView->imageFilterModel()->setSortOrder((ItemSortSettings::SortOrder) order); settings->emitSetupChanged(); } void ItemIconView::slotSeparateImages(int categoryMode) { ApplicationSettings* const settings = ApplicationSettings::instance(); if (!settings) { return; } settings->setImageSeparationMode(categoryMode); d->iconView->imageFilterModel()->setCategorizationMode((ItemSortSettings::CategorizationMode) categoryMode); } void ItemIconView::slotImageSeparationSortOrder(int order) { ApplicationSettings* const settings = ApplicationSettings::instance(); if (!settings) { return; } settings->setImageSeparationSortOrder(order); d->iconView->imageFilterModel()->setCategorizationSortOrder((ItemSortSettings::SortOrder) order); } void ItemIconView::slotMoveSelectionToAlbum() { d->utilities->createNewAlbumForInfos(selectedInfoList(false, true), currentAlbum()); } void ItemIconView::slotImagePaste() { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->slotPaste(); break; default: d->iconView->paste(); } } void ItemIconView::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 ItemIconView::toggleTag(int tagID) { ItemInfoList tagToRemove, tagToAssign; const ItemInfoList selectedList = selectedInfoList(ApplicationSettings::Metadata); foreach (const ItemInfo& 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 ItemIconView::slotAssignPickLabel(int pickId) { FileActionMngr::instance()->assignPickLabel(selectedInfoList(ApplicationSettings::Metadata), pickId); } void ItemIconView::slotAssignColorLabel(int colorId) { FileActionMngr::instance()->assignColorLabel(selectedInfoList(ApplicationSettings::Metadata), colorId); } void ItemIconView::slotAssignRating(int rating) { FileActionMngr::instance()->assignRating(selectedInfoList(ApplicationSettings::Metadata), rating); } void ItemIconView::slotAssignTag(int tagID) { FileActionMngr::instance()->assignTags(selectedInfoList(ApplicationSettings::Metadata), QList() << tagID); } void ItemIconView::slotRemoveTag(int tagID) { FileActionMngr::instance()->removeTags(selectedInfoList(ApplicationSettings::Metadata), QList() << tagID); } void ItemIconView::slotSlideShowAll() { slideShow(allInfo(ApplicationSettings::Slideshow)); } void ItemIconView::slotSlideShowSelection() { slideShow(selectedInfoList(ApplicationSettings::Slideshow)); } void ItemIconView::slotSlideShowRecursive() { QList albumList = AlbumManager::instance()->currentAlbums(); Album* album = nullptr; 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 ItemIconView::slotSlideShowManualFromCurrent() { slotSlideShowManualFrom(currentInfo()); } void ItemIconView::slotSlideShowManualFrom(const ItemInfo& 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 ItemIconView::slideShow(const ItemInfoList& infoList) { SlideShowBuilder* const builder = new SlideShowBuilder(infoList); connect(builder, SIGNAL(signalComplete(SlideShowSettings)), this, SLOT(slotSlideShowBuilderComplete(SlideShowSettings))); builder->run(); } void ItemIconView::slotSlideShowBuilderComplete(const SlideShowSettings& settings) { QPointer slide = new SlideShow(new DBInfoIface(this, QList()), 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 ItemIconView::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 ItemIconView::setRecurseAlbums(bool recursive) { d->iconView->imageAlbumModel()->setRecurseAlbums(recursive); } void ItemIconView::setRecurseTags(bool recursive) { d->iconView->imageAlbumModel()->setRecurseTags(recursive); } void ItemIconView::setAllGroupsOpen(bool open) { if (!d->iconView->getFaceMode()) { d->iconView->imageFilterModel()->setAllGroupsOpen(open); } ApplicationSettings::instance()->setAllGroupsOpen(open); } void ItemIconView::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 ItemIconView::slotImageChangeFailed(const QString& message, const QStringList& fileNames) { if (fileNames.isEmpty()) { return; } DMessageBox::showInformationList(QMessageBox::Critical, qApp->activeWindow(), qApp->applicationName(), message, fileNames); } void ItemIconView::slotLeftSideBarActivateAlbums() { d->leftSideBar->setActiveTab(d->albumFolderSideBar); } void ItemIconView::slotLeftSideBarActivateTags() { d->leftSideBar->setActiveTab(d->tagViewSideBar); } void ItemIconView::slotLeftSideBarActivate(SidebarWidget* widget) { d->leftSideBar->setActiveTab(widget); } void ItemIconView::slotLeftSideBarActivate(QWidget* widget) { slotLeftSideBarActivate(static_cast(widget)); } void ItemIconView::slotRightSideBarActivateTitles() { d->rightSideBar->setActiveTab(d->rightSideBar->imageDescEditTab()); d->rightSideBar->imageDescEditTab()->setFocusToTitlesEdit(); } void ItemIconView::slotRightSideBarActivateComments() { d->rightSideBar->setActiveTab(d->rightSideBar->imageDescEditTab()); d->rightSideBar->imageDescEditTab()->setFocusToCommentsEdit(); } void ItemIconView::slotRightSideBarActivateAssignedTags() { d->rightSideBar->setActiveTab(d->rightSideBar->imageDescEditTab()); d->rightSideBar->imageDescEditTab()->activateAssignedTagsButton(); } void ItemIconView::slotRatingChanged(const QUrl& url, int rating) { rating = qMin(RatingMax, qMax(RatingMin, rating)); ItemInfo info = ItemInfo::fromUrl(url); if (!info.isNull()) { FileActionMngr::instance()->assignRating(info, rating); } } void ItemIconView::slotColorLabelChanged(const QUrl& url, int color) { ItemInfo info = ItemInfo::fromUrl(url); if (!info.isNull()) { FileActionMngr::instance()->assignColorLabel(info, color); } } void ItemIconView::slotPickLabelChanged(const QUrl& url, int pick) { ItemInfo info = ItemInfo::fromUrl(url); if (!info.isNull()) { FileActionMngr::instance()->assignPickLabel(info, pick); } } void ItemIconView::slotToggleTag(const QUrl& url, int tagID) { ItemInfo info = ItemInfo::fromUrl(url); if (!info.isNull()) { if (info.tagIds().contains(tagID)) FileActionMngr::instance()->removeTag(info, tagID); else FileActionMngr::instance()->assignTag(info, tagID); } } bool ItemIconView::hasCurrentItem() const { return !currentInfo().isNull(); } void ItemIconView::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 ItemIconView::slotImageExifOrientation(int orientation) { FileActionMngr::instance()->setExifOrientation( selectedInfoList(ApplicationSettings::Metadata), orientation); } void ItemIconView::imageTransform(MetaEngineRotation::TransformationAction transform) { FileActionMngr::instance()->transform( selectedInfoList(ApplicationSettings::Metadata), transform); } ItemInfo ItemIconView::currentInfo() const { switch (viewMode()) { case StackedView::TableViewMode: return d->tableView->currentInfo(); #ifdef HAVE_MARBLE case StackedView::MapWidgetMode: return d->mapView->currentItemInfo(); #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 ItemInfo(); } } Album* ItemIconView::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 nullptr; } } ItemInfoList ItemIconView::selectedInfoList(const bool currentFirst, const bool grouping) const { switch (viewMode()) { case StackedView::TableViewMode: if (currentFirst) { return d->tableView->selectedItemInfosCurrentFirst(grouping); } return d->tableView->selectedItemInfos(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->selectedItemInfosCurrentFirst(grouping); } return d->iconView->selectedItemInfos(grouping); default: return ItemInfoList(); } } ItemInfoList ItemIconView::selectedInfoList(const ApplicationSettings::OperationType type, const bool currentFirst) const { return selectedInfoList(currentFirst, selectedNeedGroupResolving(type)); } ItemInfoList ItemIconView::allInfo(const bool grouping) const { switch (viewMode()) { case StackedView::TableViewMode: return d->tableView->allItemInfos(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->allItemInfos(grouping); default: return ItemInfoList(); } } ItemInfoList ItemIconView::allInfo(const ApplicationSettings::OperationType type) const { return allInfo(allNeedGroupResolving(type)); } bool ItemIconView::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 ItemIconView::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 ItemIconView::currentUrl() const { const ItemInfo cInfo = currentInfo(); return cInfo.fileUrl(); } void ItemIconView::slotSetCurrentWhenAvailable(const qlonglong id) { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->slotSetCurrentWhenAvailable(id); break; default: d->iconView->setCurrentWhenAvailable(id); } } void ItemIconView::slotAwayFromSelection() { switch (viewMode()) { case StackedView::TableViewMode: d->tableView->slotAwayFromSelection(); break; default: d->iconView->awayFromSelection(); } } StackedView::StackedViewMode ItemIconView::viewMode() const { return d->stackedview->viewMode(); } void ItemIconView::slotSetupMetadataFilters(int tab) { Setup::execMetadataFilters(this, tab); } void ItemIconView::toggleFullScreen(bool set) { d->stackedview->imagePreviewView()->toggleFullScreen(set); } void ItemIconView::setToolsIconView(DCategorizedView* const view) { d->rightSideBar->appendTab(view, QIcon::fromTheme(QLatin1String("document-edit")), i18n("Tools")); } void ItemIconView::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 ItemIconView::slotShowContextMenuOnInfo(QContextMenuEvent* event, const ItemInfo& info, const QList& extraGroupingActions, ItemFilterModel* imageFilterModel) { QList selectedImageIds = selectedInfoList(true, true).toImageIdList(); // -------------------------------------------------------- QMenu menu(this); ContextMenuHelper cmHelper(&menu); cmHelper.setItemFilterModel(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(ItemInfo)), this, SLOT(slotGotoAlbumAndItem(ItemInfo))); connect(&cmHelper, SIGNAL(signalGotoAlbum(ItemInfo)), d->albumHistory, SLOT(slotClearSelectPAlbum(ItemInfo))); connect(&cmHelper, SIGNAL(signalGotoDate(ItemInfo)), this, SLOT(slotGotoDateAndItem(ItemInfo))); connect(&cmHelper, SIGNAL(signalSetThumbnail(ItemInfo)), this, SLOT(slotSetAsAlbumThumbnail(ItemInfo))); 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(signalCreateGroupByTimelapse()), this, SLOT(slotCreateGroupByTimelapseFromSelection())); 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 ItemIconView::slotShowGroupContextMenu(QContextMenuEvent* event, const QList& selectedInfos, ItemFilterModel* imageFilterModel) { QList selectedImageIDs; foreach (const ItemInfo& info, selectedInfos) { selectedImageIDs << info.id(); } QMenu popmenu(this); ContextMenuHelper cmhelper(&popmenu); cmhelper.setItemFilterModel(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(signalCreateGroupByTimelapse()), this, SLOT(slotCreateGroupByTimelapseFromSelection())); connect(&cmhelper, SIGNAL(signalUngroup()), this, SLOT(slotUngroupSelected())); connect(&cmhelper, SIGNAL(signalRemoveFromGroup()), this, SLOT(slotRemoveSelectedFromGroup())); cmhelper.exec(event->globalPos()); } void ItemIconView::slotSetAsAlbumThumbnail(const ItemInfo& info) { d->utilities->setAsAlbumThumbnail(currentAlbum(), info); } void ItemIconView::slotCreateGroupFromSelection() { FileActionMngr::instance()->addToGroup(currentInfo(), selectedInfoList(false, true)); } void ItemIconView::slotCreateGroupByTimeFromSelection() { d->utilities->createGroupByTimeFromInfoList(selectedInfoList(false, true)); } void ItemIconView::slotCreateGroupByFilenameFromSelection() { d->utilities->createGroupByFilenameFromInfoList(selectedInfoList(false, true)); } void ItemIconView::slotCreateGroupByTimelapseFromSelection() { d->utilities->createGroupByTimelapseFromInfoList(selectedInfoList(false, true)); } void ItemIconView::slotRemoveSelectedFromGroup() { FileActionMngr::instance()->removeFromGroup(selectedInfoList(false, true)); } void ItemIconView::slotUngroupSelected() { FileActionMngr::instance()->ungroup(selectedInfoList(false, true)); } void ItemIconView::slotNofificationError(const QString& message, int type) { d->errorWidget->setMessageType((DNotificationWidget::MessageType)type); d->errorWidget->setText(message); d->errorWidget->animatedShowTemporized(15000); // Notification will be closed automatically in 15s } } // namespace Digikam diff --git a/core/libs/album/treeview/albumselectiontreeview.cpp b/core/libs/album/treeview/albumselectiontreeview.cpp index 1c2343ee32..7ba8464665 100644 --- a/core/libs/album/treeview/albumselectiontreeview.cpp +++ b/core/libs/album/treeview/albumselectiontreeview.cpp @@ -1,404 +1,404 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2005-05-06 * Description : Albums folder view. * * Copyright (C) 2005-2006 by Joern Ahrens * Copyright (C) 2006-2020 by Gilles Caulier * Copyright (C) 2009-2012 by Andi Clemens * Copyright (C) 2009-2011 by Johannes Wienke * * 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 "albumselectiontreeview.h" // Qt includes #include #include #include #include // KDE includes #include // Local includes #include "digikam_debug.h" #include "tagscache.h" #include "albummanager.h" #include "facescansettings.h" #include "applicationsettings.h" #include "contextmenuhelper.h" #include "itemviewtooltip.h" #include "tooltipfiller.h" #include "thumbsgenerator.h" #include "newitemsfinder.h" #include "facesdetector.h" #include "coredbaccess.h" #include "coredb.h" namespace Digikam { class Q_DECL_HIDDEN AlbumViewToolTip: public ItemViewToolTip { public: explicit AlbumViewToolTip(AlbumSelectionTreeView* const view) : ItemViewToolTip(view) { } AlbumSelectionTreeView* view() const { return static_cast(ItemViewToolTip::view()); } protected: virtual QString tipContents() { PAlbum* const album = view()->albumForIndex(currentIndex()); return (ToolTipFiller::albumTipContents(album, view()->albumModel()->albumCount(album))); } }; // ---------------------------------------------------------------------------------------------------- class Q_DECL_HIDDEN AlbumSelectionTreeView::Private { public: explicit Private() : enableToolTips(false), albumModificationHelper(nullptr), toolTip(nullptr), renameAction(nullptr), resetIconAction(nullptr), findDuplAction(nullptr), scanFacesAction(nullptr), repairHiddenAction(nullptr), rebuildThumbsAction(nullptr), contextMenuElement(nullptr) { } bool enableToolTips; AlbumModificationHelper* albumModificationHelper; AlbumViewToolTip* toolTip; QAction* renameAction; QAction* resetIconAction; QAction* findDuplAction; QAction* scanFacesAction; QAction* repairHiddenAction; QAction* rebuildThumbsAction; class AlbumSelectionTreeViewContextMenuElement; AlbumSelectionTreeViewContextMenuElement* contextMenuElement; }; // ---------------------------------------------------------------------------------------------------- class Q_DECL_HIDDEN AlbumSelectionTreeView::Private::AlbumSelectionTreeViewContextMenuElement : public AbstractAlbumTreeView::ContextMenuElement { public: explicit AlbumSelectionTreeViewContextMenuElement(AlbumSelectionTreeView::Private* const d) : d(d) { } virtual void addActions(AbstractAlbumTreeView*, ContextMenuHelper& cmh, Album* a) { if (!a || a->isRoot()) { return; } PAlbum* const album = dynamic_cast(a); if (!album) { return; } if (album->isAlbumRoot()) { cmh.addActionNewAlbum(d->albumModificationHelper, album); cmh.addAction(QLatin1String("album_openinfilemanager")); cmh.addAction(QLatin1String("album_openinterminal")); return; } // -------------------------------------------------------- cmh.addActionNewAlbum(d->albumModificationHelper, album); cmh.addAction(QLatin1String("album_openinfilemanager")); cmh.addAction(QLatin1String("album_openinterminal")); cmh.addSeparator(); // -------------------------------------------------------- cmh.addActionRenameAlbum(d->albumModificationHelper, album); cmh.addActionResetAlbumIcon(d->albumModificationHelper, album); cmh.addSeparator(); // -------------------------------------------------------- cmh.addAction(d->findDuplAction); d->albumModificationHelper->bindAlbum(d->findDuplAction, album); cmh.addAction(d->scanFacesAction); d->albumModificationHelper->bindAlbum(d->scanFacesAction, album); cmh.addAction(d->rebuildThumbsAction); d->albumModificationHelper->bindAlbum(d->rebuildThumbsAction, album); cmh.addImportMenu(); cmh.addExportMenu(); cmh.addAlbumActions(); cmh.addSeparator(); // -------------------------------------------------------- cmh.addAction(d->repairHiddenAction); d->albumModificationHelper->bindAlbum(d->repairHiddenAction, album); cmh.addSeparator(); // -------------------------------------------------------- cmh.addActionDeleteAlbum(d->albumModificationHelper, album); cmh.addSeparator(); // -------------------------------------------------------- cmh.addActionEditAlbum(d->albumModificationHelper, album); } public: AlbumSelectionTreeView::Private* const d; }; // ---------------------------------------------------------------------------------------------------- AlbumSelectionTreeView::AlbumSelectionTreeView(QWidget* const parent, AlbumModel* const model, AlbumModificationHelper* const albumModificationHelper) : AlbumTreeView(parent), d(new Private) { setAlbumModel(model); d->albumModificationHelper = albumModificationHelper; d->toolTip = new AlbumViewToolTip(this); d->findDuplAction = new QAction(QIcon::fromTheme(QLatin1String("tools-wizard")), i18n("Find Duplicates..."), this); d->scanFacesAction = new QAction(QIcon::fromTheme(QLatin1String("list-add-user")), i18n("Scan for Faces"), this); d->repairHiddenAction = new QAction(QIcon::fromTheme(QLatin1String("edit-group")), i18n("Repair hidden Items"), this); d->rebuildThumbsAction = new QAction(QIcon::fromTheme(QLatin1String("view-refresh")), i18n("Refresh"), this); connect(d->findDuplAction, SIGNAL(triggered()), this, SLOT(slotFindDuplicates())); connect(d->scanFacesAction, SIGNAL(triggered()), this, SLOT(slotScanForFaces())); connect(d->repairHiddenAction, SIGNAL(triggered()), this, SLOT(slotRepairHiddenItems())); connect(d->rebuildThumbsAction, SIGNAL(triggered()), this, SLOT(slotRebuildThumbs())); setSortingEnabled(true); setSelectAlbumOnClick(true); setEnableContextMenu(true); setContextMenuTitle(i18n("Albums")); d->contextMenuElement = new Private::AlbumSelectionTreeViewContextMenuElement(d); addContextMenuElement(d->contextMenuElement); } AlbumSelectionTreeView::~AlbumSelectionTreeView() { delete d->contextMenuElement; delete d; } void AlbumSelectionTreeView::setEnableToolTips(bool enable) { d->enableToolTips = enable; } void AlbumSelectionTreeView::slotFindDuplicates() { emit signalFindDuplicates(d->albumModificationHelper->boundAlbum(sender())); } void AlbumSelectionTreeView::slotScanForFaces() { PAlbum* const album = d->albumModificationHelper->boundAlbum(sender()); if (!album) { return; } AlbumList albums; albums << album; if (album->childCount()) { if (QMessageBox::question(this, i18n("Scan for Faces"), i18n("Should sub-albums be scanned too?")) == QMessageBox::Yes) { albums << album->childAlbums(true); } } FaceScanSettings settings; settings.accuracy = ApplicationSettings::instance()->getFaceDetectionAccuracy(); settings.recognizeAlgorithm = RecognitionDatabase::RecognizeAlgorithm::DNN; // Default now change to DNN - settings.task = FaceScanSettings::Detect; + settings.task = FaceScanSettings::DetectAndRecognize; settings.alreadyScannedHandling = FaceScanSettings::Rescan; settings.albums = albums; FacesDetector* const tool = new FacesDetector(settings); tool->start(); } void AlbumSelectionTreeView::slotRepairHiddenItems() { PAlbum* const album = d->albumModificationHelper->boundAlbum(sender()); if (!album) { return; } int needTaggingTag = TagsCache::instance()->getOrCreateInternalTag(InternalTagName::needTaggingHistoryGraph()); int originalVersionTag = TagsCache::instance()->getOrCreateInternalTag(InternalTagName::originalVersion()); foreach (const qlonglong& id, CoreDbAccess().db()->getItemIDsInAlbum(album->id())) { ItemInfo info(id); if (!info.isNull() && info.isGrouped()) { if (info.groupImage().albumId() != album->id()) { info.removeFromGroup(); } } if (!info.hasDerivedImages() && info.tagIds().contains(originalVersionTag)) { info.removeTag(originalVersionTag); info.setTag(needTaggingTag); } } } void AlbumSelectionTreeView::slotRebuildThumbs() { PAlbum* const album = d->albumModificationHelper->boundAlbum(sender()); if (!album) { return; } ThumbsGenerator* const tool = new ThumbsGenerator(true, album->id()); tool->start(); // if physical album, schedule a collection scan of current album's path if (album && album->type() == Album::PHYSICAL) { NewItemsFinder* const tool2 = new NewItemsFinder(NewItemsFinder::ScheduleCollectionScan, QStringList() << static_cast(album)->folderPath()); tool2->start(); } } bool AlbumSelectionTreeView::viewportEvent(QEvent* event) { // let the base class handle the event if it is not a tool tip request if (event->type() != QEvent::ToolTip) { return AlbumTreeView::viewportEvent(event); } // only show tool tips if requested if (!d->enableToolTips) { return false; } // check that we got a correct event QHelpEvent* const helpEvent = dynamic_cast (event); if (!helpEvent) { qCDebug(DIGIKAM_GENERAL_LOG) << "Unable to determine the correct type of the event. " << "This should not happen."; return false; } // find the item this tool tip belongs to QModelIndex index = indexAt(helpEvent->pos()); if (!index.isValid()) { return true; } PAlbum* const album = albumForIndex(index); if (!album || album->isRoot() || album->isAlbumRoot()) { // there was no album so we really don't want to show a tooltip. return true; } QRect itemRect = visualRect(index); if (!itemRect.contains(helpEvent->pos())) { return true; } QStyleOptionViewItem option = viewOptions(); option.rect = itemRect; // visualRect can be larger than viewport, intersect with viewport rect option.rect &= viewport()->rect(); option.state |= (index == currentIndex() ? QStyle::State_HasFocus : QStyle::State_None); d->toolTip->show(option, index); return true; } } // namespace Digikam