diff --git a/NEWS b/NEWS index 28ed5f9ef0..b286558d5f 100644 --- a/NEWS +++ b/NEWS @@ -1,533 +1,534 @@ digiKam 6.0.0-beta1 - Release date: 2018-08-19 ***************************************************************************************************** NEW FEATURES: ImageEditor : Add Web services Import and Export tools. Showfoto : Add Web services Import and Export tools. LightTable : Add Web services Import and Export tools. Database : Similarity database has been moved to a dedicated file to not bloat core database with computed finger-prints. This will speed-up query in core database in case of Similarity feature is used. Database : New video metadata parser based on ffmpeg to populate database. Search : Add video support to find files based on properties registered on database. General : Use DrMinGW has crash handler under Windows. General : Port all export/import tool to OAuth2 authentification. General : New tool to export to Pinterest social network. General : New tool to export to OneDrive webservice. General : New tool to export to Box webservice. General : All bundles use last Lenfun 0.3.95 to process automatic lens correction. General : Add QWebEngine support. General : Fix all Krazy static analyzer reports. General : Update internal Libraw to last 0.19.0. New camera supported: * Apple: Phone 8, iPhone 8 plus, iPhone X * BlackMagic: URSA Mini 4k, URSA Mini 4.6k, URSA Mini Pro 4.6k * Canon: PowerShot A410, A540, D10, ELPH 130 IS, ELPH 160 IS, SD750, SX100 IS,SX130 IS, SX160 IS, SX510 HS, SX10 IS, IXUS 900Ti PowerShot G1 X Mark III, G9 X Mark II, EOS 6D Mark II, EOS 77D, EOS 200D, EOS 800D, EOS M6, EOS M100 * Casio: EX-ZR4100/5100 * DJI: Phantom4 Pro/Pro+, Zenmuse X5, Zenmuse X5R * FujiFilm: S6500fd, GFX 50S, X100f, X-A3, X-A5, X-A10, X-A20, X-E3, X-H1, X-T20 * Hasselblad: H6D-100c, A6D-100c * Huawei: P9 (EVA-L09/AL00), Honor6a, Honor9, Mate10 (BLA-L29) * Leica: CL, M10, TL2 * LG: V20 (F800K), VS995 * Nikon: D850, D5600, D7500, Coolpix B700 * Olympus: E-PL9, E-M10 Mark III, TG-5 * OnePlus: A3303, A5000 * Panasonic: DMC-FZ45, DMC-FZ72, DC-FZ80/82, DC-G9 (std. res mode only), DC-GF10/GF90, DC-GH5, DC-GX9, DC-GX800/850/GF9, DMC-LX1, DC-ZS70 (DC-TZ90/91/92, DC-T93), DC-TZ100/101/ZS100, DC-TZ200/ZS200 * PARROT: Bebop 2, Bebop Drone * Pentax: KP * PhaseOne: IQ3 100MP Trichromatic * Samsung: Galaxy Nexus, Galaxy S3, S6 (SM-G920F), S7, S7 Edge, S8 (SM-G950U) * Sony: A7R III, A9, DSC-RX0, DSC-RX10IV * Yi: M1 * YUNEEC: CGO3, CGO3P * Xiaoyi: YIAC3 (YI 4k) Tags : Add possibility to merge tags by drag & drop. IconView : Add capability to re-organize the contents manually. HTML Gallery : New Vanilla theme to emulate export to HTML from Adobe LightRoom. HTML Gallery : New Blue Frame theme. HTML Gallery : New Kiosk-Mode theme. ***************************************************************************************************** BUGFIXES: 001 ==> 172650 - No export tools available. 002 ==> 149591 - The export menu is blank. 003 ==> 300424 - Export tools not detected. 004 ==> 327743 - MediaWiki export not displayed. 005 ==> 348146 - Export tools configuration module. 006 ==> 243275 - Crashing when calling configuration. 007 ==> 257134 - Crashes when entering its settings. 008 ==> 230666 - Crash during start. 009 ==> 306698 - Crashes after update to KDE. 010 ==> 207640 - Crashes immediately at startup, sometimes at closing. 011 ==> 245628 - Crash when enabling/disabling Facebook import/export. 012 ==> 097317 - sigsegv [New Thread 1100241184 (LWP 5665)]. 013 ==> 245776 - Crashes when selecting Settings. 014 ==> 245775 - Crashes even without export tools installed. 015 ==> 254283 - Crash as soon as i click settings. 016 ==> 255733 - crash when reopening configuration dialog. 017 ==> 262050 - Crash after new install and scan to mysql database. 018 ==> 263871 - Crashed after searching for duplicates. 019 ==> 268242 - Crashes after I clicked on 'Settings'. 020 ==> 276882 - Add export tool buttons to toolbar. 021 ==> 284801 - Export to picasaweb crashes. 022 ==> 277669 - Crash after files moved. 023 ==> 281250 - Crash after disabling Export tools. 024 ==> 202637 - Crash trying to start export tool. 025 ==> 306693 - after update to KDE host application crashes on startup. 026 ==> 282781 - Crashes when reopening configuration dialog after disabling export tools. 027 ==> 285499 - Crash when settings window opened. 028 ==> 297629 - Crashed when importing from Nikon P7000. 029 ==> 303338 - Crashes when clicking "send to" button. 030 ==> 307619 - Refuses to load Export tools. 031 ==> 311812 - Export tools not loading, SO version not defined. 032 ==> 313186 - Crashes on attempt to use the "Send to" menu. 033 ==> 313356 - Crashed when clicking the "send to" button. 034 ==> 313577 - Crashes when pressing the "send to" button. 035 ==> 313890 - Crash when clicking "Send to...". 036 ==> 315033 - Crashes on pressing Send To... button. 037 ==> 315914 - The facebook tool crashes everytime on initialization. 038 ==> 326556 - Export tools are not loaded when starting host application for second time. 039 ==> 095175 - crash on loading, signal 11 SIGSEGV. 040 ==> 175844 - Crashes at startup loading Export tools. 041 ==> 306511 - Crash during start. 042 ==> 234021 - Crash on loading. 043 ==> 219772 - Opening the application causes crash. 044 ==> 294173 - Crash after Image resize start. 045 ==> 306881 - Crashed when attempting to open Export tools. 046 ==> 306495 - Crash changing settings linux ubuntu lucid. 047 ==> 306497 - Crash after changing settings segmentation fault possible 2nd report? 048 ==> 185470 - "Import from facebook" is listed twice in import menu. 049 ==> 334045 - MediaWiki option not available in Export menu when plugin activated. 050 ==> 142112 - Can't save on my webspace with ShowFoto. 051 ==> 167417 - Showfoto cannot save files of CIFS mount. 052 ==> 125164 - Flickr export tool should respect host application selection. 053 ==> 238927 - Host application quits when uploading to Flickr. 054 ==> 326740 - Selection of tools is set to default after each update. 055 ==> 233063 - Add progress indicator when moving or copy files [patch]. 056 ==> 361829 - Rotated MP4 video with "Orientation" flag are not played back in the correct rotation angle. 057 ==> 329854 - digiKam doesn't rotate video thumbnail. 058 ==> 376661 - When importing ~200,000 video files Digikam crashes in about 2-5 seconds of starting. 059 ==> 377072 - Cannot read video metadata. 060 ==> 374453 - Extract right video date from MP4 files metadata. 061 ==> 377177 - Geolocation / GPS information doesn't appear in video metadata. 062 ==> 383588 - Imported video files have time shifted exactly 2 hours later. 063 ==> 380847 - MP4 video not importing with correct date. 064 ==> 373682 - geolocalisation filter does not take care of the videos geolocalisation tags. 065 ==> 340925 - digiKam crash when start it. 066 ==> 331506 - digiKam crashes on startup. 067 ==> 335816 - Crash when trying to add a big collection. 068 ==> 353295 - digiKam repeatedly crashes while importing pictures. 069 ==> 341433 - Crash when opening digiKam application. 070 ==> 375562 - digiKam crashes while scanning images into sqlite database. 071 ==> 334782 - Crash while doing nothing. 072 ==> 362672 - Crash on start of digiKam. 073 ==> 341023 - Crash after startup during check for updated images. 074 ==> 386891 - Crashed while adding pictures. 075 ==> 342666 - digiKam crashes during find new items. 076 ==> 341274 - digiKam crash on startup. 077 ==> 343708 - Crash when scanning album. 078 ==> 332721 - Crash when reading a certain MP4 video file. 079 ==> 343736 - Crashes when rebuilding thumbnails from database. 080 ==> 346356 - digiKam crashes when adding 90.000 pictures to library. 081 ==> 343714 - digiKam crash when scanning for new items. 082 ==> 341091 - digiKam crashes when updating the MySQL database of a a hudge photo collection. 083 ==> 340879 - digiKam crashes after getting unexpected but reasonable output from libexiv2. 084 ==> 342712 - Crash on collection scanning. 085 ==> 356704 - digiKam still crashes while scanning a new photo directory and subdirs. 086 ==> 339269 - Segfault when opening a folder that contains unknown file types (mov, avi, xcf). 087 ==> 364635 - digiKam crashes on startup. 088 ==> 357356 - digiKam crash on startup while scanning photos. 089 ==> 341554 - digiKam crashed by Data-Import from NFS. 090 ==> 345457 - digiKam crashes at "loading tools". 091 ==> 349635 - Crash of digiKam - moving album. 092 ==> 342604 - digiKam crash. 093 ==> 331450 - Signal 8 on album opening. 094 ==> 342030 - digiKam crashes when checking an AVI video file using exiv2. 095 ==> 352777 - Crash during scan. 096 ==> 352944 - digiKam crashes on start. 097 ==> 343643 - digiKam crashes while perform initial scanning of custom photo folder. 098 ==> 342000 - digiKam crash when opening folder with Videos (Album or SD Card import). 099 ==> 353447 - digiKam crashes when scanning files. 100 ==> 346807 - Crashes on startup. 101 ==> 364639 - digiKam crashed while opening database. 102 ==> 341504 - Crash while using application. 103 ==> 367691 - Searching for pictures crashes at 30% every time. 104 ==> 334604 - Crash after changing disk partions. 105 ==> 351689 - Crash on opening digiKam. 106 ==> 149267 - digiKam crashes after finding avi and so on. 107 ==> 170387 - Add movies management. 108 ==> 369629 - digiKam does not use GPS data from video files. 109 ==> 367880 - Nexus 5X videos show up upside-down in digiKam. 110 ==> 330116 - digiKam does not take care about GPS info stored in MP4 video files. 111 ==> 339150 - digikam crashes when trying to display video file. 112 ==> 344406 - Crash at start. 113 ==> 339909 - digiKam Segmentation Fault on open. 114 ==> 343231 - Crash at scanning for new fotos. 115 ==> 340373 - Crash on scanning video directory. 116 ==> 134679 - Video and audio files are not imported. 117 ==> 375357 - No video preview. 118 ==> 261773 - Batch renaming does not complete when MP4 video file is processed. 119 ==> 185915 - Album View: "Created" time of video set to "00:00". 120 ==> 303218 - digiKam import crashes when you select video files. 121 ==> 374241 - Bad video date rename. 122 ==> 375646 - Be able to scan only photo, not video and audio. 123 ==> 262499 - Cannot rename .AVI files. 124 ==> 199261 - Import avi movies from sdcard wrong date and no thumbnail. 125 ==> 181521 - NEF's in descending order, AVI in ascending order in import from SD-card. 126 ==> 392019 - Two persons can point to the same face tag in pictures. 127 ==> 392013 - Metadata explorer does not show XMP face rectangles. 128 ==> 389508 - Dates Side Menu Is Not Updated Automatically After Exif Date Change [patch]. 129 ==> 331864 - Merge Tags with same name when moving to same hierarchy level. 130 ==> 347302 - Reassign name to face. 131 ==> 391747 - BQM Tool "Remove Metadata" doesn't remove all metadata from image. 132 ==> 285683 - Already imported pictures not recognized after daylight savings time. 133 ==> 392309 - Icons are pixelated when my display scale factor is 1.2 134 ==> 392405 - Function 'getImageIdsFromArea' argument order different. 135 ==> 386224 - Metadata is not updated when moving tags. 136 ==> 370245 - Be able to rename tags which have been setted in pictures. 137 ==> 374470 - Deleted tags are not removed from file metadata. 138 ==> 374516 - Persons metadata are not updated after a tag removed. 139 ==> 392436 - Count Files in directory. 140 ==> 363859 - digiKam core port from QWebKit to QWebEngine [patch]. 141 ==> 392427 - Cannot add collection on network drive. 142 ==> 392022 - Position of a face tag appears on top of bottom of the list, instead of being sorted alphabetically. 143 ==> 372763 - Rename does not give options on Conflict. 144 ==> 391533 - Feature request: add "NOT" tag matching condition in "Filters" panel. 145 ==> 381222 - digiKam crash on fuzzy search. 146 ==> 386275 - Crash caused by QtAV. 147 ==> 372342 - Face tag area is very short [patch]. 148 ==> 391348 - People Side Menu Shows Only Faces Not People Tagged Images. 149 ==> 385630 - Views Requiring Maps Takes ~30s to Launch. 150 ==> 192908 - Allow to split icon-view in order to show multiple albums at the same time. 151 ==> 339088 - GIT master: crash when clicking through images in preview, with face recognition running in background. 152 ==> 341605 - Crash if I attempt to use left-sidebar tags tab. 153 ==> 227266 - Handle Video Date from metadata. 154 ==> 227259 - Needs to Edit Video Date. 155 ==> 373284 - digiKam crashed with SIGSEGV in QSortFilterProxyModel::parent(). 156 ==> 384807 - digikam 5.7.0 AppImage bundle : provide a more recent ffmpeg version for video support. 157 ==> 391835 - Deleted pictures still appear in group. 158 ==> 387483 - Elegant theme: Selected frame colors swapped [patch]. 159 ==> 375424 - Thumbnails are not being removed from AlbumsView after moving the images to Trash. 160 ==> 368796 - Problem with Exif-tags: ImageDescription and UserComment. 161 ==> 392417 - AppImage (5.9.0-01-x86-64) does not support "--install" cli parameter. 162 ==> 392922 - digikam-6.0.0 fail to start. 163 ==> 391399 - Not possible to add location bookmarks in Digikam >5.6.0. 164 ==> 380876 - Tags in Digikam DB maintained after being removed from file and file re-scanned. 165 ==> 392017 - Merging, renaming and removing face tags. 166 ==> 352711 - Externally removed tags are not removed from digiKam. 167 ==> 393108 - Tags not always visible when selecting multiple pictures in a group. 168 ==> 392656 - Selecting a root album for face scan doesn't include subfolders, but rather scans an unexpected album set. 169 ==> 329438 - Rename function with Date & Time does not work with NTFS. 170 ==> 376473 - Can"t set empty IPTC country code when using metadata templates. 171 ==> 380289 - Cannot write to Albums residing on NFS. 172 ==> 384465 - With Compact Flash Card Created date in thumbnails is wrong. 173 ==> 381958 - Cannot add additional collection. 174 ==> 383747 - "Rotate only by setting a flag" Changes Image Instead. 175 ==> 387977 - No icon only view of "Extras sidebar": sidebar taking up a lot of space. 176 ==> 277502 - All versions of version set always displayed in Album view [patch]. 177 ==> 393283 - Caption not updating Exif.Image.ImageDescription field. 178 ==> 391060 - Crashes on undo of very large tif. 179 ==> 366305 - Add a message at startup about the lack of temporary space to perform Undo operations. 180 ==> 366391 - Rotating an image seems to forget to reset the orientation flag. 181 ==> 393654 - Not able to select gpx file. 182 ==> 367596 - Sub-folder count images but don't show them (unsupported JPEG file?). 183 ==> 379922 - Digikam won't remove tags set by Windows Explorer. 184 ==> 379081 - GPS data are in file but geolocation indicator is not shown and map view empty. 185 ==> 354819 - Specific pictures not showing up in digikam. 186 ==> 393855 - MySQL/MariaDB upgrade fails. 187 ==> 384603 - Camera Creation Date not set from EXIF data. 188 ==> 386959 - Properties view: wrong creation date [patch]. 189 ==> 393970 - No mts video thumbnails. 190 ==> 393728 - Reread metadata from Video uses sidecar only. 191 ==> 393925 - UpdateSchemaFromV7ToV9 fails due to duplicate key in album_2. 192 ==> 393773 - showfoto crashes when geotagging. 193 ==> 388199 - No context menu to copy coordinates from map. 194 ==> 393399 - Windows defender freaks out in windows 10 and Edge. 195 ==> 392134 - SIGSEGV While Scanning Faces [patch]. 196 ==> 394168 - OSM Search Yields No Results. 197 ==> 377719 - Cannot rename file with overwrite [patch]. 198 ==> 388002 - remove kio related legacy [patch] 199 ==> 394242 - Import settings unneccesarily asks to overwrite image database, and crashes when I decline. 200 ==> 394278 - A slideshow theme for kiosk mode. 201 ==> 340389 - digiKam crashes while editing pictures for color balancing on OSX [patch]. 202 ==> 394413 - Unify group handling [patch]. 203 ==> 394573 - Revers geodata from open street map does not work. 204 ==> 394590 - Feature request: being able to filter on all metadatas fields. 205 ==> 394671 - Distortion on Panasonic DMC-LX15. 206 ==> 393205 - Advanced rename very slow. 207 ==> 382474 - Thumbnail regeneration. 208 ==> 394865 - digikam suspicious crash on exit. 209 ==> 390541 - Tooltip background cannot be changed. 210 ==> 391521 - "Tool-tip" box difficult to read due to default color scheme. 211 ==> 377849 - Albums disappear when the network is interrupted. 212 ==> 394988 - PgDown and PgUp hardcoded in preview mode. 213 ==> 366312 - Efficient photo tagging workflow got lost in transition from 4.x to 5. 214 ==> 395093 - Being able to export a list of paths from a selection of thumbnails. 215 ==> 395144 - When zooming in preview, face tags show on wrong places. 216 ==> 275671 - Scan single image for faces. 217 ==> 395199 - Uploading large video files to flickr fails. 218 ==> 348274 - "Change Account" immediately opens web page in browser, before I click Continue 219 ==> 263347 - Print wizard ignores selected paper size, reverts to A4. 220 ==> 395579 - Only one tag being exported to flickr. 221 ==> 395790 - Rename with nested tags breaks due to | bar character. 222 ==> 395875 - ImageEditor window is blank when opened a second time. 223 ==> 385822 - [Suggested feature] Re-use thumbnails from the database for the items in Trash. 224 ==> 382174 - Not creating thumbnails and not editing (F4) files created for Samsung panorama jpgs [patch]. 225 ==> 376124 - Some Photos are not previewed. 226 ==> 386188 - Preview Does Not Display Some JPGs Editor Crashes Program. 227 ==> 394906 - Toggling "use file metadata" for input will make Digikam forget all imported photos. 228 ==> 388391 - Windows x64 installer crashes at 60%. 229 ==> 377433 - Crash on opening settings. 230 ==> 390286 - Please update version of lensfun. 231 ==> 386649 - Crash on opening RAW file from OnePlus One. 232 ==> 172836 - No menu item for lensfun. 233 ==> 319462 - Crash while applying lensfun distortion correction a second time. 234 ==> 380844 - Demosaicing choosing VCD & AHD then update. 235 ==> 380843 - Demosaicing. 236 ==> 301219 - digiKam crash. 237 ==> 216013 - try to open extras/ batch raw converter was followed by a crash. 238 ==> 102045 - RAW conversion in digikam fails to convert or generate preview. 239 ==> 137281 - Cannot convert nef into raw. 240 ==> 230763 - Exif ISO data missing when converting Olympus ORF. 241 ==> 137278 - 16-bit/channel workspace when working with RAW conversions. 242 ==> 133004 - Canon CRW portrait preview upside-down. 243 ==> 221345 - Do not process search immediately when enter text to query. 244 ==> 396234 - Add a feature which allow to switch latitude and longitude. 245 ==> 396283 - Missing images in album preview. 246 ==> 396352 - Some iptc tags are not displayed in the metadata part. 247 ==> 396434 - Uncontrolled log messages oversize log file up to run out of disk space. 248 ==> 396482 - Empty folder selector window after select and click on "Import selected elements". 249 ==> 396170 - Gallery creation error. 250 ==> 140374 - HTML Gallery export fails to parse xml from non-UTF8 metadata in jpeg. 251 ==> 396712 - "Save Search" does not work. 252 ==> 396944 - Integrity constraint violation on Albums.icons when migrating from sqlite to mysql. 253 ==> 396952 - Cut and Paste Into Caption Has Incorrect Font Initially. 254 ==> 091562 - Change order of pictures in the virtual album manually. 255 ==> 098340 - Re-sort images in albums 256 ==> 177355 - Feature request: export slideshow in lighttable. 257 ==> 158520 - Wishlist sort thumbnails manually and rename images. 258 ==> 191000 - Wish: Visual tool to change the sort order of photos. 259 ==> 216802 - digiKam ability to sort album with "picture is before picture". 260 ==> 230136 - It lacks the ability to sort photos manually. 261 ==> 236249 - Wish: custom sort in album view. 262 ==> 323559 - Wish: Albums like Playlists in Amarok. 263 ==> 337002 - Manual image sort. 264 ==> 397167 - Some tags are not displayed on the preview. 265 ==> 397207 - Too many open files, when reverse geocoding many images. 266 ==> 397278 - DNG conversion not possible. 267 ==> 397311 - DIN A relation in "Aspect Ratio Crop". 268 ==> 222716 - digiKam does not start. Showing: Reading database. 269 ==> 276633 - Crash when using map view inside of digiKam. 270 ==> 224706 - digiKam for KDE on Windows "Failed to rename Album" (KDirWatch Relevant). 271 ==> 383016 - digiKam with incomplete German translation. 272 ==> 244982 - digiKam crashes at initial configuration. 273 ==> 366453 - digiKam crash while using mouse over title bar. 274 ==> 278490 - Incorrect tab layout with slider/spinbox/reset button. 275 ==> 324642 - digiKam crash when starting a bug report while offline. 276 ==> 238392 - digiKam Camera interface : rename dialog interprets alt-s as plain s when button greyed out. 277 ==> 397177 - image editor does not export exif and IPTC data when saving to PNG. 278 ==> 341276 - Picture bigger than 5MB are not previewed. 279 ==> 388908 - Error while scanning with HP F300 series. 280 ==> 381723 - digiKam crashed when I tried to close the window opened by clicking import button. 281 ==> 345288 - Crash from digiKam when try customizing a shortcut to a Tag. 282 ==> 381193 - digiKam crashes after uploading photos from smartphone via USB. 283 ==> 275670 - Face preview image incorrect on 'rotated' images. 284 ==> 395199 - Uploading large video files to flickr fails [patch]. 285 ==> 240144 - digiKam : When I press the left button of the mouse on a photo, a menu appears, but no items are seen. 286 ==> 240229 - White contextual menu problem. 287 ==> 309508 - Export to Flickr does not send the geodata. 288 ==> 383987 - Flickr tool no longer authenticates to Flickr. 289 ==> 338333 - Account problem. 290 ==> 397001 - The "maximise" button is missing in decoration of the geolocation editor window [patch]. 291 ==> 397406 - Digikam shouldn't use parentheses when renaming files. 292 ==> 397411 - Not being able to move files in a removable media collection which is not mounted. 293 ==> 227566 - digiKam does not allow smb:// shared folder as picture collection. 294 ==> 395201 - SSL broken in 5.9.0 AppImage bundle. 295 ==> 385363 - digiKam crashes when authorizing access to Google photo because of SSL error in AppImage. 296 ==> 348277 - Please focus auth code input field in the GDrive authentication dialog. 297 ==> 383174 - Google photo, export stops after a random quantity of photos. 298 ==> 387422 - Flickr export authorization does not work. 299 ==> 397126 - Fail to replace a photo in google photo. 300 ==> 387201 - kioslave needed by flickr export but not included in appimage. 301 ==> 389785 - 'Open in Filemanager' dolphin not working. 302 ==> 396619 - All Exports fail - cannot find ioslave. 303 ==> 254512 - Crash when initializing the export to Flickr.com. 304 ==> 237818 - Crash when uploading multiple images to Flickr. 305 ==> 286754 - Crash when when entering collection name in flickr uploader. 306 ==> 337980 - Flickr Export tool can no longer obtain a new token. 307 ==> 151018 - Requires new token with every invokation. 308 ==> 132922 - Export to flickr doesn't work. 309 ==> 149864 - Dialog box pops up saying 'Error Occured: Missing signature. We can not proceed further". 310 ==> 196179 - Flickr export does not work. 311 ==> 391734 - Can't export to google photos: SSL Handshake failed. 312 ==> 386402 - Not all page sizes for selected printer can be selected. 313 ==> 395557 - Printformat not selectable. 314 ==> 340644 - Allow to use standard photo paper sizes. 315 ==> 330906 - Crashes when exporting to HTML. 316 ==> 309316 - Html gallery export crash and other bugs. 317 ==> 314248 - digiKam crashing when exporting pictures to html. 318 ==> 225725 - Crash using HTML export. 319 ==> 396092 - Don't init search till user press a buttom specifically for this task. 320 ==> 397376 - Search in Geolocation doesn't work for Streets / location, only for City. 321 ==> 393259 - Configuration conflicts. 322 ==> 391329 - Two actions that wants to use same shortcut (Ctrl+Shift+,). 323 ==> 391655 - Kubuntu 18.04 beta, Digikam 5.6.0 Ambiguous Shortcuts - Zoom to 100% and Configure Digikam share the same shortcut (Ctrl+Shift+,). 324 ==> 393031 - Two actions for digikam[helpfully identified as a bug]. 325 ==> 395518 - When manually typing face name, sort the filtered tags by recent usage. 326 ==> 304202 - No option to re-read metadata from XMP sidecar file. 327 ==> 289445 - Allow to create Contact Sheet from an album. 328 ==> 164750 - Picture alignment and background picture. 329 ==> 338180 - Add "Toggle auto-refresh" option in search view. 330 ==> 359235 - digiKam doesn't response after start when StatusBar=Disabled in digikamrc. 331 ==> 090550 - Linking error with jpeg. 332 ==> 393974 - Appimage bundle does not automatically recognize Gphoto2 devices connected. 333 ==> 141288 - Error KIoexec usb camera. 334 ==> 397554 - digiKam crashes while running BatchQueueManager. 335 ==> 379261 - Crash on attempting camera import. 336 ==> 379335 - digiKam crashes when deleting images in the download window [patch]. 337 ==> 394291 - Cannot upgrade mysql db from v7 to v9. 338 ==> 389468 - Immediate Crash On Metadata Sync. 339 ==> 379807 - ShowFoto crashes when clicking Color Effects from menu. 340 ==> 257301 - showfoto reaches an assert when saving file with "~/" in the path. 341 ==> 183629 - Digikam/Showfoto Dark Theme: The selected photo filename is nearly invisible. 342 ==> 249379 - All versions of Digikam/Showfoto/KDE download is missing a file. 343 ==> 237286 - digiKam crash after to scan collection (upgrate from 9.10 to 10.04). 344 ==> 254878 - digiKam error segmentation fault when open it. 345 ==> 255759 - digikam crash when open it kunbuntu lucid. 346 ==> 249009 - digiKam crashes at initialisation. 347 ==> 236647 - After upgrading to Ubuntu 10.04 digiKam crashes everytime it is launched. 348 ==> 235905 - digiKam crash after upgrade. 349 ==> 185265 - digiKam constantly using some CPU in a poll loop due a timeout 350 ==> 250364 - digiKam crashes at start-up in xubuntu 10.04. 351 ==> 253205 - digiKam crashes while loading on Ubunu 10.04. 352 ==> 249033 - After upgrade to 10.04 digiKam crashes after starting always. 353 ==> 300713 - Crash while editing tag in digiKam. 354 ==> 184443 - digiKam save as "JPEG" appends a ".JPEG" file extension. Bad! 355 ==> 189084 - Crash while editing toolbars (here from digiKam camera GUI). 356 ==> 205275 - After changing symbols in bar on preview digikam closes. 357 ==> 214418 - Crash while importing into digiKam. 358 ==> 279909 - digiKam crashed when I tried to import photos from my iPhone 4. 359 ==> 287616 - digiKam crash when selecting folder to store photos. 360 ==> 327714 - digiKam crashes when starting up [Qt Bmp Image IO]. 361 ==> 396892 - digiKam font sizes cannot be changed. Mostly too small. 362 ==> 371726 - Dates view empty using MYSQL due to SQL query error (fix supplied). 363 ==> 382217 - Use normalized connects [patch]. 364 ==> 113692 - digiKam thumbnail hangs on .mov movie. 365 ==> 185638 - digiKam crash on startup. 366 ==> 350404 - digiKam crashes at startup. 367 ==> 301583 - digiKam crash on preview avi. 368 ==> 236960 - No video in digiKam embedded viewer no way to change codec? 369 ==> 227113 - digiKam crashes when selecting a movie. 370 ==> 274333 - digiKam crashed upon startup. 371 ==> 247019 - digiKam crashes in Album view with Canon IXUS 90 video clip. 372 ==> 238525 - digiKam crashes on browsing in album view. 373 ==> 317437 - digiKam crashes on startup. 374 ==> 237183 - digiKam crashes on playing Quicktime movies. 375 ==> 256644 - digiKam crashes after adding photos to light table. 376 ==> 245033 - digiKam falls on video files. 377 ==> 252411 - digiKam crashes when .AVI videoclip is launched. 378 ==> 247399 - digiKam crashes when viewing videos. 379 ==> 261706 - digiKam crashed after downloading pictures. 380 ==> 172170 - digiKam embedded video player - video not synchronized with sound. 381 ==> 293173 - digiKam does not play videos. 382 ==> 182401 - Wrong color palette on playback videos within digiKam. 383 ==> 219419 - digiKam crashes after splash screen with PTP. 384 ==> 397565 - Unable to launch in OS X after install. 385 ==> 337978 - digiKam crashes on startup - always. 386 ==> 215673 - digiKam movie no preview. 387 ==> 204481 - digikam: Wizard not translated in French. 388 ==> 365694 - digiKam 5.0.0 : every menus are in French, excepted the menu bar. 389 ==> 394434 - Installation problem mysql internal on mac os high sierra [patch]. 390 ==> 397696 - [Website] On Fedora, use dnf instead of yum. 391 ==> 392970 - Website: Mention KDE Familly. 392 ==> 394694 - Showfoto crashes on change picture size. 393 ==> 326006 - digiKam Raw engine generates pink & black stripe on the right. 394 ==> 379984 - ASSERT failure in Q_GLOBAL_STATIC: "The global static was used after being destroyed". 395 ==> 373572 - File synchronization. 396 ==> 296768 - When creating thumbnails, digiKam uses 80% CPU - quadcore 3800, 9GB RAM. 397 ==> 397777 - Need to default to native filesystem browser on first run to see external drives. 398 ==> 279818 - digiKam crashed when updating fingerprints. 399 ==> 275931 - digiKam crashed when trying to stop a batch queue. 400 ==> 272144 - Alphabetically sorting of the tools in BQM. 401 ==> 271531 - Cannot edit canon crw-pics. 402 ==> 397739 - Menu icons are not scaled correctly on external/secondary screen (2560x1440) while using MacBookPro. 403 ==> 380841 - Crash while correcting color manually. 404 ==> 378176 - Using tool causes program to crash. 405 ==> 395842 - digiKam crashes adjusting color balance on a RAW file. 406 ==> 388608 - Faces engine hangs and crashes. 407 ==> 397855 - Not compatible with Windows 10. 408 ==> 391039 - digiKam stalled after trying to make a panorama. 409 ==> 184318 - Starting digiKam it crashed and caused the signal 11 (SIGSEGV). 410 ==> 222740 - Starting digiKam cause sound system to report pulseaudio is removed. 411 ==> 378697 - Add image carousel to front page screenshots. 412 ==> 180375 - Web page: Wrong link to Alpenglow Webpage. 413 ==> 331141 - Broken link to database schema in web site digikam.org pointing to project.kde.org. 414 ==> 397862 - Reordering geolocation bookmarks will remove them from the list. 415 ==> 223348 - digiKam crash during album view browsing AVIs with PgUp/PgDown. 416 ==> 156146 - Reading data base, digiKam don't start. 417 ==> 118090 - digiKam crashed while attempting to save scanned (tiff) image. 418 ==> 397828 - Operation cancelled when exporting to flickr. 419 ==> 397924 - Merge tag names of people. 420 ==> 397425 - Bug when trying find duplicates. 421 ==> 397496 - Wish: Read facetags from jpg files edited in Mylio. 422 ==> 397727 - Don't show "Mod."" label when no modified timestamp exists on an image. 423 ==> 397893 - MacOS : digiKam do not link with libksane 18.08.0. 424 ==> 397990 - Carousel images too large. 425 ==> 389273 - Copy/move selected items to anothor Album doesn't work correctly [patch]. 426 ==> 261471 - Crashes when trying to delete photos or albums. 427 ==> 342108 - Crashes when trying to import images 428 ==> 341268 - digiKam freeze each time I select a photograph in a collection. 429 ==> 388551 - Error message at startup showing that Marble plugins are not loading but they do. 430 ==> 342110 - Bug reporting feature gives error wont report bug. 431 ==> 387047 - Easily accessible signatures. 432 ==> 286286 - digiKam crashes if I request fullscreen mode. 433 ==> 292522 - digiKam crashes on startup. 434 ==> 294791 - digiKam and Showfoto crashes while switching to fullscreen mode. 435 ==> 347589 - Menu icons size is not unified - text overlapping. 436 ==> 382053 - digiKam preferences when using mysql host port resets to default (3306) when accessing preferences. 437 ==> 388227 - Image version always shown. 438 ==> 386561 - Cannot import images from mac /Volumes/. 439 ==> 396491 - Versions are not grouped despite the correct setting. 440 ==> 389505 - Database port reset to 3306 when oppening digiKam setup (working with maiaDB10). 441 ==> 266165 - Advanced slideshow crash. 442 ==> 387372 - With Digikam Version 5.7 is no preview possible. 443 ==> 286341 - Crash at startup with a "Bus Error". 444 ==> 329050 - Application crashes while starts. 445 ==> 396374 - editing a picture (F4) presents an empty screen. 446 ==> 336874 - After exiting full screen, Menu Bar disappear and crash. 447 ==> 237494 - B&W JPEG displayed incorrectly. 448 ==> 265749 - Blank context menus. 449 ==> 274733 - Delete file permanentry works wrong. 450 ==> 383711 - All Albums Disappear. 451 ==> 378929 - DNG conversion fails in Windows 10 for Olympus ORF files. 452 ==> 170458 - Object position on pictures. 453 ==> 184638 - Generate XMP for raw files. 454 ==> 200380 - Usability of editing exif comments. 455 ==> 195090 - Thumbnails bar should have no empty space. 456 ==> 196730 - Add Color Space converter to batch queue tool. 457 ==> 207921 - Using image editing tools in fullscreen modes leaves right sidebar open. 458 ==> 211066 - TIFFs written by digiKam not readable with GIMP. 459 ==> 224603 - One-touch download when connecting media. 460 ==> 282021 - Impossible to start... 461 ==> 202430 - Crash after startup on Mac OS X. 462 ==> 139153 - Can't compile from source. 463 ==> 380971 - Albums disappear when the network is interrupted. (5.6.0). 464 ==> 342673 - Rebuild fingerprints crashes with large number (>110000) of images. 465 ==> 261134 - Drag a folder into album view - deletes source folder. 466 ==> 365809 - Menu bar disappears after having used full screen mode. 467 ==> 383924 - Tags syncing and reading from file not working. 468 ==> 395788 - If tags have a in them rename effectively deletes the file. 469 ==> 388596 - Main area remains empty with Qt 5.9.3. 470 ==> 387552 - digiKam suddenly is unable to read or display any images. 471 ==> 397972 - Unable to navigate in DK during flickr export. -472 ==> +472 ==> 390228 - No clear rule on where digikam wants to import. +473 ==> diff --git a/core/utilities/import/main/importui.cpp b/core/utilities/import/main/importui.cpp index 40915102e1..a943466812 100644 --- a/core/utilities/import/main/importui.cpp +++ b/core/utilities/import/main/importui.cpp @@ -1,2698 +1,2697 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2004-09-16 * Description : Import tool interface * * Copyright (C) 2004-2005 by Renchi Raju * Copyright (C) 2006-2018 by Gilles Caulier * Copyright (C) 2006-2011 by Marcel Wiesweg * Copyright (C) 2012 by Andi Clemens * Copyright (C) 2012 by Islam Wazery * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "importui.h" #include "importui_p.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include #include // Local includes #include "drawdecoder.h" #include "dlayoutbox.h" #include "dexpanderbox.h" #include "dfileselector.h" #include "digikam_debug.h" #include "digikam_globals.h" #include "cameramessagebox.h" #include "advancedrenamemanager.h" #include "album.h" #include "albummanager.h" #include "applicationsettings.h" #include "albumselectdialog.h" #include "cameracontroller.h" #include "camerafolderdialog.h" #include "camerainfodialog.h" #include "cameralist.h" #include "cameranamehelper.h" #include "cameratype.h" #include "capturedlg.h" #include "collectionlocation.h" #include "collectionmanager.h" #include "collectionscanner.h" #include "componentsinfo.h" #include "dlogoaction.h" #include "coredbdownloadhistory.h" #include "dzoombar.h" #include "fileactionmngr.h" #include "freespacewidget.h" #include "iccsettings.h" #include "imagepropertiessidebarcamgui.h" #include "importsettings.h" #include "importview.h" #include "imagedialog.h" #include "dnotificationwrapper.h" #include "newitemsfinder.h" #include "parsesettings.h" #include "renamecustomizer.h" #include "scancontroller.h" #include "setup.h" #include "sidebar.h" #include "statusprogressbar.h" #include "thememanager.h" #include "thumbnailsize.h" #include "importthumbnailmodel.h" #include "imagepropertiestab.h" namespace Digikam { ImportUI* ImportUI::m_instance = 0; ImportUI::ImportUI(const QString& cameraTitle, const QString& model, const QString& port, const QString& path, int startIndex) : DXmlGuiWindow(0), d(new Private) { setConfigGroupName(QLatin1String("Camera Settings")); setXMLFile(QLatin1String("importui5.rc")); setFullScreenOptions(FS_IMPORTUI); setWindowFlags(Qt::Window); m_instance = this; // -------------------------------------------------------- QString title = CameraNameHelper::cameraName(cameraTitle); d->cameraTitle = (title.isEmpty()) ? cameraTitle : title; setCaption(d->cameraTitle); setupCameraController(model, port, path); setupUserArea(); setInitialSorting(); setupActions(); setupStatusBar(); setupAccelerators(); // -- Make signals/slots connections --------------------------------- setupConnections(); sidebarTabTitleStyleChanged(); slotColorManagementOptionsChanged(); // -- Read settings -------------------------------------------------- readSettings(); setAutoSaveSettings(configGroupName(), true); // ------------------------------------------------------------------- //d->historyUpdater = new CameraHistoryUpdater(this); //connect (d->historyUpdater, SIGNAL(signalHistoryMap(CHUpdateItemMap)), //this, SLOT(slotRefreshIconView(CHUpdateItemMap))); //connect(d->historyUpdater, SIGNAL(signalBusy(bool)), // this, SLOT(slotBusy(bool))); // -------------------------------------------------------- d->progressTimer = new QTimer(this); connect(d->progressTimer, SIGNAL(timeout()), this, SLOT(slotProgressTimerDone())); // -------------------------------------------------------- d->renameCustomizer->setStartIndex(startIndex); d->view->setFocus(); // -- Init icon view zoom factor -------------------------- slotThumbSizeChanged(ImportSettings::instance()->getDefaultIconSize()); slotZoomSliderChanged(ImportSettings::instance()->getDefaultIconSize()); // try to connect in the end, this allows us not to block the UI to show up.. QTimer::singleShot(0, d->controller, SLOT(slotConnect())); } ImportUI::~ImportUI() { saveSettings(); m_instance = 0; disconnect(d->view, 0, this, 0); delete d->view; delete d->rightSideBar; delete d->controller; delete d; } ImportUI* ImportUI::instance() { return m_instance; } void ImportUI::setupUserArea() { DHBox* const widget = new DHBox(this); d->splitter = new SidebarSplitter(widget); DVBox* const vbox = new DVBox(d->splitter); d->view = new ImportView(this, vbox); d->view->importFilterModel()->setCameraThumbsController(d->camThumbsCtrl); d->view->importFilterModel()->setStringTypeNatural(ApplicationSettings::instance()->isStringTypeNatural()); d->historyView = new DHistoryView(vbox); d->rightSideBar = new ImagePropertiesSideBarCamGui(widget, d->splitter, Qt::RightEdge, true); d->rightSideBar->setObjectName(QLatin1String("CameraGui Sidebar Right")); d->splitter->setFrameStyle(QFrame::NoFrame); d->splitter->setFrameShadow(QFrame::Plain); d->splitter->setFrameShape(QFrame::NoFrame); d->splitter->setOpaqueResize(false); d->splitter->setStretchFactor(0, 10); // set iconview default size to max. vbox->setStretchFactor(d->view, 10); vbox->setStretchFactor(d->historyView, 2); vbox->setContentsMargins(QMargins()); vbox->setSpacing(0); d->errorWidget = new DNotificationWidget(vbox); d->errorWidget->setMessageType(DNotificationWidget::Error); d->errorWidget->setCloseButtonVisible(false); d->errorWidget->hide(); // ------------------------------------------------------------------------- d->advBox = new DExpanderBox(d->rightSideBar); d->advBox->setObjectName(QLatin1String("Camera Settings Expander")); d->renameCustomizer = new RenameCustomizer(d->advBox, d->cameraTitle); d->renameCustomizer->setWhatsThis(i18n("Set how digiKam will rename files as they are downloaded.")); d->advBox->addItem(d->renameCustomizer, QIcon::fromTheme(QLatin1String("insert-image")), i18n("File Renaming Options"), QLatin1String("RenameCustomizer"), true); // -- Albums Auto-creation options ----------------------------------------- d->albumCustomizer = new AlbumCustomizer(d->advBox); d->advBox->addItem(d->albumCustomizer, QIcon::fromTheme(QLatin1String("folder-new")), i18n("Auto-creation of Albums"), QLatin1String("AlbumBox"), false); // -- On the Fly options --------------------------------------------------- d->advancedSettings = new AdvancedSettings(d->advBox); d->advBox->addItem(d->advancedSettings, QIcon::fromTheme(QLatin1String("system-run")), i18n("On the Fly Operations (JPEG only)"), QLatin1String("OnFlyBox"), true); // -- DNG convert options -------------------------------------------------- d->dngConvertSettings = new DNGConvertSettings(d->advBox); d->advBox->addItem(d->dngConvertSettings, QIcon::fromTheme(QLatin1String("image-x-adobe-dng")), i18n("DNG Convert Options"), QLatin1String("DNGSettings"), false); // -- Scripting options ---------------------------------------------------- d->scriptingSettings = new ScriptingSettings(d->advBox); d->advBox->addItem(d->scriptingSettings, QIcon::fromTheme(QLatin1String("utilities-terminal")), i18n("Scripting"), QLatin1String("ScriptingBox"), false); d->advBox->addStretch(); d->rightSideBar->appendTab(d->advBox, QIcon::fromTheme(QLatin1String("configure")), i18n("Settings")); d->rightSideBar->loadState(); // ------------------------------------------------------------------------- setCentralWidget(widget); } void ImportUI::setupActions() { d->cameraActions = new QActionGroup(this); KActionCollection *ac = actionCollection(); // -- File menu ---------------------------------------------------- d->cameraCancelAction = new QAction(QIcon::fromTheme(QLatin1String("process-stop")), i18nc("@action Cancel process", "Cancel"), this); connect(d->cameraCancelAction, SIGNAL(triggered()), this, SLOT(slotCancelButton())); ac->addAction(QLatin1String("importui_cancelprocess"), d->cameraCancelAction); d->cameraCancelAction->setEnabled(false); // ----------------------------------------------------------------- d->cameraInfoAction = new QAction(QIcon::fromTheme(QLatin1String("camera-photo")), i18nc("@action Information about camera", "Information"), this); connect(d->cameraInfoAction, SIGNAL(triggered()), this, SLOT(slotInformation())); ac->addAction(QLatin1String("importui_info"), d->cameraInfoAction); d->cameraActions->addAction(d->cameraInfoAction); // ----------------------------------------------------------------- d->cameraCaptureAction = new QAction(QIcon::fromTheme(QLatin1String("webcamreceive")), i18nc("@action Capture photo from camera", "Capture"), this); connect(d->cameraCaptureAction, SIGNAL(triggered()), this, SLOT(slotCapture())); ac->addAction(QLatin1String("importui_capture"), d->cameraCaptureAction); d->cameraActions->addAction(d->cameraCaptureAction); // ----------------------------------------------------------------- QAction* const closeAction = buildStdAction(StdCloseAction, this, SLOT(close()), this); ac->addAction(QLatin1String("importui_close"), closeAction); // -- Edit menu ---------------------------------------------------- d->selectAllAction = new QAction(i18nc("@action:inmenu", "Select All"), this); connect(d->selectAllAction, SIGNAL(triggered()), d->view, SLOT(slotSelectAll())); ac->addAction(QLatin1String("importui_selectall"), d->selectAllAction); ac->setDefaultShortcut(d->selectAllAction, Qt::CTRL + Qt::Key_A); d->cameraActions->addAction(d->selectAllAction); // ----------------------------------------------------------------- d->selectNoneAction = new QAction(i18nc("@action:inmenu", "Select None"), this); connect(d->selectNoneAction, SIGNAL(triggered()), d->view, SLOT(slotSelectNone())); ac->addAction(QLatin1String("importui_selectnone"), d->selectNoneAction); ac->setDefaultShortcut(d->selectNoneAction, Qt::CTRL + Qt::SHIFT + Qt::Key_A); d->cameraActions->addAction(d->selectNoneAction); // ----------------------------------------------------------------- d->selectInvertAction = new QAction(i18nc("@action:inmenu", "Invert Selection"), this); connect(d->selectInvertAction, SIGNAL(triggered()), d->view, SLOT(slotSelectInvert())); ac->addAction(QLatin1String("importui_selectinvert"), d->selectInvertAction); ac->setDefaultShortcut(d->selectInvertAction, Qt::CTRL + Qt::Key_Asterisk); d->cameraActions->addAction(d->selectInvertAction); // ----------------------------------------------------------- d->selectNewItemsAction = new QAction(QIcon::fromTheme(QLatin1String("folder-favorites")), i18nc("@action:inmenu", "Select New Items"), this); connect(d->selectNewItemsAction, SIGNAL(triggered()), this, SLOT(slotSelectNew())); ac->addAction(QLatin1String("importui_selectnewitems"), d->selectNewItemsAction); d->cameraActions->addAction(d->selectNewItemsAction); // ----------------------------------------------------------- d->selectLockedItemsAction = new QAction(QIcon::fromTheme(QLatin1String("object-locked")), i18nc("@action:inmenu", "Select Locked Items"), this); connect(d->selectLockedItemsAction, SIGNAL(triggered()), this, SLOT(slotSelectLocked())); ac->addAction(QLatin1String("importui_selectlockeditems"), d->selectLockedItemsAction); ac->setDefaultShortcut(d->selectLockedItemsAction, Qt::CTRL + Qt::Key_L); d->cameraActions->addAction(d->selectLockedItemsAction); // --- Download actions ---------------------------------------------------- d->downloadAction = new QMenu(i18nc("@title:menu", "Download"), this); d->downloadAction->setIcon(QIcon::fromTheme(QLatin1String("document-save"))); ac->addAction(QLatin1String("importui_imagedownload"), d->downloadAction->menuAction()); d->cameraActions->addAction(d->downloadAction->menuAction()); d->downloadNewAction = new QAction(QIcon::fromTheme(QLatin1String("folder-favorites")), i18nc("@action", "Download New"), this); connect(d->downloadNewAction, SIGNAL(triggered()), this, SLOT(slotDownloadNew())); ac->addAction(QLatin1String("importui_imagedownloadnew"), d->downloadNewAction); ac->setDefaultShortcut(d->downloadNewAction, Qt::CTRL + Qt::Key_N); d->downloadAction->addAction(d->downloadNewAction); d->cameraActions->addAction(d->downloadNewAction); d->downloadSelectedAction = new QAction(QIcon::fromTheme(QLatin1String("document-save")), i18nc("@action", "Download Selected"), this); connect(d->downloadSelectedAction, SIGNAL(triggered()), this, SLOT(slotDownloadSelected())); ac->addAction(QLatin1String("importui_imagedownloadselected"), d->downloadSelectedAction); d->downloadSelectedAction->setEnabled(false); d->downloadAction->addAction(d->downloadSelectedAction); d->cameraActions->addAction(d->downloadSelectedAction); d->downloadAllAction = new QAction(QIcon::fromTheme(QLatin1String("document-save")), i18nc("@action", "Download All"), this); connect(d->downloadAllAction, SIGNAL(triggered()), this, SLOT(slotDownloadAll())); ac->addAction(QLatin1String("importui_imagedownloadall"), d->downloadAllAction); d->downloadAction->addAction(d->downloadAllAction); d->cameraActions->addAction(d->downloadAllAction); // ------------------------------------------------------------------------- d->downloadDelNewAction = new QAction(i18nc("@action", "Download && Delete New"), this); connect(d->downloadDelNewAction, SIGNAL(triggered()), this, SLOT(slotDownloadAndDeleteNew())); ac->addAction(QLatin1String("importui_imagedownloaddeletenew"), d->downloadDelNewAction); ac->setDefaultShortcut(d->downloadDelNewAction, Qt::CTRL + Qt::SHIFT + Qt::Key_N); d->cameraActions->addAction(d->downloadDelNewAction); // ----------------------------------------------------------------- d->downloadDelSelectedAction = new QAction(i18nc("@action", "Download && Delete Selected"), this); connect(d->downloadDelSelectedAction, SIGNAL(triggered()), this, SLOT(slotDownloadAndDeleteSelected())); ac->addAction(QLatin1String("importui_imagedownloaddeleteselected"), d->downloadDelSelectedAction); d->downloadDelSelectedAction->setEnabled(false); d->cameraActions->addAction(d->downloadDelSelectedAction); // ------------------------------------------------------------------------- d->downloadDelAllAction = new QAction(i18nc("@action", "Download && Delete All"), this); connect(d->downloadDelAllAction, SIGNAL(triggered()), this, SLOT(slotDownloadAndDeleteAll())); ac->addAction(QLatin1String("importui_imagedownloaddeleteall"), d->downloadDelAllAction); d->cameraActions->addAction(d->downloadDelAllAction); // ------------------------------------------------------------------------- d->uploadAction = new QAction(QIcon::fromTheme(QLatin1String("media-flash-sd-mmc")), i18nc("@action", "Upload..."), this); connect(d->uploadAction, SIGNAL(triggered()), this, SLOT(slotUpload())); ac->addAction(QLatin1String("importui_imageupload"), d->uploadAction); ac->setDefaultShortcut(d->uploadAction, Qt::CTRL + Qt::Key_U); d->cameraActions->addAction(d->uploadAction); // ------------------------------------------------------------------------- d->lockAction = new QAction(QIcon::fromTheme(QLatin1String("object-locked")), i18nc("@action", "Toggle Lock"), this); connect(d->lockAction, SIGNAL(triggered()), this, SLOT(slotToggleLock())); ac->addAction(QLatin1String("importui_imagelock"), d->lockAction); ac->setDefaultShortcut(d->lockAction, Qt::CTRL + Qt::Key_G); d->cameraActions->addAction(d->lockAction); // ------------------------------------------------------------------------- d->markAsDownloadedAction = new QAction(QIcon::fromTheme(QLatin1String("dialog-ok-apply")), i18nc("@action", "Mark as downloaded"), this); connect(d->markAsDownloadedAction, SIGNAL(triggered()), this, SLOT(slotMarkAsDownloaded())); ac->addAction(QLatin1String("importui_imagemarkasdownloaded"), d->markAsDownloadedAction); d->cameraActions->addAction(d->markAsDownloadedAction); // --- Delete actions ------------------------------------------------------ d->deleteAction = new QMenu(i18nc("@title:menu", "Delete"), this); d->deleteAction->setIcon(QIcon::fromTheme(QLatin1String("user-trash"))); ac->addAction(QLatin1String("importui_delete"), d->deleteAction->menuAction()); d->cameraActions->addAction(d->deleteAction->menuAction()); d->deleteSelectedAction = new QAction(QIcon::fromTheme(QLatin1String("edit-delete")), i18nc("@action", "Delete Selected"), this); connect(d->deleteSelectedAction, SIGNAL(triggered()), this, SLOT(slotDeleteSelected())); ac->addAction(QLatin1String("importui_imagedeleteselected"), d->deleteSelectedAction); ac->setDefaultShortcut(d->deleteSelectedAction, Qt::Key_Delete); d->deleteSelectedAction->setEnabled(false); d->deleteAction->addAction(d->deleteSelectedAction); d->cameraActions->addAction(d->deleteSelectedAction); d->deleteAllAction = new QAction(QIcon::fromTheme(QLatin1String("edit-delete")), i18nc("@action", "Delete All"), this); connect(d->deleteAllAction, SIGNAL(triggered()), this, SLOT(slotDeleteAll())); ac->addAction(QLatin1String("importui_imagedeleteall"), d->deleteAllAction); d->deleteAction->addAction(d->deleteAllAction); d->cameraActions->addAction(d->deleteAllAction); d->deleteNewAction = new QAction(QIcon::fromTheme(QLatin1String("edit-delete")), i18nc("@action", "Delete New"), this); connect(d->deleteNewAction, SIGNAL(triggered()), this, SLOT(slotDeleteNew())); ac->addAction(QLatin1String("importui_imagedeletenew"), d->deleteNewAction); d->deleteAction->addAction(d->deleteNewAction); d->cameraActions->addAction(d->deleteNewAction); // --- Icon view, items preview, and map actions ------------------------------------------------------ d->imageViewSelectionAction = new KSelectAction(QIcon::fromTheme(QLatin1String("view-preview")), i18nc("@title:group", "Views"), this); ac->addAction(QLatin1String("importui_view_selection"), d->imageViewSelectionAction); d->iconViewAction = new QAction(QIcon::fromTheme(QLatin1String("view-list-icons")), i18nc("@action Go to thumbnails (icon) view", "Thumbnails"), this); d->iconViewAction->setCheckable(true); ac->addAction(QLatin1String("importui_icon_view"), d->iconViewAction); connect(d->iconViewAction, SIGNAL(triggered()), d->view, SLOT(slotIconView())); d->imageViewSelectionAction->addAction(d->iconViewAction); d->camItemPreviewAction = new QAction(QIcon::fromTheme(QLatin1String("view-preview")), i18nc("@action View the selected image", "Preview Item"), this); d->camItemPreviewAction->setCheckable(true); ac->addAction(QLatin1String("importui_item_view"), d->camItemPreviewAction); ac->setDefaultShortcut(d->camItemPreviewAction, Qt::Key_F3); connect(d->camItemPreviewAction, SIGNAL(triggered()), d->view, SLOT(slotImagePreview())); d->imageViewSelectionAction->addAction(d->camItemPreviewAction); #ifdef HAVE_MARBLE d->mapViewAction = new QAction(QIcon::fromTheme(QLatin1String("globe")), i18nc("@action Switch to map view", "Map"), this); d->mapViewAction->setCheckable(true); ac->addAction(QLatin1String("importui_map_view"), d->mapViewAction); connect(d->mapViewAction, SIGNAL(triggered()), d->view, SLOT(slotMapWidgetView())); d->imageViewSelectionAction->addAction(d->mapViewAction); #endif // HAVE_MARBLE /// @todo Add table view stuff here // -- Item Sorting ------------------------------------------------------------ d->itemSortAction = new KSelectAction(i18nc("@title:menu", "&Sort Items"), this); d->itemSortAction->setWhatsThis(i18nc("@info:whatsthis", "The value by which the items are sorted in the thumbnail view")); QSignalMapper* const imageSortMapper = new QSignalMapper(this); connect(imageSortMapper, SIGNAL(mapped(int)), d->view, SLOT(slotSortImagesBy(int))); ac->addAction(QLatin1String("item_sort"), d->itemSortAction); // map to CamItemSortSettings enum QAction* const sortByNameAction = d->itemSortAction->addAction(i18nc("item:inmenu Sort by", "By Name")); QAction* const sortByPathAction = d->itemSortAction->addAction(i18nc("item:inmenu Sort by", "By Path")); QAction* const sortByDateAction = d->itemSortAction->addAction(i18nc("item:inmenu Sort by", "By Date")); //TODO: Implement sort by creation date. QAction* const sortByFileSizeAction = d->itemSortAction->addAction(i18nc("item:inmenu Sort by", "By Size")); QAction* const sortByRatingAction = d->itemSortAction->addAction(i18nc("item:inmenu Sort by", "By Rating")); QAction* const sortByDownloadAction = d->itemSortAction->addAction(i18nc("item:inmenu Sort by", "By Download State")); connect(sortByNameAction, SIGNAL(triggered()), imageSortMapper, SLOT(map())); connect(sortByPathAction, SIGNAL(triggered()), imageSortMapper, SLOT(map())); connect(sortByDateAction, SIGNAL(triggered()), imageSortMapper, SLOT(map())); //TODO: Implement sort by creation date. connect(sortByFileSizeAction, SIGNAL(triggered()), imageSortMapper, SLOT(map())); connect(sortByRatingAction, SIGNAL(triggered()), imageSortMapper, SLOT(map())); connect(sortByDownloadAction, SIGNAL(triggered()), imageSortMapper, SLOT(map())); imageSortMapper->setMapping(sortByNameAction, (int)CamItemSortSettings::SortByFileName); imageSortMapper->setMapping(sortByPathAction, (int)CamItemSortSettings::SortByFilePath); imageSortMapper->setMapping(sortByDateAction, (int)CamItemSortSettings::SortByCreationDate); //TODO: Implement sort by creation date. imageSortMapper->setMapping(sortByFileSizeAction, (int)CamItemSortSettings::SortByFileSize); imageSortMapper->setMapping(sortByRatingAction, (int)CamItemSortSettings::SortByRating); imageSortMapper->setMapping(sortByDownloadAction, (int)CamItemSortSettings::SortByDownloadState); d->itemSortAction->setCurrentItem(ImportSettings::instance()->getImageSortBy()); // -- Item Sort Order ------------------------------------------------------------ d->itemSortOrderAction = new KSelectAction(i18nc("@title:inmenu", "Item Sorting &Order"), this); d->itemSortOrderAction->setWhatsThis(i18nc("@info:whatsthis", "Defines whether items are sorted in ascending or descending manner.")); QSignalMapper* const imageSortOrderMapper = new QSignalMapper(this); connect(imageSortOrderMapper, SIGNAL(mapped(int)), d->view, SLOT(slotSortImagesOrder(int))); ac->addAction(QLatin1String("item_sort_order"), d->itemSortOrderAction); QAction* const sortAscendingAction = d->itemSortOrderAction->addAction(QIcon::fromTheme(QLatin1String("view-sort-ascending")), i18nc("@item:inmenu Sorting Order", "Ascending")); QAction* const sortDescendingAction = d->itemSortOrderAction->addAction(QIcon::fromTheme(QLatin1String("view-sort-descending")), i18nc("@item:inmenu Sorting Order", "Descending")); connect(sortAscendingAction, SIGNAL(triggered()), imageSortOrderMapper, SLOT(map())); connect(sortDescendingAction, SIGNAL(triggered()), imageSortOrderMapper, SLOT(map())); imageSortOrderMapper->setMapping(sortAscendingAction, (int)CamItemSortSettings::AscendingOrder); imageSortOrderMapper->setMapping(sortDescendingAction, (int)CamItemSortSettings::DescendingOrder); d->itemSortOrderAction->setCurrentItem(ImportSettings::instance()->getImageSortOrder()); // -- Item Grouping ------------------------------------------------------------ d->itemsGroupAction = new KSelectAction(i18nc("@title:menu", "&Group Items"), this); d->itemsGroupAction->setWhatsThis(i18nc("@info:whatsthis", "The categories in which the items in the thumbnail view are displayed")); QSignalMapper* const itemSeparationMapper = new QSignalMapper(this); connect(itemSeparationMapper, SIGNAL(mapped(int)), d->view, SLOT(slotSeparateImages(int))); ac->addAction(QLatin1String("item_group"), d->itemsGroupAction); // map to CamItemSortSettings enum QAction* const noCategoriesAction = d->itemsGroupAction->addAction(i18nc("@item:inmenu Group Items", "Flat List")); QAction* const groupByFolderAction = d->itemsGroupAction->addAction(i18nc("@item:inmenu Group Items", "By Folder")); QAction* const groupByFormatAction = d->itemsGroupAction->addAction(i18nc("@item:inmenu Group Items", "By Format")); QAction* const groupByDateAction = d->itemsGroupAction->addAction(i18nc("@item:inmenu Group Items", "By Date")); connect(noCategoriesAction, SIGNAL(triggered()), itemSeparationMapper, SLOT(map())); connect(groupByFolderAction, SIGNAL(triggered()), itemSeparationMapper, SLOT(map())); connect(groupByFormatAction, SIGNAL(triggered()), itemSeparationMapper, SLOT(map())); connect(groupByDateAction, SIGNAL(triggered()), itemSeparationMapper, SLOT(map())); itemSeparationMapper->setMapping(noCategoriesAction, (int)CamItemSortSettings::NoCategories); itemSeparationMapper->setMapping(groupByFolderAction, (int)CamItemSortSettings::CategoryByFolder); itemSeparationMapper->setMapping(groupByFormatAction, (int)CamItemSortSettings::CategoryByFormat); itemSeparationMapper->setMapping(groupByDateAction, (int)CamItemSortSettings::CategoryByDate); d->itemsGroupAction->setCurrentItem(ImportSettings::instance()->getImageSeparationMode()); // -- Standard 'View' menu actions --------------------------------------------- d->increaseThumbsAction = buildStdAction(StdZoomInAction, d->view, SLOT(slotZoomIn()), this); d->increaseThumbsAction->setEnabled(false); QKeySequence keysPlus(d->increaseThumbsAction->shortcut()[0], Qt::Key_Plus); ac->addAction(QLatin1String("importui_zoomplus"), d->increaseThumbsAction); ac->setDefaultShortcut(d->increaseThumbsAction, keysPlus); d->decreaseThumbsAction = buildStdAction(StdZoomOutAction, d->view, SLOT(slotZoomOut()), this); d->decreaseThumbsAction->setEnabled(false); QKeySequence keysMinus(d->decreaseThumbsAction->shortcut()[0], Qt::Key_Minus); ac->addAction(QLatin1String("importui_zoomminus"), d->decreaseThumbsAction); ac->setDefaultShortcut(d->decreaseThumbsAction, keysMinus); d->zoomFitToWindowAction = new QAction(QIcon::fromTheme(QLatin1String("zoom-fit-best")), i18nc("@action:inmenu", "Fit to &Window"), this); connect(d->zoomFitToWindowAction, SIGNAL(triggered()), d->view, SLOT(slotFitToWindow())); ac->addAction(QLatin1String("import_zoomfit2window"), d->zoomFitToWindowAction); ac->setDefaultShortcut(d->zoomFitToWindowAction, Qt::ALT + Qt::CTRL + Qt::Key_E); d->zoomTo100percents = new QAction(QIcon::fromTheme(QLatin1String("zoom-original")), i18nc("@action:inmenu", "Zoom to 100%"), this); connect(d->zoomTo100percents, SIGNAL(triggered()), d->view, SLOT(slotZoomTo100Percents())); ac->addAction(QLatin1String("import_zoomto100percents"), d->zoomTo100percents); ac->setDefaultShortcut(d->zoomTo100percents, Qt::CTRL + Qt::Key_Period); // ------------------------------------------------------------------------------------------------ d->viewCMViewAction = new QAction(QIcon::fromTheme(QLatin1String("video-display")), i18n("Color-Managed View"), this); d->viewCMViewAction->setCheckable(true); connect(d->viewCMViewAction, SIGNAL(triggered()), this, SLOT(slotToggleColorManagedView())); ac->addAction(QLatin1String("color_managed_view"), d->viewCMViewAction); ac->setDefaultShortcut(d->viewCMViewAction, Qt::Key_F12); // ------------------------------------------------------------------------------------------------ createFullScreenAction(QLatin1String("importui_fullscreen")); createSidebarActions(); d->showLogAction = new QAction(QIcon::fromTheme(QLatin1String("edit-find")), i18nc("@option:check", "Show History"), this); d->showLogAction->setCheckable(true); connect(d->showLogAction, SIGNAL(triggered()), this, SLOT(slotShowLog())); ac->addAction(QLatin1String("importui_showlog"), d->showLogAction); ac->setDefaultShortcut(d->showLogAction, Qt::CTRL + Qt::Key_H); d->showBarAction = new QAction(QIcon::fromTheme(QLatin1String("view-choose")), i18nc("@option:check", "Show Thumbbar"), this); d->showBarAction->setCheckable(true); connect(d->showBarAction, SIGNAL(triggered()), this, SLOT(slotToggleShowBar())); ac->addAction(QLatin1String("showthumbs"), d->showBarAction); ac->setDefaultShortcut(d->showBarAction, Qt::CTRL+Qt::Key_T); d->showBarAction->setEnabled(false); // --------------------------------------------------------------------------------- ThemeManager::instance()->registerThemeActions(this); // Standard 'Help' menu actions createHelpActions(); // Provides a menu entry that allows showing/hiding the toolbar(s) setStandardToolBarMenuEnabled(true); // Provides a menu entry that allows showing/hiding the statusbar createStandardStatusBarAction(); // Standard 'Configure' menu actions createSettingsActions(); // -- Keyboard-only actions added to ---------------------------------- QAction* const altBackwardAction = new QAction(i18nc("@action", "Previous Image"), this); ac->addAction(QLatin1String("importui_backward_shift_space"), altBackwardAction); ac->setDefaultShortcut(altBackwardAction, Qt::SHIFT + Qt::Key_Space); connect(altBackwardAction, SIGNAL(triggered()), d->view, SLOT(slotPrevItem())); // --------------------------------------------------------------------------------- d->connectAction = new QAction(QIcon::fromTheme(QLatin1String("view-refresh")), i18nc("@action Connection failed, try again?", "Retry"), this); connect(d->connectAction, SIGNAL(triggered()), d->controller, SLOT(slotConnect())); createGUI(xmlFile()); cleanupActions(); showMenuBarAction()->setChecked(!menuBar()->isHidden()); // NOTE: workaround for bug #171080 } void ImportUI::updateActions() { CamItemInfoList list = d->view->selectedCamItemInfos(); bool hasSelection = list.count() > 0; d->downloadDelSelectedAction->setEnabled(hasSelection && d->controller->cameraDeleteSupport()); d->deleteSelectedAction->setEnabled(hasSelection && d->controller->cameraDeleteSupport()); d->camItemPreviewAction->setEnabled(hasSelection && cameraUseUMSDriver()); d->downloadSelectedAction->setEnabled(hasSelection); d->lockAction->setEnabled(hasSelection); if (hasSelection) { // only enable "Mark as downloaded" if at least one // selected image has not been downloaded bool haveNotDownloadedItem = false; foreach(const CamItemInfo& info, list) { haveNotDownloadedItem = !(info.downloaded == CamItemInfo::DownloadedYes); if (haveNotDownloadedItem) { break; } } d->markAsDownloadedAction->setEnabled(haveNotDownloadedItem); } else { d->markAsDownloadedAction->setEnabled(false); } } void ImportUI::setupConnections() { //TODO: Needs testing. connect(d->advancedSettings, SIGNAL(signalDownloadNameChanged()), this, SLOT(slotUpdateDownloadName())); connect(d->dngConvertSettings, SIGNAL(signalDownloadNameChanged()), this, SLOT(slotUpdateDownloadName())); connect(d->historyView, SIGNAL(signalEntryClicked(QVariant)), this, SLOT(slotHistoryEntryClicked(QVariant))); connect(IccSettings::instance(), SIGNAL(settingsChanged()), this, SLOT(slotColorManagementOptionsChanged())); // ------------------------------------------------------------------------- connect(d->view, SIGNAL(signalImageSelected(CamItemInfoList,CamItemInfoList)), this, SLOT(slotImageSelected(CamItemInfoList,CamItemInfoList))); connect(d->view, SIGNAL(signalSwitchedToPreview()), this, SLOT(slotSwitchedToPreview())); connect(d->view, SIGNAL(signalSwitchedToIconView()), this, SLOT(slotSwitchedToIconView())); connect(d->view, SIGNAL(signalSwitchedToMapView()), this, SLOT(slotSwitchedToMapView())); connect(d->view, SIGNAL(signalNewSelection(bool)), this, SLOT(slotNewSelection(bool))); // ------------------------------------------------------------------------- connect(d->view, SIGNAL(signalThumbSizeChanged(int)), this, SLOT(slotThumbSizeChanged(int))); connect(d->view, SIGNAL(signalZoomChanged(double)), this, SLOT(slotZoomChanged(double))); connect(d->zoomBar, SIGNAL(signalZoomSliderChanged(int)), this, SLOT(slotZoomSliderChanged(int))); connect(d->zoomBar, SIGNAL(signalZoomValueEdited(double)), d->view, SLOT(setZoomFactor(double))); connect(this, SIGNAL(signalWindowHasMoved()), d->zoomBar, SLOT(slotUpdateTrackerPos())); // ------------------------------------------------------------------------- connect(CollectionManager::instance(), SIGNAL(locationStatusChanged(CollectionLocation,int)), this, SLOT(slotCollectionLocationStatusChanged(CollectionLocation,int))); connect(ApplicationSettings::instance(), SIGNAL(setupChanged()), this, SLOT(slotSetupChanged())); connect(d->renameCustomizer, SIGNAL(signalChanged()), this, SLOT(slotUpdateDownloadName())); } void ImportUI::setupStatusBar() { d->statusProgressBar = new StatusProgressBar(statusBar()); d->statusProgressBar->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); d->statusProgressBar->setNotificationTitle(d->cameraTitle, QIcon::fromTheme(QLatin1String("camera-photo"))); statusBar()->addWidget(d->statusProgressBar, 100); //------------------------------------------------------------------------------ d->cameraFreeSpace = new FreeSpaceWidget(statusBar(), 100); if (cameraUseGPhotoDriver()) { d->cameraFreeSpace->setMode(FreeSpaceWidget::GPhotoCamera); connect(d->controller, SIGNAL(signalFreeSpace(ulong,ulong)), this, SLOT(slotCameraFreeSpaceInfo(ulong,ulong))); } else { d->cameraFreeSpace->setMode(FreeSpaceWidget::UMSCamera); d->cameraFreeSpace->setPath(d->controller->cameraPath()); } statusBar()->addWidget(d->cameraFreeSpace, 1); //------------------------------------------------------------------------------ d->albumLibraryFreeSpace = new FreeSpaceWidget(statusBar(), 100); d->albumLibraryFreeSpace->setMode(FreeSpaceWidget::AlbumLibrary); statusBar()->addWidget(d->albumLibraryFreeSpace, 1); refreshCollectionFreeSpace(); //------------------------------------------------------------------------------ //TODO: Replace it with FilterStatusBar after advanced filtring is implemented. d->filterComboBox = new FilterComboBox(statusBar()); setFilter(d->filterComboBox->currentFilter()); statusBar()->addWidget(d->filterComboBox, 1); connect(d->filterComboBox, SIGNAL(filterChanged(Filter*)), this, SLOT(setFilter(Filter*))); //------------------------------------------------------------------------------ d->zoomBar = new DZoomBar(statusBar()); d->zoomBar->setZoomToFitAction(d->zoomFitToWindowAction); d->zoomBar->setZoomTo100Action(d->zoomTo100percents); d->zoomBar->setZoomPlusAction(d->increaseThumbsAction); d->zoomBar->setZoomMinusAction(d->decreaseThumbsAction); d->zoomBar->setBarMode(DZoomBar::ThumbsSizeCtrl); statusBar()->addPermanentWidget(d->zoomBar, 1); } void ImportUI::setupCameraController(const QString& model, const QString& port, const QString& path) { d->controller = new CameraController(this, d->cameraTitle, model, port, path); connect(d->controller, SIGNAL(signalConnected(bool)), this, SLOT(slotConnected(bool))); connect(d->controller, SIGNAL(signalLogMsg(QString,DHistoryView::EntryType,QString,QString)), this, SLOT(slotLogMsg(QString,DHistoryView::EntryType,QString,QString))); connect(d->controller, SIGNAL(signalCameraInformation(QString,QString,QString)), this, SLOT(slotCameraInformation(QString,QString,QString))); connect(d->controller, SIGNAL(signalBusy(bool)), this, SLOT(slotBusy(bool))); connect(d->controller, SIGNAL(signalFolderList(QStringList)), this, SLOT(slotFolderList(QStringList))); connect(d->controller, SIGNAL(signalDownloaded(QString,QString,int)), this, SLOT(slotDownloaded(QString,QString,int))); connect(d->controller, SIGNAL(signalDownloadComplete(QString,QString,QString,QString)), this, SLOT(slotDownloadComplete(QString,QString,QString,QString))); connect(d->controller, SIGNAL(signalSkipped(QString,QString)), this, SLOT(slotSkipped(QString,QString))); connect(d->controller, SIGNAL(signalDeleted(QString,QString,bool)), this, SLOT(slotDeleted(QString,QString,bool))); connect(d->controller, SIGNAL(signalLocked(QString,QString,bool)), this, SLOT(slotLocked(QString,QString,bool))); connect(d->controller, SIGNAL(signalMetadata(QString,QString,DMetadata)), this, SLOT(slotMetadata(QString,QString,DMetadata))); connect(d->controller, SIGNAL(signalUploaded(CamItemInfo)), this, SLOT(slotUploaded(CamItemInfo))); d->controller->start(); // Setup Thumbnails controller ------------------------------------------------------- d->camThumbsCtrl = new CameraThumbsCtrl(d->controller, this); } CameraThumbsCtrl* ImportUI::getCameraThumbsCtrl() const { return d->camThumbsCtrl; } void ImportUI::setupAccelerators() { KActionCollection *ac = actionCollection(); QAction* const escapeAction = new QAction(i18nc("@action", "Exit Preview Mode"), this); ac->addAction(QLatin1String("exit_preview_mode"), escapeAction); ac->setDefaultShortcut(escapeAction, Qt::Key_Escape); connect(escapeAction, SIGNAL(triggered()), this, SIGNAL(signalEscapePressed())); QAction* const nextImageAction = new QAction(i18nc("@action","Next Image"), this); nextImageAction->setIcon(QIcon::fromTheme(QLatin1String("go-next"))); ac->addAction(QLatin1String("next_image"), nextImageAction); ac->setDefaultShortcut(nextImageAction, Qt::Key_Space); connect(nextImageAction, SIGNAL(triggered()), d->view, SLOT(slotNextItem())); QAction* const previousImageAction = new QAction(i18nc("@action", "Previous Image"), this); previousImageAction->setIcon(QIcon::fromTheme(QLatin1String("go-previous"))); ac->addAction(QLatin1String("previous_image"), previousImageAction); ac->setDefaultShortcuts(previousImageAction, QList() << Qt::Key_Backspace << Qt::SHIFT+Qt::Key_Space); connect(previousImageAction, SIGNAL(triggered()), d->view, SLOT(slotPrevItem())); QAction* const firstImageAction = new QAction(i18nc("@action Go to first image", "First Image"), this); ac->addAction(QLatin1String("first_image"), firstImageAction); ac->setDefaultShortcut(firstImageAction, Qt::Key_Home); connect(firstImageAction, SIGNAL(triggered()), d->view, SLOT(slotFirstItem())); QAction* const lastImageAction = new QAction(i18nc("@action Go to last image", "Last Image"), this); ac->addAction(QLatin1String("last_image"), lastImageAction); ac->setDefaultShortcut(lastImageAction, Qt::Key_End); connect(lastImageAction, SIGNAL(triggered()), d->view, SLOT(slotLastItem())); } void ImportUI::readSettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(d->configGroupName); readFullScreenSettings(group); d->showBarAction->setChecked(ImportSettings::instance()->getShowThumbbar()); d->showLogAction->setChecked(group.readEntry(QLatin1String("ShowLog"), false)); d->albumCustomizer->readSettings(group); d->advancedSettings->readSettings(group); d->dngConvertSettings->readSettings(group); d->scriptingSettings->readSettings(group); d->advBox->readSettings(group); d->splitter->restoreState(group); slotShowLog(); } void ImportUI::saveSettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(d->configGroupName); ImportSettings::instance()->setShowThumbbar(d->showBarAction->isChecked()); ImportSettings::instance()->saveSettings(); group.writeEntry(QLatin1String("ShowLog"), d->showLogAction->isChecked()); d->albumCustomizer->saveSettings(group); d->advancedSettings->saveSettings(group); d->dngConvertSettings->saveSettings(group); d->scriptingSettings->saveSettings(group); d->advBox->writeSettings(group); d->rightSideBar->saveState(); d->splitter->saveState(group); d->filterComboBox->saveSettings(); config->sync(); } bool ImportUI::isBusy() const { return d->busy; } bool ImportUI::isClosed() const { return d->closed; } QString ImportUI::cameraTitle() const { return d->cameraTitle; } DownloadSettings ImportUI::downloadSettings() const { DownloadSettings settings = d->advancedSettings->settings(); d->dngConvertSettings->settings(&settings); d->scriptingSettings->settings(&settings); return settings; } void ImportUI::setInitialSorting() { d->view->slotSeparateImages(ImportSettings::instance()->getImageSeparationMode()); d->view->slotSortImagesBy(ImportSettings::instance()->getImageSortBy()); d->view->slotSortImagesOrder(ImportSettings::instance()->getImageSortOrder()); } void ImportUI::slotCancelButton() { d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode, i18nc("@info:status", "Canceling current operation, please wait...")); d->controller->slotCancel(); //d->historyUpdater->slotCancel(); d->currentlyDeleting.clear(); refreshFreeSpace(); } void ImportUI::refreshFreeSpace() { if (cameraUseGPhotoDriver()) { d->controller->getFreeSpace(); } else { d->cameraFreeSpace->refresh(); } } void ImportUI::closeEvent(QCloseEvent* e) { if (dialogClosed()) { DXmlGuiWindow::closeEvent(e); } else { e->ignore(); } } void ImportUI::moveEvent(QMoveEvent* e) { Q_UNUSED(e) emit signalWindowHasMoved(); } void ImportUI::slotClose() { /* FIXME if (dialogClosed()) reject(); */ } bool ImportUI::dialogClosed() { if (d->closed) { return true; } if (isBusy()) { if (QMessageBox::question(this, qApp->applicationName(), i18nc("@info", "Do you want to close the dialog " "and cancel the current operation?"), QMessageBox::Yes | QMessageBox::No ) == QMessageBox::No) { return false; } } d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode, i18nc("@info:status", "Disconnecting from camera, please wait...")); if (isBusy()) { d->controller->slotCancel(); // will be read in slotBusy later and finishDialog // will be called only when everything is finished d->closed = true; } else { d->closed = true; finishDialog(); } return true; } void ImportUI::finishDialog() { // Look if an item have been downloaded to computer during camera GUI session. // If yes, update the starting number value used to rename camera items from camera list. if (d->view->downloadedCamItemInfos() > 0) { CameraList* const clist = CameraList::defaultList(); if (clist) { clist->changeCameraStartIndex(d->cameraTitle, d->renameCustomizer->startIndex()); } } if (!d->foldersToScan.isEmpty()) { // TODO is this note valid anymore with new progress handling? // When a directory is created, a watch is put on it to spot new files // but it can occur that the file is copied there before the watch is // completely setup. That is why as an extra safeguard run CollectionScanner // over the folders we used. Bug: 119201 d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode, i18nc("@info:status", "Scanning for new files, please wait...")); NewItemsFinder* const tool = new NewItemsFinder(NewItemsFinder::ScheduleCollectionScan, d->foldersToScan.toList()); tool->start(); d->foldersToScan.clear(); } deleteLater(); if (!d->lastDestURL.isEmpty()) { emit signalLastDestination(d->lastDestURL); } saveSettings(); } void ImportUI::slotBusy(bool val) { if (!val) // Camera is available for actions. { if (!d->busy) { return; } d->busy = false; d->cameraCancelAction->setEnabled(false); d->cameraActions->setEnabled(true); d->advBox->setEnabled(true); d->view->setEnabled(true); // selection-dependent update of lockAction, markAsDownloadedAction, // downloadSelectedAction, downloadDelSelectedAction, deleteSelectedAction updateActions(); m_animLogo->stop(); d->statusProgressBar->setProgressValue(0); d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode, i18nc("@info:status", "Ready")); // like WDestructiveClose, but after camera controller operation has safely finished if (d->closed) { finishDialog(); } } else // Camera is busy. { if (d->busy) { return; } if (!m_animLogo->running()) { m_animLogo->start(); } d->busy = true; d->cameraActions->setEnabled(false); } } void ImportUI::slotZoomSliderChanged(int size) { d->view->setThumbSize(size); } void ImportUI::slotZoomChanged(double zoom) { double zmin = d->view->zoomMin(); double zmax = d->view->zoomMax(); d->zoomBar->setZoom(zoom, zmin, zmax); if (!fullScreenIsActive()) { d->zoomBar->triggerZoomTrackerToolTip(); } } void ImportUI::slotThumbSizeChanged(int size) { d->zoomBar->setThumbsSize(size); if (!fullScreenIsActive()) { d->zoomBar->triggerZoomTrackerToolTip(); } } void ImportUI::slotConnected(bool val) { if (!val) { d->errorWidget->setText(i18nc("@info", "Failed to connect to the camera. " "Please make sure it is connected " "properly and turned on.")); d->errorWidget->actions().clear(); d->errorWidget->addAction(d->connectAction); d->errorWidget->addAction(d->showPreferencesAction); d->errorWidget->animatedShow(); } else { // disable unsupported actions d->uploadAction->setEnabled(d->controller->cameraUploadSupport()); d->cameraCaptureAction->setEnabled(d->controller->cameraCaptureImageSupport()); d->errorWidget->hide(); refreshFreeSpace(); // FIXME ugly c&p from slotFolderList KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(d->configGroupName); bool useMetadata = group.readEntry(d->configUseFileMetadata, false); d->controller->listRootFolder(useMetadata); } } void ImportUI::slotFolderList(const QStringList& folderList) { if (d->closed) { return; } d->statusProgressBar->setProgressValue(0); d->statusProgressBar->setProgressTotalSteps(0); KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(d->configGroupName); bool useMetadata = group.readEntry(d->configUseFileMetadata, false); // when getting a list of subfolders, request their contents and also their subfolders for (QStringList::const_iterator it = folderList.constBegin(); it != folderList.constEnd(); ++it) { d->controller->listFiles(*it, useMetadata); d->controller->listFolders(*it); } } void ImportUI::setFilter(Filter *filter) { d->view->importFilterModel()->setFilter(filter); } void ImportUI::slotCapture() { if (d->busy) { return; } CaptureDlg* const captureDlg = new CaptureDlg(this, d->controller, d->cameraTitle); captureDlg->show(); } void ImportUI::slotInformation() { if (d->busy) { return; } d->controller->getCameraInformation(); } void ImportUI::slotCameraInformation(const QString& summary, const QString& manual, const QString& about) { CameraInfoDialog* const infoDlg = new CameraInfoDialog(this, summary, manual, about); infoDlg->show(); } void ImportUI::slotUpload() { if (d->busy) { return; } QList urls = ImageDialog::getImageURLs(this, QUrl::fromLocalFile(CollectionManager::instance()->oneAlbumRootPath()), i18nc("@title:window", "Select Image to Upload")); if (!urls.isEmpty()) { slotUploadItems(urls); } } void ImportUI::slotUploadItems(const QList& urls) { if (d->busy) { return; } if (urls.isEmpty()) { return; } if (d->cameraFreeSpace->isValid()) { // Check if space require to upload new items in camera is enough. quint64 totalKbSize = 0; for (QList::const_iterator it = urls.constBegin() ; it != urls.constEnd() ; ++it) { QFileInfo fi((*it).toLocalFile()); totalKbSize += fi.size() / 1024; } if (totalKbSize >= d->cameraFreeSpace->kBAvail()) { QMessageBox::critical(this, qApp->applicationName(), i18nc("@info", "There is not enough free space on the Camera Medium " "to upload pictures.\n\n" "Space require: %1\n" "Available free space: %2", ImagePropertiesTab::humanReadableBytesCount(totalKbSize * 1024), ImagePropertiesTab::humanReadableBytesCount(d->cameraFreeSpace->kBAvail() * 1024))); return; } } QMap map = countItemsByFolders(); QPointer dlg = new CameraFolderDialog(this, map, d->controller->cameraTitle(), d->controller->cameraPath()); if (dlg->exec() != QDialog::Accepted) { delete dlg; return; } // since we access members here, check if the pointer is still valid if (!dlg) { return; } QString cameraFolder = dlg->selectedFolderPath(); for (QList::const_iterator it = urls.constBegin(); it != urls.constEnd(); ++it) { QFileInfo fi((*it).toLocalFile()); if (!fi.exists()) { continue; } if (fi.isDir()) { continue; } QString ext = QLatin1Char('.') + fi.completeSuffix(); QString name = fi.fileName(); name.truncate(fi.fileName().length() - ext.length()); bool ok; CamItemInfo uploadInfo; uploadInfo.folder = cameraFolder; uploadInfo.name = name + ext; while (d->view->hasImage(uploadInfo)) { QString msg(i18nc("@info", "Camera Folder %1 already contains the item %2.
" "Please enter a new filename (without extension):
", QDir::toNativeSeparators(cameraFolder), fi.fileName())); uploadInfo.name = QInputDialog::getText(this, i18nc("@title:window", "File already exists"), msg, QLineEdit::Normal, name, &ok) + ext; if (!ok) { return; } } d->controller->upload(fi, uploadInfo.name, cameraFolder); } delete dlg; } void ImportUI::slotUploaded(const CamItemInfo& /*itemInfo*/) { if (d->closed) { return; } refreshFreeSpace(); } void ImportUI::slotDownloadNew() { slotSelectNew(); QTimer::singleShot(0, this, SLOT(slotDownloadSelected())); } void ImportUI::slotDownloadAndDeleteNew() { slotSelectNew(); QTimer::singleShot(0, this, SLOT(slotDownloadAndDeleteSelected())); } void ImportUI::slotDownloadSelected() { slotDownload(true, false); } void ImportUI::slotDownloadAndDeleteSelected() { slotDownload(true, true); } void ImportUI::slotDownloadAll() { slotDownload(false, false); } void ImportUI::slotDownloadAndDeleteAll() { slotDownload(false, true); } void ImportUI::slotDownload(bool onlySelected, bool deleteAfter, Album* album) { if (d->albumCustomizer->folderDateFormat() == AlbumCustomizer::CustomDateFormat && !d->albumCustomizer->customDateFormatIsValid()) { QMessageBox::information(this, qApp->applicationName(), i18nc("@info", "Your custom target album date format is not valid. Please check your settings...")); return; } // See bug #143934: force to select all items to prevent problem // when !renameCustomizer->useDefault() ==> iconItem->getDownloadName() // can return an empty string in this case because it depends on selection. if (!onlySelected) { d->view->slotSelectAll(); } // Update the download names. slotNewSelection(d->view->selectedUrls().count() > 0); // -- Get the destination album from digiKam library --------------- PAlbum* pAlbum = 0; if (!album) { AlbumManager* const man = AlbumManager::instance(); // Check if default target album option is enabled. KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(d->configGroupName); bool useDefaultTarget = group.readEntry(d->configUseDefaultTargetAlbum, false); if (useDefaultTarget) { PAlbum* const pa = man->findPAlbum(group.readEntry(d->configDefaultTargetAlbumId, 0)); if (pa) { CollectionLocation cl = CollectionManager::instance()->locationForAlbumRootId(pa->albumRootId()); if (!cl.isAvailable() || cl.isNull()) { QMessageBox::information(this,qApp->applicationName(), i18nc("@info", "Collection which host your default target album set to process " "download from camera device is not available. Please select another one from " "camera configuration dialog.")); return; } } else { QMessageBox::information(this, qApp->applicationName(), i18nc("@info", "Your default target album set to process download " "from camera device is not available. Please select another one from " "camera configuration dialog.")); return; } pAlbum = pa; } else { AlbumList list = man->currentAlbums(); int albumId = 0; if (!list.isEmpty()) { albumId = group.readEntry(d->configLastTargetAlbum, list.first()->globalID()); } album = man->findAlbum(albumId); - album = 0; if (album && album->type() != Album::PHYSICAL) { album = 0; } QString header(i18nc("@info", "

