QGraphicsWidget *StackFolder::graphicsWidget() { if (m_graphicsWidget) { return m_graphicsWidget; } setAcceptDrops(true); PreviewGenerator *previewGenerator = PreviewGenerator::createInstance(); previewGenerator->setPlugins(m_previewPlugins); TypeImageProvider *typeImageProvider = new TypeImageProvider(); ModeImageProvider *modeImageProvider = new ModeImageProvider(); PreviewImageProvider *previewImageProvider = new PreviewImageProvider(); m_viewer = new Viewer; m_directory = new Directory(this); m_directory->setModel(m_model); m_directory->setTopUrl(m_url); m_directory->setUrl(m_url); connect(m_directory, SIGNAL(fileActivated()), this, SLOT(fileActivated())); connect(m_directory, SIGNAL(dataAdded(const QModelIndex&, int, int)), this, SLOT(dataAdded(const QModelIndex&, int, int))); connect(m_directory, SIGNAL(viewerRequested(const QString&, int, int, int, int)), this, SLOT(runViewer(const QString&, int, int, int, int))); connect(m_directory, SIGNAL(viewerCanceled()), this, SLOT(stopViewer())); connect(m_directory, SIGNAL(activatedDragAndDrop(const KFileItem&)), this, SLOT(activatedDragAndDrop(const KFileItem&))); qmlRegisterType<File>("File", 1, 0, "File"); qmlRegisterType<QGraphicsDropShadowEffect>("Effects", 1, 0, "DropShadow"); QDeclarativeEngine *m_engine = new QDeclarativeEngine; m_engine->addImageProvider("type", typeImageProvider); m_engine->addImageProvider("mode", modeImageProvider); m_engine->addImageProvider("preview", previewImageProvider); m_engine->rootContext()->setContextProperty("directory", m_directory); QString qmlMainFilePath = KStandardDirs::locate("data", "plasma/packages/org.kde.stackfolder/contents/ui/main.qml"); QDeclarativeComponent component(m_engine, QUrl::fromLocalFile(qmlMainFilePath)); QObject *object = component.create(); QGraphicsLayoutItem *graphicsObject = qobject_cast<QGraphicsLayoutItem*>(object); QObject::connect(object, SIGNAL(currentChanged()), m_viewer, SLOT(stop())); m_layout = new QGraphicsLinearLayout(Qt::Vertical); m_layout->setContentsMargins(10, 0, 10, 0); m_layout->addItem(graphicsObject); m_graphicsWidget = new QGraphicsWidget(this); m_graphicsWidget->setLayout(m_layout); QGraphicsLinearLayout *lay = dynamic_cast<QGraphicsLinearLayout *>(layout()); //lay->setContentsMargins(3, 0, 3, 6); lay->setContentsMargins(0, 0, 0, 0); lay->setSpacing(0); return m_graphicsWidget; }
void *PreviewGenerator::PreviewRun(void *param) { // Lower scheduling priority, to avoid problems with recordings. if (setpriority(PRIO_PROCESS, 0, 9)) VERBOSE(VB_IMPORTANT, LOC + "Setting priority failed." + ENO); PreviewGenerator *gen = (PreviewGenerator*) param; gen->createSockets = true; gen->Run(); gen->deleteLater(); return NULL; }
void StackFolder::activatedDragAndDrop(const KFileItem &item) { QMimeData *mime = new QMimeData; QList<QUrl> urls; urls.append(item.url()); mime->setUrls(urls); QDrag *drag = new QDrag(view()); drag->setMimeData(mime); QString local_path = item.localPath(); PreviewGenerator *gen = PreviewGenerator::createInstance(); Q_ASSERT(gen != 0); if (gen->hasPreviewPixmap(local_path)) { drag->setPixmap(gen->getPreviewPixmap(item.localPath()).scaled(KIconLoader::SizeMedium, KIconLoader::SizeMedium, Qt::KeepAspectRatio)); } else drag->setPixmap(item.pixmap(0)); drag->exec(Qt::CopyAction | Qt::MoveAction | Qt::LinkAction, Qt::CopyAction); }
int preview_helper(const QString &chanid, const QString &starttime, long long previewFrameNumber, long long previewSeconds, const QSize &previewSize, const QString &infile, const QString &outfile) { // Lower scheduling priority, to avoid problems with recordings. if (setpriority(PRIO_PROCESS, 0, 9)) VERBOSE(VB_GENERAL, "Setting priority failed." + ENO); ProgramInfo *pginfo = NULL; if (!chanid.isEmpty() && !starttime.isEmpty()) { pginfo = ProgramInfo::GetProgramFromRecorded(chanid, starttime); if (!pginfo) { VERBOSE(VB_IMPORTANT, QString( "Can not locate recording made on '%1' at '%2'") .arg(chanid).arg(starttime)); return GENERIC_EXIT_NOT_OK; } } else if (!infile.isEmpty()) { pginfo = ProgramInfo::GetProgramFromBasename(infile); if (!pginfo) { VERBOSE(VB_IMPORTANT, QString( "Can not locate recording '%1'").arg(infile)); return GENERIC_EXIT_NOT_OK; } } else { VERBOSE(VB_IMPORTANT, "Can not locate recording for preview"); return GENERIC_EXIT_NOT_OK; } PreviewGenerator *previewgen = new PreviewGenerator(pginfo, true); if (previewFrameNumber >= 0) previewgen->SetPreviewTimeAsFrameNumber(previewFrameNumber); if (previewSeconds >= 0) previewgen->SetPreviewTimeAsSeconds(previewSeconds); previewgen->SetOutputSize(previewSize); previewgen->SetOutputFilename(outfile); previewgen->RunReal(); previewgen->deleteLater(); delete pginfo; return GENERIC_EXIT_OK; }
QFileInfo Content::GetPreviewImage( int nChanId, const QDateTime &recstarttsRaw, int nWidth, int nHeight, int nSecsIn ) { if (!recstarttsRaw.isValid()) { QString sMsg = QString("GetPreviewImage: bad start time '%1'") .arg(MythDate::toString(recstarttsRaw, MythDate::ISODate)); LOG(VB_GENERAL, LOG_ERR, sMsg); throw sMsg; } QDateTime recstartts = recstarttsRaw.toUTC(); // ---------------------------------------------------------------------- // Read Recording From Database // ---------------------------------------------------------------------- ProgramInfo pginfo( (uint)nChanId, recstartts); if (!pginfo.GetChanID()) { LOG(VB_GENERAL, LOG_ERR, QString("GetPreviewImage: No recording for '%1'") .arg(ProgramInfo::MakeUniqueKey(nChanId, recstartts))); return QFileInfo(); } if (pginfo.GetHostname().toLower() != gCoreContext->GetHostName().toLower()) { QString sMsg = QString("GetPreviewImage: Wrong Host '%1' request from '%2'") .arg( gCoreContext->GetHostName()) .arg( pginfo.GetHostname() ); LOG(VB_UPNP, LOG_ERR, sMsg); throw HttpRedirectException( pginfo.GetHostname() ); } QString sFileName = GetPlaybackURL(&pginfo); // ---------------------------------------------------------------------- // check to see if default preview image is already created. // ---------------------------------------------------------------------- QString sPreviewFileName; if (nSecsIn <= 0) { nSecsIn = -1; sPreviewFileName = sFileName + ".png"; } else { sPreviewFileName = QString("%1.%2.png").arg(sFileName).arg(nSecsIn); } if (!QFile::exists( sPreviewFileName )) { // ------------------------------------------------------------------ // Must generate Preview Image, Generate Image and save. // ------------------------------------------------------------------ if (!pginfo.IsLocal() && sFileName.startsWith("/")) pginfo.SetPathname(sFileName); if (!pginfo.IsLocal()) return QFileInfo(); PreviewGenerator *previewgen = new PreviewGenerator( &pginfo, QString(), PreviewGenerator::kLocal); previewgen->SetPreviewTimeAsSeconds( nSecsIn ); previewgen->SetOutputFilename ( sPreviewFileName ); bool ok = previewgen->Run(); previewgen->deleteLater(); if (!ok) return QFileInfo(); } float fAspect = 0.0; QImage *pImage = new QImage(sPreviewFileName); if (!pImage) return QFileInfo(); if (fAspect <= 0) fAspect = (float)(pImage->width()) / pImage->height(); if (fAspect == 0) { delete pImage; return QFileInfo(); } bool bDefaultPixmap = (nWidth == 0) && (nHeight == 0); if ( nWidth == 0 ) nWidth = (int)rint(nHeight * fAspect); if ( nHeight == 0 ) nHeight = (int)rint(nWidth / fAspect); QString sNewFileName; if (bDefaultPixmap) sNewFileName = sPreviewFileName; else sNewFileName = QString( "%1.%2.%3x%4.png" ) .arg( sFileName ) .arg( nSecsIn ) .arg( nWidth ) .arg( nHeight ); // ---------------------------------------------------------------------- // check to see if scaled preview image is already created. // ---------------------------------------------------------------------- if (QFile::exists( sNewFileName )) { delete pImage; return QFileInfo( sNewFileName ); } PreviewGenerator *previewgen = new PreviewGenerator( &pginfo, QString(), PreviewGenerator::kLocal); previewgen->SetPreviewTimeAsSeconds( nSecsIn ); previewgen->SetOutputFilename ( sNewFileName ); previewgen->SetOutputSize (QSize(nWidth,nHeight)); bool ok = previewgen->Run(); previewgen->deleteLater(); if (!ok) return QFileInfo(); delete pImage; return QFileInfo( sNewFileName ); }
int preview_helper(uint chanid, QDateTime starttime, long long previewFrameNumber, long long previewSeconds, const QSize &previewSize, const QString &infile, const QString &outfile) { // Lower scheduling priority, to avoid problems with recordings. if (setpriority(PRIO_PROCESS, 0, 9)) LOG(VB_GENERAL, LOG_ERR, "Setting priority failed." + ENO); if (!chanid || !starttime.isValid()) ProgramInfo::QueryKeyFromPathname(infile, chanid, starttime); ProgramInfo *pginfo = NULL; if (chanid && starttime.isValid()) { pginfo = new ProgramInfo(chanid, starttime); if (!pginfo->GetChanID()) { LOG(VB_GENERAL, LOG_ERR, QString("Cannot locate recording made on '%1' at '%2'") .arg(chanid).arg(starttime.toString(Qt::ISODate))); delete pginfo; return GENERIC_EXIT_NOT_OK; } pginfo->SetPathname(pginfo->GetPlaybackURL(false, true)); } else if (!infile.isEmpty()) { if (!QFileInfo(infile).isReadable()) { LOG(VB_GENERAL, LOG_ERR, QString("Cannot read this file '%1'").arg(infile)); return GENERIC_EXIT_NOT_OK; } pginfo = new ProgramInfo( infile, ""/*plot*/, ""/*title*/, ""/*subtitle*/, ""/*director*/, 0/*season*/, 0/*episode*/, ""/*inetref*/, 120/*length_in_minutes*/, 1895/*year*/, ""/*id*/); } else { LOG(VB_GENERAL, LOG_ERR, "Cannot locate recording to preview"); return GENERIC_EXIT_NOT_OK; } PreviewGenerator *previewgen = new PreviewGenerator( pginfo, QString(), PreviewGenerator::kLocal); if (previewFrameNumber >= 0) previewgen->SetPreviewTimeAsFrameNumber(previewFrameNumber); if (previewSeconds >= 0) previewgen->SetPreviewTimeAsSeconds(previewSeconds); previewgen->SetOutputSize(previewSize); previewgen->SetOutputFilename(outfile); bool ok = previewgen->RunReal(); previewgen->deleteLater(); delete pginfo; return (ok) ? GENERIC_EXIT_OK : GENERIC_EXIT_NOT_OK; }
QString PreviewGeneratorQueue::GeneratePreviewImage( ProgramInfo &pginfo, const QSize &size, const QString &outputfile, long long time, bool in_seconds, QString token) { QString key = QString("%1_%2x%3_%4%5") .arg(pginfo.GetBasename()).arg(size.width()).arg(size.height()) .arg(time).arg(in_seconds?"s":"f"); if (pginfo.GetAvailableStatus() == asPendingDelete) { SendEvent(pginfo, "PREVIEW_FAILED", key, token, "Pending Delete", QDateTime()); return QString(); } QString filename = (outputfile.isEmpty()) ? pginfo.GetPathname() + ".png" : outputfile; QString ret_file = filename; QString ret; bool is_special = !outputfile.isEmpty() || time >= 0 || size.width() || size.height(); bool needs_gen = true; if (!is_special) { QDateTime previewLastModified; bool streaming = filename.left(1) != "/"; bool locally_accessible = false; bool bookmark_updated = false; QDateTime bookmark_ts = pginfo.QueryBookmarkTimeStamp(); QDateTime cmp_ts; if (bookmark_ts.isValid()) cmp_ts = bookmark_ts; else if (MythDate::current() >= pginfo.GetRecordingEndTime()) cmp_ts = pginfo.GetLastModifiedTime(); else cmp_ts = pginfo.GetRecordingStartTime(); if (streaming) { ret_file = QString("%1/remotecache/%2") .arg(GetConfDir()).arg(filename.section('/', -1)); QFileInfo finfo(ret_file); if (finfo.isReadable() && finfo.lastModified() >= cmp_ts) { // This is just an optimization to avoid // hitting the backend if our cached copy // is newer than the bookmark, or if we have // a preview and do not update it when the // bookmark changes. previewLastModified = finfo.lastModified(); } else if (!IsGeneratingPreview(key)) { previewLastModified = RemoteGetPreviewIfModified(pginfo, ret_file); } } else { QFileInfo fi(filename); if ((locally_accessible = fi.isReadable())) previewLastModified = fi.lastModified(); } bookmark_updated = (!previewLastModified.isValid() || (previewLastModified <= cmp_ts)); if (bookmark_updated && bookmark_ts.isValid() && previewLastModified.isValid()) { ClearPreviewGeneratorAttempts(key); } bool preview_exists = previewLastModified.isValid(); if (0) { QString alttext = (bookmark_ts.isValid()) ? QString() : QString("\n\t\t\tcmp_ts: %1") .arg(cmp_ts.toString(Qt::ISODate)); LOG(VB_GENERAL, LOG_INFO, QString("previewLastModified: %1\n\t\t\t" "bookmark_ts: %2%3\n\t\t\t" "pginfo.lastmodified: %4") .arg(previewLastModified.toString(Qt::ISODate)) .arg(bookmark_ts.toString(Qt::ISODate)) .arg(alttext) .arg(pginfo.GetLastModifiedTime(MythDate::ISODate)) + QString("Title: %1\n\t\t\t") .arg(pginfo.toString(ProgramInfo::kTitleSubtitle)) + QString("File '%1' \n\t\t\tCache '%2'") .arg(filename).arg(ret_file) + QString("\n\t\t\tPreview Exists: %1, Bookmark Updated: %2, " "Need Preview: %3") .arg(preview_exists).arg(bookmark_updated) .arg((bookmark_updated || !preview_exists))); } needs_gen = bookmark_updated || !preview_exists; if (!needs_gen) { if (locally_accessible) ret = filename; else if (preview_exists && QFileInfo(ret_file).isReadable()) ret = ret_file; } } if (needs_gen && !IsGeneratingPreview(key)) { uint attempts = IncPreviewGeneratorAttempts(key); if (attempts < m_maxAttempts) { LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Requesting preview for '%1'") .arg(key)); PreviewGenerator *pg = new PreviewGenerator(&pginfo, token, m_mode); if (!outputfile.isEmpty() || time >= 0 || size.width() || size.height()) { pg->SetPreviewTime(time, in_seconds); pg->SetOutputFilename(outputfile); pg->SetOutputSize(size); } SetPreviewGenerator(key, pg); LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Requested preview for '%1'").arg(key)); } else if (attempts >= m_maxAttempts) { LOG(VB_GENERAL, LOG_ERR, LOC + QString("Attempted to generate preview for '%1' " "%2 times; >= max(%3)") .arg(key).arg(attempts).arg(m_maxAttempts)); } } else if (needs_gen) { LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Not requesting preview for %1," "as it is already being generated") .arg(pginfo.toString(ProgramInfo::kTitleSubtitle))); IncPreviewGeneratorPriority(key, token); } UpdatePreviewGeneratorThreads(); if (!ret.isEmpty()) { QString msg = "On Disk"; QDateTime dt = QFileInfo(ret).lastModified(); SendEvent(pginfo, "PREVIEW_SUCCESS", ret, token, msg, dt); } else { uint queue_depth, token_cnt; GetInfo(key, queue_depth, token_cnt); QString msg = QString("Queue depth %1, our tokens %2") .arg(queue_depth).arg(token_cnt); SendEvent(pginfo, "PREVIEW_QUEUED", ret, token, msg, QDateTime()); } return ret; }
int preview_helper(const QString &_chanid, const QString &starttime, long long previewFrameNumber, long long previewSeconds, const QSize &previewSize, const QString &infile, const QString &outfile) { // Lower scheduling priority, to avoid problems with recordings. if (setpriority(PRIO_PROCESS, 0, 9)) VERBOSE(VB_GENERAL, "Setting priority failed." + ENO); uint chanid = _chanid.toUInt(); QDateTime recstartts = myth_dt_from_string(starttime); if (!chanid || !recstartts.isValid()) ProgramInfo::ExtractKeyFromPathname(infile, chanid, recstartts); ProgramInfo *pginfo = NULL; if (chanid && recstartts.isValid()) { pginfo = new ProgramInfo(chanid, recstartts); if (!pginfo->GetChanID()) { VERBOSE(VB_IMPORTANT, QString( "Cannot locate recording made on '%1' at '%2'") .arg(chanid).arg(starttime)); delete pginfo; return PREVIEWGEN_EXIT_NOT_OK; } pginfo->SetPathname(pginfo->GetPlaybackURL(false, true)); } else if (!infile.isEmpty()) { if (!QFileInfo(infile).isReadable()) { VERBOSE(VB_IMPORTANT, QString( "Cannot read this file '%1'").arg(infile)); return PREVIEWGEN_EXIT_NOT_OK; } pginfo = new ProgramInfo( infile, ""/*plot*/, ""/*title*/, ""/*subtitle*/, ""/*director*/, 0/*season*/, 0/*episode*/, 120/*length_in_minutes*/, 1895/*year*/); } else { VERBOSE(VB_IMPORTANT, "Cannot locate recording to preview"); return PREVIEWGEN_EXIT_NOT_OK; } PreviewGenerator *previewgen = new PreviewGenerator( pginfo, QString(), PreviewGenerator::kLocal); if (previewFrameNumber >= 0) previewgen->SetPreviewTimeAsFrameNumber(previewFrameNumber); if (previewSeconds >= 0) previewgen->SetPreviewTimeAsSeconds(previewSeconds); previewgen->SetOutputSize(previewSize); previewgen->SetOutputFilename(outfile); bool ok = previewgen->RunReal(); previewgen->deleteLater(); delete pginfo; return (ok) ? PREVIEWGEN_EXIT_OK : PREVIEWGEN_EXIT_NOT_OK; }
QFileInfo Content::GetPreviewImage( int nRecordedId, int nChanId, const QDateTime &recstarttsRaw, int nWidth, int nHeight, int nSecsIn, const QString &sFormat ) { if ((nRecordedId <= 0) && (nChanId <= 0 || !recstarttsRaw.isValid())) throw QString("Recorded ID or Channel ID and StartTime appears invalid."); if (!sFormat.isEmpty() && !QImageWriter::supportedImageFormats().contains(sFormat.toLower().toLocal8Bit())) { throw "GetPreviewImage: Specified 'Format' is not supported."; } // ---------------------------------------------------------------------- // Read Recording From Database // ---------------------------------------------------------------------- // TODO Should use RecordingInfo ProgramInfo pginfo; if (nRecordedId > 0) pginfo = ProgramInfo(nRecordedId); else pginfo = ProgramInfo(nChanId, recstarttsRaw.toUTC()); if (!pginfo.GetChanID()) { LOG(VB_GENERAL, LOG_ERR, QString("GetPreviewImage: No recording for '%1'") .arg(nRecordedId)); return QFileInfo(); } if (pginfo.GetHostname().toLower() != gCoreContext->GetHostName().toLower()) { QString sMsg = QString("GetPreviewImage: Wrong Host '%1' request from '%2'") .arg( gCoreContext->GetHostName()) .arg( pginfo.GetHostname() ); LOG(VB_UPNP, LOG_ERR, sMsg); throw HttpRedirectException( pginfo.GetHostname() ); } QString sImageFormat = sFormat; if (sImageFormat.isEmpty()) sImageFormat = "PNG"; QString sFileName = GetPlaybackURL(&pginfo); // ---------------------------------------------------------------------- // check to see if default preview image is already created. // ---------------------------------------------------------------------- QString sPreviewFileName; if (nSecsIn <= 0) { nSecsIn = -1; sPreviewFileName = QString("%1.png").arg(sFileName); } else { sPreviewFileName = QString("%1.%2.png").arg(sFileName).arg(nSecsIn); } if (!QFile::exists( sPreviewFileName )) { // ------------------------------------------------------------------ // Must generate Preview Image, Generate Image and save. // ------------------------------------------------------------------ if (!pginfo.IsLocal() && sFileName.startsWith("/")) pginfo.SetPathname(sFileName); if (!pginfo.IsLocal()) return QFileInfo(); PreviewGenerator *previewgen = new PreviewGenerator( &pginfo, QString(), PreviewGenerator::kLocal); previewgen->SetPreviewTimeAsSeconds( nSecsIn ); previewgen->SetOutputFilename ( sPreviewFileName ); bool ok = previewgen->Run(); previewgen->deleteLater(); if (!ok) return QFileInfo(); } bool bDefaultPixmap = (nWidth == 0) && (nHeight == 0); QString sNewFileName; if (bDefaultPixmap) sNewFileName = sPreviewFileName; else { sNewFileName = QString( "%1.%2.%3x%4.%5" ) .arg( sFileName ) .arg( nSecsIn ) .arg( nWidth == 0 ? -1 : nWidth ) .arg( nHeight == 0 ? -1 : nHeight ) .arg( sImageFormat.toLower() ); // ---------------------------------------------------------------------- // check to see if scaled preview image is already created and isn't // out of date // ---------------------------------------------------------------------- if (QFile::exists( sNewFileName )) { if (QFileInfo(sPreviewFileName).lastModified() <= QFileInfo(sNewFileName).lastModified()) return QFileInfo( sNewFileName ); } QImage image = QImage(sPreviewFileName); if (image.isNull()) return QFileInfo(); // We can just re-scale the default (full-size version) to avoid // a preview generator run if ( nWidth <= 0 ) image = image.scaledToHeight(nHeight, Qt::SmoothTransformation); else if ( nHeight <= 0 ) image = image.scaledToWidth(nWidth, Qt::SmoothTransformation); else image = image.scaled(nWidth, nHeight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); image.save(sNewFileName, sImageFormat.toUpper().toLocal8Bit()); // Let anybody update it bool ret = makeFileAccessible(sNewFileName.toLocal8Bit().constData()); if (!ret) { LOG(VB_GENERAL, LOG_ERR, "Unable to change permissions on " "preview image. Backends and frontends " "running under different users will be " "unable to access it"); } } if (QFile::exists( sNewFileName )) return QFileInfo( sNewFileName ); PreviewGenerator *previewgen = new PreviewGenerator( &pginfo, QString(), PreviewGenerator::kLocal); previewgen->SetPreviewTimeAsSeconds( nSecsIn ); previewgen->SetOutputFilename ( sNewFileName ); previewgen->SetOutputSize (QSize(nWidth,nHeight)); bool ok = previewgen->Run(); previewgen->deleteLater(); if (!ok) return QFileInfo(); return QFileInfo( sNewFileName ); }