diff options
Diffstat (limited to 'src/libs/imageproperties/talbumlistview.cpp')
-rw-r--r-- | src/libs/imageproperties/talbumlistview.cpp | 528 |
1 files changed, 528 insertions, 0 deletions
diff --git a/src/libs/imageproperties/talbumlistview.cpp b/src/libs/imageproperties/talbumlistview.cpp new file mode 100644 index 00000000..1369d228 --- /dev/null +++ b/src/libs/imageproperties/talbumlistview.cpp @@ -0,0 +1,528 @@ +/* ============================================================ + * + * 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 <tdepopupmenu.h> +#include <tdelocale.h> +#include <kurl.h> +#include <kcursor.h> +#include <tdeapplication.h> +#include <kiconloader.h> +#include <tdemessagebox.h> +#include <tdeconfig.h> +#include <tdeglobalsettings.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(), TQ_SIGNAL(signalTAlbumsDirty(const TQMap<int, int>&)), + this, TQ_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; + + TDEPopupMenu 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 + { + TDEPopupMenu 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 + { + TDEPopupMenu 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 |