diff --git a/core/app/main/digikamapp_export.cpp b/core/app/main/digikamapp_export.cpp index de032ac050..069747b0b5 100644 --- a/core/app/main/digikamapp_export.cpp +++ b/core/app/main/digikamapp_export.cpp @@ -1,202 +1,208 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2002-16-10 * Description : main digiKam interface implementation - Export tools * * Copyright (C) 2002-2018 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "digikamapp.h" #include "digikamapp_p.h" namespace Digikam { void DigikamApp::slotExpoBlending() { ExpoBlendingManager::instance()->checkBinaries(); ExpoBlendingManager::instance()->setItemsList(view()->selectedUrls(ApplicationSettings::Tools)); ExpoBlendingManager::instance()->run(); } void DigikamApp::slotPanorama() { #ifdef HAVE_PANORAMA PanoManager::instance()->checkBinaries(); PanoManager::instance()->setItemsList(view()->selectedUrls(ApplicationSettings::Tools)); PanoManager::instance()->run(); #endif } void DigikamApp::slotVideoSlideshow() { #ifdef HAVE_MEDIAPLAYER QPointer w = new VidSlideWizard(this, new DBInfoIface(this, QList(), ApplicationSettings::Tools)); w->exec(); delete w; #endif } void DigikamApp::slotSendByMail() { QPointer w = new MailWizard(this, new DBInfoIface(this, QList(), ApplicationSettings::Tools)); w->exec(); delete w; } void DigikamApp::slotPrintCreator() { QPointer w = new AdvPrintWizard(this, new DBInfoIface(this, QList(), ApplicationSettings::Tools)); w->exec(); delete w; } void DigikamApp::slotHtmlGallery() { #ifdef HAVE_HTMLGALLERY QPointer w = new HTMLWizard(this, new DBInfoIface(this, QList(), ApplicationSettings::Tools)); w->exec(); delete w; #endif } void DigikamApp::slotCalendar() { QPointer w = new CalWizard(view()->selectedUrls(ApplicationSettings::Tools), this); w->exec(); delete w; } void DigikamApp::slotPresentation() { d->view->presentation(); } void DigikamApp::slotMediaServer() { DBInfoIface* const iface = new DBInfoIface(this, QList(), ApplicationSettings::Tools); // NOTE: We overwrite the default albums chooser object name for load save check items state between sessions. // The goal is not mix these settings with other export tools. iface->setObjectName(QLatin1String("SetupMediaServerIface")); QPointer w = new DMediaServerDlg(this, iface); w->exec(); delete w; } void DigikamApp::slotExportTool() { QAction* const tool = dynamic_cast(sender()); if (tool == m_exportDropboxAction) { QPointer w = new DBWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } + else if (tool == m_exportOnedriveAction) + { + QPointer w = new ODWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this); + w->exec(); + delete w; + } else if (tool == m_exportFacebookAction) { QPointer w = new FbWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportFlickrAction) { QPointer w = new FlickrWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportGdriveAction) { QPointer w = new GSWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this, QLatin1String("googledriveexport")); w->exec(); delete w; } else if (tool == m_exportGphotoAction) { QPointer w = new GSWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this, QLatin1String("googlephotoexport")); w->exec(); delete w; } else if (tool == m_exportImageshackAction) { QPointer w = new ImageShackWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportImgurAction) { QPointer w = new ImgurWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportPiwigoAction) { QPointer w = new PiwigoWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportRajceAction) { QPointer w = new RajceWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportSmugmugAction) { QPointer w = new SmugWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportYandexfotkiAction) { QPointer w = new YFWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } #ifdef HAVE_MEDIAWIKI else if (tool == m_exportMediawikiAction) { QPointer w = new MediaWikiWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } #endif #ifdef HAVE_VKONTAKTE else if (tool == m_exportVkontakteAction) { QPointer w = new VKWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } #endif #ifdef HAVE_KIO else if (tool == m_exportFileTransferAction) { QPointer w = new FTExportWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } #endif } } // namespace Digikam diff --git a/core/app/main/digikamapp_p.h b/core/app/main/digikamapp_p.h index 724fadb66e..a3dc9b9cb9 100644 --- a/core/app/main/digikamapp_p.h +++ b/core/app/main/digikamapp_p.h @@ -1,461 +1,462 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2007-31-01 * Description : main digiKam interface implementation * * Copyright (C) 2007-2018 by Gilles Caulier * Copyright (C) 2014 by Mohamed_Anwer * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_APP_PRIVATE_H #define DIGIKAM_APP_PRIVATE_H // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include #include #include #include #include #include // Local includes #include "digikam_config.h" #include "digikam_debug.h" #include "albummanager.h" #include "applicationsettings.h" #include "cameralist.h" #include "cameratype.h" #include "cameranamehelper.h" #include "dsplashscreen.h" #include "dzoombar.h" #include "digikamview.h" #include "metadatastatusbar.h" #include "imagepropertiestab.h" #include "importui.h" #include "setup.h" #include "actioncategorizedview.h" #include "drawdecoder.h" #include "dlayoutbox.h" #include "album.h" #include "coredb.h" #include "albummodel.h" #include "albumselectdialog.h" #include "albumthumbnailloader.h" #include "dbinfoiface.h" #include "imagegps.h" #include "categorizeditemmodel.h" #include "collectionscanner.h" #include "collectionmanager.h" #include "componentsinfo.h" #include "coredbthumbinfoprovider.h" #include "dio.h" #include "dlogoaction.h" #include "fileactionmngr.h" #include "filterstatusbar.h" #include "iccsettings.h" #include "imageattributeswatch.h" #include "imageinfo.h" #include "imagewindow.h" #include "lighttablewindow.h" #include "queuemgrwindow.h" #include "loadingcache.h" #include "loadingcacheinterface.h" #include "loadsavethread.h" #include "metaengine_rotation.h" #include "scancontroller.h" #include "setupeditor.h" #include "setupicc.h" #include "thememanager.h" #include "thumbnailloadthread.h" #include "thumbnailsize.h" #include "dmetadata.h" #include "tagscache.h" #include "tagsactionmngr.h" #include "databaseserverstarter.h" #include "metadatasettings.h" #include "statusbarprogresswidget.h" #include "dbmigrationdlg.h" #include "progressmanager.h" #include "progressview.h" #include "maintenancedlg.h" #include "maintenancemngr.h" #include "newitemsfinder.h" #include "dbcleaner.h" #include "tagsmanager.h" #include "imagesortsettings.h" #include "metadatahubmngr.h" #include "metadataedit.h" #include "expoblendingmanager.h" #include "calwizard.h" #include "mailwizard.h" #include "advprintwizard.h" #include "dfiledialog.h" #include "dmediaservermngr.h" #include "dmediaserverdlg.h" #include "dbwindow.h" +#include "odwindow.h" #include "fbwindow.h" #include "flickrwindow.h" #include "gswindow.h" #include "imageshackwindow.h" #include "imgurwindow.h" #include "piwigowindow.h" #include "rajcewindow.h" #include "smugwindow.h" #include "yfwindow.h" #ifdef HAVE_MEDIAWIKI # include "mediawikiwindow.h" #endif #ifdef HAVE_VKONTAKTE # include "vkwindow.h" #endif #ifdef HAVE_KIO # include "ftexportwindow.h" # include "ftimportwindow.h" #endif #ifdef HAVE_MARBLE # include "geolocationedit.h" #endif #ifdef HAVE_HTMLGALLERY # include "htmlwizard.h" #endif #ifdef HAVE_DBUS # include "digikamadaptor.h" #endif #ifdef HAVE_PANORAMA # include "panomanager.h" #endif #ifdef HAVE_MEDIAPLAYER # include "vidslidewizard.h" #endif #ifdef HAVE_KFILEMETADATA # include "baloowrap.h" #endif class KToolBarPopupAction; namespace Digikam { class SearchTextBar; class FilterStatusBar; class TagsActionMngr; class DAdjustableLabel; class ProgressEntry { public: explicit ProgressEntry() : progress(0), canCancel(false) { } QString message; float progress; bool canCancel; }; // ------------------------------------------------------------------------------ class DigikamApp::Private { public: explicit Private() : autoShowZoomToolTip(false), validIccPath(true), cameraMenu(0), usbMediaMenu(0), cardReaderMenu(0), quickImportMenu(0), config(0), newAction(0), moveSelectionToAlbumAction(0), deleteAction(0), renameAction(0), imageDeletePermanentlyAction(0), imageDeletePermanentlyDirectlyAction(0), imageTrashDirectlyAction(0), backwardActionMenu(0), forwardActionMenu(0), addImagesAction(0), propsEditAction(0), addFoldersAction(0), openInFileManagerAction(0), refreshAction(0), writeAlbumMetadataAction(0), readAlbumMetadataAction(0), browseTagsAction(0), openTagMngrAction(0), newTagAction(0), deleteTagAction(0), editTagAction(0), assignTagAction(0), imageViewSelectionAction(0), imagePreviewAction(0), #ifdef HAVE_MARBLE imageMapViewAction(0), #endif // HAVE_MARBLE imageTableViewAction(0), imageIconViewAction(0), imageLightTableAction(0), imageAddLightTableAction(0), imageAddCurrentQueueAction(0), imageAddNewQueueAction(0), imageViewAction(0), imageWriteMetadataAction(0), imageReadMetadataAction(0), imageFindSimilarAction(0), imageSetExifOrientation1Action(0), imageSetExifOrientation2Action(0), imageSetExifOrientation3Action(0), imageSetExifOrientation4Action(0), imageSetExifOrientation5Action(0), imageSetExifOrientation6Action(0), imageSetExifOrientation7Action(0), imageSetExifOrientation8Action(0), imageRenameAction(0), imageRotateActionMenu(0), imageFlipActionMenu(0), imageAutoExifActionMenu(0), imageDeleteAction(0), imageExifOrientationActionMenu(0), openWithAction(0), ieAction(0), ltAction(0), cutItemsAction(0), copyItemsAction(0), pasteItemsAction(0), selectAllAction(0), selectNoneAction(0), selectInvertAction(0), zoomPlusAction(0), zoomMinusAction(0), zoomFitToWindowAction(0), zoomTo100percents(0), imageSortAction(0), imageSortOrderAction(0), imageSeparationAction(0), imageSeparationSortOrderAction(0), albumSortAction(0), recurseAlbumsAction(0), recurseTagsAction(0), showBarAction(0), viewCMViewAction(0), slideShowAction(0), slideShowAllAction(0), slideShowSelectionAction(0), slideShowRecursiveAction(0), bqmAction(0), maintenanceAction(0), qualityAction(0), advSearchAction(0), addCameraSeparatorAction(0), quitAction(0), tipAction(0), backwardSignalMapper(0), forwardSignalMapper(0), manualCameraActionGroup(0), solidCameraActionGroup(0), solidUsmActionGroup(0), exifOrientationActionGroup(0), eventLoop(0), metadataStatusBar(0), filterStatusBar(0), splashScreen(0), view(0), cameraList(0), tagsActionManager(0), zoomBar(0), statusLabel(0), modelCollection(0) { } bool autoShowZoomToolTip; bool validIccPath; QMenu* cameraMenu; QMenu* usbMediaMenu; QMenu* cardReaderMenu; QMenu* quickImportMenu; QHash cameraAppearanceTimes; KSharedConfig::Ptr config; // Album Actions QAction* newAction; QAction* moveSelectionToAlbumAction; QAction* deleteAction; QAction* renameAction; QAction* imageDeletePermanentlyAction; QAction* imageDeletePermanentlyDirectlyAction; QAction* imageTrashDirectlyAction; KToolBarPopupAction* backwardActionMenu; KToolBarPopupAction* forwardActionMenu; QAction* addImagesAction; QAction* propsEditAction; QAction* addFoldersAction; QAction* openInFileManagerAction; QAction* refreshAction; QAction* writeAlbumMetadataAction; QAction* readAlbumMetadataAction; // Tag Actions QAction* browseTagsAction; QAction* openTagMngrAction; QAction* newTagAction; QAction* deleteTagAction; QAction* editTagAction; QAction* assignTagAction; // Image Actions KSelectAction* imageViewSelectionAction; QAction* imagePreviewAction; #ifdef HAVE_MARBLE QAction* imageMapViewAction; #endif // HAVE_MARBLE QAction* imageTableViewAction; QAction* imageIconViewAction; QAction* imageLightTableAction; QAction* imageAddLightTableAction; QAction* imageAddCurrentQueueAction; QAction* imageAddNewQueueAction; QAction* imageViewAction; QAction* imageWriteMetadataAction; QAction* imageReadMetadataAction; QAction* imageFindSimilarAction; QAction* imageSetExifOrientation1Action; QAction* imageSetExifOrientation2Action; QAction* imageSetExifOrientation3Action; QAction* imageSetExifOrientation4Action; QAction* imageSetExifOrientation5Action; QAction* imageSetExifOrientation6Action; QAction* imageSetExifOrientation7Action; QAction* imageSetExifOrientation8Action; QAction* imageRenameAction; QMenu* imageRotateActionMenu; QMenu* imageFlipActionMenu; QAction* imageAutoExifActionMenu; QAction* imageDeleteAction; QMenu* imageExifOrientationActionMenu; QAction* openWithAction; QAction* ieAction; QAction* ltAction; // Edit Actions QAction* cutItemsAction; QAction* copyItemsAction; QAction* pasteItemsAction; QAction* selectAllAction; QAction* selectNoneAction; QAction* selectInvertAction; // View Actions QAction* zoomPlusAction; QAction* zoomMinusAction; QAction* zoomFitToWindowAction; QAction* zoomTo100percents; KSelectAction* imageSortAction; KSelectAction* imageSortOrderAction; KSelectAction* imageSeparationAction; KSelectAction* imageSeparationSortOrderAction; KSelectAction* albumSortAction; QAction* recurseAlbumsAction; QAction* recurseTagsAction; QAction* showBarAction; QAction* viewCMViewAction; // Tools Actions QMenu* slideShowAction; QAction* slideShowAllAction; QAction* slideShowSelectionAction; QAction* slideShowRecursiveAction; QAction* bqmAction; QAction* maintenanceAction; QAction* qualityAction; QAction* advSearchAction; // Application Actions QAction* addCameraSeparatorAction; QAction* quitAction; QAction* tipAction; QSignalMapper* backwardSignalMapper; QSignalMapper* forwardSignalMapper; QActionGroup* manualCameraActionGroup; QActionGroup* solidCameraActionGroup; QActionGroup* solidUsmActionGroup; QActionGroup* exifOrientationActionGroup; QMap > cameraUIMap; QEventLoop* eventLoop; QString solidErrorMessage; MetadataStatusBar* metadataStatusBar; FilterStatusBar* filterStatusBar; DSplashScreen* splashScreen; DigikamView* view; CameraList* cameraList; TagsActionMngr* tagsActionManager; DZoomBar* zoomBar; DAdjustableLabel* statusLabel; DigikamModelCollection* modelCollection; }; } // namespace Digikam #endif // DIGIKAM_APP_PRIVATE_H diff --git a/core/libs/widgets/mainview/dxmlguiwindow.cpp b/core/libs/widgets/mainview/dxmlguiwindow.cpp index 0f391d1434..f668c0bcdd 100644 --- a/core/libs/widgets/mainview/dxmlguiwindow.cpp +++ b/core/libs/widgets/mainview/dxmlguiwindow.cpp @@ -1,1224 +1,1234 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2013-04-29 * Description : digiKam XML GUI window * * Copyright (C) 2013-2018 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "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" namespace Digikam { class 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_animLogo = 0; // Export tools m_exportDropboxAction = 0; + m_exportOnedriveAction = 0; m_exportFacebookAction = 0; m_exportFlickrAction = 0; m_exportGdriveAction = 0; m_exportGphotoAction = 0; m_exportImageshackAction = 0; m_exportImgurAction = 0; m_exportPiwigoAction = 0; m_exportRajceAction = 0; m_exportSmugmugAction = 0; m_exportYandexfotkiAction = 0; #ifdef HAVE_MEDIAWIKI m_exportMediawikiAction = 0; #endif #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); KXmlGuiWindow::closeEvent(e); } 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::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 thummbbar 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 thummbbar 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: return KStandardAction::open(recvr, slot, parent); 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(QString::fromLatin1("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"))); + 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_exportFacebookAction = new QAction(i18n("Export to &Facebook..."), this); m_exportFacebookAction->setIcon(QIcon::fromTheme(QString::fromLatin1("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(QString::fromLatin1("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(QString::fromLatin1("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(QString::fromLatin1("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(QString::fromLatin1("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(QString::fromLatin1("imgur"))); actionCollection()->addAction(QLatin1String("export_imgur"), m_exportImgurAction); connect(m_exportImgurAction, SIGNAL(triggered(bool)), this, SLOT(slotExportTool())); m_exportPiwigoAction = new QAction(i18n("Export to &Piwigo..."), this); m_exportPiwigoAction->setIcon(QIcon::fromTheme(QString::fromLatin1("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(QString::fromLatin1("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(QString::fromLatin1("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(QString::fromLatin1("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())); #ifdef HAVE_MEDIAWIKI m_exportMediawikiAction = new QAction(i18n("Export to MediaWiki..."), this); m_exportMediawikiAction->setIcon(QIcon::fromTheme(QString::fromLatin1("mediawiki"))); actionCollection()->addAction(QLatin1String("export_mediawiki"), m_exportMediawikiAction); connect(m_exportMediawikiAction, SIGNAL(triggered(bool)), this, SLOT(slotExportTool())); #endif #ifdef HAVE_VKONTAKTE m_exportVkontakteAction = new QAction(i18n("Export to &VKontakte..."), this); m_exportVkontakteAction->setIcon(QIcon::fromTheme(QString::fromLatin1("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(QString::fromLatin1("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(QString::fromLatin1("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(QString::fromLatin1("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(QString::fromLatin1("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_exportFacebookAction << m_exportFlickrAction << m_exportGdriveAction << m_exportGphotoAction << m_exportImageshackAction << m_exportImgurAction << m_exportPiwigoAction << m_exportRajceAction << m_exportSmugmugAction << m_exportYandexfotkiAction #ifdef HAVE_MEDIAWIKI << m_exportMediawikiAction #endif #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 ; } } // namespace Digikam diff --git a/core/libs/widgets/mainview/dxmlguiwindow.h b/core/libs/widgets/mainview/dxmlguiwindow.h index cfef62521d..07bff1d241 100644 --- a/core/libs/widgets/mainview/dxmlguiwindow.h +++ b/core/libs/widgets/mainview/dxmlguiwindow.h @@ -1,392 +1,393 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2013-04-29 * Description : digiKam XML GUI window * * Copyright (C) 2013-2018 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_DXML_GUI_WINDOW_H #define DIGIKAM_DXML_GUI_WINDOW_H // Qt includes #include #include #include #include // KDE includes #include #include // Local includes #include "digikam_export.h" #include "digikam_config.h" #include "dlogoaction.h" #ifdef HAVE_KSANE # include "ksaneaction.h" #endif class QEvent; class KToolBar; namespace Digikam { /** Optional parts which can be hidden or not from managed window configuration panel */ enum FullScreenOptions { FS_TOOLBARS = 0x00000001, /// Manage Tools bar in full-screen mode. FS_THUMBBAR = 0x00000002, /// Manage Thumb bar in full-screen mode. FS_SIDEBARS = 0x00000004, /// Manage Side bars in full-screen mode. FS_NONE = 0x00000008, /// No full-screen options. FS_ALBUMGUI = FS_TOOLBARS | FS_THUMBBAR | FS_SIDEBARS, /// Album GUI Config. FS_EDITOR = FS_TOOLBARS | FS_THUMBBAR | FS_SIDEBARS, /// Image Editor Config. FS_LIGHTTABLE = FS_TOOLBARS | FS_SIDEBARS, /// Light Table Config. FS_IMPORTUI = FS_TOOLBARS | FS_THUMBBAR | FS_SIDEBARS /// Import UI Config. }; enum StdActionType { StdCopyAction = 0, StdPasteAction, StdCutAction, StdQuitAction, StdCloseAction, StdZoomInAction, StdZoomOutAction, StdOpenAction, StdSaveAction, StdSaveAsAction, StdRevertAction, StdBackAction, StdForwardAction }; static const QString s_configFullScreenHideToolBarsEntry(QLatin1String("FullScreen Hide ToolBars")); static const QString s_configFullScreenHideThumbBarEntry(QLatin1String("FullScreen Hide ThumbBar")); static const QString s_configFullScreenHideSideBarsEntry(QLatin1String("FullScreen Hide SideBars")); /** Data container to use in managed window. */ class DIGIKAM_EXPORT DXmlGuiWindow : public KXmlGuiWindow { Q_OBJECT public: explicit DXmlGuiWindow(QWidget* const parent=0, Qt::WindowFlags f=KDE_DEFAULT_WINDOWFLAGS); ~DXmlGuiWindow(); /** Manage config group name used by window instance to get/set settings from config file */ void setConfigGroupName(const QString& name); QString configGroupName() const; /** List of Webservices export actions */ QList exportActions() const; /** List of Webservices export actions */ QList importActions() const; /** Create Geolocation Edit tool action. */ void createGeolocationEditAction(); /** Create Metadata Edit tool action. */ void createMetadataEditAction(); /** Create Presentation tool action. */ void createPresentationAction(); /** Create Calendar tool action. */ void createCalendarAction(); /** Create Exposure Blending tool action. */ void createExpoBlendingAction(); /** Create Panorama tool action. */ void createPanoramaAction(); /** Create Video Slideshow tool action. */ void createVideoSlideshowAction(); /** Create HTML Gallery tool action. */ void createHtmlGalleryAction(); /** Create Print Creator tool action. */ void createPrintCreatorAction(); /** Create Send by Mail tool action. */ void createSendByMailAction(); /** Create Media Server action to share through DLNA. */ void createMediaServerAction(); /** Create common actions to setup all digiKam main windows. */ void createSettingsActions(); /** Create common actions from Export menu for all digiKam main windows. */ void createExportActions(); /** Create common actions from Import menu for all digiKam main windows. */ void createImportActions(); /** Create common actions from Help menu for all digiKam main windows. */ void createHelpActions(bool coreOptions=true); /** Cleanup unwanted actions from action collection. */ void cleanupActions(); /** Create common actions to handle side-bar through keyboard shortcuts. */ void createSidebarActions(); /** Set full-screen options to managed window */ void setFullScreenOptions(int options); /** Create Full-screen action to action collection instance from managed window * set through setManagedWindow(). This action is connected to slotToggleFullScreen() slot. * 'name' is action name used in KDE UI rc file. */ void createFullScreenAction(const QString& name); /** Read full-screen settings fr void slotConfNotifications();om KDE config file. */ void readFullScreenSettings(const KConfigGroup& group); /** Return true if managed window is currently in Full Screen Mode. */ bool fullScreenIsActive() const; static void openHandbook(); static void restoreWindowSize(QWindow* const win, const KConfigGroup& group); static void saveWindowSize(QWindow* const win, KConfigGroup& group); static QAction* buildStdAction(StdActionType type, const QObject* const recvr, const char* const slot, QObject* const parent); /** * If we have some local breeze icon resource, prefer it. */ static void setupIconTheme(); protected: DLogoAction* m_animLogo; QAction* m_metadataEditAction; QAction* m_geolocationEditAction; QAction* m_presentationAction; QAction* m_calendarAction; QAction* m_htmlGalleryAction; QAction* m_printCreatorAction; QAction* m_sendByMailAction; QAction* m_expoBlendingAction; QAction* m_panoramaAction; QAction* m_videoslideshowAction; QAction* m_mediaServerAction; QAction* m_exportDropboxAction; + QAction* m_exportOnedriveAction; QAction* m_exportFacebookAction; QAction* m_exportFlickrAction; QAction* m_exportGdriveAction; QAction* m_exportGphotoAction; QAction* m_exportImageshackAction; QAction* m_exportImgurAction; QAction* m_exportPiwigoAction; QAction* m_exportRajceAction; QAction* m_exportSmugmugAction; QAction* m_exportYandexfotkiAction; #ifdef HAVE_MEDIAWIKI QAction* m_exportMediawikiAction; #endif #ifdef HAVE_VKONTAKTE QAction* m_exportVkontakteAction; #endif #ifdef HAVE_KIO QAction* m_exportFileTransferAction; #endif QAction* m_importGphotoAction; QAction* m_importSmugmugAction; #ifdef HAVE_KIO QAction* m_importFileTransferAction; #endif #ifdef HAVE_KSANE KSaneAction* m_ksaneAction; #endif protected: QAction* showMenuBarAction() const; QAction* showStatusBarAction() const; /** Call this method from your main window to show keyboard shortcut config dialog * with an extra action collection to configure. This method is called by slotEditKeys() * which can be re-implement in child class for cutomization. */ void editKeyboardShortcuts(KActionCollection* const extraac=0, const QString& actitle=QString()); void closeEvent(QCloseEvent* e); void keyPressEvent(QKeyEvent* e); bool eventFilter(QObject* obj, QEvent* ev); /** Re-implement this method if you want to manage sidebars visibility in full-screen mode. * By default this method do nothing. */ virtual void showSideBars(bool visible); /** Re-implement this method if you want to manage thumbbar visibility in full-screen mode. * By default this method do nothing. */ virtual void showThumbBar(bool visible); /** Re-implement this method if you want to manage customized view visibility in full-screen mode. * This method is called by switchWindowToFullScreen(). By default this method do nothing. */ virtual void customizedFullScreenMode(bool set); /** Re-implement this method if managed window has a thumbbar. This must return visibility state of it. */ virtual bool thumbbarVisibility() const; private Q_SLOTS: void slotToggleFullScreen(bool); void slotShowMenuBar(); void slotShowStatusBar(); void slotConfNotifications(); void slotConfToolbars(); void slotNewToolbarConfig(); void slotRawCameraList(); void slotDonateMoney(); void slotRecipesBook(); void slotContribute(); void slotHelpContents(); // Slots for common Help Actions virtual void slotComponentsInfo() {}; virtual void slotDBStat() {}; // Slots for common Sidebar Actions virtual void slotToggleLeftSideBar() {}; virtual void slotToggleRightSideBar() {}; virtual void slotPreviousLeftSideBarTab() {}; virtual void slotNextLeftSideBarTab() {}; virtual void slotPreviousRightSideBarTab() {}; virtual void slotNextRightSideBarTab() {}; // Slots for common Settings actions virtual void slotEditKeys() { editKeyboardShortcuts(); }; virtual void slotSetup() = 0; // Called by KSane action. virtual void slotImportFromScanner() {}; // Called by Metadata Edit tool. virtual void slotEditMetadata() {}; // Called by Geolocation Edit tool. virtual void slotEditGeolocation() {}; // Called by Presentation tool. virtual void slotPresentation() {}; // Called by SendByMail tool. virtual void slotSendByMail() {}; // Called by PrintCreator tool. virtual void slotPrintCreator() {}; // Called by HTML Gallery tool. virtual void slotHTMLGallery() {}; // Called by Calendar tool. virtual void slotCalendar() {}; // Called by Video Slideshow tool. virtual void slotVideoSlideshow() {}; // Called by Panorama tool. virtual void slotPanorama() {}; // Called by Exposure Blending tool. virtual void slotExpoBlending() {}; // Called by Media Server tool. virtual void slotMediaServer() {}; // Called by Webservices Export tools. virtual void slotExportTool() {}; // Called by Webservices Import tools. virtual void slotImportTool() {}; private: /** Used by slotToggleFullScreen() to switch tool-bar visibility in managed window */ void showToolBars(bool visible); /** Return main tool bar instance created in managed window. */ KToolBar* mainToolBar() const; private: class Private; Private* const d; }; } // namespace Digikam #endif // DIGIKAM_DXML_GUI_WINDOW_H diff --git a/core/showfoto/main/showfoto.cpp b/core/showfoto/main/showfoto.cpp index 7e78ed1d78..c9f0c8bd1c 100644 --- a/core/showfoto/main/showfoto.cpp +++ b/core/showfoto/main/showfoto.cpp @@ -1,1622 +1,1629 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2004-11-22 * Description : stand alone digiKam image editor GUI * * Copyright (C) 2004-2018 by Gilles Caulier * Copyright (C) 2006-2012 by Marcel Wiesweg * Copyright (C) 2009-2011 by Andi Clemens * Copyright (C) 2004-2005 by Renchi Raju * Copyright (C) 2005-2006 by Tom Albers * Copyright (C) 2008 by Arnd Baecker * Copyright (C) 2013-2015 by Mohamed_Anwer * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "showfoto.h" #include "showfoto_p.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include #include // Local includes #include "drawdecoder.h" #include "digikam_globals.h" #include "digikam_debug.h" #include "canvas.h" #include "editorcore.h" #include "dmetadata.h" #include "editorstackview.h" #include "dfileoperations.h" #include "iccsettingscontainer.h" #include "imagedialog.h" #include "iofilesettings.h" #include "loadingcache.h" #include "loadingcacheinterface.h" #include "metadatasettings.h" #include "metadataedit.h" #include "presentationmngr.h" #include "savingcontext.h" #include "showfotosetup.h" #include "showfotosetupmisc.h" #include "setupicc.h" #include "slideshow.h" #include "statusprogressbar.h" #include "thememanager.h" #include "thumbnailsize.h" #include "dnotificationwrapper.h" #include "showfotodelegate.h" #include "showfotothumbnailmodel.h" #include "showfotocategorizedview.h" #include "showfotosettings.h" #include "dmetainfoiface.h" #include "dexpanderbox.h" #include "dfiledialog.h" #include "calwizard.h" #include "expoblendingmanager.h" #include "mailwizard.h" #include "advprintwizard.h" #include "dmediaservermngr.h" #include "dmediaserverdlg.h" #include "dbwindow.h" +#include "odwindow.h" #include "fbwindow.h" #include "flickrwindow.h" #include "gswindow.h" #include "imageshackwindow.h" #include "imgurwindow.h" #include "piwigowindow.h" #include "rajcewindow.h" #include "smugwindow.h" #include "yfwindow.h" #ifdef HAVE_MEDIAWIKI # include "mediawikiwindow.h" #endif #ifdef HAVE_VKONTAKTE # include "vkwindow.h" #endif #ifdef HAVE_KIO # include "ftexportwindow.h" # include "ftimportwindow.h" #endif #ifdef HAVE_MARBLE # include "geolocationedit.h" #endif #ifdef HAVE_HTMLGALLERY # include "htmlwizard.h" #endif #ifdef HAVE_PANORAMA # include "panomanager.h" #endif #ifdef HAVE_MEDIAPLAYER # include "vidslidewizard.h" #endif namespace ShowFoto { ShowFoto::ShowFoto(const QList& urlList) : Digikam::EditorWindow(QLatin1String("Showfoto")), d(new Private) { setXMLFile(QLatin1String("showfotoui5.rc")); m_nonDestructive = false; // Show splash-screen at start up. KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(configGroupName()); if (group.readEntry(QLatin1String("ShowSplash"), true) && !qApp->isSessionRestored()) { d->splash = new Digikam::DSplashScreen(); d->splash->show(); } // Setup loading cache and thumbnails interface. Digikam::LoadingCacheInterface::initialize(); Digikam::MetadataSettings::instance(); d->thumbLoadThread = new Digikam::ThumbnailLoadThread(); d->thumbLoadThread->setThumbnailSize(Digikam::ThumbnailSize::Huge); d->thumbLoadThread->setSendSurrogatePixmap(true); // Check ICC profiles repository availability if (d->splash) { d->splash->setMessage(i18n("Checking ICC repository...")); } d->validIccPath = Digikam::SetupICC::iccRepositoryIsValid(); // Populate Themes if (d->splash) { d->splash->setMessage(i18n("Loading themes...")); } Digikam::ThemeManager::instance(); // -- Build the GUI ----------------------------------- setupUserArea(); setupActions(); setupStatusBar(); createGUI(xmlFile()); cleanupActions(); // Create tool selection view setupSelectToolsAction(); // Create context menu. setupContextMenu(); // Make signals/slots connections setupConnections(); // -- Read settings -------------------------------- readSettings(); applySettings(); setAutoSaveSettings(configGroupName(), true); d->rightSideBar->loadState(); //-------------------------------------------------- d->thumbBarDock->reInitialize(); // -- Load current items --------------------------- slotDroppedUrls(urlList); if (!d->infoList.isEmpty()) { slotOpenUrl(d->thumbBar->currentInfo()); } } ShowFoto::~ShowFoto() { delete m_canvas; m_canvas = 0; Digikam::ThumbnailLoadThread::cleanUp(); Digikam::LoadingCacheInterface::cleanUp(); Digikam::DMediaServerMngr::instance()->saveAtShutdown(); delete d->model; delete d->filterModel; delete d->thumbBar; delete d->rightSideBar; delete d->thumbLoadThread; delete d; } bool ShowFoto::queryClose() { // wait if a save operation is currently running if (!waitForSavingToComplete()) { return false; } if (!d->thumbBar->currentInfo().isNull() && !promptUserSave(d->thumbBar->currentUrl())) { return false; } saveSettings(); return true; } void ShowFoto::show() { // Remove Splashscreen. if (d->splash) { d->splash->finish(this); delete d->splash; d->splash = 0; } // Display application window. QMainWindow::show(); // Report errors from ICC repository path. KSharedConfig::Ptr config = KSharedConfig::openConfig(); if (!d->validIccPath) { QString message = i18n("