Please select the destination album from the digiKam library to " "import the camera pictures into.

")); album = AlbumSelectDialog::selectAlbum(this, dynamic_cast(album), header); if (!album) { return; } pAlbum = dynamic_cast(album); group.writeEntry(d->configLastTargetAlbum, album->globalID()); } } else { pAlbum = dynamic_cast(album); } if (!pAlbum) { qCDebug(DIGIKAM_IMPORTUI_LOG) << "Destination Album is null"; return; } // -- Check disk space ------------------------ // See bug #139519: Always check free space available before to // download items selection from camera. if (!checkDiskSpace(pAlbum)) { return; } // -- Prepare and download camera items ------------------------ // Since we show camera items in reverse order, downloading need to be done also in reverse order. downloadCameraItems(pAlbum, onlySelected, deleteAfter); } void ImportUI::slotDownloaded(const QString& folder, const QString& file, int status) { // Is auto-rotate option checked? bool autoRotate = downloadSettings().autoRotate; bool previewItems = ImportSettings::instance()->getPreviewItemsWhileDownload(); CamItemInfo& info = d->view->camItemInfoRef(folder, file); if (!info.isNull()) { setDownloaded(info, status); if (status == CamItemInfo::DownloadStarted && previewItems) { emit signalPreviewRequested(info, true); } if (d->rightSideBar->url() == info.url()) { updateRightSideBar(info); } if (info.downloaded == CamItemInfo::DownloadedYes) { int curr = d->statusProgressBar->progressValue(); d->statusProgressBar->setProgressValue(curr + 1); d->renameCustomizer->setStartIndex(d->renameCustomizer->startIndex() + 1); CoreDbDownloadHistory::setDownloaded(QString::fromUtf8(d->controller->cameraMD5ID()), info.name, info.size, info.ctime); } } // Download all items is complete ? if (d->statusProgressBar->progressValue() == d->statusProgressBar->progressTotalSteps()) { if (d->deleteAfter) { // No need passive pop-up here, because we will ask to confirm items deletion with dialog. deleteItems(true, true); } else { // Pop-up a notification to inform user when all is done, and inform if auto-rotation will take place. if (autoRotate) { DNotificationWrapper(QLatin1String("cameradownloaded"), i18nc("@info Popup notification", "Images download finished, you can now detach your camera while the images will be auto-rotated"), this, windowTitle()); } else { DNotificationWrapper(QLatin1String("cameradownloaded"), i18nc("@info Popup notification", "Images download finished"), this, windowTitle()); } } } } void ImportUI::slotDownloadComplete(const QString&, const QString&, const QString& destFolder, const QString&) { ScanController::instance()->scheduleCollectionScanRelaxed(destFolder); autoRotateItems(); } void ImportUI::slotSkipped(const QString& folder, const QString& file) { CamItemInfo info = d->view->camItemInfo(folder, file); if (!info.isNull()) { setDownloaded(info, CamItemInfo::DownloadedNo); } int curr = d->statusProgressBar->progressValue(); d->statusProgressBar->setProgressValue(curr + 1); } void ImportUI::slotMarkAsDownloaded() { CamItemInfoList list = d->view->selectedCamItemInfos(); foreach(const CamItemInfo& info, list) { setDownloaded(d->view->camItemInfoRef(info.folder, info.name), CamItemInfo::DownloadedYes); CoreDbDownloadHistory::setDownloaded(QString::fromUtf8(d->controller->cameraMD5ID()), info.name, info.size, info.ctime); } } void ImportUI::slotToggleLock() { CamItemInfoList list = d->view->selectedCamItemInfos(); int count = list.count(); if (count > 0) { d->statusProgressBar->setProgressValue(0); d->statusProgressBar->setProgressTotalSteps(count); d->statusProgressBar->setProgressBarMode(StatusProgressBar::ProgressBarMode); } foreach(const CamItemInfo& info, list) { QString folder = info.folder; QString file = info.name; int writePerm = info.writePermissions; bool lock = true; // If item is currently locked, unlock it. if (writePerm == 0) { lock = false; } d->controller->lockFile(folder, file, lock); } } void ImportUI::slotLocked(const QString& folder, const QString& file, bool status) { if (status) { CamItemInfo& info = d->view->camItemInfoRef(folder, file); if (!info.isNull()) { toggleLock(info); if (d->rightSideBar->url() == info.url()) { updateRightSideBar(info); } } } int curr = d->statusProgressBar->progressValue(); d->statusProgressBar->setProgressValue(curr + 1); } void ImportUI::slotUpdateDownloadName() { QList selected = d->view->selectedUrls(); bool hasNoSelection = selected.count() == 0; CamItemInfoList list = d->view->allItems(); DownloadSettings settings = downloadSettings(); QString newName; foreach(const CamItemInfo& info, list) { CamItemInfo& refInfo = d->view->camItemInfoRef(info.folder, info.name); // qCDebug(DIGIKAM_IMPORTUI_LOG) << "slotDownloadNameChanged, old: " << refInfo.downloadName; newName = info.name; if (hasNoSelection || selected.contains(info.url())) { if (d->renameCustomizer->useDefault()) { newName = d->renameCustomizer->newName(info.name); } else if (d->renameCustomizer->isEnabled()) { newName = d->renameCustomizer->newName(info.url().toLocalFile()); } else if (!refInfo.downloadName.isEmpty()) { newName = refInfo.downloadName; } // Renaming files for the converting jpg to a lossless format // is from cameracontroller.cpp moved here. if (settings.convertJpeg && info.mime == QLatin1String("image/jpeg")) { QFileInfo fi(newName); QString ext = fi.suffix(); if (!ext.isEmpty()) { if (ext[0].isUpper() && ext[ext.length()-1].isUpper()) { ext = settings.losslessFormat.toUpper(); } else if (ext[0].isUpper()) { ext = settings.losslessFormat.toLower(); ext[0] = ext[0].toUpper(); } else { ext = settings.losslessFormat.toLower(); } newName = fi.completeBaseName() + QLatin1Char('.') + ext; } else { newName = newName + QLatin1Char('.') + settings.losslessFormat.toLower(); } } else if (settings.convertDng && info.mime == QLatin1String("image/x-raw")) { QFileInfo fi(newName); QString ext = fi.suffix(); if (!ext.isEmpty()) { if (ext[0].isUpper() && (ext[ext.length()-1].isUpper() || ext[ext.length()-1].isDigit())) { ext = QLatin1String("DNG"); } else if (ext[0].isUpper()) { ext = QLatin1String("Dng"); } else { ext = QLatin1String("dng"); } newName = fi.completeBaseName() + QLatin1Char('.') + ext; } else { newName = newName + QLatin1Char('.') + QLatin1String("dng"); } } } refInfo.downloadName = newName; // qCDebug(DIGIKAM_IMPORTUI_LOG) << "slotDownloadNameChanged, new: " << refInfo.downloadName; } d->view->updateIconView(); } //FIXME: the new pictures are marked by CameraHistoryUpdater which is not working yet. void ImportUI::slotSelectNew() { CamItemInfoList infos = d->view->allItems(); CamItemInfoList toBeSelected; foreach(const CamItemInfo& info, infos) { if (info.downloaded == CamItemInfo::DownloadedNo) { toBeSelected << info; } } d->view->setSelectedCamItemInfos(toBeSelected); } void ImportUI::slotSelectLocked() { CamItemInfoList allItems = d->view->allItems(); CamItemInfoList toBeSelected; foreach(const CamItemInfo& info, allItems) { if (info.writePermissions == 0) { toBeSelected << info; } } d->view->setSelectedCamItemInfos(toBeSelected); } void ImportUI::toggleLock(CamItemInfo& info) { if (!info.isNull()) { if (info.writePermissions == 0) { info.writePermissions = 1; } else { info.writePermissions = 0; } } } // TODO is this really necessary? why not just use the folders from listfolders call? QMap ImportUI::countItemsByFolders() const { QString path; QMap map; QMap::iterator it; CamItemInfoList infos = d->view->allItems(); foreach(const CamItemInfo& info, infos) { path = info.folder; if (!path.isEmpty() && path.endsWith(QLatin1Char('/'))) { path.truncate(path.length() - 1); } it = map.find(path); if (it == map.end()) { map.insert(path, 1); } else { it.value() ++; } } return map; } void ImportUI::setDownloaded(CamItemInfo& itemInfo, int status) { itemInfo.downloaded = status; d->progressValue = 0; if (itemInfo.downloaded == CamItemInfo::DownloadStarted) { d->progressTimer->start(500); } else { d->progressTimer->stop(); } } void ImportUI::slotProgressTimerDone() { d->progressTimer->start(300); } void ImportUI::itemsSelectionSizeInfo(unsigned long& fSizeKB, unsigned long& dSizeKB) { qint64 fSize = 0; // Files size qint64 dSize = 0; // Estimated space requires to download and process files. QList selected = d->view->selectedUrls(); CamItemInfoList list = d->view->allItems(); DownloadSettings settings = downloadSettings(); foreach(const CamItemInfo& info, list) { if (selected.contains(info.url())) { qint64 size = info.size; if (size < 0) // -1 if size is not provided by camera { continue; } fSize += size; if (info.mime == QLatin1String("image/jpeg")) { if (settings.convertJpeg) { // Estimated size is around 5 x original size when JPEG=>PNG. dSize += size * 5; } else if (settings.autoRotate) { // We need a double size to perform rotation. dSize += size * 2; } else { // Real file size is added. dSize += size; } } else if (settings.convertDng && info.mime == QLatin1String("image/x-raw")) { // Estimated size is around 2 x original size when RAW=>DNG. dSize += size * 2; } else { dSize += size; } } } fSizeKB = fSize / 1024; dSizeKB = dSize / 1024; } void ImportUI::checkItem4Deletion(const CamItemInfo& info, QStringList& folders, QStringList& files, CamItemInfoList& deleteList, CamItemInfoList& lockedList) { if (info.writePermissions != 0) // Item not locked ? { QString folder = info.folder; QString file = info.name; folders.append(folder); files.append(file); deleteList.append(info); } else { lockedList.append(info); } } void ImportUI::deleteItems(bool onlySelected, bool onlyDownloaded) { QStringList folders; QStringList files; CamItemInfoList deleteList; CamItemInfoList lockedList; CamItemInfoList list = onlySelected ? d->view->selectedCamItemInfos() : d->view->allItems(); foreach(const CamItemInfo& info, list) { if (onlyDownloaded) { if (info.downloaded == CamItemInfo::DownloadedYes) { checkItem4Deletion(info, folders, files, deleteList, lockedList); } } else { checkItem4Deletion(info, folders, files, deleteList, lockedList); } } // If we want to delete some locked files, just give a feedback to user. if (!lockedList.isEmpty()) { QString infoMsg(i18nc("@info", "The items listed below are locked by camera (read-only). " "These items will not be deleted. If you really want to delete these items, " "please unlock them and try again.")); CameraMessageBox::informationList(d->camThumbsCtrl, this, i18n("Information"), infoMsg, lockedList); } if (folders.isEmpty()) { return; } QString warnMsg(i18ncp("@info", "About to delete this image. " "Deleted file is unrecoverable. " "Are you sure?", "About to delete these %1 images. " "Deleted files are unrecoverable. " "Are you sure?", deleteList.count())); if (CameraMessageBox::warningContinueCancelList(d->camThumbsCtrl, this, i18n("Warning"), warnMsg, deleteList, QLatin1String("DontAskAgainToDeleteItemsFromCamera")) == QMessageBox::Yes) { QStringList::const_iterator itFolder = folders.constBegin(); QStringList::const_iterator itFile = files.constBegin(); d->statusProgressBar->setProgressValue(0); d->statusProgressBar->setProgressTotalSteps(deleteList.count()); d->statusProgressBar->setProgressBarMode(StatusProgressBar::ProgressBarMode); // enable cancel action. d->cameraCancelAction->setEnabled(true); for (; itFolder != folders.constEnd(); ++itFolder, ++itFile) { d->controller->deleteFile(*itFolder, *itFile); // the currentlyDeleting list is used to prevent loading items which // will immanently be deleted into the sidebar and wasting time d->currentlyDeleting.append(*itFolder + *itFile); } } } bool ImportUI::checkDiskSpace(PAlbum *pAlbum) { if (!pAlbum) { return false; } unsigned long fSize = 0; unsigned long dSize = 0; itemsSelectionSizeInfo(fSize, dSize); QString albumRootPath = pAlbum->albumRootPath(); unsigned long kBAvail = d->albumLibraryFreeSpace->kBAvail(albumRootPath); if (dSize >= kBAvail) { int result = QMessageBox::warning(this, i18nc("@title:window", "Insufficient Disk Space"), i18nc("@info", "There is not enough free space on the disk of the album you selected " "to download and process the selected pictures from the camera.\n\n" "Estimated space required: %1\n" "Available free space: %2\n\n" "Try Anyway?", ImagePropertiesTab::humanReadableBytesCount(dSize * 1024), ImagePropertiesTab::humanReadableBytesCount(kBAvail * 1024)), QMessageBox::Yes | QMessageBox::No); if (result == QMessageBox::No) { return false; } } return true; } bool ImportUI::downloadCameraItems(PAlbum* pAlbum, bool onlySelected, bool deleteAfter) { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(d->configGroupName); SetupCamera::ConflictRule rule = (SetupCamera::ConflictRule)group.readEntry(d->configFileSaveConflictRule, (int)SetupCamera::DIFFNAME); d->controller->downloadPrep(rule); QString downloadName; DownloadSettingsList allItems; DownloadSettings settings = downloadSettings(); QUrl url = pAlbum->fileUrl(); int downloadedItems = 0; // -- Download camera items ------------------------------- QList selected = d->view->selectedUrls(); CamItemInfoList list = d->view->allItems(); QSet usedDownloadPaths; foreach(const CamItemInfo& info, list) { if (onlySelected && !(selected.contains(info.url()))) { continue; } settings.folder = info.folder; settings.file = info.name; settings.mime = info.mime; settings.pickLabel = info.pickLabel; settings.colorLabel = info.colorLabel; settings.rating = info.rating; // downloadName should already be set by now downloadName = info.downloadName; QUrl downloadUrl(url); if (!createSubAlbums(downloadUrl, info)) { return false; } d->foldersToScan << downloadUrl.toLocalFile(); if (downloadName.isEmpty()) { downloadUrl = downloadUrl.adjusted(QUrl::StripTrailingSlash); downloadUrl.setPath(downloadUrl.path() + QLatin1Char('/') + settings.file); } else { // when using custom renaming (e.g. by date, see bug 179902) // make sure that we create unique names downloadUrl = downloadUrl.adjusted(QUrl::StripTrailingSlash); downloadUrl.setPath(downloadUrl.path() + QLatin1Char('/') + downloadName); QString suggestedPath = downloadUrl.toLocalFile(); if (usedDownloadPaths.contains(suggestedPath)) { QFileInfo fi(downloadName); QString suffix = QLatin1Char('.') + fi.suffix(); QString pathWithoutSuffix(suggestedPath); pathWithoutSuffix.chop(suffix.length()); QString currentVariant; int counter = 1; do { currentVariant = pathWithoutSuffix + QLatin1Char('-') + QString::number(counter++) + suffix; } while (usedDownloadPaths.contains(currentVariant)); usedDownloadPaths << currentVariant; downloadUrl = QUrl::fromLocalFile(currentVariant); } else { usedDownloadPaths << suggestedPath; } } settings.dest = downloadUrl.toLocalFile(); allItems.append(settings); if (settings.autoRotate && settings.mime == QLatin1String("image/jpeg")) { d->autoRotateItemsList << downloadUrl.toLocalFile(); qCDebug(DIGIKAM_IMPORTUI_LOG) << "autorotating for " << downloadUrl; } ++downloadedItems; } if (downloadedItems <= 0) { return false; } d->lastDestURL = url; d->statusProgressBar->setNotify(true); d->statusProgressBar->setProgressValue(0); d->statusProgressBar->setProgressTotalSteps(downloadedItems); d->statusProgressBar->setProgressBarMode(StatusProgressBar::ProgressBarMode); // enable cancel action. d->cameraCancelAction->setEnabled(true); // disable settings tab here instead of slotBusy: // Only needs to be disabled while downloading d->advBox->setEnabled(false); d->view->setEnabled(false); d->deleteAfter = deleteAfter; d->controller->download(allItems); return true; } bool ImportUI::createSubAlbums(QUrl& downloadUrl, const CamItemInfo& info) { bool success = true; if (d->albumCustomizer->autoAlbumDateEnabled()) { success &= createDateBasedSubAlbum(downloadUrl, info); } if (d->albumCustomizer->autoAlbumExtEnabled()) { success &= createExtBasedSubAlbum(downloadUrl, info); } return success; } bool ImportUI::createSubAlbum(QUrl& downloadUrl, const QString& subalbum, const QDate& date) { QString errMsg; if (!createAutoAlbum(downloadUrl, subalbum, date, errMsg)) { QMessageBox::critical(this, qApp->applicationName(), errMsg); return false; } downloadUrl = downloadUrl.adjusted(QUrl::StripTrailingSlash); downloadUrl.setPath(downloadUrl.path() + QLatin1Char('/') + subalbum); return true; } bool ImportUI::createDateBasedSubAlbum(QUrl& downloadUrl, const CamItemInfo& info) { QString dirName; QDateTime dateTime = info.ctime; switch (d->albumCustomizer->folderDateFormat()) { case AlbumCustomizer::TextDateFormat: dirName = dateTime.date().toString(Qt::TextDate); break; case AlbumCustomizer::LocalDateFormat: dirName = dateTime.date().toString(Qt::LocalDate); break; case AlbumCustomizer::IsoDateFormat: dirName = dateTime.date().toString(Qt::ISODate); break; default: // Custom dirName = dateTime.date().toString(d->albumCustomizer->customDateFormat()); break; } return createSubAlbum(downloadUrl, dirName, dateTime.date()); } bool ImportUI::createExtBasedSubAlbum(QUrl& downloadUrl, const CamItemInfo& info) { // We use the target file name to compute sub-albums name to take a care about // conversion on the fly option. QFileInfo fi(info.downloadName.isEmpty() ? info.name : info.downloadName); QString subAlbum = fi.suffix().toUpper(); if (fi.suffix().toUpper() == QLatin1String("JPEG") || fi.suffix().toUpper() == QLatin1String("JPE")) { subAlbum = QLatin1String("JPG"); } if (fi.suffix().toUpper() == QLatin1String("TIFF")) { subAlbum = QLatin1String("TIF"); } if (fi.suffix().toUpper() == QLatin1String("MPEG") || fi.suffix().toUpper() == QLatin1String("MPE") || fi.suffix().toUpper() == QLatin1String("MPO")) { subAlbum = QLatin1String("MPG"); } return createSubAlbum(downloadUrl, subAlbum, info.ctime.date()); } void ImportUI::slotDeleteNew() { slotSelectNew(); QTimer::singleShot(0, this, SLOT(slotDeleteSelected())); } void ImportUI::slotDeleteSelected() { deleteItems(true, false); } void ImportUI::slotDeleteAll() { deleteItems(false, false); } void ImportUI::slotDeleted(const QString& folder, const QString& file, bool status) { if (status) { // do this after removeItem. d->currentlyDeleting.removeAll(folder + file); } int curr = d->statusProgressBar->progressValue(); d->statusProgressBar->setProgressTotalSteps(curr + 1); refreshFreeSpace(); } void ImportUI::slotMetadata(const QString& folder, const QString& file, const DMetadata& meta) { CamItemInfo info = d->view->camItemInfo(folder, file); if (!info.isNull()) { d->rightSideBar->itemChanged(info, meta); } } void ImportUI::slotNewSelection(bool hasSelection) { updateActions(); QList renameFiles; CamItemInfoList list = hasSelection ? d->view->selectedCamItemInfos() : d->view->allItems(); foreach(const CamItemInfo& info, list) { ParseSettings parseSettings; parseSettings.fileUrl = info.url(); parseSettings.creationTime = info.ctime; renameFiles.append(parseSettings); } d->renameCustomizer->renameManager()->reset(); d->renameCustomizer->renameManager()->addFiles(renameFiles); d->renameCustomizer->renameManager()->parseFiles(); slotUpdateDownloadName(); unsigned long fSize = 0; unsigned long dSize = 0; itemsSelectionSizeInfo(fSize, dSize); d->albumLibraryFreeSpace->setEstimatedDSizeKb(dSize); } void ImportUI::slotImageSelected(const CamItemInfoList& selection, const CamItemInfoList& listAll) { if (d->cameraCancelAction->isEnabled()) { return; } int num_images = listAll.count(); switch (selection.count()) { case 0: { d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode, i18ncp("@info:status", "No item selected (%1 item)", "No item selected (%1 items)", num_images)); d->rightSideBar->slotNoCurrentItem(); break; } case 1: { // if selected item is in the list of item which will be deleted, set no current item if (!d->currentlyDeleting.contains(selection.first().folder + selection.first().name)) { updateRightSideBar(selection.first()); int index = listAll.indexOf(selection.first()) + 1; d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode, i18nc("@info:status Filename of first selected item of number of items", "%1 (%2 of %3)", selection.first().url().fileName(), index, num_images)); } else { d->rightSideBar->slotNoCurrentItem(); d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode, i18ncp("@info:status", "No item selected (%1 item)", "No item selected (%1 items)", num_images)); } break; } default: { d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode, i18ncp("@info:status", "%2/%1 item selected", "%2/%1 items selected", num_images, selection.count())); break; } } slotNewSelection(d->view->selectedCamItemInfos().count() > 0); } void ImportUI::updateRightSideBar(const CamItemInfo& info) { d->rightSideBar->itemChanged(info, DMetadata()); if (!d->busy) { d->controller->getMetadata(info.folder, info.name); } } QString ImportUI::identifyCategoryforMime(const QString& mime) { return mime.split(QLatin1Char('/')).at(0); } void ImportUI::autoRotateItems() { if (d->statusProgressBar->progressValue() != d->statusProgressBar->progressTotalSteps()) { return; } if (d->autoRotateItemsList.isEmpty()) { return; } ImageInfoList list; CollectionScanner scanner; foreach(const QString& downloadPath, d->autoRotateItemsList) { qlonglong id = scanner.scanFile(downloadPath, CollectionScanner::ModifiedScan); list << ImageInfo(id); } FileActionMngr::instance()->transform(list, MetaEngineRotation::NoTransformation); d->autoRotateItemsList.clear(); } bool ImportUI::createAutoAlbum(const QUrl& parentURL, const QString& sub, const QDate& date, QString& errMsg) const { QUrl url(parentURL); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + QLatin1Char('/') + sub); // first stat to see if the album exists QFileInfo info(url.toLocalFile()); if (info.exists()) { // now check if its really a directory if (info.isDir()) { return true; } else { errMsg = i18nc("@info", "A file with the same name (%1) already exists in folder %2.", sub, QDir::toNativeSeparators(parentURL.toLocalFile())); return false; } } // looks like the directory does not exist, try to create it. // First we make sure that the parent exists. PAlbum* parent = AlbumManager::instance()->findPAlbum(parentURL); if (!parent) { errMsg = i18nc("@info", "Failed to find Album for path %1.", QDir::toNativeSeparators(parentURL.toLocalFile())); return false; } // Create the album, with any parent albums required for the structure QUrl albumUrl(parentURL); foreach(const QString& folder, sub.split(QLatin1Char('/'), QString::SkipEmptyParts)) { albumUrl = albumUrl.adjusted(QUrl::StripTrailingSlash); albumUrl.setPath(albumUrl.path() + QLatin1Char('/') + folder); PAlbum* album = AlbumManager::instance()->findPAlbum(albumUrl); if (!album) { album = AlbumManager::instance()->createPAlbum(parent, folder, QString(), date, QString(), errMsg); if (!album) { return false; } } parent = album; } return true; } void ImportUI::slotSetup() { Setup::execDialog(this); } void ImportUI::slotCameraFreeSpaceInfo(unsigned long kBSize, unsigned long kBAvail) { d->cameraFreeSpace->addInformation(kBSize, kBSize - kBAvail, kBAvail, QString()); } bool ImportUI::cameraDeleteSupport() const { return d->controller->cameraDeleteSupport(); } bool ImportUI::cameraUploadSupport() const { return d->controller->cameraUploadSupport(); } bool ImportUI::cameraMkDirSupport() const { return d->controller->cameraMkDirSupport(); } bool ImportUI::cameraDelDirSupport() const { return d->controller->cameraDelDirSupport(); } bool ImportUI::cameraUseUMSDriver() const { return d->controller->cameraDriverType() == DKCamera::UMSDriver; } bool ImportUI::cameraUseGPhotoDriver() const { return d->controller->cameraDriverType() == DKCamera::GPhotoDriver; } void ImportUI::enableZoomPlusAction(bool val) { d->increaseThumbsAction->setEnabled(val); } void ImportUI::enableZoomMinusAction(bool val) { d->decreaseThumbsAction->setEnabled(val); } void ImportUI::slotComponentsInfo() { showDigikamComponentsInfo(); } void ImportUI::slotDBStat() { showDigikamDatabaseStat(); } void ImportUI::refreshCollectionFreeSpace() { d->albumLibraryFreeSpace->setPaths(CollectionManager::instance()->allAvailableAlbumRootPaths()); } void ImportUI::slotCollectionLocationStatusChanged(const CollectionLocation&, int) { refreshCollectionFreeSpace(); } void ImportUI::slotToggleShowBar() { showThumbBar(d->showBarAction->isChecked()); } void ImportUI::slotLogMsg(const QString& msg, DHistoryView::EntryType type, const QString& folder, const QString& file) { d->statusProgressBar->setProgressText(msg); QStringList meta; meta << folder << file; d->historyView->addEntry(msg, type, QVariant(meta)); } void ImportUI::slotShowLog() { d->showLogAction->isChecked() ? d->historyView->show() : d->historyView->hide(); } void ImportUI::slotHistoryEntryClicked(const QVariant& metadata) { QStringList meta = metadata.toStringList(); QString folder = meta.at(0); QString file = meta.at(1); d->view->scrollTo(folder, file); } void ImportUI::showSideBars(bool visible) { visible ? d->rightSideBar->restore() : d->rightSideBar->backup(); } void ImportUI::slotToggleRightSideBar() { d->rightSideBar->isExpanded() ? d->rightSideBar->shrink() : d->rightSideBar->expand(); } void ImportUI::slotPreviousRightSideBarTab() { d->rightSideBar->activePreviousTab(); } void ImportUI::slotNextRightSideBarTab() { d->rightSideBar->activeNextTab(); } void ImportUI::showThumbBar(bool visible) { d->view->toggleShowBar(visible); } bool ImportUI::thumbbarVisibility() const { return d->showBarAction->isChecked(); } void ImportUI::slotSwitchedToPreview() { d->zoomBar->setBarMode(DZoomBar::PreviewZoomCtrl); d->imageViewSelectionAction->setCurrentAction(d->camItemPreviewAction); toogleShowBar(); } void ImportUI::slotSwitchedToIconView() { d->zoomBar->setBarMode(DZoomBar::ThumbsSizeCtrl); d->imageViewSelectionAction->setCurrentAction(d->iconViewAction); toogleShowBar(); } void ImportUI::slotSwitchedToMapView() { d->zoomBar->setBarMode(DZoomBar::ThumbsSizeCtrl); #ifdef HAVE_MARBLE d->imageViewSelectionAction->setCurrentAction(d->mapViewAction); #endif // HAVE_MARBLE toogleShowBar(); } void ImportUI::customizedFullScreenMode(bool set) { toolBarMenuAction()->setEnabled(!set); showMenuBarAction()->setEnabled(!set); showStatusBarAction()->setEnabled(!set); set ? d->showBarAction->setEnabled(false) : toogleShowBar(); d->view->toggleFullScreen(set); } void ImportUI::toogleShowBar() { switch (d->view->viewMode()) { case ImportStackedView::PreviewImageMode: case ImportStackedView::MediaPlayerMode: d->showBarAction->setEnabled(true); break; default: d->showBarAction->setEnabled(false); break; } } void ImportUI::slotSetupChanged() { d->view->importFilterModel()->setStringTypeNatural(ApplicationSettings::instance()->isStringTypeNatural()); // Load full-screen options KConfigGroup group = KSharedConfig::openConfig()->group(ApplicationSettings::instance()->generalConfigGroupName()); readFullScreenSettings(group); d->view->applySettings(); sidebarTabTitleStyleChanged(); } void ImportUI::sidebarTabTitleStyleChanged() { d->rightSideBar->setStyle(ApplicationSettings::instance()->getSidebarTitleStyle()); d->rightSideBar->applySettings(); } void ImportUI::slotToggleColorManagedView() { if (!IccSettings::instance()->isEnabled()) { return; } bool cmv = !IccSettings::instance()->settings().useManagedPreviews; IccSettings::instance()->setUseManagedPreviews(cmv); d->camThumbsCtrl->clearCache(); } void ImportUI::slotColorManagementOptionsChanged() { ICCSettingsContainer settings = IccSettings::instance()->settings(); d->viewCMViewAction->blockSignals(true); d->viewCMViewAction->setEnabled(settings.enableCM); d->viewCMViewAction->setChecked(settings.useManagedPreviews); d->viewCMViewAction->blockSignals(false); } } // namespace Digikam