void ExtractOneVideoFrame::markShortVideo(const DB::FileName &fileName) { if (s_tokenForShortVideos.isNull()) { Utilities::StringSet usedTokens = MainWindow::TokenEditor::tokensInUse().toSet(); for ( int ch = 'A'; ch <= 'Z'; ++ch ) { QString token = QChar::fromLatin1( (char) ch ); if (!usedTokens.contains(token)) { s_tokenForShortVideos = token; break; } } if (s_tokenForShortVideos.isNull()) { // Hmmm, no free token. OK lets just skip setting tokens. return; } KMessageBox::information(MainWindow::Window::theMainWindow(), i18n("Unable to extract video thumbnails from some files. " "Either the file is damaged in some way, or the video is ultra short. " "For your convenience, the token '%1' " "has been set on those videos.\n\n" "(You might need to wait till the video extraction led in your status bar has stopped blinking, " "to see all affected videos.)", s_tokenForShortVideos)); } DB::ImageInfoPtr info = DB::ImageDB::instance()->info(fileName); DB::CategoryPtr tokensCategory = DB::ImageDB::instance()->categoryCollection()->categoryForSpecial(DB::Category::TokensCategory); info->addCategoryInfo(tokensCategory->name(), s_tokenForShortVideos); MainWindow::DirtyIndicator::markDirty(); }
void BackgroundJobs::SearchForVideosWithoutVideoThumbnailsJob::execute() { const DB::FileNameList images = DB::ImageDB::instance()->images(); for( const DB::FileName& image : images ) { const DB::ImageInfoPtr info = image.info(); if ( !info->isVideo() ) continue; // silently ignore videos not (currently) on disk: if ( ! info->fileName().exists() ) continue; const DB::FileName thumbnailName = BackgroundJobs::HandleVideoThumbnailRequestJob::frameName(info->fileName(),9); if ( thumbnailName.exists() ) continue; BackgroundJobs::ReadVideoLengthJob* readVideoLengthJob = new BackgroundJobs::ReadVideoLengthJob(info->fileName(), BackgroundTaskManager::BackgroundVideoPreviewRequest); for (int i=0; i<10; ++i) { ExtractOneThumbnailJob* extractJob = new ExtractOneThumbnailJob( info->fileName(), i, BackgroundTaskManager::BackgroundVideoPreviewRequest ); extractJob->addDependency(readVideoLengthJob); } BackgroundTaskManager::JobManager::instance()->addJob( readVideoLengthJob); } emit completed(); }
void ThumbnailView::Delegate::paintVideoInfo(QPainter *painter, const QRect& pixmapRect, const QModelIndex &index) const { DB::ImageInfoPtr imageInfo = model()->imageAt(index.row()).info(); if (!imageInfo || imageInfo->mediaType() != DB::Video ) return; const QString text = videoLengthText(imageInfo); const QRect metricsRect = painter->fontMetrics().boundingRect(text); const int margin = 3; const QRect textRect = QRect(pixmapRect.right()-metricsRect.width()-margin, pixmapRect.bottom()-metricsRect.height()-margin, metricsRect.width(), metricsRect.height()); const QRect backgroundRect = textRect.adjusted(-margin,-margin, margin, margin); if ( backgroundRect.width() > pixmapRect.width()/2 ) { // Don't show the time if the box would fill more than half the thumbnail return; } painter->save(); painter->fillRect(backgroundRect, QBrush( QColor(0,0,0,128))); painter->setPen(Qt::white); painter->drawText(textRect, text); painter->restore(); }
ImportExport::ClashInfo ImportExport::MD5CheckPage::clashes(const ImportSettings& settings) { QStringList myCategories; Q_FOREACH( const CategoryMatchSetting& matcher, settings.categoryMatchSetting() ) { myCategories.append( matcher.DBCategoryName() ); } ClashInfo res( myCategories ); DB::ImageInfoList list = settings.selectedImages(); Q_FOREACH( DB::ImageInfoPtr info, list ) { if ( !DB::ImageDB::instance()->md5Map()->contains(info->MD5Sum()) ) continue; const DB::FileName name = DB::ImageDB::instance()->md5Map()->lookup(info->MD5Sum()); DB::ImageInfoPtr other = DB::ImageDB::instance()->info(name); if ( info->label() != other->label() ) res.label = true; if ( info->description() != other->description() ) res.description = true; if ( info->angle() != other->angle() ) res.orientation = true; if (info->date() != other->date() ) res.date = true; Q_FOREACH( const CategoryMatchSetting& matcher, settings.categoryMatchSetting() ) { const QString XMLFileCategory = matcher.XMLCategoryName(); const QString DBCategory = matcher.DBCategoryName(); if ( mapCategoriesToDB( matcher, info->itemsOfCategory( XMLFileCategory ) ) != other->itemsOfCategory( DBCategory ) ) res.categories[DBCategory] = true; } } return res; }
void ExtractOneThumbnailJob::execute() { if ( m_wasCanceled || frameName().exists() ) emit completed(); else { DB::ImageInfoPtr info = DB::ImageDB::instance()->info(m_fileName); const int length = info->videoLength(); ImageManager::ExtractOneVideoFrame::extract(m_fileName, length*m_index/10.0, this, SLOT(frameLoaded(QImage))); } }
QString ThumbnailView::Delegate::videoLengthText(const DB::ImageInfoPtr &imageInfo) const { const int length = imageInfo->videoLength(); if ( length < 0 ) return i18nc("No video length could be determined, so we just display 'video' instead of the video length.","video"); const int hours = length/60/60; const int minutes = (length/60)%60; const int secs = length % 60; QString res; if (hours > 0) res = QString::number(hours) + QLatin1String(":"); if (minutes < 10 && hours > 0) res += QLatin1String("0"); res += QString::number(minutes); res += QLatin1String(":"); if (secs < 10) res += QLatin1String("0"); res += QString::number(secs); return res; }
QDomElement ImportExport::XMLHandler::save( QDomDocument doc, const DB::ImageInfoPtr& info ) { QDomElement elm = doc.createElement( QString::fromLatin1("image") ); elm.setAttribute( QString::fromLatin1("label"), info->label() ); elm.setAttribute( QString::fromLatin1("description"), info->description() ); DB::ImageDate date = info->date(); QDateTime start = date.start(); QDateTime end = date.end(); elm.setAttribute( QString::fromLatin1("yearFrom"), start.date().year() ); elm.setAttribute( QString::fromLatin1("monthFrom"), start.date().month() ); elm.setAttribute( QString::fromLatin1("dayFrom"), start.date().day() ); elm.setAttribute( QString::fromLatin1("hourFrom"), start.time().hour() ); elm.setAttribute( QString::fromLatin1("minuteFrom"), start.time().minute() ); elm.setAttribute( QString::fromLatin1("secondFrom"), start.time().second() ); elm.setAttribute( QString::fromLatin1("yearTo"), end.date().year() ); elm.setAttribute( QString::fromLatin1("monthTo"), end.date().month() ); elm.setAttribute( QString::fromLatin1("dayTo"), end.date().day() ); elm.setAttribute( QString::fromLatin1( "width" ), info->size().width() ); elm.setAttribute( QString::fromLatin1( "height" ), info->size().height() ); elm.setAttribute( QString::fromLatin1( "md5sum" ), info->MD5Sum().toHexString() ); elm.setAttribute( QString::fromLatin1( "angle" ), info->angle() ); writeCategories( doc, elm, info ); return elm; }
void ImportExport::XMLHandler::writeCategories( QDomDocument doc, QDomElement root, const DB::ImageInfoPtr& info ) { QDomElement elm = doc.createElement( QString::fromLatin1("options") ); bool anyAtAll = false; QStringList grps = info->availableCategories(); Q_FOREACH(const QString &name, grps ) { QDomElement opt = doc.createElement( QString::fromLatin1("option") ); opt.setAttribute( QString::fromLatin1("name"), name ); StringSet items = info->itemsOfCategory(name); bool any = false; Q_FOREACH( const QString &item, items ) { QDomElement val = doc.createElement( QString::fromLatin1("value") ); val.setAttribute( QString::fromLatin1("value"), item ); opt.appendChild( val ); any = true; anyAtAll = true; }
void ToolTip::requestImage( const DB::FileName& fileName ) { int size = Settings::SettingsData::instance()->previewSize(); DB::ImageInfoPtr info = DB::ImageDB::instance()->info( fileName ); if ( size != 0 ) { ImageManager::ImageRequest* request = new ImageManager::ImageRequest( fileName, QSize( size, size ), info->angle(), this ); request->setPriority( ImageManager::Viewer ); ImageManager::AsyncLoader::instance()->load( request ); } else renderToolTip(); }
void ThumbnailView::Delegate::paintStackedIndicator( QPainter* painter, const QRect &pixmapRect, const QModelIndex& index ) const { DB::ImageInfoPtr imageInfo = model()->imageAt(index.row()).info(); if (!imageInfo || !imageInfo->isStacked()) return; const QRect cellRect = widget()->visualRect( index ); // Calculate the three points for the bottom most/right most lines int leftX = cellRect.left(); int rightX = cellRect.right() + 5; // 5 for the 3D effect if ( isFirst( index.row() ) ) leftX = pixmapRect.left() + pixmapRect.width()/2; if ( isLast( index.row() ) ) rightX = pixmapRect.right(); QPoint bottomLeftPoint( leftX, pixmapRect.bottom() ); QPoint bottomRightPoint( rightX, pixmapRect.bottom() ); QPoint topPoint = isLast( index.row() ) ? QPoint( rightX, pixmapRect.top() + pixmapRect.height()/2 ) : QPoint(); // Paint the lines. painter->save(); for ( int i=0; i < 8; ++i ) { painter->setPen( QPen(i % 2 == 0 ? Qt::black : Qt::white) ); painter->drawLine(bottomLeftPoint,bottomRightPoint); if ( topPoint != QPoint() ) { painter->drawLine( bottomRightPoint, topPoint ); topPoint -= QPoint(1,1); } bottomLeftPoint -= QPoint( isFirst( index.row()) ? 1 : 0, 1 ); bottomRightPoint -= QPoint( isLast( index.row()) ? 1 : 0, 1); } painter->restore(); }
void MainWindow::ExternalPopup::populate( DB::ImageInfoPtr current, const DB::FileNameList& imageList ) { _list = imageList; _currentInfo = current; clear(); QAction *action; QStringList list = QStringList() << i18n("Current Item") << i18n("All Selected Items") << i18n("Copy and Open"); for ( int which = 0; which < 3; ++which ) { if ( which == 0 && !current ) continue; const bool multiple = (_list.count() > 1); const bool enabled = (which != 1 && _currentInfo ) || (which == 1 && multiple); // Submenu QMenu *submenu = addMenu( list[which] ); submenu->setEnabled(enabled); // Fetch set of offers OfferType offers; if ( which == 0 ) offers = appInfos( DB::FileNameList() << current->fileName() ); else offers = appInfos( imageList ); for ( OfferType::const_iterator offerIt = offers.begin(); offerIt != offers.end(); ++offerIt ) { action = submenu->addAction( (*offerIt).first ); action->setObjectName( (*offerIt).first ); // Notice this is needed to find the application later! action->setIcon( KIcon((*offerIt).second) ); action->setData( which ); action->setEnabled( enabled ); } // A personal command action = submenu->addAction( i18n("Open With...") ); action->setObjectName( i18n("Open With...") ); // Notice this is needed to find the application later! // XXX: action->setIcon( KIcon((*offerIt).second) ); action->setData( which ); action->setEnabled( enabled ); // A personal command // XXX: see kdialog.h for simple usage action = submenu->addAction( i18n("Your Command Line") ); action->setObjectName( i18n("Your Command Line") ); // Notice this is needed to find the application later! // XXX: action->setIcon( KIcon((*offerIt).second) ); action->setData( which ); action->setEnabled( enabled ); } }