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/libs/imageproperties/talbumlistview.cpp

529 lines
14 KiB

/* ============================================================
*
* This file is a part of digiKam project
* http://www.digikam.org
*
* Date : 2006-18-12
* Description : A list view to display digiKam Tags.
*
* 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 <tqheader.h>
// KDE includes.
#include <kpopupmenu.h>
#include <klocale.h>
#include <kurl.h>
#include <kcursor.h>
#include <kapplication.h>
#include <kiconloader.h>
#include <kmessagebox.h>
#include <tdeconfig.h>
#include <kglobalsettings.h>
#include <kdialogbase.h>
// Local includes.
#include "ddebug.h"
#include "albumiconitem.h"
#include "albumlister.h"
#include "albummanager.h"
#include "albumdb.h"
#include "album.h"
#include "albumsettings.h"
#include "imageinfo.h"
#include "navigatebarwidget.h"
#include "dragobjects.h"
#include "imageattributeswatch.h"
#include "albumthumbnailloader.h"
#include "statusprogressbar.h"
#include "talbumlistview.h"
#include "talbumlistview.moc"
// X11 includes.
extern "C"
{
#include <X11/Xlib.h>
}
namespace Digikam
{
TAlbumCheckListItem::TAlbumCheckListItem(TQListView* parent, TAlbum* album)
: FolderCheckListItem(parent, album->title(), TQCheckListItem::RadioButtonController)
{
setDragEnabled(true);
m_album = album;
m_count = 0;
if (m_album)
m_album->setExtraData(listView(), this);
}
TAlbumCheckListItem::TAlbumCheckListItem(TQCheckListItem* parent, TAlbum* album)
: FolderCheckListItem(parent, album->title(), TQCheckListItem::CheckBox)
{
setDragEnabled(true);
m_album = album;
m_count = 0;
if (m_album)
m_album->setExtraData(listView(), this);
}
void TAlbumCheckListItem::refresh()
{
if (!m_album) return;
if (AlbumSettings::instance()->getShowFolderTreeViewItemsCount() &&
dynamic_cast<TAlbumCheckListItem*>(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() )
{
TAlbumCheckListItem *item = (TAlbumCheckListItem*)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 TAlbumCheckListItem::stateChange(bool val)
{
TQCheckListItem::stateChange(val);
((TAlbumListView*)listView())->stateChanged(this);
}
void TAlbumCheckListItem::setOpen(bool o)
{
TQListViewItem::setOpen(o);
refresh();
}
TAlbum* TAlbumCheckListItem::album() const
{
return m_album;
}
int TAlbumCheckListItem::id() const
{
return m_album ? m_album->id() : 0;
}
void TAlbumCheckListItem::setCount(int count)
{
m_count = count;
refresh();
}
int TAlbumCheckListItem::count()
{
return m_count;
}
void TAlbumCheckListItem::setStatus(MetadataHub::TagStatus status)
{
if (status == MetadataHub::MetadataDisjoint)
{
if (type() != TQCheckListItem::RadioButtonController) setTristate(true);
setState(TQCheckListItem::NoChange);
}
else
{
if (type() != TQCheckListItem::RadioButtonController) setTristate(false);
setOn(status.hasTag);
}
}
// ------------------------------------------------------------------------
TAlbumListView::TAlbumListView(TQWidget* parent)
: FolderView(parent, "TAlbumListView")
{
addColumn(i18n("Tags"));
header()->hide();
setResizeMode(TQListView::LastColumn);
setRootIsDecorated(true);
setAcceptDrops(true);
viewport()->setAcceptDrops(true);
connect(AlbumManager::instance(), TQT_SIGNAL(signalTAlbumsDirty(const TQMap<int, int>&)),
this, TQT_SLOT(slotRefresh(const TQMap<int, int>&)));
}
TAlbumListView::~TAlbumListView()
{
saveViewState();
}
void TAlbumListView::stateChanged(TAlbumCheckListItem *item)
{
emit signalItemStateChanged(item);
}
TQDragObject* TAlbumListView::dragObject()
{
TAlbumCheckListItem *item = dynamic_cast<TAlbumCheckListItem*>(dragItem());
if(!item)
return 0;
if(!item->parent())
return 0;
TagDrag *t = new TagDrag(item->id(), this);
t->setPixmap(*item->pixmap(0));
return t;
}
bool TAlbumListView::acceptDrop(const TQDropEvent *e) const
{
TQPoint vp = contentsToViewport(e->pos());
TAlbumCheckListItem *itemDrop = dynamic_cast<TAlbumCheckListItem*>(itemAt(vp));
TAlbumCheckListItem *itemDrag = dynamic_cast<TAlbumCheckListItem*>(dragItem());
if(TagDrag::canDecode(e) || TagListDrag::canDecode(e))
{
// Allow dragging at the root, to move the tag to 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;
}
if (ItemDrag::canDecode(e) && itemDrop && itemDrop->album()->parent())
{
// Only other possibility is image items being dropped
// And allow this only if there is a Tag to be dropped
// on and also the Tag is not root.
return true;
}
return false;
}
void TAlbumListView::contentsDropEvent(TQDropEvent *e)
{
TQListView::contentsDropEvent(e);
if(!acceptDrop(e))
return;
TQPoint vp = contentsToViewport(e->pos());
TAlbumCheckListItem *itemDrop = dynamic_cast<TAlbumCheckListItem*>(itemAt(vp));
if(TagDrag::canDecode(e))
{
TQByteArray ba = e->encodedData("digikam/tag-id");
TQDataStream ds(ba, IO_ReadOnly);
int tagID;
ds >> tagID;
AlbumManager* man = AlbumManager::instance();
TAlbum* talbum = man->findTAlbum(tagID);
if(!talbum)
return;
if (talbum == itemDrop->album())
return;
KPopupMenu popMenu(this);
popMenu.insertTitle(SmallIcon("digikam"), i18n("Tags"));
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)
{
TAlbum *newParentTag = 0;
if (!itemDrop)
{
// move dragItem to the root
newParentTag = AlbumManager::instance()->findTAlbum(0);
}
else
{
// move dragItem as child of dropItem
newParentTag = itemDrop->album();
}
TQString errMsg;
if (!AlbumManager::instance()->moveTAlbum(talbum, newParentTag, errMsg))
{
KMessageBox::error(this, errMsg);
}
if(itemDrop && !itemDrop->isOpen())
itemDrop->setOpen(true);
}
return;
}
if (ItemDrag::canDecode(e))
{
TAlbum *destAlbum = itemDrop->album();
TAlbum *srcAlbum;
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;
// all the albumids will be the same
int albumID = albumIDs.first();
srcAlbum = AlbumManager::instance()->findTAlbum(albumID);
if (!srcAlbum)
{
DWarning() << "Could not find source album of drag"
<< endl;
return;
}
int id = 0;
char keys_return[32];
XQueryKeymap(x11Display(), keys_return);
int key_1 = XKeysymToKeycode(x11Display(), 0xFFE3);
int key_2 = XKeysymToKeycode(x11Display(), 0xFFE4);
if(srcAlbum == destAlbum)
{
// 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
{
KPopupMenu popMenu(this);
popMenu.insertTitle(SmallIcon("digikam"), i18n("Tags"));
popMenu.insertItem(i18n("Set as Tag 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;
AlbumManager::instance()->updateTAlbumIcon(destAlbum, TQString(),
imageIDs.first(), errMsg);
}
return;
}
// If a ctrl key is pressed while dropping the drag object,
// the tag is assigned to the images without showing a
// popup menu.
if (((keys_return[key_1 / 8]) && (1 << (key_1 % 8))) ||
((keys_return[key_2 / 8]) && (1 << (key_2 % 8))))
{
id = 10;
}
else
{
KPopupMenu popMenu(this);
popMenu.insertTitle(SmallIcon("digikam"), i18n("Tags"));
popMenu.insertItem( SmallIcon("tag"), i18n("Assign Tag '%1' to Items")
.arg(destAlbum->prettyURL()), 10) ;
popMenu.insertSeparator(-1);
popMenu.insertItem( SmallIcon("cancel"), i18n("C&ancel") );
popMenu.setMouseTracking(true);
id = popMenu.exec(TQCursor::pos());
}
if (id == 10)
{
emit signalProgressBarMode(StatusProgressBar::ProgressBarMode,
i18n("Assign tag to images. Please wait..."));
AlbumLister::instance()->blockSignals(true);
AlbumManager::instance()->albumDB()->beginTransaction();
int i=0;
for (TQValueList<int>::const_iterator it = imageIDs.begin();
it != imageIDs.end(); ++it)
{
// create temporary ImageInfo object
ImageInfo info(*it);
MetadataHub hub;
hub.load(&info);
hub.setTag(destAlbum, true);
hub.write(&info, MetadataHub::PartialWrite);
hub.write(info.filePath(), MetadataHub::FullWriteIfChanged);
emit signalProgressValue((int)((i++/(float)imageIDs.count())*100.0));
kapp->processEvents();
}
AlbumLister::instance()->blockSignals(false);
AlbumManager::instance()->albumDB()->commitTransaction();
ImageAttributesWatch::instance()->imagesChanged(destAlbum->id());
emit signalProgressBarMode(StatusProgressBar::TextMode, TQString());
}
}
}
void TAlbumListView::refresh()
{
TQListViewItemIterator it(this);
while (it.current())
{
TAlbumCheckListItem* item = dynamic_cast<TAlbumCheckListItem*>(*it);
if (item)
item->refresh();
++it;
}
}
void TAlbumListView::slotRefresh(const TQMap<int, int>& tagsStatMap)
{
TQListViewItemIterator it(this);
while (it.current())
{
TAlbumCheckListItem* item = dynamic_cast<TAlbumCheckListItem*>(*it);
if (item)
{
if (item->album())
{
int id = item->id();
TQMap<int, int>::const_iterator it2 = tagsStatMap.find(id);
if ( it2 != tagsStatMap.end() )
item->setCount(it2.data());
}
}
++it;
}
refresh();
}
void TAlbumListView::loadViewState()
{
TDEConfig *config = kapp->config();
config->setGroup(name());
int selectedItem = config->readNumEntry("LastSelectedItem", 0);
TQValueList<int> openFolders;
if(config->hasKey("OpenFolders"))
{
openFolders = config->readIntListEntry("OpenFolders");
}
TAlbumCheckListItem *item = 0;
TAlbumCheckListItem *foundItem = 0;
TQListViewItemIterator it(this->lastItem());
for( ; it.current(); --it)
{
item = dynamic_cast<TAlbumCheckListItem*>(it.current());
if(!item)
continue;
// Start the album root always open
if(openFolders.contains(item->id()) || item->id() == 0)
setOpen(item, true);
else
setOpen(item, false);
if(item->id() == selectedItem)
{
// Save the found selected item so that it can be made visible.
foundItem = item;
}
}
// Important note: this cannot be done inside the previous loop
// because opening folders prevents the visibility.
// Fixes bug #144815.
// (Looks a bit like a bug in TQt to me ...)
if (foundItem)
{
setSelected(foundItem, true);
ensureItemVisible(foundItem);
}
}
void TAlbumListView::saveViewState()
{
TDEConfig *config = kapp->config();
config->setGroup(name());
TAlbumCheckListItem *item = dynamic_cast<TAlbumCheckListItem*>(selectedItem());
if(item)
config->writeEntry("LastSelectedItem", item->id());
else
config->writeEntry("LastSelectedItem", 0);
TQValueList<int> openFolders;
TQListViewItemIterator it(this);
for( ; it.current(); ++it)
{
item = dynamic_cast<TAlbumCheckListItem*>(it.current());
if(item && isOpen(item))
openFolders.push_back(item->id());
}
config->writeEntry("OpenFolders", openFolders);
}
} // NameSpace Digikam