/* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2002-16-10 * Description : album icon view * * Copyright (C) 2002-2005 by Renchi Raju * Copyright (C) 2002-2008 by Gilles Caulier * Copyright (C) 2006-2008 by Marcel Wiesweg * * 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. * * ============================================================ */ #ifdef HAVE_CONFIG_H #include #endif // C Ansi includes. extern "C" { #include #include #include } // C++ includes. #include // TQt includes. #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 #include #include #include #include #include #include #if KDE_IS_VERSION(3,2,0) #include #include #else #include #endif // LibKipi includes. #include #include // LibKDcraw includes. #include #include #if KDCRAW_VERSION < 0x000106 #include #endif // Local includes. #include "constants.h" #include "ddebug.h" #include "album.h" #include "albummanager.h" #include "dio.h" #include "albumlister.h" #include "albumfiletip.h" #include "albumsettings.h" #include "imagewindow.h" #include "thumbnailsize.h" #include "themeengine.h" #include "dpopupmenu.h" #include "tagspopupmenu.h" #include "ratingpopupmenu.h" #include "pixmapmanager.h" #include "cameraui.h" #include "dragobjects.h" #include "dmetadata.h" #include "albumdb.h" #include "imageattributeswatch.h" #include "deletedialog.h" #include "albumiconitem.h" #include "albumicongroupitem.h" #include "loadingcacheinterface.h" #include "lighttablewindow.h" #include "statusprogressbar.h" #include "metadatahub.h" #include "albumiconview.h" #include "albumiconview.moc" namespace Digikam { class AlbumIconViewPrivate { public: void init() { imageLister = 0; currentAlbum = 0; albumSettings = 0; pixMan = 0; toolTip = 0; } TQString albumTitle; TQString albumDate; TQString albumComments; TQRect itemRect; TQRect itemRatingRect; TQRect itemDateRect; TQRect itemModDateRect; TQRect itemPixmapRect; TQRect itemNameRect; TQRect itemCommentsRect; TQRect itemResolutionRect; TQRect itemSizeRect; TQRect itemTagRect; TQRect bannerRect; TQPixmap itemRegPixmap; TQPixmap itemSelPixmap; TQPixmap bannerPixmap; TQPixmap ratingPixmap; TQFont fnReg; TQFont fnCom; TQFont fnXtra; TQDict itemDict; KURL itemUrlToFind; AlbumLister *imageLister; Album *currentAlbum; const AlbumSettings *albumSettings; TQIntDict albumDict; PixmapManager *pixMan; ThumbnailSize thumbSize; AlbumFileTip *toolTip; }; AlbumIconView::AlbumIconView(TQWidget* parent) : IconView(parent) { d = new AlbumIconViewPrivate; d->init(); d->imageLister = AlbumLister::instance(); d->pixMan = new PixmapManager(this); d->toolTip = new AlbumFileTip(this); setAcceptDrops(true); viewport()->setAcceptDrops(true); // -- Load rating Pixmap ------------------------------------------ KGlobal::dirs()->addResourceType("digikam_rating", KGlobal::dirs()->kde_default("data") + "digikam/data"); TQString ratingPixPath = KGlobal::dirs()->findResourceDir("digikam_rating", "rating.png"); ratingPixPath += "/rating.png"; d->ratingPixmap = TQPixmap(ratingPixPath); TQPainter painter(&d->ratingPixmap); painter.fillRect(0, 0, d->ratingPixmap.width(), d->ratingPixmap.height(), ThemeEngine::instance()->textSpecialRegColor()); painter.end(); // -- ImageLister connections ------------------------------------- connect(d->imageLister, TQT_SIGNAL(signalNewFilteredItems(const ImageInfoList&)), this, TQT_SLOT(slotImageListerNewItems(const ImageInfoList&))); connect(d->imageLister, TQT_SIGNAL(signalDeleteFilteredItem(ImageInfo*)), this, TQT_SLOT(slotImageListerDeleteItem(ImageInfo*)) ); connect(d->imageLister, TQT_SIGNAL(signalClear()), this, TQT_SLOT(slotImageListerClear())); // -- Icon connections -------------------------------------------- connect(this, TQT_SIGNAL(signalDoubleClicked(IconItem*)), this, TQT_SLOT(slotDoubleClicked(IconItem*))); connect(this, TQT_SIGNAL(signalReturnPressed(IconItem*)), this, TQT_SLOT(slotDoubleClicked(IconItem*))); connect(this, TQT_SIGNAL(signalRightButtonClicked(IconItem*, const TQPoint &)), this, TQT_SLOT(slotRightButtonClicked(IconItem*, const TQPoint &))); connect(this, TQT_SIGNAL(signalRightButtonClicked(const TQPoint &)), this, TQT_SLOT(slotRightButtonClicked(const TQPoint &))); connect(this, TQT_SIGNAL(signalSelectionChanged()), this, TQT_SLOT(slotSelectionChanged())); connect(this, TQT_SIGNAL(signalShowToolTip(IconItem*)), this, TQT_SLOT(slotShowToolTip(IconItem*))); // -- ThemeEngine connections --------------------------------------- connect(ThemeEngine::instance(), TQT_SIGNAL(signalThemeChanged()), TQT_SLOT(slotThemeChanged())); // -- Pixmap manager connections ------------------------------------ connect(d->pixMan, TQT_SIGNAL(signalPixmap(const KURL&)), TQT_SLOT(slotGotThumbnail(const KURL&))); // -- ImageAttributesWatch connections ------------------------------ ImageAttributesWatch *watch = ImageAttributesWatch::instance(); connect(watch, TQT_SIGNAL(signalImageTagsChanged(TQ_LLONG)), this, TQT_SLOT(slotImageAttributesChanged(TQ_LLONG))); connect(watch, TQT_SIGNAL(signalImagesChanged(int)), this, TQT_SLOT(slotAlbumImagesChanged(int))); connect(watch, TQT_SIGNAL(signalImageRatingChanged(TQ_LLONG)), this, TQT_SLOT(slotImageAttributesChanged(TQ_LLONG))); connect(watch, TQT_SIGNAL(signalImageDateChanged(TQ_LLONG)), this, TQT_SLOT(slotImageAttributesChanged(TQ_LLONG))); connect(watch, TQT_SIGNAL(signalImageCaptionChanged(TQ_LLONG)), this, TQT_SLOT(slotImageAttributesChanged(TQ_LLONG))); } AlbumIconView::~AlbumIconView() { delete d->pixMan; delete d->toolTip; delete d; } void AlbumIconView::applySettings(const AlbumSettings* settings) { if (!settings) return; d->albumSettings = settings; d->imageLister->setNamesFilter(d->albumSettings->getAllFileFilter()); d->thumbSize = (ThumbnailSize::Size)d->albumSettings->getDefaultIconSize(); setEnableToolTips(d->albumSettings->getShowToolTips()); updateBannerRectPixmap(); updateItemRectsPixmap(); d->imageLister->stop(); clear(); d->pixMan->setThumbnailSize(d->thumbSize.size()); if (d->currentAlbum) { d->imageLister->openAlbum(d->currentAlbum); } } void AlbumIconView::setThumbnailSize(const ThumbnailSize& thumbSize) { if ( d->thumbSize != thumbSize) { d->thumbSize = thumbSize; d->pixMan->setThumbnailSize(d->thumbSize.size()); updateBannerRectPixmap(); updateItemRectsPixmap(); IconItem *currentIconItem = currentItem(); triggerRearrangement(); setStoredVisibleItem(currentIconItem); } } void AlbumIconView::setAlbum(Album* album) { if (!album) { d->currentAlbum = 0; d->imageLister->stop(); clear(); return; } if (d->currentAlbum == album) return; d->imageLister->stop(); clear(); d->currentAlbum = album; d->imageLister->openAlbum(d->currentAlbum); updateBannerRectPixmap(); updateItemRectsPixmap(); } void AlbumIconView::setAlbumItemToFind(const KURL& url) { d->itemUrlToFind = url; } void AlbumIconView::refreshIcon(AlbumIconItem* item) { if (!item) return; emit signalSelectionChanged(); } void AlbumIconView::clear(bool update) { emit signalCleared(); d->pixMan->clear(); d->itemDict.clear(); d->albumDict.clear(); IconView::clear(update); emit signalSelectionChanged(); } void AlbumIconView::slotImageListerNewItems(const ImageInfoList& itemList) { if (!d->currentAlbum || d->currentAlbum->isRoot()) return; ImageInfo* item; for (ImageInfoListIterator it(itemList); (item = it.current()); ++it) { KURL url( item->kurl() ); url.cleanPath(); if (AlbumIconItem *oldItem = d->itemDict.find(url.url())) { slotImageListerDeleteItem(oldItem->imageInfo()); } AlbumIconGroupItem* group = d->albumDict.find(item->albumID()); if (!group) { group = new AlbumIconGroupItem(this, item->albumID()); d->albumDict.insert(item->albumID(), group); } if (!item->album()) { DWarning() << "No album for item: " << item->name() << ", albumID: " << item->albumID() << endl; continue; } AlbumIconItem* iconItem = new AlbumIconItem(group, item); item->setViewItem(iconItem); d->itemDict.insert(url.url(), iconItem); } // Make the icon, specified by d->itemUrlToFind, the current one // in the album icon view and make it visible. // This is for example used after a "Go To", // e.g. from tags (or date) view to folder view. // Note that AlbumIconView::slotImageListerNewItems may // be called several times after another, because images get // listed in packages of 200. // Therefore the item might not always be available in the very // first call when there are sufficiently many images. // Also, because of this, we cannot reset the item which is to be found, // i.e. something like d->itemUrlToFind = 0, after the item was found, // as then the visibility of this item is lost in a subsequent call. if (!d->itemUrlToFind.isEmpty()) { AlbumIconItem* icon = findItem(d->itemUrlToFind.url()); if (icon) { clearSelection(); updateContents(); setCurrentItem(icon); ensureItemVisible(icon); // make the item really visible // (the previous ensureItemVisible does not work) setStoredVisibleItem(icon); triggerRearrangement(); } } emit signalItemsAdded(); } void AlbumIconView::slotImageListerDeleteItem(ImageInfo* item) { if (!item->getViewItem()) return; AlbumIconItem* iconItem = static_cast(item->getViewItem()); KURL url(item->kurl()); url.cleanPath(); AlbumIconItem *oldItem = d->itemDict[url.url()]; if( oldItem && (oldItem->imageInfo()->id() != iconItem->imageInfo()->id())) { return; } //d->pixMan->remove(item->kurl()); emit signalItemDeleted(iconItem); delete iconItem; item->setViewItem(0); d->itemDict.remove(url.url()); IconGroupItem* group = firstGroup(); IconGroupItem* tmp; while (group) { tmp = group->nextGroup(); if (group->count() == 0) { d->albumDict.remove(((AlbumIconGroupItem*)group)->albumID()); delete group; } group = tmp; } } void AlbumIconView::slotImageListerClear() { clear(); } void AlbumIconView::slotDoubleClicked(IconItem *item) { if (!item) return; if (d->albumSettings->getItemRightClickAction() == AlbumSettings::ShowPreview) { // icon effect takes too much time //KIconEffect::visualActivate(viewport(), contentsRectToViewport(item->rect())); signalPreviewItem(static_cast(item)); } else { KIconEffect::visualActivate(viewport(), contentsRectToViewport(item->rect())); slotDisplayItem(static_cast(item)); } } void AlbumIconView::slotRightButtonClicked(const TQPoint& pos) { if (!d->currentAlbum) return; if (d->currentAlbum->isRoot() || ( d->currentAlbum->type() != Album::PHYSICAL && d->currentAlbum->type() != Album::TAG)) { return; } TQPopupMenu popmenu(this); KAction *paste = KStdAction::paste(TQT_TQOBJECT(this), TQT_SLOT(slotPaste()), 0); TQMimeSource *data = kapp->clipboard()->data(TQClipboard::Clipboard); if(!data || !TQUriDrag::canDecode(data)) { paste->setEnabled(false); } paste->plug(&popmenu); popmenu.exec(pos); delete paste; } void AlbumIconView::slotRightButtonClicked(IconItem *item, const TQPoint& pos) { if (!item) return; AlbumIconItem* iconItem = static_cast(item); // -------------------------------------------------------- KMimeType::Ptr mimePtr = KMimeType::findByURL(iconItem->imageInfo()->kurl(), 0, true, true); TQValueVector serviceVector; KTrader::OfferList offers = KTrader::self()->query(mimePtr->name(), "Type == 'Application'"); TQPopupMenu openWithMenu; KTrader::OfferList::Iterator iter; KService::Ptr ptr; int index = 100; for( iter = offers.begin(); iter != offers.end(); ++iter ) { ptr = *iter; openWithMenu.insertItem( ptr->pixmap(KIcon::Small), ptr->name(), index++); serviceVector.push_back(ptr); } // Obtain a list of all selected images. // This is needed both for the goto tags submenu here and also // for the "move to trash" and further actions below. TQValueList selectedImageIDs; for (IconItem *it = firstItem(); it; it=it->nextItem()) { if (it->isSelected()) { AlbumIconItem *selItem = static_cast(it); selectedImageIDs.append(selItem->imageInfo()->id()); } } // -------------------------------------------------------- // Provide Goto folder and/or date pop-up menu TQPopupMenu gotoMenu; gotoMenu.insertItem(SmallIcon("folder_image"), i18n("Album"), 20); gotoMenu.insertItem(SmallIcon("date"), i18n("Date"), 21); TagsPopupMenu* gotoTagsPopup = new TagsPopupMenu(selectedImageIDs, 1000, TagsPopupMenu::DISPLAY); int gotoTagId = gotoMenu.insertItem(SmallIcon("tag"), i18n("Tag"), gotoTagsPopup); // Disable the goto Tag popup menu, if there are no tags at all. AlbumManager* man = AlbumManager::instance(); if (!man->albumDB()->hasTags(selectedImageIDs)) gotoMenu.setItemEnabled(gotoTagId, false); connect(gotoTagsPopup, TQT_SIGNAL(signalTagActivated(int)), this, TQT_SLOT(slotGotoTag(int))); if (d->currentAlbum->type() == Album::PHYSICAL ) { // If the currently selected album is the same as album to // which the image belongs, then disable the "Go To" Album. // (Note that in recursive album view these can be different). if (iconItem->imageInfo()->albumID() == d->currentAlbum->id()) gotoMenu.setItemEnabled(20, false); } else if (d->currentAlbum->type() == Album::DATE ) { gotoMenu.setItemEnabled(21, false); } // -------------------------------------------------------- DPopupMenu popmenu(this); popmenu.insertItem(SmallIcon("viewimage"), i18n("View..."), 18); popmenu.insertItem(SmallIcon("editimage"), i18n("Edit..."), 10); popmenu.insertItem(SmallIcon("lighttableadd"), i18n("Add to Light Table"), 19); // Note that the numbers 18, 10, 19 are used below in // the switch(id) for popmenu.exec(pos); // For the goto menu such a number is not needed, // because only the above 20 and 21 of the goto popup are used, // but it has to be provided. popmenu.insertItem(SmallIcon("goto"), i18n("Go To"), &gotoMenu, 12); // If there is more than one image selected, disable the goto menu entry. if (selectedImageIDs.count() > 1) { popmenu.setItemEnabled(12, false); } popmenu.insertItem(i18n("Open With"), &openWithMenu, 11); // Merge in the KIPI plugins actions ---------------------------- KIPI::PluginLoader* kipiPluginLoader = KIPI::PluginLoader::instance(); KIPI::PluginLoader::PluginList pluginList = kipiPluginLoader->pluginList(); for (KIPI::PluginLoader::PluginList::const_iterator it = pluginList.begin(); it != pluginList.end(); ++it) { KIPI::Plugin* plugin = (*it)->plugin(); if (plugin && (*it)->name() == "JPEGLossless") { DDebug() << "Found JPEGLossless plugin" << endl; KActionPtrList actionList = plugin->actions(); for (KActionPtrList::const_iterator iter = actionList.begin(); iter != actionList.end(); ++iter) { KAction* action = *iter; if (TQString::fromLatin1(action->name()) == TQString::fromLatin1("jpeglossless_rotate")) { action->plug(&popmenu); } } } } // -------------------------------------------------------- popmenu.insertItem(SmallIcon("pencil"), i18n("Rename..."), 15); popmenu.insertSeparator(); // -------------------------------------------------------- if (d->currentAlbum) { if (d->currentAlbum->type() == Album::PHYSICAL ) { popmenu.insertItem(i18n("Set as Album Thumbnail"), 17); popmenu.insertSeparator(); } else if (d->currentAlbum->type() == Album::TAG ) { popmenu.insertItem(i18n("Set as Tag Thumbnail"), 17); popmenu.insertSeparator(); } } // -------------------------------------------------------- KAction *copy = KStdAction::copy(TQT_TQOBJECT(this), TQT_SLOT(slotCopy()), 0); KAction *paste = KStdAction::paste(TQT_TQOBJECT(this), TQT_SLOT(slotPaste()), 0); TQMimeSource *data = kapp->clipboard()->data(TQClipboard::Clipboard); if(!data || !TQUriDrag::canDecode(data)) { paste->setEnabled(false); } copy->plug(&popmenu); paste->plug(&popmenu); popmenu.insertSeparator(); // -------------------------------------------------------- popmenu.insertItem(SmallIcon("edittrash"), i18n("Move to Trash", "Move %n Files to Trash" , selectedImageIDs.count() ), 16); popmenu.insertSeparator(); // Bulk assignment/removal of tags -------------------------- TagsPopupMenu* assignTagsPopup = new TagsPopupMenu(selectedImageIDs, 1000, TagsPopupMenu::ASSIGN); TagsPopupMenu* removeTagsPopup = new TagsPopupMenu(selectedImageIDs, 1000, TagsPopupMenu::REMOVE); connect(assignTagsPopup, TQT_SIGNAL(signalTagActivated(int)), this, TQT_SLOT(slotAssignTag(int))); connect(removeTagsPopup, TQT_SIGNAL(signalTagActivated(int)), this, TQT_SLOT(slotRemoveTag(int))); popmenu.insertItem(i18n("Assign Tag"), assignTagsPopup); int removeTagId = popmenu.insertItem(i18n("Remove Tag"), removeTagsPopup); // Performance: Only check for tags if there are <250 images selected // Also disable the remove Tag popup menu, if there are no tags at all. if (selectedImageIDs.count() > 250 || !man->albumDB()->hasTags(selectedImageIDs)) popmenu.setItemEnabled(removeTagId, false); popmenu.insertSeparator(); // Assign Star Rating ------------------------------------------- RatingPopupMenu ratingMenu; connect(&ratingMenu, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotAssignRating(int))); popmenu.insertItem(i18n("Assign Rating"), &ratingMenu); // -------------------------------------------------------- int id = popmenu.exec(pos); switch(id) { case 10: { slotDisplayItem(iconItem); break; } case 15: { slotRename(iconItem); break; } case 16: { slotDeleteSelectedItems(); break; } case 17: { slotSetAlbumThumbnail(iconItem); break; } case 18: { signalPreviewItem(iconItem); break; } case 19: { // add images to existing images in the light table insertSelectionToLightTable(true); break; } case 20: // goto album { // send a signal to the parent widget (digikamview.cpp) emit signalGotoAlbumAndItem(iconItem); break; } case 21: // goto date { // send a signal to the parent widget (digikamview.cpp) emit signalGotoDateAndItem(iconItem); break; } default: break; } //--------------------------------------------------------------- if (id >= 100 && id < 1000) { KService::Ptr imageServicePtr = serviceVector[id-100]; KURL::List urlList; for (IconItem *it = firstItem(); it; it=it->nextItem()) { if (it->isSelected()) { AlbumIconItem *selItem = static_cast(it); urlList.append(selItem->imageInfo()->kurl()); } } if (urlList.count()) KRun::run(*imageServicePtr, urlList); } serviceVector.clear(); delete assignTagsPopup; delete removeTagsPopup; delete copy; delete paste; } void AlbumIconView::slotCopy() { if (!d->currentAlbum) return; KURL::List urls; KURL::List kioURLs; TQValueList albumIDs; TQValueList imageIDs; for (IconItem *it = firstItem(); it; it=it->nextItem()) { if (it->isSelected()) { AlbumIconItem *albumItem = static_cast(it); urls.append(albumItem->imageInfo()->kurl()); kioURLs.append(albumItem->imageInfo()->kurlForKIO()); imageIDs.append(albumItem->imageInfo()->id()); } } albumIDs.append(d->currentAlbum->id()); if (urls.isEmpty()) return; TQDragObject* drag = 0; drag = new ItemDrag(urls, kioURLs, albumIDs, imageIDs, this); kapp->clipboard()->setData(drag); } void AlbumIconView::slotPaste() { TQMimeSource *data = kapp->clipboard()->data(TQClipboard::Clipboard); if(!data) return; Album *album = 0; // Check if we working on grouped items view. if (groupCount() > 1) { AlbumIconGroupItem *grp = dynamic_cast(findGroup(TQCursor::pos())); if (grp) { if(d->currentAlbum->type() == Album::PHYSICAL) album = dynamic_cast(AlbumManager::instance()->findPAlbum(grp->albumID())); else if(d->currentAlbum->type() == Album::TAG) album = dynamic_cast(AlbumManager::instance()->findTAlbum(grp->albumID())); } } if (!album) album = d->currentAlbum; if(d->currentAlbum->type() == Album::PHYSICAL && TQUriDrag::canDecode(data)) { PAlbum* palbum = (PAlbum*)album; // B.K.O #119205: do not handle root album. if (palbum->isRoot()) return; KURL destURL(palbum->kurl()); KURL::List srcURLs; KURLDrag::decode(data, srcURLs); KIO::Job* job = DIO::copy(srcURLs, destURL); connect(job, TQT_SIGNAL(result(KIO::Job*)), this, TQT_SLOT(slotDIOResult(KIO::Job*))); } else if(d->currentAlbum->type() == Album::TAG && ItemDrag::canDecode(data)) { TAlbum* talbum = (TAlbum*)album; // B.K.O #119205: do not handle root album. if (talbum->isRoot()) return; KURL::List urls; KURL::List kioURLs; TQValueList albumIDs; TQValueList imageIDs; if (!ItemDrag::decode(data, urls, kioURLs, albumIDs, imageIDs)) return; if (urls.isEmpty() || kioURLs.isEmpty() || albumIDs.isEmpty() || imageIDs.isEmpty()) return; TQPtrList list; for (TQValueList::const_iterator it = imageIDs.begin(); it != imageIDs.end(); ++it) { ImageInfo *info = new ImageInfo(*it); list.append(info); } changeTagOnImageInfos(list, TQValueList() << talbum->id(), true, true); } } void AlbumIconView::slotSetAlbumThumbnail(AlbumIconItem *iconItem) { if(!d->currentAlbum) return; if(d->currentAlbum->type() == Album::PHYSICAL) { PAlbum *album = static_cast(d->currentAlbum); TQString err; AlbumManager::instance()->updatePAlbumIcon( album, iconItem->imageInfo()->id(), err ); } else if (d->currentAlbum->type() == Album::TAG) { TAlbum *album = static_cast(d->currentAlbum); TQString err; AlbumManager::instance()->updateTAlbumIcon( album, TQString(), iconItem->imageInfo()->id(), err ); } } void AlbumIconView::slotRename(AlbumIconItem* item) { if (!item) return; // Create a copy of the item. After entering the event loop // in the dialog, we cannot be sure about the item's status. ImageInfo renameInfo(*item->imageInfo()); TQFileInfo fi(item->imageInfo()->name()); TQString ext = TQString(".") + fi.extension(false); TQString name = fi.fileName(); name.truncate(fi.fileName().length() - ext.length()); bool ok; #if KDE_IS_VERSION(3,2,0) TQString newName = KInputDialog::getText(i18n("Rename Item (%1)").arg(fi.fileName()), i18n("Enter new name (without extension):"), name, &ok, this); #else TQString newName = KLineEditDlg::getText(i18n("Rename Item (%1)").arg(fi.fileName()), i18n("Enter new name (without extension):"), name, &ok, this); #endif if (!ok) return; KURL oldURL = renameInfo.kurlForKIO(); KURL newURL = oldURL; newURL.setFileName(newName + ext); KIO::CopyJob* job = DIO::rename(oldURL, newURL); connect(job, TQT_SIGNAL(result(KIO::Job*)), this, TQT_SLOT(slotDIOResult(KIO::Job*))); connect(job, TQT_SIGNAL(copyingDone(KIO::Job *, const KURL &, const KURL &, bool, bool)), this, TQT_SLOT(slotRenamed(KIO::Job*, const KURL &, const KURL&))); // The AlbumManager KDirWatch will trigger a DIO::scan. // When this is completed, DIO will call AlbumLister::instance()->refresh(). // Usually the AlbumLister will ignore changes to already listed items. // So the renamed item need explicitly be invalidated. d->imageLister->invalidateItem(&renameInfo); } void AlbumIconView::slotRenamed(KIO::Job*, const KURL &, const KURL&newURL) { // reconstruct file path from digikamalbums:// URL KURL fileURL; fileURL.setPath(newURL.user()); fileURL.addPath(newURL.path()); // refresh thumbnail d->pixMan->remove(fileURL); // clean LoadingCache as well - be pragmatic, do it here. LoadingCacheInterface::cleanFromCache(fileURL.path()); } void AlbumIconView::slotDeleteSelectedItems(bool deletePermanently) { KURL::List urlList; KURL::List kioUrlList; for (IconItem *it = firstItem(); it; it=it->nextItem()) { if (it->isSelected()) { AlbumIconItem *iconItem = static_cast(it); urlList.append(iconItem->imageInfo()->kurl()); kioUrlList.append(iconItem->imageInfo()->kurlForKIO()); } } if (urlList.count() <= 0) return; DeleteDialog dialog(this); if (!dialog.confirmDeleteList(urlList, DeleteDialogMode::Files, deletePermanently ? DeleteDialogMode::NoChoiceDeletePermanently : DeleteDialogMode::NoChoiceTrash)) return; bool useTrash = !dialog.shouldDelete(); // trash does not like non-local URLs, put is not implemented KIO::Job* job = DIO::del(useTrash ? urlList : kioUrlList, useTrash); connect(job, TQT_SIGNAL(result(KIO::Job*)), this, TQT_SLOT(slotDIOResult(KIO::Job*))); // The AlbumManager KDirWatch will trigger a DIO::scan. // When this is completed, DIO will call AlbumLister::instance()->refresh(). } void AlbumIconView::slotDeleteSelectedItemsDirectly(bool useTrash) { // This method deletes the selected items directly, without confirmation. // It is not used in the default setup. KURL::List kioUrlList; KURL::List urlList; for (IconItem *it = firstItem(); it; it=it->nextItem()) { if (it->isSelected()) { AlbumIconItem *iconItem = static_cast(it); kioUrlList.append(iconItem->imageInfo()->kurlForKIO()); urlList.append(iconItem->imageInfo()->kurl()); } } if (kioUrlList.count() <= 0) return; // trash does not like non-local URLs, put is not implemented KIO::Job* job = DIO::del(useTrash ? urlList : kioUrlList , useTrash); connect(job, TQT_SIGNAL(result(KIO::Job*)), this, TQT_SLOT(slotDIOResult(KIO::Job*))); } void AlbumIconView::slotFilesModified() { d->imageLister->refresh(); } void AlbumIconView::slotFilesModified(const KURL& url) { refreshItems(url); } void AlbumIconView::slotImageWindowURLChanged(const KURL &url) { IconItem* item = findItem(url.url()); if (item) setCurrentItem(item); } void AlbumIconView::slotDisplayItem(AlbumIconItem *item) { if (!item) return; AlbumSettings *settings = AlbumSettings::instance(); if (!settings) return; TQString currentFileExtension = item->imageInfo()->name().section( '.', -1 ); TQString imagefilter = settings->getImageFileFilter().lower() + settings->getImageFileFilter().upper(); #if KDCRAW_VERSION < 0x000106 if (KDcrawIface::DcrawBinary::instance()->versionIsRight()) { // add raw files only if dcraw is available imagefilter += settings->getRawFileFilter().lower() + settings->getRawFileFilter().upper(); } #else // add raw files only if dcraw is available imagefilter += settings->getRawFileFilter().lower() + settings->getRawFileFilter().upper(); #endif // If the current item is not an image file. if ( !imagefilter.contains(currentFileExtension) ) { KMimeType::Ptr mimePtr = KMimeType::findByURL(item->imageInfo()->kurl(), 0, true, true); KTrader::OfferList offers = KTrader::self()->query(mimePtr->name(), "Type == 'Application'"); if (offers.isEmpty()) return; KService::Ptr ptr = offers.first(); // Run the dedicated app to show the item. KRun::run(*ptr, item->imageInfo()->kurl()); return; } // Run Digikam ImageEditor with all image files in the current Album. ImageInfoList imageInfoList; ImageInfo *currentImageInfo = 0; for (IconItem *it = firstItem() ; it ; it = it->nextItem()) { AlbumIconItem *iconItem = static_cast(it); TQString fileExtension = iconItem->imageInfo()->kurl().fileName().section( '.', -1 ); if ( imagefilter.find(fileExtension) != -1 ) { ImageInfo *info = new ImageInfo(*iconItem->imageInfo()); info->setViewItem(0); imageInfoList.append(info); if (iconItem == item) currentImageInfo = info; } } ImageWindow *imview = ImageWindow::imagewindow(); imview->disconnect(this); connect(imview, TQT_SIGNAL(signalFileAdded(const KURL&)), this, TQT_SLOT(slotFilesModified())); connect(imview, TQT_SIGNAL(signalFileModified(const KURL&)), this, TQT_SLOT(slotFilesModified(const KURL&))); connect(imview, TQT_SIGNAL(signalFileDeleted(const KURL&)), this, TQT_SLOT(slotFilesModified())); connect(imview, TQT_SIGNAL(signalURLChanged(const KURL&)), this, TQT_SLOT(slotImageWindowURLChanged(const KURL &))); imview->loadImageInfos(imageInfoList, currentImageInfo, d->currentAlbum ? i18n("Album \"%1\"").arg(d->currentAlbum->title()) : TQString(), true); if (imview->isHidden()) imview->show(); imview->raise(); imview->setFocus(); } void AlbumIconView::insertSelectionToLightTable(bool addTo) { // Run Light Table with all selected image files in the current Album. // If addTo is false, the light table will be emptied before adding // the images. ImageInfoList imageInfoList; for (IconItem *it = firstItem() ; it ; it = it->nextItem()) { if ((*it).isSelected()) { AlbumIconItem *iconItem = static_cast(it); ImageInfo *info = new ImageInfo(*iconItem->imageInfo()); info->setViewItem(0); imageInfoList.append(info); } } insertToLightTable(imageInfoList, imageInfoList.first(), addTo); } void AlbumIconView::insertToLightTable(const ImageInfoList& list, ImageInfo* current, bool addTo) { LightTableWindow *ltview = LightTableWindow::lightTableWindow(); ltview->disconnect(this); connect(ltview, TQT_SIGNAL(signalFileDeleted(const KURL&)), this, TQT_SLOT(slotFilesModified())); connect(this, TQT_SIGNAL(signalItemsUpdated(const KURL::List&)), ltview, TQT_SLOT(slotItemsUpdated(const KURL::List&))); if (ltview->isHidden()) ltview->show(); ltview->raise(); ltview->setFocus(); // If addTo is false, the light table will be emptied before adding // the images. ltview->loadImageInfos(list, current, addTo); ltview->setLeftRightItems(list, addTo); } // ------------------------------------------------------------------------------ AlbumIconItem* AlbumIconView::firstSelectedItem() const { AlbumIconItem *iconItem = 0; for (IconItem *it = firstItem(); it; it = it->nextItem()) { if (it->isSelected()) { iconItem = static_cast(it); break; } } return iconItem; } const AlbumSettings* AlbumIconView::settings() const { return d->albumSettings; } ThumbnailSize AlbumIconView::thumbnailSize() const { return d->thumbSize; } void AlbumIconView::resizeEvent(TQResizeEvent *e) { IconView::resizeEvent(e); if (d->bannerRect.width() != frameRect().width()) updateBannerRectPixmap(); } // -- DnD --------------------------------------------------- void AlbumIconView::startDrag() { if (!d->currentAlbum) return; KURL::List urls; KURL::List kioURLs; TQValueList albumIDs; TQValueList imageIDs; for (IconItem *it = firstItem(); it; it=it->nextItem()) { if (it->isSelected()) { AlbumIconItem *albumItem = static_cast(it); urls.append(albumItem->imageInfo()->kurl()); kioURLs.append(albumItem->imageInfo()->kurlForKIO()); imageIDs.append(albumItem->imageInfo()->id()); } } albumIDs.append(d->currentAlbum->id()); if (urls.isEmpty()) return; TQPixmap icon(DesktopIcon("image", 48)); int w = icon.width(); int h = icon.height(); TQPixmap pix(w+4,h+4); TQString text(TQString::number(urls.count())); TQPainter p(&pix); p.fillRect(0, 0, w+4, h+4, TQColor(TQt::white)); p.setPen(TQPen(TQt::black, 1)); p.drawRect(0, 0, w+4, h+4); p.drawPixmap(2, 2, icon); TQRect r = p.boundingRect(2,2,w,h,TQt::AlignLeft|TQt::AlignTop,text); r.setWidth(TQMAX(r.width(),r.height())); r.setHeight(TQMAX(r.width(),r.height())); p.fillRect(r, TQColor(0,80,0)); p.setPen(TQt::white); TQFont f(font()); f.setBold(true); p.setFont(f); p.drawText(r, TQt::AlignCenter, text); p.end(); TQDragObject* drag = 0; drag = new ItemDrag(urls, kioURLs, albumIDs, imageIDs, this); if (drag) { drag->setPixmap(pix); drag->drag(); } } void AlbumIconView::contentsDragMoveEvent(TQDragMoveEvent *event) { if (!d->currentAlbum || (AlbumDrag::canDecode(event) || !TQUriDrag::canDecode(event) && !CameraDragObject::canDecode(event) && !TagListDrag::canDecode(event) && !TagDrag::canDecode(event) && !CameraItemListDrag::canDecode(event) && !ItemDrag::canDecode(event))) { event->ignore(); return; } event->accept(); } void AlbumIconView::contentsDropEvent(TQDropEvent *event) { if (!d->currentAlbum || (AlbumDrag::canDecode(event) || !TQUriDrag::canDecode(event) && !CameraDragObject::canDecode(event) && !TagListDrag::canDecode(event) && !TagDrag::canDecode(event) && !CameraItemListDrag::canDecode(event) && !ItemDrag::canDecode(event))) { event->ignore(); return; } Album *album = 0; // Check if we working on grouped items view. if (groupCount() > 1) { AlbumIconGroupItem *grp = dynamic_cast(findGroup(TQCursor::pos())); if (grp) { if(d->currentAlbum->type() == Album::PHYSICAL) album = dynamic_cast(AlbumManager::instance()->findPAlbum(grp->albumID())); else if(d->currentAlbum->type() == Album::TAG) album = dynamic_cast(AlbumManager::instance()->findTAlbum(grp->albumID())); } } if (!album) album = d->currentAlbum; KURL::List urls; KURL::List kioURLs; TQValueList albumIDs; TQValueList imageIDs; if (ItemDrag::decode(event, urls, kioURLs, albumIDs, imageIDs)) { // Drag & drop inside of digiKam // Check if items dropped come from outside current album. KURL::List extUrls; ImageInfoList extImgInfList; for (TQValueList::iterator it = imageIDs.begin(); it != imageIDs.end(); ++it) { ImageInfo *info = new ImageInfo(*it); if (info->albumID() != album->id()) { extUrls.append(info->kurlForKIO()); extImgInfList.append(info); } } if(extUrls.isEmpty()) { event->ignore(); return; } else if (album->type() == Album::PHYSICAL) { PAlbum* palbum = (PAlbum*)album; KURL destURL(palbum->kurl()); KURL::List srcURLs; KURLDrag::decode(event, srcURLs); TQPopupMenu popMenu(this); popMenu.insertItem( SmallIcon("goto"), i18n("&Move Here"), 10 ); popMenu.insertItem( SmallIcon("editcopy"), i18n("&Copy Here"), 11 ); popMenu.insertSeparator(-1); popMenu.insertItem( SmallIcon("cancel"), i18n("C&ancel") ); popMenu.setMouseTracking(true); int id = popMenu.exec(TQCursor::pos()); switch(id) { case 10: { KIO::Job* job = DIO::move(srcURLs, destURL); connect(job, TQT_SIGNAL(result(KIO::Job*)), this, TQT_SLOT(slotDIOResult(KIO::Job*))); break; } case 11: { KIO::Job* job = DIO::copy(srcURLs, destURL); connect(job, TQT_SIGNAL(result(KIO::Job*)), this, TQT_SLOT(slotDIOResult(KIO::Job*))); break; } default: break; } } } else if (TQUriDrag::canDecode(event) && album->type() == Album::PHYSICAL) { // Drag & drop outside of digiKam PAlbum* palbum = (PAlbum*)album; KURL destURL(palbum->kurl()); KURL::List srcURLs; KURLDrag::decode(event, srcURLs); TQPopupMenu popMenu(this); popMenu.insertItem( SmallIcon("goto"), i18n("&Move Here"), 10 ); popMenu.insertItem( SmallIcon("editcopy"), i18n("&Copy Here"), 11 ); popMenu.insertSeparator(-1); popMenu.insertItem( SmallIcon("cancel"), i18n("C&ancel") ); popMenu.setMouseTracking(true); int id = popMenu.exec(TQCursor::pos()); switch(id) { case 10: { KIO::Job* job = DIO::move(srcURLs, destURL); connect(job, TQT_SIGNAL(result(KIO::Job*)), this, TQT_SLOT(slotDIOResult(KIO::Job*))); break; } case 11: { KIO::Job* job = DIO::copy(srcURLs, destURL); connect(job, TQT_SIGNAL(result(KIO::Job*)), this, TQT_SLOT(slotDIOResult(KIO::Job*))); break; } default: break; } } else if(TagDrag::canDecode(event)) { TQByteArray ba = event->encodedData("digikam/tag-id"); TQDataStream ds(ba, IO_ReadOnly); int tagID; ds >> tagID; AlbumManager* man = AlbumManager::instance(); TAlbum* talbum = man->findTAlbum(tagID); if (talbum) { TQPopupMenu popMenu(this); bool moreItemsSelected = false; bool itemDropped = false; AlbumIconItem *albumItem = findItem(event->pos()); if (albumItem) itemDropped = true; for (IconItem *it = firstItem(); it; it = it->nextItem()) { if (it->isSelected() && it != albumItem) { moreItemsSelected = true; break; } } if (moreItemsSelected) popMenu.insertItem(SmallIcon("tag"), i18n("Assign '%1' to &Selected Items").arg(talbum->tagPath().mid(1)), 10); if (itemDropped) popMenu.insertItem(SmallIcon("tag"), i18n("Assign '%1' to &This Item").arg(talbum->tagPath().mid(1)), 12); popMenu.insertItem(SmallIcon("tag"), i18n("Assign '%1' to &All Items").arg(talbum->tagPath().mid(1)), 11); popMenu.insertSeparator(-1); popMenu.insertItem(SmallIcon("cancel"), i18n("&Cancel")); popMenu.setMouseTracking(true); int id = popMenu.exec(TQCursor::pos()); switch(id) { case 10: // Selected Items { emit signalProgressBarMode(StatusProgressBar::ProgressBarMode, i18n("Assigning image tags. Please wait...")); // always give a copy of the image infos (the "true"). Else there were crashes reported. changeTagOnImageInfos(selectedImageInfos(true), TQValueList() << tagID, true, true); emit signalProgressBarMode(StatusProgressBar::TextMode, TQString()); break; } case 11: // All Items { emit signalProgressBarMode(StatusProgressBar::ProgressBarMode, i18n("Assigning image tags. Please wait...")); changeTagOnImageInfos(allImageInfos(true), TQValueList() << tagID, true, true); emit signalProgressBarMode(StatusProgressBar::TextMode, TQString()); break; } case 12: // Dropped Item only. { AlbumIconItem *albumItem = findItem(event->pos()); if (albumItem) { TQPtrList infos; infos.append(albumItem->imageInfo()); changeTagOnImageInfos(infos, TQValueList() << tagID, true, false); } break; } default: break; } } } else if(TagListDrag::canDecode(event)) { TQByteArray ba = event->encodedData("digikam/taglist"); TQDataStream ds(ba, IO_ReadOnly); TQValueList tagIDs; ds >> tagIDs; TQPopupMenu popMenu(this); bool moreItemsSelected = false; bool itemDropped = false; AlbumIconItem *albumItem = findItem(event->pos()); if (albumItem) itemDropped = true; for (IconItem *it = firstItem(); it; it = it->nextItem()) { if (it->isSelected() && it != albumItem) { moreItemsSelected = true; break; } } if (moreItemsSelected) popMenu.insertItem(SmallIcon("tag"), i18n("Assign Tags to &Selected Items"), 10); if (itemDropped) popMenu.insertItem(SmallIcon("tag"), i18n("Assign Tags to &This Item"), 12); popMenu.insertItem(SmallIcon("tag"), i18n("Assign Tags to &All Items"), 11); popMenu.insertSeparator(-1); popMenu.insertItem(SmallIcon("cancel"), i18n("&Cancel")); popMenu.setMouseTracking(true); int id = popMenu.exec(TQCursor::pos()); switch(id) { case 10: // Selected Items { emit signalProgressBarMode(StatusProgressBar::ProgressBarMode, i18n("Assigning image tags. Please wait...")); changeTagOnImageInfos(selectedImageInfos(true), tagIDs, true, true); emit signalProgressBarMode(StatusProgressBar::TextMode, TQString()); break; } case 11: // All Items { emit signalProgressBarMode(StatusProgressBar::ProgressBarMode, i18n("Assigning image tags. Please wait...")); changeTagOnImageInfos(allImageInfos(true), tagIDs, true, true); emit signalProgressBarMode(StatusProgressBar::TextMode, TQString()); break; } case 12: // Dropped item only. { AlbumIconItem *albumItem = findItem(event->pos()); if (albumItem) { TQPtrList infos; infos.append(albumItem->imageInfo()); changeTagOnImageInfos(infos, tagIDs, true, false); } break; } default: break; } } else if(CameraItemListDrag::canDecode(event)) { CameraUI *ui = dynamic_cast(event->source()); if (ui) { TQPopupMenu popMenu(this); popMenu.insertItem(SmallIcon("down"), i18n("Download from camera"), 10); popMenu.insertItem(SmallIcon("down"), i18n("Download && Delete from camera"), 11); popMenu.insertSeparator(-1); popMenu.insertItem(SmallIcon("cancel"), i18n("&Cancel")); popMenu.setMouseTracking(true); int id = popMenu.exec(TQCursor::pos()); switch(id) { case 10: // Download from camera { ui->slotDownload(true, false, album); break; } case 11: // Download and Delete from camera { ui->slotDownload(true, true, album); break; } default: break; } } } else { event->ignore(); } } void AlbumIconView::changeTagOnImageInfos(const TQPtrList &list, const TQValueList &tagIDs, bool addOrRemove, bool progress) { float cnt = list.count(); int i = 0; d->imageLister->blockSignals(true); AlbumManager::instance()->albumDB()->beginTransaction(); for (TQPtrList::const_iterator it = list.begin(); it != list.end(); ++it) { MetadataHub hub; hub.load(*it); for (TQValueList::const_iterator tagIt = tagIDs.begin(); tagIt != tagIDs.end(); ++tagIt) { hub.setTag(*tagIt, addOrRemove); } hub.write(*it, MetadataHub::PartialWrite); hub.write((*it)->filePath(), MetadataHub::FullWriteIfChanged); if (progress) { emit signalProgressValue((int)((i++/cnt)*100.0)); kapp->processEvents(); } } d->imageLister->blockSignals(false); AlbumManager::instance()->albumDB()->commitTransaction(); if (d->currentAlbum && d->currentAlbum->type() == Album::TAG) { d->imageLister->refresh(); } updateContents(); } bool AlbumIconView::acceptToolTip(IconItem *item, const TQPoint &mousePos) { AlbumIconItem *iconItem = dynamic_cast(item); if (iconItem && iconItem->clickToOpenRect().contains(mousePos)) { return true; } else { return false; } } void AlbumIconView::slotShowToolTip(IconItem* item) { d->toolTip->setIconItem(dynamic_cast(item)); } KURL::List AlbumIconView::allItems() { KURL::List itemList; for (IconItem *it = firstItem(); it; it = it->nextItem()) { AlbumIconItem *item = (AlbumIconItem*) it; itemList.append(item->imageInfo()->kurl()); } return itemList; } KURL::List AlbumIconView::selectedItems() { KURL::List itemList; for (IconItem *it = firstItem(); it; it = it->nextItem()) { if (it->isSelected()) { AlbumIconItem *item = (AlbumIconItem*) it; itemList.append(item->imageInfo()->kurl()); } } return itemList; } TQPtrList AlbumIconView::allImageInfos(bool copy) const { // Returns the list of ImageInfos of all items, // with the extra feature that the currentItem is the first in the list. TQPtrList list; for (IconItem *it = firstItem(); it; it = it->nextItem()) { AlbumIconItem *iconItem = static_cast(it); ImageInfo *info = iconItem->imageInfo(); if (copy) info = new ImageInfo(*info); if (iconItem == currentItem()) list.prepend(info); else list.append(info); } return list; } TQPtrList AlbumIconView::selectedImageInfos(bool copy) const { // Returns the list of ImageInfos of currently selected items, // with the extra feature that the currentItem is the first in the list. TQPtrList list; for (IconItem *it = firstItem(); it; it = it->nextItem()) { AlbumIconItem *iconItem = static_cast(it); if (it->isSelected()) { ImageInfo *info = iconItem->imageInfo(); if (copy) info = new ImageInfo(*info); if (iconItem == currentItem()) list.prepend(info); else list.append(info); } } return list; } void AlbumIconView::refresh() { d->imageLister->stop(); clear(); d->imageLister->openAlbum(d->currentAlbum); } void AlbumIconView::refreshItems(const KURL::List& urlList) { if (!d->currentAlbum || urlList.empty()) return; // we do two things here: // 1. refresh the imageinfo for the file // 2. refresh the thumbnails for (KURL::List::const_iterator it = urlList.begin(); it != urlList.end(); ++it) { AlbumIconItem* iconItem = findItem((*it).url()); if (!iconItem) continue; iconItem->imageInfo()->refresh(); d->pixMan->remove(iconItem->imageInfo()->kurl()); // clean LoadingCache as well - be pragmatic, do it here. LoadingCacheInterface::cleanFromCache((*it).path()); } emit signalItemsUpdated(urlList); // trigger a delayed rearrangement, in case we need to resort items triggerRearrangement(); } void AlbumIconView::slotGotThumbnail(const KURL& url) { AlbumIconItem* iconItem = findItem(url.url()); if (!iconItem) return; iconItem->repaint(); } void AlbumIconView::slotSelectionChanged() { if (firstSelectedItem()) emitItemsSelected(true); else emitItemsSelected(false); } void AlbumIconView::slotSetExifOrientation( int orientation ) { KURL::List urlList; int i = 0; for (IconItem *it = firstItem(); it; it=it->nextItem()) { if (it->isSelected()) { AlbumIconItem *iconItem = static_cast(it); urlList.append(iconItem->imageInfo()->kurl()); } } if (urlList.count() <= 0) return; TQStringList faildItems; KURL::List::Iterator it; float cnt = (float)urlList.count(); emit signalProgressBarMode(StatusProgressBar::ProgressBarMode, i18n("Revising Exif Qt::Orientation tags. Please wait...")); for( it = urlList.begin(); it != urlList.end(); ++it ) { DDebug() << "Setting Exif Qt::Orientation tag to " << orientation << endl; DMetadata metadata((*it).path()); DMetadata::ImageOrientation o = (DMetadata::ImageOrientation)orientation; metadata.setImageOrientation(o); if (!metadata.applyChanges()) { faildItems.append((*it).filename()); } else { ImageAttributesWatch::instance()->fileMetadataChanged((*it)); } emit signalProgressValue((int)((i++/cnt)*100.0)); kapp->processEvents(); } emit signalProgressBarMode(StatusProgressBar::TextMode, TQString()); if (!faildItems.isEmpty()) { if (faildItems.count() == 1) { KMessageBox::error(0, i18n("Failed to revise Exif orientation for file %1.") .arg(faildItems[0])); } else { KMessageBox::errorList(0, i18n("Failed to revise Exif orientation these files:"), faildItems); } } refreshItems(urlList); } TQRect AlbumIconView::itemRect() const { return d->itemRect; } TQRect AlbumIconView::itemRatingRect() const { return d->itemRatingRect; } TQRect AlbumIconView::itemDateRect() const { return d->itemDateRect; } TQRect AlbumIconView::itemModDateRect() const { return d->itemModDateRect; } TQRect AlbumIconView::itemPixmapRect() const { return d->itemPixmapRect; } TQRect AlbumIconView::itemNameRect() const { return d->itemNameRect; } TQRect AlbumIconView::itemCommentsRect() const { return d->itemCommentsRect; } TQRect AlbumIconView::itemResolutionRect() const { return d->itemResolutionRect; } TQRect AlbumIconView::itemTagRect() const { return d->itemTagRect; } TQRect AlbumIconView::itemSizeRect() const { return d->itemSizeRect; } TQRect AlbumIconView::bannerRect() const { return d->bannerRect; } TQPixmap* AlbumIconView::itemBaseRegPixmap() const { return &d->itemRegPixmap; } TQPixmap* AlbumIconView::itemBaseSelPixmap() const { return &d->itemSelPixmap; } TQPixmap AlbumIconView::bannerPixmap() const { return d->bannerPixmap; } TQPixmap AlbumIconView::ratingPixmap() const { return d->ratingPixmap; } TQFont AlbumIconView::itemFontReg() const { return d->fnReg; } TQFont AlbumIconView::itemFontCom() const { return d->fnCom; } TQFont AlbumIconView::itemFontXtra() const { return d->fnXtra; } void AlbumIconView::updateBannerRectPixmap() { d->bannerRect = TQRect(0, 0, 0, 0); // Title -------------------------------------------------------- TQFont fn(font()); int fnSize = fn.pointSize(); bool usePointSize; if (fnSize > 0) { fn.setPointSize(fnSize+2); usePointSize = true; } else { fnSize = fn.pixelSize(); fn.setPixelSize(fnSize+2); usePointSize = false; } fn.setBold(true); TQFontMetrics fm(fn); TQRect tr = fm.boundingRect(0, 0, frameRect().width(), 0xFFFFFFFF, TQt::AlignLeft | TQt::AlignVCenter, "XXX"); d->bannerRect.setHeight(tr.height()); if (usePointSize) fn.setPointSize(font().pointSize()); else fn.setPixelSize(font().pixelSize()); fn.setBold(false); fm = TQFontMetrics(fn); tr = fm.boundingRect(0, 0, frameRect().width(), 0xFFFFFFFF, TQt::AlignLeft | TQt::AlignVCenter, "XXX"); d->bannerRect.setHeight(d->bannerRect.height() + tr.height() + 10); d->bannerRect.setWidth(frameRect().width()); d->bannerPixmap = ThemeEngine::instance()->bannerPixmap(d->bannerRect.width(), d->bannerRect.height()); } void AlbumIconView::updateItemRectsPixmap() { d->itemRect = TQRect(0,0,0,0); d->itemRatingRect = TQRect(0,0,0,0); d->itemDateRect = TQRect(0,0,0,0); d->itemModDateRect = TQRect(0,0,0,0); d->itemPixmapRect = TQRect(0,0,0,0); d->itemNameRect = TQRect(0,0,0,0); d->itemCommentsRect = TQRect(0,0,0,0); d->itemResolutionRect = TQRect(0,0,0,0); d->itemSizeRect = TQRect(0,0,0,0); d->itemTagRect = TQRect(0,0,0,0); d->fnReg = font(); d->fnCom = font(); d->fnXtra = font(); d->fnCom.setItalic(true); int fnSz = d->fnReg.pointSize(); if (fnSz > 0) { d->fnCom.setPointSize(fnSz-1); d->fnXtra.setPointSize(fnSz-2); } else { fnSz = d->fnReg.pixelSize(); d->fnCom.setPixelSize(fnSz-1); d->fnXtra.setPixelSize(fnSz-2); } int margin = 5; int w = d->thumbSize.size() + 2*margin; TQFontMetrics fm(d->fnReg); TQRect oneRowRegRect = fm.boundingRect(0, 0, w, 0xFFFFFFFF, TQt::AlignTop | TQt::AlignHCenter, "XXXXXXXXX"); fm = TQFontMetrics(d->fnCom); TQRect oneRowComRect = fm.boundingRect(0, 0, w, 0xFFFFFFFF, TQt::AlignTop | TQt::AlignHCenter, "XXXXXXXXX"); fm = TQFontMetrics(d->fnXtra); TQRect oneRowXtraRect = fm.boundingRect(0, 0, w, 0xFFFFFFFF, TQt::AlignTop | TQt::AlignHCenter, "XXXXXXXXX"); int y = margin; d->itemPixmapRect = TQRect(margin, y, w, d->thumbSize.size()+margin); y = d->itemPixmapRect.bottom(); if (d->albumSettings->getIconShowRating()) { d->itemRatingRect = TQRect(margin, y, w, d->ratingPixmap.height()); y = d->itemRatingRect.bottom(); } if (d->albumSettings->getIconShowName()) { d->itemNameRect = TQRect(margin, y, w, oneRowRegRect.height()); y = d->itemNameRect.bottom(); } if (d->albumSettings->getIconShowComments()) { d->itemCommentsRect = TQRect(margin, y, w, oneRowComRect.height()); y = d->itemCommentsRect.bottom(); } if (d->albumSettings->getIconShowDate()) { d->itemDateRect = TQRect(margin, y, w, oneRowXtraRect.height()); y = d->itemDateRect.bottom(); } if (d->albumSettings->getIconShowModDate()) { d->itemModDateRect = TQRect(margin, y, w, oneRowXtraRect.height()); y = d->itemModDateRect.bottom(); } if (d->albumSettings->getIconShowResolution()) { d->itemResolutionRect = TQRect(margin, y, w, oneRowXtraRect.height()); y = d->itemResolutionRect.bottom() ; } if (d->albumSettings->getIconShowSize()) { d->itemSizeRect = TQRect(margin, y, w, oneRowXtraRect.height()); y = d->itemSizeRect.bottom(); } if (d->albumSettings->getIconShowTags()) { d->itemTagRect = TQRect(margin, y, w, oneRowComRect.height()); y = d->itemTagRect.bottom(); } d->itemRect = TQRect(0, 0, w+2*margin, y+margin); d->itemRegPixmap = ThemeEngine::instance()->thumbRegPixmap(d->itemRect.width(), d->itemRect.height()); d->itemSelPixmap = ThemeEngine::instance()->thumbSelPixmap(d->itemRect.width(), d->itemRect.height()); } void AlbumIconView::slotThemeChanged() { TQPainter painter(&d->ratingPixmap); painter.fillRect(0, 0, d->ratingPixmap.width(), d->ratingPixmap.height(), ThemeEngine::instance()->textSpecialRegColor()); painter.end(); updateBannerRectPixmap(); updateItemRectsPixmap(); viewport()->update(); } AlbumIconItem* AlbumIconView::findItem(const TQPoint& pos) { return dynamic_cast(IconView::findItem(pos)); } AlbumIconItem* AlbumIconView::findItem(const TQString& url) const { return d->itemDict.find(url); } AlbumIconItem* AlbumIconView::nextItemToThumbnail() const { TQRect r(contentsX(), contentsY(), visibleWidth(), visibleHeight()); IconItem *fItem = findFirstVisibleItem(r); IconItem *lItem = findLastVisibleItem(r); if (!fItem || !lItem) return 0; AlbumIconItem* firstItem = static_cast(fItem); AlbumIconItem* lastItem = static_cast(lItem); AlbumIconItem* item = firstItem; while (item) { if (item->isDirty()) return item; if (item == lastItem) break; item = (AlbumIconItem*)item->nextItem(); } return 0; } PixmapManager* AlbumIconView::pixmapManager() const { return d->pixMan; } void AlbumIconView::slotAlbumModified() { d->imageLister->stop(); clear(); d->imageLister->openAlbum(d->currentAlbum); updateBannerRectPixmap(); updateItemRectsPixmap(); } void AlbumIconView::slotGotoTag(int tagID) { // send a signal to the parent widget (digikamview.cpp) to change // to Tag view and the corresponding item emit signalGotoTagAndItem(tagID); } void AlbumIconView::slotAssignTag(int tagID) { emit signalProgressBarMode(StatusProgressBar::ProgressBarMode, i18n("Assigning image tags. Please wait...")); changeTagOnImageInfos(selectedImageInfos(true), TQValueList() << tagID, true, true); emit signalProgressBarMode(StatusProgressBar::TextMode, TQString()); } void AlbumIconView::slotRemoveTag(int tagID) { emit signalProgressBarMode(StatusProgressBar::ProgressBarMode, i18n("Removing image tags. Please wait...")); changeTagOnImageInfos(selectedImageInfos(true), TQValueList() << tagID, false, true); emit signalProgressBarMode(StatusProgressBar::TextMode, TQString()); } void AlbumIconView::slotAssignRating(int rating) { emit signalProgressBarMode(StatusProgressBar::ProgressBarMode, i18n("Assigning image ratings. Please wait...")); int i = 0; float cnt = (float)countSelected(); rating = TQMIN(RatingMax, TQMAX(RatingMin, rating)); MetadataHub hub; d->imageLister->blockSignals(true); AlbumManager::instance()->albumDB()->beginTransaction(); for (IconItem *it = firstItem() ; it ; it = it->nextItem()) { if (it->isSelected()) { AlbumIconItem *albumItem = dynamic_cast(it); if (albumItem) { ImageInfo* info = albumItem->imageInfo(); hub.load(info); hub.setRating(rating); hub.write(info, MetadataHub::PartialWrite); hub.write(info->filePath(), MetadataHub::FullWriteIfChanged); emit signalProgressValue((int)((i++/cnt)*100.0)); kapp->processEvents(); } } } d->imageLister->blockSignals(false); AlbumManager::instance()->albumDB()->commitTransaction(); emit signalProgressBarMode(StatusProgressBar::TextMode, TQString()); updateContents(); } void AlbumIconView::slotAssignRatingNoStar() { slotAssignRating(0); } void AlbumIconView::slotAssignRatingOneStar() { slotAssignRating(1); } void AlbumIconView::slotAssignRatingTwoStar() { slotAssignRating(2); } void AlbumIconView::slotAssignRatingThreeStar() { slotAssignRating(3); } void AlbumIconView::slotAssignRatingFourStar() { slotAssignRating(4); } void AlbumIconView::slotAssignRatingFiveStar() { slotAssignRating(5); } void AlbumIconView::slotDIOResult(KIO::Job* job) { if (job->error()) job->showErrorDialog(this); } void AlbumIconView::slotImageAttributesChanged(TQ_LLONG imageId) { AlbumIconItem *firstItem = static_cast(findFirstVisibleItem()); AlbumIconItem *lastItem = static_cast(findLastVisibleItem()); for (AlbumIconItem *item = firstItem; item; item = static_cast(item->nextItem())) { if (item->imageInfo()->id() == imageId) { updateContents(); return; } if (item == lastItem) break; } } void AlbumIconView::slotAlbumImagesChanged(int /*albumId*/) { updateContents(); } } // namespace Digikam