You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
digikam/digikam/digikam/albumiconview.cpp

2342 lines
67 KiB

/* ============================================================
*
* 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 <renchi@pooh.tam.uiuc.edu>
* Copyright (C) 2002-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
* Copyright (C) 2006-2008 by Marcel Wiesweg <marcel.wiesweg@gmx.de>
*
* 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 <config.h>
#endif
// C Ansi includes.
extern "C"
{
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
}
// C++ includes.
#include <cstdio>
// TQt includes.
#include <tqpixmap.h>
#include <tqimage.h>
#include <tqstring.h>
#include <tqstringlist.h>
#include <tqevent.h>
#include <tqpainter.h>
#include <tqpoint.h>
#include <tqpopupmenu.h>
#include <tqdatetime.h>
#include <tqfileinfo.h>
#include <tqfile.h>
#include <tqdragobject.h>
#include <tqcursor.h>
#include <tqvaluevector.h>
#include <tqptrlist.h>
#include <tqintdict.h>
#include <tqdict.h>
#include <tqdatastream.h>
#include <tqtimer.h>
#include <tqclipboard.h>
// KDE includes.
#include <tdeapplication.h>
#include <kurl.h>
#include <kurldrag.h>
#include <tdelocale.h>
#include <tdeglobal.h>
#include <tdemessagebox.h>
#include <kiconloader.h>
#include <kpropsdlg.h>
#include <ktrader.h>
#include <kservice.h>
#include <krun.h>
#include <tdeaction.h>
#include <kstandarddirs.h>
#include <kiconeffect.h>
#include <kdebug.h>
#include <tdeversion.h>
#if KDE_IS_VERSION(3,2,0)
#include <kcalendarsystem.h>
#include <kinputdialog.h>
#else
#include <klineeditdlg.h>
#endif
// LibKipi includes.
#include <libkipi/pluginloader.h>
#include <libkipi/plugin.h>
// LibKDcraw includes.
#include <libkdcraw/version.h>
#include <libkdcraw/kdcraw.h>
#if KDCRAW_VERSION < 0x000106
#include <libkdcraw/dcrawbinary.h>
#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<AlbumIconItem> itemDict;
KURL itemUrlToFind;
AlbumLister *imageLister;
Album *currentAlbum;
const AlbumSettings *albumSettings;
TQIntDict<AlbumIconGroupItem> 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 ------------------------------------------
TDEGlobal::dirs()->addResourceType("digikam_rating", TDEGlobal::dirs()->kde_default("data")
+ "digikam/data");
TQString ratingPixPath = TDEGlobal::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, TQ_SIGNAL(signalNewFilteredItems(const ImageInfoList&)),
this, TQ_SLOT(slotImageListerNewItems(const ImageInfoList&)));
connect(d->imageLister, TQ_SIGNAL(signalDeleteFilteredItem(ImageInfo*)),
this, TQ_SLOT(slotImageListerDeleteItem(ImageInfo*)) );
connect(d->imageLister, TQ_SIGNAL(signalClear()),
this, TQ_SLOT(slotImageListerClear()));
// -- Icon connections --------------------------------------------
connect(this, TQ_SIGNAL(signalDoubleClicked(IconItem*)),
this, TQ_SLOT(slotDoubleClicked(IconItem*)));
connect(this, TQ_SIGNAL(signalReturnPressed(IconItem*)),
this, TQ_SLOT(slotDoubleClicked(IconItem*)));
connect(this, TQ_SIGNAL(signalRightButtonClicked(IconItem*, const TQPoint &)),
this, TQ_SLOT(slotRightButtonClicked(IconItem*, const TQPoint &)));
connect(this, TQ_SIGNAL(signalRightButtonClicked(const TQPoint &)),
this, TQ_SLOT(slotRightButtonClicked(const TQPoint &)));
connect(this, TQ_SIGNAL(signalSelectionChanged()),
this, TQ_SLOT(slotSelectionChanged()));
connect(this, TQ_SIGNAL(signalShowToolTip(IconItem*)),
this, TQ_SLOT(slotShowToolTip(IconItem*)));
// -- ThemeEngine connections ---------------------------------------
connect(ThemeEngine::instance(), TQ_SIGNAL(signalThemeChanged()),
TQ_SLOT(slotThemeChanged()));
// -- Pixmap manager connections ------------------------------------
connect(d->pixMan, TQ_SIGNAL(signalPixmap(const KURL&)),
TQ_SLOT(slotGotThumbnail(const KURL&)));
// -- ImageAttributesWatch connections ------------------------------
ImageAttributesWatch *watch = ImageAttributesWatch::instance();
connect(watch, TQ_SIGNAL(signalImageTagsChanged(TQ_LLONG)),
this, TQ_SLOT(slotImageAttributesChanged(TQ_LLONG)));
connect(watch, TQ_SIGNAL(signalImagesChanged(int)),
this, TQ_SLOT(slotAlbumImagesChanged(int)));
connect(watch, TQ_SIGNAL(signalImageRatingChanged(TQ_LLONG)),
this, TQ_SLOT(slotImageAttributesChanged(TQ_LLONG)));
connect(watch, TQ_SIGNAL(signalImageDateChanged(TQ_LLONG)),
this, TQ_SLOT(slotImageAttributesChanged(TQ_LLONG)));
connect(watch, TQ_SIGNAL(signalImageCaptionChanged(TQ_LLONG)),
this, TQ_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<AlbumIconItem*>(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
//TDEIconEffect::visualActivate(viewport(), contentsRectToViewport(item->rect()));
signalPreviewItem(static_cast<AlbumIconItem *>(item));
}
else
{
TDEIconEffect::visualActivate(viewport(), contentsRectToViewport(item->rect()));
slotDisplayItem(static_cast<AlbumIconItem *>(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);
TDEAction *paste = KStdAction::paste(this, TQ_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<AlbumIconItem *>(item);
// --------------------------------------------------------
KMimeType::Ptr mimePtr = KMimeType::findByURL(iconItem->imageInfo()->kurl(), 0, true, true);
TQValueVector<KService::Ptr> serviceVector;
TDETrader::OfferList offers = TDETrader::self()->query(mimePtr->name(), "Type == 'Application'");
TQPopupMenu openWithMenu;
TDETrader::OfferList::Iterator iter;
KService::Ptr ptr;
int index = 100;
for( iter = offers.begin(); iter != offers.end(); ++iter )
{
ptr = *iter;
openWithMenu.insertItem( ptr->pixmap(TDEIcon::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<TQ_LLONG> selectedImageIDs;
for (IconItem *it = firstItem(); it; it=it->nextItem())
{
if (it->isSelected())
{
AlbumIconItem *selItem = static_cast<AlbumIconItem *>(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, TQ_SIGNAL(signalTagActivated(int)),
this, TQ_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;
TDEActionPtrList actionList = plugin->actions();
for (TDEActionPtrList::const_iterator iter = actionList.begin();
iter != actionList.end(); ++iter)
{
TDEAction* 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();
}
}
// --------------------------------------------------------
TDEAction *copy = KStdAction::copy(this, TQ_SLOT(slotCopy()), 0);
TDEAction *paste = KStdAction::paste(this, TQ_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, TQ_SIGNAL(signalTagActivated(int)),
this, TQ_SLOT(slotAssignTag(int)));
connect(removeTagsPopup, TQ_SIGNAL(signalTagActivated(int)),
this, TQ_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, TQ_SIGNAL(activated(int)),
this, TQ_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<AlbumIconItem *>(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<int> albumIDs;
TQValueList<int> imageIDs;
for (IconItem *it = firstItem(); it; it=it->nextItem())
{
if (it->isSelected())
{
AlbumIconItem *albumItem = static_cast<AlbumIconItem *>(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<AlbumIconGroupItem*>(findGroup(TQCursor::pos()));
if (grp)
{
if(d->currentAlbum->type() == Album::PHYSICAL)
album = dynamic_cast<Album*>(AlbumManager::instance()->findPAlbum(grp->albumID()));
else if(d->currentAlbum->type() == Album::TAG)
album = dynamic_cast<Album*>(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);
TDEIO::Job* job = DIO::copy(srcURLs, destURL);
connect(job, TQ_SIGNAL(result(TDEIO::Job*)),
this, TQ_SLOT(slotDIOResult(TDEIO::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<int> albumIDs;
TQValueList<int> imageIDs;
if (!ItemDrag::decode(data, urls, kioURLs, albumIDs, imageIDs))
return;
if (urls.isEmpty() || kioURLs.isEmpty() || albumIDs.isEmpty() || imageIDs.isEmpty())
return;
TQPtrList<ImageInfo> list;
for (TQValueList<int>::const_iterator it = imageIDs.begin();
it != imageIDs.end(); ++it)
{
ImageInfo *info = new ImageInfo(*it);
list.append(info);
}
changeTagOnImageInfos(list, TQValueList<int>() << talbum->id(), true, true);
}
}
void AlbumIconView::slotSetAlbumThumbnail(AlbumIconItem *iconItem)
{
if(!d->currentAlbum)
return;
if(d->currentAlbum->type() == Album::PHYSICAL)
{
PAlbum *album = static_cast<PAlbum*>(d->currentAlbum);
TQString err;
AlbumManager::instance()->updatePAlbumIcon( album,
iconItem->imageInfo()->id(),
err );
}
else if (d->currentAlbum->type() == Album::TAG)
{
TAlbum *album = static_cast<TAlbum*>(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);
TDEIO::CopyJob* job = DIO::rename(oldURL, newURL);
connect(job, TQ_SIGNAL(result(TDEIO::Job*)),
this, TQ_SLOT(slotDIOResult(TDEIO::Job*)));
connect(job, TQ_SIGNAL(copyingDone(TDEIO::Job *, const KURL &, const KURL &, bool, bool)),
this, TQ_SLOT(slotRenamed(TDEIO::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(TDEIO::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<AlbumIconItem *>(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
TDEIO::Job* job = DIO::del(useTrash ? urlList : kioUrlList, useTrash);
connect(job, TQ_SIGNAL(result(TDEIO::Job*)),
this, TQ_SLOT(slotDIOResult(TDEIO::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<AlbumIconItem *>(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
TDEIO::Job* job = DIO::del(useTrash ? urlList : kioUrlList , useTrash);
connect(job, TQ_SIGNAL(result(TDEIO::Job*)),
this, TQ_SLOT(slotDIOResult(TDEIO::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);
TDETrader::OfferList offers = TDETrader::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<AlbumIconItem *>(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, TQ_SIGNAL(signalFileAdded(const KURL&)),
this, TQ_SLOT(slotFilesModified()));
connect(imview, TQ_SIGNAL(signalFileModified(const KURL&)),
this, TQ_SLOT(slotFilesModified(const KURL&)));
connect(imview, TQ_SIGNAL(signalFileDeleted(const KURL&)),
this, TQ_SLOT(slotFilesModified()));
connect(imview, TQ_SIGNAL(signalURLChanged(const KURL&)),
this, TQ_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<AlbumIconItem *>(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, TQ_SIGNAL(signalFileDeleted(const KURL&)),
this, TQ_SLOT(slotFilesModified()));
connect(this, TQ_SIGNAL(signalItemsUpdated(const KURL::List&)),
ltview, TQ_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<AlbumIconItem *>(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<int> albumIDs;
TQValueList<int> imageIDs;
for (IconItem *it = firstItem(); it; it=it->nextItem())
{
if (it->isSelected())
{
AlbumIconItem *albumItem = static_cast<AlbumIconItem *>(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-x-generic", 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<AlbumIconGroupItem*>(findGroup(TQCursor::pos()));
if (grp)
{
if(d->currentAlbum->type() == Album::PHYSICAL)
album = dynamic_cast<Album*>(AlbumManager::instance()->findPAlbum(grp->albumID()));
else if(d->currentAlbum->type() == Album::TAG)
album = dynamic_cast<Album*>(AlbumManager::instance()->findTAlbum(grp->albumID()));
}
}
if (!album)
album = d->currentAlbum;
KURL::List urls;
KURL::List kioURLs;
TQValueList<int> albumIDs;
TQValueList<int> 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<int>::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("edit-copy"), 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:
{
TDEIO::Job* job = DIO::move(srcURLs, destURL);
connect(job, TQ_SIGNAL(result(TDEIO::Job*)),
this, TQ_SLOT(slotDIOResult(TDEIO::Job*)));
break;
}
case 11:
{
TDEIO::Job* job = DIO::copy(srcURLs, destURL);
connect(job, TQ_SIGNAL(result(TDEIO::Job*)),
this, TQ_SLOT(slotDIOResult(TDEIO::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("edit-copy"), 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:
{
TDEIO::Job* job = DIO::move(srcURLs, destURL);
connect(job, TQ_SIGNAL(result(TDEIO::Job*)),
this, TQ_SLOT(slotDIOResult(TDEIO::Job*)));
break;
}
case 11:
{
TDEIO::Job* job = DIO::copy(srcURLs, destURL);
connect(job, TQ_SIGNAL(result(TDEIO::Job*)),
this, TQ_SLOT(slotDIOResult(TDEIO::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<int>() << 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<int>() << tagID, true, true);
emit signalProgressBarMode(StatusProgressBar::TextMode, TQString());
break;
}
case 12: // Dropped Item only.
{
AlbumIconItem *albumItem = findItem(event->pos());
if (albumItem)
{
TQPtrList<ImageInfo> infos;
infos.append(albumItem->imageInfo());
changeTagOnImageInfos(infos, TQValueList<int>() << tagID, true, false);
}
break;
}
default:
break;
}
}
}
else if(TagListDrag::canDecode(event))
{
TQByteArray ba = event->encodedData("digikam/taglist");
TQDataStream ds(ba, IO_ReadOnly);
TQValueList<int> 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<ImageInfo> infos;
infos.append(albumItem->imageInfo());
changeTagOnImageInfos(infos, tagIDs, true, false);
}
break;
}
default:
break;
}
}
else if(CameraItemListDrag::canDecode(event))
{
CameraUI *ui = dynamic_cast<CameraUI*>(event->source());
if (ui)
{
TQPopupMenu popMenu(this);
popMenu.insertItem(SmallIcon("go-down"), i18n("Download from camera"), 10);
popMenu.insertItem(SmallIcon("go-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<ImageInfo> &list, const TQValueList<int> &tagIDs, bool addOrRemove, bool progress)
{
float cnt = list.count();
int i = 0;
d->imageLister->blockSignals(true);
AlbumManager::instance()->albumDB()->beginTransaction();
for (TQPtrList<ImageInfo>::const_iterator it = list.begin(); it != list.end(); ++it)
{
MetadataHub hub;
hub.load(*it);
for (TQValueList<int>::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<AlbumIconItem*>(item);
if (iconItem && iconItem->clickToOpenRect().contains(mousePos))
{
return true;
}
else
{
return false;
}
}
void AlbumIconView::slotShowToolTip(IconItem* item)
{
d->toolTip->setIconItem(dynamic_cast<AlbumIconItem*>(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<ImageInfo> 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<ImageInfo> list;
for (IconItem *it = firstItem(); it; it = it->nextItem())
{
AlbumIconItem *iconItem = static_cast<AlbumIconItem *>(it);
ImageInfo *info = iconItem->imageInfo();
if (copy)
info = new ImageInfo(*info);
if (iconItem == currentItem())
list.prepend(info);
else
list.append(info);
}
return list;
}
TQPtrList<ImageInfo> 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<ImageInfo> list;
for (IconItem *it = firstItem(); it; it = it->nextItem())
{
AlbumIconItem *iconItem = static_cast<AlbumIconItem *>(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<AlbumIconItem *>(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 Orientation tags. Please wait..."));
for( it = urlList.begin(); it != urlList.end(); ++it )
{
DDebug() << "Setting Exif 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<AlbumIconItem*>(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<AlbumIconItem*>(fItem);
AlbumIconItem* lastItem = static_cast<AlbumIconItem*>(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<int>() << 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<int>() << 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<AlbumIconItem*>(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(TDEIO::Job* job)
{
if (job->error())
job->showErrorDialog(this);
}
void AlbumIconView::slotImageAttributesChanged(TQ_LLONG imageId)
{
AlbumIconItem *firstItem = static_cast<AlbumIconItem *>(findFirstVisibleItem());
AlbumIconItem *lastItem = static_cast<AlbumIconItem *>(findLastVisibleItem());
for (AlbumIconItem *item = firstItem; item;
item = static_cast<AlbumIconItem *>(item->nextItem()))
{
if (item->imageInfo()->id() == imageId)
{
updateContents();
return;
}
if (item == lastItem)
break;
}
}
void AlbumIconView::slotAlbumImagesChanged(int /*albumId*/)
{
updateContents();
}
} // namespace Digikam