diff --git a/NEWS b/NEWS index 37ff6b7005..9254bf8ad0 100644 --- a/NEWS +++ b/NEWS @@ -1,677 +1,678 @@ digiKam 6.0.0 - Release date: 2019-02-10 ***************************************************************************************************** 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 : Add new Exiv2 0.27 support. General : Add new Lensfun 0.4 support. General : Use DrMinGW has crash handler under Windows. General : Port all export/import tool to OAuth2 authentification. General : New tool to adjust quickly time and date information from items. Tool will be available in AlbumView, ImageEditor, LightTable, and Showfoto. General : New function to group images by timelapse / burst 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 : New tool to export to Ipfs 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.2. 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) Collection : Add tool button to update an existing collection to the new drive or path. Tags : Add possibility to merge tags by drag & drop. IconView : Add capability to re-organize the contents manually. IconView : Add capability to separate the contents by month. 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 ==> 390228 - No clear rule on where digikam wants to import. 473 ==> 187274 - The dialogue to export to an HTML gallery has an album selected but the Next button is greyed out. 474 ==> 129762 - Flickr export tool should export whole host application albums. 475 ==> 130966 - Exporting to html gallery doesn't include subalbums. 476 ==> 097396 - Export to HTML stops/ slow. 477 ==> 128035 - HTML export adds extra .jpg extention to all image filenames. 478 ==> 129870 - Album sent to HTMLGallery tool doesn't respect the view order. 479 ==> 111462 - Exporting multiple "tag" albums in HTML produces invalid hyperlinks on main webpage. 480 ==> 147770 - Use a hierarchical treeview in HTMLExport (instead of a listview). 481 ==> 259748 - Xorg crashes when launching the "Export to flickr" tool. 482 ==> 398206 - Strongly underexposed areas of the jpeg file are white rather than pure black. 483 ==> 127498 - Reduce image size delete exif data. 484 ==> 219009 - Crashed when selecting photos for upload. 485 ==> 234395 - Unable to get list of albums. 486 ==> 241587 - Flickr export reencode jpeg before sending them. 487 ==> 278890 - Showfoto crashes with qt 4.8. 488 ==> 355744 - Segfault on SmugMug upload. 489 ==> 358704 - Request authorization does not occur and upload becomes impossible. 490 ==> 175233 - Showfoto crashes on windows. 491 ==> 259623 - Application: showFoto (showfoto), signal: Segmentation fault (opening jpg). 492 ==> 194832 - Showfoto open and crash after one second. 493 ==> 390287 - digiKam crashes when I do batch renames. 494 ==> 390290 - Trying to use "red eyes" reduction function make showfoto crash. 495 ==> 388542 - DNG crash when i open a .nef files. 496 ==> 390580 - First crashes when saving tiff file, then crashes when starting. 497 ==> 391721 - No photography is displayed in the main view. 498 ==> 392813 - Showfoto crashed when clicked on close button in title bar. 499 ==> 393069 - I do not see images in the file browser, only in calendar. 500 ==> 392189 - Database upgrade fails. 501 ==> 386653 - Message error on face detectior. 502 ==> 398287 - Print creator causes digiKam crash when orientation is changed. 503 ==> 397305 - Failed to add tag to database. 504 ==> 398462 - IPTC from Ligthroom. 505 ==> 397340 - Update image file timestamps if metadata is written to sidecar file [patch]. 506 ==> 398331 - Xmp sidecar files are not reloaded on change. 507 ==> 380341 - Modified sidecar not rescanned. 508 ==> 339342 - SCAN : Search for new items does not recognize modified tags in sidecar files. 509 ==> 387351 - Meta data for RAW files checkbox disabled. 510 ==> 398676 - Time Adjust in Batch Queue Manager jumps from hour to second. 511 ==> 338533 - Sort by date should use picture created date not modified date. 512 ==> 398675 - Image Rotation Inflates File Size. 513 ==> 309520 - GROUP : add 'group by month' into 'View.. | group by...' menu. 514 ==> 398714 - MicrosoftPhoto:LastKeywordXMP does not show up in digkam tags list. 515 ==> 388386 - Time adjustment tool is misleading and potentially leads to data loss. 516 ==> 366777 - No preview for Time Adjust tool. 517 ==> 306092 - Creation date as file name - doesn't work in BQM. 518 ==> 089993 - Allow setting time to specific date/time. 519 ==> 099894 - TimeAdjust only modifies file modification date, not EXIF. 520 ==> 119232 - Mass changing date for jpegs without EXIF. 521 ==> 119634 - Batch operation to change the date to several images at the same time. 522 ==> 134306 - Image mass tagging feature. 523 ==> 211845 - Missing progress bar while changing images dates. 524 ==> 249320 - Unable to change time file. 525 ==> 282559 - Graphical interface for changing dates and time. 526 ==> 354668 - Crashes when adjusting time and date on two or more photos at a time. 527 ==> 360770 - Crash when adjusting time on many pictures. 528 ==> 362104 - digiKam crashes when changing date and time of more than 25 selected pictures 529 ==> 366450 - Batch time adjust is ok, but time not adjusted in digikam thumbnail. 530 ==> 378006 - Preview of the time adjust result. 531 ==> 398624 - Cannot edit Date in XMP video metadata. 532 ==> 398810 - "Dates" panel is not refreshed after a photo with a new year is added. 533 ==> 398986 - Deleting a tag while using it as filter removes all images from the current view. 534 ==> 370093 - Opening a picture (double-click) in Showfoto (default viewer) does not show the other pictures in the folder (similar to Bug 221245). 535 ==> 398479 - digiKam crashing at startup Thread 2 Crashed:: Digikam::ScanController. 536 ==> 397808 - digiKam Mac Package crashes after resume when screen configuration changes. 537 ==> 399071 - "Adjust Time Date" tool shows all times as "00:00:00". 538 ==> 399134 - Progress bar or status when importing from camera/card reader. 539 ==> 399153 - Selecting a picture with a tag and another without that tag, the checkbox is black instead of gray. 540 ==> 384759 - Can't adjust timestamp of RAW files. 541 ==> 399221 - Cannot scroll in videos by clicking on the progress bar (only by moving the progress slider). 542 ==> 399315 - Horizontal scroll bar aligned to the right by default. 543 ==> 397962 - digiKam 6.0 does not start after install. 544 ==> 399336 - Google maps – "For development purposes only" printed on the map. 545 ==> 399338 - Count of items in Tree Views does not match total number of items. 546 ==> 399292 - Video file datetime not shown correctly after editing. 547 ==> 370553 - Adjust date - not possible to update "digiKam timestamp". 548 ==> 329091 - MySQL : needs to set "max-allowed-packet" server settings from 4.096 to 16.777.216 to prevent Maintenance tool crash. 549 ==> 399406 - digiKam Crash on advance rename. 550 ==> 397386 - Add a separate checkbox to "Show Rating". 551 ==> 335870 - Nexus 4 in PTP mode gets error: The specified camera ("/org/kde/solid/udev/...") is not supported. 552 ==> 399917 - Fails to build with QT5.7.1 553 ==> 399762 - digiKam Geolocation Correlator ignores time offset. 554 ==> 400148 - Files exported in google photos does not have their filename as name, but their date. 555 ==> 373678 - Videos exported in google photos are not available (still processing state). 556 ==> 400139 - Titles are not exported anymore on google photos. 557 ==> 400216 - Components Information window: no standardized uppercase/lowercase. 558 ==> 400217 - Incorrect Video date/time information: shifted by 2 hours. 559 ==> 396961 - Empty space on interface on thumbnail view. 560 ==> 400436 - Crash when saving jpeg files with metadata. 561 ==> 400492 - Rotation does not work. 562 ==> 246727 - Add undo functionality to move to trash action. 563 ==> 400637 - IPFS icons have non-square size, causing them to get blurred. 564 ==> 400434 - Trash content disappears after selecting 'Map' or 'Table' view. 565 ==> 394660 - Crashes when refreshing. 566 ==> 400712 - File modification timestamp is updated when images are moved to collection on removable media. 567 ==> 394214 - Import .mp4 files does not preserve file mtime as date stamp. 568 ==> 400762 - Trash - "Delete All Permanently" button not visible. 569 ==> 400792 - Failure to export to JPEG 2000. 570 ==> 400777 - Group images by timelapse / burst [patch]. 571 ==> 400902 - NAS Mysql cannot connect with instructions given by Dmitry Popov. 572 ==> 400918 - Tags are erroneously copied to untagged images in a selection when new tag added. 573 ==> 375197 - It is possible to rotate video thumbnails (but the video isn't rotated). 574 ==> 334678 - Thumbnails fail to generate for certain AVI files - infinite loop. 575 ==> 400917 - Rotation of picture in Preview mode: thumbnail not rotated. 576 ==> 400960 - Do not reset horizontal scroll bar slider position when selecting album. 577 ==> 400766 - Export to Onedrive: not possible to export into subfolder. 578 ==> 398207 - Box.com video upload fails despite successful authentication. 579 ==> 401160 - Build against lensfun-devel. 580 ==> 401173 - Wish for file saving: set changed datetime to exif datetime. 581 ==> 401423 - Video sidecar files nor read or written. 582 ==> 401438 - Calendar plugin prints improper month names (Czech localization). 583 ==> 401515 - Export to OneDrive: created subfolders not correctly managed. 584 ==> 401516 - Export to (Onedrive, Dropbox ...): list of subfolders not correctly displayed (problems if several subfolders have the same name). 585 ==> 401645 - digiKam crashes on possibly damaged video-file. 586 ==> 401676 - BQM resize tool : allow to resize by percentage (%). 587 ==> 401709 - Double clicking a name in a face-frame closes image preview. 588 ==> 401811 - DB migration (SQLite -> MySQL) fails if images are in trash. 589 ==> 401767 - digiKam unable to find existing path. 590 ==> 215486 - Collection not found in location on disk with UUID (LVM volume). 591 ==> 401834 - The "Scanning Faces" dialog box is too large and can't be resized in french language. 592 ==> 401664 - Trash shows list view only no thumbnails. 593 ==> 402029 - Find New Items process takes significantly longer to finish on 6.0.0. 594 ==> 402286 - Metadata settings don't display the combo value options. 595 ==> 402288 - The default Xmp.lr.hierarchicalSubject setting does not read darktable tags. 596 ==> 402300 - Template string in Help > About. 597 ==> 402283 - Duplicate entries drive to unpredictable performance. 598 ==> 402380 - Database schema upgrade to V10 is incomplete. 599 ==> 402379 - Moving location of RAW file causes loss of metadata. 600 ==> 366211 - When changing database, cannot open thumbnails into edit window. 601 ==> 402496 - digiKam crashed after a while during face recognition. 602 ==> 402726 - Piwigo export is missing. 603 ==> 401301 - digiKam Close crash. 604 ==> 401837 - Button Caption transcription error in french. 605 ==> 398880 - digiKam stays as a background process after closing. 606 ==> 398129 - ExpoBlend tool filename dialog shows previous file's name. -607 ==> +607 ==> 402556 - digikam-data conflict with dropbox installation. +608 ==> diff --git a/core/data/icons/box/16-apps-box.png b/core/data/icons/box/16-apps-dk-box.png similarity index 100% rename from core/data/icons/box/16-apps-box.png rename to core/data/icons/box/16-apps-dk-box.png diff --git a/core/data/icons/box/22-apps-box.png b/core/data/icons/box/22-apps-dk-box.png similarity index 100% rename from core/data/icons/box/22-apps-box.png rename to core/data/icons/box/22-apps-dk-box.png diff --git a/core/data/icons/box/32-apps-box.png b/core/data/icons/box/32-apps-dk-box.png similarity index 100% rename from core/data/icons/box/32-apps-box.png rename to core/data/icons/box/32-apps-dk-box.png diff --git a/core/data/icons/box/48-apps-box.png b/core/data/icons/box/48-apps-dk-box.png similarity index 100% rename from core/data/icons/box/48-apps-box.png rename to core/data/icons/box/48-apps-dk-box.png diff --git a/core/data/icons/dropbox/16-apps-dropbox.png b/core/data/icons/dropbox/16-apps-dk-dropbox.png similarity index 100% rename from core/data/icons/dropbox/16-apps-dropbox.png rename to core/data/icons/dropbox/16-apps-dk-dropbox.png diff --git a/core/data/icons/dropbox/22-apps-dropbox.png b/core/data/icons/dropbox/22-apps-dk-dropbox.png similarity index 100% rename from core/data/icons/dropbox/22-apps-dropbox.png rename to core/data/icons/dropbox/22-apps-dk-dropbox.png diff --git a/core/data/icons/dropbox/32-apps-dropbox.png b/core/data/icons/dropbox/32-apps-dk-dropbox.png similarity index 100% rename from core/data/icons/dropbox/32-apps-dropbox.png rename to core/data/icons/dropbox/32-apps-dk-dropbox.png diff --git a/core/data/icons/dropbox/48-apps-dropbox.png b/core/data/icons/dropbox/48-apps-dk-dropbox.png similarity index 100% rename from core/data/icons/dropbox/48-apps-dropbox.png rename to core/data/icons/dropbox/48-apps-dk-dropbox.png diff --git a/core/data/icons/facebook/16-apps-facebook-white.png b/core/data/icons/facebook/16-apps-dk-facebook-white.png similarity index 100% rename from core/data/icons/facebook/16-apps-facebook-white.png rename to core/data/icons/facebook/16-apps-dk-facebook-white.png diff --git a/core/data/icons/facebook/16-apps-facebook.png b/core/data/icons/facebook/16-apps-dk-facebook.png similarity index 100% rename from core/data/icons/facebook/16-apps-facebook.png rename to core/data/icons/facebook/16-apps-dk-facebook.png diff --git a/core/data/icons/facebook/22-apps-facebook-white.png b/core/data/icons/facebook/22-apps-dk-facebook-white.png similarity index 100% rename from core/data/icons/facebook/22-apps-facebook-white.png rename to core/data/icons/facebook/22-apps-dk-facebook-white.png diff --git a/core/data/icons/facebook/22-apps-facebook.png b/core/data/icons/facebook/22-apps-dk-facebook.png similarity index 100% rename from core/data/icons/facebook/22-apps-facebook.png rename to core/data/icons/facebook/22-apps-dk-facebook.png diff --git a/core/data/icons/facebook/32-apps-facebook-white.png b/core/data/icons/facebook/32-apps-dk-facebook-white.png similarity index 100% rename from core/data/icons/facebook/32-apps-facebook-white.png rename to core/data/icons/facebook/32-apps-dk-facebook-white.png diff --git a/core/data/icons/facebook/32-apps-facebook.png b/core/data/icons/facebook/32-apps-dk-facebook.png similarity index 100% rename from core/data/icons/facebook/32-apps-facebook.png rename to core/data/icons/facebook/32-apps-dk-facebook.png diff --git a/core/data/icons/facebook/48-apps-facebook-white.png b/core/data/icons/facebook/48-apps-dk-facebook-white.png similarity index 100% rename from core/data/icons/facebook/48-apps-facebook-white.png rename to core/data/icons/facebook/48-apps-dk-facebook-white.png diff --git a/core/data/icons/facebook/48-apps-facebook.png b/core/data/icons/facebook/48-apps-dk-facebook.png similarity index 100% rename from core/data/icons/facebook/48-apps-facebook.png rename to core/data/icons/facebook/48-apps-dk-facebook.png diff --git a/core/data/icons/facebook/sc-apps-facebook-white.svgz b/core/data/icons/facebook/sc-apps-dk-facebook-white.svgz similarity index 100% rename from core/data/icons/facebook/sc-apps-facebook-white.svgz rename to core/data/icons/facebook/sc-apps-dk-facebook-white.svgz diff --git a/core/data/icons/facebook/sc-apps-facebook.svgz b/core/data/icons/facebook/sc-apps-dk-facebook.svgz similarity index 100% rename from core/data/icons/facebook/sc-apps-facebook.svgz rename to core/data/icons/facebook/sc-apps-dk-facebook.svgz diff --git a/core/data/icons/flickr/16-apps-flickr.png b/core/data/icons/flickr/16-apps-dk-flickr.png similarity index 100% rename from core/data/icons/flickr/16-apps-flickr.png rename to core/data/icons/flickr/16-apps-dk-flickr.png diff --git a/core/data/icons/flickr/22-apps-flickr.png b/core/data/icons/flickr/22-apps-dk-flickr.png similarity index 100% rename from core/data/icons/flickr/22-apps-flickr.png rename to core/data/icons/flickr/22-apps-dk-flickr.png diff --git a/core/data/icons/flickr/32-apps-flickr.png b/core/data/icons/flickr/32-apps-dk-flickr.png similarity index 100% rename from core/data/icons/flickr/32-apps-flickr.png rename to core/data/icons/flickr/32-apps-dk-flickr.png diff --git a/core/data/icons/flickr/48-apps-flickr.png b/core/data/icons/flickr/48-apps-dk-flickr.png similarity index 100% rename from core/data/icons/flickr/48-apps-flickr.png rename to core/data/icons/flickr/48-apps-dk-flickr.png diff --git a/core/data/icons/flickr/sc-apps-flickr.svgz b/core/data/icons/flickr/sc-apps-dk-flickr.svgz similarity index 100% rename from core/data/icons/flickr/sc-apps-flickr.svgz rename to core/data/icons/flickr/sc-apps-dk-flickr.svgz diff --git a/core/data/icons/gdrive/16-apps-googledrive.png b/core/data/icons/gdrive/16-apps-dk-googledrive.png similarity index 100% rename from core/data/icons/gdrive/16-apps-googledrive.png rename to core/data/icons/gdrive/16-apps-dk-googledrive.png diff --git a/core/data/icons/gdrive/22-apps-googledrive.png b/core/data/icons/gdrive/22-apps-dk-googledrive.png similarity index 100% rename from core/data/icons/gdrive/22-apps-googledrive.png rename to core/data/icons/gdrive/22-apps-dk-googledrive.png diff --git a/core/data/icons/gdrive/32-apps-googledrive.png b/core/data/icons/gdrive/32-apps-dk-googledrive.png similarity index 100% rename from core/data/icons/gdrive/32-apps-googledrive.png rename to core/data/icons/gdrive/32-apps-dk-googledrive.png diff --git a/core/data/icons/gdrive/48-apps-googledrive.png b/core/data/icons/gdrive/48-apps-dk-googledrive.png similarity index 100% rename from core/data/icons/gdrive/48-apps-googledrive.png rename to core/data/icons/gdrive/48-apps-dk-googledrive.png diff --git a/core/data/icons/gphoto/16-apps-googlephoto.png b/core/data/icons/gphoto/16-apps-dk-googlephoto.png similarity index 100% rename from core/data/icons/gphoto/16-apps-googlephoto.png rename to core/data/icons/gphoto/16-apps-dk-googlephoto.png diff --git a/core/data/icons/gphoto/22-apps-googlephoto.png b/core/data/icons/gphoto/22-apps-dk-googlephoto.png similarity index 100% rename from core/data/icons/gphoto/22-apps-googlephoto.png rename to core/data/icons/gphoto/22-apps-dk-googlephoto.png diff --git a/core/data/icons/gphoto/32-apps-googlephoto.png b/core/data/icons/gphoto/32-apps-dk-googlephoto.png similarity index 100% rename from core/data/icons/gphoto/32-apps-googlephoto.png rename to core/data/icons/gphoto/32-apps-dk-googlephoto.png diff --git a/core/data/icons/gphoto/48-apps-googlephoto.png b/core/data/icons/gphoto/48-apps-dk-googlephoto.png similarity index 100% rename from core/data/icons/gphoto/48-apps-googlephoto.png rename to core/data/icons/gphoto/48-apps-dk-googlephoto.png diff --git a/core/data/icons/gphoto/sc-apps-googlephoto.svgz b/core/data/icons/gphoto/sc-apps-dk-googlephoto.svgz similarity index 100% rename from core/data/icons/gphoto/sc-apps-googlephoto.svgz rename to core/data/icons/gphoto/sc-apps-dk-googlephoto.svgz diff --git a/core/data/icons/imageshack/16-apps-imageshack.png b/core/data/icons/imageshack/16-apps-dk-imageshack.png similarity index 100% rename from core/data/icons/imageshack/16-apps-imageshack.png rename to core/data/icons/imageshack/16-apps-dk-imageshack.png diff --git a/core/data/icons/imageshack/22-apps-imageshack.png b/core/data/icons/imageshack/22-apps-dk-imageshack.png similarity index 100% rename from core/data/icons/imageshack/22-apps-imageshack.png rename to core/data/icons/imageshack/22-apps-dk-imageshack.png diff --git a/core/data/icons/imageshack/32-apps-imageshack.png b/core/data/icons/imageshack/32-apps-dk-imageshack.png similarity index 100% rename from core/data/icons/imageshack/32-apps-imageshack.png rename to core/data/icons/imageshack/32-apps-dk-imageshack.png diff --git a/core/data/icons/imageshack/48-apps-imageshack.png b/core/data/icons/imageshack/48-apps-dk-imageshack.png similarity index 100% rename from core/data/icons/imageshack/48-apps-imageshack.png rename to core/data/icons/imageshack/48-apps-dk-imageshack.png diff --git a/core/data/icons/imgur/16-apps-imgur.png b/core/data/icons/imgur/16-apps-dk-imgur.png similarity index 100% rename from core/data/icons/imgur/16-apps-imgur.png rename to core/data/icons/imgur/16-apps-dk-imgur.png diff --git a/core/data/icons/imgur/22-apps-imgur.png b/core/data/icons/imgur/22-apps-dk-imgur.png similarity index 100% rename from core/data/icons/imgur/22-apps-imgur.png rename to core/data/icons/imgur/22-apps-dk-imgur.png diff --git a/core/data/icons/imgur/32-apps-imgur.png b/core/data/icons/imgur/32-apps-dk-imgur.png similarity index 100% rename from core/data/icons/imgur/32-apps-imgur.png rename to core/data/icons/imgur/32-apps-dk-imgur.png diff --git a/core/data/icons/imgur/48-apps-imgur.png b/core/data/icons/imgur/48-apps-dk-imgur.png similarity index 100% rename from core/data/icons/imgur/48-apps-imgur.png rename to core/data/icons/imgur/48-apps-dk-imgur.png diff --git a/core/data/icons/imgur/sc-apps-imgur.svgz b/core/data/icons/imgur/sc-apps-dk-imgur.svgz similarity index 100% rename from core/data/icons/imgur/sc-apps-imgur.svgz rename to core/data/icons/imgur/sc-apps-dk-imgur.svgz diff --git a/core/data/icons/ipfs/16-apps-ipfs.png b/core/data/icons/ipfs/16-apps-dk-ipfs.png similarity index 100% rename from core/data/icons/ipfs/16-apps-ipfs.png rename to core/data/icons/ipfs/16-apps-dk-ipfs.png diff --git a/core/data/icons/ipfs/22-apps-ipfs.png b/core/data/icons/ipfs/22-apps-dk-ipfs.png similarity index 100% rename from core/data/icons/ipfs/22-apps-ipfs.png rename to core/data/icons/ipfs/22-apps-dk-ipfs.png diff --git a/core/data/icons/ipfs/32-apps-ipfs.png b/core/data/icons/ipfs/32-apps-dk-ipfs.png similarity index 100% rename from core/data/icons/ipfs/32-apps-ipfs.png rename to core/data/icons/ipfs/32-apps-dk-ipfs.png diff --git a/core/data/icons/ipfs/48-apps-ipfs.png b/core/data/icons/ipfs/48-apps-dk-ipfs.png similarity index 100% rename from core/data/icons/ipfs/48-apps-ipfs.png rename to core/data/icons/ipfs/48-apps-dk-ipfs.png diff --git a/core/data/icons/ipfs/sc-apps-ipfs.svgz b/core/data/icons/ipfs/sc-apps-dk-ipfs.svgz similarity index 100% rename from core/data/icons/ipfs/sc-apps-ipfs.svgz rename to core/data/icons/ipfs/sc-apps-dk-ipfs.svgz diff --git a/core/data/icons/mediawiki/16-apps-mediawiki.png b/core/data/icons/mediawiki/16-apps-dk-mediawiki.png similarity index 100% rename from core/data/icons/mediawiki/16-apps-mediawiki.png rename to core/data/icons/mediawiki/16-apps-dk-mediawiki.png diff --git a/core/data/icons/mediawiki/22-apps-mediawiki.png b/core/data/icons/mediawiki/22-apps-dk-mediawiki.png similarity index 100% rename from core/data/icons/mediawiki/22-apps-mediawiki.png rename to core/data/icons/mediawiki/22-apps-dk-mediawiki.png diff --git a/core/data/icons/mediawiki/32-apps-mediawiki.png b/core/data/icons/mediawiki/32-apps-dk-mediawiki.png similarity index 100% rename from core/data/icons/mediawiki/32-apps-mediawiki.png rename to core/data/icons/mediawiki/32-apps-dk-mediawiki.png diff --git a/core/data/icons/mediawiki/48-apps-mediawiki.png b/core/data/icons/mediawiki/48-apps-dk-mediawiki.png similarity index 100% rename from core/data/icons/mediawiki/48-apps-mediawiki.png rename to core/data/icons/mediawiki/48-apps-dk-mediawiki.png diff --git a/core/data/icons/mediawiki/sc-apps-mediawiki.svgz b/core/data/icons/mediawiki/sc-apps-dk-mediawiki.svgz similarity index 100% rename from core/data/icons/mediawiki/sc-apps-mediawiki.svgz rename to core/data/icons/mediawiki/sc-apps-dk-mediawiki.svgz diff --git a/core/data/icons/onedrive/16-apps-onedrive.png b/core/data/icons/onedrive/16-apps-dk-onedrive.png similarity index 100% rename from core/data/icons/onedrive/16-apps-onedrive.png rename to core/data/icons/onedrive/16-apps-dk-onedrive.png diff --git a/core/data/icons/onedrive/22-apps-onedrive.png b/core/data/icons/onedrive/22-apps-dk-onedrive.png similarity index 100% rename from core/data/icons/onedrive/22-apps-onedrive.png rename to core/data/icons/onedrive/22-apps-dk-onedrive.png diff --git a/core/data/icons/onedrive/32-apps-onedrive.png b/core/data/icons/onedrive/32-apps-dk-onedrive.png similarity index 100% rename from core/data/icons/onedrive/32-apps-onedrive.png rename to core/data/icons/onedrive/32-apps-dk-onedrive.png diff --git a/core/data/icons/onedrive/48-apps-onedrive.png b/core/data/icons/onedrive/48-apps-dk-onedrive.png similarity index 100% rename from core/data/icons/onedrive/48-apps-onedrive.png rename to core/data/icons/onedrive/48-apps-dk-onedrive.png diff --git a/core/data/icons/pinterest/16-apps-pinterest.png b/core/data/icons/pinterest/16-apps-dk-pinterest.png similarity index 100% rename from core/data/icons/pinterest/16-apps-pinterest.png rename to core/data/icons/pinterest/16-apps-dk-pinterest.png diff --git a/core/data/icons/pinterest/22-apps-pinterest.png b/core/data/icons/pinterest/22-apps-dk-pinterest.png similarity index 100% rename from core/data/icons/pinterest/22-apps-pinterest.png rename to core/data/icons/pinterest/22-apps-dk-pinterest.png diff --git a/core/data/icons/pinterest/32-apps-pinterest.png b/core/data/icons/pinterest/32-apps-dk-pinterest.png similarity index 100% rename from core/data/icons/pinterest/32-apps-pinterest.png rename to core/data/icons/pinterest/32-apps-dk-pinterest.png diff --git a/core/data/icons/pinterest/48-apps-pinterest.png b/core/data/icons/pinterest/48-apps-dk-pinterest.png similarity index 100% rename from core/data/icons/pinterest/48-apps-pinterest.png rename to core/data/icons/pinterest/48-apps-dk-pinterest.png diff --git a/core/data/icons/piwigo/16-apps-piwigo.png b/core/data/icons/piwigo/16-apps-dk-piwigo.png similarity index 100% rename from core/data/icons/piwigo/16-apps-piwigo.png rename to core/data/icons/piwigo/16-apps-dk-piwigo.png diff --git a/core/data/icons/piwigo/22-apps-piwigo.png b/core/data/icons/piwigo/22-apps-dk-piwigo.png similarity index 100% rename from core/data/icons/piwigo/22-apps-piwigo.png rename to core/data/icons/piwigo/22-apps-dk-piwigo.png diff --git a/core/data/icons/piwigo/32-apps-piwigo.png b/core/data/icons/piwigo/32-apps-dk-piwigo.png similarity index 100% rename from core/data/icons/piwigo/32-apps-piwigo.png rename to core/data/icons/piwigo/32-apps-dk-piwigo.png diff --git a/core/data/icons/piwigo/48-apps-piwigo.png b/core/data/icons/piwigo/48-apps-dk-piwigo.png similarity index 100% rename from core/data/icons/piwigo/48-apps-piwigo.png rename to core/data/icons/piwigo/48-apps-dk-piwigo.png diff --git a/core/data/icons/piwigo/sc-apps-piwigo.svgz b/core/data/icons/piwigo/sc-apps-dk-piwigo.svgz similarity index 100% rename from core/data/icons/piwigo/sc-apps-piwigo.svgz rename to core/data/icons/piwigo/sc-apps-dk-piwigo.svgz diff --git a/core/data/icons/rajce/16-apps-rajce.png b/core/data/icons/rajce/16-apps-dk-rajce.png similarity index 100% rename from core/data/icons/rajce/16-apps-rajce.png rename to core/data/icons/rajce/16-apps-dk-rajce.png diff --git a/core/data/icons/rajce/22-apps-rajce.png b/core/data/icons/rajce/22-apps-dk-rajce.png similarity index 100% rename from core/data/icons/rajce/22-apps-rajce.png rename to core/data/icons/rajce/22-apps-dk-rajce.png diff --git a/core/data/icons/rajce/32-apps-rajce.png b/core/data/icons/rajce/32-apps-dk-rajce.png similarity index 100% rename from core/data/icons/rajce/32-apps-rajce.png rename to core/data/icons/rajce/32-apps-dk-rajce.png diff --git a/core/data/icons/rajce/48-apps-rajce.png b/core/data/icons/rajce/48-apps-dk-rajce.png similarity index 100% rename from core/data/icons/rajce/48-apps-rajce.png rename to core/data/icons/rajce/48-apps-dk-rajce.png diff --git a/core/data/icons/smugmug/16-apps-smugmug.png b/core/data/icons/smugmug/16-apps-dk-smugmug.png similarity index 100% rename from core/data/icons/smugmug/16-apps-smugmug.png rename to core/data/icons/smugmug/16-apps-dk-smugmug.png diff --git a/core/data/icons/smugmug/22-apps-smugmug.png b/core/data/icons/smugmug/22-apps-dk-smugmug.png similarity index 100% rename from core/data/icons/smugmug/22-apps-smugmug.png rename to core/data/icons/smugmug/22-apps-dk-smugmug.png diff --git a/core/data/icons/smugmug/32-apps-smugmug.png b/core/data/icons/smugmug/32-apps-dk-smugmug.png similarity index 100% rename from core/data/icons/smugmug/32-apps-smugmug.png rename to core/data/icons/smugmug/32-apps-dk-smugmug.png diff --git a/core/data/icons/smugmug/48-apps-smugmug.png b/core/data/icons/smugmug/48-apps-dk-smugmug.png similarity index 100% rename from core/data/icons/smugmug/48-apps-smugmug.png rename to core/data/icons/smugmug/48-apps-dk-smugmug.png diff --git a/core/data/icons/smugmug/sc-apps-smugmug.svgz b/core/data/icons/smugmug/sc-apps-dk-smugmug.svgz similarity index 100% rename from core/data/icons/smugmug/sc-apps-smugmug.svgz rename to core/data/icons/smugmug/sc-apps-dk-smugmug.svgz diff --git a/core/libs/widgets/mainview/dxmlguiwindow.cpp b/core/libs/widgets/mainview/dxmlguiwindow.cpp index cbd9a958b8..753750868c 100644 --- a/core/libs/widgets/mainview/dxmlguiwindow.cpp +++ b/core/libs/widgets/mainview/dxmlguiwindow.cpp @@ -1,1381 +1,1381 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2013-04-29 * Description : digiKam XML GUI window * * Copyright (C) 2013-2019 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "dxmlguiwindow.h" // Qt includes #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 #include #include #include #include #include #include #include #include #ifdef HAVE_KNOTIFYCONFIG # include #endif // Local includes #include "digikam_debug.h" #include "digikam_globals.h" #include "daboutdata.h" #include "webbrowserdlg.h" #include "wsstarter.h" namespace Digikam { class Q_DECL_HIDDEN DXmlGuiWindow::Private { public: explicit Private() { fsOptions = FS_NONE; fullScreenAction = 0; fullScreenBtn = 0; dirtyMainToolBar = false; fullScreenHideToolBars = false; fullScreenHideThumbBar = true; fullScreenHideSideBars = false; thumbbarVisibility = true; menubarVisibility = true; statusbarVisibility = true; libsInfoAction = 0; showMenuBarAction = 0; showStatusBarAction = 0; about = 0; dbStatAction = 0; anim = 0; } public: /** * Settings taken from managed window configuration to handle toolbar visibility in full-screen mode */ bool fullScreenHideToolBars; /** * Settings taken from managed window configuration to handle thumbbar visibility in full-screen mode */ bool fullScreenHideThumbBar; /** * Settings taken from managed window configuration to handle toolbar visibility in full-screen mode */ bool fullScreenHideSideBars; /** * Full-Screen options. See FullScreenOptions enum and setFullScreenOptions() for details. */ int fsOptions; /** * Action plug in managed window to switch fullscreen state */ KToggleFullScreenAction* fullScreenAction; /** * Show only if toolbar is hidden */ QToolButton* fullScreenBtn; /** * Used by slotToggleFullScreen() to manage state of full-screen button on managed window */ bool dirtyMainToolBar; /** * Store previous visibility of toolbars before ful-screen mode. */ QMap toolbarsVisibility; /** * Store previous visibility of thumbbar before ful-screen mode. */ bool thumbbarVisibility; /** * Store previous visibility of menubar before ful-screen mode. */ bool menubarVisibility; /** * Store previous visibility of statusbar before ful-screen mode. */ bool statusbarVisibility; // Common Help actions QAction* dbStatAction; QAction* libsInfoAction; QAction* showMenuBarAction; QAction* showStatusBarAction; DAboutData* about; DLogoAction* anim; QString configGroupName; }; // -------------------------------------------------------------------------------------------------- DXmlGuiWindow::DXmlGuiWindow(QWidget* const parent, Qt::WindowFlags f) : KXmlGuiWindow(parent, f), d(new Private) { m_expoBlendingAction = 0; m_panoramaAction = 0; m_videoslideshowAction = 0; m_htmlGalleryAction = 0; m_sendByMailAction = 0; m_printCreatorAction = 0; m_calendarAction = 0; m_presentationAction = 0; m_metadataEditAction = 0; m_geolocationEditAction = 0; m_mediaServerAction = 0; m_timeAdjustAction = 0; m_animLogo = 0; // Export tools m_exportDropboxAction = 0; m_exportOnedriveAction = 0; m_exportPinterestAction = 0; m_exportBoxAction = 0; m_exportFacebookAction = 0; m_exportFlickrAction = 0; m_exportGdriveAction = 0; m_exportGphotoAction = 0; m_exportImageshackAction = 0; m_exportImgurAction = 0; m_exportIpfsAction = 0; m_exportPiwigoAction = 0; m_exportRajceAction = 0; m_exportSmugmugAction = 0; m_exportYandexfotkiAction = 0; m_exportMediawikiAction = 0; #ifdef HAVE_VKONTAKTE m_exportVkontakteAction = 0; #endif #ifdef HAVE_KIO m_exportFileTransferAction = 0; #endif // Import tools m_importGphotoAction = 0; m_importSmugmugAction = 0; #ifdef HAVE_KIO m_importFileTransferAction = 0; #endif #ifdef HAVE_KSANE m_ksaneAction = 0; #endif installEventFilter(this); } DXmlGuiWindow::~DXmlGuiWindow() { delete d; } void DXmlGuiWindow::setConfigGroupName(const QString& name) { d->configGroupName = name; } QString DXmlGuiWindow::configGroupName() const { return d->configGroupName; } void DXmlGuiWindow::closeEvent(QCloseEvent* e) { if (fullScreenIsActive()) slotToggleFullScreen(false); if (!testAttribute(Qt::WA_DeleteOnClose)) { setVisible(false); e->ignore(); return; } KXmlGuiWindow::closeEvent(e); e->accept(); } void DXmlGuiWindow::setFullScreenOptions(int options) { d->fsOptions = options; } void DXmlGuiWindow::createHelpActions(bool coreOptions) { d->libsInfoAction = new QAction(QIcon::fromTheme(QLatin1String("help-about")), i18n("Components Information"), this); connect(d->libsInfoAction, SIGNAL(triggered()), this, SLOT(slotComponentsInfo())); actionCollection()->addAction(QLatin1String("help_librariesinfo"), d->libsInfoAction); d->about = new DAboutData(this); QAction* const rawCameraListAction = new QAction(QIcon::fromTheme(QLatin1String("image-x-adobe-dng")), i18n("Supported RAW Cameras"), this); connect(rawCameraListAction, SIGNAL(triggered()), this, SLOT(slotRawCameraList())); actionCollection()->addAction(QLatin1String("help_rawcameralist"), rawCameraListAction); QAction* const donateMoneyAction = new QAction(QIcon::fromTheme(QLatin1String("globe")), i18n("Donate..."), this); connect(donateMoneyAction, SIGNAL(triggered()), this, SLOT(slotDonateMoney())); actionCollection()->addAction(QLatin1String("help_donatemoney"), donateMoneyAction); QAction* const recipesBookAction = new QAction(QIcon::fromTheme(QLatin1String("globe")), i18n("Recipes Book..."), this); connect(recipesBookAction, SIGNAL(triggered()), this, SLOT(slotRecipesBook())); actionCollection()->addAction(QLatin1String("help_recipesbook"), recipesBookAction); QAction* const contributeAction = new QAction(QIcon::fromTheme(QLatin1String("globe")), i18n("Contribute..."), this); connect(contributeAction, SIGNAL(triggered()), this, SLOT(slotContribute())); actionCollection()->addAction(QLatin1String("help_contribute"), contributeAction); QAction* const helpAction = new QAction(QIcon::fromTheme(QLatin1String("help-contents")), i18n("Online Handbook..."), this); connect(helpAction, SIGNAL(triggered()), this, SLOT(slotHelpContents())); actionCollection()->addAction(QLatin1String("help_handbook"), helpAction); m_animLogo = new DLogoAction(this); actionCollection()->addAction(QLatin1String("logo_action"), m_animLogo); // Add options only for core components (typically all excepted Showfoto) if (coreOptions) { d->dbStatAction = new QAction(QIcon::fromTheme(QLatin1String("network-server-database")), i18n("Database Statistics"), this); connect(d->dbStatAction, SIGNAL(triggered()), this, SLOT(slotDBStat())); actionCollection()->addAction(QLatin1String("help_dbstat"), d->dbStatAction); } } void DXmlGuiWindow::cleanupActions() { QAction* ac = actionCollection()->action(QLatin1String("help_about_kde")); if (ac) actionCollection()->removeAction(ac); ac = actionCollection()->action(QLatin1String("help_donate")); if (ac) actionCollection()->removeAction(ac); ac = actionCollection()->action(QLatin1String("help_contents")); if (ac) actionCollection()->removeAction(ac); /* QList lst = actionCollection()->actions(); foreach (QAction* const act, lst) qCDebug(DIGIKAM_WIDGETS_LOG) << "action: " << act->objectName(); */ } void DXmlGuiWindow::createSidebarActions() { KActionCollection* const ac = actionCollection(); QAction* const tlsb = new QAction(i18n("Toggle Left Side-bar"), this); connect(tlsb, SIGNAL(triggered()), this, SLOT(slotToggleLeftSideBar())); ac->addAction(QLatin1String("toggle-left-sidebar"), tlsb); ac->setDefaultShortcut(tlsb, Qt::CTRL + Qt::META + Qt::Key_Left); QAction* const trsb = new QAction(i18n("Toggle Right Side-bar"), this); connect(trsb, SIGNAL(triggered()), this, SLOT(slotToggleRightSideBar())); ac->addAction(QLatin1String("toggle-right-sidebar"), trsb); ac->setDefaultShortcut(trsb, Qt::CTRL + Qt::META + Qt::Key_Right); QAction* const plsb = new QAction(i18n("Previous Left Side-bar Tab"), this); connect(plsb, SIGNAL(triggered()), this, SLOT(slotPreviousLeftSideBarTab())); ac->addAction(QLatin1String("previous-left-sidebar-tab"), plsb); ac->setDefaultShortcut(plsb, Qt::CTRL + Qt::META + Qt::Key_Home); QAction* const nlsb = new QAction(i18n("Next Left Side-bar Tab"), this); connect(nlsb, SIGNAL(triggered()), this, SLOT(slotNextLeftSideBarTab())); ac->addAction(QLatin1String("next-left-sidebar-tab"), nlsb); ac->setDefaultShortcut(nlsb, Qt::CTRL + Qt::META + Qt::Key_End); QAction* const prsb = new QAction(i18n("Previous Right Side-bar Tab"), this); connect(prsb, SIGNAL(triggered()), this, SLOT(slotPreviousRightSideBarTab())); ac->addAction(QLatin1String("previous-right-sidebar-tab"), prsb); ac->setDefaultShortcut(prsb, Qt::CTRL + Qt::META + Qt::Key_PageUp); QAction* const nrsb = new QAction(i18n("Next Right Side-bar Tab"), this); connect(nrsb, SIGNAL(triggered()), this, SLOT(slotNextRightSideBarTab())); ac->addAction(QLatin1String("next-right-sidebar-tab"), nrsb); ac->setDefaultShortcut(nrsb, Qt::CTRL + Qt::META + Qt::Key_PageDown); } void DXmlGuiWindow::createSettingsActions() { d->showMenuBarAction = KStandardAction::showMenubar(this, SLOT(slotShowMenuBar()), actionCollection()); #ifdef Q_OS_OSX // Under MacOS the menu bar visibility is managed by desktop. d->showMenuBarAction->setVisible(false); #endif d->showStatusBarAction = actionCollection()->action(QLatin1String("options_show_statusbar")); if (!d->showStatusBarAction) { qCWarning(DIGIKAM_WIDGETS_LOG) << "Status bar menu action cannot be found in action collection"; d->showStatusBarAction = new QAction(i18n("Show Statusbar"), this); d->showStatusBarAction->setCheckable(true); d->showStatusBarAction->setChecked(true); connect(d->showStatusBarAction, SIGNAL(toggled(bool)), this, SLOT(slotShowStatusBar())); actionCollection()->addAction(QLatin1String("options_show_statusbar"), d->showStatusBarAction); } KStandardAction::keyBindings(this, SLOT(slotEditKeys()), actionCollection()); KStandardAction::preferences(this, SLOT(slotSetup()), actionCollection()); KStandardAction::configureToolbars(this, SLOT(slotConfToolbars()), actionCollection()); #ifdef HAVE_KNOTIFYCONFIG KStandardAction::configureNotifications(this, SLOT(slotConfNotifications()), actionCollection()); #endif } QAction* DXmlGuiWindow::showMenuBarAction() const { return d->showMenuBarAction; } QAction* DXmlGuiWindow::showStatusBarAction() const { return d->showStatusBarAction; } void DXmlGuiWindow::slotShowMenuBar() { menuBar()->setVisible(d->showMenuBarAction->isChecked()); } void DXmlGuiWindow::slotShowStatusBar() { statusBar()->setVisible(d->showStatusBarAction->isChecked()); } void DXmlGuiWindow::slotConfNotifications() { #ifdef HAVE_KNOTIFYCONFIG KNotifyConfigWidget::configure(this); #endif } void DXmlGuiWindow::editKeyboardShortcuts(KActionCollection* const extraac, const QString& actitle) { KShortcutsDialog dialog(KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsAllowed, this); dialog.addCollection(actionCollection(), i18nc("general keyboard shortcuts", "General")); if (extraac) dialog.addCollection(extraac, actitle); dialog.configure(); } void DXmlGuiWindow::slotConfToolbars() { KConfigGroup group = KSharedConfig::openConfig()->group(configGroupName()); saveMainWindowSettings(group); KEditToolBar dlg(factory(), this); connect(&dlg, SIGNAL(newToolbarConfig()), this, SLOT(slotNewToolbarConfig())); dlg.exec(); } void DXmlGuiWindow::slotNewToolbarConfig() { KConfigGroup group = KSharedConfig::openConfig()->group(configGroupName()); applyMainWindowSettings(group); } void DXmlGuiWindow::createGeolocationEditAction() { #ifdef HAVE_MARBLE m_geolocationEditAction = new QAction(QIcon::fromTheme(QLatin1String("globe")), i18n("Edit Geolocation..."), this); actionCollection()->addAction(QLatin1String("geolocation_edit"), m_geolocationEditAction); actionCollection()->setDefaultShortcut(m_geolocationEditAction, Qt::CTRL + Qt::SHIFT + Qt::Key_G); connect(m_geolocationEditAction, SIGNAL(triggered(bool)), this, SLOT(slotEditGeolocation())); #endif } void DXmlGuiWindow::createMetadataEditAction() { m_metadataEditAction = new QAction(QIcon::fromTheme(QLatin1String("format-text-code")), i18n("Edit Metadata..."), this); actionCollection()->addAction(QLatin1String("metadata_edit"), m_metadataEditAction); actionCollection()->setDefaultShortcut(m_metadataEditAction, Qt::CTRL + Qt::SHIFT + Qt::Key_M); connect(m_metadataEditAction, SIGNAL(triggered(bool)), this, SLOT(slotEditMetadata())); } void DXmlGuiWindow::createTimeAdjustAction() { m_timeAdjustAction = new QAction(QIcon::fromTheme(QLatin1String("appointment-new")), i18n("Adjust Time && Date..."), this); actionCollection()->addAction(QLatin1String("timeadjust_edit"), m_timeAdjustAction); actionCollection()->setDefaultShortcut(m_timeAdjustAction, Qt::CTRL + Qt::SHIFT + Qt::Key_D); connect(m_timeAdjustAction, SIGNAL(triggered(bool)), this, SLOT(slotTimeAdjust())); } void DXmlGuiWindow::createPresentationAction() { m_presentationAction = new QAction(QIcon::fromTheme(QLatin1String("view-presentation")), i18n("Presentation..."), this); actionCollection()->addAction(QLatin1String("presentation"), m_presentationAction); actionCollection()->setDefaultShortcut(m_presentationAction, Qt::ALT + Qt::SHIFT + Qt::Key_F9); connect(m_presentationAction, SIGNAL(triggered()), this, SLOT(slotPresentation())); } void DXmlGuiWindow::createExpoBlendingAction() { m_expoBlendingAction = new QAction(QIcon::fromTheme(QLatin1String("expoblending")), i18nc("@action", "Create Stacked Images..."), this); actionCollection()->addAction(QLatin1String("expoblending"), m_expoBlendingAction); connect(m_expoBlendingAction, SIGNAL(triggered(bool)), this, SLOT(slotExpoBlending())); } void DXmlGuiWindow::createPanoramaAction() { #ifdef HAVE_PANORAMA m_panoramaAction = new QAction(QIcon::fromTheme(QLatin1String("panorama")), i18nc("@action", "Create panorama..."), this); actionCollection()->addAction(QLatin1String("panorama"), m_panoramaAction); connect(m_panoramaAction, SIGNAL(triggered(bool)), this, SLOT(slotPanorama())); #endif } void DXmlGuiWindow::createVideoSlideshowAction() { #ifdef HAVE_MEDIAPLAYER m_videoslideshowAction = new QAction(QIcon::fromTheme(QLatin1String("media-record")), i18nc("@action", "Create video slideshow..."), this); actionCollection()->addAction(QLatin1String("videoslideshow"), m_videoslideshowAction); connect(m_videoslideshowAction, SIGNAL(triggered(bool)), this, SLOT(slotVideoSlideshow())); #endif } void DXmlGuiWindow::createCalendarAction() { m_calendarAction = new QAction(QIcon::fromTheme(QLatin1String("view-calendar")), i18nc("@action", "Create Calendar..."), this); actionCollection()->addAction(QLatin1String("calendar"), m_calendarAction); connect(m_calendarAction, SIGNAL(triggered(bool)), this, SLOT(slotCalendar())); } void DXmlGuiWindow::createSendByMailAction() { m_sendByMailAction = new QAction(QIcon::fromTheme(QLatin1String("mail-send")), i18nc("@action", "Send by Mail..."), this); actionCollection()->addAction(QLatin1String("sendbymail"), m_sendByMailAction); connect(m_sendByMailAction, SIGNAL(triggered(bool)), this, SLOT(slotSendByMail())); } void DXmlGuiWindow::createPrintCreatorAction() { m_printCreatorAction = new QAction(QIcon::fromTheme(QLatin1String("document-print")), i18nc("@action", "Print Creator..."), this); actionCollection()->addAction(QLatin1String("printcreator"), m_printCreatorAction); connect(m_printCreatorAction, SIGNAL(triggered(bool)), this, SLOT(slotPrintCreator())); } void DXmlGuiWindow::createHtmlGalleryAction() { #ifdef HAVE_HTMLGALLERY m_htmlGalleryAction = new QAction(QIcon::fromTheme(QLatin1String("text-html")), i18nc("@action", "Create Html gallery..."), this); actionCollection()->setDefaultShortcut(m_htmlGalleryAction, Qt::ALT + Qt::SHIFT + Qt::Key_H); actionCollection()->addAction(QLatin1String("htmlgallery"), m_htmlGalleryAction); connect(m_htmlGalleryAction, SIGNAL(triggered(bool)), this, SLOT(slotHtmlGallery())); #endif } void DXmlGuiWindow::createMediaServerAction() { m_mediaServerAction = new QAction(QIcon::fromTheme(QLatin1String("arrow-right-double")), i18n("Share with DLNA"), this); actionCollection()->addAction(QLatin1String("mediaserver"), m_mediaServerAction); connect(m_mediaServerAction, SIGNAL(triggered(bool)), this, SLOT(slotMediaServer())); } void DXmlGuiWindow::createFullScreenAction(const QString& name) { d->fullScreenAction = KStandardAction::fullScreen(0, 0, this, this); actionCollection()->addAction(name, d->fullScreenAction); d->fullScreenBtn = new QToolButton(this); d->fullScreenBtn->setDefaultAction(d->fullScreenAction); d->fullScreenBtn->hide(); connect(d->fullScreenAction, SIGNAL(toggled(bool)), this, SLOT(slotToggleFullScreen(bool))); } void DXmlGuiWindow::readFullScreenSettings(const KConfigGroup& group) { if (d->fsOptions & FS_TOOLBARS) d->fullScreenHideToolBars = group.readEntry(s_configFullScreenHideToolBarsEntry, false); if (d->fsOptions & FS_THUMBBAR) d->fullScreenHideThumbBar = group.readEntry(s_configFullScreenHideThumbBarEntry, true); if (d->fsOptions & FS_SIDEBARS) d->fullScreenHideSideBars = group.readEntry(s_configFullScreenHideSideBarsEntry, false); } void DXmlGuiWindow::slotToggleFullScreen(bool set) { KToggleFullScreenAction::setFullScreen(this, set); customizedFullScreenMode(set); if (!set) { qCDebug(DIGIKAM_WIDGETS_LOG) << "TURN OFF fullscreen"; // restore menubar if (d->menubarVisibility) menuBar()->setVisible(true); // restore statusbar if (d->statusbarVisibility) statusBar()->setVisible(true); // restore sidebars if ((d->fsOptions & FS_SIDEBARS) && d->fullScreenHideSideBars) showSideBars(true); // restore thumbbar if ((d->fsOptions & FS_THUMBBAR) && d->fullScreenHideThumbBar) showThumbBar(d->thumbbarVisibility); // restore toolbars and manage full-screen button showToolBars(true); d->fullScreenBtn->hide(); if (d->dirtyMainToolBar) { KToolBar* const mainbar = mainToolBar(); if (mainbar) { mainbar->removeAction(d->fullScreenAction); } } } else { qCDebug(DIGIKAM_WIDGETS_LOG) << "TURN ON fullscreen"; // hide menubar #ifdef Q_OS_WIN d->menubarVisibility = d->showMenuBarAction->isChecked(); #else d->menubarVisibility = menuBar()->isVisible(); #endif menuBar()->setVisible(false); // hide statusbar #ifdef Q_OS_WIN d->statusbarVisibility = d->showStatusBarAction->isChecked(); #else d->statusbarVisibility = statusBar()->isVisible(); #endif statusBar()->setVisible(false); // hide sidebars if ((d->fsOptions & FS_SIDEBARS) && d->fullScreenHideSideBars) showSideBars(false); // hide thumbbar d->thumbbarVisibility = thumbbarVisibility(); if ((d->fsOptions & FS_THUMBBAR) && d->fullScreenHideThumbBar) showThumbBar(false); // hide toolbars and manage full-screen button if ((d->fsOptions & FS_TOOLBARS) && d->fullScreenHideToolBars) { showToolBars(false); } else { showToolBars(true); // add fullscreen action if necessary in toolbar KToolBar* const mainbar = mainToolBar(); if (mainbar && !mainbar->actions().contains(d->fullScreenAction)) { if (mainbar->actions().isEmpty()) { mainbar->addAction(d->fullScreenAction); } else { mainbar->insertAction(mainbar->actions().first(), d->fullScreenAction); } d->dirtyMainToolBar = true; } else { // If FullScreen button is enabled in toolbar settings, // we shall not remove it when leaving of fullscreen mode. d->dirtyMainToolBar = false; } } } } bool DXmlGuiWindow::fullScreenIsActive() const { if (d->fullScreenAction) return d->fullScreenAction->isChecked(); qCDebug(DIGIKAM_WIDGETS_LOG) << "FullScreenAction is not initialized"; return false; } bool DXmlGuiWindow::eventFilter(QObject* obj, QEvent* ev) { if (obj == this) { if (ev && (ev->type() == QEvent::HoverMove) && fullScreenIsActive()) { // We will handle a stand alone FullScreen button action on top/right corner of screen // only if managed window tool bar is hidden, and if we switched already in Full Screen mode. KToolBar* const mainbar = mainToolBar(); if (mainbar) { if (((d->fsOptions & FS_TOOLBARS) && d->fullScreenHideToolBars) || !mainbar->isVisible()) { QHoverEvent* const mev = dynamic_cast(ev); if (mev) { QPoint pos(mev->pos()); QRect desktopRect = QApplication::desktop()->screenGeometry(this); QRect sizeRect(QPoint(0, 0), d->fullScreenBtn->size()); QRect topLeft, topRight; QRect topRightLarger; desktopRect = QRect(desktopRect.y(), desktopRect.y(), desktopRect.width(), desktopRect.height()); topLeft = sizeRect; topRight = sizeRect; topLeft.moveTo(desktopRect.x(), desktopRect.y()); topRight.moveTo(desktopRect.x() + desktopRect.width() - sizeRect.width() - 1, topLeft.y()); topRightLarger = topRight.adjusted(-25, 0, 0, 10); if (topRightLarger.contains(pos)) { d->fullScreenBtn->move(topRight.topLeft()); d->fullScreenBtn->show(); } else { d->fullScreenBtn->hide(); } return false; } } } } } // pass the event on to the parent class return QObject::eventFilter(obj, ev); } void DXmlGuiWindow::keyPressEvent(QKeyEvent* e) { if (e->key() == Qt::Key_Escape) { if (fullScreenIsActive()) { d->fullScreenAction->activate(QAction::Trigger); } } } KToolBar* DXmlGuiWindow::mainToolBar() const { QList toolbars = toolBars(); KToolBar* mainToolbar = 0; foreach (KToolBar* const toolbar, toolbars) { if (toolbar && (toolbar->objectName() == QLatin1String("mainToolBar"))) { mainToolbar = toolbar; break; } } return mainToolbar; } void DXmlGuiWindow::showToolBars(bool visible) { // We will hide toolbars: store previous state for future restoring. if (!visible) { d->toolbarsVisibility.clear(); foreach (KToolBar* const toolbar, toolBars()) { if (toolbar) { bool visibility = toolbar->isVisible(); d->toolbarsVisibility.insert(toolbar, visibility); } } } // Switch toolbars visibility for (QMap::const_iterator it = d->toolbarsVisibility.constBegin(); it != d->toolbarsVisibility.constEnd(); ++it) { KToolBar* const toolbar = it.key(); bool visibility = it.value(); if (toolbar) { if (visible && visibility) toolbar->show(); else toolbar->hide(); } } // We will show toolbars: restore previous state. if (visible) { for (QMap::const_iterator it = d->toolbarsVisibility.constBegin(); it != d->toolbarsVisibility.constEnd(); ++it) { KToolBar* const toolbar = it.key(); bool visibility = it.value(); if (toolbar) { visibility ? toolbar->show() : toolbar->hide(); } } } } void DXmlGuiWindow::showSideBars(bool visible) { Q_UNUSED(visible); } void DXmlGuiWindow::showThumbBar(bool visible) { Q_UNUSED(visible); } void DXmlGuiWindow::customizedFullScreenMode(bool set) { Q_UNUSED(set); } bool DXmlGuiWindow::thumbbarVisibility() const { return true; } void DXmlGuiWindow::slotHelpContents() { openHandbook(); } void DXmlGuiWindow::openHandbook() { QUrl url = QUrl(QString::fromUtf8("https://docs.kde.org/trunk5/en/extragear-graphics/%1/index.html") .arg(QApplication::applicationName())); WebBrowserDlg* const browser = new WebBrowserDlg(url, qApp->activeWindow()); browser->show(); } void DXmlGuiWindow::restoreWindowSize(QWindow* const win, const KConfigGroup& group) { KWindowConfig::restoreWindowSize(win, group); } void DXmlGuiWindow::saveWindowSize(QWindow* const win, KConfigGroup& group) { KWindowConfig::saveWindowSize(win, group); } QAction* DXmlGuiWindow::buildStdAction(StdActionType type, const QObject* const recvr, const char* const slot, QObject* const parent) { switch(type) { case StdCopyAction: return KStandardAction::copy(recvr, slot, parent); break; case StdPasteAction: return KStandardAction::paste(recvr, slot, parent); break; case StdCutAction: return KStandardAction::cut(recvr, slot, parent); break; case StdQuitAction: return KStandardAction::quit(recvr, slot, parent); break; case StdCloseAction: return KStandardAction::close(recvr, slot, parent); break; case StdZoomInAction: return KStandardAction::zoomIn(recvr, slot, parent); break; case StdZoomOutAction: return KStandardAction::zoomOut(recvr, slot, parent); break; case StdOpenAction: #ifndef __clang_analyzer__ // NOTE: disable false positive report from scan build about open() return KStandardAction::open(recvr, slot, parent); #endif break; case StdSaveAction: return KStandardAction::save(recvr, slot, parent); break; case StdSaveAsAction: return KStandardAction::saveAs(recvr, slot, parent); break; case StdRevertAction: return KStandardAction::revert(recvr, slot, parent); break; case StdBackAction: return KStandardAction::back(recvr, slot, parent); break; case StdForwardAction: return KStandardAction::forward(recvr, slot, parent); break; default: return 0; break; } } void DXmlGuiWindow::slotRawCameraList() { showRawCameraList(); } void DXmlGuiWindow::slotDonateMoney() { WebBrowserDlg* const browser = new WebBrowserDlg(QUrl(QLatin1String("https://www.digikam.org/donate/")), qApp->activeWindow()); browser->show(); } void DXmlGuiWindow::slotRecipesBook() { WebBrowserDlg* const browser = new WebBrowserDlg(QUrl(QLatin1String("https://www.digikam.org/recipes_book/")), qApp->activeWindow()); browser->show(); } void DXmlGuiWindow::slotContribute() { WebBrowserDlg* const browser = new WebBrowserDlg(QUrl(QLatin1String("https://www.digikam.org/contribute/")), qApp->activeWindow()); browser->show(); } void DXmlGuiWindow::setupIconTheme() { // Let QStandardPaths handle this, it will look for app local stuff // this means e.g. for mac: "/../Resources" and for win: "/data". bool hasBreeze = false; const QString breezeIcons = QStandardPaths::locate(QStandardPaths::DataLocation, QLatin1String("breeze.rcc")); if (!breezeIcons.isEmpty() && QFile::exists(breezeIcons)) { QResource::registerResource(breezeIcons); hasBreeze = true; } bool hasBreezeDark = false; const QString breezeDarkIcons = QStandardPaths::locate(QStandardPaths::DataLocation, QLatin1String("breeze-dark.rcc")); if (!breezeDarkIcons.isEmpty() && QFile::exists(breezeDarkIcons)) { QResource::registerResource(breezeDarkIcons); hasBreezeDark = true; } if (hasBreeze || hasBreezeDark) { // Tell Qt about the theme QIcon::setThemeSearchPaths(QStringList() << QLatin1String(":/icons")); // Tell icons loader an co. about the theme KConfigGroup cg(KSharedConfig::openConfig(), "Icons"); if (hasBreeze) { QIcon::setThemeName(QLatin1String("breeze")); cg.writeEntry("Theme", "breeze"); qCDebug(DIGIKAM_WIDGETS_LOG) << "Breeze icons resource file found"; } else if (hasBreezeDark) { QIcon::setThemeName(QLatin1String("breeze-dark")); cg.writeEntry("Theme", "breeze-dark"); qCDebug(DIGIKAM_WIDGETS_LOG) << "Breeze-dark icons resource file found"; } else { qCDebug(DIGIKAM_WIDGETS_LOG) << "No icons resource file found"; } cg.sync(); } } void DXmlGuiWindow::createExportActions() { m_exportDropboxAction = new QAction(i18n("Export to &Dropbox..."), this); - m_exportDropboxAction->setIcon(QIcon::fromTheme(QLatin1String("dropbox"))); + m_exportDropboxAction->setIcon(QIcon::fromTheme(QLatin1String("dk-dropbox"))); actionCollection()->addAction(QLatin1String("export_dropbox"), m_exportDropboxAction); actionCollection()->setDefaultShortcut(m_exportDropboxAction, Qt::ALT + Qt::SHIFT + Qt::CTRL + Qt::Key_D); connect(m_exportDropboxAction, SIGNAL(triggered(bool)), this, SLOT(slotExportTool())); m_exportOnedriveAction = new QAction(i18n("Export to &Onedrive..."), this); - m_exportOnedriveAction->setIcon(QIcon::fromTheme(QString::fromLatin1("onedrive"))); + m_exportOnedriveAction->setIcon(QIcon::fromTheme(QLatin1String("dk-onedrive"))); actionCollection()->addAction(QLatin1String("export_onedrive"), m_exportOnedriveAction); actionCollection()->setDefaultShortcut(m_exportOnedriveAction, Qt::ALT + Qt::SHIFT + Qt::CTRL + Qt::Key_O); connect(m_exportOnedriveAction, SIGNAL(triggered(bool)), this, SLOT(slotExportTool())); m_exportPinterestAction = new QAction(i18n("Export to &Pinterest..."), this); - m_exportPinterestAction->setIcon(QIcon::fromTheme(QString::fromLatin1("pinterest"))); + m_exportPinterestAction->setIcon(QIcon::fromTheme(QLatin1String("dk-pinterest"))); actionCollection()->addAction(QLatin1String("export_pinterest"), m_exportPinterestAction); actionCollection()->setDefaultShortcut(m_exportPinterestAction, Qt::ALT + Qt::SHIFT + Qt::CTRL + Qt::Key_I); connect(m_exportPinterestAction, SIGNAL(triggered(bool)), this, SLOT(slotExportTool())); m_exportBoxAction = new QAction(i18n("Export to &Box..."), this); - m_exportBoxAction->setIcon(QIcon::fromTheme(QString::fromLatin1("box"))); + m_exportBoxAction->setIcon(QIcon::fromTheme(QLatin1String("dk-box"))); actionCollection()->addAction(QLatin1String("export_box"), m_exportBoxAction); actionCollection()->setDefaultShortcut(m_exportBoxAction, Qt::ALT + Qt::SHIFT + Qt::CTRL + Qt::Key_B); connect(m_exportBoxAction, SIGNAL(triggered(bool)), this, SLOT(slotExportTool())); m_exportFacebookAction = new QAction(i18n("Export to &Facebook..."), this); - m_exportFacebookAction->setIcon(QIcon::fromTheme(QString::fromLatin1("facebook"))); + m_exportFacebookAction->setIcon(QIcon::fromTheme(QString::fromLatin1("dk-facebook"))); actionCollection()->addAction(QLatin1String("export_facebook"), m_exportFacebookAction); actionCollection()->setDefaultShortcut(m_exportFacebookAction, Qt::ALT + Qt::SHIFT + Qt::Key_F); connect(m_exportFacebookAction, SIGNAL(triggered(bool)), this, SLOT(slotExportTool())); m_exportFlickrAction = new QAction(i18n("Export to Flick&r..."), this); - m_exportFlickrAction->setIcon(QIcon::fromTheme(QLatin1String("flickr"))); + m_exportFlickrAction->setIcon(QIcon::fromTheme(QLatin1String("dk-flickr"))); actionCollection()->addAction(QLatin1String("export_flickr"), m_exportFlickrAction); actionCollection()->setDefaultShortcut(m_exportFlickrAction, Qt::ALT + Qt::SHIFT + Qt::Key_R); connect(m_exportFlickrAction, SIGNAL(triggered(bool)), this, SLOT(slotExportTool())); m_exportGdriveAction = new QAction(i18n("Export to &Google Drive..."), this); - m_exportGdriveAction->setIcon(QIcon::fromTheme(QLatin1String("googledrive"))); + m_exportGdriveAction->setIcon(QIcon::fromTheme(QLatin1String("dk-googledrive"))); actionCollection()->addAction(QLatin1String("export_googledrive"), m_exportGdriveAction); actionCollection()->setDefaultShortcut(m_exportGdriveAction, Qt::ALT + Qt::SHIFT + Qt::CTRL + Qt::Key_G); connect(m_exportGdriveAction, SIGNAL(triggered(bool)), this, SLOT(slotExportTool())); m_exportGphotoAction = new QAction(i18n("Export to &Google Photos..."), this); - m_exportGphotoAction->setIcon(QIcon::fromTheme(QLatin1String("googlephoto"))); + m_exportGphotoAction->setIcon(QIcon::fromTheme(QLatin1String("dk-googlephoto"))); actionCollection()->addAction(QLatin1String("export_googlephoto"), m_exportGphotoAction); actionCollection()->setDefaultShortcut(m_exportGphotoAction, Qt::ALT + Qt::SHIFT + Qt::Key_P); connect(m_exportGphotoAction, SIGNAL(triggered(bool)), this, SLOT(slotExportTool())); m_exportImageshackAction = new QAction(i18n("Export to &Imageshack..."), this); - m_exportImageshackAction->setIcon(QIcon::fromTheme(QLatin1String("imageshack"))); + m_exportImageshackAction->setIcon(QIcon::fromTheme(QLatin1String("dk-imageshack"))); actionCollection()->addAction(QLatin1String("export_imageshack"), m_exportImageshackAction); actionCollection()->setDefaultShortcut(m_exportImageshackAction, Qt::ALT + Qt::SHIFT + Qt::Key_M); connect(m_exportImageshackAction, SIGNAL(triggered(bool)), this, SLOT(slotExportTool())); m_exportImgurAction = new QAction(i18n("Export to &Imgur.."), this); - m_exportImgurAction->setIcon(QIcon::fromTheme(QLatin1String("imgur"))); + m_exportImgurAction->setIcon(QIcon::fromTheme(QLatin1String("dk-imgur"))); actionCollection()->addAction(QLatin1String("export_imgur"), m_exportImgurAction); connect(m_exportImgurAction, SIGNAL(triggered(bool)), this, SLOT(slotExportTool())); m_exportIpfsAction = new QAction(i18n("Export to &Ipfs.."), this); - m_exportIpfsAction->setIcon(QIcon::fromTheme(QLatin1String("ipfs"))); + m_exportIpfsAction->setIcon(QIcon::fromTheme(QLatin1String("dk-ipfs"))); actionCollection()->addAction(QLatin1String("export_ipfs"), m_exportIpfsAction); connect(m_exportIpfsAction, SIGNAL(triggered(bool)), this, SLOT(slotExportTool())); m_exportPiwigoAction = new QAction(i18n("Export to &Piwigo..."), this); - m_exportPiwigoAction->setIcon(QIcon::fromTheme(QLatin1String("piwigo"))); + m_exportPiwigoAction->setIcon(QIcon::fromTheme(QLatin1String("dk-piwigo"))); actionCollection()->addAction(QLatin1String("export_piwigo"), m_exportPiwigoAction); connect(m_exportPiwigoAction, SIGNAL(triggered(bool)), this, SLOT(slotExportTool())); m_exportRajceAction = new QAction(i18n("Export to &Rajce.net..."), this); - m_exportRajceAction->setIcon(QIcon::fromTheme(QLatin1String("rajce"))); + m_exportRajceAction->setIcon(QIcon::fromTheme(QLatin1String("dk-rajce"))); actionCollection()->addAction(QLatin1String("export_rajce"), m_exportRajceAction); actionCollection()->setDefaultShortcut(m_exportRajceAction, Qt::ALT + Qt::SHIFT + Qt::Key_J); connect(m_exportRajceAction, SIGNAL(triggered(bool)), this, SLOT(slotExportTool())); m_exportSmugmugAction = new QAction(i18n("Export to &SmugMug..."), this); - m_exportSmugmugAction->setIcon(QIcon::fromTheme(QLatin1String("smugmug"))); + m_exportSmugmugAction->setIcon(QIcon::fromTheme(QLatin1String("dk-smugmug"))); actionCollection()->addAction(QLatin1String("export_smugmug"), m_exportSmugmugAction); actionCollection()->setDefaultShortcut(m_exportSmugmugAction, Qt::ALT + Qt::SHIFT + Qt::Key_S); connect(m_exportSmugmugAction, SIGNAL(triggered(bool)), this, SLOT(slotExportTool())); m_exportYandexfotkiAction = new QAction(i18n("Export to &Yandex.Fotki..."), this); m_exportYandexfotkiAction->setIcon(QIcon::fromTheme(QLatin1String("internet-web-browser"))); actionCollection()->addAction(QLatin1String("export_yandexfotki"), m_exportYandexfotkiAction); actionCollection()->setDefaultShortcut(m_exportYandexfotkiAction, Qt::ALT + Qt::SHIFT + Qt::Key_Y); connect(m_exportYandexfotkiAction, SIGNAL(triggered(bool)), this, SLOT(slotExportTool())); m_exportMediawikiAction = new QAction(i18n("Export to MediaWiki..."), this); - m_exportMediawikiAction->setIcon(QIcon::fromTheme(QLatin1String("MediaWiki"))); + m_exportMediawikiAction->setIcon(QIcon::fromTheme(QLatin1String("dk-mediawiki"))); actionCollection()->addAction(QLatin1String("export_MediaWiki"), m_exportMediawikiAction); connect(m_exportMediawikiAction, SIGNAL(triggered(bool)), this, SLOT(slotExportTool())); #ifdef HAVE_VKONTAKTE m_exportVkontakteAction = new QAction(i18n("Export to &VKontakte..."), this); m_exportVkontakteAction->setIcon(QIcon::fromTheme(QLatin1String("preferences-web-browser-shortcuts"))); actionCollection()->addAction(QLatin1String("export_vkontakte"), m_exportVkontakteAction); connect(m_exportVkontakteAction, SIGNAL(triggered(bool)), this, SLOT(slotExportTool())); #endif #ifdef HAVE_KIO m_exportFileTransferAction = new QAction(i18n("Export to remote storage..."), this); m_exportFileTransferAction->setIcon(QIcon::fromTheme(QLatin1String("folder-html"))); actionCollection()->addAction(QLatin1String("export_filetransfer"), m_exportFileTransferAction); actionCollection()->setDefaultShortcut(m_exportYandexfotkiAction, Qt::ALT + Qt::SHIFT + Qt::Key_K); connect(m_exportFileTransferAction, SIGNAL(triggered(bool)), this, SLOT(slotExportTool())); #endif } void DXmlGuiWindow::createImportActions() { m_importGphotoAction = new QAction(i18n("Import from &Google Photos..."), this); - m_importGphotoAction->setIcon(QIcon::fromTheme(QLatin1String("googlephoto"))); + m_importGphotoAction->setIcon(QIcon::fromTheme(QLatin1String("dk-googlephoto"))); actionCollection()->addAction(QLatin1String("import_googlephoto"), m_importGphotoAction); actionCollection()->setDefaultShortcut(m_importGphotoAction, Qt::ALT + Qt::SHIFT + Qt::CTRL + Qt::Key_P); connect(m_importGphotoAction, SIGNAL(triggered(bool)), this, SLOT(slotImportTool())); m_importSmugmugAction = new QAction(i18n("Import from &SmugMug..."), this); - m_importSmugmugAction->setIcon(QIcon::fromTheme(QLatin1String("smugmug"))); + m_importSmugmugAction->setIcon(QIcon::fromTheme(QLatin1String("dk-smugmug"))); actionCollection()->addAction(QLatin1String("import_smugmug"), m_importSmugmugAction); actionCollection()->setDefaultShortcut(m_importSmugmugAction, Qt::ALT + Qt::SHIFT + Qt::CTRL + Qt::Key_S); connect(m_importSmugmugAction, SIGNAL(triggered(bool)), this, SLOT(slotImportTool())); #ifdef HAVE_KIO m_importFileTransferAction = new QAction(i18n("Import from remote storage..."), this); m_importFileTransferAction->setIcon(QIcon::fromTheme(QLatin1String("folder-html"))); actionCollection()->addAction(QLatin1String("import_filetransfer"), m_importFileTransferAction); actionCollection()->setDefaultShortcut(m_importFileTransferAction, Qt::ALT + Qt::SHIFT + Qt::Key_I); connect(m_importFileTransferAction, SIGNAL(triggered(bool)), this, SLOT(slotImportTool())); #endif #ifdef HAVE_KSANE m_ksaneAction = new KSaneAction(this); actionCollection()->addAction(QLatin1String("import_scan"), m_ksaneAction); connect(m_ksaneAction, SIGNAL(triggered(bool)), this, SLOT(slotImportFromScanner())); #endif } QList DXmlGuiWindow::exportActions() const { return QList() << m_exportDropboxAction << m_exportOnedriveAction << m_exportPinterestAction << m_exportBoxAction << m_exportFacebookAction << m_exportFlickrAction << m_exportGdriveAction << m_exportGphotoAction << m_exportImageshackAction << m_exportImgurAction << m_exportIpfsAction << m_exportPiwigoAction << m_exportRajceAction << m_exportSmugmugAction << m_exportYandexfotkiAction << m_exportMediawikiAction #ifdef HAVE_VKONTAKTE << m_exportVkontakteAction #endif #ifdef HAVE_KIO << m_exportFileTransferAction; #endif ; } QList DXmlGuiWindow::importActions() const { return QList() << m_importGphotoAction << m_importSmugmugAction #ifdef HAVE_KIO << m_importFileTransferAction #endif #ifdef HAVE_KSANE << m_ksaneAction #endif ; } int DXmlGuiWindow::actionToWebService(QAction* const action) const { if (action == m_exportBoxAction) { return WSStarter::ExportBox; } else if (action == m_exportDropboxAction) { return WSStarter::ExportDropbox; } else if (action == m_exportFacebookAction) { return WSStarter::ExportFacebook; } #ifdef HAVE_KIO else if (action == m_exportFileTransferAction) { return WSStarter::ExportFileTransfer; } #endif else if (action == m_exportFlickrAction) { return WSStarter::ExportFlickr; } else if (action == m_exportGdriveAction) { return WSStarter::ExportGdrive; } else if (action == m_exportGphotoAction) { return WSStarter::ExportGphoto; } else if (action == m_exportImageshackAction) { return WSStarter::ExportImageshack; } else if (action == m_exportImgurAction) { return WSStarter::ExportImgur; } else if (action == m_exportIpfsAction) { return WSStarter::ExportIpfs; } else if (action == m_exportMediawikiAction) { return WSStarter::ExportMediawiki; } else if (action == m_exportOnedriveAction) { return WSStarter::ExportOnedrive; } else if (action == m_exportPinterestAction) { return WSStarter::ExportPinterest; } else if (action == m_exportPiwigoAction) { return WSStarter::ExportPiwigo; } else if (action == m_exportRajceAction) { return WSStarter::ExportRajce; } else if (action == m_exportSmugmugAction) { return WSStarter::ExportSmugmug; } #ifdef HAVE_VKONTAKTE else if (action == m_exportVkontakteAction) { return WSStarter::ExportVkontakte; } #endif else if (action == m_exportYandexfotkiAction) { return WSStarter::ExportYandexfotki; } else if (action == m_importGphotoAction) { return WSStarter::ImportGphoto; } #ifdef HAVE_KIO else if (action == m_importFileTransferAction) { return WSStarter::ImportFileTransfer; } #endif else if (action == m_importSmugmugAction) { return WSStarter::ImportSmugmug; } return WSStarter::ExportUnknown; } } // namespace Digikam diff --git a/core/utilities/assistants/webservices/box/boxwindow.cpp b/core/utilities/assistants/webservices/box/boxwindow.cpp index c4ee70494e..3d885ddf5a 100644 --- a/core/utilities/assistants/webservices/box/boxwindow.cpp +++ b/core/utilities/assistants/webservices/box/boxwindow.cpp @@ -1,468 +1,468 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2018-05-20 * Description : a tool to export images to Box web service * * Copyright (C) 2018 by Tarek Talaat * * 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 "boxwindow.h" // Qt includes #include #include #include #include #include #include // KDE includes #include #include #include // Local includes #include "digikam_debug.h" #include "ditemslist.h" #include "digikam_version.h" #include "boxtalker.h" #include "boxitem.h" #include "boxnewalbumdlg.h" #include "boxwidget.h" namespace Digikam { class Q_DECL_HIDDEN BOXWindow::Private { public: explicit Private() { imagesCount = 0; imagesTotal = 0; widget = 0; albumDlg = 0; talker = 0; } unsigned int imagesCount; unsigned int imagesTotal; BOXWidget* widget; BOXNewAlbumDlg* albumDlg; BOXTalker* talker; QString currentAlbumName; QList transferQueue; }; BOXWindow::BOXWindow(DInfoInterface* const iface, QWidget* const /*parent*/) : WSToolDialog(0), d(new Private) { d->widget = new BOXWidget(this, iface, QLatin1String("Box")); d->widget->imagesList()->setIface(iface); setMainWidget(d->widget); setModal(false); setWindowTitle(i18n("Export to Box")); startButton()->setText(i18n("Start Upload")); startButton()->setToolTip(i18n("Start upload to Box")); d->widget->setMinimumSize(700, 500); connect(d->widget->imagesList(), SIGNAL(signalImageListChanged()), this, SLOT(slotImageListChanged())); connect(d->widget->getChangeUserBtn(), SIGNAL(clicked()), this, SLOT(slotUserChangeRequest())); connect(d->widget->getNewAlbmBtn(), SIGNAL(clicked()), this, SLOT(slotNewAlbumRequest())); connect(d->widget->getReloadBtn(), SIGNAL(clicked()), this, SLOT(slotReloadAlbumsRequest())); connect(startButton(), SIGNAL(clicked()), this, SLOT(slotStartTransfer())); d->albumDlg = new BOXNewAlbumDlg(this, QLatin1String("Box")); d->talker = new BOXTalker(this); connect(d->talker,SIGNAL(signalBusy(bool)), this, SLOT(slotBusy(bool))); connect(d->talker, SIGNAL(signalLinkingFailed()), this, SLOT(slotSignalLinkingFailed())); connect(d->talker, SIGNAL(signalLinkingSucceeded()), this, SLOT(slotSignalLinkingSucceeded())); connect(d->talker, SIGNAL(signalSetUserName(QString)), this, SLOT(slotSetUserName(QString))); connect(d->talker, SIGNAL(signalListAlbumsFailed(QString)), this, SLOT(slotListAlbumsFailed(QString))); connect(d->talker, SIGNAL(signalListAlbumsDone(QList >)), // krazy:exclude=normalize this, SLOT(slotListAlbumsDone(QList >))); // krazy:exclude=normalize connect(d->talker, SIGNAL(signalCreateFolderFailed(QString)), this, SLOT(slotCreateFolderFailed(QString))); connect(d->talker, SIGNAL(signalCreateFolderSucceeded()), this, SLOT(slotCreateFolderSucceeded())); connect(d->talker, SIGNAL(signalAddPhotoFailed(QString)), this, SLOT(slotAddPhotoFailed(QString))); connect(d->talker, SIGNAL(signalAddPhotoSucceeded()), this, SLOT(slotAddPhotoSucceeded())); connect(this, SIGNAL(finished(int)), this, SLOT(slotFinished())); readSettings(); buttonStateChange(false); d->talker->link(); } BOXWindow::~BOXWindow() { delete d->widget; delete d->albumDlg; delete d->talker; delete d; } void BOXWindow::readSettings() { KConfig config; KConfigGroup grp = config.group("Box Settings"); d->currentAlbumName = grp.readEntry("Current Album",QString()); if (grp.readEntry("Resize", false)) { d->widget->getResizeCheckBox()->setChecked(true); d->widget->getDimensionSpB()->setEnabled(true); } else { d->widget->getResizeCheckBox()->setChecked(false); d->widget->getDimensionSpB()->setEnabled(false); } d->widget->getDimensionSpB()->setValue(grp.readEntry("Maximum Width", 1600)); d->widget->getImgQualitySpB()->setValue(grp.readEntry("Image Quality", 90)); KConfigGroup dialogGroup = config.group("Box Export Dialog"); winId(); KWindowConfig::restoreWindowSize(windowHandle(), dialogGroup); resize(windowHandle()->size()); } void BOXWindow::writeSettings() { KConfig config; KConfigGroup grp = config.group("Box Settings"); grp.writeEntry("Current Album", d->currentAlbumName); grp.writeEntry("Resize", d->widget->getResizeCheckBox()->isChecked()); grp.writeEntry("Maximum Width", d->widget->getDimensionSpB()->value()); grp.writeEntry("Image Quality", d->widget->getImgQualitySpB()->value()); KConfigGroup dialogGroup = config.group("Box Export Dialog"); KWindowConfig::saveWindowSize(windowHandle(), dialogGroup); config.sync(); } void BOXWindow::reactivate() { d->widget->imagesList()->loadImagesFromCurrentSelection(); d->widget->progressBar()->hide(); show(); } void BOXWindow::setItemsList(const QList& urls) { d->widget->imagesList()->slotAddImages(urls); } void BOXWindow::slotBusy(bool val) { if (val) { setCursor(Qt::WaitCursor); d->widget->getChangeUserBtn()->setEnabled(false); buttonStateChange(false); } else { setCursor(Qt::ArrowCursor); d->widget->getChangeUserBtn()->setEnabled(true); buttonStateChange(true); } } void BOXWindow::slotSetUserName(const QString& msg) { d->widget->updateLabels(msg, QLatin1String("")); } void BOXWindow::slotListAlbumsDone(const QList >& list) { d->widget->getAlbumsCoB()->clear(); for (int i = 0 ; i < list.size() ; ++i) { d->widget->getAlbumsCoB()->addItem( QIcon::fromTheme(QLatin1String("system-users")), list.value(i).second, list.value(i).second); if (d->currentAlbumName == QString(list.value(i).second)) { d->widget->getAlbumsCoB()->setCurrentIndex(i); } } buttonStateChange(true); d->talker->getUserName(); } void BOXWindow::slotStartTransfer() { d->widget->imagesList()->clearProcessedStatus(); if (d->widget->imagesList()->imageUrls().isEmpty()) { QMessageBox::critical(this, i18nc("@title:window", "Error"), i18n("No image selected. Please select which images should be uploaded.")); return; } if (!(d->talker->authenticated())) { QPointer warn = new QMessageBox(QMessageBox::Warning, i18n("Warning"), i18n("Authentication failed. Click \"Continue\" to authenticate."), QMessageBox::Yes | QMessageBox::No); (warn->button(QMessageBox::Yes))->setText(i18n("Continue")); (warn->button(QMessageBox::No))->setText(i18n("Cancel")); if (warn->exec() == QMessageBox::Yes) { d->talker->link(); delete warn; return; } else { delete warn; return; } } d->transferQueue = d->widget->imagesList()->imageUrls(); if (d->transferQueue.isEmpty()) { return; } d->currentAlbumName = d->widget->getAlbumsCoB()->itemData(d->widget->getAlbumsCoB()->currentIndex()).toString(); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "StartTransfer:" << d->currentAlbumName << "INDEX: " << d->widget->getAlbumsCoB()->currentIndex(); d->imagesTotal = d->transferQueue.count(); d->imagesCount = 0; d->widget->progressBar()->setFormat(i18n("%v / %m")); d->widget->progressBar()->setMaximum(d->imagesTotal); d->widget->progressBar()->setValue(0); d->widget->progressBar()->show(); d->widget->progressBar()->progressScheduled(i18n("Box export"), true, true); - d->widget->progressBar()->progressThumbnailChanged(QIcon(QLatin1String("box")).pixmap(22, 22)); + d->widget->progressBar()->progressThumbnailChanged(QIcon(QLatin1String("dk-box")).pixmap(22, 22)); uploadNextPhoto(); } void BOXWindow::uploadNextPhoto() { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "uploadNextPhoto:" << d->transferQueue.count(); if (d->transferQueue.isEmpty()) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "empty"; d->widget->progressBar()->progressCompleted(); return; } QString imgPath = d->transferQueue.first().toLocalFile(); QString temp = d->currentAlbumName; bool result = d->talker->addPhoto(imgPath, temp, d->widget->getResizeCheckBox()->isChecked(), d->widget->getDimensionSpB()->value(), d->widget->getImgQualitySpB()->value()); if (!result) { slotAddPhotoFailed(QLatin1String("")); return; } } void BOXWindow::slotAddPhotoFailed(const QString& msg) { if (QMessageBox::question(this, i18n("Uploading Failed"), i18n("Failed to upload photo to Box." "\n%1\n" "Do you want to continue?", msg)) != QMessageBox::Yes) { d->transferQueue.clear(); d->widget->progressBar()->hide(); } else { d->transferQueue.pop_front(); d->imagesTotal--; d->widget->progressBar()->setMaximum(d->imagesTotal); d->widget->progressBar()->setValue(d->imagesCount); uploadNextPhoto(); } } void BOXWindow::slotAddPhotoSucceeded() { // Remove photo uploaded from the list d->widget->imagesList()->removeItemByUrl(d->transferQueue.first()); d->transferQueue.pop_front(); d->imagesCount++; d->widget->progressBar()->setMaximum(d->imagesTotal); d->widget->progressBar()->setValue(d->imagesCount); uploadNextPhoto(); } void BOXWindow::slotImageListChanged() { startButton()->setEnabled(!(d->widget->imagesList()->imageUrls().isEmpty())); } void BOXWindow::slotNewAlbumRequest() { if (d->albumDlg->exec() == QDialog::Accepted) { BOXFolder newFolder; d->albumDlg->getFolderTitle(newFolder); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "slotNewAlbumRequest:" << newFolder.title; d->currentAlbumName = d->widget->getAlbumsCoB()->itemData(d->widget->getAlbumsCoB()->currentIndex()).toString(); QString temp = d->currentAlbumName + newFolder.title; d->talker->createFolder(temp); } } void BOXWindow::slotReloadAlbumsRequest() { d->talker->listFolders(); } void BOXWindow::slotSignalLinkingFailed() { slotSetUserName(QLatin1String("")); d->widget->getAlbumsCoB()->clear(); if (QMessageBox::question(this, i18n("Login Failed"), i18n("Authentication failed. Do you want to try again?")) == QMessageBox::Yes) { d->talker->link(); } } void BOXWindow::slotSignalLinkingSucceeded() { slotBusy(false); d->talker->listFolders(); } void BOXWindow::slotListAlbumsFailed(const QString& msg) { QMessageBox::critical(this, QString(), i18n("Box call failed:\n%1", msg)); } void BOXWindow::slotCreateFolderFailed(const QString& msg) { QMessageBox::critical(this, QString(), i18n("Box call failed:\n%1", msg)); } void BOXWindow::slotCreateFolderSucceeded() { d->talker->listFolders(); } void BOXWindow::slotTransferCancel() { d->transferQueue.clear(); d->widget->progressBar()->hide(); d->talker->cancel(); } void BOXWindow::slotUserChangeRequest() { slotSetUserName(QLatin1String("")); d->widget->getAlbumsCoB()->clear(); d->talker->unLink(); d->talker->link(); } void BOXWindow::buttonStateChange(bool state) { d->widget->getNewAlbmBtn()->setEnabled(state); d->widget->getReloadBtn()->setEnabled(state); startButton()->setEnabled(state); } void BOXWindow::slotFinished() { writeSettings(); d->widget->imagesList()->listView()->clear(); } void BOXWindow::closeEvent(QCloseEvent* e) { if (!e) { return; } slotFinished(); e->accept(); } } // namespace Digikam diff --git a/core/utilities/assistants/webservices/common/wizard/wsintropage.cpp b/core/utilities/assistants/webservices/common/wizard/wsintropage.cpp index fc1c059954..93df615c4b 100644 --- a/core/utilities/assistants/webservices/common/wizard/wsintropage.cpp +++ b/core/utilities/assistants/webservices/common/wizard/wsintropage.cpp @@ -1,238 +1,238 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2017-06-27 * Description : intro page to export tool where user can choose web service to export, * existent accounts and function mode (export/import). * * Copyright (C) 2017-2019 by Gilles Caulier * Copyright (C) 2018 by Thanh Trung Dinh * * 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 "wsintropage.h" // Qt includes #include #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "digikam_debug.h" #include "dlayoutbox.h" #include "wswizard.h" #include "wssettings.h" namespace Digikam { class Q_DECL_HIDDEN WSIntroPage::Private { public: explicit Private(QWizard* const dialog) : imageGetOption(0), hbox(0), wizard(0), iface(0), wsOption(0), accountOption(0) { wizard = dynamic_cast(dialog); if (wizard) { iface = wizard->iface(); settings = wizard->settings(); } } QComboBox* imageGetOption; DHBox* hbox; WSWizard* wizard; WSSettings* settings; DInfoInterface* iface; QComboBox* wsOption; QComboBox* accountOption; }; WSIntroPage::WSIntroPage(QWizard* const dialog, const QString& title) : DWizardPage(dialog, title), d(new Private(dialog)) { DVBox* const vbox = new DVBox(this); QLabel* const desc = new QLabel(vbox); desc->setWordWrap(true); desc->setOpenExternalLinks(true); desc->setText(i18n("" "

Welcome to Web Services Tool

" "

This assistant will guide you step by step, to export " "your items to popular Internet data hosting service.

" "

Before exporting contents, you will be able to adjust items' properties " "according to your remote Web service capabilities.

" "
")); /* -------------------- * ComboBox for image selection method */ d->hbox = new DHBox(vbox); QLabel* const getImageLabel = new QLabel(i18n("&Choose operation:"), d->hbox); d->imageGetOption = new QComboBox(d->hbox); d->imageGetOption->insertItem(WSSettings::EXPORT, i18n("Export to web services")); d->imageGetOption->insertItem(WSSettings::IMPORT, i18n("Import from web services")); getImageLabel->setBuddy(d->imageGetOption); connect(d->imageGetOption, SIGNAL(currentIndexChanged(int)), this, SLOT(slotImageGetOptionChanged(int))); /* -------------------- * ComboBox for web service selection */ DHBox* const wsBox = new DHBox(vbox); QLabel* const wsLabel = new QLabel(i18n("&Choose remote Web Service:"), wsBox); d->wsOption = new QComboBox(wsBox); QMap map = WSSettings::webServiceNames(); QMap::const_iterator it = map.constBegin(); while (it != map.constEnd()) { QString wsName = it.value().toLower(); QIcon icon = QIcon::fromTheme(wsName.remove(QLatin1Char(' '))); d->wsOption->addItem(icon, it.value(), (int)it.key()); ++it; } wsLabel->setBuddy(d->wsOption); connect(d->wsOption, SIGNAL(currentIndexChanged(QString)), this, SLOT(slotWebServiceOptionChanged(QString))); /* -------------------- * ComboBox for user account selection * * An empty option is added to accounts, so that user can choose to login with new account */ DHBox* const accountBox = new DHBox(vbox); QLabel* const accountLabel = new QLabel(i18n("&Choose account:"), accountBox); d->accountOption = new QComboBox(accountBox); QStringList accounts = QStringList(QString("")) << d->settings->allUserNames(map.constBegin().value()); foreach(const QString& account, accounts) { d->accountOption->addItem(account); } accountLabel->setBuddy(d->accountOption); /* -------------------- * Place widget in the view */ vbox->setStretchFactor(desc, 3); vbox->setStretchFactor(d->hbox, 1); vbox->setStretchFactor(wsBox, 3); vbox->setStretchFactor(accountBox, 3); setPageWidget(vbox); setLeftBottomPix(QIcon::fromTheme(QLatin1String("folder-html"))); } WSIntroPage::~WSIntroPage() { delete d; } void WSIntroPage::slotImageGetOptionChanged(int index) { QMap map = WSSettings::webServiceNames(); d->wsOption->clear(); /* * index == 0 <=> Export * index == 1 <=> Import, for now we only have Google Photo and Smugmug in this option */ if (index == 0) { QMap::const_iterator it = map.constBegin(); while (it != map.constEnd()) { QString wsName = it.value().toLower(); QIcon icon = QIcon::fromTheme(wsName.remove(QLatin1Char(' '))); qCDebug(DIGIKAM_WEBSERVICES_LOG) << wsName.remove(QLatin1Char(' ')); d->wsOption->addItem(icon, it.value(), (int)it.key()); ++it; } } else { - d->wsOption->addItem(QIcon::fromTheme(QLatin1String("smugmug")), + d->wsOption->addItem(QIcon::fromTheme(QLatin1String("dk-smugmug")), map[WSSettings::WebService::SMUGMUG], WSSettings::WebService::SMUGMUG); - d->wsOption->addItem(QIcon::fromTheme(QLatin1String("googlephoto")), + d->wsOption->addItem(QIcon::fromTheme(QLatin1String("dk-googlephoto")), map[WSSettings::WebService::GPHOTO], WSSettings::WebService::GPHOTO); } } void WSIntroPage::slotWebServiceOptionChanged(const QString& serviceName) { d->accountOption->clear(); // An empty option is added to accounts, so that user can choose to login with new account QStringList accounts = QStringList(QString("")) << d->settings->allUserNames(serviceName); foreach(const QString& account, accounts) { d->accountOption->addItem(account); } } void WSIntroPage::initializePage() { d->imageGetOption->setCurrentIndex(d->wizard->settings()->selMode); } bool WSIntroPage::validatePage() { d->wizard->settings()->selMode = (WSSettings::Selection)d->imageGetOption->currentIndex(); d->wizard->settings()->webService = (WSSettings::WebService)d->wsOption->currentIndex(); d->wizard->settings()->userName = d->accountOption->currentText(); return true; } } // namespace Digikam diff --git a/core/utilities/assistants/webservices/common/wsselectuserdlg.cpp b/core/utilities/assistants/webservices/common/wsselectuserdlg.cpp index d412711907..2aac429010 100644 --- a/core/utilities/assistants/webservices/common/wsselectuserdlg.cpp +++ b/core/utilities/assistants/webservices/common/wsselectuserdlg.cpp @@ -1,163 +1,163 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2015-16-05 * Description : a dialog to select user for Web Service tools * * Copyright (C) 2015 by Shourya Singh Gupta * Copyright (C) 2016-2019 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "wsselectuserdlg.h" // Qt includes #include #include #include #include #include #include // KDE includes #include #include #include namespace Digikam { class Q_DECL_HIDDEN WSSelectUserDlg::Private { public: explicit Private() { userComboBox = 0; label = 0; okButton = 0; } QComboBox* userComboBox; QLabel* label; QPushButton* okButton; QString userName; QString serviceName; }; WSSelectUserDlg::WSSelectUserDlg(QWidget* const parent, const QString& serviceName) : QDialog(parent), d(new Private) { d->serviceName = serviceName; setWindowTitle(i18n("Account Selector")); setModal(true); QDialogButtonBox* const buttonBox = new QDialogButtonBox(); QPushButton* const buttonNewAccount = new QPushButton(buttonBox); buttonNewAccount->setText(i18n("Add another account")); buttonNewAccount->setIcon(QIcon::fromTheme(QLatin1String("network-workgroup"))); buttonBox->addButton(buttonNewAccount, QDialogButtonBox::AcceptRole); buttonBox->addButton(QDialogButtonBox::Ok); buttonBox->addButton(QDialogButtonBox::Close); buttonBox->button(QDialogButtonBox::Close)->setDefault(true); d->okButton = buttonBox->button(QDialogButtonBox::Ok); if (d->serviceName == QLatin1String("23")) { setWindowIcon(QIcon::fromTheme(QLatin1String("hq"))); } else { - setWindowIcon(QIcon::fromTheme(QLatin1String("flickr"))); + setWindowIcon(QIcon::fromTheme(QLatin1String("dk-flickr"))); } d->userName = QString(); d->label = new QLabel(this); d->label->setText(i18n("Choose the %1 account to use for exporting images:", d->serviceName)); d->userComboBox = new QComboBox(this); QVBoxLayout* const mainLayout = new QVBoxLayout(this); mainLayout->addWidget(d->label); mainLayout->addWidget(d->userComboBox); mainLayout->addWidget(buttonBox); setLayout(mainLayout); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); connect(buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(slotOkClicked())); connect(buttonNewAccount, SIGNAL(clicked()), this, SLOT(slotNewAccountClicked())); } WSSelectUserDlg::~WSSelectUserDlg() { delete d->userComboBox; delete d->label; delete d; } void WSSelectUserDlg::reactivate() { KConfig config; d->userComboBox->clear(); foreach(const QString& group, config.groupList()) { if (!(group.contains(d->serviceName))) continue; KConfigGroup grp = config.group(group); if (QString::compare(grp.readEntry(QLatin1String("username")), QString(), Qt::CaseInsensitive) == 0) continue; d->userComboBox->addItem(grp.readEntry(QLatin1String("username"))); } d->okButton->setEnabled(d->userComboBox->count() > 0); exec(); } void WSSelectUserDlg::slotOkClicked() { d->userName = d->userComboBox->currentText(); } void WSSelectUserDlg::slotNewAccountClicked() { d->userName = QString(); } QString WSSelectUserDlg::getUserName() const { return d->userName; } } // namespace Digikam diff --git a/core/utilities/assistants/webservices/dropbox/dbwindow.cpp b/core/utilities/assistants/webservices/dropbox/dbwindow.cpp index 61dc4f5ade..408745262a 100644 --- a/core/utilities/assistants/webservices/dropbox/dbwindow.cpp +++ b/core/utilities/assistants/webservices/dropbox/dbwindow.cpp @@ -1,461 +1,461 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2013-11-18 * Description : a tool to export images to Dropbox web service * * Copyright (C) 2013 by Pankaj Kumar * Copyright (C) 2013-2019 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "dbwindow.h" // Qt includes #include #include #include #include #include // KDE includes #include #include #include // Local includes #include "digikam_debug.h" #include "ditemslist.h" #include "digikam_version.h" #include "dbtalker.h" #include "dbitem.h" #include "dbnewalbumdlg.h" #include "dbwidget.h" namespace Digikam { class Q_DECL_HIDDEN DBWindow::Private { public: explicit Private() { imagesCount = 0; imagesTotal = 0; widget = 0; albumDlg = 0; talker = 0; } unsigned int imagesCount; unsigned int imagesTotal; DBWidget* widget; DBNewAlbumDlg* albumDlg; DBTalker* talker; QString currentAlbumName; QList transferQueue; }; DBWindow::DBWindow(DInfoInterface* const iface, QWidget* const /*parent*/) : WSToolDialog(0), d(new Private) { d->widget = new DBWidget(this, iface, QLatin1String("Dropbox")); d->widget->imagesList()->setIface(iface); setMainWidget(d->widget); setModal(false); setWindowTitle(i18n("Export to Dropbox")); startButton()->setText(i18n("Start Upload")); startButton()->setToolTip(i18n("Start upload to Dropbox")); d->widget->setMinimumSize(700, 500); connect(d->widget->imagesList(), SIGNAL(signalImageListChanged()), this, SLOT(slotImageListChanged())); connect(d->widget->getChangeUserBtn(), SIGNAL(clicked()), this, SLOT(slotUserChangeRequest())); connect(d->widget->getNewAlbmBtn(), SIGNAL(clicked()), this, SLOT(slotNewAlbumRequest())); connect(d->widget->getReloadBtn(), SIGNAL(clicked()), this, SLOT(slotReloadAlbumsRequest())); connect(startButton(), SIGNAL(clicked()), this, SLOT(slotStartTransfer())); d->albumDlg = new DBNewAlbumDlg(this, QLatin1String("Dropbox")); d->talker = new DBTalker(this); connect(d->talker, SIGNAL(signalBusy(bool)), this, SLOT(slotBusy(bool))); connect(d->talker, SIGNAL(signalLinkingFailed()), this, SLOT(slotSignalLinkingFailed())); connect(d->talker, SIGNAL(signalLinkingSucceeded()), this, SLOT(slotSignalLinkingSucceeded())); connect(d->talker, SIGNAL(signalSetUserName(QString)), this, SLOT(slotSetUserName(QString))); connect(d->talker, SIGNAL(signalListAlbumsFailed(QString)), this, SLOT(slotListAlbumsFailed(QString))); connect(d->talker, SIGNAL(signalListAlbumsDone(QList >)), // krazy:exclude=normalize this, SLOT(slotListAlbumsDone(QList >))); // krazy:exclude=normalize connect(d->talker, SIGNAL(signalCreateFolderFailed(QString)), this, SLOT(slotCreateFolderFailed(QString))); connect(d->talker, SIGNAL(signalCreateFolderSucceeded()), this, SLOT(slotCreateFolderSucceeded())); connect(d->talker, SIGNAL(signalAddPhotoFailed(QString)), this, SLOT(slotAddPhotoFailed(QString))); connect(d->talker, SIGNAL(signalAddPhotoSucceeded()), this, SLOT(slotAddPhotoSucceeded())); connect(this, SIGNAL(finished(int)), this, SLOT(slotFinished())); readSettings(); buttonStateChange(false); d->talker->link(); } DBWindow::~DBWindow() { delete d->widget; delete d->albumDlg; delete d->talker; delete d; } void DBWindow::setItemsList(const QList& urls) { d->widget->imagesList()->slotAddImages(urls); } void DBWindow::reactivate() { d->widget->imagesList()->loadImagesFromCurrentSelection(); d->widget->progressBar()->hide(); show(); } void DBWindow::readSettings() { KConfig config; KConfigGroup grp = config.group("Dropbox Settings"); d->currentAlbumName = grp.readEntry("Current Album",QString()); if (grp.readEntry("Resize", false)) { d->widget->getResizeCheckBox()->setChecked(true); d->widget->getDimensionSpB()->setEnabled(true); } else { d->widget->getResizeCheckBox()->setChecked(false); d->widget->getDimensionSpB()->setEnabled(false); } d->widget->getDimensionSpB()->setValue(grp.readEntry("Maximum Width", 1600)); d->widget->getImgQualitySpB()->setValue(grp.readEntry("Image Quality", 90)); winId(); KConfigGroup dialogGroup = config.group("Dropbox Export Dialog"); KWindowConfig::restoreWindowSize(windowHandle(), dialogGroup); resize(windowHandle()->size()); } void DBWindow::writeSettings() { KConfig config; KConfigGroup grp = config.group("Dropbox Settings"); grp.writeEntry("Current Album", d->currentAlbumName); grp.writeEntry("Resize", d->widget->getResizeCheckBox()->isChecked()); grp.writeEntry("Maximum Width", d->widget->getDimensionSpB()->value()); grp.writeEntry("Image Quality", d->widget->getImgQualitySpB()->value()); KConfigGroup dialogGroup = config.group("Dropbox Export Dialog"); KWindowConfig::saveWindowSize(windowHandle(), dialogGroup); config.sync(); } void DBWindow::slotSetUserName(const QString& msg) { d->widget->updateLabels(msg, QLatin1String("")); } void DBWindow::slotListAlbumsDone(const QList >& list) { d->widget->getAlbumsCoB()->clear(); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "slotListAlbumsDone:" << list.size(); for (int i = 0 ; i < list.size() ; ++i) { d->widget->getAlbumsCoB()->addItem( QIcon::fromTheme(QLatin1String("system-users")), list.value(i).second, list.value(i).first); if (d->currentAlbumName == list.value(i).first) { d->widget->getAlbumsCoB()->setCurrentIndex(i); } } buttonStateChange(true); d->talker->getUserName(); } void DBWindow::slotBusy(bool val) { if (val) { setCursor(Qt::WaitCursor); d->widget->getChangeUserBtn()->setEnabled(false); buttonStateChange(false); } else { setCursor(Qt::ArrowCursor); d->widget->getChangeUserBtn()->setEnabled(true); buttonStateChange(true); } } void DBWindow::slotStartTransfer() { d->widget->imagesList()->clearProcessedStatus(); if (d->widget->imagesList()->imageUrls().isEmpty()) { QMessageBox::critical(this, i18nc("@title:window", "Error"), i18n("No image selected. Please select which images should be uploaded.")); return; } if (!(d->talker->authenticated())) { if (QMessageBox::question(this, i18n("Login Failed"), i18n("Authentication failed. Do you want to try again?")) == QMessageBox::Yes) { d->talker->link(); return; } else { return; } } d->transferQueue = d->widget->imagesList()->imageUrls(); if (d->transferQueue.isEmpty()) { return; } d->currentAlbumName = d->widget->getAlbumsCoB()->itemData(d->widget->getAlbumsCoB()->currentIndex()).toString(); d->imagesTotal = d->transferQueue.count(); d->imagesCount = 0; d->widget->progressBar()->setFormat(i18n("%v / %m")); d->widget->progressBar()->setMaximum(d->imagesTotal); d->widget->progressBar()->setValue(0); d->widget->progressBar()->show(); d->widget->progressBar()->progressScheduled(i18n("Dropbox export"), true, true); d->widget->progressBar()->progressThumbnailChanged( - QIcon(QLatin1String("dropbox")).pixmap(22, 22)); + QIcon(QLatin1String("dk-dropbox")).pixmap(22, 22)); uploadNextPhoto(); } void DBWindow::uploadNextPhoto() { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "uploadNextPhoto:" << d->transferQueue.count(); if (d->transferQueue.isEmpty()) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "empty"; d->widget->progressBar()->progressCompleted(); return; } QString imgPath = d->transferQueue.first().toLocalFile(); QString temp = d->currentAlbumName + QLatin1Char('/'); bool res = d->talker->addPhoto(imgPath, temp, d->widget->getResizeCheckBox()->isChecked(), d->widget->getDimensionSpB()->value(), d->widget->getImgQualitySpB()->value()); if (!res) { slotAddPhotoFailed(QLatin1String("")); return; } } void DBWindow::slotAddPhotoFailed(const QString& msg) { if (QMessageBox::question(this, i18n("Uploading Failed"), i18n("Failed to upload photo to Dropbox." "\n%1\n" "Do you want to continue?", msg)) != QMessageBox::Yes) { d->transferQueue.clear(); d->widget->progressBar()->hide(); } else { d->transferQueue.removeFirst(); d->imagesTotal--; d->widget->progressBar()->setMaximum(d->imagesTotal); d->widget->progressBar()->setValue(d->imagesCount); uploadNextPhoto(); } } void DBWindow::slotAddPhotoSucceeded() { // Remove photo uploaded from the list d->widget->imagesList()->removeItemByUrl(d->transferQueue.first()); d->transferQueue.removeFirst(); d->imagesCount++; d->widget->progressBar()->setMaximum(d->imagesTotal); d->widget->progressBar()->setValue(d->imagesCount); uploadNextPhoto(); } void DBWindow::slotImageListChanged() { startButton()->setEnabled(!(d->widget->imagesList()->imageUrls().isEmpty())); } void DBWindow::slotNewAlbumRequest() { if (d->albumDlg->exec() == QDialog::Accepted) { DBFolder newFolder; d->albumDlg->getFolderTitle(newFolder); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "slotNewAlbumRequest:" << newFolder.title; d->currentAlbumName = d->widget->getAlbumsCoB()->itemData(d->widget->getAlbumsCoB()->currentIndex()).toString(); QString temp = d->currentAlbumName + newFolder.title; d->talker->createFolder(temp); } } void DBWindow::slotReloadAlbumsRequest() { d->talker->listFolders(); } void DBWindow::slotSignalLinkingFailed() { slotSetUserName(QLatin1String("")); d->widget->getAlbumsCoB()->clear(); if (QMessageBox::question(this, i18n("Login Failed"), i18n("Authentication failed. Do you want to try again?")) == QMessageBox::Yes) { d->talker->link(); } } void DBWindow::slotSignalLinkingSucceeded() { d->talker->listFolders(); } void DBWindow::slotListAlbumsFailed(const QString& msg) { QMessageBox::critical(this, QString(), i18n("Dropbox call failed:\n%1", msg)); } void DBWindow::slotCreateFolderFailed(const QString& msg) { QMessageBox::critical(this, QString(), i18n("Dropbox call failed:\n%1", msg)); } void DBWindow::slotCreateFolderSucceeded() { d->talker->listFolders(); } void DBWindow::slotTransferCancel() { d->transferQueue.clear(); d->widget->progressBar()->hide(); d->talker->cancel(); } void DBWindow::slotUserChangeRequest() { slotSetUserName(QLatin1String("")); d->widget->getAlbumsCoB()->clear(); d->talker->unLink(); d->talker->link(); } void DBWindow::buttonStateChange(bool state) { d->widget->getNewAlbmBtn()->setEnabled(state); d->widget->getReloadBtn()->setEnabled(state); startButton()->setEnabled(state); } void DBWindow::slotFinished() { writeSettings(); d->widget->imagesList()->listView()->clear(); } void DBWindow::closeEvent(QCloseEvent* e) { if (!e) { return; } slotFinished(); e->accept(); } } // namespace Digikam diff --git a/core/utilities/assistants/webservices/facebook/fbwindow.cpp b/core/utilities/assistants/webservices/facebook/fbwindow.cpp index 6804160e5d..44fc0fb9e8 100644 --- a/core/utilities/assistants/webservices/facebook/fbwindow.cpp +++ b/core/utilities/assistants/webservices/facebook/fbwindow.cpp @@ -1,666 +1,666 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2005-17-26 * Description : a tool to export items to Facebook web service * * Copyright (C) 2005-2008 by Vardhman Jain * Copyright (C) 2008-2019 by Gilles Caulier * Copyright (C) 2008-2009 by Luka Renko * Copyright (C) 2018 by Thanh Trung Dinh * * 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 "fbwindow.h" // Qt includes #include #include #include #include #include #include #include #include #include // KDE includes #include #include #include // Local includes #include "digikam_debug.h" #include "dmetadata.h" #include "ditemslist.h" #include "digikam_version.h" #include "dprogresswdg.h" #include "wstoolutils.h" #include "fbitem.h" #include "fbtalker.h" #include "fbwidget.h" #include "fbnewalbumdlg.h" #include "previewloadthread.h" namespace Digikam { class Q_DECL_HIDDEN FbWindow::Private { public: explicit Private(QWidget* const parent, DInfoInterface* const interface) { iface = interface; widget = new FbWidget(parent, iface, QLatin1String("Facebook")); imgList = widget->imagesList(); progressBar = widget->progressBar(); changeUserBtn = widget->getChangeUserBtn(); albumsCoB = widget->getAlbumsCoB(); newAlbumBtn = widget->getNewAlbmBtn(); reloadAlbumsBtn = widget->getReloadBtn(); resizeChB = widget->getResizeCheckBox(); dimensionSpB = widget->getDimensionSpB(); imageQualitySpB = widget->getImgQualitySpB(); imagesCount = 0; imagesTotal = 0; talker = 0; albumDlg = 0; } FbWidget* widget; DItemsList* imgList; QPushButton* changeUserBtn; QComboBox* albumsCoB; QPushButton* newAlbumBtn; QPushButton* reloadAlbumsBtn; QCheckBox* resizeChB; QSpinBox* dimensionSpB; QSpinBox* imageQualitySpB; DProgressWdg* progressBar; unsigned int imagesCount; unsigned int imagesTotal; QString tmpDir; QString tmpPath; QString profileAID; QString currentAlbumID; QList transferQueue; FbTalker* talker; FbNewAlbumDlg* albumDlg; DInfoInterface* iface; }; FbWindow::FbWindow(DInfoInterface* const iface, QWidget* const /*parent*/) : WSToolDialog(0), d(new Private(this, iface)) { d->tmpPath.clear(); d->tmpDir = WSToolUtils::makeTemporaryDir("facebook").absolutePath() + QLatin1Char('/'); setMainWidget(d->widget); setModal(false); setWindowTitle(i18n("Export to Facebook Web Service")); startButton()->setText(i18n("Start Upload")); startButton()->setToolTip(i18n("Start upload to Facebook web service")); d->widget->setMinimumSize(700, 500); d->changeUserBtn->setStyleSheet(QLatin1String("QPushButton {background-color: " "#3b5998; color: #ffffff;}")); - d->changeUserBtn->setIcon(QIcon::fromTheme(QLatin1String("facebook-white"))); + d->changeUserBtn->setIcon(QIcon::fromTheme(QLatin1String("dk-facebook-white"))); d->changeUserBtn->setText(i18n("Continue with Facebook")); // ------------------------------------------------------------------------ connect(d->imgList, SIGNAL(signalImageListChanged()), this, SLOT(slotImageListChanged())); connect(d->changeUserBtn, SIGNAL(clicked()), this, SLOT(slotUserChangeRequest())); connect(d->newAlbumBtn, SIGNAL(clicked()), this, SLOT(slotNewAlbumRequest())); connect(d->widget, SIGNAL(reloadAlbums(long long)), this, SLOT(slotReloadAlbumsRequest(long long))); connect(startButton(), SIGNAL(clicked()), this, SLOT(slotStartTransfer())); connect(this, SIGNAL(finished(int)), this, SLOT(slotFinished())); connect(this, SIGNAL(cancelClicked()), this, SLOT(slotCancelClicked())); d->albumDlg = new FbNewAlbumDlg(this, QLatin1String("Facebook")); // ------------------------------------------------------------------------ d->talker = new FbTalker(this); connect(d->talker, SIGNAL(signalBusy(bool)), this, SLOT(slotBusy(bool))); connect(d->talker, SIGNAL(signalLoginProgress(int,int,QString)), this, SLOT(slotLoginProgress(int,int,QString))); connect(d->talker, SIGNAL(signalLoginDone(int,QString)), this, SLOT(slotLoginDone(int,QString))); connect(d->talker, SIGNAL(signalAddPhotoDone(int,QString)), this, SLOT(slotAddPhotoDone(int,QString))); connect(d->talker, SIGNAL(signalCreateAlbumDone(int,QString,QString)), this, SLOT(slotCreateAlbumDone(int,QString,QString))); connect(d->talker, SIGNAL(signalListAlbumsDone(int,QString,QList)), this, SLOT(slotListAlbumsDone(int,QString,QList))); connect(d->progressBar, SIGNAL(signalProgressCanceled()), this, SLOT(slotStopAndCloseProgressBar())); // ------------------------------------------------------------------------ readSettings(); buttonStateChange(false); authenticate(false); } FbWindow::~FbWindow() { WSToolUtils::removeTemporaryDir("facebook"); delete d->albumDlg; delete d->talker; delete d; } void FbWindow::slotStopAndCloseProgressBar() { // Cancel the operation slotCancelClicked(); // Write settings and tidy up slotFinished(); // Close the dialog reject(); } void FbWindow::slotFinished() { writeSettings(); d->imgList->listView()->clear(); d->progressBar->progressCompleted(); } void FbWindow::slotCancelClicked() { setRejectButtonMode(QDialogButtonBox::Close); d->talker->cancel(); d->transferQueue.clear(); d->imgList->cancelProcess(); d->progressBar->hide(); d->progressBar->progressCompleted(); } void FbWindow::closeEvent(QCloseEvent* e) { if (!e) { return; } slotFinished(); e->accept(); } void FbWindow::readSettings() { KConfig config; KConfigGroup grp = config.group("Facebook Settings"); if (grp.readEntry("Resize", false)) { d->resizeChB->setChecked(true); d->dimensionSpB->setEnabled(true); } else { d->resizeChB->setChecked(false); d->dimensionSpB->setEnabled(false); } d->currentAlbumID = grp.readEntry("Current Album", QString()); d->dimensionSpB->setValue(grp.readEntry("Maximum Width", 1600)); d->imageQualitySpB->setValue(grp.readEntry("Image Quality", 85)); winId(); KConfigGroup dialogGroup = config.group("Facebook Export Dialog"); KWindowConfig::restoreWindowSize(windowHandle(), dialogGroup); resize(windowHandle()->size()); } void FbWindow::writeSettings() { KConfig config; KConfigGroup grp = config.group("Facebook Settings"); grp.writeEntry("Current Album", d->currentAlbumID); grp.writeEntry("Resize", d->resizeChB->isChecked()); grp.writeEntry("Maximum Width", d->dimensionSpB->value()); grp.writeEntry("Image Quality", d->imageQualitySpB->value()); KConfigGroup dialogGroup = config.group("Facebook Export Dialog"); KWindowConfig::saveWindowSize(windowHandle(), dialogGroup); config.sync(); } void FbWindow::authenticate(bool forceLogin) { d->progressBar->show(); d->progressBar->setFormat(QLatin1String("")); setRejectButtonMode(QDialogButtonBox::Cancel); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Calling Login method "; if (forceLogin) { d->talker->link(); } else { d->talker->readSettings(); } } void FbWindow::slotLoginProgress(int step, int maxStep, const QString& label) { DProgressWdg* const progressBar = d->progressBar; if (!label.isEmpty()) { progressBar->setFormat(label); } if (maxStep > 0) { progressBar->setMaximum(maxStep); } progressBar->setValue(step); } void FbWindow::slotLoginDone(int errCode, const QString& errMsg) { setRejectButtonMode(QDialogButtonBox::Close); d->progressBar->hide(); buttonStateChange(d->talker->linked()); if (d->talker->linked()) { d->changeUserBtn->setText(i18n("Log Out of Facebook")); } else { d->changeUserBtn->setText(i18n("Continue with Facebook")); } FbUser user = d->talker->getUser(); setProfileAID(user.id.toLongLong()); d->widget->updateLabels(user.name, user.profileURL); d->albumsCoB->clear(); if (errCode == 0 && d->talker->linked()) { d->albumsCoB->addItem(i18n(""), QString()); d->talker->listAlbums(); // get albums to fill combo box } else if (errCode > 0) { QMessageBox::critical(this, QString(), i18n("Facebook Call Failed: %1\n", errMsg)); } } void FbWindow::slotListAlbumsDone(int errCode, const QString& errMsg, const QList& albumsList) { QString albumDebug = QLatin1String(""); foreach (const FbAlbum& album, albumsList) { albumDebug.append(QString::fromLatin1("%1: %2\n").arg(album.id).arg(album.title)); } qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Received albums (errCode = " << errCode << ", errMsg = " << errMsg << "): " << albumDebug; if (errCode != 0) { QMessageBox::critical(this, QString(), i18n("Facebook Call Failed: %1\n", errMsg)); return; } d->albumsCoB->clear(); d->albumsCoB->addItem(i18n(""), QString()); for (int i = 0 ; i < albumsList.size() ; ++i) { QString albumIcon; switch (albumsList.at(i).privacy) { case FB_ME: albumIcon = QLatin1String("secure-card"); break; case FB_FRIENDS: albumIcon = QLatin1String("user-identity"); break; case FB_FRIENDS_OF_FRIENDS: albumIcon = QLatin1String("system-users"); break; case FB_EVERYONE: albumIcon = QLatin1String("folder-html"); break; case FB_CUSTOM: albumIcon = QLatin1String("configure"); break; } d->albumsCoB->addItem(QIcon::fromTheme(albumIcon), albumsList.at(i).title, albumsList.at(i).id); if (d->currentAlbumID == albumsList.at(i).id) { d->albumsCoB->setCurrentIndex(i + 1); } } } void FbWindow::buttonStateChange(bool state) { d->newAlbumBtn->setEnabled(state); d->reloadAlbumsBtn->setEnabled(state); startButton()->setEnabled(state); } void FbWindow::slotBusy(bool val) { if (val) { setCursor(Qt::WaitCursor); d->changeUserBtn->setEnabled(false); buttonStateChange(false); } else { setCursor(Qt::ArrowCursor); d->changeUserBtn->setEnabled(true); buttonStateChange(d->talker->linked()); } } void FbWindow::slotUserChangeRequest() { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Slot Change User Request"; if (d->talker->linked()) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Slot User Logout"; d->talker->logout(); } else { authenticate(true); } } void FbWindow::slotReloadAlbumsRequest(long long userID) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Reload Albums Request for UID:" << userID; if (userID == 0) { FbUser user = d->talker->getUser(); setProfileAID(user.id.toLongLong()); d->talker->listAlbums(); // re-get albums from current user } else { setProfileAID(userID); d->talker->listAlbums(userID); // re-get albums for friend } } void FbWindow::slotNewAlbumRequest() { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Slot New Album Request"; if (d->albumDlg->exec() == QDialog::Accepted) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Calling New Album method"; FbAlbum newAlbum; d->albumDlg->getAlbumProperties(newAlbum); d->talker->createAlbum(newAlbum); } } void FbWindow::slotStartTransfer() { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "slotStartTransfer invoked"; d->imgList->clearProcessedStatus(); d->transferQueue = d->imgList->imageUrls(); if (d->transferQueue.isEmpty()) { return; } d->currentAlbumID = d->albumsCoB->itemData(d->albumsCoB->currentIndex()).toString(); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "upload request got album id from widget: " << d->currentAlbumID; d->imagesTotal = d->transferQueue.count(); d->imagesCount = 0; setRejectButtonMode(QDialogButtonBox::Cancel); d->progressBar->setFormat(i18n("%v / %m")); d->progressBar->setMaximum(d->imagesTotal); d->progressBar->setValue(0); d->progressBar->show(); d->progressBar->progressScheduled(i18n("Facebook export"), true, true); - d->progressBar->progressThumbnailChanged(QIcon::fromTheme(QLatin1String("facebook")).pixmap(22, 22)); + d->progressBar->progressThumbnailChanged(QIcon::fromTheme(QLatin1String("dk-facebook")).pixmap(22, 22)); uploadNextPhoto(); } void FbWindow::setProfileAID(long long userID) { // store AID of Profile Photos album // http://wiki.developers.facebook.com/index.php/Profile_archive_album d->profileAID = QString::number((userID << 32) + (-3 & 0xFFFFFFFF)); } QString FbWindow::getImageCaption(const QString& fileName) { DItemInfo info(d->iface->itemInfo(QUrl::fromLocalFile(fileName))); // Facebook doesn't support image titles. Include it in descriptions if needed. QStringList descriptions = QStringList() << info.title() << info.comment(); descriptions.removeAll(QLatin1String("")); return descriptions.join(QLatin1String("\n\n")); } bool FbWindow::prepareImageForUpload(const QString& imgPath, QString& caption) { QImage image = PreviewLoadThread::loadHighQualitySynchronously(imgPath).copyQImage(); if (image.isNull()) { image.load(imgPath); } if (image.isNull()) { return false; } // get temporary file name d->tmpPath = d->tmpDir + QFileInfo(imgPath).baseName().trimmed() + QLatin1String(".jpg"); // rescale image if requested int maxDim = d->dimensionSpB->value(); if (d->resizeChB->isChecked() && (image.width() > maxDim || image.height() > maxDim)) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Resizing to " << maxDim; image = image.scaled(maxDim, maxDim, Qt::KeepAspectRatio, Qt::SmoothTransformation); } qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Saving to temp file: " << d->tmpPath; image.save(d->tmpPath, "JPEG", d->imageQualitySpB->value()); // copy meta data to temporary image DMetadata meta; if (meta.load(imgPath)) { caption = getImageCaption(imgPath); meta.setItemDimensions(image.size()); meta.setItemOrientation(MetaEngine::ORIENTATION_NORMAL); meta.setMetadataWritingMode((int)DMetadata::WRITE_TO_FILE_ONLY); meta.save(d->tmpPath, true); } else { caption.clear(); } return true; } void FbWindow::uploadNextPhoto() { if (d->transferQueue.isEmpty()) { setRejectButtonMode(QDialogButtonBox::Close); d->progressBar->hide(); d->progressBar->progressCompleted(); return; } d->imgList->processing(d->transferQueue.first()); QString imgPath = d->transferQueue.first().toLocalFile(); d->progressBar->setMaximum(d->imagesTotal); d->progressBar->setValue(d->imagesCount); QString caption; if (d->resizeChB->isChecked()) { if (!prepareImageForUpload(imgPath, caption)) { slotAddPhotoDone(666, i18n("Cannot open file")); return; } d->talker->addPhoto(d->tmpPath, d->currentAlbumID, caption); } else { caption = getImageCaption(imgPath); d->tmpPath.clear(); d->talker->addPhoto(imgPath, d->currentAlbumID, caption); } } void FbWindow::slotAddPhotoDone(int errCode, const QString& errMsg) { // Remove temporary file if it was used if (!d->tmpPath.isEmpty()) { QFile::remove(d->tmpPath); d->tmpPath.clear(); } d->imgList->processed(d->transferQueue.first(), (errCode == 0)); if (errCode == 0) { d->transferQueue.removeFirst(); d->imagesCount++; } else { if (QMessageBox::question(this, i18n("Uploading Failed"), i18n("Failed to upload photo into Facebook: %1\n" "Do you want to continue?", errMsg)) != QMessageBox::Yes) { setRejectButtonMode(QDialogButtonBox::Close); d->progressBar->hide(); d->progressBar->progressCompleted(); d->transferQueue.clear(); return; } } uploadNextPhoto(); } void FbWindow::slotCreateAlbumDone(int errCode, const QString& errMsg, const QString& newAlbumID) { if (errCode != 0) { QMessageBox::critical(this, QString(), i18n("Facebook Call Failed: %1", errMsg)); return; } // reload album list and automatically select new album d->currentAlbumID = newAlbumID; d->talker->listAlbums(); } void FbWindow::slotImageListChanged() { startButton()->setEnabled(!(d->imgList->imageUrls().isEmpty())); } } // namespace Digikam diff --git a/core/utilities/assistants/webservices/flickr/flickrwindow.cpp b/core/utilities/assistants/webservices/flickr/flickrwindow.cpp index d227faf629..f60ec1c64c 100644 --- a/core/utilities/assistants/webservices/flickr/flickrwindow.cpp +++ b/core/utilities/assistants/webservices/flickr/flickrwindow.cpp @@ -1,888 +1,888 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2005-17-06 * Description : a tool to export images to Flickr web service * * Copyright (C) 2005-2008 by Vardhman Jain * Copyright (C) 2008-2019 by Gilles Caulier * Copyright (C) 2009 by Luka Renko * * 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 "flickrwindow.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include #include // Local includes #include "dprogresswdg.h" #include "flickrtalker.h" #include "flickritem.h" #include "flickrlist.h" #include "wsselectuserdlg.h" #include "digikam_debug.h" #include "flickrnewalbumdlg.h" #include "previewloadthread.h" #include "flickrwidget_p.h" namespace Digikam { class Q_DECL_HIDDEN FlickrWindow::Private { public: explicit Private() { uploadCount = 0; uploadTotal = 0; newAlbumBtn = 0; changeUserButton = 0; removeAccount = 0; albumsListComboBox = 0; publicCheckBox = 0; familyCheckBox = 0; friendsCheckBox = 0; exportHostTagsCheckBox = 0; stripSpaceTagsCheckBox = 0; addExtraTagsCheckBox = 0; originalCheckBox = 0; resizeCheckBox = 0; dimensionSpinBox = 0; imageQualitySpinBox = 0; extendedPublicationButton = 0; extendedTagsButton = 0; contentTypeComboBox = 0; safetyLevelComboBox = 0; userNameDisplayLabel = 0; authProgressDlg = 0; tagsLineEdit = 0; widget = 0; talker = 0; imglst = 0; select = 0; albumDlg = 0; iface = 0; } unsigned int uploadCount; unsigned int uploadTotal; QString serviceName; QPushButton* newAlbumBtn; QPushButton* changeUserButton; QPushButton* removeAccount; QComboBox* albumsListComboBox; QCheckBox* publicCheckBox; QCheckBox* familyCheckBox; QCheckBox* friendsCheckBox; QCheckBox* exportHostTagsCheckBox; QCheckBox* stripSpaceTagsCheckBox; QCheckBox* addExtraTagsCheckBox; QCheckBox* originalCheckBox; QCheckBox* resizeCheckBox; QSpinBox* dimensionSpinBox; QSpinBox* imageQualitySpinBox; QPushButton* extendedPublicationButton; QPushButton* extendedTagsButton; WSComboBoxIntermediate* contentTypeComboBox; WSComboBoxIntermediate* safetyLevelComboBox; QString username; QString userId; QString lastSelectedAlbum; QLabel* userNameDisplayLabel; QProgressDialog* authProgressDlg; QList< QPair > uploadQueue; QLineEdit* tagsLineEdit; FlickrWidget* widget; FlickrTalker* talker; FlickrList* imglst; WSSelectUserDlg* select; FlickrNewAlbumDlg* albumDlg; DInfoInterface* iface; }; FlickrWindow::FlickrWindow(DInfoInterface* const iface, QWidget* const /*parent*/, const QString& serviceName) : WSToolDialog(0), d(new Private) { d->iface = iface; d->serviceName = serviceName; setWindowTitle(i18n("Export to %1 Web Service", d->serviceName)); setModal(false); KConfig config; KConfigGroup grp = config.group(QString::fromLatin1("%1Export Settings").arg(d->serviceName)); if (grp.exists()) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << QString::fromLatin1("%1Export Settings").arg(d->serviceName) << " exists, deleting it"; grp.deleteGroup(); } d->select = new WSSelectUserDlg(0, serviceName); d->uploadCount = 0; d->uploadTotal = 0; d->widget = new FlickrWidget(this, iface, serviceName); d->albumDlg = new FlickrNewAlbumDlg(this, QLatin1String("Flickr")); d->albumsListComboBox = d->widget->getAlbumsCoB(); d->newAlbumBtn = d->widget->getNewAlbmBtn(); d->originalCheckBox = d->widget->getOriginalCheckBox(); d->resizeCheckBox = d->widget->getResizeCheckBox(); d->publicCheckBox = d->widget->d->publicCheckBox; d->familyCheckBox = d->widget->d->familyCheckBox; d->friendsCheckBox = d->widget->d->friendsCheckBox; d->dimensionSpinBox = d->widget->getDimensionSpB(); d->imageQualitySpinBox = d->widget->getImgQualitySpB(); d->extendedTagsButton = d->widget->d->extendedTagsButton; d->addExtraTagsCheckBox = d->widget->d->addExtraTagsCheckBox; d->extendedPublicationButton = d->widget->d->extendedPublicationButton; d->safetyLevelComboBox = d->widget->d->safetyLevelComboBox; d->contentTypeComboBox = d->widget->d->contentTypeComboBox; d->tagsLineEdit = d->widget->d->tagsLineEdit; d->exportHostTagsCheckBox = d->widget->d->exportHostTagsCheckBox; d->stripSpaceTagsCheckBox = d->widget->d->stripSpaceTagsCheckBox; d->changeUserButton = d->widget->getChangeUserBtn(); d->removeAccount = d->widget->d->removeAccount; d->userNameDisplayLabel = d->widget->getUserNameLabel(); d->imglst = d->widget->d->imglst; startButton()->setText(i18n("Start Uploading")); startButton()->setToolTip(QString()); setMainWidget(d->widget); d->widget->setMinimumSize(800, 600); connect(d->imglst, SIGNAL(signalImageListChanged()), this, SLOT(slotImageListChanged())); // -------------------------------------------------------------------------- d->talker = new FlickrTalker(this, serviceName, d->iface); connect(d->talker, SIGNAL(signalError(QString)), d->talker, SLOT(slotError(QString))); connect(d->talker, SIGNAL(signalBusy(bool)), this, SLOT(slotBusy(bool))); connect(d->talker, SIGNAL(signalAddPhotoSucceeded(QString)), this, SLOT(slotAddPhotoSucceeded(QString))); connect(d->talker, SIGNAL(signalAddPhotoFailed(QString)), this, SLOT(slotAddPhotoFailed(QString))); connect(d->talker, SIGNAL(signalAddPhotoSetSucceeded()), this, SLOT(slotAddPhotoSetSucceeded())); connect(d->talker, SIGNAL(signalListPhotoSetsSucceeded()), this, SLOT(slotPopulatePhotoSetComboBox())); connect(d->talker, SIGNAL(signalListPhotoSetsFailed(QString)), this, SLOT(slotListPhotoSetsFailed(QString))); connect(d->talker, SIGNAL(signalLinkingSucceeded()), this, SLOT(slotLinkingSucceeded())); connect(d->widget->progressBar(), SIGNAL(signalProgressCanceled()), this, SLOT(slotAddPhotoCancelAndClose())); connect(d->widget->getReloadBtn(), SIGNAL(clicked()), this, SLOT(slotReloadPhotoSetRequest())); // -------------------------------------------------------------------------- connect(d->changeUserButton, SIGNAL(clicked()), this, SLOT(slotUserChangeRequest())); connect(d->removeAccount, SIGNAL(clicked()), this, SLOT(slotRemoveAccount())); connect(d->newAlbumBtn, SIGNAL(clicked()), this, SLOT(slotCreateNewPhotoSet())); // -------------------------------------------------------------------------- d->authProgressDlg = new QProgressDialog(this); d->authProgressDlg->setModal(true); d->authProgressDlg->setAutoReset(true); d->authProgressDlg->setAutoClose(true); d->authProgressDlg->setMaximum(0); d->authProgressDlg->reset(); connect(d->authProgressDlg, SIGNAL(canceled()), this, SLOT(slotAuthCancel())); d->talker->m_authProgressDlg = d->authProgressDlg; // -------------------------------------------------------------------------- connect(this, &QDialog::finished, this, &FlickrWindow::slotFinished); connect(this, SIGNAL(cancelClicked()), this, SLOT(slotCancelClicked())); connect(startButton(), &QPushButton::clicked, this, &FlickrWindow::slotUser1); d->select->reactivate(); readSettings(d->select->getUserName()); d->talker->link(d->select->getUserName()); } FlickrWindow::~FlickrWindow() { delete d->select; delete d->authProgressDlg; delete d->talker; delete d->widget; delete d; } void FlickrWindow::setItemsList(const QList& urls) { d->widget->imagesList()->slotAddImages(urls); } void FlickrWindow::closeEvent(QCloseEvent* e) { if (!e) { return; } slotFinished(); e->accept(); } void FlickrWindow::slotFinished() { writeSettings(); d->imglst->listView()->clear(); } void FlickrWindow::setUiInProgressState(bool inProgress) { setRejectButtonMode(inProgress ? QDialogButtonBox::Cancel : QDialogButtonBox::Close); if (inProgress) { d->widget->progressBar()->show(); } else { d->widget->progressBar()->hide(); d->widget->progressBar()->progressCompleted(); } } void FlickrWindow::slotCancelClicked() { d->talker->cancel(); d->uploadQueue.clear(); setUiInProgressState(false); } void FlickrWindow::slotAddPhotoCancelAndClose() { writeSettings(); d->imglst->listView()->clear(); d->uploadQueue.clear(); d->widget->progressBar()->reset(); setUiInProgressState(false); d->talker->cancel(); reject(); } void FlickrWindow::reactivate() { d->userNameDisplayLabel->setText(QString()); readSettings(d->select->getUserName()); d->talker->link(d->select->getUserName()); d->widget->d->imglst->loadImagesFromCurrentSelection(); show(); } void FlickrWindow::readSettings(QString uname) { KConfig config; QString groupName = QString::fromLatin1("%1%2Export Settings").arg(d->serviceName, uname); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Group name is:" << groupName; KConfigGroup grp = config.group(groupName); d->exportHostTagsCheckBox->setChecked(grp.readEntry("Export Host Tags", false)); d->extendedTagsButton->setChecked(grp.readEntry("Show Extended Tag Options", false)); d->addExtraTagsCheckBox->setChecked(grp.readEntry("Add Extra Tags", false)); d->stripSpaceTagsCheckBox->setChecked(grp.readEntry("Strip Space From Tags", false)); d->publicCheckBox->setChecked(grp.readEntry("Public Sharing", false)); d->familyCheckBox->setChecked(grp.readEntry("Family Sharing", false)); d->friendsCheckBox->setChecked(grp.readEntry("Friends Sharing", false)); d->extendedPublicationButton->setChecked(grp.readEntry("Show Extended Publication Options", false)); int safetyLevel = d->safetyLevelComboBox->findData(QVariant(grp.readEntry("Safety Level", 0))); if (safetyLevel == -1) { safetyLevel = 0; } d->safetyLevelComboBox->setCurrentIndex(safetyLevel); int contentType = d->contentTypeComboBox->findData(QVariant(grp.readEntry("Content Type", 0))); if (contentType == -1) { contentType = 0; } d->contentTypeComboBox->setCurrentIndex(contentType); d->originalCheckBox->setChecked(grp.readEntry("Upload Original", false)); d->resizeCheckBox->setChecked(grp.readEntry("Resize", false)); d->dimensionSpinBox->setValue(grp.readEntry("Maximum Width", 1600)); d->imageQualitySpinBox->setValue(grp.readEntry("Image Quality", 85)); winId(); KConfigGroup dialogGroup = config.group(QString::fromLatin1("%1Export Dialog").arg(d->serviceName)); KWindowConfig::restoreWindowSize(windowHandle(), dialogGroup); resize(windowHandle()->size()); } void FlickrWindow::writeSettings() { KConfig config; QString groupName = QString::fromLatin1("%1%2Export Settings").arg(d->serviceName, d->username); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Group name is:" << groupName; if (QString::compare(QString::fromLatin1("%1Export Settings").arg(d->serviceName), groupName) == 0) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Not writing entry of group" << groupName; return; } KConfigGroup grp = config.group(groupName); grp.writeEntry("username", d->username); grp.writeEntry("Export Host Tags", d->exportHostTagsCheckBox->isChecked()); grp.writeEntry("Show Extended Tag Options", d->extendedTagsButton->isChecked()); grp.writeEntry("Add Extra Tags", d->addExtraTagsCheckBox->isChecked()); grp.writeEntry("Strip Space From Tags", d->stripSpaceTagsCheckBox->isChecked()); grp.writeEntry("Public Sharing", d->publicCheckBox->isChecked()); grp.writeEntry("Family Sharing", d->familyCheckBox->isChecked()); grp.writeEntry("Friends Sharing", d->friendsCheckBox->isChecked()); grp.writeEntry("Show Extended Publication Options", d->extendedPublicationButton->isChecked()); int safetyLevel = d->safetyLevelComboBox->itemData(d->safetyLevelComboBox->currentIndex()).toInt(); grp.writeEntry("Safety Level", safetyLevel); int contentType = d->contentTypeComboBox->itemData(d->contentTypeComboBox->currentIndex()).toInt(); grp.writeEntry("Content Type", contentType); grp.writeEntry("Resize", d->resizeCheckBox->isChecked()); grp.writeEntry("Upload Original", d->originalCheckBox->isChecked()); grp.writeEntry("Maximum Width", d->dimensionSpinBox->value()); grp.writeEntry("Image Quality", d->imageQualitySpinBox->value()); KConfigGroup dialogGroup = config.group(QString::fromLatin1("%1Export Dialog").arg(d->serviceName)); KWindowConfig::saveWindowSize(windowHandle(), dialogGroup); config.sync(); } void FlickrWindow::slotLinkingSucceeded() { d->username = d->talker->getUserName(); d->userId = d->talker->getUserId(); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "SlotLinkingSucceeded invoked setting user Display name to" << d->username; d->userNameDisplayLabel->setText(QString::fromLatin1("%1").arg(d->username)); KConfig config; foreach(const QString& group, config.groupList()) { if (!(group.contains(d->serviceName))) continue; KConfigGroup grp = config.group(group); if (group.contains(d->username)) { readSettings(d->username); break; } } writeSettings(); d->talker->listPhotoSets(); } void FlickrWindow::slotBusy(bool val) { if (val) { setCursor(Qt::WaitCursor); } else { setCursor(Qt::ArrowCursor); } } void FlickrWindow::slotError(const QString& msg) { QMessageBox::critical(this, i18n("Error"), msg); } void FlickrWindow::slotUserChangeRequest() { writeSettings(); d->userNameDisplayLabel->setText(QString()); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Slot Change User Request"; d->select->reactivate(); readSettings(d->select->getUserName()); d->talker->link(d->select->getUserName()); } void FlickrWindow::slotRemoveAccount() { KConfig config; QString groupName = QString::fromLatin1("%1%2Export Settings").arg(d->serviceName, d->username); KConfigGroup grp = config.group(groupName); if (grp.exists()) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Removing Account having group" << groupName; grp.deleteGroup(); } d->talker->unLink(); d->talker->removeUserName(d->serviceName + d->username); d->userNameDisplayLabel->setText(QString()); d->username = QString(); } /** * Try to guess a sensible set name from the urls given. * Currently, it extracs the last path name component, and returns the most * frequently seen. The function could be expanded to, for example, only * accept the path if it occurs at least 50% of the time. It could also look * further up in the path name. */ QString FlickrWindow::guessSensibleSetName(const QList& urlList) const { QMap nrFolderOccurences; // Extract last component of directory foreach(const QUrl& url, urlList) { QString dir = url.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).toLocalFile(); QStringList list = dir.split(QLatin1Char('/')); if (list.isEmpty()) continue; nrFolderOccurences[list.last()]++; } int maxCount = 0; int totalCount = 0; QString name; for (QMap::const_iterator it = nrFolderOccurences.constBegin(); it != nrFolderOccurences.constEnd() ; ++it) { totalCount += it.value(); if (it.value() > maxCount) { maxCount = it.value(); name = it.key(); } } // If there is only one entry or one name appears at least twice, return the suggestion if (totalCount == 1 || maxCount > 1) return name; return QString(); } /** This method is called when the photo set creation button is pressed. It * summons a creation dialog for user input. When that is closed, it * creates a new photo set in the local list. The id gets the form of * UNDEFINED_ followed by a number, to indicate that it doesn't exist on * Flickr yet. */ void FlickrWindow::slotCreateNewPhotoSet() { if (d->albumDlg->exec() == QDialog::Accepted) { FPhotoSet fps; d->albumDlg->getFolderProperties(fps); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "in slotCreateNewPhotoSet()" << fps.title; // Lets find an UNDEFINED_ style id that isn't taken yet.s QString id; int i = 0; id = QLatin1String("UNDEFINED_") + QString::number(i); QLinkedList::iterator it = d->talker->m_photoSetsList->begin(); while (it != d->talker->m_photoSetsList->end()) { FPhotoSet fps = *it; if (fps.id == id) { id = QLatin1String("UNDEFINED_") + QString::number(++i); it = d->talker->m_photoSetsList->begin(); } ++it; } fps.id = id; qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Created new photoset with temporary id" << id; // Append the new photoset to the list. d->talker->m_photoSetsList->prepend(fps); d->talker->m_selectedPhotoSet = fps; // Re-populate the photo sets combo box. slotPopulatePhotoSetComboBox(); } else { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "New Photoset creation aborted"; } } void FlickrWindow::slotAuthCancel() { d->talker->cancel(); d->authProgressDlg->hide(); } void FlickrWindow::slotPopulatePhotoSetComboBox() { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "slotPopulatePhotoSetComboBox invoked"; if (d->talker && d->talker->m_photoSetsList) { QLinkedList * const list = d->talker->m_photoSetsList; d->albumsListComboBox->clear(); d->albumsListComboBox->insertItem(0, i18n("Photostream Only")); d->albumsListComboBox->insertSeparator(1); QLinkedList::iterator it = list->begin(); int index = 2; int curr_index = 0; while (it != list->end()) { FPhotoSet photoSet = *it; QString name = photoSet.title; // Store the id as user data, because the title is not unique. QVariant id = QVariant(photoSet.id); if (id == d->talker->m_selectedPhotoSet.id) { curr_index = index; } d->albumsListComboBox->insertItem(index++, name, id); ++it; } d->albumsListComboBox->setCurrentIndex(curr_index); } } /** This slot is call when 'Start Uploading' button is pressed. */ void FlickrWindow::slotUser1() { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "SlotUploadImages invoked"; //d->widget->d->tab->setCurrentIndex(FlickrWidget::FILELIST); if (d->imglst->imageUrls().isEmpty()) { return; } typedef QPair Pair; d->uploadQueue.clear(); for (int i = 0 ; i < d->imglst->listView()->topLevelItemCount() ; ++i) { FlickrListViewItem* const lvItem = dynamic_cast(d->imglst->listView()->topLevelItem(i)); if (lvItem) { DItemInfo info(d->iface->itemInfo(lvItem->url())); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Adding images" << lvItem->url() << " to the list"; FPhotoInfo temp; temp.title = info.title(); temp.description = info.comment(); temp.size = info.fileSize(); temp.is_public = lvItem->isPublic() ? 1 : 0; temp.is_family = lvItem->isFamily() ? 1 : 0; temp.is_friend = lvItem->isFriends() ? 1 : 0; temp.safety_level = lvItem->safetyLevel(); temp.content_type = lvItem->contentType(); QStringList tagsFromDialog = d->tagsLineEdit->text().split(QLatin1Char(','), QString::SkipEmptyParts); QStringList tagsFromList = lvItem->extraTags(); QStringList allTags; QStringList::Iterator itTags; // Tags from the dialog itTags = tagsFromDialog.begin(); while (itTags != tagsFromDialog.end()) { allTags.append(*itTags); ++itTags; } // Tags from the database if (d->exportHostTagsCheckBox->isChecked()) { QStringList tagsFromDatabase; tagsFromDatabase = info.keywords(); itTags = tagsFromDatabase.begin(); while (itTags != tagsFromDatabase.end()) { allTags.append(*itTags); ++itTags; } } // Tags from the list view. itTags = tagsFromList.begin(); while (itTags != tagsFromList.end()) { allTags.append(*itTags); ++itTags; } // Remove spaces if the user doesn't like them. if (d->stripSpaceTagsCheckBox->isChecked()) { for (QStringList::iterator it = allTags.begin(); it != allTags.end(); ++it) { *it = (*it).trimmed().remove(QLatin1Char(' ')); } } // Debug the tag list. itTags = allTags.begin(); while (itTags != allTags.end()) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Tags list:" << (*itTags); ++itTags; } temp.tags = allTags; d->uploadQueue.append(Pair(lvItem->url(), temp)); } } d->uploadTotal = d->uploadQueue.count(); d->uploadCount = 0; d->widget->progressBar()->reset(); slotAddPhotoNext(); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "SlotUploadImages done"; } void FlickrWindow::slotAddPhotoNext() { if (d->uploadQueue.isEmpty()) { d->widget->progressBar()->reset(); setUiInProgressState(false); return; } typedef QPair Pair; Pair pathComments = d->uploadQueue.first(); FPhotoInfo info = pathComments.second; QString selectedPhotoSetId = d->albumsListComboBox->itemData(d->albumsListComboBox->currentIndex()).toString(); if (selectedPhotoSetId.isEmpty()) { d->talker->m_selectedPhotoSet = FPhotoSet(); } else { QLinkedList::iterator it = d->talker->m_photoSetsList->begin(); while (it != d->talker->m_photoSetsList->end()) { if (it->id == selectedPhotoSetId) { d->talker->m_selectedPhotoSet = *it; break; } ++it; } } qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Max allowed file size is:" << d->talker->getMaxAllowedFileSize().toLongLong() << "File Size is" << info.size; bool res = d->talker->addPhoto(pathComments.first.toLocalFile(), //the file path info, d->originalCheckBox->isChecked(), d->resizeCheckBox->isChecked(), d->dimensionSpinBox->value(), d->imageQualitySpinBox->value()); if (!res) { slotAddPhotoFailed(QLatin1String("")); return; } if (d->widget->progressBar()->isHidden()) { setUiInProgressState(true); d->widget->progressBar()->progressScheduled(i18n("Flickr Export"), true, true); - d->widget->progressBar()->progressThumbnailChanged(QIcon(QLatin1String("flickr")).pixmap(22, 22)); + d->widget->progressBar()->progressThumbnailChanged(QIcon(QLatin1String("dk-flickr")).pixmap(22, 22)); } } void FlickrWindow::slotAddPhotoSucceeded(const QString& photoId) { QUrl photoUrl = d->uploadQueue.first().first; // Set location for uploaded photo DItemInfo info(d->iface->itemInfo(photoUrl)); if (info.hasGeolocationInfo() && !photoId.isEmpty()) { d->talker->setGeoLocation(photoId, QString::number(info.latitude()), QString::number(info.longitude())); return; } // Remove photo uploaded from the list d->imglst->removeItemByUrl(photoUrl); d->uploadQueue.removeFirst(); d->uploadCount++; d->widget->progressBar()->setMaximum(d->uploadTotal); d->widget->progressBar()->setValue(d->uploadCount); slotAddPhotoNext(); } void FlickrWindow::slotListPhotoSetsFailed(const QString& msg) { QMessageBox::critical(this, QLatin1String("Error"), i18n("Failed to Fetch Photoset information from %1. %2\n", d->serviceName, msg)); } void FlickrWindow::slotAddPhotoFailed(const QString& msg) { QPointer warn = new QMessageBox(QMessageBox::Warning, i18n("Warning"), i18n("Failed to upload photo into %1. %2\nDo you want to continue?", d->serviceName, msg), QMessageBox::Yes | QMessageBox::No); (warn->button(QMessageBox::Yes))->setText(i18n("Continue")); (warn->button(QMessageBox::No))->setText(i18n("Cancel")); if (warn->exec() != QMessageBox::Yes) { d->uploadQueue.clear(); d->widget->progressBar()->reset(); setUiInProgressState(false); } else { d->uploadQueue.removeFirst(); d->uploadTotal--; d->widget->progressBar()->setMaximum(d->uploadTotal); d->widget->progressBar()->setValue(d->uploadCount); slotAddPhotoNext(); } delete warn; } /* Method called when a photo set has been successfully created on Flickr. * It functions to restart the normal flow after a photo set has been created * on Flickr. */ void FlickrWindow::slotAddPhotoSetSucceeded() { slotPopulatePhotoSetComboBox(); slotAddPhotoSucceeded(QLatin1String("")); } void FlickrWindow::slotImageListChanged() { startButton()->setEnabled(!(d->widget->d->imglst->imageUrls().isEmpty())); } void FlickrWindow::slotReloadPhotoSetRequest() { d->talker->listPhotoSets(); } } // namespace Digikam diff --git a/core/utilities/assistants/webservices/google/gswindow.cpp b/core/utilities/assistants/webservices/google/gswindow.cpp index 13c249bd45..de1c075e6f 100644 --- a/core/utilities/assistants/webservices/google/gswindow.cpp +++ b/core/utilities/assistants/webservices/google/gswindow.cpp @@ -1,1389 +1,1389 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2013-11-18 * Description : a tool to export items to Google web services * * Copyright (C) 2013 by Pankaj Kumar * Copyright (C) 2015 by Shourya Singh Gupta * Copyright (C) 2013-2018 by Caulier Gilles * * 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 "gswindow.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include #include #include // Local includes #include "wstoolutils.h" #include "ditemslist.h" #include "digikam_version.h" #include "dprogresswdg.h" #include "gdtalker.h" #include "gsitem.h" #include "gsnewalbumdlg.h" #include "gswidget.h" #include "gptalker.h" #include "gsreplacedlg.h" #include "digikam_debug.h" namespace Digikam { class Q_DECL_HIDDEN GSWindow::Private { public: explicit Private() { widget = 0; albumDlg = 0; gphotoAlbumDlg = 0; talker = 0; gphotoTalker = 0; iface = 0; imagesCount = 0; imagesTotal = 0; renamingOpt = 0; service = GoogleService::GPhotoImport; } unsigned int imagesCount; unsigned int imagesTotal; int renamingOpt; QString serviceName; QString toolName; GoogleService service; QString tmp; GSWidget* widget; GSNewAlbumDlg* albumDlg; GSNewAlbumDlg* gphotoAlbumDlg; GDTalker* talker; GPTalker* gphotoTalker; QString currentAlbumId; QList< QPair > transferQueue; QList< QPair > uploadQueue; DInfoInterface* iface; DMetadata meta; }; GSWindow::GSWindow(DInfoInterface* const iface, QWidget* const /*parent*/, const QString& serviceName) : WSToolDialog(0), d(new Private) { d->iface = iface; d->serviceName = serviceName; if (QString::compare(d->serviceName, QLatin1String("googledriveexport"), Qt::CaseInsensitive) == 0) { d->service = GoogleService::GDrive; d->toolName = QLatin1String("Google Drive"); } else if (QString::compare(d->serviceName, QLatin1String("googlephotoexport"), Qt::CaseInsensitive) == 0) { d->service = GoogleService::GPhotoExport; d->toolName = QLatin1String("Google Photos/PicasaWeb"); } else { d->service = GoogleService::GPhotoImport; d->toolName = QLatin1String("Google Photos/PicasaWeb"); } d->tmp = WSToolUtils::makeTemporaryDir("google").absolutePath() + QLatin1Char('/');; d->widget = new GSWidget(this, d->iface, d->service, d->toolName); setMainWidget(d->widget); setModal(false); switch (d->service) { case GoogleService::GDrive: setWindowTitle(i18n("Export to Google Drive")); startButton()->setText(i18n("Start Upload")); startButton()->setToolTip(i18n("Start upload to Google Drive")); d->widget->setMinimumSize(700,500); d->albumDlg = new GSNewAlbumDlg(this, d->serviceName, d->toolName); d->talker = new GDTalker(this); connect(d->talker,SIGNAL(signalBusy(bool)), this,SLOT(slotBusy(bool))); connect(d->talker,SIGNAL(signalAccessTokenObtained()), this,SLOT(slotAccessTokenObtained())); connect(d->talker, SIGNAL(signalAuthenticationRefused()), this,SLOT(slotAuthenticationRefused())); connect(d->talker,SIGNAL(signalSetUserName(QString)), this,SLOT(slotSetUserName(QString))); connect(d->talker,SIGNAL(signalListAlbumsDone(int,QString,QList)), this,SLOT(slotListAlbumsDone(int,QString,QList))); connect(d->talker,SIGNAL(signalCreateFolderDone(int,QString)), this,SLOT(slotCreateFolderDone(int,QString))); connect(d->talker,SIGNAL(signalAddPhotoDone(int,QString)), this,SLOT(slotAddPhotoDone(int,QString))); connect(d->talker, SIGNAL(signalUploadPhotoDone(int,QString,QStringList)), this, SLOT(slotUploadPhotoDone(int,QString,QStringList))); readSettings(); buttonStateChange(false); d->talker->doOAuth(); break; case GoogleService::GPhotoImport: case GoogleService::GPhotoExport: if (d->service == GoogleService::GPhotoExport) { setWindowTitle(i18n("Export to Google Photos/PicasaWeb Service")); startButton()->setText(i18n("Start Upload")); startButton()->setToolTip(i18n("Start upload to Google Photos/PicasaWeb Service")); d->widget->setMinimumSize(700, 500); } else { setWindowTitle(i18n("Import from Google Photos/PicasaWeb Service")); startButton()->setText(i18n("Start Download")); startButton()->setToolTip(i18n("Start download from Google Photos/PicasaWeb service")); d->widget->setMinimumSize(300, 400); } d->gphotoAlbumDlg = new GSNewAlbumDlg(this, d->serviceName, d->toolName); d->gphotoTalker = new GPTalker(this); connect(d->gphotoTalker, SIGNAL(signalBusy(bool)), this, SLOT(slotBusy(bool))); connect(d->gphotoTalker,SIGNAL(signalSetUserName(QString)), this,SLOT(slotSetUserName(QString))); connect(d->gphotoTalker, SIGNAL(signalAccessTokenObtained()), this, SLOT(slotAccessTokenObtained())); connect(d->gphotoTalker, SIGNAL(signalAuthenticationRefused()), this,SLOT(slotAuthenticationRefused())); connect(d->gphotoTalker, SIGNAL(signalListAlbumsDone(int,QString,QList)), this, SLOT(slotListAlbumsDone(int,QString,QList))); connect(d->gphotoTalker, SIGNAL(signalCreateAlbumDone(int,QString,QString)), this, SLOT(slotCreateFolderDone(int,QString,QString))); connect(d->gphotoTalker, SIGNAL(signalAddPhotoDone(int,QString)), this, SLOT(slotAddPhotoDone(int,QString))); connect(d->gphotoTalker, SIGNAL(signalUploadPhotoDone(int,QString,QStringList)), this, SLOT(slotUploadPhotoDone(int,QString,QStringList))); connect(d->gphotoTalker, SIGNAL(signalGetPhotoDone(int,QString,QByteArray)), this, SLOT(slotGetPhotoDone(int,QString,QByteArray))); readSettings(); buttonStateChange(false); d->gphotoTalker->doOAuth(); break; } connect(d->widget->imagesList(), SIGNAL(signalImageListChanged()), this, SLOT(slotImageListChanged())); connect(d->widget->getChangeUserBtn(), SIGNAL(clicked()), this, SLOT(slotUserChangeRequest())); connect(d->widget->getNewAlbmBtn(), SIGNAL(clicked()), this,SLOT(slotNewAlbumRequest())); connect(d->widget->getReloadBtn(), SIGNAL(clicked()), this, SLOT(slotReloadAlbumsRequest())); connect(startButton(), SIGNAL(clicked()), this, SLOT(slotStartTransfer())); connect(this, SIGNAL(finished(int)), this, SLOT(slotFinished())); } GSWindow::~GSWindow() { delete d->widget; delete d->albumDlg; delete d->gphotoAlbumDlg; delete d->talker; delete d->gphotoTalker; delete d; } void GSWindow::reactivate() { d->widget->imagesList()->loadImagesFromCurrentSelection(); d->widget->progressBar()->hide(); show(); } void GSWindow::readSettings() { KConfig config; KConfigGroup grp; switch (d->service) { case GoogleService::GDrive: grp = config.group("Google Drive Settings"); break; default: grp = config.group("Google Photo Settings"); break; } d->currentAlbumId = grp.readEntry("Current Album",QString()); if (grp.readEntry("Resize", false)) { d->widget->getResizeCheckBox()->setChecked(true); d->widget->getDimensionSpB()->setEnabled(true); } else { d->widget->getResizeCheckBox()->setChecked(false); d->widget->getDimensionSpB()->setEnabled(false); } d->widget->getDimensionSpB()->setValue(grp.readEntry("Maximum Width", 1600)); d->widget->getImgQualitySpB()->setValue(grp.readEntry("Image Quality", 90)); if (d->service == GoogleService::GPhotoExport && d->widget->m_tagsBGrp) { d->widget->m_tagsBGrp->button(grp.readEntry("Tag Paths", 0))->setChecked(true); } KConfigGroup dialogGroup; switch (d->service) { case GoogleService::GDrive: dialogGroup = config.group("Google Drive Export Dialog"); break; case GoogleService::GPhotoExport: dialogGroup = config.group("Google Photo Export Dialog"); break; case GoogleService::GPhotoImport: dialogGroup = config.group("Google Photo Import Dialog"); break; } winId(); KWindowConfig::restoreWindowSize(windowHandle(), dialogGroup); resize(windowHandle()->size()); } void GSWindow::writeSettings() { KConfig config; KConfigGroup grp; switch (d->service) { case GoogleService::GDrive: grp = config.group("Google Drive Settings"); break; default: grp = config.group("Google Photo Settings"); break; } grp.writeEntry("Current Album", d->currentAlbumId); grp.writeEntry("Resize", d->widget->getResizeCheckBox()->isChecked()); grp.writeEntry("Maximum Width", d->widget->getDimensionSpB()->value()); grp.writeEntry("Image Quality", d->widget->getImgQualitySpB()->value()); if (d->service == GoogleService::GPhotoExport && d->widget->m_tagsBGrp) { grp.writeEntry("Tag Paths", d->widget->m_tagsBGrp->checkedId()); } KConfigGroup dialogGroup; switch (d->service) { case GoogleService::GDrive: dialogGroup = config.group("Google Drive Export Dialog"); break; case GoogleService::GPhotoExport: dialogGroup = config.group("Google Photo Export Dialog"); break; case GoogleService::GPhotoImport: dialogGroup = config.group("Google Photo Import Dialog"); break; } KWindowConfig::saveWindowSize(windowHandle(), dialogGroup); config.sync(); } void GSWindow::slotSetUserName(const QString& msg) { d->widget->updateLabels(msg); } void GSWindow::slotListPhotosDoneForDownload(int errCode, const QString& errMsg, const QList & photosList) { disconnect(d->gphotoTalker, SIGNAL(signalListPhotosDone(int,QString,QList)), this, SLOT(slotListPhotosDoneForDownload(int,QString,QList))); if (errCode == 0) { QMessageBox::critical(this, i18nc("@title:window", "Error"), i18n("Google Photos/PicasaWeb Call Failed: %1\n", errMsg)); return; } typedef QPair Pair; d->transferQueue.clear(); QList::const_iterator itPWP; for (itPWP = photosList.begin() ; itPWP != photosList.end() ; ++itPWP) { d->transferQueue.append(Pair((*itPWP).originalURL, (*itPWP))); } if (d->transferQueue.isEmpty()) return; d->currentAlbumId = d->widget->getAlbumsCoB()->itemData(d->widget->getAlbumsCoB()->currentIndex()).toString(); d->imagesTotal = d->transferQueue.count(); d->imagesCount = 0; d->widget->progressBar()->setFormat(i18n("%v / %m")); d->widget->progressBar()->show(); d->renamingOpt = 0; // start download with first photo in queue downloadNextPhoto(); } void GSWindow::slotListPhotosDoneForUpload(int errCode, const QString& errMsg, const QList & photosList) { qCCritical(DIGIKAM_WEBSERVICES_LOG)<< "err Code is "<< errCode <<" Err Message is "<< errMsg; disconnect(d->gphotoTalker, SIGNAL(signalListPhotosDone(int,QString,QList)), this, SLOT(slotListPhotosDoneForUpload(int,QString,QList))); if (errCode == 0) { QMessageBox::critical(this, i18nc("@title:window", "Error"), i18n("Google Photos/PicasaWeb Call Failed: %1\n", errMsg)); return; } typedef QPair Pair; d->transferQueue.clear(); QList urlList = d->widget->imagesList()->imageUrls(true); if (urlList.isEmpty()) return; for (QList::ConstIterator it = urlList.constBegin() ; it != urlList.constEnd() ; ++it) { DItemInfo info(d->iface->itemInfo((*it))); GSPhoto temp; temp.title = info.name(); // Google Photo doesn't support image titles. Include it in descriptions if needed. QStringList descriptions = QStringList() << info.title() << info.comment(); descriptions.removeAll(QLatin1String("")); temp.description = descriptions.join(QLatin1String("\n\n")); // check for existing items QString localId; if (d->meta.load((*it).toLocalFile())) { localId = d->meta.getXmpTagString("Xmp.digiKam.picasawebGPhotoId"); } QList::const_iterator itPWP; for (itPWP = photosList.begin(); itPWP != photosList.end(); ++itPWP) { if ((*itPWP).id == localId) { temp.id = localId; temp.editUrl = (*itPWP).editUrl; temp.thumbURL = (*itPWP).thumbURL; break; } } // Tags from the database temp.gpsLat.setNum(info.latitude()); temp.gpsLon.setNum(info.longitude()); temp.tags = info.tagsPath(); d->transferQueue.append(Pair((*it), temp)); } if (d->transferQueue.isEmpty()) return; d->currentAlbumId = d->widget->getAlbumsCoB()->itemData(d->widget->getAlbumsCoB()->currentIndex()).toString(); d->imagesTotal = d->transferQueue.count(); d->imagesCount = 0; d->widget->progressBar()->setFormat(i18n("%v / %m")); d->widget->progressBar()->setMaximum(d->imagesTotal); d->widget->progressBar()->setValue(0); d->widget->progressBar()->show(); d->widget->progressBar()->progressScheduled(i18n("Google Photo Export"), true, true); - d->widget->progressBar()->progressThumbnailChanged(QIcon((QLatin1String("googlephoto"))).pixmap(22, 22)); + d->widget->progressBar()->progressThumbnailChanged(QIcon((QLatin1String("dk-googlephoto"))).pixmap(22, 22)); d->renamingOpt = 0; uploadNextPhoto(); } void GSWindow::slotListAlbumsDone(int code, const QString& errMsg, const QList & list) { switch (d->service) { case GoogleService::GDrive: if (code == 0) { QMessageBox::critical(this, i18nc("@title:window", "Error"), i18n("Google Drive Call Failed: %1\n", errMsg)); return; } d->widget->getAlbumsCoB()->clear(); for (int i = 0 ; i < list.size() ; ++i) { d->widget->getAlbumsCoB()->addItem(QIcon::fromTheme(QLatin1String("system-users")), list.value(i).title, list.value(i).id); if (d->currentAlbumId == list.value(i).id) { d->widget->getAlbumsCoB()->setCurrentIndex(i); } } buttonStateChange(true); d->talker->getUserName(); break; default: if (code == 0) { QMessageBox::critical(this, i18nc("@title:window", "Error"), i18n("Google Photos/PicasaWeb Call Failed: %1\n", errMsg)); return; } d->widget->getAlbumsCoB()->clear(); for (int i = 0 ; i < list.size() ; ++i) { QString albumIcon; if (list.at(i).isWriteable) { albumIcon = QLatin1String("folder"); } else { albumIcon = QLatin1String("folder-locked"); } d->widget->getAlbumsCoB()->addItem(QIcon::fromTheme(albumIcon), list.at(i).title, list.at(i).id); if (d->currentAlbumId == list.at(i).id) d->widget->getAlbumsCoB()->setCurrentIndex(i); buttonStateChange(true); } break; } } void GSWindow::slotBusy(bool val) { if (val) { setCursor(Qt::WaitCursor); d->widget->getChangeUserBtn()->setEnabled(false); buttonStateChange(false); } else { setCursor(Qt::ArrowCursor); d->widget->getChangeUserBtn()->setEnabled(true); buttonStateChange(true); } } void GSWindow::googlePhotoTransferHandler() { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Google Photo Transfer invoked"; switch (d->service) { case GoogleService::GPhotoImport: // list photos of the album, then start download connect(d->gphotoTalker, SIGNAL(signalListPhotosDone(int,QString,QList)), this, SLOT(slotListPhotosDoneForDownload(int,QString,QList))); d->gphotoTalker->listPhotos( d->widget->getAlbumsCoB()->itemData(d->widget->getAlbumsCoB()->currentIndex()).toString(), d->widget->getDimensionCoB()->itemData(d->widget->getDimensionCoB()->currentIndex()).toString()); break; default: // list photos of the album, then start upload with add/update items connect(d->gphotoTalker, SIGNAL(signalListPhotosDone(int,QString,QList)), this, SLOT(slotListPhotosDoneForUpload(int,QString,QList))); d->gphotoTalker->listPhotos( d->widget->getAlbumsCoB()->itemData(d->widget->getAlbumsCoB()->currentIndex()).toString()); break; } } void GSWindow::slotStartTransfer() { d->widget->imagesList()->clearProcessedStatus(); switch (d->service) { case GoogleService::GDrive: case GoogleService::GPhotoExport: if (d->widget->imagesList()->imageUrls().isEmpty()) { QMessageBox::critical(this, i18nc("@title:window", "Error"), i18n("No image selected. Please select which images should be uploaded.")); return; } break; case GoogleService::GPhotoImport: break; } switch (d->service) { case GoogleService::GDrive: if (!(d->talker->authenticated())) { QPointer warn = new QMessageBox(QMessageBox::Warning, i18n("Warning"), i18n("Authentication failed. Click \"Continue\" to authenticate."), QMessageBox::Yes | QMessageBox::No); (warn->button(QMessageBox::Yes))->setText(i18n("Continue")); (warn->button(QMessageBox::No))->setText(i18n("Cancel")); if (warn->exec() == QMessageBox::Yes) { d->talker->doOAuth(); delete warn; return; } else { delete warn; return; } } break; default: if (!(d->gphotoTalker->authenticated())) { QPointer warn = new QMessageBox(QMessageBox::Warning, i18n("Warning"), i18n("Authentication failed. Click \"Continue\" to authenticate."), QMessageBox::Yes | QMessageBox::No); (warn->button(QMessageBox::Yes))->setText(i18n("Continue")); (warn->button(QMessageBox::No))->setText(i18n("Cancel")); if (warn->exec() == QMessageBox::Yes) { d->gphotoTalker->doOAuth(); delete warn; return; } else { delete warn; return; } } /** * (Trung) At that time, googlePhotoTransferHandler is only used for GPhotoImport, * since we don't sync image to update in GPhotoExport */ if (d->service == GoogleService::GPhotoImport) { googlePhotoTransferHandler(); return; } } typedef QPair Pair; for (int i = 0 ; i < (d->widget->imagesList()->imageUrls().size()) ; ++i) { DItemInfo info(d->iface->itemInfo(d->widget->imagesList()->imageUrls().value(i))); GSPhoto temp; qCDebug(DIGIKAM_WEBSERVICES_LOG) << "in start transfer info " <service) { case GoogleService::GDrive: temp.title = info.title(); break; default: temp.title = info.name(); break; } temp.description = info.comment().section(QLatin1String("\n"), 0, 0); temp.gpsLat.setNum(info.latitude()); temp.gpsLon.setNum(info.longitude()); temp.tags = info.tagsPath(); d->transferQueue.append(Pair(d->widget->imagesList()->imageUrls().value(i),temp)); } d->currentAlbumId = d->widget->getAlbumsCoB()->itemData(d->widget->getAlbumsCoB()->currentIndex()).toString(); d->imagesTotal = d->transferQueue.count(); d->imagesCount = 0; d->widget->progressBar()->setFormat(i18n("%v / %m")); d->widget->progressBar()->setMaximum(d->imagesTotal); d->widget->progressBar()->setValue(0); d->widget->progressBar()->show(); d->widget->progressBar()->progressScheduled(i18n("Google Drive export"), true, true); - d->widget->progressBar()->progressThumbnailChanged(QIcon(QLatin1String("googledrive")).pixmap(22, 22)); + d->widget->progressBar()->progressThumbnailChanged(QIcon(QLatin1String("dk-googledrive")).pixmap(22, 22)); uploadNextPhoto(); } void GSWindow::uploadNextPhoto() { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "in upload nextphoto " << d->transferQueue.count(); if (d->transferQueue.isEmpty()) { //d->widget->progressBar()->hide(); d->widget->progressBar()->progressCompleted(); /** * Now all raw photos have been added, * for GPhoto: prepare to upload on user account * for GDrive: get listPhotoId to write metadata and finish upload */ if (d->service == GoogleService::GPhotoExport) { emit d->gphotoTalker->signalReadyToUpload(); } else { emit d->talker->signalReadyToUpload(); } return; } typedef QPair Pair; Pair pathComments = d->transferQueue.first(); GSPhoto info = pathComments.second; bool res = true; d->widget->imagesList()->processing(pathComments.first); switch (d->service) { case GoogleService::GDrive: { res = d->talker->addPhoto(pathComments.first.toLocalFile(), info, d->currentAlbumId, d->widget->getResizeCheckBox()->isChecked(), d->widget->getDimensionSpB()->value(), d->widget->getImgQualitySpB()->value()); break; } case GoogleService::GPhotoExport: { bool bCancel = false; bool bAdd = true; if (!info.id.isEmpty() && !info.editUrl.isEmpty()) { switch (d->renamingOpt) { case PWR_ADD_ALL: bAdd = true; break; case PWR_REPLACE_ALL: bAdd = false; break; default: { QPointer dlg = new ReplaceDialog(this, QLatin1String(""), d->iface, pathComments.first, info.thumbURL); dlg->exec(); switch (dlg->getResult()) { case PWR_ADD_ALL: d->renamingOpt = PWR_ADD_ALL; break; case PWR_ADD: bAdd = true; break; case PWR_REPLACE_ALL: d->renamingOpt = PWR_REPLACE_ALL; break; case PWR_REPLACE: bAdd = false; break; case PWR_CANCEL: default: bCancel = true; break; } delete dlg; break; } } } // adjust tags according to radio button clicked if (d->widget->m_tagsBGrp) { switch (d->widget->m_tagsBGrp->checkedId()) { case GPTagLeaf: { QStringList newTags; QStringList::const_iterator itT; for (itT = info.tags.constBegin() ; itT != info.tags.constEnd() ; ++itT) { QString strTmp = *itT; int idx = strTmp.lastIndexOf(QLatin1Char('/')); if (idx > 0) { strTmp.remove(0, idx + 1); } newTags.append(strTmp); } info.tags = newTags; break; } case GPTagSplit: { QSet newTagsSet; QStringList::const_iterator itT; for (itT = info.tags.constBegin() ; itT != info.tags.constEnd() ; ++itT) { QStringList strListTmp = itT->split(QLatin1Char('/')); QStringList::const_iterator itT2; for (itT2 = strListTmp.constBegin() ; itT2 != strListTmp.constEnd() ; ++itT2) { if (!newTagsSet.contains(*itT2)) { newTagsSet.insert(*itT2); } } } info.tags.clear(); QSet::const_iterator itT3; for (itT3 = newTagsSet.begin() ; itT3 != newTagsSet.end() ; ++itT3) { info.tags.append(*itT3); } break; } case GPTagCombined: default: break; } } if (bCancel) { slotTransferCancel(); res = true; } else { if (bAdd) { res = d->gphotoTalker->addPhoto(pathComments.first.toLocalFile(), info, d->currentAlbumId, d->widget->getResizeCheckBox()->isChecked(), d->widget->getDimensionSpB()->value(), d->widget->getImgQualitySpB()->value()); } else { res = d->gphotoTalker->updatePhoto(pathComments.first.toLocalFile(), info, d->widget->getResizeCheckBox()->isChecked(), d->widget->getDimensionSpB()->value(), d->widget->getImgQualitySpB()->value()); } } break; } case GoogleService::GPhotoImport: break; } if (!res) { slotAddPhotoDone(0, QLatin1String("")); return; } } void GSWindow::downloadNextPhoto() { if (d->transferQueue.isEmpty()) { d->widget->progressBar()->hide(); d->widget->progressBar()->progressCompleted(); return; } d->widget->progressBar()->setMaximum(d->imagesTotal); d->widget->progressBar()->setValue(d->imagesCount); QString imgPath = d->transferQueue.first().first.url(); d->gphotoTalker->getPhoto(imgPath); } void GSWindow::slotGetPhotoDone(int errCode, const QString& errMsg, const QByteArray& photoData) { GSPhoto item = d->transferQueue.first().second; /** * (Trung) * Google Photo API now does not support title for image, so we use creation time for image name instead */ QString itemName(item.title); if (item.title.isEmpty()) { itemName = QString::fromLatin1("image-%1").arg(item.creationTime); } QUrl tmpUrl = QUrl::fromLocalFile(QString(d->tmp + itemName)); if (item.mimeType == QLatin1String("video/mpeg4")) { tmpUrl = tmpUrl.adjusted(QUrl::RemoveFilename); tmpUrl.setPath(tmpUrl.path() + item.title + QLatin1String(".mp4")); } if (errCode == 1) { QString errText; QFile imgFile(tmpUrl.toLocalFile()); if (!imgFile.open(QIODevice::WriteOnly)) { errText = imgFile.errorString(); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "error write"; } else if (imgFile.write(photoData) != photoData.size()) { errText = imgFile.errorString(); } else { imgFile.close(); } if (errText.isEmpty()) { if (d->meta.load(tmpUrl.toLocalFile())) { if (d->meta.supportXmp() && d->meta.canWriteXmp(tmpUrl.toLocalFile())) { d->meta.setXmpTagString("Xmp.digiKam.picasawebGPhotoId", item.id); d->meta.setXmpKeywords(item.tags); } if (!item.gpsLat.isEmpty() && !item.gpsLon.isEmpty()) { d->meta.setGPSInfo(0.0, item.gpsLat.toDouble(), item.gpsLon.toDouble()); } d->meta.setMetadataWritingMode((int)DMetadata::WRITE_TO_FILE_ONLY); d->meta.save(tmpUrl.toLocalFile()); } d->transferQueue.removeFirst(); d->imagesCount++; } else { QPointer warn = new QMessageBox(QMessageBox::Warning, i18n("Warning"), i18n("Failed to save photo: %1\n" "Do you want to continue?", errText), QMessageBox::Yes | QMessageBox::No); (warn->button(QMessageBox::Yes))->setText(i18n("Continue")); (warn->button(QMessageBox::No))->setText(i18n("Cancel")); if (warn->exec() != QMessageBox::Yes) { slotTransferCancel(); delete warn; return; } delete warn; } } else { QPointer warn = new QMessageBox(QMessageBox::Warning, i18n("Warning"), i18n("Failed to download photo: %1\n" "Do you want to continue?", errMsg), QMessageBox::Yes | QMessageBox::No); (warn->button(QMessageBox::Yes))->setText(i18n("Continue")); (warn->button(QMessageBox::No))->setText(i18n("Cancel")); if (warn->exec() != QMessageBox::Yes) { slotTransferCancel(); delete warn; return; } delete warn; } QUrl newUrl = QUrl::fromLocalFile(QString::fromLatin1("%1/%2").arg(d->widget->getDestinationPath()) .arg(tmpUrl.fileName())); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "location " << newUrl.url(); QFileInfo targetInfo(newUrl.toLocalFile()); if (targetInfo.exists()) { int i = 0; bool fileFound = false; do { QFileInfo newTargetInfo(newUrl.toLocalFile()); if (!newTargetInfo.exists()) { fileFound = false; } else { newUrl = newUrl.adjusted(QUrl::RemoveFilename); newUrl.setPath(newUrl.path() + targetInfo.completeBaseName() + QString::fromUtf8("_%1.").arg(++i) + targetInfo.completeSuffix()); fileFound = true; } } while (fileFound); } if (!QFile::rename(tmpUrl.toLocalFile(), newUrl.toLocalFile())) { QMessageBox::critical(this, i18nc("@title:window", "Error"), i18n("Failed to save image to %1", newUrl.toLocalFile())); } /* TODO else { KPItemInfo info(newUrl); info.setName(item.title); info.setDescription(item.description); info.setTagsPath(item.tags); if (!item.gpsLat.isEmpty() && !item.gpsLon.isEmpty()) { info.setLatitude(item.gpsLat.toDouble()); info.setLongitude(item.gpsLon.toDouble()); } } */ downloadNextPhoto(); } void GSWindow::slotAddPhotoDone(int err, const QString& msg) { if (err == 0) { d->widget->imagesList()->processed(d->transferQueue.first().first,false); QPointer warn = new QMessageBox(QMessageBox::Warning, i18n("Warning"), i18n("Failed to upload photo to %1.\n%2\nDo you want to continue?", d->toolName,msg), QMessageBox::Yes | QMessageBox::No); (warn->button(QMessageBox::Yes))->setText(i18n("Continue")); (warn->button(QMessageBox::No))->setText(i18n("Cancel")); if (warn->exec() != QMessageBox::Yes) { d->transferQueue.clear(); d->widget->progressBar()->hide(); } else { d->transferQueue.removeFirst(); d->imagesTotal--; d->widget->progressBar()->setMaximum(d->imagesTotal); d->widget->progressBar()->setValue(d->imagesCount); uploadNextPhoto(); } delete warn; } else { /** * (Trung) Take first item out of transferQueue and append to uploadQueue, * in order to use it again to write id in slotUploadPhotoDone */ QPair item = d->transferQueue.first(); d->uploadQueue.append(item); // Remove photo uploaded from the transfer queue d->transferQueue.removeFirst(); d->imagesCount++; qCDebug(DIGIKAM_WEBSERVICES_LOG) << "In slotAddPhotoSucceeded" << d->imagesCount; d->widget->progressBar()->setMaximum(d->imagesTotal); d->widget->progressBar()->setValue(d->imagesCount); uploadNextPhoto(); } } void GSWindow::slotUploadPhotoDone(int err, const QString& msg, const QStringList& listPhotoId) { if (err == 0) { QPointer warn = new QMessageBox(QMessageBox::Warning, i18n("Warning"), i18n("Failed to finish uploading photo to %1.\n%2\nNo image uploaded to your account.", d->toolName,msg), QMessageBox::Yes); (warn->button(QMessageBox::Yes))->setText(i18n("OK")); d->uploadQueue.clear(); d->widget->progressBar()->hide(); delete warn; } else { foreach (const QString& photoId, listPhotoId) { // Remove image from upload list and from UI QPair item = d->uploadQueue.takeFirst(); d->widget->imagesList()->removeItemByUrl(item.first); QUrl fileUrl = item.first; qCDebug(DIGIKAM_WEBSERVICES_LOG) << "photoID: " << photoId; if (d->meta.supportXmp() && d->meta.canWriteXmp(fileUrl.toLocalFile()) && d->meta.load(fileUrl.toLocalFile()) && !photoId.isEmpty()) { d->meta.setXmpTagString("Xmp.digiKam.picasawebGPhotoId", photoId); d->meta.save(fileUrl.toLocalFile()); } } if(!d->widget->imagesList()->imageUrls().isEmpty()) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "continue to upload"; emit d->gphotoTalker->signalReadyToUpload(); } } } void GSWindow::slotImageListChanged() { startButton()->setEnabled(!(d->widget->imagesList()->imageUrls().isEmpty())); } void GSWindow::slotNewAlbumRequest() { switch (d->service) { case GoogleService::GDrive: if (d->albumDlg->exec() == QDialog::Accepted) { GSFolder newFolder; d->albumDlg->getAlbumProperties(newFolder); d->currentAlbumId = d->widget->getAlbumsCoB()->itemData(d->widget->getAlbumsCoB()->currentIndex()).toString(); d->talker->createFolder(newFolder.title, d->currentAlbumId); } break; default: if (d->gphotoAlbumDlg->exec() == QDialog::Accepted) { GSFolder newFolder; d->gphotoAlbumDlg->getAlbumProperties(newFolder); d->gphotoTalker->createAlbum(newFolder); } break; } } void GSWindow::slotReloadAlbumsRequest() { switch (d->service) { case GoogleService::GDrive: d->talker->listFolders(); break; case GoogleService::GPhotoImport: case GoogleService::GPhotoExport: d->gphotoTalker->listAlbums(); break; } } void GSWindow::slotAccessTokenObtained() { switch (d->service) { case GoogleService::GDrive: d->talker->listFolders(); break; case GoogleService::GPhotoImport: case GoogleService::GPhotoExport: d->gphotoTalker->getLoggedInUser(); break; } } void GSWindow::slotAuthenticationRefused() { // QMessageBox::critical(this, i18nc("@title:window", "Error"), // i18n("An authentication error occurred: account failed to link")); // Clear list albums d->widget->getAlbumsCoB()->clear(); // Clear user name d->widget->updateLabels(QString("")); return; } void GSWindow::slotCreateFolderDone(int code, const QString& msg, const QString& albumId) { switch (d->service) { case GoogleService::GDrive: if (code == 0) QMessageBox::critical(this, i18nc("@title:window", "Error"), i18n("Google Drive call failed:\n%1", msg)); else { d->currentAlbumId = albumId; d->talker->listFolders(); } break; case GoogleService::GPhotoImport: case GoogleService::GPhotoExport: if (code == 0) QMessageBox::critical(this, i18nc("@title:window", "Error"), i18n("Google Photos/PicasaWeb call failed:\n%1", msg)); else { d->currentAlbumId = albumId; d->gphotoTalker->listAlbums(); } break; } } void GSWindow::slotTransferCancel() { d->transferQueue.clear(); d->widget->progressBar()->hide(); switch (d->service) { case GoogleService::GDrive: d->talker->cancel(); break; case GoogleService::GPhotoImport: case GoogleService::GPhotoExport: d->gphotoTalker->cancel(); break; } } void GSWindow::slotUserChangeRequest() { QPointer warn = new QMessageBox(QMessageBox::Warning, i18n("Warning"), i18n("You will be logged out of your account, " "click \"Continue\" to authenticate for another account"), QMessageBox::Yes | QMessageBox::No); (warn->button(QMessageBox::Yes))->setText(i18n("Continue")); (warn->button(QMessageBox::No))->setText(i18n("Cancel")); if (warn->exec() == QMessageBox::Yes) { /** * We do not force user to logout from their account * We simply unlink user account and direct use to login page to login new account * (In the future, we may not unlink() user, but let them change account and * choose which one they want to use) * After unlink(), waiting actively until O2 completely unlink() account, before doOAuth() again */ switch (d->service) { case GoogleService::GDrive: d->talker->unlink(); while(d->talker->authenticated()); d->talker->doOAuth(); break; case GoogleService::GPhotoImport: case GoogleService::GPhotoExport: d->gphotoTalker->unlink(); while(d->gphotoTalker->authenticated()); d->gphotoTalker->doOAuth(); break; } } delete warn; } void GSWindow::buttonStateChange(bool state) { d->widget->getNewAlbmBtn()->setEnabled(state); d->widget->getReloadBtn()->setEnabled(state); startButton()->setEnabled(state); } void GSWindow::slotFinished() { writeSettings(); d->widget->imagesList()->listView()->clear(); } void GSWindow::closeEvent(QCloseEvent* e) { if (!e) { return; } slotFinished(); e->accept(); } } // namespace Digikam diff --git a/core/utilities/assistants/webservices/imageshack/imageshackwindow.cpp b/core/utilities/assistants/webservices/imageshack/imageshackwindow.cpp index 6743d2db42..6bc10f1eb2 100644 --- a/core/utilities/assistants/webservices/imageshack/imageshackwindow.cpp +++ b/core/utilities/assistants/webservices/imageshack/imageshackwindow.cpp @@ -1,454 +1,454 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2012-02-02 * Description : a tool to export items to ImageShack web service * * Copyright (C) 2012 by Dodon Victor * Copyright (C) 2013-2018 by Caulier Gilles * * 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 "imageshackwindow.h" // Qt includes #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 #include // Local includes #include "digikam_debug.h" #include "imageshacksession.h" #include "imageshackwidget_p.h" #include "imageshacktalker.h" #include "dprogresswdg.h" #include "wslogindialog.h" #include "imageshacknewalbumdlg.h" namespace Digikam { class Q_DECL_HIDDEN ImageShackWindow::Private { public: explicit Private() { imagesCount = 0; imagesTotal = 0; session = 0; widget = 0; talker = 0; albumDlg = 0; iface = 0; } unsigned int imagesCount; unsigned int imagesTotal; QString newAlbmTitle; QList transferQueue; ImageShackSession* session; ImageShackWidget* widget; ImageShackTalker* talker; ImageShackNewAlbumDlg* albumDlg; DInfoInterface* iface; }; ImageShackWindow::ImageShackWindow(DInfoInterface* const iface, QWidget* const /*parent*/) : WSToolDialog(0), d(new Private) { d->session = new ImageShackSession(); d->iface = iface; d->widget = new ImageShackWidget(this, d->session, d->iface, QLatin1String("ImageShack")); d->widget->setMinimumSize(700, 500); setMainWidget(d->widget); setWindowTitle(i18n("Export to ImageShack")); setModal(false); d->albumDlg = new ImageShackNewAlbumDlg(this, QLatin1String("ImageShack")); connect(d->widget->d->chgRegCodeBtn, SIGNAL(clicked(bool)), this, SLOT(slotChangeRegistrantionCode())); startButton()->setText(i18n("Upload")); startButton()->setToolTip(i18n("Start upload to ImageShack web service")); startButton()->setEnabled(false); connect(d->widget->d->imgList, SIGNAL(signalImageListChanged()), this, SLOT(slotImageListChanged())); // ----------------------------------------------------------- connect(this, SIGNAL(signalBusy(bool)), this, SLOT(slotBusy(bool))); d->talker = new ImageShackTalker(d->session); connect(d->talker, SIGNAL(signalBusy(bool)), this, SLOT(slotBusy(bool))); connect(d->talker, SIGNAL(signalJobInProgress(int,int,QString)), this, SLOT(slotJobInProgress(int,int,QString))); connect(d->talker, SIGNAL(signalLoginDone(int,QString)), this, SLOT(slotLoginDone(int,QString))); connect(d->talker, SIGNAL(signalGetGalleriesDone(int,QString)), this, SLOT(slotGetGalleriesDone(int,QString))); connect(d->talker, SIGNAL(signalUpdateGalleries(QStringList,QStringList)), d->widget, SLOT(slotGetGalleries(QStringList,QStringList))); connect(d->talker, SIGNAL(signalAddPhotoDone(int,QString)), this, SLOT(slotAddPhotoDone(int,QString))); connect(d->widget, SIGNAL(signalReloadGalleries()), this, SLOT(slotGetGalleries())); connect(startButton(), SIGNAL(clicked()), this, SLOT(slotStartTransfer())); connect(this, SIGNAL(finished(int)), this, SLOT(slotFinished())); connect(this, SIGNAL(cancelClicked()), this, SLOT(slotCancelClicked())); connect(d->widget->getNewAlbmBtn(), SIGNAL(clicked()), this, SLOT(slotNewAlbumRequest())); readSettings(); QTimer::singleShot(20, this, SLOT(authenticate())); } ImageShackWindow::~ImageShackWindow() { delete d->session; delete d; } void ImageShackWindow::slotImageListChanged() { startButton()->setEnabled(!d->widget->d->imgList->imageUrls().isEmpty()); } void ImageShackWindow::slotFinished() { saveSettings(); d->widget->d->progressBar->progressCompleted(); d->widget->d->imgList->listView()->clear(); } void ImageShackWindow::closeEvent(QCloseEvent* e) { if (!e) { return; } slotFinished(); e->accept(); } void ImageShackWindow::readSettings() { winId(); KConfig config; KConfigGroup group = config.group("ImageShack Settings"); KWindowConfig::restoreWindowSize(windowHandle(), group); resize(windowHandle()->size()); if (group.readEntry("Private", false)) { d->widget->d->privateImagesChb->setChecked(true); } if (group.readEntry("Rembar", false)) { d->widget->d->remBarChb->setChecked(true); } else { d->widget->d->remBarChb->setChecked(false); } } void ImageShackWindow::saveSettings() { KConfig config; KConfigGroup group = config.group("ImageShack Settings"); KWindowConfig::saveWindowSize(windowHandle(), group); group.writeEntry("Private", d->widget->d->privateImagesChb->isChecked()); group.writeEntry("Rembar", d->widget->d->remBarChb->isChecked()); group.sync(); } void ImageShackWindow::slotStartTransfer() { d->widget->d->imgList->clearProcessedStatus(); d->transferQueue = d->widget->d->imgList->imageUrls(); if (d->transferQueue.isEmpty()) { return; } qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Transfer started!"; d->imagesTotal = d->transferQueue.count(); d->imagesCount = 0; d->widget->d->progressBar->setFormat(i18n("%v / %m")); d->widget->d->progressBar->setMaximum(d->imagesTotal); d->widget->d->progressBar->setValue(0); d->widget->d->progressBar->setVisible(true); d->widget->d->progressBar->progressScheduled(i18n("Image Shack Export"), false, true); - d->widget->d->progressBar->progressThumbnailChanged(QIcon(QLatin1String("imageshack")).pixmap(22, 22)); + d->widget->d->progressBar->progressThumbnailChanged(QIcon(QLatin1String("dk-imageshack")).pixmap(22, 22)); uploadNextItem(); } void ImageShackWindow::slotCancelClicked() { d->talker->cancel(); d->transferQueue.clear(); d->widget->d->imgList->cancelProcess(); d->widget->d->progressBar->setVisible(false); d->widget->d->progressBar->progressCompleted(); } void ImageShackWindow::slotChangeRegistrantionCode() { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Change registration code"; authenticate(); } void ImageShackWindow::authenticate() { emit signalBusy(true); d->widget->progressBar()->show(); d->widget->d->progressBar->setValue(0); d->widget->d->progressBar->setMaximum(4); d->widget->progressBar()->setFormat(i18n("Authenticating...")); WSLoginDialog* const dlg = new WSLoginDialog(this, QLatin1String("ImageShack")); if (dlg->exec() == QDialog::Accepted) { d->session->setEmail(dlg->login()); d->session->setPassword(dlg->password()); d->talker->authenticate(); } } void ImageShackWindow::slotBusy(bool val) { if (val) { setCursor(Qt::WaitCursor); d->widget->d->chgRegCodeBtn->setEnabled(false); startButton()->setEnabled(false); setRejectButtonMode(QDialogButtonBox::Cancel); } else { setCursor(Qt::ArrowCursor); d->widget->d->chgRegCodeBtn->setEnabled(true); startButton()->setEnabled(d->session->loggedIn() && !d->widget->imagesList()->imageUrls().isEmpty()); setRejectButtonMode(QDialogButtonBox::Close); } } void ImageShackWindow::slotJobInProgress(int step, int maxStep, const QString &format) { if (maxStep > 0) { d->widget->d->progressBar->setMaximum(maxStep); } d->widget->d->progressBar->setValue(step); if (!format.isEmpty()) { d->widget->d->progressBar->setFormat(format); } } void ImageShackWindow::slotLoginDone(int errCode, const QString& errMsg) { d->widget->updateLabels(); if (!errCode && d->session->loggedIn()) { d->session->saveSettings(); startButton()->setEnabled(!d->widget->imagesList()->imageUrls().isEmpty()); d->talker->getGalleries(); } else { QMessageBox::critical(this, QString(), i18n("Login failed: %1\n", errMsg)); startButton()->setEnabled(false); d->widget->d->progressBar->setVisible(false); slotBusy(false); } } void ImageShackWindow::slotGetGalleriesDone(int errCode, const QString &errMsg) { slotBusy(false); d->widget->d->progressBar->setVisible(false); if (errCode) { QMessageBox::critical(this, QString(), i18n("Failed to get galleries list: %1\n", errMsg)); } } void ImageShackWindow::uploadNextItem() { if (d->transferQueue.isEmpty()) { d->widget->d->progressBar->hide(); return; } d->widget->d->imgList->processing(d->transferQueue.first()); QString imgPath = d->transferQueue.first().toLocalFile(); d->widget->d->progressBar->setMaximum(d->imagesTotal); d->widget->d->progressBar->setValue(d->imagesCount); QMap opts; if (d->widget->d->privateImagesChb->isChecked()) { opts[QLatin1String("public")] = QLatin1String("no"); } if (d->widget->d->remBarChb->isChecked()) { opts[QLatin1String("rembar")] = QLatin1String("yes"); } // tags if (!d->widget->d->tagsFld->text().isEmpty()) { QString str = d->widget->d->tagsFld->text(); QStringList tagsList; tagsList = str.split(QRegExp(QLatin1String("\\W+")), QString::SkipEmptyParts); opts[QLatin1String("tags")] = tagsList.join(QLatin1Char(',')); } opts[QLatin1String("auth_token")] = d->session->authToken(); int gidx = d->widget->d->galleriesCob->currentIndex(); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Album ID is "<< d->widget->d->galleriesCob->itemData(gidx).toString(); switch(gidx) { case 0: d->talker->uploadItem(imgPath, opts); break; case 1: opts[QLatin1String("album")] = d->newAlbmTitle; d->talker->uploadItemToGallery(imgPath, d->newAlbmTitle, opts); break; default: opts[QLatin1String("album")] = d->widget->d->galleriesCob->itemData(gidx).toString(); d->talker->uploadItemToGallery(imgPath, d->widget->d->galleriesCob->itemData(gidx).toString(), opts); } } void ImageShackWindow::slotAddPhotoDone(int errCode, const QString& errMsg) { d->widget->d->imgList->processed(d->transferQueue.first(), (errCode == 0)); if (!errCode) { d->widget->imagesList()->removeItemByUrl(d->transferQueue.first()); d->transferQueue.removeFirst(); d->imagesCount++; } else { if (QMessageBox::question(this, i18n("Uploading Failed"), i18n("Failed to upload photo into ImageShack: %1\n" "Do you want to continue?", errMsg)) != QMessageBox::Yes) { d->widget->d->progressBar->setVisible(false); d->transferQueue.clear(); return; } } uploadNextItem(); } void ImageShackWindow::slotGetGalleries() { d->widget->d->progressBar->setVisible(true); d->talker->getGalleries(); } void ImageShackWindow::slotNewAlbumRequest() { if (d->albumDlg->exec() == QDialog::Accepted) { d->newAlbmTitle = d->albumDlg->getAlbumTitle(); } } } // namespace Digikam diff --git a/core/utilities/assistants/webservices/onedrive/odwindow.cpp b/core/utilities/assistants/webservices/onedrive/odwindow.cpp index c15e89e81f..2c6389870f 100644 --- a/core/utilities/assistants/webservices/onedrive/odwindow.cpp +++ b/core/utilities/assistants/webservices/onedrive/odwindow.cpp @@ -1,466 +1,466 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2018-05-20 * Description : a tool to export images to Onedrive web service * * Copyright (C) 2018 by Tarek Talaat * * 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 "odwindow.h" // Qt includes #include #include #include #include #include #include // KDE includes #include #include #include // Local includes #include "digikam_debug.h" #include "ditemslist.h" #include "digikam_version.h" #include "odtalker.h" #include "oditem.h" #include "odnewalbumdlg.h" #include "odwidget.h" namespace Digikam { class Q_DECL_HIDDEN ODWindow::Private { public: explicit Private() { imagesCount = 0; imagesTotal = 0; widget = 0; albumDlg = 0; talker = 0; } unsigned int imagesCount; unsigned int imagesTotal; ODWidget* widget; ODNewAlbumDlg* albumDlg; ODTalker* talker; QString currentAlbumName; QList transferQueue; }; ODWindow::ODWindow(DInfoInterface* const iface, QWidget* const /*parent*/) : WSToolDialog(0), d(new Private) { d->widget = new ODWidget(this, iface, QLatin1String("Onedrive")); d->widget->imagesList()->setIface(iface); setMainWidget(d->widget); setModal(false); setWindowTitle(i18n("Export to Onedrive")); startButton()->setText(i18n("Start Upload")); startButton()->setToolTip(i18n("Start upload to Onedrive")); d->widget->setMinimumSize(700, 500); connect(d->widget->imagesList(), SIGNAL(signalImageListChanged()), this, SLOT(slotImageListChanged())); connect(d->widget->getChangeUserBtn(), SIGNAL(clicked()), this, SLOT(slotUserChangeRequest())); connect(d->widget->getNewAlbmBtn(), SIGNAL(clicked()), this, SLOT(slotNewAlbumRequest())); connect(d->widget->getReloadBtn(), SIGNAL(clicked()), this, SLOT(slotReloadAlbumsRequest())); connect(startButton(), SIGNAL(clicked()), this, SLOT(slotStartTransfer())); d->albumDlg = new ODNewAlbumDlg(this, QLatin1String("Onedrive")); d->talker = new ODTalker(this); connect(d->talker,SIGNAL(signalBusy(bool)), this,SLOT(slotBusy(bool))); connect(d->talker,SIGNAL(signalLinkingFailed()), this,SLOT(slotSignalLinkingFailed())); connect(d->talker,SIGNAL(signalLinkingSucceeded()), this,SLOT(slotSignalLinkingSucceeded())); connect(d->talker,SIGNAL(signalSetUserName(QString)), this,SLOT(slotSetUserName(QString))); connect(d->talker,SIGNAL(signalListAlbumsFailed(QString)), this,SLOT(slotListAlbumsFailed(QString))); connect(d->talker,SIGNAL(signalListAlbumsDone(QList >)), // krazy:exclude=normalize this,SLOT(slotListAlbumsDone(QList >))); // krazy:exclude=normalize connect(d->talker,SIGNAL(signalCreateFolderFailed(QString)), this,SLOT(slotCreateFolderFailed(QString))); connect(d->talker,SIGNAL(signalCreateFolderSucceeded()), this,SLOT(slotCreateFolderSucceeded())); connect(d->talker,SIGNAL(signalAddPhotoFailed(QString)), this,SLOT(slotAddPhotoFailed(QString))); connect(d->talker,SIGNAL(signalAddPhotoSucceeded()), this,SLOT(slotAddPhotoSucceeded())); connect(this, SIGNAL(finished(int)), this, SLOT(slotFinished())); readSettings(); buttonStateChange(false); d->talker->readSettings(); } ODWindow::~ODWindow() { delete d->widget; delete d->albumDlg; delete d->talker; delete d; } void ODWindow::readSettings() { KConfig config; KConfigGroup grp = config.group("Onedrive Settings"); d->currentAlbumName = grp.readEntry("Current Album",QString()); if (grp.readEntry("Resize", false)) { d->widget->getResizeCheckBox()->setChecked(true); d->widget->getDimensionSpB()->setEnabled(true); } else { d->widget->getResizeCheckBox()->setChecked(false); d->widget->getDimensionSpB()->setEnabled(false); } d->widget->getDimensionSpB()->setValue(grp.readEntry("Maximum Width", 1600)); d->widget->getImgQualitySpB()->setValue(grp.readEntry("Image Quality", 90)); KConfigGroup dialogGroup = config.group("Onedrive Export Dialog"); winId(); KWindowConfig::restoreWindowSize(windowHandle(), dialogGroup); resize(windowHandle()->size()); } void ODWindow::writeSettings() { KConfig config; KConfigGroup grp = config.group("Onedrive Settings"); grp.writeEntry("Current Album", d->currentAlbumName); grp.writeEntry("Resize", d->widget->getResizeCheckBox()->isChecked()); grp.writeEntry("Maximum Width", d->widget->getDimensionSpB()->value()); grp.writeEntry("Image Quality", d->widget->getImgQualitySpB()->value()); KConfigGroup dialogGroup = config.group("Onedrive Export Dialog"); KWindowConfig::saveWindowSize(windowHandle(), dialogGroup); config.sync(); } void ODWindow::reactivate() { d->widget->imagesList()->loadImagesFromCurrentSelection(); d->widget->progressBar()->hide(); show(); } void ODWindow::setItemsList(const QList& urls) { d->widget->imagesList()->slotAddImages(urls); } void ODWindow::slotBusy(bool val) { if (val) { setCursor(Qt::WaitCursor); d->widget->getChangeUserBtn()->setEnabled(false); buttonStateChange(false); } else { setCursor(Qt::ArrowCursor); d->widget->getChangeUserBtn()->setEnabled(true); buttonStateChange(true); } } void ODWindow::slotSetUserName(const QString& msg) { d->widget->updateLabels(msg, QLatin1String("")); } void ODWindow::slotListAlbumsDone(const QList >& list) { d->widget->getAlbumsCoB()->clear(); for (int i = 0 ; i < list.size() ; ++i) { d->widget->getAlbumsCoB()->addItem( QIcon::fromTheme(QLatin1String("system-users")), list.value(i).second, list.value(i).first); if (d->currentAlbumName == list.value(i).first) { d->widget->getAlbumsCoB()->setCurrentIndex(i); } } buttonStateChange(true); d->talker->getUserName(); } void ODWindow::slotStartTransfer() { d->widget->imagesList()->clearProcessedStatus(); if (d->widget->imagesList()->imageUrls().isEmpty()) { QMessageBox::critical(this, i18nc("@title:window", "Error"), i18n("No image selected. Please select which images should be uploaded.")); return; } if (!(d->talker->authenticated())) { QPointer warn = new QMessageBox(QMessageBox::Warning, i18n("Warning"), i18n("Authentication failed. Click \"Continue\" to authenticate."), QMessageBox::Yes | QMessageBox::No); (warn->button(QMessageBox::Yes))->setText(i18n("Continue")); (warn->button(QMessageBox::No))->setText(i18n("Cancel")); if (warn->exec() == QMessageBox::Yes) { d->talker->link(); delete warn; return; } else { delete warn; return; } } d->transferQueue = d->widget->imagesList()->imageUrls(); if (d->transferQueue.isEmpty()) { return; } d->currentAlbumName = d->widget->getAlbumsCoB()->itemData(d->widget->getAlbumsCoB()->currentIndex()).toString(); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "StartTransfer:" << d->currentAlbumName << "INDEX: " << d->widget->getAlbumsCoB()->currentIndex(); d->imagesTotal = d->transferQueue.count(); d->imagesCount = 0; d->widget->progressBar()->setFormat(i18n("%v / %m")); d->widget->progressBar()->setMaximum(d->imagesTotal); d->widget->progressBar()->setValue(0); d->widget->progressBar()->show(); d->widget->progressBar()->progressScheduled(i18n("Onedrive export"), true, true); - d->widget->progressBar()->progressThumbnailChanged(QIcon(QLatin1String("onedrive")).pixmap(22, 22)); + d->widget->progressBar()->progressThumbnailChanged(QIcon(QLatin1String("dk-onedrive")).pixmap(22, 22)); uploadNextPhoto(); } void ODWindow::uploadNextPhoto() { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "uploadNextPhoto:" << d->transferQueue.count(); if (d->transferQueue.isEmpty()) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "empty"; d->widget->progressBar()->progressCompleted(); return; } QString imgPath = d->transferQueue.first().toLocalFile(); QString temp = d->currentAlbumName + QLatin1Char('/'); bool result = d->talker->addPhoto(imgPath, temp, d->widget->getResizeCheckBox()->isChecked(), d->widget->getDimensionSpB()->value(), d->widget->getImgQualitySpB()->value()); if (!result) { slotAddPhotoFailed(QLatin1String("")); return; } } void ODWindow::slotAddPhotoFailed(const QString& msg) { if (QMessageBox::question(this, i18n("Uploading Failed"), i18n("Failed to upload photo to OneDrive." "\n%1\n" "Do you want to continue?", msg)) != QMessageBox::Yes) { d->transferQueue.clear(); d->widget->progressBar()->hide(); } else { d->transferQueue.pop_front(); d->imagesTotal--; d->widget->progressBar()->setMaximum(d->imagesTotal); d->widget->progressBar()->setValue(d->imagesCount); uploadNextPhoto(); } } void ODWindow::slotAddPhotoSucceeded() { // Remove photo uploaded from the list d->widget->imagesList()->removeItemByUrl(d->transferQueue.first()); d->transferQueue.pop_front(); d->imagesCount++; d->widget->progressBar()->setMaximum(d->imagesTotal); d->widget->progressBar()->setValue(d->imagesCount); uploadNextPhoto(); } void ODWindow::slotImageListChanged() { startButton()->setEnabled(!(d->widget->imagesList()->imageUrls().isEmpty())); } void ODWindow::slotNewAlbumRequest() { if (d->albumDlg->exec() == QDialog::Accepted) { ODFolder newFolder; d->albumDlg->getFolderTitle(newFolder); d->currentAlbumName = d->widget->getAlbumsCoB()->itemData(d->widget->getAlbumsCoB()->currentIndex()).toString(); QString temp = d->currentAlbumName + newFolder.title; d->talker->createFolder(temp); } } void ODWindow::slotReloadAlbumsRequest() { d->talker->listFolders(); } void ODWindow::slotSignalLinkingFailed() { slotSetUserName(QLatin1String("")); d->widget->getAlbumsCoB()->clear(); if (QMessageBox::question(this, i18n("Login Failed"), i18n("Authentication failed. Do you want to try again?")) == QMessageBox::Yes) { d->talker->link(); } } void ODWindow::slotSignalLinkingSucceeded() { d->talker->listFolders(); } void ODWindow::slotListAlbumsFailed(const QString& msg) { QMessageBox::critical(this, QString(), i18n("Onedrive call failed:\n%1", msg)); } void ODWindow::slotCreateFolderFailed(const QString& msg) { QMessageBox::critical(this, QString(), i18n("Onedrive call failed:\n%1", msg)); } void ODWindow::slotCreateFolderSucceeded() { d->talker->listFolders(); } void ODWindow::slotTransferCancel() { d->transferQueue.clear(); d->widget->progressBar()->hide(); d->talker->cancel(); } void ODWindow::slotUserChangeRequest() { slotSetUserName(QLatin1String("")); d->widget->getAlbumsCoB()->clear(); d->talker->unLink(); d->talker->link(); } void ODWindow::buttonStateChange(bool state) { d->widget->getNewAlbmBtn()->setEnabled(state); d->widget->getReloadBtn()->setEnabled(state); startButton()->setEnabled(state); } void ODWindow::slotFinished() { writeSettings(); d->widget->imagesList()->listView()->clear(); } void ODWindow::closeEvent(QCloseEvent* e) { if (!e) { return; } slotFinished(); e->accept(); } } // namespace Digikam diff --git a/core/utilities/assistants/webservices/pinterest/pwindow.cpp b/core/utilities/assistants/webservices/pinterest/pwindow.cpp index 9e625a4451..f4e2ec6c7c 100644 --- a/core/utilities/assistants/webservices/pinterest/pwindow.cpp +++ b/core/utilities/assistants/webservices/pinterest/pwindow.cpp @@ -1,466 +1,466 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2018-05-20 * Description : a tool to export images to Pinterest web service * * Copyright (C) 2018 by Tarek Talaat * * 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 "pwindow.h" // Qt includes #include #include #include #include #include #include // KDE includes #include #include #include // Local includes #include "digikam_debug.h" #include "ditemslist.h" #include "digikam_version.h" #include "ptalker.h" #include "pitem.h" #include "pnewalbumdlg.h" #include "pwidget.h" namespace Digikam { class Q_DECL_HIDDEN PWindow::Private { public: explicit Private() { imagesCount = 0; imagesTotal = 0; widget = 0; albumDlg = 0; talker = 0; } unsigned int imagesCount; unsigned int imagesTotal; PWidget* widget; PNewAlbumDlg* albumDlg; PTalker* talker; QString currentAlbumName; QList transferQueue; }; PWindow::PWindow(DInfoInterface* const iface, QWidget* const /*parent*/) : WSToolDialog(0), d(new Private) { d->widget = new PWidget(this, iface, QLatin1String("Pinterest")); d->widget->imagesList()->setIface(iface); setMainWidget(d->widget); setModal(false); setWindowTitle(i18n("Export to Pinterest")); startButton()->setText(i18n("Start Upload")); startButton()->setToolTip(i18n("Start upload to Pinterest")); d->widget->setMinimumSize(700, 500); connect(d->widget->imagesList(), SIGNAL(signalImageListChanged()), this, SLOT(slotImageListChanged())); connect(d->widget->getChangeUserBtn(), SIGNAL(clicked()), this, SLOT(slotUserChangeRequest())); connect(d->widget->getNewAlbmBtn(), SIGNAL(clicked()), this, SLOT(slotNewBoardRequest())); connect(d->widget->getReloadBtn(), SIGNAL(clicked()), this, SLOT(slotReloadBoardsRequest())); connect(startButton(), SIGNAL(clicked()), this, SLOT(slotStartTransfer())); d->albumDlg = new PNewAlbumDlg(this, QLatin1String("Pinterest")); d->talker = new PTalker(this); connect(d->talker,SIGNAL(signalBusy(bool)), this,SLOT(slotBusy(bool))); connect(d->talker,SIGNAL(signalLinkingFailed()), this,SLOT(slotSignalLinkingFailed())); connect(d->talker,SIGNAL(signalLinkingSucceeded()), this,SLOT(slotSignalLinkingSucceeded())); connect(d->talker,SIGNAL(signalSetUserName(QString)), this,SLOT(slotSetUserName(QString))); connect(d->talker,SIGNAL(signalListBoardsFailed(QString)), this,SLOT(slotListBoardsFailed(QString))); connect(d->talker,SIGNAL(signalListBoardsDone(QList >)), // krazy:exclude=normalize this,SLOT(slotListBoardsDone(QList >))); // krazy:exclude=normalize connect(d->talker,SIGNAL(signalCreateBoardFailed(QString)), this,SLOT(slotCreateBoardFailed(QString))); connect(d->talker,SIGNAL(signalCreateBoardSucceeded()), this,SLOT(slotCreateBoardSucceeded())); connect(d->talker,SIGNAL(signalAddPinFailed(QString)), this,SLOT(slotAddPinFailed(QString))); connect(d->talker,SIGNAL(signalAddPinSucceeded()), this,SLOT(slotAddPinSucceeded())); connect(this, SIGNAL(finished(int)), this, SLOT(slotFinished())); readSettings(); buttonStateChange(false); d->talker->readSettings(); } PWindow::~PWindow() { delete d->widget; delete d->albumDlg; delete d->talker; delete d; } void PWindow::readSettings() { KConfig config; KConfigGroup grp = config.group("Pinterest Settings"); d->currentAlbumName = grp.readEntry("Current Album",QString()); if (grp.readEntry("Resize", false)) { d->widget->getResizeCheckBox()->setChecked(true); d->widget->getDimensionSpB()->setEnabled(true); } else { d->widget->getResizeCheckBox()->setChecked(false); d->widget->getDimensionSpB()->setEnabled(false); } d->widget->getDimensionSpB()->setValue(grp.readEntry("Maximum Width", 1600)); d->widget->getImgQualitySpB()->setValue(grp.readEntry("Image Quality", 90)); KConfigGroup dialogGroup = config.group("Pinterest Export Dialog"); winId(); KWindowConfig::restoreWindowSize(windowHandle(), dialogGroup); resize(windowHandle()->size()); } void PWindow::writeSettings() { KConfig config; KConfigGroup grp = config.group("Pinterest Settings"); grp.writeEntry("Current Album", d->currentAlbumName); grp.writeEntry("Resize", d->widget->getResizeCheckBox()->isChecked()); grp.writeEntry("Maximum Width", d->widget->getDimensionSpB()->value()); grp.writeEntry("Image Quality", d->widget->getImgQualitySpB()->value()); KConfigGroup dialogGroup = config.group("Pinterest Export Dialog"); KWindowConfig::saveWindowSize(windowHandle(), dialogGroup); config.sync(); } void PWindow::reactivate() { d->widget->imagesList()->loadImagesFromCurrentSelection(); d->widget->progressBar()->hide(); show(); } void PWindow::setItemsList(const QList& urls) { d->widget->imagesList()->slotAddImages(urls); } void PWindow::slotBusy(bool val) { if (val) { setCursor(Qt::WaitCursor); d->widget->getChangeUserBtn()->setEnabled(false); buttonStateChange(false); } else { setCursor(Qt::ArrowCursor); d->widget->getChangeUserBtn()->setEnabled(true); buttonStateChange(true); } } void PWindow::slotSetUserName(const QString& msg) { d->widget->updateLabels(msg, QLatin1String("")); } void PWindow::slotListBoardsDone(const QList >& list) { d->widget->getAlbumsCoB()->clear(); for (int i = 0 ; i < list.size() ; ++i) { d->widget->getAlbumsCoB()->addItem( QIcon::fromTheme(QLatin1String("system-users")), list.value(i).second, list.value(i).second); if (d->currentAlbumName == list.value(i).first) { d->widget->getAlbumsCoB()->setCurrentIndex(i); } } buttonStateChange(true); d->talker->getUserName(); } void PWindow::slotStartTransfer() { d->widget->imagesList()->clearProcessedStatus(); if (d->widget->imagesList()->imageUrls().isEmpty()) { QMessageBox::critical(this, i18nc("@title:window", "Error"), i18n("No image selected. Please select which images should be uploaded.")); return; } if (!(d->talker->authenticated())) { QPointer warn = new QMessageBox(QMessageBox::Warning, i18n("Warning"), i18n("Authentication failed. Click \"Continue\" to authenticate."), QMessageBox::Yes | QMessageBox::No); (warn->button(QMessageBox::Yes))->setText(i18n("Continue")); (warn->button(QMessageBox::No))->setText(i18n("Cancel")); if (warn->exec() == QMessageBox::Yes) { d->talker->link(); delete warn; return; } else { delete warn; return; } } d->transferQueue = d->widget->imagesList()->imageUrls(); if (d->transferQueue.isEmpty()) { return; } d->currentAlbumName = d->widget->getAlbumsCoB()->itemData(d->widget->getAlbumsCoB()->currentIndex()).toString(); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "StartTransfer:" << d->currentAlbumName << "INDEX: " << d->widget->getAlbumsCoB()->currentIndex(); d->imagesTotal = d->transferQueue.count(); d->imagesCount = 0; d->widget->progressBar()->setFormat(i18n("%v / %m")); d->widget->progressBar()->setMaximum(d->imagesTotal); d->widget->progressBar()->setValue(0); d->widget->progressBar()->show(); d->widget->progressBar()->progressScheduled(i18n("Pinterest export"), true, true); - d->widget->progressBar()->progressThumbnailChanged(QIcon(QLatin1String("pinterest")).pixmap(22, 22)); + d->widget->progressBar()->progressThumbnailChanged(QIcon(QLatin1String("dk-pinterest")).pixmap(22, 22)); uploadNextPhoto(); } void PWindow::uploadNextPhoto() { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "uploadNextPhoto:" << d->transferQueue.count(); if (d->transferQueue.isEmpty()) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "empty"; d->widget->progressBar()->progressCompleted(); return; } QString imgPath = d->transferQueue.first().toLocalFile(); QString temp = d->currentAlbumName; bool result = d->talker->addPin(imgPath, temp, d->widget->getResizeCheckBox()->isChecked(), d->widget->getDimensionSpB()->value(), d->widget->getImgQualitySpB()->value()); if (!result) { slotAddPinFailed(QLatin1String("")); return; } } void PWindow::slotAddPinFailed(const QString& msg) { if (QMessageBox::question(this, i18n("Uploading Failed"), i18n("Failed to upload photo to Pinterest." "\n%1\n" "Do you want to continue?", msg)) != QMessageBox::Yes) { d->transferQueue.clear(); d->widget->progressBar()->hide(); } else { d->transferQueue.pop_front(); d->imagesTotal--; d->widget->progressBar()->setMaximum(d->imagesTotal); d->widget->progressBar()->setValue(d->imagesCount); uploadNextPhoto(); } } void PWindow::slotAddPinSucceeded() { // Remove photo uploaded from the list d->widget->imagesList()->removeItemByUrl(d->transferQueue.first()); d->transferQueue.pop_front(); d->imagesCount++; d->widget->progressBar()->setMaximum(d->imagesTotal); d->widget->progressBar()->setValue(d->imagesCount); uploadNextPhoto(); } void PWindow::slotImageListChanged() { startButton()->setEnabled(!(d->widget->imagesList()->imageUrls().isEmpty())); } void PWindow::slotNewBoardRequest() { if (d->albumDlg->exec() == QDialog::Accepted) { PFolder newFolder; d->albumDlg->getFolderTitle(newFolder); d->currentAlbumName = d->widget->getAlbumsCoB()->itemData(d->widget->getAlbumsCoB()->currentIndex()).toString(); QString temp = newFolder.title; d->talker->createBoard(temp); } } void PWindow::slotReloadBoardsRequest() { d->talker->listBoards(); } void PWindow::slotSignalLinkingFailed() { slotSetUserName(QLatin1String("")); d->widget->getAlbumsCoB()->clear(); if (QMessageBox::question(this, i18n("Login Failed"), i18n("Authentication failed. Do you want to try again?")) == QMessageBox::Yes) { d->talker->link(); } } void PWindow::slotSignalLinkingSucceeded() { d->talker->listBoards(); } void PWindow::slotListBoardsFailed(const QString& msg) { QMessageBox::critical(this, QString(), i18n("Pinterest call failed:\n%1", msg)); } void PWindow::slotCreateBoardFailed(const QString& msg) { QMessageBox::critical(this, QString(), i18n("Pinterest call failed:\n%1", msg)); } void PWindow::slotCreateBoardSucceeded() { d->talker->listBoards(); } void PWindow::slotTransferCancel() { d->transferQueue.clear(); d->widget->progressBar()->hide(); d->talker->cancel(); } void PWindow::slotUserChangeRequest() { slotSetUserName(QLatin1String("")); d->widget->getAlbumsCoB()->clear(); d->talker->unLink(); d->talker->link(); } void PWindow::buttonStateChange(bool state) { d->widget->getNewAlbmBtn()->setEnabled(state); d->widget->getReloadBtn()->setEnabled(state); startButton()->setEnabled(state); } void PWindow::slotFinished() { writeSettings(); d->widget->imagesList()->listView()->clear(); } void PWindow::closeEvent(QCloseEvent* e) { if (!e) { return; } slotFinished(); e->accept(); } } // namespace Digikam diff --git a/core/utilities/assistants/webservices/smugmug/smugwindow.cpp b/core/utilities/assistants/webservices/smugmug/smugwindow.cpp index 23deb5d74c..4f64e3b895 100644 --- a/core/utilities/assistants/webservices/smugmug/smugwindow.cpp +++ b/core/utilities/assistants/webservices/smugmug/smugwindow.cpp @@ -1,1028 +1,1028 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2005-17-06 * Description : a tool to export images to Smugmug web service * * Copyright (C) 2005-2008 by Vardhman Jain * Copyright (C) 2008-2019 by Gilles Caulier * Copyright (C) 2008-2009 by Luka Renko * * 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 "smugwindow.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include #include #include // Local includes #include "digikam_debug.h" #include "ditemslist.h" #include "wstoolutils.h" #include "digikam_version.h" #include "dprogresswdg.h" #include "dmetadata.h" #include "previewloadthread.h" #include "smugitem.h" #include "smugtalker.h" #include "smugwidget.h" #include "smugnewalbumdlg.h" namespace Digikam { class Q_DECL_HIDDEN SmugWindow::Private { public: explicit Private() { import = false; imagesCount = 0; imagesTotal = 0; anonymousImport = false; currentAlbumID = 0; currentTmplID = 0; currentCategoryID = 0; loginDlg = 0; talker = 0; widget = 0; albumDlg = 0; iface = 0; } bool import; unsigned int imagesCount; unsigned int imagesTotal; QString tmpDir; QString tmpPath; bool anonymousImport; QString anonymousNick; QString email; QString password; qint64 currentAlbumID; QString currentAlbumKey; qint64 currentTmplID; qint64 currentCategoryID; WSLoginDialog* loginDlg; QList transferQueue; SmugTalker* talker; SmugWidget* widget; SmugNewAlbumDlg* albumDlg; DInfoInterface* iface; }; SmugWindow::SmugWindow(DInfoInterface* const iface, QWidget* const /*parent*/, bool import, QString /*nickName*/) : WSToolDialog(0), d(new Private) { d->tmpPath.clear(); d->tmpDir = WSToolUtils::makeTemporaryDir("smug").absolutePath() + QLatin1Char('/');; d->import = import; d->iface = iface; d->widget = new SmugWidget(this, iface, import); setMainWidget(d->widget); setModal(false); if (import) { setWindowTitle(i18n("Import from SmugMug Web Service")); startButton()->setText(i18n("Start Download")); startButton()->setToolTip(i18n("Start download from SmugMug web service")); d->widget->setMinimumSize(300, 400); } else { setWindowTitle(i18n("Export to SmugMug Web Service")); startButton()->setText(i18n("Start Upload")); startButton()->setToolTip(i18n("Start upload to SmugMug web service")); d->widget->setMinimumSize(700, 500); } connect(d->widget, SIGNAL(signalUserChangeRequest(bool)), this, SLOT(slotUserChangeRequest(bool)) ); connect(d->widget->m_imgList, SIGNAL(signalImageListChanged()), this, SLOT(slotImageListChanged()) ); connect(d->widget->m_reloadAlbumsBtn, SIGNAL(clicked()), this, SLOT(slotReloadAlbumsRequest()) ); connect(d->widget->m_newAlbumBtn, SIGNAL(clicked()), this, SLOT(slotNewAlbumRequest()) ); connect(startButton(), &QPushButton::clicked, this, &SmugWindow::slotStartTransfer); connect(this, &WSToolDialog::cancelClicked, this, &SmugWindow::slotCancelClicked); connect(this, &QDialog::finished, this, &SmugWindow::slotDialogFinished); // ------------------------------------------------------------------------ /** * This is deprecated because we know use O2 to login * * if (nickName.isEmpty()) * { * d->loginDlg = new WSLoginDialog(this, * i18n("Enter the email address and password for your " * "SmugMug account")); * } */ // ------------------------------------------------------------------------ d->albumDlg = new SmugNewAlbumDlg(this); /** * Categories are deprecated * * connect(d->albumDlg->categoryCombo(), SIGNAL(currentIndexChanged(int)), * this, SLOT(slotCategorySelectionChanged(int)) ); * connect(d->albumDlg->templateCombo(), SIGNAL(currentIndexChanged(int)), * this, SLOT(slotTemplateSelectionChanged(int)) ); */ // ------------------------------------------------------------------------ d->talker = new SmugTalker(d->iface, this); connect(d->talker, SIGNAL(signalBusy(bool)), this, SLOT(slotBusy(bool))); connect(d->talker, SIGNAL(signalLoginProgress(int,int,QString)), this, SLOT(slotLoginProgress(int,int,QString))); connect(d->talker, SIGNAL(signalLoginDone(int,QString)), this, SLOT(slotLoginDone(int,QString))); connect(d->talker, SIGNAL(signalAddPhotoDone(int,QString)), this, SLOT(slotAddPhotoDone(int,QString))); connect(d->talker, SIGNAL(signalGetPhotoDone(int,QString,QByteArray)), this, SLOT(slotGetPhotoDone(int,QString,QByteArray))); connect(d->talker, SIGNAL(signalCreateAlbumDone(int,QString,qint64,QString)), this, SLOT(slotCreateAlbumDone(int,QString,qint64,QString))); connect(d->talker, SIGNAL(signalListAlbumsDone(int,QString,QList)), this, SLOT(slotListAlbumsDone(int,QString,QList))); connect(d->talker, SIGNAL(signalListPhotosDone(int,QString,QList)), this, SLOT(slotListPhotosDone(int,QString,QList))); connect(d->talker, SIGNAL(signalListAlbumTmplDone(int,QString,QList)), this, SLOT(slotListAlbumTmplDone(int,QString,QList))); /** * Categories deprecated in API v2 * connect(d->talker, SIGNAL(signalListCategoriesDone(int,QString,QList)), * this, SLOT(slotListCategoriesDone(int,QString,QList))); * connect(d->talker, SIGNAL(signalListSubCategoriesDone(int,QString,QList)), * this, SLOT(slotListSubCategoriesDone(int,QString,QList))); */ connect(d->widget->progressBar(), SIGNAL(signalProgressCanceled()), this, SLOT(slotStopAndCloseProgressBar())); // ------------------------------------------------------------------------ readSettings(); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Calling Login method"; buttonStateChange(d->talker->loggedIn()); authenticate(); // if(!nickName.isEmpty()) // { // qCDebug(DIGIKAM_WEBSERVICES_LOG) << "login with nickname"; // authenticateWithNickName(nickName); // } // else // { // if (d->import) // { // // if no e-mail, switch to anonymous login // if (d->anonymousImport || d->email.isEmpty()) // { // d->anonymousImport = true; // authenticate(); // } // else // { // authenticate(d->email, d->password); // } // // d->widget->setAnonymous(d->anonymousImport); // } // else // { // // export cannot login anonymously: pop-up login window` // if (d->email.isEmpty()) // slotUserChangeRequest(false); // else // authenticate(d->email, d->password); // } // } } SmugWindow::~SmugWindow() { WSToolUtils::removeTemporaryDir("smug"); delete d->talker; delete d; } void SmugWindow::closeEvent(QCloseEvent* e) { if (!e) { return; } slotDialogFinished(); e->accept(); } void SmugWindow::slotDialogFinished() { slotCancelClicked(); /** * We should not logout without user consent * * if (d->talker->loggedIn()) * d->talker->logout(); */ writeSettings(); d->widget->imagesList()->listView()->clear(); } void SmugWindow::setUiInProgressState(bool inProgress) { setRejectButtonMode(inProgress ? QDialogButtonBox::Cancel : QDialogButtonBox::Close); if (inProgress) { d->widget->progressBar()->show(); } else { d->widget->progressBar()->hide(); d->widget->progressBar()->progressCompleted(); } } void SmugWindow::slotCancelClicked() { d->talker->cancel(); d->transferQueue.clear(); d->widget->m_imgList->cancelProcess(); setUiInProgressState(false); } void SmugWindow::slotStopAndCloseProgressBar() { slotCancelClicked(); writeSettings(); d->widget->imagesList()->listView()->clear(); reject(); } void SmugWindow::reactivate() { d->widget->imagesList()->loadImagesFromCurrentSelection(); show(); } void SmugWindow::authenticate() { setUiInProgressState(true); d->widget->progressBar()->setFormat(QString()); d->talker->login(); } void SmugWindow::readSettings() { KConfig config; KConfigGroup grp = config.group("Smug Settings"); d->anonymousImport = grp.readEntry("AnonymousImport", true); d->email = grp.readEntry("Email"); d->password = grp.readEntry("Password"); d->currentAlbumID = grp.readEntry("Current Album", -1); d->currentAlbumKey = grp.readEntry("Current Key", -1); if (grp.readEntry("Resize", false)) { d->widget->m_resizeChB->setChecked(true); d->widget->m_dimensionSpB->setEnabled(true); d->widget->m_imageQualitySpB->setEnabled(true); } else { d->widget->m_resizeChB->setChecked(false); d->widget->m_dimensionSpB->setEnabled(false); d->widget->m_imageQualitySpB->setEnabled(false); } d->widget->m_dimensionSpB->setValue(grp.readEntry("Maximum Width", 1600)); d->widget->m_imageQualitySpB->setValue(grp.readEntry("Image Quality", 85)); if (d->import) { winId(); KConfigGroup dialogGroup = config.group("Smug Import Dialog"); KWindowConfig::restoreWindowSize(windowHandle(), dialogGroup); resize(windowHandle()->size()); } else { winId(); KConfigGroup dialogGroup = config.group("Smug Export Dialog"); KWindowConfig::restoreWindowSize(windowHandle(), dialogGroup); resize(windowHandle()->size()); } } void SmugWindow::writeSettings() { KConfig config; KConfigGroup grp = config.group("Smug Settings"); grp.writeEntry("AnonymousImport", d->anonymousImport); grp.writeEntry("Email", d->email); grp.writeEntry("Password", d->password); grp.writeEntry("Current Album", d->currentAlbumID); grp.writeEntry("Current Key", d->currentAlbumKey); grp.writeEntry("Resize", d->widget->m_resizeChB->isChecked()); grp.writeEntry("Maximum Width", d->widget->m_dimensionSpB->value()); grp.writeEntry("Image Quality", d->widget->m_imageQualitySpB->value()); if (d->import) { KConfigGroup dialogGroup = config.group("Smug Import Dialog"); KWindowConfig::saveWindowSize(windowHandle(), dialogGroup); } else { KConfigGroup dialogGroup = config.group("Smug Export Dialog"); KWindowConfig::saveWindowSize(windowHandle(), dialogGroup); } config.sync(); } void SmugWindow::slotLoginProgress(int step, int maxStep, const QString &label) { DProgressWdg* progressBar = d->widget->progressBar(); if (!label.isEmpty()) progressBar->setFormat(label); if (maxStep > 0) progressBar->setMaximum(maxStep); progressBar->setValue(step); } void SmugWindow::slotLoginDone(int errCode, const QString &errMsg) { setUiInProgressState(false); buttonStateChange(d->talker->loggedIn()); SmugUser user = d->talker->getUser(); d->widget->updateLabels(user.email, user.displayName, user.nickName); d->widget->m_albumsCoB->clear(); if (errCode == 0 && d->talker->loggedIn()) { if (d->import) { d->anonymousImport = d->widget->isAnonymous(); // anonymous: list albums after login only if nick is not empty QString nick = d->widget->getNickName(); if (!nick.isEmpty() || !d->anonymousImport) { d->talker->listAlbums(nick); } } else { // get albums from current user d->talker->listAlbums(); } } else { QMessageBox::critical(QApplication::activeWindow(), i18n("Error"), i18n("SmugMug Call Failed: %1\n", errMsg)); } } void SmugWindow::slotListAlbumsDone(int errCode, const QString &errMsg, const QList & albumsList) { if (errCode != 0) { QMessageBox::critical(QApplication::activeWindow(), i18n("Error"), i18n("SmugMug Call Failed: %1\n", errMsg)); return; } d->widget->m_albumsCoB->clear(); for (int i = 0; i < albumsList.size(); ++i) { QString albumIcon; if (!albumsList.at(i).password.isEmpty()) albumIcon = QLatin1String("folder-locked"); else if (albumsList.at(i).isPublic) albumIcon = QLatin1String("folder-image"); else albumIcon = QLatin1String("folder"); QString data = QString::fromLatin1("%1:%2").arg(albumsList.at(i).id).arg(albumsList.at(i).key); d->widget->m_albumsCoB->addItem(QIcon::fromTheme(albumIcon), albumsList.at(i).title, data); if (d->currentAlbumID == albumsList.at(i).id) d->widget->m_albumsCoB->setCurrentIndex(i); } } void SmugWindow::slotListPhotosDone(int errCode, const QString &errMsg, const QList & photosList) { if (errCode != 0) { QMessageBox::critical(QApplication::activeWindow(), i18n("Error"), i18n("SmugMug Call Failed: %1\n", errMsg)); return; } d->transferQueue.clear(); for (int i = 0; i < photosList.size(); ++i) { d->transferQueue.append(photosList.at(i).originalURL); } if (d->transferQueue.isEmpty()) return; d->imagesTotal = d->transferQueue.count(); d->imagesCount = 0; d->widget->progressBar()->setMaximum(d->imagesTotal); d->widget->progressBar()->setValue(0); // start download with first photo in queue downloadNextPhoto(); } void SmugWindow::slotListAlbumTmplDone(int errCode, const QString &errMsg, const QList & albumTList) { // always put at least default subcategory d->albumDlg->templateCombo()->clear(); d->albumDlg->templateCombo()->addItem(i18n("<none>"), 0); if (errCode != 0) { QMessageBox::critical(QApplication::activeWindow(), i18n("Error"), i18n("SmugMug Call Failed: %1\n", errMsg)); return; } for (int i = 0; i < albumTList.size(); ++i) { QString albumIcon; if (!albumTList.at(i).password.isEmpty()) albumIcon = QLatin1String("folder-locked"); else if (albumTList.at(i).isPublic) albumIcon = QLatin1String("folder-image"); else albumIcon = QLatin1String("folder"); d->albumDlg->templateCombo()->addItem(QIcon::fromTheme(albumIcon), albumTList.at(i).name, albumTList.at(i).id); if (d->currentTmplID == albumTList.at(i).id) d->albumDlg->templateCombo()->setCurrentIndex(i+1); } d->currentTmplID = d->albumDlg->templateCombo()->itemData(d->albumDlg->templateCombo()->currentIndex()).toLongLong(); // now fill in categories /** * Categories now are deprecated in API v2 * d->talker->listCategories(); */ } /** * Categories now are deprecated in API v2 * void SmugWindow::slotListCategoriesDone(int errCode, const QString& errMsg, const QList & categoriesList) { if (errCode != 0) { QMessageBox::critical(QApplication::activeWindow(), i18n("Error"), i18n("SmugMug Call Failed: %1\n", errMsg)); return; } d->albumDlg->categoryCombo()->clear(); for (int i = 0; i < categoriesList.size(); ++i) { d->albumDlg->categoryCombo()->addItem( categoriesList.at(i).name, categoriesList.at(i).id); if (d->currentCategoryID == categoriesList.at(i).id) d->albumDlg->categoryCombo()->setCurrentIndex(i); } d->currentCategoryID = d->albumDlg->categoryCombo()->itemData( d->albumDlg->categoryCombo()->currentIndex()).toLongLong(); d->talker->listSubCategories(d->currentCategoryID); } void SmugWindow::slotListSubCategoriesDone(int errCode, const QString &errMsg, const QList & categoriesList) { // always put at least default subcategory d->albumDlg->subCategoryCombo()->clear(); d->albumDlg->subCategoryCombo()->addItem(i18n("<none>"), 0); if (errCode != 0) { QMessageBox::critical(QApplication::activeWindow(), i18n("Error"), i18n("SmugMug Call Failed: %1\n", errMsg)); return; } for (int i = 0; i < categoriesList.size(); ++i) { d->albumDlg->subCategoryCombo()->addItem( categoriesList.at(i).name, categoriesList.at(i).id); } } */ void SmugWindow::slotTemplateSelectionChanged(int index) { if (index < 0) return; d->currentTmplID = d->albumDlg->templateCombo()->itemData(index).toLongLong(); // if template is selected, then disable Security & Privacy d->albumDlg->privateGroupBox()->setEnabled(d->currentTmplID == 0); } /** * Categories now are deprecated in API v2 * void SmugWindow::slotCategorySelectionChanged(int index) { if (index < 0) return; // subcategories are per category -> reload d->currentCategoryID = d->albumDlg->categoryCombo()->itemData(index).toLongLong(); d->talker->listSubCategories(d->currentCategoryID); } */ void SmugWindow::buttonStateChange(bool state) { d->widget->m_newAlbumBtn->setEnabled(state); d->widget->m_reloadAlbumsBtn->setEnabled(state); startButton()->setEnabled(state); } void SmugWindow::slotBusy(bool val) { if (val) { setCursor(Qt::WaitCursor); d->widget->m_changeUserBtn->setEnabled(false); buttonStateChange(false); } else { setCursor(Qt::ArrowCursor); d->widget->m_changeUserBtn->setEnabled(!d->widget->isAnonymous()); buttonStateChange(d->talker->loggedIn()); } } void SmugWindow::slotUserChangeRequest(bool /*anonymous*/) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Slot Change User Request"; QPointer warn = new QMessageBox(QMessageBox::Warning, i18n("Warning"), i18n("You will be logged out of your account, " "click \"Continue\" to authenticate for another account."), QMessageBox::Yes | QMessageBox::No); (warn->button(QMessageBox::Yes))->setText(i18n("Continue")); (warn->button(QMessageBox::No))->setText(i18n("Cancel")); if (warn->exec() == QMessageBox::Yes) { // Unlink user account and wait active until really logged out d->talker->logout(); while(d->talker->loggedIn()); // Re-login authenticate(); } delete warn; /* if (anonymous) { authenticate(); } else { // fill in current email and password d->loginDlg->setLogin(d->email); d->loginDlg->setPassword(d->password); if (d->loginDlg->exec()) { d->email = d->loginDlg->login(); d->password = d->loginDlg->password(); authenticate(d->email, d->password); } } */ } void SmugWindow::slotReloadAlbumsRequest() { if (d->import) { d->talker->listAlbums(d->widget->getNickName()); } else { // get albums for current user d->talker->listAlbums(); } } void SmugWindow::slotNewAlbumRequest() { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Slot New Album Request"; // get list of album templates from SmugMug to fill in dialog d->talker->listAlbumTmpl(); if (d->albumDlg->exec() == QDialog::Accepted) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Calling New Album method"; d->currentTmplID = d->albumDlg->templateCombo()->itemData( d->albumDlg->templateCombo()->currentIndex()).toLongLong(); /** * Categories are deprecated * * d->currentCategoryID = d->albumDlg->categoryCombo()->itemData( * d->albumDlg->categoryCombo()->currentIndex()).toLongLong(); */ SmugAlbum newAlbum; d->albumDlg->getAlbumProperties(newAlbum); d->talker->createAlbum(newAlbum); } } void SmugWindow::slotStartTransfer() { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "slotStartTransfer invoked"; if (d->import) { d->widget->progressBar()->setFormat(i18n("%v / %m")); d->widget->progressBar()->setMaximum(0); d->widget->progressBar()->setValue(0); d->widget->progressBar()->progressScheduled(i18n("SmugMug Import"), true, true); d->widget->progressBar()->progressThumbnailChanged( - QIcon(QLatin1String("smugmug")).pixmap(22, 22)); + QIcon(QLatin1String("dk-smugmug")).pixmap(22, 22)); setUiInProgressState(true); // list photos of the album, then start download QString dataStr = d->widget->m_albumsCoB->itemData(d->widget->m_albumsCoB->currentIndex()).toString(); int colonIdx = dataStr.indexOf(QLatin1Char(':')); qint64 albumID = dataStr.left(colonIdx).toLongLong(); QString albumKey = dataStr.right(dataStr.length() - colonIdx - 1); d->talker->listPhotos(albumID, albumKey, d->widget->getAlbumPassword(), d->widget->getSitePassword()); } else { d->widget->m_imgList->clearProcessedStatus(); d->transferQueue = d->widget->m_imgList->imageUrls(); if (d->transferQueue.isEmpty()) return; QString data = d->widget->m_albumsCoB->itemData(d->widget->m_albumsCoB->currentIndex()).toString(); int colonIdx = data.indexOf(QLatin1Char(':')); d->currentAlbumID = data.left(colonIdx).toLongLong(); d->currentAlbumKey = data.right(data.length() - colonIdx - 1); d->imagesTotal = d->transferQueue.count(); d->imagesCount = 0; d->widget->progressBar()->setFormat(i18n("%v / %m")); d->widget->progressBar()->setMaximum(d->imagesTotal); d->widget->progressBar()->setValue(0); d->widget->progressBar()->progressScheduled(i18n("SmugMug Export"), true, true); - d->widget->progressBar()->progressThumbnailChanged(QIcon(QLatin1String("smugmug")).pixmap(22, 22)); + d->widget->progressBar()->progressThumbnailChanged(QIcon(QLatin1String("dk-smugmug")).pixmap(22, 22)); setUiInProgressState(true); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "d->currentAlbumID" << d->currentAlbumID; uploadNextPhoto(); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "slotStartTransfer done"; } } bool SmugWindow::prepareImageForUpload(const QString& imgPath) const { QImage image = PreviewLoadThread::loadHighQualitySynchronously(imgPath).copyQImage(); if (image.isNull()) { image.load(imgPath); } if (image.isNull()) { return false; } // get temporary file name d->tmpPath = d->tmpDir + QFileInfo(imgPath).baseName().trimmed() + QLatin1String(".jpg"); // rescale image if requested int maxDim = d->widget->m_dimensionSpB->value(); if (d->widget->m_resizeChB->isChecked() && (image.width() > maxDim || image.height() > maxDim)) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Resizing to " << maxDim; image = image.scaled(maxDim, maxDim, Qt::KeepAspectRatio, Qt::SmoothTransformation); } qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Saving to temp file: " << d->tmpPath; image.save(d->tmpPath, "JPEG", d->widget->m_imageQualitySpB->value()); // copy meta-data to temporary image DMetadata meta; if (meta.load(imgPath)) { meta.setItemDimensions(image.size()); meta.setItemOrientation(MetaEngine::ORIENTATION_NORMAL); meta.setMetadataWritingMode((int)DMetadata::WRITE_TO_FILE_ONLY); meta.save(d->tmpPath, true); } return true; } void SmugWindow::uploadNextPhoto() { if (d->transferQueue.isEmpty()) { setUiInProgressState(false); return; } d->widget->m_imgList->processing(d->transferQueue.first()); QUrl imgPath = d->transferQueue.first(); DItemInfo info(d->iface->itemInfo(imgPath)); d->widget->progressBar()->setMaximum(d->imagesTotal); d->widget->progressBar()->setValue(d->imagesCount); bool res; if (d->widget->m_resizeChB->isChecked()) { if (!prepareImageForUpload(imgPath.toLocalFile())) { slotAddPhotoDone(666, i18n("Cannot open file")); return; } res = d->talker->addPhoto(d->tmpPath, d->currentAlbumID, d->currentAlbumKey, info.comment()); } else { d->tmpPath.clear(); res = d->talker->addPhoto(imgPath.toLocalFile(), d->currentAlbumID, d->currentAlbumKey, info.comment()); } if (!res) { slotAddPhotoDone(666, i18n("Cannot open file")); return; } } void SmugWindow::slotAddPhotoDone(int errCode, const QString& errMsg) { // Remove temporary file if it was used if (!d->tmpPath.isEmpty()) { QFile::remove(d->tmpPath); d->tmpPath.clear(); } d->widget->m_imgList->processed(d->transferQueue.first(), (errCode == 0)); if (errCode == 0) { d->transferQueue.removeFirst(); d->imagesCount++; } else { if (QMessageBox::question(this, i18n("Uploading Failed"), i18n("Failed to upload photo to SmugMug." "\n%1\n" "Do you want to continue?", errMsg)) != QMessageBox::Yes) { setUiInProgressState(false); d->transferQueue.clear(); return; } } uploadNextPhoto(); } void SmugWindow::downloadNextPhoto() { if (d->transferQueue.isEmpty()) { setUiInProgressState(false); return; } d->widget->progressBar()->setMaximum(d->imagesTotal); d->widget->progressBar()->setValue(d->imagesCount); QString imgPath = d->transferQueue.first().url(); d->talker->getPhoto(imgPath); } void SmugWindow::slotGetPhotoDone(int errCode, const QString& errMsg, const QByteArray& photoData) { QString imgPath = d->widget->getDestinationPath() + QLatin1Char('/') + d->transferQueue.first().fileName(); qCDebug(DIGIKAM_WEBSERVICES_LOG) << imgPath; if (errCode == 0) { QString errText; QFile imgFile(imgPath); if (!imgFile.open(QIODevice::WriteOnly)) { errText = imgFile.errorString(); } else if (imgFile.write(photoData) != photoData.size()) { errText = imgFile.errorString(); } else { imgFile.close(); } if (errText.isEmpty()) { d->transferQueue.removeFirst(); d->imagesCount++; } else { if (QMessageBox::question(this, i18n("Processing Failed"), i18n("Failed to save photo: %1\n" "Do you want to continue?", errText)) != QMessageBox::Yes) { d->transferQueue.clear(); setUiInProgressState(false); return; } } } else { if (QMessageBox::question(this, i18n("Processing Failed"), i18n("Failed to download photo: %1\n" "Do you want to continue?", errMsg)) != QMessageBox::Yes) { d->transferQueue.clear(); setUiInProgressState(false); return; } } downloadNextPhoto(); } void SmugWindow::slotCreateAlbumDone(int errCode, const QString& errMsg, qint64 newAlbumID, const QString& newAlbumKey) { if (errCode != 0) { QMessageBox::critical(QApplication::activeWindow(), i18n("Error"), i18n("SmugMug Call Failed: %1\n", errMsg)); return; } // reload album list and automatically select new album d->currentAlbumID = newAlbumID; d->currentAlbumKey = newAlbumKey; d->talker->listAlbums(); } void SmugWindow::slotImageListChanged() { startButton()->setEnabled(!(d->widget->m_imgList->imageUrls().isEmpty())); } } // namespace Digikam