/* ============================================================ * * 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-2008 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. * * ============================================================ */ // C++ includes. #include // TQt includes. #include #include #include #include #include #include #include // KDE includes. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Local includes. #include "constants.h" #include "ddebug.h" #include "dlogoaction.h" #include "dpopupmenu.h" #include "dragobjects.h" #include "canvas.h" #include "dimginterface.h" #include "dimg.h" #include "dmetadata.h" #include "imageplugin.h" #include "imagepluginloader.h" #include "imageprint.h" #include "albummanager.h" #include "album.h" #include "albumdb.h" #include "albumsettings.h" #include "syncjob.h" #include "imageinfo.h" #include "imagepropertiessidebardb.h" #include "tagspopupmenu.h" #include "ratingpopupmenu.h" #include "slideshow.h" #include "setup.h" #include "iccsettingscontainer.h" #include "iofilesettingscontainer.h" #include "loadingcacheinterface.h" #include "savingcontextcontainer.h" #include "statusprogressbar.h" #include "imageattributeswatch.h" #include "deletedialog.h" #include "metadatahub.h" #include "themeengine.h" #include "editorstackview.h" #include "imagewindow.h" #include "imagewindow.moc" namespace Digikam { class ImageWindowPriv { public: ImageWindowPriv() { allowSaving = true; star0 = 0; star1 = 0; star2 = 0; star3 = 0; star4 = 0; star5 = 0; fileDeletePermanentlyAction = 0; fileDeletePermanentlyDirectlyAction = 0; fileTrashDirectlyAction = 0; imageInfoCurrent = 0; rightSidebar = 0; } // If image editor is launched by camera interface, current // image cannot be saved. bool allowSaving; KURL::List urlList; KURL urlCurrent; // Rating actions. KAction *star0; KAction *star1; KAction *star2; KAction *star3; KAction *star4; KAction *star5; // Delete actions KAction *fileDeletePermanentlyAction; KAction *fileDeletePermanentlyDirectlyAction; KAction *fileTrashDirectlyAction; ImageInfoList imageInfoList; ImageInfo *imageInfoCurrent; ImagePropertiesSideBarDB *rightSidebar; }; 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( "Image Editor" ) { d = new ImageWindowPriv; m_instance = this; setAcceptDrops(true); // -- Build the GUI ------------------------------- setupUserArea(); setupStatusBar(); setupActions(); // Load image plugins to GUI m_imagePluginLoader = ImagePluginLoader::instance(); loadImagePlugins(); // Create context menu. setupContextMenu(); // Make signals/slots connections setupConnections(); // -- Read settings -------------------------------- readSettings(); applySettings(); setAutoSaveSettings("ImageViewer Settings"); //------------------------------------------------------------- d->rightSidebar->loadViewState(); d->rightSidebar->populateTags(); } ImageWindow::~ImageWindow() { m_instance = 0; unLoadImagePlugins(); // No need to delete m_imagePluginLoader instance here, it will be done by main interface. delete d->rightSidebar; delete d; } Sidebar* ImageWindow::rightSideBar() const { return dynamic_cast(d->rightSidebar); } void ImageWindow::closeEvent(TQCloseEvent* e) { if (!e) return; if (!queryClose()) return; // put right side bar in a defined state emit signalNoCurrentItem(); m_canvas->resetImage(); saveSettings(); e->accept(); } bool ImageWindow::queryClose() { // Note: we reimplement 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->urlCurrent); } void ImageWindow::setupConnections() { setupStandardConnections(); // To toggle properly keyboards shortcuts from comments & tags side bar tab. connect(d->rightSidebar, TQT_SIGNAL(signalNextItem()), TQT_TQOBJECT(this), TQT_SLOT(slotForward())); connect(d->rightSidebar, TQT_SIGNAL(signalPrevItem()), TQT_TQOBJECT(this), TQT_SLOT(slotBackward())); connect(this, TQT_SIGNAL(signalSelectionChanged( const TQRect &)), d->rightSidebar, TQT_SLOT(slotImageSelectionChanged( const TQRect &))); connect(this, TQT_SIGNAL(signalNoCurrentItem()), d->rightSidebar, TQT_SLOT(slotNoCurrentItem())); ImageAttributesWatch *watch = ImageAttributesWatch::instance(); connect(watch, TQT_SIGNAL(signalFileMetadataChanged(const KURL &)), TQT_TQOBJECT(this), TQT_SLOT(slotFileMetadataChanged(const KURL &))); } void ImageWindow::setupUserArea() { TQWidget* widget = new TQWidget(this); TQHBoxLayout *lay = new TQHBoxLayout(widget); m_splitter = new TQSplitter(widget); m_stackView = new EditorStackView(m_splitter); m_canvas = new Canvas(m_stackView); m_stackView->setCanvas(m_canvas); m_stackView->setViewMode(EditorStackView::CanvasMode); m_canvas->makeDefaultEditingCanvas(); TQSizePolicy rightSzPolicy(TQSizePolicy::Preferred, TQSizePolicy::Expanding, 2, 1); m_canvas->setSizePolicy(rightSzPolicy); d->rightSidebar = new ImagePropertiesSideBarDB(widget, "ImageEditor Right Sidebar", m_splitter, Sidebar::Right, true); lay->addWidget(m_splitter); lay->addWidget(d->rightSidebar); m_splitter->setFrameStyle( TQFrame::NoFrame ); m_splitter->setFrameShadow( TQFrame::Plain ); m_splitter->setFrameShape( TQFrame::NoFrame ); m_splitter->setOpaqueResize(false); setCentralWidget(widget); } void ImageWindow::setupActions() { setupStandardActions(); // Provides a menu entry that allows showing/hiding the toolbar(s) setStandardToolBarMenuEnabled(true); // Provides a menu entry that allows showing/hiding the statusbar createStandardStatusBarAction(); // -- Rating actions --------------------------------------------------------------- d->star0 = new KAction(i18n("Assign Rating \"No Stars\""), CTRL+Key_0, TQT_TQOBJECT(this), TQT_SLOT(slotAssignRatingNoStar()), actionCollection(), "imageview_ratenostar"); d->star1 = new KAction(i18n("Assign Rating \"One Star\""), CTRL+Key_1, TQT_TQOBJECT(this), TQT_SLOT(slotAssignRatingOneStar()), actionCollection(), "imageview_rateonestar"); d->star2 = new KAction(i18n("Assign Rating \"Two Stars\""), CTRL+Key_2, TQT_TQOBJECT(this), TQT_SLOT(slotAssignRatingTwoStar()), actionCollection(), "imageview_ratetwostar"); d->star3 = new KAction(i18n("Assign Rating \"Three Stars\""), CTRL+Key_3, TQT_TQOBJECT(this), TQT_SLOT(slotAssignRatingThreeStar()), actionCollection(), "imageview_ratethreestar"); d->star4 = new KAction(i18n("Assign Rating \"Four Stars\""), CTRL+Key_4, TQT_TQOBJECT(this), TQT_SLOT(slotAssignRatingFourStar()), actionCollection(), "imageview_ratefourstar"); d->star5 = new KAction(i18n("Assign Rating \"Five Stars\""), CTRL+Key_5, TQT_TQOBJECT(this), TQT_SLOT(slotAssignRatingFiveStar()), actionCollection(), "imageview_ratefivestar"); // -- Special Delete actions --------------------------------------------------------------- // Pop up dialog to ask user whether to permanently delete d->fileDeletePermanentlyAction = new KAction(i18n("Delete File Permanently"), "editdelete", SHIFT+Key_Delete, TQT_TQOBJECT(this), TQT_SLOT(slotDeleteCurrentItemPermanently()), actionCollection(), "image_delete_permanently"); // These two actions are hidden, no menu entry, no toolbar entry, no shortcut. // Power users may add them. d->fileDeletePermanentlyDirectlyAction = new KAction(i18n("Delete Permanently without Confirmation"), "editdelete", 0, TQT_TQOBJECT(this), TQT_SLOT(slotDeleteCurrentItemPermanentlyDirectly()), actionCollection(), "image_delete_permanently_directly"); d->fileTrashDirectlyAction = new KAction(i18n("Move to Trash without Confirmation"), "edittrash", 0, TQT_TQOBJECT(this), TQT_SLOT(slotTrashCurrentItemDirectly()), actionCollection(), "image_trash_directly"); // --------------------------------------------------------------------------------- new DLogoAction(actionCollection(), "logo_action"); createGUI("digikamimagewindowui.rc", false); setupStandardAccelerators(); } void ImageWindow::applySettings() { applyStandardSettings(); AlbumSettings *settings = AlbumSettings::instance(); m_canvas->setExifOrient(settings->getExifRotate()); m_setExifOrientationTag = settings->getExifSetOrientation(); refreshView(); } void ImageWindow::refreshView() { d->rightSidebar->refreshTagsView(); } void ImageWindow::loadURL(const KURL::List& urlList, const KURL& urlCurrent, const TQString& caption, bool allowSaving) { if (!promptUserSave(d->urlCurrent)) return; d->urlList = urlList; d->urlCurrent = urlCurrent; d->imageInfoList = ImageInfoList(); d->imageInfoCurrent = 0; loadCurrentList(caption, allowSaving); } void ImageWindow::loadImageInfos(const ImageInfoList &imageInfoList, ImageInfo *imageInfoCurrent, const TQString& caption, bool allowSaving) { // The ownership of objects of imageInfoList is passed to us. // imageInfoCurrent is contained in imageInfoList. // Very first thing is to check for changes, user may choose to cancel operation if (!promptUserSave(d->urlCurrent)) { // delete objects from list for (ImageInfoList::iterator it = imageInfoList.begin(); it != imageInfoList.end(); ++it) delete *it; return; } // take over ImageInfo list d->imageInfoList = imageInfoList; d->imageInfoCurrent = imageInfoCurrent; d->imageInfoList.setAutoDelete(true); // create URL list d->urlList = KURL::List(); ImageInfoListIterator it(d->imageInfoList); ImageInfo *info; for (; (info = it.current()); ++it) { d->urlList.append(info->kurl()); } d->urlCurrent = d->imageInfoCurrent->kurl(); loadCurrentList(caption, allowSaving); } void ImageWindow::loadCurrentList(const TQString& caption, bool allowSaving) { // this method contains the code shared by loadURL and loadImageInfos // if window is iconified, show it if (isMinimized()) { KWin::deIconifyWindow(winId()); } if (!caption.isEmpty()) setCaption(i18n("Image Editor - %1").arg(caption)); else setCaption(i18n("Image Editor")); d->allowSaving = allowSaving; m_saveAction->setEnabled(false); m_revertAction->setEnabled(false); m_undoAction->setEnabled(false); m_redoAction->setEnabled(false); TQTimer::singleShot(0, TQT_TQOBJECT(this), TQT_SLOT(slotLoadCurrent())); } void ImageWindow::slotLoadCurrent() { KURL::List::iterator it = d->urlList.find(d->urlCurrent); if (it != d->urlList.end()) { m_canvas->load(d->urlCurrent.path(), m_IOFileSettings); ++it; if (it != d->urlList.end()) m_canvas->preload((*it).path()); } // 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 DImgInterface loads the full version. // So first let DImgInterface create its loading task, only then any external objects. setViewToURL(d->urlCurrent); } void ImageWindow::setViewToURL(const KURL &url) { emit signalURLChanged(url); } void ImageWindow::slotForward() { if(!promptUserSave(d->urlCurrent)) return; KURL::List::iterator it = d->urlList.find(d->urlCurrent); int index = d->imageInfoList.find(d->imageInfoCurrent); if (it != d->urlList.end()) { if (d->urlCurrent != d->urlList.last()) { KURL urlNext = *(++it); d->imageInfoCurrent = d->imageInfoList.at(index + 1); d->urlCurrent = urlNext; slotLoadCurrent(); } } } void ImageWindow::slotBackward() { if(!promptUserSave(d->urlCurrent)) return; KURL::List::iterator it = d->urlList.find(d->urlCurrent); int index = d->imageInfoList.find(d->imageInfoCurrent); if (it != d->urlList.begin()) { if (d->urlCurrent != d->urlList.first()) { KURL urlPrev = *(--it); d->imageInfoCurrent = d->imageInfoList.at(index - 1); d->urlCurrent = urlPrev; slotLoadCurrent(); } } } void ImageWindow::slotFirst() { if(!promptUserSave(d->urlCurrent)) return; d->urlCurrent = d->urlList.first(); d->imageInfoCurrent = d->imageInfoList.first(); slotLoadCurrent(); } void ImageWindow::slotLast() { if(!promptUserSave(d->urlCurrent)) return; d->urlCurrent = d->urlList.last(); d->imageInfoCurrent = d->imageInfoList.last(); slotLoadCurrent(); } void ImageWindow::slotContextMenu() { if (m_contextMenu) { RatingPopupMenu *ratingMenu = 0; TagsPopupMenu *assignTagsMenu = 0; TagsPopupMenu *removeTagsMenu = 0; int separatorID1 = -1; int separatorID2 = -1; if (d->imageInfoCurrent) { // Bulk assignment/removal of tags -------------------------- TQ_LLONG id = d->imageInfoCurrent->id(); TQValueList idList; idList.append(id); assignTagsMenu = new TagsPopupMenu(idList, 1000, TagsPopupMenu::ASSIGN); removeTagsMenu = new TagsPopupMenu(idList, 2000, TagsPopupMenu::REMOVE); separatorID1 = m_contextMenu->insertSeparator(); m_contextMenu->insertItem(i18n("Assign Tag"), assignTagsMenu); int i = m_contextMenu->insertItem(i18n("Remove Tag"), removeTagsMenu); connect(assignTagsMenu, TQT_SIGNAL(signalTagActivated(int)), TQT_TQOBJECT(this), TQT_SLOT(slotAssignTag(int))); connect(removeTagsMenu, TQT_SIGNAL(signalTagActivated(int)), TQT_TQOBJECT(this), TQT_SLOT(slotRemoveTag(int))); AlbumDB* db = AlbumManager::instance()->albumDB(); if (!db->hasTags( idList )) m_contextMenu->setItemEnabled(i, false); separatorID2 = m_contextMenu->insertSeparator(); // Assign Star Rating ------------------------------------------- ratingMenu = new RatingPopupMenu(); connect(ratingMenu, TQT_SIGNAL(activated(int)), TQT_TQOBJECT(this), TQT_SLOT(slotAssignRating(int))); m_contextMenu->insertItem(i18n("Assign Rating"), ratingMenu); } m_contextMenu->exec(TQCursor::pos()); if (separatorID1 != -1) m_contextMenu->removeItem(separatorID1); if (separatorID2 != -1) m_contextMenu->removeItem(separatorID2); delete assignTagsMenu; delete removeTagsMenu; delete ratingMenu; } } void ImageWindow::slotChanged() { TQString mpixels; TQSize dims(m_canvas->imageWidth(), m_canvas->imageHeight()); mpixels.setNum(dims.width()*dims.height()/1000000.0, 'f', 2); TQString str = (!dims.isValid()) ? i18n("Unknown") : i18n("%1x%2 (%3Mpx)") .arg(dims.width()).arg(dims.height()).arg(mpixels); m_resLabel->setText(str); if (d->urlCurrent.isValid()) { KURL u(d->urlCurrent.directory()); DImg* img = m_canvas->interface()->getImg(); if (d->imageInfoCurrent) { d->rightSidebar->itemChanged(d->imageInfoCurrent, m_canvas->getSelectedArea(), img); } else { d->rightSidebar->itemChanged(d->urlCurrent, m_canvas->getSelectedArea(), img); } } } void ImageWindow::slotUndoStateChanged(bool moreUndo, bool moreRedo, bool canSave) { m_revertAction->setEnabled(canSave); m_undoAction->setEnabled(moreUndo); m_redoAction->setEnabled(moreRedo); if (d->allowSaving) m_saveAction->setEnabled(canSave); if (!moreUndo) m_rotatedOrFlipped = false; } void ImageWindow::slotAssignTag(int tagID) { if (d->imageInfoCurrent) { MetadataHub hub; hub.load(d->imageInfoCurrent); hub.setTag(tagID, true); hub.write(d->imageInfoCurrent, MetadataHub::PartialWrite); hub.write(d->imageInfoCurrent->filePath(), MetadataHub::FullWriteIfChanged); } } void ImageWindow::slotRemoveTag(int tagID) { if (d->imageInfoCurrent) { MetadataHub hub; hub.load(d->imageInfoCurrent); hub.setTag(tagID, false); hub.write(d->imageInfoCurrent, MetadataHub::PartialWrite); hub.write(d->imageInfoCurrent->filePath(), MetadataHub::FullWriteIfChanged); } } void ImageWindow::slotAssignRatingNoStar() { slotAssignRating(0); } void ImageWindow::slotAssignRatingOneStar() { slotAssignRating(1); } void ImageWindow::slotAssignRatingTwoStar() { slotAssignRating(2); } void ImageWindow::slotAssignRatingThreeStar() { slotAssignRating(3); } void ImageWindow::slotAssignRatingFourStar() { slotAssignRating(4); } void ImageWindow::slotAssignRatingFiveStar() { slotAssignRating(5); } void ImageWindow::slotAssignRating(int rating) { rating = TQMIN(RatingMax, TQMAX(RatingMin, rating)); if (d->imageInfoCurrent) { MetadataHub hub; hub.load(d->imageInfoCurrent); hub.setRating(rating); hub.write(d->imageInfoCurrent, MetadataHub::PartialWrite); hub.write(d->imageInfoCurrent->filePath(), MetadataHub::FullWriteIfChanged); } } void ImageWindow::slotUpdateItemInfo() { uint index = d->urlList.findIndex(d->urlCurrent); m_rotatedOrFlipped = false; TQString text = d->urlCurrent.filename() + i18n(" (%2 of %3)") .arg(TQString::number(index+1)) .arg(TQString::number(d->urlList.count())); m_nameLabel->setText(text); if (d->urlList.count() == 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 == 0) { m_backwardAction->setEnabled(false); m_firstAction->setEnabled(false); } if (index == d->urlList.count()-1) { 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. KURL u(d->urlCurrent.directory()); PAlbum *palbum = AlbumManager::instance()->findPAlbum(u); if (!palbum) { m_fileDeleteAction->setEnabled(false); } else { m_fileDeleteAction->setEnabled(true); } } bool ImageWindow::setup(bool iccSetupPage) { Setup setup(this, 0, iccSetupPage ? Setup::IccProfiles : Setup::LastPageUsed); if (setup.exec() != TQDialog::Accepted) return false; kapp->config()->sync(); applySettings(); return true; } void ImageWindow::toggleGUI2FullScreen() { if (m_fullScreen) d->rightSidebar->restore(); else d->rightSidebar->backup(); } 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.path(), m_canvas->currentImage()); // notify main app that file changed emit signalFileModified(m_savingContext->destinationURL); // all that is done in slotLoadCurrent, except for loading KURL::List::iterator it = d->urlList.find(d->urlCurrent); setViewToURL(*it); if (++it != d->urlList.end()) { m_canvas->preload((*it).path()); } //slotLoadCurrent(); } void ImageWindow::saveAsIsComplete() { // Nothing to be done if operating without database if (!d->imageInfoCurrent) return; // Find the src and dest albums ------------------------------------------ KURL srcDirURL(TQDir::cleanDirPath(m_savingContext->srcURL.directory())); PAlbum* srcAlbum = AlbumManager::instance()->findPAlbum(srcDirURL); KURL dstDirURL(TQDir::cleanDirPath(m_savingContext->destinationURL.directory())); PAlbum* dstAlbum = AlbumManager::instance()->findPAlbum(dstDirURL); if (dstAlbum && srcAlbum) { // Now copy the metadata of the original file to the new file ------------ ImageInfo newInfo(d->imageInfoCurrent->copyItem(dstAlbum, m_savingContext->destinationURL.fileName())); if ( d->urlList.find(m_savingContext->destinationURL) == d->urlList.end() ) { // The image file did not exist in the list. KURL::List::iterator it = d->urlList.find(m_savingContext->srcURL); int index = d->urlList.findIndex(m_savingContext->srcURL); d->urlList.insert(it, m_savingContext->destinationURL); d->imageInfoCurrent = new ImageInfo(newInfo); d->imageInfoList.insert(index, d->imageInfoCurrent); } else if (d->urlCurrent != m_savingContext->destinationURL) { for (ImageInfo *info = d->imageInfoList.first(); info; info = d->imageInfoList.next()) { if (info->kurl() == m_savingContext->destinationURL) { d->imageInfoCurrent = new ImageInfo(newInfo); // setAutoDelete is true d->imageInfoList.replace(d->imageInfoList.at(), d->imageInfoCurrent); break; } } } d->urlCurrent = m_savingContext->destinationURL; m_canvas->switchToLastSaved(m_savingContext->destinationURL.path()); slotUpdateItemInfo(); // 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.path(), m_canvas->currentImage()); // notify main app that file changed or a file is added if(m_savingContext->destinationExisted) emit signalFileModified(m_savingContext->destinationURL); else emit signalFileAdded(m_savingContext->destinationURL); // all that is done in slotLoadCurrent, except for loading KURL::List::iterator it = d->urlList.find(d->urlCurrent); if (it != d->urlList.end()) { setViewToURL(*it); m_canvas->preload((*++it).path()); } } else { //TODO: make the user aware that the new path has not been used as new current filename // because it is outside the digikam album hierachy } } bool ImageWindow::save() { // Sanity check. Just to be homogenous with SaveAs. if (d->imageInfoCurrent) { // Write metadata from database to DImg MetadataHub hub; hub.load(d->imageInfoCurrent); DImg image(m_canvas->currentImage()); hub.write(image, MetadataHub::FullWrite); } startingSave(d->urlCurrent); return true; } bool ImageWindow::saveAs() { // If image editor is started from CameraGUI, there is no ImageInfo instance to use. if (d->imageInfoCurrent) { // Write metadata from database to DImg MetadataHub hub; hub.load(d->imageInfoCurrent); DImg image(m_canvas->currentImage()); hub.write(image, MetadataHub::FullWrite); } return ( startingSaveAs(d->urlCurrent) ); } 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 KURL u; u.setPath(d->urlCurrent.directory()); PAlbum *palbum = AlbumManager::instance()->findPAlbum(u); // if available, provide a digikamalbums:// URL to KIO KURL kioURL; if (d->imageInfoCurrent) kioURL = d->imageInfoCurrent->kurlForKIO(); else kioURL = d->urlCurrent; KURL fileURL = d->urlCurrent; if (!palbum) return; bool useTrash; if (ask) { bool preselectDeletePermanently = permanently; DeleteDialog dialog(this); KURL::List urlList; urlList.append(d->urlCurrent); if (!dialog.confirmDeleteList(urlList, DeleteDialogMode::Files, preselectDeletePermanently ? DeleteDialogMode::NoChoiceDeletePermanently : DeleteDialogMode::NoChoiceTrash)) return; useTrash = !dialog.shouldDelete(); } else { useTrash = !permanently; } // bring all (sidebar) to a defined state without letting them sit on the deleted file emit signalNoCurrentItem(); // trash does not like non-local URLs, put is not implemented if (useTrash) kioURL = fileURL; if (!SyncJob::del(kioURL, useTrash)) { TQString errMsg(SyncJob::lastErrorMsg()); KMessageBox::error(this, errMsg, errMsg); return; } emit signalFileDeleted(d->urlCurrent); KURL CurrentToRemove = d->urlCurrent; KURL::List::iterator it = d->urlList.find(d->urlCurrent); int index = d->imageInfoList.find(d->imageInfoCurrent); if (it != d->urlList.end()) { if (d->urlCurrent != d->urlList.last()) { // Try to get the next image in the current Album... KURL urlNext = *(++it); d->urlCurrent = urlNext; d->imageInfoCurrent = d->imageInfoList.at(index + 1); d->urlList.remove(CurrentToRemove); d->imageInfoList.remove(index); slotLoadCurrent(); return; } else if (d->urlCurrent != d->urlList.first()) { // Try to get the previous image in the current Album. KURL urlPrev = *(--it); d->urlCurrent = urlPrev; d->imageInfoCurrent = d->imageInfoList.at(index - 1); d->urlList.remove(CurrentToRemove); d->imageInfoList.remove(index); slotLoadCurrent(); return; } } // No image in the current Album -> Quit ImageEditor... KMessageBox::information(this, i18n("There is no image to show in the current album.\n" "The image editor will be closed."), i18n("No Image in Current Album")); close(); } void ImageWindow::slotFileMetadataChanged(const KURL &url) { if (url == d->urlCurrent) { m_canvas->readMetadataFromFile(url.path()); } } void ImageWindow::slotFilePrint() { printImage(d->urlCurrent); }; void ImageWindow::slideShow(bool startWithCurrent, SlideShowSettings& settings) { float cnt; DMetadata meta; int i = 0; m_cancelSlideShow = false; settings.exifRotate = AlbumSettings::instance()->getExifRotate(); if (!d->imageInfoList.isEmpty()) { // We have started image editor from Album GUI. we get picture comments from database. m_nameLabel->progressBarMode(StatusProgressBar::CancelProgressBarMode, i18n("Preparing slideshow. Please wait...")); cnt = (float)d->imageInfoList.count(); for (ImageInfo *info = d->imageInfoList.first() ; !m_cancelSlideShow && info ; info = d->imageInfoList.next()) { SlidePictureInfo pictInfo; pictInfo.comment = info->caption(); // Perform optimizations: only read pictures metadata if necessary. if (settings.printApertureFocal || settings.printExpoSensitivity || settings.printMakeModel) { meta.load(info->kurl().path()); pictInfo.photoInfo = meta.getPhotographInformations(); } // In case of dateTime extraction from metadata failed pictInfo.photoInfo.dateTime = info->dateTime(); settings.pictInfoMap.insert(info->kurl(), pictInfo); m_nameLabel->setProgressValue((int)((i++/cnt)*100.0)); kapp->processEvents(); } } else { // We have started image editor from Camera GUI. we get picture comments from metadata. m_nameLabel->progressBarMode(StatusProgressBar::CancelProgressBarMode, i18n("Preparing slideshow. Please wait...")); cnt = (float)d->urlList.count(); for (KURL::List::Iterator it = d->urlList.begin() ; !m_cancelSlideShow && (it != d->urlList.end()) ; ++it) { SlidePictureInfo pictInfo; meta.load((*it).path()); pictInfo.comment = meta.getImageComment(); pictInfo.photoInfo = meta.getPhotographInformations(); settings.pictInfoMap.insert(*it, pictInfo); m_nameLabel->setProgressValue((int)((i++/cnt)*100.0)); kapp->processEvents(); } } m_nameLabel->progressBarMode(StatusProgressBar::TextMode, TQString()); if (!m_cancelSlideShow) { settings.exifRotate = AlbumSettings::instance()->getExifRotate(); settings.fileList = d->urlList; SlideShow *slide = new SlideShow(settings); if (startWithCurrent) slide->setCurrent(d->urlCurrent); slide->show(); } } void ImageWindow::dragMoveEvent(TQDragMoveEvent *e) { int albumID; TQValueList albumIDs; TQValueList imageIDs; KURL::List urls; KURL::List kioURLs; if (ItemDrag::decode(e, urls, kioURLs, albumIDs, imageIDs) || AlbumDrag::decode(e, urls, albumID) || TagDrag::canDecode(e)) { e->accept(); return; } e->ignore(); } void ImageWindow::dropEvent(TQDropEvent *e) { int albumID; TQValueList albumIDs; TQValueList imageIDs; KURL::List urls; KURL::List kioURLs; if (ItemDrag::decode(e, urls, kioURLs, albumIDs, imageIDs)) { ImageInfoList imageInfoList; for (TQValueList::const_iterator it = imageIDs.begin(); it != imageIDs.end(); ++it) { ImageInfo *info = new ImageInfo(*it); imageInfoList.append(info); } if (imageInfoList.isEmpty()) { e->ignore(); return; } TQString ATitle; AlbumManager* man = AlbumManager::instance(); PAlbum* palbum = man->findPAlbum(albumIDs.first()); if (palbum) ATitle = palbum->title(); TAlbum* talbum = man->findTAlbum(albumIDs.first()); if (talbum) ATitle = talbum->title(); loadImageInfos(imageInfoList, imageInfoList.first(), i18n("Album \"%1\"").arg(ATitle), true); e->accept(); } else if (AlbumDrag::decode(e, urls, albumID)) { AlbumManager* man = AlbumManager::instance(); TQValueList itemIDs = man->albumDB()->getItemIDsInAlbum(albumID); ImageInfoList imageInfoList; for (TQValueList::const_iterator it = itemIDs.begin(); it != itemIDs.end(); ++it) { ImageInfo *info = new ImageInfo(*it); imageInfoList.append(info); } if (imageInfoList.isEmpty()) { e->ignore(); return; } TQString ATitle; PAlbum* palbum = man->findPAlbum(albumIDs.first()); if (palbum) ATitle = palbum->title(); loadImageInfos(imageInfoList, imageInfoList.first(), i18n("Album \"%1\"").arg(ATitle), true); e->accept(); } else if(TagDrag::canDecode(e)) { TQByteArray ba = e->encodedData("digikam/tag-id"); TQDataStream ds(ba, IO_ReadOnly); int tagID; ds >> tagID; AlbumManager* man = AlbumManager::instance(); TQValueList itemIDs = man->albumDB()->getItemIDsInTag(tagID, true); ImageInfoList imageInfoList; for (TQValueList::const_iterator it = itemIDs.begin(); it != itemIDs.end(); ++it) { ImageInfo *info = new ImageInfo(*it); imageInfoList.append(info); } if (imageInfoList.isEmpty()) { e->ignore(); return; } TQString ATitle; TAlbum* talbum = man->findTAlbum(tagID); if (talbum) ATitle = talbum->title(); loadImageInfos(imageInfoList, imageInfoList.first(), i18n("Album \"%1\"").arg(ATitle), true); e->accept(); } else { e->ignore(); } } void ImageWindow::slotRevert() { if(!promptUserSave(d->urlCurrent)) return; m_canvas->slotRestore(); } void ImageWindow::slotChangeTheme(const TQString& theme) { AlbumSettings::instance()->setCurrentTheme(theme); ThemeEngine::instance()->slotChangeTheme(theme); } } // namespace Digikam