/* ============================================================ * * 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 * Copyright (C) 2003-2009 by Gilles Caulier * Copyright (C) 2006-2009 by Marcel Wiesweg * 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 #include #include #include #include #include // KDE includes. #include #include #include #include #include #include #include #include #include #include #include #include // 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 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, TQT_SIGNAL(signalProgressBarMode(int, const TQString&)), this, TQT_SIGNAL(signalProgressBarMode(int, const TQString&))); connect(d->tagsView, TQT_SIGNAL(signalProgressValue(int)), this, TQT_SIGNAL(signalProgressValue(int))); connect(popupMenu, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotRecentTagsMenuActivated(int))); connect(d->tagsView, TQT_SIGNAL(signalItemStateChanged(TAlbumCheckListItem *)), this, TQT_SLOT(slotItemStateChanged(TAlbumCheckListItem *))); connect(d->commentsEdit, TQT_SIGNAL(textChanged()), this, TQT_SLOT(slotCommentChanged())); connect(d->dateTimeEdit, TQT_SIGNAL(dateTimeChanged(const TQDateTime& )), this, TQT_SLOT(slotDateTimeChanged(const TQDateTime&))); connect(d->ratingWidget, TQT_SIGNAL(signalRatingChanged(int)), this, TQT_SLOT(slotRatingChanged(int))); connect(d->tagsView, TQT_SIGNAL(rightButtonClicked(TQListViewItem*, const TQPoint &, int)), this, TQT_SLOT(slotRightButtonClicked(TQListViewItem*, const TQPoint&, int))); connect(d->tagsSearchBar, TQT_SIGNAL(signalTextChanged(const TQString&)), this, TQT_SLOT(slotTagsSearchChanged(const TQString&))); connect(this, TQT_SIGNAL(signalTagFilterMatch(bool)), d->tagsSearchBar, TQT_SLOT(slotSearchResult(bool))); connect(d->assignedTagsBtn, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotAssignedTagsToggled(bool))); connect(d->newTagEdit->lineEdit(), TQT_SIGNAL(returnPressed(const TQString&)), this, TQT_SLOT(slotCreateNewTag())); connect(d->applyBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotApplyAllChanges())); connect(d->revertBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotRevertAllChanges())); connect(d->moreMenu, TQT_SIGNAL(aboutToShow()), this, TQT_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, TQT_SIGNAL(signalAlbumAdded(Album*)), this, TQT_SLOT(slotAlbumAdded(Album*))); connect(man, TQT_SIGNAL(signalAlbumDeleted(Album*)), this, TQT_SLOT(slotAlbumDeleted(Album*))); connect(man, TQT_SIGNAL(signalAlbumRenamed(Album*)), this, TQT_SLOT(slotAlbumRenamed(Album*))); connect(man, TQT_SIGNAL(signalAlbumsCleared()), this, TQT_SLOT(slotAlbumsCleared())); connect(man, TQT_SIGNAL(signalAlbumIconChanged(Album*)), this, TQT_SLOT(slotAlbumIconChanged(Album*))); connect(man, TQT_SIGNAL(signalTAlbumMoved(TAlbum*, TAlbum*)), this, TQT_SLOT(slotAlbumMoved(TAlbum*, TAlbum*))); // Connect to thumbnail loader ----------------------------- 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 to attribute watch ------------------------------ ImageAttributesWatch *watch = ImageAttributesWatch::instance(); connect(watch, TQT_SIGNAL(signalImageTagsChanged(TQ_LLONG)), this, TQT_SLOT(slotImageTagsChanged(TQ_LLONG))); connect(watch, TQT_SIGNAL(signalImagesChanged(int)), this, TQT_SLOT(slotImagesChanged(int))); connect(watch, TQT_SIGNAL(signalImageRatingChanged(TQ_LLONG)), this, TQT_SLOT(slotImageRatingChanged(TQ_LLONG))); connect(watch, TQT_SIGNAL(signalImageDateChanged(TQ_LLONG)), this, TQT_SLOT(slotImageDateChanged(TQ_LLONG))); connect(watch, TQT_SIGNAL(signalImageCaptionChanged(TQ_LLONG)), this, TQT_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("

You have edited the comment of the image. ", "

You have edited the comment of %n images. ", d->currInfos.count()); else if (d->hub.dateTimeChanged()) text = i18n("

You have edited the date of the image. ", "

You have edited the date of %n images. ", d->currInfos.count()); else if (d->hub.ratingChanged()) text = i18n("

You have edited the rating of the image. ", "

You have edited the rating of %n images. ", d->currInfos.count()); else if (d->hub.tagsChanged()) text = i18n("

You have edited the tags of the image. ", "

You have edited the tags of %n images. ", d->currInfos.count()); text += i18n("Do you want to apply your changes?

"); } else { text = i18n("

You have edited the metadata of the image:

    ", "

    You have edited the metadata of %n images:

      ", d->currInfos.count()); if (d->hub.commentChanged()) text += i18n("
    • comment
    • "); if (d->hub.dateTimeChanged()) text += i18n("
    • date
    • "); if (d->hub.ratingChanged()) text += i18n("
    • rating
    • "); if (d->hub.tagsChanged()) text += i18n("
    • tags
    • "); text += "

    "; text += i18n("Do you want to apply your changes?

    "); } 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 list; if (info) list.append(info); setInfos(list); } void ImageDescEditTab::setItems(TQPtrList infos) { slotChangingItems(); setInfos(infos); } void ImageDescEditTab::setInfos(TQPtrList 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(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(item); if(!viewItem) album = AlbumManager::instance()->findTAlbum(0); else album = viewItem->album(); } if(!album) return; d->ABCMenu = new TQPopupMenu; connect(d->ABCMenu, TQT_SIGNAL( aboutToShow() ), this, TQT_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(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(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(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; 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 ImageDescEditTab::slotMoreMenu() { d->moreMenu->clear(); if (singleSelection()) { d->moreMenu->insertItem(i18n("Read metadata from file to database"), this, TQT_SLOT(slotReadFromFileMetadataToDatabase())); int writeActionId = d->moreMenu->insertItem(i18n("Write metadata to each file"), this, TQT_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, TQT_SLOT(slotReadFromFileMetadataToDatabase())); d->moreMenu->insertItem(i18n("Write metadata to each file"), this, TQT_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(TQT_TQWIDGET(TQT_TQWIDGET(kapp->activeWindow())), parAlbum, title, icon)) return; } TQMap errMap; AlbumList tList = TagEditDlg::createTAlbum(parAlbum, title, icon, errMap); TagEditDlg::showtagsListCreationError(TQT_TQWIDGET(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"), "editdelete")); 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(TQT_TQWIDGET(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(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(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(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(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(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(d->tagsView->selectedItem()); if (item) mainRootAlbum = item->album(); TQMap 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