• Skip to content
  • Skip to link menu
KDE 4.4 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

digikam

albumiconview.cpp

Go to the documentation of this file.
00001 /* ============================================================
00002  *
00003  * This file is a part of digiKam project
00004  * http://www.digikam.org
00005  *
00006  * Date        : 2002-16-10
00007  * Description : album icon view
00008  *
00009  * Copyright (C) 2002-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
00010  * Copyright (C) 2002-2009 by Gilles Caulier <caulier dot gilles at gmail dot com>
00011  * Copyright (C) 2006-2009 by Marcel Wiesweg <marcel.wiesweg@gmx.de>
00012  * Copyright (C) 2009 by Andi Clemens <andi dot clemens at gmx dot net>
00013  *
00014  * This program is free software; you can redistribute it
00015  * and/or modify it under the terms of the GNU General
00016  * Public License as published by the Free Software Foundation;
00017  * either version 2, or (at your option)
00018  * any later version.
00019  *
00020  * This program is distributed in the hope that it will be useful,
00021  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00022  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023  * GNU General Public License for more details.
00024  *
00025  * ============================================================ */
00026 
00027 #include "albumiconview.moc"
00028 
00029 // C ANSI includes
00030 
00031 extern "C"
00032 {
00033 #include <sys/types.h>
00034 #include <sys/stat.h>
00035 #include <unistd.h>
00036 }
00037 
00038 // C++ includes
00039 
00040 #include <cstdio>
00041 #include <cmath>
00042 
00043 // Qt includes
00044 
00045 #include <QClipboard>
00046 #include <QCursor>
00047 #include <QDataStream>
00048 #include <QDateTime>
00049 #include <QDragMoveEvent>
00050 #include <QDropEvent>
00051 #include <QEvent>
00052 #include <QFile>
00053 #include <QFileInfo>
00054 #include <QImage>
00055 #include <QPainter>
00056 #include <QPixmap>
00057 #include <QPoint>
00058 #include <QPolygon>
00059 #include <QResizeEvent>
00060 #include <QString>
00061 #include <QStringList>
00062 #include <QTimer>
00063 #include <QMap>
00064 
00065 // KDE includes
00066 
00067 #include <kaction.h>
00068 #include <kactioncollection.h>
00069 #include <kapplication.h>
00070 #include <kcalendarsystem.h>
00071 #include <kdeversion.h>
00072 #include <kglobal.h>
00073 #include <kiconeffect.h>
00074 #include <kiconloader.h>
00075 #include <kinputdialog.h>
00076 #include <kio/jobuidelegate.h>
00077 #include <klocale.h>
00078 #include <kmenu.h>
00079 #include <kmessagebox.h>
00080 #include <kmimetypetrader.h>
00081 #include <kpropsdlg.h>
00082 #include <krun.h>
00083 #include <kstandardaction.h>
00084 #include <kstandarddirs.h>
00085 #include <ktrader.h>
00086 #include <kurl.h>
00087 #include <kwindowsystem.h>
00088 #include <kdebug.h>
00089 
00090 // LibKDcraw includes
00091 
00092 #include <libkdcraw/kdcraw.h>
00093 #include <libkdcraw/version.h>
00094 
00095 #if KDCRAW_VERSION < 0x000400
00096 #include <libkdcraw/dcrawbinary.h>
00097 #endif
00098 
00099 // Local includes
00100 
00101 #include "album.h"
00102 #include "albumdb.h"
00103 #include "albumicongroupitem.h"
00104 #include "albumiconitem.h"
00105 #include "albumiconviewtooltip.h"
00106 #include "albumlister.h"
00107 #include "albummanager.h"
00108 #include "albumselectdialog.h"
00109 #include "albumsettings.h"
00110 #include "cameraui.h"
00111 #include "contextmenuhelper.h"
00112 #include "databaseaccess.h"
00113 #include "databasetransaction.h"
00114 #include "ddragobjects.h"
00115 #include "deletedialog.h"
00116 #include "digikamapp.h"
00117 #include "dio.h"
00118 #include "dmetadata.h"
00119 #include "dpopupmenu.h"
00120 #include "imageattributeswatch.h"
00121 #include "imageinfo.h"
00122 #include "imagewindow.h"
00123 #include "lighttablewindow.h"
00124 #include "loadingcacheinterface.h"
00125 #include "metadatahub.h"
00126 #include "queuemgrwindow.h"
00127 #include "ratingpopupmenu.h"
00128 #include "scancontroller.h"
00129 #include "statusprogressbar.h"
00130 #include "tagspopupmenu.h"
00131 #include "themeengine.h"
00132 #include "thumbnailloadthread.h"
00133 #include "thumbnailsize.h"
00134 
00135 namespace Digikam
00136 {
00137 
00138 class AlbumIconViewPrivate
00139 {
00140 public:
00141 
00142     void init()
00143     {
00144         imageLister   = 0;
00145         currentAlbum  = 0;
00146         albumSettings = 0;
00147         toolTip       = 0;
00148 
00149         // Pre-computed star polygon for a 15x15 pixmap.
00150         starPolygon << QPoint(0,  6);
00151         starPolygon << QPoint(5,  5);
00152         starPolygon << QPoint(7,  0);
00153         starPolygon << QPoint(9,  5);
00154         starPolygon << QPoint(14, 6);
00155         starPolygon << QPoint(10, 9);
00156         starPolygon << QPoint(11, 14);
00157         starPolygon << QPoint(7,  11);
00158         starPolygon << QPoint(3,  14);
00159         starPolygon << QPoint(4,  9);
00160 
00161         starPolygonSize = QSize(15, 15);
00162 
00163         ratingPixmaps   = QVector<QPixmap>(10);
00164     }
00165 
00166     QString                          albumTitle;
00167     QString                          albumDate;
00168     QString                          albumComments;
00169 
00170     QRect                            itemRect;
00171     QRect                            itemRatingRect;
00172     QRect                            itemDateRect;
00173     QRect                            itemModDateRect;
00174     QRect                            itemPixmapRect;
00175     QRect                            itemNameRect;
00176     QRect                            itemCommentsRect;
00177     QRect                            itemResolutionRect;
00178     QRect                            itemSizeRect;
00179     QRect                            itemTagRect;
00180     QRect                            bannerRect;
00181 
00182     QPixmap                          itemRegPixmap;
00183     QPixmap                          itemSelPixmap;
00184     QPixmap                          bannerPixmap;
00185     QVector<QPixmap>                 ratingPixmaps;
00186 
00187     QFont                            fnReg;
00188     QFont                            fnCom;
00189     QFont                            fnXtra;
00190 
00191     QPolygon                         starPolygon;
00192     QSize                            starPolygonSize;
00193 
00194     QHash<QString, AlbumIconItem*>   itemDict;
00195     QHash<ImageInfo, AlbumIconItem*> itemInfoMap;
00196 
00197     KUrl                             itemUrlToFind;
00198 
00199     AlbumLister*                     imageLister;
00200     Album*                           currentAlbum;
00201     const AlbumSettings*             albumSettings;
00202     QHash<int, AlbumIconGroupItem*>  albumDict;
00203 
00204     ThumbnailSize                    thumbSize;
00205 
00206     AlbumIconViewToolTip*            toolTip;
00207 };
00208 
00209 AlbumIconView::AlbumIconView(QWidget* parent)
00210              : IconView(parent), d(new AlbumIconViewPrivate)
00211 {
00212     d->init();
00213     d->imageLister = AlbumLister::instance();
00214     d->toolTip     = new AlbumIconViewToolTip(this);
00215 
00216     setAcceptDrops(true);
00217     viewport()->setAcceptDrops(true);
00218 
00219     // -- ImageLister connections -------------------------------------
00220 
00221     connect(d->imageLister, SIGNAL(signalNewFilteredItems(const ImageInfoList&)),
00222             this, SLOT(slotImageListerNewItems(const ImageInfoList&)));
00223 
00224     connect(d->imageLister, SIGNAL(signalDeleteFilteredItem(const ImageInfo &)),
00225             this, SLOT(slotImageListerDeleteItem(const ImageInfo &)) );
00226 
00227     connect(d->imageLister, SIGNAL(signalClear()),
00228             this, SLOT(slotImageListerClear()));
00229 
00230     // -- Icon connections --------------------------------------------
00231 
00232     connect(this, SIGNAL(signalDoubleClicked(IconItem*)),
00233             this, SLOT(slotDoubleClicked(IconItem*)));
00234 
00235     connect(this, SIGNAL(signalReturnPressed(IconItem*)),
00236             this, SLOT(slotDoubleClicked(IconItem*)));
00237 
00238     connect(this, SIGNAL(signalRightButtonClicked(IconItem*, const QPoint &)),
00239             this, SLOT(slotRightButtonClicked(IconItem*, const QPoint &)));
00240 
00241     connect(this, SIGNAL(signalRightButtonClicked(const QPoint &)),
00242             this, SLOT(slotRightButtonClicked(const QPoint &)));
00243 
00244     connect(this, SIGNAL(signalSelectionChanged()),
00245             this, SLOT(slotSelectionChanged()));
00246 
00247     connect(this, SIGNAL(signalShowToolTip(IconItem*)),
00248             this, SLOT(slotShowToolTip(IconItem*)));
00249 
00250     // -- ThemeEngine connections ---------------------------------------
00251 
00252     connect(ThemeEngine::instance(), SIGNAL(signalThemeChanged()),
00253             this, SLOT(slotThemeChanged()));
00254 
00255     // -- Pixmap manager connections ------------------------------------
00256 
00257     connect(ThumbnailLoadThread::defaultIconViewThread(), SIGNAL(signalThumbnailLoaded(const LoadingDescription &, const QPixmap&)),
00258             this, SLOT(slotThumbnailLoaded(const LoadingDescription &, const QPixmap&)));
00259 
00260     // -- ImageAttributesWatch connections ------------------------------
00261 
00262     ImageAttributesWatch *watch = ImageAttributesWatch::instance();
00263 
00264     connect(watch, SIGNAL(signalImageTagsChanged(qlonglong)),
00265             this, SLOT(slotImageAttributesChanged(qlonglong)));
00266 
00267     connect(watch, SIGNAL(signalImagesChanged(int)),
00268             this, SLOT(slotAlbumImagesChanged(int)));
00269 
00270     connect(watch, SIGNAL(signalImageRatingChanged(qlonglong)),
00271             this, SLOT(slotImageAttributesChanged(qlonglong)));
00272 
00273     connect(watch, SIGNAL(signalImageDateChanged(qlonglong)),
00274             this, SLOT(slotImageAttributesChanged(qlonglong)));
00275 
00276     connect(watch, SIGNAL(signalImageCaptionChanged(qlonglong)),
00277             this, SLOT(slotImageAttributesChanged(qlonglong)));
00278 
00279     // -- FileWatch connections ------------------------------
00280 
00281     LoadingCacheInterface::connectToSignalFileChanged(this,
00282             SLOT(slotFileChanged(const QString &)));
00283 
00284     // -- Internal connections ------------------------------
00285 
00286     // defer this action from handling of drag event, see bug #159855
00287     connect(this, SIGNAL(changeTagOnImageInfos(const ImageInfoList &, const QList<int> &, bool, bool)),
00288             this, SLOT(slotChangeTagOnImageInfos(const ImageInfoList &, const QList<int> &, bool, bool)),
00289             Qt::QueuedConnection);
00290 }
00291 
00292 AlbumIconView::~AlbumIconView()
00293 {
00294     delete d->toolTip;
00295     delete d;
00296 }
00297 
00298 void AlbumIconView::applySettings(const AlbumSettings* settings)
00299 {
00300     if (!settings)
00301         return;
00302 
00303     d->albumSettings = settings;
00304 
00305     d->thumbSize = (ThumbnailSize::Size)d->albumSettings->getDefaultIconSize();
00306 
00307     setEnableToolTips(d->albumSettings->getShowToolTips());
00308 
00309     updateRectsAndPixmaps();
00310 
00311     d->imageLister->stop();
00312     clear();
00313 
00314     ThumbnailLoadThread::defaultIconViewThread()->setThumbnailSize(d->thumbSize.size());
00315 
00316     if (d->currentAlbum)
00317     {
00318         d->imageLister->openAlbum(d->currentAlbum);
00319     }
00320 }
00321 
00322 void AlbumIconView::setThumbnailSize(const ThumbnailSize& thumbSize)
00323 {
00324     if ( d->thumbSize != thumbSize)
00325     {
00326         d->thumbSize = thumbSize;
00327         ThumbnailLoadThread::defaultIconViewThread()->setThumbnailSize(d->thumbSize.size());
00328 
00329         updateRectsAndPixmaps();
00330         IconItem *currentIconItem = currentItem();
00331         triggerRearrangement();
00332         setStoredVisibleItem(currentIconItem);
00333     }
00334 }
00335 
00336 void AlbumIconView::setAlbum(Album* album)
00337 {
00338     if (!album)
00339     {
00340         d->currentAlbum = 0;
00341         d->imageLister->stop();
00342         clear();
00343 
00344         return;
00345     }
00346 
00347     if (d->currentAlbum == album)
00348         return;
00349 
00350     d->imageLister->stop();
00351     clear();
00352 
00353     d->currentAlbum = album;
00354     d->imageLister->openAlbum(d->currentAlbum);
00355 
00356     updateRectsAndPixmaps();
00357 }
00358 
00359 void AlbumIconView::setAlbumItemToFind(const KUrl& url)
00360 {
00361     d->itemUrlToFind = url;
00362 }
00363 
00364 void AlbumIconView::refreshIcon(AlbumIconItem* item)
00365 {
00366     if (!item)
00367         return;
00368 
00369     emit signalSelectionChanged();
00370 }
00371 
00372 void AlbumIconView::clear(bool update)
00373 {
00374     emit signalCleared();
00375 
00376     d->itemDict.clear();
00377     d->albumDict.clear();
00378     d->itemInfoMap.clear();
00379 
00380     IconView::clear(update);
00381 
00382     emit signalSelectionChanged();
00383 }
00384 
00385 void AlbumIconView::slotImageListerNewItems(const ImageInfoList& itemList)
00386 {
00387     if (!d->currentAlbum || d->currentAlbum->isRoot())
00388         return;
00389 
00390     for (ImageInfoList::const_iterator it = itemList.constBegin(); it != itemList.constEnd(); ++it)
00391     {
00392         KUrl url( it->fileUrl() );
00393         url.cleanPath();
00394 
00395         if (d->itemInfoMap.contains(*it))
00396         {
00397             // TODO: Make sure replacing slotImageListerDeleteItem with continue here is not wrong
00398             //slotImageListerDeleteItem((*itMap)->imageInfo());
00399             continue;
00400         }
00401 
00402         AlbumIconGroupItem* group = d->albumDict.value(it->albumId());
00403         if (!group)
00404         {
00405             group = new AlbumIconGroupItem(this, it->albumId());
00406             d->albumDict.insert(it->albumId(), group);
00407         }
00408 
00409         PAlbum *album = AlbumManager::instance()->findPAlbum(it->albumId());
00410         if (!album)
00411         {
00412             kWarning() << "No album for item: " << it->name()
00413                             << ", albumID: " << it->albumId();
00414             continue;
00415         }
00416 
00417         AlbumIconItem* iconItem = new AlbumIconItem(group, (*it));
00418 
00419         d->itemDict.insert(url.url(), iconItem);
00420         d->itemInfoMap.insert((*it), iconItem);
00421     }
00422 
00423     // Make the icon, specified by d->itemUrlToFind, the current one
00424     // in the album icon view and make it visible.
00425     // This is for example used after a "Go To",
00426     // e.g. from tags (or date) view to folder view.
00427     // Note that AlbumIconView::slotImageListerNewItems may
00428     // be called several times after another, because images get
00429     // listed in packages of 200.
00430     // Therefore the item might not always be available in the very
00431     // first call when there are sufficiently many images.
00432     // Also, because of this, we cannot reset the item which is to be found,
00433     // i.e. something like d->itemUrlToFind = 0, after the item was found,
00434     // as then the visibility of this item is lost in a subsequent call.
00435     if (!d->itemUrlToFind.isEmpty())
00436     {
00437         AlbumIconItem* icon = findItem(d->itemUrlToFind.url());
00438         if (icon)
00439         {
00440             clearSelection();
00441             updateContents();
00442             setCurrentItem(icon);
00443             ensureItemVisible(icon);
00444 
00445             // make the item really visible
00446             // (the previous ensureItemVisible does not work)
00447             setStoredVisibleItem(icon);
00448             triggerRearrangement();
00449 
00450             // use only once (#180223)
00451             d->itemUrlToFind = KUrl();
00452         }
00453     }
00454 
00455     emit signalItemsAdded();
00456 }
00457 
00458 void AlbumIconView::slotImageListerDeleteItem(const ImageInfo& item)
00459 {
00460     QHash<ImageInfo, AlbumIconItem*>::ConstIterator itMap = d->itemInfoMap.constFind(item);
00461     if (itMap == d->itemInfoMap.constEnd())
00462         return;
00463 
00464     AlbumIconItem* iconItem = (*itMap);
00465 
00466     /*
00467     // ?? Necessary? For what situation?
00468     KUrl url(item->kurl());
00469     url.cleanPath();
00470 
00471     AlbumIconItem *oldItem = d->itemDict[url.url()];
00472 
00473     if( oldItem &&
00474        (oldItem->imageInfo()->id() != iconItem->imageInfo()->id()))
00475     {
00476         return;
00477     }
00478     */
00479 
00480     //d->pixMan->deleteThumbnail(item->kurl());
00481 
00482     emit signalItemDeleted(iconItem);
00483 
00484     delete iconItem;
00485 
00486     d->itemInfoMap.remove(item);
00487     d->itemDict.remove(item.fileUrl().url());
00488 
00489     IconGroupItem* group = firstGroup();
00490     IconGroupItem* tmp;
00491 
00492     while (group)
00493     {
00494         tmp = group->nextGroup();
00495 
00496         if (group->count() == 0)
00497         {
00498             d->albumDict.remove(((AlbumIconGroupItem*)group)->albumID());
00499             delete group;
00500         }
00501 
00502         group = tmp;
00503     }
00504 }
00505 
00506 void AlbumIconView::slotImageListerClear()
00507 {
00508     clear();
00509 }
00510 
00511 void AlbumIconView::slotDoubleClicked(IconItem *item)
00512 {
00513     if (!item) return;
00514 
00515     if (d->albumSettings->getItemLeftClickAction() == AlbumSettings::ShowPreview)
00516     {
00517         // icon effect takes too much time
00518         //KIconEffect::visualActivate(viewport(), contentsRectToViewport(item->rect()));
00519         signalPreviewItem(static_cast<AlbumIconItem *>(item));
00520     }
00521     else
00522     {
00523         // FIXME: this method has diseapear from kdelibs4
00524         //KIconEffect::visualActivate(viewport(), contentsRectToViewport(item->rect()));
00525         slotDisplayItem(static_cast<AlbumIconItem *>(item));
00526     }
00527 }
00528 
00529 void AlbumIconView::slotRightButtonClicked(const QPoint& pos)
00530 {
00531     if (!d->currentAlbum)
00532         return;
00533 
00534     if (d->currentAlbum->isRoot() ||
00535          (   d->currentAlbum->type() != Album::PHYSICAL
00536           && d->currentAlbum->type() != Album::TAG))
00537     {
00538         return;
00539     }
00540 
00541     KMenu popmenu(this);
00542     KAction *paste        = KStandardAction::paste(this, SLOT(slotPaste()), 0);
00543     const QMimeData *data = kapp->clipboard()->mimeData(QClipboard::Clipboard);
00544 
00545     if(!data || !KUrl::List::canDecode(data))
00546         paste->setEnabled(false);
00547 
00548     popmenu.addAction(paste);
00549     popmenu.exec(pos);
00550     delete paste;
00551 }
00552 
00553 void AlbumIconView::slotRightButtonClicked(IconItem *item, const QPoint&)
00554 {
00555     if (!item) return;
00556 
00557     AlbumIconItem* iconItem = static_cast<AlbumIconItem *>(item);
00558     ImageInfo imageInfo     = iconItem->imageInfo();
00559 
00560     // --------------------------------------------------------
00561 
00562     QList<qlonglong> selectedImageIDs;
00563     foreach (ImageInfo info, selectedImageInfosCurrentFirst())
00564     {
00565         selectedImageIDs << info.id();
00566     }
00567 
00568     // Temporary actions --------------------------------------
00569 
00570     QAction  *viewAction = new QAction(SmallIcon("viewimage"), i18nc("View the selected image", "View"),  this);
00571     viewAction->setEnabled(selectedImageIDs.count() == 1);
00572 
00573     // --------------------------------------------------------
00574 
00575     DPopupMenu popmenu(this);
00576     ContextMenuHelper cmhelper(&popmenu);
00577 
00578     cmhelper.addAction("album_new_from_selection");
00579     cmhelper.addAction(viewAction);
00580     cmhelper.addAction("image_edit");
00581     cmhelper.addServicesMenu(selectedItems());
00582     cmhelper.addKipiActions();
00583     popmenu.addSeparator();
00584     // --------------------------------------------------------
00585     cmhelper.addAction("image_find_similar");
00586     cmhelper.addActionLightTable();
00587     cmhelper.addQueueManagerMenu();
00588     cmhelper.addGotoMenu(selectedImageIDs);
00589     cmhelper.addAction("image_rename");
00590     popmenu.addSeparator();
00591     // --------------------------------------------------------
00592     cmhelper.addActionCopy(this, SLOT(slotCopy()));
00593     cmhelper.addActionPaste(this, SLOT(slotPaste()));
00594     cmhelper.addActionItemDelete(this, SLOT(slotDeleteSelectedItems()), selectedImageIDs.count());
00595     popmenu.addSeparator();
00596     // --------------------------------------------------------
00597     cmhelper.addActionThumbnail(selectedImageIDs, d->currentAlbum);
00598     // --------------------------------------------------------
00599     cmhelper.addAssignTagsMenu(selectedImageIDs);
00600     cmhelper.addRemoveTagsMenu(selectedImageIDs);
00601     popmenu.addSeparator();
00602     // --------------------------------------------------------
00603     cmhelper.addRatingMenu();
00604 
00605     // special action handling --------------------------------
00606 
00607     connect(&cmhelper, SIGNAL(signalAssignTag(int)),
00608             this, SLOT(slotAssignTag(int)));
00609 
00610     connect(&cmhelper, SIGNAL(signalRemoveTag(int)),
00611             this, SLOT(slotRemoveTag(int)));
00612 
00613     connect(&cmhelper, SIGNAL(signalGotoTag(int)),
00614             this, SLOT(slotGotoTag(int)));
00615 
00616     connect(&cmhelper, SIGNAL(signalGotoAlbum(ImageInfo&)),
00617             this, SIGNAL(signalGotoAlbumAndItem(ImageInfo&)));
00618 
00619     connect(&cmhelper, SIGNAL(signalGotoDate(ImageInfo&)),
00620             this, SIGNAL(signalGotoDateAndItem(ImageInfo&)));
00621 
00622     connect(&cmhelper, SIGNAL(signalAssignRating(int)),
00623             this, SLOT(slotAssignRating(int)));
00624 
00625     connect(&cmhelper, SIGNAL(signalSetThumbnail(ImageInfo&)),
00626             this, SLOT(slotSetAlbumThumbnail(ImageInfo&)));
00627 
00628     connect(&cmhelper, SIGNAL(signalAddToExistingQueue(int)),
00629             this, SIGNAL(signalAddToExistingQueue(int)));
00630 
00631     // --------------------------------------------------------
00632 
00633     QAction *choice = cmhelper.exec(QCursor::pos());
00634     if (choice)
00635     {
00636         if (choice == viewAction)
00637             emit signalPreviewItem(iconItem);
00638     }
00639 }
00640 
00641 void AlbumIconView::slotCopy()
00642 {
00643     if (!d->currentAlbum)
00644         return;
00645 
00646     KUrl::List urls;
00647     KUrl::List kioURLs;
00648     QList<int> albumIDs;
00649     QList<int> imageIDs;
00650 
00651     for (IconItem *it = firstItem(); it; it=it->nextItem())
00652     {
00653         if (it->isSelected())
00654         {
00655             AlbumIconItem *albumItem = static_cast<AlbumIconItem *>(it);
00656             ImageInfo info = albumItem->imageInfo();
00657             urls.append(info.fileUrl());
00658             kioURLs.append(info.databaseUrl());
00659             imageIDs.append(info.id());
00660         }
00661     }
00662     albumIDs.append(d->currentAlbum->id());
00663 
00664     if (urls.isEmpty())
00665         return;
00666 
00667     kapp->clipboard()->setMimeData(new DItemDrag(urls, kioURLs, albumIDs, imageIDs));
00668 }
00669 
00670 void AlbumIconView::slotPaste()
00671 {
00672     const QMimeData *data = kapp->clipboard()->mimeData(QClipboard::Clipboard);
00673     if(!data)
00674         return;
00675 
00676     Album *album = 0;
00677 
00678     // Check if we working on grouped items view.
00679     if (groupCount() > 1)
00680     {
00681         AlbumIconGroupItem *grp = dynamic_cast<AlbumIconGroupItem*>(findGroup(QCursor::pos()));
00682         if (grp)
00683         {
00684             if(d->currentAlbum->type() == Album::PHYSICAL)
00685                 album = dynamic_cast<Album*>(AlbumManager::instance()->findPAlbum(grp->albumID()));
00686             else if(d->currentAlbum->type() == Album::TAG)
00687                 album = dynamic_cast<Album*>(AlbumManager::instance()->findTAlbum(grp->albumID()));
00688         }
00689     }
00690     if (!album)
00691         album = d->currentAlbum;
00692 
00693     if (d->currentAlbum->type() == Album::PHYSICAL)
00694     {
00695         if (DItemDrag::canDecode(data))
00696         {
00697             // Drag & drop inside of digiKam
00698 
00699             PAlbum* palbum = (PAlbum*)album;
00700 
00701             // B.K.O #119205: do not handle root album.
00702             if (palbum->isRoot())
00703                 return;
00704 
00705             KUrl::List urls;
00706             KUrl::List kioURLs;
00707             QList<int> albumIDs;
00708             QList<int> imageIDs;
00709 
00710             if (!DItemDrag::decode(data, urls, kioURLs, albumIDs, imageIDs))
00711                 return;
00712 
00713             if (urls.isEmpty() || kioURLs.isEmpty() || albumIDs.isEmpty() || imageIDs.isEmpty())
00714                 return;
00715 
00716             // Check if items dropped come from outside current album.
00717             KUrl::List extUrls;
00718             QList<qlonglong> extImageIDs;
00719             for (QList<int>::ConstIterator it = imageIDs.constBegin(); it != imageIDs.constEnd(); ++it)
00720             {
00721                 ImageInfo info(*it);
00722                 if (info.albumId() != album->id())
00723                 {
00724                     extUrls << info.databaseUrl();
00725                     extImageIDs << *it;
00726                 }
00727             }
00728 
00729             if(extUrls.isEmpty())
00730                 return;
00731 
00732             KIO::Job* job = DIO::copy(kioURLs, extImageIDs, palbum);
00733             connect(job, SIGNAL(result(KJob*)),
00734                     this, SLOT(slotDIOResult(KJob*)));
00735         }
00736         else if (KUrl::List::canDecode(data))
00737         {
00738             PAlbum* palbum = (PAlbum*)album;
00739 
00740             // B.K.O #119205: do not handle root album.
00741             if (palbum->isRoot())
00742                 return;
00743 
00744             KUrl::List srcURLs = KUrl::List::fromMimeData(data);
00745 
00746             KIO::Job* job = DIO::copy(srcURLs, palbum);
00747             connect(job, SIGNAL(result(KJob*)),
00748                     this, SLOT(slotDIOResult(KJob*)));
00749         }
00750     }
00751     else if(d->currentAlbum->type() == Album::TAG && DItemDrag::canDecode(data))
00752     {
00753         TAlbum* talbum = (TAlbum*)album;
00754 
00755         // B.K.O #119205: do not handle root album.
00756         if (talbum->isRoot())
00757             return;
00758 
00759         KUrl::List urls;
00760         KUrl::List kioURLs;
00761         QList<int> albumIDs;
00762         QList<int> imageIDs;
00763 
00764         if (!DItemDrag::decode(data, urls, kioURLs, albumIDs, imageIDs))
00765             return;
00766 
00767         if (urls.isEmpty() || kioURLs.isEmpty() || albumIDs.isEmpty() || imageIDs.isEmpty())
00768             return;
00769 
00770         ImageInfoList list;
00771         for (QList<int>::const_iterator it = imageIDs.constBegin();
00772              it != imageIDs.constEnd(); ++it)
00773         {
00774             ImageInfo info(*it);
00775             list.append(info);
00776         }
00777 
00778         emit changeTagOnImageInfos(list, QList<int>() << talbum->id(), true, true);
00779     }
00780 }
00781 
00782 void AlbumIconView::slotSetAlbumThumbnail(ImageInfo& imageInfo)
00783 {
00784     if(!d->currentAlbum)
00785         return;
00786 
00787     if(d->currentAlbum->type() == Album::PHYSICAL)
00788     {
00789         PAlbum *album = static_cast<PAlbum*>(d->currentAlbum);
00790 
00791         QString err;
00792         AlbumManager::instance()->updatePAlbumIcon( album,
00793                                                     imageInfo.id(),
00794                                                     err );
00795     }
00796     else if (d->currentAlbum->type() == Album::TAG)
00797     {
00798         TAlbum *album = static_cast<TAlbum*>(d->currentAlbum);
00799 
00800         QString err;
00801         AlbumManager::instance()->updateTAlbumIcon( album,
00802                                                     QString(),
00803                                                     imageInfo.id(),
00804                                                     err );
00805     }
00806 }
00807 
00808 void AlbumIconView::slotRename(AlbumIconItem* item)
00809 {
00810     if (!item)
00811         return;
00812 
00813     // Create a copy of the item. After entering the event loop
00814     // in the dialog, we cannot be sure about the item's status.
00815     ImageInfo renameInfo = item->imageInfo();
00816 
00817     QFileInfo fi(renameInfo.name());
00818     QString ext  = QString(".") + fi.suffix();
00819     QString name = fi.fileName();
00820     name.truncate(fi.fileName().length() - ext.length());
00821 
00822     bool ok;
00823 
00824     QString newName = KInputDialog::getText(i18n("Rename Item (%1)",fi.fileName()),
00825                                             i18n("Enter new name (without extension):"),
00826                                             name, &ok, this);
00827     if (!ok)
00828         return;
00829 
00830     KIO::CopyJob* job = DIO::rename(renameInfo, newName + ext);
00831 
00832     connect(job, SIGNAL(result(KJob*)),
00833             this, SLOT(slotDIOResult(KJob*)));
00834 
00835     connect(job, SIGNAL(copyingDone(KIO::Job *, const KUrl &, const KUrl &, bool, bool)),
00836             this, SLOT(slotRenamed(KIO::Job*, const KUrl &, const KUrl&)));
00837 
00838     //TODO: The explanation is outdated. Check if we can safely remove.
00839     // The AlbumManager KDirWatch will trigger a DIO::scan.
00840     // When this is completed, DIO will call AlbumLister::instance()->refresh().
00841     // Usually the AlbumLister will ignore changes to already listed items.
00842     // So the renamed item need explicitly be invalidated.
00843     d->imageLister->invalidateItem(renameInfo);
00844 }
00845 
00846 void AlbumIconView::slotRenamed(KIO::Job*, const KUrl &, const KUrl&newURL)
00847 {
00848     // reconstruct file path from digikamalbums:// URL
00849     KUrl fileURL;
00850     fileURL.setPath(newURL.user());
00851     fileURL.addPath(newURL.path());
00852 
00853     // refresh thumbnail
00854     ThumbnailLoadThread::deleteThumbnail(fileURL.path());
00855     // clean LoadingCache as well - be pragmatic, do it here.
00856     LoadingCacheInterface::fileChanged(fileURL.path());
00857 }
00858 
00859 void AlbumIconView::slotDeleteSelectedItems(bool deletePermanently)
00860 {
00861     KUrl::List  urlList;
00862     KUrl::List  kioUrlList;
00863 
00864     for (IconItem *it = firstItem(); it; it=it->nextItem())
00865     {
00866         if (it->isSelected())
00867         {
00868             AlbumIconItem *iconItem = static_cast<AlbumIconItem *>(it);
00869             ImageInfo info = iconItem->imageInfo();
00870             urlList.append(info.fileUrl());
00871             kioUrlList.append(info.databaseUrl());
00872         }
00873     }
00874 
00875     if (urlList.count() <= 0)
00876         return;
00877 
00878     DeleteDialog dialog(this);
00879 
00880     if (!dialog.confirmDeleteList(urlList,
00881                                   DeleteDialogMode::Files,
00882                                   deletePermanently ?
00883                                   DeleteDialogMode::NoChoiceDeletePermanently :
00884                                   DeleteDialogMode::NoChoiceTrash))
00885         return;
00886 
00887     bool useTrash = !dialog.shouldDelete();
00888 
00889     // trash does not like non-local URLs, put is not implemented
00890     KIO::Job* job = DIO::del(useTrash ? urlList : kioUrlList, useTrash);
00891 
00892     connect(job, SIGNAL(result(KJob*)),
00893             this, SLOT(slotDIOResult(KJob*)));
00894 }
00895 
00896 void AlbumIconView::slotDeleteSelectedItemsDirectly(bool useTrash)
00897 {
00898     // This method deletes the selected items directly, without confirmation.
00899     // It is not used in the default setup.
00900 
00901     KUrl::List kioUrlList;
00902     KUrl::List urlList;
00903 
00904     for (IconItem *it = firstItem(); it; it=it->nextItem())
00905     {
00906         if (it->isSelected())
00907         {
00908             AlbumIconItem *iconItem = static_cast<AlbumIconItem *>(it);
00909             ImageInfo info = iconItem->imageInfo();
00910             kioUrlList.append(info.databaseUrl());
00911             urlList.append(info.fileUrl());
00912         }
00913     }
00914 
00915     if (kioUrlList.count() <= 0)
00916         return;
00917 
00918     // trash does not like non-local URLs, put is not implemented
00919     KIO::Job* job = DIO::del(useTrash ? urlList : kioUrlList , useTrash);
00920 
00921     connect(job, SIGNAL(result(KJob*)),
00922             this, SLOT(slotDIOResult(KJob*)));
00923 }
00924 
00925 void AlbumIconView::slotFilesModified()
00926 {
00927     d->imageLister->refresh();
00928 }
00929 
00930 void AlbumIconView::slotFilesModified(const KUrl& url)
00931 {
00932     refreshItems(url);
00933 }
00934 
00935 void AlbumIconView::slotImageWindowURLChanged(const KUrl& url)
00936 {
00937     IconItem* item = findItem(url.url());
00938     if (item)
00939         setCurrentItem(item);
00940 }
00941 
00942 void AlbumIconView::slotDisplayItem(AlbumIconItem *item)
00943 {
00944     if (!item) return;
00945 
00946     AlbumSettings *settings = AlbumSettings::instance();
00947 
00948     if (!settings) return;
00949 
00950     QString currentFileExtension = item->imageInfo().name().section( '.', -1 );
00951     QString imagefilter = settings->getImageFileFilter().toLower() +
00952                           settings->getImageFileFilter().toUpper();
00953 
00954 #if KDCRAW_VERSION < 0x000400
00955     if (KDcrawIface::DcrawBinary::instance()->versionIsRight())
00956     {
00957         // add raw files only if dcraw is available
00958         imagefilter += settings->getRawFileFilter().toLower() +
00959                        settings->getRawFileFilter().toUpper();
00960     }
00961 #else
00962     // add raw files only if dcraw is available
00963     imagefilter += settings->getRawFileFilter().toLower() +
00964                    settings->getRawFileFilter().toUpper();
00965 #endif
00966 
00967     // If the current item is not an image file.
00968     if ( !imagefilter.contains(currentFileExtension) )
00969     {
00970         KMimeType::Ptr mimePtr = KMimeType::findByUrl(item->imageInfo().fileUrl(), 0, true, true);
00971         const KService::List offers = KServiceTypeTrader::self()->query(mimePtr->name(), "Type == 'Application'");
00972 
00973         if (offers.isEmpty())
00974             return;
00975 
00976         KService::Ptr ptr = offers.first();
00977         // Run the dedicated app to show the item.
00978         KRun::run(*ptr, item->imageInfo().fileUrl(), this);
00979         return;
00980     }
00981 
00982     // Run digiKam ImageEditor with all image from current Album.
00983 
00984     ImageInfoList list;
00985     ImageInfo     current;
00986 
00987     for (IconItem *it = firstItem() ; it ; it = it->nextItem())
00988     {
00989         AlbumIconItem *iconItem = static_cast<AlbumIconItem*>(it);
00990         ImageInfo info          = iconItem->imageInfo();
00991         QString fileExtension   = info.fileUrl().fileName().section( '.', -1 );
00992 
00993         if ( imagefilter.indexOf(fileExtension) != -1 )
00994         {
00995             list << info;
00996             if (iconItem == item)
00997                 current = info;
00998         }
00999     }
01000 
01001     ImageWindow *imview = ImageWindow::imagewindow();
01002 
01003     imview->disconnect(this);
01004 
01005     //connect(imview, SIGNAL(signalFileAdded(const KUrl&)),
01006       //      this, SLOT(slotFilesModified()));
01007 
01008     //connect(imview, SIGNAL(signalFileModified(const KUrl&)),
01009       //      this, SLOT(slotFilesModified(const KUrl&)));
01010 
01011     //connect(imview, SIGNAL(signalFileDeleted(const KUrl&)),
01012       //      this, SLOT(slotFilesModified()));
01013 
01014     connect(imview, SIGNAL(signalURLChanged(const KUrl&)),
01015             this, SLOT(slotImageWindowURLChanged(const KUrl &)));
01016 
01017     imview->loadImageInfos(list, current,
01018                            d->currentAlbum ? i18n("Album \"%1\"",d->currentAlbum->title()) : QString(),
01019                            true);
01020 
01021     if (imview->isHidden())
01022         imview->show();
01023 
01024     if (imview->isMinimized())
01025         KWindowSystem::unminimizeWindow(imview->winId());
01026     KWindowSystem::activateWindow(imview->winId());
01027 }
01028 
01029 void AlbumIconView::insertSelectionToLightTable(bool addTo)
01030 {
01031     // Run Light Table with all selected image files in the current Album.
01032     // If addTo is false, the light table will be emptied before adding
01033     // the images.
01034     ImageInfoList imageInfoList;
01035 
01036     for (IconItem *it = firstItem() ; it ; it = it->nextItem())
01037     {
01038         if ((*it).isSelected())
01039         {
01040             AlbumIconItem *iconItem = static_cast<AlbumIconItem *>(it);
01041             imageInfoList << iconItem->imageInfo();
01042         }
01043     }
01044 
01045     insertToLightTable(imageInfoList, imageInfoList.first(), addTo);
01046 }
01047 
01048 void AlbumIconView::insertToLightTable(const ImageInfoList& list, const ImageInfo& current, bool addTo)
01049 {
01050     LightTableWindow *ltview = LightTableWindow::lightTableWindow();
01051 
01052     // If addTo is false, the light table will be emptied before adding
01053     // the images.
01054     ltview->loadImageInfos(list, current, addTo);
01055     ltview->setLeftRightItems(list, addTo);
01056 
01057     if (ltview->isHidden())
01058         ltview->show();
01059 
01060     if (ltview->isMinimized())
01061         KWindowSystem::unminimizeWindow(ltview->winId());
01062     KWindowSystem::activateWindow(ltview->winId());
01063 
01064 }
01065 
01066 // ------------------------------------------------------------------------------
01067 
01068 void AlbumIconView::insertSelectionToCurrentQueue()
01069 {
01070     ImageInfoList imageInfoList = selectedImageInfos();
01071     insertToQueueManager(imageInfoList, imageInfoList.first(), false);
01072 }
01073 
01074 void AlbumIconView::insertSelectionToNewQueue()
01075 {
01076     ImageInfoList imageInfoList = selectedImageInfos();
01077     insertToQueueManager(imageInfoList, imageInfoList.first(), true);
01078 }
01079 
01080 void AlbumIconView::insertToQueueManager(const ImageInfoList& list, const ImageInfo& /*current*/, bool newQueue)
01081 {
01082     QueueMgrWindow *bqmview = QueueMgrWindow::queueManagerWindow();
01083 
01084     if (bqmview->isHidden())
01085         bqmview->show();
01086 
01087     if (bqmview->isMinimized())
01088         KWindowSystem::unminimizeWindow(bqmview->winId());
01089     KWindowSystem::activateWindow(bqmview->winId());
01090 
01091     if (newQueue) bqmview->addNewQueue();
01092 
01093     bqmview->loadImageInfos(list, bqmview->currentQueueId());
01094 }
01095 
01096 void AlbumIconView::insertSilentToQueueManager(const ImageInfoList& list, const ImageInfo& /*current*/, int queueid)
01097 {
01098     QueueMgrWindow *bqmview = QueueMgrWindow::queueManagerWindow();
01099     bqmview->loadImageInfos(list, queueid);
01100 }
01101 
01102 // ------------------------------------------------------------------------------
01103 
01104 AlbumIconItem* AlbumIconView::firstSelectedItem() const
01105 {
01106     AlbumIconItem *iconItem = 0;
01107     for (IconItem *it = firstItem(); it; it = it->nextItem())
01108     {
01109         if (it->isSelected())
01110         {
01111             iconItem = static_cast<AlbumIconItem *>(it);
01112             break;
01113         }
01114     }
01115 
01116     return iconItem;
01117 }
01118 
01119 const AlbumSettings* AlbumIconView::settings() const
01120 {
01121     return d->albumSettings;
01122 }
01123 
01124 ThumbnailSize AlbumIconView::thumbnailSize() const
01125 {
01126     return d->thumbSize;
01127 }
01128 
01129 void AlbumIconView::resizeEvent(QResizeEvent *e)
01130 {
01131     IconView::resizeEvent(e);
01132 
01133     if (d->bannerRect.width() != frameRect().width())
01134         updateRectsAndPixmaps();
01135 }
01136 
01137 // -- DnD ---------------------------------------------------
01138 
01139 void AlbumIconView::startDrag()
01140 {
01141     if (!d->currentAlbum)
01142         return;
01143 
01144     KUrl::List urls;
01145     KUrl::List kioURLs;
01146     QList<int> albumIDs;
01147     QList<int> imageIDs;
01148 
01149     for (IconItem *it = firstItem(); it; it=it->nextItem())
01150     {
01151         if (it->isSelected())
01152         {
01153             AlbumIconItem *albumItem = static_cast<AlbumIconItem *>(it);
01154             ImageInfo info = albumItem->imageInfo();
01155             urls.append(info.fileUrl());
01156             kioURLs.append(info.databaseUrl());
01157             imageIDs.append(info.id());
01158         }
01159     }
01160     albumIDs.append(d->currentAlbum->id());
01161 
01162     if (urls.isEmpty())
01163         return;
01164 
01165     QPixmap icon(DesktopIcon("image-jp2", 48));
01166     int w = icon.width();
01167     int h = icon.height();
01168 
01169     QPixmap pix(w+4, h+4);
01170     QString text(QString::number(urls.count()));
01171 
01172     QPainter p(&pix);
01173     p.fillRect(0, 0, pix.width()-1, pix.height()-1, QColor(Qt::white));
01174     p.setPen(QPen(Qt::black, 1));
01175     p.drawRect(0, 0, pix.width()-1, pix.height()-1);
01176     p.drawPixmap(2, 2, icon);
01177     QRect r = p.boundingRect(2, 2, w, h, Qt::AlignLeft|Qt::AlignTop, text);
01178     r.setWidth(qMax(r.width(), r.height()));
01179     r.setHeight(qMax(r.width(), r.height()));
01180     p.fillRect(r, QColor(0, 80, 0));
01181     p.setPen(Qt::white);
01182     QFont f(font());
01183     f.setBold(true);
01184     p.setFont(f);
01185     p.drawText(r, Qt::AlignCenter, text);
01186     p.end();
01187 
01188     QDrag* drag = new QDrag(this);
01189     drag->setMimeData(new DItemDrag(urls, kioURLs, albumIDs, imageIDs));
01190     drag->setPixmap(pix);
01191     drag->exec();
01192 }
01193 
01194 void AlbumIconView::contentsDragEnterEvent(QDragEnterEvent *e)
01195 {
01196     if (!d->currentAlbum || (DAlbumDrag::canDecode(e->mimeData()) ||
01197                             (!KUrl::List::canDecode(e->mimeData())          &&
01198                              !DCameraDragObject::canDecode(e->mimeData())   &&
01199                              !DTagListDrag::canDecode(e->mimeData())        &&
01200                              !DTagDrag::canDecode(e->mimeData())            &&
01201                              !DCameraItemListDrag::canDecode(e->mimeData()) &&
01202                              !DItemDrag::canDecode(e->mimeData()))))
01203     {
01204         return;
01205     }
01206     e->acceptProposedAction();
01207 }
01208 
01209 void AlbumIconView::contentsDropEvent(QDropEvent *e)
01210 {
01211     if (!d->currentAlbum || (DAlbumDrag::canDecode(e->mimeData()) ||
01212                             (!KUrl::List::canDecode(e->mimeData())          &&
01213                              !DCameraDragObject::canDecode(e->mimeData())   &&
01214                              !DTagListDrag::canDecode(e->mimeData())        &&
01215                              !DTagDrag::canDecode(e->mimeData())            &&
01216                              !DCameraItemListDrag::canDecode(e->mimeData()) &&
01217                              !DItemDrag::canDecode(e->mimeData()))))
01218     {
01219         e->ignore();
01220         return;
01221     }
01222 
01223     Album *album = 0;
01224 
01225     // Check if we working on grouped items view.
01226     if (groupCount() > 1)
01227     {
01228         AlbumIconGroupItem *grp = dynamic_cast<AlbumIconGroupItem*>(findGroup(QCursor::pos()));
01229         if (grp)
01230         {
01231             if(d->currentAlbum->type() == Album::PHYSICAL)
01232                 album = dynamic_cast<Album*>(AlbumManager::instance()->findPAlbum(grp->albumID()));
01233             else if(d->currentAlbum->type() == Album::TAG)
01234                 album = dynamic_cast<Album*>(AlbumManager::instance()->findTAlbum(grp->albumID()));
01235         }
01236     }
01237     if (!album)
01238         album = d->currentAlbum;
01239 
01240     KUrl::List urls;
01241     KUrl::List kioURLs;
01242     QList<int> albumIDs;
01243     QList<int> imageIDs;
01244 
01245     if (DItemDrag::decode(e->mimeData(), urls, kioURLs, albumIDs, imageIDs))
01246     {
01247         // Drag & drop inside of digiKam
01248 
01249         // Check if items dropped come from outside current album.
01250         KUrl::List extUrls;
01251         QList<qlonglong> extImageIDs;
01252         for (QList<int>::const_iterator it = imageIDs.constBegin(); it != imageIDs.constEnd(); ++it)
01253         {
01254             ImageInfo info(*it);
01255             if (info.albumId() != album->id())
01256             {
01257                 extUrls << info.databaseUrl();
01258                 extImageIDs << *it;
01259             }
01260         }
01261 
01262         if(extUrls.isEmpty())
01263         {
01264             e->ignore();
01265             return;
01266         }
01267         else if (album->type() == Album::PHYSICAL)
01268         {
01269             PAlbum* palbum = (PAlbum*)album;
01270 
01271             KMenu popMenu(this);
01272             QAction *moveAction = popMenu.addAction( SmallIcon("go-jump"), i18n("&Move Here"));
01273             QAction *copyAction = popMenu.addAction( SmallIcon("edit-copy"), i18n("&Copy Here"));
01274             popMenu.addSeparator();
01275             popMenu.addAction( SmallIcon("dialog-cancel"), i18n("C&ancel") );
01276 
01277             popMenu.setMouseTracking(true);
01278             QAction *choice = popMenu.exec(QCursor::pos());
01279             if (choice == moveAction)
01280             {
01281                 KIO::Job* job = DIO::move(extUrls, extImageIDs, palbum);
01282                 connect(job, SIGNAL(result(KJob*)),
01283                         this, SLOT(slotDIOResult(KJob*)));
01284             }
01285             else if (choice == copyAction)
01286             {
01287                 KIO::Job* job = DIO::copy(extUrls, extImageIDs, palbum);
01288                 connect(job, SIGNAL(result(KJob*)),
01289                         this, SLOT(slotDIOResult(KJob*)));
01290             }
01291         }
01292     }
01293     else if (KUrl::List::canDecode(e->mimeData()) && d->currentAlbum->type() == Album::PHYSICAL)
01294     {
01295         // Drag & drop outside of digiKam
01296         PAlbum* palbum = (PAlbum*)album;
01297 
01298         KUrl::List srcURLs = KUrl::List::fromMimeData(e->mimeData());
01299 
01300         KMenu popMenu(this);
01301         QAction *moveAction = popMenu.addAction( SmallIcon("go-jump"), i18n("&Move Here"));
01302         QAction *copyAction = popMenu.addAction( SmallIcon("edit-copy"), i18n("&Copy Here"));
01303         popMenu.addSeparator();
01304         popMenu.addAction( SmallIcon("dialog-cancel"), i18n("C&ancel") );
01305 
01306         popMenu.setMouseTracking(true);
01307         QAction *choice = popMenu.exec(QCursor::pos());
01308         if (choice == moveAction)
01309         {
01310             KIO::Job* job = DIO::move(srcURLs, palbum);
01311             connect(job, SIGNAL(result(KJob*)),
01312                     this, SLOT(slotDIOResult(KJob*)));
01313         }
01314         else if (choice == copyAction)
01315         {
01316             KIO::Job* job = DIO::copy(srcURLs, palbum);
01317             connect(job, SIGNAL(result(KJob*)),
01318                     this, SLOT(slotDIOResult(KJob*)));
01319         }
01320     }
01321     else if(DTagDrag::canDecode(e->mimeData()))
01322     {
01323         int tagID;
01324         if (!DTagDrag::decode(e->mimeData(), tagID))
01325             return;
01326 
01327         AlbumManager* man = AlbumManager::instance();
01328         TAlbum* talbum    = man->findTAlbum(tagID);
01329 
01330         if (talbum)
01331         {
01332             KMenu popMenu(this);
01333 
01334             bool moreItemsSelected = false;
01335             bool itemDropped = false;
01336 
01337             AlbumIconItem *albumItem = findItem(e->pos());
01338             if (albumItem)
01339                 itemDropped = true;
01340 
01341             for (IconItem *it = firstItem(); it; it = it->nextItem())
01342             {
01343                 if (it->isSelected() && it != albumItem)
01344                 {
01345                     moreItemsSelected = true;
01346                     break;
01347                 }
01348             }
01349 
01350             QAction *assignToSelectedAction = 0;
01351             if (moreItemsSelected)
01352                 assignToSelectedAction =
01353                         popMenu.addAction(SmallIcon("tag"), i18n("Assign '%1' to &Selected Items",talbum->tagPath().mid(1)));
01354 
01355             QAction *assignToThisAction = 0;
01356             if (itemDropped)
01357                 assignToThisAction =
01358                         popMenu.addAction(SmallIcon("tag"), i18n("Assign '%1' to &This Item",talbum->tagPath().mid(1)));
01359 
01360             QAction *assignToAllAction =
01361                 popMenu.addAction(SmallIcon("tag"), i18n("Assign '%1' to &All Items",talbum->tagPath().mid(1)));
01362 
01363             popMenu.addSeparator();
01364             popMenu.addAction(SmallIcon("dialog-cancel"), i18n("&Cancel"));
01365 
01366             popMenu.setMouseTracking(true);
01367             QAction *choice = popMenu.exec(QCursor::pos());
01368             if (choice)
01369             {
01370                 if (choice == assignToSelectedAction)    // Selected Items
01371                 {
01372                     emit changeTagOnImageInfos(selectedImageInfosCurrentFirst(), QList<int>() << tagID, true, true);
01373                 }
01374                 else if (choice == assignToAllAction)    // All Items
01375                 {
01376                     emit changeTagOnImageInfos(allImageInfos(), QList<int>() << tagID, true, true);
01377                 }
01378                 else if (choice == assignToThisAction)  // Dropped Item only.
01379                 {
01380                     AlbumIconItem *albumItem = findItem(e->pos());
01381                     if (albumItem)
01382                     {
01383                         ImageInfoList infos;
01384                         infos << albumItem->imageInfo();
01385                         emit changeTagOnImageInfos(infos, QList<int>() << tagID, true, false);
01386                     }
01387                 }
01388             }
01389         }
01390     }
01391     else if(DTagListDrag::canDecode(e->mimeData()))
01392     {
01393         QList<int> tagIDs;
01394         DTagListDrag::decode(e->mimeData(), tagIDs);
01395 
01396         KMenu popMenu(this);
01397 
01398         bool moreItemsSelected = false;
01399         bool itemDropped = false;
01400 
01401         AlbumIconItem *albumItem = findItem(e->pos());
01402         if (albumItem)
01403             itemDropped = true;
01404 
01405         for (IconItem *it = firstItem(); it; it = it->nextItem())
01406         {
01407             if (it->isSelected() && it != albumItem)
01408             {
01409                 moreItemsSelected = true;
01410                 break;
01411             }
01412         }
01413 
01414         QAction *assignToSelectedAction = 0;
01415         if (moreItemsSelected)
01416             assignToSelectedAction = popMenu.addAction(SmallIcon("tag"), i18n("Assign Tags to &Selected Items"));
01417 
01418         QAction *assignToThisAction = 0;
01419         if (itemDropped)
01420             assignToThisAction = popMenu.addAction(SmallIcon("tag"), i18n("Assign Tags to &This Item"));
01421 
01422         QAction *assignToAllAction =
01423             popMenu.addAction(SmallIcon("tag"), i18n("Assign Tags to &All Items"));
01424 
01425         popMenu.addSeparator();
01426         popMenu.addAction(SmallIcon("dialog-cancel"), i18n("&Cancel"));
01427 
01428         popMenu.setMouseTracking(true);
01429         QAction *choice = popMenu.exec(QCursor::pos());
01430         if (choice)
01431         {
01432             if (choice == assignToSelectedAction)    // Selected Items
01433             {
01434                 slotChangeTagOnImageInfos(selectedImageInfosCurrentFirst(), tagIDs, true, true);
01435             }
01436             else if (choice == assignToAllAction)    // All Items
01437             {
01438                 slotChangeTagOnImageInfos(allImageInfos(), tagIDs, true, true);
01439             }
01440             else if (choice == assignToThisAction)    // Dropped item only.
01441             {
01442                 AlbumIconItem *albumItem = findItem(e->pos());
01443                 if (albumItem)
01444                 {
01445                     ImageInfoList infos;
01446                     infos << albumItem->imageInfo();
01447                     slotChangeTagOnImageInfos(infos, tagIDs, true, false);
01448                 }
01449             }
01450         }
01451     }
01452     else if(DCameraItemListDrag::canDecode(e->mimeData()))
01453     {
01454         CameraUI *ui = dynamic_cast<CameraUI*>(e->source());
01455         if (ui)
01456         {
01457             KMenu popMenu(this);
01458             popMenu.addTitle(SmallIcon("digikam"), i18n("My Albums"));
01459             QAction *downAction    = popMenu.addAction(SmallIcon("file-export"),
01460                                                        i18n("Download From Camera"));
01461             QAction *downDelAction = popMenu.addAction(SmallIcon("file-export"),
01462                                                        i18n("Download && Delete From Camera"));
01463             popMenu.addSeparator();
01464             popMenu.addAction(SmallIcon("dialog-cancel"), i18n("C&ancel"));
01465             popMenu.setMouseTracking(true);
01466             QAction *choice = popMenu.exec(QCursor::pos());
01467             if (choice)
01468             {
01469                 if (choice == downAction)
01470                     ui->slotDownload(true, false, album);
01471                 else if (choice == downDelAction)
01472                     ui->slotDownload(true, true, album);
01473             }
01474         }
01475     }
01476     else
01477     {
01478         e->ignore();
01479     }
01480 }
01481 
01482 void AlbumIconView::slotChangeTagOnImageInfos(const ImageInfoList& list, const QList<int>& tagIDs, bool addOrRemove, bool progress)
01483 {
01484     float cnt = list.count();
01485     int i     = 0;
01486 
01487     if (progress)
01488     {
01489         if (addOrRemove)
01490             emit signalProgressBarMode(StatusProgressBar::ProgressBarMode,
01491                                        i18n("Assigning image tags. Please wait..."));
01492         else
01493             emit signalProgressBarMode(StatusProgressBar::ProgressBarMode,
01494                                        i18n("Removing image tags. Please wait..."));
01495     }
01496 
01497     d->imageLister->blockSignals(true);
01498     ScanController::instance()->suspendCollectionScan();
01499     DatabaseTransaction transaction;
01500     foreach(const ImageInfo& info, list)
01501     {
01502         MetadataHub hub;
01503 
01504         hub.load(info);
01505 
01506         for (QList<int>::const_iterator tagIt = tagIDs.constBegin(); tagIt != tagIDs.constEnd(); ++tagIt)
01507         {
01508             hub.setTag(*tagIt, addOrRemove);
01509         }
01510 
01511         QString filePath = info.filePath();
01512         hub.write(info, MetadataHub::PartialWrite);
01513         bool fileChanged = hub.write(filePath, MetadataHub::FullWriteIfChanged);
01514         if (fileChanged)
01515             ScanController::instance()->scanFileDirectly(filePath);
01516 
01517         if (progress)
01518         {
01519             emit signalProgressValue((int)((i++/cnt)*100.0));
01520             kapp->processEvents();
01521         }
01522     }
01523     ScanController::instance()->resumeCollectionScan();
01524     d->imageLister->blockSignals(false);
01525 
01526     if (progress)
01527         emit signalProgressBarMode(StatusProgressBar::TextMode, QString());
01528 
01529     if (d->currentAlbum && d->currentAlbum->type() == Album::TAG)
01530     {
01531         d->imageLister->refresh();
01532     }
01533     updateContents();
01534 }
01535 
01536 bool AlbumIconView::acceptToolTip(IconItem *item, const QPoint& mousePos)
01537 {
01538     AlbumIconItem *iconItem = dynamic_cast<AlbumIconItem*>(item);
01539 
01540     if (iconItem && iconItem->clickToOpenRect().contains(mousePos))
01541     {
01542         return true;
01543     }
01544     else
01545     {
01546         return false;
01547     }
01548 }
01549 
01550 void AlbumIconView::slotShowToolTip(IconItem* item)
01551 {
01552     d->toolTip->setIconItem(dynamic_cast<AlbumIconItem*>(item));
01553 }
01554 
01555 KUrl::List AlbumIconView::allItems()
01556 {
01557     KUrl::List itemList;
01558 
01559      for (IconItem *it = firstItem(); it; it = it->nextItem())
01560      {
01561          AlbumIconItem *item = (AlbumIconItem*) it;
01562          itemList.append(item->imageInfo().fileUrl());
01563      }
01564 
01565     return itemList;
01566 }
01567 
01568 KUrl::List AlbumIconView::selectedItems()
01569 {
01570     KUrl::List itemList;
01571 
01572      for (IconItem *it = firstItem(); it; it = it->nextItem())
01573      {
01574          if (it->isSelected())
01575          {
01576              AlbumIconItem *item = (AlbumIconItem*) it;
01577              itemList.append(item->imageInfo().fileUrl());
01578          }
01579      }
01580 
01581     return itemList;
01582 }
01583 
01584 ImageInfoList AlbumIconView::allImageInfos(ImageInfo* current) const
01585 {
01586     if (current)
01587     {
01588         // As default copy the first item info as current;
01589         // will be changed later when a current item is found
01590         if (firstItem())
01591             *current = static_cast<AlbumIconItem*>(firstItem())->imageInfo();
01592         else
01593             *current = ImageInfo();
01594     }
01595 
01596     IconItem *currentIconItem = currentItem();
01597     ImageInfoList list;
01598     for (IconItem *it = firstItem() ; it ; it = it->nextItem())
01599     {
01600         AlbumIconItem *iconItem = static_cast<AlbumIconItem*>(it);
01601         ImageInfo info          = iconItem->imageInfo();
01602 
01603         list << info;
01604 
01605         // If we found the current item, set current to its ImageInfo
01606         if (current && iconItem == currentIconItem)
01607             *current = info;
01608     }
01609 
01610     return list;
01611 }
01612 
01613 ImageInfoList AlbumIconView::selectedImageInfosCurrentFirst() const
01614 {
01615     // Returns the list of ImageInfos of currently selected items,
01616     // with the extra feature that the currentItem is the first in the list.
01617     ImageInfoList list;
01618     for (IconItem *it = firstItem(); it; it = it->nextItem())
01619     {
01620         AlbumIconItem *iconItem = static_cast<AlbumIconItem *>(it);
01621         if (it->isSelected())
01622         {
01623             ImageInfo info = iconItem->imageInfo();
01624 
01625             if (iconItem == currentItem())
01626                 list.prepend(info);
01627             else
01628                 list.append(info);
01629         }
01630     }
01631     return list;
01632 }
01633 
01634 ImageInfoList AlbumIconView::selectedImageInfos() const
01635 {
01636     // Returns the list of ImageInfos of currently selected items,
01637     ImageInfoList list;
01638     for (IconItem *it = firstItem(); it; it = it->nextItem())
01639     {
01640         if (it->isSelected())
01641         {
01642             AlbumIconItem *iconItem = static_cast<AlbumIconItem *>(it);
01643             list << iconItem->imageInfo();
01644         }
01645     }
01646     return list;
01647 }
01648 
01649 void AlbumIconView::refresh()
01650 {
01651     d->imageLister->stop();
01652     clear();
01653 
01654     d->imageLister->openAlbum(d->currentAlbum);
01655 }
01656 
01657 void AlbumIconView::refreshItems(const KUrl::List& urlList)
01658 {
01659     if (!d->currentAlbum || urlList.empty())
01660         return;
01661 
01662     // we do two things here:
01663     // 1. refresh the imageinfo for the file
01664     // 2. refresh the thumbnails
01665 
01666     for (KUrl::List::const_iterator it = urlList.constBegin();
01667          it != urlList.constEnd(); ++it)
01668     {
01669         AlbumIconItem* iconItem = findItem((*it).url());
01670         if (!iconItem)
01671             continue;
01672 
01673         ThumbnailLoadThread::deleteThumbnail((*it).toLocalFile());
01674         // clean LoadingCache as well - be pragmatic, do it here.
01675         LoadingCacheInterface::fileChanged((*it).toLocalFile());
01676     }
01677 
01678     emit signalItemsUpdated(urlList);
01679 
01680     // trigger a delayed rearrangement, in case we need to resort items
01681     triggerRearrangement();
01682 }
01683 
01684 void AlbumIconView::slotFileChanged(const QString& filePath)
01685 {
01686     if (!d->currentAlbum || filePath.isEmpty())
01687         return;
01688 
01689     KUrl url = KUrl::fromPath(filePath);
01690 
01691     AlbumIconItem* iconItem = findItem(url.url());
01692     if (!iconItem)
01693         return;
01694     iconItem->update();
01695 
01696     emit signalItemsUpdated(KUrl::List() << url);
01697 }
01698 
01699 void AlbumIconView::slotThumbnailLoaded(const LoadingDescription& loadingDescription, const QPixmap&)
01700 {
01701     AlbumIconItem* iconItem = findItem(KUrl::fromPath(loadingDescription.filePath).url());
01702     if (!iconItem)
01703         return;
01704 
01705     iconItem->update();
01706 }
01707 
01708 void AlbumIconView::prepareRepaint(const QList<IconItem *>& itemsToRepaint)
01709 {
01710     QStringList filePaths;
01711     foreach(IconItem *iconItem, itemsToRepaint)
01712     {
01713         AlbumIconItem *item = static_cast<AlbumIconItem *>(iconItem);
01714         filePaths << item->filePath();
01715     }
01716     ThumbnailLoadThread::defaultIconViewThread()->findGroup(filePaths);
01717 }
01718 
01719 void AlbumIconView::slotSelectionChanged()
01720 {
01721     if (firstSelectedItem())
01722         emitItemsSelected(true);
01723     else
01724         emitItemsSelected(false);
01725 }
01726 
01727 void AlbumIconView::slotSetExifOrientation( int orientation )
01728 {
01729     KUrl::List urlList;
01730     int i = 0;
01731 
01732     for (IconItem *it = firstItem(); it; it=it->nextItem())
01733     {
01734         if (it->isSelected())
01735         {
01736             AlbumIconItem *iconItem = static_cast<AlbumIconItem *>(it);
01737             urlList.append(iconItem->imageInfo().fileUrl());
01738         }
01739     }
01740 
01741     if (urlList.count() <= 0) return;
01742 
01743     QStringList failedItems;
01744     KUrl::List::Iterator it;
01745     float cnt = (float)urlList.count();
01746     emit signalProgressBarMode(StatusProgressBar::ProgressBarMode,
01747                                 i18n("Revising Exif Orientation tags. Please wait..."));
01748 
01749     for( it = urlList.begin(); it != urlList.end(); ++it )
01750     {
01751         kDebug() << "Setting Exif Orientation tag to " << orientation;
01752 
01753         DMetadata metadata((*it).toLocalFile());
01754         DMetadata::ImageOrientation o = (DMetadata::ImageOrientation)orientation;
01755         metadata.setImageOrientation(o);
01756         metadata.setWriteRawFiles(AlbumSettings::instance()->getWriteRawFiles());
01757 
01758         if (!metadata.applyChanges())
01759         {
01760             failedItems.append((*it).fileName());
01761         }
01762         else
01763         {
01764             ImageAttributesWatch::instance()->fileMetadataChanged((*it));
01765         }
01766 
01767         emit signalProgressValue((int)((i++/cnt)*100.0));
01768         kapp->processEvents();
01769     }
01770 
01771     emit signalProgressBarMode(StatusProgressBar::TextMode, QString());
01772 
01773     if (!failedItems.isEmpty())
01774     {
01775         if (failedItems.count() == 1)
01776         {
01777             KMessageBox::error(0, i18n("Failed to revise Exif orientation for file %1.",
01778                                        failedItems[0]));
01779         }
01780         else
01781         {
01782             KMessageBox::errorList(0, i18n("Failed to revise Exif orientation these files:"),
01783                                    failedItems);
01784         }
01785     }
01786 
01787     refreshItems(urlList);
01788 }
01789 
01790 QRect AlbumIconView::itemRect() const
01791 {
01792     return d->itemRect;
01793 }
01794 
01795 QRect AlbumIconView::itemRatingRect() const
01796 {
01797     return d->itemRatingRect;
01798 }
01799 
01800 QRect AlbumIconView::itemDateRect() const
01801 {
01802     return d->itemDateRect;
01803 }
01804 
01805 QRect AlbumIconView::itemModDateRect() const
01806 {
01807     return d->itemModDateRect;
01808 }
01809 
01810 QRect AlbumIconView::itemPixmapRect() const
01811 {
01812     return d->itemPixmapRect;
01813 }
01814 
01815 QRect AlbumIconView::itemNameRect() const
01816 {
01817     return d->itemNameRect;
01818 }
01819 
01820 QRect AlbumIconView::itemCommentsRect() const
01821 {
01822     return d->itemCommentsRect;
01823 }
01824 
01825 QRect AlbumIconView::itemResolutionRect() const
01826 {
01827     return d->itemResolutionRect;
01828 }
01829 
01830 QRect AlbumIconView::itemTagRect() const
01831 {
01832     return d->itemTagRect;
01833 }
01834 
01835 QRect AlbumIconView::itemSizeRect() const
01836 {
01837     return d->itemSizeRect;
01838 }
01839 
01840 QRect AlbumIconView::bannerRect() const
01841 {
01842     return d->bannerRect;
01843 }
01844 
01845 QPixmap AlbumIconView::itemBaseRegPixmap() const
01846 {
01847     return d->itemRegPixmap;
01848 }
01849 
01850 QPixmap AlbumIconView::itemBaseSelPixmap() const
01851 {
01852     return d->itemSelPixmap;
01853 }
01854 
01855 QPixmap AlbumIconView::bannerPixmap() const
01856 {
01857     return d->bannerPixmap;
01858 }
01859 
01860 QPixmap AlbumIconView::ratingPixmap(int rating, bool selected) const
01861 {
01862     if (rating < 1 || rating > 5)
01863     {
01864         QPixmap pix;
01865         if (selected)
01866             pix = d->itemSelPixmap.copy(d->itemRatingRect);
01867         else
01868             pix = d->itemRegPixmap.copy(d->itemRatingRect);
01869 
01870         return pix;
01871     }
01872 
01873     --rating;
01874     if (selected)
01875         return d->ratingPixmaps[5 + rating];
01876     else
01877         return d->ratingPixmaps[rating];
01878 }
01879 
01880 QFont AlbumIconView::itemFontReg() const
01881 {
01882     return d->fnReg;
01883 }
01884 
01885 QFont AlbumIconView::itemFontCom() const
01886 {
01887     return d->fnCom;
01888 }
01889 
01890 QFont AlbumIconView::itemFontXtra() const
01891 {
01892     return d->fnXtra;
01893 }
01894 
01895 void AlbumIconView::updateBannerRectPixmap()
01896 {
01897     d->bannerRect = QRect(0, 0, 0, 0);
01898 
01899     // Title --------------------------------------------------------
01900 
01901     QFont fn(font());
01902     int fnSize = fn.pointSize();
01903     bool usePointSize;
01904     if (fnSize > 0)
01905     {
01906         fn.setPointSize(fnSize+2);
01907         usePointSize = true;
01908     }
01909     else
01910     {
01911         fnSize = fn.pixelSize();
01912         fn.setPixelSize(fnSize+2);
01913         usePointSize = false;
01914     }
01915 
01916     fn.setBold(true);
01917     QFontMetrics fm(fn);
01918     QRect tr = fm.boundingRect(0, 0, frameRect().width(),
01919                                0xFFFFFFFF, Qt::AlignLeft | Qt::AlignVCenter,
01920                                "XXX");
01921     d->bannerRect.setHeight(tr.height());
01922 
01923     if (usePointSize)
01924         fn.setPointSize(font().pointSize());
01925     else
01926         fn.setPixelSize(font().pixelSize());
01927 
01928     fn.setBold(false);
01929     fm = QFontMetrics(fn);
01930 
01931     tr = fm.boundingRect(0, 0, frameRect().width(),
01932                          0xFFFFFFFF, Qt::AlignLeft | Qt::AlignVCenter,
01933                          "XXX");
01934 
01935     d->bannerRect.setHeight(d->bannerRect.height() + tr.height() + 10);
01936     d->bannerRect.setWidth(frameRect().width());
01937 
01938     d->bannerPixmap = ThemeEngine::instance()->bannerPixmap(d->bannerRect.width(),
01939                                                             d->bannerRect.height());
01940 }
01941 
01942 void AlbumIconView::updateRectsAndPixmaps()
01943 {
01944     updateBannerRectPixmap();
01945 
01946     d->itemRect           = QRect(0, 0, 0, 0);
01947     d->itemRatingRect     = QRect(0, 0, 0, 0);
01948     d->itemDateRect       = QRect(0, 0, 0, 0);
01949     d->itemModDateRect    = QRect(0, 0, 0, 0);
01950     d->itemPixmapRect     = QRect(0, 0, 0, 0);
01951     d->itemNameRect       = QRect(0, 0, 0, 0);
01952     d->itemCommentsRect   = QRect(0, 0, 0, 0);
01953     d->itemResolutionRect = QRect(0, 0, 0, 0);
01954     d->itemSizeRect       = QRect(0, 0, 0, 0);
01955     d->itemTagRect        = QRect(0, 0, 0, 0);
01956 
01957     d->fnReg  = font();
01958     d->fnCom  = font();
01959     d->fnXtra = font();
01960     d->fnCom.setItalic(true);
01961 
01962     int fnSz = d->fnReg.pointSize();
01963     if (fnSz > 0)
01964     {
01965         d->fnCom.setPointSize(fnSz-1);
01966         d->fnXtra.setPointSize(fnSz-2);
01967     }
01968     else
01969     {
01970         fnSz = d->fnReg.pixelSize();
01971         d->fnCom.setPixelSize(fnSz-1);
01972         d->fnXtra.setPixelSize(fnSz-2);
01973     }
01974 
01975     const int radius = 3;
01976     const int margin = 5;
01977     int w            = d->thumbSize.size() + 2*radius;
01978 
01979     QFontMetrics fm(d->fnReg);
01980     QRect oneRowRegRect = fm.boundingRect(0, 0, w, 0xFFFFFFFF,
01981                                           Qt::AlignTop | Qt::AlignHCenter,
01982                                           "XXXXXXXXX");
01983     fm = QFontMetrics(d->fnCom);
01984     QRect oneRowComRect = fm.boundingRect(0, 0, w, 0xFFFFFFFF,
01985                                           Qt::AlignTop | Qt::AlignHCenter,
01986                                           "XXXXXXXXX");
01987     fm = QFontMetrics(d->fnXtra);
01988     QRect oneRowXtraRect = fm.boundingRect(0, 0, w, 0xFFFFFFFF,
01989                                            Qt::AlignTop | Qt::AlignHCenter,
01990                                            "XXXXXXXXX");
01991 
01992     QSize starPolygonSize(15, 15);
01993 
01994     int y = margin;
01995 
01996     d->itemPixmapRect = QRect(margin, y, w, d->thumbSize.size() + 2*radius);
01997     y = d->itemPixmapRect.bottom();
01998 
01999     if (d->albumSettings->getIconShowRating())
02000     {
02001         d->itemRatingRect = QRect(margin, y, w, starPolygonSize.height());
02002         y = d->itemRatingRect.bottom();
02003     }
02004 
02005     if (d->albumSettings->getIconShowName())
02006     {
02007         d->itemNameRect = QRect(margin, y, w-margin, oneRowRegRect.height());
02008         y = d->itemNameRect.bottom();
02009     }
02010 
02011     if (d->albumSettings->getIconShowComments())
02012     {
02013         d->itemCommentsRect = QRect(margin, y, w, oneRowComRect.height());
02014         y = d->itemCommentsRect.bottom();
02015     }
02016 
02017     if (d->albumSettings->getIconShowDate())
02018     {
02019         d->itemDateRect = QRect(margin, y, w, oneRowXtraRect.height());
02020         y = d->itemDateRect.bottom();
02021     }
02022 
02023     if (d->albumSettings->getIconShowModDate())
02024     {
02025         d->itemModDateRect = QRect(margin, y, w, oneRowXtraRect.height());
02026         y = d->itemModDateRect.bottom();
02027     }
02028 
02029     if (d->albumSettings->getIconShowResolution())
02030     {
02031         d->itemResolutionRect = QRect(margin, y, w, oneRowXtraRect.height());
02032         y = d->itemResolutionRect.bottom() ;
02033     }
02034 
02035     if (d->albumSettings->getIconShowSize())
02036     {
02037         d->itemSizeRect = QRect(margin, y, w, oneRowXtraRect.height());
02038         y = d->itemSizeRect.bottom();
02039     }
02040 
02041     if (d->albumSettings->getIconShowTags())
02042     {
02043         d->itemTagRect = QRect(margin, y, w, oneRowComRect.height());
02044         y = d->itemTagRect.bottom();
02045     }
02046 
02047     d->itemRect      = QRect(0, 0, w + 2*margin, y+margin+radius);
02048 
02049     d->itemRegPixmap = ThemeEngine::instance()->thumbRegPixmap(d->itemRect.width(),
02050                                                                d->itemRect.height());
02051 
02052     d->itemSelPixmap = ThemeEngine::instance()->thumbSelPixmap(d->itemRect.width(),
02053                                                                d->itemRect.height());
02054 
02055     // -- Generate rating pixmaps ------------------------------------------
02056 
02057     // We use antialiasing and want to pre-render the pixmaps.
02058     // So we need the background at the time of painting,
02059     // and the background may be a gradient, and will be different for selected items.
02060     // This makes 5*2 (small) pixmaps.
02061     if (d->albumSettings->getIconShowRating())
02062     {
02063         for (int sel=0; sel<2; ++sel)
02064         {
02065             QPixmap basePix;
02066 
02067             // do this once for regular, once for selected backgrounds
02068             if (sel)
02069                 basePix = d->itemSelPixmap.copy(d->itemRatingRect);
02070             else
02071                 basePix = d->itemRegPixmap.copy(d->itemRatingRect);
02072 
02073             for (int rating=1; rating<=5; ++rating)
02074             {
02075                 // we store first the 5 regular, then the 5 selected pixmaps, for simplicity
02076                 int index = (sel * 5 + rating) - 1;
02077 
02078                 // copy background
02079                 d->ratingPixmaps[index] = basePix;
02080                 // open a painter
02081                 QPainter painter(&d->ratingPixmaps[index]);
02082 
02083                 // use antialiasing
02084                 painter.setRenderHint(QPainter::Antialiasing, true);
02085                 painter.setBrush(ThemeEngine::instance()->textSpecialRegColor());
02086                 QPen pen(ThemeEngine::instance()->textRegColor());
02087                 // set a pen which joins the lines at a filled angle
02088                 pen.setJoinStyle(Qt::MiterJoin);
02089                 painter.setPen(pen);
02090 
02091                 // move painter while drawing polygons
02092                 painter.translate( lround((d->itemRatingRect.width() - margin - rating*(starPolygonSize.width()+1))/2.0) + 2, 1 );
02093                 for (int s=0; s<rating; ++s)
02094                 {
02095                     painter.drawPolygon(d->starPolygon, Qt::WindingFill);
02096                     painter.translate(starPolygonSize.width() + 1, 0);
02097                 }
02098             }
02099         }
02100     }
02101 
02102     clearThumbnailBorderCache();
02103 }
02104 
02105 void AlbumIconView::slotThemeChanged()
02106 {
02107     updateRectsAndPixmaps();
02108     viewport()->update();
02109 }
02110 
02111 AlbumIconItem* AlbumIconView::findItem(const QPoint& pos)
02112 {
02113     return dynamic_cast<AlbumIconItem*>(IconView::findItem(pos));
02114 }
02115 
02116 AlbumIconItem* AlbumIconView::findItem(const QString& url) const
02117 {
02118     return d->itemDict.value(url);
02119 }
02120 
02121 AlbumIconItem* AlbumIconView::nextItemToThumbnail() const
02122 {
02123     QRect r(contentsX(), contentsY(), visibleWidth(), visibleHeight());
02124     IconItem *fItem = findFirstVisibleItem(r);
02125     IconItem *lItem = findLastVisibleItem(r);
02126     if (!fItem || !lItem)
02127         return 0;
02128 
02129     AlbumIconItem* firstItem = static_cast<AlbumIconItem*>(fItem);
02130     AlbumIconItem* lastItem  = static_cast<AlbumIconItem*>(lItem);
02131     AlbumIconItem* item      = firstItem;
02132     while (item)
02133     {
02134         if (item->isDirty())
02135             return item;
02136         if (item == lastItem)
02137             break;
02138         item = (AlbumIconItem*)item->nextItem();
02139     }
02140 
02141     return 0;
02142 }
02143 
02144 void AlbumIconView::slotAlbumModified()
02145 {
02146     d->imageLister->stop();
02147     clear();
02148 
02149     d->imageLister->openAlbum(d->currentAlbum);
02150 
02151     updateRectsAndPixmaps();
02152 }
02153 
02154 void AlbumIconView::slotGotoTag(int tagID)
02155 {
02156     // send a signal to the parent widget (digikamview.cpp) to change
02157     // to Tag view and the corresponding item
02158 
02159     emit signalGotoTagAndItem(tagID);
02160 }
02161 
02162 void AlbumIconView::slotAssignTag(int tagID)
02163 {
02164     slotChangeTagOnImageInfos(selectedImageInfosCurrentFirst(), QList<int>() << tagID, true, true);
02165 }
02166 
02167 void AlbumIconView::slotRemoveTag(int tagID)
02168 {
02169     slotChangeTagOnImageInfos(selectedImageInfosCurrentFirst(), QList<int>() << tagID, false, true);
02170 }
02171 
02172 void AlbumIconView::slotAssignRating(int rating)
02173 {
02174     emit signalProgressBarMode(StatusProgressBar::ProgressBarMode,
02175                                 i18n("Assigning image ratings. Please wait..."));
02176 
02177     int   i   = 0;
02178     float cnt = (float)countSelected();
02179     rating    = qMin(RatingMax, qMax(RatingMin, rating));
02180     MetadataHub hub;
02181 
02182     QList<ImageInfo> infos;
02183     for (IconItem *it = firstItem() ; it ; it = it->nextItem())
02184     {
02185         if (it->isSelected())
02186         {
02187             AlbumIconItem *albumItem = dynamic_cast<AlbumIconItem *>(it);
02188             if (albumItem)
02189                 infos << albumItem->imageInfo();
02190         }
02191     }
02192 
02193     d->imageLister->blockSignals(true);
02194     ScanController::instance()->suspendCollectionScan();
02195     DatabaseTransaction transaction;
02196     foreach (const ImageInfo& info, infos)
02197     {
02198         hub.load(info);
02199 
02200         hub.setRating(rating);
02201 
02202         QString filePath = info.filePath();
02203         hub.write(info, MetadataHub::PartialWrite);
02204         hub.write(info.filePath(), MetadataHub::FullWriteIfChanged);
02205         bool fileChanged = hub.write(filePath, MetadataHub::FullWriteIfChanged);
02206 
02207         if (fileChanged)
02208             ScanController::instance()->scanFileDirectly(filePath);
02209 
02210         emit signalProgressValue((int)((i++/cnt)*100.0));
02211         kapp->processEvents();
02212     }
02213     ScanController::instance()->resumeCollectionScan();
02214     d->imageLister->blockSignals(false);
02215 
02216     emit signalProgressBarMode(StatusProgressBar::TextMode, QString());
02217     updateContents();
02218 }
02219 
02220 void AlbumIconView::slotAssignRatingNoStar()
02221 {
02222     slotAssignRating(0);
02223 }
02224 
02225 void AlbumIconView::slotAssignRatingOneStar()
02226 {
02227     slotAssignRating(1);
02228 }
02229 
02230 void AlbumIconView::slotAssignRatingTwoStar()
02231 {
02232     slotAssignRating(2);
02233 }
02234 
02235 void AlbumIconView::slotAssignRatingThreeStar()
02236 {
02237     slotAssignRating(3);
02238 }
02239 
02240 void AlbumIconView::slotAssignRatingFourStar()
02241 {
02242     slotAssignRating(4);
02243 }
02244 
02245 void AlbumIconView::slotAssignRatingFiveStar()
02246 {
02247     slotAssignRating(5);
02248 }
02249 
02250 void AlbumIconView::slotDIOResult(KJob* kjob)
02251 {
02252     KIO::Job *job = static_cast<KIO::Job*>(kjob);
02253     if (job->error())
02254     {
02255         job->ui()->setWindow(this);
02256         job->ui()->showErrorMessage();
02257     }
02258 }
02259 
02260 void AlbumIconView::slotImageAttributesChanged(qlonglong imageId)
02261 {
02262     AlbumIconItem *firstItem = static_cast<AlbumIconItem *>(findFirstVisibleItem());
02263     AlbumIconItem *lastItem  = static_cast<AlbumIconItem *>(findLastVisibleItem());
02264     for (AlbumIconItem *item = firstItem; item;
02265          item = static_cast<AlbumIconItem *>(item->nextItem()))
02266     {
02267         if (item->imageInfo().id() == imageId)
02268         {
02269             updateContents();
02270             return;
02271         }
02272         if (item == lastItem)
02273             break;
02274     }
02275 }
02276 
02277 void AlbumIconView::slotAlbumImagesChanged(int /*albumId*/)
02278 {
02279     updateContents();
02280 }
02281 
02282 void AlbumIconView::slotEditRatingFromItem(int rating)
02283 {
02284     rating = qMin(RatingMax, qMax(RatingMin, rating));
02285 
02286     d->imageLister->blockSignals(true);
02287     ScanController::instance()->suspendCollectionScan();
02288     DatabaseTransaction transaction;
02289     AlbumIconItem *albumItem = dynamic_cast<AlbumIconItem*>(ratingItem());
02290     if (albumItem)
02291     {
02292         ImageInfo info = albumItem->imageInfo();
02293 
02294         MetadataHub hub;
02295         hub.load(info);
02296         hub.setRating(rating);
02297 
02298         QString filePath = info.filePath();
02299         hub.write(info, MetadataHub::PartialWrite);
02300         hub.write(info.filePath(), MetadataHub::FullWriteIfChanged);
02301         bool fileChanged = hub.write(filePath, MetadataHub::FullWriteIfChanged);
02302 
02303         if (fileChanged)
02304             ScanController::instance()->scanFileDirectly(filePath);
02305     }
02306 
02307     ScanController::instance()->resumeCollectionScan();
02308     d->imageLister->blockSignals(false);
02309     updateContents();
02310 }
02311 
02312 void AlbumIconView::slotMoveSelectionToAlbum()
02313 {
02314     KUrl::List kioURLs;
02315     QList<qlonglong> selectedImageIDs;
02316 
02317     for (IconItem *it = firstItem(); it; it=it->nextItem())
02318     {
02319         if (it->isSelected())
02320         {
02321             AlbumIconItem *selItem = static_cast<AlbumIconItem *>(it);
02322             selectedImageIDs.append(selItem->imageInfo().id());
02323             kioURLs.append(selItem->imageInfo().fileUrl());
02324         }
02325     }
02326 
02327     if (kioURLs.isEmpty() || selectedImageIDs.isEmpty())
02328         return;
02329 
02330     Album *album = AlbumManager::instance()->currentAlbum();
02331     if (album && album->type() != Album::PHYSICAL)
02332         album = 0;
02333 
02334     QString header(i18n("<p>Please select the destination album from the digiKam library to "
02335                         "move the selected images into.</p>"));
02336 
02337     album = AlbumSelectDialog::selectAlbum(this, (PAlbum*)album, header);
02338     if (!album) return;
02339 
02340     KIO::Job* job = DIO::move(kioURLs, selectedImageIDs, (PAlbum*)album);
02341     connect(job, SIGNAL(result(KJob*)),
02342             this, SLOT(slotDIOResult(KJob*)));
02343 }
02344 
02345 }  // namespace Digikam

digikam

Skip menu "digikam"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

API Reference

Skip menu "API Reference"
  • digikam
Generated for API Reference by doxygen 1.5.9-20090814
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal