]> git.sesse.net Git - kdenlive/commitdiff
Continue progress on clip jobs: add extract zone action (cuts a clip through ffmpeg...
authorJean-Baptiste Mardelle <jb@kdenlive.org>
Mon, 19 Dec 2011 22:32:00 +0000 (23:32 +0100)
committerJean-Baptiste Mardelle <jb@kdenlive.org>
Mon, 19 Dec 2011 22:32:00 +0000 (23:32 +0100)
20 files changed:
src/CMakeLists.txt
src/clipmanager.cpp
src/clipproperties.cpp
src/mainwindow.cpp
src/monitor.cpp
src/monitor.h
src/projectitem.cpp
src/projectitem.h
src/projectlist.cpp
src/projectlist.h
src/projecttree/CMakeLists.txt
src/projecttree/abstractclipjob.h
src/projecttree/cutclipjob.cpp [new file with mode: 0644]
src/projecttree/cutclipjob.h [new file with mode: 0644]
src/projecttree/proxyclipjob.cpp
src/projecttree/proxyclipjob.h
src/renderer.cpp
src/timecode.cpp
src/timecode.h
src/widgets/cutjobdialog_ui.ui [new file with mode: 0644]

index 9f957281061629c5b792d13fdda84310a584c3e2..351157de45ead8c3545b2e9ccf674e24096cbadb 100644 (file)
@@ -256,6 +256,7 @@ kde4_add_ui_files(kdenlive_UIS
   widgets/wizardstandard_ui.ui
   widgets/keywordval_ui.ui
   widgets/fontval_ui.ui
+  widgets/cutjobdialog_ui.ui
 )
 
 if(OPENGL_FOUND)
index dcd935a2de4650b97b6ef9d5a82be31e10cce060..160d3375676eda4d678899de79f71aa3c532350a 100644 (file)
@@ -463,9 +463,8 @@ void ClipManager::resetProducersList(const QList <Mlt::Producer *> prods, bool d
 void ClipManager::slotAddClipList(const KUrl::List urls, const QString &group, const QString &groupId)
 {
     QUndoCommand *addClips = new QUndoCommand();
-
     foreach(const KUrl & file, urls) {
-        if (KIO::NetAccess::exists(file, KIO::NetAccess::SourceSide, NULL)) {
+        if (QFile::exists(file.path())) {//KIO::NetAccess::exists(file, KIO::NetAccess::SourceSide, NULL)) {
             if (!getClipByResource(file.path()).empty()) {
                 if (KMessageBox::warningContinueCancel(kapp->activeWindow(), i18n("Clip <b>%1</b><br />already exists in project, what do you want to do?", file.path()), i18n("Clip already exists")) == KMessageBox::Cancel)
                     continue;
@@ -529,6 +528,7 @@ void ClipManager::slotAddClipList(const KUrl::List urls, const QString &group, c
             }
             new AddClipCommand(m_doc, doc.documentElement(), QString::number(id), true, addClips);
         }
+        else kDebug()<<"// CANNOT READ FILE: "<<file;
     }
     if (addClips->childCount() > 0) {
         addClips->setText(i18np("Add clip", "Add clips", addClips->childCount()));
index 42214833f5530e79867ee2a720a2dbe5e304f2ca..db4c3bc815e8f0601d1bd60987cbc9f152b1a9a9 100644 (file)
@@ -401,6 +401,13 @@ ClipProperties::ClipProperties(DocClipBase *clip, Timecode tc, double fps, QWidg
             new QTreeWidgetItem(m_view.clip_vproperties, QStringList() << i18n("Frame rate") << props.value("fps"));
             if (!m_view.clip_framerate->isEnabled()) m_view.clip_framerate->setValue(props.value("fps").toDouble());
         }
+
+        if (props.contains("progressive")) {
+            int scanning = props.value("progressive").toInt();
+            QString txt = scanning == 1 ? i18n("Progressive") : i18n("Interlaced");
+            new QTreeWidgetItem(m_view.clip_vproperties, QStringList() << i18n("Scanning") << txt);
+        }
+        
         if (props.contains("aspect_ratio"))
             new QTreeWidgetItem(m_view.clip_vproperties, QStringList() << i18n("Pixel aspect ratio") << props.value("aspect_ratio"));
 
@@ -409,6 +416,7 @@ ClipProperties::ClipProperties(DocClipBase *clip, Timecode tc, double fps, QWidg
 
         if (props.contains("colorspace"))
             new QTreeWidgetItem(m_view.clip_vproperties, QStringList() << i18n("Colorspace") << ProfilesDialog::getColorspaceDescription(props.value("colorspace").toInt()));
+        
 
         int width = 180.0 * KdenliveSettings::project_display_ratio();
         if (width % 2 == 1) width++;
index a090bf03df96f6d5ebef8425631d113df5323b94..6aedb516c0e7609a9109433a8ae498d433b76da0 100644 (file)
@@ -232,6 +232,7 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString &
     connect(m_projectList, SIGNAL(refreshClip(const QString &, bool)), m_monitorManager, SLOT(slotRefreshCurrentMonitor(const QString &)));
     connect(m_projectList, SIGNAL(findInTimeline(const QString&)), this, SLOT(slotClipInTimeline(const QString&)));
     connect(m_clipMonitor, SIGNAL(zoneUpdated(QPoint)), m_projectList, SLOT(slotUpdateClipCut(QPoint)));
+    connect(m_clipMonitor, SIGNAL(extractZone(const QString &, QPoint)), m_projectList, SLOT(slotCutClipJob(const QString &, QPoint)));
 
     m_projectMonitorDock = new QDockWidget(i18n("Project Monitor"), this);
     m_projectMonitorDock->setObjectName("project_monitor");
@@ -4477,6 +4478,7 @@ void MainWindow::slotElapsedTime()
     kDebug()<<"-----------------------------------------\n"<<"Time elapsed: "<<m_timer.elapsed()<<"\n-------------------------";
 }
 
+
 #include "mainwindow.moc"
 
 #ifdef DEBUG_MAINW
index 2b7cc30fd7ad89af0caeaa0b784542e371cab1bb..891f0fd31e77e1c30816438c8f54c8aa7b3a2d5f 100644 (file)
@@ -274,6 +274,8 @@ void Monitor::setupMenu(QMenu *goMenu, QAction *playZone, QAction *loopZone, QMe
     if (m_name == "clip") {
         m_contextMenu->addMenu(m_markerMenu);
         m_contextMenu->addAction(KIcon("document-save"), i18n("Save zone"), this, SLOT(slotSaveZone()));
+        QAction *extractZone = m_configMenu->addAction(KIcon("document-new"), i18n("Extract Zone"), this, SLOT(slotExtractCurrentZone()));
+        m_contextMenu->addAction(extractZone);
     }
     QAction *extractFrame = m_configMenu->addAction(KIcon("document-new"), i18n("Extract frame"), this, SLOT(slotExtractCurrentFrame()));
     m_contextMenu->addAction(extractFrame);
@@ -566,6 +568,12 @@ void Monitor::slotSetThumbFrame()
     emit refreshClipThumbnail(m_currentClip->getId(), true);
 }
 
+void Monitor::slotExtractCurrentZone()
+{
+    if (m_currentClip == NULL) return;
+    emit extractZone(m_currentClip->getId(), m_ruler->zone());
+}
+
 void Monitor::slotExtractCurrentFrame()
 {
     QImage frame;
index 04e5af2d98bee6b4736d3829e70e3a2f78e5ac8e..518ba072db368f9ac5e71628db9bf1186679b2d7 100644 (file)
@@ -199,6 +199,7 @@ private slots:
     void slotSetVolume(int volume);
     void slotShowVolume();
     void slotEditMarker();
+    void slotExtractCurrentZone();
 
 public slots:
     void slotOpenFile(const QString &);
@@ -252,6 +253,8 @@ signals:
     /** @brief  Editing transitions / effects over the monitor requires the renderer to send frames as QImage.
      *      This causes a major slowdown, so we only enable it if required */
     void requestFrameForAnalysis(bool);
+    /** @brief Request a zone extraction (ffmpeg transcoding). */
+    void extractZone(const QString &id, QPoint zone);
 };
 
 #endif
index 469d7e29a3b9db55caa9c2d235967896e2e533e1..43f91e9b3f267045bd9dafcfa60acadb308e3855 100644 (file)
@@ -30,7 +30,9 @@
 #include <QFile>
 
 const int DurationRole = Qt::UserRole + 1;
-const int ProxyRole = Qt::UserRole + 5;
+const int JobProgressRole = Qt::UserRole + 5;
+const int JobTypeRole = Qt::UserRole + 6;
+const int JobCrasMessage = Qt::UserRole + 7;
 const int itemHeight = 38;
 
 ProjectItem::ProjectItem(QTreeWidget * parent, DocClipBase *clip) :
@@ -167,7 +169,7 @@ void ProjectItem::slotSetToolTip()
 {
     QString tip;
     if (m_clip->isPlaceHolder()) tip.append(i18n("Missing") + " | ");
-    int s = data(0, ProxyRole).toInt();
+    int s = data(0, JobProgressRole).toInt();
     if (s == CREATINGJOB || s > 0) {
         tip.append(i18n("Building proxy clip") + " | ");
     }
@@ -263,11 +265,16 @@ void ProjectItem::setProperties(const QMap < QString, QString > &attributes, con
     }
 }
 
-void ProjectItem::setProxyStatus(CLIPJOBSTATUS status, int progress)
+void ProjectItem::setJobStatus(CLIPJOBSTATUS status, int progress, JOBTYPE jobType)
 {
-    if (progress > 0) setData(0, ProxyRole, progress);
+    if (status == JOBCRASHED) {
+        if (jobType == PROXYJOB) setData(0, JobCrasMessage, i18n("Proxy crashed"));
+        else if (jobType == CUTJOB) setData(0, JobCrasMessage, i18n("Transcoding crashed"));
+    }
+    setData(0, JobTypeRole, jobType);
+    if (progress > 0) setData(0, JobProgressRole, progress);
     else {
-        setData(0, ProxyRole, status);
+        setData(0, JobProgressRole, status);
         slotSetToolTip();
     }
 }
@@ -275,22 +282,29 @@ void ProjectItem::setProxyStatus(CLIPJOBSTATUS status, int progress)
 bool ProjectItem::hasProxy() const
 {
     if (m_clip == NULL) return false;
-    if (m_clip->getProperty("proxy").isEmpty() || m_clip->getProperty("proxy") == "-" || data(0, ProxyRole).toInt() == JOBCRASHED) return false;
+    if (m_clip->getProperty("proxy").isEmpty() || m_clip->getProperty("proxy") == "-" || data(0, JobProgressRole).toInt() == JOBCRASHED) return false;
     return true;
 }
 
 bool ProjectItem::isProxyReady() const
 {
-     return (data(0, ProxyRole).toInt() == JOBDONE);
+     return (data(0, JobProgressRole).toInt() == JOBDONE);
 }
 
-bool ProjectItem::isProxyRunning() const
+bool ProjectItem::isJobRunning() const
 {
-    int s = data(0, ProxyRole).toInt();
+    int s = data(0, JobProgressRole).toInt();
     if (s == JOBWAITING || s == CREATINGJOB || s > 0) return true;
     return false;
 }
 
+bool ProjectItem::isProxyRunning() const
+{
+    int s = data(0, JobProgressRole).toInt();
+    if ((s == CREATINGJOB || s > 0) && data(0, JobTypeRole).toInt() == (int) PROXYJOB) return true;
+    return false;
+}
+
 bool ProjectItem::playlistHasProxies(const QString path)
 {
     kDebug()<<"// CHECKING FOR PROXIES";
index 4bdf653a285db8b935f008c4f1b5d9c3bd5a39b3..06a6802ea4189443555157aeae3ea683363146d3 100644 (file)
@@ -30,6 +30,8 @@
 
 #include "gentime.h"
 #include "definitions.h"
+#include "projecttree/abstractclipjob.h"
+
 
 class DocClipBase;
 
@@ -63,12 +65,14 @@ public:
     QString getClipHash() const;
     static int itemDefaultHeight();
     void slotSetToolTip();
-    /** \brief Set the status of proxy clip creation. 0 = no proxy, 1 = creating proxy, 2 = proxy created. */
-    void setProxyStatus(CLIPJOBSTATUS status, int progress = 0);
+    /** \brief Set the status of the clip job. */
+    void setJobStatus(CLIPJOBSTATUS status, int progress = 0, JOBTYPE jobType = NOJOBTYPE);
     /** \brief Returns the proxy status for this clip (true means there is a proxy clip). */
     bool hasProxy() const;
     /** \brief Returns true if the proxy for this clip is ready. */
     bool isProxyReady() const;
+    /** \brief Returns true if there is a job currently running for this clip. */
+    bool isJobRunning() const;
     /** \brief Returns true if we are currently creating the proxy for this clip. */
     bool isProxyRunning() const;
 
index 38391bd26143cb9c693d71b50478c80978759faa..174e5ff2065889fab7df3d5e47304db650cef043 100644 (file)
@@ -21,6 +21,7 @@
 #include "projectitem.h"
 #include "commands/addfoldercommand.h"
 #include "projecttree/proxyclipjob.h"
+#include "projecttree/cutclipjob.h"
 #include "kdenlivesettings.h"
 #include "slideshowclip.h"
 #include "ui_colorclip_ui.h"
@@ -40,6 +41,7 @@
 #include "commands/addclipcutcommand.h"
 
 #include "ui_templateclip_ui.h"
+#include "ui_cutjobdialog_ui.h"
 
 #include <KDebug>
 #include <KAction>
@@ -52,6 +54,7 @@
 #include <KApplication>
 #include <KStandardDirs>
 #include <KColorScheme>
+#include <KUrlRequester>
 
 #ifdef NEPOMUK
 #include <nepomuk/global.h>
@@ -268,6 +271,7 @@ ProjectList::ProjectList(QWidget *parent) :
     connect(m_listView, SIGNAL(requestMenu(const QPoint &, QTreeWidgetItem *)), this, SLOT(slotContextMenu(const QPoint &, QTreeWidgetItem *)));
     connect(m_listView, SIGNAL(addClip()), this, SLOT(slotAddClip()));
     connect(m_listView, SIGNAL(addClip(const QList <QUrl>, const QString &, const QString &)), this, SLOT(slotAddClip(const QList <QUrl>, const QString &, const QString &)));
+    connect(this, SIGNAL(addClip(const QString, const QString &, const QString &)), this, SLOT(slotAddClip(const QString, const QString &, const QString &)));
     connect(m_listView, SIGNAL(addClipCut(const QString &, int, int)), this, SLOT(slotAddClipCut(const QString &, int, int)));
     connect(m_listView, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(slotItemEdited(QTreeWidgetItem *, int)));
     connect(m_listView, SIGNAL(showProperties(DocClipBase *)), this, SIGNAL(showClipProperties(DocClipBase *)));
@@ -627,7 +631,7 @@ void ProjectList::slotReloadClip(const QString &id)
             continue;
         }
         item = static_cast <ProjectItem *>(selected.at(i));
-        if (item && !item->isProxyRunning()) {
+        if (item && !hasPendingProxy(item)) {
             DocClipBase *clip = item->referencedClip();
             if (!clip || !clip->isClean() || m_render->isProcessing(item->clipId())) {
                 kDebug()<<"//// TRYING TO RELOAD: "<<item->clipId()<<", but it is busy";
@@ -893,7 +897,7 @@ void ProjectList::slotUpdateClipProperties(ProjectItem *clip, QMap <QString, QSt
     clip->setProperties(properties);
     if (properties.contains("proxy")) {
         if (properties.value("proxy") == "-" || properties.value("proxy").isEmpty())
-            clip->setProxyStatus(NOJOB);
+            clip->setJobStatus(NOJOB);
     }
     if (properties.contains("name")) {
         monitorItemEditing(false);
@@ -1114,6 +1118,7 @@ void ProjectList::slotDeleteClip(const QString &clipId)
         kDebug() << "/// Cannot find clip to delete";
         return;
     }
+    deleteJobsForClip(clipId);
     if (item->isProxyRunning()) m_abortProxy.append(item->referencedClip()->getProperty("proxy"));
     m_listView->blockSignals(true);
     QTreeWidgetItem *newSelectedItem = m_listView->itemAbove(item);
@@ -1241,7 +1246,7 @@ void ProjectList::slotAddClip(DocClipBase *clip, bool getProperties)
         m_render->getFileProperties(e, clip->getId(), m_listView->iconSize().height(), true);
     }
     // WARNING: code below triggers unnecessary reload of all proxy clips on document loading... is it useful in some cases?
-    /*else if (item->hasProxy() && !item->isProxyRunning()) {
+    /*else if (item->hasProxy() && !item->isJobRunning()) {
         slotCreateProxy(clip->getId());
     }*/
     
@@ -1439,11 +1444,11 @@ void ProjectList::updateAllClips(bool displayRatioChanged, bool fpsChanged, QStr
                 bool replace = false;
                 if (brokenClips.contains(item->clipId())) {
                     // if this is a proxy clip, disable proxy
-                    item->setProxyStatus(NOJOB);
+                    item->setJobStatus(NOJOB);
                     clip->setProperty("proxy", "-");
                     replace = true;
                 }
-                if (clip->isPlaceHolder() == false && !item->isProxyRunning()) {
+                if (clip->isPlaceHolder() == false && !hasPendingProxy(item)) {
                     QDomElement xml = clip->toXML();
                     if (fpsChanged) {
                         xml.removeAttribute("out");
@@ -1524,6 +1529,14 @@ QString ProjectList::getExtensions()
     return allExtensions.simplified();
 }
 
+void ProjectList::slotAddClip(const QString url, const QString &groupName, const QString &groupId)
+{
+    kDebug()<<"// Adding clip: "<<url;
+    QList <QUrl> list;
+    list.append(url);
+    slotAddClip(list, groupName, groupId);
+}
+
 void ProjectList::slotAddClip(const QList <QUrl> givenList, const QString &groupName, const QString &groupId)
 {
     if (!m_commandStack)
@@ -1651,7 +1664,7 @@ void ProjectList::slotRemoveInvalidProxy(const QString &id, bool durationError)
             kDebug() << "Proxy duration is wrong, try changing transcoding parameters.";
             emit displayMessage(i18n("Proxy clip unusable (duration is different from original)."), -2);
         }
-        item->setProxyStatus(JOBCRASHED);
+        item->setJobStatus(JOBCRASHED);
         QString path = item->referencedClip()->getProperty("proxy");
         KUrl proxyFolder(m_doc->projectFolder().path( KUrl::AddTrailingSlash) + "proxy/");
 
@@ -1983,9 +1996,9 @@ void ProjectList::slotReplyGetFileProperties(const QString &clipId, Mlt::Produce
 
         // Proxy stuff
         QString size = properties.value("frame_size");
-        if (!useProxy() && clip->getProperty("proxy").isEmpty()) setProxyStatus(item, NOJOB);
-        if (useProxy() && generateProxy() && clip->getProperty("proxy") == "-") setProxyStatus(item, NOJOB);
-        else if (useProxy() && !item->hasProxy() && !item->isProxyRunning()) {
+        if (!useProxy() && clip->getProperty("proxy").isEmpty()) setJobStatus(item, NOJOB);
+        if (useProxy() && generateProxy() && clip->getProperty("proxy") == "-") setJobStatus(item, NOJOB);
+        else if (useProxy() && !item->hasProxy() && !hasPendingProxy(item)) {
             // proxy video and image clips
             int maxSize;
             CLIPTYPE t = item->clipType();
@@ -2474,13 +2487,13 @@ QMap <QString, QString> ProjectList::getProxies()
 void ProjectList::slotCreateProxy(const QString id)
 {
     ProjectItem *item = getItemById(id);
-    if (!item || item->isProxyRunning() || item->referencedClip()->isPlaceHolder()) return;
+    if (!item || hasPendingProxy(item) || item->referencedClip()->isPlaceHolder()) return;
     QString path = item->referencedClip()->getProperty("proxy");
     if (path.isEmpty()) {
-        setProxyStatus(item, JOBCRASHED);
+        setJobStatus(item, JOBCRASHED);
         return;
     }
-    setProxyStatus(item, JOBWAITING);
+
     if (m_abortProxy.contains(path)) m_abortProxy.removeAll(path);
     if (m_processingProxy.contains(path)) {
         // Proxy is already being generated
@@ -2488,19 +2501,70 @@ void ProjectList::slotCreateProxy(const QString id)
     }
     if (QFileInfo(path).size() > 0) {
         // Proxy already created
-        setProxyStatus(item, JOBDONE);
+        setJobStatus(item, JOBDONE);
         slotGotProxy(path);
         return;
     }
+    if (!item->isJobRunning()) setJobStatus(item, JOBWAITING);
     m_processingProxy.append(path);
 
-    /*PROXYINFO info;
-    info.dest = path;
-    info.src = item->clipUrl().path();
-    info.type = item->clipType();
-    info.exif = QString(item->referencedClip()->producerProperty("_exif_orientation")).toInt();*/
-    ProxyJob *job = new ProxyJob(PROXYJOB, item->clipType(), item->clipId(), QStringList() << path << item->clipUrl().path() << item->referencedClip()->producerProperty("_exif_orientation") << m_doc->getDocumentProperty("proxyparams").simplified() << QString::number(m_render->frameRenderWidth()) << QString::number(m_render->renderHeight()));
+    ProxyJob *job = new ProxyJob(item->clipType(), id, QStringList() << path << item->clipUrl().path() << item->referencedClip()->producerProperty("_exif_orientation") << m_doc->getDocumentProperty("proxyparams").simplified() << QString::number(m_render->frameRenderWidth()) << QString::number(m_render->renderHeight()));
+    m_jobList.append(job);
+    
+    startJobProcess();
+}
+
+void ProjectList::slotCutClipJob(const QString &id, QPoint zone)
+{
+    ProjectItem *item = getItemById(id);
+    if (!item|| item->referencedClip()->isPlaceHolder()) return;
+    QString dest = item->clipUrl().path();
+    QString ext = dest.section('.', -1);
+    dest = dest.section('.', 0, -2) + "_" + QString::number(zone.x()) + "." + ext;
+    
+    double clipFps = item->referencedClip()->getProperty("fps").toDouble();
+    if (clipFps == 0) clipFps = m_fps;
+    // if clip and project have different frame rate, adjust in and out
+    int in = zone.x();
+    int out = zone.y();
+    in = GenTime(in, m_timecode.fps()).frames(clipFps);
+    out = GenTime(out, m_timecode.fps()).frames(clipFps);
+    int max = GenTime(item->clipMaxDuration(), m_timecode.fps()).frames(clipFps);
+    int duration = out - in;
+    QString timeIn = Timecode::getStringTimecode(in, clipFps, true);
+    QString timeOut = Timecode::getStringTimecode(duration, clipFps, true);
+    
+    QDialog *d = new QDialog(this);
+    Ui::CutJobDialog_UI ui;
+    ui.setupUi(d);
+    ui.file_url->fileDialog()->setOperationMode(KFileDialog::Saving);
+    ui.file_url->setUrl(KUrl(dest));
+    ui.info_label->setText(i18n("Extracting %1 out of %2", timeOut, Timecode::getStringTimecode(max, clipFps, true)));
+    if (d->exec() != QDialog::Accepted) return;
+    dest = ui.file_url->url().path();
+    QString extraParams = ui.extra_params->toPlainText().simplified();
+    delete d;
+    
+    if (QFileInfo(dest).size() > 0) {
+        // Clip already created
+        setJobStatus(item, JOBDONE);
+        emit addClip(dest, QString(), QString());
+        return;
+    }
+    if (!item->isJobRunning()) setJobStatus(item, JOBWAITING);
+    m_processingProxy.append(dest);
+    QStringList jobParams;
+    jobParams << dest << item->clipUrl().path() << timeIn << timeOut << QString::number(duration);
+    if (!extraParams.isEmpty()) jobParams << extraParams;
+    CutClipJob *job = new CutClipJob(item->clipType(), id, jobParams);
     m_jobList.append(job);
+    
+    startJobProcess();
+}
+
+
+void ProjectList::startJobProcess()
+{
     int ct = 0;
     if (!m_proxyThreads.futures().isEmpty()) {
         // Remove inactive threads
@@ -2514,7 +2578,7 @@ void ProjectList::slotCreateProxy(const QString id)
     }
     emit jobCount(ct + m_jobList.count());
     
-    if (m_proxyThreads.futures().isEmpty() || m_proxyThreads.futures().count() < KdenliveSettings::proxythreads()) m_proxyThreads.addFuture(QtConcurrent::run(this, &ProjectList::slotGenerateProxy));
+    if (m_proxyThreads.futures().isEmpty() || m_proxyThreads.futures().count() < KdenliveSettings::proxythreads()) m_proxyThreads.addFuture(QtConcurrent::run(this, &ProjectList::slotProcessJobs));
 }
 
 void ProjectList::slotAbortProxy(const QString id, const QString path)
@@ -2531,7 +2595,7 @@ void ProjectList::slotAbortProxy(const QString id, const QString path)
     }
 }
 
-void ProjectList::slotGenerateProxy()
+void ProjectList::slotProcessJobs()
 {
     while (!m_jobList.isEmpty() && !m_abortAllJobs) {
         emit projectModified();
@@ -2577,7 +2641,7 @@ void ProjectList::slotGenerateProxy()
         QFile file(job->destination());
         if (!file.open(QIODevice::WriteOnly)) {
             for (int i = 0; i < processingItems.count(); i++)
-                setProxyStatus(processingItems.at(i), JOBCRASHED);
+                setJobStatus(processingItems.at(i), JOBCRASHED);
             m_processingProxy.removeAll(job->destination());
             delete job;
             continue;
@@ -2586,7 +2650,8 @@ void ProjectList::slotGenerateProxy()
         QFile::remove(job->destination());
     
         for (int i = 0; i < processingItems.count(); i++)
-            setProxyStatus(processingItems.at(i), CREATINGJOB, 0); //, job->description);
+            setJobStatus(processingItems.at(i), CREATINGJOB, 0, job->jobType);
+
         bool success;
         QProcess *jobProcess = job->startJob(&success);
             
@@ -2594,9 +2659,11 @@ void ProjectList::slotGenerateProxy()
         if (jobProcess == NULL) {
             // job is finished
             for (int i = 0; i < processingItems.count(); i++)
-                setProxyStatus(processingItems.at(i), success ? JOBDONE : JOBCRASHED);
+                setJobStatus(processingItems.at(i), success ? JOBDONE : JOBCRASHED);
             if (success) {
-                slotGotProxy(job->destination());
+                if (job->jobType == PROXYJOB) slotGotProxy(job->destination());
+                //TODO: set folder for transcoded clips
+                else if (job->jobType == CUTJOB) emit addClip(job->destination(), QString(), QString());
             }
             else {
                 QFile::remove(job->destination());
@@ -2617,14 +2684,14 @@ void ProjectList::slotGenerateProxy()
                 if (!m_closing) {
                     emit cancelRunningJob(job->clipId(), job->cancelProperties());
                     /*for (int i = 0; i < processingItems.count(); i++)
-                        setProxyStatus(processingItems.at(i), NOJOB);*/
+                        setJobStatus(processingItems.at(i), NOJOB);*/
                 }
                 else continue;
                 result = -2;
             }
             else {
                 int progress = job->processLogInfo();
-                if (progress > -1) processLogInfo(processingItems, progress);
+                if (progress > -1) processLogInfo(processingItems, progress, job->jobType);
             }
             jobProcess->waitForFinished(500);
         }
@@ -2639,14 +2706,16 @@ void ProjectList::slotGenerateProxy()
         if (result == QProcess::NormalExit) {
             // proxy successfully created
             for (int i = 0; i < processingItems.count(); i++)
-                setProxyStatus(processingItems.at(i), JOBDONE);
-            slotGotProxy(job->destination());
+                setJobStatus(processingItems.at(i), JOBDONE);
+            if (job->jobType == PROXYJOB) slotGotProxy(job->destination());
+            //TODO: set folder for transcoded clips
+            else if (job->jobType == CUTJOB) emit addClip(job->destination(), QString(), QString());
         }
         else if (result == QProcess::CrashExit) {
             // Proxy process crashed
             QFile::remove(job->destination());
             for (int i = 0; i < processingItems.count(); i++)
-                setProxyStatus(processingItems.at(i), JOBCRASHED);
+                setJobStatus(processingItems.at(i), JOBCRASHED);
         }
         delete job;
         continue;
@@ -2662,10 +2731,10 @@ void ProjectList::slotGenerateProxy()
 }
 
 
-void ProjectList::processLogInfo(QList <ProjectItem *>items, int progress)
+void ProjectList::processLogInfo(QList <ProjectItem *>items, int progress, JOBTYPE jobType)
 {
     for (int i = 0; i < items.count(); i++)
-        setProxyStatus(items.at(i), CREATINGJOB, progress);
+        setJobStatus(items.at(i), CREATINGJOB, progress, jobType);
 }
 
 void ProjectList::updateProxyConfig()
@@ -2687,7 +2756,7 @@ void ProjectList::updateProxyConfig()
         }
         CLIPTYPE t = item->clipType();
         if ((t == VIDEO || t == AV || t == UNKNOWN) && item->referencedClip() != NULL) {
-            if  (generateProxy() && useProxy() && !item->isProxyRunning()) {
+            if  (generateProxy() && useProxy() && !hasPendingProxy(item)) {
                 DocClipBase *clip = item->referencedClip();
                 if (clip->getProperty("frame_size").section('x', 0, 0).toInt() > m_doc->getDocumentProperty("proxyminsize").toInt()) {
                     if (clip->getProperty("proxy").isEmpty()) {
@@ -2846,11 +2915,11 @@ void ProjectList::slotDeleteProxy(const QString proxyPath)
     QFile::remove(proxyPath);
 }
 
-void ProjectList::setProxyStatus(ProjectItem *item, CLIPJOBSTATUS status, int progress)
+void ProjectList::setJobStatus(ProjectItem *item, CLIPJOBSTATUS status, int progress, JOBTYPE jobType)
 {
     if (item == NULL || m_abortAllJobs) return;
     monitorItemEditing(false);
-    item->setProxyStatus(status, progress);
+    item->setJobStatus(status, progress, jobType);
     if (status == JOBCRASHED) {
         DocClipBase *clip = item->referencedClip();
         if (!clip) {
@@ -2949,4 +3018,30 @@ void ProjectList::slotCancelRunningJob(const QString id, stringMap newProps)
     m_commandStack->push(command);    
 }
 
+bool ProjectList::hasPendingProxy(ProjectItem *item)
+{
+    if (!item || !item->referencedClip() || m_abortAllJobs) return false;
+    for (int i = 0; i < m_jobList.count(); i++) {
+        if (m_abortAllJobs) break;
+        if (m_jobList.at(i)->clipId() == item->clipId() && m_jobList.at(i)->jobType == PROXYJOB) return true;
+    }
+    if (item->isProxyRunning()) return true;
+    return false;
+}
+
+void ProjectList::deleteJobsForClip(const QString &clipId)
+{
+    QList <AbstractClipJob *> jobsToDelete;
+    for (int i = 0; i < m_jobList.count(); i++) {
+        if (m_abortAllJobs) break;
+        if (m_jobList.at(i)->clipId() == clipId) {
+            AbstractClipJob *job = m_jobList.takeAt(i);
+            delete job;
+            i--;
+        }
+    }
+}
+
+
+
 #include "projectlist.moc"
index e273b724cb1343c84aff155d0112b81576a21c4e..a2ee232a8cd0a4cdbb9d21a419dcc14f5f873941 100644 (file)
@@ -51,6 +51,7 @@
 #include "kdenlivesettings.h"
 #include "folderprojectitem.h"
 #include "subprojectitem.h"
+#include "projecttree/abstractclipjob.h"
 #include <kdialog.h>
 
 namespace Mlt
@@ -170,7 +171,7 @@ public:
                     }
                 }
                 else if (proxy == JOBCRASHED) {
-                    proxyText = i18n("Proxy crashed");
+                    proxyText = index.data(Qt::UserRole + 7).toString();
                     QRectF txtBounding = painter->boundingRect(r2, Qt::AlignRight | Qt::AlignVCenter, " " + proxyText + " ");
                     painter->setPen(Qt::NoPen);
                     painter->setBrush(option.palette.highlight());
@@ -269,6 +270,7 @@ public slots:
 
     /** @brief Prepares removing the selected items. */
     void slotRemoveClip();
+    void slotAddClip(const QString url, const QString &groupName, const QString &groupId);
     void slotAddClip(const QList <QUrl> givenList = QList <QUrl> (), const QString &groupName = QString(), const QString &groupId = QString());
 
     /** @brief Adds, edits or deletes a folder item.
@@ -288,6 +290,8 @@ public slots:
     void slotForceProcessing(const QString &id);
     /** @brief Remove all instances of a proxy and delete the file. */
     void slotDeleteProxy(const QString proxyPath);
+    /** @brief Start a hard cut clip job. */
+    void slotCutClipJob(const QString &id, QPoint zone);
 
 private:
     ProjectListView *m_listView;
@@ -354,16 +358,22 @@ private:
 
     /** @brief Set the Proxy status on a clip. 
      * @param item The clip item to set status
-     * @param status The proxy status (see definitions.h) */
-    void setProxyStatus(ProjectItem *item, CLIPJOBSTATUS status, int progress = 0);
+     * @param status The job status (see definitions.h) */
+    void setJobStatus(ProjectItem *item, CLIPJOBSTATUS status, int progress = 0, JOBTYPE jobType = NOJOBTYPE);
     /** @brief Process ffmpeg output to find out process progress. */
-    void processLogInfo(QList <ProjectItem *>items, int progress);
+    void processLogInfo(QList <ProjectItem *>items, int progress, JOBTYPE jobType);
     void monitorItemEditing(bool enable);
     /** @brief Get cached thumbnail for a project's clip or create it if no cache. */
     void getCachedThumbnail(ProjectItem *item);
     void getCachedThumbnail(SubProjectItem *item);
     /** @brief The clip is about to be reloaded, cancel thumbnail requests. */
     void resetThumbsProducer(DocClipBase *clip);
+    /** @brief Check if it is necessary to start a job thread. */
+    void startJobProcess();
+    /** @brief Check if a clip has a running or pending proxy process. */
+    bool hasPendingProxy(ProjectItem *item);
+    /** @brief Delete pending jobs for a clip. */
+    void deleteJobsForClip(const QString &clipId);
 
 private slots:
     void slotClipSelected();
@@ -402,8 +412,8 @@ private slots:
     void slotCreateProxy(const QString id);
     /** @brief Stop creation of this clip's proxy. */
     void slotAbortProxy(const QString id, const QString path);
-    /** @brief Start creation of proxy clip. */
-    void slotGenerateProxy();
+    /** @brief Start creation of clip jobs. */
+    void slotProcessJobs();
     /** @brief Discard running and pending clip jobs. */
     void slotCancelJobs();
     /** @brief Discard a running clip jobs. */
@@ -434,6 +444,7 @@ signals:
     /** @brief Set number of running jobs. */
     void jobCount(int);
     void cancelRunningJob(const QString, stringMap);
+    void addClip(const QString, const QString &, const QString &);
 };
 
 #endif
index 8cac2b7ede0ef4f38331807a0fc4d673126c54cb..f05f9fcc060f1a46aa09a2020985fe8598db38cc 100644 (file)
@@ -2,5 +2,6 @@ set(kdenlive_SRCS
   ${kdenlive_SRCS}
   projecttree/abstractclipjob.cpp
   projecttree/proxyclipjob.cpp
+  projecttree/cutclipjob.cpp
   PARENT_SCOPE
 )
index 74c656ca7fec120d07f54b298985a6dcb76951ce..6975b4765a8f3a5b34de0947112b44740cbdeba5 100644 (file)
@@ -26,7 +26,7 @@
 
 #include "definitions.h"
 
-enum JOBTYPE { PROXYJOB = 1, CUTJOB = 2};
+enum JOBTYPE { NOJOBTYPE = 0, PROXYJOB = 1, CUTJOB = 2};
 
 class AbstractClipJob : public QObject
 {
diff --git a/src/projecttree/cutclipjob.cpp b/src/projecttree/cutclipjob.cpp
new file mode 100644 (file)
index 0000000..9397e2b
--- /dev/null
@@ -0,0 +1,106 @@
+/***************************************************************************
+ *                                                                         *
+ *   Copyright (C) 2011 by Jean-Baptiste Mardelle (jb@kdenlive.org)        *
+ *                                                                         *
+ *   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 of the License, 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.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
+ ***************************************************************************/
+
+#include "cutclipjob.h"
+#include "kdenlivesettings.h"
+#include "kdenlivedoc.h"
+
+#include <KDebug>
+#include <KLocale>
+
+CutClipJob::CutClipJob(CLIPTYPE cType, const QString &id, QStringList parameters) : AbstractClipJob(CUTJOB, cType, id, parameters)
+{
+    description = i18n("clip cut");
+    m_dest = parameters.at(0);
+    m_src = parameters.at(1);
+    m_start = parameters.at(2);
+    m_end = parameters.at(3);
+    m_jobDuration = parameters.at(4).toInt();
+    if (parameters.count() == 6) m_cutExtraParams = parameters.at(5).simplified();
+}
+
+QProcess *CutClipJob::startJob(bool *ok)
+{
+    // Special case: playlist clips (.mlt or .kdenlive project files)
+    if (clipType == AV || clipType == AUDIO || clipType == VIDEO) {
+       QStringList parameters;
+        parameters << "-i" << m_src;
+        parameters << "-ss" << m_start <<"-t" << m_end;
+        parameters << "-acodec" << "copy" << "-vcodec" << "copy";
+        if (!m_cutExtraParams.isEmpty()) {
+            foreach(const QString &s, m_cutExtraParams.split(' '))
+                parameters << s;
+        }
+
+        // Make sure we don't block when proxy file already exists
+        parameters << "-y";
+        parameters << m_dest;
+        m_jobProcess = new QProcess;
+        m_jobProcess->setProcessChannelMode(QProcess::MergedChannels);
+        kDebug()<<"// STARTING CIUT JOS: "<<parameters;
+        m_jobProcess->start("ffmpeg", parameters);
+        m_jobProcess->waitForStarted();
+       return m_jobProcess;
+    }
+    *ok = false;
+    return NULL;
+}
+
+int CutClipJob::processLogInfo()
+{
+    if (!m_jobProcess || m_jobDuration == 0) return -1;
+    QString log = m_jobProcess->readAll();
+    kDebug()<<log;
+    int progress;
+    // Parse FFmpeg output
+    if (log.contains("frame=")) {
+        int progress = log.section("frame=", 1, 1).simplified().section(' ', 0, 0).toInt();
+        kDebug()<<"// PROgress: "<<progress<<", DUR: "<<m_jobDuration;
+        return (int) (100.0 * progress / m_jobDuration);
+    }
+    else if (log.contains("time=")) {
+        QString time = log.section("time=", 1, 1).simplified().section(' ', 0, 0);
+        if (time.contains(':')) {
+            QStringList numbers = time.split(':');
+            progress = numbers.at(0).toInt() * 3600 + numbers.at(1).toInt() * 60 + numbers.at(2).toDouble();
+        }
+        else progress = (int) time.toDouble();
+        kDebug()<<"// PROgress: "<<progress<<", DUR: "<<m_jobDuration;
+        return (int) (100.0 * progress / m_jobDuration);
+    }
+    return -1;
+}
+
+CutClipJob::~CutClipJob()
+{
+}
+
+const QString CutClipJob::destination() const
+{
+    return m_dest;
+}
+
+stringMap CutClipJob::cancelProperties()
+{
+    QMap <QString, QString> props;
+    return props;
+}
+
+
diff --git a/src/projecttree/cutclipjob.h b/src/projecttree/cutclipjob.h
new file mode 100644 (file)
index 0000000..c6178cf
--- /dev/null
@@ -0,0 +1,51 @@
+/***************************************************************************
+ *                                                                         *
+ *   Copyright (C) 2011 by Jean-Baptiste Mardelle (jb@kdenlive.org)        *
+ *                                                                         *
+ *   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 of the License, 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.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
+ ***************************************************************************/
+
+#ifndef CUTCLIPJOB
+#define CUTCLIPJOB
+
+#include <QObject>
+#include <QProcess>
+
+#include "abstractclipjob.h"
+
+
+class CutClipJob : public AbstractClipJob
+{
+    Q_OBJECT
+
+public:
+    CutClipJob(CLIPTYPE cType, const QString &id, QStringList parameters);
+    virtual ~ CutClipJob();
+    const QString destination() const;
+    QProcess *startJob(bool *ok);
+    stringMap cancelProperties();
+    int processLogInfo();
+    
+private:
+    QString m_dest;
+    QString m_src;
+    QString m_start;
+    QString m_end;
+    QString m_cutExtraParams;
+    int m_jobDuration;
+};
+
+#endif
index 5526eb2b34d446f1ab222ed3bf29fc81704d6f8a..9ff69087e0855e18f3e7891f7da94eecec031788 100644 (file)
@@ -25,7 +25,7 @@
 #include <KDebug>
 #include <KLocale>
 
-ProxyJob::ProxyJob(JOBTYPE type, CLIPTYPE cType, const QString &id, QStringList parameters) : AbstractClipJob(type, cType, id, parameters),
+ProxyJob::ProxyJob(CLIPTYPE cType, const QString &id, QStringList parameters) : AbstractClipJob(PROXYJOB, cType, id, parameters),
     m_jobDuration(0),
     m_isFfmpegJob(true)
 {
@@ -130,8 +130,8 @@ QProcess *ProxyJob::startJob(bool *ok)
        QStringList parameters;
         parameters << "-i" << m_src;
         QString params = m_proxyParams;
-        foreach(QString s, params.split(' '))
-        parameters << s;
+        foreach(const QString &s, params.split(' '))
+            parameters << s;
 
         // Make sure we don't block when proxy file already exists
         parameters << "-y";
index 82366aff490206bfce3a1a8a2f430d8b9a241799..20c04d3fa1e85ee95e8623973baf37ab10bb1f73 100644 (file)
@@ -32,7 +32,7 @@ class ProxyJob : public AbstractClipJob
     Q_OBJECT
 
 public:
-    ProxyJob(JOBTYPE type, CLIPTYPE cType, const QString &id, QStringList parameters);
+    ProxyJob(CLIPTYPE cType, const QString &id, QStringList parameters);
     virtual ~ ProxyJob();
     const QString destination() const;
     QProcess *startJob(bool *ok);
index a0ff4312f8ad1c4e7cc738db423f71ca7ce26c43..17f264705a13435bb5e0b19857ecc4629312dc5a 100644 (file)
@@ -915,6 +915,9 @@ void Render::processFileProperties()
             int video_max = 0;
             int default_audio = producer->get_int("audio_index");
             int audio_max = 0;
+            
+            int scan = producer->get_int("meta.media.progressive");
+            filePropertyMap["progressive"] = QString::number(scan);
 
             // Find maximum stream index values
             for (int ix = 0; ix < producer->get_int("meta.media.nb_streams"); ix++) {
index ca51d7cf54422505429ad2620da7a09eb3f90c6a..08d524d13b274eabfa2bc52c8a39eb8e91b2a13d 100644 (file)
@@ -210,7 +210,7 @@ const QString Timecode::getTimecodeFromFrames(int frames) const
 
 
 //static
-QString Timecode::getStringTimecode(int frames, const double &fps)
+QString Timecode::getStringTimecode(int frames, const double &fps, bool showFrames)
 {
     // Returns the timecode in an hh:mm:ss format
 
@@ -221,6 +221,7 @@ QString Timecode::getStringTimecode(int frames, const double &fps)
     }
 
     int seconds = (int)(frames / fps);
+    int frms = frames % (int) (fps + 0.5);
     int minutes = seconds / 60;
     seconds = seconds % 60;
     int hours = minutes / 60;
@@ -233,6 +234,10 @@ QString Timecode::getStringTimecode(int frames, const double &fps)
     text.append(QString::number(minutes).rightJustified(2, '0', false));
     text.append(':');
     text.append(QString::number(seconds).rightJustified(2, '0', false));
+    if (showFrames) {
+        text.append('.');
+        text.append(QString::number(frms).rightJustified(2, '0', false));
+    }
     return text;
 }
 
index c98ac209589e700651ff3976bb499c1967b664be..35a6f41e87df791254ceb6f7950fe68e0cee2be7 100644 (file)
@@ -50,7 +50,7 @@ public:
     int getDisplayFrameCount(const QString &duration, bool frameDisplay) const;
     int getFrameCount(const QString &duration) const;
     static QString getEasyTimecode(const GenTime & time, const double &fps);
-    static QString getStringTimecode(int frames, const double &fps);
+    static QString getStringTimecode(int frames, const double &fps, bool showFrames = false);
     const QString getDisplayTimecodeFromFrames(int frames, bool frameDisplay) const;
     const QString getTimecodeFromFrames(int frames) const;
     double fps() const;
diff --git a/src/widgets/cutjobdialog_ui.ui b/src/widgets/cutjobdialog_ui.ui
new file mode 100644 (file)
index 0000000..cd8a118
--- /dev/null
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CutJobDialog_UI</class>
+ <widget class="QDialog" name="CutJobDialog_UI">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>359</width>
+    <height>171</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Cut Clip</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_2">
+   <item row="1" column="0" colspan="2">
+    <widget class="QTabWidget" name="tabWidget">
+     <property name="currentIndex">
+      <number>0</number>
+     </property>
+     <widget class="QWidget" name="tab">
+      <attribute name="title">
+       <string>Cut file</string>
+      </attribute>
+      <layout class="QGridLayout" name="gridLayout_3">
+       <item row="2" column="0" colspan="2">
+        <widget class="QCheckBox" name="add_clip">
+         <property name="text">
+          <string>Add new clip to project</string>
+         </property>
+        </widget>
+       </item>
+       <item row="3" column="1">
+        <spacer name="verticalSpacer">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>40</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item row="1" column="1">
+        <widget class="KUrlRequester" name="file_url">
+         <property name="mode">
+          <set>KFile::File|KFile::LocalOnly</set>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="0">
+        <widget class="QLabel" name="label">
+         <property name="text">
+          <string>Save to</string>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="0" colspan="2">
+        <widget class="QLabel" name="info_label">
+         <property name="text">
+          <string/>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="tab_2">
+      <attribute name="title">
+       <string>Advanced</string>
+      </attribute>
+      <layout class="QGridLayout" name="gridLayout">
+       <item row="1" column="0">
+        <widget class="QTextEdit" name="extra_params"/>
+       </item>
+       <item row="0" column="0">
+        <widget class="QLabel" name="label_2">
+         <property name="text">
+          <string>Extra parameters</string>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </widget>
+   </item>
+   <item row="2" column="0" colspan="2">
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>KUrlRequester</class>
+   <extends>QFrame</extends>
+   <header>kurlrequester.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>CutJobDialog_UI</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>CutJobDialog_UI</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>