/* ============================================================ * * 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 * Copyright (C) 2009 by Andi Clemens * * 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 // KDE includes. #include #include #include #include #include #include #include #include #include #include // 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 } 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(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&)), this, TQT_SLOT(slotRefresh(const TQMap&))); } TAlbumListView::~TAlbumListView() { saveViewState(); } void TAlbumListView::stateChanged(TAlbumCheckListItem *item) { emit signalItemStateChanged(item); } TQDragObject* TAlbumListView::dragObject() { TAlbumCheckListItem *item = dynamic_cast(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(itemAt(vp)); TAlbumCheckListItem *itemDrag = dynamic_cast(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(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 albumIDs; TQValueList 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::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(*it); if (item) item->refresh(); ++it; } } void TAlbumListView::slotRefresh(const TQMap& tagsStatMap) { TQListViewItemIterator it(this); while (it.current()) { TAlbumCheckListItem* item = dynamic_cast(*it); if (item) { if (item->album()) { int id = item->id(); TQMap::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 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(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(selectedItem()); if(item) config->writeEntry("LastSelectedItem", item->id()); else config->writeEntry("LastSelectedItem", 0); TQValueList openFolders; TQListViewItemIterator it(this); for( ; it.current(); ++it) { item = dynamic_cast(it.current()); if(item && isOpen(item)) openFolders.push_back(item->id()); } config->writeEntry("OpenFolders", openFolders); } } // NameSpace Digikam