|
|
|
/* ============================================================
|
|
|
|
*
|
|
|
|
* 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 <kconfig.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* tqparent, TAlbum* album)
|
|
|
|
: FolderCheckListItem(tqparent, album->title(), TQCheckListItem::RadioButtonController)
|
|
|
|
{
|
|
|
|
setDragEnabled(true);
|
|
|
|
m_album = album;
|
|
|
|
m_count = 0;
|
|
|
|
|
|
|
|
if (m_album)
|
|
|
|
m_album->setExtraData(listView(), this);
|
|
|
|
}
|
|
|
|
|
|
|
|
TAlbumCheckListItem::TAlbumCheckListItem(TQCheckListItem* tqparent, TAlbum* album)
|
|
|
|
: FolderCheckListItem(tqparent, 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*>(tqparent()))
|
|
|
|
{
|
|
|
|
if (isOpen())
|
|
|
|
setText(0, TQString("%1 (%2)").tqarg(m_album->title()).tqarg(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)").tqarg(m_album->title()).tqarg(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::settqStatus(MetadataHub::TagtqStatus 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* tqparent)
|
|
|
|
: FolderView(tqparent, "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->tqparent())
|
|
|
|
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 tqparent on its child makes no sense
|
|
|
|
if(itemDrag && itemDrag->album()->isAncestorOf(itemDrop->album()))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ItemDrag::canDecode(e) && itemDrop && itemDrop->album()->tqparent())
|
|
|
|
{
|
|
|
|
// 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->tqencodedData("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")
|
|
|
|
.tqarg(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()
|
|
|
|
{
|
|
|
|
KConfig *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()
|
|
|
|
{
|
|
|
|
KConfig *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
|