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/albumfolderview.cpp

1637 lines
44 KiB

/* ============================================================
*
* This file is a part of digiKam project
* http://www.digikam.org
*
* Date : 2005-05-06
* Description : Albums folder view.
*
* Copyright (C) 2005-2006 by Joern Ahrens <joern.ahrens@kdemail.net>
* Copyright (C) 2006-2009 by Gilles Caulier <caulier dot gilles at gmail dot com>
* Copyright (C) 2009 by Andi Clemens <andi dot clemens at gmx dot net>
*
* 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.
*
* ============================================================ */
// TQt includes.
#include <tqpixmap.h>
#include <tqguardedptr.h>
#include <tqdir.h>
#include <tdepopupmenu.h>
#include <tqcursor.h>
#include <tqdatastream.h>
#include <tqvaluelist.h>
#include <tqdatetime.h>
// KDE includes.
#include <tdelocale.h>
#include <tdeglobal.h>
#include <kcalendarsystem.h>
#include <kiconloader.h>
#include <tdeapplication.h>
#include <tdemessagebox.h>
#include <tdeaction.h>
#include <tdefiledialog.h>
#include <tdeversion.h>
#if KDE_IS_VERSION(3,2,0)
#include <kinputdialog.h>
#else
#include <klineeditdlg.h>
#endif
// Local includes.
#include "ddebug.h"
#include "digikamapp.h"
#include "albumlister.h"
#include "album.h"
#include "albumdb.h"
#include "albumpropsedit.h"
#include "albummanager.h"
#include "albumsettings.h"
#include "thumbnailjob.h"
#include "thumbnailsize.h"
#include "folderitem.h"
#include "cameraui.h"
#include "dio.h"
#include "dragobjects.h"
#include "albumthumbnailloader.h"
#include "deletedialog.h"
#include "albumfolderview.h"
#include "albumfolderview.moc"
// X11 C Ansi includes.
extern "C"
{
#include <X11/Xlib.h>
}
namespace Digikam
{
class AlbumFolderViewItem : public FolderItem
{
public:
AlbumFolderViewItem(TQListView *parent, PAlbum *album);
AlbumFolderViewItem(TQListViewItem *parent, PAlbum *album);
// special group item (collection/dates)
AlbumFolderViewItem(TQListViewItem* parent, const TQString& name,
int year, int month);
PAlbum* album() const;
int id() const;
bool isGroupItem() const;
int compare(TQListViewItem *i, int col, bool ascending) const;
void refresh();
void setOpen(bool o);
void setCount(int count);
int count();
private:
bool m_groupItem;
int m_count;
int m_year;
int m_month;
PAlbum *m_album;
};
AlbumFolderViewItem::AlbumFolderViewItem(TQListView *parent, PAlbum *album)
: FolderItem(parent, album->title())
{
setDragEnabled(true);
m_album = album;
m_groupItem = false;
m_count = 0;
}
AlbumFolderViewItem::AlbumFolderViewItem(TQListViewItem *parent, PAlbum *album)
: FolderItem(parent, album->title())
{
setDragEnabled(true);
m_album = album;
m_groupItem = false;
m_count = 0;
}
// special group item (collection/dates)
AlbumFolderViewItem::AlbumFolderViewItem(TQListViewItem* parent, const TQString& name,
int year, int month)
: FolderItem(parent, name, true)
{
m_album = 0;
m_year = year;
m_month = month;
m_groupItem = true;
m_count = 0;
}
void AlbumFolderViewItem::refresh()
{
if (!m_album) return;
if (AlbumSettings::instance()->getShowFolderTreeViewItemsCount() &&
dynamic_cast<AlbumFolderViewItem*>(parent()))
{
if (isOpen())
setText(0, TQString("%1 (%2)").arg(m_album->title()).arg(m_count));
else
{
int countRecursive = m_count;
AlbumIterator it(m_album);
while ( it.current() )
{
AlbumFolderViewItem *item = (AlbumFolderViewItem*)it.current()->extraData(listView());
if (item)
countRecursive += item->count();
++it;
}
setText(0, TQString("%1 (%2)").arg(m_album->title()).arg(countRecursive));
}
}
else
{
setText(0, m_album->title());
}
}
void AlbumFolderViewItem::setOpen(bool o)
{
TQListViewItem::setOpen(o);
refresh();
}
PAlbum* AlbumFolderViewItem::album() const
{
return m_album;
}
int AlbumFolderViewItem::id() const
{
if (m_groupItem)
{
if (m_year != 0 && m_month != 0)
{
return (m_year*(-100) + m_month*(-1));
}
else
{
return ( - (AlbumSettings::instance()->getAlbumCollectionNames()
.findIndex(text(0)) ) );
}
}
else
{
return m_album ? m_album->id() : 0;
}
}
bool AlbumFolderViewItem::isGroupItem() const
{
return m_groupItem;
}
int AlbumFolderViewItem::compare(TQListViewItem *i, int col, bool ascending) const
{
if (!m_groupItem || m_year == 0 || m_month == 0)
return TQListViewItem::compare(i, col, ascending);
AlbumFolderViewItem* thatItem = dynamic_cast<AlbumFolderViewItem*>(i);
if (!thatItem)
return 0;
int myWeight = m_year*100 + m_month;
int hisWeight = thatItem->m_year*100 + thatItem->m_month;
if (myWeight == hisWeight)
return 0;
else if (myWeight > hisWeight)
return 1;
else
return -1;
}
void AlbumFolderViewItem::setCount(int count)
{
m_count = count;
refresh();
}
int AlbumFolderViewItem::count()
{
return m_count;
}
// -----------------------------------------------------------------------------
class AlbumFolderViewPriv
{
public:
AlbumFolderViewPriv()
{
albumMan = 0;
iconThumbJob = 0;
}
AlbumManager *albumMan;
ThumbnailJob *iconThumbJob;
TQValueList<AlbumFolderViewItem*> groupItems;
};
AlbumFolderView::AlbumFolderView(TQWidget *parent)
: FolderView(parent, "AlbumFolderView")
{
d = new AlbumFolderViewPriv();
d->albumMan = AlbumManager::instance();
d->iconThumbJob = 0;
addColumn(i18n("My Albums"));
setResizeMode(TQListView::LastColumn);
setRootIsDecorated(false);
setAllColumnsShowFocus(true);
setAcceptDrops(true);
viewport()->setAcceptDrops(true);
connect(d->albumMan, TQ_SIGNAL(signalAlbumAdded(Album*)),
this, TQ_SLOT(slotAlbumAdded(Album*)));
connect(d->albumMan, TQ_SIGNAL(signalAlbumDeleted(Album*)),
this, TQ_SLOT(slotAlbumDeleted(Album*)));
connect(d->albumMan, TQ_SIGNAL(signalAlbumsCleared()),
this, TQ_SLOT(slotAlbumsCleared()));
connect(d->albumMan, TQ_SIGNAL(signalAlbumIconChanged(Album*)),
this, TQ_SLOT(slotAlbumIconChanged(Album*)));
connect(d->albumMan, TQ_SIGNAL(signalAlbumRenamed(Album*)),
this, TQ_SLOT(slotAlbumRenamed(Album*)));
connect(d->albumMan, TQ_SIGNAL(signalPAlbumsDirty(const TQMap<int, int>&)),
this, TQ_SLOT(slotRefresh(const TQMap<int, int>&)));
AlbumThumbnailLoader *loader = AlbumThumbnailLoader::instance();
connect(loader, TQ_SIGNAL(signalThumbnail(Album *, const TQPixmap&)),
this, TQ_SLOT(slotGotThumbnailFromIcon(Album *, const TQPixmap&)));
connect(loader, TQ_SIGNAL(signalFailed(Album *)),
this, TQ_SLOT(slotThumbnailLost(Album *)));
connect(loader, TQ_SIGNAL(signalReloadThumbnails()),
this, TQ_SLOT(slotReloadThumbnails()));
connect(this, TQ_SIGNAL(contextMenuRequested(TQListViewItem*, const TQPoint&, int)),
this, TQ_SLOT(slotContextMenu(TQListViewItem*, const TQPoint&, int)));
connect(this, TQ_SIGNAL(selectionChanged()),
this, TQ_SLOT(slotSelectionChanged()));
}
AlbumFolderView::~AlbumFolderView()
{
if (d->iconThumbJob)
d->iconThumbJob->kill();
saveViewState();
delete d;
}
void AlbumFolderView::slotTextFolderFilterChanged(const TQString& filter)
{
if (filter.isEmpty())
{
collapseView();
return;
}
TQString search = filter.lower();
bool atleastOneMatch = false;
AlbumList pList = d->albumMan->allPAlbums();
for (AlbumList::iterator it = pList.begin(); it != pList.end(); ++it)
{
PAlbum* palbum = (PAlbum*)(*it);
// don't touch the root Album
if (palbum->isRoot())
continue;
bool match = palbum->title().lower().contains(search);
bool doesExpand = false;
if (!match)
{
// check if any of the parents match the search
Album* parent = palbum->parent();
while (parent && !parent->isRoot())
{
if (parent->title().lower().contains(search))
{
match = true;
break;
}
parent = parent->parent();
}
}
if (!match)
{
// check if any of the children match the search
AlbumIterator it(palbum);
while (it.current())
{
if ((*it)->title().lower().contains(search))
{
match = true;
doesExpand = true;
break;
}
++it;
}
}
AlbumFolderViewItem* viewItem = (AlbumFolderViewItem*) palbum->extraData(this);
if (match)
{
atleastOneMatch = true;
if (viewItem)
{
viewItem->setVisible(true);
viewItem->setOpen(doesExpand);
}
}
else
{
if (viewItem)
{
viewItem->setVisible(false);
viewItem->setOpen(false);
}
}
}
emit signalTextFolderFilterMatch(atleastOneMatch);
}
void AlbumFolderView::slotAlbumAdded(Album *album)
{
if(!album)
return;
PAlbum *palbum = dynamic_cast<PAlbum*>(album);
if(!palbum)
return;
bool failed;
AlbumFolderViewItem* parent = findParent(palbum, failed);
if (failed)
{
DWarning() << k_funcinfo << " Failed to find Album parent "
<< palbum->url() << endl;
return;
}
AlbumFolderViewItem *item;
if (!parent)
{
// root album
item = new AlbumFolderViewItem(this, palbum);
palbum->setExtraData(this, item);
item->setOpen(true);
}
else
{
item = new AlbumFolderViewItem(parent, palbum);
palbum->setExtraData(this, item);
}
setAlbumThumbnail(palbum);
}
void AlbumFolderView::slotAlbumDeleted(Album *album)
{
if(!album)
return;
PAlbum* palbum = dynamic_cast<PAlbum*>(album);
if(!palbum)
return;
if(!palbum->icon().isEmpty() && d->iconThumbJob)
d->iconThumbJob->removeItem(palbum->icon());
AlbumFolderViewItem* item = (AlbumFolderViewItem*) palbum->extraData(this);
if(item)
{
AlbumFolderViewItem *itemParent = dynamic_cast<AlbumFolderViewItem*>(item->parent());
if(itemParent)
itemParent->takeItem(item);
else
takeItem(item);
delete item;
clearEmptyGroupItems();
}
}
void AlbumFolderView::slotAlbumRenamed(Album *album)
{
PAlbum* palbum = dynamic_cast<PAlbum*>(album);
if(!palbum)
return;
AlbumFolderViewItem* item = (AlbumFolderViewItem*) palbum->extraData(this);
if(item)
item->refresh();
if (item->parent())
item->parent()->sort();
}
void AlbumFolderView::slotAlbumsCleared()
{
d->groupItems.clear();
clear();
}
void AlbumFolderView::setAlbumThumbnail(PAlbum *album)
{
if(!album)
return;
AlbumFolderViewItem* item = (AlbumFolderViewItem*) album->extraData(this);
if(!item)
return;
// Either, getThumbnail returns true and loads an icon asynchronously.
// Then, for the time being, we set the standard icon.
// Or, no icon is associated with the album, then we set the standard icon anyway.
AlbumThumbnailLoader *loader = AlbumThumbnailLoader::instance();
item->setPixmap(0, loader->getStandardAlbumIcon(album));
loader->getAlbumThumbnail(album);
}
void AlbumFolderView::setCurrentAlbum(Album *album)
{
if(!album) return;
AlbumFolderViewItem* item = (AlbumFolderViewItem*) album->extraData(this);
if(!item) return;
setCurrentItem(item);
ensureItemVisible(item);
}
void AlbumFolderView::slotGotThumbnailFromIcon(Album *album,
const TQPixmap& thumbnail)
{
if(!album || album->type() != Album::PHYSICAL)
return;
AlbumFolderViewItem* item = (AlbumFolderViewItem*)album->extraData(this);
if(!item)
return;
item->setPixmap(0, thumbnail);
}
void AlbumFolderView::slotThumbnailLost(Album *)
{
// we already set the standard icon before loading
}
void AlbumFolderView::slotReloadThumbnails()
{
AlbumList tList = d->albumMan->allPAlbums();
for (AlbumList::iterator it = tList.begin(); it != tList.end(); ++it)
{
PAlbum* album = (PAlbum*)(*it);
setAlbumThumbnail(album);
}
}
void AlbumFolderView::slotAlbumIconChanged(Album* album)
{
if(!album || album->type() != Album::PHYSICAL)
return;
setAlbumThumbnail((PAlbum*)album);
}
void AlbumFolderView::slotSelectionChanged()
{
if (!active())
return;
TQListViewItem* selItem = 0;
TQListViewItemIterator it(this);
while(it.current())
{
if(it.current()->isSelected())
{
selItem = it.current();
break;
}
++it;
}
if(!selItem)
{
d->albumMan->setCurrentAlbum(0);
return;
}
AlbumFolderViewItem *albumitem = dynamic_cast<AlbumFolderViewItem*>(selItem);
if(!albumitem)
{
d->albumMan->setCurrentAlbum(0);
return;
}
d->albumMan->setCurrentAlbum(albumitem->album());
}
void AlbumFolderView::slotContextMenu(TQListViewItem *listitem, const TQPoint &, int)
{
TDEActionMenu menuImport(i18n("Import"));
TDEActionMenu menuExport(i18n("Export"));
TDEActionMenu menuKIPIBatch(i18n("Batch Process"));
TDEPopupMenu popmenu(this);
popmenu.insertTitle(SmallIcon("digikam"), i18n("My Albums"));
popmenu.insertItem(SmallIcon("albumfolder-new"), i18n("New Album..."), 10);
AlbumFolderViewItem *item = dynamic_cast<AlbumFolderViewItem*>(listitem);
if (item && !item->album())
{
// if collection/date return
return;
}
// Root folder only shows "New Album..."
if(item && item->parent())
{
popmenu.insertItem(SmallIcon("pencil"), i18n("Rename..."), 14);
popmenu.insertItem(SmallIcon("albumfolder-properties"), i18n("Album Properties..."), 11);
popmenu.insertItem(SmallIcon("reload_page"), i18n("Reset Album Icon"), 13);
popmenu.insertSeparator();
// Add KIPI Albums plugins Actions
TDEAction *action;
const TQPtrList<TDEAction>& albumActions = DigikamApp::getinstance()->menuAlbumActions();
if(!albumActions.isEmpty())
{
TQPtrListIterator<TDEAction> it(albumActions);
while((action = it.current()))
{
action->plug(&popmenu);
++it;
}
}
// Add All Import Actions
const TQPtrList<TDEAction> importActions = DigikamApp::getinstance()->menuImportActions();
if(!importActions.isEmpty())
{
TQPtrListIterator<TDEAction> it3(importActions);
while((action = it3.current()))
{
menuImport.insert(action);
++it3;
}
menuImport.plug(&popmenu);
}
// Add All Export Actions
const TQPtrList<TDEAction> exportActions = DigikamApp::getinstance()->menuExportActions();
if(!exportActions.isEmpty())
{
TQPtrListIterator<TDEAction> it4(exportActions);
while((action = it4.current()))
{
menuExport.insert(action);
++it4;
}
menuExport.plug(&popmenu);
}
// Add KIPI Batch processes plugins Actions
const TQPtrList<TDEAction>& batchActions = DigikamApp::getinstance()->menuBatchActions();
if(!batchActions.isEmpty())
{
TQPtrListIterator<TDEAction> it2(batchActions);
while((action = it2.current()))
{
menuKIPIBatch.insert(action);
++it2;
}
menuKIPIBatch.plug(&popmenu);
}
if(!albumActions.isEmpty() || !batchActions.isEmpty() ||
!importActions.isEmpty())
{
popmenu.insertSeparator(-1);
}
if(AlbumSettings::instance()->getUseTrash())
{
popmenu.insertItem(SmallIcon("edittrash"),
i18n("Move Album to Trash"), 12);
}
else
{
popmenu.insertItem(SmallIcon("edit-delete"),
i18n("Delete Album"), 12);
}
}
switch(popmenu.exec((TQCursor::pos())))
{
case 10:
{
albumNew(item);
break;
}
case 11:
{
albumEdit(item);
break;
}
case 12:
{
albumDelete(item);
break;
}
case 13:
{
TQString err;
d->albumMan->updatePAlbumIcon(item->album(), 0, err);
break;
}
case 14:
{
albumRename(item);
break;
}
default:
break;
}
}
void AlbumFolderView::albumNew()
{
AlbumFolderViewItem *item = dynamic_cast<AlbumFolderViewItem*>(selectedItem());
if (!item)
{
item = dynamic_cast<AlbumFolderViewItem*>(firstChild());
}
if (!item)
return;
albumNew(item);
}
void AlbumFolderView::albumNew(AlbumFolderViewItem *item)
{
AlbumSettings* settings = AlbumSettings::instance();
if(!settings)
{
DWarning() << "AlbumFolderView: Couldn't get Album Settings" << endl;
return;
}
TQDir libraryDir(settings->getAlbumLibraryPath());
if(!libraryDir.exists())
{
KMessageBox::error(0,
i18n("The album library has not been set correctly.\n"
"Select \"Configure Digikam\" from the Settings "
"menu and choose a folder to use for the album "
"library."));
return;
}
PAlbum *parent;
if(!item)
parent = d->albumMan->findPAlbum(0);
else
parent = item->album();
if (!parent)
return;
TQString title;
TQString comments;
TQString collection;
TQDate date;
TQStringList albumCollections;
if(!AlbumPropsEdit::createNew(parent, title, comments, date, collection,
albumCollections))
return;
TQStringList oldAlbumCollections(AlbumSettings::instance()->getAlbumCollectionNames());
if(albumCollections != oldAlbumCollections)
{
AlbumSettings::instance()->setAlbumCollectionNames(albumCollections);
resort();
}
TQString errMsg;
PAlbum* album = d->albumMan->createPAlbum(parent, title, comments,
date, collection, errMsg);
if (!album)
{
KMessageBox::error(0, errMsg);
return;
}
// by this time the signalAlbumAdded has been fired and the appropriate
// AlbumFolderViewItem has been created. Now make this folderviewitem visible
AlbumFolderViewItem* newItem = (AlbumFolderViewItem*)album->extraData(this);
if (newItem)
{
if(item)
item->setOpen(true);
ensureItemVisible(newItem);
}
}
void AlbumFolderView::albumDelete()
{
AlbumFolderViewItem *item = dynamic_cast<AlbumFolderViewItem*>(selectedItem());
if(!item)
return;
albumDelete(item);
}
void AlbumFolderView::albumDelete(AlbumFolderViewItem *item)
{
PAlbum *album = item->album();
if(!album || album->isRoot())
return;
// find subalbums
KURL::List childrenList;
addAlbumChildrenToList(childrenList, album);
DeleteDialog dialog(this);
// All subalbums will be presented in the list as well
if (!dialog.confirmDeleteList(childrenList,
childrenList.size() == 1 ?
DeleteDialogMode::Albums : DeleteDialogMode::Subalbums,
DeleteDialogMode::UserPreference))
return;
bool useTrash = !dialog.shouldDelete();
// Currently trash tdeioslave can handle only full paths.
// pass full folder path to the trashing job
KURL u;
u.setProtocol("file");
u.setPath(album->folderPath());
TDEIO::Job* job = DIO::del(u, useTrash);
connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
this, TQ_SLOT(slotDIOResult(TDEIO::Job *)));
}
void AlbumFolderView::addAlbumChildrenToList(KURL::List &list, Album *album)
{
// simple recursive helper function
if (album)
{
list.append(album->kurl());
AlbumIterator it(album);
while(it.current())
{
addAlbumChildrenToList(list, *it);
++it;
}
}
}
void AlbumFolderView::slotDIOResult(TDEIO::Job* job)
{
if (job->error())
job->showErrorDialog(this);
}
void AlbumFolderView::albumRename()
{
AlbumFolderViewItem *item = dynamic_cast<AlbumFolderViewItem*>(selectedItem());
if(!item)
return;
albumRename(item);
}
void AlbumFolderView::albumRename(AlbumFolderViewItem* item)
{
PAlbum *album = item->album();
if (!album)
return;
TQString oldTitle(album->title());
bool ok;
#if KDE_IS_VERSION(3,2,0)
TQString title = KInputDialog::getText(i18n("Rename Album (%1)").arg(oldTitle),
i18n("Enter new album name:"),
oldTitle, &ok, this);
#else
TQString title = KLineEditDlg::getText(i18n("Rename Item (%1)").arg(oldTitle),
i18n("Enter new album name:"),
oldTitle, &ok, this);
#endif
if (!ok)
return;
if(title != oldTitle)
{
TQString errMsg;
if (!d->albumMan->renamePAlbum(album, title, errMsg))
KMessageBox::error(0, errMsg);
}
emit signalAlbumModified();
}
void AlbumFolderView::albumEdit()
{
AlbumFolderViewItem *item = dynamic_cast<AlbumFolderViewItem*>(selectedItem());
if(!item)
return;
albumEdit(item);
}
void AlbumFolderView::albumEdit(AlbumFolderViewItem* item)
{
PAlbum *album = item->album();
if (!album)
return;
TQString oldTitle(album->title());
TQString oldComments(album->caption());
TQString oldCollection(album->collection());
TQDate oldDate(album->date());
TQStringList oldAlbumCollections(AlbumSettings::instance()->getAlbumCollectionNames());
TQString title, comments, collection;
TQDate date;
TQStringList albumCollections;
if(AlbumPropsEdit::editProps(album, title, comments, date,
collection, albumCollections))
{
if(comments != oldComments)
album->setCaption(comments);
if(date != oldDate && date.isValid())
album->setDate(date);
if(collection != oldCollection)
album->setCollection(collection);
AlbumSettings::instance()->setAlbumCollectionNames(albumCollections);
resort();
// Do this last : so that if anything else changed we can
// successfuly save to the db with the old name
if(title != oldTitle)
{
TQString errMsg;
if (!d->albumMan->renamePAlbum(album, title, errMsg))
KMessageBox::error(0, errMsg);
}
emit signalAlbumModified();
}
}
TQDragObject* AlbumFolderView::dragObject()
{
AlbumFolderViewItem *item = dynamic_cast<AlbumFolderViewItem*>(dragItem());
if(!item)
return 0;
PAlbum *album = item->album();
if(album->isRoot())
return 0;
AlbumDrag *a = new AlbumDrag(album->kurl(), album->id(), this);
if(!a)
return 0;
a->setPixmap(*item->pixmap(0));
return a;
}
bool AlbumFolderView::acceptDrop(const TQDropEvent *e) const
{
TQPoint vp = contentsToViewport(e->pos());
AlbumFolderViewItem *itemDrop = dynamic_cast<AlbumFolderViewItem*>(itemAt(vp));
AlbumFolderViewItem *itemDrag = dynamic_cast<AlbumFolderViewItem*>(dragItem());
if(AlbumDrag::canDecode(e))
{
switch(AlbumSettings::instance()->getAlbumSortOrder())
{
case(AlbumSettings::ByFolder):
{
// Allow dragging at the root, to move the album at the root
if(!itemDrop)
return true;
// Dragging an item on itself makes no sense
if(itemDrag == itemDrop)
return false;
// Dragging a parent on its child makes no sense
if(itemDrag && itemDrag->album()->isAncestorOf(itemDrop->album()))
return false;
return true;
}
case (AlbumSettings::ByCollection):
{
if (!itemDrop)
return false;
// Only allow dragging onto Collection
if (itemDrop->isGroupItem())
return true;
return false;
}
default:
{
return false;
}
}
}
if(itemDrop && !itemDrop->parent())
{
// Do not allow drop images on album root
return false;
}
if (itemDrop && itemDrop->isGroupItem())
{
// do not allow drop on a group item
return false;
}
if(ItemDrag::canDecode(e))
{
return true;
}
if (CameraItemListDrag::canDecode(e))
{
return true;
}
if(TQUriDrag::canDecode(e))
{
return true;
}
return false;
}
void AlbumFolderView::contentsDropEvent(TQDropEvent *e)
{
FolderView::contentsDropEvent(e);
if(!acceptDrop(e))
return;
TQPoint vp = contentsToViewport(e->pos());
AlbumFolderViewItem *itemDrop = dynamic_cast<AlbumFolderViewItem*>(itemAt(vp));
if(AlbumDrag::canDecode(e))
{
AlbumFolderViewItem *itemDrag = dynamic_cast<AlbumFolderViewItem*>(dragItem());
if(!itemDrag)
return;
if (AlbumSettings::instance()->getAlbumSortOrder()
== AlbumSettings::ByFolder)
{
// TODO: Copy?
TDEPopupMenu popMenu(this);
popMenu.insertTitle(SmallIcon("digikam"), i18n("My Albums"));
popMenu.insertItem(SmallIcon("goto"), i18n("&Move Here"), 10);
popMenu.insertSeparator(-1);
popMenu.insertItem(SmallIcon("cancel"), i18n("C&ancel"), 20);
popMenu.setMouseTracking(true);
int id = popMenu.exec(TQCursor::pos());
if(id == 10)
{
PAlbum *album = itemDrag->album();
PAlbum *destAlbum;
if(!itemDrop)
{
// move dragItem to the root
destAlbum = d->albumMan->findPAlbum(0);
}
else
{
// move dragItem below dropItem
destAlbum = itemDrop->album();
}
TDEIO::Job* job = DIO::move(album->kurl(), destAlbum->kurl());
connect(job, TQ_SIGNAL(result(TDEIO::Job*)),
this, TQ_SLOT(slotDIOResult(TDEIO::Job*)));
}
}
else if (AlbumSettings::instance()->getAlbumSortOrder()
== AlbumSettings::ByCollection)
{
if (!itemDrop)
return;
if (itemDrop->isGroupItem())
{
PAlbum *album = itemDrag->album();
if (!album)
return;
album->setCollection(itemDrop->text(0));
resort();
}
}
return;
}
if (ItemDrag::canDecode(e))
{
if (!itemDrop)
return;
PAlbum *destAlbum = itemDrop->album();
KURL::List urls;
KURL::List kioURLs;
TQValueList<int> albumIDs;
TQValueList<int> imageIDs;
if (!ItemDrag::decode(e, urls, kioURLs, albumIDs, imageIDs))
return;
if (urls.isEmpty() || kioURLs.isEmpty() || albumIDs.isEmpty() || imageIDs.isEmpty())
return;
// Check if items dropped come from outside current album.
// This can be the case with reccursive content album mode.
KURL::List extUrls;
ImageInfoList extImgInfList;
for (TQValueList<int>::iterator it = imageIDs.begin(); it != imageIDs.end(); ++it)
{
ImageInfo *info = new ImageInfo(*it);
if (info->albumID() != destAlbum->id())
{
extUrls.append(info->kurlForKIO());
extImgInfList.append(info);
}
}
int id = 0;
char keys_return[32];
XQueryKeymap(x11Display(), keys_return);
int key_1 = XKeysymToKeycode(x11Display(), 0xFFE3);
int key_2 = XKeysymToKeycode(x11Display(), 0xFFE4);
int key_3 = XKeysymToKeycode(x11Display(), 0xFFE1);
int key_4 = XKeysymToKeycode(x11Display(), 0xFFE2);
if(extUrls.isEmpty())
{
// Setting the dropped image as the album thumbnail
// If the ctrl key is pressed, when dropping the image, the
// thumbnail is set without a popup menu
if (((keys_return[key_1 / 8]) && (1 << (key_1 % 8))) ||
((keys_return[key_2 / 8]) && (1 << (key_2 % 8))))
{
id = 12;
}
else
{
TDEPopupMenu popMenu(this);
popMenu.insertTitle(SmallIcon("digikam"), i18n("My Albums"));
popMenu.insertItem(i18n("Set as Album Thumbnail"), 12);
popMenu.insertSeparator(-1);
popMenu.insertItem( SmallIcon("cancel"), i18n("C&ancel") );
popMenu.setMouseTracking(true);
id = popMenu.exec(TQCursor::pos());
}
if(id == 12)
{
TQString errMsg;
d->albumMan->updatePAlbumIcon(destAlbum, imageIDs.first(), errMsg);
}
return;
}
// If shift key is pressed while dragging, move the drag object without
// displaying popup menu -> move
if (((keys_return[key_3 / 8]) && (1 << (key_3 % 8))) ||
((keys_return[key_4 / 8]) && (1 << (key_4 % 8))))
{
id = 10;
}
// If ctrl key is pressed while dragging, copy the drag object without
// displaying popup menu -> copy
else if (((keys_return[key_1 / 8]) && (1 << (key_1 % 8))) ||
((keys_return[key_2 / 8]) && (1 << (key_2 % 8))))
{
id = 11;
}
else
{
TDEPopupMenu popMenu(this);
popMenu.insertTitle(SmallIcon("digikam"), i18n("My Albums"));
popMenu.insertItem( SmallIcon("goto"), i18n("&Move Here"), 10 );
popMenu.insertItem( SmallIcon("edit-copy"), i18n("&Copy Here"), 11 );
if (imageIDs.count() == 1)
popMenu.insertItem(i18n("Set as Album Thumbnail"), 12);
popMenu.insertSeparator(-1);
popMenu.insertItem( SmallIcon("cancel"), i18n("C&ancel") );
popMenu.setMouseTracking(true);
id = popMenu.exec(TQCursor::pos());
}
switch(id)
{
case 10:
{
TDEIO::Job* job = DIO::move(extUrls, destAlbum->kurl());
connect(job, TQ_SIGNAL(result(TDEIO::Job*)),
this, TQ_SLOT(slotDIOResult(TDEIO::Job*)));
// In recurssive album contents mode, we need to force AlbumLister to take a care about
// moved items. This will have no incidence in normal mode.
ImageInfo* item;
for (ImageInfoListIterator it(extImgInfList); (item = it.current()) ; ++it)
{
AlbumLister::instance()->invalidateItem(item);
}
break;
}
case 11:
{
TDEIO::Job* job = DIO::copy(extUrls, destAlbum->kurl());
connect(job, TQ_SIGNAL(result(TDEIO::Job*)),
this, TQ_SLOT(slotDIOResult(TDEIO::Job*)));
break;
}
case 12:
{
TQString errMsg;
d->albumMan->updatePAlbumIcon(destAlbum, imageIDs.first(), errMsg);
}
default:
break;
}
return;
}
// -- DnD from Camera GUI ------------------------------------------------
if(CameraItemListDrag::canDecode(e))
{
Album *album = dynamic_cast<Album*>(itemDrop->album());
if (!album) return;
CameraUI *ui = dynamic_cast<CameraUI*>(e->source());
if (ui)
{
TDEPopupMenu popMenu(this);
popMenu.insertTitle(SmallIcon("digikam"), i18n("My Albums"));
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;
}
}
}
// -- DnD from an external source ----------------------------------------
if(TQUriDrag::canDecode(e))
{
PAlbum* destAlbum = 0;
if (itemDrop)
destAlbum = itemDrop->album();
else
destAlbum = d->albumMan->findPAlbum(0);
// B.K.O #119205: do not handle root album.
if (destAlbum->isRoot())
return;
KURL destURL(destAlbum->kurl());
KURL::List srcURLs;
KURLDrag::decode(e, srcURLs);
char keys_return[32];
XQueryKeymap(x11Display(), keys_return);
int id = 0;
int key_1 = XKeysymToKeycode(x11Display(), 0xFFE3);
int key_2 = XKeysymToKeycode(x11Display(), 0xFFE4);
int key_3 = XKeysymToKeycode(x11Display(), 0xFFE1);
int key_4 = XKeysymToKeycode(x11Display(), 0xFFE2);
// If shift key is pressed while dropping, move the drag object without
// displaying popup menu -> move
if(((keys_return[key_3 / 8]) && (1 << (key_3 % 8))) ||
((keys_return[key_4 / 8]) && (1 << (key_4 % 8))))
{
id = 10;
}
// If ctrl key is pressed while dropping, copy the drag object without
// displaying popup menu -> copy
else if(((keys_return[key_1 / 8]) && (1 << (key_1 % 8))) ||
((keys_return[key_2 / 8]) && (1 << (key_2 % 8))))
{
id = 11;
}
else
{
TDEPopupMenu popMenu(this);
popMenu.insertTitle(SmallIcon("digikam"), i18n("My Albums"));
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);
id = popMenu.exec(TQCursor::pos());
}
switch(id)
{
case 10:
{
TDEIO::Job* job = DIO::move(srcURLs, destAlbum->kurl());
connect(job, TQ_SIGNAL(result(TDEIO::Job*)),
this, TQ_SLOT(slotDIOResult(TDEIO::Job*)));
break;
}
case 11:
{
TDEIO::Job* job = DIO::copy(srcURLs, destAlbum->kurl());
connect(job, TQ_SIGNAL(result(TDEIO::Job*)),
this, TQ_SLOT(slotDIOResult(TDEIO::Job*)));
break;
}
default:
break;
}
return;
}
}
void AlbumFolderView::albumImportFolder()
{
AlbumSettings* settings = AlbumSettings::instance();
TQDir libraryDir(settings->getAlbumLibraryPath());
if(!libraryDir.exists())
{
KMessageBox::error(0,
i18n("The album library has not been set correctly.\n"
"Select \"Configure digiKam\" from the Settings "
"menu and choose a folder to use for the album "
"library."));
return;
}
PAlbum* parent = 0;
if(selectedItem())
{
AlbumFolderViewItem *folderItem = dynamic_cast<AlbumFolderViewItem*>(selectedItem());
Album *album = folderItem->album();
if (album && album->type() == Album::PHYSICAL)
{
parent = dynamic_cast<PAlbum*>(album);
}
}
if(!parent)
parent = dynamic_cast<PAlbum*>(d->albumMan->findPAlbum(0));
TQString libraryPath = parent->folderPath();
KFileDialog dlg(TQString(), "inode/directory", this, "importFolder", true);
dlg.setCaption(i18n("Select folders to import"));
dlg.setMode(KFile::Directory | KFile::Files);
if(dlg.exec() != TQDialog::Accepted)
return;
KURL::List urls = dlg.selectedURLs();
if(urls.empty())
return;
TDEIO::Job* job = DIO::copy(urls, parent->kurl());
connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
this, TQ_SLOT(slotDIOResult(TDEIO::Job *)));
}
void AlbumFolderView::selectItem(int id)
{
PAlbum* album = d->albumMan->findPAlbum(id);
if(!album)
return;
AlbumFolderViewItem *item = (AlbumFolderViewItem*)album->extraData(this);
if(item)
{
setSelected(item, true);
ensureItemVisible(item);
}
}
AlbumFolderViewItem* AlbumFolderView::findParent(PAlbum* album, bool& failed)
{
if (album->isRoot())
{
failed = false;
return 0;
}
switch(AlbumSettings::instance()->getAlbumSortOrder())
{
case(AlbumSettings::ByFolder):
{
return findParentByFolder(album, failed);
}
case(AlbumSettings::ByCollection):
{
return findParentByCollection(album, failed);
}
case(AlbumSettings::ByDate):
{
return findParentByDate(album, failed);
}
}
failed = true;
return 0;
}
AlbumFolderViewItem* AlbumFolderView::findParentByFolder(PAlbum* album, bool& failed)
{
AlbumFolderViewItem* parent =
(AlbumFolderViewItem*) album->parent()->extraData(this);
if (!parent)
{
failed = true;
return 0;
}
failed = false;
return parent;
}
AlbumFolderViewItem* AlbumFolderView::findParentByCollection(PAlbum* album, bool& failed)
{
TQStringList collectionList = AlbumSettings::instance()->getAlbumCollectionNames();
TQString collection = album->collection();
if (collection.isEmpty() || !collectionList.contains(collection))
collection = i18n("Uncategorized Albums");
AlbumFolderViewItem* parent = 0;
for (TQValueList<AlbumFolderViewItem*>::iterator it=d->groupItems.begin();
it != d->groupItems.end(); ++it)
{
AlbumFolderViewItem* groupItem = *it;
if (groupItem->text(0) == collection)
{
parent = groupItem;
break;
}
}
// Need to create a new parent item
if (!parent)
{
parent = new AlbumFolderViewItem(firstChild(), collection, 0, 0);
d->groupItems.append(parent);
}
failed = false;
return parent;
}
AlbumFolderViewItem* AlbumFolderView::findParentByDate(PAlbum* album, bool& failed)
{
TQDate date = album->date();
TQString timeString = TQString::number(date.year()) + ", " +
TDEGlobal::locale()->calendar()->monthName(date, false);
AlbumFolderViewItem* parent = 0;
for (TQValueList<AlbumFolderViewItem*>::iterator it=d->groupItems.begin();
it != d->groupItems.end(); ++it)
{
AlbumFolderViewItem* groupItem = *it;
if (groupItem->text(0) == timeString)
{
parent = groupItem;
break;
}
}
// Need to create a new parent item
if (!parent)
{
parent = new AlbumFolderViewItem(firstChild(), timeString,
date.year(), date.month());
d->groupItems.append(parent);
}
failed = false;
return parent;
}
void AlbumFolderView::resort()
{
AlbumFolderViewItem* prevSelectedItem = dynamic_cast<AlbumFolderViewItem*>(selectedItem());
if (prevSelectedItem && prevSelectedItem->isGroupItem())
prevSelectedItem = 0;
AlbumList pList(d->albumMan->allPAlbums());
for (AlbumList::iterator it = pList.begin(); it != pList.end(); ++it)
{
PAlbum *album = (PAlbum*)(*it);
if (!album->isRoot() && album->extraData(this))
{
reparentItem(static_cast<AlbumFolderViewItem*>(album->extraData(this)));
}
}
// Clear any groupitems which have been left empty
clearEmptyGroupItems();
if (prevSelectedItem)
{
ensureItemVisible(prevSelectedItem);
setSelected(prevSelectedItem, true);
}
}
void AlbumFolderView::reparentItem(AlbumFolderViewItem* folderItem)
{
if (!folderItem)
return;
PAlbum* album = folderItem->album();
if (!album || album->isRoot())
return;
AlbumFolderViewItem* oldParent = dynamic_cast<AlbumFolderViewItem*>(folderItem->parent());
bool failed;
AlbumFolderViewItem* newParent = findParent(album, failed);
if (failed)
return;
if (oldParent == newParent)
return;
if (oldParent)
oldParent->removeItem(folderItem);
else
removeItem(folderItem);
// insert into new parent
if (newParent)
newParent->insertItem(folderItem);
else
insertItem(folderItem);
}
void AlbumFolderView::clearEmptyGroupItems()
{
TQValueList<AlbumFolderViewItem*> deleteItems;
for (TQValueList<AlbumFolderViewItem*>::iterator it=d->groupItems.begin();
it != d->groupItems.end(); ++it)
{
AlbumFolderViewItem* groupItem = *it;
if (!groupItem->firstChild())
{
deleteItems.append(groupItem);
}
}
for (TQValueList<AlbumFolderViewItem*>::iterator it=deleteItems.begin();
it != deleteItems.end(); ++it)
{
d->groupItems.remove(*it);
delete *it;
}
}
void AlbumFolderView::refresh()
{
TQListViewItemIterator it(this);
while (it.current())
{
AlbumFolderViewItem* item = dynamic_cast<AlbumFolderViewItem*>(*it);
if (item)
item->refresh();
++it;
}
}
void AlbumFolderView::slotRefresh(const TQMap<int, int>& albumsStatMap)
{
TQListViewItemIterator it(this);
while (it.current())
{
AlbumFolderViewItem* item = dynamic_cast<AlbumFolderViewItem*>(*it);
if (item)
{
if (item->album())
{
int id = item->id();
TQMap<int, int>::const_iterator it2 = albumsStatMap.find(id);
if ( it2 != albumsStatMap.end() )
item->setCount(it2.data());
}
}
++it;
}
refresh();
}
} // namespace Digikam