The ICC profile path seems to be invalid.

" "

If you want to set it now, select \"Yes\", otherwise " "select \"No\". In this case, \"Color Management\" feature " "will be disabled until you solve this issue

"); if (QMessageBox::warning(this, qApp->applicationName(), message, QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { if (!setup(true)) { KConfigGroup group = config->group(QLatin1String("Color Management")); group.writeEntry(QLatin1String("EnableCM"), false); config->sync(); } } else { KConfigGroup group = config->group(QLatin1String("Color Management")); group.writeEntry(QLatin1String("EnableCM"), false); config->sync(); } } // Start the Media Server if necessary Digikam::DMediaServerMngr::instance()->loadAtStartup(); } void ShowFoto::setupConnections() { setupStandardConnections(); connect(d->thumbBarDock, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), d->thumbBar, SLOT(slotDockLocationChanged(Qt::DockWidgetArea))); connect(d->thumbBar, SIGNAL(showfotoItemInfoActivated(ShowfotoItemInfo)), this, SLOT(slotShowfotoItemInfoActivated(ShowfotoItemInfo))); connect(this, SIGNAL(signalSelectionChanged(QRect)), d->rightSideBar, SLOT(slotImageSelectionChanged(QRect))); connect(this, &ShowFoto::signalOpenFolder, this, &ShowFoto::slotOpenFolder); connect(this, &ShowFoto::signalOpenFile, this, &ShowFoto::slotOpenFile); connect(this,SIGNAL(signalInfoList(ShowfotoItemInfoList&)), d->model,SLOT(reAddShowfotoItemInfos(ShowfotoItemInfoList&))); connect(d->thumbLoadThread,SIGNAL(signalThumbnailLoaded(LoadingDescription,QPixmap)), d->model,SLOT(slotThumbnailLoaded(LoadingDescription,QPixmap))); connect(this, SIGNAL(signalNoCurrentItem()), d->rightSideBar, SLOT(slotNoCurrentItem())); connect(d->rightSideBar, SIGNAL(signalSetupMetadataFilters(int)), this, SLOT(slotSetupMetadataFilters(int))); connect(d->dDHandler, SIGNAL(signalDroppedUrls(QList)), this, SLOT(slotDroppedUrls(QList))); } void ShowFoto::setupUserArea() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(configGroupName()); QWidget* const widget = new QWidget(this); QHBoxLayout* const hlay = new QHBoxLayout(widget); m_splitter = new Digikam::SidebarSplitter(widget); KMainWindow* const viewContainer = new KMainWindow(widget, Qt::Widget); m_splitter->addWidget(viewContainer); m_stackView = new Digikam::EditorStackView(viewContainer); m_canvas = new Digikam::Canvas(m_stackView); viewContainer->setCentralWidget(m_stackView); m_splitter->setFrameStyle(QFrame::NoFrame); m_splitter->setFrameShape(QFrame::NoFrame); m_splitter->setFrameShadow(QFrame::Plain); m_splitter->setStretchFactor(1, 10); // set Canvas default size to max. m_splitter->setOpaqueResize(false); m_canvas->makeDefaultEditingCanvas(); m_stackView->setCanvas(m_canvas); m_stackView->setViewMode(Digikam::EditorStackView::CanvasMode); d->rightSideBar = new Digikam::ImagePropertiesSideBar(widget, m_splitter, Qt::RightEdge); d->rightSideBar->setObjectName(QLatin1String("ShowFoto Sidebar Right")); hlay->addWidget(m_splitter); hlay->addWidget(d->rightSideBar); hlay->setContentsMargins(QMargins()); hlay->setSpacing(0); // Code to check for the now depreciated HorizontalThumbar directive. It // is found, it is honored and deleted. The state will from than on be saved // by viewContainers built-in mechanism. Qt::DockWidgetArea dockArea = Qt::LeftDockWidgetArea; d->thumbBarDock = new Digikam::ThumbBarDock(viewContainer, Qt::Tool); d->thumbBarDock->setObjectName(QLatin1String("editor_thumbbar")); d->thumbBarDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea); d->thumbBar = new ShowfotoThumbnailBar(d->thumbBarDock); d->thumbBarDock->setWidget(d->thumbBar); viewContainer->addDockWidget(dockArea, d->thumbBarDock); d->thumbBarDock->setFloating(false); d->model = new ShowfotoThumbnailModel(d->thumbBar); d->model->setThumbnailLoadThread(d->thumbLoadThread); d->dDHandler = new ShowfotoDragDropHandler(d->model); d->model->setDragDropHandler(d->dDHandler); d->filterModel = new ShowfotoFilterModel(d->thumbBar); d->filterModel->setSourceShowfotoModel(d->model); d->filterModel->setCategorizationMode(ShowfotoItemSortSettings::NoCategories); d->filterModel->sort(0); d->thumbBar->setModels(d->model, d->filterModel); d->thumbBar->setSelectionMode(QAbstractItemView::SingleSelection); viewContainer->setAutoSaveSettings(QLatin1String("ImageViewer Thumbbar"), true); d->thumbBar->installOverlays(); setCentralWidget(widget); } void ShowFoto::setupActions() { Digikam::ThemeManager::instance()->setThemeMenuAction(new QMenu(i18n("&Themes"), this)); setupStandardActions(); // Extra 'File' menu actions --------------------------------------------- d->fileOpenAction = buildStdAction(StdOpenAction, this, SLOT(slotOpenFile()), this); actionCollection()->addAction(QLatin1String("showfoto_open_file"), d->fileOpenAction); // --------- d->openFilesInFolderAction = new QAction(QIcon::fromTheme(QLatin1String("folder-pictures")), i18n("Open folder"), this); actionCollection()->setDefaultShortcut(d->openFilesInFolderAction, Qt::CTRL+Qt::SHIFT+Qt::Key_O); connect(d->openFilesInFolderAction, &QAction::triggered, this, &ShowFoto::slotOpenFilesInFolder); actionCollection()->addAction(QLatin1String("showfoto_open_folder"), d->openFilesInFolderAction); // --------- QAction* const quit = buildStdAction(StdQuitAction, this, SLOT(close()), this); actionCollection()->addAction(QLatin1String("showfoto_quit"), quit); // -- Standard 'Help' menu actions --------------------------------------------- createHelpActions(false); } void ShowFoto::readSettings() { d->settings = ShowfotoSettings::instance(); readStandardSettings(); QString defaultDir = d->settings->getLastOpenedDir(); if (defaultDir.isNull()) { defaultDir = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation); } d->lastOpenedDirectory = QUrl::fromLocalFile(defaultDir); d->rightSideBar->loadState(); Digikam::ThemeManager::instance()->setCurrentTheme(d->settings->getCurrentTheme()); d->thumbBar->setToolTipEnabled(d->settings->getShowToolTip()); } void ShowFoto::saveSettings() { saveStandardSettings(); d->settings->setLastOpenedDir(d->lastOpenedDirectory.toLocalFile()); d->settings->setCurrentTheme(Digikam::ThemeManager::instance()->currentThemeName()); d->settings->syncConfig(); d->rightSideBar->saveState(); } void ShowFoto::applySettings() { applyStandardSettings(); d->settings->readSettings(); d->rightSideBar->setStyle(d->settings->getRightSideBarStyle() == 0 ? DMultiTabBar::ActiveIconText : DMultiTabBar::AllIconsText); QString currentStyle = qApp->style()->objectName(); QString newStyle = d->settings->getApplicationStyle(); if (currentStyle.compare(newStyle, Qt::CaseInsensitive) != 0) { qApp->setStyle(newStyle); qApp->style()->polish(qApp); qCDebug(DIGIKAM_SHOWFOTO_LOG) << "Switch to widget style: " << newStyle; } m_fileDeleteAction->setIcon(QIcon::fromTheme(QLatin1String("edit-delete"))); m_fileDeleteAction->setText(i18n("Delete File")); d->thumbBar->setToolTipEnabled(d->settings->getShowToolTip()); d->rightSideBar->slotLoadMetadataFilters(); // Determine sort ordering for the entries from the Showfoto settings: if (d->settings->getReverseSort()) { d->filterModel->setSortOrder(ShowfotoItemSortSettings::DescendingOrder); } else { d->filterModel->setSortOrder(ShowfotoItemSortSettings::AscendingOrder); } switch (d->settings->getSortRole()) { case SetupMisc::SortByName: { d->filterModel->setSortRole(ShowfotoItemSortSettings::SortByFileName); break; } case SetupMisc::SortByFileSize: { d->filterModel->setSortRole(ShowfotoItemSortSettings::SortByFileSize); break; } default: { d->filterModel->setSortRole(ShowfotoItemSortSettings::SortByCreationDate); break; } } } void ShowFoto::slotOpenFile() { if (!d->thumbBar->currentInfo().isNull() && !promptUserSave(d->thumbBar->currentUrl())) { return; } QList urls = Digikam::ImageDialog::getImageURLs(this, d->lastOpenedDirectory); openUrls(urls); } void ShowFoto::openUrls(const QList &urls) { if (!urls.isEmpty()) { ShowfotoItemInfoList infos; ShowfotoItemInfo iteminfo; DMetadata meta; for (QList::const_iterator it = urls.constBegin(); it != urls.constEnd(); ++it) { QFileInfo fi((*it).toLocalFile()); iteminfo.name = fi.fileName(); iteminfo.mime = fi.suffix(); iteminfo.size = fi.size(); iteminfo.url = QUrl::fromLocalFile(fi.filePath()); iteminfo.folder = fi.path(); iteminfo.dtime = fi.created(); meta.load(fi.filePath()); iteminfo.ctime = meta.getImageDateTime(); iteminfo.width = meta.getImageDimensions().width(); iteminfo.height = meta.getImageDimensions().height(); iteminfo.photoInfo = meta.getPhotographInformation(); infos.append(iteminfo); } if (d->droppedUrls) { //replace the equal sign with "<<" to keep the previous pics in the list d->infoList << infos; } else { d->infoList = infos; d->model->clearShowfotoItemInfos(); emit signalInfoList(d->infoList); slotOpenUrl(d->thumbBar->currentInfo()); } } } void ShowFoto::slotOpenUrl(const ShowfotoItemInfo& info) { if (d->thumbBar->currentInfo().isNull()) { return; } QString localFile; if (info.url.isLocalFile()) { // file protocol. We do not need the network localFile = info.url.toLocalFile(); } else { QMessageBox::critical(this, i18n("Error Loading File"), i18n("Failed to load file: %1\n" "Remote file handling is not supported", info.url.fileName())); return; } d->currentLoadedUrl = info.url; m_canvas->load(localFile, m_IOFileSettings); //TODO : add preload here like in ImageWindow::slotLoadCurrent() ??? } void ShowFoto::slotShowfotoItemInfoActivated(const ShowfotoItemInfo& info) { if (!d->thumbBar->currentInfo().isNull() && !promptUserSave(d->currentLoadedUrl)) { d->thumbBar->setCurrentUrl(d->currentLoadedUrl); return; } slotOpenUrl(info); } Digikam::ThumbBarDock* ShowFoto::thumbBar() const { return d->thumbBarDock; } Digikam::Sidebar* ShowFoto::rightSideBar() const { return (dynamic_cast(d->rightSideBar)); } void ShowFoto::slotChanged() { QString mpixels; QSize dims(m_canvas->imageWidth(), m_canvas->imageHeight()); mpixels.setNum(dims.width()*dims.height()/1000000.0, 'f', 2); QString str = (!dims.isValid()) ? i18nc("unknown image dimensions", "Unknown") : i18nc("%1 width, %2 height, %3 mpixels", "%1x%2 (%3Mpx)", dims.width(),dims.height(),mpixels); m_resLabel->setAdjustedText(str); if (!d->thumbBar->currentInfo().isNull()) { if (d->thumbBar->currentUrl().isValid()) { QRect sel = m_canvas->getSelectedArea(); Digikam::DImg* const img = m_canvas->interface()->getImg(); d->rightSideBar->itemChanged(d->thumbBar->currentUrl(), sel, img); } } } void ShowFoto::toggleActions(bool val) { toggleStandardActions(val); } void ShowFoto::slotFilePrint() { printImage(d->thumbBar->currentUrl()); } void ShowFoto::slotSetup() { setup(false); } void ShowFoto::slotSetupICC() { setup(true); } bool ShowFoto::setup(bool iccSetupPage) { QPointer setup = new Setup(this, iccSetupPage ? Setup::ICCPage : Setup::LastPageUsed); if (setup->exec() != QDialog::Accepted) { delete setup; return false; } KSharedConfig::openConfig()->sync(); applySettings(); if (d->itemsNb == 0) { slotUpdateItemInfo(); toggleActions(false); } delete setup; return true; } void ShowFoto::slotUpdateItemInfo() { d->itemsNb = d->thumbBar->showfotoItemInfos().size(); int index = 0; QString text; if (d->itemsNb > 0) { index = 1; for (int i = 0; i < d->itemsNb; i++) { QUrl url = d->thumbBar->showfotoItemInfos().at(i).url; if (url.matches(d->thumbBar->currentUrl(), QUrl::None)) { break; } ++index; } text = i18nc(" ( of )", "%1 (%2 of %3)", d->thumbBar->currentInfo().name, index, d->itemsNb); setCaption(QDir::toNativeSeparators(d->thumbBar->currentUrl().adjusted(QUrl::RemoveFilename).toLocalFile())); } else { text = QLatin1String(""); setCaption(QLatin1String("")); } m_nameLabel->setText(text); toggleNavigation(index); } void ShowFoto::slotOpenFolder(const QUrl& url) { if (!d->thumbBar->currentInfo().isNull() && !promptUserSave(d->thumbBar->currentUrl())) { return; } m_canvas->load(QString(), m_IOFileSettings); d->thumbBar->showfotoItemInfos().clear(); emit signalNoCurrentItem(); openFolder(url); toggleNavigation(1); } void ShowFoto::slotOpenFilesInFolder() { if (!d->thumbBar->currentInfo().isNull() && !promptUserSave(d->thumbBar->currentUrl())) { return; } QUrl url = QUrl::fromLocalFile(DFileDialog::getExistingDirectory(this, i18n("Open Images From Folder"), d->lastOpenedDirectory.toLocalFile())); if (!url.isEmpty()) { m_canvas->load(QString(), m_IOFileSettings); d->thumbBar->showfotoItemInfos().clear(); d->lastOpenedDirectory = url; emit signalNoCurrentItem(); openFolder(url); toggleNavigation(1); } } void ShowFoto::slotFirst() { if (!d->thumbBar->currentInfo().isNull() && !promptUserSave(d->thumbBar->currentUrl())) { return; } d->thumbBar->toFirstIndex(); d->thumbBar->setCurrentInfo(d->thumbBar->showfotoItemInfos().first()); slotOpenUrl(d->thumbBar->showfotoItemInfos().first()); } void ShowFoto::slotLast() { if (!d->thumbBar->currentInfo().isNull() && !promptUserSave(d->thumbBar->currentUrl())) { return; } d->thumbBar->toLastIndex(); d->thumbBar->setCurrentInfo(d->thumbBar->showfotoItemInfos().last()); slotOpenUrl(d->thumbBar->showfotoItemInfos().last()); } void ShowFoto::slotForward() { if (!d->thumbBar->currentInfo().isNull() && !promptUserSave(d->thumbBar->currentUrl())) { return; } bool currentIsNull = d->thumbBar->currentInfo().isNull(); if (!currentIsNull) { d->thumbBar->toNextIndex(); slotOpenUrl(d->thumbBar->currentInfo()); } } void ShowFoto::slotBackward() { if (!d->thumbBar->currentInfo().isNull() && !promptUserSave(d->thumbBar->currentUrl())) { return; } bool currentIsNull = d->thumbBar->currentInfo().isNull(); if (!currentIsNull) { d->thumbBar->toPreviousIndex(); slotOpenUrl(d->thumbBar->currentInfo()); } } void ShowFoto::toggleNavigation(int index) { if (!m_actionEnabledState) { return; } if (d->itemsNb == 0 || d->itemsNb == 1) { m_backwardAction->setEnabled(false); m_forwardAction->setEnabled(false); m_firstAction->setEnabled(false); m_lastAction->setEnabled(false); } else { m_backwardAction->setEnabled(true); m_forwardAction->setEnabled(true); m_firstAction->setEnabled(true); m_lastAction->setEnabled(true); } if (index == 1) { m_backwardAction->setEnabled(false); m_firstAction->setEnabled(false); } if (index == d->itemsNb) { m_forwardAction->setEnabled(false); m_lastAction->setEnabled(false); } } void ShowFoto::slotPrepareToLoad() { Digikam::EditorWindow::slotPrepareToLoad(); // Here we enable specific actions on showfoto. d->openFilesInFolderAction->setEnabled(true); d->fileOpenAction->setEnabled(true); } void ShowFoto::slotLoadingStarted(const QString& filename) { Digikam::EditorWindow::slotLoadingStarted(filename); // Here we disable specific actions on showfoto. d->openFilesInFolderAction->setEnabled(false); d->fileOpenAction->setEnabled(false); } void ShowFoto::slotLoadingFinished(const QString& filename, bool success) { Digikam::EditorWindow::slotLoadingFinished(filename, success); // Here we re-enable specific actions on showfoto. d->openFilesInFolderAction->setEnabled(true); d->fileOpenAction->setEnabled(true); } void ShowFoto::slotSavingStarted(const QString& filename) { Digikam::EditorWindow::slotSavingStarted(filename); // Here we disable specific actions on showfoto. d->openFilesInFolderAction->setEnabled(false); d->fileOpenAction->setEnabled(false); } void ShowFoto::moveFile() { /* * moveFile() -> moveLocalFile() -> movingSaveFileFinished() * | | * finishSaving(true) save...IsComplete() */ qCDebug(DIGIKAM_SHOWFOTO_LOG) << m_savingContext.destinationURL << m_savingContext.destinationURL.isLocalFile(); if (m_savingContext.destinationURL.isLocalFile()) { qCDebug(DIGIKAM_SHOWFOTO_LOG) << "moving a local file"; EditorWindow::moveFile(); } else { QMessageBox::critical(this, i18n("Error Saving File"), i18n("Failed to save file: %1", i18n("Remote file handling is not supported"))); } } void ShowFoto::finishSaving(bool success) { Digikam::EditorWindow::finishSaving(success); // Here we re-enable specific actions on showfoto. d->openFilesInFolderAction->setEnabled(true); d->fileOpenAction->setEnabled(true); } void ShowFoto::saveIsComplete() { Digikam::LoadingCacheInterface::putImage(m_savingContext.destinationURL.toLocalFile(), m_canvas->currentImage()); //d->thumbBar->invalidateThumb(d->currentItem); // Pop-up a message to bring user when save is done. Digikam::DNotificationWrapper(QLatin1String("editorsavefilecompleted"), i18n("Image saved successfully"), this, windowTitle()); resetOrigin(); } void ShowFoto::saveAsIsComplete() { resetOriginSwitchFile(); /* Digikam::LoadingCacheInterface::putImage(m_savingContext.destinationURL.toLocalFile(), m_canvas->currentImage()); // Add the file to the list of thumbbar images if it's not there already Digikam::ThumbBarItem* foundItem = d->thumbBar->findItemByUrl(m_savingContext.destinationURL); d->thumbBar->invalidateThumb(foundItem); qCDebug(DIGIKAM_SHOWFOTO_LOG) << wantedUrls; if (!foundItem) { foundItem = new Digikam::ThumbBarItem(d->thumbBar, m_savingContext.destinationURL); } // shortcut slotOpenUrl d->thumbBar->blockSignals(true); d->thumbBar->setSelected(foundItem); d->thumbBar->blockSignals(false); d->currentItem = foundItem; slotUpdateItemInfo(); // Pop-up a message to bring user when save is done. Digikam::DNotificationWrapper("editorsavefilecompleted", i18n("Image saved successfully"), this, windowTitle()); */ } void ShowFoto::saveVersionIsComplete() { } QUrl ShowFoto::saveDestinationUrl() { if (d->thumbBar->currentInfo().isNull()) { qCWarning(DIGIKAM_GENERAL_LOG) << "Cannot return the url of the image to save " << "because no image is selected."; return QUrl(); } return d->thumbBar->currentUrl(); } bool ShowFoto::save() { if (d->thumbBar->currentInfo().isNull()) { qCWarning(DIGIKAM_GENERAL_LOG) << "This should not happen"; return true; } startingSave(d->currentLoadedUrl); return true; } bool ShowFoto::saveAs() { if (d->thumbBar->currentInfo().isNull()) { qCWarning(DIGIKAM_GENERAL_LOG) << "This should not happen"; return false; } return (startingSaveAs(d->currentLoadedUrl)); } void ShowFoto::slotDeleteCurrentItem() { QUrl urlCurrent(d->thumbBar->currentUrl()); QString warnMsg(i18n("About to delete file \"%1\"\nAre you sure?", urlCurrent.fileName())); if (QMessageBox::warning(this, qApp->applicationName(), warnMsg, QMessageBox::Apply | QMessageBox::Abort) != QMessageBox::Apply) { return; } else { bool ret = QFile::remove(urlCurrent.toLocalFile()); if (!ret) { QMessageBox::critical(this, qApp->applicationName(), i18n("Cannot delete \"%1\"", urlCurrent.fileName())); return; } // No error, remove item in thumbbar. d->model->removeIndex(d->thumbBar->currentIndex()); // Disable menu actions and SideBar if no current image. d->itemsNb = d->thumbBar->showfotoItemInfos().size(); if (d->itemsNb == 0) { slotUpdateItemInfo(); toggleActions(false); m_canvas->load(QString(), m_IOFileSettings); } else { // If there is an image after the deleted one, make that selected. slotOpenUrl(d->thumbBar->currentInfo()); } } } void ShowFoto::slotContextMenu() { if (m_contextMenu) { m_contextMenu->addSeparator(); addServicesMenu(); m_contextMenu->exec(QCursor::pos()); } } void ShowFoto::slideShow(Digikam::SlideShowSettings& settings) { if (!d->thumbBar->showfotoItemInfos().size()) { return; } settings.exifRotate = Digikam::MetadataSettings::instance()->settings().exifRotate; settings.fileList = d->thumbBar->urls(); int i = 0; float cnt = settings.fileList.count(); m_cancelSlideShow = false; Digikam::DMetadata meta; m_nameLabel->setProgressBarMode(Digikam::StatusProgressBar::CancelProgressBarMode, i18n("Preparing slideshow. Please wait...")); for (QList::ConstIterator it = settings.fileList.constBegin() ; !m_cancelSlideShow && (it != settings.fileList.constEnd()) ; ++it) { Digikam::SlidePictureInfo pictInfo; meta.load((*it).toLocalFile()); pictInfo.comment = meta.getImageComments()[QLatin1String("x-default")].caption; pictInfo.photoInfo = meta.getPhotographInformation(); settings.pictInfoMap.insert(*it, pictInfo); m_nameLabel->setProgressValue((int)((i++/cnt)*100.0f)); qApp->processEvents(); } m_nameLabel->setProgressBarMode(Digikam::StatusProgressBar::TextMode, QString()); if (!m_cancelSlideShow) { Digikam::SlideShow* const slide = new Digikam::SlideShow(settings); if (settings.startWithCurrent) { slide->setCurrentItem(d->thumbBar->currentUrl()); } slide->show(); } } void ShowFoto::slotPresentation() { Digikam::PresentationMngr* const mngr = new Digikam::PresentationMngr(this); Digikam::DMetadata meta; QList urlList = d->thumbBar->urls(); int i = 0; float cnt = urlList.count(); m_cancelSlideShow = false; m_nameLabel->setProgressBarMode(Digikam::StatusProgressBar::CancelProgressBarMode, i18n("Preparing presentation. Please wait...")); for (QList::ConstIterator it = urlList.constBegin() ; !m_cancelSlideShow && (it != urlList.constEnd()) ; ++it) { meta.load((*it).toLocalFile()); mngr->addFile(*it, meta.getImageComments()[QLatin1String("x-default")].caption); m_nameLabel->setProgressValue((int)((i++/cnt)*100.0f)); qApp->processEvents(); } m_nameLabel->setProgressBarMode(Digikam::StatusProgressBar::TextMode, QString()); mngr->showConfigDialog(); } void ShowFoto::slotRevert() { if (!promptUserSave(d->thumbBar->currentUrl())) { return; } m_canvas->slotRestore(); } bool ShowFoto::saveNewVersion() { return false; } bool ShowFoto::saveCurrentVersion() { return false; } bool ShowFoto::saveNewVersionAs() { return false; } bool ShowFoto::saveNewVersionInFormat(const QString&) { return false; } void ShowFoto::openFolder(const QUrl& url) { if (!url.isValid() || !url.isLocalFile()) { return; } // Parse image IO mime types registration to get files filter pattern. QString filter; QStringList mimeTypes = supportedImageMimeTypes(QIODevice::ReadOnly, filter); QString patterns = filter.toLower(); patterns.append (QLatin1String(" ")); patterns.append (filter.toUpper()); qCDebug(DIGIKAM_SHOWFOTO_LOG) << "patterns=" << patterns; // Get all image files from directory. QDir dir(url.toLocalFile(), patterns); dir.setFilter(QDir::Files); if (!dir.exists()) { return; } QFileInfoList fileinfolist = dir.entryInfoList(); if (fileinfolist.isEmpty()) { //emit signalSorry(); return; } QFileInfoList::const_iterator fi; ShowfotoItemInfoList infos; ShowfotoItemInfo iteminfo; DMetadata meta; // And open all items in image editor. for (fi = fileinfolist.constBegin(); fi != fileinfolist.constEnd(); ++fi) { iteminfo.name = (*fi).fileName(); iteminfo.mime = (*fi).suffix(); iteminfo.size = (*fi).size(); iteminfo.folder = (*fi).path(); iteminfo.url = QUrl::fromLocalFile((*fi).filePath()); iteminfo.dtime = (*fi).created(); meta.load((*fi).filePath()); iteminfo.ctime = meta.getImageDateTime(); iteminfo.width = meta.getImageDimensions().width(); iteminfo.height = meta.getImageDimensions().height(); iteminfo.photoInfo = meta.getPhotographInformation(); infos.append(iteminfo); } if (d->droppedUrls) { d->infoList << infos; } else { d->infoList = infos; d->model->clearShowfotoItemInfos(); emit signalInfoList(d->infoList); slotOpenUrl(d->thumbBar->currentInfo()); } d->lastOpenedDirectory = QUrl::fromLocalFile(dir.absolutePath()); } void ShowFoto::slotDroppedUrls(const QList& droppedUrls) { if (!droppedUrls.isEmpty()) { QList validUrls; foreach (const QUrl& url, droppedUrls) { if (url.isValid()) { validUrls << url; } } d->droppedUrls = true; QList imagesUrls; QList foldersUrls; foreach (const QUrl& url, validUrls) { if (QMimeDatabase().mimeTypeForUrl(url).name().startsWith(QLatin1String("image"), Qt::CaseInsensitive)) { imagesUrls << url; } if (QMimeDatabase().mimeTypeForUrl(url).name() == QLatin1String("inode/directory")) { foldersUrls << url; } } if (!imagesUrls.isEmpty()) { openUrls(imagesUrls); } if (!foldersUrls.isEmpty()) { foreach (const QUrl& fUrl, foldersUrls) { openFolder(fUrl); } } d->model->clearShowfotoItemInfos(); emit signalInfoList(d->infoList); if (!d->infoList.isEmpty()) { slotOpenUrl(d->thumbBar->currentInfo()); } else { QMessageBox::information(this, qApp->applicationName(), i18n("There is no dropped item to process.")); qWarning(DIGIKAM_SHOWFOTO_LOG) << "infolist is empty.."; } d->droppedUrls = false; } } void ShowFoto::slotSetupMetadataFilters(int tab) { Setup::execMetadataFilters(this, tab+1); } void ShowFoto::slotAddedDropedItems(QDropEvent* e) { QList list = e->mimeData()->urls(); QList urls; foreach(const QUrl& url, list) { QFileInfo fi(url.toLocalFile()); if (fi.exists()) { urls.append(url); } } e->accept(); if (!urls.isEmpty()) { slotDroppedUrls(urls); } } void ShowFoto::slotFileWithDefaultApplication() { Digikam::DFileOperations::openFilesWithDefaultApplication(QList() << d->thumbBar->currentUrl()); } void ShowFoto::addServicesMenu() { addServicesMenuForUrl(d->thumbBar->currentUrl()); } void ShowFoto::slotOpenWith(QAction* action) { openWith(d->thumbBar->currentUrl(), action); } void ShowFoto::slotImportFromScanner() { #ifdef HAVE_KSANE QString place = QDir::homePath(); QStringList pics = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation); if (!pics.isEmpty()) place = pics.first(); QUrl trg = saveDestinationUrl(); if (!trg.isEmpty()) { QString path = trg.adjusted(QUrl::RemoveFilename).toLocalFile(); if (!path.isEmpty()) place = path; } m_ksaneAction->activate(place, configGroupName()); connect(m_ksaneAction, SIGNAL(signalImportedImage(QUrl)), this, SLOT(slotImportedImagefromScanner(QUrl))); #endif } void ShowFoto::slotImportedImagefromScanner(const QUrl& url) { openUrls(QList() << url); } void ShowFoto::slotEditGeolocation() { #ifdef HAVE_MARBLE QList infos = d->thumbBar->urls(); if (infos.isEmpty()) { return; } QPointer dialog = new GeolocationEdit(0, new DMetaInfoIface(this, d->thumbBar->urls()), QApplication::activeWindow()); dialog->setImages(infos); dialog->exec(); delete dialog; // Update image information everywhere. slotChanged(); #endif } void ShowFoto::slotEditMetadata() { if (d->thumbBar->currentInfo().isNull()) { return; } QPointer dialog = new MetadataEditDialog(QApplication::activeWindow(), QList() << d->thumbBar->currentInfo().url); dialog->exec(); delete dialog; // Update image information everywhere. slotChanged(); } void ShowFoto::slotHtmlGallery() { #ifdef HAVE_HTMLGALLERY QPointer w = new HTMLWizard(this, new DMetaInfoIface(this, d->thumbBar->urls())); w->exec(); delete w; #endif } void ShowFoto::slotCalendar() { QPointer w = new CalWizard(d->thumbBar->urls(), this); w->exec(); delete w; } void ShowFoto::slotPanorama() { #ifdef HAVE_PANORAMA PanoManager::instance()->checkBinaries(); PanoManager::instance()->setItemsList(d->thumbBar->urls()); PanoManager::instance()->run(); #endif } void ShowFoto::slotExpoBlending() { ExpoBlendingManager::instance()->checkBinaries(); ExpoBlendingManager::instance()->setItemsList(d->thumbBar->urls()); ExpoBlendingManager::instance()->run(); } void ShowFoto::slotVideoSlideshow() { #ifdef HAVE_MEDIAPLAYER QPointer w = new VidSlideWizard(this, new DMetaInfoIface(this, d->thumbBar->urls())); w->exec(); delete w; #endif } void ShowFoto::slotSendByMail() { QPointer w = new MailWizard(this, new DMetaInfoIface(this, d->thumbBar->urls())); w->exec(); delete w; } void ShowFoto::slotPrintCreator() { QPointer w = new AdvPrintWizard(this, new DMetaInfoIface(this, d->thumbBar->urls())); w->exec(); delete w; } void ShowFoto::slotMediaServer() { QPointer w = new DMediaServerDlg(this, new DMetaInfoIface(this, d->thumbBar->urls())); w->exec(); delete w; } void ShowFoto::slotExportTool() { QAction* const tool = dynamic_cast(sender()); if (tool == m_exportDropboxAction) { QPointer w = new DBWindow(new DMetaInfoIface(this, d->thumbBar->urls()), this); w->exec(); delete w; } + else if (tool == m_exportOnedriveAction) + { + QPointer w = new ODWindow(new DMetaInfoIface(this, d->thumbBar->urls()), this); + w->exec(); + delete w; + } else if (tool == m_exportFacebookAction) { QPointer w = new FbWindow(new DMetaInfoIface(this, d->thumbBar->urls()), this); w->exec(); delete w; } else if (tool == m_exportFlickrAction) { QPointer w = new FlickrWindow(new DMetaInfoIface(this, d->thumbBar->urls()), this); w->exec(); delete w; } else if (tool == m_exportGdriveAction) { QPointer w = new GSWindow(new DMetaInfoIface(this, d->thumbBar->urls()), this, QLatin1String("googledriveexport")); w->exec(); delete w; } else if (tool == m_exportGphotoAction) { QPointer w = new GSWindow(new DMetaInfoIface(this, d->thumbBar->urls()), this, QLatin1String("googlephotoexport")); w->exec(); delete w; } else if (tool == m_exportImageshackAction) { QPointer w = new ImageShackWindow(new DMetaInfoIface(this, d->thumbBar->urls()), this); w->exec(); delete w; } else if (tool == m_exportImgurAction) { QPointer w = new ImgurWindow(new DMetaInfoIface(this, d->thumbBar->urls()), this); w->exec(); delete w; } else if (tool == m_exportPiwigoAction) { QPointer w = new PiwigoWindow(new DMetaInfoIface(this, d->thumbBar->urls()), this); w->exec(); delete w; } else if (tool == m_exportRajceAction) { QPointer w = new RajceWindow(new DMetaInfoIface(this, d->thumbBar->urls()), this); w->exec(); delete w; } else if (tool == m_exportSmugmugAction) { QPointer w = new SmugWindow(new DMetaInfoIface(this, d->thumbBar->urls()), this); w->exec(); delete w; } else if (tool == m_exportYandexfotkiAction) { QPointer w = new YFWindow(new DMetaInfoIface(this, d->thumbBar->urls()), this); w->exec(); delete w; } #ifdef HAVE_MEDIAWIKI else if (tool == m_exportMediawikiAction) { QPointer w = new MediaWikiWindow(new DMetaInfoIface(this, d->thumbBar->urls()), this); w->exec(); delete w; } #endif #ifdef HAVE_VKONTAKTE else if (tool == m_exportVkontakteAction) { QPointer w = new VKWindow(new DMetaInfoIface(this, d->thumbBar->urls()), this); w->exec(); delete w; } #endif #ifdef HAVE_KIO else if (tool == m_exportFileTransferAction) { QPointer w = new FTExportWindow(new DMetaInfoIface(this, d->thumbBar->urls()), this); w->exec(); delete w; } #endif } void ShowFoto::slotImportTool() { QAction* const tool = dynamic_cast(sender()); if (tool == m_importGphotoAction) { QPointer w = new GSWindow(new DMetaInfoIface(this, QList() << d->thumbBar->currentUrl()), this, QLatin1String("googlephotoimport")); w->exec(); delete w; } else if (tool == m_importSmugmugAction) { QPointer w = new SmugWindow(new DMetaInfoIface(this, QList() << d->thumbBar->currentUrl()), this, true); w->exec(); delete w; } #ifdef HAVE_KIO else if (tool == m_importFileTransferAction) { QPointer w = new FTImportWindow(new DMetaInfoIface(this, QList() << d->thumbBar->currentUrl()), this); w->exec(); delete w; } #endif } } // namespace ShowFoto #include "moc_showfoto.cpp" diff --git a/core/utilities/assistants/webservices/CMakeLists.txt b/core/utilities/assistants/webservices/CMakeLists.txt index bb5567d589..1c3455fdbe 100644 --- a/core/utilities/assistants/webservices/CMakeLists.txt +++ b/core/utilities/assistants/webservices/CMakeLists.txt @@ -1,248 +1,258 @@ # # Copyright (c) 2010-2018 by Gilles Caulier, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (POLICY CMP0063) cmake_policy(SET CMP0063 NEW) endif (POLICY CMP0063) include_directories($ $ $ $ $ $ $ $ $ ) if(KF5KIO_FOUND) include_directories($ $ ) endif() - + # OAuth2 library --------------------------------------------------- # The o2 library does not adhere to the flags we use remove_definitions( -DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII -DQT_NO_URL_CAST_FROM_STRING -DQT_NO_CAST_FROM_BYTEARRAY) # It also does not export symbols, so export all by default unset(CMAKE_CXX_VISIBILITY_PRESET) if(WIN32) add_definitions(-DO2_DLL_EXPORT) endif() # Copied from o2/src/CMakeLists.txt set(CMAKE_AUTOMOC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(libwso2_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/common/o2/src/o2.cpp ${CMAKE_CURRENT_SOURCE_DIR}/common/o2/src/o2reply.cpp ${CMAKE_CURRENT_SOURCE_DIR}/common/o2/src/o2replyserver.cpp ${CMAKE_CURRENT_SOURCE_DIR}/common/o2/src/o2requestor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/common/o2/src/o2simplecrypt.cpp ${CMAKE_CURRENT_SOURCE_DIR}/common/o2/src/o0settingsstore.cpp ${CMAKE_CURRENT_SOURCE_DIR}/common/o2/src/o0baseauth.cpp ${CMAKE_CURRENT_SOURCE_DIR}/common/o2/src/o0abstractstore.h ${CMAKE_CURRENT_SOURCE_DIR}/common/o2/src/o0globals.h # Enable when needed ${CMAKE_CURRENT_SOURCE_DIR}/common/o2/src/o1.cpp ${CMAKE_CURRENT_SOURCE_DIR}/common/o2/src/o1requestor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/common/o2/src/o1timedreply.cpp #${CMAKE_CURRENT_SOURCE_DIR}/common/o2/src/o1smugmug.cpp #${CMAKE_CURRENT_SOURCE_DIR}/common/o2/src/o1twitter.h #${CMAKE_CURRENT_SOURCE_DIR}/common/o2/src/oxtwitter.cpp #${CMAKE_CURRENT_SOURCE_DIR}/common/o2/src/o1dropbox.h #${CMAKE_CURRENT_SOURCE_DIR}/common/o2/src/o1flickr.h #${CMAKE_CURRENT_SOURCE_DIR}/common/o2/src/o2gft.cpp #${CMAKE_CURRENT_SOURCE_DIR}/common/o2/src/o2facebook.cpp #${CMAKE_CURRENT_SOURCE_DIR}/common/o2/src/o2skydrive.cpp #${CMAKE_CURRENT_SOURCE_DIR}/common/o2/src/o2hubic.cpp #${CMAKE_CURRENT_SOURCE_DIR}/common/o2/src/o2uber.cpp ) # Helper classes ------------------------------------------------------------------ set(libwebservices_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/common/wscomboboxdelegate.cpp ${CMAKE_CURRENT_SOURCE_DIR}/common/wscomboboxintermediate.cpp ${CMAKE_CURRENT_SOURCE_DIR}/common/wstoolutils.cpp ${CMAKE_CURRENT_SOURCE_DIR}/common/wssettingswidget.cpp ${CMAKE_CURRENT_SOURCE_DIR}/common/wsnewalbumdialog.cpp ${CMAKE_CURRENT_SOURCE_DIR}/common/wsselectuserdlg.cpp ${CMAKE_CURRENT_SOURCE_DIR}/common/wstooldialog.cpp ${CMAKE_CURRENT_SOURCE_DIR}/common/wslogindialog.cpp ${CMAKE_CURRENT_SOURCE_DIR}/common/manager/wssettings.cpp ${CMAKE_CURRENT_SOURCE_DIR}/common/wizard/wsalbumspage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/common/wizard/wsfinalpage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/common/wizard/wsimagespage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/common/wizard/wsintropage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/common/wizard/wssettingspage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/common/wizard/wswizard.cpp ) # Flickr tool ---------------------------------------------------------------- set(libwsflickr_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/flickr/flickrlist.cpp ${CMAKE_CURRENT_SOURCE_DIR}/flickr/flickrmpform.cpp ${CMAKE_CURRENT_SOURCE_DIR}/flickr/flickrtalker.cpp ${CMAKE_CURRENT_SOURCE_DIR}/flickr/flickrwidget.cpp ${CMAKE_CURRENT_SOURCE_DIR}/flickr/flickrnewalbumdlg.cpp ${CMAKE_CURRENT_SOURCE_DIR}/flickr/flickrtalker.cpp ${CMAKE_CURRENT_SOURCE_DIR}/flickr/flickrwindow.cpp ) # Imgur tool ---------------------------------------------------------------- set(libwsimgur_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/imgur/imgurtalker.cpp ${CMAKE_CURRENT_SOURCE_DIR}/imgur/imgurimageslist.cpp ${CMAKE_CURRENT_SOURCE_DIR}/imgur/imgurwindow.cpp ) # DropBox tool -------------------------------------------------------------- set(libwsdropbox_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/dropbox/dbnewalbumdlg.cpp ${CMAKE_CURRENT_SOURCE_DIR}/dropbox/dbmpform.cpp ${CMAKE_CURRENT_SOURCE_DIR}/dropbox/dbtalker.cpp ${CMAKE_CURRENT_SOURCE_DIR}/dropbox/dbwidget.cpp ${CMAKE_CURRENT_SOURCE_DIR}/dropbox/dbwindow.cpp ) +# OneDrive tool -------------------------------------------------------------- + +set(libwsonedrive_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/onedrive/odnewalbumdlg.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/onedrive/odmpform.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/onedrive/odtalker.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/onedrive/odwidget.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/onedrive/odwindow.cpp +) + # SmugMug tool ------------------------------------------------------------- set(libwssmugmug_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/smugmug/smugnewalbumdlg.cpp ${CMAKE_CURRENT_SOURCE_DIR}/smugmug/smugmpform.cpp ${CMAKE_CURRENT_SOURCE_DIR}/smugmug/smugtalker.cpp ${CMAKE_CURRENT_SOURCE_DIR}/smugmug/smugwidget.cpp ${CMAKE_CURRENT_SOURCE_DIR}/smugmug/smugwindow.cpp ) # ImageShack tool ------------------------------------------------------------- set(libwsimageshack_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/imageshack/imageshacksession.cpp ${CMAKE_CURRENT_SOURCE_DIR}/imageshack/imageshacknewalbumdlg.cpp ${CMAKE_CURRENT_SOURCE_DIR}/imageshack/imageshackmpform.cpp ${CMAKE_CURRENT_SOURCE_DIR}/imageshack/imageshacktalker.cpp ${CMAKE_CURRENT_SOURCE_DIR}/imageshack/imageshackwidget.cpp ${CMAKE_CURRENT_SOURCE_DIR}/imageshack/imageshackwindow.cpp ) # FaceBook tool ------------------------------------------------------------- set(libwsfacebook_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/facebook/fbnewalbumdlg.cpp ${CMAKE_CURRENT_SOURCE_DIR}/facebook/fbmpform.cpp ${CMAKE_CURRENT_SOURCE_DIR}/facebook/fbtalker.cpp ${CMAKE_CURRENT_SOURCE_DIR}/facebook/fbwidget.cpp ${CMAKE_CURRENT_SOURCE_DIR}/facebook/fbwindow.cpp ) # Rajce tool ---------------------------------------------------------------- set(libwsrajce_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/rajce/rajcenewalbumdlg.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rajce/rajcempform.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rajce/rajcecommand.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rajce/rajcetalker.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rajce/rajcesession.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rajce/rajcealbum.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rajce/rajcewidget.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rajce/rajcewindow.cpp ) # Google tool ---------------------------------------------------------------- set(libwsgoogle_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/google/gdrive/gdmpform.cpp ${CMAKE_CURRENT_SOURCE_DIR}/google/gdrive/gdtalker.cpp ${CMAKE_CURRENT_SOURCE_DIR}/google/gphoto/gpmpform.cpp ${CMAKE_CURRENT_SOURCE_DIR}/google/gphoto/gptalker.cpp ${CMAKE_CURRENT_SOURCE_DIR}/google/gstalkerbase.cpp ${CMAKE_CURRENT_SOURCE_DIR}/google/gsreplacedlg.cpp ${CMAKE_CURRENT_SOURCE_DIR}/google/gsnewalbumdlg.cpp ${CMAKE_CURRENT_SOURCE_DIR}/google/gswindow.cpp ${CMAKE_CURRENT_SOURCE_DIR}/google/gswidget.cpp ) # YandexFotki tool ---------------------------------------------------------------- set(libwsyandexfotki_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/yandexfotki/yfalbum.cpp ${CMAKE_CURRENT_SOURCE_DIR}/yandexfotki/yfauth.cpp ${CMAKE_CURRENT_SOURCE_DIR}/yandexfotki/yfrsa.cpp ${CMAKE_CURRENT_SOURCE_DIR}/yandexfotki/yftalker.cpp ${CMAKE_CURRENT_SOURCE_DIR}/yandexfotki/yfphoto.cpp ${CMAKE_CURRENT_SOURCE_DIR}/yandexfotki/yfnewalbumdlg.cpp ${CMAKE_CURRENT_SOURCE_DIR}/yandexfotki/yfwindow.cpp ${CMAKE_CURRENT_SOURCE_DIR}/yandexfotki/yfwidget.cpp ) # Piwigo tool ------------------------------------------------------------- set(libwspiwigo_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/piwigo/piwigologindlg.cpp ${CMAKE_CURRENT_SOURCE_DIR}/piwigo/piwigotalker.cpp ${CMAKE_CURRENT_SOURCE_DIR}/piwigo/piwigosession.cpp ${CMAKE_CURRENT_SOURCE_DIR}/piwigo/piwigowindow.cpp ) # MediaWiki tool ------------------------------------------------------------ if(KF5MediaWiki_FOUND) set(libwsmediawiki_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/mediawiki/mediawikiwindow.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mediawiki/mediawikiwidget.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mediawiki/mediawikitalker.cpp ) endif() # VKontakte tool ------------------------------------------------------------ if(KF5Vkontakte_FOUND) set(libwsvkontakte_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/vkontakte/vkwindow.cpp ${CMAKE_CURRENT_SOURCE_DIR}/vkontakte/vknewalbumdlg.cpp ${CMAKE_CURRENT_SOURCE_DIR}/vkontakte/vkalbumchooser.cpp ${CMAKE_CURRENT_SOURCE_DIR}/vkontakte/vkauthwidget.cpp ) endif() # FileTransfer tool --------------------------------------------------------- if(KF5KIO_FOUND) set(libwsfiletransfer_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/filetransfer/ftexportwindow.cpp ${CMAKE_CURRENT_SOURCE_DIR}/filetransfer/ftexportwidget.cpp ${CMAKE_CURRENT_SOURCE_DIR}/filetransfer/ftimportwindow.cpp ${CMAKE_CURRENT_SOURCE_DIR}/filetransfer/ftimportwidget.cpp ) endif() - + # ------------------------------------------------------------------------------ add_library(webservices_src OBJECT ${libwebservices_SRCS} ${libwso2_SRCS} ${libwsflickr_SRCS} ${libwsimgur_SRCS} ${libwsdropbox_SRCS} + ${libwsonedrive_SRCS} ${libwssmugmug_SRCS} ${libwsimageshack_SRCS} ${libwsfacebook_SRCS} ${libwsrajce_SRCS} ${libwsgoogle_SRCS} ${libwsyandexfotki_SRCS} ${libwspiwigo_SRCS} ${libwsmediawiki_SRCS} ${libwsvkontakte_SRCS} ${libwsfiletransfer_SRCS} ) diff --git a/core/utilities/assistants/webservices/common/o2/src/o0globals.h b/core/utilities/assistants/webservices/common/o2/src/o0globals.h index f04a149c87..8f5751c69a 100644 --- a/core/utilities/assistants/webservices/common/o2/src/o0globals.h +++ b/core/utilities/assistants/webservices/common/o2/src/o0globals.h @@ -1,62 +1,62 @@ #ifndef O0GLOBALS_H #define O0GLOBALS_H // Common constants const char O2_ENCRYPTION_KEY[] = "12345678"; -const char O2_CALLBACK_URL[] = "http://127.0.0.1:%1/"; +const char O2_CALLBACK_URL[] = "http://localhost:%1/login/authorized"; const char O2_MIME_TYPE_XFORM[] = "application/x-www-form-urlencoded"; const char O2_MIME_TYPE_JSON[] = "application/json"; // QSettings key names const char O2_KEY_TOKEN[] = "token.%1"; const char O2_KEY_TOKEN_SECRET[] = "tokensecret.%1"; const char O2_KEY_CODE[] = "code.%1"; const char O2_KEY_EXPIRES[] = "expires.%1"; const char O2_KEY_REFRESH_TOKEN[] = "refreshtoken.%1"; const char O2_KEY_LINKED[] = "linked.%1"; const char O2_KEY_EXTRA_TOKENS[] = "extratokens.%1"; // OAuth 1/1.1 Request Parameters const char O2_OAUTH_CALLBACK[] = "oauth_callback"; const char O2_OAUTH_CONSUMER_KEY[] = "oauth_consumer_key"; const char O2_OAUTH_NONCE[] = "oauth_nonce"; const char O2_OAUTH_SIGNATURE[] = "oauth_signature"; const char O2_OAUTH_SIGNATURE_METHOD[] = "oauth_signature_method"; const char O2_OAUTH_TIMESTAMP[] = "oauth_timestamp"; const char O2_OAUTH_VERSION[] = "oauth_version"; // OAuth 1/1.1 Response Parameters const char O2_OAUTH_TOKEN[] = "oauth_token"; const char O2_OAUTH_TOKEN_SECRET[] = "oauth_token_secret"; const char O2_OAUTH_CALLBACK_CONFIRMED[] = "oauth_callback_confirmed"; const char O2_OAUTH_VERFIER[] = "oauth_verifier"; // OAuth 2 Request Parameters const char O2_OAUTH2_RESPONSE_TYPE[] = "response_type"; const char O2_OAUTH2_CLIENT_ID[] = "client_id"; const char O2_OAUTH2_CLIENT_SECRET[] = "client_secret"; const char O2_OAUTH2_USERNAME[] = "username"; const char O2_OAUTH2_PASSWORD[] = "password"; const char O2_OAUTH2_REDIRECT_URI[] = "redirect_uri"; const char O2_OAUTH2_SCOPE[] = "scope"; const char O2_OAUTH2_GRANT_TYPE_CODE[] = "code"; const char O2_OAUTH2_GRANT_TYPE_TOKEN[] = "token"; const char O2_OAUTH2_GRANT_TYPE_PASSWORD[] = "password"; const char O2_OAUTH2_GRANT_TYPE[] = "grant_type"; const char O2_OAUTH2_API_KEY[] = "api_key"; // OAuth 2 Response Parameters const char O2_OAUTH2_ACCESS_TOKEN[] = "access_token"; const char O2_OAUTH2_REFRESH_TOKEN[] = "refresh_token"; const char O2_OAUTH2_EXPIRES_IN[] = "expires_in"; // OAuth signature types const char O2_SIGNATURE_TYPE_HMAC_SHA1[] = "HMAC-SHA1"; const char O2_SIGNATURE_TYPE_PLAINTEXT[] = "PLAINTEXT"; // Parameter values const char O2_AUTHORIZATION_CODE[] = "authorization_code"; // Standard HTTP headers const char O2_HTTP_AUTHORIZATION_HEADER[] = "Authorization"; #endif // O0GLOBALS_H diff --git a/core/utilities/assistants/webservices/common/o2/src/o2.cpp b/core/utilities/assistants/webservices/common/o2/src/o2.cpp index 760d3dd311..fd20c17be3 100644 --- a/core/utilities/assistants/webservices/common/o2/src/o2.cpp +++ b/core/utilities/assistants/webservices/common/o2/src/o2.cpp @@ -1,512 +1,515 @@ #include #include #include #include #include #include #include #include #include #include #include #include #if QT_VERSION >= 0x050000 #include #include #include #else #include #include #endif #include "o2.h" #include "o2replyserver.h" #include "o0globals.h" #include "o0settingsstore.h" /// Parse JSON data into a QVariantMap static QVariantMap parseTokenResponse(const QByteArray &data) { #if QT_VERSION >= 0x050000 QJsonParseError err; QJsonDocument doc = QJsonDocument::fromJson(data, &err); if (err.error != QJsonParseError::NoError) { qWarning() << "parseTokenResponse: Failed to parse token response due to err:" << err.errorString(); return QVariantMap(); } if (!doc.isObject()) { qWarning() << "parseTokenResponse: Token response is not an object"; return QVariantMap(); } return doc.object().toVariantMap(); #else QScriptEngine engine; QScriptValue value = engine.evaluate("(" + QString(data) + ")"); QScriptValueIterator it(value); QVariantMap map; while (it.hasNext()) { it.next(); map.insert(it.name(), it.value().toVariant()); } return map; #endif } /// Add query parameters to a query static void addQueryParametersToUrl(QUrl &url, QList > parameters) { #if QT_VERSION < 0x050000 url.setQueryItems(parameters); #else QUrlQuery query(url); query.setQueryItems(parameters); url.setQuery(query); #endif } O2::O2(QObject *parent, QNetworkAccessManager *manager, O0AbstractStore *store): O0BaseAuth(parent, store) { manager_ = manager ? manager : new QNetworkAccessManager(this); grantFlow_ = GrantFlowAuthorizationCode; localhostPolicy_ = QString(O2_CALLBACK_URL); qRegisterMetaType("QNetworkReply::NetworkError"); } O2::GrantFlow O2::grantFlow() { return grantFlow_; } void O2::setGrantFlow(O2::GrantFlow value) { grantFlow_ = value; Q_EMIT grantFlowChanged(); } QString O2::username() { return username_; } void O2::setUsername(const QString &value) { username_ = value; Q_EMIT usernameChanged(); } QString O2::password() { return password_; } void O2::setPassword(const QString &value) { password_ = value; Q_EMIT passwordChanged(); } QString O2::scope() { return scope_; } void O2::setScope(const QString &value) { scope_ = value; Q_EMIT scopeChanged(); } QString O2::requestUrl() { return requestUrl_.toString(); } void O2::setRequestUrl(const QString &value) { requestUrl_ = value; Q_EMIT requestUrlChanged(); } QVariantMap O2::extraRequestParams() { return extraReqParams_; } void O2::setExtraRequestParams(const QVariantMap &value) { extraReqParams_ = value; Q_EMIT extraRequestParamsChanged(); } QString O2::tokenUrl() { return tokenUrl_.toString(); } void O2::setTokenUrl(const QString &value) { tokenUrl_= value; Q_EMIT tokenUrlChanged(); } QString O2::refreshTokenUrl() { return refreshTokenUrl_.toString(); } void O2::setRefreshTokenUrl(const QString &value) { refreshTokenUrl_ = value; Q_EMIT refreshTokenUrlChanged(); } void O2::link() { qDebug() << "O2::link"; // Create the reply server if it doesn't exist // and we don't use an external web interceptor if(!useExternalWebInterceptor_) { if(replyServer_ == NULL) { replyServer_ = new O2ReplyServer(this); connect(replyServer_, SIGNAL(verificationReceived(QMap)), this, SLOT(onVerificationReceived(QMap))); connect(replyServer_, SIGNAL(serverClosed(bool)), this, SLOT(serverHasClosed(bool))); } } if (linked()) { qDebug() << "O2::link: Linked already"; Q_EMIT linkingSucceeded(); return; } setLinked(false); setToken(""); setTokenSecret(""); setExtraTokens(QVariantMap()); setRefreshToken(QString()); setExpires(0); if (grantFlow_ == GrantFlowAuthorizationCode || grantFlow_ == GrantFlowImplicit) { if (useExternalWebInterceptor_) { // Save redirect URI, as we have to reuse it when requesting the access token redirectUri_ = localhostPolicy_.arg(localPort()); } else { // Start listening to authentication replies if (!replyServer_->isListening()) { if (replyServer_->listen(QHostAddress::Any, localPort_)) { qDebug() << "O2::link: Reply server listening on port" << localPort(); } else { qWarning() << "O2::link: Reply server failed to start listening on port" << localPort(); Q_EMIT linkingFailed(); return; } } - + // Save redirect URI, as we have to reuse it when requesting the access token redirectUri_ = localhostPolicy_.arg(replyServer_->serverPort()); } - + // Assemble intial authentication URL QList > parameters; parameters.append(qMakePair(QString(O2_OAUTH2_RESPONSE_TYPE), (grantFlow_ == GrantFlowAuthorizationCode)? QString(O2_OAUTH2_GRANT_TYPE_CODE): QString(O2_OAUTH2_GRANT_TYPE_TOKEN))); parameters.append(qMakePair(QString(O2_OAUTH2_CLIENT_ID), clientId_)); - if ( !redirectUri_.isEmpty() ) + if ( !redirectUri_.isEmpty() ){ parameters.append(qMakePair(QString(O2_OAUTH2_REDIRECT_URI), redirectUri_)); + qDebug() << "redirectURI" << redirectUri_; + } if ( !scope_.isEmpty() ) parameters.append(qMakePair(QString(O2_OAUTH2_SCOPE), scope_.replace( " ", "+" ))); if ( !apiKey_.isEmpty() ) parameters.append(qMakePair(QString(O2_OAUTH2_API_KEY), apiKey_)); foreach (QString key, extraRequestParams().keys()) { parameters.append(qMakePair(key, extraRequestParams().value(key).toString())); } // Show authentication URL with a web browser QUrl url(requestUrl_); addQueryParametersToUrl(url, parameters); qDebug() << "O2::link: Emit openBrowser" << url.toString(); Q_EMIT openBrowser(url); + qDebug() << "Heloo"; } else if (grantFlow_ == GrantFlowResourceOwnerPasswordCredentials) { QList parameters; parameters.append(O0RequestParameter(O2_OAUTH2_CLIENT_ID, clientId_.toUtf8())); if ( !clientSecret_.isEmpty() ) parameters.append(O0RequestParameter(O2_OAUTH2_CLIENT_SECRET, clientSecret_.toUtf8())); parameters.append(O0RequestParameter(O2_OAUTH2_USERNAME, username_.toUtf8())); parameters.append(O0RequestParameter(O2_OAUTH2_PASSWORD, password_.toUtf8())); parameters.append(O0RequestParameter(O2_OAUTH2_GRANT_TYPE, O2_OAUTH2_GRANT_TYPE_PASSWORD)); parameters.append(O0RequestParameter(O2_OAUTH2_SCOPE, scope_.toUtf8())); if ( !apiKey_.isEmpty() ) parameters.append(O0RequestParameter(O2_OAUTH2_API_KEY, apiKey_.toUtf8())); foreach (QString key, extraRequestParams().keys()) { parameters.append(O0RequestParameter(key.toUtf8(), extraRequestParams().value(key).toByteArray())); } QByteArray payload = O0BaseAuth::createQueryParameters(parameters); qDebug() << "O2::link: Sending token request for resource owner flow"; QUrl url(tokenUrl_); QNetworkRequest tokenRequest(url); tokenRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); QNetworkReply *tokenReply = manager_->post(tokenRequest, payload); connect(tokenReply, SIGNAL(finished()), this, SLOT(onTokenReplyFinished()), Qt::QueuedConnection); connect(tokenReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onTokenReplyError(QNetworkReply::NetworkError)), Qt::QueuedConnection); } } void O2::unlink() { qDebug() << "O2::unlink"; setLinked(false); setToken(QString()); setRefreshToken(QString()); setExpires(0); setExtraTokens(QVariantMap()); Q_EMIT linkingSucceeded(); } void O2::onVerificationReceived(const QMap response) { qDebug() << "O2::onVerificationReceived:" << response; qDebug() << "O2::onVerificationReceived: Emitting closeBrowser()"; Q_EMIT closeBrowser(); if (response.contains("error")) { qWarning() << "O2::onVerificationReceived: Verification failed:" << response; Q_EMIT linkingFailed(); return; } if (grantFlow_ == GrantFlowAuthorizationCode) { // Save access code setCode(response.value(QString(O2_OAUTH2_GRANT_TYPE_CODE))); // Exchange access code for access/refresh tokens QString query; if(!apiKey_.isEmpty()) query = QString("?" + QString(O2_OAUTH2_API_KEY) + "=" + apiKey_); QNetworkRequest tokenRequest(QUrl(tokenUrl_.toString() + query)); tokenRequest.setHeader(QNetworkRequest::ContentTypeHeader, O2_MIME_TYPE_XFORM); tokenRequest.setRawHeader("Accept", O2_MIME_TYPE_JSON); QMap parameters; parameters.insert(O2_OAUTH2_GRANT_TYPE_CODE, code()); parameters.insert(O2_OAUTH2_CLIENT_ID, clientId_); parameters.insert(O2_OAUTH2_CLIENT_SECRET, clientSecret_); parameters.insert(O2_OAUTH2_REDIRECT_URI, redirectUri_); parameters.insert(O2_OAUTH2_GRANT_TYPE, O2_AUTHORIZATION_CODE); QByteArray data = buildRequestBody(parameters); qDebug() << QString("O2::onVerificationReceived: Exchange access code data:\n%1").arg(QString(data)); QNetworkReply *tokenReply = manager_->post(tokenRequest, data); timedReplies_.add(tokenReply); connect(tokenReply, SIGNAL(finished()), this, SLOT(onTokenReplyFinished()), Qt::QueuedConnection); connect(tokenReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onTokenReplyError(QNetworkReply::NetworkError)), Qt::QueuedConnection); } else if (grantFlow_ == GrantFlowImplicit) { // Check for mandatory tokens if (response.contains(O2_OAUTH2_ACCESS_TOKEN)) { qDebug() << "O2::onVerificationReceived: Access token returned for implicit flow"; setToken(response.value(O2_OAUTH2_ACCESS_TOKEN)); if (response.contains(O2_OAUTH2_EXPIRES_IN)) { bool ok = false; int expiresIn = response.value(O2_OAUTH2_EXPIRES_IN).toInt(&ok); if (ok) { qDebug() << "O2::onVerificationReceived: Token expires in" << expiresIn << "seconds"; setExpires((int)(QDateTime::currentMSecsSinceEpoch() / 1000 + expiresIn)); } } setLinked(true); Q_EMIT linkingSucceeded(); } else { qWarning() << "O2::onVerificationReceived: Access token missing from response for implicit flow"; Q_EMIT linkingFailed(); } } else { setToken(response.value(O2_OAUTH2_ACCESS_TOKEN)); setRefreshToken(response.value(O2_OAUTH2_REFRESH_TOKEN)); } } QString O2::code() { QString key = QString(O2_KEY_CODE).arg(clientId_); return store_->value(key); } void O2::setCode(const QString &c) { QString key = QString(O2_KEY_CODE).arg(clientId_); store_->setValue(key, c); } void O2::onTokenReplyFinished() { qDebug() << "O2::onTokenReplyFinished"; QNetworkReply *tokenReply = qobject_cast(sender()); if (!tokenReply) { qDebug() << "O2::onTokenReplyFinished: reply is null"; return; } if (tokenReply->error() == QNetworkReply::NoError) { QByteArray replyData = tokenReply->readAll(); // Dump replyData // SENSITIVE DATA in RelWithDebInfo or Debug builds //qDebug() << "O2::onTokenReplyFinished: replyData\n"; //qDebug() << QString( replyData ); QVariantMap tokens = parseTokenResponse(replyData); // Dump tokens qDebug() << "O2::onTokenReplyFinished: Tokens returned:\n"; foreach (QString key, tokens.keys()) { // SENSITIVE DATA in RelWithDebInfo or Debug builds, so it is truncated first qDebug() << key << ": "<< tokens.value( key ).toString().left( 3 ) << "..."; } // Check for mandatory tokens if (tokens.contains(O2_OAUTH2_ACCESS_TOKEN)) { qDebug() << "O2::onTokenReplyFinished: Access token returned"; setToken(tokens.take(O2_OAUTH2_ACCESS_TOKEN).toString()); bool ok = false; int expiresIn = tokens.take(O2_OAUTH2_EXPIRES_IN).toInt(&ok); if (ok) { qDebug() << "O2::onTokenReplyFinished: Token expires in" << expiresIn << "seconds"; setExpires((int)(QDateTime::currentMSecsSinceEpoch() / 1000 + expiresIn)); } setRefreshToken(tokens.take(O2_OAUTH2_REFRESH_TOKEN).toString()); setExtraTokens(tokens); timedReplies_.remove(tokenReply); setLinked(true); Q_EMIT linkingSucceeded(); } else { qWarning() << "O2::onTokenReplyFinished: Access token missing from response"; Q_EMIT linkingFailed(); } } tokenReply->deleteLater(); } void O2::onTokenReplyError(QNetworkReply::NetworkError error) { QNetworkReply *tokenReply = qobject_cast(sender()); qWarning() << "O2::onTokenReplyError: " << error << ": " << tokenReply->errorString(); qDebug() << "O2::onTokenReplyError: " << tokenReply->readAll(); setToken(QString()); setRefreshToken(QString()); timedReplies_.remove(tokenReply); Q_EMIT linkingFailed(); } QByteArray O2::buildRequestBody(const QMap ¶meters) { QByteArray body; bool first = true; foreach (QString key, parameters.keys()) { if (first) { first = false; } else { body.append("&"); } QString value = parameters.value(key); body.append(QUrl::toPercentEncoding(key) + QString("=").toUtf8() + QUrl::toPercentEncoding(value)); } return body; } int O2::expires() { QString key = QString(O2_KEY_EXPIRES).arg(clientId_); return store_->value(key).toInt(); } void O2::setExpires(int v) { QString key = QString(O2_KEY_EXPIRES).arg(clientId_); store_->setValue(key, QString::number(v)); } QString O2::refreshToken() { QString key = QString(O2_KEY_REFRESH_TOKEN).arg(clientId_); return store_->value(key); } void O2::setRefreshToken(const QString &v) { qDebug() << "O2::setRefreshToken" << v.left(4) << "..."; QString key = QString(O2_KEY_REFRESH_TOKEN).arg(clientId_); store_->setValue(key, v); } void O2::refresh() { qDebug() << "O2::refresh: Token: ..." << refreshToken().right(7); if (refreshToken().isEmpty()) { qWarning() << "O2::refresh: No refresh token"; onRefreshError(QNetworkReply::AuthenticationRequiredError); return; } if (refreshTokenUrl_.isEmpty()) { qWarning() << "O2::refresh: Refresh token URL not set"; onRefreshError(QNetworkReply::AuthenticationRequiredError); return; } QNetworkRequest refreshRequest(refreshTokenUrl_); refreshRequest.setHeader(QNetworkRequest::ContentTypeHeader, O2_MIME_TYPE_XFORM); QMap parameters; parameters.insert(O2_OAUTH2_CLIENT_ID, clientId_); parameters.insert(O2_OAUTH2_CLIENT_SECRET, clientSecret_); parameters.insert(O2_OAUTH2_REFRESH_TOKEN, refreshToken()); parameters.insert(O2_OAUTH2_GRANT_TYPE, O2_OAUTH2_REFRESH_TOKEN); QByteArray data = buildRequestBody(parameters); QNetworkReply *refreshReply = manager_->post(refreshRequest, data); timedReplies_.add(refreshReply); connect(refreshReply, SIGNAL(finished()), this, SLOT(onRefreshFinished()), Qt::QueuedConnection); connect(refreshReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRefreshError(QNetworkReply::NetworkError)), Qt::QueuedConnection); } void O2::onRefreshFinished() { QNetworkReply *refreshReply = qobject_cast(sender()); - + if (refreshReply->error() == QNetworkReply::NoError) { QByteArray reply = refreshReply->readAll(); QVariantMap tokens = parseTokenResponse(reply); setToken(tokens.value(O2_OAUTH2_ACCESS_TOKEN).toString()); setExpires((int)(QDateTime::currentMSecsSinceEpoch() / 1000 + tokens.value(O2_OAUTH2_EXPIRES_IN).toInt())); QString refreshToken = tokens.value(O2_OAUTH2_REFRESH_TOKEN).toString(); if(!refreshToken.isEmpty()) { setRefreshToken(refreshToken); } else { qDebug() << "No new refresh token. Keep the old one."; } timedReplies_.remove(refreshReply); setLinked(true); Q_EMIT linkingSucceeded(); Q_EMIT refreshFinished(QNetworkReply::NoError); qDebug() << " New token expires in" << expires() << "seconds"; } else { qDebug() << "O2::onRefreshFinished: Error" << (int)refreshReply->error() << refreshReply->errorString(); } refreshReply->deleteLater(); } void O2::onRefreshError(QNetworkReply::NetworkError error) { QNetworkReply *refreshReply = qobject_cast(sender()); qWarning() << "O2::onRefreshError: " << error; unlink(); timedReplies_.remove(refreshReply); Q_EMIT refreshFinished(error); } void O2::serverHasClosed(bool paramsfound) { if ( !paramsfound ) { // server has probably timed out after receiving first response Q_EMIT linkingFailed(); } } QString O2::localhostPolicy() const { return localhostPolicy_; } void O2::setLocalhostPolicy(const QString &value) { localhostPolicy_ = value; } QString O2::apiKey() { return apiKey_; } void O2::setApiKey(const QString &value) { apiKey_ = value; } bool O2::ignoreSslErrors() { return timedReplies_.ignoreSslErrors(); } void O2::setIgnoreSslErrors(bool ignoreSslErrors) { timedReplies_.setIgnoreSslErrors(ignoreSslErrors); } diff --git a/core/utilities/assistants/webservices/common/o2/src/o2.h b/core/utilities/assistants/webservices/common/o2/src/o2.h index cb9ae228c8..fc500e5b96 100644 --- a/core/utilities/assistants/webservices/common/o2/src/o2.h +++ b/core/utilities/assistants/webservices/common/o2/src/o2.h @@ -1,173 +1,175 @@ #ifndef O2_H #define O2_H #include #include #include #include #include "o0export.h" #include "o0baseauth.h" #include "o2reply.h" #include "o0abstractstore.h" /// Simple OAuth2 authenticator. class O0_EXPORT O2: public O0BaseAuth { Q_OBJECT Q_ENUMS(GrantFlow) public: /// Authorization flow types. enum GrantFlow { GrantFlowAuthorizationCode, ///< @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-4.1 GrantFlowImplicit, ///< @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-4.2 GrantFlowResourceOwnerPasswordCredentials, }; /// Authorization flow. Q_PROPERTY(GrantFlow grantFlow READ grantFlow WRITE setGrantFlow NOTIFY grantFlowChanged) GrantFlow grantFlow(); void setGrantFlow(GrantFlow value); /// Resource owner username. /// O2 instances with the same (username, password) share the same "linked" and "token" properties. Q_PROPERTY(QString username READ username WRITE setUsername NOTIFY usernameChanged) QString username(); void setUsername(const QString &value); /// Resource owner password. /// O2 instances with the same (username, password) share the same "linked" and "token" properties. Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged) QString password(); void setPassword(const QString &value); /// Scope of authentication. Q_PROPERTY(QString scope READ scope WRITE setScope NOTIFY scopeChanged) QString scope(); void setScope(const QString &value); /// Localhost policy. By default it's value is http://127.0.0.1:%1/, however some services may /// require the use of http://localhost:%1/ or any other value. Q_PROPERTY(QString localhostPolicy READ localhostPolicy WRITE setLocalhostPolicy) QString localhostPolicy() const; void setLocalhostPolicy(const QString &value); /// API key. Q_PROPERTY(QString apiKey READ apiKey WRITE setApiKey) QString apiKey(); void setApiKey(const QString &value); /// Allow ignoring SSL errors? /// E.g. SurveyMonkey fails on Mac due to SSL error. Ignoring the error circumvents the problem Q_PROPERTY(bool ignoreSslErrors READ ignoreSslErrors WRITE setIgnoreSslErrors) bool ignoreSslErrors(); void setIgnoreSslErrors(bool ignoreSslErrors); /// Request URL. Q_PROPERTY(QString requestUrl READ requestUrl WRITE setRequestUrl NOTIFY requestUrlChanged) QString requestUrl(); void setRequestUrl(const QString &value); /// User-defined extra parameters to append to request URL Q_PROPERTY(QVariantMap extraRequestParams READ extraRequestParams WRITE setExtraRequestParams NOTIFY extraRequestParamsChanged) QVariantMap extraRequestParams(); void setExtraRequestParams(const QVariantMap &value); /// Token request URL. Q_PROPERTY(QString tokenUrl READ tokenUrl WRITE setTokenUrl NOTIFY tokenUrlChanged) QString tokenUrl(); void setTokenUrl(const QString &value); /// Token refresh URL. Q_PROPERTY(QString refreshTokenUrl READ refreshTokenUrl WRITE setRefreshTokenUrl NOTIFY refreshTokenUrlChanged) QString refreshTokenUrl(); void setRefreshTokenUrl(const QString &value); + void setoneDriveRedirectUrl(const QString &value); + public: /// Constructor. /// @param parent Parent object. explicit O2(QObject *parent = 0, QNetworkAccessManager *manager = 0, O0AbstractStore *store = 0); /// Get authentication code. QString code(); /// Get refresh token. QString refreshToken(); /// Get token expiration time (seconds from Epoch). int expires(); public Q_SLOTS: /// Authenticate. Q_INVOKABLE virtual void link(); /// De-authenticate. Q_INVOKABLE virtual void unlink(); /// Refresh token. Q_INVOKABLE void refresh(); /// Handle situation where reply server has opted to close its connection void serverHasClosed(bool paramsfound = false); Q_SIGNALS: /// Emitted when a token refresh has been completed or failed. void refreshFinished(QNetworkReply::NetworkError error); // Property change signals void grantFlowChanged(); void scopeChanged(); void usernameChanged(); void passwordChanged(); void requestUrlChanged(); void extraRequestParamsChanged(); void refreshTokenUrlChanged(); void tokenUrlChanged(); public Q_SLOTS: /// Handle verification response. virtual void onVerificationReceived(QMap); protected Q_SLOTS: /// Handle completion of a token request. virtual void onTokenReplyFinished(); /// Handle failure of a token request. virtual void onTokenReplyError(QNetworkReply::NetworkError error); /// Handle completion of a refresh request. virtual void onRefreshFinished(); /// Handle failure of a refresh request. virtual void onRefreshError(QNetworkReply::NetworkError error); protected: /// Build HTTP request body. QByteArray buildRequestBody(const QMap ¶meters); /// Set authentication code. void setCode(const QString &v); /// Set refresh token. void setRefreshToken(const QString &v); /// Set token expiration time. void setExpires(int v); protected: QString username_; QString password_; QUrl requestUrl_; QVariantMap extraReqParams_; QUrl tokenUrl_; QUrl refreshTokenUrl_; QString scope_; QString code_; QString localhostPolicy_; QString apiKey_; QNetworkAccessManager *manager_; O2ReplyList timedReplies_; GrantFlow grantFlow_; }; #endif // O2_H diff --git a/core/utilities/assistants/webservices/onedrive/oditem.h b/core/utilities/assistants/webservices/onedrive/oditem.h new file mode 100644 index 0000000000..79d9424027 --- /dev/null +++ b/core/utilities/assistants/webservices/onedrive/oditem.h @@ -0,0 +1,60 @@ +/* ============================================================ + * + * 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) 2013 by Pankaj Kumar + * Copyright (C) 2013-2018 by Gilles Caulier + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef OD_ITEM_H +#define OD_ITEM_H + +// Qt includes + +#include + +namespace Digikam{ + +class ODPhoto +{ +public: + + ODPhoto() + { + + } + + QString title; +}; + +class ODFolder +{ + +public: + + ODFolder() + { + + } + + QString title; +}; + +} //namespace Digikam + +#endif // OD_ITEM_H diff --git a/core/utilities/assistants/webservices/onedrive/odmpform.cpp b/core/utilities/assistants/webservices/onedrive/odmpform.cpp new file mode 100644 index 0000000000..f4ad0b037c --- /dev/null +++ b/core/utilities/assistants/webservices/onedrive/odmpform.cpp @@ -0,0 +1,66 @@ +/* ============================================================ + * + * 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) 2013 by Pankaj Kumar + * Copyright (C) 2013-2018 by Gilles Caulier + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + + // local includes + + #include "odmpform.h" + + // Qt includes + + #include + + // Local includes + + #include "digikam_debug.h" + + namespace Digikam + { + + ODMPForm::ODMPForm() + { + } + + ODMPForm::~ODMPForm() + { + } + + bool ODMPForm::addFile(const QString& imgPath) + { + QFile file(imgPath); + + if (!file.open(QIODevice::ReadOnly)) + { + return false; + } + + m_buffer = file.readAll(); + + return true; + } + + QByteArray ODMPForm::formData() const + { + return m_buffer; + } + + } // namespace Digikam diff --git a/core/utilities/assistants/webservices/onedrive/odmpform.h b/core/utilities/assistants/webservices/onedrive/odmpform.h new file mode 100644 index 0000000000..b2f1306d92 --- /dev/null +++ b/core/utilities/assistants/webservices/onedrive/odmpform.h @@ -0,0 +1,52 @@ +/* ============================================================ + * + * 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) 2013 by Pankaj Kumar + * Copyright (C) 2013-2018 by Gilles Caulier + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef OD_MPFORM_H +#define OD_MPFORM_H + +// Qt includes + +#include + +namespace Digikam +{ + +class ODMPForm +{ + +public: + + explicit ODMPForm(); + ~ODMPForm(); + + bool addFile(const QString& imgPath); + QByteArray formData() const; + +private: + + QByteArray m_buffer; +}; + +} // namespace Digikam + +#endif // OD_MPFORM_H diff --git a/core/utilities/assistants/webservices/onedrive/odnewalbumdlg.cpp b/core/utilities/assistants/webservices/onedrive/odnewalbumdlg.cpp new file mode 100644 index 0000000000..5d619f66b6 --- /dev/null +++ b/core/utilities/assistants/webservices/onedrive/odnewalbumdlg.cpp @@ -0,0 +1,53 @@ +/* ============================================================ + * + * 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) 2013 by Pankaj Kumar + * Copyright (C) 2013-2018 by Gilles Caulier + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + + #include "odnewalbumdlg.h" + + // Local includes + + #include "digikam_debug.h" + #include "oditem.h" + +namespace Digikam +{ + +ODNewAlbumDlg::ODNewAlbumDlg(QWidget* const parent, const QString& toolName) + : WSNewAlbumDialog(parent, toolName) +{ + hideDateTime(); + hideDesc(); + hideLocation(); + getMainWidget()->setMinimumSize(300, 0); +} + +ODNewAlbumDlg::~ODNewAlbumDlg() +{ +} + +void ODNewAlbumDlg::getFolderTitle(ODFolder& folder) +{ + folder.title = QLatin1String("/") + getTitleEdit()->text(); + qCDebug(DIGIKAM_WEBSERVICES_LOG) << "getFolderTitle:" << folder.title; +} + +} // namespace Digikam diff --git a/core/utilities/assistants/webservices/onedrive/odnewalbumdlg.h b/core/utilities/assistants/webservices/onedrive/odnewalbumdlg.h new file mode 100644 index 0000000000..721403d337 --- /dev/null +++ b/core/utilities/assistants/webservices/onedrive/odnewalbumdlg.h @@ -0,0 +1,50 @@ +/* ============================================================ + * + * 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) 2013 by Pankaj Kumar + * Copyright (C) 2013-2018 by Gilles Caulier + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef OD_NEW_ALBUM_DLG_H +#define OD_NEW_ALBUM_DLG_H + +// Local includes + +#include "wsnewalbumdialog.h" + +namespace Digikam +{ + +class ODFolder; + +class ODNewAlbumDlg : public WSNewAlbumDialog +{ + Q_OBJECT + +public: + + explicit ODNewAlbumDlg(QWidget* const parent, const QString& toolName); + ~ODNewAlbumDlg(); + + void getFolderTitle(ODFolder& folder); +}; + +} // namespace Digikam + +#endif // OD_NEW_ALBUM_DLG_H diff --git a/core/utilities/assistants/webservices/onedrive/odtalker.cpp b/core/utilities/assistants/webservices/onedrive/odtalker.cpp new file mode 100644 index 0000000000..8f0f577cbd --- /dev/null +++ b/core/utilities/assistants/webservices/onedrive/odtalker.cpp @@ -0,0 +1,419 @@ +#include + +// Qt includes + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Local includes + +#include "digikam_debug.h" +#include "digikam_version.h" +#include "wstoolutils.h" +#include "odwindow.h" +#include "oditem.h" +#include "odmpform.h" +#include "previewloadthread.h" +#include "o0settingsstore.h" + +namespace Digikam +{ + +class ODTalker::Private +{ +public: + + enum State + { + OD_USERNAME = 0, + OD_LISTFOLDERS, + OD_CREATEFOLDER, + OD_ADDPHOTO + }; + +public: + + explicit Private() + { + clientId = QLatin1String("8bd716b2-7b89-4475-8449-8edc1e808cc6"); + clientSecret = QLatin1String("rxcfCE31{@}kemIKCMH145?"); + scope = QLatin1String("files.readwrite"); + + authUrl = QLatin1String("https://login.microsoftonline.com/common/oauth2/v2.0/authorize"); + tokenUrl = QLatin1String("https://login.microsoftonline.com/common/oauth2/v2.0/token"); + redirectUrl = QLatin1String("http://localhost:5000/login/authorized"); + + state = OD_USERNAME; + settings = 0; + netMngr = 0; + reply = 0; + o2 = 0; + } + +public: + + QString clientId; + QString clientSecret; + QString authUrl; + QString tokenUrl; + QString scope; + QString redirectUrl; + + QWidget* parent; + QNetworkAccessManager* netMngr; + + QNetworkReply* reply; + + QSettings* settings; + + State state; + + QByteArray buffer; + + DMetadata meta; + + O2* o2; +}; +ODTalker::ODTalker(QWidget* const parent) + : d(new Private) +{ + d->parent = parent; + d->netMngr = new QNetworkAccessManager(this); + + connect(d->netMngr, SIGNAL(finished(QNetworkReply*)), + this, SLOT(slotFinished(QNetworkReply*))); + + d->o2 = new O2(this); + + d->o2->setClientId(d->clientId); + d->o2->setClientSecret(d->clientSecret); + d->o2->setRefreshTokenUrl(d->tokenUrl); + d->o2->setRequestUrl(d->authUrl); + d->o2->setTokenUrl(d->tokenUrl); + d->o2->setScope(d->scope); + d->o2->setLocalPort(5000); + + d->settings = WSToolUtils::getOauthSettings(this); + O0SettingsStore* const store = new O0SettingsStore(d->settings, QLatin1String(O2_ENCRYPTION_KEY), this); + store->setGroupKey(QLatin1String("Onedrive")); + d->o2->setStore(store); + + connect(d->o2, SIGNAL(linkingFailed()), + this, SLOT(slotLinkingFailed())); + + connect(d->o2, SIGNAL(linkingSucceeded()), + this, SLOT(slotLinkingSucceeded())); + + connect(d->o2, SIGNAL(openBrowser(QUrl)), + this, SLOT(slotOpenBrowser(QUrl))); +} +ODTalker::~ODTalker() +{ + if (d->reply) + { + d->reply->abort(); + } + delete d; +} +void ODTalker::link() +{ + emit signalBusy(true); + d->o2->link(); +} +void ODTalker::unLink() +{ + d->o2->unlink(); +} + +void ODTalker::slotLinkingFailed() +{ + qCDebug(DIGIKAM_WEBSERVICES_LOG) << "LINK to Onedrive fail"; + emit signalBusy(false); +} +void ODTalker::slotLinkingSucceeded() +{ + if (!d->o2->linked()) + { + qCDebug(DIGIKAM_WEBSERVICES_LOG) << "UNLINK to Onedrive ok"; + emit signalBusy(false); + return; + } + + qCDebug(DIGIKAM_WEBSERVICES_LOG) << "LINK to Onedrive ok"; + emit signalLinkingSucceeded(); +} +void ODTalker::slotOpenBrowser(const QUrl& url) +{ + qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Open Browser..."; + QDesktopServices::openUrl(url); +} +bool ODTalker::authenticated() +{ + return d->o2->linked(); +} +void ODTalker::cancel() +{ + if (d->reply) + { + d->reply->abort(); + d->reply = 0; + } + + emit signalBusy(false); +} +void ODTalker::createFolder(const QString& path) +{ + //path also has name of new folder so send path parameter accordingly + qCDebug(DIGIKAM_WEBSERVICES_LOG) << "createFolder:" << path; + + QUrl url(QLatin1String("https://api.dropboxapi.com/2/files/create_folder_v2")); + + QNetworkRequest netRequest(url); + netRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String(O2_MIME_TYPE_JSON)); + netRequest.setRawHeader("Authorization", QString::fromLatin1("Bearer %1").arg(d->o2->token()).toUtf8()); + + QByteArray postData = QString::fromUtf8("{\"path\": \"%1\"}").arg(path).toUtf8(); + + d->reply = d->netMngr->post(netRequest, postData); + + d->state = Private::OD_CREATEFOLDER; + d->buffer.resize(0); + emit signalBusy(true); +} +void ODTalker::getUserName() +{ + QUrl url(QLatin1String("https://graph.microsoft.com/v1.0/me")); + + QNetworkRequest netRequest(url); + netRequest.setRawHeader("Authorization", QString::fromLatin1("bearer %1").arg(d->o2->token()).toUtf8()); + netRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("application/json")); + + d->reply = d->netMngr->get(netRequest); + qCDebug(DIGIKAM_WEBSERVICES_LOG) << "AFter Request Usar "; + d->state = Private::OD_USERNAME; + d->buffer.resize(0); + emit signalBusy(true); + qCDebug(DIGIKAM_WEBSERVICES_LOG) << "exiting"; +} + +/** Get list of folders by parsing json sent by dropbox + */ +void ODTalker::listFolders(const QString& path) +{ + QUrl url(QLatin1String("https://graph.microsoft.com/v1.0/me/drive/root/children"));; + + QNetworkRequest netRequest(url); + netRequest.setRawHeader("Authorization", QString::fromLatin1("bearer %1").arg(d->o2->token()).toUtf8()); + netRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("application/json")); + + d->reply = d->netMngr->get(netRequest); + + d->state = Private::OD_LISTFOLDERS; + d->buffer.resize(0); + emit signalBusy(true); +} + +bool ODTalker::addPhoto(const QString& imgPath, const QString& uploadFolder, bool rescale, int maxDim, int imageQuality) +{ + if (d->reply) + { + d->reply->abort(); + d->reply = 0; + } + + emit signalBusy(true); + + ODMPForm form; + QImage image = PreviewLoadThread::loadHighQualitySynchronously(imgPath).copyQImage(); + + if (image.isNull()) + { + return false; + } + + QString path = WSToolUtils::makeTemporaryDir("onedrive").filePath(QFileInfo(imgPath) + .baseName().trimmed() + QLatin1String(".jpg")); + + if (rescale && (image.width() > maxDim || image.height() > maxDim)) + { + image = image.scaled(maxDim,maxDim, Qt::KeepAspectRatio,Qt::SmoothTransformation); + } + + image.save(path,"JPEG",imageQuality); + + if (d->meta.load(imgPath)) + { + d->meta.setImageDimensions(image.size()); + d->meta.setImageOrientation(DMetadata::ORIENTATION_NORMAL); + d->meta.setImageProgramId(QLatin1String("digiKam"), digiKamVersion()); + d->meta.setMetadataWritingMode((int)DMetadata::WRITETOIMAGEONLY); + d->meta.save(path); + } + + if (!form.addFile(path)) + { + emit signalBusy(false); + return false; + } + + QString uploadPath = uploadFolder + QUrl(QUrl::fromLocalFile(imgPath)).fileName(); + QUrl url(QString::fromLatin1("https://graph.microsoft.com/v1.0/me/drive/root:/%1:/content").arg(uploadPath)); + + QNetworkRequest netRequest(url); + netRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("application/octet-stream")); + netRequest.setRawHeader("Authorization", QString::fromLatin1("bearer {%1}").arg(d->o2->token()).toUtf8()); + + d->reply = d->netMngr->put(netRequest, form.formData()); + + d->state = Private::OD_ADDPHOTO; + d->buffer.resize(0); + emit signalBusy(true); + return true; +} +void ODTalker::slotFinished(QNetworkReply* reply) +{ + if (reply != d->reply) + { + return; + } + + d->reply = 0; + + if (reply->error() != QNetworkReply::NoError) + { + if (d->state != Private::OD_CREATEFOLDER) + { + emit signalBusy(false); + QMessageBox::critical(QApplication::activeWindow(), + i18n("Error"), reply->errorString()); + + reply->deleteLater(); + return; + } + } + + d->buffer.append(reply->readAll()); + + switch (d->state) + { + case Private::OD_LISTFOLDERS: + qCDebug(DIGIKAM_WEBSERVICES_LOG) << "In OD_LISTFOLDERS"; + parseResponseListFolders(d->buffer); + break; + case Private::OD_CREATEFOLDER: + qCDebug(DIGIKAM_WEBSERVICES_LOG) << "In OD_CREATEFOLDER"; + parseResponseCreateFolder(d->buffer); + break; + case Private::OD_ADDPHOTO: + qCDebug(DIGIKAM_WEBSERVICES_LOG) << "In OD_ADDPHOTO"; + parseResponseAddPhoto(d->buffer); + break; + case Private::OD_USERNAME: + qCDebug(DIGIKAM_WEBSERVICES_LOG) << "In OD_USERNAME"; + parseResponseUserName(d->buffer); + break; + default: + break; + } + + reply->deleteLater(); +} +void ODTalker::parseResponseAddPhoto(const QByteArray& data) +{ + QJsonDocument doc = QJsonDocument::fromJson(data); + QJsonObject jsonObject = doc.object(); + bool success = jsonObject.contains(QLatin1String("size")); + emit signalBusy(false); + + if (!success) + { + emit signalAddPhotoFailed(i18n("Failed to upload photo")); + } + else + { + emit signalAddPhotoSucceeded(); + } +} +void ODTalker::parseResponseUserName(const QByteArray& data) +{ + QJsonDocument doc = QJsonDocument::fromJson(data); + QString name = doc.object()[QLatin1String("displayName")].toString(); + + qCDebug(DIGIKAM_WEBSERVICES_LOG) << "parseResponseUserName: "< > list; + list.append(qMakePair(QLatin1String(""), QLatin1String("root"))); + + foreach (const QJsonValue& value, jsonArray) + { + QString id; + QJsonObject folder; + QString folderName; + + QJsonObject obj = value.toObject(); + folder = obj[QLatin1String("folder")].toObject(); + + if(!folder.isEmpty()){ + id = folder[QLatin1String("id")].toString(); + folderName = obj[QLatin1String("name")].toString(); + qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Folder Name is" << folderName; + list.append(qMakePair(id, folderName)); + + } + } + + emit signalBusy(false); + emit signalListAlbumsDone(list); +} + +void ODTalker::parseResponseCreateFolder(const QByteArray& data) +{ + QJsonDocument doc = QJsonDocument::fromJson(data); + QJsonObject jsonObject = doc.object(); + bool fail = jsonObject.contains(QLatin1String("error")); + + emit signalBusy(false); + + if (fail) + { + emit signalCreateFolderFailed(jsonObject[QLatin1String("error_summary")].toString()); + } + else + { + emit signalCreateFolderSucceeded(); + } +} + +} // namespace Digikam diff --git a/core/utilities/assistants/webservices/onedrive/odtalker.h b/core/utilities/assistants/webservices/onedrive/odtalker.h new file mode 100644 index 0000000000..22dfc0f932 --- /dev/null +++ b/core/utilities/assistants/webservices/onedrive/odtalker.h @@ -0,0 +1,101 @@ +/* ============================================================ + * + * 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) 2013 by Pankaj Kumar + * Copyright (C) 2013-2018 by Gilles Caulier + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef OD_TALKER_H +#define OD_TALKER_H + +// Qt includes + +#include +#include +#include +#include +#include +#include + +// Local includes + +#include "oditem.h" +#include "o2.h" +#include "o0globals.h" +#include "dmetadata.h" + +namespace Digikam +{ + +class ODTalker : public QObject +{ + Q_OBJECT + +public: + + explicit ODTalker(QWidget* const parent); + ~ODTalker(); + +public: + + void link(); + void unLink(); + void getUserName(); + bool authenticated(); + void cancel(); + bool addPhoto(const QString& imgPath, const QString& uploadFolder, bool rescale, int maxDim, int imageQuality); + void listFolders(const QString& path = QString()); + void createFolder(const QString& path); + +Q_SIGNALS: + + void signalBusy(bool val); + void signalLinkingSucceeded(); + void signalLinkingFailed(); + void signalSetUserName(const QString& msg); + void signalListAlbumsFailed(const QString& msg); + void signalListAlbumsDone(const QList >& list); + void signalCreateFolderFailed(const QString& msg); + void signalCreateFolderSucceeded(); + void signalAddPhotoFailed(const QString& msg); + void signalAddPhotoSucceeded(); + +private Q_SLOTS: + + void slotLinkingFailed(); + void slotLinkingSucceeded(); + void slotOpenBrowser(const QUrl& url); + void slotFinished(QNetworkReply* reply); + +private: + + void parseResponseUserName(const QByteArray& data); + void parseResponseListFolders(const QByteArray& data); + void parseResponseCreateFolder(const QByteArray& data); + void parseResponseAddPhoto(const QByteArray& data); + +private: + + class Private; + Private* const d; +}; + +} // namespace Digikam + +#endif // OD_TALKER_H diff --git a/core/utilities/assistants/webservices/onedrive/odwidget.cpp b/core/utilities/assistants/webservices/onedrive/odwidget.cpp new file mode 100644 index 0000000000..6d2600f0b7 --- /dev/null +++ b/core/utilities/assistants/webservices/onedrive/odwidget.cpp @@ -0,0 +1,70 @@ +/* ============================================================ + * + * 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) 2013 by Pankaj Kumar + * Copyright (C) 2013-2018 by Gilles Caulier + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + #include "odwidget.h" + +// Qt includes + +#include +#include + +// Local includes + +namespace Digikam +{ + +ODWidget::ODWidget(QWidget* const parent, + DInfoInterface* const iface, + const QString& toolName) + : WSSettingsWidget(parent, iface, toolName) +{ + getUploadBox()->hide(); + getSizeBox()->hide(); +} + +ODWidget::~ODWidget() +{ +} + +void ODWidget::updateLabels(const QString& name, const QString& url) +{ + QString web(QLatin1String("https://www.onedrive.com/")); + + if (!url.isEmpty()) + web = url; + + getHeaderLbl()->setText(QString::fromLatin1( + "

" + "Onedrive" + "

").arg(web)); + + if (name.isEmpty()) + { + getUserNameLabel()->clear(); + } + else + { + getUserNameLabel()->setText(QString::fromLatin1("%1").arg(name)); + } +} + +} // namespace Digikam diff --git a/core/utilities/assistants/webservices/onedrive/odwidget.h b/core/utilities/assistants/webservices/onedrive/odwidget.h new file mode 100644 index 0000000000..ed864aa33b --- /dev/null +++ b/core/utilities/assistants/webservices/onedrive/odwidget.h @@ -0,0 +1,62 @@ +/* ============================================================ + * + * 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) 2013 by Pankaj Kumar + * Copyright (C) 2013-2018 by Gilles Caulier + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef OD_WIDGET_H +#define OD_WIDGET_H + +// Qt includes + +#include + +// Local includes + +#include "wssettingswidget.h" +#include "oditem.h" +#include "dinfointerface.h" + +class QButtonGroup; + +namespace Digikam +{ + +class ODWidget : public WSSettingsWidget +{ + Q_OBJECT + +public: + + explicit ODWidget(QWidget* const parent, + DInfoInterface* const iface, + const QString& toolName); + ~ODWidget(); + + void updateLabels(const QString& name = QString(), + const QString& url = QString()) Q_DECL_OVERRIDE; + +private: + friend class ODWindow; +}; + +} // namespace Digikam + +#endif // OD_WIDGET_H diff --git a/core/utilities/assistants/webservices/onedrive/odwindow.cpp b/core/utilities/assistants/webservices/onedrive/odwindow.cpp new file mode 100644 index 0000000000..cebc0a9e90 --- /dev/null +++ b/core/utilities/assistants/webservices/onedrive/odwindow.cpp @@ -0,0 +1,445 @@ +#include "odwindow.h" + +// Qt includes + +#include +#include +#include +#include +#include + +// KDE includes + +#include +#include +#include + +// Local includes + +#include "digikam_debug.h" +#include "dimageslist.h" +#include "digikam_version.h" +#include "odtalker.h" +#include "oditem.h" +#include "odnewalbumdlg.h" +#include "odwidget.h" + +namespace Digikam +{ + +class 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 >)), + this,SLOT(slotListAlbumsDone(QList >))); + + 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(); +} + +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); + d->widget->getImgQualitySpB()->setEnabled(true); + } + else + { + d->widget->getResizeCheckBox()->setChecked(false); + d->widget->getDimensionSpB()->setEnabled(false); + d->widget->getImgQualitySpB()->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(); + 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 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())) + { + QMessageBox warn(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(); + 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("Onedrive export"), true, true); + d->widget->progressBar()->progressThumbnailChanged(QIcon(QLatin1String("dropbox")).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 + QLatin1String("/"); + + 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 Dropbox." + "\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); + 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 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/onedrive/odwindow.h b/core/utilities/assistants/webservices/onedrive/odwindow.h new file mode 100644 index 0000000000..57abee1395 --- /dev/null +++ b/core/utilities/assistants/webservices/onedrive/odwindow.h @@ -0,0 +1,98 @@ +/* ============================================================ + * + * 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) 2013 by Pankaj Kumar + * Copyright (C) 2013-2018 by Gilles Caulier + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef OD_WINDOW_H +#define OD_WINDOW_H + +// Qt includes + +#include +#include +#include + +// Local includes + +#include "wstooldialog.h" +#include "digikam_export.h" +#include "dinfointerface.h" + +class QCloseEvent; +class QUrl; + +namespace Digikam +{ + +class DIGIKAM_EXPORT ODWindow : public WSToolDialog +{ + Q_OBJECT + +public: + + explicit ODWindow(DInfoInterface* const iface, QWidget* const parent); + ~ODWindow(); + + void reactivate(); + + void setItemsList(const QList& urls); + +private: + + void readSettings(); + void writeSettings(); + + void uploadNextPhoto(); + + void buttonStateChange(bool state); + void closeEvent(QCloseEvent*) Q_DECL_OVERRIDE; + +private Q_SLOTS: + + void slotImageListChanged(); + void slotUserChangeRequest(); + void slotNewAlbumRequest(); + void slotReloadAlbumsRequest(); + void slotStartTransfer(); + + void slotBusy(bool); + void slotSignalLinkingFailed(); + void slotSignalLinkingSucceeded(); + void slotSetUserName(const QString& msg); + void slotListAlbumsFailed(const QString& msg); + void slotListAlbumsDone(const QList >& list); + void slotCreateFolderFailed(const QString& msg); + void slotCreateFolderSucceeded(); + void slotAddPhotoFailed(const QString& msg); + void slotAddPhotoSucceeded(); + void slotTransferCancel(); + + void slotFinished(); + +private: + + class Private; + Private* const d; +}; + +} // namespace Digikam + +#endif // GS_WINDOW_H diff --git a/core/utilities/imageeditor/main/imagewindow.cpp b/core/utilities/imageeditor/main/imagewindow.cpp index 68f893e306..69cadc9a25 100644 --- a/core/utilities/imageeditor/main/imagewindow.cpp +++ b/core/utilities/imageeditor/main/imagewindow.cpp @@ -1,2026 +1,2033 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2004-02-12 * Description : digiKam image editor GUI * * Copyright (C) 2004-2005 by Renchi Raju * Copyright (C) 2004-2018 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "imagewindow.h" #include "imagewindow_p.h" // C++ includes #include #include #include // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include #include #include namespace Digikam { ImageWindow* ImageWindow::m_instance = 0; ImageWindow* ImageWindow::imageWindow() { if (!m_instance) { new ImageWindow(); } return m_instance; } bool ImageWindow::imageWindowCreated() { return m_instance; } ImageWindow::ImageWindow() : EditorWindow(QLatin1String("Image Editor")), d(new Private) { setXMLFile(QLatin1String("imageeditorui5.rc")); m_instance = this; // We don't want to be deleted on close setAttribute(Qt::WA_DeleteOnClose, false); setAcceptDrops(true); // -- Build the GUI ------------------------------- setupUserArea(); setupActions(); setupStatusBar(); createGUI(xmlFile()); cleanupActions(); showMenuBarAction()->setChecked(!menuBar()->isHidden()); // NOTE: workaround for bug #171080 // Create tool selection view setupSelectToolsAction(); // Create context menu. setupContextMenu(); // Make signals/slots connections setupConnections(); // -- Read settings -------------------------------- readSettings(); KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(configGroupName()); applyMainWindowSettings(group); d->thumbBarDock->setShouldBeVisible(group.readEntry(d->configShowThumbbarEntry, false)); setAutoSaveSettings(configGroupName(), true); d->viewContainer->setAutoSaveSettings(QLatin1String("ImageViewer Thumbbar"), true); //------------------------------------------------------------- d->rightSideBar->setConfigGroup(KConfigGroup(&group, QLatin1String("Right Sidebar"))); d->rightSideBar->loadState(); d->rightSideBar->populateTags(); slotSetupChanged(); } ImageWindow::~ImageWindow() { m_instance = 0; delete d->rightSideBar; delete d->thumbBar; delete d; } void ImageWindow::closeEvent(QCloseEvent* e) { if (!queryClose()) { e->ignore(); return; } // put right side bar in a defined state emit signalNoCurrentItem(); m_canvas->resetImage(); // There is one nasty habit with the thumbnail bar if it is floating: it // doesn't close when the parent window does, so it needs to be manually // closed. If the light table is opened again, its original state needs to // be restored. // This only needs to be done when closing a visible window and not when // destroying a closed window, since the latter case will always report that // the thumbnail bar isn't visible. if (isVisible()) { thumbBar()->hide(); } KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(configGroupName()); saveMainWindowSettings(group); saveSettings(); d->rightSideBar->setConfigGroup(KConfigGroup(&group, "Right Sidebar")); d->rightSideBar->saveState(); DXmlGuiWindow::closeEvent(e); e->accept(); } void ImageWindow::showEvent(QShowEvent*) { // Restore the visibility of the thumbbar and start autosaving again. thumbBar()->restoreVisibility(); } bool ImageWindow::queryClose() { // Note: we re-implement closeEvent above for this window. // Additionally, queryClose is called from DigikamApp. // wait if a save operation is currently running if (!waitForSavingToComplete()) { return false; } return promptUserSave(d->currentUrl()); } void ImageWindow::setupUserArea() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(configGroupName()); QWidget* const widget = new QWidget(this); QHBoxLayout* const hlay = new QHBoxLayout(widget); m_splitter = new SidebarSplitter(widget); d->viewContainer = new KMainWindow(widget, Qt::Widget); m_splitter->addWidget(d->viewContainer); m_stackView = new EditorStackView(d->viewContainer); m_canvas = new Canvas(m_stackView); d->viewContainer->setCentralWidget(m_stackView); m_splitter->setFrameStyle(QFrame::NoFrame); m_splitter->setFrameShape(QFrame::NoFrame); m_splitter->setFrameShadow(QFrame::Plain); m_splitter->setStretchFactor(0, 10); // set Canvas default size to max. m_splitter->setOpaqueResize(false); m_canvas->makeDefaultEditingCanvas(); m_stackView->setCanvas(m_canvas); m_stackView->setViewMode(EditorStackView::CanvasMode); d->rightSideBar = new ImagePropertiesSideBarDB(widget, m_splitter, Qt::RightEdge, true); d->rightSideBar->setObjectName(QLatin1String("ImageEditor Right Sidebar")); d->rightSideBar->getFiltersHistoryTab()->addOpenImageAction(); hlay->addWidget(m_splitter); hlay->addWidget(d->rightSideBar); hlay->setContentsMargins(QMargins()); hlay->setSpacing(0); // Code to check for the now depreciated HorizontalThumbar directive. It // is found, it is honored and deleted. The state will from than on be saved // by d->viewContainers built-in mechanism. Qt::DockWidgetArea dockArea = Qt::LeftDockWidgetArea; if (group.hasKey(d->configHorizontalThumbbarEntry)) { if (group.readEntry(d->configHorizontalThumbbarEntry, true)) { // Horizontal thumbbar layout dockArea = Qt::TopDockWidgetArea; } group.deleteEntry(d->configHorizontalThumbbarEntry); } d->imageInfoModel = new ImageListModel(this); d->imageFilterModel = new ImageFilterModel(this); d->imageFilterModel->setSourceImageModel(d->imageInfoModel); d->imageInfoModel->setWatchFlags(d->imageFilterModel->suggestedWatchFlags()); d->imageInfoModel->setThumbnailLoadThread(ThumbnailLoadThread::defaultIconViewThread()); d->imageFilterModel->setCategorizationMode(ImageSortSettings::NoCategories); d->imageFilterModel->setStringTypeNatural(ApplicationSettings::instance()->isStringTypeNatural()); d->imageFilterModel->setSortRole((ImageSortSettings::SortRole)ApplicationSettings::instance()->getImageSortOrder()); d->imageFilterModel->setSortOrder((ImageSortSettings::SortOrder)ApplicationSettings::instance()->getImageSorting()); d->imageFilterModel->setAllGroupsOpen(true); // disable filtering out by group, see bug #283847 d->imageFilterModel->sort(0); // an initial sorting is necessary d->dragDropHandler = new ImageDragDropHandler(d->imageInfoModel); d->dragDropHandler->setReadOnlyDrop(true); d->imageInfoModel->setDragDropHandler(d->dragDropHandler); // The thumb bar is placed in a detachable/dockable widget. d->thumbBarDock = new ThumbBarDock(d->viewContainer, Qt::Tool); d->thumbBarDock->setObjectName(QLatin1String("editor_thumbbar")); d->thumbBar = new ImageThumbnailBar(d->thumbBarDock); d->thumbBar->setModels(d->imageInfoModel, d->imageFilterModel); d->thumbBarDock->setWidget(d->thumbBar); d->viewContainer->addDockWidget(dockArea, d->thumbBarDock); d->thumbBarDock->setFloating(false); //d->thumbBar->slotDockLocationChanged(dockArea); setCentralWidget(widget); } void ImageWindow::setupConnections() { setupStandardConnections(); connect(this, SIGNAL(loadCurrentLater()), this, SLOT(slotLoadCurrent()), Qt::QueuedConnection); // To toggle properly keyboards shortcuts from comments & tags side bar tab. connect(d->rightSideBar, SIGNAL(signalNextItem()), this, SLOT(slotForward())); connect(d->rightSideBar, SIGNAL(signalPrevItem()), this, SLOT(slotBackward())); connect(d->rightSideBar->getFiltersHistoryTab(), SIGNAL(actionTriggered(ImageInfo)), this, SLOT(openImage(ImageInfo))); connect(this, SIGNAL(signalSelectionChanged(QRect)), d->rightSideBar, SLOT(slotImageSelectionChanged(QRect))); connect(this, SIGNAL(signalNoCurrentItem()), d->rightSideBar, SLOT(slotNoCurrentItem())); ImageAttributesWatch* watch = ImageAttributesWatch::instance(); connect(watch, SIGNAL(signalFileMetadataChanged(QUrl)), this, SLOT(slotFileMetadataChanged(QUrl))); /* connect(CoreDbAccess::databaseWatch(), SIGNAL(collectionImageChange(CollectionImageChangeset)), this, SLOT(slotCollectionImageChange(CollectionImageChangeset)), Qt::QueuedConnection); connect(d->imageFilterModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(slotRowsAboutToBeRemoved(QModelIndex,int,int))); */ connect(d->thumbBar, SIGNAL(currentChanged(ImageInfo)), this, SLOT(slotThumbBarImageSelected(ImageInfo))); connect(d->dragDropHandler, SIGNAL(imageInfosDropped(QList)), this, SLOT(slotDroppedOnThumbbar(QList))); connect(d->thumbBarDock, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), d->thumbBar, SLOT(slotDockLocationChanged(Qt::DockWidgetArea))); connect(d->imageInfoModel, SIGNAL(allRefreshingFinished()), this, SLOT(slotThumbBarModelReady())); connect(ApplicationSettings::instance(), SIGNAL(setupChanged()), this, SLOT(slotSetupChanged())); } void ImageWindow::setupActions() { setupStandardActions(); KActionCollection* const ac = actionCollection(); d->toMainWindowAction = new QAction(QIcon::fromTheme(QLatin1String("view-list-icons")), i18nc("@action Finish editing, close editor, back to main window", "Close Editor"), this); connect(d->toMainWindowAction, SIGNAL(triggered()), this, SLOT(slotToMainWindow())); ac->addAction(QLatin1String("imageview_tomainwindow"), d->toMainWindowAction); // -- Special Delete actions --------------------------------------------------------------- // Pop up dialog to ask user whether to permanently delete d->fileDeletePermanentlyAction = new QAction(QIcon::fromTheme(QLatin1String("edit-delete")), i18n("Delete File Permanently"), this); connect(d->fileDeletePermanentlyAction, SIGNAL(triggered()), this, SLOT(slotDeleteCurrentItemPermanently())); ac->addAction(QLatin1String("image_delete_permanently"), d->fileDeletePermanentlyAction); ac->setDefaultShortcut(d->fileDeletePermanentlyAction, Qt::SHIFT + Qt::Key_Delete); // These two actions are hidden, no menu entry, no toolbar entry, no shortcut. // Power users may add them. d->fileDeletePermanentlyDirectlyAction = new QAction(QIcon::fromTheme(QLatin1String("edit-delete")), i18n("Delete Permanently without Confirmation"), this); connect(d->fileDeletePermanentlyDirectlyAction, SIGNAL(triggered()), this, SLOT(slotDeleteCurrentItemPermanentlyDirectly())); ac->addAction(QLatin1String("image_delete_permanently_directly"), d->fileDeletePermanentlyDirectlyAction); d->fileTrashDirectlyAction = new QAction(QIcon::fromTheme(QLatin1String("user-trash")), i18n("Move to Trash without Confirmation"), this); connect(d->fileTrashDirectlyAction, SIGNAL(triggered()), this, SLOT(slotTrashCurrentItemDirectly())); ac->addAction(QLatin1String("image_trash_directly"), d->fileTrashDirectlyAction); // --------------------------------------------------------------------------------- createHelpActions(); // Labels shortcuts must be registered here to be saved in XML GUI files if user customize it. TagsActionMngr::defaultManager()->registerLabelsActions(ac); QAction* const editTitles = new QAction(i18n("Edit Titles"), this); ac->addAction(QLatin1String("edit_titles"), editTitles); ac->setDefaultShortcut(editTitles, Qt::META + Qt::Key_T); connect(editTitles, SIGNAL(triggered()), this, SLOT(slotRightSideBarActivateTitles())); QAction* const editComments = new QAction(i18n("Edit Comments"), this); ac->addAction(QLatin1String("edit_comments"), editComments); ac->setDefaultShortcut(editComments, Qt::META + Qt::Key_C); connect(editComments, SIGNAL(triggered()), this, SLOT(slotRightSideBarActivateComments())); QAction* const assignedTags = new QAction(i18n("Show Assigned Tags"), this); ac->addAction(QLatin1String("assigned _tags"), assignedTags); ac->setDefaultShortcut(assignedTags, Qt::META + Qt::Key_A); connect(assignedTags, SIGNAL(triggered()), this, SLOT(slotRightSideBarActivateAssignedTags())); } void ImageWindow::slotSetupChanged() { applyStandardSettings(); VersionManagerSettings versionSettings = ApplicationSettings::instance()->getVersionManagerSettings(); d->versionManager.setSettings(versionSettings); m_nonDestructive = versionSettings.enabled; toggleNonDestructiveActions(); d->imageFilterModel->setStringTypeNatural(ApplicationSettings::instance()->isStringTypeNatural()); d->imageFilterModel->setSortRole((ImageSortSettings::SortRole)ApplicationSettings::instance()->getImageSortOrder()); d->imageFilterModel->setSortOrder((ImageSortSettings::SortOrder)ApplicationSettings::instance()->getImageSorting()); d->rightSideBar->setStyle(ApplicationSettings::instance()->getSidebarTitleStyle()); } void ImageWindow::loadImageInfos(const ImageInfoList& imageInfoList, const ImageInfo& imageInfoCurrent, const QString& caption) { // Very first thing is to check for changes, user may choose to cancel operation if (!promptUserSave(d->currentUrl(), AskIfNeeded)) { return; } d->currentImageInfo = ImageInfo(); d->currentImageInfo = imageInfoCurrent; // Note: Addition is asynchronous, indexes not yet available // We enable thumbbar as soon as indexes are available // If not, we load imageInfoCurrent, then the index 0, then again imageInfoCurrent d->thumbBar->setEnabled(false); d->imageInfoModel->setImageInfos(imageInfoList); d->setThumbBarToCurrent(); if (!caption.isEmpty()) { setCaption(i18n("Image Editor - %1", caption)); } else { setCaption(i18n("Image Editor")); } // it can slightly improve the responsiveness when inserting an event loop run here QTimer::singleShot(0, this, SLOT(slotLoadImageInfosStage2())); } void ImageWindow::slotLoadImageInfosStage2() { // if window is minimized, show it if (isMinimized()) { KWindowSystem::unminimizeWindow(winId()); } slotLoadCurrent(); } void ImageWindow::slotThumbBarModelReady() { d->thumbBar->setEnabled(true); } void ImageWindow::openImage(const ImageInfo& info) { if (d->currentImageInfo == info) { return; } d->currentImageInfo = info; d->ensureModelContains(d->currentImageInfo); slotLoadCurrent(); } void ImageWindow::slotLoadCurrent() { if (!d->currentIsValid()) { return; } m_canvas->load(d->currentImageInfo.filePath(), m_IOFileSettings); QModelIndex next = d->nextIndex(); if (next.isValid()) { m_canvas->preload(d->imageInfo(next).filePath()); } d->setThumbBarToCurrent(); // Do this _after_ the canvas->load(), so that the main view histogram does not load // a smaller version if a raw image, and after that the EditorCore loads the full version. // So first let EditorCore create its loading task, only then any external objects. setViewToURL(d->currentUrl()); } void ImageWindow::setViewToURL(const QUrl& url) { emit signalURLChanged(url); } void ImageWindow::slotThumbBarImageSelected(const ImageInfo& info) { if (d->currentImageInfo == info || !d->thumbBar->isEnabled()) { return; } if (!promptUserSave(d->currentUrl(), AskIfNeeded, false)) { return; } d->currentImageInfo = info; slotLoadCurrent(); } void ImageWindow::slotDroppedOnThumbbar(const QList& infos) { // Check whether dropped image list is empty if (infos.isEmpty()) { return; } // Create new list and images that are not present currently in the thumbbar QList toAdd; foreach(const ImageInfo& it, infos) { QModelIndex index(d->imageFilterModel->indexForImageInfo(it)); if( !index.isValid() ) { toAdd.append(it); } } // Loading images if new images are dropped if (!toAdd.isEmpty()) { loadImageInfos(toAdd, toAdd.first(), QString()); } } void ImageWindow::slotFileOriginChanged(const QString& filePath) { // By redo or undo, we have virtually switched to a new image. // So we do _not_ load anything! ImageInfo newCurrent = ImageInfo::fromLocalFile(filePath); if (newCurrent.isNull() || !d->imageInfoModel->hasImage(newCurrent)) { return; } d->currentImageInfo = newCurrent; d->setThumbBarToCurrent(); setViewToURL(d->currentUrl()); } void ImageWindow::loadIndex(const QModelIndex& index) { if (!promptUserSave(d->currentUrl(), AskIfNeeded)) { return; } if (!index.isValid()) { return; } d->currentImageInfo = d->imageFilterModel->imageInfo(index); slotLoadCurrent(); } void ImageWindow::slotForward() { loadIndex(d->nextIndex()); } void ImageWindow::slotBackward() { loadIndex(d->previousIndex()); } void ImageWindow::slotFirst() { loadIndex(d->firstIndex()); } void ImageWindow::slotLast() { loadIndex(d->lastIndex()); } void ImageWindow::slotContextMenu() { if (m_contextMenu) { m_contextMenu->addSeparator(); addServicesMenu(); m_contextMenu->addSeparator(); TagsPopupMenu* assignTagsMenu = 0; TagsPopupMenu* removeTagsMenu = 0; // Bulk assignment/removal of tags -------------------------- QList idList; idList << d->currentImageInfo.id(); assignTagsMenu = new TagsPopupMenu(idList, TagsPopupMenu::RECENTLYASSIGNED, this); removeTagsMenu = new TagsPopupMenu(idList, TagsPopupMenu::REMOVE, this); assignTagsMenu->menuAction()->setText(i18n("Assign Tag")); removeTagsMenu->menuAction()->setText(i18n("Remove Tag")); m_contextMenu->addSeparator(); m_contextMenu->addMenu(assignTagsMenu); m_contextMenu->addMenu(removeTagsMenu); connect(assignTagsMenu, SIGNAL(signalTagActivated(int)), this, SLOT(slotAssignTag(int))); connect(removeTagsMenu, SIGNAL(signalTagActivated(int)), this, SLOT(slotRemoveTag(int))); connect(assignTagsMenu, SIGNAL(signalPopupTagsView()), d->rightSideBar, SLOT(slotPopupTagsView())); if (!CoreDbAccess().db()->hasTags(idList)) { m_contextMenu->menuAction()->setEnabled(false); } m_contextMenu->addSeparator(); // Assign Labels ------------------------------------------- QMenu* const menuLabels = new QMenu(i18n("Assign Labels"), m_contextMenu); PickLabelMenuAction* const pmenu = new PickLabelMenuAction(m_contextMenu); ColorLabelMenuAction* const cmenu = new ColorLabelMenuAction(m_contextMenu); RatingMenuAction* const rmenu = new RatingMenuAction(m_contextMenu); menuLabels->addAction(pmenu->menuAction()); menuLabels->addAction(cmenu->menuAction()); menuLabels->addAction(rmenu->menuAction()); m_contextMenu->addMenu(menuLabels); connect(pmenu, SIGNAL(signalPickLabelChanged(int)), this, SLOT(slotAssignPickLabel(int))); connect(cmenu, SIGNAL(signalColorLabelChanged(int)), this, SLOT(slotAssignColorLabel(int))); connect(rmenu, SIGNAL(signalRatingChanged(int)), this, SLOT(slotAssignRating(int))); // -------------------------------------------------------------- m_contextMenu->exec(QCursor::pos()); delete assignTagsMenu; delete removeTagsMenu; delete cmenu; delete pmenu; delete rmenu; delete menuLabels; } } void ImageWindow::slotChanged() { QString mpixels; QSize dims(m_canvas->imageWidth(), m_canvas->imageHeight()); mpixels.setNum(dims.width()*dims.height() / 1000000.0, 'f', 2); QString str = (!dims.isValid()) ? i18n("Unknown") : i18n("%1x%2 (%3Mpx)", dims.width(), dims.height(), mpixels); m_resLabel->setAdjustedText(str); if (!d->currentIsValid()) { return; } DImg* const img = m_canvas->interface()->getImg(); DImageHistory history = m_canvas->interface()->getImageHistory(); DImageHistory redoHistory = m_canvas->interface()->getImageHistoryOfFullRedo(); d->rightSideBar->itemChanged(d->currentImageInfo, m_canvas->getSelectedArea(), img, redoHistory); // Filters for redo will be turn in grey out d->rightSideBar->getFiltersHistoryTab()->setEnabledHistorySteps(history.actionCount()); /* if (!d->currentImageInfo.isNull()) { } else { d->rightSideBar->itemChanged(d->currentUrl(), m_canvas->getSelectedArea(), img); } */ } void ImageWindow::slotToggleTag(const QUrl& url, int tagID) { toggleTag(ImageInfo::fromUrl(url), tagID); } void ImageWindow::toggleTag(int tagID) { toggleTag(d->currentImageInfo, tagID); } void ImageWindow::toggleTag(const ImageInfo& info, int tagID) { if (!info.isNull()) { if (info.tagIds().contains(tagID)) { FileActionMngr::instance()->removeTag(info, tagID); } else { FileActionMngr::instance()->assignTag(info, tagID); } } } void ImageWindow::slotAssignTag(int tagID) { if (!d->currentImageInfo.isNull()) { FileActionMngr::instance()->assignTag(d->currentImageInfo, tagID); } } void ImageWindow::slotRemoveTag(int tagID) { if (!d->currentImageInfo.isNull()) { FileActionMngr::instance()->removeTag(d->currentImageInfo, tagID); } } void ImageWindow::slotAssignPickLabel(int pickId) { assignPickLabel(d->currentImageInfo, pickId); } void ImageWindow::slotAssignColorLabel(int colorId) { assignColorLabel(d->currentImageInfo, colorId); } void ImageWindow::assignPickLabel(const ImageInfo& info, int pickId) { if (!info.isNull()) { FileActionMngr::instance()->assignPickLabel(info, pickId); } } void ImageWindow::assignColorLabel(const ImageInfo& info, int colorId) { if (!info.isNull()) { FileActionMngr::instance()->assignColorLabel(info, colorId); } } void ImageWindow::slotAssignRating(int rating) { assignRating(d->currentImageInfo, rating); } void ImageWindow::assignRating(const ImageInfo& info, int rating) { rating = qMin(RatingMax, qMax(RatingMin, rating)); if (!info.isNull()) { FileActionMngr::instance()->assignRating(info, rating); } } void ImageWindow::slotRatingChanged(const QUrl& url, int rating) { assignRating(ImageInfo::fromUrl(url), rating); } void ImageWindow::slotColorLabelChanged(const QUrl& url, int color) { assignColorLabel(ImageInfo::fromUrl(url), color); } void ImageWindow::slotPickLabelChanged(const QUrl& url, int pick) { assignPickLabel(ImageInfo::fromUrl(url), pick); } void ImageWindow::slotUpdateItemInfo() { QString text = i18nc(" ( of )", "%1 (%2 of %3)", d->currentImageInfo.name(), QString::number(d->currentIndex().row() + 1), QString::number(d->imageFilterModel->rowCount())); m_nameLabel->setText(text); if (!m_actionEnabledState) { return; } if (d->imageInfoModel->rowCount() == 1) { m_backwardAction->setEnabled(false); m_forwardAction->setEnabled(false); m_firstAction->setEnabled(false); m_lastAction->setEnabled(false); } else { m_backwardAction->setEnabled(true); m_forwardAction->setEnabled(true); m_firstAction->setEnabled(true); m_lastAction->setEnabled(true); } if (d->currentIndex() == d->firstIndex()) { m_backwardAction->setEnabled(false); m_firstAction->setEnabled(false); } if (d->currentIndex() == d->lastIndex()) { m_forwardAction->setEnabled(false); m_lastAction->setEnabled(false); } /* // Disable some menu actions if the current root image URL // is not include in the digiKam Albums library database. // This is necessary when ImageEditor is opened from cameraclient. QUrl u(d->currentUrl().directory()); PAlbum* palbum = AlbumManager::instance()->findPAlbum(u); if (!palbum) { m_fileDeleteAction->setEnabled(false); } else { m_fileDeleteAction->setEnabled(true); } */ } void ImageWindow::slotSetup() { Setup::execDialog(this); } void ImageWindow::slotSetupICC() { Setup::execSinglePage(this, Setup::ICCPage); } void ImageWindow::slotToMainWindow() { close(); } void ImageWindow::saveIsComplete() { // With save(), we do not reload the image but just continue using the data. // This means that a saving operation does not lead to quality loss for // subsequent editing operations. // put image in cache, the LoadingCacheInterface cares for the details LoadingCacheInterface::putImage(m_savingContext.destinationURL.toLocalFile(), m_canvas->currentImage()); ImageInfo info = ScanController::instance()->scannedInfo(m_savingContext.destinationURL.toLocalFile()); // Save new face tags to the image saveFaceTagsToImage(info); // reset the orientation flag in the database DMetadata meta(m_canvas->currentImage().getMetadata()); d->currentImageInfo.setOrientation(meta.getImageOrientation()); // Pop-up a message to bring user when save is done. DNotificationWrapper(QLatin1String("editorsavefilecompleted"), i18n("Image saved successfully"), this, windowTitle()); resetOrigin(); QModelIndex next = d->nextIndex(); if (next.isValid()) { m_canvas->preload(d->imageInfo(next).filePath()); } slotUpdateItemInfo(); setViewToURL(d->currentImageInfo.fileUrl()); } void ImageWindow::saveVersionIsComplete() { qCDebug(DIGIKAM_GENERAL_LOG) << "save version done"; saveAsIsComplete(); } void ImageWindow::saveAsIsComplete() { qCDebug(DIGIKAM_GENERAL_LOG) << "Saved" << m_savingContext.srcURL << "to" << m_savingContext.destinationURL; // Nothing to be done if operating without database if (d->currentImageInfo.isNull()) { return; } if (CollectionManager::instance()->albumRootPath(m_savingContext.srcURL).isNull() || CollectionManager::instance()->albumRootPath(m_savingContext.destinationURL).isNull()) { // not in-collection operation - nothing to do return; } // copy the metadata of the original file to the new file qCDebug(DIGIKAM_GENERAL_LOG) << "was versioned" << (m_savingContext.executedOperation == SavingContext::SavingStateVersion) << "current" << d->currentImageInfo.id() << d->currentImageInfo.name() << "destinations" << m_savingContext.versionFileOperation.allFilePaths(); ImageInfo sourceInfo = d->currentImageInfo; // Set new current index. Employ synchronous scanning for this main file. d->currentImageInfo = ScanController::instance()->scannedInfo(m_savingContext.destinationURL.toLocalFile()); if (m_savingContext.destinationExisted) { // reset the orientation flag in the database DMetadata meta(m_canvas->currentImage().getMetadata()); d->currentImageInfo.setOrientation(meta.getImageOrientation()); } QStringList derivedFilePaths; if (m_savingContext.executedOperation == SavingContext::SavingStateVersion) { derivedFilePaths = m_savingContext.versionFileOperation.allFilePaths(); } else { derivedFilePaths << m_savingContext.destinationURL.toLocalFile(); } // Will ensure files are scanned, and then copy attributes in a thread FileActionMngr::instance()->copyAttributes(sourceInfo, derivedFilePaths); // The model updates asynchronously, so we need to force addition of the main entry d->ensureModelContains(d->currentImageInfo); // Save new face tags to the image saveFaceTagsToImage(d->currentImageInfo); // set origin of EditorCore: "As if" the last saved image was loaded directly resetOriginSwitchFile(); // If the DImg is put in the cache under the new name, this means the new file will not be reloaded. // This may irritate users who want to check for quality loss in lossy formats. // In any case, only do that if the format did not change - too many assumptions otherwise (see bug #138949). if (m_savingContext.originalFormat == m_savingContext.format) { LoadingCacheInterface::putImage(m_savingContext.destinationURL.toLocalFile(), m_canvas->currentImage()); } // all that is done in slotLoadCurrent, except for loading d->thumbBar->setCurrentIndex(d->currentIndex()); QModelIndex next = d->nextIndex(); if (next.isValid()) { m_canvas->preload(d->imageInfo(next).filePath()); } setViewToURL(d->currentImageInfo.fileUrl()); slotUpdateItemInfo(); // Pop-up a message to bring user when save is done. DNotificationWrapper(QLatin1String("editorsavefilecompleted"), i18n("Image saved successfully"), this, windowTitle()); } void ImageWindow::prepareImageToSave() { if (!d->currentImageInfo.isNull()) { MetadataHub hub; hub.load(d->currentImageInfo); // Get face tags d->newFaceTags.clear(); QMultiMap faceTags; faceTags = hub.loadIntegerFaceTags(d->currentImageInfo); if (!faceTags.isEmpty()) { QSize tempS = d->currentImageInfo.dimensions(); QMap::const_iterator it; for (it = faceTags.constBegin() ; it != faceTags.constEnd() ; ++it) { // Start transform each face rect QRect faceRect = it.value().toRect(); int tempH = tempS.height(); int tempW = tempS.width(); qCDebug(DIGIKAM_GENERAL_LOG) << ">>>>>>>>>face rect before:" << faceRect.x() << faceRect.y() << faceRect.width() << faceRect.height(); for (int i = 0 ; i < m_transformQue.size() ; i++) { EditorWindow::TransformType type = m_transformQue[i]; switch (type) { case EditorWindow::TransformType::RotateLeft: faceRect = TagRegion::ajustToRotatedImg(faceRect, QSize(tempW, tempH), 1); std::swap(tempH, tempW); break; case EditorWindow::TransformType::RotateRight: faceRect = TagRegion::ajustToRotatedImg(faceRect, QSize(tempW, tempH), 0); std::swap(tempH, tempW); break; case EditorWindow::TransformType::FlipHorizontal: faceRect = TagRegion::ajustToFlippedImg(faceRect, QSize(tempW, tempH), 0); break; case EditorWindow::TransformType::FlipVertical: faceRect = TagRegion::ajustToFlippedImg(faceRect, QSize(tempW, tempH), 1); break; default: break; } qCDebug(DIGIKAM_GENERAL_LOG) << ">>>>>>>>>face rect transform:" << faceRect.x() << faceRect.y() << faceRect.width() << faceRect.height(); } d->newFaceTags.insertMulti(it.key(), QVariant(faceRect)); } } // Ensure there is a UUID for the source image in the database, // even if not in the source image's metadata if (d->currentImageInfo.uuid().isNull()) { QString uuid = m_canvas->interface()->ensureHasCurrentUuid(); d->currentImageInfo.setUuid(uuid); } else { m_canvas->interface()->provideCurrentUuid(d->currentImageInfo.uuid()); } } } void ImageWindow::saveFaceTagsToImage(const ImageInfo& info) { if (!info.isNull() && !d->newFaceTags.isEmpty()) { // Delete all old faces FaceTagsEditor().removeAllFaces(info.id()); QMap::const_iterator it; for (it = d->newFaceTags.constBegin() ; it != d->newFaceTags.constEnd() ; ++it) { int tagId = FaceTags::getOrCreateTagForPerson(it.key()); if (tagId) { TagRegion region(it.value().toRect()); FaceTagsEditor().add(info.id(), tagId, region, false); } else { qCDebug(DIGIKAM_GENERAL_LOG) << "Failed to create a person tag for name" << it.key(); } } MetadataHub hub; hub.load(info); QSize tempS = info.dimensions(); hub.setFaceTags(d->newFaceTags, tempS); hub.write(info.filePath(), MetadataHub::WRITE_ALL); } m_transformQue.clear(); d->newFaceTags.clear(); } VersionManager* ImageWindow::versionManager() const { return &d->versionManager; } bool ImageWindow::save() { prepareImageToSave(); startingSave(d->currentUrl()); return true; } bool ImageWindow::saveAs() { prepareImageToSave(); return startingSaveAs(d->currentUrl()); } bool ImageWindow::saveNewVersion() { prepareImageToSave(); return startingSaveNewVersion(d->currentUrl()); } bool ImageWindow::saveCurrentVersion() { prepareImageToSave(); return startingSaveCurrentVersion(d->currentUrl()); } bool ImageWindow::saveNewVersionAs() { prepareImageToSave(); return startingSaveNewVersionAs(d->currentUrl()); } bool ImageWindow::saveNewVersionInFormat(const QString& format) { prepareImageToSave(); return startingSaveNewVersionInFormat(d->currentUrl(), format); } QUrl ImageWindow::saveDestinationUrl() { return d->currentUrl(); } void ImageWindow::slotDeleteCurrentItem() { deleteCurrentItem(true, false); } void ImageWindow::slotDeleteCurrentItemPermanently() { deleteCurrentItem(true, true); } void ImageWindow::slotDeleteCurrentItemPermanentlyDirectly() { deleteCurrentItem(false, true); } void ImageWindow::slotTrashCurrentItemDirectly() { deleteCurrentItem(false, false); } void ImageWindow::deleteCurrentItem(bool ask, bool permanently) { // This function implements all four of the above slots. // The meaning of permanently differs depending on the value of ask if (d->currentImageInfo.isNull()) { return; } if (!promptUserDelete(d->currentUrl())) { return; } bool useTrash; if (ask) { bool preselectDeletePermanently = permanently; DeleteDialog dialog(this); QList urlList; urlList << d->currentUrl(); if (!dialog.confirmDeleteList(urlList, DeleteDialogMode::Files, preselectDeletePermanently ? DeleteDialogMode::NoChoiceDeletePermanently : DeleteDialogMode::NoChoiceTrash)) { return; } useTrash = !dialog.shouldDelete(); } else { useTrash = !permanently; } DIO::del(d->currentImageInfo, useTrash); // bring all (sidebar) to a defined state without letting them sit on the deleted file emit signalNoCurrentItem(); // We have database information, which means information will get through // everywhere. Just do it asynchronously. removeCurrent(); } void ImageWindow::removeCurrent() { if (!d->currentIsValid()) { return; } if (m_canvas->interface()->undoState().hasChanges) { m_canvas->slotRestore(); } d->imageInfoModel->removeImageInfo(d->currentImageInfo); if (d->imageInfoModel->isEmpty()) { // No image in the current Album -> Quit ImageEditor... QMessageBox::information(this, i18n("No Image in Current Album"), i18n("There is no image to show in the current album.\n" "The image editor will be closed.")); close(); } } void ImageWindow::slotFileMetadataChanged(const QUrl& url) { if (url == d->currentUrl()) { m_canvas->interface()->readMetadataFromFile(url.toLocalFile()); } } /* * Should all be done by ItemViewCategorized * void ImageWindow::slotRowsAboutToBeRemoved(const QModelIndex& parent, int start, int end) { // ignore when closed if (!isVisible() || !d->currentIsValid()) { return; } QModelIndex currentIndex = d->currentIndex(); if (currentIndex.row() >= start && currentIndex.row() <= end) { promptUserSave(d->currentUrl(), AlwaysNewVersion, false); // ensure selection int totalToRemove = end - start + 1; if (d->imageFilterModel->rowCount(parent) > totalToRemove) { if (end == d->imageFilterModel->rowCount(parent) - 1) { loadIndex(d->imageFilterModel->index(start - 1, 0)); // last remaining, no next one left } else { loadIndex(d->imageFilterModel->index(end + 1, 0)); // next remaining } } } }*/ /* void ImageWindow::slotCollectionImageChange(const CollectionImageChangeset& changeset) { bool needLoadCurrent = false; switch (changeset.operation()) { case CollectionImageChangeset::Removed: for (int i=0; iimageInfoList.size(); ++i) { if (changeset.containsImage(d->imageInfoList[i].id())) { if (d->currentImageInfo == d->imageInfoList[i]) { promptUserSave(d->currentUrl(), AlwaysNewVersion, false); if (removeItem(i)) { needLoadCurrent = true; } } else { removeItem(i); } --i; } } break; case CollectionImageChangeset::RemovedAll: for (int i=0; iimageInfoList.size(); ++i) { if (changeset.containsAlbum(d->imageInfoList[i].albumId())) { if (d->currentImageInfo == d->imageInfoList[i]) { promptUserSave(d->currentUrl(), AlwaysNewVersion, false); if (removeItem(i)) { needLoadCurrent = true; } } else { removeItem(i); } --i; } } break; default: break; } if (needLoadCurrent) { QTimer::singleShot(0, this, SLOT(slotLoadCurrent())); } } */ void ImageWindow::slotFilePrint() { printImage(d->currentUrl()); } void ImageWindow::slotPresentation() { PresentationMngr* const mngr = new PresentationMngr(this); foreach(const ImageInfo& info, d->imageInfoModel->imageInfos()) { mngr->addFile(info.fileUrl(), info.comment()); qApp->processEvents(); } mngr->showConfigDialog(); } void ImageWindow::slideShow(SlideShowSettings& settings) { m_cancelSlideShow = false; settings.exifRotate = MetadataSettings::instance()->settings().exifRotate; if (!d->imageInfoModel->isEmpty()) { // We have started image editor from Album GUI. we get picture comments from database. m_nameLabel->setProgressBarMode(StatusProgressBar::CancelProgressBarMode, i18n("Preparing slideshow. Please wait...")); float cnt = (float)d->imageInfoModel->rowCount(); int i = 0; foreach(const ImageInfo& info, d->imageInfoModel->imageInfos()) { SlidePictureInfo pictInfo; pictInfo.comment = info.comment(); pictInfo.rating = info.rating(); pictInfo.colorLabel = info.colorLabel(); pictInfo.pickLabel = info.pickLabel(); pictInfo.photoInfo = info.photoInfoContainer(); settings.pictInfoMap.insert(info.fileUrl(), pictInfo); settings.fileList << info.fileUrl(); m_nameLabel->setProgressValue((int)((i++ / cnt) * 100.0)); qApp->processEvents(); } } /* else { // We have started image editor from Camera GUI. we get picture comments from metadata. m_nameLabel->setProgressBarMode(StatusProgressBar::CancelProgressBarMode, i18n("Preparing slideshow. Please wait...")); cnt = (float)d->urlList.count(); DMetadata meta; settings.fileList = d->urlList; for (QList::Iterator it = d->urlList.begin() ; !m_cancelSlideShow && (it != d->urlList.end()) ; ++it) { SlidePictureInfo pictInfo; meta.load((*it).toLocalFile()); pictInfo.comment = meta.getImageComments()[QString("x-default")].caption; pictInfo.photoInfo = meta.getPhotographInformation(); settings.pictInfoMap.insert(*it, pictInfo); m_nameLabel->setProgressValue((int)((i++/cnt)*100.0)); qApp->processEvents(); } } */ m_nameLabel->setProgressBarMode(StatusProgressBar::TextMode, QString()); if (!m_cancelSlideShow) { SlideShow* const slide = new SlideShow(settings); TagsActionMngr::defaultManager()->registerActionsToWidget(slide); if (settings.startWithCurrent) { slide->setCurrentItem(d->currentUrl()); } connect(slide, SIGNAL(signalRatingChanged(QUrl,int)), this, SLOT(slotRatingChanged(QUrl,int))); connect(slide, SIGNAL(signalColorLabelChanged(QUrl,int)), this, SLOT(slotColorLabelChanged(QUrl,int))); connect(slide, SIGNAL(signalPickLabelChanged(QUrl,int)), this, SLOT(slotPickLabelChanged(QUrl,int))); connect(slide, SIGNAL(signalToggleTag(QUrl,int)), this, SLOT(slotToggleTag(QUrl,int))); slide->show(); } } void ImageWindow::dragMoveEvent(QDragMoveEvent* e) { int albumID; QList albumIDs; QList imageIDs; QList urls; if (DItemDrag::decode(e->mimeData(), urls, albumIDs, imageIDs) || DAlbumDrag::decode(e->mimeData(), urls, albumID) || DTagListDrag::canDecode(e->mimeData())) { e->accept(); return; } e->ignore(); } void ImageWindow::dropEvent(QDropEvent* e) { int albumID; QList albumIDs; QList imageIDs; QList urls; if (DItemDrag::decode(e->mimeData(), urls, albumIDs, imageIDs)) { ImageInfoList imageInfoList(imageIDs); if (imageInfoList.isEmpty()) { e->ignore(); return; } QString ATitle; AlbumManager* const man = AlbumManager::instance(); PAlbum* const palbum = man->findPAlbum(albumIDs.first()); if (palbum) { ATitle = palbum->title(); } loadImageInfos(imageInfoList, imageInfoList.first(), i18n("Album \"%1\"", ATitle)); e->accept(); } else if (DAlbumDrag::decode(e->mimeData(), urls, albumID)) { AlbumManager* const man = AlbumManager::instance(); QList itemIDs = CoreDbAccess().db()->getItemIDsInAlbum(albumID); ImageInfoList imageInfoList(itemIDs); if (imageInfoList.isEmpty()) { e->ignore(); return; } QString ATitle; PAlbum* const palbum = man->findPAlbum(albumIDs.first()); if (palbum) { ATitle = palbum->title(); } loadImageInfos(imageInfoList, imageInfoList.first(), i18n("Album \"%1\"", ATitle)); e->accept(); } else if (DTagListDrag::canDecode(e->mimeData())) { QList tagIDs; if (!DTagListDrag::decode(e->mimeData(), tagIDs)) { return; } AlbumManager* const man = AlbumManager::instance(); QList itemIDs = CoreDbAccess().db()->getItemIDsInTag(tagIDs.first(), true); ImageInfoList imageInfoList(itemIDs); if (imageInfoList.isEmpty()) { e->ignore(); return; } QString ATitle; TAlbum* const talbum = man->findTAlbum(tagIDs.first()); if (talbum) { ATitle = talbum->title(); } loadImageInfos(imageInfoList, imageInfoList.first(), i18n("Album \"%1\"", ATitle)); e->accept(); } else { e->ignore(); } } void ImageWindow::slotRevert() { if (!promptUserSave(d->currentUrl(), AskIfNeeded)) { return; } if (m_canvas->interface()->undoState().hasChanges) { m_canvas->slotRestore(); } } void ImageWindow::slotOpenOriginal() { if (!hasOriginalToRestore()) { return; } if (!promptUserSave(d->currentUrl(), AskIfNeeded)) { return; } // this time, with mustBeAvailable = true DImageHistory availableResolved = ImageScanner::resolvedImageHistory(m_canvas->interface()->getImageHistory(), true); QList originals = availableResolved.referredImagesOfType(HistoryImageId::Original); HistoryImageId originalId = m_canvas->interface()->getImageHistory().originalReferredImage(); if (originals.isEmpty()) { //TODO: point to remote collection QMessageBox::warning(this, i18nc("@title", "File Not Available"), i18nc("@info", "The original file (%1) is currently not available", originalId.m_fileName)); return; } QList imageInfos; foreach(const HistoryImageId& id, originals) { QUrl url = QUrl::fromLocalFile(id.m_filePath); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + QLatin1Char('/') + (id.m_fileName)); imageInfos << ImageInfo::fromUrl(url); } ImageScanner::sortByProximity(imageInfos, d->currentImageInfo); if (!imageInfos.isEmpty() && !imageInfos.first().isNull()) { openImage(imageInfos.first()); } } bool ImageWindow::hasOriginalToRestore() { // not implemented for db-less situation, so check for ImageInfo return !d->currentImageInfo.isNull() && EditorWindow::hasOriginalToRestore(); } DImageHistory ImageWindow::resolvedImageHistory(const DImageHistory& history) { return ImageScanner::resolvedImageHistory(history); } ThumbBarDock* ImageWindow::thumbBar() const { return d->thumbBarDock; } Sidebar* ImageWindow::rightSideBar() const { return (dynamic_cast(d->rightSideBar)); } void ImageWindow::slotComponentsInfo() { showDigikamComponentsInfo(); } void ImageWindow::slotDBStat() { showDigikamDatabaseStat(); } void ImageWindow::slotAddedDropedItems(QDropEvent* e) { int albumID; QList albumIDs; QList imageIDs; QList urls; ImageInfoList imgList; if (DItemDrag::decode(e->mimeData(), urls, albumIDs, imageIDs)) { imgList = ImageInfoList(imageIDs); } else if (DAlbumDrag::decode(e->mimeData(), urls, albumID)) { QList itemIDs = CoreDbAccess().db()->getItemIDsInAlbum(albumID); imgList = ImageInfoList(itemIDs); } else if (DTagListDrag::canDecode(e->mimeData())) { QList tagIDs; if (!DTagListDrag::decode(e->mimeData(), tagIDs)) { return; } QList itemIDs = CoreDbAccess().db()->getItemIDsInTag(tagIDs.first(), true); imgList = ImageInfoList(itemIDs); } e->accept(); if (!imgList.isEmpty()) { loadImageInfos(imgList, imgList.first(), QString()); } } void ImageWindow::slotFileWithDefaultApplication() { DFileOperations::openFilesWithDefaultApplication(QList() << d->currentUrl()); } void ImageWindow::addServicesMenu() { addServicesMenuForUrl(d->currentUrl()); } void ImageWindow::slotOpenWith(QAction* action) { openWith(d->currentUrl(), action); } void ImageWindow::slotRightSideBarActivateTitles() { d->rightSideBar->setActiveTab(d->rightSideBar->imageDescEditTab()); d->rightSideBar->imageDescEditTab()->setFocusToTitlesEdit(); } void ImageWindow::slotRightSideBarActivateComments() { d->rightSideBar->setActiveTab(d->rightSideBar->imageDescEditTab()); d->rightSideBar->imageDescEditTab()->setFocusToCommentsEdit(); } void ImageWindow::slotRightSideBarActivateAssignedTags() { d->rightSideBar->setActiveTab(d->rightSideBar->imageDescEditTab()); d->rightSideBar->imageDescEditTab()->activateAssignedTagsButton(); } void ImageWindow::slotImportFromScanner() { #ifdef HAVE_KSANE m_ksaneAction->activate(DigikamApp::instance()->scannerTargetPlace(), configGroupName()); connect(m_ksaneAction, SIGNAL(signalImportedImage(QUrl)), this, SLOT(slotImportedImagefromScanner(QUrl))); #endif } void ImageWindow::slotImportedImagefromScanner(const QUrl& url) { ImageInfo info = ScanController::instance()->scannedInfo(url.toLocalFile()); openImage(info); } void ImageWindow::slotEditGeolocation() { #ifdef HAVE_MARBLE ImageInfoList infos = d->thumbBar->allImageInfos(); if (infos.isEmpty()) { return; } TagModel* const tagModel = new TagModel(AbstractAlbumModel::IgnoreRootAlbum, this); TagPropertiesFilterModel* const filterModel = new TagPropertiesFilterModel(this); filterModel->setSourceAlbumModel(tagModel); filterModel->sort(0); QPointer dialog = new GeolocationEdit(filterModel, new DBInfoIface(this, d->thumbBar->allUrls()), QApplication::activeWindow()); dialog->setItems(ImageGPS::infosToItems(infos)); dialog->exec(); delete dialog; // Refresh Database with new metadata from files. foreach(const ImageInfo& inf, infos) { ScanController::instance()->scannedInfo(inf.fileUrl().toLocalFile()); } #endif } void ImageWindow::slotEditMetadata() { if (d->currentImageInfo.isNull()) return; QUrl url = d->currentImageInfo.fileUrl(); QPointer dialog = new MetadataEditDialog(QApplication::activeWindow(), QList() << url); dialog->exec(); delete dialog; // Refresh Database with new metadata from file. CollectionScanner scanner; scanner.scanFile(url.toLocalFile(), CollectionScanner::Rescan); } void ImageWindow::slotHtmlGallery() { #ifdef HAVE_HTMLGALLERY QPointer w = new HTMLWizard(this, new DBInfoIface(this, d->thumbBar->allUrls())); w->exec(); delete w; #endif } void ImageWindow::slotCalendar() { QPointer w = new CalWizard(d->thumbBar->allUrls(), this); w->exec(); delete w; } void ImageWindow::slotPanorama() { #ifdef HAVE_PANORAMA PanoManager::instance()->checkBinaries(); PanoManager::instance()->setItemsList(d->thumbBar->allUrls()); PanoManager::instance()->run(); #endif } void ImageWindow::slotVideoSlideshow() { #ifdef HAVE_MEDIAPLAYER QPointer w = new VidSlideWizard(this, new DBInfoIface(this, d->thumbBar->allUrls())); w->exec(); delete w; #endif } void ImageWindow::slotExpoBlending() { ExpoBlendingManager::instance()->checkBinaries(); ExpoBlendingManager::instance()->setItemsList(d->thumbBar->allUrls()); ExpoBlendingManager::instance()->run(); } void ImageWindow::slotSendByMail() { QPointer w = new MailWizard(this, new DBInfoIface(this, d->thumbBar->allUrls())); w->exec(); delete w; } void ImageWindow::slotPrintCreator() { QPointer w = new AdvPrintWizard(this, new DBInfoIface(this, d->thumbBar->allUrls())); w->exec(); delete w; } void ImageWindow::slotMediaServer() { DBInfoIface* const iface = new DBInfoIface(this, QList(), ApplicationSettings::Tools); // NOTE: We overwrite the default albums chooser object name for load save check items state between sessions. // The goal is not mix these settings with other export tools. iface->setObjectName(QLatin1String("SetupMediaServerIface")); QPointer w = new DMediaServerDlg(this, iface); w->exec(); delete w; } void ImageWindow::slotExportTool() { QAction* const tool = dynamic_cast(sender()); if (tool == m_exportDropboxAction) { QPointer w = new DBWindow(new DBInfoIface(this, d->thumbBar->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } + else if (tool == m_exportOnedriveAction) + { + QPointer w = new ODWindow(new DBInfoIface(this, d->thumbBar->allUrls(), + ApplicationSettings::ImportExport), this); + w->exec(); + delete w; + } else if (tool == m_exportFacebookAction) { QPointer w = new FbWindow(new DBInfoIface(this, d->thumbBar->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportFlickrAction) { QPointer w = new FlickrWindow(new DBInfoIface(this, d->thumbBar->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportGdriveAction) { QPointer w = new GSWindow(new DBInfoIface(this, d->thumbBar->allUrls(), ApplicationSettings::ImportExport), this, QLatin1String("googledriveexport")); w->exec(); delete w; } else if (tool == m_exportGphotoAction) { QPointer w = new GSWindow(new DBInfoIface(this, d->thumbBar->allUrls(), ApplicationSettings::ImportExport), this, QLatin1String("googlephotoexport")); w->exec(); delete w; } else if (tool == m_exportImageshackAction) { QPointer w = new ImageShackWindow(new DBInfoIface(this, d->thumbBar->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportImgurAction) { QPointer w = new ImgurWindow(new DBInfoIface(this, d->thumbBar->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportPiwigoAction) { QPointer w = new PiwigoWindow(new DBInfoIface(this, d->thumbBar->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportRajceAction) { QPointer w = new RajceWindow(new DBInfoIface(this, d->thumbBar->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportSmugmugAction) { QPointer w = new SmugWindow(new DBInfoIface(this, d->thumbBar->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportYandexfotkiAction) { QPointer w = new YFWindow(new DBInfoIface(this, d->thumbBar->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } #ifdef HAVE_MEDIAWIKI else if (tool == m_exportMediawikiAction) { QPointer w = new MediaWikiWindow(new DBInfoIface(this, d->thumbBar->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } #endif #ifdef HAVE_VKONTAKTE else if (tool == m_exportVkontakteAction) { QPointer w = new VKWindow(new DBInfoIface(this, d->thumbBar->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } #endif #ifdef HAVE_KIO else if (tool == m_exportFileTransferAction) { QPointer w = new FTExportWindow(new DBInfoIface(this, d->thumbBar->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } #endif } void ImageWindow::slotImportTool() { QAction* const tool = dynamic_cast(sender()); if (tool == m_importGphotoAction) { QPointer w = new GSWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this, QLatin1String("googlephotoimport")); w->exec(); delete w; } else if (tool == m_importSmugmugAction) { QPointer w = new SmugWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this, true); w->exec(); delete w; } #ifdef HAVE_KIO else if (tool == m_importFileTransferAction) { QPointer w = new FTImportWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } #endif } } // namespace Digikam diff --git a/core/utilities/imageeditor/main/imagewindow_p.h b/core/utilities/imageeditor/main/imagewindow_p.h index fa1e15f323..bda4066b81 100644 --- a/core/utilities/imageeditor/main/imagewindow_p.h +++ b/core/utilities/imageeditor/main/imagewindow_p.h @@ -1,287 +1,288 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2004-02-12 * Description : digiKam image editor GUI * * Copyright (C) 2004-2005 by Renchi Raju * Copyright (C) 2004-2018 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_IMAGE_WINDOW_PRIVATE_H #define DIGIKAM_IMAGE_WINDOW_PRIVATE_H // Local includes #include "versionmanager.h" #include "dlayoutbox.h" #include "album.h" #include "coredb.h" #include "albummanager.h" #include "albummodel.h" #include "albumfiltermodel.h" #include "applicationsettings.h" #include "canvas.h" #include "collectionlocation.h" #include "collectionmanager.h" #include "collectionscanner.h" #include "componentsinfo.h" #include "coredbaccess.h" #include "coredbwatch.h" #include "coredbchangesets.h" #include "ddragobjects.h" #include "deletedialog.h" #include "dimg.h" #include "editorcore.h" #include "dimagehistory.h" #include "digikamapp.h" #include "dio.h" #include "dmetadata.h" #include "editorstackview.h" #include "fileactionmngr.h" #include "dfileoperations.h" #include "digikam_globals.h" #include "digikam_debug.h" #include "iccsettingscontainer.h" #include "imageattributeswatch.h" #include "imagefiltermodel.h" #include "imagedragdrop.h" #include "imagedescedittab.h" #include "imageinfo.h" #include "imagegps.h" #include "imagelistmodel.h" #include "imagepropertiessidebardb.h" #include "imagepropertiesversionstab.h" #include "imagescanner.h" #include "imagethumbnailbar.h" #include "iofilesettings.h" #include "dnotificationwrapper.h" #include "loadingcacheinterface.h" #include "metadatahub.h" #include "metadatasettings.h" #include "metadataedit.h" #include "colorlabelwidget.h" #include "picklabelwidget.h" #include "presentationmngr.h" #include "ratingwidget.h" #include "savingcontext.h" #include "scancontroller.h" #include "setup.h" #include "slideshow.h" #include "statusprogressbar.h" #include "syncjob.h" #include "tagsactionmngr.h" #include "tagscache.h" #include "tagspopupmenu.h" #include "tagregion.h" #include "thememanager.h" #include "thumbbardock.h" #include "thumbnailloadthread.h" #include "undostate.h" #include "dexpanderbox.h" #include "dbinfoiface.h" #include "calwizard.h" #include "expoblendingmanager.h" #include "mailwizard.h" #include "advprintwizard.h" #include "dmediaserverdlg.h" #include "facetagseditor.h" #include "dbwindow.h" +#include "odwindow.h" #include "fbwindow.h" #include "flickrwindow.h" #include "gswindow.h" #include "imageshackwindow.h" #include "imgurwindow.h" #include "piwigowindow.h" #include "rajcewindow.h" #include "smugwindow.h" #include "yfwindow.h" #ifdef HAVE_MEDIAWIKI # include "mediawikiwindow.h" #endif #ifdef HAVE_VKONTAKTE # include "vkwindow.h" #endif #ifdef HAVE_KIO # include "ftexportwindow.h" # include "ftimportwindow.h" #endif #ifdef HAVE_MARBLE # include "geolocationedit.h" #endif #ifdef HAVE_HTMLGALLERY # include "htmlwizard.h" #endif #ifdef HAVE_PANORAMA # include "panomanager.h" #endif #ifdef HAVE_MEDIAPLAYER # include "vidslidewizard.h" #endif namespace Digikam { class DatabaseVersionManager : public VersionManager { public: virtual QString toplevelDirectory(const QString& path) { CollectionLocation loc = CollectionManager::instance()->locationForPath(path); if (!loc.isNull()) { return loc.albumRootPath(); } return QLatin1String("/"); } }; // ----------------------------------------------------------------------------------------- class ImageWindow::Private { public: Private() : viewContainer(0), toMainWindowAction(0), fileDeletePermanentlyAction(0), fileDeletePermanentlyDirectlyAction(0), fileTrashDirectlyAction(0), imageInfoModel(0), imageFilterModel(0), dragDropHandler(0), thumbBar(0), thumbBarDock(0), rightSideBar(0) { } QModelIndex currentIndex() const { return imageFilterModel->indexForImageInfo(currentImageInfo); } QModelIndex currentSourceIndex() const { return imageInfoModel->indexForImageInfo(currentImageInfo); } bool currentIsValid() const { return !currentImageInfo.isNull(); } QUrl currentUrl() const { return currentImageInfo.fileUrl(); } QModelIndex nextIndex() const { return imageFilterModel->index(currentIndex().row() + 1, 0); } QModelIndex previousIndex() const { return imageFilterModel->index(currentIndex().row() - 1, 0); } QModelIndex firstIndex() const { return imageFilterModel->index(0, 0); } QModelIndex lastIndex() const { return imageFilterModel->index(imageFilterModel->rowCount() - 1, 0); } ImageInfo imageInfo(const QModelIndex& index) const { return imageFilterModel->imageInfo(index); } void setThumbBarToCurrent() { QModelIndex index = imageFilterModel->indexForImageInfo(currentImageInfo); if (index.isValid()) { thumbBar->setCurrentIndex(index); } else { thumbBar->setCurrentWhenAvailable(currentImageInfo.id()); } } void ensureModelContains(const ImageInfo& info) { if (!imageInfoModel->hasImage(info)) { imageInfoModel->addImageInfoSynchronously(info); imageFilterModel->sort(imageFilterModel->sortColumn()); } } public: static const QString configShowThumbbarEntry; static const QString configHorizontalThumbbarEntry; KMainWindow* viewContainer; QAction* toMainWindowAction; // Delete actions QAction* fileDeletePermanentlyAction; QAction* fileDeletePermanentlyDirectlyAction; QAction* fileTrashDirectlyAction; ImageInfo currentImageInfo; ImageListModel* imageInfoModel; ImageFilterModel* imageFilterModel; ImageDragDropHandler* dragDropHandler; ImageThumbnailBar* thumbBar; ThumbBarDock* thumbBarDock; ImagePropertiesSideBarDB* rightSideBar; DatabaseVersionManager versionManager; QMultiMap newFaceTags; }; const QString ImageWindow::Private::configShowThumbbarEntry(QLatin1String("Show Thumbbar")); const QString ImageWindow::Private::configHorizontalThumbbarEntry(QLatin1String("HorizontalThumbbar")); } // namespace Digikam #endif // DIGIKAM_IMAGE_WINDOW_PRIVATE_H diff --git a/core/utilities/lighttable/lighttablewindow.cpp b/core/utilities/lighttable/lighttablewindow.cpp index dddedcb679..14e3a5da59 100644 --- a/core/utilities/lighttable/lighttablewindow.cpp +++ b/core/utilities/lighttable/lighttablewindow.cpp @@ -1,2081 +1,2089 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2007-03-05 * Description : digiKam light table GUI * * Copyright (C) 2007-2018 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "lighttablewindow.h" #include "lighttablewindow_p.h" // Qt includes #include #include #include #include #include #include #include #include // KDE includes #include #include // Local includes #include "drawdecoder.h" #include "digikam_debug.h" #include "componentsinfo.h" #include "digikamapp.h" #include "thememanager.h" #include "dimg.h" #include "dio.h" #include "dmetadata.h" #include "dfileoperations.h" #include "metadatasettings.h" #include "metadataedit.h" #include "applicationsettings.h" #include "albummanager.h" #include "loadingcacheinterface.h" #include "deletedialog.h" #include "iccsettings.h" #include "imagewindow.h" #include "imagegps.h" #include "imagedescedittab.h" #include "presentationmngr.h" #include "slideshowbuilder.h" #include "slideshow.h" #include "setup.h" #include "syncjob.h" #include "lighttablepreview.h" #include "albummodel.h" #include "albumfiltermodel.h" #include "coredbchangesets.h" #include "collectionscanner.h" #include "scancontroller.h" #include "tagsactionmngr.h" #include "thumbbardock.h" #include "thumbnailsize.h" #include "thumbnailloadthread.h" #include "dexpanderbox.h" #include "dbinfoiface.h" #include "calwizard.h" #include "expoblendingmanager.h" #include "mailwizard.h" #include "advprintwizard.h" #include "dmediaserverdlg.h" #include "dbwindow.h" +#include "odwindow.h" #include "fbwindow.h" #include "flickrwindow.h" #include "gswindow.h" #include "imageshackwindow.h" #include "imgurwindow.h" #include "piwigowindow.h" #include "rajcewindow.h" #include "smugwindow.h" #include "yfwindow.h" #ifdef HAVE_MEDIAWIKI # include "mediawikiwindow.h" #endif #ifdef HAVE_VKONTAKTE # include "vkwindow.h" #endif #ifdef HAVE_KIO # include "ftexportwindow.h" # include "ftimportwindow.h" #endif #ifdef HAVE_MARBLE # include "geolocationedit.h" #endif #ifdef HAVE_HTMLGALLERY # include "htmlwizard.h" #endif #ifdef HAVE_PANORAMA # include "panomanager.h" #endif #ifdef HAVE_MEDIAPLAYER # include "vidslidewizard.h" #endif namespace Digikam { LightTableWindow* LightTableWindow::m_instance = 0; LightTableWindow* LightTableWindow::lightTableWindow() { if (!m_instance) { new LightTableWindow(); } return m_instance; } bool LightTableWindow::lightTableWindowCreated() { return m_instance; } LightTableWindow::LightTableWindow() : DXmlGuiWindow(0), d(new Private) { setConfigGroupName(QLatin1String("LightTable Settings")); setXMLFile(QLatin1String("lighttablewindowui5.rc")); m_instance = this; setWindowFlags(Qt::Window); setCaption(i18n("Light Table")); // We don't want to be deleted on close setAttribute(Qt::WA_DeleteOnClose, false); setFullScreenOptions(FS_LIGHTTABLE); // -- Build the GUI ------------------------------- setupUserArea(); setupActions(); setupStatusBar(); // ------------------------------------------------ setupConnections(); slotColorManagementOptionsChanged(); readSettings(); d->leftSideBar->populateTags(); d->rightSideBar->populateTags(); applySettings(); setAutoSaveSettings(configGroupName(), true); } LightTableWindow::~LightTableWindow() { m_instance = 0; delete d->thumbView; delete d->rightSideBar; delete d->leftSideBar; delete d; } void LightTableWindow::readSettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(configGroupName()); d->hSplitter->restoreState(group, QLatin1String("Horizontal Splitter State")); d->barViewDock->setShouldBeVisible(group.readEntry(QLatin1String("Show Thumbbar"), true)); d->navigateByPairAction->setChecked(group.readEntry(QLatin1String("Navigate By Pair"), false)); slotToggleNavigateByPair(); d->leftSideBar->setConfigGroup(KConfigGroup(&group, QLatin1String("Left Sidebar"))); d->leftSideBar->loadState(); d->rightSideBar->setConfigGroup(KConfigGroup(&group, QLatin1String("Right Sidebar"))); d->rightSideBar->loadState(); readFullScreenSettings(group); } void LightTableWindow::writeSettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(configGroupName()); d->hSplitter->saveState(group, QLatin1String("Horizontal Splitter State")); group.writeEntry(QLatin1String("Show Thumbbar"), d->barViewDock->shouldBeVisible()); group.writeEntry(QLatin1String("Navigate By Pair"), d->navigateByPairAction->isChecked()); group.writeEntry(QLatin1String("Clear On Close"), d->clearOnCloseAction->isChecked()); d->leftSideBar->setConfigGroup(KConfigGroup(&group, QLatin1String("Left Sidebar"))); d->leftSideBar->saveState(); d->rightSideBar->setConfigGroup(KConfigGroup(&group, QLatin1String("Right Sidebar"))); d->rightSideBar->saveState(); config->sync(); } void LightTableWindow::applySettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(configGroupName()); d->autoLoadOnRightPanel = group.readEntry(QLatin1String("Auto Load Right Panel"), true); d->autoSyncPreview = group.readEntry(QLatin1String("Auto Sync Preview"), true); d->clearOnCloseAction->setChecked(group.readEntry(QLatin1String("Clear On Close"), false)); slotApplicationSettingsChanged(); // Restore full screen Mode readFullScreenSettings(group); // NOTE: Image orientation settings in thumbbar is managed by image model. refreshView(); } void LightTableWindow::refreshView() { d->leftSideBar->refreshTagsView(); d->rightSideBar->refreshTagsView(); } void LightTableWindow::closeEvent(QCloseEvent* e) { if (!e) { return; } if (d->clearOnCloseAction->isChecked()) { slotClearItemsList(); } // There is one nasty habit with the thumbnail bar if it is floating: it // doesn't close when the parent window does, so it needs to be manually // closed. If the light table is opened again, its original state needs to // be restored. // This only needs to be done when closing a visible window and not when // destroying a closed window, since the latter case will always report that // the thumbnail bar isn't visible. if (isVisible()) { d->barViewDock->hide(); } writeSettings(); DXmlGuiWindow::closeEvent(e); e->accept(); } void LightTableWindow::showEvent(QShowEvent*) { // Restore the visibility of the thumbbar and start autosaving again. d->barViewDock->restoreVisibility(); } void LightTableWindow::setupUserArea() { QWidget* const mainW = new QWidget(this); d->hSplitter = new SidebarSplitter(Qt::Horizontal, mainW); QHBoxLayout* const hlay = new QHBoxLayout(mainW); // The left sidebar d->leftSideBar = new ImagePropertiesSideBarDB(mainW, d->hSplitter, Qt::LeftEdge, true); // The central preview is wrapped in a KMainWindow so that the thumbnail // bar can float around it. KMainWindow* const viewContainer = new KMainWindow(mainW, Qt::Widget); d->hSplitter->addWidget(viewContainer); d->previewView = new LightTableView(viewContainer); viewContainer->setCentralWidget(d->previewView); // The right sidebar. d->rightSideBar = new ImagePropertiesSideBarDB(mainW, d->hSplitter, Qt::RightEdge, true); hlay->addWidget(d->leftSideBar); hlay->addWidget(d->hSplitter); hlay->addWidget(d->rightSideBar); hlay->setSpacing(0); hlay->setContentsMargins(QMargins()); hlay->setStretchFactor(d->hSplitter, 10); d->hSplitter->setFrameStyle(QFrame::NoFrame); d->hSplitter->setFrameShadow(QFrame::Plain); d->hSplitter->setFrameShape(QFrame::NoFrame); d->hSplitter->setOpaqueResize(false); d->hSplitter->setStretchFactor(1, 10); // set previewview+thumbbar container default size to max. // The thumb bar is placed in a detachable/dockable widget. d->barViewDock = new ThumbBarDock(viewContainer, Qt::Tool); d->barViewDock->setObjectName(QLatin1String("lighttable_thumbbar")); d->thumbView = new LightTableThumbBar(d->barViewDock); d->barViewDock->setWidget(d->thumbView); viewContainer->addDockWidget(Qt::TopDockWidgetArea, d->barViewDock); d->barViewDock->setFloating(false); // Restore the previous state. This doesn't emit the proper signals to the // dock widget, so it has to be manually reinitialized. viewContainer->setAutoSaveSettings(QLatin1String("LightTable Thumbbar"), true); connect(d->barViewDock, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), d->thumbView, SLOT(slotDockLocationChanged(Qt::DockWidgetArea))); d->barViewDock->reInitialize(); setCentralWidget(mainW); } void LightTableWindow::setupStatusBar() { d->leftZoomBar = new DZoomBar(statusBar()); d->leftZoomBar->setZoomToFitAction(d->leftZoomFitToWindowAction); d->leftZoomBar->setZoomTo100Action(d->leftZoomTo100percents); d->leftZoomBar->setZoomPlusAction(d->leftZoomPlusAction); d->leftZoomBar->setZoomMinusAction(d->leftZoomMinusAction); d->leftZoomBar->setBarMode(DZoomBar::PreviewZoomCtrl); d->leftZoomBar->setEnabled(false); statusBar()->addWidget(d->leftZoomBar, 1); d->leftFileName = new DAdjustableLabel(statusBar()); d->leftFileName->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); statusBar()->addWidget(d->leftFileName, 10); d->statusProgressBar = new StatusProgressBar(statusBar()); d->statusProgressBar->setAlignment(Qt::AlignCenter); statusBar()->addWidget(d->statusProgressBar, 10); d->rightFileName = new DAdjustableLabel(statusBar()); d->rightFileName->setAlignment(Qt::AlignRight | Qt::AlignVCenter); statusBar()->addWidget(d->rightFileName, 10); d->rightZoomBar = new DZoomBar(statusBar()); d->rightZoomBar->setZoomToFitAction(d->rightZoomFitToWindowAction); d->rightZoomBar->setZoomTo100Action(d->rightZoomTo100percents); d->rightZoomBar->setZoomPlusAction(d->rightZoomPlusAction); d->rightZoomBar->setZoomMinusAction(d->rightZoomMinusAction); d->rightZoomBar->setBarMode(DZoomBar::PreviewZoomCtrl); d->rightZoomBar->setEnabled(false); statusBar()->addWidget(d->rightZoomBar, 1); } void LightTableWindow::setupConnections() { connect(ApplicationSettings::instance(), SIGNAL(setupChanged()), this, SLOT(slotApplicationSettingsChanged())); connect(ThemeManager::instance(), SIGNAL(signalThemeChanged()), this, SLOT(slotThemeChanged())); connect(IccSettings::instance(), SIGNAL(settingsChanged()), this, SLOT(slotColorManagementOptionsChanged())); // Thumbs bar connections --------------------------------------- connect(d->thumbView, SIGNAL(signalSetItemOnLeftPanel(ImageInfo)), this, SLOT(slotSetItemOnLeftPanel(ImageInfo))); connect(d->thumbView, SIGNAL(signalSetItemOnRightPanel(ImageInfo)), this, SLOT(slotSetItemOnRightPanel(ImageInfo))); connect(d->thumbView, SIGNAL(signalRemoveItem(ImageInfo)), this, SLOT(slotRemoveItem(ImageInfo))); connect(d->thumbView, SIGNAL(signalEditItem(ImageInfo)), this, SLOT(slotEditItem(ImageInfo))); connect(d->thumbView, SIGNAL(signalClearAll()), this, SLOT(slotClearItemsList())); connect(d->thumbView, SIGNAL(signalDroppedItems(QList)), this, SLOT(slotThumbbarDroppedItems(QList))); connect(d->thumbView, SIGNAL(currentChanged(ImageInfo)), this, SLOT(slotItemSelected(ImageInfo))); connect(d->thumbView, SIGNAL(signalContentChanged()), this, SLOT(slotRefreshStatusBar())); // Zoom bars connections ----------------------------------------- connect(d->leftZoomBar, SIGNAL(signalZoomSliderChanged(int)), d->previewView, SLOT(slotLeftZoomSliderChanged(int))); connect(d->leftZoomBar, SIGNAL(signalZoomValueEdited(double)), d->previewView, SLOT(setLeftZoomFactor(double))); connect(d->rightZoomBar, SIGNAL(signalZoomSliderChanged(int)), d->previewView, SLOT(slotRightZoomSliderChanged(int))); connect(d->rightZoomBar, SIGNAL(signalZoomValueEdited(double)), d->previewView, SLOT(setRightZoomFactor(double))); // View connections --------------------------------------------- connect(d->previewView, SIGNAL(signalLeftPopupTagsView()), d->leftSideBar, SLOT(slotPopupTagsView())); connect(d->previewView, SIGNAL(signalRightPopupTagsView()), d->rightSideBar, SLOT(slotPopupTagsView())); connect(d->previewView, SIGNAL(signalLeftZoomFactorChanged(double)), this, SLOT(slotLeftZoomFactorChanged(double))); connect(d->previewView, SIGNAL(signalRightZoomFactorChanged(double)), this, SLOT(slotRightZoomFactorChanged(double))); connect(d->previewView, SIGNAL(signalEditItem(ImageInfo)), this, SLOT(slotEditItem(ImageInfo))); connect(d->previewView, SIGNAL(signalDeleteItem(ImageInfo)), this, SLOT(slotDeleteItem(ImageInfo))); connect(d->previewView, SIGNAL(signalSlideShow()), this, SLOT(slotSlideShowAll())); connect(d->previewView, SIGNAL(signalLeftSlideShowCurrent()), this, SLOT(slotLeftSlideShowManualFromCurrent())); connect(d->previewView, SIGNAL(signalRightSlideShowCurrent()), this, SLOT(slotRightSlideShowManualFromCurrent())); connect(d->previewView, SIGNAL(signalLeftDroppedItems(ImageInfoList)), this, SLOT(slotLeftDroppedItems(ImageInfoList))); connect(d->previewView, SIGNAL(signalRightDroppedItems(ImageInfoList)), this, SLOT(slotRightDroppedItems(ImageInfoList))); connect(d->previewView, SIGNAL(signalToggleOnSyncPreview(bool)), this, SLOT(slotToggleOnSyncPreview(bool))); connect(d->previewView, SIGNAL(signalLeftPreviewLoaded(bool)), this, SLOT(slotLeftPreviewLoaded(bool))); connect(d->previewView, SIGNAL(signalRightPreviewLoaded(bool)), this, SLOT(slotRightPreviewLoaded(bool))); connect(d->previewView, SIGNAL(signalLeftPanelLeftButtonClicked()), this, SLOT(slotLeftPanelLeftButtonClicked())); connect(d->previewView, SIGNAL(signalRightPanelLeftButtonClicked()), this, SLOT(slotRightPanelLeftButtonClicked())); connect(this, SIGNAL(signalWindowHasMoved()), d->leftZoomBar, SLOT(slotUpdateTrackerPos())); connect(this, SIGNAL(signalWindowHasMoved()), d->rightZoomBar, SLOT(slotUpdateTrackerPos())); // -- FileWatch connections ------------------------------ LoadingCacheInterface::connectToSignalFileChanged(this, SLOT(slotFileChanged(QString))); } void LightTableWindow::setupActions() { // -- Standard 'File' menu actions --------------------------------------------- KActionCollection* const ac = actionCollection(); d->backwardAction = buildStdAction(StdBackAction, this, SLOT(slotBackward()), this); ac->addAction(QLatin1String("lighttable_backward"), d->backwardAction); ac->setDefaultShortcuts(d->backwardAction, QList() << Qt::Key_PageUp << Qt::Key_Backspace); d->forwardAction = buildStdAction(StdForwardAction, this, SLOT(slotForward()), this); ac->addAction(QLatin1String("lighttable_forward"), d->forwardAction); ac->setDefaultShortcuts(d->forwardAction, QList() << Qt::Key_PageDown << Qt::Key_Space); d->forwardAction->setEnabled(false); d->firstAction = new QAction(QIcon::fromTheme(QLatin1String("go-first")), i18n("&First"), this); d->firstAction->setEnabled(false); connect(d->firstAction, SIGNAL(triggered()), this, SLOT(slotFirst())); ac->addAction(QLatin1String("lighttable_first"), d->firstAction); ac->setDefaultShortcuts(d->firstAction, QList() << Qt::CTRL + Qt::Key_Home); d->lastAction = new QAction(QIcon::fromTheme(QLatin1String("go-last")), i18n("&Last"), this); d->lastAction->setEnabled(false); connect(d->lastAction, SIGNAL(triggered()), this, SLOT(slotLast())); ac->addAction(QLatin1String("lighttable_last"), d->lastAction); ac->setDefaultShortcuts(d->lastAction, QList() << Qt::CTRL + Qt::Key_End); d->setItemLeftAction = new QAction(QIcon::fromTheme(QLatin1String("go-previous")), i18n("On left"), this); d->setItemLeftAction->setEnabled(false); d->setItemLeftAction->setWhatsThis(i18n("Show item on left panel")); connect(d->setItemLeftAction, SIGNAL(triggered()), this, SLOT(slotSetItemLeft())); ac->addAction(QLatin1String("lighttable_setitemleft"), d->setItemLeftAction); ac->setDefaultShortcut(d->setItemLeftAction, Qt::CTRL + Qt::Key_L); d->setItemRightAction = new QAction(QIcon::fromTheme(QLatin1String("go-next")), i18n("On right"), this); d->setItemRightAction->setEnabled(false); d->setItemRightAction->setWhatsThis(i18n("Show item on right panel")); connect(d->setItemRightAction, SIGNAL(triggered()), this, SLOT(slotSetItemRight())); ac->addAction(QLatin1String("lighttable_setitemright"), d->setItemRightAction); ac->setDefaultShortcut(d->setItemRightAction, Qt::CTRL + Qt::Key_R); d->editItemAction = new QAction(QIcon::fromTheme(QLatin1String("document-edit")), i18n("Edit"), this); d->editItemAction->setEnabled(false); connect(d->editItemAction, SIGNAL(triggered()), this, SLOT(slotEditItem())); ac->addAction(QLatin1String("lighttable_edititem"), d->editItemAction); ac->setDefaultShortcut(d->editItemAction, Qt::Key_F4); QAction* const openWithAction = new QAction(QIcon::fromTheme(QLatin1String("preferences-desktop-filetype-association")), i18n("Open With Default Application"), this); openWithAction->setWhatsThis(i18n("Open the item with default assigned application.")); connect(openWithAction, SIGNAL(triggered()), this, SLOT(slotFileWithDefaultApplication())); ac->addAction(QLatin1String("open_with_default_application"), openWithAction); ac->setDefaultShortcut(openWithAction, Qt::META + Qt::Key_F4); d->removeItemAction = new QAction(QIcon::fromTheme(QLatin1String("list-remove")), i18n("Remove item from LightTable"), this); d->removeItemAction->setEnabled(false); connect(d->removeItemAction, SIGNAL(triggered()), this, SLOT(slotRemoveItem())); ac->addAction(QLatin1String("lighttable_removeitem"), d->removeItemAction); ac->setDefaultShortcut(d->removeItemAction, Qt::CTRL + Qt::Key_K); d->clearListAction = new QAction(QIcon::fromTheme(QLatin1String("edit-clear")), i18n("Remove all items from LightTable"), this); d->clearListAction->setEnabled(false); connect(d->clearListAction, SIGNAL(triggered()), this, SLOT(slotClearItemsList())); ac->addAction(QLatin1String("lighttable_clearlist"), d->clearListAction); ac->setDefaultShortcut(d->clearListAction, Qt::CTRL + Qt::SHIFT + Qt::Key_K); d->fileDeleteAction = new QAction(QIcon::fromTheme(QLatin1String("user-trash")), i18nc("Non-pluralized", "Move to Trash"), this); d->fileDeleteAction->setEnabled(false); connect(d->fileDeleteAction, SIGNAL(triggered()), this, SLOT(slotDeleteItem())); ac->addAction(QLatin1String("lighttable_filedelete"), d->fileDeleteAction); ac->setDefaultShortcut(d->fileDeleteAction, Qt::Key_Delete); d->fileDeleteFinalAction = new QAction(QIcon::fromTheme(QLatin1String("edit-delete")), i18n("Delete immediately"), this); d->fileDeleteFinalAction->setEnabled(false); connect(d->fileDeleteFinalAction, SIGNAL(triggered()), this, SLOT(slotDeleteFinalItem())); ac->addAction(QLatin1String("lighttable_filefinaldelete"), d->fileDeleteFinalAction); ac->setDefaultShortcut(d->fileDeleteFinalAction, Qt::SHIFT + Qt::Key_Delete); QAction* const closeAction = buildStdAction(StdCloseAction, this, SLOT(close()), this); ac->addAction(QLatin1String("lighttable_close"), closeAction); // -- Standard 'View' menu actions --------------------------------------------- d->syncPreviewAction = new QAction(QIcon::fromTheme(QLatin1String("view-split-left-right")), i18n("Synchronize"), this); d->syncPreviewAction->setEnabled(false); d->syncPreviewAction->setCheckable(true); d->syncPreviewAction->setWhatsThis(i18n("Synchronize preview from left and right panels")); connect(d->syncPreviewAction, SIGNAL(triggered()), this, SLOT(slotToggleSyncPreview())); ac->addAction(QLatin1String("lighttable_syncpreview"), d->syncPreviewAction); ac->setDefaultShortcut(d->syncPreviewAction, Qt::CTRL + Qt::SHIFT + Qt::Key_Y); d->navigateByPairAction = new QAction(QIcon::fromTheme(QLatin1String("system-run")), i18n("By Pair"), this); d->navigateByPairAction->setEnabled(false); d->navigateByPairAction->setCheckable(true); d->navigateByPairAction->setWhatsThis(i18n("Navigate by pairs with all items")); connect(d->navigateByPairAction, SIGNAL(triggered()), this, SLOT(slotToggleNavigateByPair())); ac->addAction(QLatin1String("lighttable_navigatebypair"), d->navigateByPairAction); ac->setDefaultShortcut(d->navigateByPairAction, Qt::CTRL + Qt::SHIFT + Qt::Key_P); d->clearOnCloseAction = new QAction(QIcon::fromTheme(QLatin1String("edit-clear")), i18n("Clear On Close"), this); d->clearOnCloseAction->setEnabled(true); d->clearOnCloseAction->setCheckable(true); d->clearOnCloseAction->setToolTip(i18n("Clear light table when it is closed")); d->clearOnCloseAction->setWhatsThis(i18n("Remove all images from the light table when it is closed")); ac->addAction(QLatin1String("lighttable_clearonclose"), d->clearOnCloseAction); ac->setDefaultShortcut(d->clearOnCloseAction, Qt::CTRL + Qt::SHIFT + Qt::Key_C); d->showBarAction = d->barViewDock->getToggleAction(this); ac->addAction(QLatin1String("lighttable_showthumbbar"), d->showBarAction); ac->setDefaultShortcut(d->showBarAction, Qt::CTRL + Qt::Key_T); createFullScreenAction(QLatin1String("lighttable_fullscreen")); createSidebarActions(); d->slideShowAction = new QAction(QIcon::fromTheme(QLatin1String("view-presentation")), i18n("Slideshow"), this); connect(d->slideShowAction, SIGNAL(triggered()), this, SLOT(slotSlideShowAll())); ac->addAction(QLatin1String("lighttable_slideshow"), d->slideShowAction); ac->setDefaultShortcut(d->slideShowAction, Qt::Key_F9); createPresentationAction(); // -- Standard 'Tools' menu actions ------------------------ createMetadataEditAction(); createGeolocationEditAction(); createHtmlGalleryAction(); createPanoramaAction(); createExpoBlendingAction(); createCalendarAction(); createVideoSlideshowAction(); createSendByMailAction(); createPrintCreatorAction(); createMediaServerAction(); createExportActions(); createImportActions(); // Left Panel Zoom Actions d->leftZoomPlusAction = buildStdAction(StdZoomInAction, d->previewView, SLOT(slotIncreaseLeftZoom()), this); d->leftZoomPlusAction->setEnabled(false); QKeySequence leftKeysPlus(d->leftZoomPlusAction->shortcut()[0], Qt::Key_Plus); ac->addAction(QLatin1String("lighttable_zoomplus_left"), d->leftZoomPlusAction); ac->setDefaultShortcut(d->leftZoomPlusAction, leftKeysPlus); d->leftZoomMinusAction = buildStdAction(StdZoomOutAction, d->previewView, SLOT(slotDecreaseLeftZoom()), this); d->leftZoomMinusAction->setEnabled(false); QKeySequence leftKeysMinus(d->leftZoomMinusAction->shortcut()[0], Qt::Key_Minus); ac->addAction(QLatin1String("lighttable_zoomminus_left"), d->leftZoomMinusAction); ac->setDefaultShortcut(d->leftZoomMinusAction, leftKeysMinus); d->leftZoomTo100percents = new QAction(QIcon::fromTheme(QLatin1String("zoom-original")), i18n("Zoom to 100%"), this); connect(d->leftZoomTo100percents, SIGNAL(triggered()), d->previewView, SLOT(slotLeftZoomTo100())); ac->addAction(QLatin1String("lighttable_zoomto100percents_left"), d->leftZoomTo100percents); ac->setDefaultShortcut(d->leftZoomTo100percents, Qt::CTRL + Qt::Key_Period); d->leftZoomFitToWindowAction = new QAction(QIcon::fromTheme(QLatin1String("zoom-fit-best")), i18n("Fit to &Window"), this); connect(d->leftZoomFitToWindowAction, SIGNAL(triggered()), d->previewView, SLOT(slotLeftFitToWindow())); ac->addAction(QLatin1String("lighttable_zoomfit2window_left"), d->leftZoomFitToWindowAction); ac->setDefaultShortcut(d->leftZoomFitToWindowAction, Qt::ALT + Qt::CTRL + Qt::Key_E); // Right Panel Zoom Actions d->rightZoomPlusAction = buildStdAction(StdZoomInAction, d->previewView, SLOT(slotIncreaseRightZoom()), this); d->rightZoomPlusAction->setEnabled(false); QKeySequence rightKeysPlus(d->rightZoomPlusAction->shortcut()[0], Qt::SHIFT + Qt::CTRL + Qt::Key_Plus, Qt::SHIFT + Qt::Key_Plus); ac->addAction(QLatin1String("lighttable_zoomplus_right"), d->rightZoomPlusAction); ac->setDefaultShortcut(d->rightZoomPlusAction, rightKeysPlus); d->rightZoomMinusAction = buildStdAction(StdZoomOutAction, d->previewView, SLOT(slotDecreaseRightZoom()), this); d->rightZoomMinusAction->setEnabled(false); QKeySequence rightKeysMinus(d->rightZoomMinusAction->shortcut()[0], Qt::SHIFT + Qt::CTRL + Qt::Key_Minus, Qt::SHIFT + Qt::Key_Minus); ac->addAction(QLatin1String("lighttable_zoomminus_right"), d->rightZoomMinusAction); ac->setDefaultShortcut(d->rightZoomMinusAction, rightKeysMinus); d->rightZoomTo100percents = new QAction(QIcon::fromTheme(QLatin1String("zoom-original")), i18n("Zoom to 100%"), this); connect(d->rightZoomTo100percents, SIGNAL(triggered()), d->previewView, SLOT(slotRightZoomTo100())); ac->addAction(QLatin1String("lighttable_zoomto100percents_right"), d->rightZoomTo100percents); ac->setDefaultShortcut(d->rightZoomTo100percents, Qt::SHIFT + Qt::CTRL + Qt::Key_Period); d->rightZoomFitToWindowAction = new QAction(QIcon::fromTheme(QLatin1String("zoom-fit-best")), i18n("Fit to &Window"), this); connect(d->rightZoomFitToWindowAction, SIGNAL(triggered()), d->previewView, SLOT(slotRightFitToWindow())); ac->addAction(QLatin1String("lighttable_zoomfit2window_right"), d->rightZoomFitToWindowAction); ac->setDefaultShortcut(d->rightZoomFitToWindowAction, Qt::SHIFT + Qt::CTRL + Qt::Key_E); // ----------------------------------------------------------- d->viewCMViewAction = new QAction(QIcon::fromTheme(QLatin1String("video-display")), i18n("Color-Managed View"), this); d->viewCMViewAction->setCheckable(true); connect(d->viewCMViewAction, SIGNAL(triggered()), this, SLOT(slotToggleColorManagedView())); ac->addAction(QLatin1String("color_managed_view"), d->viewCMViewAction); ac->setDefaultShortcut(d->viewCMViewAction, Qt::Key_F12); // ----------------------------------------------------------------------------- ThemeManager::instance()->registerThemeActions(this); // Standard 'Help' menu actions createHelpActions(); // Provides a menu entry that allows showing/hiding the toolbar(s) setStandardToolBarMenuEnabled(true); // Provides a menu entry that allows showing/hiding the statusbar createStandardStatusBarAction(); // Standard 'Configure' menu actions createSettingsActions(); // -- Keyboard-only actions ---------------------------------------------------- d->addPageUpDownActions(this, this); QAction* const altBackwardAction = new QAction(i18n("Previous Image"), this); ac->addAction(QLatin1String("lighttable_backward_shift_space"), altBackwardAction); ac->setDefaultShortcut(altBackwardAction, Qt::SHIFT + Qt::Key_Space); connect(altBackwardAction, SIGNAL(triggered()), this, SLOT(slotBackward())); // Labels shortcuts must be registered here to be saved in XML GUI files if user customize it. TagsActionMngr::defaultManager()->registerLabelsActions(ac); QAction* const editTitlesRight = new QAction(i18n("Edit Titles on the Right"), this); ac->addAction(QLatin1String("edit_titles_right"), editTitlesRight); ac->setDefaultShortcut(editTitlesRight, Qt::META + Qt::Key_T); connect(editTitlesRight, SIGNAL(triggered()), this, SLOT(slotRightSideBarActivateTitles())); QAction* const editCommentsRight = new QAction(i18n("Edit Comments on the Right"), this); ac->addAction(QLatin1String("edit_comments_right"), editCommentsRight); ac->setDefaultShortcut(editCommentsRight, Qt::META + Qt::Key_C); connect(editCommentsRight, SIGNAL(triggered()), this, SLOT(slotRightSideBarActivateComments())); QAction* const editTitlesLeft = new QAction(i18n("Edit Titles on the Left"), this); ac->addAction(QLatin1String("edit_titles_left"), editTitlesLeft); ac->setDefaultShortcut(editTitlesLeft, Qt::SHIFT + Qt::META + Qt::Key_T); connect(editTitlesLeft, SIGNAL(triggered()), this, SLOT(slotLeftSideBarActivateTitles())); QAction* const editCommentsLeft = new QAction(i18n("Edit Comments on the Left"), this); ac->addAction(QLatin1String("edit_comments_left"), editCommentsLeft); ac->setDefaultShortcut(editCommentsLeft, Qt::SHIFT + Qt::META + Qt::Key_C); connect(editCommentsLeft, SIGNAL(triggered()), this, SLOT(slotLeftSideBarActivateComments())); QAction* const assignedTagsRight = new QAction(i18n("Show Assigned Tags on the Right"), this); ac->addAction(QLatin1String("assigned _tags_right"), assignedTagsRight); ac->setDefaultShortcut(assignedTagsRight, Qt::META + Qt::Key_A); connect(assignedTagsRight, SIGNAL(triggered()), this, SLOT(slotRightSideBarActivateAssignedTags())); QAction* const assignedTagsLeft = new QAction(i18n("Show Assigned Tags on the Left"), this); ac->addAction(QLatin1String("assigned _tags_left"), assignedTagsLeft); ac->setDefaultShortcut(assignedTagsLeft, Qt::SHIFT + Qt::META + Qt::Key_A); connect(assignedTagsLeft, SIGNAL(triggered()), this, SLOT(slotLeftSideBarActivateAssignedTags())); // --------------------------------------------------------------------------------- createGUI(xmlFile()); cleanupActions(); showMenuBarAction()->setChecked(!menuBar()->isHidden()); // NOTE: workaround for bug #171080 } // Deal with items dropped onto the thumbbar (e.g. from the Album view) void LightTableWindow::slotThumbbarDroppedItems(const QList& list) { // Setting the third parameter of loadImageInfos to true // means that the images are added to the presently available images. loadImageInfos(ImageInfoList() << list, ImageInfo(), true); } // We get here either // - via CTRL+L (from the albumview) // a) digikamapp.cpp: CTRL+key_L leads to slotImageLightTable()) // b) digikamview.cpp: void DigikamView::slotImageLightTable() // calls d->iconView->insertToLightTable(list, info); // c) albumiconview.cpp: AlbumIconView::insertToLightTable // calls ltview->loadImageInfos(list, current); // - via drag&drop, i.e. calls issued by the ...Dropped... routines void LightTableWindow::loadImageInfos(const ImageInfoList& list, const ImageInfo& givenImageInfoCurrent, bool addTo) { // Clear all items before adding new images to the light table. qCDebug(DIGIKAM_GENERAL_LOG) << "Clearing LT" << (!addTo); if (!addTo) { slotClearItemsList(); } ImageInfoList l = list; ImageInfo imageInfoCurrent = givenImageInfoCurrent; if (imageInfoCurrent.isNull() && !l.isEmpty()) { imageInfoCurrent = l.first(); } d->thumbView->setItems(l); QModelIndex index = d->thumbView->findItemByInfo(imageInfoCurrent); if (index.isValid()) { d->thumbView->setCurrentIndex(index); } else { d->thumbView->setCurrentWhenAvailable(imageInfoCurrent.id()); } } bool LightTableWindow::isEmpty() const { return (d->thumbView->countItems() == 0); } void LightTableWindow::slotRefreshStatusBar() { d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode, i18np("%1 item on Light Table", "%1 items on Light Table", d->thumbView->countItems())); } void LightTableWindow::slotFileChanged(const QString& path) { QUrl url = QUrl::fromLocalFile(path); // NOTE: Thumbbar handle change through ImageCategorizedView if (!d->previewView->leftImageInfo().isNull()) { if (d->previewView->leftImageInfo().fileUrl() == url) { d->previewView->leftReload(); d->leftSideBar->itemChanged(d->previewView->leftImageInfo()); } } if (!d->previewView->rightImageInfo().isNull()) { if (d->previewView->rightImageInfo().fileUrl() == url) { d->previewView->rightReload(); d->rightSideBar->itemChanged(d->previewView->rightImageInfo()); } } } void LightTableWindow::slotLeftPanelLeftButtonClicked() { if (d->navigateByPairAction->isChecked()) { return; } d->thumbView->setCurrentInfo(d->previewView->leftImageInfo()); } void LightTableWindow::slotRightPanelLeftButtonClicked() { // With navigate by pair option, only the left panel can be selected. if (d->navigateByPairAction->isChecked()) { return; } d->thumbView->setCurrentInfo(d->previewView->rightImageInfo()); } void LightTableWindow::slotLeftPreviewLoaded(bool b) { d->leftZoomBar->setEnabled(b); d->leftFileName->setAdjustedText(); if (b) { d->leftFileName->setAdjustedText(d->previewView->leftImageInfo().name()); d->previewView->checkForSelection(d->thumbView->currentInfo()); d->thumbView->setOnLeftPanel(d->previewView->leftImageInfo()); QModelIndex index = d->thumbView->findItemByInfo(d->previewView->leftImageInfo()); if (d->navigateByPairAction->isChecked() && index.isValid()) { QModelIndex next = d->thumbView->nextIndex(index); if (next.isValid()) { d->thumbView->setOnRightPanel(d->thumbView->findItemByIndex(next)); slotSetItemOnRightPanel(d->thumbView->findItemByIndex(next)); } else { QModelIndex first = d->thumbView->firstIndex(); slotSetItemOnRightPanel(first.isValid() ? d->thumbView->findItemByIndex(first) : ImageInfo()); } } } } void LightTableWindow::slotRightPreviewLoaded(bool b) { d->rightZoomBar->setEnabled(b); d->rightFileName->setAdjustedText(); if (b) { d->rightFileName->setAdjustedText(d->previewView->rightImageInfo().name()); d->previewView->checkForSelection(d->thumbView->currentInfo()); d->thumbView->setOnRightPanel(d->previewView->rightImageInfo()); QModelIndex index = d->thumbView->findItemByInfo(d->previewView->rightImageInfo()); if (index.isValid()) { d->thumbView->setOnRightPanel(d->thumbView->findItemByIndex(index)); } } } void LightTableWindow::slotItemSelected(const ImageInfo& info) { bool hasInfo = !info.isNull(); d->setItemLeftAction->setEnabled(hasInfo); d->setItemRightAction->setEnabled(hasInfo); d->editItemAction->setEnabled(hasInfo); d->removeItemAction->setEnabled(hasInfo); d->clearListAction->setEnabled(hasInfo); d->fileDeleteAction->setEnabled(hasInfo); d->fileDeleteFinalAction->setEnabled(hasInfo); d->backwardAction->setEnabled(hasInfo); d->forwardAction->setEnabled(hasInfo); d->firstAction->setEnabled(hasInfo); d->lastAction->setEnabled(hasInfo); d->syncPreviewAction->setEnabled(hasInfo); d->navigateByPairAction->setEnabled(hasInfo); d->slideShowAction->setEnabled(hasInfo); if (hasInfo) { QModelIndex curr = d->thumbView->findItemByInfo(info); if (curr.isValid()) { if (!d->thumbView->previousIndex(curr).isValid()) { d->firstAction->setEnabled(false); } if (!d->thumbView->nextIndex(curr).isValid()) { d->lastAction->setEnabled(false); } if (d->navigateByPairAction->isChecked()) { d->setItemLeftAction->setEnabled(false); d->setItemRightAction->setEnabled(false); d->thumbView->setOnLeftPanel(info); slotSetItemOnLeftPanel(info); } else if (d->autoLoadOnRightPanel && !d->thumbView->isOnLeftPanel(info)) { d->thumbView->setOnRightPanel(info); slotSetItemOnRightPanel(info); } } } d->previewView->checkForSelection(info); } // Deal with one (or more) items dropped onto the left panel void LightTableWindow::slotLeftDroppedItems(const ImageInfoList& list) { ImageInfo info = list.first(); // add the image to the existing images loadImageInfos(list, info, true); // We will check if first item from list is already stored in thumbbar // Note that the thumbbar stores all ImageInfo reference // in memory for preview object. QModelIndex index = d->thumbView->findItemByInfo(info); if (index.isValid()) { slotSetItemOnLeftPanel(info); } } // Deal with one (or more) items dropped onto the right panel void LightTableWindow::slotRightDroppedItems(const ImageInfoList& list) { ImageInfo info = list.first(); // add the image to the existing images loadImageInfos(list, info, true); // We will check if first item from list is already stored in thumbbar // Note that the thumbbar stores all ImageInfo reference // in memory for preview object. QModelIndex index = d->thumbView->findItemByInfo(info); if (index.isValid()) { slotSetItemOnRightPanel(info); // Make this item the current one. d->thumbView->setCurrentInfo(info); } } // Set the images for the left and right panel. void LightTableWindow::setLeftRightItems(const ImageInfoList& list, bool addTo) { ImageInfoList l = list; if (l.count() == 0) { return; } ImageInfo info = l.first(); QModelIndex index = d->thumbView->findItemByInfo(info); if (l.count() == 1 && !addTo) { // Just one item; this is used for the left panel. d->thumbView->setOnLeftPanel(info); slotSetItemOnLeftPanel(info); d->thumbView->setCurrentInfo(info); return; } if (index.isValid()) { // The first item is used for the left panel. if (!addTo) { d->thumbView->setOnLeftPanel(info); slotSetItemOnLeftPanel(info); } // The subsequent item is used for the right panel. QModelIndex next = d->thumbView->nextIndex(index); if (next.isValid() && !addTo) { ImageInfo nextInf = d->thumbView->findItemByIndex(next); d->thumbView->setOnRightPanel(nextInf); slotSetItemOnRightPanel(nextInf); if (!d->navigateByPairAction->isChecked()) { d->thumbView->setCurrentInfo(nextInf); } } // If navigate by pairs is active, the left panel item is selected. // (Fixes parts of bug #150296) if (d->navigateByPairAction->isChecked()) { d->thumbView->setCurrentInfo(info); } } } void LightTableWindow::slotSetItemLeft() { if (!d->thumbView->currentInfo().isNull()) { slotSetItemOnLeftPanel(d->thumbView->currentInfo()); } } void LightTableWindow::slotSetItemRight() { if (!d->thumbView->currentInfo().isNull()) { slotSetItemOnRightPanel(d->thumbView->currentInfo()); } } void LightTableWindow::slotSetItemOnLeftPanel(const ImageInfo& info) { d->previewView->setLeftImageInfo(info); if (!info.isNull()) { d->leftSideBar->itemChanged(info); } else { d->leftSideBar->slotNoCurrentItem(); } } void LightTableWindow::slotSetItemOnRightPanel(const ImageInfo& info) { d->previewView->setRightImageInfo(info); if (!info.isNull()) { d->rightSideBar->itemChanged(info); } else { d->rightSideBar->slotNoCurrentItem(); } } void LightTableWindow::slotClearItemsList() { if (!d->previewView->leftImageInfo().isNull()) { d->previewView->setLeftImageInfo(); d->leftSideBar->slotNoCurrentItem(); } if (!d->previewView->rightImageInfo().isNull()) { d->previewView->setRightImageInfo(); d->rightSideBar->slotNoCurrentItem(); } d->thumbView->clear(); } void LightTableWindow::slotDeleteItem() { deleteItem(false); } void LightTableWindow::slotDeleteItem(const ImageInfo& info) { deleteItem(info, false); } void LightTableWindow::slotDeleteFinalItem() { deleteItem(true); } void LightTableWindow::slotDeleteFinalItem(const ImageInfo& info) { deleteItem(info, true); } void LightTableWindow::deleteItem(bool permanently) { if (!d->thumbView->currentInfo().isNull()) { deleteItem(d->thumbView->currentInfo(), permanently); } } void LightTableWindow::deleteItem(const ImageInfo& info, bool permanently) { QUrl u = info.fileUrl(); PAlbum* const palbum = AlbumManager::instance()->findPAlbum(u.adjusted(QUrl::RemoveFilename)); if (!palbum) { return; } qCDebug(DIGIKAM_GENERAL_LOG) << "Item to delete: " << u; bool useTrash; bool preselectDeletePermanently = permanently; DeleteDialog dialog(this); QList urlList; urlList.append(u); if (!dialog.confirmDeleteList(urlList, DeleteDialogMode::Files, preselectDeletePermanently ? DeleteDialogMode::NoChoiceDeletePermanently : DeleteDialogMode::NoChoiceTrash)) { return; } useTrash = !dialog.shouldDelete(); DIO::del(info, useTrash); } void LightTableWindow::slotRemoveItem() { if (!d->thumbView->currentInfo().isNull()) { slotRemoveItem(d->thumbView->currentInfo()); } } void LightTableWindow::slotRemoveItem(const ImageInfo& info) { /* if (!d->previewView->leftImageInfo().isNull()) { if (d->previewView->leftImageInfo() == info) { d->previewView->setLeftImageInfo(); d->leftSideBar->slotNoCurrentItem(); } } if (!d->previewView->rightImageInfo().isNull()) { if (d->previewView->rightImageInfo() == info) { d->previewView->setRightImageInfo(); d->rightSideBar->slotNoCurrentItem(); } } d->thumbView->removeItemByInfo(info); d->thumbView->setSelected(d->thumbView->currentItem()); */ // When either the image from the left or right panel is removed, // there are various situations to account for. // To describe them, 4 images A B C D are used // and the subscript _L and _ R mark the currently // active item on the left and right panel ImageInfo new_linfo; ImageInfo new_rinfo; bool leftPanelActive = false; ImageInfo curr_linfo = d->previewView->leftImageInfo(); ImageInfo curr_rinfo = d->previewView->rightImageInfo(); qint64 infoId = info.id(); // First determine the next images to the current left and right image: ImageInfo next_linfo; ImageInfo next_rinfo; if (!curr_linfo.isNull()) { QModelIndex index = d->thumbView->findItemByInfo(curr_linfo); if (index.isValid()) { QModelIndex next = d->thumbView->nextIndex(index); if (next.isValid()) { next_linfo = d->thumbView->findItemByIndex(next); } } } if (!curr_rinfo.isNull()) { QModelIndex index = d->thumbView->findItemByInfo(curr_rinfo); if (index.isValid()) { QModelIndex next = d->thumbView->nextIndex(index); if (next.isValid()) { next_rinfo = d->thumbView->findItemByIndex(next); } } } d->thumbView->removeItemByInfo(info); // Make sure that next_linfo and next_rinfo are still available: if (!d->thumbView->findItemByInfo(next_linfo).isValid()) { next_linfo = ImageInfo(); } if (!d->thumbView->findItemByInfo(next_rinfo).isValid()) { next_rinfo = ImageInfo(); } // removal of the left panel item? if (!curr_linfo.isNull()) { if (curr_linfo.id() == infoId) { leftPanelActive = true; // Delete the item A_L of the left panel: // 1) A_L B_R C D -> B_L C_R D // 2) A_L B C_R D -> B C_L D_R // 3) A_L B C D_R -> B_R C D_L // 4) A_L B_R -> A_L // some more corner cases: // 5) A B_L C_R D -> A C_L D_R // 6) A B_L C_R -> A_R C_L // 7) A_LR B C D -> B_L C_R D (does not yet work) // I.e. in 3) we wrap around circularly. // When removing the left panel image, // put the right panel image into the left panel. // Check if this one is not the same (i.e. also removed). if (!curr_rinfo.isNull()) { if (curr_rinfo.id() != infoId) { new_linfo = curr_rinfo; // Set the right panel to the next image: new_rinfo = next_rinfo; // set the right panel active, but not in pair mode if (!d->navigateByPairAction->isChecked()) { leftPanelActive = false; } } } } } // removal of the right panel item? if (!curr_rinfo.isNull()) { if (curr_rinfo.id() == infoId) { // Leave the left panel as the current one new_linfo = curr_linfo; // Set the right panel to the next image new_rinfo = next_rinfo; } } // Now we deal with the corner cases, where no left or right item exists. // If the right panel would be set, but not the left-one, then swap if (new_linfo.isNull() && !new_rinfo.isNull()) { new_linfo = new_rinfo; new_rinfo = ImageInfo(); leftPanelActive = true; } if (new_linfo.isNull()) { if (d->thumbView->countItems() > 0) { QModelIndex first = d->thumbView->firstIndex(); new_linfo = d->thumbView->findItemByIndex(first); } } // Make sure that new_linfo and new_rinfo exist. // This addresses a crash occurring if the last image is removed // in the navigate by pairs mode. if (!d->thumbView->findItemByInfo(new_linfo).isValid()) { new_linfo = ImageInfo(); } if (!d->thumbView->findItemByInfo(new_rinfo).isValid()) { new_rinfo = ImageInfo(); } // no right item defined? if (new_rinfo.isNull()) { // If there are at least two items, we can find reasonable right image. if (d->thumbView->countItems() > 1) { // See if there is an item next to the left one: QModelIndex index = d->thumbView->findItemByInfo(new_linfo); QModelIndex next; if (index.isValid()) { next = d->thumbView->nextIndex(index); } if (next.isValid()) { new_rinfo = d->thumbView->findItemByIndex(next); } else { // If there is no item to the right of new_linfo // then we can choose the first item for new_rinfo // (as we made sure that there are at least two items) QModelIndex first = d->thumbView->firstIndex(); new_rinfo = d->thumbView->findItemByIndex(first); } } } // Check if left and right are set to the same if (!new_linfo.isNull() && !new_rinfo.isNull()) { if (new_linfo.id() == new_rinfo.id()) { // Only keep the left one new_rinfo = ImageInfo(); } } // If the right panel would be set, but not the left-one, then swap // (note that this has to be done here again!) if (new_linfo.isNull() && !new_rinfo.isNull()) { new_linfo = new_rinfo; new_rinfo = ImageInfo(); leftPanelActive = true; } // set the image for the left panel if (!new_linfo.isNull()) { d->thumbView->setOnLeftPanel(new_linfo); slotSetItemOnLeftPanel(new_linfo); // make this the selected item if the left was active before if (leftPanelActive) { d->thumbView->setCurrentInfo(new_linfo); } } else { d->previewView->setLeftImageInfo(); d->leftSideBar->slotNoCurrentItem(); } // set the image for the right panel if (!new_rinfo.isNull()) { d->thumbView->setOnRightPanel(new_rinfo); slotSetItemOnRightPanel(new_rinfo); // make this the selected item if the left was active before if (!leftPanelActive) { d->thumbView->setCurrentInfo(new_rinfo); } } else { d->previewView->setRightImageInfo(); d->rightSideBar->slotNoCurrentItem(); } } void LightTableWindow::slotEditItem() { if (!d->thumbView->currentInfo().isNull()) { slotEditItem(d->thumbView->currentInfo()); } } void LightTableWindow::slotEditItem(const ImageInfo& info) { ImageWindow* const im = ImageWindow::imageWindow(); ImageInfoList list = d->thumbView->allImageInfos(); im->loadImageInfos(list, info, i18n("Light Table")); if (im->isHidden()) { im->show(); } else { im->raise(); } im->setFocus(); } void LightTableWindow::slotPresentation() { PresentationMngr* const mngr = new PresentationMngr(this); foreach(const ImageInfo& info, d->thumbView->allImageInfos()) { mngr->addFile(info.fileUrl(), info.comment()); qApp->processEvents(); } mngr->showConfigDialog(); } void LightTableWindow::slotSlideShowAll() { SlideShowBuilder* const builder = new SlideShowBuilder(d->thumbView->allImageInfos()); d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode, i18n("Preparing slideshow. Please wait...")); connect(builder, SIGNAL(signalComplete(SlideShowSettings)), this, SLOT(slotSlideShowBuilderComplete(SlideShowSettings))); builder->run(); } void LightTableWindow::slotLeftSlideShowManualFromCurrent() { slotSlideShowManualFrom(d->previewView->leftImageInfo()); d->fromLeftPreview = true; } void LightTableWindow::slotRightSlideShowManualFromCurrent() { slotSlideShowManualFrom(d->previewView->rightImageInfo()); d->fromLeftPreview = false; } void LightTableWindow::slotSlideShowManualFrom(const ImageInfo& info) { SlideShowBuilder* const builder = new SlideShowBuilder(d->thumbView->allImageInfos()); builder->setOverrideStartFrom(info); builder->setAutoPlayEnabled(false); d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode, i18n("Preparing slideshow. Please wait...")); connect(builder, SIGNAL(signalComplete(SlideShowSettings)), this, SLOT(slotSlideShowBuilderComplete(SlideShowSettings))); builder->run(); } void LightTableWindow::slotSlideShowBuilderComplete(const SlideShowSettings& settings) { SlideShow* const slide = new SlideShow(settings); TagsActionMngr::defaultManager()->registerActionsToWidget(slide); d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode, QString()); slotRefreshStatusBar(); if (settings.imageUrl.isValid()) { slide->setCurrentItem(settings.imageUrl); } else if (settings.startWithCurrent) { slide->setCurrentItem(d->thumbView->currentInfo().fileUrl()); } connect(slide, SIGNAL(signalRatingChanged(QUrl,int)), d->thumbView, SLOT(slotRatingChanged(QUrl,int))); connect(slide, SIGNAL(signalColorLabelChanged(QUrl,int)), d->thumbView, SLOT(slotColorLabelChanged(QUrl,int))); connect(slide, SIGNAL(signalPickLabelChanged(QUrl,int)), d->thumbView, SLOT(slotPickLabelChanged(QUrl,int))); connect(slide, SIGNAL(signalToggleTag(QUrl,int)), d->thumbView, SLOT(slotToggleTag(QUrl,int))); connect(slide, SIGNAL(signalLastItemUrl(QUrl)), this, SLOT(slotSlideShowLastItemUrl(QUrl))); slide->show(); } void LightTableWindow::slotSlideShowLastItemUrl(const QUrl& url) { if (d->fromLeftPreview && !d->navigateByPairAction->isChecked()) { d->thumbView->blockSignals(true); d->thumbView->setCurrentUrl(url); d->thumbView->blockSignals(false); slotSetItemLeft(); } else { d->thumbView->setCurrentUrl(url); } } void LightTableWindow::slotSetup() { Setup::execDialog(this); } void LightTableWindow::slotLeftZoomFactorChanged(double zoom) { double zmin = d->previewView->leftZoomMin(); double zmax = d->previewView->leftZoomMax(); d->leftZoomBar->setZoom(zoom, zmin, zmax); d->leftZoomPlusAction->setEnabled(!d->previewView->leftMaxZoom()); d->leftZoomMinusAction->setEnabled(!d->previewView->leftMinZoom()); } void LightTableWindow::slotRightZoomFactorChanged(double zoom) { double zmin = d->previewView->rightZoomMin(); double zmax = d->previewView->rightZoomMax(); d->rightZoomBar->setZoom(zoom, zmin, zmax); d->rightZoomPlusAction->setEnabled(!d->previewView->rightMaxZoom()); d->rightZoomMinusAction->setEnabled(!d->previewView->rightMinZoom()); } void LightTableWindow::slotToggleSyncPreview() { d->previewView->setSyncPreview(d->syncPreviewAction->isChecked()); } void LightTableWindow::slotToggleOnSyncPreview(bool t) { d->syncPreviewAction->setEnabled(t); if (!t) { d->syncPreviewAction->setChecked(false); } else { if (d->autoSyncPreview) { d->syncPreviewAction->setChecked(true); } } } void LightTableWindow::slotBackward() { d->thumbView->toPreviousIndex(); } void LightTableWindow::slotForward() { d->thumbView->toNextIndex(); } void LightTableWindow::slotFirst() { d->thumbView->toFirstIndex(); } void LightTableWindow::slotLast() { d->thumbView->toLastIndex(); } void LightTableWindow::slotToggleNavigateByPair() { d->thumbView->setNavigateByPair(d->navigateByPairAction->isChecked()); d->previewView->setNavigateByPair(d->navigateByPairAction->isChecked()); slotItemSelected(d->thumbView->currentInfo()); } void LightTableWindow::slotComponentsInfo() { showDigikamComponentsInfo(); } void LightTableWindow::slotDBStat() { showDigikamDatabaseStat(); } void LightTableWindow::slotApplicationSettingsChanged() { d->leftSideBar->setStyle(ApplicationSettings::instance()->getSidebarTitleStyle()); d->rightSideBar->setStyle(ApplicationSettings::instance()->getSidebarTitleStyle()); /// @todo Which part of the settings has to be reloaded? // d->rightSideBar->applySettings(); d->previewView->setPreviewSettings(ApplicationSettings::instance()->getPreviewSettings()); } void LightTableWindow::moveEvent(QMoveEvent* e) { Q_UNUSED(e) emit signalWindowHasMoved(); } void LightTableWindow::toggleTag(int tagID) { d->thumbView->toggleTag(tagID); } void LightTableWindow::slotAssignPickLabel(int pickId) { d->thumbView->slotAssignPickLabel(pickId); } void LightTableWindow::slotAssignColorLabel(int colorId) { d->thumbView->slotAssignColorLabel(colorId); } void LightTableWindow::slotAssignRating(int rating) { d->thumbView->slotAssignRating(rating); } void LightTableWindow::slotThemeChanged() { d->previewView->checkForSelection(d->previewView->leftImageInfo()); d->previewView->checkForSelection(d->previewView->rightImageInfo()); } void LightTableWindow::showSideBars(bool visible) { if (visible) { d->leftSideBar->restore(); d->rightSideBar->restore(); } else { d->leftSideBar->backup(); d->rightSideBar->backup(); } } void LightTableWindow::slotToggleLeftSideBar() { d->leftSideBar->isExpanded() ? d->leftSideBar->shrink() : d->leftSideBar->expand(); } void LightTableWindow::slotToggleRightSideBar() { d->rightSideBar->isExpanded() ? d->rightSideBar->shrink() : d->rightSideBar->expand(); } void LightTableWindow::slotPreviousLeftSideBarTab() { d->leftSideBar->activePreviousTab(); } void LightTableWindow::slotNextLeftSideBarTab() { d->leftSideBar->activeNextTab(); } void LightTableWindow::slotPreviousRightSideBarTab() { d->rightSideBar->activePreviousTab(); } void LightTableWindow::slotNextRightSideBarTab() { d->rightSideBar->activeNextTab(); } void LightTableWindow::customizedFullScreenMode(bool set) { showStatusBarAction()->setEnabled(!set); toolBarMenuAction()->setEnabled(!set); showMenuBarAction()->setEnabled(!set); d->showBarAction->setEnabled(!set); d->previewView->toggleFullScreen(set); } void LightTableWindow::slotFileWithDefaultApplication() { if (!d->thumbView->currentInfo().isNull()) { DFileOperations::openFilesWithDefaultApplication(QList() << d->thumbView->currentInfo().fileUrl()); } } void LightTableWindow::slotRightSideBarActivateTitles() { d->rightSideBar->setActiveTab(d->rightSideBar->imageDescEditTab()); d->rightSideBar->imageDescEditTab()->setFocusToTitlesEdit(); } void LightTableWindow::slotRightSideBarActivateComments() { d->rightSideBar->setActiveTab(d->rightSideBar->imageDescEditTab()); d->rightSideBar->imageDescEditTab()->setFocusToCommentsEdit(); } void LightTableWindow::slotRightSideBarActivateAssignedTags() { d->rightSideBar->setActiveTab(d->rightSideBar->imageDescEditTab()); d->rightSideBar->imageDescEditTab()->activateAssignedTagsButton(); } void LightTableWindow::slotLeftSideBarActivateTitles() { d->leftSideBar->setActiveTab(d->leftSideBar->imageDescEditTab()); d->leftSideBar->imageDescEditTab()->setFocusToTitlesEdit(); } void LightTableWindow::slotLeftSideBarActivateComments() { d->leftSideBar->setActiveTab(d->leftSideBar->imageDescEditTab()); d->leftSideBar->imageDescEditTab()->setFocusToCommentsEdit(); } void LightTableWindow::slotLeftSideBarActivateAssignedTags() { d->leftSideBar->setActiveTab(d->leftSideBar->imageDescEditTab()); d->leftSideBar->imageDescEditTab()->activateAssignedTagsButton(); } void LightTableWindow::slotToggleColorManagedView() { if (!IccSettings::instance()->isEnabled()) { return; } bool cmv = !IccSettings::instance()->settings().useManagedPreviews; IccSettings::instance()->setUseManagedPreviews(cmv); } void LightTableWindow::slotColorManagementOptionsChanged() { ICCSettingsContainer settings = IccSettings::instance()->settings(); d->viewCMViewAction->blockSignals(true); d->viewCMViewAction->setEnabled(settings.enableCM); d->viewCMViewAction->setChecked(settings.useManagedPreviews); d->viewCMViewAction->blockSignals(false); } void LightTableWindow::slotEditGeolocation() { #ifdef HAVE_MARBLE ImageInfoList infos = d->thumbView->allImageInfos(); if (infos.isEmpty()) { return; } TagModel* const tagModel = new TagModel(AbstractAlbumModel::IgnoreRootAlbum, this); TagPropertiesFilterModel* const filterModel = new TagPropertiesFilterModel(this); filterModel->setSourceAlbumModel(tagModel); filterModel->sort(0); QPointer dialog = new GeolocationEdit(filterModel, new DBInfoIface(this, d->thumbView->allUrls()), QApplication::activeWindow()); dialog->setItems(ImageGPS::infosToItems(infos)); dialog->exec(); delete dialog; // Refresh Database with new metadata from files. foreach(const ImageInfo& inf, infos) { ScanController::instance()->scannedInfo(inf.fileUrl().toLocalFile()); } #endif } void LightTableWindow::slotEditMetadata() { if (d->thumbView->currentInfo().isNull()) { return; } QUrl url = d->thumbView->currentInfo().fileUrl(); QPointer dialog = new MetadataEditDialog(QApplication::activeWindow(), QList() << url); dialog->exec(); delete dialog; // Refresh Database with new metadata from file. CollectionScanner scanner; scanner.scanFile(url.toLocalFile(), CollectionScanner::Rescan); } void LightTableWindow::slotImportFromScanner() { #ifdef HAVE_KSANE m_ksaneAction->activate(DigikamApp::instance()->scannerTargetPlace(), configGroupName()); connect(m_ksaneAction, SIGNAL(signalImportedImage(QUrl)), this, SLOT(slotImportedImagefromScanner(QUrl))); #endif } void LightTableWindow::slotImportedImagefromScanner(const QUrl& url) { ImageInfo info = ScanController::instance()->scannedInfo(url.toLocalFile()); loadImageInfos(ImageInfoList() << info, info, true); } void LightTableWindow::slotHtmlGallery() { #ifdef HAVE_HTMLGALLERY QPointer w = new HTMLWizard(this, new DBInfoIface(this, d->thumbView->allUrls())); w->exec(); delete w; #endif } void LightTableWindow::slotCalendar() { QPointer w = new CalWizard(d->thumbView->allUrls(), this); w->exec(); delete w; } void LightTableWindow::slotPanorama() { #ifdef HAVE_PANORAMA PanoManager::instance()->checkBinaries(); PanoManager::instance()->setItemsList(d->thumbView->allUrls()); PanoManager::instance()->run(); #endif } void LightTableWindow::slotExpoBlending() { ExpoBlendingManager::instance()->checkBinaries(); ExpoBlendingManager::instance()->setItemsList(d->thumbView->allUrls()); ExpoBlendingManager::instance()->run(); } void LightTableWindow::slotVideoSlideshow() { #ifdef HAVE_MEDIAPLAYER QPointer w = new VidSlideWizard(this, new DBInfoIface(this, d->thumbView->allUrls())); w->exec(); delete w; #endif } void LightTableWindow::slotSendByMail() { QPointer w = new MailWizard(this, new DBInfoIface(this, d->thumbView->allUrls())); w->exec(); delete w; } void LightTableWindow::slotPrintCreator() { QPointer w = new AdvPrintWizard(this, new DBInfoIface(this, d->thumbView->allUrls())); w->exec(); delete w; } void LightTableWindow::slotMediaServer() { DBInfoIface* const iface = new DBInfoIface(this, QList(), ApplicationSettings::Tools); // NOTE: We overwrite the default albums chooser object name for load save check items state between sessions. // The goal is not mix these settings with other export tools. iface->setObjectName(QLatin1String("SetupMediaServerIface")); QPointer w = new DMediaServerDlg(this, iface); w->exec(); delete w; } void LightTableWindow::slotExportTool() { QAction* const tool = dynamic_cast(sender()); if (tool == m_exportDropboxAction) { QPointer w = new DBWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } + else if (tool == m_exportDropboxAction) + { + QPointer w = new ODWindow(new DBInfoIface(this, d->thumbView->allUrls(), + ApplicationSettings::ImportExport), this); + w->exec(); + delete w; + } else if (tool == m_exportFacebookAction) { QPointer w = new FbWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportFlickrAction) { QPointer w = new FlickrWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportGdriveAction) { QPointer w = new GSWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this, QLatin1String("googledriveexport")); w->exec(); delete w; } else if (tool == m_exportGphotoAction) { QPointer w = new GSWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this, QLatin1String("googlephotoexport")); w->exec(); delete w; } else if (tool == m_exportImageshackAction) { QPointer w = new ImageShackWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportImgurAction) { QPointer w = new ImgurWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportPiwigoAction) { QPointer w = new PiwigoWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportRajceAction) { QPointer w = new RajceWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportSmugmugAction) { QPointer w = new SmugWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } else if (tool == m_exportYandexfotkiAction) { QPointer w = new YFWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } #ifdef HAVE_MEDIAWIKI else if (tool == m_exportMediawikiAction) { - QPointer w = new MediaWikiWindow(new DBInfoIface(this, d->thumbView->allUrls(), + QPointer w = new MediaWikiWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } #endif #ifdef HAVE_VKONTAKTE else if (tool == m_exportVkontakteAction) { QPointer w = new VKWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } #endif #ifdef HAVE_KIO else if (tool == m_exportFileTransferAction) { QPointer w = new FTExportWindow(new DBInfoIface(this, d->thumbView->allUrls(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } #endif } void LightTableWindow::slotImportTool() { QAction* const tool = dynamic_cast(sender()); if (tool == m_importGphotoAction) { QPointer w = new GSWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this, QLatin1String("googlephotoimport")); w->exec(); delete w; } else if (tool == m_importSmugmugAction) { QPointer w = new SmugWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this, true); w->exec(); delete w; } #ifdef HAVE_KIO else if (tool == m_importFileTransferAction) { QPointer w = new FTImportWindow(new DBInfoIface(this, QList(), ApplicationSettings::ImportExport), this); w->exec(); delete w; } #endif } } // namespace Digikam