diff options
Diffstat (limited to 'src/libs/imageproperties/imagedescedittab.cpp')
-rw-r--r-- | src/libs/imageproperties/imagedescedittab.cpp | 1763 |
1 files changed, 1763 insertions, 0 deletions
diff --git a/src/libs/imageproperties/imagedescedittab.cpp b/src/libs/imageproperties/imagedescedittab.cpp new file mode 100644 index 00000000..f79b1d7c --- /dev/null +++ b/src/libs/imageproperties/imagedescedittab.cpp @@ -0,0 +1,1763 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2003-03-09 + * Description : Captions, Tags, and Rating properties editor + * + * Copyright (C) 2003-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2003-2009 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2009 by Marcel Wiesweg <marcel.wiesweg@gmx.de> + * 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 <tqhbox.h> +#include <tqvbox.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqtoolbutton.h> +#include <tqpushbutton.h> +#include <tqiconset.h> +#include <tqwhatsthis.h> +#include <tqtooltip.h> +#include <tqscrollview.h> + +// KDE includes. + +#include <tdeabc/stdaddressbook.h> +#include <tdepopupmenu.h> +#include <tdelocale.h> +#include <kurl.h> +#include <kcursor.h> +#include <tdeapplication.h> +#include <kiconloader.h> +#include <tdemessagebox.h> +#include <ktextedit.h> +#include <tdeconfig.h> +#include <klineedit.h> +#include <kdialogbase.h> + +// Local includes. + +#include "ddebug.h" +#include "dmetadata.h" +#include "kdatetimeedit.h" +#include "albumiconitem.h" +#include "albumdb.h" +#include "album.h" +#include "albumsettings.h" +#include "albumlister.h" +#include "albumthumbnailloader.h" +#include "tageditdlg.h" +#include "navigatebarwidget.h" +#include "ratingwidget.h" +#include "talbumlistview.h" +#include "tagfilterview.h" +#include "imageinfo.h" +#include "imageattributeswatch.h" +#include "metadatahub.h" +#include "statusprogressbar.h" +#include "searchtextbar.h" +#include "imagedescedittab.h" +#include "imagedescedittab.moc" + +namespace Digikam +{ + +class ImageDescEditTabPriv +{ + +public: + + ImageDescEditTabPriv() + { + modified = false; + ignoreImageAttributesWatch = false; + recentTagsBtn = 0; + commentsEdit = 0; + tagsSearchBar = 0; + dateTimeEdit = 0; + tagsView = 0; + ratingWidget = 0; + ABCMenu = 0; + assignedTagsBtn = 0; + applyBtn = 0; + revertBtn = 0; + newTagEdit = 0; + toggleAutoTags = TagFilterView::NoToggleAuto; + } + + bool modified; + bool ignoreImageAttributesWatch; + + TQToolButton *recentTagsBtn; + TQToolButton *assignedTagsBtn; + TQToolButton *revertBtn; + + TQPopupMenu *ABCMenu; + + TQPushButton *applyBtn; + + TQPushButton *moreButton; + TQPopupMenu *moreMenu; + + KTextEdit *commentsEdit; + + KDateTimeEdit *dateTimeEdit; + + SearchTextBar *tagsSearchBar; + SearchTextBar *newTagEdit; + + TQPtrList<ImageInfo> currInfos; + + TAlbumListView *tagsView; + + RatingWidget *ratingWidget; + + TagFilterView::ToggleAutoTags toggleAutoTags; + + MetadataHub hub; +}; + +ImageDescEditTab::ImageDescEditTab(TQWidget *parent, bool navBar) + : NavigateBarTab(parent) +{ + d = new ImageDescEditTabPriv; + + setupNavigateBar(navBar); + + TQScrollView *sv = new TQScrollView(this); + sv->viewport()->setBackgroundMode(TQt::PaletteBackground); + sv->setResizePolicy(TQScrollView::AutoOneFit); + sv->setFrameStyle(TQFrame::NoFrame); + + TQWidget *settingsArea = new TQWidget(sv->viewport()); + sv->addChild(settingsArea); + m_navigateBarLayout->addWidget(sv); + + TQGridLayout *settingsLayout = new TQGridLayout(settingsArea, 6, 1, + KDialog::spacingHint(), KDialog::spacingHint()); + + // Captions/Date/Rating view ----------------------------------- + + TQVBox *commentsBox = new TQVBox(settingsArea); + new TQLabel(i18n("Caption:"), commentsBox); + d->commentsEdit = new KTextEdit(commentsBox); + d->commentsEdit->setTextFormat(TQTextEdit::PlainText); + d->commentsEdit->setCheckSpellingEnabled(true); + d->commentsEdit->setFixedHeight(100); + + TQHBox *dateBox = new TQHBox(settingsArea); + new TQLabel(i18n("Date:"), dateBox); + d->dateTimeEdit = new KDateTimeEdit(dateBox, "datepicker"); + + TQHBox *ratingBox = new TQHBox(settingsArea); + new TQLabel(i18n("Rating:"), ratingBox); + d->ratingWidget = new RatingWidget(ratingBox); + + // Tags view --------------------------------------------------- + + d->newTagEdit = new SearchTextBar(settingsArea, "ImageDescEditTabNewTagEdit", i18n("Enter new tag here...")); + TQWhatsThis::add(d->newTagEdit, i18n("Enter here the text used to create new tags. " + "'/' can be used here to create a hierarchy of tags. " + "',' can be used here to create more than one hierarchy at the same time.")); + + d->tagsView = new TAlbumListView(settingsArea); + + TQHBox *tagsSearch = new TQHBox(settingsArea); + tagsSearch->setSpacing(KDialog::spacingHint()); + + d->tagsSearchBar = new SearchTextBar(tagsSearch, "ImageDescEditTabTagsSearchBar"); + + d->assignedTagsBtn = new TQToolButton(tagsSearch); + TQToolTip::add(d->assignedTagsBtn, i18n("Tags already assigned")); + d->assignedTagsBtn->setIconSet(kapp->iconLoader()->loadIcon("tag-assigned", + TDEIcon::NoGroup, TDEIcon::SizeSmall, + TDEIcon::DefaultState, 0, true)); + d->assignedTagsBtn->setToggleButton(true); + + d->recentTagsBtn = new TQToolButton(tagsSearch); + TQPopupMenu *popupMenu = new TQPopupMenu(d->recentTagsBtn); + TQToolTip::add(d->recentTagsBtn, i18n("Recent Tags")); + d->recentTagsBtn->setIconSet(kapp->iconLoader()->loadIcon("tag-recents", + TDEIcon::NoGroup, TDEIcon::SizeSmall, + TDEIcon::DefaultState, 0, true)); + d->recentTagsBtn->setUsesBigPixmap(false); + d->recentTagsBtn->setPopup(popupMenu); + d->recentTagsBtn->setPopupDelay(1); + + // Buttons ----------------------------------------- + + TQHBox *buttonsBox = new TQHBox(settingsArea); + buttonsBox->setSpacing(KDialog::spacingHint()); + + d->revertBtn = new TQToolButton(buttonsBox); + d->revertBtn->setIconSet(SmallIcon("reload_page")); + TQToolTip::add(d->revertBtn, i18n("Revert all changes")); + d->revertBtn->setEnabled(false); + + d->applyBtn = new TQPushButton(i18n("Apply"), buttonsBox); + d->applyBtn->setIconSet(SmallIcon("button_ok")); + d->applyBtn->setEnabled(false); + TQToolTip::add(d->applyBtn, i18n("Apply all changes to images")); + buttonsBox->setStretchFactor(d->applyBtn, 10); + + d->moreButton = new TQPushButton(i18n("More"), buttonsBox); + d->moreMenu = new TQPopupMenu(this); + d->moreButton->setPopup(d->moreMenu); + + // -------------------------------------------------- + + settingsLayout->addMultiCellWidget(commentsBox, 0, 0, 0, 1); + settingsLayout->addMultiCellWidget(dateBox, 1, 1, 0, 1); + settingsLayout->addMultiCellWidget(ratingBox, 2, 2, 0, 1); + settingsLayout->addMultiCellWidget(d->newTagEdit, 3, 3, 0, 1); + settingsLayout->addMultiCellWidget(d->tagsView, 4, 4, 0, 1); + settingsLayout->addMultiCellWidget(tagsSearch, 5, 5, 0, 1); + settingsLayout->addMultiCellWidget(buttonsBox, 6, 6, 0, 1); + settingsLayout->setRowStretch(4, 10); + + // -------------------------------------------------- + + connect(d->tagsView, TQ_SIGNAL(signalProgressBarMode(int, const TQString&)), + this, TQ_SIGNAL(signalProgressBarMode(int, const TQString&))); + + connect(d->tagsView, TQ_SIGNAL(signalProgressValue(int)), + this, TQ_SIGNAL(signalProgressValue(int))); + + connect(popupMenu, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotRecentTagsMenuActivated(int))); + + connect(d->tagsView, TQ_SIGNAL(signalItemStateChanged(TAlbumCheckListItem *)), + this, TQ_SLOT(slotItemStateChanged(TAlbumCheckListItem *))); + + connect(d->commentsEdit, TQ_SIGNAL(textChanged()), + this, TQ_SLOT(slotCommentChanged())); + + connect(d->dateTimeEdit, TQ_SIGNAL(dateTimeChanged(const TQDateTime& )), + this, TQ_SLOT(slotDateTimeChanged(const TQDateTime&))); + + connect(d->ratingWidget, TQ_SIGNAL(signalRatingChanged(int)), + this, TQ_SLOT(slotRatingChanged(int))); + + connect(d->tagsView, TQ_SIGNAL(rightButtonClicked(TQListViewItem*, const TQPoint &, int)), + this, TQ_SLOT(slotRightButtonClicked(TQListViewItem*, const TQPoint&, int))); + + connect(d->tagsSearchBar, TQ_SIGNAL(signalTextChanged(const TQString&)), + this, TQ_SLOT(slotTagsSearchChanged(const TQString&))); + + connect(this, TQ_SIGNAL(signalTagFilterMatch(bool)), + d->tagsSearchBar, TQ_SLOT(slotSearchResult(bool))); + + connect(d->assignedTagsBtn, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotAssignedTagsToggled(bool))); + + connect(d->newTagEdit->lineEdit(), TQ_SIGNAL(returnPressed(const TQString&)), + this, TQ_SLOT(slotCreateNewTag())); + + connect(d->applyBtn, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotApplyAllChanges())); + + connect(d->revertBtn, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotRevertAllChanges())); + + connect(d->moreMenu, TQ_SIGNAL(aboutToShow()), + this, TQ_SLOT(slotMoreMenu())); + + // Initialize --------------------------------------------- + + d->commentsEdit->installEventFilter(this); + d->dateTimeEdit->installEventFilter(this); + d->ratingWidget->installEventFilter(this); + d->tagsView->installEventFilter(this); + updateRecentTags(); + + // Connect to album manager ----------------------------- + + AlbumManager* man = AlbumManager::instance(); + + connect(man, TQ_SIGNAL(signalAlbumAdded(Album*)), + this, TQ_SLOT(slotAlbumAdded(Album*))); + + connect(man, TQ_SIGNAL(signalAlbumDeleted(Album*)), + this, TQ_SLOT(slotAlbumDeleted(Album*))); + + connect(man, TQ_SIGNAL(signalAlbumRenamed(Album*)), + this, TQ_SLOT(slotAlbumRenamed(Album*))); + + connect(man, TQ_SIGNAL(signalAlbumsCleared()), + this, TQ_SLOT(slotAlbumsCleared())); + + connect(man, TQ_SIGNAL(signalAlbumIconChanged(Album*)), + this, TQ_SLOT(slotAlbumIconChanged(Album*))); + + connect(man, TQ_SIGNAL(signalTAlbumMoved(TAlbum*, TAlbum*)), + this, TQ_SLOT(slotAlbumMoved(TAlbum*, TAlbum*))); + + // Connect to thumbnail loader ----------------------------- + + AlbumThumbnailLoader *loader = AlbumThumbnailLoader::instance(); + + connect(loader, TQ_SIGNAL(signalThumbnail(Album *, const TQPixmap&)), + this, TQ_SLOT(slotGotThumbnailFromIcon(Album *, const TQPixmap&))); + + connect(loader, TQ_SIGNAL(signalFailed(Album *)), + this, TQ_SLOT(slotThumbnailLost(Album *))); + + connect(loader, TQ_SIGNAL(signalReloadThumbnails()), + this, TQ_SLOT(slotReloadThumbnails())); + + // Connect to attribute watch ------------------------------ + + ImageAttributesWatch *watch = ImageAttributesWatch::instance(); + + connect(watch, TQ_SIGNAL(signalImageTagsChanged(TQ_LLONG)), + this, TQ_SLOT(slotImageTagsChanged(TQ_LLONG))); + + connect(watch, TQ_SIGNAL(signalImagesChanged(int)), + this, TQ_SLOT(slotImagesChanged(int))); + + connect(watch, TQ_SIGNAL(signalImageRatingChanged(TQ_LLONG)), + this, TQ_SLOT(slotImageRatingChanged(TQ_LLONG))); + + connect(watch, TQ_SIGNAL(signalImageDateChanged(TQ_LLONG)), + this, TQ_SLOT(slotImageDateChanged(TQ_LLONG))); + + connect(watch, TQ_SIGNAL(signalImageCaptionChanged(TQ_LLONG)), + this, TQ_SLOT(slotImageCaptionChanged(TQ_LLONG))); + + // -- read config --------------------------------------------------------- + + TDEConfig* config = kapp->config(); + config->setGroup("Tag List View"); + d->toggleAutoTags = (TagFilterView::ToggleAutoTags)(config->readNumEntry("Toggle Auto Tags", + TagFilterView::NoToggleAuto)); +} + +ImageDescEditTab::~ImageDescEditTab() +{ + slotChangingItems(); + + /* + AlbumList tList = AlbumManager::instance()->allTAlbums(); + for (AlbumList::iterator it = tList.begin(); it != tList.end(); ++it) + { + (*it)->removeExtraData(this); + } + */ + + TDEConfig* config = kapp->config(); + config->setGroup("Tag List View"); + config->writeEntry("Toggle Auto Tags", (int)(d->toggleAutoTags)); + config->sync(); + + delete d; +} + +bool ImageDescEditTab::singleSelection() const +{ + return (d->currInfos.count() == 1); +} + +void ImageDescEditTab::slotChangingItems() +{ + if (!d->modified) + return; + + if (d->currInfos.isEmpty()) + return; + + if (!AlbumSettings::instance()->getApplySidebarChangesDirectly()) + { + KDialogBase *dialog = new KDialogBase(i18n("Apply changes?"), + KDialogBase::Yes | KDialogBase::No, + KDialogBase::Yes, KDialogBase::No, + this, "applyChanges", + true, true, + KStdGuiItem::yes(), KStdGuiItem::discard()); + + int changedFields = 0; + if (d->hub.commentChanged()) + changedFields++; + if (d->hub.dateTimeChanged()) + changedFields++; + if (d->hub.ratingChanged()) + changedFields++; + if (d->hub.tagsChanged()) + changedFields++; + + TQString text; + if (changedFields == 1) + { + if (d->hub.commentChanged()) + text = i18n("<qt><p>You have edited the comment of the image. ", + "<qt><p>You have edited the comment of %n images. ", + d->currInfos.count()); + else if (d->hub.dateTimeChanged()) + text = i18n("<qt><p>You have edited the date of the image. ", + "<qt><p>You have edited the date of %n images. ", + d->currInfos.count()); + else if (d->hub.ratingChanged()) + text = i18n("<qt><p>You have edited the rating of the image. ", + "<qt><p>You have edited the rating of %n images. ", + d->currInfos.count()); + else if (d->hub.tagsChanged()) + text = i18n("<qt><p>You have edited the tags of the image. ", + "<qt><p>You have edited the tags of %n images. ", + d->currInfos.count()); + + text += i18n("Do you want to apply your changes?</p></qt>"); + } + else + { + text = i18n("<qt><p>You have edited the metadata of the image: </p><ul>", + "<qt><p>You have edited the metadata of %n images: </p><ul>", + d->currInfos.count()); + + if (d->hub.commentChanged()) + text += i18n("<li>comment</li>"); + if (d->hub.dateTimeChanged()) + text += i18n("<li>date</li>"); + if (d->hub.ratingChanged()) + text += i18n("<li>rating</li>"); + if (d->hub.tagsChanged()) + text += i18n("<li>tags</li>"); + + text += "</ul><p>"; + + text += i18n("Do you want to apply your changes?</p></qt>"); + } + + bool alwaysApply = false; + int returnCode = KMessageBox::createKMessageBox + (dialog, TQMessageBox::Information, + text, TQStringList(), + i18n("Always apply changes without confirmation"), + &alwaysApply, KMessageBox::Notify); + + if (alwaysApply) + AlbumSettings::instance()->setApplySidebarChangesDirectly(true); + + if (returnCode == KDialogBase::User1) + return; + // otherwise apply + } + + slotApplyAllChanges(); +} + +void ImageDescEditTab::slotApplyAllChanges() +{ + if (!d->modified) + return; + + if (d->currInfos.isEmpty()) + return; + + bool progressInfo = (d->currInfos.count() > 1); + emit signalProgressBarMode(StatusProgressBar::ProgressBarMode, + i18n("Applying changes to images. Please wait...")); + MetadataWriteSettings writeSettings = MetadataHub::defaultWriteSettings(); + + // debugging - use this to indicate reentry from event loop (kapp->processEvents) + // remove before final release + if (d->ignoreImageAttributesWatch) + { + DWarning() << "ImageDescEditTab::slotApplyAllChanges(): re-entering from event loop!" << endl; + } + + // we are now changing attributes ourselves + d->ignoreImageAttributesWatch = true; + AlbumLister::instance()->blockSignals(true); + AlbumManager::instance()->albumDB()->beginTransaction(); + int i=0; + for (ImageInfo *info = d->currInfos.first(); info; info = d->currInfos.next()) + { + // apply to database + d->hub.write(info); + // apply to file metadata + d->hub.write(info->filePath(), MetadataHub::FullWrite, writeSettings); + + emit signalProgressValue((int)((i++/(float)d->currInfos.count())*100.0)); + if (progressInfo) + kapp->processEvents(); + } + AlbumLister::instance()->blockSignals(false); + AlbumManager::instance()->albumDB()->commitTransaction(); + + d->ignoreImageAttributesWatch = false; + + emit signalProgressBarMode(StatusProgressBar::TextMode, TQString()); + + d->modified = false; + d->hub.resetChanged(); + d->applyBtn->setEnabled(false); + d->revertBtn->setEnabled(false); + + updateRecentTags(); + updateTagsView(); +} + +void ImageDescEditTab::slotRevertAllChanges() +{ + if (!d->modified) + return; + + if (d->currInfos.isEmpty()) + return; + + setInfos(d->currInfos); +} + +void ImageDescEditTab::setItem(ImageInfo *info) +{ + slotChangingItems(); + TQPtrList<ImageInfo> list; + if (info) + list.append(info); + setInfos(list); +} + +void ImageDescEditTab::setItems(TQPtrList<ImageInfo> infos) +{ + slotChangingItems(); + setInfos(infos); +} + +void ImageDescEditTab::setInfos(TQPtrList<ImageInfo> infos) +{ + if (infos.isEmpty()) + { + d->hub = MetadataHub(); + d->commentsEdit->blockSignals(true); + d->commentsEdit->clear(); + d->commentsEdit->blockSignals(false); + d->currInfos.clear(); + setEnabled(false); + return; + } + + setEnabled(true); + d->currInfos = infos; + d->modified = false; + d->hub = MetadataHub(); + d->applyBtn->setEnabled(false); + d->revertBtn->setEnabled(false); + + for (ImageInfo *info = d->currInfos.first(); info; info = d->currInfos.next()) + { + d->hub.load(info); + } + + updateComments(); + updateRating(); + updateDate(); + updateTagsView(); +} + +void ImageDescEditTab::slotReadFromFileMetadataToDatabase() +{ + emit signalProgressBarMode(StatusProgressBar::ProgressBarMode, + i18n("Reading metadata from files. Please wait...")); + + d->ignoreImageAttributesWatch = true; + AlbumManager::instance()->albumDB()->beginTransaction(); + int i=0; + for (ImageInfo *info = d->currInfos.first(); info; info = d->currInfos.next()) + { + // A batch operation: a hub for each single file, not the common hub + MetadataHub fileHub(MetadataHub::NewTagsImport); + // read in from DMetadata + fileHub.load(info->filePath()); + // write out to database + fileHub.write(info); + + emit signalProgressValue((int)((i++/(float)d->currInfos.count())*100.0)); + kapp->processEvents(); + } + AlbumManager::instance()->albumDB()->commitTransaction(); + d->ignoreImageAttributesWatch = false; + + emit signalProgressBarMode(StatusProgressBar::TextMode, TQString()); + + // reload everything + setInfos(d->currInfos); +} + +void ImageDescEditTab::slotWriteToFileMetadataFromDatabase() +{ + emit signalProgressBarMode(StatusProgressBar::ProgressBarMode, + i18n("Writing metadata to files. Please wait...")); + MetadataWriteSettings writeSettings = MetadataHub::defaultWriteSettings(); + + int i=0; + for (ImageInfo *info = d->currInfos.first(); info; info = d->currInfos.next()) + { + MetadataHub fileHub; + // read in from database + fileHub.load(info); + // write out to file DMetadata + fileHub.write(info->filePath()); + + emit signalProgressValue((int)((i++/(float)d->currInfos.count())*100.0)); + kapp->processEvents(); + } + + emit signalProgressBarMode(StatusProgressBar::TextMode, TQString()); +} + +bool ImageDescEditTab::eventFilter(TQObject *, TQEvent *e) +{ + if ( e->type() == TQEvent::KeyPress ) + { + TQKeyEvent *k = (TQKeyEvent *)e; + if (k->state() == TQt::ControlButton && + (k->key() == TQt::Key_Enter || k->key() == TQt::Key_Return)) + { + emit signalNextItem(); + return true; + } + else if (k->state() == TQt::ShiftButton && + (k->key() == TQt::Key_Enter || k->key() == TQt::Key_Return)) + { + emit signalPrevItem(); + return true; + } + + return false; + } + + return false; +} + +void ImageDescEditTab::populateTags() +{ + d->tagsView->clear(); + + AlbumList tList = AlbumManager::instance()->allTAlbums(); + for (AlbumList::iterator it = tList.begin(); it != tList.end(); ++it) + { + TAlbum *tag = (TAlbum*)(*it); + slotAlbumAdded(tag); + } + + d->tagsView->loadViewState(); +} + +void ImageDescEditTab::slotItemStateChanged(TAlbumCheckListItem *item) +{ + TagFilterView::ToggleAutoTags oldAutoTags = d->toggleAutoTags; + + switch(d->toggleAutoTags) + { + case TagFilterView::Children: + d->toggleAutoTags = TagFilterView::NoToggleAuto; + toggleChildTags(item->album(), item->isOn()); + d->toggleAutoTags = oldAutoTags; + break; + case TagFilterView::Parents: + d->toggleAutoTags = TagFilterView::NoToggleAuto; + toggleParentTags(item->album(), item->isOn()); + d->toggleAutoTags = oldAutoTags; + break; + case TagFilterView::ChildrenAndParents: + d->toggleAutoTags = TagFilterView::NoToggleAuto; + toggleChildTags(item->album(), item->isOn()); + toggleParentTags(item->album(), item->isOn()); + d->toggleAutoTags = oldAutoTags; + break; + default: + break; + } + + d->hub.setTag(item->album(), item->isOn()); + + d->tagsView->blockSignals(true); + item->setStatus(d->hub.tagStatus(item->album())); + d->tagsView->blockSignals(false); + + slotModified(); +} + +void ImageDescEditTab::slotCommentChanged() +{ + // we cannot trust that the text actually changed + // (there are bogus signals caused by spell checking, see bug 141663) + // so we have to check before marking the metadata as modified + if (d->hub.comment() == d->commentsEdit->text()) + return; + + d->hub.setComment(d->commentsEdit->text()); + setMetadataWidgetStatus(d->hub.commentStatus(), d->commentsEdit); + slotModified(); +} + +void ImageDescEditTab::slotDateTimeChanged(const TQDateTime& dateTime) +{ + d->hub.setDateTime(dateTime); + setMetadataWidgetStatus(d->hub.dateTimeStatus(), d->dateTimeEdit); + slotModified(); +} + +void ImageDescEditTab::slotRatingChanged(int rating) +{ + d->hub.setRating(rating); + // no handling for MetadataDisjoint needed for rating, + // we set it to 0 when disjoint, see below + slotModified(); +} + +void ImageDescEditTab::slotModified() +{ + d->modified = true; + d->applyBtn->setEnabled(true); + d->revertBtn->setEnabled(true); +} + +void ImageDescEditTab::assignRating(int rating) +{ + d->ratingWidget->setRating(rating); +} + +void ImageDescEditTab::updateTagsView() +{ + d->tagsView->blockSignals(true); + + TQListViewItemIterator it( d->tagsView); + while (it.current()) + { + TAlbumCheckListItem* tItem = dynamic_cast<TAlbumCheckListItem*>(it.current()); + if (tItem) + tItem->setStatus(d->hub.tagStatus(tItem->album())); + ++it; + } + + // The condition is a temporary fix not to destroy name filtering on image change. + // See comments in these methods. + if (d->assignedTagsBtn->isOn()) + slotAssignedTagsToggled(d->assignedTagsBtn->isOn()); + + d->tagsView->blockSignals(false); +} + +void ImageDescEditTab::updateComments() +{ + d->commentsEdit->blockSignals(true); + d->commentsEdit->setText(d->hub.comment()); + setMetadataWidgetStatus(d->hub.commentStatus(), d->commentsEdit); + d->commentsEdit->blockSignals(false); +} + +void ImageDescEditTab::updateRating() +{ + d->ratingWidget->blockSignals(true); + if (d->hub.ratingStatus() == MetadataHub::MetadataDisjoint) + d->ratingWidget->setRating(0); + else + d->ratingWidget->setRating(d->hub.rating()); + d->ratingWidget->blockSignals(false); +} + +void ImageDescEditTab::updateDate() +{ + d->dateTimeEdit->blockSignals(true); + d->dateTimeEdit->setDateTime(d->hub.dateTime()); + setMetadataWidgetStatus(d->hub.dateTimeStatus(), d->dateTimeEdit); + d->dateTimeEdit->blockSignals(false); +} + +void ImageDescEditTab::setMetadataWidgetStatus(int status, TQWidget *widget) +{ + if (status == MetadataHub::MetadataDisjoint) + { + // For text widgets: Set text color to color of disabled text + TQPalette palette = widget->palette(); + palette.setColor(TQColorGroup::Text, palette.color(TQPalette::Disabled, TQColorGroup::Text)); + widget->setPalette(palette); + } + else + { + widget->unsetPalette(); + } +} + +void ImageDescEditTab::slotRightButtonClicked(TQListViewItem *item, const TQPoint &, int ) +{ + TAlbum *album; + + if (!item) + { + album = AlbumManager::instance()->findTAlbum(0); + } + else + { + TAlbumCheckListItem* viewItem = dynamic_cast<TAlbumCheckListItem*>(item); + + if(!viewItem) + album = AlbumManager::instance()->findTAlbum(0); + else + album = viewItem->album(); + } + + if(!album) + return; + + d->ABCMenu = new TQPopupMenu; + + connect(d->ABCMenu, TQ_SIGNAL( aboutToShow() ), + this, TQ_SLOT( slotABCContextMenu() )); + + TDEPopupMenu popmenu(this); + popmenu.insertTitle(SmallIcon("digikam"), i18n("Tags")); + popmenu.insertItem(SmallIcon("tag-new"), i18n("New Tag..."), 10); + popmenu.insertItem(SmallIcon("tag-addressbook"), i18n("Create Tag From AddressBook"), d->ABCMenu); + + if (!album->isRoot()) + { + 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 (!album->isRoot()) + { + 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 (!album->isRoot()) + { + 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); + + TagFilterView::ToggleAutoTags oldAutoTags = d->toggleAutoTags; + + int choice = popmenu.exec((TQCursor::pos())); + switch( choice ) + { + case 10: // New Tag. + { + tagNew(album); + break; + } + case 11: // Edit Tag Properties. + { + if (!album->isRoot()) + tagEdit(album); + break; + } + case 12: // Delete Tag. + { + if (!album->isRoot()) + tagDelete(album); + break; + } + case 13: // Reset Tag Icon. + { + TQString errMsg; + AlbumManager::instance()->updateTAlbumIcon(album, TQString("tag"), 0, errMsg); + break; + } + case 14: // Select All Tags. + { + d->toggleAutoTags = TagFilterView::NoToggleAuto; + TQListViewItemIterator it(d->tagsView, TQListViewItemIterator::NotChecked); + while (it.current()) + { + TAlbumCheckListItem* item = dynamic_cast<TAlbumCheckListItem*>(it.current()); + if (item->isVisible()) + item->setOn(true); + ++it; + } + d->toggleAutoTags = oldAutoTags; + break; + } + case 15: // Deselect All Tags. + { + d->toggleAutoTags = TagFilterView::NoToggleAuto; + TQListViewItemIterator it(d->tagsView, TQListViewItemIterator::Checked); + while (it.current()) + { + TAlbumCheckListItem* item = dynamic_cast<TAlbumCheckListItem*>(it.current()); + if (item->isVisible()) + item->setOn(false); + ++it; + } + d->toggleAutoTags = oldAutoTags; + break; + } + case 16: // Invert All Tags Selection. + { + d->toggleAutoTags = TagFilterView::NoToggleAuto; + TQListViewItemIterator it(d->tagsView); + while (it.current()) + { + TAlbumCheckListItem* item = dynamic_cast<TAlbumCheckListItem*>(it.current()); + if (item->isVisible()) + item->setOn(!item->isOn()); + ++it; + } + d->toggleAutoTags = oldAutoTags; + break; + } + case 17: // Select Child Tags. + { + d->toggleAutoTags = TagFilterView::NoToggleAuto; + toggleChildTags(album, true); + TAlbumCheckListItem *item = (TAlbumCheckListItem*)album->extraData(d->tagsView); + item->setOn(true); + d->toggleAutoTags = oldAutoTags; + break; + } + case 18: // Deselect Child Tags. + { + d->toggleAutoTags = TagFilterView::NoToggleAuto; + toggleChildTags(album, false); + TAlbumCheckListItem *item = (TAlbumCheckListItem*)album->extraData(d->tagsView); + item->setOn(false); + d->toggleAutoTags = oldAutoTags; + break; + } + case 19: // Select Parent Tags. + { + d->toggleAutoTags = TagFilterView::NoToggleAuto; + toggleParentTags(album, true); + TAlbumCheckListItem *item = (TAlbumCheckListItem*)album->extraData(d->tagsView); + item->setOn(true); + d->toggleAutoTags = oldAutoTags; + break; + } + case 20: // Deselect Parent Tags. + { + d->toggleAutoTags = TagFilterView::NoToggleAuto; + toggleParentTags(album, false); + TAlbumCheckListItem *item = (TAlbumCheckListItem*)album->extraData(d->tagsView); + item->setOn(false); + d->toggleAutoTags = oldAutoTags; + break; + } + case 21: // No toggle auto tags. + { + d->toggleAutoTags = TagFilterView::NoToggleAuto; + break; + } + case 22: // Toggle auto Children tags. + { + d->toggleAutoTags = TagFilterView::Children; + break; + } + case 23: // Toggle auto Parents tags. + { + d->toggleAutoTags = TagFilterView::Parents; + break; + } + case 24: // Toggle auto Children and Parents tags. + { + d->toggleAutoTags = TagFilterView::ChildrenAndParents; + break; + } + default: + break; + } + + if ( choice > 100 ) + { + tagNew(album, d->ABCMenu->text( choice ), "tag-people" ); + } + + delete d->ABCMenu; + d->ABCMenu = 0; +} + +void ImageDescEditTab::slotABCContextMenu() +{ + d->ABCMenu->clear(); + + int counter = 100; + TDEABC::AddressBook* ab = TDEABC::StdAddressBook::self(); + TQStringList names; + for ( TDEABC::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 ImageDescEditTab::slotMoreMenu() +{ + d->moreMenu->clear(); + + if (singleSelection()) + { + d->moreMenu->insertItem(i18n("Read metadata from file to database"), this, TQ_SLOT(slotReadFromFileMetadataToDatabase())); + int writeActionId = d->moreMenu->insertItem(i18n("Write metadata to each file"), this, TQ_SLOT(slotWriteToFileMetadataFromDatabase())); + // we do not need a "Write to file" action here because the apply button will do just that + // if selection is a single file. + // Adding the option will confuse users: Does the apply button not write to file? + // Removing the option will confuse users: There is not option to write to file! (not visible in single selection) + // Disabling will confuse users: Why is it disabled? + d->moreMenu->setItemEnabled(writeActionId, false); + } + else + { + // We need to make clear that this action is different from the Apply button, + // which saves the same changes to all files. These batch operations operate on each single file. + d->moreMenu->insertItem(i18n("Read metadata from each file to database"), this, TQ_SLOT(slotReadFromFileMetadataToDatabase())); + d->moreMenu->insertItem(i18n("Write metadata to each file"), this, TQ_SLOT(slotWriteToFileMetadataFromDatabase())); + } +} + +void ImageDescEditTab::tagNew(TAlbum* parAlbum, const TQString& _title, const TQString& _icon) const +{ + if (!parAlbum) + return; + + TQString title = _title; + TQString icon = _icon; + + if (title.isNull()) + { + if (!TagEditDlg::tagCreate(kapp->activeWindow(), parAlbum, title, icon)) + return; + } + + TQMap<TQString, TQString> errMap; + AlbumList tList = TagEditDlg::createTAlbum(parAlbum, title, icon, errMap); + TagEditDlg::showtagsListCreationError(kapp->activeWindow(), errMap); + + for (AlbumList::iterator it = tList.begin(); it != tList.end(); ++it) + { + TAlbumCheckListItem* item = (TAlbumCheckListItem*)(*it)->extraData(d->tagsView); + if (item) + { + item->setOn(true); + d->tagsView->setSelected(item, true); + d->tagsView->ensureItemVisible(item); + } + } +} + +void ImageDescEditTab::tagDelete(TAlbum *album) +{ + if (!album || album->isRoot()) + return; + + AlbumManager *albumMan = AlbumManager::instance(); + + if (album == albumMan->currentAlbum() || + album->isAncestorOf(albumMan->currentAlbum())) + { + KMessageBox::error(this, i18n("You are currently viewing items in the " + "tag '%1' that you are about to delete. " + "You will need to apply change first " + "if you want to delete the tag." ) + .arg(album->title())); + return; + } + + // find number of subtags + int children = 0; + AlbumIterator iter(album); + while(iter.current()) + { + children++; + ++iter; + } + + 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(album->title())); + + if(result != KMessageBox::Continue) + return; + } + + TQString message; + LLongList assignedItems = albumMan->albumDB()->getItemIDsInTag(album->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(album->title()); + } + else + { + message = i18n("Delete '%1' tag?").arg(album->title()); + } + + int result = KMessageBox::warningContinueCancel(this, message, + i18n("Delete Tag"), + KGuiItem(i18n("Delete"), + "edit-delete")); + + if (result == KMessageBox::Continue) + { + TQString errMsg; + if (!albumMan->deleteTAlbum(album, errMsg)) + KMessageBox::error(this, errMsg); + } +} + +void ImageDescEditTab::tagEdit(TAlbum* album) +{ + if (!album || album->isRoot()) + return; + + TQString title; + TQString icon; + + if (!TagEditDlg::tagEdit(kapp->activeWindow(), album, title, icon)) + return; + + AlbumManager *albumMan = AlbumManager::instance(); + if (album->title() != title) + { + TQString errMsg; + if (!albumMan->renameTAlbum(album, title, errMsg)) + { + KMessageBox::error(this, errMsg); + return; + } + } + + if (album->icon() != icon) + { + TQString errMsg; + if (!albumMan->updateTAlbumIcon(album, icon, 0, errMsg)) + { + KMessageBox::error(this, errMsg); + } + } +} + +void ImageDescEditTab::slotAlbumAdded(Album* a) +{ + if (!a || a->type() != Album::TAG) + return; + + TAlbumCheckListItem* viewItem = 0; + + TAlbum* tag = dynamic_cast<TAlbum*>(a); + if (!tag) + return; + + if (tag->isRoot()) + { + viewItem = new TAlbumCheckListItem(d->tagsView, tag); + } + else + { + TAlbumCheckListItem* parent = (TAlbumCheckListItem*)(tag->parent()->extraData(d->tagsView)); + if (!parent) + { + DWarning() << k_funcinfo << "Failed to find parent for Tag " << tag->title() + << endl; + return; + } + + viewItem = new TAlbumCheckListItem(parent, tag); + d->tagsSearchBar->lineEdit()->completionObject()->addItem(tag->title()); + d->newTagEdit->lineEdit()->completionObject()->addItem(tag->tagPath()); + d->newTagEdit->lineEdit()->completionObject()->addItem(tag->tagPath().remove(0, 1)); // without root "/" + } + + if (viewItem) + { + // commenting this out due to the issues described in bug 148166. + // viewItem->setOpen(true); + setTagThumbnail(tag); + } +} + +void ImageDescEditTab::slotAlbumDeleted(Album* a) +{ + if (!a || a->isRoot() || a->type() != Album::TAG) + return; + + TAlbum* album = (TAlbum*)a; + + d->tagsSearchBar->lineEdit()->completionObject()->removeItem(album->title()); + d->newTagEdit->lineEdit()->completionObject()->removeItem(album->tagPath()); + d->newTagEdit->lineEdit()->completionObject()->removeItem(album->tagPath().remove(0, 1)); // without root "/" + TAlbumCheckListItem* viewItem = (TAlbumCheckListItem*)album->extraData(d->tagsView); + delete viewItem; + album->removeExtraData(this); + d->hub.setTag(album, false, MetadataHub::MetadataDisjoint); +} + +void ImageDescEditTab::slotAlbumsCleared() +{ + d->tagsView->clear(); + d->tagsSearchBar->lineEdit()->completionObject()->clear(); + d->newTagEdit->lineEdit()->completionObject()->clear(); +} + +void ImageDescEditTab::slotAlbumIconChanged(Album* a) +{ + if (!a || a->isRoot() || a->type() != Album::TAG) + return; + + setTagThumbnail((TAlbum *)a); +} + +void ImageDescEditTab::slotAlbumMoved(TAlbum* tag, TAlbum* newParent) +{ + if (!tag || !newParent) + return; + + TAlbumCheckListItem* item = (TAlbumCheckListItem*)tag->extraData(d->tagsView); + if (!item) + return; + + if (item->parent()) + { + TQListViewItem* oldPItem = item->parent(); + oldPItem->takeItem(item); + } + else + { + d->tagsView->takeItem(item); + } + + TAlbumCheckListItem* newPItem = (TAlbumCheckListItem*)newParent->extraData(d->tagsView); + if (newPItem) + newPItem->insertItem(item); + else + d->tagsView->insertItem(item); +} + +void ImageDescEditTab::slotAlbumRenamed(Album* album) +{ + if (!album || album->isRoot() || album->type() != Album::TAG) + return; + + TAlbum* tag = (TAlbum*)album; + d->tagsSearchBar->lineEdit()->completionObject()->addItem(tag->title()); + d->newTagEdit->lineEdit()->completionObject()->addItem(tag->tagPath()); + d->newTagEdit->lineEdit()->completionObject()->addItem(tag->tagPath().remove(0, 1)); // without root "/" + slotTagsSearchChanged(d->tagsSearchBar->lineEdit()->text()); + TAlbumCheckListItem* item = (TAlbumCheckListItem*)(tag->extraData(d->tagsView)); + if (item) + item->refresh(); +} + +void ImageDescEditTab::toggleChildTags(TAlbum *album, bool b) +{ + if (!album) + return; + + AlbumIterator it(album); + while ( it.current() ) + { + TAlbum *ta = (TAlbum*)it.current(); + TAlbumCheckListItem *item = (TAlbumCheckListItem*)(ta->extraData(d->tagsView)); + if (item) + if (item->isVisible()) + item->setOn(b); + ++it; + } +} + +void ImageDescEditTab::toggleParentTags(TAlbum *album, bool b) +{ + if (!album) + return; + + TQListViewItemIterator it(d->tagsView); + while (it.current()) + { + TAlbumCheckListItem* item = dynamic_cast<TAlbumCheckListItem*>(it.current()); + if (item->isVisible()) + { + if (!item->album()) + continue; + if (item->album() == album->parent()) + { + item->setOn(b); + toggleParentTags(item->album() , b); + } + } + ++it; + } +} + +void ImageDescEditTab::setTagThumbnail(TAlbum *album) +{ + if(!album) + return; + + TAlbumCheckListItem* item = (TAlbumCheckListItem*)album->extraData(d->tagsView); + + 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); + } + } +} + +void ImageDescEditTab::slotGotThumbnailFromIcon(Album *album, const TQPixmap& thumbnail) +{ + if(!album || album->type() != Album::TAG) + return; + + // update item in tags tree + TAlbumCheckListItem* item = (TAlbumCheckListItem*)album->extraData(d->tagsView); + if(!item) + return; + + AlbumThumbnailLoader *loader = AlbumThumbnailLoader::instance(); + TQPixmap blendedIcon = loader->blendIcons(loader->getStandardTagIcon(), thumbnail); + item->setPixmap(0, blendedIcon); + + // update item in recent tags popup menu, if found there in + TQPopupMenu *menu = d->recentTagsBtn->popup(); + if (menu->indexOf(album->id()) != -1) + { + menu->changeItem(album->id(), thumbnail, menu->text(album->id())); + } +} + +void ImageDescEditTab::slotThumbnailLost(Album *) +{ + // we already set the standard icon before loading +} + +void ImageDescEditTab::slotReloadThumbnails() +{ + AlbumList tList = AlbumManager::instance()->allTAlbums(); + for (AlbumList::iterator it = tList.begin(); it != tList.end(); ++it) + { + TAlbum* tag = (TAlbum*)(*it); + setTagThumbnail(tag); + } +} + +void ImageDescEditTab::slotImageTagsChanged(TQ_LLONG imageId) +{ + // don't lose modifications + if (d->ignoreImageAttributesWatch || d->modified) + return; + + reloadForMetadataChange(imageId); +} + +void ImageDescEditTab::slotImagesChanged(int albumId) +{ + if (d->ignoreImageAttributesWatch || d->modified) + return; + + Album *a = AlbumManager::instance()->findAlbum(albumId); + if (d->currInfos.isEmpty() || !a || a->isRoot() || a->type() != Album::TAG) + return; + + setInfos(d->currInfos); +} + +void ImageDescEditTab::slotImageRatingChanged(TQ_LLONG imageId) +{ + if (d->ignoreImageAttributesWatch || d->modified) + return; + + reloadForMetadataChange(imageId); +} + +void ImageDescEditTab::slotImageCaptionChanged(TQ_LLONG imageId) +{ + if (d->ignoreImageAttributesWatch || d->modified) + return; + + reloadForMetadataChange(imageId); +} + +void ImageDescEditTab::slotImageDateChanged(TQ_LLONG imageId) +{ + if (d->ignoreImageAttributesWatch || d->modified) + return; + + reloadForMetadataChange(imageId); +} + +// private common code for above methods +void ImageDescEditTab::reloadForMetadataChange(TQ_LLONG imageId) +{ + if (d->currInfos.isEmpty()) + return; + + if (singleSelection()) + { + if (d->currInfos.first()->id() == imageId) + setInfos(d->currInfos); + } + else + { + // if image id is in our list, update + for (ImageInfo *info = d->currInfos.first(); info; info = d->currInfos.next()) + { + if (info->id() == imageId) + { + setInfos(d->currInfos); + return; + } + } + } +} + +void ImageDescEditTab::updateRecentTags() +{ + TQPopupMenu *menu = d->recentTagsBtn->popup(); + menu->clear(); + + AlbumManager* albumMan = AlbumManager::instance(); + IntList recentTags = albumMan->albumDB()->getRecentlyAssignedTags(); + + if (recentTags.isEmpty()) + { + menu->insertItem(i18n("No Recently Assigned Tags"), 0); + menu->setItemEnabled(0, false); + } + else + { + for (IntList::const_iterator it = recentTags.begin(); + it != recentTags.end(); ++it) + { + TAlbum* album = albumMan->findTAlbum(*it); + if (album) + { + AlbumThumbnailLoader *loader = AlbumThumbnailLoader::instance(); + TQPixmap icon; + if (!loader->getTagThumbnail(album, icon)) + { + if (icon.isNull()) + { + icon = loader->getStandardTagIcon(album, AlbumThumbnailLoader::SmallerSize); + } + } + TQString text = album->title() + " (" + ((TAlbum*)album->parent())->prettyURL() + ')'; + menu->insertItem(icon, text, album->id()); + } + } + } +} + +void ImageDescEditTab::slotRecentTagsMenuActivated(int id) +{ + AlbumManager* albumMan = AlbumManager::instance(); + + if (id > 0) + { + TAlbum* album = albumMan->findTAlbum(id); + if (album) + { + TAlbumCheckListItem* viewItem = (TAlbumCheckListItem*)album->extraData(d->tagsView); + if (viewItem) + { + viewItem->setOn(true); + d->tagsView->setSelected(viewItem, true); + d->tagsView->ensureItemVisible(viewItem); + } + } + } +} + +void ImageDescEditTab::slotTagsSearchChanged(const TQString& filter) +{ + if (filter.isEmpty()) + { + d->tagsView->collapseView(FolderView::OmitRoot); + return; + } + + //TODO: this will destroy assigned-tags filtering. Unify in one method. + TQString search = filter.lower(); + + bool atleastOneMatch = false; + + AlbumList tList = AlbumManager::instance()->allTAlbums(); + for (AlbumList::iterator it = tList.begin(); it != tList.end(); ++it) + { + TAlbum* tag = (TAlbum*)(*it); + + // don't touch the root Tag + if (tag->isRoot()) + continue; + + bool match = tag->title().lower().contains(search); + bool doesExpand = false; + if (!match) + { + // check if any of the parents match the search + Album* parent = tag->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(tag); + while (it.current()) + { + if ((*it)->title().lower().contains(search)) + { + match = true; + doesExpand = true; + break; + } + ++it; + } + } + + TAlbumCheckListItem* viewItem = (TAlbumCheckListItem*)(tag->extraData(d->tagsView)); + + if (match) + { + atleastOneMatch = true; + + if (viewItem) + { + viewItem->setVisible(true); + viewItem->setOpen(doesExpand); + } + } + else + { + if (viewItem) + { + viewItem->setVisible(false); + viewItem->setOpen(false); + } + } + } + + if (search.isEmpty()) + { + TAlbum* root = AlbumManager::instance()->findTAlbum(0); + TAlbumCheckListItem* rootItem = (TAlbumCheckListItem*)(root->extraData(d->tagsView)); + if (rootItem) + rootItem->setText(0, root->title()); + } + else + { + TAlbum* root = AlbumManager::instance()->findTAlbum(0); + TAlbumCheckListItem* rootItem = (TAlbumCheckListItem*)(root->extraData(d->tagsView)); + if (rootItem) + rootItem->setText(0, i18n("Found Tags")); + } + + emit signalTagFilterMatch(atleastOneMatch); +} + +void ImageDescEditTab::slotAssignedTagsToggled(bool t) +{ + //TODO: this will destroy name filtering. Unify in one method. + TQListViewItemIterator it(d->tagsView); + while (it.current()) + { + TAlbumCheckListItem* item = dynamic_cast<TAlbumCheckListItem*>(it.current()); + TAlbum *tag = item->album(); + if (tag) + { + if (!tag->isRoot()) + { + if (t) + { + MetadataHub::TagStatus status = d->hub.tagStatus(item->album()); + bool tagAssigned = (status == MetadataHub::MetadataAvailable && status.hasTag) + || status == MetadataHub::MetadataDisjoint; + item->setVisible(tagAssigned); + + if (tagAssigned) + { + Album* parent = tag->parent(); + while (parent && !parent->isRoot()) + { + TAlbumCheckListItem *pitem = (TAlbumCheckListItem*)parent->extraData(d->tagsView); + pitem->setVisible(true); + parent = parent->parent(); + } + } + } + else + { + item->setVisible(true); + } + } + } + ++it; + } + + // correct visibilities afterwards: + // As TQListViewItem::setVisible works recursively on all it's children + // we have to correct this + if (t) + { + it = d->tagsView; + while (it.current()) + { + TAlbumCheckListItem* item = dynamic_cast<TAlbumCheckListItem*>(it.current()); + TAlbum *tag = item->album(); + if (tag) + { + if (!tag->isRoot()) + { + // only if the current item is not marked as tagged, check all children + MetadataHub::TagStatus status = d->hub.tagStatus(item->album()); + bool tagAssigned = (status == MetadataHub::MetadataAvailable && status.hasTag) + || status == MetadataHub::MetadataDisjoint; + if (!tagAssigned) + { + bool somethingIsSet = false; + TQListViewItem* nextSibling = (*it)->nextSibling(); + TQListViewItemIterator tmpIt = it; + ++tmpIt; + while (*tmpIt != nextSibling ) + { + TAlbumCheckListItem* tmpItem = dynamic_cast<TAlbumCheckListItem*>(tmpIt.current()); + MetadataHub::TagStatus tmpStatus = d->hub.tagStatus(tmpItem->album()); + bool tmpTagAssigned = (tmpStatus == MetadataHub::MetadataAvailable && tmpStatus.hasTag) + || tmpStatus == MetadataHub::MetadataDisjoint; + if(tmpTagAssigned) + { + somethingIsSet = true; + } + ++tmpIt; + } + if (!somethingIsSet) + { + item->setVisible(false); + } + } + } + } + ++it; + } + } + + TAlbum *root = AlbumManager::instance()->findTAlbum(0); + TAlbumCheckListItem *rootItem = (TAlbumCheckListItem*)(root->extraData(d->tagsView)); + if (rootItem) + { + if (t) + rootItem->setText(0, i18n("Assigned Tags")); + else + rootItem->setText(0, root->title()); + } +} + +void ImageDescEditTab::refreshTagsView() +{ + d->tagsView->refresh(); +} + +void ImageDescEditTab::slotCreateNewTag() +{ + TQString tagStr = d->newTagEdit->text(); + if (tagStr.isEmpty()) return; + + TAlbum *mainRootAlbum = 0; + TAlbumCheckListItem* item = dynamic_cast<TAlbumCheckListItem*>(d->tagsView->selectedItem()); + if (item) + mainRootAlbum = item->album(); + + TQMap<TQString, TQString> errMap; + AlbumList tList = TagEditDlg::createTAlbum(mainRootAlbum, tagStr, TQString("tag"), errMap); + + for (AlbumList::iterator it = tList.begin(); it != tList.end(); ++it) + { + TAlbumCheckListItem* item = (TAlbumCheckListItem*)(*it)->extraData(d->tagsView); + if (item) + { + item->setOn(true); + d->tagsView->ensureItemVisible(item); + } + } + + d->newTagEdit->lineEdit()->clear(); +} + +} // NameSpace Digikam |