/* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2005-05-05 * Description : tags filter view * * Copyright (C) 2005 by Renchi Raju * 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 #include #include #include #include // KDE includes. #include #include #include #include #include #include #include #include #include // Local includes. #include "ddebug.h" #include "albummanager.h" #include "albumsettings.h" #include "albumdb.h" #include "album.h" #include "albumlister.h" #include "albumthumbnailloader.h" #include "syncjob.h" #include "dragobjects.h" #include "folderitem.h" #include "imageattributeswatch.h" #include "imageinfo.h" #include "metadatahub.h" #include "tageditdlg.h" #include "statusprogressbar.h" #include "tagfilterview.h" #include "tagfilterview.moc" // X11 includes. extern "C" { #include } namespace Digikam { class TagFilterViewItem : public FolderCheckListItem { public: TagFilterViewItem(TQListView* parent, TAlbum* tag, bool untagged=false); TagFilterViewItem(TQListViewItem* parent, TAlbum* tag); TAlbum* album() const; int id() const; bool untagged() const; void refresh(); void setOpen(bool o); void setCount(int count); int count(); int compare(TQListViewItem* i, int column, bool ascending) const; private: void stateChange(bool val); void paintCell(TQPainter* p, const TQColorGroup & cg, int column, int width, int align); private: bool m_untagged; int m_count; TAlbum *m_album; }; TagFilterViewItem::TagFilterViewItem(TQListView* parent, TAlbum* album, bool untagged) : FolderCheckListItem(parent, album ? album->title() : i18n("Not Tagged"), TQCheckListItem::CheckBox/*Controller*/) { m_album = album; m_untagged = untagged; m_count = 0; setDragEnabled(!untagged); if (m_album) m_album->setExtraData(listView(), this); } TagFilterViewItem::TagFilterViewItem(TQListViewItem* parent, TAlbum* album) : FolderCheckListItem(parent, album->title(), TQCheckListItem::CheckBox/*Controller*/) { m_album = album; m_untagged = false; m_count = 0; setDragEnabled(true); if (m_album) m_album->setExtraData(listView(), this); } void TagFilterViewItem::refresh() { if (!m_album) return; if (AlbumSettings::instance()->getShowFolderTreeViewItemsCount()) { 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() ) { TagFilterViewItem *item = (TagFilterViewItem*)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 TagFilterViewItem::stateChange(bool val) { TQCheckListItem::stateChange(val); /* NOTE G.Caulier 2007/01/08: this code is now disable because TagFilterViewItem have been changed from TQCheckListItem::CheckBoxController to TQCheckListItem::CheckBox. // All TagFilterViewItems are CheckBoxControllers. If they have no children, // they should be of type CheckBox, but that is not possible with our way of adding items. // When clicked, children-less items first change to the NoChange state, and a second // click is necessary to set them to On and make the filter take effect. // So set them to On if the condition is met. if (!firstChild() && state() == NoChange) { setState(On); } */ ((TagFilterView*)listView())->stateChanged(this); } int TagFilterViewItem::compare(TQListViewItem* i, int column, bool ascending) const { if (m_untagged) return 1; TagFilterViewItem* dItem = dynamic_cast(i); if (!dItem) return 0; if (dItem && dItem->m_untagged) return -1; return TQListViewItem::compare(i, column, ascending); } void TagFilterViewItem::paintCell(TQPainter* p, const TQColorGroup & cg, int column, int width, int align) { if (!m_untagged) { FolderCheckListItem::paintCell(p, cg, column, width, align); return; } TQFont f(listView()->font()); f.setBold(true); f.setItalic(true); p->setFont(f); TQColorGroup mcg(cg); mcg.setColor(TQColorGroup::Text, TQt::darkRed); FolderCheckListItem::paintCell(p, mcg, column, width, align); } void TagFilterViewItem::setOpen(bool o) { TQListViewItem::setOpen(o); refresh(); } TAlbum* TagFilterViewItem::album() const { return m_album; } int TagFilterViewItem::id() const { return m_album ? m_album->id() : 0; } void TagFilterViewItem::setCount(int count) { m_count = count; refresh(); } int TagFilterViewItem::count() { return m_count; } bool TagFilterViewItem::untagged() const { return m_untagged; } // --------------------------------------------------------------------- class TagFilterViewPrivate { public: TagFilterViewPrivate() { ABCMenu = 0; timer = 0; toggleAutoTags = TagFilterView::NoToggleAuto; matchingCond = AlbumLister::OrCondition; } TQTimer *timer; TQPopupMenu *ABCMenu; TagFilterView::ToggleAutoTags toggleAutoTags; AlbumLister::MatchingCondition matchingCond; }; TagFilterView::TagFilterView(TQWidget* parent) : FolderView(parent, "TagFilterView") { d = new TagFilterViewPrivate; d->timer = new TQTimer(this); addColumn(i18n("Tag Filters")); setResizeMode(TQListView::LastColumn); setRootIsDecorated(true); setAcceptDrops(true); viewport()->setAcceptDrops(true); TagFilterViewItem* notTaggedItem = new TagFilterViewItem(this, 0, true); notTaggedItem->setPixmap(0, AlbumThumbnailLoader::instance()->getStandardTagIcon()); // ------------------------------------------------------------------------ connect(AlbumManager::instance(), TQT_SIGNAL(signalTAlbumsDirty(const TQMap&)), this, TQT_SLOT(slotRefresh(const TQMap&))); connect(AlbumManager::instance(), TQT_SIGNAL(signalAlbumAdded(Album*)), this, TQT_SLOT(slotTagAdded(Album*))); connect(AlbumManager::instance(), TQT_SIGNAL(signalAlbumDeleted(Album*)), this, TQT_SLOT(slotTagDeleted(Album*))); connect(AlbumManager::instance(), TQT_SIGNAL(signalAlbumRenamed(Album*)), this, TQT_SLOT(slotTagRenamed(Album*))); connect(AlbumManager::instance(), TQT_SIGNAL(signalAlbumsCleared()), this, TQT_SLOT(slotClear())); connect(AlbumManager::instance(), TQT_SIGNAL(signalAlbumIconChanged(Album*)), this, TQT_SLOT(slotAlbumIconChanged(Album*))); connect(AlbumManager::instance(), TQT_SIGNAL(signalTAlbumMoved(TAlbum*, TAlbum*)), this, TQT_SLOT(slotTagMoved(TAlbum*, TAlbum*))); // ------------------------------------------------------------------------ AlbumThumbnailLoader *loader = AlbumThumbnailLoader::instance(); connect(loader, TQT_SIGNAL(signalThumbnail(Album *, const TQPixmap&)), this, TQT_SLOT(slotGotThumbnailFromIcon(Album *, const TQPixmap&))); connect(loader, TQT_SIGNAL(signalFailed(Album *)), this, TQT_SLOT(slotThumbnailLost(Album *))); connect(loader, TQT_SIGNAL(signalReloadThumbnails()), this, TQT_SLOT(slotReloadThumbnails())); connect(this, TQT_SIGNAL(contextMenuRequested(TQListViewItem*, const TQPoint&, int)), this, TQT_SLOT(slotContextMenu(TQListViewItem*, const TQPoint&, int))); connect(d->timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotTimeOut())); // ------------------------------------------------------------------------ TDEConfig* config = kapp->config(); config->setGroup("Tag Filters View"); d->matchingCond = (AlbumLister::MatchingCondition)(config->readNumEntry("Matching Condition", AlbumLister::OrCondition)); d->toggleAutoTags = (ToggleAutoTags)(config->readNumEntry("Toggle Auto Tags", NoToggleAuto)); } TagFilterView::~TagFilterView() { TDEConfig* config = kapp->config(); config->setGroup("Tag Filters View"); config->writeEntry("Matching Condition", (int)(d->matchingCond)); config->writeEntry("Toggle Auto Tags", (int)(d->toggleAutoTags)); config->sync(); saveViewState(); delete d->timer; delete d; } void TagFilterView::slotTextTagFilterChanged(const TQString& filter) { if (filter.isEmpty()) { collapseView(); return; } TQString search = filter.lower(); bool atleastOneMatch = false; AlbumList tList = AlbumManager::instance()->allTAlbums(); for (AlbumList::iterator it = tList.begin(); it != tList.end(); ++it) { TAlbum* talbum = (TAlbum*)(*it); // don't touch the root Album if (talbum->isRoot()) continue; bool match = talbum->title().lower().contains(search); bool doesExpand = false; if (!match) { // check if any of the parents match the search Album* parent = talbum->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(talbum); while (it.current()) { if ((*it)->title().lower().contains(search)) { match = true; doesExpand = true; break; } ++it; } } TagFilterViewItem* viewItem = (TagFilterViewItem*) talbum->extraData(this); if (match) { atleastOneMatch = true; if (viewItem) { viewItem->setVisible(true); viewItem->setOpen(doesExpand); } } else { if (viewItem) { viewItem->setVisible(false); viewItem->setOpen(false); } } } emit signalTextTagFilterMatch(atleastOneMatch); } void TagFilterView::stateChanged(TagFilterViewItem* item) { ToggleAutoTags oldAutoTags = d->toggleAutoTags; switch(d->toggleAutoTags) { case Children: d->toggleAutoTags = TagFilterView::NoToggleAuto; toggleChildTags(item, item->isOn()); d->toggleAutoTags = oldAutoTags; break; case Parents: d->toggleAutoTags = TagFilterView::NoToggleAuto; toggleParentTags(item, item->isOn()); d->toggleAutoTags = oldAutoTags; break; case ChildrenAndParents: d->toggleAutoTags = TagFilterView::NoToggleAuto; toggleChildTags(item, item->isOn()); toggleParentTags(item, item->isOn()); d->toggleAutoTags = oldAutoTags; break; default: break; } triggerChange(); } void TagFilterView::triggerChange() { d->timer->start(50, true); } TQDragObject* TagFilterView::dragObject() { TagFilterViewItem *item = dynamic_cast(dragItem()); if(!item) return 0; TagDrag *t = new TagDrag(item->id(), this); t->setPixmap(*item->pixmap(0)); return t; } bool TagFilterView::acceptDrop(const TQDropEvent *e) const { TQPoint vp = contentsToViewport(e->pos()); TagFilterViewItem *itemDrop = dynamic_cast(itemAt(vp)); TagFilterViewItem *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; // Do not allow dragging at the "Not Tagged" item. if (itemDrop->untagged()) return false; // 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->untagged()) { TAlbum *tag = itemDrop->album(); if (tag) { if (tag->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 or "Not Tagged" item. return true; } } } return false; } void TagFilterView::contentsDropEvent(TQDropEvent *e) { FolderView::contentsDropEvent(e); if (!acceptDrop(e)) return; TQPoint vp = contentsToViewport(e->pos()); TagFilterViewItem *itemDrop = dynamic_cast(itemAt(vp)); if (!itemDrop || itemDrop->untagged()) return; 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("Tag Filters")); 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(); 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; int id = 0; char keys_return[32]; XQueryKeymap(x11Display(), keys_return); int key_1 = XKeysymToKeycode(x11Display(), 0xFFE3); int key_2 = XKeysymToKeycode(x11Display(), 0xFFE4); // 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("Tag Filters")); popMenu.insertItem(SmallIcon("tag"), i18n("Assign Tag '%1' to Items") .arg(destAlbum->prettyURL()), 10) ; popMenu.insertItem(i18n("Set as Tag Thumbnail"), 11); 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("Assigning image tags. 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()); } else if(id == 11) { TQString errMsg; AlbumManager::instance()->updateTAlbumIcon(destAlbum, TQString(), imageIDs.first(), errMsg); } } } void TagFilterView::slotTagAdded(Album* album) { if (!album || album->isRoot()) return; TAlbum* tag = dynamic_cast(album); if (!tag) return; if (tag->parent()->isRoot()) { new TagFilterViewItem(this, tag); } else { TagFilterViewItem* parent = (TagFilterViewItem*)(tag->parent()->extraData(this)); if (!parent) { DWarning() << k_funcinfo << " Failed to find parent for Tag " << tag->tagPath() << endl; return; } new TagFilterViewItem(parent, tag); } setTagThumbnail(tag); } void TagFilterView::slotTagRenamed(Album* album) { if (!album) return; TAlbum* tag = dynamic_cast(album); if (!tag) return; TagFilterViewItem* item = (TagFilterViewItem*)(tag->extraData(this)); if (item) item->refresh(); } void TagFilterView::slotTagMoved(TAlbum* tag, TAlbum* newParent) { if (!tag || !newParent) return; TagFilterViewItem* item = (TagFilterViewItem*)(tag->extraData(this)); if (!item) return; if (item->parent()) { TQListViewItem* oldPItem = item->parent(); oldPItem->takeItem(item); TagFilterViewItem* newPItem = (TagFilterViewItem*)(newParent->extraData(this)); if (newPItem) newPItem->insertItem(item); else insertItem(item); } else { takeItem(item); TagFilterViewItem* newPItem = (TagFilterViewItem*)(newParent->extraData(this)); if (newPItem) newPItem->insertItem(item); else insertItem(item); } } void TagFilterView::slotTagDeleted(Album* album) { if (!album || album->isRoot()) return; TAlbum* tag = dynamic_cast(album); if (!tag) return; TagFilterViewItem* item = (TagFilterViewItem*)(album->extraData(this)); if (!item) return; // NOTE: see B.K.O #158558: unselected tag filter and all childrens before to delete it. toggleChildTags(item, false); item->setOn(false); album->removeExtraData(this); delete item; } void TagFilterView::setTagThumbnail(TAlbum *album) { if(!album) return; TagFilterViewItem* item = (TagFilterViewItem*) album->extraData(this); if(!item) return; AlbumThumbnailLoader *loader = AlbumThumbnailLoader::instance(); TQPixmap icon; if (!loader->getTagThumbnail(album, icon)) { if (icon.isNull()) { item->setPixmap(0, loader->getStandardTagIcon(album)); } else { TQPixmap blendedIcon = loader->blendIcons(loader->getStandardTagIcon(), icon); item->setPixmap(0, blendedIcon); } } else { // for the time being, set standard icon item->setPixmap(0, loader->getStandardTagIcon(album)); } } void TagFilterView::slotGotThumbnailFromIcon(Album *album, const TQPixmap& thumbnail) { if(!album || album->type() != Album::TAG) return; TagFilterViewItem* item = (TagFilterViewItem*)album->extraData(this); if(!item) return; AlbumThumbnailLoader *loader = AlbumThumbnailLoader::instance(); TQPixmap blendedIcon = loader->blendIcons(loader->getStandardTagIcon(), thumbnail); item->setPixmap(0, blendedIcon); } void TagFilterView::slotThumbnailLost(Album *) { // we already set the standard icon before loading } void TagFilterView::slotReloadThumbnails() { AlbumList tList = AlbumManager::instance()->allTAlbums(); for (AlbumList::iterator it = tList.begin(); it != tList.end(); ++it) { TAlbum* tag = (TAlbum*)(*it); setTagThumbnail(tag); } } void TagFilterView::slotAlbumIconChanged(Album* album) { if(!album || album->type() != Album::TAG) return; setTagThumbnail((TAlbum *)album); } void TagFilterView::slotClear() { clear(); TagFilterViewItem* notTaggedItem = new TagFilterViewItem(this, 0, true); notTaggedItem->setPixmap(0, AlbumThumbnailLoader::instance()->getStandardTagIcon()); } void TagFilterView::slotTimeOut() { TQValueList filterTags; bool showUnTagged = false; TQListViewItemIterator it(this, TQListViewItemIterator::Checked); while (it.current()) { TagFilterViewItem* item = (TagFilterViewItem*)it.current(); if (item->album()) filterTags.append(item->album()->id()); else if (item->untagged()) showUnTagged = true; ++it; } AlbumLister::instance()->setTagFilter(filterTags, d->matchingCond, showUnTagged); } void TagFilterView::slotContextMenu(TQListViewItem* it, const TQPoint&, int) { TagFilterViewItem *item = dynamic_cast(it); if (item && item->untagged()) return; d->ABCMenu = new TQPopupMenu; connect(d->ABCMenu, TQT_SIGNAL( aboutToShow() ), this, TQT_SLOT( slotABCContextMenu() )); KPopupMenu popmenu(this); popmenu.insertTitle(SmallIcon("digikam"), i18n("Tag Filters")); popmenu.insertItem(SmallIcon("tag-new"), i18n("New Tag..."), 10); popmenu.insertItem(SmallIcon("tag-addressbook"), i18n("Create Tag From AddressBook"), d->ABCMenu); if (item) { popmenu.insertItem(SmallIcon("tag-properties"), i18n("Edit Tag Properties..."), 11); popmenu.insertItem(SmallIcon("tag-reset"), i18n("Reset Tag Icon"), 13); popmenu.insertSeparator(-1); popmenu.insertItem(SmallIcon("tag-delete"), i18n("Delete Tag"), 12); } popmenu.insertSeparator(-1); TQPopupMenu selectTagsMenu; selectTagsMenu.insertItem(i18n("All Tags"), 14); if (item) { selectTagsMenu.insertSeparator(-1); selectTagsMenu.insertItem(i18n("Children"), 17); selectTagsMenu.insertItem(i18n("Parents"), 19); } popmenu.insertItem(i18n("Select"), &selectTagsMenu); TQPopupMenu deselectTagsMenu; deselectTagsMenu.insertItem(i18n("All Tags"), 15); if (item) { deselectTagsMenu.insertSeparator(-1); deselectTagsMenu.insertItem(i18n("Children"), 18); deselectTagsMenu.insertItem(i18n("Parents"), 20); } popmenu.insertItem(i18n("Deselect"), &deselectTagsMenu); popmenu.insertItem(i18n("Invert Selection"), 16); popmenu.insertSeparator(-1); TQPopupMenu toggleAutoMenu; toggleAutoMenu.setCheckable(true); toggleAutoMenu.insertItem(i18n("None"), 21); toggleAutoMenu.insertSeparator(-1); toggleAutoMenu.insertItem(i18n("Children"), 22); toggleAutoMenu.insertItem(i18n("Parents"), 23); toggleAutoMenu.insertItem(i18n("Both"), 24); toggleAutoMenu.setItemChecked(21 + d->toggleAutoTags, true); popmenu.insertItem(i18n("Toggle Auto"), &toggleAutoMenu); TQPopupMenu matchingCongMenu; matchingCongMenu.setCheckable(true); matchingCongMenu.insertItem(i18n("Or Between Tags"), 25); matchingCongMenu.insertItem(i18n("And Between Tags"), 26); matchingCongMenu.setItemChecked((d->matchingCond == AlbumLister::OrCondition) ? 25 : 26, true); popmenu.insertItem(i18n("Matching Condition"), &matchingCongMenu); ToggleAutoTags oldAutoTags = d->toggleAutoTags; int choice = popmenu.exec((TQCursor::pos())); switch( choice ) { case 10: // New Tag. { tagNew(item); break; } case 11: // Edit Tag Properties. { tagEdit(item); break; } case 12: // Delete Tag. { tagDelete(item); break; } case 13: // Reset Tag Icon. { TQString errMsg; AlbumManager::instance()->updateTAlbumIcon(item->album(), TQString("tag"), 0, errMsg); break; } case 14: // Select All Tags. { d->toggleAutoTags = TagFilterView::NoToggleAuto; TQListViewItemIterator it(this, TQListViewItemIterator::NotChecked); while (it.current()) { TagFilterViewItem* item = (TagFilterViewItem*)it.current(); // Ignore "Not Tagged" tag filter. if (!item->untagged()) item->setOn(true); ++it; } triggerChange(); d->toggleAutoTags = oldAutoTags; break; } case 15: // Deselect All Tags. { d->toggleAutoTags = TagFilterView::NoToggleAuto; TQListViewItemIterator it(this, TQListViewItemIterator::Checked); while (it.current()) { TagFilterViewItem* item = (TagFilterViewItem*)it.current(); // Ignore "Not Tagged" tag filter. if (!item->untagged()) item->setOn(false); ++it; } triggerChange(); d->toggleAutoTags = oldAutoTags; break; } case 16: // Invert All Tags Selection. { d->toggleAutoTags = TagFilterView::NoToggleAuto; TQListViewItemIterator it(this); while (it.current()) { TagFilterViewItem* item = (TagFilterViewItem*)it.current(); // Ignore "Not Tagged" tag filter. if (!item->untagged()) item->setOn(!item->isOn()); ++it; } triggerChange(); d->toggleAutoTags = oldAutoTags; break; } case 17: // Select Child Tags. { d->toggleAutoTags = TagFilterView::NoToggleAuto; toggleChildTags(item, true); TagFilterViewItem *tItem = (TagFilterViewItem*)item->album()->extraData(this); tItem->setOn(true); d->toggleAutoTags = oldAutoTags; break; } case 18: // Deselect Child Tags. { d->toggleAutoTags = TagFilterView::NoToggleAuto; toggleChildTags(item, false); TagFilterViewItem *tItem = (TagFilterViewItem*)item->album()->extraData(this); tItem->setOn(false); d->toggleAutoTags = oldAutoTags; break; } case 19: // Select Parent Tags. { d->toggleAutoTags = TagFilterView::NoToggleAuto; toggleParentTags(item, true); TagFilterViewItem *tItem = (TagFilterViewItem*)item->album()->extraData(this); tItem->setOn(true); d->toggleAutoTags = oldAutoTags; break; } case 20: // Deselect Parent Tags. { d->toggleAutoTags = TagFilterView::NoToggleAuto; toggleParentTags(item, false); TagFilterViewItem *tItem = (TagFilterViewItem*)item->album()->extraData(this); tItem->setOn(false); d->toggleAutoTags = oldAutoTags; break; } case 21: // No toggle auto tags. { d->toggleAutoTags = NoToggleAuto; break; } case 22: // Toggle auto Children tags. { d->toggleAutoTags = Children; break; } case 23: // Toggle auto Parents tags. { d->toggleAutoTags = Parents; break; } case 24: // Toggle auto Children and Parents tags. { d->toggleAutoTags = ChildrenAndParents; break; } case 25: // Or Between Tags. { d->matchingCond = AlbumLister::OrCondition; triggerChange(); break; } case 26: // And Between Tags. { d->matchingCond = AlbumLister::AndCondition; triggerChange(); break; } default: break; } if ( choice > 100 ) { tagNew(item, d->ABCMenu->text( choice ), "tag-people" ); } delete d->ABCMenu; d->ABCMenu = 0; } void TagFilterView::slotABCContextMenu() { d->ABCMenu->clear(); int counter = 100; KABC::AddressBook* ab = KABC::StdAddressBook::self(); TQStringList names; for ( KABC::AddressBook::Iterator it = ab->begin(); it != ab->end(); ++it ) { names.push_back(it->formattedName()); } qHeapSort(names); for ( TQStringList::Iterator it = names.begin(); it != names.end(); ++it ) { TQString name = *it; if ( !name.isNull() ) d->ABCMenu->insertItem( name, ++counter ); } if (counter == 100) { d->ABCMenu->insertItem( i18n("No AddressBook entries found"), ++counter ); d->ABCMenu->setItemEnabled( counter, false ); } } void TagFilterView::tagNew(TagFilterViewItem* item, const TQString& _title, const TQString& _icon) { TAlbum *parent; TQString title = _title; TQString icon = _icon; AlbumManager *man = AlbumManager::instance(); if (!item) parent = man->findTAlbum(0); else parent = item->album(); if (title.isNull()) { if (!TagEditDlg::tagCreate(TQT_TQWIDGET(kapp->activeWindow()), parent, title, icon)) return; } TQMap errMap; AlbumList tList = TagEditDlg::createTAlbum(parent, title, icon, errMap); TagEditDlg::showtagsListCreationError(TQT_TQWIDGET(kapp->activeWindow()), errMap); for (AlbumList::iterator it = tList.begin(); it != tList.end(); ++it) { TagFilterViewItem* item = (TagFilterViewItem*)(*it)->extraData(this); if (item) { clearSelection(); setSelected(item, true); setCurrentItem(item); ensureItemVisible(item); } } } void TagFilterView::tagEdit(TagFilterViewItem* item) { if (!item) return; TAlbum *tag = item->album(); if (!tag) return; TQString title, icon; if (!TagEditDlg::tagEdit(TQT_TQWIDGET(kapp->activeWindow()), tag, title, icon)) { return; } AlbumManager* man = AlbumManager::instance(); if (tag->title() != title) { TQString errMsg; if(!man->renameTAlbum(tag, title, errMsg)) KMessageBox::error(0, errMsg); else item->refresh(); } if (tag->icon() != icon) { TQString errMsg; if (!man->updateTAlbumIcon(tag, icon, 0, errMsg)) KMessageBox::error(0, errMsg); else setTagThumbnail(tag); } } void TagFilterView::tagDelete(TagFilterViewItem* item) { if (!item) return; TAlbum *tag = item->album(); if (!tag || tag->isRoot()) return; // find number of subtags int children = 0; AlbumIterator iter(tag); while(iter.current()) { children++; ++iter; } AlbumManager* man = AlbumManager::instance(); if (children) { int result = KMessageBox::warningContinueCancel(this, i18n("Tag '%1' has one subtag. " "Deleting this will also delete " "the subtag. " "Do you want to continue?", "Tag '%1' has %n subtags. " "Deleting this will also delete " "the subtags. " "Do you want to continue?", children).arg(tag->title())); if(result != KMessageBox::Continue) return; } TQString message; LLongList assignedItems = man->albumDB()->getItemIDsInTag(tag->id()); if (!assignedItems.isEmpty()) { message = i18n("Tag '%1' is assigned to one item. " "Do you want to continue?", "Tag '%1' is assigned to %n items. " "Do you want to continue?", assignedItems.count()).arg(tag->title()); } else { message = i18n("Delete '%1' tag?").arg(tag->title()); } int result = KMessageBox::warningContinueCancel(0, message, i18n("Delete Tag"), KGuiItem(i18n("Delete"), "editdelete")); if (result == KMessageBox::Continue) { TQString errMsg; if (!man->deleteTAlbum(tag, errMsg)) KMessageBox::error(0, errMsg); } } void TagFilterView::toggleChildTags(TagFilterViewItem* tItem, bool b) { if (!tItem) return; TAlbum *album = tItem->album(); if (!album) return; AlbumIterator it(album); while ( it.current() ) { TAlbum *ta = (TAlbum*)it.current(); TagFilterViewItem *item = (TagFilterViewItem*)ta->extraData(this); if (item) { if (item->isVisible()) item->setOn(b); } ++it; } } void TagFilterView::toggleParentTags(TagFilterViewItem* tItem, bool b) { if (!tItem) return; TAlbum *album = tItem->album(); if (!album) return; TQListViewItemIterator it(this); while (it.current()) { TagFilterViewItem* item = dynamic_cast(it.current()); if (item->isVisible()) { Album *a = dynamic_cast(item->album()); if (a) { if (a == album->parent()) { item->setOn(b); toggleParentTags(item, b); } } } ++it; } } void TagFilterView::refresh() { TQListViewItemIterator it(this); while (it.current()) { TagFilterViewItem* item = dynamic_cast(*it); if (item) item->refresh(); ++it; } } void TagFilterView::slotRefresh(const TQMap& tagsStatMap) { TQListViewItemIterator it(this); while (it.current()) { TagFilterViewItem* 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 TagFilterView::slotResetTagFilters() { TQListViewItemIterator it(this); while (it.current()) { TagFilterViewItem* item = dynamic_cast(*it); if (item && item->isOn()) item->setOn(false); ++it; } } void TagFilterView::loadViewState() { TDEConfig *config = kapp->config(); config->setGroup(name()); int selectedItem = config->readNumEntry("LastSelectedItem", 0); TQValueList openFolders; if(config->hasKey("OpenFolders")) { openFolders = config->readIntListEntry("OpenFolders"); } TagFilterViewItem *item = 0; TagFilterViewItem *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 TagFilterView::saveViewState() { TDEConfig *config = kapp->config(); config->setGroup(name()); TagFilterViewItem *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