void TagModificationHelper::slotTagDelete(TAlbum* t) { if (!t || t->isRoot()) { return; } AlbumPointer<TAlbum> tag(t); // find number of subtags int children = 0; AlbumIterator iter(tag); while (iter.current()) { ++children; ++iter; } // ask for deletion of children if (children) { int result = KMessageBox::warningContinueCancel(d->dialogParent, i18np("Tag '%2' has one subtag. " "Deleting this will also delete " "the subtag. " "Do you want to continue?", "Tag '%2' has %1 subtags. " "Deleting this will also delete " "the subtags. " "Do you want to continue?", children, tag->title())); if (result != KMessageBox::Continue || !tag) { return; } } QString message; QList<qlonglong> assignedItems = DatabaseAccess().db()->getItemIDsInTag(tag->id()); if (!assignedItems.isEmpty()) { message = i18np("Tag '%2' is assigned to one item. " "Do you want to continue?", "Tag '%2' is assigned to %1 items. " "Do you want to continue?", assignedItems.count(), tag->title()); } else { message = i18n("Delete '%1' tag?", tag->title()); } int result = KMessageBox::warningContinueCancel(0, message, i18n("Delete Tag"), KGuiItem(i18n("Delete"), "edit-delete")); if (result == KMessageBox::Continue && tag) { emit aboutToDeleteTag(tag); QString errMsg; if (!AlbumManager::instance()->deleteTAlbum(tag, errMsg)) { KMessageBox::error(0, errMsg); } } }
void ImageScanner::scanImageInformation() { DatabaseFields::ImageInformation dbFields = DatabaseFields::ImageInformationAll; QVariantList infos; if (m_scanMode == NewScan || m_scanMode == Rescan) { MetadataFields fields; fields << MetadataInfo::Rating << MetadataInfo::CreationDate << MetadataInfo::DigitizationDate << MetadataInfo::Orientation; QVariantList metadataInfos = m_metadata.getMetadataFields(fields); // creation date: fall back to file system property if (metadataInfos[1].isNull() || !metadataInfos[1].toDateTime().isValid()) { metadataInfos[1] = creationDateFromFilesystem(m_fileInfo); } // Some fields should only be overwritten if set in metadata if (m_scanMode == Rescan) { if (metadataInfos[0].isNull() || metadataInfos[0].toInt() == -1) { dbFields &= ~DatabaseFields::Rating; metadataInfos.removeAt(0); } } infos << metadataInfos; } QSize size = m_img.size(); infos << size.width() << size.height() << detectFormat() << m_img.originalBitDepth() << m_img.originalColorModel(); if (m_scanMode == NewScan) { DatabaseAccess().db()->addImageInformation(m_scanInfo.id, infos, dbFields); } else if (m_scanMode == Rescan) { DatabaseAccess().db()->changeImageInformation(m_scanInfo.id, infos, dbFields); } else // ModifiedScan { // Does _not_ update rating and orientation! DatabaseAccess().db()->changeImageInformation(m_scanInfo.id, infos, DatabaseFields::Width | DatabaseFields::Height | DatabaseFields::Format | DatabaseFields::ColorDepth | DatabaseFields::ColorModel); } }
void ImageScanner::scanTags() { // Check Keywords tag paths. QVariant var = m_metadata.getMetadataField(MetadataInfo::Keywords); QStringList keywords = var.toStringList(); if (!keywords.isEmpty()) { // get tag ids, create if necessary QList<int> tagIds = TagsCache::instance()->getOrCreateTags(keywords); DatabaseAccess().db()->addTagsToItems(QList<qlonglong>() << m_scanInfo.id, tagIds); } // Check Pick Label tag. int pickId = m_metadata.getImagePickLabel(); if (pickId != -1) { kDebug() << "Pick Label found : " << pickId; int tagId = TagsCache::instance()->getTagForPickLabel((PickLabel)pickId); if (tagId) { DatabaseAccess().db()->addTagsToItems(QList<qlonglong>() << m_scanInfo.id, QList<int>() << tagId); kDebug() << "Assigned Pick Label Tag : " << tagId; } else { kDebug() << "Cannot find Pick Label Tag for : " << pickId; } } // Check Color Label tag. int colorId = m_metadata.getImageColorLabel(); if (colorId != -1) { kDebug() << "Color Label found : " << colorId; int tagId = TagsCache::instance()->getTagForColorLabel((ColorLabel)colorId); if (tagId) { DatabaseAccess().db()->addTagsToItems(QList<qlonglong>() << m_scanInfo.id, QList<int>() << tagId); kDebug() << "Assigned Color Label Tag : " << tagId; } else { kDebug() << "Cannot find Color Label Tag for : " << colorId; } } }
bool ImageScanner::resolveImageHistory(qlonglong imageId, const QString& historyXml, QList<qlonglong>* needTaggingIds) { /** Stage 2 of history scanning */ if (historyXml.isNull()) { return true; // "true" means nothing is left to resolve } DImageHistory history = DImageHistory::fromXml(historyXml); if (history.isNull()) { return true; } ImageHistoryGraph graph; graph.addScannedHistory(history, imageId); if (!graph.hasEdges()) { return true; } QPair<QList<qlonglong>, QList<qlonglong> > cloud = graph.relationCloudParallel(); DatabaseAccess().db()->addImageRelations(cloud.first, cloud.second, DatabaseRelation::DerivedFrom); int needResolvingTag = TagsCache::instance()->getOrCreateInternalTag(InternalTagName::needResolvingHistory()); int needTaggingTag = TagsCache::instance()->getOrCreateInternalTag(InternalTagName::needTaggingHistoryGraph()); // remove the needResolvingHistory tag from all images in graph DatabaseAccess().db()->removeTagsFromItems(graph.allImageIds(), QList<int>() << needResolvingTag); // mark a single image from the graph (sufficient for find the full relation cloud) QList<ImageInfo> roots = graph.rootImages(); if (!roots.isEmpty()) { DatabaseAccess().db()->addItemTag(roots.first().id(), needTaggingTag); if (needTaggingIds) { *needTaggingIds << roots.first().id(); } } return !graph.hasUnresolvedEntries(); }
void ImageScanner::updateImage() { prepareImage(); DatabaseAccess().db()->updateItem(m_scanInfo.id, m_scanInfo.category, m_scanInfo.modificationDate, m_scanInfo.fileSize, m_scanInfo.uniqueHash); }
void ImageLister::listAlbum(ImageListerReceiver* const receiver, int albumRootId, const QString& album) { if (d->listOnlyAvailableImages) { if (!CollectionManager::instance()->locationForAlbumRootId(albumRootId).isAvailable()) { return; } } QList<QVariant> albumIds; if (d->recursive) { QList<int> intAlbumIds = DatabaseAccess().db()->getAlbumAndSubalbumsForPath(albumRootId, album); if (intAlbumIds.isEmpty()) { return; } foreach(int id, intAlbumIds) { albumIds << id; } }
void TagProperties::removeProperty(const QString& key, const QString& value) { if (d->properties.contains(key, value)) { DatabaseAccess().db()->removeTagProperties(d->tagId, key, value); d->properties.remove(key, value); } }
void TagProperties::removeProperties(const QString& key) { if (!d->isNull() && d->properties.contains(key)) { DatabaseAccess().db()->removeTagProperties(d->tagId, key); d->properties.remove(key); } }
void ImageScanner::scanImageMetadata() { QVariantList metadataInfos = m_metadata.getMetadataFields(allImageMetadataFields()); if (hasValidField(metadataInfos)) { DatabaseAccess().db()->addImageMetadata(m_scanInfo.id, metadataInfos); } }
void TagProperties::addProperty(const QString& key, const QString& value) { if (d->isNull() || d->properties.contains(key, value)) { return; } d->properties.insert(key, value); DatabaseAccess().db()->addTagProperty(d->tagId, key, value); }
void ImageScanner::scanImageHistoryIfModified() { // If a file has a modified history, it must have a new UUID QString previousUuid = DatabaseAccess().db()->getImageUuid(m_scanInfo.id); QString currentUuid = m_metadata.getImageUniqueId(); if (previousUuid != currentUuid) { scanImageHistory(); } }
bool ImageScanner::scanFromIdenticalFile() { // Get a list of other images that are identical. Source image shall not be included. QList<ItemScanInfo> candidates = DatabaseAccess().db()->getIdenticalFiles(m_scanInfo.uniqueHash, m_scanInfo.fileSize, m_scanInfo.id); if (!candidates.isEmpty()) { // Sort by priority, as implemented by custom lessThan() qStableSort(candidates.begin(), candidates.end(), lessThanForIdentity); kDebug() << "Recognized" << m_fileInfo.filePath() << "as identical to item" << candidates.first().id; // Copy attributes. // Todo for the future is to worry about syncing identical files. DatabaseAccess().db()->copyImageAttributes(candidates.first().id, m_scanInfo.id); return true; } return false; }
void TagProperties::setProperty(const QString& key, const QString& value) { if (d->properties.contains(key, value) && d->properties.count(key) == 1) { return; } // for single entries in db, this can of course be optimized using a single UPDATE WHERE removeProperties(key); d->properties.insert(key, value); DatabaseAccess().db()->addTagProperty(d->tagId, key, value); }
void ImageScanner::addImage(int albumId) { prepareImage(); m_scanInfo.albumID = albumId; m_scanInfo.status = DatabaseItem::Visible; kDebug() << "Adding new item" << m_fileInfo.filePath(); m_scanInfo.id = DatabaseAccess().db()->addItem(m_scanInfo.albumID, m_scanInfo.itemName, m_scanInfo.status, m_scanInfo.category, m_scanInfo.modificationDate, m_scanInfo.fileSize, m_scanInfo.uniqueHash); }
void AlbumPropsEdit::slotDateHighButtonClicked() { setCursor(Qt::WaitCursor); QDate highDate = DatabaseAccess().db()->getAlbumHighestDate(d->album->id()); setCursor(Qt::ArrowCursor); if (highDate.isValid()) { d->datePicker->setDate(highDate); } }
void ImageScanner::scanImageHistory() { /** Stage 1 of history scanning */ QString historyXml = m_metadata.getImageHistory(); if (!historyXml.isEmpty()) { DatabaseAccess().db()->setImageHistory(m_scanInfo.id, historyXml); // Delay history resolution by setting this tag: // Resolution depends on the presence of other images, possibly only when the scanning process has finished DatabaseAccess().db()->addItemTag(m_scanInfo.id, TagsCache::instance()-> getOrCreateInternalTag(InternalTagName::needResolvingHistory())); m_hasHistoryToResolve = true; } QString uuid = m_metadata.getImageUniqueId(); if (!uuid.isNull()) { DatabaseAccess().db()->setImageUuid(m_scanInfo.id, uuid); } }
void AlbumPropsEdit::slotDateAverageButtonClicked() { setCursor(Qt::WaitCursor); QDate avDate = DatabaseAccess().db()->getAlbumAverageDate(d->album->id()); setCursor(Qt::ArrowCursor); if (avDate.isValid()) { d->datePicker->setDate(avDate); } else { KMessageBox::error(this, i18n("Could not calculate an average."), i18n("Could Not Calculate Average")); } }
void PatientManager::readDatabase() { QList<Patient> patients = DatabaseAccess().db()->findPatients(); emit progressStarted(patients.size()); QHash<int, int> oldIds = d->patientIdHash; QList<Patient::Ptr> newPatientList; foreach (Patient data, patients) { int index = d->patientIdHash.value(data.id, -1); oldIds.remove(data.id); if (index == -1) { Patient::Ptr p = createPatient(data); loadData(p); emit patientAdded(d->patients.size()-1, p); } else { loadData(d->patients[index]); } emit progressValue(d->patients.size()); }
void ImageScanner::scanImagePosition() { // This list must reflect the order required by AlbumDB::addImagePosition MetadataFields fields; fields << MetadataInfo::Latitude << MetadataInfo::LatitudeNumber << MetadataInfo::Longitude << MetadataInfo::LongitudeNumber << MetadataInfo::Altitude << MetadataInfo::PositionOrientation << MetadataInfo::PositionTilt << MetadataInfo::PositionRoll << MetadataInfo::PositionAccuracy << MetadataInfo::PositionDescription; QVariantList metadataInfos = m_metadata.getMetadataFields(fields); if (hasValidField(metadataInfos)) { DatabaseAccess().db()->addImagePosition(m_scanInfo.id, metadataInfos); } }
void ImageWindow::slotContextMenu() { if (m_contextMenu) { TagsPopupMenu* assignTagsMenu = 0; TagsPopupMenu* removeTagsMenu = 0; // Bulk assignment/removal of tags -------------------------- QList<qlonglong> idList; idList << d->currentImageInfo.id(); assignTagsMenu = new TagsPopupMenu(idList, TagsPopupMenu::RECENTLYASSIGNED, this); removeTagsMenu = new TagsPopupMenu(idList, TagsPopupMenu::REMOVE, this); assignTagsMenu->menuAction()->setText(i18n("Assign Tag")); removeTagsMenu->menuAction()->setText(i18n("Remove Tag")); m_contextMenu->addSeparator(); m_contextMenu->addMenu(assignTagsMenu); m_contextMenu->addMenu(removeTagsMenu); connect(assignTagsMenu, SIGNAL(signalTagActivated(int)), this, SLOT(slotAssignTag(int))); connect(removeTagsMenu, SIGNAL(signalTagActivated(int)), this, SLOT(slotRemoveTag(int))); connect(assignTagsMenu, SIGNAL(signalPopupTagsView()), d->rightSideBar, SLOT(slotPopupTagsView())); if (!DatabaseAccess().db()->hasTags( idList )) { m_contextMenu->menuAction()->setEnabled(false); } m_contextMenu->addSeparator(); // Assign Labels ------------------------------------------- KMenu* menuLabels = new KMenu(i18n("Assign Labels"), m_contextMenu); PickLabelMenuAction* pmenu = new PickLabelMenuAction(m_contextMenu); ColorLabelMenuAction* cmenu = new ColorLabelMenuAction(m_contextMenu); RatingMenuAction* rmenu = new RatingMenuAction(m_contextMenu); menuLabels->addAction(pmenu); menuLabels->addAction(cmenu); menuLabels->addAction(rmenu); m_contextMenu->addMenu(menuLabels); connect(pmenu, SIGNAL(signalPickLabelChanged(int)), this, SLOT(slotAssignPickLabel(int))); connect(cmenu, SIGNAL(signalColorLabelChanged(int)), this, SLOT(slotAssignColorLabel(int))); connect(rmenu, SIGNAL(signalRatingChanged(int)), this, SLOT(slotAssignRating(int))); // -------------------------------------------------------------- m_contextMenu->exec(QCursor::pos()); delete assignTagsMenu; delete removeTagsMenu; delete cmenu; delete pmenu; delete rmenu; delete menuLabels; } }
void TagModificationHelper::slotMultipleTagDel(QList<TAlbum* >& tags) { QString tagWithChildrens; QString tagWithImages; QMultiMap<int, TAlbum*> sortedTags; foreach(TAlbum* const t, tags) { if (!t || t->isRoot()) { continue; } AlbumPointer<TAlbum> tag(t); // find number of subtags int children = 0; AlbumIterator iter(tag); while (iter.current()) { ++children; ++iter; } if(children) tagWithChildrens.append(tag->title() + QString(" ")); QList<qlonglong> assignedItems = DatabaseAccess().db()->getItemIDsInTag(tag->id()); if(!assignedItems.isEmpty()) tagWithImages.append(tag->title() + QString(" ")); /** * Tags must be deleted from children to parents, if we don't want * to step on invalid index. Use QMultiMap to order them by distance * to root tag */ Album* parent = t; int depth = 0; while(!parent->isRoot()) { parent = parent->parent(); depth++; } sortedTags.insert(depth,tag); } // ask for deletion of children if (!tagWithChildrens.isEmpty()) { int result = KMessageBox::warningContinueCancel(0, i18n("Tags '%1' have one or more subtags. " "Deleting them will also delete " "the subtags. " "Do you want to continue?", tagWithChildrens)); if (result != KMessageBox::Continue) { return; } } QString message; if (!tagWithImages.isEmpty()) { message = i18n("Tags '%1' are assigned to one or more items. " "Do you want to continue?", tagWithImages); } else { message = i18n("Delete '%1' tag(s)?", tagWithImages); } int result = KMessageBox::warningContinueCancel(0, message, i18n("Delete Tag"), KGuiItem(i18n("Delete"), "edit-delete")); if (result == KMessageBox::Continue) { QMultiMap<int, TAlbum*>::iterator it; /** * QMultimap doesn't provide reverse iterator, -1 is required * because end() points after the last element */ for(it = sortedTags.end()-1; it != sortedTags.begin()-1; --it) { emit aboutToDeleteTag(it.value()); QString errMsg; if (!AlbumManager::instance()->deleteTAlbum(it.value(), errMsg)) { KMessageBox::error(0, errMsg); } } } }
bool ImageScanner::resolveImageHistory(qlonglong id, QList<qlonglong>* needTaggingIds) { ImageHistoryEntry history = DatabaseAccess().db()->getImageHistory(id); return resolveImageHistory(id, history.history, needTaggingIds); }
void ImageScanner::tagImageHistoryGraph(qlonglong id) { /** Stage 3 of history scanning */ ImageInfo info(id); if (info.isNull()) { return; } //kDebug() << "tagImageHistoryGraph" << id; // Load relation cloud, history of info and of all leaves of the tree into the graph, fully resolved ImageHistoryGraph graph = ImageHistoryGraph::fromInfo(info, ImageHistoryGraph::LoadAll, ImageHistoryGraph::NoProcessing); kDebug() << graph; int originalVersionTag = TagsCache::instance()->getOrCreateInternalTag(InternalTagName::originalVersion()); int currentVersionTag = TagsCache::instance()->getOrCreateInternalTag(InternalTagName::currentVersion()); int intermediateVersionTag = TagsCache::instance()->getOrCreateInternalTag(InternalTagName::intermediateVersion()); int needTaggingTag = TagsCache::instance()->getOrCreateInternalTag(InternalTagName::needTaggingHistoryGraph()); // Remove all relevant tags DatabaseAccess().db()->removeTagsFromItems(graph.allImageIds(), QList<int>() << originalVersionTag << currentVersionTag << intermediateVersionTag << needTaggingTag); if (!graph.hasEdges()) { return; } // get category info QList<qlonglong> originals, intermediates, currents; QHash<ImageInfo, HistoryImageId::Types> types = graph.categorize(); QHash<ImageInfo, HistoryImageId::Types>::iterator it; for (it = types.begin(); it != types.end(); ++it) { kDebug() << "Image" << it.key().id() << "type" << it.value(); HistoryImageId::Types types = it.value(); if (types & HistoryImageId::Original) { originals << it.key().id(); } if (types & HistoryImageId::Intermediate) { intermediates << it.key().id(); } if (types & HistoryImageId::Current) { currents << it.key().id(); } } if (!originals.isEmpty()) { DatabaseAccess().db()->addTagsToItems(originals, QList<int>() << originalVersionTag); } if (!intermediates.isEmpty()) { DatabaseAccess().db()->addTagsToItems(intermediates, QList<int>() << intermediateVersionTag); } if (!currents.isEmpty()) { DatabaseAccess().db()->addTagsToItems(currents, QList<int>() << currentVersionTag); } }