]> git.sesse.net Git - kdenlive/commitdiff
Merge branch 'master' into effectstack
authorJean-Baptiste Mardelle <jb@kdenlive.org>
Mon, 19 Mar 2012 13:05:53 +0000 (14:05 +0100)
committerJean-Baptiste Mardelle <jb@kdenlive.org>
Mon, 19 Mar 2012 13:05:53 +0000 (14:05 +0100)
Conflicts:
src/CMakeLists.txt

168 files changed:
ChangeLog
data/blacklisted_effects.txt
effects/CMakeLists.txt
effects/README
effects/boxblur.xml
effects/dynamictext.xml [new file with mode: 0644]
effects/frei0r_iirblur.xml
effects/frei0r_squareblur.xml
effects/sox_gain.xml
icons/CMakeLists.txt
src/CMakeLists.txt
src/abstractmonitor.cpp
src/abstractmonitor.h
src/archivewidget.cpp
src/archivewidget.h
src/audioscopes/CMakeLists.txt [deleted file]
src/blackmagic/include/DeckLinkAPIVersion.h
src/choosecolorwidget.cpp
src/choosecolorwidget.h
src/clipitem.cpp
src/clipitem.h
src/clipmanager.cpp
src/clipmanager.h
src/clipproperties.cpp
src/clipproperties.h
src/clipstabilize.cpp [new file with mode: 0644]
src/clipstabilize.h [new file with mode: 0644]
src/cliptranscode.cpp
src/cliptranscode.h
src/colorcorrection/vectorscopegenerator.cpp
src/colorscopes/CMakeLists.txt [deleted file]
src/customruler.cpp
src/customtrackview.cpp
src/customtrackview.h
src/definitions.h
src/docclipbase.cpp
src/docclipbase.h
src/documentchecker.cpp
src/documentchecker.h
src/documentvalidator.cpp
src/documentvalidator.h
src/dvdwizardchapters.cpp
src/effectslistview.cpp
src/effectslistwidget.cpp
src/effectstackedit.cpp
src/effectstackedit.h
src/effectstackview.cpp
src/effectstackview.h
src/geometrywidget.cpp
src/headertrack.cpp
src/headertrack.h
src/kdenlive.desktop
src/kdenlive.notifyrc
src/kdenlivedoc.cpp
src/kdenlivedoc.h
src/kdenlivesettings.kcfg
src/kdenlivesettingsdialog.cpp
src/kdenlivesettingsdialog.h
src/kdenlivetranscodingrc
src/kdenliveui.rc
src/keyframehelper.cpp
src/keyframehelper.h
src/kthumb.cpp
src/kthumb.h
src/mainwindow.cpp
src/mainwindow.h
src/mltdevicecapture.cpp
src/mltdevicecapture.h
src/monitor.cpp
src/monitor.h
src/monitoreditwidget.cpp
src/monitoreditwidget.h
src/monitormanager.cpp
src/monitormanager.h
src/projectitem.cpp
src/projectitem.h
src/projectlist.cpp
src/projectlist.h
src/projectlistview.cpp
src/projectsettings.cpp
src/projectsettings.h
src/projecttree/CMakeLists.txt [new file with mode: 0644]
src/projecttree/abstractclipjob.cpp [new file with mode: 0644]
src/projecttree/abstractclipjob.h [new file with mode: 0644]
src/projecttree/cutclipjob.cpp [new file with mode: 0644]
src/projecttree/cutclipjob.h [new file with mode: 0644]
src/projecttree/meltjob.cpp [new file with mode: 0644]
src/projecttree/meltjob.h [new file with mode: 0644]
src/projecttree/proxyclipjob.cpp [new file with mode: 0644]
src/projecttree/proxyclipjob.h [new file with mode: 0644]
src/recmonitor.cpp
src/recmonitor.h
src/renderer.cpp
src/renderer.h
src/renderwidget.cpp
src/renderwidget.h
src/scopes/CMakeLists.txt [new file with mode: 0644]
src/scopes/abstractscopewidget.cpp [moved from src/abstractscopewidget.cpp with 99% similarity]
src/scopes/abstractscopewidget.h [moved from src/abstractscopewidget.h with 82% similarity]
src/scopes/audioscopes/CMakeLists.txt [new file with mode: 0644]
src/scopes/audioscopes/abstractaudioscopewidget.cpp [moved from src/audioscopes/abstractaudioscopewidget.cpp with 93% similarity]
src/scopes/audioscopes/abstractaudioscopewidget.h [moved from src/audioscopes/abstractaudioscopewidget.h with 89% similarity]
src/scopes/audioscopes/audiosignal.cpp [moved from src/audiosignal.cpp with 75% similarity]
src/scopes/audioscopes/audiosignal.h [moved from src/audiosignal.h with 72% similarity]
src/scopes/audioscopes/audiospectrum.cpp [moved from src/audioscopes/audiospectrum.cpp with 100% similarity]
src/scopes/audioscopes/audiospectrum.h [moved from src/audioscopes/audiospectrum.h with 95% similarity]
src/scopes/audioscopes/ffttools.cpp [moved from src/audioscopes/ffttools.cpp with 100% similarity]
src/scopes/audioscopes/ffttools.h [moved from src/audioscopes/ffttools.h with 100% similarity]
src/scopes/audioscopes/spectrogram.cpp [moved from src/audioscopes/spectrogram.cpp with 100% similarity]
src/scopes/audioscopes/spectrogram.h [moved from src/audioscopes/spectrogram.h with 100% similarity]
src/scopes/colorscopes/CMakeLists.txt [new file with mode: 0644]
src/scopes/colorscopes/abstractgfxscopewidget.cpp [moved from src/colorscopes/abstractgfxscopewidget.cpp with 54% similarity]
src/scopes/colorscopes/abstractgfxscopewidget.h [moved from src/colorscopes/abstractgfxscopewidget.h with 85% similarity]
src/scopes/colorscopes/histogram.cpp [moved from src/colorscopes/histogram.cpp with 97% similarity]
src/scopes/colorscopes/histogram.h [moved from src/colorscopes/histogram.h with 94% similarity]
src/scopes/colorscopes/rgbparade.cpp [moved from src/colorscopes/rgbparade.cpp with 97% similarity]
src/scopes/colorscopes/rgbparade.h [moved from src/colorscopes/rgbparade.h with 90% similarity]
src/scopes/colorscopes/vectorscope.cpp [moved from src/colorscopes/vectorscope.cpp with 99% similarity]
src/scopes/colorscopes/vectorscope.h [moved from src/colorscopes/vectorscope.h with 94% similarity]
src/scopes/colorscopes/waveform.cpp [moved from src/colorscopes/waveform.cpp with 98% similarity]
src/scopes/colorscopes/waveform.h [moved from src/colorscopes/waveform.h with 90% similarity]
src/scopes/scopemanager.cpp [new file with mode: 0644]
src/scopes/scopemanager.h [new file with mode: 0644]
src/slideshowclip.cpp
src/smallruler.cpp
src/smallruler.h
src/stopmotion/stopmotion.cpp
src/stopmotion/stopmotion.h
src/timecode.cpp
src/timecode.h
src/timecodedisplay.cpp
src/timecodedisplay.h
src/titledocument.cpp
src/titlewidget.cpp
src/titlewidget.h
src/trackview.cpp
src/trackview.h
src/transition.cpp
src/utils/CMakeLists.txt [new file with mode: 0644]
src/utils/abstractservice.cpp [new file with mode: 0644]
src/utils/abstractservice.h [new file with mode: 0644]
src/utils/archiveorg.cpp [new file with mode: 0644]
src/utils/archiveorg.h [new file with mode: 0644]
src/utils/freesound.cpp [new file with mode: 0644]
src/utils/freesound.h [new file with mode: 0644]
src/utils/openclipart.cpp [new file with mode: 0644]
src/utils/openclipart.h [new file with mode: 0644]
src/utils/resourcewidget.cpp [new file with mode: 0644]
src/utils/resourcewidget.h [new file with mode: 0644]
src/widgets/archivewidget_ui.ui
src/widgets/clipproperties_ui.ui
src/widgets/clipstabilize_ui.ui [new file with mode: 0644]
src/widgets/configcapture_ui.ui
src/widgets/configenv_ui.ui
src/widgets/configtranscode_ui.ui
src/widgets/cutjobdialog_ui.ui [new file with mode: 0644]
src/widgets/fontval_ui.ui [new file with mode: 0644]
src/widgets/freesound_ui.ui [new file with mode: 0644]
src/widgets/geometrywidget_ui.ui
src/widgets/keywordval_ui.ui [new file with mode: 0644]
src/widgets/missingclips_ui.ui
src/widgets/projectsettings_ui.ui
src/widgets/recmonitor_ui.ui
src/widgets/renderwidget_ui.ui
src/widgets/slideshowclip_ui.ui
src/widgets/timeline_ui.ui
src/widgets/titlewidget_ui.ui
thumbnailer/westleypreview.desktop

index 7ab7cc49b3440bda00fa903c3707512de1990ef2..0cd6f028600a2c30e9856a32f29f3d5f822e0f88 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,35 @@
+Current git
+    * Fix archiving feature not saving playlist clips and slowmotion clips inside them
+    * Fix Crash recovery feature triggering error messages about wrong path
+    * Fix rendering jobs sometimes not starting
+    * Fix crash on proxy creation (concurrency issue)
+    * Fix zone playing
+    * Fix click on monitor sometimes not triggering play
+    * Add Online Resource Widget allowing easy search and download of online services (freesound, openclipart, archive.org)
+    * Introduce generic job framework for project tree jobs
+    * Fix color change not working in title widget
+    * Fix crash when moving a folder and a clip in project tree
+    * Fix profile warning with clips that have 1088 pixels height
+    * Add audio only recording (works while playing)
+
+0.8.2.1
+    * Fix title text oultine transparency not working
+    * Make titler window fit on smaller resolutions (1024x768)
+    * Fix corruption when undoing and redoing a transition add + move
+    * Fix possible crash in thumbnails
+    * Fix possible crashes in clip transcoding and improve feedback when failing
+    * Various small optimizations (unnecessary clip reloads)
+    * Fix timecode widget hard to edit and sometimes giving random values
+    * Workaround locale issue ahappening when system C locale and Qt's locale did not give the same numeric separator
+    * Fix audio thumbnail concurrency issue
+    * Fix various video thumbnails issues (don't load several times the same thumb, load all of them, ...)
+    * Fix crash when opening a file dialog on KDE < 4.5
+    * Fix various proxy issues (missing extension, concurrency, disabling broken proxy, ...)
+    * Fix startup crash caused by invalid parsing of v4l data
+    * Fix project tree disabled after loading some projects / creating new one
+    * Fix corrupted timeline / monitor timecode
+    * Fix search path for Luma files when missing
+
 0.8.2
     * Load zone thumbnails from disk if available.
     * Optimise document loading.
index e7510c4225f36259095e53d2cbb4a629aa1e5ffd..3b3d11d2c59e35e2149cb5d410fd1b41e5bdf1e6 100644 (file)
@@ -38,7 +38,7 @@ frei0r.facedetect
 frei0r.facebl0r
 frei0r.flippo
 frei0r.glow
-frei0r.iirblur
+frei0r.IIRblur
 frei0r.hqdn3d
 frei0r.hueshift0r
 frei0r.lenscorrection
@@ -98,7 +98,6 @@ resize
 resample
 mono
 
-dynamictext
 
 # Effects need extra GUI to create the resulting melt.xml with the corrected content
 videostab
index c32a199c40db763c8411a57844cceb496f412794..8aa6c04d59fe14b128e7febdba59e704aeeb0662 100644 (file)
@@ -10,6 +10,7 @@ chroma_hold.xml
 chroma.xml
 crop.xml
 dust.xml
+dynamictext.xml
 freeze.xml
 gamma.xml
 grain.xml
index 4ee6646694cab05f7b986a68bb18efe15a6eb90e..b19bba359646e952d539051ba95c7901ce468814 100644 (file)
@@ -71,15 +71,17 @@ The rest:
                 - multiple choice
                 - represented by a drop-down menu
                 - additional parameter attribute:
-                    - "paramlist": list of possible values separated by comma (no whitespaces!)
+                    - "paramlist": list of possible values separated by semicolon (no whitespaces!)
                 - addtional tag:
-                    - "paramlistdisplay": (optional) list of names to use for the values
+                    - "paramlistdisplay": (optional) list of names to use for the values separated by comma
             - "position":
                 - time stored as frame number
                 - represented by a slider
             - "color":
-                - color value, similar to representation HTML ("#rrggbb" or "0xrrggbb")
+                - color value, similar to representation HTML ("#rrggbb"/"#aarrggbb" or "0xrrggbbaa")
                 - represented by a button opening the KDE color dialog + a color picker button
+                - additional attributes:
+                    - "alpha": (default = "0") use to enable alpha support
             - "keyframe":
                 - keyframable number
                 - keyframes are opt-in (only one keyframe by default -> should be prefered over "constant" whenever possible)
@@ -112,6 +114,13 @@ The rest:
                 - cubic Bézier spline editor for the frei0r color curves filter (new version, might be reused for other filters)
             - "roto-spline":
                 - GUI for the rotoscoping filter (spline on the monitor)
+            - "keywords":
+                - Text entry with a selection of possible keywords to be inserted in the text.
+                - additional tags:
+                    - "keywords": list of possible keyword values separated by semicolon
+                    - "keywordsdisplay": list of names to use for the values separated by semicolon
+            - "fontfamily":
+                - Font typeface entry
 ==========
 
 ==========
index 570de690415093185e87b0665e13a139fbde964f..761388e11f90e618f6552aa478e6ef7dd889629d 100644 (file)
@@ -1,7 +1,7 @@
 <!DOCTYPE kpartgui>
 <effect tag="boxblur" id="boxblur">
        <name>Box Blur</name>
-       <description>Blur image with keyframes</description>
+       <description>Box blur (separate horizontal and vertical blur)</description>
        <author>Leny Grisel</author>
        <parameter type="constant" name="hori" max="50" min="1" default="1">
                <name>Horizontal multiplicator</name>
diff --git a/effects/dynamictext.xml b/effects/dynamictext.xml
new file mode 100644 (file)
index 0000000..dcfbbb1
--- /dev/null
@@ -0,0 +1,46 @@
+<!DOCTYPE kpartgui>
+<effect tag="dynamictext" id="dynamictext">
+    <name>Dynamic Text</name>
+    <description>Overlay text with keywords replaced</description>
+    <author>Brian Matherly</author>
+    <parameter type="geometry" name="geometry" default="0%/0%:100%x100%:100" fixed="0">
+        <name>Geometry</name>
+    </parameter>
+    <parameter type="fontfamily" name="family" default="Sans">
+        <name>Font Family</name>
+    </parameter>
+    <parameter type="constant" name="size" max="200" min="8" default="48">
+        <name>Font Size</name>
+    </parameter>
+    <parameter type="constant" name="weight" max="900" min="100" default="400">
+        <name>Font Weight</name>
+    </parameter>
+    <parameter type="color" name="fgcolour" default="0x000000ff" alpha="1">
+        <name>Foreground Color</name>
+    </parameter>
+    <parameter type="color" name="bgcolour" default="0x00000020" alpha="1">
+        <name>Background Color</name>
+    </parameter>
+    <parameter type="color" name="olcolour" default="0x00000000" alpha="1">
+        <name>Outline Color</name>
+    </parameter>
+    <parameter type="constant" name="outline" max="3" min="0" default="0">
+        <name>Outline Width</name>
+    </parameter>
+    <parameter type="constant" name="pad" max="500" min="0" default="0">
+        <name>Padding</name>
+    </parameter>
+    <parameter type="list" name="halign" default="left" paramlist="left;centre;right">
+        <paramlistdisplay>Left,Center,Right</paramlistdisplay>
+        <name>Horizontal Alignment</name>
+    </parameter>
+    <parameter type="list" name="valign" default="top" paramlist="top;middle;bottom">
+        <paramlistdisplay>Top,Middle,Bottom</paramlistdisplay>
+        <name>Vertical Alignment</name>
+    </parameter>
+    <parameter type="keywords" name="argument" default="#timecode#">
+        <name>Text</name>
+        <keywords>#timecode#;#frame#;#filedate#;#meta.media.0.stream.frame_rate#;#meta.media.0.codec.name#;#meta.media.0.codec.bit_rate#;#meta.media.width#;#meta.media.height#;#meta.attr.comment.markup#</keywords>
+        <keywordsdisplay>timecode;frame;file date;source frame rate;source codec;source bit rate;source width;source height;source comment</keywordsdisplay>
+    </parameter>
+</effect>
index f17750855b6dd6aa361043da233f2fa34ac91303..f190444a40b7925ddf0410141db52eff8038be98 100644 (file)
@@ -1,7 +1,7 @@
 <!DOCTYPE kpartgui>
 <effect tag="frei0r.IIRblur" id="frei0r.IIRblur">
-        <name>IIR Blur</name>
-        <description>Blur using 2D IIR filters</description>
+        <name>Blur</name>
+        <description>Blur using 2D IIR filters (Exponential, Lowpass, Gaussian)</description>
         <author>Marko Cebokli</author>
         
         <parameter type="simplekeyframe" name="Amount" default="40" min="0" max="1000" factor="1000">
index 642bd20e431db10782dd318c298a385a68a8e007..1c0c3be32cb2f662e4e696a6ed88563184e6eb34 100644 (file)
@@ -1,7 +1,7 @@
 <!DOCTYPE kpartgui>
 <effect tag="frei0r.squareblur" id="frei0r.squareblur">
        <name>Square Blur</name>
-       <description>Variable-size square blur (frei0r.squareblur)</description>
+       <description>Square blur</description>
        <author>Drone</author>
        <parameter type="simplekeyframe" name="Kernel size" max="500" min="0" default="50" factor="1000">
                <name>Kernel size</name>
index d43f91ee782591634ecfb7ca65459ff878f9d286..d40552b5242a1a4c0a6ead625972c7e270088bcb 100644 (file)
@@ -3,7 +3,10 @@
        <name>Sox Gain</name>
        <description>Sox gain audio effect</description>
        <author>http://sox.sourceforge.net</author>
-       <parameter type="constant" name="gain" max="50" min="-50" default="5">
+       <parameter type="double" name="gain" max="50" min="-50" default="5.00" decimals="2">
                <name>Gain</name>
        </parameter>
+       <parameter type="filterjob" filtertag="sox:analysis" filterparams="" consumer="null" consumerparams="video_off=1 all=1 terminate_on_pause=1" wantedproperties="gain" finalfilter="sox_gain">
+               <name>Normalize</name>
+       </parameter>
 </effect>
index 6ab32fbdd5dd4f8fabadeccb8c77ae2c5f17002e..c41644a6a9fc09970c4812ff8876b9176d87a32e 100644 (file)
@@ -1,3 +1,3 @@
 #FILE(GLOB files "${CMAKE_CURRENT_SOURCE_DIR}/*.svg*")
-kde4_install_icons( ${DATA_INSTALL_DIR}/kdenlive/icons)
+kde4_install_icons( ${DATA_INSTALL_DIR}/kdenlive/icons )
 #install( FILES ${files} DESTINATION ${ICON_INSTALL_DIR} )
index 843beac7461dcb0117bddceb73bf389f86e2506e..fdbd92b4e020295f6e862702bf435c30424466ac 100644 (file)
@@ -69,20 +69,21 @@ macro_log_feature(QJSON_FOUND
   "http://qjson.sourceforge.net"
   FALSE
   ""
-  "Required to build the rotoscoping filter"
+  "Required to build the rotoscoping filter and for Freesound.org queries"
 )
 
-add_subdirectory(audioscopes)
+
 add_subdirectory(beziercurve)
-add_subdirectory(blackmagic)
 add_subdirectory(colorcorrection)
-add_subdirectory(colorscopes)
 add_subdirectory(commands)
+add_subdirectory(projecttree)
+add_subdirectory(utils)
 add_subdirectory(databackup)
 add_subdirectory(effectstack)
 add_subdirectory(kiss_fft)
 add_subdirectory(mimetypes)
 add_subdirectory(onmonitoritems)
+add_subdirectory(scopes)
 add_subdirectory(simplekeyframes)
 add_subdirectory(stopmotion)
 
@@ -103,15 +104,14 @@ list(APPEND kdenlive_SRCS
   abstractclipitem.cpp
   abstractgroupitem.cpp
   abstractmonitor.cpp
-  abstractscopewidget.cpp
   archivewidget.cpp
-  audiosignal.cpp
   choosecolorwidget.cpp
   clipdurationdialog.cpp
   clipitem.cpp
   clipmanager.cpp
   clipproperties.cpp
   cliptranscode.cpp
+  clipstabilize.cpp
   colorpickerwidget.cpp
   colorplaneexport.cpp
   colortools.cpp
@@ -197,6 +197,7 @@ kde4_add_ui_files(kdenlive_UIS
   widgets/clipproperties_ui.ui
   widgets/cliptranscode_ui.ui
   widgets/collapsiblewidget_ui.ui
+  widgets/clipstabilize_ui.ui
   widgets/colorclip_ui.ui
   widgets/colorplaneexport_ui.ui
   widgets/configcapture_ui.ui
@@ -214,6 +215,7 @@ kde4_add_ui_files(kdenlive_UIS
   widgets/effectlist_ui.ui
   widgets/effectstack_ui.ui
   widgets/effectstack2_ui.ui
+  widgets/freesound_ui.ui
   widgets/geometryval_ui.ui
   widgets/geometrywidget_ui.ui
   widgets/histogram_ui.ui
@@ -254,6 +256,9 @@ kde4_add_ui_files(kdenlive_UIS
   widgets/wizardextra_ui.ui
   widgets/wizardmltcheck_ui.ui
   widgets/wizardstandard_ui.ui
+  widgets/keywordval_ui.ui
+  widgets/fontval_ui.ui
+  widgets/cutjobdialog_ui.ui
 )
 
 if(OPENGL_FOUND)
@@ -311,6 +316,7 @@ target_link_libraries(kdenlive
   ${KDE4_KNEWSTUFF_LIBS}
   ${KDE4_KNOTIFYCONFIG_LIBRARY}
   ${KDE4_KROSSUI_LIBS}
+  ${KDE4_SOLID_LIBS}
   ${QT_LIBRARIES}
   ${LIBMLT_LIBRARY}
   ${LIBMLTPLUS_LIBRARY}
index 270bd4f6151b8ab274885dae5f15e463f8436784..fa6f43c935e96852f7a65412a2061df3e89c48a1 100644 (file)
 
 #include "abstractmonitor.h"
 #include "kdenlivesettings.h"
+#include "monitormanager.h"
 
 #include <KDebug>
 
 #include <QPaintEvent>
+#include <QDesktopWidget>
+#include <QVBoxLayout>
 
-VideoPreviewContainer::VideoPreviewContainer(QWidget *parent) :
-    QFrame(parent),
-    m_dar(1.0),
-    m_refresh(false)
+
+AbstractMonitor::AbstractMonitor(Kdenlive::MONITORID id, MonitorManager *manager, QWidget *parent): 
+    QWidget(parent),
+    videoSurface(NULL),
+    m_id(id),
+    m_monitorManager(manager)
 {
-    setFrameShape(QFrame::NoFrame);
-    setFocusPolicy(Qt::ClickFocus);
-    setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
-    connect(&m_refreshTimer, SIGNAL(timeout()), this, SLOT(update()));
-    m_refreshTimer.setSingleShot(false);
-    m_refreshTimer.setInterval(200);
+    videoBox = new VideoContainer(this);
 }
 
-VideoPreviewContainer::~VideoPreviewContainer()
+
+AbstractMonitor::~AbstractMonitor()
 {
-    qDeleteAll(m_imageQueue);
+    if (videoSurface)
+       delete videoSurface;
 }
 
-//virtual
-void VideoPreviewContainer::resizeEvent( QResizeEvent * /*event*/ )
+void AbstractMonitor::createVideoSurface()
 {
-    updateDisplayZone();
+    QVBoxLayout *lay = new QVBoxLayout;
+    lay->setContentsMargins(0, 0, 0, 0);
+    videoSurface = new VideoSurface;
+    lay->addWidget(videoSurface);
+    videoBox->setLayout(lay);
 }
 
-void VideoPreviewContainer::setRatio(double ratio)
+bool AbstractMonitor::isActive() const
 {
-    m_dar = ratio;
-    updateDisplayZone();
+    return m_monitorManager->isActive(m_id);
 }
 
+bool AbstractMonitor::slotActivateMonitor()
+{
+    return m_monitorManager->activateMonitor(m_id);
+}
 
-void VideoPreviewContainer::updateDisplayZone()
+VideoContainer::VideoContainer(AbstractMonitor* monitor, QWidget *parent) :
+    QFrame(parent)
+    , m_monitor(monitor)
 {
-    QRect rect = this->frameRect();
-    int paintW = rect.height() * m_dar + 0.5;
-    if (paintW > rect.width()) {
-        int paintH = rect.width() / m_dar + 0.5;
-        int diff = (rect.height() - paintH)  / 2;
-        rect.adjust(0, diff, 0, 0);
-        rect.setHeight(paintH);
-    }
-    else {
-        int diff = (rect.width() - paintW)  / 2;
-        rect.adjust(diff, 0, 0, 0);
-        rect.setWidth(paintW);
-    }
-    m_displayRect = rect;
-    m_refresh = true;
+    setFrameShape(QFrame::NoFrame);
+    setFocusPolicy(Qt::ClickFocus);
+    //setEnabled(false);
+    setContentsMargins(0, 0, 0, 0);
+    setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
 }
 
-void VideoPreviewContainer::setImage(QImage img)
+// virtual
+void VideoContainer::mouseReleaseEvent(QMouseEvent * event)
 {
-    if (m_imageQueue.count() > 2) {
-        delete m_imageQueue.takeLast();
+    if (event->button() != Qt::RightButton) {
+        if (m_monitor->isActive()) {
+            m_monitor->slotPlay();
+        }
     }
-    m_imageQueue.prepend(new QImage(img));
-    update();
 }
 
-void VideoPreviewContainer::stop()
+// virtual
+void VideoContainer::keyPressEvent(QKeyEvent *event)
 {
-    //m_refreshTimer.stop();
-    qDeleteAll(m_imageQueue);
-    m_imageQueue.clear();
+    // Exit fullscreen with Esc key
+    if (event->key() == Qt::Key_Escape && isFullScreen()) {
+        switchFullScreen();
+        event->setAccepted(true);
+    } else event->setAccepted(false);
 }
 
-void VideoPreviewContainer::start()
+// virtual
+void VideoContainer::wheelEvent(QWheelEvent * event)
 {
-    //m_refreshTimer.start();
+    m_monitor->slotMouseSeek(event->delta(), event->modifiers() == Qt::ControlModifier);
+    event->accept();
 }
 
-// virtual
-void VideoPreviewContainer::paintEvent(QPaintEvent *event)
+void VideoContainer::mouseDoubleClickEvent(QMouseEvent * event)
+{
+    if (!KdenliveSettings::openglmonitors())
+        switchFullScreen();
+    event->accept();
+}
+
+void VideoContainer::switchFullScreen()
 {
-    if (m_imageQueue.isEmpty()) return;
-    QImage *img = m_imageQueue.takeFirst();
-    QPainter painter(this);
-    if (m_refresh) {
-        painter.fillRect(event->rect(), QColor(KdenliveSettings::window_background()));
-        m_refresh = false;
+    // TODO: disable screensaver?
+    Qt::WindowFlags flags = windowFlags();
+    if (!isFullScreen()) {
+        // Check if we ahave a multiple monitor setup
+        setUpdatesEnabled(false);
+#if QT_VERSION >= 0x040600
+        int monitors = QApplication::desktop()->screenCount();
+#else
+        int monitors = QApplication::desktop()->numScreens();
+#endif
+        if (monitors > 1) {
+            QRect screenres;
+            // Move monitor widget to the second screen (one screen for Kdenlive, the other one for the Monitor widget
+            int currentScreen = QApplication::desktop()->screenNumber(this);
+            if (currentScreen < monitors - 1)
+                screenres = QApplication::desktop()->screenGeometry(currentScreen + 1);
+            else
+                screenres = QApplication::desktop()->screenGeometry(currentScreen - 1);
+            move(QPoint(screenres.x(), screenres.y()));
+            resize(screenres.width(), screenres.height());
+        }
+
+        m_baseFlags = flags & (Qt::Window | Qt::SubWindow);
+        flags |= Qt::Window;
+        flags ^= Qt::SubWindow;
+        setWindowFlags(flags);
+#ifdef Q_WS_X11
+        // This works around a bug with Compiz
+        // as the window must be visible before we can set the state
+        show();
+        raise();
+        setWindowState(windowState() | Qt::WindowFullScreen);   // set
+#else
+        setWindowState(windowState() | Qt::WindowFullScreen);   // set
+        setUpdatesEnabled(true);
+        show();
+#endif
+        setEnabled(true);
+    } else {
+        setUpdatesEnabled(false);
+        flags ^= (Qt::Window | Qt::SubWindow); //clear the flags...
+        flags |= m_baseFlags; //then we reset the flags (window and subwindow)
+        setWindowFlags(flags);
+        setWindowState(windowState()  ^ Qt::WindowFullScreen);   // reset
+        setUpdatesEnabled(true);
+        setEnabled(false);
+        show();
     }
-    painter.drawImage(m_displayRect, *img);
-    delete img;
 }
 
+VideoSurface::VideoSurface(QWidget* parent) :
+    QWidget(parent)
+{
+    // MonitorRefresh is used as container for the SDL display (it's window id is passed to SDL)
+    setAttribute(Qt::WA_PaintOnScreen);
+    setAttribute(Qt::WA_OpaquePaintEvent);
+    setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
+    setAttribute(Qt::WA_NoSystemBackground);
+    setUpdatesEnabled(false);
+}
+
+void VideoSurface::paintEvent(QPaintEvent *event)
+{
+    Q_UNUSED(event);
+    //WARNING: This might trigger unnecessary refreshes from MLT's producer, but without this,
+    // as soon as monitor is covered by a popup menu or another window, image is corrupted.
+    emit refreshMonitor();
+}
 
index 1167e6c446f8bc09b677158f193ee1fc2df7e9d8..58fc10931cfdf3486f7e84a9c1112857ee47d926 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef ABSTRACTMONITOR_H
 #define ABSTRACTMONITOR_H
 
+#include "definitions.h"
+
 #include <QObject>
 #include <QVector>
 #include <QWidget>
 
 #include <stdint.h>
 
-class VideoPreviewContainer : public QFrame
-{
-    Q_OBJECT
-public:
-    VideoPreviewContainer(QWidget *parent = 0);
-    ~VideoPreviewContainer();
-    /** @brief Set the image to be displayed, will be put in the queue. */
-    void setImage(QImage img);
-    /** @brief Start the display refresh timer. */
-    void start();
-    /** @brief Stop the display refresh timer. */
-    void stop();
-    /** @brief Set the display ratio for this display. */
-    void setRatio(double ratio);
-
-protected:
-    virtual void paintEvent(QPaintEvent */*event*/);
-    virtual void resizeEvent(QResizeEvent * event);
-
-private:
-    /** @brief The display aspect ratio for profile. */
-    double m_dar;
-    /** @brief When true, the whole widget surface will be repainted, useful when resizing widget. */
-    bool m_refresh;
-    /** @brief The rectangle defining the area for painting our image. */
-    QRect m_displayRect;
-    /** @brief The queue of images to be displayed. */
-    QList <QImage *> m_imageQueue;
-    /** @brief We refresh the image with a timer, since this widget is only for preview during capture. */
-    QTimer m_refreshTimer;
-    /** @brief Re-calculate the display zone after a resize or aspect ratio change. */
-    void updateDisplayZone();
-};
-
-
+class MonitorManager;
+class VideoContainer;
 
 class AbstractRender: public QObject
 {
@@ -74,7 +43,7 @@ Q_OBJECT public:
      *  @param name A unique identifier for this renderer
      *  @param winid The parent widget identifier (required for SDL display). Set to 0 for OpenGL rendering
      *  @param profile The MLT profile used for the renderer (default one will be used if empty). */
-    AbstractRender(const QString &name, QWidget *parent = 0):QObject(parent), sendFrameForAnalysis(false), m_name(name) {};
+    AbstractRender(Kdenlive::MONITORID name, QWidget *parent = 0):QObject(parent), sendFrameForAnalysis(false), m_name(name) {};
 
     /** @brief Destroy the MLT Renderer. */
     virtual ~AbstractRender() {};
@@ -82,6 +51,9 @@ Q_OBJECT public:
     /** @brief This property is used to decide if the renderer should convert it's frames to QImage for use in other Kdenlive widgets. */
     bool sendFrameForAnalysis;
     
+    /** @brief This property is used to decide if the renderer should send audio data for monitoring. */
+    bool analyseAudio;
+    
     const QString &name() const {return m_name;};
 
     /** @brief Someone needs us to send again a frame. */
@@ -95,21 +67,68 @@ signals:
     void frameUpdated(QImage);
 
     /** @brief This signal contains the audio of the current frame. */
-    void audioSamplesSignal(QVector<int16_t>, int, int, int);
+    void audioSamplesSignal(QVector<int16_t>,int,int,int);
+};
+
+
+
+class VideoSurface : public QWidget
+{
+    Q_OBJECT
+public:
+    VideoSurface(QWidget *parent = 0);
+    
+signals:
+    void refreshMonitor();
+
+protected:
+    virtual void paintEvent ( QPaintEvent * event );
 };
 
+
 class AbstractMonitor : public QWidget
 {
     Q_OBJECT
 public:
-    AbstractMonitor(QWidget *parent = 0): QWidget(parent) {};
-    virtual ~AbstractMonitor() {};
+    AbstractMonitor(Kdenlive::MONITORID id, MonitorManager *manager, QWidget *parent = 0);
+    Kdenlive::MONITORID id() {return m_id;};
+    virtual ~AbstractMonitor();
     virtual AbstractRender *abstractRender() = 0;
-    virtual const QString name() const = 0;
-
+    bool isActive() const;
+    VideoContainer *videoBox;
+    VideoSurface *videoSurface;
+    void createVideoSurface();
+    
+    
 public slots:
     virtual void stop() = 0;
     virtual void start() = 0;
+    virtual void slotPlay() = 0;
+    virtual void slotMouseSeek(int eventDelta, bool fast) = 0;
+    bool slotActivateMonitor();
+    virtual void slotSwitchFullScreen() = 0;
+
+protected:
+    Kdenlive::MONITORID m_id;
+    MonitorManager *m_monitorManager;
+};
+
+class VideoContainer : public QFrame
+{
+    Q_OBJECT
+public:
+    VideoContainer(AbstractMonitor *monitor, QWidget *parent = 0);
+    void switchFullScreen();
+
+protected:
+    virtual void mouseDoubleClickEvent(QMouseEvent * event);
+    virtual void mouseReleaseEvent(QMouseEvent *event);
+    void keyPressEvent(QKeyEvent *event);
+    virtual void wheelEvent(QWheelEvent * event);
+
+private:
+    Qt::WindowFlags m_baseFlags;
+    AbstractMonitor *m_monitor;
 };
 
 #endif
index db2b9e8db2c6d033c1db1f17a42db70beb343ad0..bee3707f224e1f7b0e7d0bff0cfce5658e219e0b 100644 (file)
@@ -32,6 +32,9 @@
 #include <KDebug>
 #include <KApplication>
 #include <kio/directorysizejob.h>
+#if KDE_IS_VERSION(4,7,0)
+#include <KMessageWidget>
+#endif
 
 #include <QTreeWidget>
 #include <QtConcurrentRun>
@@ -46,7 +49,8 @@ ArchiveWidget::ArchiveWidget(QString projectName, QDomDocument doc, QList <DocCl
         m_doc(doc),
         m_abortArchive(false),
         m_extractMode(false),
-        m_extractArchive(NULL)
+        m_extractArchive(NULL),
+        m_missingClips(0)
 {
     setAttribute(Qt::WA_DeleteOnClose);
     setupUi(this);
@@ -55,6 +59,7 @@ ArchiveWidget::ArchiveWidget(QString projectName, QDomDocument doc, QList <DocCl
     connect(archive_url, SIGNAL(textChanged (const QString &)), this, SLOT(slotCheckSpace()));
     connect(this, SIGNAL(archivingFinished(bool)), this, SLOT(slotArchivingFinished(bool)));
     connect(this, SIGNAL(archiveProgress(int)), this, SLOT(slotArchivingProgress(int)));
+    connect(proxy_only, SIGNAL(stateChanged(int)), this, SLOT(slotProxyOnly(int)));
 
     // Setup categories
     QTreeWidgetItem *videos = new QTreeWidgetItem(files_list, QStringList() << i18n("Video clips"));
@@ -77,6 +82,10 @@ ArchiveWidget::ArchiveWidget(QString projectName, QDomDocument doc, QList <DocCl
     texts->setIcon(0, KIcon("text-plain"));
     texts->setData(0, Qt::UserRole, "texts");
     texts->setExpanded(false);
+    QTreeWidgetItem *playlists = new QTreeWidgetItem(files_list, QStringList() << i18n("Playlist clips"));
+    playlists->setIcon(0, KIcon("video-mlt-playlist"));
+    playlists->setData(0, Qt::UserRole, "playlist");
+    playlists->setExpanded(false);
     QTreeWidgetItem *others = new QTreeWidgetItem(files_list, QStringList() << i18n("Other clips"));
     others->setIcon(0, KIcon("unknown"));
     others->setData(0, Qt::UserRole, "others");
@@ -95,53 +104,80 @@ ArchiveWidget::ArchiveWidget(QString projectName, QDomDocument doc, QList <DocCl
     QStringList allFonts;
     KUrl::List fileUrls;
     QStringList fileNames;
+    QStringList extraImageUrls;
+    QStringList otherUrls;
     generateItems(lumas, luma_list);
 
-    QStringList slideUrls;
-    QStringList audioUrls;
-    QStringList videoUrls;
-    QStringList imageUrls;
-    QStringList otherUrls;
-    QStringList proxyUrls;
+    QMap <QString, QString> slideUrls;
+    QMap <QString, QString> audioUrls;
+    QMap <QString, QString>videoUrls;
+    QMap <QString, QString>imageUrls;
+    QMap <QString, QString>playlistUrls;
+    QMap <QString, QString>proxyUrls;
 
     for (int i = 0; i < list.count(); i++) {
         DocClipBase *clip = list.at(i);
         CLIPTYPE t = clip->clipType();
+        QString id = clip->getId();
         if (t == SLIDESHOW) {
             KUrl slideUrl = clip->fileURL();
             //TODO: Slideshow files
-            slideUrls << slideUrl.path();
+            slideUrls.insert(id, slideUrl.path());
         }
-        else if (t == IMAGE) imageUrls << clip->fileURL().path();
+        else if (t == IMAGE) imageUrls.insert(id, clip->fileURL().path());
         else if (t == TEXT) {
             QStringList imagefiles = TitleWidget::extractImageList(clip->getProperty("xmldata"));
             QStringList fonts = TitleWidget::extractFontList(clip->getProperty("xmldata"));
-            imageUrls << imagefiles;
+            extraImageUrls << imagefiles;
             allFonts << fonts;
         } else if (t == PLAYLIST) {
+            playlistUrls.insert(id, clip->fileURL().path());
             QStringList files = ProjectSettings::extractPlaylistUrls(clip->fileURL().path());
             otherUrls << files;
         }
         else if (!clip->fileURL().isEmpty()) {
-            if (t == AUDIO) audioUrls << clip->fileURL().path();
+            if (t == AUDIO) audioUrls.insert(id, clip->fileURL().path());
             else {
-                videoUrls << clip->fileURL().path();
+                videoUrls.insert(id, clip->fileURL().path());
                 // Check if we have a proxy
                 QString proxy = clip->getProperty("proxy");
-                if (!proxy.isEmpty() && proxy != "-" && QFile::exists(proxy)) proxyUrls << proxy;
+                if (!proxy.isEmpty() && proxy != "-" && QFile::exists(proxy)) proxyUrls.insert(id, proxy);
             }
         }
     }
 
+    generateItems(images, extraImageUrls);
     generateItems(sounds, audioUrls);
     generateItems(videos, videoUrls);
     generateItems(images, imageUrls);
     generateItems(slideshows, slideUrls);
+    generateItems(playlists, playlistUrls);
     generateItems(others, otherUrls);
     generateItems(proxies, proxyUrls);
     
     allFonts.removeDuplicates();
 
+#if KDE_IS_VERSION(4,7,0)
+        m_infoMessage = new KMessageWidget(this);
+        QVBoxLayout *s =  static_cast <QVBoxLayout*> (layout());
+        s->insertWidget(5, m_infoMessage);
+        m_infoMessage->setCloseButtonVisible(false);
+        m_infoMessage->setWordWrap(true);
+        m_infoMessage->hide();
+#endif
+        
+        // missing clips, warn user
+    if (m_missingClips > 0) {
+        QString infoText = i18np("You have %1 missing clip in your project.", "You have %1 missing clips in your project.", m_missingClips);
+#if KDE_IS_VERSION(4,7,0)
+        m_infoMessage->setMessageType(KMessageWidget::Warning);
+        m_infoMessage->setText(infoText);
+        m_infoMessage->animatedShow();
+#else
+        KMessageBox::sorry(this, infoText);
+#endif
+    }
+
     //TODO: fonts
 
     // Hide unused categories, add item count
@@ -170,7 +206,7 @@ ArchiveWidget::ArchiveWidget(QString projectName, QDomDocument doc, QList <DocCl
     buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Archive"));
     connect(buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(slotStartArchiving()));
     buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
-    
+
     slotCheckSpace();
 }
 
@@ -187,6 +223,7 @@ ArchiveWidget::ArchiveWidget(const KUrl &url, QWidget * parent):
     connect(this, SIGNAL(showMessage(const QString &, const QString &)), this, SLOT(slotDisplayMessage(const QString &, const QString &)));
     
     compressed_archive->setHidden(true);
+    proxy_only->setHidden(true);
     project_files->setHidden(true);
     files_list->setHidden(true);
     label->setText(i18n("Extract to"));
@@ -194,7 +231,7 @@ ArchiveWidget::ArchiveWidget(const KUrl &url, QWidget * parent):
     archive_url->setUrl(KUrl(QDir::homePath()));
     buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Extract"));
     connect(buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(slotStartExtracting()));
-    buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
+    buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true);
     adjustSize();
     m_archiveThread = QtConcurrent::run(this, &ArchiveWidget::openArchiveForExtraction);
 }
@@ -206,11 +243,24 @@ ArchiveWidget::~ArchiveWidget()
 }
 
 void ArchiveWidget::slotDisplayMessage(const QString &icon, const QString &text)
-{
+{    
     icon_info->setPixmap(KIcon(icon).pixmap(16, 16));
     text_info->setText(text);
 }
 
+void ArchiveWidget::slotJobResult(bool success, const QString &text)
+{
+#if KDE_IS_VERSION(4,7,0)
+    m_infoMessage->setMessageType(success ? KMessageWidget::Positive : KMessageWidget::Warning);
+    m_infoMessage->setText(text);
+    m_infoMessage->animatedShow();
+#else
+    if (success) icon_info->setPixmap(KIcon("dialog-ok").pixmap(16, 16));
+    else icon_info->setPixmap(KIcon("dialog-close").pixmap(16, 16));
+    text_info->setText(text);
+#endif
+}
+
 void ArchiveWidget::openArchiveForExtraction()
 {
     emit showMessage("system-run", i18n("Opening archive..."));
@@ -291,11 +341,14 @@ void ArchiveWidget::generateItems(QTreeWidgetItem *parentItem, QStringList items
                     dir.setNameFilters(filters);
                     QFileInfoList resultList = dir.entryInfoList(QDir::Files);
                     QStringList slideImages;
+                    qint64 totalSize = 0;
                     for (int i = 0; i < resultList.count(); i++) {
-                        m_requestedSize += resultList.at(i).size();
+                        totalSize += resultList.at(i).size();
                         slideImages << resultList.at(i).absoluteFilePath();
                     }
                     item->setData(0, Qt::UserRole + 1, slideImages);
+                    item->setData(0, Qt::UserRole + 3, totalSize);
+                    m_requestedSize += totalSize;
             }
             else {
                 // pattern url (like clip%.3d.png)
@@ -308,13 +361,16 @@ void ArchiveWidget::generateItems(QTreeWidgetItem *parentItem, QStringList items
                 QStringList slideImages;
                 QString directory = dir.absolutePath();
                 if (!directory.endsWith('/')) directory.append('/');
+                qint64 totalSize = 0;
                 foreach(const QString & path, result) {
                     if (rx.exactMatch(path)) {
-                        m_requestedSize += QFileInfo(directory + path).size();
+                        totalSize += QFileInfo(directory + path).size();
                         slideImages <<  directory + path;
                     }
                 }
                 item->setData(0, Qt::UserRole + 1, slideImages);
+                item->setData(0, Qt::UserRole + 3, totalSize);
+                m_requestedSize += totalSize;
             }                    
         }
         else if (filesList.contains(fileName)) {
@@ -329,16 +385,111 @@ void ArchiveWidget::generateItems(QTreeWidgetItem *parentItem, QStringList items
             item->setData(0, Qt::UserRole, fileName);
         }
         if (!isSlideshow) {
-            m_requestedSize += QFileInfo(file).size();
+            qint64 fileSize = QFileInfo(file).size();
+            if (fileSize <= 0) {
+                item->setIcon(0, KIcon("edit-delete"));
+                m_missingClips++;
+            }
+            else {
+                m_requestedSize += fileSize;
+                item->setData(0, Qt::UserRole + 3, fileSize);
+            }
             filesList << fileName;
         }
     }
 }
 
+void ArchiveWidget::generateItems(QTreeWidgetItem *parentItem, QMap <QString, QString> items)
+{
+    QStringList filesList;
+    QString fileName;
+    int ix = 0;
+    bool isSlideshow = parentItem->data(0, Qt::UserRole).toString() == "slideshows";
+    QMap<QString, QString>::const_iterator it = items.constBegin();
+    while (it != items.constEnd()) {
+        QString file = it.value();
+        QTreeWidgetItem *item = new QTreeWidgetItem(parentItem, QStringList() << file);
+        // Store the clip's id
+        item->setData(0, Qt::UserRole + 2, it.key());
+        fileName = KUrl(file).fileName();
+        if (isSlideshow) {
+            // we store each slideshow in a separate subdirectory
+            item->setData(0, Qt::UserRole, ix);
+            ix++;
+            KUrl slideUrl(file);
+            QDir dir(slideUrl.directory(KUrl::AppendTrailingSlash));
+            if (slideUrl.fileName().startsWith(".all.")) {
+                // mimetype slideshow (for example *.png)
+                    QStringList filters;
+                    QString extension;
+                    // TODO: improve jpeg image detection with extension like jpeg, requires change in MLT image producers
+                    filters << "*." + slideUrl.fileName().section('.', -1);
+                    dir.setNameFilters(filters);
+                    QFileInfoList resultList = dir.entryInfoList(QDir::Files);
+                    QStringList slideImages;
+                    qint64 totalSize = 0;
+                    for (int i = 0; i < resultList.count(); i++) {
+                        totalSize += resultList.at(i).size();
+                        slideImages << resultList.at(i).absoluteFilePath();
+                    }
+                    item->setData(0, Qt::UserRole + 1, slideImages);
+                    item->setData(0, Qt::UserRole + 3, totalSize);
+                    m_requestedSize += totalSize;
+            }
+            else {
+                // pattern url (like clip%.3d.png)
+                QStringList result = dir.entryList(QDir::Files);
+                QString filter = slideUrl.fileName();
+                QString ext = filter.section('.', -1);
+                filter = filter.section('%', 0, -2);
+                QString regexp = "^" + filter + "\\d+\\." + ext + "$";
+                QRegExp rx(regexp);
+                QStringList slideImages;
+                qint64 totalSize = 0;
+                QString directory = dir.absolutePath();
+                if (!directory.endsWith('/')) directory.append('/');
+                foreach(const QString & path, result) {
+                    if (rx.exactMatch(path)) {
+                        totalSize += QFileInfo(directory + path).size();
+                        slideImages <<  directory + path;
+                    }
+                }
+                item->setData(0, Qt::UserRole + 1, slideImages);
+                item->setData(0, Qt::UserRole + 3, totalSize);
+                m_requestedSize += totalSize;
+            }                    
+        }
+        else if (filesList.contains(fileName)) {
+            // we have 2 files with same name
+            int ix = 0;
+            QString newFileName = fileName.section('.', 0, -2) + "_" + QString::number(ix) + "." + fileName.section('.', -1);
+            while (filesList.contains(newFileName)) {
+                ix ++;
+                newFileName = fileName.section('.', 0, -2) + "_" + QString::number(ix) + "." + fileName.section('.', -1);
+            }
+            fileName = newFileName;
+            item->setData(0, Qt::UserRole, fileName);
+        }
+        if (!isSlideshow) {
+            qint64 fileSize = QFileInfo(file).size();
+            if (fileSize <= 0) {
+                item->setIcon(0, KIcon("edit-delete"));
+                m_missingClips++;
+            }
+            else {
+                m_requestedSize += fileSize;
+                item->setData(0, Qt::UserRole + 3, fileSize);
+            }
+            filesList << fileName;
+        }
+        ++it;
+    }
+}
+
 void ArchiveWidget::slotCheckSpace()
 {
     KDiskFreeSpaceInfo inf = KDiskFreeSpaceInfo::freeSpaceInfo( archive_url->url().path());
-    KIO::filesize_t freeSize = inf.available();;
+    KIO::filesize_t freeSize = inf.available();
     if (freeSize > m_requestedSize) {
         // everything is ok
         buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true);
@@ -370,6 +521,7 @@ bool ArchiveWidget::slotStartArchiving(bool firstPass)
         slotDisplayMessage("system-run", i18n("Archiving..."));
         repaint();
         archive_url->setEnabled(false);
+        proxy_only->setEnabled(false);
         compressed_archive->setEnabled(false);
     }
     KUrl::List files;
@@ -377,28 +529,34 @@ bool ArchiveWidget::slotStartArchiving(bool firstPass)
     QString destPath;
     QTreeWidgetItem *parentItem;
     bool isSlideshow = false;
+    
+    // We parse all files going into one folder, then start the copy job
+    
     for (int i = 0; i < files_list->topLevelItemCount(); i++) {
         parentItem = files_list->topLevelItem(i);
-        if (parentItem->childCount() > 0 && !parentItem->isDisabled()) {
+        if (parentItem->isDisabled()) {
+            parentItem->setExpanded(false);
+            continue;
+        }
+        if (parentItem->childCount() > 0) {
             if (parentItem->data(0, Qt::UserRole).toString() == "slideshows") {
                 KUrl slideFolder(archive_url->url().path(KUrl::AddTrailingSlash) + "slideshows");
                 if (isArchive) m_foldersList.append("slideshows");
                 else KIO::NetAccess::mkdir(slideFolder, this);
                 isSlideshow = true;
             }
+            else isSlideshow = false;
             files_list->setCurrentItem(parentItem);
-            if (!isSlideshow) parentItem->setDisabled(true);
+            parentItem->setExpanded(true);
             destPath = parentItem->data(0, Qt::UserRole).toString() + "/";
             destUrl = KUrl(archive_url->url().path(KUrl::AddTrailingSlash) + destPath);
             QTreeWidgetItem *item;
             for (int j = 0; j < parentItem->childCount(); j++) {
                 item = parentItem->child(j);
+                if (item->isDisabled()) continue;
                 // Special case: slideshows
                 if (isSlideshow) {
-                    if (item->isDisabled()) {
-                        continue;
-                    }
-                    destPath.append(item->data(0, Qt::UserRole).toString() + "/");
+                    destPath += item->data(0, Qt::UserRole).toString() + "/";
                     destUrl = KUrl(archive_url->url().path(KUrl::AddTrailingSlash) + destPath);
                     QStringList srcFiles = item->data(0, Qt::UserRole + 1).toStringList();
                     for (int k = 0; k < srcFiles.count(); k++) {
@@ -423,6 +581,7 @@ bool ArchiveWidget::slotStartArchiving(bool firstPass)
                     else m_duplicateFiles.insert(KUrl(item->text(0)), KUrl(destUrl.path(KUrl::AddTrailingSlash) + item->data(0, Qt::UserRole).toString()));
                 }
             }
+            if (!isSlideshow) parentItem->setDisabled(true);
             break;
         }
     }
@@ -476,20 +635,21 @@ void ArchiveWidget::slotArchivingFinished(KJob *job)
             // Archiving finished
             progressBar->setValue(100);
             if (processProjectFile()) {
-                slotDisplayMessage("dialog-ok", i18n("Project was successfully archived."));
+                slotJobResult(true, i18n("Project was successfully archived."));
             }
             else {
-                slotDisplayMessage("dialog-close", i18n("There was an error processing project file"));
+                slotJobResult(false, i18n("There was an error processing project file"));
             }
         } else processProjectFile();
     }
     else {
         m_copyJob = NULL;
-        slotDisplayMessage("dialog-close", i18n("There was an error while copying the files: %1", job->errorString()));
+        slotJobResult(false, i18n("There was an error while copying the files: %1", job->errorString()));
     }
     if (!compressed_archive->isChecked()) {
         buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Archive"));
         archive_url->setEnabled(true);
+        proxy_only->setEnabled(true);
         compressed_archive->setEnabled(true);
         for (int i = 0; i < files_list->topLevelItemCount(); i++) {
             files_list->topLevelItem(i)->setDisabled(false);
@@ -666,14 +826,16 @@ void ArchiveWidget::createArchive()
 void ArchiveWidget::slotArchivingFinished(bool result)
 {
     if (result) {
-        slotDisplayMessage("dialog-ok", i18n("Project was successfully archived."));
+        slotJobResult(true, i18n("Project was successfully archived."));
+        buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
     }
     else {
-        slotDisplayMessage("dialog-close", i18n("There was an error processing project file"));
+        slotJobResult(false, i18n("There was an error processing project file"));
     }
     progressBar->setValue(100);
     buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Archive"));
     archive_url->setEnabled(true);
+    proxy_only->setEnabled(true);
     compressed_archive->setEnabled(true);
     for (int i = 0; i < files_list->topLevelItemCount(); i++) {
         files_list->topLevelItem(i)->setDisabled(false);
@@ -770,3 +932,74 @@ void ArchiveWidget::slotExtractingFinished()
     }
     else accept();
 }
+
+void ArchiveWidget::slotProxyOnly(int onlyProxy)
+{
+    m_requestedSize = 0;
+    if (onlyProxy == Qt::Checked) {
+        // Archive proxy clips
+        QStringList proxyIdList;
+        QTreeWidgetItem *parentItem = NULL;
+
+        // Build list of existing proxy ids
+        for (int i = 0; i < files_list->topLevelItemCount(); i++) {
+            parentItem = files_list->topLevelItem(i);
+            if (parentItem->data(0, Qt::UserRole).toString() == "proxy") break;
+        }
+        if (!parentItem) return;
+        int items = parentItem->childCount();
+        for (int j = 0; j < items; j++) {
+            proxyIdList << parentItem->child(j)->data(0, Qt::UserRole + 2).toString();
+        }
+        
+        // Parse all items to disable original clips for existing proxies
+        for (int i = 0; i < proxyIdList.count(); i++) {
+            QString id = proxyIdList.at(i);
+            if (id.isEmpty()) continue;
+            for (int j = 0; j < files_list->topLevelItemCount(); j++) {
+                parentItem = files_list->topLevelItem(j);
+                if (parentItem->data(0, Qt::UserRole).toString() == "proxy") continue;
+                items = parentItem->childCount();
+                for (int k = 0; k < items; k++) {
+                    if (parentItem->child(k)->data(0, Qt::UserRole + 2).toString() == id) {
+                        // This item has a proxy, do not archive it
+                        parentItem->child(k)->setFlags(Qt::ItemIsSelectable);
+                        break;
+                    }
+                }
+            }
+        }
+    }
+    else {
+        // Archive all clips
+        for (int i = 0; i < files_list->topLevelItemCount(); i++) {
+            QTreeWidgetItem *parentItem = files_list->topLevelItem(i);
+            int items = parentItem->childCount();
+            for (int j = 0; j < items; j++) {
+                parentItem->child(j)->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
+            }
+        }
+    }
+    
+    // Calculate requested size
+    int total = 0;
+    for (int i = 0; i < files_list->topLevelItemCount(); i++) {
+        QTreeWidgetItem *parentItem = files_list->topLevelItem(i);
+        int items = parentItem->childCount();
+        int itemsCount = 0;
+        bool isSlideshow = parentItem->data(0, Qt::UserRole).toString() == "slideshows";
+        
+        for (int j = 0; j < items; j++) {
+            if (!parentItem->child(j)->isDisabled()) {
+                m_requestedSize += parentItem->child(j)->data(0, Qt::UserRole + 3).toInt();
+                if (isSlideshow) total += parentItem->child(j)->data(0, Qt::UserRole + 1).toStringList().count();
+                else total ++;
+                itemsCount ++;
+            }
+        }
+        parentItem->setText(0, parentItem->text(0).section("(", 0, 0) + i18np("(%1 item)", "(%1 items)", itemsCount));
+    }
+    project_files->setText(i18np("%1 file to archive, requires %2", "%1 files to archive, requires %2", total, KIO::convertSize(m_requestedSize)));
+    slotCheckSpace();
+}
+
index e76aa669255c604749797f57666629cb32a62695..ace36c6ff27bbef65a1af7f69dc7780efa7f2bb7 100644 (file)
 #include "docclipbase.h"
 
 #include <kio/global.h>
+#include <KIO/CopyJob>
+#include <KTemporaryFile>
+#include <kdeversion.h>
+
 #include <QLabel>
 #include <QDialog>
 #include <QList>
-#include <KIO/CopyJob>
-#include <KTemporaryFile>
+
 
 class KJob;
 class KArchive;
@@ -41,6 +44,10 @@ class KArchive;
  * @author Jean-Baptiste Mardelle
  */
 
+#if KDE_IS_VERSION(4,7,0)
+    class KMessageWidget;
+#endif
+
 class ArchiveWidget : public QDialog, public Ui::ArchiveWidget_UI
 {
     Q_OBJECT
@@ -70,6 +77,8 @@ private slots:
     void slotGotProgress(KJob*);
     void openArchiveForExtraction();
     void slotDisplayMessage(const QString &icon, const QString &text);
+    void slotJobResult(bool success, const QString &text);
+    void slotProxyOnly(int onlyProxy);
 
 protected:
     virtual void closeEvent ( QCloseEvent * e );
@@ -91,9 +100,16 @@ private:
     QString m_projectName;
     QTimer *m_progressTimer;
     KArchive *m_extractArchive;
+    int m_missingClips;
+    
+#if KDE_IS_VERSION(4,7,0)
+    KMessageWidget *m_infoMessage;
+#endif
 
     /** @brief Generate tree widget subitems from a string list of urls. */
     void generateItems(QTreeWidgetItem *parentItem, QStringList items);
+    /** @brief Generate tree widget subitems from a map of clip ids / urls. */
+    void generateItems(QTreeWidgetItem *parentItem, QMap <QString, QString> items);
     /** @brief Replace urls in project file. */
     bool processProjectFile();
 
diff --git a/src/audioscopes/CMakeLists.txt b/src/audioscopes/CMakeLists.txt
deleted file mode 100644 (file)
index 7b8ef2b..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-set(kdenlive_SRCS
-  ${kdenlive_SRCS}
-  audioscopes/abstractaudioscopewidget.cpp
-  audioscopes/audiospectrum.cpp
-  audioscopes/ffttools.cpp
-  audioscopes/spectrogram.cpp
-  PARENT_SCOPE
-)
index de9b497a2059872d28f7db80e75c7e9b318749e8..2681ed0a0aa1bc926d72c46653a03ad0a7e42840 100644 (file)
@@ -30,8 +30,8 @@
 #ifndef __DeckLink_API_Verison_h__
 #define __DeckLink_API_Version_h__
 
-#define BLACKMAGIC_DECKLINK_API_VERSION                                        0x08060100
-#define BLACKMAGIC_DECKLINK_API_VERSION_STRING                 "8.6.1"
+#define BLACKMAGIC_DECKLINK_API_VERSION                                        0x09000000
+#define BLACKMAGIC_DECKLINK_API_VERSION_STRING                 "9.0"
 
 #endif // __DeckLink_API_Version_h__
 
index 1b81ca3123536d11f667a43adeaa75d088df1299..86138195450f47ea95432f8e63519780e71dd82e 100644 (file)
 
 #include <KColorButton>
 #include <KLocalizedString>
+#include <kdeversion.h>
 
+static QColor stringToColor(QString strColor)
+{
+    bool ok = false;
+    QColor color("black");
+    int intval = 0;
+
+    if (strColor.startsWith("0x")) {
+        if (strColor.length() == 10) {
+            // 0xRRGGBBAA
+            intval = strColor.toUInt(&ok, 16);
+            color.setRgb( ( intval >> 24 ) & 0xff,   // r
+                          ( intval >> 16 ) & 0xff,   // g
+                          ( intval >>  8 ) & 0xff,   // b
+                          ( intval       ) & 0xff ); // a
+        } else {
+            // 0xRRGGBB, 0xRGB
+            color.setNamedColor(strColor.replace(0, 2, "#"));
+        }
+    } else {
+        if (strColor.length() == 9) {
+            // #AARRGGBB
+            strColor = strColor.replace('#', "0x");
+            intval = strColor.toUInt(&ok, 16);
+            color.setRgb( ( intval >> 16 ) & 0xff,   // r
+                          ( intval >>  8 ) & 0xff,   // g
+                          ( intval       ) & 0xff,   // b
+                          ( intval >> 24 ) & 0xff ); // a
+        } else {
+            // #RRGGBB, #RGB
+            color.setNamedColor(strColor);
+        }
+    }
+
+    return color;
+}
 
-ChooseColorWidget::ChooseColorWidget(QString text, QColor color, QWidget *parent) :
+static QString colorToString(QColor color, bool alpha)
+{
+    QString colorStr;
+    QTextStream stream(&colorStr);
+    stream << "#";
+    stream.setIntegerBase(16);
+    stream.setFieldWidth(2);
+    stream.setFieldAlignment(QTextStream::AlignRight);
+    stream.setPadChar('0');
+    if(alpha)
+    {
+        stream << color.alpha();
+    }
+    stream <<  color.red() << color.green() << color.blue();
+
+    return colorStr;
+}
+
+ChooseColorWidget::ChooseColorWidget(QString text, QString color, QWidget *parent) :
         QWidget(parent)
 {
     QHBoxLayout *layout = new QHBoxLayout(this);
@@ -36,22 +90,40 @@ ChooseColorWidget::ChooseColorWidget(QString text, QColor color, QWidget *parent
     layout->setSpacing(0);
 
     QLabel *label = new QLabel(text, this);
-    m_button = new KColorButton(color, this);
-    m_button->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
-    ColorPickerWidget *picker = new ColorPickerWidget(this);
+
+    QWidget *rightSide = new QWidget(this);
+    QHBoxLayout *rightSideLayout = new QHBoxLayout(rightSide);
+    rightSideLayout->setContentsMargins(0, 0, 0, 0);
+    rightSideLayout->setSpacing(0);
+
+    m_button = new KColorButton(stringToColor(color), rightSide);
+//     m_button->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
+    ColorPickerWidget *picker = new ColorPickerWidget(rightSide);
 
     layout->addWidget(label);
-    layout->addWidget(m_button);
-    layout->addWidget(picker, 0, Qt::AlignRight);
+    layout->addWidget(rightSide);
+    rightSideLayout->addWidget(m_button);
+    rightSideLayout->addWidget(picker, 0, Qt::AlignRight);
 
     connect(picker, SIGNAL(colorPicked(QColor)), this, SLOT(setColor(QColor)));
     connect(picker, SIGNAL(displayMessage(const QString&, int)), this, SIGNAL(displayMessage(const QString&, int)));
     connect(m_button, SIGNAL(changed(QColor)), this, SIGNAL(modified()));
 }
 
-QColor ChooseColorWidget::getColor()
+QString ChooseColorWidget::getColor()
+{
+    bool alphaChannel = false;
+#if KDE_IS_VERSION(4,5,0)
+    alphaChannel = m_button->isAlphaChannelEnabled();
+#endif
+    return colorToString(m_button->color(), alphaChannel);
+}
+
+void ChooseColorWidget::setAlphaChannelEnabled(bool enabled)
 {
-    return m_button->color();
+#if KDE_IS_VERSION(4,5,0)
+    m_button->setAlphaChannelEnabled(enabled);
+#endif
 }
 
 void ChooseColorWidget::setColor(QColor color)
index deac2b818b9039c06195d1c87517e6694c3e0bc8..4c2c2ff2bb46246043e7b3e57457d0b4c8438687 100644 (file)
@@ -39,10 +39,13 @@ public:
     /** @brief Sets up the widget.
     * @param text (optional) What the color will be used for
     * @param color (optional) initial color */
-    ChooseColorWidget(QString text = QString(), QColor color = QColor(), QWidget* parent = 0);
+    ChooseColorWidget(QString text = QString(), QString color = "0xffffffff", QWidget* parent = 0);
 
     /** @brief Gets the choosen color. */
-    QColor getColor();
+    QString getColor();
+    /** @brief Enable the use of alpha channel.
+    * @param enabled (required) whether alpha is enabled or disabled */
+    void setAlphaChannelEnabled(bool enabled);
 
 private:
     KColorButton *m_button;
index cac5eda2b4690f0c6f683d3588161c1a903ece7a..2c5fd7b9ab97087182d57b38f07efa3590e63a3b 100644 (file)
@@ -124,6 +124,8 @@ ClipItem::ClipItem(DocClipBase *clip, ItemInfo info, double fps, double speed, i
 ClipItem::~ClipItem()
 {
     blockSignals(true);
+    m_endThumbTimer.stop();
+    m_startThumbTimer.stop();
     if (scene()) scene()->removeItem(this);
     if (m_clipType == VIDEO || m_clipType == AV || m_clipType == SLIDESHOW || m_clipType == PLAYLIST) {
         //disconnect(m_clip->thumbProducer(), SIGNAL(thumbReady(int, QImage)), this, SLOT(slotThumbReady(int, QImage)));
@@ -573,7 +575,14 @@ void ClipItem::slotFetchThumbs()
         frames.append((int)(m_speedIndependantInfo.cropStart + m_speedIndependantInfo.cropDuration).frames(m_fps) - 1);
     }
 
-    m_clip->slotExtractImage(frames);
+    if (!frames.isEmpty()) m_clip->slotExtractImage(frames);
+}
+
+void ClipItem::stopThumbs()
+{
+    // Clip is about to be deleted, make sure we don't request thumbnails
+    disconnect(&m_startThumbTimer, SIGNAL(timeout()), this, SLOT(slotGetStartThumb()));
+    disconnect(&m_endThumbTimer, SIGNAL(timeout()), this, SLOT(slotGetEndThumb()));
 }
 
 void ClipItem::slotGetStartThumb()
index c5323905b182dc98a4dcaa76506a1c5de938f7a9..5629743fee8b328384b946f714a5a8d157c63a15 100644 (file)
@@ -173,6 +173,8 @@ public:
      * Which producer is returned depends on the type of this clip (audioonly, videoonly, normal) */
     Mlt::Producer *getProducer(int track, bool trackSpecific = true);
     void resetFrameWidth(int width);
+    /** @brief Clip is about to be deleted, block thumbs. */
+    void stopThumbs();
 
 protected:
     //virtual void mouseMoveEvent(QGraphicsSceneMouseEvent * event);
index a06874543bb3d5dbded0a5ea7c970fd28497b7b6..af4522a6cdeb76c9dfc48d460195e920ee85a7ea 100644 (file)
@@ -45,9 +45,9 @@ ClipManager::ClipManager(KdenliveDoc *doc) :
     QObject(),
     m_audioThumbsQueue(),
     m_doc(doc),
-    m_generatingAudioId(),
     m_abortThumb(false),
-    m_closing(false)
+    m_closing(false),
+    m_abortAudioThumb(false)
 {
     m_clipIdCounter = 1;
     m_folderIdCounter = 1;
@@ -68,15 +68,14 @@ ClipManager::~ClipManager()
 {
     m_closing = true;
     m_abortThumb = true;
+    m_abortAudioThumb = true;
     m_thumbsThread.waitForFinished();
+    m_audioThumbsThread.waitForFinished();
     m_thumbsMutex.lock();
     m_requestedThumbs.clear();
-    m_thumbsMutex.unlock();
     m_audioThumbsQueue.clear();
-    m_generatingAudioId.clear();
-    m_thumbsMutex.lock();
-    m_requestedThumbs.clear();
     m_thumbsMutex.unlock();
+
     qDeleteAll(m_clipList);
     m_clipList.clear();
 #if KDE_IS_VERSION(4,5,0)
@@ -87,13 +86,16 @@ ClipManager::~ClipManager()
 void ClipManager::clear()
 {
     m_abortThumb = true;
+    m_abortAudioThumb = true;
     m_thumbsThread.waitForFinished();
+    m_audioThumbsThread.waitForFinished();
     m_thumbsMutex.lock();
     m_requestedThumbs.clear();
+    m_audioThumbsQueue.clear();
     m_thumbsMutex.unlock();
     m_abortThumb = false;
+    m_abortAudioThumb = false;
     m_folderList.clear();
-    m_audioThumbsQueue.clear();
     m_modifiedClips.clear();
     qDeleteAll(m_clipList);
     m_clipList.clear();
@@ -125,94 +127,209 @@ void ClipManager::requestThumbs(const QString id, QList <int> frames)
 
 void ClipManager::stopThumbs(const QString &id)
 {
-    if (m_requestedThumbs.isEmpty() || m_closing) return;
+    if (m_closing || (m_requestedThumbs.isEmpty() && m_processingThumbId != id && m_audioThumbsQueue.isEmpty() && m_processingAudioThumbId != id)) return;
+    // Abort video thumbs for this clip
     m_abortThumb = true;
     m_thumbsThread.waitForFinished();
     m_thumbsMutex.lock();
     m_requestedThumbs.remove(id);
+    m_audioThumbsQueue.removeAll(id);
     m_thumbsMutex.unlock();
     m_abortThumb = false;
-    if (!m_thumbsThread.isRunning()) {
+
+    // Abort audio thumbs for this clip
+    if (m_processingAudioThumbId == id) {
+        m_abortAudioThumb = true;
+        m_audioThumbsThread.waitForFinished();
+        m_abortAudioThumb = false;
+    }
+    
+    if (!m_thumbsThread.isRunning() && !m_requestedThumbs.isEmpty()) {
         m_thumbsThread = QtConcurrent::run(this, &ClipManager::slotGetThumbs);
     }
+    
+    if (!m_audioThumbsThread.isRunning() && !m_audioThumbsQueue.isEmpty()) {
+        m_audioThumbsThread = QtConcurrent::run(this, &ClipManager::slotGetAudioThumbs);
+    }
 }
 
 void ClipManager::slotGetThumbs()
 {
-    QMap<QString, int>::iterator i = m_requestedThumbs.begin();
-    while (i != m_requestedThumbs.end() && !m_abortThumb) {
-        QString producerId = i.key();
+    QMap<QString, int>::const_iterator i;
+    int max;
+    int done = 0;
+    while (!m_requestedThumbs.isEmpty() && !m_abortThumb) {
         m_thumbsMutex.lock();
-        QList<int> values = m_requestedThumbs.values(producerId);
-        i = m_requestedThumbs.erase(i);
+        i = m_requestedThumbs.constBegin();
+        m_processingThumbId = i.key();
+        QList<int> values = m_requestedThumbs.values(m_processingThumbId);
+        m_requestedThumbs.remove(m_processingThumbId);
         m_thumbsMutex.unlock();
         qSort(values);
-        DocClipBase *clip = getClipById(producerId);
+        DocClipBase *clip = getClipById(m_processingThumbId);
         if (!clip) continue;
+        max = m_requestedThumbs.size() + values.count();
         while (!values.isEmpty() && clip->thumbProducer() && !m_abortThumb) {
             clip->thumbProducer()->getThumb(values.takeFirst());
+            done++;
+            if (max > 3) emit displayMessage(i18n("Loading thumbnails"), 100 * done / max);
         }
     }
+    m_processingThumbId.clear();
+    emit displayMessage(QString(), -1);
 }
 
 void ClipManager::checkAudioThumbs()
 {
     if (!KdenliveSettings::audiothumbnails()) {
-        if (!m_generatingAudioId.isEmpty()) {
-            DocClipBase *clip = getClipById(m_generatingAudioId);
-            if (clip) clip->slotClearAudioCache();
+        if (m_audioThumbsThread.isRunning()) {
+            m_abortAudioThumb = true;
+            m_thumbsMutex.lock();
+            m_audioThumbsQueue.clear();
+            m_thumbsMutex.unlock();
+            m_audioThumbsThread.waitForFinished();
+            m_abortAudioThumb = false;
         }
-        m_audioThumbsQueue.clear();
-        m_generatingAudioId.clear();
         return;
     }
 
+    m_thumbsMutex.lock();
     for (int i = 0; i < m_clipList.count(); i++) {
-        m_audioThumbsQueue.append(m_clipList.at(i)->getId());
+        DocClipBase *clip = m_clipList.at(i);
+        if (clip->hasAudioThumb() && !clip->audioThumbCreated())
+            m_audioThumbsQueue.append(m_clipList.at(i)->getId());
+    }
+    m_thumbsMutex.unlock();
+    if (!m_audioThumbsThread.isRunning() && !m_audioThumbsQueue.isEmpty()) {
+        m_audioThumbsThread = QtConcurrent::run(this, &ClipManager::slotGetAudioThumbs);
     }
-    if (m_generatingAudioId.isEmpty()) startAudioThumbsGeneration();
 }
 
 void ClipManager::askForAudioThumb(const QString &id)
 {
     DocClipBase *clip = getClipById(id);
-    if (clip && KdenliveSettings::audiothumbnails()) {
-        m_audioThumbsQueue.append(id);
-        if (m_generatingAudioId.isEmpty()) startAudioThumbsGeneration();
+    if (clip && KdenliveSettings::audiothumbnails() && (clip->hasAudioThumb())) {
+        m_thumbsMutex.lock();
+        if (!m_audioThumbsQueue.contains(id)) m_audioThumbsQueue.append(id);
+        m_thumbsMutex.unlock();
+        if (!m_audioThumbsThread.isRunning()) m_audioThumbsThread = QtConcurrent::run(this, &ClipManager::slotGetAudioThumbs);
     }
 }
 
-void ClipManager::startAudioThumbsGeneration()
+void ClipManager::slotGetAudioThumbs()
 {
-    if (!KdenliveSettings::audiothumbnails()) {
-        m_audioThumbsQueue.clear();
-        m_generatingAudioId.clear();
-        return;
-    }
-    if (!m_audioThumbsQueue.isEmpty()) {
-        m_generatingAudioId = m_audioThumbsQueue.takeFirst();
-        DocClipBase *clip = getClipById(m_generatingAudioId);
-        if (!clip || !clip->slotGetAudioThumbs())
-            endAudioThumbsGeneration(m_generatingAudioId);
-    } else {
-        m_generatingAudioId.clear();
-    }
-}
+    Mlt::Profile prof((char*) KdenliveSettings::current_profile().toUtf8().constData());
+    mlt_audio_format audioFormat = mlt_audio_pcm;
+    while (!m_abortAudioThumb && !m_audioThumbsQueue.isEmpty()) {
+        m_thumbsMutex.lock();
+        m_processingAudioThumbId = m_audioThumbsQueue.takeFirst();
+        m_thumbsMutex.unlock();
+        DocClipBase *clip = getClipById(m_processingAudioThumbId);
+        if (!clip || clip->audioThumbCreated()) continue;
+        KUrl url = clip->fileURL();
+        QString hash = clip->getClipHash();
+        if (hash.isEmpty()) continue;
+        QString audioPath = projectFolder() + "/thumbs/" + hash + ".thumb";
+        double lengthInFrames = clip->duration().frames(m_doc->fps());
+        //FIXME: should this be hardcoded??
+        int channels = 2;
+        int frequency = 48000;
+        int arrayWidth = 20;
+        double frame = 0.0;
+        audioByteArray storeIn;
+        QFile f(audioPath);
+        if (QFileInfo(audioPath).size() > 0 && f.open(QIODevice::ReadOnly)) {
+            const QByteArray channelarray = f.readAll();
+            f.close();
+            if (channelarray.size() != arrayWidth*(frame + lengthInFrames) * channels) {
+                kDebug() << "--- BROKEN THUMB FOR: " << url.fileName() << " ---------------------- ";
+                f.remove();
+                continue;
+            }
+            kDebug() << "reading audio thumbs from file";
+
+            int h1 = arrayWidth * channels;
+            int h2 = (int) frame * h1;
+            int h3;
+            for (int z = (int) frame; z < (int)(frame + lengthInFrames) && !m_abortAudioThumb; z++) {
+                h3 = 0;
+                for (int c = 0; c < channels; c++) {
+                    QByteArray audioArray(arrayWidth, '\x00');
+                    for (int i = 0; i < arrayWidth; i++) {
+                        audioArray[i] = channelarray.at(h2 + h3 + i);
+                    }
+                    h3 += arrayWidth;
+                    storeIn[z][c] = audioArray;
+                }
+                h2 += h1;
+            }
+            if (!m_abortAudioThumb) clip->updateAudioThumbnail(storeIn);
+            continue;
+        } 
+        
+        if (!f.open(QIODevice::WriteOnly)) {
+            kDebug() << "++++++++  ERROR WRITING TO FILE: " << audioPath;
+            kDebug() << "++++++++  DISABLING AUDIO THUMBS";
+            m_thumbsMutex.lock();
+            m_audioThumbsQueue.clear();
+            m_thumbsMutex.unlock();
+            KdenliveSettings::setAudiothumbnails(false);
+            break;
+        }
 
-void ClipManager::endAudioThumbsGeneration(const QString &requestedId)
-{
-    if (!KdenliveSettings::audiothumbnails()) {
-        m_audioThumbsQueue.clear();
-        m_generatingAudioId.clear();
-        return;
-    }
-    if (!m_audioThumbsQueue.isEmpty()) {
-        if (m_generatingAudioId == requestedId) {
-            startAudioThumbsGeneration();
+        Mlt::Producer producer(prof, url.path().toUtf8().constData());
+        if (!producer.is_valid()) {
+            kDebug() << "++++++++  INVALID CLIP: " << url.path();
+            continue;
+        }
+        
+        producer.set("video_index", "-1");
+
+        if (KdenliveSettings::normaliseaudiothumbs()) {
+            Mlt::Filter m_convert(prof, "volume");
+            m_convert.set("gain", "normalise");
+            producer.attach(m_convert);
+        }
+
+        int last_val = 0;
+        int val = 0;
+        double framesPerSecond = mlt_producer_get_fps(producer.get_producer());
+        Mlt::Frame *mlt_frame;
+
+        for (int z = (int) frame; z < (int)(frame + lengthInFrames) && producer.is_valid() &&  !m_abortAudioThumb; z++) {
+            val = (int)((z - frame) / (frame + lengthInFrames) * 100.0);
+            if (last_val != val && val > 1) {
+                setThumbsProgress(i18n("Creating audio thumbnail for %1", url.fileName()), val);
+                last_val = val;
+            }
+            producer.seek(z);
+            mlt_frame = producer.get_frame();
+            if (mlt_frame && mlt_frame->is_valid()) {
+                int samples = mlt_sample_calculator(framesPerSecond, frequency, mlt_frame_get_position(mlt_frame->get_frame()));
+                qint16* pcm = static_cast<qint16*>(mlt_frame->get_audio(audioFormat, frequency, channels, samples));
+                for (int c = 0; c < channels; c++) {
+                    QByteArray audioArray;
+                    audioArray.resize(arrayWidth);
+                    for (int i = 0; i < audioArray.size(); i++) {
+                        audioArray[i] = ((*(pcm + c + i * samples / audioArray.size())) >> 9) + 127 / 2 ;
+                    }
+                    f.write(audioArray);
+                    storeIn[z][c] = audioArray;
+                }
+            } else {
+                f.write(QByteArray(arrayWidth, '\x00'));
+            }
+            delete mlt_frame;
+        }
+        f.close();
+        setThumbsProgress(i18n("Creating audio thumbnail for %1", url.fileName()), -1);
+        if (m_abortAudioThumb) {
+            f.remove();
+        } else {
+            clip->updateAudioThumbnail(storeIn);
         }
-    } else {
-        m_generatingAudioId.clear();
     }
+    m_processingAudioThumbId.clear();
 }
 
 void ClipManager::setThumbsProgress(const QString &message, int progress)
@@ -345,12 +462,11 @@ void ClipManager::resetProducersList(const QList <Mlt::Producer *> prods, bool d
     emit checkAllClips(displayRatioChanged, fpsChanged, brokenClips);
 }
 
-void ClipManager::slotAddClipList(const KUrl::List urls, const QString &group, const QString &groupId)
+void ClipManager::slotAddClipList(const KUrl::List urls, const QString &group, const QString &groupId, const QString &comment)
 {
     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;
@@ -362,6 +478,7 @@ void ClipManager::slotAddClipList(const KUrl::List urls, const QString &group, c
             prod.setAttribute("resource", file.path());
             uint id = m_clipIdCounter++;
             prod.setAttribute("id", QString::number(id));
+            if (!comment.isEmpty()) prod.setAttribute("description", comment);
             if (!group.isEmpty()) {
                 prod.setAttribute("groupname", group);
                 prod.setAttribute("groupid", groupId);
@@ -414,6 +531,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()));
@@ -421,9 +539,9 @@ void ClipManager::slotAddClipList(const KUrl::List urls, const QString &group, c
     }
 }
 
-void ClipManager::slotAddClipFile(const KUrl &url, const QString &group, const QString &groupId)
+void ClipManager::slotAddClipFile(const KUrl &url, const QString &group, const QString &groupId, const QString &comment)
 {
-    slotAddClipList(KUrl::List(url), group, groupId);
+    slotAddClipList(KUrl::List(url), group, groupId, comment);
 }
 
 void ClipManager::slotAddXmlClipFile(const QString &name, const QDomElement &xml, const QString &group, const QString &groupId)
@@ -464,29 +582,18 @@ void ClipManager::slotAddColorClipFile(const QString &name, const QString &color
     m_doc->commandStack()->push(command);
 }
 
-void ClipManager::slotAddSlideshowClipFile(const QString &name, const QString &path, int count, const QString &duration,
-        const bool loop, const bool crop, const bool fade,
-        const QString &luma_duration, const QString &luma_file, const int softness,
-        const QString &animation, const QString &group, const QString &groupId)
+void ClipManager::slotAddSlideshowClipFile(QMap <QString, QString> properties, const QString &group, const QString &groupId)
 {
     QDomDocument doc;
     QDomElement prod = doc.createElement("producer");
     doc.appendChild(prod);
-    prod.setAttribute("resource", path);
+    QMap<QString, QString>::const_iterator i = properties.constBegin();
+    while (i != properties.constEnd()) {
+        prod.setAttribute(i.key(), i.value());
+        ++i;
+    }
     prod.setAttribute("type", (int) SLIDESHOW);
     uint id = m_clipIdCounter++;
-    prod.setAttribute("id", QString::number(id));
-    prod.setAttribute("in", "0");
-    prod.setAttribute("out", m_doc->getFramePos(duration) * count);
-    prod.setAttribute("ttl", m_doc->getFramePos(duration));
-    prod.setAttribute("luma_duration", m_doc->getFramePos(luma_duration));
-    prod.setAttribute("name", name);
-    prod.setAttribute("loop", loop);
-    prod.setAttribute("crop", crop);
-    prod.setAttribute("fade", fade);
-    prod.setAttribute("softness", QString::number(softness));
-    prod.setAttribute("luma_file", luma_file);
-    prod.setAttribute("animation", animation);
     if (!group.isEmpty()) {
         prod.setAttribute("groupname", group);
         prod.setAttribute("groupid", groupId);
index 9ac2cfd2dbcc1bf9e25d8bea670b5df2b7f48a83..ce5089278a6a8f91e2d39be969988c137ca945aa 100644 (file)
@@ -72,22 +72,19 @@ Q_OBJECT public:
      * @param url file to add
      * @param group name of the group to insert the file in (can be empty)
      * @param groupId id of the group (if any) */
-    void slotAddClipFile(const KUrl &url, const QString &group, const QString &groupId);
+    void slotAddClipFile(const KUrl &url, const QString &group, const QString &groupId, const QString &comment = QString());
 
     /** @brief Adds a list of files to the project.
      * @param urls files to add
      * @param group name of the group to insert the files in (can be empty)
      * @param groupId id of the group (if any)
      * It checks for duplicated items and asks to the user for instructions. */
-    void slotAddClipList(const KUrl::List urls, const QString &group, const QString &groupId);
+    void slotAddClipList(const KUrl::List urls, const QString &group, const QString &groupId, const QString &comment = QString());
     void slotAddTextClipFile(const QString &titleName, int out, const QString &xml, const QString &group, const QString &groupId);
     void slotAddTextTemplateClip(QString titleName, const KUrl &path, const QString &group, const QString &groupId);
     void slotAddXmlClipFile(const QString &name, const QDomElement &xml, const QString &group, const QString &groupId);
     void slotAddColorClipFile(const QString &name, const QString &color, QString duration, const QString &group, const QString &groupId);
-    void slotAddSlideshowClipFile(const QString &name, const QString &path, int count, const QString &duration,
-                                  const bool loop, const bool crop,const bool fade,
-                                  const QString &luma_duration, const QString &luma_file, const int softness,
-                                  const QString &animation, const QString &group, const QString &groupId);
+    void slotAddSlideshowClipFile(QMap <QString, QString> properties, const QString &group, const QString &groupId);
     DocClipBase *getClipById(QString clipId);
     const QList <DocClipBase *> getClipByResource(QString resource);
     void slotDeleteClips(QStringList ids);
@@ -98,8 +95,6 @@ Q_OBJECT public:
     int getFreeClipId();
     int getFreeFolderId();
     int lastClipId() const;
-    void startAudioThumbsGeneration();
-    void endAudioThumbsGeneration(const QString &requestedId);
     void askForAudioThumb(const QString &id);
     QString projectFolder() const;
     void clearUnusedProducers();
@@ -129,6 +124,7 @@ private slots:
     /** Check the list of externally modified clips, and process them if they were not modified in the last 1500 milliseconds */
     void slotProcessModifiedClips();
     void slotGetThumbs();
+    void slotGetAudioThumbs();
 
 private:   // Private attributes
     /** the list of clips in the document */
@@ -141,7 +137,6 @@ private:   // Private attributes
     KdenliveDoc *m_doc;
     int m_clipIdCounter;
     int m_folderIdCounter;
-    QString m_generatingAudioId;
     KDirWatch m_fileWatcher;
     /** Timer used to reload clips when they have been externally modified */
     QTimer m_modifiedTimer;
@@ -151,10 +146,17 @@ private:   // Private attributes
     QMap <QString, int> m_requestedThumbs;
     QMutex m_thumbsMutex;
     QFuture<void> m_thumbsThread;
+    /** @brief The id of currently processed clip for thumbs creation. */
+    QString m_processingThumbId;
     /** @brief If true, abort processing of clip thumbs before removing a clip. */
     bool m_abortThumb;
     /** @brief We are about to delete the clip producer, stop processing thumbs. */
     bool m_closing;
+    QFuture<void> m_audioThumbsThread;
+    /** @brief If true, abort processing of audio thumbs. */
+    bool m_abortAudioThumb;
+    /** @brief The id of currently processed clip for audio thumbs creation. */
+    QString m_processingAudioThumbId;
 
 signals:
     void reloadClip(const QString &);
@@ -162,6 +164,7 @@ signals:
     void missingClip(const QString &);
     void availableClip(const QString &);
     void checkAllClips(bool displayRatioChanged, bool fpsChanged, QStringList brokenClips);
+    void displayMessage(const QString &, int);
 };
 
 #endif
index f0f3e05181123d62affaf61e1bf1259932b48712..b448d45375124dfc2af5fa097131cbf4567d46d9 100644 (file)
 #include <KStandardDirs>
 #include <KDebug>
 #include <KFileItem>
+#include <kdeversion.h>
+#include <KUrlLabel>
+#include <KRun>
+
+#ifdef USE_NEPOMUK
+#if KDE_IS_VERSION(4,6,0)
+#include <Nepomuk/Variant>
+#include <Nepomuk/Resource>
+#include <Nepomuk/ResourceManager>
+#include <Nepomuk/Vocabulary/NIE>
+#endif
+#endif
+
 
 #include <QDir>
 
@@ -401,6 +414,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 +429,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++;
@@ -430,8 +451,7 @@ ClipProperties::ClipProperties(DocClipBase *clip, Timecode tc, double fps, QWidg
         m_view.clip_filesize->setHidden(true);
         m_view.label_size->setHidden(true);
     }
-    m_view.clip_duration->setInputMask("");
-    m_view.clip_duration->setValidator(tc.validator());
+    m_view.clip_duration->setInputMask(tc.mask());
     m_view.clip_duration->setText(tc.getTimecode(m_clip->duration()));
     if (t != IMAGE && t != COLOR && t != TEXT) m_view.clip_duration->setReadOnly(true);
     else {
@@ -447,6 +467,31 @@ ClipProperties::ClipProperties(DocClipBase *clip, Timecode tc, double fps, QWidg
     m_view.marker_delete->setIcon(KIcon("trash-empty"));
     m_view.marker_delete->setToolTip(i18n("Delete marker"));
 
+        // Check for Nepomuk metadata
+#ifdef USE_NEPOMUK
+#if KDE_IS_VERSION(4,6,0)
+    if (!url.isEmpty()) {
+        Nepomuk::ResourceManager::instance()->init();
+        Nepomuk::Resource res( url.path() );
+        // Check if file has a license
+        if (res.hasProperty(Nepomuk::Vocabulary::NIE::license())) {
+            QString ltype = res.property(Nepomuk::Vocabulary::NIE::licenseType()).toString();
+            m_view.clip_license->setText(i18n("License: %1", res.property(Nepomuk::Vocabulary::NIE::license()).toString()));
+            if (ltype.startsWith("http")) {
+                m_view.clip_license->setUrl(ltype);
+                connect(m_view.clip_license, SIGNAL(leftClickedUrl(const QString &)), this, SLOT(slotOpenUrl(const QString &)));
+            }
+        }
+        else m_view.clip_license->setHidden(true);
+    }
+    else m_view.clip_license->setHidden(true);
+#else
+    m_view.clip_license->setHidden(true);
+#endif
+#else
+    m_view.clip_license->setHidden(true);
+#endif
+    
     slotFillMarkersList();
     connect(m_view.marker_new, SIGNAL(clicked()), this, SLOT(slotAddMarker()));
     connect(m_view.marker_edit, SIGNAL(clicked()), this, SLOT(slotEditMarker()));
@@ -456,7 +501,7 @@ ClipProperties::ClipProperties(DocClipBase *clip, Timecode tc, double fps, QWidg
     connect(this, SIGNAL(accepted()), this, SLOT(slotApplyProperties()));
     connect(m_view.buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(slotApplyProperties()));
     m_view.buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
-    //adjustSize();
+    adjustSize();
 }
 
 
@@ -612,8 +657,10 @@ ClipProperties::~ClipProperties()
 
 void ClipProperties::slotApplyProperties()
 {
-    if (m_clip != NULL)
-        emit applyNewClipProperties(m_clip->getId(), m_clip->properties(), properties(), needsTimelineRefresh(), needsTimelineReload());
+    if (m_clip != NULL) {
+        QMap <QString, QString> props = properties();
+        emit applyNewClipProperties(m_clip->getId(), m_clip->currentProperties(props), props, needsTimelineRefresh(), needsTimelineReload());
+    }
     m_view.buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
 }
 
@@ -1026,6 +1073,11 @@ void ClipProperties::slotDeleteProxy()
       if (m_proxyContainer) delete m_proxyContainer;
 }
 
+void ClipProperties::slotOpenUrl(const QString &url)
+{
+    new KRun(KUrl(url), this);
+}
+
 #include "clipproperties.moc"
 
 
index 5dad49494b04b67eb975a57bfb427c0b062cdf23..93cf57eb8a2aa919c15f905246e6dca6ea3be664 100644 (file)
@@ -69,6 +69,7 @@ private slots:
     void slotApplyProperties();
     void slotModified();
     void slotDeleteProxy();
+    void slotOpenUrl(const QString &url);
 
 private:
     Ui::ClipProperties_UI m_view;
diff --git a/src/clipstabilize.cpp b/src/clipstabilize.cpp
new file mode 100644 (file)
index 0000000..cc741b2
--- /dev/null
@@ -0,0 +1,276 @@
+/***************************************************************************
+ *   Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org)        *
+ *   Copyright (C) 2011 by Marco Gittler (marco@gitma.de)                  *
+ *                                                                         *
+ *   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 "clipstabilize.h"
+#include "doubleparameterwidget.h"
+
+#include <KDebug>
+#include <mlt++/Mlt.h>
+#include "kdenlivesettings.h"
+#include <KGlobalSettings>
+#include <KMessageBox>
+#include <KColorScheme>
+#include <QtConcurrentRun>
+#include <QTimer>
+#include <QSlider>
+#include <KFileDialog>
+
+ClipStabilize::ClipStabilize(const QString &dest, int count, const QString &filterName,QWidget * parent) :
+        QDialog(parent), 
+        m_filtername(filterName),
+        m_count(count),
+        vbox(NULL)
+{
+    setFont(KGlobalSettings::toolBarFont());
+    setupUi(this);
+    setWindowTitle(i18n("Stabilize Clip"));
+    auto_add->setText(i18np("Add clip to project", "Add clips to project", count));
+
+    QPalette p = palette();
+    KColorScheme scheme(p.currentColorGroup(), KColorScheme::View, KSharedConfig::openConfig(KdenliveSettings::colortheme()));
+    QColor dark_bg = scheme.shade(KColorScheme::DarkShade);
+    QColor selected_bg = scheme.decoration(KColorScheme::FocusColor).color();
+    QColor hover_bg = scheme.decoration(KColorScheme::HoverColor).color();
+    QColor light_bg = scheme.shade(KColorScheme::LightShade);
+
+    QString stylesheet(QString("QProgressBar:horizontal {border: 1px solid %1;border-radius:0px;border-top-left-radius: 4px;border-bottom-left-radius: 4px;border-right: 0px;background:%4;padding: 0px;text-align:left center}\
+                QProgressBar:horizontal#dragOnly {background: %1} QProgressBar:horizontal:hover#dragOnly {background: %3} QProgressBar:horizontal:hover {border: 1px solid %3;border-right: 0px;}\
+                QProgressBar::chunk:horizontal {background: %1;} QProgressBar::chunk:horizontal:hover {background: %3;}\
+                QProgressBar:horizontal[inTimeline=\"true\"] { border: 1px solid %2;border-right: 0px;background: %4;padding: 0px;text-align:left center } QProgressBar::chunk:horizontal[inTimeline=\"true\"] {background: %2;}\
+                QAbstractSpinBox#dragBox {border: 1px solid %1;border-top-right-radius: 4px;border-bottom-right-radius: 4px;padding-right:0px;} QAbstractSpinBox::down-button#dragBox {width:0px;padding:0px;}\
+                QAbstractSpinBox::up-button#dragBox {width:0px;padding:0px;} QAbstractSpinBox[inTimeline=\"true\"]#dragBox { border: 1px solid %2;} QAbstractSpinBox:hover#dragBox {border: 1px solid %3;} ")
+            .arg(dark_bg.name()).arg(selected_bg.name()).arg(hover_bg.name()).arg(light_bg.name()));
+    setStyleSheet(stylesheet);
+
+    if (m_count == 1) {
+        QString newFile = dest;
+        newFile.append(".mlt");
+        KUrl dest(newFile);
+        dest_url->setMode(KFile::File);
+        dest_url->setUrl(KUrl(newFile));
+        dest_url->fileDialog()->setOperationMode(KFileDialog::Saving);
+    } else {
+        label_dest->setText(i18n("Destination folder"));
+        dest_url->setMode(KFile::Directory);
+        dest_url->setUrl(KUrl(dest));
+        dest_url->fileDialog()->setOperationMode(KFileDialog::Saving);
+    }
+
+    if (m_filtername=="videostab"){
+        QStringList ls;
+        ls << "shutterangle,type,int,value,0,min,0,max,100,tooltip,Angle that Images could be maximum rotated";
+        fillParameters(ls);
+    }else if (m_filtername=="videostab2"){
+        QStringList ls;
+        ls << "accuracy,type,int,value,4,min,1,max,10,tooltip,Accuracy of Shakiness detection";
+        ls << "shakiness,type,int,value,4,min,1,max,10,tooltip,How shaky is the Video";
+        ls << "stepsize,type,int,value,6,min,0,max,100,tooltip,Stepsize of Detection process minimum around";
+        ls << "algo,type,bool,value,1,min,0,max,1,tooltip,0 = Bruteforce 1 = small measurement fields";
+        ls << "mincontrast,type,double,value,0.3,min,0,max,1,factor,1,decimals,2,tooltip,Below this Contrast Field is discarded";
+        ls << "show,type,int,value,0,min,0,max,2,tooltip,0 = draw nothing. 1 or 2 show fields and transforms";
+        ls << "smoothing,type,int,value,10,min,0,max,100,tooltip,number of frames for lowpass filtering";
+        ls << "maxshift,type,int,value,-1,min,-1,max,1000,tooltip,max number of pixels to shift";
+        ls << "maxangle,type,int,value,-1,min,-1,max,1000,tooltip,max anglen to rotate (in rad)";
+        ls << "crop,type,bool,value,0,min,0,max,1,tooltip,0 = keep border  1 = black background";
+        ls << "invert,type,bool,value,0,min,0,max,1,tooltip,invert transform";
+        ls << "realtive,type,bool,value,1,min,0,max,1,tooltip,0 = absolute transform  1= relative";
+        ls << "zoom,type,int,value,0,min,-500,max,500,tooltip,additional zoom during transform";
+        ls << "optzoom,type,bool,value,1,min,0,max,1,tooltip,use optimal zoom (calulated from transforms)";
+        ls << "sharpen,type,double,value,0.8,min,0,max,1,decimals,1,tooltip,sharpen transformed image";
+        fillParameters(ls);
+
+    }
+
+    //connect(buttonBox,SIGNAL(rejected()), this, SLOT(slotAbortStabilize()));
+
+    vbox=new QVBoxLayout(optionsbox);
+    QHashIterator<QString,QHash<QString,QString> > hi(m_ui_params);
+    while(hi.hasNext()){
+        hi.next();
+        QHash<QString,QString> val=hi.value();
+        if (val["type"]=="int" || val["type"]=="double"){
+            DoubleParameterWidget *dbl=new DoubleParameterWidget(hi.key(), val["value"].toDouble(),
+                    val["min"].toDouble(),val["max"].toDouble(),val["value"].toDouble(),
+                    "",0/*id*/,""/*suffix*/,val["decimals"]!=""?val["decimals"].toInt():0,this);
+            dbl->setObjectName(hi.key());
+            dbl->setToolTip(val["tooltip"]);
+            connect(dbl,SIGNAL(valueChanged(double)),this,SLOT(slotUpdateParams()));
+            vbox->addWidget(dbl);
+        }else if (val["type"]=="bool"){
+            QCheckBox *ch=new QCheckBox(hi.key(),this);
+            ch->setCheckState(val["value"] == "0" ? Qt::Unchecked : Qt::Checked);
+            ch->setObjectName(hi.key());
+            connect(ch, SIGNAL(stateChanged(int)) , this,SLOT(slotUpdateParams()));
+            ch->setToolTip(val["tooltip"]);
+            vbox->addWidget(ch);
+        
+        }
+    }
+    adjustSize();
+}
+
+ClipStabilize::~ClipStabilize()
+{
+    /*if (m_stabilizeProcess.state() != QProcess::NotRunning) {
+        m_stabilizeProcess.close();
+    }*/
+}
+
+QStringList ClipStabilize::params()
+{
+    //we must return a stringlist with:
+    // producerparams << filtername << filterparams << consumer << consumerparams
+    QStringList params;
+    // producer params
+    params << QString();
+    // filter
+    params << m_filtername;
+    QStringList filterparamsList;
+    QHashIterator <QString,QHash<QString,QString> > it(m_ui_params);
+    while (it.hasNext()){
+        it.next();
+        filterparamsList << it.key() + "=" + it.value().value("value");
+    }
+    params << filterparamsList.join(" ");
+    
+    // consumer
+    params << "xml";
+    // consumer params
+    QString title = i18n("Stabilised");
+    params << QString("all=1 title=\"%1\"").arg(title);
+    return params;
+}
+
+QString ClipStabilize::destination() const
+{
+    if (m_count == 1)
+        return dest_url->url().path();
+    else
+        return dest_url->url().directory(KUrl::AppendTrailingSlash);
+}
+
+QString ClipStabilize::desc() const
+{
+    return i18n("Stabilize clip");
+}
+
+void ClipStabilize::slotStartStabilize()
+{
+    /*
+    if (m_consumer && !m_consumer->is_stopped()) {
+        return;
+    }
+    m_duration = 0;
+    QStringList parameters;
+    QString destination;
+    //QString params = ffmpeg_params->toPlainText().simplified();
+    if (urls_list->count() > 0) {
+        source_url->setUrl(m_urls.takeFirst());
+        destination = dest_url->url().path(KUrl::AddTrailingSlash)+ source_url->url().fileName()+".mlt";
+        QList<QListWidgetItem *> matching = urls_list->findItems(source_url->url().path(), Qt::MatchExactly);
+        if (matching.count() > 0) {
+            matching.at(0)->setFlags(Qt::ItemIsSelectable);
+            urls_list->setCurrentItem(matching.at(0));
+        }
+    } else {
+        destination = dest_url->url().path();
+    }
+    QString s_url = source_url->url().path();
+
+    if (QFile::exists(destination)) {
+            if (KMessageBox::questionYesNo(this, i18n("File %1 already exists.\nDo you want to overwrite it?", destination )) == KMessageBox::No) return;
+    }
+    buttonBox->button(QDialogButtonBox::Abort)->setText(i18n("Abort"));
+
+    if (m_profile){
+        m_playlist= new Mlt::Playlist;
+        Mlt::Filter filter(*m_profile,filtername.toUtf8().data());
+        QHashIterator <QString,QHash<QString,QString> > it(m_ui_params);
+        while (it.hasNext()){
+            it.next();
+            filter.set(
+                    it.key().toAscii().data(),
+                    QString::number(it.value()["value"].toDouble()).toAscii().data());
+        }
+        Mlt::Producer p(*m_profile,s_url.toUtf8().data());
+        if (p.is_valid()) {
+            m_playlist->append(p);
+            m_playlist->attach(filter);
+            m_consumer= new Mlt::Consumer(*m_profile,"xml",destination.toUtf8().data());
+            m_consumer->set("all",1);
+            m_consumer->set("real_time",-2);
+            m_consumer->connect(*m_playlist);
+            m_stabilizeRun = QtConcurrent::run(this, &ClipStabilize::slotRunStabilize);
+            m_timer->start(500);
+            button_start->setEnabled(false);
+        }
+    }
+*/
+}
+
+
+
+void ClipStabilize::slotUpdateParams()
+{
+    for (int i=0;i<vbox->count();i++){
+        QWidget* w=vbox->itemAt(i)->widget();
+        QString name=w->objectName();
+        if (name !="" && m_ui_params.contains(name)){
+            if (m_ui_params[name]["type"]=="int" || m_ui_params[name]["type"]=="double"){
+                DoubleParameterWidget *dbl=(DoubleParameterWidget*)w;
+                m_ui_params[name]["value"]=QString::number((double)(dbl->getValue()));
+            }else if (m_ui_params[name]["type"]=="bool"){
+                QCheckBox *ch=(QCheckBox*)w;
+                m_ui_params[name]["value"]= ch->checkState() == Qt::Checked ? "1" : "0" ;
+            }
+        }
+    }
+}
+
+bool ClipStabilize::autoAddClip() const
+{
+    return auto_add->isChecked();
+}
+
+void ClipStabilize::fillParameters(QStringList lst)
+{
+
+    m_ui_params.clear();
+    while (!lst.isEmpty()){
+        QString vallist=lst.takeFirst();
+        QStringList cont=vallist.split(",");
+        QString name=cont.takeFirst();
+        while (!cont.isEmpty()){
+            QString valname=cont.takeFirst();
+            QString val;
+            if (!cont.isEmpty()){
+                val=cont.takeFirst();
+            }
+            m_ui_params[name][valname]=val;
+        }
+    }
+
+}
+
+
+#include "clipstabilize.moc"
+
+
diff --git a/src/clipstabilize.h b/src/clipstabilize.h
new file mode 100644 (file)
index 0000000..269c0c4
--- /dev/null
@@ -0,0 +1,74 @@
+/***************************************************************************
+ *   Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org)        *
+ *   Copyright (C) 2011 by Marco Gittler (marco@gitma.de)                  *
+ *                                                                         *
+ *   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 CLIPSTABILIZE_H
+#define CLIPSTABILIZE_H
+
+
+#include "ui_clipstabilize_ui.h"
+
+#include <KUrl>
+#include <QProcess>
+#include <QFuture>
+
+class QTimer;
+namespace Mlt{
+       class Profile;
+       class Playlist;
+       class Consumer;
+       class Filter;
+};
+
+class ClipStabilize : public QDialog, public Ui::ClipStabilize_UI
+{
+    Q_OBJECT
+
+public:
+    ClipStabilize(const QString &dest, int count, const QString &filterName,QWidget * parent = 0);
+    ~ClipStabilize();
+    /** @brief Should the generated clip be added to current project. */
+    bool autoAddClip() const;
+    /** @brief Return the filter parameters. */
+    QStringList params();
+    /** @brief Return the destination file or folder. */
+    QString destination() const;
+    /** @brief Return the job description. */
+    QString desc() const;
+
+
+private slots:
+    void slotStartStabilize();
+    void slotUpdateParams();
+
+private:
+    QString m_filtername;
+    int m_count;
+    QHash<QString,QHash<QString,QString> > m_ui_params;
+    QVBoxLayout *vbox;
+    void fillParameters(QStringList);
+
+signals:
+    void addClip(KUrl url);
+};
+
+
+#endif
+
index 8dbf6df4430c436500464390dbf4ca5c24ed450c..fac4a04061ddd64d2b1413a1aad1720c761746bf 100644 (file)
@@ -32,6 +32,13 @@ ClipTranscode::ClipTranscode(KUrl::List urls, const QString &params, const QStri
     setFont(KGlobalSettings::toolBarFont());
     setupUi(this);
     setAttribute(Qt::WA_DeleteOnClose);
+#if KDE_IS_VERSION(4,7,0)
+    m_infoMessage = new KMessageWidget;
+    QGridLayout *s =  static_cast <QGridLayout*> (layout());
+    s->addWidget(m_infoMessage, 10, 0, 1, -1);
+    m_infoMessage->setCloseButtonVisible(false);
+    m_infoMessage->hide();
+#endif
     log_text->setHidden(true);
     setWindowTitle(i18n("Transcode Clip"));
     auto_add->setText(i18np("Add clip to project", "Add clips to project", m_urls.count()));
@@ -72,7 +79,7 @@ ClipTranscode::ClipTranscode(KUrl::List urls, const QString &params, const QStri
         QMapIterator<QString, QString> i(profiles);
         while (i.hasNext()) {
             i.next();
-            QStringList data = i.value().split(";", QString::SkipEmptyParts);
+            QStringList data = i.value().split(";");
             profile_list->addItem(i.key(), data.at(0));
             if (data.count() > 1) profile_list->setItemData(profile_list->count() - 1, data.at(1), Qt::UserRole + 1);
         }
@@ -85,6 +92,8 @@ ClipTranscode::ClipTranscode(KUrl::List urls, const QString &params, const QStri
     m_transcodeProcess.setProcessChannelMode(QProcess::MergedChannels);
     connect(&m_transcodeProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(slotShowTranscodeInfo()));
     connect(&m_transcodeProcess, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(slotTranscodeFinished(int, QProcess::ExitStatus)));
+    
+    ffmpeg_params->setMaximumHeight(QFontMetrics(font()).lineSpacing() * 5);
 
     adjustSize();
 }
@@ -94,6 +103,9 @@ ClipTranscode::~ClipTranscode()
     if (m_transcodeProcess.state() != QProcess::NotRunning) {
         m_transcodeProcess.close();
     }
+#if KDE_IS_VERSION(4,7,0)
+    delete m_infoMessage;
+#endif
 }
 
 void ClipTranscode::slotStartTransCode()
@@ -102,10 +114,15 @@ void ClipTranscode::slotStartTransCode()
         return;
     }
     m_duration = 0;
+    m_destination.clear();
+#if KDE_IS_VERSION(4,7,0)
+    m_infoMessage->animatedHide();
+#endif
     QStringList parameters;
     QString destination;
     QString params = ffmpeg_params->toPlainText().simplified();
-    if (urls_list->count() > 0) {
+    if (m_urls.count() > 0 && urls_list->count() > 0) {
+        // We are processing multiple clips
         source_url->setUrl(m_urls.takeFirst());
         destination = dest_url->url().path(KUrl::AddTrailingSlash) + source_url->url().fileName();
         QList<QListWidgetItem *> matching = urls_list->findItems(source_url->url().path(), Qt::MatchExactly);
@@ -118,19 +135,19 @@ void ClipTranscode::slotStartTransCode()
     }
     QString extension = params.section("%1", 1, 1).section(' ', 0, 0);
     QString s_url = source_url->url().path();
-
     parameters << "-i" << s_url;
     if (QFile::exists(destination + extension)) {
         if (KMessageBox::questionYesNo(this, i18n("File %1 already exists.\nDo you want to overwrite it?", destination + extension)) == KMessageBox::No) return;
         parameters << "-y";
     }
     foreach(QString s, params.split(' '))
-    parameters << s.replace("%1", destination);
+        parameters << s.replace("%1", destination);
     buttonBox->button(QDialogButtonBox::Abort)->setText(i18n("Abort"));
 
-    //kDebug() << "/// FFMPEG ARGS: " << parameters;
-
+    m_destination = destination + extension;
     m_transcodeProcess.start("ffmpeg", parameters);
+    source_url->setEnabled(false);
+    dest_url->setEnabled(false);
     button_start->setEnabled(false);
 
 }
@@ -138,11 +155,11 @@ void ClipTranscode::slotStartTransCode()
 void ClipTranscode::slotShowTranscodeInfo()
 {
     QString log = QString(m_transcodeProcess.readAll());
-    int progress;
     if (m_duration == 0) {
         if (log.contains("Duration:")) {
             QString data = log.section("Duration:", 1, 1).section(',', 0, 0).simplified();
             QStringList numbers = data.split(':');
+            if (numbers.size() < 3) return;
             m_duration = numbers.at(0).toInt() * 3600 + numbers.at(1).toInt() * 60 + numbers.at(2).toDouble();
             log_text->setHidden(true);
             job_progress->setHidden(false);
@@ -153,16 +170,16 @@ void ClipTranscode::slotShowTranscodeInfo()
         }
     }
     else if (log.contains("time=")) {
+        int progress;
         QString time = log.section("time=", 1, 1).simplified().section(' ', 0, 0);
         if (time.contains(':')) {
             QStringList numbers = time.split(':');
+            if (numbers.size() < 3) return;
             progress = numbers.at(0).toInt() * 3600 + numbers.at(1).toInt() * 60 + numbers.at(2).toDouble();
         }
         else progress = (int) time.toDouble();
-        kDebug()<<"// PROGRESS: "<<progress<<", "<<m_duration;
         job_progress->setValue((int) (100.0 * progress / m_duration));
     }
-    //kDebug() << "//LOG: " << log;
     log_text->setPlainText(log);
 }
 
@@ -170,8 +187,14 @@ void ClipTranscode::slotTranscodeFinished(int exitCode, QProcess::ExitStatus exi
 {
     buttonBox->button(QDialogButtonBox::Abort)->setText(i18n("Close"));
     button_start->setEnabled(true);
+    source_url->setEnabled(true);
+    dest_url->setEnabled(true);
     m_duration = 0;
 
+    if (QFileInfo(m_destination).size() <= 0) {
+        // Destination file does not exist, transcoding failed
+        exitCode = 1;
+    }
     if (exitCode == 0 && exitStatus == QProcess::NormalExit) {
         log_text->setHtml(log_text->toPlainText() + "<br /><b>" + i18n("Transcoding finished."));
         if (auto_add->isChecked()) {
@@ -188,11 +211,33 @@ void ClipTranscode::slotTranscodeFinished(int exitCode, QProcess::ExitStatus exi
             slotStartTransCode();
             return;
         } else if (auto_close->isChecked()) accept();
+        else {
+#if KDE_IS_VERSION(4,7,0)
+            m_infoMessage->setMessageType(KMessageWidget::Positive);
+            m_infoMessage->setText(i18n("Transcoding finished."));
+            m_infoMessage->animatedShow();
+#else
+            log_text->setVisible(true);
+#endif
+        }
     } else {
-        log_text->setHtml(log_text->toPlainText() + "<br /><b>" + i18n("Transcoding FAILED!"));
+#if KDE_IS_VERSION(4,7,0)
+        m_infoMessage->setMessageType(KMessageWidget::Warning);
+        m_infoMessage->setText(i18n("Transcoding failed!"));
+        m_infoMessage->animatedShow();
+#else
+        log_text->setHtml(log_text->toPlainText() + "<br /><b>" + i18n("Transcoding failed!"));
+#endif
+        log_text->setVisible(true);
     }
-
     m_transcodeProcess.close();
+    
+    //Refill url list in case user wants to transcode to another format
+    if (urls_list->count() > 0) {
+        m_urls.clear();
+        for (int i = 0; i < urls_list->count(); i++)
+            m_urls << urls_list->item(i)->text();
+    }
 }
 
 void ClipTranscode::slotUpdateParams(int ix)
index 84f2f78423d34b958b7e5a9439d8d9731d465783..8de1db82e80b5b1132cf6a62cb6024bf625b0fe3 100644 (file)
 #include "ui_cliptranscode_ui.h"
 
 #include <KUrl>
+#include <kdeversion.h>
+#if KDE_IS_VERSION(4,7,0)
+#include <KMessageWidget>
+#endif
 
 #include <QProcess>
 
@@ -47,7 +51,13 @@ private:
     QProcess m_transcodeProcess;
     KUrl::List m_urls;
     int m_duration;
+    /** @brief The path for destination transcoded file. */
+    QString m_destination;
 
+#if KDE_IS_VERSION(4,7,0)
+    KMessageWidget *m_infoMessage;
+#endif
+    
 signals:
     void addClip(KUrl url);
 };
index 4ee5eccc1c41b71434b101fa19d0f11a9a8e51b2..1c8e08dbb4011eca6fece8b9fa52866124a87a8a 100644 (file)
@@ -138,7 +138,7 @@ QImage VectorscopeGenerator::calculateVectorscope(const QSize &vectorscopeSize,
     QPoint pt;
     QRgb px;
 
-    const int stepsize = 4*accelFactor;
+    const int stepsize = 4 * accelFactor;
 
     // Just an average for the number of image pixels per scope pixel.
     // NOTE: byteCount() has to be replaced by (img.bytesPerLine()*img.height()) for Qt 4.5 to compile, see: http://doc.trolltech.org/4.6/qimage.html#bytesPerLine
diff --git a/src/colorscopes/CMakeLists.txt b/src/colorscopes/CMakeLists.txt
deleted file mode 100644 (file)
index d2df8d0..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-set(kdenlive_SRCS
-  ${kdenlive_SRCS}
-  colorscopes/abstractgfxscopewidget.cpp
-  colorscopes/histogram.cpp
-  colorscopes/rgbparade.cpp
-  colorscopes/vectorscope.cpp
-  colorscopes/waveform.cpp
-  PARENT_SCOPE
-)
index e173297466794337bbdcb9a7ea1734baeaf6f8c9..336a8d66fd6b299afa77efa6bbfebafe32a7bc36 100644 (file)
 #include <QMouseEvent>
 #include <QStylePainter>
 
-static const int FIX_WIDTH = 24; /* widget width in pixel */
-static const int LINE_END = (FIX_WIDTH - 3);
-static const int END_MARK_LENGTH = (FIX_WIDTH - 8);
-static const int BIG_MARK_LENGTH = (END_MARK_LENGTH * 3 / 4);
-static const int BIG_MARK_X2 = LINE_END;
-static const int BIG_MARK_X1 = (BIG_MARK_X2 - BIG_MARK_LENGTH);
-static const int MIDDLE_MARK_LENGTH = (END_MARK_LENGTH / 2);
-static const int MIDDLE_MARK_X2 = LINE_END;
-static const int MIDDLE_MARK_X1 = (MIDDLE_MARK_X2 - MIDDLE_MARK_LENGTH);
-static const int LITTLE_MARK_LENGTH = (MIDDLE_MARK_LENGTH / 2);
-static const int LITTLE_MARK_X2 = LINE_END;
-static const int LITTLE_MARK_X1 = (LITTLE_MARK_X2 - LITTLE_MARK_LENGTH);
-
+static int MAX_HEIGHT;
+// Width of a frame in pixels
 static int FRAME_SIZE;
+// Height of the timecode text
 static int LABEL_SIZE;
-static const int END_LABEL_X = 4;
-static const int END_LABEL_Y = (END_LABEL_X + LABEL_SIZE - 2);
+
+static int BIG_MARK_X;
+static int MIDDLE_MARK_X;
+static int LITTLE_MARK_X;
 
 static int littleMarkDistance;
 static int mediumMarkDistance;
@@ -68,7 +60,15 @@ CustomRuler::CustomRuler(Timecode tc, CustomTrackView *parent) :
 {
     setFont(KGlobalSettings::toolBarFont());
     QFontMetricsF fontMetrics(font());
-    LABEL_SIZE = fontMetrics.ascent() - 2;
+    // Define size variables
+    LABEL_SIZE = fontMetrics.ascent();
+    setMinimumHeight(LABEL_SIZE * 2);
+    setMaximumHeight(LABEL_SIZE * 2);
+    MAX_HEIGHT = height();
+    BIG_MARK_X = LABEL_SIZE + 1;
+    int mark_length = MAX_HEIGHT - BIG_MARK_X;
+    MIDDLE_MARK_X = BIG_MARK_X + mark_length / 2;
+    LITTLE_MARK_X = BIG_MARK_X + mark_length / 3;
     updateFrameSize();
     m_scale = 3;
     m_zoneColor = KStatefulBrush(KColorScheme::View, KColorScheme::PositiveBackground, KSharedConfig::openConfig(KdenliveSettings::colortheme())).brush(this).color();
@@ -86,7 +86,6 @@ CustomRuler::CustomRuler(Timecode tc, CustomTrackView *parent) :
     m_goMenu = m_contextMenu->addMenu(i18n("Go To"));
     connect(m_goMenu, SIGNAL(triggered(QAction *)), this, SLOT(slotGoToGuide(QAction *)));
     setMouseTracking(true);
-    setMinimumHeight(20);
 }
 
 void CustomRuler::updateProjectFps(Timecode t)
@@ -266,9 +265,9 @@ int CustomRuler::offset() const
 void CustomRuler::slotCursorMoved(int oldpos, int newpos)
 {
     if (qAbs(oldpos - newpos) * m_factor > m_textSpacing) {
-        update(oldpos * m_factor - offset() - 6, 0, 17, height());
-        update(newpos * m_factor - offset() - 6, 0, 17, height());
-    } else update(qMin(oldpos, newpos) * m_factor - offset() - 6, 0, qAbs(oldpos - newpos) * m_factor + 17, height());
+        update(oldpos * m_factor - offset() - 6, BIG_MARK_X, 14, MAX_HEIGHT - BIG_MARK_X);
+        update(newpos * m_factor - offset() - 6, BIG_MARK_X, 14, MAX_HEIGHT - BIG_MARK_X);
+    } else update(qMin(oldpos, newpos) * m_factor - offset() - 6, BIG_MARK_X, qAbs(oldpos - newpos) * m_factor + 14, MAX_HEIGHT - BIG_MARK_X);
 }
 
 void CustomRuler::setPixelPerMark(int rate)
@@ -342,16 +341,15 @@ void CustomRuler::paintEvent(QPaintEvent *e)
 {
     QStylePainter p(this);
     p.setClipRect(e->rect());
-    const int projectEnd = (int)(m_duration * m_factor);
-    p.fillRect(0, 0, projectEnd - m_offset, height(), palette().alternateBase().color());
+    
+    // Draw background
+    p.fillRect(0, 0, m_duration * m_factor - m_offset, MAX_HEIGHT, palette().alternateBase().color());
 
+    // Draw zone background
     const int zoneStart = (int)(m_zoneStart * m_factor);
     const int zoneEnd = (int)(m_zoneEnd * m_factor);
-    const QRect zoneRect();
-
-    p.fillRect(zoneStart - m_offset, height() / 2, zoneEnd - zoneStart, height() / 2, m_zoneColor);
-
-    const int value  = m_view->cursorPos() * m_factor - m_offset;
+    p.fillRect(zoneStart - m_offset, LABEL_SIZE + 2, zoneEnd - zoneStart, MAX_HEIGHT - LABEL_SIZE - 2, m_zoneColor);
+    
     int minval = (e->rect().left() + m_offset) / FRAME_SIZE - 1;
     const int maxval = (e->rect().right() + m_offset) / FRAME_SIZE + 1;
     if (minval < 0)
@@ -359,19 +357,22 @@ void CustomRuler::paintEvent(QPaintEvent *e)
 
     double f, fend;
     const int offsetmax = maxval * FRAME_SIZE;
+    int offsetmin;
 
     p.setPen(palette().text().color());
 
     // draw time labels
-    int offsetmin = (e->rect().left() + m_offset) / m_textSpacing;
-    offsetmin = offsetmin * m_textSpacing;
-    for (f = offsetmin; f < offsetmax; f += m_textSpacing) {
-        QString lab;
-        if (KdenliveSettings::frametimecode())
-            lab = QString::number((int)(f / m_factor + 0.5));
-        else
-            lab = m_timecode.getTimecodeFromFrames((int)(f / m_factor + 0.5));
-        p.drawText(f - m_offset + 2, LABEL_SIZE, lab);
+    if (e->rect().y() < LABEL_SIZE) {
+        offsetmin = (e->rect().left() + m_offset) / m_textSpacing;
+        offsetmin = offsetmin * m_textSpacing;
+        for (f = offsetmin; f < offsetmax; f += m_textSpacing) {
+            QString lab;
+            if (KdenliveSettings::frametimecode())
+                lab = QString::number((int)(f / m_factor + 0.5));
+            else
+                lab = m_timecode.getTimecodeFromFrames((int)(f / m_factor + 0.5));
+            p.drawText(f - m_offset + 2, LABEL_SIZE, lab);
+        }
     }
 
     offsetmin = (e->rect().left() + m_offset) / littleMarkDistance;
@@ -380,7 +381,7 @@ void CustomRuler::paintEvent(QPaintEvent *e)
     fend = m_scale * littleMarkDistance;
     if (fend > 5) {
         for (f = offsetmin - m_offset; f < offsetmax - m_offset; f += fend)
-            p.drawLine((int)f, LITTLE_MARK_X1, (int)f, LITTLE_MARK_X2);
+            p.drawLine((int)f, LITTLE_MARK_X, (int)f, MAX_HEIGHT);
     }
 
     offsetmin = (e->rect().left() + m_offset) / mediumMarkDistance;
@@ -389,7 +390,7 @@ void CustomRuler::paintEvent(QPaintEvent *e)
     fend = m_scale * mediumMarkDistance;
     if (fend > 5) {
         for (f = offsetmin - m_offset - fend; f < offsetmax - m_offset + fend; f += fend)
-            p.drawLine((int)f, MIDDLE_MARK_X1, (int)f, MIDDLE_MARK_X2);
+            p.drawLine((int)f, MIDDLE_MARK_X, (int)f, MAX_HEIGHT);
     }
 
     offsetmin = (e->rect().left() + m_offset) / bigMarkDistance;
@@ -398,32 +399,32 @@ void CustomRuler::paintEvent(QPaintEvent *e)
     fend = m_scale * bigMarkDistance;
     if (fend > 5) {
         for (f = offsetmin - m_offset; f < offsetmax - m_offset; f += fend)
-            p.drawLine((int)f, BIG_MARK_X1, (int)f, BIG_MARK_X2);
+            p.drawLine((int)f, BIG_MARK_X, (int)f, MAX_HEIGHT);
     }
 
     // draw zone cursors
-    int off = offset();
     if (zoneStart > 0) {
         QPolygon pa(4);
-        pa.setPoints(4, zoneStart - off + 3, 9, zoneStart - off, 9, zoneStart - off, 18, zoneStart - off + 3, 18);
+        pa.setPoints(4, zoneStart - m_offset + 3, LABEL_SIZE + 2, zoneStart - m_offset, LABEL_SIZE + 2, zoneStart - m_offset, MAX_HEIGHT - 1, zoneStart - m_offset + 3, MAX_HEIGHT - 1);
         p.drawPolyline(pa);
     }
 
     if (zoneEnd > 0) {
         QColor center(Qt::white);
         center.setAlpha(150);
-        QRect rec(zoneStart - off + (zoneEnd - zoneStart) / 2 - 4, 9, 8, 9);
+        QRect rec(zoneStart - m_offset + (zoneEnd - zoneStart) / 2 - 4, LABEL_SIZE + 2, 8, MAX_HEIGHT - LABEL_SIZE - 3);
         p.fillRect(rec, center);
         p.drawRect(rec);
 
         QPolygon pa(4);
-        pa.setPoints(4, zoneEnd - off - 3, 9, zoneEnd - off, 9, zoneEnd - off, 18, zoneEnd - off - 3, 18);
+        pa.setPoints(4, zoneEnd - m_offset - 3, LABEL_SIZE + 2, zoneEnd - m_offset, LABEL_SIZE + 2, zoneEnd - m_offset, MAX_HEIGHT - 1, zoneEnd - m_offset - 3, MAX_HEIGHT - 1);
         p.drawPolyline(pa);
     }
-
+    
     // draw pointer
+    const int value  = m_view->cursorPos() * m_factor - m_offset;
     QPolygon pa(3);
-    pa.setPoints(3, value - 6, 8, value + 6, 8, value, 16);
+    pa.setPoints(3, value - 6, BIG_MARK_X, value + 6, BIG_MARK_X, value, MAX_HEIGHT - 1);
     p.setBrush(palette().highlight());
     p.drawPolygon(pa);
 }
index 32e787908c36aa1fac9dce78094bba1e0addab94..cc75b20f515da8153416e123f9eac89b9ccfe2e0 100644 (file)
@@ -602,7 +602,7 @@ void CustomTrackView::mouseMoveEvent(QMouseEvent * event)
             // razor tool over a clip, display current frame in monitor
             if (false && !m_blockRefresh && item->type() == AVWIDGET) {
                 //TODO: solve crash when showing frame when moving razor over clip
-                emit showClipFrame(((ClipItem *) item)->baseClip(), QPoint(), mappedXPos - (clip->startPos() - clip->cropStart()).frames(m_document->fps()));
+                emit showClipFrame(((ClipItem *) item)->baseClip(), QPoint(), false, mappedXPos - (clip->startPos() - clip->cropStart()).frames(m_document->fps()));
             }
             event->accept();
             return;
@@ -1896,7 +1896,7 @@ void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement insertedE
         return;
     }
     QDomElement effect = insertedEffect.cloneNode().toElement();
-    //kDebug() << "// update effect ix: " << effect.attribute("kdenlive_ix")<<", TRACK: "<<track;
+    //kDebug() << "// update effect ix: " << effect.attribute("kdenlive_ix")<<", GAIN: "<<EffectsList::parameter(effect, "gain");
     if (pos < GenTime()) {
         // editing a track effect
         EffectsParameterList effectParams = getEffectArgs(effect);
@@ -1964,6 +1964,7 @@ void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement insertedE
                 emit clipItemSelected(clip, ix);
         }
     }
+    else emit displayMessage(i18n("Cannot find clip to update effect"), ErrorMessage);
     setDocumentModified();
 }
 
@@ -3776,10 +3777,10 @@ void CustomTrackView::deleteClip(ItemInfo info, bool refresh)
         emit displayMessage(i18n("Error removing clip at %1 on track %2", m_document->timecode().getTimecodeFromFrames(info.startPos.frames(m_document->fps())), info.track), ErrorMessage);
         kDebug()<<"CANNOT REMOVE: "<<info.startPos.frames(m_document->fps())<<", TK: "<<info.track;
         //m_document->renderer()->saveSceneList(QString("/tmp/error%1.mlt").arg(m_ct), QDomElement());
-        exit(1);
         return;
     }
     m_waitingThumbs.removeAll(item);
+    item->stopThumbs();
     if (item->isSelected()) emit clipItemSelected(NULL);
     item->baseClip()->removeReference();
     m_document->updateClip(item->baseClip()->getId());
@@ -4104,9 +4105,10 @@ void CustomTrackView::addClip(QDomElement xml, const QString &clipId, ItemInfo i
         emit displayMessage(i18n("Waiting for clip..."), InformationMessage);
         emit forceClipProcessing(clipId);
         qApp->processEvents();
-        for (int i = 0; i < 3; i++) {
+        for (int i = 0; i < 10; i++) {
             if (baseclip->getProducer() == NULL) {
-                m_producerNotReady.wait(&m_mutex, 500 + 500 * i);
+                qApp->processEvents();
+                m_producerNotReady.wait(&m_mutex, 200);
             } else break;
         }
         if (baseclip->getProducer() == NULL) {
@@ -4229,7 +4231,7 @@ ClipItem *CustomTrackView::getClipItemAt(GenTime pos, int track)
 
 Transition *CustomTrackView::getTransitionItemAt(int pos, int track)
 {
-    const QPointF p(pos, (track + 1) * m_tracksHeight);
+    const QPointF p(pos, track * m_tracksHeight + Transition::itemOffset() + 1);
     QList<QGraphicsItem *> list = scene()->items(p);
     Transition *clip = NULL;
     for (int i = 0; i < list.size(); i++) {
@@ -4250,7 +4252,7 @@ Transition *CustomTrackView::getTransitionItemAt(GenTime pos, int track)
 Transition *CustomTrackView::getTransitionItemAtEnd(GenTime pos, int track)
 {
     int framepos = (int)(pos.frames(m_document->fps()));
-    const QPointF p(framepos - 1, (track + 1) * m_tracksHeight);
+    const QPointF p(framepos - 1, track * m_tracksHeight + Transition::itemOffset() + 1);
     QList<QGraphicsItem *> list = scene()->items(p);
     Transition *clip = NULL;
     for (int i = 0; i < list.size(); i++) {
@@ -4266,7 +4268,7 @@ Transition *CustomTrackView::getTransitionItemAtEnd(GenTime pos, int track)
 
 Transition *CustomTrackView::getTransitionItemAtStart(GenTime pos, int track)
 {
-    const QPointF p(pos.frames(m_document->fps()), (track + 1) * m_tracksHeight);
+    const QPointF p(pos.frames(m_document->fps()), track * m_tracksHeight + Transition::itemOffset() + 1);
     QList<QGraphicsItem *> list = scene()->items(p);
     Transition *clip = NULL;
     for (int i = 0; i < list.size(); ++i) {
@@ -6341,6 +6343,33 @@ void CustomTrackView::slotSelectTrack(int ix)
     viewport()->update();
 }
 
+void CustomTrackView::slotSelectClipsInTrack()
+{
+    QRectF rect(0, m_selectedTrack * m_tracksHeight + m_tracksHeight / 2, sceneRect().width(), m_tracksHeight / 2 - 1);
+    QList<QGraphicsItem *> selection = m_scene->items(rect);
+    m_scene->clearSelection();
+    for (int i = 0; i < selection.count(); i++) {
+        if (selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET || selection.at(i)->type() == GROUPWIDGET) {
+            selection.at(i)->setSelected(true);
+        }
+    }    
+    resetSelectionGroup();
+    groupSelectedItems();
+}
+
+void CustomTrackView::slotSelectAllClips()
+{
+    QList<QGraphicsItem *> selection = m_scene->items();
+    m_scene->clearSelection();
+    for (int i = 0; i < selection.count(); i++) {
+        if (selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET  || selection.at(i)->type() == GROUPWIDGET) {
+            selection.at(i)->setSelected(true);
+        }
+    }
+    resetSelectionGroup();
+    groupSelectedItems();
+}
+
 void CustomTrackView::selectClip(bool add, bool group, int track, int pos)
 {
     QRectF rect;
@@ -6747,3 +6776,28 @@ void CustomTrackView::adjustEffects(ClipItem* item, ItemInfo oldInfo, QUndoComma
 }
 
 
+void CustomTrackView::slotGotFilterJobResults(const QString &/*id*/, int startPos, int track, const QString &filter, stringMap filterParams)
+{
+    ClipItem *clip = getClipItemAt(GenTime(startPos, m_document->fps()), track);
+    if (clip == NULL) {
+        emit displayMessage(i18n("Cannot find clip for effect update %1.", filter), ErrorMessage);
+        return;
+    }
+    QDomElement newEffect;
+    QDomElement effect = clip->getEffectAt(clip->selectedEffectIndex());
+    if (effect.attribute("id") == filter) {
+        newEffect = effect.cloneNode().toElement();
+        QMap<QString, QString>::const_iterator i = filterParams.constBegin();
+        while (i != filterParams.constEnd()) {
+            EffectsList::setParameter(newEffect, i.key(), i.value());
+            kDebug()<<"// RESULT FILTER: "<<i.key()<<"="<< i.value();
+            ++i;
+        }
+        EditEffectCommand *command = new EditEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), effect, newEffect, clip->selectedEffectIndex(), true);
+        m_commandStack->push(command);
+        emit clipItemSelected(clip, clip->selectedEffectIndex());
+    }
+    
+}
+
+
index 64c0ddbb8968a33ee0dbfdfd71497600787aed67..c5c62f9a0624b3fbb6c6403cb71ea31e52027abb 100644 (file)
@@ -262,6 +262,10 @@ public slots:
     * @param effect The new effect xml
     * @param ix The track index */
     void slotAddTrackEffect(const QDomElement &effect, int ix);
+    /** @brief Select all clips in selected track. */
+    void slotSelectClipsInTrack();
+    /** @brief Select all clips in timeline. */
+    void slotSelectAllClips();
 
     /** @brief Update the list of snap points (sticky timeline hotspots).
     * @param selected The currently selected clip if any
@@ -451,6 +455,9 @@ private slots:
      *  @param id The clip's Id string.
      *  @param resetThumbs Should we recreate the timeline thumbnails. */
     void slotRefreshThumbs(const QString &id, bool resetThumbs);
+    /** @brief A Filter job producer results. */
+    void slotGotFilterJobResults(const QString &id, int startPos, int track, const QString &filter, stringMap filterParams);
+
 
 signals:
     void cursorMoved(int, int);
@@ -467,7 +474,7 @@ signals:
     void trackHeightChanged();
     void tracksChanged();
     void displayMessage(const QString &, MessageType);
-    void showClipFrame(DocClipBase *, QPoint, const int);
+    void showClipFrame(DocClipBase *, QPoint, bool, const int);
     void doTrackLock(int, bool);
     void updateClipMarkers(DocClipBase *);
     void updateTrackHeaders();
index f37a36335e2de6e6f35c919ed3ac65ee24c64589..2355f34869dfde53b750dd6e64ffa840d7dcf7a8 100644 (file)
 #include "gentime.h"
 #include "effectslist.h"
 
-#include <QTreeWidgetItem>
 #include <KLocale>
 
+#include <QTreeWidgetItem>
+ #include <QtCore/QString>
+
 const int MAXCLIPDURATION = 15000;
 
+namespace Kdenlive {
+  enum MONITORID { noMonitor, clipMonitor, projectMonitor, recordMonitor, stopmotionMonitor, dvdMonitor };
+  /*const QString clipMonitor("clipMonitor");
+  const QString recordMonitor("recordMonitor");
+  const QString projectMonitor("projectMonitor");
+  const QString stopmotionMonitor("stopmotionMonitor");*/
+}
+
 enum OPERATIONTYPE { NONE = 0, MOVE = 1, RESIZESTART = 2, RESIZEEND = 3, FADEIN = 4, FADEOUT = 5, TRANSITIONSTART = 6, TRANSITIONEND = 7, MOVEGUIDE = 8, KEYFRAME = 9, SEEK = 10, SPACER = 11, RUBBERSELECTION = 12};
 enum CLIPTYPE { UNKNOWN = 0, AUDIO = 1, VIDEO = 2, AV = 3, COLOR = 4, IMAGE = 5, TEXT = 6, SLIDESHOW = 7, VIRTUAL = 8, PLAYLIST = 9 };
 
@@ -57,7 +67,7 @@ enum MessageType {
 
 enum TRACKTYPE { AUDIOTRACK = 0, VIDEOTRACK = 1 };
 
-enum PROXYSTATUS { NOPROXY = 0, PROXYWAITING = -1, CREATINGPROXY = -2, PROXYDONE = -3, PROXYCRASHED = -4};
+enum CLIPJOBSTATUS { NOJOB = 0, JOBWAITING = -1, JOBWORKING = -2, JOBDONE = -3, JOBCRASHED = -4, JOBABORTED = -5};
 
 struct TrackInfo {
     TRACKTYPE type;
index 7b97cedb55ee80fb46a244c8fbd918e20a73f6ee..f54eaff7d0d6f8d05e846be388d8650177776418 100644 (file)
@@ -48,7 +48,6 @@ DocClipBase::DocClipBase(ClipManager *clipManager, QDomElement xml, const QStrin
         m_videoOnlyProducer(NULL),
         m_snapMarkers(QList < CommentedTime >()),
         m_duration(),
-        m_audioTimer(NULL),
         m_thumbProd(NULL),
         m_audioThumbCreated(false),
         m_id(id),
@@ -88,16 +87,19 @@ DocClipBase::DocClipBase(ClipManager *clipManager, QDomElement xml, const QStrin
     if (!m_properties.contains("name")) m_properties.insert("name", url.fileName());
 
     m_thumbProd = new KThumb(clipManager, url, m_id, m_properties.value("file_hash"));
-    if (m_clipType == AV || m_clipType == AUDIO || m_clipType == PLAYLIST) slotCreateAudioTimer();
+    
+    // Setup timer to trigger audio thumbs creation
+    m_audioTimer.setSingleShot(true);
+    m_audioTimer.setInterval(800);
+    connect(&m_audioTimer, SIGNAL(timeout()), m_thumbProd, SLOT(slotCreateAudioThumbs()));
+    
 }
 
 DocClipBase::~DocClipBase()
 {
+    m_audioTimer.stop();
     delete m_thumbProd;
-    if (m_audioTimer) {
-        m_audioTimer->stop();
-        delete m_audioTimer;
-    }
+    m_thumbProd = NULL;
     qDeleteAll(m_toDeleteProducers);
     m_toDeleteProducers.clear();
     qDeleteAll(m_baseTrackProducers);
@@ -120,22 +122,15 @@ QPoint DocClipBase::zone() const
     return zone;
 }
 
-void DocClipBase::slotCreateAudioTimer()
-{
-    connect(m_thumbProd, SIGNAL(audioThumbReady(const audioByteArray&)), this , SLOT(updateAudioThumbnail(const audioByteArray&)));
-    m_audioTimer = new QTimer(this);
-    connect(m_audioTimer, SIGNAL(timeout()), this, SLOT(slotGetAudioThumbs()));
-}
 
-void DocClipBase::askForAudioThumbs()
+bool DocClipBase::hasAudioThumb() const
 {
-    if (m_thumbProd && m_audioTimer) m_thumbProd->askForAudioThumbs(getId());
+    if (m_clipType == AUDIO || m_clipType == AV || m_clipType == PLAYLIST) return true;
+    return false;
 }
 
 void DocClipBase::slotClearAudioCache()
 {
-    if (m_thumbProd) m_thumbProd->stopAudioThumbs();
-    if (m_audioTimer != NULL) m_audioTimer->stop();
     m_audioFrameCache.clear();
     m_audioThumbCreated = false;
 }
@@ -173,10 +168,7 @@ const CLIPTYPE & DocClipBase::clipType() const
 void DocClipBase::setClipType(CLIPTYPE type)
 {
     m_clipType = type;
-
     m_properties.insert("type", QString::number((int) type));
-    if (m_thumbProd && m_audioTimer == NULL && (m_clipType == AV || m_clipType == AUDIO || m_clipType == PLAYLIST))
-        slotCreateAudioTimer();
 }
 
 KUrl DocClipBase::fileURL() const
@@ -243,7 +235,7 @@ qulonglong DocClipBase::fileSize() const
 }
 
 // virtual
-QDomElement DocClipBase::toXML() const
+QDomElement DocClipBase::toXML(bool hideTemporaryProperties) const
 {
     QDomDocument doc;
     QDomElement clip = doc.createElement("producer");
@@ -251,6 +243,7 @@ QDomElement DocClipBase::toXML() const
     QMapIterator<QString, QString> i(m_properties);
     while (i.hasNext()) {
         i.next();
+        if (hideTemporaryProperties && i.key().startsWith("_")) continue;
         if (!i.value().isEmpty()) clip.setAttribute(i.key(), i.value());
     }
     doc.appendChild(clip);
@@ -272,17 +265,6 @@ void DocClipBase::setAudioThumbCreated(bool isDone)
     m_audioThumbCreated = isDone;
 }
 
-
-void DocClipBase::setThumbnail(const QPixmap & pixmap)
-{
-    m_thumbnail = pixmap;
-}
-
-const QPixmap & DocClipBase::thumbnail() const
-{
-    return m_thumbnail;
-}
-
 void DocClipBase::updateAudioThumbnail(const audioByteArray& data)
 {
     //kDebug() << "CLIPBASE RECIEDVED AUDIO DATA*********************************************";
@@ -460,9 +442,11 @@ void DocClipBase::cleanupProducers()
         }
     }*/
 
-    qDeleteAll(m_toDeleteProducers);
-    m_toDeleteProducers.clear();
-    m_replaceMutex.unlock();
+    if (!isClean()) {
+      qDeleteAll(m_toDeleteProducers);
+      m_toDeleteProducers.clear();
+      m_replaceMutex.unlock();
+    }
 }
 
 bool DocClipBase::isClean() const
@@ -497,6 +481,7 @@ void DocClipBase::setProducer(Mlt::Producer *producer, bool reset, bool readProp
                 m_thumbProd->setProducer(producer);
         }
         else m_thumbProd->setProducer(producer);
+        getAudioThumbs();
     }
     bool updated = false;
     if (id.contains('_')) {
@@ -1107,20 +1092,24 @@ QMap <QString, QString> DocClipBase::properties() const
     return m_properties;
 }
 
-bool DocClipBase::slotGetAudioThumbs()
+QMap <QString, QString> DocClipBase::currentProperties(QMap <QString, QString> props)
 {
-    if (m_thumbProd == NULL || isPlaceHolder()) return false;
-    if (!KdenliveSettings::audiothumbnails() || m_audioTimer == NULL) {
-        if (m_audioTimer != NULL) m_audioTimer->stop();
-        return false;
+    QMap <QString, QString> currentProps;
+    QMap<QString, QString>::const_iterator i = props.constBegin();
+    while (i != props.constEnd()) {
+        currentProps.insert(i.key(), m_properties.value(i.key()));
+        ++i;
     }
+    return currentProps;
+}
+
+bool DocClipBase::getAudioThumbs()
+{
+    if (m_thumbProd == NULL || isPlaceHolder() || !KdenliveSettings::audiothumbnails()) return false;
     if (m_audioThumbCreated) {
-        m_audioTimer->stop();
         return false;
     }
-    m_audioTimer->start(1500);
-    double lengthInFrames = duration().frames(KdenliveSettings::project_fps());
-    m_thumbProd->getAudioThumbs(2, 0, lengthInFrames /*must be number of frames*/, 20);
+    m_audioTimer.start();
     return true;
 }
 
@@ -1221,12 +1210,11 @@ void DocClipBase::slotExtractImage(QList <int> frames)
     m_thumbProd->extractImage(frames);
 }
 
-QPixmap DocClipBase::extractImage(int frame, int width, int height)
+QImage DocClipBase::extractImage(int frame, int width, int height)
 {
-    if (m_thumbProd == NULL) return QPixmap(width, height);
+    if (m_thumbProd == NULL) return QImage();
     QMutexLocker locker(&m_producerMutex);
-    QPixmap p = m_thumbProd->extractImage(frame, width, height);
-    return p;
+    return m_thumbProd->extractImage(frame, width, height);
 }
 
 
index f84f8d84f1221adfeee77d5629cbd27d20d7cf65..fd84c4670ea18cc055b78cbb61a35987cb9e087b 100644 (file)
@@ -83,6 +83,7 @@ Q_OBJECT public:
     /** Returns the internal unique id of the clip. */
     const QString &getId() const;
 
+    bool hasAudioThumb() const;
     //KThumb *thumbCreator;
     bool audioThumbCreated() const;
     /*void getClipMainThumb();*/
@@ -137,7 +138,7 @@ Q_OBJECT public:
     QDomDocument sceneToXML(const GenTime & startTime,
                             const GenTime & endTime) const;
     /** returns a QString containing all of the XML data required to recreate this clip. */
-    QDomElement toXML() const;
+    QDomElement toXML(bool hideTemporaryProperties = false) const;
 
     /** Returns true if the xml passed matches the values in this clip */
     bool matchesXML(const QDomElement & element) const;
@@ -161,22 +162,15 @@ Q_OBJECT public:
      * it uses it as part of it's own composition. */
     bool referencesClip(DocClipBase * clip) const;
 
-    /** Sets the thumbnail to be used by this clip */
-    void setThumbnail(const QPixmap & pixmap);
-
     /** Returns the thumbnail producer used by this clip */
     KThumb *thumbProducer();
 
-    /** Returns the thumbnail used by this clip */
-    const QPixmap & thumbnail() const;
-
     /** Cache for every audio Frame with 10 Bytes */
     /** format is frame -> channel ->bytes */
     QMap<int, QMap<int, QByteArray> > m_audioFrameCache;
 
     /** Free cache data */
     void slotClearAudioCache();
-    void askForAudioThumbs();
     QString getClipHash() const;
     void refreshThumbUrl();
     const char *producerProperty(const char *name) const;
@@ -204,11 +198,12 @@ Q_OBJECT public:
     bool hasAudioCodec(const QString &codec) const;
     bool checkHash() const;
     void setPlaceHolder(bool place);
-    QPixmap extractImage(int frame, int width, int height);
+    QImage extractImage(int frame, int width, int height);
     void clearThumbProducer();
     void reloadThumbProducer();
     void cleanupProducers();
     bool isClean() const;
+    bool getAudioThumbs();
 
 private:   // Private attributes
 
@@ -223,12 +218,8 @@ private:   // Private attributes
 
     /** A list of snap markers; these markers are added to a clips snap-to points, and are displayed as necessary. */
     QList < CommentedTime > m_snapMarkers;
-
-    /** A thumbnail for this clip */
-    QPixmap m_thumbnail;
     GenTime m_duration;
 
-    QTimer *m_audioTimer;
     KThumb *m_thumbProd;
     bool m_audioThumbCreated;
 
@@ -249,9 +240,11 @@ private:   // Private attributes
     /** Try to make sure we don't delete a producer while using it */
     QMutex m_producerMutex;
     QMutex m_replaceMutex;
+    
+    /** @brief This timer will trigger creation of audio thumbnails. */
+    QTimer m_audioTimer;
 
     /** Create connections for audio thumbnails */
-    void slotCreateAudioTimer();
     void slotRefreshProducer();
     void setProducerProperty(const char *name, int data);
     void setProducerProperty(const char *name, double data);
@@ -264,7 +257,6 @@ private:   // Private attributes
    
 public slots:
     void updateAudioThumbnail(const audioByteArray& data);
-    bool slotGetAudioThumbs();
     QList < CommentedTime > commentedSnapMarkers() const;
     GenTime findNextSnapMarker(const GenTime & currTime);
     GenTime findPreviousSnapMarker(const GenTime & currTime);
@@ -278,7 +270,10 @@ public slots:
     uint getClipThumbFrame() const;
     void setProperties(QMap <QString, QString> properties);
     void setMetadata(QMap <QString, QString> properties);
+    /** Returns all current properties for this clip */
     QMap <QString, QString> properties() const;
+    /** Return the current values for a set of properties */
+    QMap <QString, QString> currentProperties(QMap <QString, QString> props);
     QMap <QString, QString> metadata() const;
     void slotExtractImage(QList <int> frames);
 
index a89ddc13a243a05030b97b267d890fd23c5fbce1..5caafe00633fe8a5418190ce38032d03f59dc5f4 100644 (file)
@@ -56,6 +56,7 @@ const int CLIPOK = 1;
 const int CLIPPLACEHOLDER = 2;
 const int CLIPWRONGDURATION = 3;
 const int PROXYMISSING = 4;
+const int SOURCEMISSING = 5;
 
 const int LUMAMISSING = 10;
 const int LUMAOK = 11;
@@ -78,7 +79,10 @@ bool DocumentChecker::hasErrorInClips()
     int max;
     QDomNodeList documentProducers = m_doc.elementsByTagName("producer");
     QList <QDomElement> wrongDurationClips;
+    // List clips whose proxy is missing
     QList <QDomElement> missingProxies;
+    // List clips who have a working proxy but no source clip
+    QList <QDomElement> missingSources;
     m_safeImages.clear();
     m_safeFonts.clear();
     max = m_info.count();
@@ -132,9 +136,17 @@ bool DocumentChecker::hasErrorInClips()
         resource = e.attribute("resource");
         if (e.hasAttribute("proxy")) {
             QString proxyresource = e.attribute("proxy");
-            if (!proxyresource.isEmpty() && proxyresource != "-" && !KIO::NetAccess::exists(KUrl(proxyresource), KIO::NetAccess::SourceSide, 0)) {
-                // Missing clip found
-                missingProxies.append(e);
+            if (!proxyresource.isEmpty() && proxyresource != "-") {
+                // clip has a proxy
+                if (!KIO::NetAccess::exists(KUrl(proxyresource), KIO::NetAccess::SourceSide, 0)) {
+                    // Missing clip found
+                    missingProxies.append(e);
+                }
+                else if (!KIO::NetAccess::exists(KUrl(resource), KIO::NetAccess::SourceSide, 0)) {
+                    // clip has proxy but original clip is missing
+                    missingSources.append(e);
+                    continue;
+                }
             }
         }
         if (clipType == SLIDESHOW) resource = KUrl(resource).directory();
@@ -174,7 +186,7 @@ bool DocumentChecker::hasErrorInClips()
     
     
 
-    if (m_missingClips.isEmpty() && missingLumas.isEmpty() && wrongDurationClips.isEmpty() && missingProxies.isEmpty())
+    if (m_missingClips.isEmpty() && missingLumas.isEmpty() && wrongDurationClips.isEmpty() && missingProxies.isEmpty() && missingSources.isEmpty())
         return false;
 
     m_dialog = new QDialog();
@@ -263,9 +275,13 @@ bool DocumentChecker::hasErrorInClips()
         if (!m_ui.infoLabel->text().isEmpty()) m_ui.infoLabel->setText(m_ui.infoLabel->text() + ". ");
         m_ui.infoLabel->setText(m_ui.infoLabel->text() + i18n("Missing proxies will be recreated after opening."));
     }
+    if (missingSources.count() > 0) {
+        if (!m_ui.infoLabel->text().isEmpty()) m_ui.infoLabel->setText(m_ui.infoLabel->text() + ". ");
+        m_ui.infoLabel->setText(m_ui.infoLabel->text() + i18np("The project file contains a missing clip, you can still work with its proxy.", "The project file contains missing clips, you can still work with their proxies.", missingSources.count()));
+    }
 
     m_ui.removeSelected->setEnabled(!m_missingClips.isEmpty());
-    m_ui.recursiveSearch->setEnabled(!m_missingClips.isEmpty() || !missingLumas.isEmpty());
+    m_ui.recursiveSearch->setEnabled(!m_missingClips.isEmpty() || !missingLumas.isEmpty() || !missingSources.isEmpty());
     m_ui.usePlaceholders->setEnabled(!m_missingClips.isEmpty());
     m_ui.fixDuration->setEnabled(!wrongDurationClips.isEmpty());
 
@@ -310,21 +326,24 @@ bool DocumentChecker::hasErrorInClips()
         item->setToolTip(0, i18n("Duration mismatch"));
     }
 
-    if (missingProxies.count() > 0) {
+    // Check missing proxies
+    max = missingProxies.count();
+    if (max > 0) {
         QTreeWidgetItem *item = new QTreeWidgetItem(m_ui.treeWidget, QStringList() << i18n("Proxy clip"));
         item->setIcon(0, KIcon("dialog-warning"));
-        item->setText(1, i18n("%1 missing proxy clips, will be recreated on project opening", missingProxies.count()));
+        item->setText(1, i18n("%1 missing proxy clips, will be recreated on project opening", max));
         item->setData(0, hashRole, e.attribute("file_hash"));
         item->setData(0, statusRole, PROXYMISSING);
         item->setToolTip(0, i18n("Missing proxy"));
     }
 
-    max = missingProxies.count();
     for (int i = 0; i < max; i++) {
         e = missingProxies.at(i).toElement();
         QString clipType;
         QString realPath = e.attribute("resource");
         QString id = e.attribute("id");
+        // Tell Kdenlive to recreate proxy
+        e.setAttribute("_replaceproxy", "1");
         // Replace proxy url with real clip in MLT producers
         QDomNodeList properties;
         QDomElement mltProd;
@@ -356,7 +375,42 @@ bool DocumentChecker::hasErrorInClips()
         }
     }
     
-    if (missingProxies.count() > 0) {
+    if (max > 0) {
+        // original doc was modified
+        QDomElement infoXml = m_doc.elementsByTagName("kdenlivedoc").at(0).toElement();
+        infoXml.setAttribute("modified", "1");
+    }
+    
+    // Check clips with available proxies but missing original source clips
+    max = missingSources.count();
+    if (max > 0) {
+        QTreeWidgetItem *item = new QTreeWidgetItem(m_ui.treeWidget, QStringList() << i18n("Source clip"));
+        item->setIcon(0, KIcon("dialog-warning"));
+        item->setText(1, i18n("%1 missing source clips, you can only use the proxies", max));
+        item->setData(0, hashRole, e.attribute("file_hash"));
+        item->setData(0, statusRole, SOURCEMISSING);
+        item->setToolTip(0, i18n("Missing source clip"));
+        for (int i = 0; i < max; i++) {
+            e = missingSources.at(i).toElement();
+            QString clipType;
+            QString realPath = e.attribute("resource");
+            QString id = e.attribute("id");
+            // Tell Kdenlive the source is missing
+            e.setAttribute("_missingsource", "1");
+            QTreeWidgetItem *subitem = new QTreeWidgetItem(item, QStringList() << i18n("Source clip"));
+            kDebug()<<"// Adding missing source clip: "<<realPath;
+            subitem->setIcon(0, KIcon("dialog-close"));
+            subitem->setText(1, realPath);
+            subitem->setData(0, hashRole, e.attribute("file_hash"));
+            subitem->setData(0, sizeRole, e.attribute("file_size"));
+            subitem->setData(0, statusRole, CLIPMISSING);
+            int t = e.attribute("type").toInt();
+            subitem->setData(0, typeRole, t);
+            subitem->setData(0, idRole, id);
+        }
+    }
+    
+    if (max > 0) {
         // original doc was modified
         QDomElement infoXml = m_doc.elementsByTagName("kdenlivedoc").at(0).toElement();
         infoXml.setAttribute("modified", "1");
@@ -415,7 +469,20 @@ void DocumentChecker::slotSearchClips()
     QTreeWidgetItem *child = m_ui.treeWidget->topLevelItem(ix);
     QDir searchDir(newpath);
     while (child) {
-        if (child->data(0, statusRole).toInt() == CLIPMISSING) {
+        if (child->data(0, statusRole).toInt() == SOURCEMISSING) {
+            for (int j = 0; j < child->childCount(); j++) {
+                QTreeWidgetItem *subchild = child->child(j);
+                QString clipPath = searchFileRecursively(searchDir, subchild->data(0, sizeRole).toString(), subchild->data(0, hashRole).toString());
+                if (!clipPath.isEmpty()) {
+                    fixed = true;
+                    
+                    subchild->setText(1, clipPath);
+                    subchild->setIcon(0, KIcon("dialog-ok"));
+                    subchild->setData(0, statusRole, CLIPOK);
+                }
+            }
+        }
+        else if (child->data(0, statusRole).toInt() == CLIPMISSING) {
             QString clipPath = searchFileRecursively(searchDir, child->data(0, sizeRole).toString(), child->data(0, hashRole).toString());
             if (!clipPath.isEmpty()) {
                 fixed = true;
@@ -541,7 +608,7 @@ QString DocumentChecker::searchFileRecursively(const QDir &dir, const QString &m
 void DocumentChecker::slotEditItem(QTreeWidgetItem *item, int)
 {
     int t = item->data(0, typeRole).toInt();
-    if (t == TITLE_FONT_ELEMENT) return;
+    if (t == TITLE_FONT_ELEMENT || t == UNKNOWN) return;
     //|| t == TITLE_IMAGE_ELEMENT) {
 
     KUrl url = KUrlRequesterDialog::getUrl(item->text(1), m_dialog, i18n("Enter new location for file"));
@@ -565,10 +632,8 @@ void DocumentChecker::slotEditItem(QTreeWidgetItem *item, int)
 
 void DocumentChecker::acceptDialog()
 {
-    QDomElement e, property;
     QDomNodeList producers = m_doc.elementsByTagName("producer");
     QDomNodeList infoproducers = m_doc.elementsByTagName("kdenlive_producer");
-    QDomNodeList properties;
     int ix = 0;
 
     // prepare transitions
@@ -579,99 +644,110 @@ void DocumentChecker::acceptDialog()
 
     QTreeWidgetItem *child = m_ui.treeWidget->topLevelItem(ix);
     while (child) {
-        int t = child->data(0, typeRole).toInt();
-        if (child->data(0, statusRole).toInt() == CLIPOK) {
-            QString id = child->data(0, idRole).toString();
-            if (t == TITLE_IMAGE_ELEMENT) {
-                // edit images embedded in titles
-                for (int i = 0; i < infoproducers.count(); i++) {
-                    e = infoproducers.item(i).toElement();
-                    if (e.attribute("id") == id) {
-                        // Fix clip
-                        QString xml = e.attribute("xmldata");
-                        xml.replace(child->data(0, typeOriginalResource).toString(), child->text(1));
-                        e.setAttribute("xmldata", xml);
-                        break;
-                    }
-                }
-                for (int i = 0; i < producers.count(); i++) {
-                    e = producers.item(i).toElement();
-                    if (e.attribute("id").section('_', 0, 0) == id) {
-                        // Fix clip
-                        properties = e.childNodes();
-                        for (int j = 0; j < properties.count(); ++j) {
-                            property = properties.item(j).toElement();
-                            if (property.attribute("name") == "xmldata") {
-                                QString xml = property.firstChild().nodeValue();
-                                xml.replace(child->data(0, typeOriginalResource).toString(), child->text(1));
-                                property.firstChild().setNodeValue(xml);
-                                break;
-                            }
-                        }
-                    }
-                }
-            } else {
-                // edit clip url
-                for (int i = 0; i < infoproducers.count(); i++) {
-                    e = infoproducers.item(i).toElement();
-                    if (e.attribute("id") == id) {
-                        // Fix clip
-                        e.setAttribute("resource", child->text(1));
-                        e.setAttribute("name", KUrl(child->text(1)).fileName());
-                        break;
-                    }
+        if (child->data(0, statusRole).toInt() == SOURCEMISSING) {
+            for (int j = 0; j < child->childCount(); j++) {
+                fixClipItem(child->child(j), producers, infoproducers, trans);
+            }
+        }
+        else fixClipItem(child, producers, infoproducers, trans);
+        ix++;
+        child = m_ui.treeWidget->topLevelItem(ix);
+    }
+    //QDialog::accept();
+}
+
+void DocumentChecker::fixClipItem(QTreeWidgetItem *child, QDomNodeList producers, QDomNodeList infoproducers, QDomNodeList trans)
+{
+    QDomElement e, property;
+    QDomNodeList properties;
+    int t = child->data(0, typeRole).toInt();
+    if (child->data(0, statusRole).toInt() == CLIPOK) {
+        QString id = child->data(0, idRole).toString();
+        if (t == TITLE_IMAGE_ELEMENT) {
+            // edit images embedded in titles
+            for (int i = 0; i < infoproducers.count(); i++) {
+                e = infoproducers.item(i).toElement();
+                if (e.attribute("id") == id) {
+                    // Fix clip
+                    QString xml = e.attribute("xmldata");
+                    xml.replace(child->data(0, typeOriginalResource).toString(), child->text(1));
+                    e.setAttribute("xmldata", xml);
+                    break;
                 }
-                for (int i = 0; i < producers.count(); i++) {
-                    e = producers.item(i).toElement();
-                    if (e.attribute("id").section('_', 0, 0) == id || e.attribute("id").section(':', 1, 1) == id) {
-                        // Fix clip
-                        properties = e.childNodes();
-                        for (int j = 0; j < properties.count(); ++j) {
-                            property = properties.item(j).toElement();
-                            if (property.attribute("name") == "resource") {
-                                QString resource = property.firstChild().nodeValue();
-                                if (resource.contains(QRegExp("\\?[0-9]+\\.[0-9]+(&amp;strobe=[0-9]+)?$")))
-                                    property.firstChild().setNodeValue(child->text(1) + '?' + resource.section('?', -1));
-                                else
-                                    property.firstChild().setNodeValue(child->text(1));
-                                break;
-                            }
+            }
+            for (int i = 0; i < producers.count(); i++) {
+                e = producers.item(i).toElement();
+                if (e.attribute("id").section('_', 0, 0) == id) {
+                    // Fix clip
+                    properties = e.childNodes();
+                    for (int j = 0; j < properties.count(); ++j) {
+                        property = properties.item(j).toElement();
+                        if (property.attribute("name") == "xmldata") {
+                            QString xml = property.firstChild().nodeValue();
+                            xml.replace(child->data(0, typeOriginalResource).toString(), child->text(1));
+                            property.firstChild().setNodeValue(xml);
+                            break;
                         }
                     }
                 }
             }
-        } else if (child->data(0, statusRole).toInt() == CLIPPLACEHOLDER && t != TITLE_FONT_ELEMENT && t != TITLE_IMAGE_ELEMENT) {
-            QString id = child->data(0, idRole).toString();
+        } else {
+            // edit clip url
             for (int i = 0; i < infoproducers.count(); i++) {
                 e = infoproducers.item(i).toElement();
                 if (e.attribute("id") == id) {
                     // Fix clip
-                    e.setAttribute("placeholder", '1');
+                    e.setAttribute("resource", child->text(1));
+                    e.setAttribute("name", KUrl(child->text(1)).fileName());
+                    e.removeAttribute("_missingsource");
                     break;
                 }
             }
-        } else if (child->data(0, statusRole).toInt() == LUMAOK) {
-            for (int i = 0; i < trans.count(); i++) {
-                QString luma = getProperty(trans.at(i).toElement(), "luma");
-                
-                kDebug() << "luma: " << luma;
-                if (!luma.isEmpty() && luma == child->data(0, idRole).toString()) {
-                    setProperty(trans.at(i).toElement(), "luma", child->text(1));
-                    kDebug() << "replace with; " << child->text(1);
+            for (int i = 0; i < producers.count(); i++) {
+                e = producers.item(i).toElement();
+                if (e.attribute("id").section('_', 0, 0) == id || e.attribute("id").section(':', 1, 1) == id) {
+                    // Fix clip
+                    properties = e.childNodes();
+                    for (int j = 0; j < properties.count(); ++j) {
+                        property = properties.item(j).toElement();
+                        if (property.attribute("name") == "resource") {
+                            QString resource = property.firstChild().nodeValue();
+                            if (resource.contains(QRegExp("\\?[0-9]+\\.[0-9]+(&amp;strobe=[0-9]+)?$")))
+                                property.firstChild().setNodeValue(child->text(1) + '?' + resource.section('?', -1));
+                            else
+                                property.firstChild().setNodeValue(child->text(1));
+                            break;
+                        }
+                    }
                 }
             }
-        } else if (child->data(0, statusRole).toInt() == LUMAMISSING) {
-            for (int i = 0; i < trans.count(); i++) {
-                QString luma = getProperty(trans.at(i).toElement(), "luma");
-                if (!luma.isEmpty() && luma == child->data(0, idRole).toString()) {
-                    setProperty(trans.at(i).toElement(), "luma", QString());
-                }
+        }
+    } else if (child->data(0, statusRole).toInt() == CLIPPLACEHOLDER && t != TITLE_FONT_ELEMENT && t != TITLE_IMAGE_ELEMENT) {
+        QString id = child->data(0, idRole).toString();
+        for (int i = 0; i < infoproducers.count(); i++) {
+            e = infoproducers.item(i).toElement();
+            if (e.attribute("id") == id) {
+                // Fix clip
+                e.setAttribute("placeholder", '1');
+                break;
+            }
+        }
+    } else if (child->data(0, statusRole).toInt() == LUMAOK) {
+        for (int i = 0; i < trans.count(); i++) {
+            QString luma = getProperty(trans.at(i).toElement(), "luma");
+            if (!luma.isEmpty() && luma == child->data(0, idRole).toString()) {
+                setProperty(trans.at(i).toElement(), "luma", child->text(1));
+                kDebug() << "replace with; " << child->text(1);
+            }
+        }
+    } else if (child->data(0, statusRole).toInt() == LUMAMISSING) {
+        for (int i = 0; i < trans.count(); i++) {
+            QString luma = getProperty(trans.at(i).toElement(), "luma");
+            if (!luma.isEmpty() && luma == child->data(0, idRole).toString()) {
+                setProperty(trans.at(i).toElement(), "luma", QString());
             }
         }
-        ix++;
-        child = m_ui.treeWidget->topLevelItem(ix);
     }
-    //QDialog::accept();
 }
 
 void DocumentChecker::slotPlaceholders()
index 90be9360487c3462ce1a23a986213a5c31807116..58a23db0ce905ffd830661fc4aa4296df516f812 100644 (file)
@@ -66,6 +66,8 @@ private:
     QList <QDomElement> m_missingClips;
     QStringList m_safeImages;
     QStringList m_safeFonts;
+    
+    void fixClipItem(QTreeWidgetItem *child, QDomNodeList producers, QDomNodeList infoproducers, QDomNodeList trans);
 };
 
 
index a31c18a841cf29688b6d1b06a38267fdf5c709fb..898bd456e5784780f42bad7021d93e9d934ac761 100644 (file)
@@ -27,7 +27,6 @@
 #include <KMessageBox>
 #include <KApplication>
 #include <KLocale>
-#include <KUrl>
 #include <KStandardDirs>
 
 #include <QFile>
 
 #include <mlt++/Mlt.h>
 
-#include "locale.h"
+#include <locale>
 
 
-DocumentValidator::DocumentValidator(QDomDocument doc):
+DocumentValidator::DocumentValidator(QDomDocument doc, KUrl documentUrl):
         m_doc(doc),
+        m_url(documentUrl),
         m_modified(false)
 {}
 
@@ -57,15 +57,40 @@ bool DocumentValidator::validate(const double currentVersion)
     // Check if we're validating a Kdenlive project
     if (kdenliveDoc.isNull())
         return false;
+    
+    QString rootDir = mlt.attribute("root");
+    if (rootDir == "$CURRENTPATH") {
+        // The document was extracted from a Kdenlive archived project, fix root directory$
+        QString playlist = m_doc.toString();
+        playlist.replace("$CURRENTPATH", m_url.directory(KUrl::IgnoreTrailingSlash));
+        m_doc.setContent(playlist);
+        mlt = m_doc.firstChildElement("mlt");
+        kdenliveDoc = mlt.firstChildElement("kdenlivedoc");
+    }
 
     // Previous MLT / Kdenlive versions used C locale by default
     QLocale documentLocale = QLocale::c();
     
     if (mlt.hasAttribute("LC_NUMERIC")) {
-        // Set locale for the document
-        // WARNING: what should be done in case the locale does not exist on the system?
-        setlocale(LC_NUMERIC, mlt.attribute("LC_NUMERIC").toUtf8().constData());
+        // Set locale for the document        
+        QString newLocale = setlocale(LC_NUMERIC, mlt.attribute("LC_NUMERIC").toUtf8().constData());
         documentLocale = QLocale(mlt.attribute("LC_NUMERIC"));
+
+        // Make sure Qt locale and C++ locale have the same numeric separator, might not be the case
+        // With some locales since C++ and Qt use a different database for locales
+        char *separator = localeconv()->decimal_point;
+        if (separator != documentLocale.decimalPoint()) {
+            if (newLocale.isEmpty()) {
+                // Requested locale not available, ask for install
+                KMessageBox::sorry(kapp->activeWindow(), i18n("The document was created in \"%1\" locale, which is not installed on your system. Please install that language pack. Until then, Kdenlive might not be able to correctly open the document.", mlt.attribute("LC_NUMERIC")));
+                
+            }
+            else KMessageBox::sorry(kapp->activeWindow(), i18n("There is a locale conflict on your system. The document uses locale %1 which uses a \"%2\" as numeric separator (in system libraries) but Qt expects \"%3\". You might not be able to correctly open the project.", mlt.attribute("LC_NUMERIC"), separator, documentLocale.decimalPoint()));
+            kDebug()<<"------\n!!! system locale is not similar to Qt's locale... be prepared for bugs!!!\n------";
+            // HACK: There is a locale conflict, so set locale to at least have correct decimal point
+            if (strncmp(separator, ".", 1) == 0) documentLocale = QLocale::c();
+            else if (strncmp(separator, ",", 1) == 0) documentLocale = QLocale("fr_FR.UTF-8");
+        }
     }
     
     documentLocale.setNumberOptions(QLocale::OmitGroupSeparator);
index 5708f5fcae38ec466b7fbbe538aac399ec8620c1..70766ed5726be71d420ecbc22ad71c8f9a0f4e74 100644 (file)
 #include <QDomDocument>
 #include <QColor>
 
-class QScriptValue;
+#include <KUrl>
 
+class QScriptValue;
 
 class DocumentValidator
 {
 
 public:
-    DocumentValidator(QDomDocument doc);
+    DocumentValidator(QDomDocument doc, KUrl documentUrl);
     bool isProject() const;
     bool validate(const double currentVersion);
     bool isModified() const;
 
 private:
     QDomDocument m_doc;
+    KUrl m_url;
     bool m_modified;
     bool upgrade(double version, const double currentVersion);
     QStringList getInfoFromEffectName(const QString oldName);
index 807e1803fee4c3a567ba828f3e630d87b90e4f14..52464b3f6a10bfa296046876f91dcc283923e024 100644 (file)
@@ -148,7 +148,7 @@ void DvdWizardChapters::setVobFiles(bool isPal, bool isWide, const QStringList &
     if (isWide) profile.append("_wide");
     m_manager->resetProfiles(m_tc);
     if (m_monitor == NULL) {
-        m_monitor = new Monitor("chapter", m_manager, profile, this);
+        m_monitor = new Monitor(Kdenlive::dvdMonitor, m_manager, profile, this);
         //m_monitor->start();
         QVBoxLayout *vbox = new QVBoxLayout;
         vbox->addWidget(m_monitor);
index fafd97553ad30bed357c067d20eb934d1bcc834b..def04eca0f3186d1d7d4f9e7a6a8489dd36f0143 100644 (file)
@@ -35,7 +35,7 @@ EffectsListView::EffectsListView(QWidget *parent) :
 {
     setupUi(this);
 
-    QString style = "QTreeView::branch:has-siblings:!adjoins-item{border-image:none;border:0px} \
+    QString styleSheet = "QTreeView::branch:has-siblings:!adjoins-item{border-image:none;border:0px} \
     QTreeView::branch:has-siblings:adjoins-item {border-image: none;border:0px}      \
     QTreeView::branch:!has-children:!has-siblings:adjoins-item {border-image: none;border:0px} \
     QTreeView::branch:has-children:!has-siblings:closed,QTreeView::branch:closed:has-children:has-siblings {   \
@@ -45,14 +45,18 @@ EffectsListView::EffectsListView(QWidget *parent) :
 
     QMenu *contextMenu = new QMenu(this);
     m_effectsList = new EffectsListWidget(contextMenu);
-    m_effectsList->setStyleSheet(style);
+    m_effectsList->setStyleSheet(styleSheet);
     QVBoxLayout *lyr = new QVBoxLayout(effectlistframe);
     lyr->addWidget(m_effectsList);
     lyr->setContentsMargins(0, 0, 0, 0);
     search_effect->setTreeWidget(m_effectsList);
     search_effect->setToolTip(i18n("Search in the effect list"));
+    
+    int size = style()->pixelMetric(QStyle::PM_SmallIconSize);
+    QSize iconSize(size, size);
     buttonInfo->setIcon(KIcon("help-about"));
     buttonInfo->setToolTip(i18n("Show/Hide the effect description"));
+    buttonInfo->setIconSize(iconSize);
     setFocusPolicy(Qt::StrongFocus);
     setFocusProxy(search_effect);
     m_effectsList->setFocusProxy(search_effect);
index e9a260dc0089611d3944b678120b1b7e719331bc..d4459627e6110dac903d0a3ab876ea18614bec4d 100644 (file)
@@ -164,12 +164,30 @@ void EffectsListWidget::initList(QMenu *effectsMenu, KActionCategory *effectActi
     sortByColumn(0, Qt::AscendingOrder);
 
     // populate effects menu
+    QMenu *sub1 = NULL;
+    QMenu *sub2 = NULL;
+    QMenu *sub3 = NULL;
+    QMenu *sub4 = NULL;
     for (int i = 0; i < topLevelItemCount(); i++) {
         if (!topLevelItem(i)->childCount())
             continue;
         QMenu *sub = new QMenu(topLevelItem(i)->text(0), effectsMenu);
         effectsMenu->addMenu(sub);
-        for (int j = 0; j < topLevelItem(i)->childCount(); j++) {
+        int effectsInCategory = topLevelItem(i)->childCount();
+        bool hasSubCategories = false;
+        if (effectsInCategory > 60) {
+            // create subcategories if there are too many effects
+            hasSubCategories = true;
+            sub1 = new QMenu(i18nc("menu name for effects names between these 2 letters", "0 - F"), sub);
+            sub->addMenu(sub1);
+            sub2 = new QMenu(i18nc("menu name for effects names between these 2 letters", "G - L"), sub);
+            sub->addMenu(sub2);
+            sub3 = new QMenu(i18nc("menu name for effects names between these 2 letters", "M - R"), sub);
+            sub->addMenu(sub3);
+            sub4 = new QMenu(i18nc("menu name for effects names between these 2 letters", "S - Z"), sub);
+            sub->addMenu(sub4);
+        }
+        for (int j = 0; j < effectsInCategory; j++) {
                 QTreeWidgetItem *item = topLevelItem(i)->child(j);
                 KAction *a = new KAction(KIcon(item->icon(0)), item->text(0), sub);
                 QStringList data = item->data(0, IdRole).toStringList();
@@ -177,7 +195,26 @@ void EffectsListWidget::initList(QMenu *effectsMenu, KActionCategory *effectActi
                 if (id.isEmpty()) id = data.at(0);
                 a->setData(data);
                 a->setIconVisibleInMenu(false);
-                sub->addAction(a);
+                if (hasSubCategories) {
+                    // put action in sub category
+                    QRegExp rx("^[s-z].+");
+                    if (rx.exactMatch(item->text(0).toLower())) {
+                        sub4->addAction(a);
+                    } else {
+                        rx.setPattern("^[m-r].+");
+                        if (rx.exactMatch(item->text(0).toLower())) {
+                            sub3->addAction(a);
+                        }
+                        else {
+                            rx.setPattern("^[g-l].+");
+                            if (rx.exactMatch(item->text(0).toLower())) {
+                                sub2->addAction(a);
+                            }
+                            else sub1->addAction(a);
+                        }
+                    }
+                }
+                else sub->addAction(a);
                 effectActions->addAction("video_effect_" + id, a);
         }
     }
index 2a9566795d7bd50f28b933843867ecb6ad5b7039..2f3d1d8d16f61bd45ba771281832b3eb0d7d267b 100644 (file)
@@ -20,6 +20,8 @@
 #include "ui_boolval_ui.h"
 #include "ui_wipeval_ui.h"
 #include "ui_urlval_ui.h"
+#include "ui_keywordval_ui.h"
+#include "ui_fontval_ui.h"
 #include "complexparameter.h"
 #include "geometryval.h"
 #include "positionedit.h"
@@ -70,6 +72,14 @@ class Urlval: public QWidget, public Ui::Urlval_UI
 {
 };
 
+class Keywordval: public QWidget, public Ui::Keywordval_UI
+{
+};
+
+class Fontval: public QWidget, public Ui::Fontval_UI
+{
+};
+
 QMap<QString, QImage> EffectStackEdit::iconCache;
 
 EffectStackEdit::EffectStackEdit(Monitor *monitor, QWidget *parent) :
@@ -252,7 +262,6 @@ void EffectStackEdit::transferParamDesc(const QDomElement &d, ItemInfo info, boo
         QString comment;
         if (!commentElem.isNull())
             comment = i18n(commentElem.text().toUtf8().data());
-        QWidget * toFillin = new QWidget(m_baseWidget);
         QString value = pa.attribute("value").isNull() ?
                         pa.attribute("default") : pa.attribute("value");
 
@@ -279,7 +288,9 @@ void EffectStackEdit::transferParamDesc(const QDomElement &d, ItemInfo info, boo
             connect(this, SIGNAL(showComments(bool)), doubleparam, SLOT(slotShowComment(bool)));
         } else if (type == "list") {
             Listval *lsval = new Listval;
+            QWidget * toFillin = new QWidget(m_baseWidget);
             lsval->setupUi(toFillin);
+            m_vbox->addWidget(toFillin);
             QStringList listitems = pa.attribute("paramlist").split(';');
             if (listitems.count() == 1) {
                 // probably custom effect created before change to ';' as separator
@@ -317,7 +328,9 @@ void EffectStackEdit::transferParamDesc(const QDomElement &d, ItemInfo info, boo
             m_uiItems.append(lsval);
         } else if (type == "bool") {
             Boolval *bval = new Boolval;
+            QWidget * toFillin = new QWidget(m_baseWidget);
             bval->setupUi(toFillin);
+            m_vbox->addWidget(toFillin);
             bval->checkBox->setCheckState(value == "0" ? Qt::Unchecked : Qt::Checked);
             bval->name->setText(paramName);
             bval->labelComment->setText(comment);
@@ -391,10 +404,8 @@ void EffectStackEdit::transferParamDesc(const QDomElement &d, ItemInfo info, boo
                 m_keyframeEditor->addParameter(pa);
             }
         } else if (type == "color") {
-            if (value.startsWith('#'))
-                value = value.replace('#', "0x");
-            bool ok;
-            ChooseColorWidget *choosecolor = new ChooseColorWidget(paramName, QColor(value.toUInt(&ok, 16)), this);
+            ChooseColorWidget *choosecolor = new ChooseColorWidget(paramName, value, this);
+            choosecolor->setAlphaChannelEnabled(pa.attribute("alpha") == "1");
             m_vbox->addWidget(choosecolor);
             m_valueItems[paramName] = choosecolor;
             connect(choosecolor, SIGNAL(displayMessage(const QString&, int)), this, SIGNAL(displayMessage(const QString&, int)));
@@ -471,7 +482,9 @@ void EffectStackEdit::transferParamDesc(const QDomElement &d, ItemInfo info, boo
 #endif
         } else if (type == "wipe") {
             Wipeval *wpval = new Wipeval;
+            QWidget * toFillin = new QWidget(m_baseWidget);
             wpval->setupUi(toFillin);
+            m_vbox->addWidget(toFillin);
             wipeInfo w = getWipeInfo(value);
             switch (w.start) {
             case UP:
@@ -526,7 +539,9 @@ void EffectStackEdit::transferParamDesc(const QDomElement &d, ItemInfo info, boo
             m_uiItems.append(wpval);
         } else if (type == "url") {
             Urlval *cval = new Urlval;
+            QWidget * toFillin = new QWidget(m_baseWidget);
             cval->setupUi(toFillin);
+            m_vbox->addWidget(toFillin);
             cval->label->setText(paramName);
             cval->urlwidget->fileDialog()->setFilter(ProjectList::getExtensions());
             m_valueItems[paramName] = cval;
@@ -534,13 +549,51 @@ void EffectStackEdit::transferParamDesc(const QDomElement &d, ItemInfo info, boo
             connect(cval->urlwidget, SIGNAL(returnPressed()) , this, SLOT(collectAllParameters()));
             connect(cval->urlwidget, SIGNAL(urlSelected(const KUrl&)) , this, SLOT(collectAllParameters()));
             m_uiItems.append(cval);
-        } else {
-            delete toFillin;
-            toFillin = NULL;
-        }
-
-        if (toFillin)
+        } else if (type == "keywords") {
+            Keywordval* kval = new Keywordval;
+            QWidget * toFillin = new QWidget(m_baseWidget);
+            kval->setupUi(toFillin);
             m_vbox->addWidget(toFillin);
+            kval->label->setText(paramName);
+            kval->lineeditwidget->setText(value);
+            QDomElement klistelem = pa.firstChildElement("keywords");
+            QDomElement kdisplaylistelem = pa.firstChildElement("keywordsdisplay");
+            QStringList keywordlist;
+            QStringList keyworddisplaylist;
+            if (!klistelem.isNull()) {
+                keywordlist = klistelem.text().split(';');
+                keyworddisplaylist = i18n(kdisplaylistelem.text().toUtf8().data()).split(';');
+            }
+            if (keyworddisplaylist.count() != keywordlist.count()) {
+                keyworddisplaylist = keywordlist;
+            }
+            for (int i = 0; i < keywordlist.count(); i++) {
+                kval->comboboxwidget->addItem(keyworddisplaylist.at(i), keywordlist.at(i));
+            }
+            // Add disabled user prompt at index 0
+            kval->comboboxwidget->insertItem(0, i18n("<select a keyword>"), "");
+            kval->comboboxwidget->model()->setData( kval->comboboxwidget->model()->index(0,0), QVariant(Qt::NoItemFlags), Qt::UserRole -1);
+            kval->comboboxwidget->setCurrentIndex(0);
+            m_valueItems[paramName] = kval;
+            connect(kval->lineeditwidget, SIGNAL(editingFinished()) , this, SLOT(collectAllParameters()));
+            connect(kval->comboboxwidget, SIGNAL(activated (const QString&)), this, SLOT(collectAllParameters()));
+            m_uiItems.append(kval);
+        } else if (type == "fontfamily") {
+            Fontval* fval = new Fontval;
+            QWidget * toFillin = new QWidget(m_baseWidget);
+            fval->setupUi(toFillin);
+            m_vbox->addWidget(toFillin);
+            fval->name->setText(paramName);
+            fval->fontfamilywidget->setCurrentFont(QFont(value));
+            m_valueItems[paramName] = fval;
+            connect(fval->fontfamilywidget, SIGNAL(currentFontChanged(const QFont &)), this, SLOT(collectAllParameters())) ;
+            m_uiItems.append(fval);
+        } else if (type == "filterjob") {
+            QPushButton *button = new QPushButton(paramName, m_baseWidget);
+            m_vbox->addWidget(button);
+            m_valueItems[paramName] = button;
+            connect(button, SIGNAL(pressed()), this, SLOT(slotStartFilterJobAction()));   
+        }
     }
 
     if (stretch)
@@ -685,7 +738,7 @@ void EffectStackEdit::collectAllParameters()
             setValue = box->checkState() == Qt::Checked ? "1" : "0" ;
         } else if (type == "color") {
             ChooseColorWidget *choosecolor = ((ChooseColorWidget*)m_valueItems.value(paramName));
-            setValue = choosecolor->getColor().name();
+            setValue = choosecolor->getColor();
         } else if (type == "complex") {
             ComplexParameter *complex = ((ComplexParameter*)m_valueItems.value(paramName));
             namenode.item(i) = complex->getParamDesc();
@@ -801,6 +854,19 @@ void EffectStackEdit::collectAllParameters()
         } else if (type == "url") {
             KUrlRequester *req = ((Urlval*)m_valueItems.value(paramName))->urlwidget;
             setValue = req->url().path();
+        } else if (type == "keywords"){
+            QLineEdit *line = ((Keywordval*)m_valueItems.value(paramName))->lineeditwidget;
+            QComboBox *combo = ((Keywordval*)m_valueItems.value(paramName))->comboboxwidget;
+            if(combo->currentIndex())
+            {
+                QString comboval = combo->itemData(combo->currentIndex()).toString();
+                line->insert(comboval);
+                combo->setCurrentIndex(0);
+            }
+            setValue = line->text();
+        } else if (type == "fontfamily") {
+            QFontComboBox* fontfamily = ((Fontval*)m_valueItems.value(paramName))->fontfamilywidget;
+            setValue = fontfamily->currentFont().family();
         }
 
         if (!setValue.isNull())
@@ -836,3 +902,18 @@ void EffectStackEdit::slotSyncEffectsPos(int pos)
 {
     emit syncEffectsPos(pos);
 }
+
+void EffectStackEdit::slotStartFilterJobAction()
+{
+    QDomNodeList namenode = m_params.elementsByTagName("parameter");
+    for (int i = 0; i < namenode.count() ; i++) {
+        QDomElement pa = namenode.item(i).toElement();
+        QString type = pa.attribute("type");
+        if (type == "filterjob") {
+            emit startFilterJob(pa.attribute("filtertag"), pa.attribute("filterparams"), pa.attribute("finalfilter"), pa.attribute("consumer"), pa.attribute("consumerparams"), pa.attribute("wantedproperties"));
+            kDebug()<<" - - -PROPS:\n"<<pa.attribute("filtertag")<<"-"<< pa.attribute("filterparams")<<"-"<< pa.attribute("consumer")<<"-"<< pa.attribute("consumerparams")<<"-"<< pa.attribute("wantedproperties");
+            break;
+        }
+    }
+}
+
index ea41b30ff0125f11edc4f68a1ad9dc6e43a1a52f..73f117ecd709628ac14ff4712bf4ef8827721e68 100644 (file)
@@ -96,6 +96,9 @@ public slots:
 
     /** @brief Pass position changes of the timeline cursor to the effects to keep their local timelines in sync. */
     void slotSyncEffectsPos(int pos);
+    
+private slots:
+    void slotStartFilterJobAction();
 
 signals:
     void parameterChanged(const QDomElement &, const QDomElement &);
@@ -105,6 +108,8 @@ signals:
     void syncEffectsPos(int pos);
     void showComments(bool show);
     void effectStateChanged(bool enabled);
+    /** @brief Start an MLT filter job on this clip. */
+    void startFilterJob(const QString &filterName, const QString &filterParams, const QString &finalFilterName, const QString &consumer, const QString &consumerParams, const QString &properties);
 };
 
 #endif
index 11f09cca007e0fcf5e4b20efcc7a4e1f3f6d65dd..a917ff7e00bf6861c9ddcc1a64781cf917b3a8d5 100644 (file)
@@ -59,19 +59,27 @@ EffectStackView::EffectStackView(Monitor *monitor, QWidget *parent) :
     //m_ui.region_url->fileDialog()->setFilter(ProjectList::getExtensions());
     //m_ui.effectlist->horizontalHeader()->setVisible(false);
     //m_ui.effectlist->verticalHeader()->setVisible(false);
+    int size = style()->pixelMetric(QStyle::PM_SmallIconSize);
+    QSize iconSize(size, size);
 
     m_ui.buttonNew->setIcon(KIcon("document-new"));
     m_ui.buttonNew->setToolTip(i18n("Add new effect"));
+    m_ui.buttonNew->setIconSize(iconSize);
     m_ui.buttonUp->setIcon(KIcon("go-up"));
     m_ui.buttonUp->setToolTip(i18n("Move effect up"));
+    m_ui.buttonUp->setIconSize(iconSize);
     m_ui.buttonDown->setIcon(KIcon("go-down"));
     m_ui.buttonDown->setToolTip(i18n("Move effect down"));
+    m_ui.buttonDown->setIconSize(iconSize);
     m_ui.buttonDel->setIcon(KIcon("edit-delete"));
     m_ui.buttonDel->setToolTip(i18n("Delete effect"));
+    m_ui.buttonDel->setIconSize(iconSize);
     m_ui.buttonSave->setIcon(KIcon("document-save"));
     m_ui.buttonSave->setToolTip(i18n("Save effect"));
+    m_ui.buttonSave->setIconSize(iconSize);
     m_ui.buttonReset->setIcon(KIcon("view-refresh"));
     m_ui.buttonReset->setToolTip(i18n("Reset effect"));
+    m_ui.buttonReset->setIconSize(iconSize);
     m_ui.checkAll->setToolTip(i18n("Enable/Disable all effects"));
     m_ui.buttonShowComments->setIcon(KIcon("help-about"));
     m_ui.buttonShowComments->setToolTip(i18n("Show additional information for the parameters"));
@@ -92,9 +100,11 @@ EffectStackView::EffectStackView(Monitor *monitor, QWidget *parent) :
     connect(m_ui.checkAll, SIGNAL(stateChanged(int)), this, SLOT(slotCheckAll(int)));
     connect(m_ui.buttonShowComments, SIGNAL(clicked()), this, SLOT(slotShowComments()));
     connect(m_effectedit, SIGNAL(parameterChanged(const QDomElement &, const QDomElement &)), this , SLOT(slotUpdateEffectParams(const QDomElement &, const QDomElement &)));
+    connect(m_effectedit, SIGNAL(startFilterJob(QString,QString,QString,QString,QString,QString)), this , SLOT(slotStartFilterJob(QString,QString,QString,QString,QString,QString)));
     connect(m_effectedit, SIGNAL(seekTimeline(int)), this , SLOT(slotSeekTimeline(int)));
     connect(m_effectedit, SIGNAL(displayMessage(const QString&, int)), this, SIGNAL(displayMessage(const QString&, int)));
     connect(m_effectedit, SIGNAL(checkMonitorPosition(int)), this, SLOT(slotCheckMonitorPosition(int)));
+    
     connect(monitor, SIGNAL(renderPosition(int)), this, SLOT(slotRenderPos(int)));
     connect(this, SIGNAL(showComments(bool)), m_effectedit, SIGNAL(showComments(bool)));
     m_effectLists["audio"] = &MainWindow::audioEffects;
@@ -229,17 +239,20 @@ void EffectStackView::slotTrackItemSelected(int ix, const TrackInfo info)
 
 void EffectStackView::slotItemChanged(QListWidgetItem *item)
 {
-    bool disable = true;
-    if (item->checkState() == Qt::Checked) disable = false;
-    m_ui.buttonReset->setEnabled(!disable || !KdenliveSettings::disable_effect_parameters());
+    bool disable = item->checkState() == Qt::Unchecked;
+    int row = m_ui.effectlist->row(item);
     int activeRow = m_ui.effectlist->currentRow();
-    if (activeRow >= 0) {
+
+    if (row == activeRow) {
+        m_ui.buttonReset->setEnabled(!disable || !KdenliveSettings::disable_effect_parameters());
         m_effectedit->updateParameter("disable", QString::number((int) disable));
-        if (m_trackMode)
-            emit changeEffectState(NULL, m_trackindex, activeRow, disable);
-        else
-            emit changeEffectState(m_clipref, -1, activeRow, disable);
     }
+
+    if (m_trackMode)
+        emit changeEffectState(NULL, m_trackindex, row, disable);
+    else
+        emit changeEffectState(m_clipref, -1, row, disable);
+
     slotUpdateCheckAllButton();
 }
 
@@ -528,4 +541,10 @@ void EffectStackView::slotShowComments()
     emit showComments(m_ui.buttonShowComments->isChecked());
 }
 
+void EffectStackView::slotStartFilterJob(const QString&filterName, const QString&filterParams, const QString&finalFilterName, const QString&consumer, const QString&consumerParams, const QString&properties)
+{
+    if (!m_clipref) return;
+    emit startFilterJob(m_clipref->info(), m_clipref->clipProducer(), filterName, filterParams, finalFilterName, consumer, consumerParams, properties);
+}
+
 #include "effectstackview.moc"
index 89055a2360374e03a9e691fa12cbe4c4903e6cb2..c2a4e2bda28866259ccc36d3fd880f394d498f64 100644 (file)
@@ -141,6 +141,9 @@ private slots:
 
     /** @brief Shows/Hides the comment box and emits showComments to notify the parameter widgets to do the same. */
     void slotShowComments();
+    
+    /** @brief Triggers a filter job on this clip. */
+    void slotStartFilterJob(const QString&filterName, const QString&filterParams, const QString&finalFilterName, const QString&consumer, const QString&consumerParams, const QString&properties);
 
 signals:
     void removeEffect(ClipItem*, int, QDomElement);
@@ -161,6 +164,7 @@ signals:
     void updateClipRegion(ClipItem*, int, QString);
     void displayMessage(const QString&, int);
     void showComments(bool show);
+    void startFilterJob(ItemInfo info, const QString &clipId, const QString &filterName, const QString &filterParams, const QString&finalFilterName, const QString &consumer, const QString &consumerParams, const QString &properties);
 };
 
 #endif
index 321ab76fecb8500362922d3e6e92e2aba66512d2..66bc4e983191cb9ef08cf991f6fec3f9ecdc4192 100644 (file)
@@ -70,17 +70,24 @@ GeometryWidget::GeometryWidget(Monitor* monitor, Timecode timecode, int clipPos,
     m_timeline = new KeyframeHelper(m_ui.frameTimeline);
     layout->addWidget(m_timeline);
     layout->setContentsMargins(0, 0, 0, 0);
+    
+    int size = style()->pixelMetric(QStyle::PM_SmallIconSize);
+    QSize iconSize(size, size);
 
     m_ui.buttonPrevious->setIcon(KIcon("media-skip-backward"));
     m_ui.buttonPrevious->setToolTip(i18n("Go to previous keyframe"));
+    m_ui.buttonPrevious->setIconSize(iconSize);
     m_ui.buttonNext->setIcon(KIcon("media-skip-forward"));
     m_ui.buttonNext->setToolTip(i18n("Go to next keyframe"));
+    m_ui.buttonNext->setIconSize(iconSize);
     m_ui.buttonAddDelete->setIcon(KIcon("document-new"));
     m_ui.buttonAddDelete->setToolTip(i18n("Add keyframe"));
+    m_ui.buttonAddDelete->setIconSize(iconSize);
 
     m_ui.buttonSync->setIcon(KIcon("insert-link"));
     m_ui.buttonSync->setToolTip(i18n("Synchronize with timeline cursor"));
     m_ui.buttonSync->setChecked(KdenliveSettings::transitionfollowcursor());
+    m_ui.buttonSync->setIconSize(iconSize);
 
     connect(m_timeline, SIGNAL(positionChanged(int)), this, SLOT(slotPositionChanged(int)));
     connect(m_timeline, SIGNAL(keyframeMoved(int)),   this, SLOT(slotKeyframeMoved(int)));
@@ -566,7 +573,6 @@ void GeometryWidget::slotUpdateGeometry()
             geom->insert(item2);
         }
     }
-    
     emit parameterChanged();
 }
 
index b806a01ceb1c20f26d78a9bb77fbb4f52b09bf1e..2241ec9b552ce0bb0703c61f5d3fb8b9536c1bfa 100644 (file)
@@ -33,7 +33,7 @@
 #include <QTimer>
 #include <QDomDocument>
 
-HeaderTrack::HeaderTrack(int index, TrackInfo info, int height, QWidget *parent) :
+HeaderTrack::HeaderTrack(int index, TrackInfo info, int height, QList <QAction *> actions, QWidget *parent) :
         QWidget(parent),
         m_index(index),
         m_type(info.type),
@@ -88,18 +88,8 @@ HeaderTrack::HeaderTrack(int index, TrackInfo info, int height, QWidget *parent)
         //horizontalSpacer;
     }
 
-    setContextMenuPolicy(Qt::DefaultContextMenu); //Qt::ActionsContextMenu);
-    QAction *insertAction = new QAction(i18n("Insert Track"), this);
-    m_menu.addAction(insertAction);
-    connect(insertAction, SIGNAL(triggered()), this, SLOT(slotAddTrack()));
-
-    QAction *removeAction = new QAction(KIcon("edit-delete"), i18n("Delete Track"), this);
-    m_menu.addAction(removeAction);
-    connect(removeAction, SIGNAL(triggered()), this, SLOT(slotDeleteTrack()));
-
-    QAction *configAction = new QAction(KIcon("configure"), i18n("Configure Track"), this);
-    m_menu.addAction(configAction);
-    connect(configAction, SIGNAL(triggered()), this, SLOT(slotConfigTrack()));
+    setContextMenuPolicy(Qt::ActionsContextMenu);
+    addActions(actions);
 }
 
 /*HeaderTrack::~HeaderTrack()
@@ -129,23 +119,13 @@ void HeaderTrack::mousePressEvent(QMouseEvent * event)
     QWidget::mousePressEvent(event);
 }
 
-// virtual
-void HeaderTrack::contextMenuEvent(QContextMenuEvent * event)
-{
-    if (track_number->hasFocus()) {
-        track_number->clearFocus();
-        return;
-    }
-    m_menu.popup(event->globalPos());
-}
-
 void HeaderTrack::mouseDoubleClickEvent(QMouseEvent* event)
 {
     if (track_number->hasFocus()) {
         track_number->clearFocus();
         return;
     }
-    slotConfigTrack();
+    emit configTrack(m_index);
     QWidget::mouseDoubleClickEvent(event);
 }
 
@@ -248,25 +228,11 @@ void HeaderTrack::slotDeleteTrack()
     QTimer::singleShot(500, this, SLOT(deleteTrack()));
 }
 
-void HeaderTrack::deleteTrack()
-{
-    emit deleteTrack(m_index);
-}
-
-void HeaderTrack::slotAddTrack()
-{
-    emit insertTrack(m_index);
-}
-
 void HeaderTrack::slotRenameTrack()
 {
     if (m_name != track_number->text()) emit renameTrack(m_index, track_number->text());
 }
 
-void HeaderTrack::slotConfigTrack()
-{
-    emit configTrack(m_index);
-}
 
 
 #include "headertrack.moc"
index aa20c3b8a1fbd42a6873f494532bd82c436b6388..8163a9fb9a8d2a2e6f689d8e426e2f0b7c4c2563 100644 (file)
@@ -32,7 +32,7 @@ class HeaderTrack : public QWidget, public Ui::TrackHeader_UI
     Q_OBJECT
 
 public:
-    HeaderTrack(int index, TrackInfo info, int height, QWidget *parent = 0);
+    HeaderTrack(int index, TrackInfo info, int height, QList <QAction *> actions, QWidget *parent = 0);
     //virtual ~HeaderTrack();
     void setLock(bool lock);
     void adjustSize(int height);
@@ -43,7 +43,6 @@ public:
 protected:
     virtual void mousePressEvent(QMouseEvent * event);
     virtual void mouseDoubleClickEvent(QMouseEvent * event);
-    virtual void contextMenuEvent(QContextMenuEvent * event);
     virtual void dropEvent(QDropEvent * event);
     virtual void dragEnterEvent(QDragEnterEvent *event);
 
@@ -51,25 +50,19 @@ private:
     int m_index;
     TRACKTYPE m_type;
     bool m_isSelected;
-    QMenu m_menu;
     QString m_name;
 
 private slots:
     void switchAudio();
     void switchVideo();
     void slotDeleteTrack();
-    void deleteTrack();
-    void slotAddTrack();
     void slotRenameTrack();
-    void slotConfigTrack();
     void switchLock(bool emitSignal = true);
 
 signals:
     void switchTrackAudio(int);
     void switchTrackVideo(int);
     void switchTrackLock(int);
-    void insertTrack(int);
-    void deleteTrack(int);
     void renameTrack(int, QString);
     void selectTrack(int);
     void configTrack(int);
index c290f22b8ecd2cf383983d8d6a899d11c622ae21..66f00539244c45a7630ee189f4df07ed5348d7bd 100644 (file)
@@ -1,36 +1,64 @@
 # KDE Config File
 [Desktop Entry]
 Name=Kdenlive
+Name[ca]=Kdenlive
 Name[cs]=Kdenlive
 Name[da]=Kdenlive
 Name[de]=Kdenlive
+Name[el]=Kdenlive
+Name[es]=Kdenlive
+Name[gl]=Kdenlive
+Name[hu]=Kdenlive
+Name[it]=Kdenlive
+Name[nb]=Kdenlive
 Name[nds]=Kdenlive
 Name[nl]=Kdenlive
+Name[pl]=Kdenlive
 Name[pt]=Kdenlive
 Name[pt_BR]=Kdenlive
+Name[sk]=Kdenlive
 Name[sv]=Kdenlive
 Name[uk]=Kdenlive
 Name[x-test]=xxKdenlivexx
 Name[zh_CN]=Kdenlive
 Name[zh_TW]=Kdenlive
 GenericName=Video Editor
+GenericName[ca]=Editor de vídeo
 GenericName[cs]=Editor videí
 GenericName[da]=Videoredigering
 GenericName[de]=Video-Editor
+GenericName[el]=Επεξεργαστής βίντεο
+GenericName[es]=Editor de video
+GenericName[gl]=Editor de vídeo
+GenericName[hu]=Videoszerkesztő
+GenericName[it]=Editor video
+GenericName[nb]=Videoredigeringsprogram
 GenericName[nl]=Video-bewerker
+GenericName[pl]=Edytor wideo
 GenericName[pt]=Editor de Vídeo
 GenericName[pt_BR]=Editor de Vídeo
+GenericName[sk]=Editor videa
 GenericName[sv]=Videoeditor
 GenericName[uk]=Відеоредактор
 GenericName[x-test]=xxVideo Editorxx
 GenericName[zh_CN]=视频编辑器
 GenericName[zh_TW]=影像編輯器
 Comment=Nonlinear video editor for KDE
+Comment[ca]=Editor de vídeo no lineal per al KDE
+Comment[cs]=Nelineární editor videí pro KDE
 Comment[da]=Ikke-lineær videoredigering til KDE
 Comment[de]=Nichtlinearer Video-Editor für KDE
+Comment[el]=Μη γραμμικός επεξεργαστής βίντεο για το KDE
+Comment[es]=Editor no lineal de video para KDE
+Comment[gl]=Editor de vídeo non linear para KDE
+Comment[hu]=Nemlineáris videoszerkesztő a KDE-hez
+Comment[it]=Editor di video non lineare per KDE
+Comment[nb]=Videoredigeringsprogram for KDE med dataklipping
 Comment[nl]=Niet-lineaire video-bewerker voor KDE
+Comment[pl]=Nieliniowy edytor wideo dla KDE
 Comment[pt]=Editor de vídeo não-linear para o KDE
 Comment[pt_BR]=Editor de vídeo não-linear para o KDE
+Comment[sk]=Nelineárny editor videa pre KDE
 Comment[sv]=Icke-linjär videoeditor för KDE
 Comment[uk]=Нелінійний редактор відео для KDE
 Comment[x-test]=xxNonlinear video editor for KDExx
index cb9ce1fc7ceb6ebe0c0c8b75edff987a56c43204..5d96f6c6f08aed41ab062b6e96aecb5a33643c43 100644 (file)
@@ -1,13 +1,22 @@
 [Global]
 IconName=kdenlive
 Comment=Kdenlive
+Comment[ca]=Kdenlive
 Comment[cs]=Kdenlive
 Comment[da]=Kdenlive
 Comment[de]=Kdenlive
+Comment[el]=Kdenlive
+Comment[es]=Kdenlive
+Comment[gl]=Kdenlive
+Comment[hu]=Kdenlive
+Comment[it]=Kdenlive
+Comment[nb]=Kdenlive
 Comment[nds]=Kdenlive
 Comment[nl]=Kdenlive
+Comment[pl]=Kdenlive
 Comment[pt]=Kdenlive
 Comment[pt_BR]=Kdenlive
+Comment[sk]=Kdenlive
 Comment[sv]=Kdenlive
 Comment[uk]=Kdenlive
 Comment[x-test]=xxKdenlivexx
@@ -16,9 +25,18 @@ Comment[zh_TW]=Kdenlive
 
 [Event/RenderFinished]
 Name=Rendering finished
+Name[ca]=Ha acabat la renderització
 Name[cs]=Renderování bylo dokončeno
 Name[da]=Rendering gennemført
+Name[de]=Rendern fertiggestellt
+Name[el]=Η αποτύπωση ολοκληρώθηκε
+Name[es]=Procesamiento finalizado
+Name[gl]=Renderizado finalizado
+Name[hu]=A renderelés befejeződött
+Name[it]=Esportazione terminata
+Name[nb]=Opptegning avsluttet
 Name[nl]=Weergave uitwerken beëindigd
+Name[pl]=Ukończono renderowanie
 Name[pt]=A geração terminou
 Name[pt_BR]=A renderização terminou
 Name[sv]=Återgivning klar
@@ -27,9 +45,18 @@ Name[x-test]=xxRendering finishedxx
 Name[zh_CN]=渲染结束
 Name[zh_TW]=已完成導出
 Comment=Rendering is over
+Comment[ca]=La renderització ja ha acabat
 Comment[cs]=Renderování je hotové
 Comment[da]=Renderingen er slut
+Comment[de]=Das Rendern ist beendet
+Comment[el]=Η αποτύπωση τελείωσε
+Comment[es]=El procesamiento ha finalizado
+Comment[gl]=Rematou o renderizado
+Comment[hu]=A renderelésnek vége
+Comment[it]=L'esportazione è terminata
+Comment[nb]=Ferdig med opptegning
 Comment[nl]=Weergave uitwerken is gereed
+Comment[pl]=Ukończono zostało zakończone
 Comment[pt]=A geração terminou
 Comment[pt_BR]=A renderização foi terminada
 Comment[sv]=Återgivningen är gjord
@@ -41,9 +68,18 @@ Action=Popup
 
 [Event/RenderStarted]
 Name=Rendering started
+Name[ca]=Ha començat la renderització
 Name[cs]=Renderování začalo
 Name[da]=Rendering påbegyndt
+Name[de]=Rendern wurde gestartet
+Name[el]=Η αποτύπωση ξεκίνησε
+Name[es]=Procesamiento inciado
+Name[gl]=Iniciado o renderizado
+Name[hu]=A renderelés elkezdődött
+Name[it]=Esportazione avviata
+Name[nb]=Opptegning påbegynt
 Name[nl]=Weergave uitwerken begonnen
+Name[pl]=Rozpoczęto renderowanie
 Name[pt]=A geração foi iniciada
 Name[pt_BR]=A renderização iniciou
 Name[sv]=Återgivning startad
@@ -52,9 +88,18 @@ Name[x-test]=xxRendering startedxx
 Name[zh_CN]=渲染开始
 Name[zh_TW]=導出已開始
 Comment=Rendering was started
+Comment[ca]=La renderització ja ha començat
 Comment[cs]=Renderování bylo začato
 Comment[da]=Renderingen blev startet
+Comment[de]=Das Rendern wurde gestartet
+Comment[el]=Η αποτύπωση ξεκίνησε
+Comment[es]=El procesamiento ha sido iniciado
+Comment[gl]=Vaise iniciar o renderizado
+Comment[hu]=A renderelés elkezdődött
+Comment[it]=L'esportazione è stata avviata
+Comment[nb]=Startet opptegning
 Comment[nl]=Weergave uitwerken is begonnen
+Comment[pl]=Renderowanie zostało rozpoczęte
 Comment[pt]=A geração foi iniciada
 Comment[pt_BR]=A renderização foi iniciada
 Comment[sv]=Återgivningen har startats
@@ -66,8 +111,18 @@ Action=Popup
 
 [Event/FrameCaptured]
 Name=Frame captured
+Name[ca]=S'ha capturat un fotograma
+Name[cs]=Snímek zachycen
 Name[da]=Billed indfanget
+Name[de]=Bild aufgenommen
+Name[el]=Σύλληψη πλαισίου
+Name[es]=Fotograma capturado
+Name[gl]=Fotograma capturado
+Name[hu]=Képkocka rögzítve
+Name[it]=Fotogramma acquisito
+Name[nb]=Stillbilde tatt
 Name[nl]=Frame opgenomen
+Name[pl]=Przechwycono klatkę
 Name[pt]=Imagem capturada
 Name[pt_BR]=Imagem capturada
 Name[sv]=Ram lagrad
@@ -76,8 +131,18 @@ Name[x-test]=xxFrame capturedxx
 Name[zh_CN]=已抓取帧
 Name[zh_TW]=影格已擷取
 Comment=A frame was captured to disk
+Comment[ca]=S'ha capturat i desat un fotograma al disc
+Comment[cs]=Snímek byl zachycen na disk
 Comment[da]=Et billed blev indfanget til disken
+Comment[de]=Ein Bild wurde aufgenommen und auf auf Festplatte gespeichert
+Comment[el]=Έγινε σύλληψη πλαισίου στο δίσκο
+Comment[es]=Un fotograma fue capturado al disco
+Comment[gl]=Capturouse un fotograma para o disco
+Comment[hu]=Egy képkocka rögzítésre került a lemezre
+Comment[it]=È stato acquisito un fotogramma sul disco
+Comment[nb]=Et stillbilde ble lagret
 Comment[nl]=Een frame is op schijf opgenomen
+Comment[pl]=Klatka została przechwycona na dysk
 Comment[pt]=Foi capturada uma imagem para o disco
 Comment[pt_BR]=Foi capturada uma imagem para o disco
 Comment[sv]=En ram har lagrats på disk
@@ -90,8 +155,17 @@ Action=Sound
 
 [Event/ReadyToCapture]
 Name=Ready to capture
+Name[ca]=A punt per capturar
 Name[da]=Klar til at indfange
+Name[de]=Bereit zur Aufnahme
+Name[el]=Έτοιμο για σύλληψη
+Name[es]=Listo para capturar
+Name[gl]=Listo para a captura
+Name[hu]=Kezdődhet a rögzítés
+Name[it]=Pronto per la registrazione
+Name[nb]=Klar til å ta stillbilde
 Name[nl]=Gereed om op te nemen
+Name[pl]=Gotowy do przechwycenia
 Name[pt]=Pronto para capturar
 Name[pt_BR]=Pronto para capturar
 Name[sv]=Klar att lagra
@@ -104,22 +178,40 @@ Action=Sound
 
 [Event/ErrorMessage]
 Name=Error
+Name[ca]=Error
 Name[cs]=Chyba
 Name[da]=Fejl
 Name[de]=Fehler
+Name[el]=Σφάλμα
+Name[es]=Error
+Name[gl]=Erro
+Name[hu]=Hiba
+Name[it]=Errore
+Name[nb]=Feil
 Name[nds]=Fehler
 Name[nl]=Fout
+Name[pl]=Błąd
 Name[pt]=Erro
 Name[pt_BR]=Erro
+Name[sk]=Chyba
 Name[sv]=Fel
 Name[uk]=Помилка
 Name[x-test]=xxErrorxx
 Name[zh_CN]=错误
 Name[zh_TW]=錯誤
 Comment=An error occurred in Kdenlive
+Comment[ca]=S'ha produït un error al Kdenlive
+Comment[cs]=V Kdenlive došlo k chybě
 Comment[da]=En fejl opstod i Kdenlive
-Comment[de]=Es ist ein Fehler in Kdenlive aufgetreten
+Comment[de]=In Kdenlive ist ein Fehler aufgetreten.
+Comment[el]=Εμφανίστηκε σφάλμα στο Kdenlive
+Comment[es]=Ha ocurrido un error en Kdenlive
+Comment[gl]=Aconteceu un erro en Kdenlive
+Comment[hu]=Hiba történt a Kdenlive-ban
+Comment[it]=Si è verificato un errore in Kdenlive
+Comment[nb]=En feil oppsto i Kdenlive
 Comment[nl]=Er is een fout opgetreden in Kdenlive
+Comment[pl]=Wystąpił błąd w Kdenlive
 Comment[pt]=Ocorreu um erro no Kdenlive
 Comment[pt_BR]=Ocorreu um erro no Kdenlive
 Comment[sv]=Ett fel uppstod i Kdenlive
index c3aefa9195142ecee9329d62527db447f3f3a9e8..d16167cbed876f0df7b855cede0951a1d02a2f58 100644 (file)
@@ -58,7 +58,7 @@
 
 const double DOCUMENTVERSION = 0.88;
 
-KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup *undoGroup, QString profileName, QMap <QString, QString> properties, const QPoint &tracks, Render *render, KTextEdit *notes, bool *openBackup, MainWindow *parent, KProgressDialog *progressDialog) :
+KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup *undoGroup, QString profileName, QMap <QString, QString> properties, QMap <QString, QString> metadata, const QPoint &tracks, Render *render, KTextEdit *notes, bool *openBackup, MainWindow *parent, KProgressDialog *progressDialog) :
     QObject(parent),
     m_autosave(NULL),
     m_url(url),
@@ -83,6 +83,7 @@ KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup
     m_clipManager = new ClipManager(this);
     m_autoSaveTimer = new QTimer(this);
     m_autoSaveTimer->setSingleShot(true);
+    connect(m_clipManager, SIGNAL(displayMessage(QString, int)), parent, SLOT(slotGotProgressInfo(QString,int)));
     bool success = false;
 
     // init default document properties
@@ -110,6 +111,13 @@ KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup
         i.next();
         m_documentProperties[i.key()] = i.value();
     }
+    
+    // Load metadata
+    QMapIterator<QString, QString> j(metadata);
+    while (j.hasNext()) {
+        j.next();
+        m_documentMetadata[j.key()] = j.value();
+    }
 
     if (QLocale().decimalPoint() != QLocale::system().decimalPoint()) {
         setlocale(LC_NUMERIC, "");
@@ -135,8 +143,7 @@ KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup
         else {
             QFile file(tmpFile);
             QString errorMsg;
-            QDomImplementation impl;
-            impl.setInvalidDataPolicy(QDomImplementation::DropInvalidChars);
+            QDomImplementation::setInvalidDataPolicy(QDomImplementation::DropInvalidChars);
             success = m_document.setContent(&file, false, &errorMsg);
             file.close();
             KIO::NetAccess::removeTempFile(tmpFile);
@@ -151,7 +158,7 @@ KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup
             else {
                 parent->slotGotProgressInfo(i18n("Validating"), 0);
                 qApp->processEvents();
-                DocumentValidator validator(m_document);
+                DocumentValidator validator(m_document, url);
                 success = validator.isProject();
                 if (!success) {
                     // It is not a project file
@@ -285,6 +292,10 @@ KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup
                                 QDomNamedNodeMap props = docproperties.attributes();
                                 for (int i = 0; i < props.count(); i++)
                                     m_documentProperties.insert(props.item(i).nodeName(), props.item(i).nodeValue());
+                                docproperties = infoXml.firstChildElement("documentmetadata");
+                                props = docproperties.attributes();
+                                for (int i = 0; i < props.count(); i++)
+                                    m_documentMetadata.insert(props.item(i).nodeName(), props.item(i).nodeValue());
 
                                 if (validator.isModified()) setModified(true);
                                 kDebug() << "Reading file: " << url.path() << ", found clips: " << producers.count();
@@ -643,6 +654,14 @@ QDomDocument KdenliveDoc::xmlSceneList(const QString &scene, const QStringList &
     }
     docproperties.setAttribute("position", m_render->seekPosition().frames(m_fps));
     addedXml.appendChild(docproperties);
+    
+    QDomElement docmetadata = sceneList.createElement("documentmetadata");
+    QMapIterator<QString, QString> j(m_documentMetadata);
+    while (j.hasNext()) {
+        j.next();
+        docmetadata.setAttribute(j.key(), j.value());
+    }
+    addedXml.appendChild(docmetadata);
 
     QDomElement docnotes = sceneList.createElement("documentnotes");
     QDomText value = sceneList.createTextNode(m_notesWidget->toHtml());
@@ -693,7 +712,7 @@ QDomDocument KdenliveDoc::xmlSceneList(const QString &scene, const QStringList &
     QDomElement e;
     QList <DocClipBase*> list = m_clipManager->documentClipList();
     for (int i = 0; i < list.count(); i++) {
-        e = list.at(i)->toXML();
+        e = list.at(i)->toXML(true);
         e.setTagName("kdenlive_producer");
         addedXml.appendChild(sceneList.importNode(e, true));
         QList < CommentedTime > marks = list.at(i)->commentedSnapMarkers();
@@ -1033,8 +1052,10 @@ bool KdenliveDoc::addClip(QDomElement elem, QString clipId, bool createClipItem)
             extension = KUrl(path).fileName();
             path = KUrl(path).directory();
         }
-
-        if (path.isEmpty() == false && QFile::exists(path) == false && elem.attribute("type").toInt() != TEXT && !elem.hasAttribute("placeholder")) {
+        if (elem.hasAttribute("_missingsource")) {
+            // Clip has proxy but missing original source
+        }
+        else if (path.isEmpty() == false && QFile::exists(path) == false && elem.attribute("type").toInt() != TEXT && !elem.hasAttribute("placeholder")) {
             kDebug() << "// FOUND MISSING CLIP: " << path << ", TYPE: " << elem.attribute("type").toInt();
             const QString size = elem.attribute("file_size");
             const QString hash = elem.attribute("file_hash");
@@ -1200,9 +1221,9 @@ void KdenliveDoc::slotAddClipList(const KUrl::List urls, const QString &group, c
 }
 
 
-void KdenliveDoc::slotAddClipFile(const KUrl &url, const QString &group, const QString &groupId)
+void KdenliveDoc::slotAddClipFile(const KUrl &url, const QString &group, const QString &groupId, const QString &comment)
 {
-    m_clipManager->slotAddClipFile(url, group, groupId);
+    m_clipManager->slotAddClipFile(url, group, groupId, comment);
     emit selectLastAddedClip(QString::number(m_clipManager->lastClipId()));
     setModified(true);
 }
@@ -1231,15 +1252,9 @@ void KdenliveDoc::slotCreateColorClip(const QString &name, const QString &color,
     emit selectLastAddedClip(QString::number(m_clipManager->lastClipId()));
 }
 
-void KdenliveDoc::slotCreateSlideshowClipFile(const QString &name, const QString &path, int count, const QString &duration,
-        const bool loop, const bool crop, const bool fade,
-        const QString &luma_duration, const QString &luma_file, const int softness,
-        const QString &animation, QString group, const QString &groupId)
+void KdenliveDoc::slotCreateSlideshowClipFile(QMap <QString, QString> properties, QString group, const QString &groupId)
 {
-    m_clipManager->slotAddSlideshowClipFile(name, path, count, duration, loop,
-                                            crop, fade, luma_duration,
-                                            luma_file, softness,
-                                            animation, group, groupId);
+    m_clipManager->slotAddSlideshowClipFile(properties, group, groupId);
     setModified(true);
     emit selectLastAddedClip(QString::number(m_clipManager->lastClipId()));
 }
@@ -1376,9 +1391,9 @@ QPoint KdenliveDoc::getTracksCount() const
     return QPoint(video, audio);
 }
 
-void KdenliveDoc::cachePixmap(const QString &fileId, const QPixmap &pix) const
+void KdenliveDoc::cacheImage(const QString &fileId, const QImage &img) const
 {
-    pix.save(m_projectFolder.path(KUrl::AddTrailingSlash) + "thumbs/" + fileId + ".png");
+    img.save(m_projectFolder.path(KUrl::AddTrailingSlash) + "thumbs/" + fileId + ".png");
 }
 
 bool KdenliveDoc::checkDocumentClips(QDomNodeList infoproducers)
@@ -1761,5 +1776,15 @@ void KdenliveDoc::cleanupBackupFiles()
     }
 }
 
+const QMap <QString, QString> KdenliveDoc::metadata() const
+{
+    return m_documentMetadata;
+}
+
+void KdenliveDoc::setMetadata(const QMap <QString, QString> meta)
+{
+    m_documentMetadata = meta;
+}
+
 #include "kdenlivedoc.moc"
 
index 9bd3ef5802d8ebc78cd8b87c06de2dc55ab4e7b1..fcdb0979170f8d6d5735103a16fcaff25314a04b 100644 (file)
@@ -52,7 +52,7 @@ class KdenliveDoc: public QObject
 {
 Q_OBJECT public:
 
-    KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup *undoGroup, QString profileName, QMap <QString, QString> properties, const QPoint &tracks, Render *render, KTextEdit *notes, bool *openBackup, MainWindow *parent = 0, KProgressDialog *progressDialog = 0);
+    KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup *undoGroup, QString profileName, QMap <QString, QString> properties, QMap <QString, QString> metadata, const QPoint &tracks, Render *render, KTextEdit *notes, bool *openBackup, MainWindow *parent = 0, KProgressDialog *progressDialog = 0);
     ~KdenliveDoc();
     QDomNodeList producersList();
     double fps() const;
@@ -83,8 +83,8 @@ Q_OBJECT public:
      *
      * If the clip wasn't added before, it tries to add it to the project. */
     bool addClipInfo(QDomElement elem, QDomElement orig, QString clipId);
-    void slotAddClipFile(const KUrl &url, const QString &group, const QString &groupId = QString());
-    void slotAddClipList(const KUrl::List urls, const QString &group, const QString &groupId = QString());
+    void slotAddClipFile(const KUrl &url, const QString &group = QString(), const QString &groupId = QString(), const QString &comment = QString());
+    void slotAddClipList(const KUrl::List urls, const QString &group = QString(), const QString &groupId = QString());
     void deleteClip(const QString &clipId);
     int getFramePos(QString duration);
     DocClipBase *getBaseClip(const QString &clipId);
@@ -140,8 +140,7 @@ Q_OBJECT public:
      * The returned duration might differ from the actual track duration!
      * It is the one stored in the track's TrackInfo. */
     int trackDuration(int ix);
-
-    void cachePixmap(const QString &fileId, const QPixmap &pix) const;
+    void cacheImage(const QString &fileId, const QImage &img) const;
     void setProjectFolder(KUrl url);
     void setZone(int start, int end);
     QPoint zone() const;
@@ -162,6 +161,10 @@ Q_OBJECT public:
     static double getDisplayRatio(const QString &path);
     /** @brief Backup the project file */
     void backupLastSavedVersion(const QString &path);
+    /** @brief Returns the document metadata (author, copyright, ...) */
+    const QMap <QString, QString> metadata() const;
+    /** @brief Set the document metadata (author, copyright, ...) */
+    void setMetadata(const QMap <QString, QString> meta);
     
 private:
     KUrl m_url;
@@ -184,6 +187,7 @@ private:
     /** @brief The project folder, used to store project files (titles, effects...). */
     KUrl m_projectFolder;
     QMap <QString, QString> m_documentProperties;
+    QMap <QString, QString> m_documentMetadata;
 
     QList <TrackInfo> m_tracksList;
     void setNewClipResource(const QString &id, const QString &path);
@@ -206,13 +210,7 @@ private:
 public slots:
     void slotCreateXmlClip(const QString &name, const QDomElement xml, QString group, const QString &groupId);
     void slotCreateColorClip(const QString &name, const QString &color, const QString &duration, QString group, const QString &groupId);
-    void slotCreateSlideshowClipFile(const QString &name, const QString &path,
-                                     int count, const QString &duration,
-                                     const bool loop, const bool crop,
-                                     const bool fade, const QString &luma_duration,
-                                     const QString &luma_file, const int softness,
-                                     const QString &animation, QString group,
-                                     const QString &groupId);
+    void slotCreateSlideshowClipFile(QMap <QString, QString> properties, QString group, const QString &groupId);
     void slotCreateTextClip(QString group, const QString &groupId, const QString &templatePath = QString());
     void slotCreateTextTemplateClip(QString group, const QString &groupId, KUrl path);
 
index 4abadc83ca3f479b4928674486ab30e43ed3d209..c3ceaf16e77dcafde56a2c38a7b66a3cd9e7602f 100644 (file)
       <default>0</default>
     </entry>
 
+    <entry name="v4l_capturevideo" type="Bool">
+      <label>Should we capture video.</label>
+      <default>true</default>
+    </entry>
+    
     <entry name="v4l_captureaudio" type="Bool">
       <label>Should we also capture audio.</label>
       <default>false</default>
       <default>true</default>
     </entry>
     
-    <entry name="recording_preview" type="UInt">
+    <entry name="enable_recording_preview" type="Bool">
       <label>Should we display video frames while capturing.</label>
-      <default>0</default>
+      <default>true</default>
+    </entry>
+    
+    <entry name="add_clip_cut" type="Bool">
+      <label>Add cutted clips to project after transcoding.</label>
+      <default>true</default>
     </entry>
 
   </group>
index ff953b5bd3748feeb2fe5a93f6278f9239ad412e..80e1670a87c9b1bbcca2e01f6ebede352732bff5 100644 (file)
@@ -22,9 +22,9 @@
 #ifdef USE_V4L
 #include "v4l/v4lcapture.h"
 #endif
-#include "blackmagic/devices.h"
 #include "encodingprofilesdialog.h"
 #include "kdenlivesettings.h"
+#include "renderer.h"
 
 #include <KStandardDirs>
 #include <KDebug>
@@ -33,6 +33,7 @@
 #include <kde_file.h>
 #include <KIO/NetAccess>
 #include <kdeversion.h>
+#include <KMessageBox>
 
 #include <QDir>
 #include <QTimer>
@@ -112,7 +113,6 @@ KdenliveSettingsDialog::KdenliveSettingsDialog(const QMap<QString, QString>& map
     }
     connect(m_configCapture.kcfg_detectedv4ldevices, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdatev4lDevice()));
     connect(m_configCapture.kcfg_v4l_format, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdatev4lCaptureProfile()));
-    connect(m_configCapture.kcfg_v4l_captureaudio, SIGNAL(toggled(bool)), m_configCapture.kcfg_v4l_alsadevice, SLOT(setEnabled(bool)));
     connect(m_configCapture.config_v4l, SIGNAL(clicked()), this, SLOT(slotEditVideo4LinuxProfile()));
 
     slotUpdatev4lDevice();
@@ -188,7 +188,18 @@ KdenliveSettingsDialog::KdenliveSettingsDialog(const QMap<QString, QString>& map
     m_page7 = addPage(p7, i18n("Transcode"), "edit-copy");
     connect(m_configTranscode.button_add, SIGNAL(clicked()), this, SLOT(slotAddTranscode()));
     connect(m_configTranscode.button_delete, SIGNAL(clicked()), this, SLOT(slotDeleteTranscode()));
-    connect(m_configTranscode.profiles_list, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(slotDialogModified()));
+    connect(m_configTranscode.profiles_list, SIGNAL(itemChanged(QListWidgetItem *)), this, SLOT(slotDialogModified()));
+    connect(m_configTranscode.profiles_list, SIGNAL(currentRowChanged(int)), this, SLOT(slotSetTranscodeProfile()));
+    
+    connect(m_configTranscode.profile_name, SIGNAL(textChanged(const QString &)), this, SLOT(slotEnableTranscodeUpdate()));
+    connect(m_configTranscode.profile_description, SIGNAL(textChanged(const QString &)), this, SLOT(slotEnableTranscodeUpdate()));
+    connect(m_configTranscode.profile_extension, SIGNAL(textChanged(const QString &)), this, SLOT(slotEnableTranscodeUpdate()));
+    connect(m_configTranscode.profile_parameters, SIGNAL(textChanged()), this, SLOT(slotEnableTranscodeUpdate()));
+    connect(m_configTranscode.profile_audioonly, SIGNAL(stateChanged(int)), this, SLOT(slotEnableTranscodeUpdate()));
+    
+    connect(m_configTranscode.button_update, SIGNAL(pressed()), this, SLOT(slotUpdateTranscodingProfile()));
+    
+    m_configTranscode.profile_parameters->setMaximumHeight(QFontMetrics(font()).lineSpacing() * 5);
 
     connect(m_configCapture.kcfg_rmd_capture_audio, SIGNAL(clicked(bool)), m_configCapture.audio_group, SLOT(setVisible(bool)));
 
@@ -255,16 +266,11 @@ KdenliveSettingsDialog::KdenliveSettingsDialog(const QMap<QString, QString>& map
     slotUpdateV4lProfile(-1);
     slotUpdateDecklinkProfile(-1);
 
-    BMInterface::getBlackMagicDeviceList(m_configCapture.kcfg_decklink_capturedevice);
-    if (m_configCapture.kcfg_decklink_capturedevice->count() > 0) {
-        QStringList modes = m_configCapture.kcfg_decklink_capturedevice->itemData(m_configCapture.kcfg_decklink_capturedevice->currentIndex()).toStringList();
-        m_configCapture.kcfg_decklink_capturedevice->setToolTip(i18n("Supported capture modes:\n") + modes.join("\n"));
+    Render::getBlackMagicDeviceList(m_configCapture.kcfg_decklink_capturedevice);
+    if (!Render::getBlackMagicOutputDeviceList(m_configSdl.kcfg_blackmagic_output_device)) {
+        // No blackmagic card found
+       m_configSdl.kcfg_external_display->setEnabled(false);
     }
-    connect(m_configCapture.kcfg_decklink_capturedevice, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateHDMIModes()));
-
-    if (BMInterface::getBlackMagicOutputDeviceList(m_configSdl.kcfg_blackmagic_output_device)) {
-        // Found blackmagic card
-    } else m_configSdl.kcfg_external_display->setEnabled(false);
 
     double dvgrabVersion = 0;
     if (!KdenliveSettings::dvgrab_path().isEmpty()) {
@@ -298,12 +304,6 @@ KdenliveSettingsDialog::KdenliveSettingsDialog(const QMap<QString, QString>& map
 
 KdenliveSettingsDialog::~KdenliveSettingsDialog() {}
 
-void KdenliveSettingsDialog::slotUpdateHDMIModes()
-{
-    QStringList modes = m_configCapture.kcfg_decklink_capturedevice->itemData(m_configCapture.kcfg_decklink_capturedevice->currentIndex()).toStringList();
-    m_configCapture.kcfg_decklink_capturedevice->setToolTip(i18n("Supported capture modes:\n") + modes.join("\n"));
-}
-
 void KdenliveSettingsDialog::slotUpdateRmdRegionStatus()
 {
     m_configCapture.region_group->setHidden(m_configCapture.kcfg_rmd_capture_type->currentIndex() != 1);
@@ -393,13 +393,17 @@ void KdenliveSettingsDialog::initDevices()
                 }
                 if (line.contains("capture")) {
                     deviceId = line.section(':', 0, 0);
-                    m_configCapture.kcfg_rmd_alsa_device->addItem(line.section(':', 1, 1), "plughw:" + QString::number(deviceId.section('-', 0, 0).toInt()) + ',' + QString::number(deviceId.section('-', 1, 1).toInt()));
-                    m_configCapture.kcfg_v4l_alsadevice->addItem(line.section(':', 1, 1), "hw:" + QString::number(deviceId.section('-', 0, 0).toInt()) + ',' + QString::number(deviceId.section('-', 1, 1).toInt()));
+                    m_configCapture.kcfg_rmd_alsa_device->addItem(line.section(':', 1, 1).simplified(), "plughw:" + QString::number(deviceId.section('-', 0, 0).toInt()) + ',' + QString::number(deviceId.section('-', 1, 1).toInt()));
+                    m_configCapture.kcfg_v4l_alsadevice->addItem(line.section(':', 1, 1).simplified(), "hw:" + QString::number(deviceId.section('-', 0, 0).toInt()) + ',' + QString::number(deviceId.section('-', 1, 1).toInt()));
                 }
             }
             file.close();
         }
     }
+    
+    // Add pulseaudio capture option
+    m_configCapture.kcfg_v4l_alsadevice->addItem(i18n("PulseAudio"), "pulse");
+    
     if (!KdenliveSettings::audiodevicename().isEmpty()) {
         // Select correct alsa device
         int ix = m_configSdl.kcfg_audio_device->findData(KdenliveSettings::audiodevicename());
@@ -436,9 +440,9 @@ void KdenliveSettingsDialog::slotReadAudioDevices()
         if (!data.startsWith(" ") && data.count(':') > 1) {
             QString card = data.section(':', 0, 0).section(' ', -1);
             QString device = data.section(':', 1, 1).section(' ', -1);
-            m_configSdl.kcfg_audio_device->addItem(data.section(':', -1), "plughw:" + card + ',' + device);
-            m_configCapture.kcfg_rmd_alsa_device->addItem(data.section(':', -1), "plughw:" + card + ',' + device);
-            m_configCapture.kcfg_v4l_alsadevice->addItem(data.section(':', -1), "hw:" + card + ',' + device);
+            m_configSdl.kcfg_audio_device->addItem(data.section(':', -1).simplified(), "plughw:" + card + ',' + device);
+            m_configCapture.kcfg_rmd_alsa_device->addItem(data.section(':', -1).simplified(), "plughw:" + card + ',' + device);
+            m_configCapture.kcfg_v4l_alsadevice->addItem(data.section(':', -1).simplified(), "hw:" + card + ',' + device);
         }
     }
 }
@@ -745,14 +749,20 @@ void KdenliveSettingsDialog::loadTranscodeProfiles()
     KConfigGroup transConfig(config, "Transcoding");
     // read the entries
     m_configTranscode.profiles_list->blockSignals(true);
+    m_configTranscode.profiles_list->clear();
     QMap< QString, QString > profiles = transConfig.entryMap();
     QMapIterator<QString, QString> i(profiles);
     while (i.hasNext()) {
         i.next();
-        QTreeWidgetItem *item = new QTreeWidgetItem(m_configTranscode.profiles_list, QStringList() << i.key() << i.value());
-        item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable);
+        QListWidgetItem *item = new QListWidgetItem(i.key());
+        QString data = i.value();
+        if (data.contains(';')) item->setToolTip(data.section(';', 1, 1));
+        item->setData(Qt::UserRole, data);
+        m_configTranscode.profiles_list->addItem(item);
+        //item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable);
     }
     m_configTranscode.profiles_list->blockSignals(false);
+    m_configTranscode.profiles_list->setCurrentRow(0);
 }
 
 void KdenliveSettingsDialog::saveTranscodeProfiles()
@@ -762,31 +772,90 @@ void KdenliveSettingsDialog::saveTranscodeProfiles()
     KConfigGroup transConfig(config, "Transcoding");
     // read the entries
     transConfig.deleteGroup();
-    int max = m_configTranscode.profiles_list->topLevelItemCount();
+    int max = m_configTranscode.profiles_list->count();
     for (int i = 0; i < max; i++) {
-        QTreeWidgetItem *item = m_configTranscode.profiles_list->topLevelItem(i);
-        transConfig.writeEntry(item->text(0), item->text(1));
+        QListWidgetItem *item = m_configTranscode.profiles_list->item(i);
+        transConfig.writeEntry(item->text(), item->data(Qt::UserRole).toString());
     }
     config->sync();
 }
 
 void KdenliveSettingsDialog::slotAddTranscode()
 {
-    QTreeWidgetItem *item = new QTreeWidgetItem(m_configTranscode.profiles_list, QStringList() << i18n("Name") << i18n("Parameters"));
-    item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable);
+    if (!m_configTranscode.profiles_list->findItems(m_configTranscode.profile_name->text(), Qt::MatchExactly).isEmpty()) {
+        KMessageBox::sorry(this, i18n("A profile with that name already exists"));
+        return;
+    }
+    QListWidgetItem *item = new QListWidgetItem(m_configTranscode.profile_name->text());
+    QString data = m_configTranscode.profile_parameters->toPlainText();
+    data.append(" %1." + m_configTranscode.profile_extension->text());
+    data.append(";");
+    if (!m_configTranscode.profile_description->text().isEmpty()) 
+        data.append(m_configTranscode.profile_description->text());
+    if (m_configTranscode.profile_audioonly->isChecked()) data.append(";audio");
+    item->setData(Qt::UserRole, data);
+    m_configTranscode.profiles_list->addItem(item);
     m_configTranscode.profiles_list->setCurrentItem(item);
-    m_configTranscode.profiles_list->editItem(item);
+    slotDialogModified();
+}
+
+void KdenliveSettingsDialog::slotUpdateTranscodingProfile()
+{
+    QListWidgetItem *item = m_configTranscode.profiles_list->currentItem();
+    if (!item) return;
+    m_configTranscode.button_update->setEnabled(false);
+    item->setText(m_configTranscode.profile_name->text());
+    QString data = m_configTranscode.profile_parameters->toPlainText();
+    data.append(" %1." + m_configTranscode.profile_extension->text());
+    data.append(";");
+    if (!m_configTranscode.profile_description->text().isEmpty())
+        data.append(m_configTranscode.profile_description->text());
+    if (m_configTranscode.profile_audioonly->isChecked()) data.append(";audio");
+    item->setData(Qt::UserRole, data);
     slotDialogModified();
 }
 
 void KdenliveSettingsDialog::slotDeleteTranscode()
 {
-    QTreeWidgetItem *item = m_configTranscode.profiles_list->currentItem();
+    QListWidgetItem *item = m_configTranscode.profiles_list->currentItem();
     if (item == NULL) return;
     delete item;
     slotDialogModified();
 }
 
+void KdenliveSettingsDialog::slotEnableTranscodeUpdate()
+{
+    if (!m_configTranscode.profile_box->isEnabled()) return;
+    bool allow = true;
+    if (m_configTranscode.profile_name->text().isEmpty() || m_configTranscode.profile_extension->text().isEmpty()) allow = false;
+    m_configTranscode.button_update->setEnabled(allow);
+}
+
+void KdenliveSettingsDialog::slotSetTranscodeProfile()
+{
+    m_configTranscode.profile_box->setEnabled(false);
+    m_configTranscode.button_update->setEnabled(false);
+    m_configTranscode.profile_name->clear();
+    m_configTranscode.profile_description->clear();
+    m_configTranscode.profile_extension->clear();
+    m_configTranscode.profile_parameters->clear();
+    m_configTranscode.profile_audioonly->setChecked(false);
+    QListWidgetItem *item = m_configTranscode.profiles_list->currentItem();
+    if (!item) {
+        return;
+    }
+    m_configTranscode.profile_name->setText(item->text());
+    QString data = item->data(Qt::UserRole).toString();
+    if (data.contains(';')) {
+        m_configTranscode.profile_description->setText(data.section(';', 1, 1));
+        if (data.section(';', 2, 2) == "audio") m_configTranscode.profile_audioonly->setChecked(true);
+        data = data.section(';', 0, 0).simplified();
+    }
+    m_configTranscode.profile_extension->setText(data.section('.', -1));
+    m_configTranscode.profile_parameters->setPlainText(data.section(' ', 0, -2));
+    m_configTranscode.profile_box->setEnabled(true);
+}
+
 void KdenliveSettingsDialog::slotShuttleModified()
 {
 #ifdef USE_JOGSHUTTLE
@@ -1015,6 +1084,7 @@ void KdenliveSettingsDialog::slotEditVideo4LinuxProfile()
     delete w;
 }
 
+
 #include "kdenlivesettingsdialog.moc"
 
 
index 8c01c3fbb915f710a29cef91e29d928bb753c9c1..9208107a22835e2e10592db56d8bad943d68e6a9 100644 (file)
@@ -65,10 +65,15 @@ private slots:
     void slotCheckAlsaDriver();
     void slotAddTranscode();
     void slotDeleteTranscode();
+    /** @brief Update current transcoding profile. */
+    void slotUpdateTranscodingProfile();
+    /** @brief Enable / disable the update profile button. */
+    void slotEnableTranscodeUpdate();
+    /** @brief Update display of current transcoding profile parameters. */
+    void slotSetTranscodeProfile();
     void slotShuttleModified();
     void slotDialogModified();
     void slotEnableCaptureFolder();
-    void slotUpdateHDMIModes();
     void slotUpdatev4lDevice();
     void slotUpdatev4lCaptureProfile();
     void slotManageEncodingProfile();
index 06e2cb90d4e46ac33aee96f3815d85f0f18f2a71..b4d54169b4cfade91185e590626ea7e76e1b2b21 100644 (file)
@@ -13,9 +13,9 @@ DNxHD 720p 50 fps 175 Mb/s=-s 1280x720 -r 50 -vb 175000k -threads 2 -vcodec dnxh
 DNxHD 720p 50 fps 115 Mb/s=-s 1280x720 -r 50 -vb 175000k -threads 2 -vcodec dnxhd -acodec copy %1.mov;High quality encoding
 DNxHD 720p 59.94 fps 220 Mb/s=-s 1280x720 -r 60000/1001 -vb 220000k -threads 2 -vcodec dnxhd -acodec copy %1.mov;High quality encoding
 DNxHD 720p 59.94 fps 145 Mb/s=-s 1280x720 -r 60000/1001 -vb 145000k -threads 2 -vcodec dnxhd -acodec copy %1.mov;High quality encoding
-Fix MPEG-1=-sameq -acodec copy -vcodec mpeg1video %1.mpg;Fix unplayable MPEG-1 files;vcodec=mpeg1video
-Fix Ogg Theora=-sameq -vcodec libtheora -acodec copy %1.ogv;Fix unplayable OGG Theora files;vcodec=theora
-Remux MPEG-2 PS/VOB=-vcodec copy -acodec copy %1.mpg;Fix audio sync in MPEG-2 vob files;vcodec=mpeg2video
+Fix MPEG-1=-sameq -acodec copy -vcodec mpeg1video %1.mpg;Fix unplayable MPEG-1 files;;vcodec=mpeg1video
+Fix Ogg Theora=-sameq -vcodec libtheora -acodec copy %1.ogv;Fix unplayable OGG Theora files;;vcodec=theora
+Remux MPEG-2 PS/VOB=-vcodec copy -acodec copy %1.mpg;Fix audio sync in MPEG-2 vob files;;vcodec=mpeg2video
 Lossless Matroska=-sn -vcodec huffyuv -acodec flac %1.mkv;High quality lossless encoding
-Wav 48000Hz=-vn -ar 48000 %1.wav;Extract audio as WAV file
+Wav 48000Hz=-vn -ar 48000 %1.wav;Extract audio as WAV file;audio
 Remux with MKV=-vcodec copy -acodec copy -sn %1.mkv
index 0a350be99db311c9aaa1e5c16fa9f080d3efe7d4..1cb088d43e2ac046ef6e38f88aa4202c0b6a2125 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
-<gui name="kdenlive" version="65">
+<gui name="kdenlive" version="69">
   <ToolBar name="extraToolBar" >
     <text>Extra Toolbar</text>
        <Action name="project_render" />
@@ -25,6 +25,9 @@
       <Action name="add_text_clip" />
       <Action name="add_text_template_clip" />
       <Action name="add_folder" /> 
+      <Action name="download_resource" /> 
+      <Menu name="extract_audio" ><text>Extract Audio</text>
+      </Menu>
       <Menu name="stabilize" ><text>Stabilize</text>
       </Menu>
       <Menu name="transcoders" ><text>Transcode</text>
@@ -35,6 +38,9 @@
        <Action name="insert_track" />
        <Action name="delete_track" />
        <Action name="config_tracks" />
+       <Separator />
+       <Action name="select_track" />
+       <Action name="select_all_tracks" />
       </Menu>
       <Separator />
       <Action name="stopmotion" />
index 20c716e77c73d3669e7bd2be4fd337a3062a45ae..5a8de19714f64963e865660f93b519f231c32f1a 100644 (file)
@@ -30,6 +30,8 @@
 #include <QStylePainter>
 #include <QApplication>
 
+const int margin = 5;
+const int cursorWidth = 6;
 
 KeyframeHelper::KeyframeHelper(QWidget *parent) :
         QWidget(parent),
@@ -37,7 +39,7 @@ KeyframeHelper::KeyframeHelper(QWidget *parent) :
         m_position(0),
         m_scale(0),
         m_movingKeyframe(false),
-        m_lineHeight(10),
+        m_lineHeight(9),
         m_drag(false),
         m_hoverKeyframe(-1)
 {
@@ -54,17 +56,18 @@ KeyframeHelper::KeyframeHelper(QWidget *parent) :
 void KeyframeHelper::mousePressEvent(QMouseEvent * event)
 {
     m_hoverKeyframe = -1;
-    if (event->button() == Qt::LeftButton) m_drag = true;
-    else {
+    if (event->button() != Qt::LeftButton) {
        QWidget::mousePressEvent(event);
        return;
     }
+    int xPos = event->x() - margin;
     if (m_geom != NULL && (event->y() < m_lineHeight)) {
         // check if we want to move a keyframe
-        int mousePos = qMax((int)(event->x() / m_scale), 0);
+        int mousePos = qMax((int)(xPos / m_scale), 0);
         Mlt::GeometryItem item;
         if (m_geom->next_key(&item, mousePos) == 0) {
-            if (qAbs(item.frame() * m_scale - (int)(event->x())) < 4) {
+            if (qAbs(item.frame() * m_scale - xPos) < 4) {
+                m_drag = true;
                 m_movingItem.x(item.x());
                 m_movingItem.y(item.y());
                 m_movingItem.w(item.w());
@@ -91,21 +94,43 @@ void KeyframeHelper::mousePressEvent(QMouseEvent * event)
             }
         }
     }
-    m_position = event->x() / m_scale;
-    emit positionChanged(m_position);
-    update();
+    if (event->y() >= m_lineHeight && event->y() < height()) {
+        m_drag = true;
+        m_position = xPos / m_scale;
+        emit positionChanged(m_position);
+        update();
+    }
+}
+
+void KeyframeHelper::leaveEvent( QEvent * event )
+{
+    Q_UNUSED(event);
+    if (m_hoverKeyframe != -1) {
+        m_hoverKeyframe = -1;
+        update();
+    }
 }
 
 // virtual
 void KeyframeHelper::mouseMoveEvent(QMouseEvent * event)
 {
+    int xPos = event->x() - margin;
     if (!m_drag) {
+        int mousePos = qMax((int)(xPos / m_scale), 0);
+        if (qAbs(m_position * m_scale - xPos) < cursorWidth && event->y() >= m_lineHeight) {
+            // Mouse over time cursor
+            if (m_hoverKeyframe != -2) {
+                m_hoverKeyframe = -2;
+                update();
+            }
+            event->accept();
+            return;
+        }
         if (m_geom != NULL && (event->y() < m_lineHeight)) {
             // check if we want to move a keyframe
-            int mousePos = qMax((int)(event->x() / m_scale), 0);
             Mlt::GeometryItem item;
             if (m_geom->next_key(&item, mousePos) == 0) {
-                if (qAbs(item.frame() * m_scale - (int)(event->x())) < 4) {
+                if (qAbs(item.frame() * m_scale - xPos) < 4) {
                     if (m_hoverKeyframe == item.frame()) return;
                     m_hoverKeyframe = item.frame();
                     setCursor(Qt::PointingHandCursor);
@@ -125,13 +150,13 @@ void KeyframeHelper::mouseMoveEvent(QMouseEvent * event)
     }
     if (m_movingKeyframe) {
         if (!m_dragStart.isNull()) {
-            if ((event->pos() - m_dragStart).manhattanLength() < QApplication::startDragDistance()) return;
+            if ((QPoint(xPos, event->y()) - m_dragStart).manhattanLength() < QApplication::startDragDistance()) return;
             m_dragStart = QPoint();
             m_geom->remove(m_movingItem.frame());
             for (int i = 0; i < m_extraGeometries.count(); i++)
                 m_extraGeometries[i]->remove(m_movingItem.frame());
         }
-        int pos = qBound(0, (int)(event->x() / m_scale), frameLength);
+        int pos = qBound(0, (int)(xPos / m_scale), frameLength);
         if (KdenliveSettings::snaptopoints() && qAbs(pos - m_position) < 5) pos = m_position;
         m_movingItem.frame(pos);
         for (int i = 0; i < m_extraMovingItems.count(); i++) {
@@ -140,9 +165,10 @@ void KeyframeHelper::mouseMoveEvent(QMouseEvent * event)
         update();
         return;
     }
-    m_position = event->x() / m_scale;
+    m_position = xPos / m_scale;
     m_position = qMax(0, m_position);
     m_position = qMin(frameLength, m_position);
+    m_hoverKeyframe = -2;
     emit positionChanged(m_position);
     update();
 }
@@ -151,7 +177,8 @@ void KeyframeHelper::mouseDoubleClickEvent(QMouseEvent * event)
 {
     if (m_geom != NULL && event->button() == Qt::LeftButton) {
         // check if we want to move a keyframe
-        int mousePos = qMax((int)(event->x() / m_scale - 5), 0);
+        int xPos = event->x() - margin;
+        int mousePos = qMax((int)(xPos / m_scale - 5), 0);
         Mlt::GeometryItem item;
         if (m_geom->next_key(&item, mousePos) == 0 && item.frame() - mousePos < 10) {
             // There is already a keyframe close to mouse click
@@ -159,7 +186,7 @@ void KeyframeHelper::mouseDoubleClickEvent(QMouseEvent * event)
             return;
         }
         // add new keyframe
-        emit addKeyframe((int)(event->x() / m_scale));
+        emit addKeyframe((int)(xPos / m_scale));
     }
 }
 
@@ -167,8 +194,8 @@ void KeyframeHelper::mouseDoubleClickEvent(QMouseEvent * event)
 void KeyframeHelper::mouseReleaseEvent(QMouseEvent * event)
 {
     m_drag = false;
-    m_hoverKeyframe = -1;
     setCursor(Qt::ArrowCursor);
+    m_hoverKeyframe = -1;
     if (m_movingKeyframe) {
         m_geom->insert(m_movingItem);
         m_movingKeyframe = false;
@@ -207,7 +234,7 @@ void KeyframeHelper::paintEvent(QPaintEvent *e)
     QStylePainter p(this);
     const QRectF clipRect = e->rect();
     p.setClipRect(clipRect);
-    m_scale = (double) width() / frameLength;
+    m_scale = (double) (width() - 2 * margin) / frameLength;
     if (m_geom != NULL) {
         int pos = 0;
         p.setPen(m_keyframe);
@@ -219,7 +246,7 @@ void KeyframeHelper::paintEvent(QPaintEvent *e)
             if (pos == m_hoverKeyframe) {
                 p.setBrush(m_selected);
             }
-            int scaledPos = pos * m_scale;
+            int scaledPos = margin + pos * m_scale;
             // draw keyframes
             p.drawLine(scaledPos, 9, scaledPos, 15);
             // draw pointer
@@ -240,7 +267,7 @@ void KeyframeHelper::paintEvent(QPaintEvent *e)
         
         if (m_movingKeyframe) {
             p.setBrush(m_selected);
-            int scaledPos = (int)(m_movingItem.frame() * m_scale);
+            int scaledPos = margin + (int)(m_movingItem.frame() * m_scale);
             // draw keyframes
             p.drawLine(scaledPos, 9, scaledPos, 15);
             // draw pointer
@@ -255,13 +282,18 @@ void KeyframeHelper::paintEvent(QPaintEvent *e)
         }
     }
     p.setPen(palette().dark().color());
-    p.drawLine(clipRect.x(), m_lineHeight, clipRect.right(), m_lineHeight);
+    p.drawLine(margin, m_lineHeight, width() - margin - 1, m_lineHeight);
+    p.drawLine(margin, m_lineHeight - 3, margin, m_lineHeight + 3);
+    p.drawLine(width() - margin - 1, m_lineHeight - 3, width() - margin - 1, m_lineHeight + 3);
 
     // draw pointer
     QPolygon pa(3);
-    const int cursor = m_position * m_scale;
-    pa.setPoints(3, cursor - 5, 16, cursor + 5, 16, cursor, 11);
-    p.setBrush(palette().dark().color());
+    const int cursor = margin + m_position * m_scale;
+    pa.setPoints(3, cursor - cursorWidth, 16, cursor + cursorWidth, 16, cursor, 10);
+    if (m_hoverKeyframe == -2)
+        p.setBrush(palette().highlight());
+    else
+        p.setBrush(palette().dark().color());
     p.drawPolygon(pa);
 }
 
index 6a01bae9dd53d2196809982fc5d752f19b1ea71f..4e8d7afe01df890b0b96bd627274da0877c6fe99 100644 (file)
@@ -42,6 +42,7 @@ protected:
     virtual void mouseMoveEvent(QMouseEvent * event);
     virtual void mouseReleaseEvent(QMouseEvent * event);
     virtual void mouseDoubleClickEvent(QMouseEvent * event);
+    virtual void leaveEvent( QEvent * event );
 
 private:
     Mlt::Geometry *m_geom;
index c6189ae7c88b35fb6292550664f88335e73de4e9..a87f654d6ac8cf6c741218f3c390ebf9b5f62815 100644 (file)
 #include <QtConcurrentRun>
 #include <QVarLengthArray>
 
-KThumb::KThumb(ClipManager *clipManager, KUrl url, const QString &id, const QString &hash, QObject * parent, const char */*name*/) :
+KThumb::KThumb(ClipManager *clipManager, KUrl url, const QString &id, const QString &hash, QObject * parent) :
     QObject(parent),
-    m_audioThumbProducer(),
     m_url(url),
     m_thumbFile(),
     m_dar(1),
     m_ratio(1),
     m_producer(NULL),
     m_clipManager(clipManager),
-    m_id(id),
-    m_stopAudioThumbs(false)
+    m_id(id)
 {
     m_thumbFile = clipManager->projectFolder() + "/thumbs/" + hash + ".thumb";
 }
@@ -58,12 +56,8 @@ KThumb::KThumb(ClipManager *clipManager, KUrl url, const QString &id, const QStr
 KThumb::~KThumb()
 {
     if (m_producer) m_clipManager->stopThumbs(m_id);
+    m_producer = NULL;
     m_intraFramesQueue.clear();
-    if (m_audioThumbProducer.isRunning()) {
-        m_stopAudioThumbs = true;
-        m_audioThumbProducer.waitForFinished();
-        slotAudioThumbOver();
-    }
     m_intra.waitForFinished();
 }
 
@@ -129,15 +123,14 @@ void KThumb::getThumb(int frame)
     emit thumbReady(frame, img);
 }
 
-QPixmap KThumb::extractImage(int frame, int width, int height)
+QImage KThumb::extractImage(int frame, int width, int height)
 {
     if (m_producer == NULL) {
-        QPixmap p(width, height);
-        p.fill(Qt::black);
-        return p;
+        QImage img(width, height, QImage::Format_ARGB32_Premultiplied);
+        img.fill(Qt::black);
+        return img;
     }
-    QImage img = getProducerFrame(frame, (int) (height * m_ratio + 0.5), width, height);
-    return QPixmap::fromImage(img);
+    return getProducerFrame(frame, (int) (height * m_ratio + 0.5), width, height);
 }
 
 //static
@@ -339,151 +332,10 @@ void KThumb::getThumbs(KUrl url, int startframe, int endframe, int width, int he
     emit thumbReady(endframe, image);
 }
 */
-void KThumb::stopAudioThumbs()
-{
-    if (m_audioThumbProducer.isRunning()) {
-        m_stopAudioThumbs = true;
-        m_audioThumbProducer.waitForFinished();
-        slotAudioThumbOver();
-    }
-}
-
-void KThumb::removeAudioThumb()
-{
-    if (m_thumbFile.isEmpty()) return;
-    stopAudioThumbs();
-    QFile f(m_thumbFile);
-    f.remove();
-}
-
-void KThumb::getAudioThumbs(int channel, double frame, double frameLength, int arrayWidth)
-{
-    if (channel == 0) {
-        slotAudioThumbOver();
-        return;
-    }
-    if (m_audioThumbProducer.isRunning()) {
-        return;
-    }
-
-    audioByteArray storeIn;
-    //FIXME: Hardcoded!!!
-    m_frequency = 48000;
-    m_channels = channel;
-
-    QFile f(m_thumbFile);
-    if (f.open(QIODevice::ReadOnly)) {
-        const QByteArray channelarray = f.readAll();
-        f.close();
-        if (channelarray.size() != arrayWidth*(frame + frameLength)*m_channels) {
-            kDebug() << "--- BROKEN THUMB FOR: " << m_url.fileName() << " ---------------------- " << endl;
-            f.remove();
-            slotAudioThumbOver();
-            return;
-        }
-
-        kDebug() << "reading audio thumbs from file";
-
-        int h1 = arrayWidth * m_channels;
-        int h2 = (int) frame * h1;
-        int h3;
-        for (int z = (int) frame; z < (int)(frame + frameLength); z++) {
-            h3 = 0;
-            for (int c = 0; c < m_channels; c++) {
-                QByteArray m_array(arrayWidth, '\x00');
-                for (int i = 0; i < arrayWidth; i++) {
-                    m_array[i] = channelarray.at(h2 + h3 + i);
-                }
-                h3 += arrayWidth;
-                storeIn[z][c] = m_array;
-            }
-            h2 += h1;
-        }
-        emit audioThumbReady(storeIn);
-        slotAudioThumbOver();
-    } else {
-        if (m_audioThumbProducer.isRunning()) return;
-        m_audioThumbFile.setFileName(m_thumbFile);
-        m_frame = frame;
-        m_frameLength = frameLength;
-        m_arrayWidth = arrayWidth;
-        m_audioThumbProducer = QtConcurrent::run(this, &KThumb::slotCreateAudioThumbs);
-        /*m_audioThumbProducer.init(m_url, m_thumbFile, frame, frameLength, m_frequency, m_channels, arrayWidth);
-        m_audioThumbProducer.start(QThread::LowestPriority);*/
-        // kDebug() << "STARTING GENERATE THMB FOR: " <<m_id<<", URL: "<< m_url << " ................................";
-    }
-}
 
 void KThumb::slotCreateAudioThumbs()
 {
-    Mlt::Profile prof((char*) KdenliveSettings::current_profile().toUtf8().constData());
-    Mlt::Producer producer(prof, m_url.path().toUtf8().constData());
-    if (!producer.is_valid()) {
-        kDebug() << "++++++++  INVALID CLIP: " << m_url.path();
-        return;
-    }
-    if (!m_audioThumbFile.open(QIODevice::WriteOnly)) {
-        kDebug() << "++++++++  ERROR WRITING TO FILE: " << m_audioThumbFile.fileName();
-        kDebug() << "++++++++  DISABLING AUDIO THUMBS";
-        KdenliveSettings::setAudiothumbnails(false);
-        return;
-    }
-
-    if (KdenliveSettings::normaliseaudiothumbs()) {
-        Mlt::Filter m_convert(prof, "volume");
-        m_convert.set("gain", "normalise");
-        producer.attach(m_convert);
-    }
-
-    int last_val = 0;
-    int val = 0;
-    mlt_audio_format m_audioFormat = mlt_audio_pcm;
-    double framesPerSecond = mlt_producer_get_fps(producer.get_producer());
-    Mlt::Frame *mlt_frame;
-    
-    for (int z = (int) m_frame; z < (int)(m_frame + m_frameLength) && producer.is_valid(); z++) {
-        if (m_stopAudioThumbs) break;
-        val = (int)((z - m_frame) / (m_frame + m_frameLength) * 100.0);
-        if (last_val != val && val > 1) {
-            m_clipManager->setThumbsProgress(i18n("Creating thumbnail for %1", m_url.fileName()), val);
-            last_val = val;
-        }
-        producer.seek(z);
-        mlt_frame = producer.get_frame();
-        if (mlt_frame && mlt_frame->is_valid()) {
-            int m_samples = mlt_sample_calculator(framesPerSecond, m_frequency, mlt_frame_get_position(mlt_frame->get_frame()));
-            qint16* m_pcm = static_cast<qint16*>(mlt_frame->get_audio(m_audioFormat, m_frequency, m_channels, m_samples));
-            for (int c = 0; c < m_channels; c++) {
-                QByteArray m_array;
-                m_array.resize(m_arrayWidth);
-                for (int i = 0; i < m_array.size(); i++) {
-                    m_array[i] = ((*(m_pcm + c + i * m_samples / m_array.size())) >> 9) + 127 / 2 ;
-                }
-                m_audioThumbFile.write(m_array);
-
-            }
-        } else {
-            m_audioThumbFile.write(QByteArray(m_arrayWidth, '\x00'));
-        }
-        delete mlt_frame;
-    }
-    m_audioThumbFile.close();
-    if (m_stopAudioThumbs) {
-        m_audioThumbFile.remove();
-    } else {
-        slotAudioThumbOver();
-    }
-}
-
-void KThumb::slotAudioThumbOver()
-{
-    m_clipManager->setThumbsProgress(i18n("Creating thumbnail for %1", m_url.fileName()), -1);
-    m_clipManager->endAudioThumbsGeneration(m_id);
-}
-
-void KThumb::askForAudioThumbs(const QString &id)
-{
-    m_clipManager->askForAudioThumb(id);
+    m_clipManager->askForAudioThumb(m_id);
 }
 
 #if KDE_IS_VERSION(4,5,0)
index b8bc3d0d1bfb11b0d36f4e2489d2b8608af1159c..142bff41c693970eb6afc086ef0a66febc2db89b 100644 (file)
@@ -56,15 +56,14 @@ class KThumb: public QObject
 Q_OBJECT public:
 
 
-    KThumb(ClipManager *clipManager, KUrl url, const QString &id, const QString &hash, QObject * parent = 0, const char *name = 0);
+    KThumb(ClipManager *clipManager, KUrl url, const QString &id, const QString &hash, QObject * parent = 0);
     ~KThumb();
     void setProducer(Mlt::Producer *producer);
-    void askForAudioThumbs(const QString &id);
     bool hasProducer() const;
     void clearProducer();
     void updateThumbUrl(const QString &hash);
     void extractImage(QList <int> frames);
-    QPixmap extractImage(int frame, int width, int height);
+    QImage extractImage(int frame, int width, int height);
 #if KDE_IS_VERSION(4,5,0)
     /** @brief Request thumbnails for the frame range. */
     void queryIntraThumbs(QList <int> missingFrames);
@@ -79,9 +78,7 @@ public slots:
 //    static QPixmap getImage(QDomElement xml, int frame, int width, int height);
     /* void getImage(KUrl url, int frame, int width, int height);
      void getThumbs(KUrl url, int startframe, int endframe, int width, int height);*/
-    void stopAudioThumbs();
-    void removeAudioThumb();
-    void getAudioThumbs(int channel, double frame, double frameLength, int arrayWidth);
+    void slotCreateAudioThumbs();
     static QPixmap getImage(KUrl url, int frame, int width, int height);
     static QImage getFrame(Mlt::Producer *producer, int framepos, int frameWidth, int displayWidth, int height);
     static QImage getFrame(Mlt::Frame *frame, int frameWidth, int displayWidth, int height);
@@ -91,15 +88,12 @@ public slots:
     static uint imageVariance(QImage image);
 
 private slots:
-    void slotAudioThumbOver();
-    void slotCreateAudioThumbs();
 #if KDE_IS_VERSION(4,5,0)
     /** @brief Fetch all requested frames. */ 
     void slotGetIntraThumbs();
 #endif
 
 private:
-    QFuture<void> m_audioThumbProducer;
     KUrl m_url;
     QString m_thumbFile;
     double m_dar;
@@ -109,13 +103,6 @@ private:
     QString m_id;
     /** @brief Controls the intra frames thumbnails process (cached thumbnails). */
     QFuture<void> m_intra;
-    QFile m_audioThumbFile;
-    bool m_stopAudioThumbs;
-    double m_frame;
-    double m_frameLength;
-    int m_frequency;
-    int m_channels;
-    int m_arrayWidth;
     /** @brief List of frame numbers from which we want to extract thumbnails. */
     QList <int> m_intraFramesQueue;
     QMutex m_mutex;
index 53c880a1e95fa72f6e909d2e0dc9e3de0fd4c371..7745ada7bce829a795b80baf0cbf2f9e809be670 100644 (file)
@@ -40,7 +40,6 @@
 #include "transitionsettings.h"
 #include "renderwidget.h"
 #include "renderer.h"
-#include "audiosignal.h"
 #ifdef USE_JOGSHUTTLE
 #include "jogshuttle.h"
 #include "jogaction.h"
 #include "config-kdenlive.h"
 #include "cliptranscode.h"
 #include "ui_templateclip_ui.h"
-#include "colorscopes/vectorscope.h"
-#include "colorscopes/waveform.h"
-#include "colorscopes/rgbparade.h"
-#include "colorscopes/histogram.h"
-#include "audioscopes/audiospectrum.h"
-#include "audioscopes/spectrogram.h"
+#include "scopes/scopemanager.h"
+#include "scopes/colorscopes/vectorscope.h"
+#include "scopes/colorscopes/waveform.h"
+#include "scopes/colorscopes/rgbparade.h"
+#include "scopes/colorscopes/histogram.h"
+#include "scopes/audioscopes/audiosignal.h"
+#include "scopes/audioscopes/audiospectrum.h"
+#include "scopes/audioscopes/spectrogram.h"
 #include "archivewidget.h"
 #include "databackup/backupwidget.h"
+#include "utils/resourcewidget.h"
 
 
 #include <KApplication>
 #include <QBitmap>
 
 #include <stdlib.h>
+#include <locale.h>
 
 // Uncomment for deeper debugging
 //#define DEBUG_MAINW
@@ -150,13 +153,22 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString &
 #endif
     m_findActivated(false),
     m_stopmotion(NULL)
-{   
+{
     qRegisterMetaType<QVector<int16_t> > ();
     qRegisterMetaType<stringMap> ("stringMap");
     qRegisterMetaType<audioByteArray> ("audioByteArray");
 
     // Init locale
     QLocale systemLocale = QLocale();
+    setlocale(LC_NUMERIC, NULL);
+    char *separator = localeconv()->decimal_point;
+    if (separator != systemLocale.decimalPoint()) {
+        kDebug()<<"------\n!!! system locale is not similar to Qt's locale... be prepared for bugs!!!\n------";
+        // HACK: There is a locale conflict, so set locale to at least have correct decimal point
+        if (strncmp(separator, ".", 1) == 0) systemLocale = QLocale::c();
+        else if (strncmp(separator, ",", 1) == 0) systemLocale = QLocale("fr_FR.UTF-8");
+    }
+
     systemLocale.setNumberOptions(QLocale::OmitGroupSeparator);
     QLocale::setDefault(systemLocale);
 
@@ -208,34 +220,36 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString &
 
     m_clipMonitorDock = new QDockWidget(i18n("Clip Monitor"), this);
     m_clipMonitorDock->setObjectName("clip_monitor");
-    m_clipMonitor = new Monitor("clip", m_monitorManager, QString(), m_timelineArea);
+    m_clipMonitor = new Monitor(Kdenlive::clipMonitor, m_monitorManager, QString(), m_timelineArea);
     m_clipMonitorDock->setWidget(m_clipMonitor);
-    
+
     // Connect the project list
-    connect(m_projectList, SIGNAL(clipSelected(DocClipBase *, QPoint)), m_clipMonitor, SLOT(slotSetClipProducer(DocClipBase *, QPoint)));
-    connect(m_projectList, SIGNAL(raiseClipMonitor()), m_clipMonitor, SLOT(activateMonitor()));
+    connect(m_projectList, SIGNAL(clipSelected(DocClipBase *, QPoint, bool)), m_clipMonitor, SLOT(slotSetClipProducer(DocClipBase *, QPoint, bool)));
+    connect(m_projectList, SIGNAL(raiseClipMonitor()), m_clipMonitor, SLOT(slotActivateMonitor()));
     connect(m_projectList, SIGNAL(loadingIsOver()), this, SLOT(slotElapsedTime()));
     connect(m_projectList, SIGNAL(displayMessage(const QString&, int)), this, SLOT(slotGotProgressInfo(const QString&, int)));
     connect(m_projectList, SIGNAL(updateRenderStatus()), this, SLOT(slotCheckRenderStatus()));
     connect(m_projectList, SIGNAL(clipNeedsReload(const QString&)),this, SLOT(slotUpdateClip(const QString &)));
     connect(m_projectList, SIGNAL(updateProfile(const QString &)), this, SLOT(slotUpdateProjectProfile(const QString &)));
-    connect(m_projectList, SIGNAL(refreshClip(const QString &, bool)), m_monitorManager, SLOT(slotRefreshCurrentMonitor()));
+    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");
-    m_projectMonitor = new Monitor("project", m_monitorManager, QString());
+    m_projectMonitor = new Monitor(Kdenlive::projectMonitor, m_monitorManager, QString());
     m_projectMonitorDock->setWidget(m_projectMonitor);
 
 #ifndef Q_WS_MAC
     m_recMonitorDock = new QDockWidget(i18n("Record Monitor"), this);
     m_recMonitorDock->setObjectName("record_monitor");
-    m_recMonitor = new RecMonitor("record", m_monitorManager);
+    m_recMonitor = new RecMonitor(Kdenlive::recordMonitor, m_monitorManager);
     m_recMonitorDock->setWidget(m_recMonitor);
     connect(m_recMonitor, SIGNAL(addProjectClip(KUrl)), this, SLOT(slotAddProjectClip(KUrl)));
     connect(m_recMonitor, SIGNAL(addProjectClipList(KUrl::List)), this, SLOT(slotAddProjectClipList(KUrl::List)));
     connect(m_recMonitor, SIGNAL(showConfigDialog(int, int)), this, SLOT(slotPreferences(int, int)));
+
 #endif /* ! Q_WS_MAC */
     m_monitorManager->initMonitors(m_clipMonitor, m_projectMonitor, m_recMonitor);
 
@@ -244,7 +258,7 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString &
     m_notesWidget = new NotesWidget();
     connect(m_notesWidget, SIGNAL(insertNotesTimecode()), this, SLOT(slotInsertNotesTimecode()));
     connect(m_notesWidget, SIGNAL(seekProject(int)), m_projectMonitor->render, SLOT(seekToFrame(int)));
-    
+
     m_notesWidget->setTabChangesFocus(true);
 #if KDE_IS_VERSION(4,4,0)
     m_notesWidget->setClickMessage(i18n("Enter your project notes here ..."));
@@ -257,6 +271,7 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString &
     m_effectStack = new EffectStackView2(m_projectMonitor);
     m_effectStackDock->setWidget(m_effectStack);
     addDockWidget(Qt::TopDockWidgetArea, m_effectStackDock);
+    connect(m_effectStack, SIGNAL(startFilterJob(ItemInfo, const QString&,const QString&,const QString&,const QString&,const QString&,const QString&,const QString&)), m_projectList, SLOT(slotStartFilterJob(ItemInfo, const QString&,const QString&,const QString&,const QString&,const QString&,const QString&,const QString&)));
 
     m_transitionConfigDock = new QDockWidget(i18n("Transition"), this);
     m_transitionConfigDock->setObjectName("transition");
@@ -270,97 +285,55 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString &
     m_effectListDock->setWidget(m_effectList);
     addDockWidget(Qt::TopDockWidgetArea, m_effectListDock);
 
-    m_vectorscope = new Vectorscope(m_monitorManager);
+    m_scopeManager = new ScopeManager(m_monitorManager);
+    m_vectorscope = new Vectorscope();
     m_vectorscopeDock = new QDockWidget(i18n("Vectorscope"), this);
     m_vectorscopeDock->setObjectName(m_vectorscope->widgetName());
     m_vectorscopeDock->setWidget(m_vectorscope);
     addDockWidget(Qt::TopDockWidgetArea, m_vectorscopeDock);
-    connect(m_vectorscopeDock, SIGNAL(visibilityChanged(bool)), m_vectorscope, SLOT(forceUpdate(bool)));
-    connect(m_vectorscopeDock, SIGNAL(visibilityChanged(bool)), this, SLOT(slotUpdateGfxScopeFrameRequest()));
-    connect(m_vectorscope, SIGNAL(requestAutoRefresh(bool)), this, SLOT(slotUpdateGfxScopeFrameRequest()));
-    m_gfxScopesList.append(m_vectorscopeDock);
+    m_scopeManager->addScope(m_vectorscope, m_vectorscopeDock);
 
-    m_waveform = new Waveform(m_monitorManager);
+    m_waveform = new Waveform();
     m_waveformDock = new QDockWidget(i18n("Waveform"), this);
     m_waveformDock->setObjectName(m_waveform->widgetName());
     m_waveformDock->setWidget(m_waveform);
     addDockWidget(Qt::TopDockWidgetArea, m_waveformDock);
-    connect(m_waveformDock, SIGNAL(visibilityChanged(bool)), m_waveform, SLOT(forceUpdate(bool)));
-    connect(m_waveformDock, SIGNAL(visibilityChanged(bool)), this, SLOT(slotUpdateGfxScopeFrameRequest()));
-    connect(m_waveform, SIGNAL(requestAutoRefresh(bool)), this, SLOT(slotUpdateGfxScopeFrameRequest()));
-    m_gfxScopesList.append(m_waveformDock);
+    m_scopeManager->addScope(m_waveform, m_waveformDock);
 
-    m_RGBParade = new RGBParade(m_monitorManager);
+    m_RGBParade = new RGBParade();
     m_RGBParadeDock = new QDockWidget(i18n("RGB Parade"), this);
     m_RGBParadeDock->setObjectName(m_RGBParade->widgetName());
     m_RGBParadeDock->setWidget(m_RGBParade);
     addDockWidget(Qt::TopDockWidgetArea, m_RGBParadeDock);
-    connect(m_RGBParadeDock, SIGNAL(visibilityChanged(bool)), m_RGBParade, SLOT(forceUpdate(bool)));
-    connect(m_RGBParadeDock, SIGNAL(visibilityChanged(bool)), this, SLOT(slotUpdateGfxScopeFrameRequest()));
-    connect(m_RGBParade, SIGNAL(requestAutoRefresh(bool)), this, SLOT(slotUpdateGfxScopeFrameRequest()));
-    m_gfxScopesList.append(m_RGBParadeDock);
+    m_scopeManager->addScope(m_RGBParade, m_RGBParadeDock);
 
-    m_histogram = new Histogram(m_monitorManager);
+    m_histogram = new Histogram();
     m_histogramDock = new QDockWidget(i18n("Histogram"), this);
     m_histogramDock->setObjectName(m_histogram->widgetName());
     m_histogramDock->setWidget(m_histogram);
     addDockWidget(Qt::TopDockWidgetArea, m_histogramDock);
-    connect(m_histogramDock, SIGNAL(visibilityChanged(bool)), m_histogram, SLOT(forceUpdate(bool)));
-    connect(m_histogramDock, SIGNAL(visibilityChanged(bool)), this, SLOT(slotUpdateGfxScopeFrameRequest()));
-    connect(m_histogram, SIGNAL(requestAutoRefresh(bool)), this, SLOT(slotUpdateGfxScopeFrameRequest()));
-    m_gfxScopesList.append(m_histogramDock);
-
+    m_scopeManager->addScope(m_histogram, m_histogramDock);
 
     m_audiosignal = new AudioSignal;
     m_audiosignalDock = new QDockWidget(i18n("Audio Signal"), this);
     m_audiosignalDock->setObjectName("audiosignal");
     m_audiosignalDock->setWidget(m_audiosignal);
     addDockWidget(Qt::TopDockWidgetArea, m_audiosignalDock);
-    connect(m_audiosignalDock, SIGNAL(visibilityChanged(bool)), this, SLOT(slotUpdateAudioScopeFrameRequest()));
-    connect(m_audiosignal, SIGNAL(updateAudioMonitoring()), this, SLOT(slotUpdateAudioScopeFrameRequest()));
+    m_scopeManager->addScope(m_audiosignal, m_audiosignalDock);
 
     m_audioSpectrum = new AudioSpectrum();
     m_audioSpectrumDock = new QDockWidget(i18n("AudioSpectrum"), this);
     m_audioSpectrumDock->setObjectName(m_audioSpectrum->widgetName());
     m_audioSpectrumDock->setWidget(m_audioSpectrum);
     addDockWidget(Qt::TopDockWidgetArea, m_audioSpectrumDock);
-    m_audioScopesList.append(m_audioSpectrum);
-    connect(m_audioSpectrumDock, SIGNAL(visibilityChanged(bool)), this, SLOT(slotUpdateAudioScopeFrameRequest()));
-    connect(m_audioSpectrum, SIGNAL(requestAutoRefresh(bool)), this, SLOT(slotUpdateAudioScopeFrameRequest()));
+    m_scopeManager->addScope(m_audioSpectrum, m_audioSpectrumDock);
 
     m_spectrogram = new Spectrogram();
     m_spectrogramDock = new QDockWidget(i18n("Spectrogram"), this);
     m_spectrogramDock->setObjectName(m_spectrogram->widgetName());
     m_spectrogramDock->setWidget(m_spectrogram);
     addDockWidget(Qt::TopDockWidgetArea, m_spectrogramDock);
-    m_audioScopesList.append(m_spectrogram);
-    connect(m_audioSpectrumDock, SIGNAL(visibilityChanged(bool)), this, SLOT(slotUpdateAudioScopeFrameRequest()));
-    connect(m_audioSpectrum, SIGNAL(requestAutoRefresh(bool)), this, SLOT(slotUpdateAudioScopeFrameRequest()));
-
-    // Connect the audio signal to the audio scope slots
-    bool b = true;
-    if (m_projectMonitor) {
-        qDebug() << "project monitor connected";
-        b &= connect(m_projectMonitor->render, SIGNAL(audioSamplesSignal(QVector<int16_t>, int, int, int)),
-                     m_audioSpectrum, SLOT(slotReceiveAudio(QVector<int16_t>, int, int, int)));
-        b &= connect(m_projectMonitor->render, SIGNAL(audioSamplesSignal(const QVector<int16_t>&, const int&, const int&, const int&)),
-                     m_audiosignal, SLOT(slotReceiveAudio(const QVector<int16_t>&, const int&, const int&, const int&)));
-        b &= connect(m_projectMonitor->render, SIGNAL(audioSamplesSignal(QVector<int16_t>,int,int,int)),
-                     m_spectrogram, SLOT(slotReceiveAudio(QVector<int16_t>,int,int,int)));
-    }
-    if (m_clipMonitor) {
-        qDebug() << "clip monitor connected";
-        b &= connect(m_clipMonitor->render, SIGNAL(audioSamplesSignal(QVector<int16_t>, int, int, int)),
-                     m_audioSpectrum, SLOT(slotReceiveAudio(QVector<int16_t>, int, int, int)));
-        b &= connect(m_clipMonitor->render, SIGNAL(audioSamplesSignal(const QVector<int16_t>&, int, int, int)),
-                     m_audiosignal, SLOT(slotReceiveAudio(const QVector<int16_t>&, int, int, int)));
-        b &= connect(m_clipMonitor->render, SIGNAL(audioSamplesSignal(QVector<int16_t>,int,int,int)),
-                     m_spectrogram, SLOT(slotReceiveAudio(QVector<int16_t>,int,int,int)));
-    }
-    // Ensure connections were set up correctly
-    Q_ASSERT(b);
-
-
+    m_scopeManager->addScope(m_spectrogram, m_spectrogramDock);
 
     // Add monitors here to keep them at the right of the window
     addDockWidget(Qt::TopDockWidgetArea, m_clipMonitorDock);
@@ -453,7 +426,7 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString &
     m_effectActions = new KActionCategory(i18n("Effects"), actionCollection());
     m_effectList->reloadEffectList(m_effectsMenu, m_effectActions);
     m_effectsActionCollection->readSettings();
-    
+
     setupGUI();
 
     // Find QDockWidget tab bars and show / hide widget title bars on right click
@@ -465,6 +438,9 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString &
 
     /*ScriptingPart* sp = new ScriptingPart(this, QStringList());
     guiFactory()->addClient(sp);*/
+    QMenu *trackMenu = (QMenu*)(factory()->container("track_menu", this));
+    if (trackMenu) trackMenu->addActions(m_tracksActionCollection->actions());
+
 
     QMenu *saveLayout = (QMenu*)(factory()->container("layout_save_as", this));
     if (saveLayout)
@@ -485,6 +461,7 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString &
     clipInTimeline->setIcon(KIcon("go-jump"));
        QHash<QString,QMenu*> menus;
        menus.insert("addMenu",static_cast<QMenu*>(factory()->container("generators", this)));
+        menus.insert("extractAudioMenu",static_cast<QMenu*>(factory()->container("extract_audio", this)));
        menus.insert("transcodeMenu",static_cast<QMenu*>(factory()->container("transcoders", this)));
        menus.insert("stabilizeMenu",static_cast<QMenu*>(factory()->container("stabilize", this)));
        menus.insert("inTimelineMenu",clipInTimeline);
@@ -590,8 +567,6 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString &
 
     connect(m_projectMonitorDock, SIGNAL(visibilityChanged(bool)), m_projectMonitor, SLOT(refreshMonitor(bool)));
     connect(m_clipMonitorDock, SIGNAL(visibilityChanged(bool)), m_clipMonitor, SLOT(refreshMonitor(bool)));
-    connect(m_monitorManager, SIGNAL(checkColorScopes()), this, SLOT(slotUpdateColorScopes()));
-    connect(m_monitorManager, SIGNAL(clearScopes()), this, SLOT(slotClearColorScopes()));
     connect(m_effectList, SIGNAL(addEffect(const QDomElement)), this, SLOT(slotAddEffect(const QDomElement)));
     connect(m_effectList, SIGNAL(reloadEffects()), this, SLOT(slotReloadEffects()));
 
@@ -627,7 +602,7 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString &
 
     actionCollection()->addAssociatedWidget(m_clipMonitor->container());
     actionCollection()->addAssociatedWidget(m_projectMonitor->container());
-    
+
     // Populate encoding profiles
     KConfig conf("encodingprofiles.rc", KConfig::FullConfig, "appdata");
     if (KdenliveSettings::proxyparams().isEmpty() || KdenliveSettings::proxyextension().isEmpty()) {
@@ -684,6 +659,8 @@ MainWindow::~MainWindow()
     delete m_clipMonitor;
     delete m_shortcutRemoveFocus;
     delete[] m_transitions;
+    delete m_monitorManager;
+    delete m_scopeManager;
     Mlt::Factory::close();
 }
 
@@ -842,10 +819,10 @@ void MainWindow::activateShuttleDevice()
     delete m_jogProcess;
     m_jogProcess = NULL;
     if (KdenliveSettings::enableshuttle() == false) return;
-    
+
     m_jogProcess = new JogShuttle(KdenliveSettings::shuttledevice());
     m_jogShuttle = new JogShuttleAction(m_jogProcess, JogShuttleConfig::actionMap(KdenliveSettings::shuttlebuttons()));
-    
+
     connect(m_jogShuttle, SIGNAL(rewindOneFrame()), m_monitorManager, SLOT(slotRewindOneFrame()));
     connect(m_jogShuttle, SIGNAL(forwardOneFrame()), m_monitorManager, SLOT(slotForwardOneFrame()));
     connect(m_jogShuttle, SIGNAL(rewind(double)), m_monitorManager, SLOT(slotRewind(double)));
@@ -912,7 +889,7 @@ void MainWindow::slotConnectMonitors()
     connect(m_projectMonitor->render, SIGNAL(replyGetFileProperties(const QString &, Mlt::Producer*, const stringMap &, const stringMap &, bool)), m_projectList, SLOT(slotReplyGetFileProperties(const QString &, Mlt::Producer*, const stringMap &, const stringMap &, bool)));
 
     connect(m_projectMonitor->render, SIGNAL(removeInvalidClip(const QString &, bool)), m_projectList, SLOT(slotRemoveInvalidClip(const QString &, bool)));
-    
+
     connect(m_projectMonitor->render, SIGNAL(removeInvalidProxy(const QString &, bool)), m_projectList, SLOT(slotRemoveInvalidProxy(const QString &, bool)));
 
     connect(m_clipMonitor, SIGNAL(refreshClipThumbnail(const QString &, bool)), m_projectList, SLOT(slotRefreshClipThumbnail(const QString &, bool)));
@@ -1279,7 +1256,7 @@ void MainWindow::setupActions()
     KAction *archiveProject =  new KAction(KIcon("file-save"), i18n("Archive Project"), this);
     collection.addAction("archive_project", archiveProject);
     connect(archiveProject, SIGNAL(triggered(bool)), this, SLOT(slotArchiveProject()));
-    
+
 
     KAction *markIn = collection.addAction("mark_in");
     markIn->setText(i18n("Set Zone In"));
@@ -1299,7 +1276,7 @@ void MainWindow::setupActions()
     KAction *fullMon = collection.addAction("monitor_fullscreen");
     fullMon->setText(i18n("Switch monitor fullscreen"));
     fullMon->setIcon(KIcon("view-fullscreen"));
-    connect(fullMon, SIGNAL(triggered(bool)), this, SLOT(slotSwitchFullscreen()));
+    connect(fullMon, SIGNAL(triggered(bool)), m_monitorManager, SLOT(slotSwitchFullscreen()));
 
     KAction *insertTree = collection.addAction("insert_project_tree");
     insertTree->setText(i18n("Insert zone in project tree"));
@@ -1527,18 +1504,29 @@ void MainWindow::setupActions()
     collection.addAction("delete_space", removeSpace);
     connect(removeSpace, SIGNAL(triggered()), this, SLOT(slotRemoveSpace()));
 
-    KAction *insertTrack = new KAction(KIcon(), i18n("Insert Track"), this);
-    collection.addAction("insert_track", insertTrack);
+    m_tracksActionCollection = new KActionCollection(this, KGlobal::mainComponent());
+    m_tracksActionCollection->addAssociatedWidget(m_timelineArea);
+
+    KAction *insertTrack = new KAction(KIcon(), i18n("Insert Track"), m_tracksActionCollection);
+    m_tracksActionCollection->addAction("insert_track", insertTrack);
     connect(insertTrack, SIGNAL(triggered()), this, SLOT(slotInsertTrack()));
 
-    KAction *deleteTrack = new KAction(KIcon(), i18n("Delete Track"), this);
-    collection.addAction("delete_track", deleteTrack);
+    KAction *deleteTrack = new KAction(KIcon(), i18n("Delete Track"), m_tracksActionCollection);
+    m_tracksActionCollection->addAction("delete_track", deleteTrack);
     connect(deleteTrack, SIGNAL(triggered()), this, SLOT(slotDeleteTrack()));
 
-    KAction *configTracks = new KAction(KIcon("configure"), i18n("Configure Tracks"), this);
-    collection.addAction("config_tracks", configTracks);
+    KAction *configTracks = new KAction(KIcon("configure"), i18n("Configure Tracks"), m_tracksActionCollection);
+    m_tracksActionCollection->addAction("config_tracks", configTracks);
     connect(configTracks, SIGNAL(triggered()), this, SLOT(slotConfigTrack()));
 
+    KAction *selectTrack = new KAction(KIcon(), i18n("Select All in Current Track"), m_tracksActionCollection);
+    connect(selectTrack, SIGNAL(triggered()), this, SLOT(slotSelectTrack()));
+    m_tracksActionCollection->addAction("select_track", selectTrack);
+
+    QAction *selectAll = KStandardAction::selectAll(this, SLOT(slotSelectAllTracks()), m_tracksActionCollection);
+    selectAll->setShortcutContext(Qt::WidgetWithChildrenShortcut);
+    m_tracksActionCollection->addAction("select_all_tracks", selectAll);
+
     KAction *addGuide = new KAction(KIcon("document-new"), i18n("Add Guide"), this);
     collection.addAction("add_guide", addGuide);
     connect(addGuide, SIGNAL(triggered()), this, SLOT(slotAddGuide()));
@@ -1625,6 +1613,10 @@ void MainWindow::setupActions()
     collection.addAction("add_folder", addFolderButton);
     connect(addFolderButton , SIGNAL(triggered()), m_projectList, SLOT(slotAddFolder()));
 
+    QAction *downloadResources = new KAction(KIcon("download"), i18n("Online Resources"), this);
+    collection.addAction("download_resource", downloadResources);
+    connect(downloadResources , SIGNAL(triggered()), this, SLOT(slotDownloadResources()));
+
     QAction *clipProperties = new KAction(KIcon("document-edit"), i18n("Clip Properties"), this);
     collection.addAction("clip_properties", clipProperties);
     clipProperties->setData("clip_properties");
@@ -1655,7 +1647,7 @@ void MainWindow::setupActions()
     proxyClip->setCheckable(true);
     proxyClip->setChecked(false);
     connect(proxyClip, SIGNAL(toggled(bool)), m_projectList, SLOT(slotProxyCurrentItem(bool)));
-    
+
     QAction *stopMotion = new KAction(KIcon("image-x-generic"), i18n("Stop Motion Capture"), this);
     collection.addAction("stopmotion", stopMotion);
     connect(stopMotion , SIGNAL(triggered()), this, SLOT(slotOpenStopmotion()));
@@ -1667,6 +1659,7 @@ void MainWindow::setupActions()
     addClips->addAction(addTitleClip);
     addClips->addAction(addTitleTemplateClip);
     addClips->addAction(addFolderButton);
+    addClips->addAction(downloadResources);
 
     addClips->addAction(reloadClip);
     addClips->addAction(proxyClip);
@@ -1827,13 +1820,14 @@ void MainWindow::newFile(bool showProjectSettings, bool force)
     QString profileName = KdenliveSettings::default_profile();
     KUrl projectFolder = KdenliveSettings::defaultprojectfolder();
     QMap <QString, QString> documentProperties;
+    QMap <QString, QString> documentMetadata;
     QPoint projectTracks(KdenliveSettings::videotracks(), KdenliveSettings::audiotracks());
     if (!showProjectSettings) {
         if (!KdenliveSettings::activatetabs())
             if (!closeCurrentDocument())
                 return;
     } else {
-        ProjectSettings *w = new ProjectSettings(NULL, QStringList(), projectTracks.x(), projectTracks.y(), KdenliveSettings::defaultprojectfolder(), false, true, this);
+        ProjectSettings *w = new ProjectSettings(NULL, QMap <QString, QString> (), QStringList(), projectTracks.x(), projectTracks.y(), KdenliveSettings::defaultprojectfolder(), false, true, this);
         if (w->exec() != QDialog::Accepted)
             return;
         if (!KdenliveSettings::activatetabs())
@@ -1853,15 +1847,16 @@ void MainWindow::newFile(bool showProjectSettings, bool force)
         documentProperties.insert("proxyextension", w->proxyExtension());
         documentProperties.insert("generateimageproxy", QString::number((int) w->generateImageProxy()));
         documentProperties.insert("proxyimageminsize", QString::number(w->proxyImageMinSize()));
+        documentMetadata = w->metadata();
         delete w;
     }
     m_timelineArea->setEnabled(true);
     m_projectList->setEnabled(true);
     bool openBackup;
-    KdenliveDoc *doc = new KdenliveDoc(KUrl(), projectFolder, m_commandStack, profileName, documentProperties, projectTracks, m_projectMonitor->render, m_notesWidget, &openBackup, this);
+    KdenliveDoc *doc = new KdenliveDoc(KUrl(), projectFolder, m_commandStack, profileName, documentProperties, documentMetadata, projectTracks, m_projectMonitor->render, m_notesWidget, &openBackup, this);
     doc->m_autosave = new KAutoSaveFile(KUrl(), doc);
     bool ok;
-    TrackView *trackView = new TrackView(doc, &ok, this);
+    TrackView *trackView = new TrackView(doc, m_tracksActionCollection->actions(), &ok, this);
     m_timelineArea->addTab(trackView, KIcon("kdenlive"), doc->description());
     if (!ok) {
         // MLT is broken
@@ -1875,7 +1870,7 @@ void MainWindow::newFile(bool showProjectSettings, bool force)
         connectDocument(trackView, doc);
     } else
         m_timelineArea->setTabBarHidden(false);
-    m_monitorManager->activateMonitor("clip");
+    m_monitorManager->activateMonitor(Kdenlive::clipMonitor);
     m_closeAction->setEnabled(m_timelineArea->count() > 1);
 }
 
@@ -1951,9 +1946,10 @@ bool MainWindow::saveFileAs(const QString &outputFileName)
     // Save timeline thumbnails
     m_activeTimeline->projectView()->saveThumbnails();
     m_activeDocument->setUrl(KUrl(outputFileName));
+    QByteArray hash = QCryptographicHash::hash(KUrl(outputFileName).encodedPath(), QCryptographicHash::Md5).toHex();
     if (m_activeDocument->m_autosave == NULL) {
-        m_activeDocument->m_autosave = new KAutoSaveFile(KUrl(outputFileName), this);
-    } else m_activeDocument->m_autosave->setManagedFile(KUrl(outputFileName));
+        m_activeDocument->m_autosave = new KAutoSaveFile(KUrl(hash), this);
+    } else m_activeDocument->m_autosave->setManagedFile(KUrl(hash));
     setCaption(m_activeDocument->description());
     m_timelineArea->setTabText(m_timelineArea->currentIndex(), m_activeDocument->description());
     m_timelineArea->setTabToolTip(m_timelineArea->currentIndex(), m_activeDocument->url().path());
@@ -2029,7 +2025,7 @@ void MainWindow::openFile(const KUrl &url)
         KMessageBox::sorry(this, i18n("File %1 is not a Kdenlive project file", url.path()));
         return;
     }
-    
+
     // Check if the document is already opened
     const int ct = m_timelineArea->count();
     bool isOpened = false;
@@ -2050,13 +2046,14 @@ void MainWindow::openFile(const KUrl &url)
     if (!KdenliveSettings::activatetabs()) if (!closeCurrentDocument()) return;
 
     // Check for backup file
-    QList<KAutoSaveFile *> staleFiles = KAutoSaveFile::staleFiles(url);
+    QByteArray hash = QCryptographicHash::hash(url.encodedPath(), QCryptographicHash::Md5).toHex();
+    QList<KAutoSaveFile *> staleFiles = KAutoSaveFile::staleFiles(KUrl(hash));
     if (!staleFiles.isEmpty()) {
         if (KMessageBox::questionYesNo(this,
                                        i18n("Auto-saved files exist. Do you want to recover them now?"),
                                        i18n("File Recovery"),
                                        KGuiItem(i18n("Recover")), KGuiItem(i18n("Don't recover"))) == KMessageBox::Yes) {
-            recoverFiles(staleFiles);
+            recoverFiles(staleFiles, url);
             return;
         } else {
             // remove the stale files
@@ -2081,7 +2078,7 @@ void MainWindow::doOpenFile(const KUrl &url, KAutoSaveFile *stale)
         delete m_stopmotion;
         m_stopmotion = NULL;
     }
-    
+
     m_timer.start();
     KProgressDialog progressDialog(this, i18n("Loading project"), i18n("Loading project"));
     progressDialog.setAllowCancel(false);
@@ -2091,7 +2088,7 @@ void MainWindow::doOpenFile(const KUrl &url, KAutoSaveFile *stale)
     qApp->processEvents();
 
     bool openBackup;
-    KdenliveDoc *doc = new KdenliveDoc(url, KdenliveSettings::defaultprojectfolder(), m_commandStack, KdenliveSettings::default_profile(), QMap <QString, QString> (), QPoint(KdenliveSettings::videotracks(), KdenliveSettings::audiotracks()), m_projectMonitor->render, m_notesWidget, &openBackup, this, &progressDialog);
+    KdenliveDoc *doc = new KdenliveDoc(stale ? KUrl(stale->fileName()) : url, KdenliveSettings::defaultprojectfolder(), m_commandStack, KdenliveSettings::default_profile(), QMap <QString, QString> (), QMap <QString, QString> (), QPoint(KdenliveSettings::videotracks(), KdenliveSettings::audiotracks()), m_projectMonitor->render, m_notesWidget, &openBackup, this, &progressDialog);
 
     progressDialog.progressBar()->setValue(1);
     progressDialog.progressBar()->setMaximum(4);
@@ -2099,11 +2096,12 @@ void MainWindow::doOpenFile(const KUrl &url, KAutoSaveFile *stale)
     qApp->processEvents();
 
     if (stale == NULL) {
-        stale = new KAutoSaveFile(url, doc);
+        QByteArray hash = QCryptographicHash::hash(url.encodedPath(), QCryptographicHash::Md5).toHex();
+        stale = new KAutoSaveFile(KUrl(hash), doc);
         doc->m_autosave = stale;
     } else {
         doc->m_autosave = stale;
-        doc->setUrl(stale->managedFile());
+        doc->setUrl(url);//stale->managedFile());
         doc->setModified(true);
         stale->setParent(doc);
     }
@@ -2113,7 +2111,7 @@ void MainWindow::doOpenFile(const KUrl &url, KAutoSaveFile *stale)
     qApp->processEvents();
 
     bool ok;
-    TrackView *trackView = new TrackView(doc, &ok, this);
+    TrackView *trackView = new TrackView(doc, m_tracksActionCollection->actions(), &ok, this);
     connectDocument(trackView, doc);
     progressDialog.progressBar()->setValue(3);
     qApp->processEvents();
@@ -2139,7 +2137,7 @@ void MainWindow::doOpenFile(const KUrl &url, KAutoSaveFile *stale)
     if (openBackup) slotOpenBackupDialog(url);
 }
 
-void MainWindow::recoverFiles(QList<KAutoSaveFile *> staleFiles)
+void MainWindow::recoverFiles(QList<KAutoSaveFile *> staleFiles, const KUrl &originUrl)
 {
     foreach(KAutoSaveFile * stale, staleFiles) {
         /*if (!stale->open(QIODevice::QIODevice::ReadOnly)) {
@@ -2150,7 +2148,7 @@ void MainWindow::recoverFiles(QList<KAutoSaveFile *> staleFiles)
         }*/
         kDebug() << "// OPENING RECOVERY: " << stale->fileName() << "\nMANAGED: " << stale->managedFile().path();
         // the stalefiles also contain ".lock" files so we must ignore them... bug in KAutoSaveFile?
-        if (!stale->fileName().endsWith(".lock")) doOpenFile(KUrl(stale->fileName()), stale);
+        if (!stale->fileName().endsWith(".lock")) doOpenFile(originUrl, stale);
         else KIO::NetAccess::del(KUrl(stale->fileName()), this);
     }
 }
@@ -2259,7 +2257,7 @@ void MainWindow::slotDetectAudioDriver()
 void MainWindow::slotEditProjectSettings()
 {
     QPoint p = m_activeDocument->getTracksCount();
-    ProjectSettings *w = new ProjectSettings(m_projectList, m_activeTimeline->projectView()->extractTransitionsLumas(), p.x(), p.y(), m_activeDocument->projectFolder().path(), true, !m_activeDocument->isModified(), this);
+    ProjectSettings *w = new ProjectSettings(m_projectList, m_activeDocument->metadata(), m_activeTimeline->projectView()->extractTransitionsLumas(), p.x(), p.y(), m_activeDocument->projectFolder().path(), true, !m_activeDocument->isModified(), this);
     connect(w, SIGNAL(disableProxies()), this, SLOT(slotDisableProxies()));
 
     if (w->exec() == QDialog::Accepted) {
@@ -2305,6 +2303,7 @@ void MainWindow::slotEditProjectSettings()
             m_activeDocument->setModified();
             slotUpdateProxySettings();
         }
+        m_activeDocument->setMetadata(w->metadata());
     }
     delete w;
 }
@@ -2473,10 +2472,10 @@ void MainWindow::connectDocument(TrackView *trackView, KdenliveDoc *doc)   //cha
             disconnect(m_activeTimeline->projectView(), SIGNAL(transitionItemSelected(Transition*, int, QPoint, bool)), m_projectMonitor, SLOT(slotSetSelectedClip(Transition*)));
             disconnect(m_activeTimeline->projectView(), SIGNAL(playMonitor()), m_projectMonitor, SLOT(slotPlay()));
             disconnect(m_activeTimeline->projectView(), SIGNAL(displayMessage(const QString&, MessageType)), m_messageLabel, SLOT(setMessage(const QString&, MessageType)));
-            disconnect(m_activeTimeline->projectView(), SIGNAL(showClipFrame(DocClipBase *, QPoint, const int)), m_clipMonitor, SLOT(slotSetClipProducer(DocClipBase *, QPoint, const int)));
-            disconnect(m_activeTimeline, SIGNAL(cursorMoved()), m_projectMonitor, SLOT(activateMonitor()));
-            disconnect(m_activeTimeline, SIGNAL(insertTrack(int)), this, SLOT(slotInsertTrack(int)));
-            disconnect(m_activeTimeline, SIGNAL(deleteTrack(int)), this, SLOT(slotDeleteTrack(int)));
+            disconnect(m_activeTimeline->projectView(), SIGNAL(showClipFrame(DocClipBase *, QPoint, bool, const int)), m_clipMonitor, SLOT(slotSetClipProducer(DocClipBase *, QPoint, bool, const int)));
+            disconnect(m_projectList, SIGNAL(gotFilterJobResults(const QString &, int, int, const QString &, stringMap)), m_activeTimeline->projectView(), SLOT(slotGotFilterJobResults(const QString &, int, int, const QString &, stringMap)));
+
+            disconnect(m_activeTimeline, SIGNAL(cursorMoved()), m_projectMonitor, SLOT(slotActivateMonitor()));
             disconnect(m_activeTimeline, SIGNAL(configTrack(int)), this, SLOT(slotConfigTrack(int)));
             disconnect(m_activeDocument, SIGNAL(docModified(bool)), this, SLOT(slotUpdateDocumentState(bool)));
             disconnect(m_effectStack, SIGNAL(updateEffect(ClipItem*, int, QDomElement, QDomElement, int)), m_activeTimeline->projectView(), SLOT(slotUpdateClipEffect(ClipItem*, int, QDomElement, QDomElement, int)));
@@ -2488,7 +2487,7 @@ void MainWindow::connectDocument(TrackView *trackView, KdenliveDoc *doc)   //cha
             disconnect(m_effectStack, SIGNAL(displayMessage(const QString&, int)), this, SLOT(slotGotProgressInfo(const QString&, int)));
             disconnect(m_transitionConfig, SIGNAL(transitionUpdated(Transition *, QDomElement)), m_activeTimeline->projectView() , SLOT(slotTransitionUpdated(Transition *, QDomElement)));
             disconnect(m_transitionConfig, SIGNAL(seekTimeline(int)), m_activeTimeline->projectView() , SLOT(setCursorPos(int)));
-            disconnect(m_activeTimeline->projectView(), SIGNAL(activateDocumentMonitor()), m_projectMonitor, SLOT(activateMonitor()));
+            disconnect(m_activeTimeline->projectView(), SIGNAL(activateDocumentMonitor()), m_projectMonitor, SLOT(slotActivateMonitor()));
             disconnect(m_activeTimeline, SIGNAL(zoneMoved(int, int)), this, SLOT(slotZoneMoved(int, int)));
             disconnect(m_projectList, SIGNAL(loadingIsOver()), m_activeTimeline->projectView(), SLOT(slotUpdateAllThumbs()));
             disconnect(m_projectList, SIGNAL(refreshClip(const QString &)), m_activeTimeline->projectView(), SLOT(slotRefreshThumbs(const QString &)));
@@ -2510,8 +2509,6 @@ void MainWindow::connectDocument(TrackView *trackView, KdenliveDoc *doc)   //cha
     connect(m_projectList, SIGNAL(clipNameChanged(const QString, const QString)), trackView->projectView(), SLOT(clipNameChanged(const QString, const QString)));
 
     //connect(trackView, SIGNAL(cursorMoved()), m_projectMonitor, SLOT(activateMonitor()));
-    connect(trackView, SIGNAL(insertTrack(int)), this, SLOT(slotInsertTrack(int)));
-    connect(trackView, SIGNAL(deleteTrack(int)), this, SLOT(slotDeleteTrack(int)));
     connect(trackView, SIGNAL(configTrack(int)), this, SLOT(slotConfigTrack(int)));
     connect(trackView, SIGNAL(updateTracksInfo()), this, SLOT(slotUpdateTrackInfo()));
     connect(trackView, SIGNAL(mousePosition(int)), this, SLOT(slotUpdateMousePosition(int)));
@@ -2532,7 +2529,7 @@ void MainWindow::connectDocument(TrackView *trackView, KdenliveDoc *doc)   //cha
     connect(doc, SIGNAL(docModified(bool)), this, SLOT(slotUpdateDocumentState(bool)));
     connect(doc, SIGNAL(guidesUpdated()), this, SLOT(slotGuidesUpdated()));
     connect(doc, SIGNAL(saveTimelinePreview(const QString &)), trackView, SLOT(slotSaveTimelinePreview(const QString)));
-    
+
     connect(m_notesWidget, SIGNAL(textChanged()), doc, SLOT(setModified()));
 
     connect(trackView->projectView(), SIGNAL(clipItemSelected(ClipItem*, int, bool)), m_effectStack, SLOT(slotClipItemSelected(ClipItem*, int)));
@@ -2549,12 +2546,14 @@ void MainWindow::connectDocument(TrackView *trackView, KdenliveDoc *doc)   //cha
     connect(trackView, SIGNAL(setZoom(int)), this, SLOT(slotSetZoom(int)));
     connect(trackView->projectView(), SIGNAL(displayMessage(const QString&, MessageType)), m_messageLabel, SLOT(setMessage(const QString&, MessageType)));
 
-    connect(trackView->projectView(), SIGNAL(showClipFrame(DocClipBase *, QPoint, const int)), m_clipMonitor, SLOT(slotSetClipProducer(DocClipBase *, QPoint, const int)));
+    connect(trackView->projectView(), SIGNAL(showClipFrame(DocClipBase *, QPoint, bool, const int)), m_clipMonitor, SLOT(slotSetClipProducer(DocClipBase *, QPoint, bool, const int)));
     connect(trackView->projectView(), SIGNAL(playMonitor()), m_projectMonitor, SLOT(slotPlay()));
 
     connect(trackView->projectView(), SIGNAL(clipItemSelected(ClipItem*, int, bool)), m_projectMonitor, SLOT(slotSetSelectedClip(ClipItem*)));
     connect(trackView->projectView(), SIGNAL(transitionItemSelected(Transition*, int, QPoint, bool)), m_projectMonitor, SLOT(slotSetSelectedClip(Transition*)));
 
+    connect(m_projectList, SIGNAL(gotFilterJobResults(const QString &, int, int, const QString &, stringMap)), trackView->projectView(), SLOT(slotGotFilterJobResults(const QString &, int, int, const QString &, stringMap)));
+
     connect(m_effectStack, SIGNAL(updateEffect(ClipItem*, int, QDomElement, QDomElement, int)), trackView->projectView(), SLOT(slotUpdateClipEffect(ClipItem*, int, QDomElement, QDomElement, int)));
     connect(m_effectStack, SIGNAL(updateClipRegion(ClipItem*, int, QString)), trackView->projectView(), SLOT(slotUpdateClipRegion(ClipItem*, int, QString)));
     connect(m_effectStack, SIGNAL(removeEffect(ClipItem*, int, QDomElement)), trackView->projectView(), SLOT(slotDeleteEffect(ClipItem*, int, QDomElement)));
@@ -2567,12 +2566,10 @@ void MainWindow::connectDocument(TrackView *trackView, KdenliveDoc *doc)   //cha
     connect(m_effectStack, SIGNAL(reloadEffects()), this, SLOT(slotReloadEffects()));
     connect(m_effectStack, SIGNAL(displayMessage(const QString&, int)), this, SLOT(slotGotProgressInfo(const QString&, int)));
 
-    connect(trackView->projectView(), SIGNAL(activateDocumentMonitor()), m_projectMonitor, SLOT(activateMonitor()));
+    connect(trackView->projectView(), SIGNAL(activateDocumentMonitor()), m_projectMonitor, SLOT(slotActivateMonitor()));
     connect(trackView, SIGNAL(zoneMoved(int, int)), this, SLOT(slotZoneMoved(int, int)));
     connect(m_projectList, SIGNAL(loadingIsOver()), trackView->projectView(), SLOT(slotUpdateAllThumbs()));
-
-
-    trackView->projectView()->setContextMenu(m_timelineContextMenu, m_timelineContextClipMenu, m_timelineContextTransitionMenu, m_clipTypeGroup, (QMenu*)(factory()->container("marker_menu", this)));
+    trackView->projectView()->setContextMenu(m_timelineContextMenu, m_timelineContextClipMenu, m_timelineContextTransitionMenu, m_clipTypeGroup, static_cast<QMenu*>(factory()->container("marker_menu", this)));
     m_activeTimeline = trackView;
     if (m_renderWidget) {
         slotCheckRenderStatus();
@@ -2601,7 +2598,7 @@ void MainWindow::connectDocument(TrackView *trackView, KdenliveDoc *doc)   //cha
 #endif
     //Update the mouse position display so it will display in DF/NDF format by default based on the project setting.
     slotUpdateMousePosition(0);
-    m_monitorManager->activateMonitor("clip");
+    m_monitorManager->activateMonitor(Kdenlive::clipMonitor);
     // set tool to select tool
     m_buttonSelectTool->setChecked(true);
 }
@@ -2623,6 +2620,7 @@ void MainWindow::slotEditKeys()
     KShortcutsDialog dialog(KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsAllowed, this);
     dialog.addCollection(actionCollection(), i18nc("general keyboard shortcuts", "General"));
     dialog.addCollection(m_effectsActionCollection, i18nc("effects and transitions keyboard shortcuts", "Effects & Transitions"));
+    dialog.addCollection(m_tracksActionCollection, i18nc("timeline track keyboard shortcuts", "Timeline and Tracks"));
     dialog.configure();
 }
 
@@ -2642,14 +2640,14 @@ void MainWindow::slotPreferences(int page, int option)
 
     // KConfigDialog didn't find an instance of this dialog, so lets
     // create it :
-    
+
     // Get the mappable actions in localized form
     QMap<QString, QString> actions;
     KActionCollection* collection = actionCollection();
     foreach (const QString& action_name, m_action_names) {
         actions[collection->action(action_name)->text()] = action_name;
     }
-    
+
     KdenliveSettingsDialog* dialog = new KdenliveSettingsDialog(actions, this);
     connect(dialog, SIGNAL(settingsChanged(const QString&)), this, SLOT(updateConfiguration()));
     connect(dialog, SIGNAL(doResetProfile()), m_monitorManager, SLOT(slotResetProfiles()));
@@ -2686,7 +2684,7 @@ void MainWindow::updateConfiguration()
 
     // Update list of transcoding profiles
     loadTranscoders();
-       loadStabilize();
+    loadStabilize();
 #ifdef USE_JOGSHUTTLE
     activateShuttleDevice();
 #endif
@@ -2921,31 +2919,50 @@ void MainWindow::slotRemoveSpace()
 
 void MainWindow::slotInsertTrack(int ix)
 {
-    m_projectMonitor->activateMonitor();
-    if (m_activeTimeline)
+    m_projectMonitor->slotActivateMonitor();
+    if (m_activeTimeline) {
+        if (ix == -1) ix = m_activeTimeline->projectView()->selectedTrack();
         m_activeTimeline->projectView()->slotInsertTrack(ix);
+    }
     if (m_activeDocument)
         m_transitionConfig->updateProjectFormat(m_activeDocument->mltProfile(), m_activeDocument->timecode(), m_activeDocument->tracksList());
 }
 
 void MainWindow::slotDeleteTrack(int ix)
 {
-    m_projectMonitor->activateMonitor();
-    if (m_activeTimeline)
+    m_projectMonitor->slotActivateMonitor();
+    if (m_activeTimeline) {
+        if (ix == -1) ix = m_activeTimeline->projectView()->selectedTrack();
         m_activeTimeline->projectView()->slotDeleteTrack(ix);
+    }
     if (m_activeDocument)
         m_transitionConfig->updateProjectFormat(m_activeDocument->mltProfile(), m_activeDocument->timecode(), m_activeDocument->tracksList());
 }
 
 void MainWindow::slotConfigTrack(int ix)
 {
-    m_projectMonitor->activateMonitor();
+    m_projectMonitor->slotActivateMonitor();
     if (m_activeTimeline)
         m_activeTimeline->projectView()->slotConfigTracks(ix);
     if (m_activeDocument)
         m_transitionConfig->updateProjectFormat(m_activeDocument->mltProfile(), m_activeDocument->timecode(), m_activeDocument->tracksList());
 }
 
+void MainWindow::slotSelectTrack()
+{
+    m_projectMonitor->slotActivateMonitor();
+    if (m_activeTimeline) {
+        m_activeTimeline->projectView()->slotSelectClipsInTrack();
+    }
+}
+
+void MainWindow::slotSelectAllTracks()
+{
+    m_projectMonitor->slotActivateMonitor();
+    if (m_activeTimeline)
+        m_activeTimeline->projectView()->slotSelectAllClips();
+}
+
 void MainWindow::slotEditGuide()
 {
     if (m_activeTimeline)
@@ -3032,10 +3049,10 @@ void MainWindow::slotEditItemDuration()
         m_activeTimeline->projectView()->editItemDuration();
 }
 
-void MainWindow::slotAddProjectClip(KUrl url)
+void MainWindow::slotAddProjectClip(KUrl url, const QString &comment)
 {
     if (m_activeDocument)
-        m_activeDocument->slotAddClipFile(url, QString());
+        m_activeDocument->slotAddClipFile(url, QString(), QString(), comment);
 }
 
 void MainWindow::slotAddProjectClipList(KUrl::List urls)
@@ -3195,7 +3212,7 @@ void MainWindow::slotShowClipProperties(DocClipBase *clip)
                 else newprops.insert("templatetext", description);
                 //newprops.insert("xmldata", m_projectList->generateTemplateXml(newtemplate, description).toString());
                 if (!newprops.isEmpty()) {
-                    EditClipCommand *command = new EditClipCommand(m_projectList, clip->getId(), clip->properties(), newprops, true);
+                    EditClipCommand *command = new EditClipCommand(m_projectList, clip->getId(), clip->currentProperties(newprops), newprops, true);
                     m_activeDocument->commandStack()->push(command);
                 }
             }
@@ -3210,7 +3227,7 @@ void MainWindow::slotShowClipProperties(DocClipBase *clip)
         if (dia_ui->exec() == QDialog::Accepted) {
             QMap <QString, QString> newprops;
             newprops.insert("xmldata", dia_ui->xml().toString());
-            if (dia_ui->outPoint() != clip->duration().frames(m_activeDocument->fps()) - 1) {
+            if (dia_ui->outPoint() != clip->duration().frames(m_activeDocument->fps())) {
                 // duration changed, we need to update duration
                 newprops.insert("out", QString::number(dia_ui->outPoint()));
                 int currentLength = QString(clip->producerProperty("length")).toInt();
@@ -3225,7 +3242,7 @@ void MainWindow::slotShowClipProperties(DocClipBase *clip)
                     dia_ui->saveTitle(path);
                 } else newprops.insert("resource", QString());
             }
-            EditClipCommand *command = new EditClipCommand(m_projectList, clip->getId(), clip->properties(), newprops, true);
+            EditClipCommand *command = new EditClipCommand(m_projectList, clip->getId(), clip->currentProperties(newprops), newprops, true);
             m_activeDocument->commandStack()->push(command);
             //m_activeTimeline->projectView()->slotUpdateClip(clip->getId());
             m_activeDocument->setModified(true);
@@ -3273,9 +3290,9 @@ void MainWindow::slotShowClipProperties(QList <DocClipBase *> cliplist, QMap<QSt
         for (int i = 0; i < cliplist.count(); i++) {
             DocClipBase *clip = cliplist.at(i);
             if (clip->clipType() == IMAGE)
-                new EditClipCommand(m_projectList, clip->getId(), clip->properties(), newImageProps, true, command);
-            else 
-                new EditClipCommand(m_projectList, clip->getId(), clip->properties(), newProps, true, command);
+                new EditClipCommand(m_projectList, clip->getId(), clip->currentProperties(newImageProps), newImageProps, true, command);
+            else
+                new EditClipCommand(m_projectList, clip->getId(), clip->currentProperties(newProps), newProps, true, command);
         }
         m_activeDocument->commandStack()->push(command);
         for (int i = 0; i < cliplist.count(); i++)
@@ -3784,17 +3801,19 @@ void MainWindow::slotMaximizeCurrent(bool)
 void MainWindow::loadStabilize()
 {
        QMenu* stabMenu= static_cast<QMenu*>(factory()->container("stabilize", this));
-       stabMenu->clear();
-       Mlt::Profile profile;
-       if (Mlt::Factory::filter(profile,(char*)"videostab")){
-               QAction *action=stabMenu->addAction("Videostab (vstab)");
-               action->setData("videostab");
-               connect(action,SIGNAL(triggered()), this, SLOT(slotStabilize()));
-       }
-       if (Mlt::Factory::filter(profile,(char*)"videostab2")){
-               QAction *action=stabMenu->addAction("Videostab (transcode)");
-               action->setData("videostab2");
-               connect(action,SIGNAL(triggered()), this, SLOT(slotStabilize()));
+       if (stabMenu){
+               stabMenu->clear();
+               Mlt::Profile profile;
+               if (Mlt::Factory::filter(profile,(char*)"videostab")){
+                       QAction *action=stabMenu->addAction("Videostab (vstab)");
+                       action->setData("videostab");
+                       connect(action,SIGNAL(triggered()), this, SLOT(slotStabilize()));
+               }
+               if (Mlt::Factory::filter(profile,(char*)"videostab2")){
+                       QAction *action=stabMenu->addAction("Videostab (transcode)");
+                       action->setData("videostab2");
+                       connect(action,SIGNAL(triggered()), this, SLOT(slotStabilize()));
+               }
        }
 
 
@@ -3805,6 +3824,9 @@ void MainWindow::loadTranscoders()
     QMenu *transMenu = static_cast<QMenu*>(factory()->container("transcoders", this));
     transMenu->clear();
 
+    QMenu *extractAudioMenu = static_cast<QMenu*>(factory()->container("extract_audio", this));
+    extractAudioMenu->clear();
+
     KSharedConfigPtr config = KSharedConfig::openConfig("kdenlivetranscodingrc");
     KConfigGroup transConfig(config, "Transcoding");
     // read the entries
@@ -3812,25 +3834,48 @@ void MainWindow::loadTranscoders()
     QMapIterator<QString, QString> i(profiles);
     while (i.hasNext()) {
         i.next();
-        QStringList data = i.value().split(";", QString::SkipEmptyParts);
-        QAction *a = transMenu->addAction(i.key());
+        QStringList data = i.value().split(";");
+        QAction *a;
+        // separate audio transcoding in a separate menu
+        if (data.count() > 2 && data.at(2) == "audio") {
+            a = extractAudioMenu->addAction(i.key());
+        }
+        else {
+            a = transMenu->addAction(i.key());
+        }
         a->setData(data);
-        if (data.count() > 1)
-            a->setToolTip(data.at(1));
+        if (data.count() > 1) a->setToolTip(data.at(1));
         connect(a, SIGNAL(triggered()), this, SLOT(slotTranscode()));
     }
 }
 
-void MainWindow::slotStabilize(KUrl::List urls)
+void MainWindow::slotStabilize()
 {
-       QString condition;
-       if (urls.isEmpty()) {
-        QAction *action = qobject_cast<QAction *>(sender());
-               if (action){
-                       QString filtername=action->data().toString();
-                       urls = m_projectList->getConditionalUrls(condition);
-               }
+    QString condition,filtername;
+    QStringList ids;
+
+    // Stablize selected clips
+    QAction *action = qobject_cast<QAction *>(sender());
+    if (action){
+        filtername=action->data().toString();
     }
+    m_projectList->startClipFilterJob(filtername, condition);
+    /*
+    if (ids.isEmpty()) {
+        m_messageLabel->setMessage(i18n("No clip to transcode"), ErrorMessage);
+        return;
+    }
+    QString destination;
+    ProjectItem *item = m_projectList->getClipById(ids.at(0));
+    if (ids.count() == 1) {
+
+    }
+    ClipStabilize *d = new ClipStabilize(destination, ids.count(), filtername);
+    //connect(d, SIGNAL(addClip(KUrl)), this, SLOT(slotAddProjectClip(KUrl)));
+    if (d->exec() == QDialog::Accepted) {
+        m_projectList->slotStabilizeClipJob(ids, d->autoAddClip(), d->params(), d->desc());
+    }
+    delete d;*/
 }
 
 void MainWindow::slotTranscode(KUrl::List urls)
@@ -3843,9 +3888,9 @@ void MainWindow::slotTranscode(KUrl::List urls)
         QStringList data = action->data().toStringList();
         params = data.at(0);
         if (data.count() > 1) desc = data.at(1);
-        if (data.count() > 2) condition = data.at(2);
-        urls << m_projectList->getConditionalUrls(condition);
-        urls.removeAll(KUrl());
+        if (data.count() > 3) condition = data.at(3);
+        m_projectList->slotTranscodeClipJob(condition, params, desc);
+        return;
     }
     if (urls.isEmpty()) {
         m_messageLabel->setMessage(i18n("No clip to transcode"), ErrorMessage);
@@ -3854,7 +3899,6 @@ void MainWindow::slotTranscode(KUrl::List urls)
     ClipTranscode *d = new ClipTranscode(urls, params, desc);
     connect(d, SIGNAL(addClip(KUrl)), this, SLOT(slotAddProjectClip(KUrl)));
     d->show();
-    //QProcess::startDetached("ffmpeg", parameters);
 }
 
 void MainWindow::slotTranscodeClip()
@@ -3970,7 +4014,7 @@ void MainWindow::slotPrepareRendering(bool scriptExport, bool zoneOnly, const QS
             }
         }
     }
-    
+
     // Do we want proxy rendering
     if (m_projectList->useProxy() && !m_renderWidget->proxyRendering()) {
         QString root = doc.documentElement().attribute("root");
@@ -4004,7 +4048,7 @@ void MainWindow::slotPrepareRendering(bool scriptExport, bool zoneOnly, const QS
                 }
             }
         }
-        
+
         /*QMapIterator<QString, QString> i(proxies);
         while (i.hasNext()) {
             i.next();
@@ -4019,7 +4063,7 @@ void MainWindow::slotPrepareRendering(bool scriptExport, bool zoneOnly, const QS
         }*/
     }
     playlistContent = doc.toString();
-    
+
     // Do save scenelist
     QFile file(playlistPath);
     if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
@@ -4033,7 +4077,7 @@ void MainWindow::slotPrepareRendering(bool scriptExport, bool zoneOnly, const QS
         return;
     }
     file.close();
-    m_renderWidget->slotExport(scriptExport, m_activeTimeline->inPoint(), m_activeTimeline->outPoint(), playlistPath, scriptPath, exportAudio);
+    m_renderWidget->slotExport(scriptExport, m_activeTimeline->inPoint(), m_activeTimeline->outPoint(), m_activeDocument->metadata(), playlistPath, scriptPath, exportAudio);
 }
 
 void MainWindow::slotUpdateTimecodeFormat(int ix)
@@ -4100,19 +4144,19 @@ void MainWindow::slotChangePalette(QAction *action, const QString &themename)
         plt = KGlobalSettings::createNewApplicationPalette(config);
 #else
         // Since there was a bug in createApplicationPalette in KDE < 4.6.3 we need
-        // to do the palette loading stuff ourselves. (https://bugs.kde.org/show_bug.cgi?id=263497)     
+        // to do the palette loading stuff ourselves. (https://bugs.kde.org/show_bug.cgi?id=263497)
         QPalette::ColorGroup states[3] = { QPalette::Active, QPalette::Inactive,
                                             QPalette::Disabled };
         // TT thinks tooltips shouldn't use active, so we use our active colors for all states
         KColorScheme schemeTooltip(QPalette::Active, KColorScheme::Tooltip, config);
+
         for ( int i = 0; i < 3 ; i++ ) {
             QPalette::ColorGroup state = states[i];
             KColorScheme schemeView(state, KColorScheme::View, config);
             KColorScheme schemeWindow(state, KColorScheme::Window, config);
             KColorScheme schemeButton(state, KColorScheme::Button, config);
             KColorScheme schemeSelection(state, KColorScheme::Selection, config);
+
             plt.setBrush( state, QPalette::WindowText, schemeWindow.foreground() );
             plt.setBrush( state, QPalette::Window, schemeWindow.background() );
             plt.setBrush( state, QPalette::Base, schemeView.background() );
@@ -4123,13 +4167,13 @@ void MainWindow::slotChangePalette(QAction *action, const QString &themename)
             plt.setBrush( state, QPalette::HighlightedText, schemeSelection.foreground() );
             plt.setBrush( state, QPalette::ToolTipBase, schemeTooltip.background() );
             plt.setBrush( state, QPalette::ToolTipText, schemeTooltip.foreground() );
+
             plt.setColor( state, QPalette::Light, schemeWindow.shade( KColorScheme::LightShade ) );
             plt.setColor( state, QPalette::Midlight, schemeWindow.shade( KColorScheme::MidlightShade ) );
             plt.setColor( state, QPalette::Mid, schemeWindow.shade( KColorScheme::MidShade ) );
             plt.setColor( state, QPalette::Dark, schemeWindow.shade( KColorScheme::DarkShade ) );
             plt.setColor( state, QPalette::Shadow, schemeWindow.shade( KColorScheme::ShadowShade ) );
+
             plt.setBrush( state, QPalette::AlternateBase, schemeView.background( KColorScheme::AlternateBackground) );
             plt.setBrush( state, QPalette::Link, schemeView.foreground( KColorScheme::LinkText ) );
             plt.setBrush( state, QPalette::LinkVisited, schemeView.foreground( KColorScheme::VisitedText ) );
@@ -4202,12 +4246,6 @@ void MainWindow::slotSwitchMonitors()
     else m_projectList->focusTree();
 }
 
-void MainWindow::slotSwitchFullscreen()
-{
-    if (m_projectMonitor->isActive()) m_projectMonitor->slotSwitchFullScreen();
-    else m_clipMonitor->slotSwitchFullScreen();
-}
-
 void MainWindow::slotInsertZoneToTree()
 {
     if (!m_clipMonitor->isActive() || m_clipMonitor->activeClip() == NULL) return;
@@ -4291,85 +4329,6 @@ void MainWindow::slotMonitorRequestRenderFrame(bool request)
     }
 }
 
-void MainWindow::slotUpdateGfxScopeFrameRequest()
-{
-    // We need a delay to make sure widgets are hidden after a close event for example
-    QTimer::singleShot(500, this, SLOT(slotDoUpdateGfxScopeFrameRequest()));
-}
-
-void MainWindow::slotDoUpdateGfxScopeFrameRequest()
-{
-    // Check scopes
-    bool request = false;
-    for (int i = 0; i < m_gfxScopesList.count(); i++) {
-        if (!m_gfxScopesList.at(i)->widget()->visibleRegion().isEmpty() && static_cast<AbstractGfxScopeWidget *>(m_gfxScopesList.at(i)->widget())->autoRefreshEnabled()) {
-            kDebug() << "SCOPE VISIBLE: " << static_cast<AbstractGfxScopeWidget *>(m_gfxScopesList.at(i)->widget())->widgetName();
-            request = true;
-            break;
-        }
-    }
-    if (!request) {
-        if (!m_projectMonitor->effectSceneDisplayed()) {
-            m_projectMonitor->render->sendFrameForAnalysis = false;
-        }
-        m_clipMonitor->render->sendFrameForAnalysis = false;
-        if (m_recMonitor)
-            m_recMonitor->analyseFrames(false);
-    } else {
-        m_projectMonitor->render->sendFrameForAnalysis = true;
-        m_clipMonitor->render->sendFrameForAnalysis = true;
-        if (m_recMonitor)
-            m_recMonitor->analyseFrames(true);
-    }
-}
-
-void MainWindow::slotUpdateAudioScopeFrameRequest()
-{
-    QTimer::singleShot(500, this, SLOT(slotDoUpdateAudioScopeFrameRequest()));
-}
-
-void MainWindow::slotDoUpdateAudioScopeFrameRequest()
-{
-    bool request = false;
-    for (int i = 0; i < m_audioScopesList.count(); i++) {
-        if (!m_audioScopesList.at(i)->visibleRegion().isEmpty() && m_audioScopesList.at(i)->autoRefreshEnabled()) {
-            kDebug() << "AUDIO SCOPE VISIBLE: " << m_audioScopesList.at(i)->widgetName();
-            request = true;
-            break;
-        }
-    }
-    // Handle audio signal separately (no common interface)
-    if (!m_audiosignal->visibleRegion().isEmpty() && m_audiosignal->monitoringEnabled()) {
-        kDebug() << "AUDIO SCOPE VISIBLE: " << "audiosignal";
-        request = true;
-    }
-#ifdef DEBUG_MAINW
-    qDebug() << "Scopes Requesting Audio data: " << request;
-#endif
-    KdenliveSettings::setMonitor_audio(request);
-    m_monitorManager->slotUpdateAudioMonitoring();
-}
-
-void MainWindow::slotUpdateColorScopes()
-{
-    bool request = false;
-    kDebug()<<"// UPDATE SCOPES";
-    for (int i = 0; i < m_gfxScopesList.count(); i++) {
-        // Check if we need the renderer to send a new frame for update
-        if (!m_gfxScopesList.at(i)->widget()->visibleRegion().isEmpty() && !(static_cast<AbstractGfxScopeWidget *>(m_gfxScopesList.at(i)->widget())->autoRefreshEnabled())) request = true;
-        static_cast<AbstractGfxScopeWidget *>(m_gfxScopesList.at(i)->widget())->slotActiveMonitorChanged();
-    }
-    if (request && m_monitorManager->activeRenderer()) {
-        m_monitorManager->activeRenderer()->sendFrameUpdate();
-    }
-}
-
-void MainWindow::slotClearColorScopes()
-{
-    for (int i = 0; i < m_gfxScopesList.count(); i++) {
-        static_cast<AbstractGfxScopeWidget *>(m_gfxScopesList.at(i)->widget())->slotClearMonitor();
-    }
-}
 
 void MainWindow::slotOpenStopmotion()
 {
@@ -4454,6 +4413,17 @@ void MainWindow::slotElapsedTime()
     kDebug()<<"-----------------------------------------\n"<<"Time elapsed: "<<m_timer.elapsed()<<"\n-------------------------";
 }
 
+
+void MainWindow::slotDownloadResources()
+{
+    QString currentFolder;
+    if (m_activeDocument) currentFolder = m_activeDocument->projectFolder().path();
+    else currentFolder = KdenliveSettings::defaultprojectfolder();
+    ResourceWidget *d = new ResourceWidget(currentFolder);
+    connect(d, SIGNAL(addClip(KUrl, const QString &)), this, SLOT(slotAddProjectClip(KUrl, const QString &)));
+    d->show();
+}
+
 #include "mainwindow.moc"
 
 #ifdef DEBUG_MAINW
index 717efb06645ef0fe2aa6cf8b1cb1d312ea258843..21e3b03935d6485b78114ce868a6451efe8fd089 100644 (file)
@@ -67,6 +67,7 @@ class JogShuttleAction;
 class DocClipBase;
 class Render;
 class Transition;
+class ScopeManager;
 class Histogram;
 class Vectorscope;
 class Waveform;
@@ -138,6 +139,8 @@ private:
     KTabWidget* m_timelineArea;
     QProgressBar *m_statusProgressBar;
 
+    ScopeManager *m_scopeManager;
+
     /** @brief Sets up all the actions and attaches them to the collection. */
     void setupActions();
     KdenliveDoc *m_activeDocument;
@@ -198,7 +201,6 @@ private:
 
     /** This list holds all the scopes used in Kdenlive, allowing to manage some global settings */
     QList <QDockWidget *> m_gfxScopesList;
-    QList <AbstractAudioScopeWidget *> m_audioScopesList;
 
     KActionCategory *m_effectActions;
     QMenu *m_effectsMenu;
@@ -210,7 +212,7 @@ private:
 
     /** Actions used in the stopmotion widget */
     KActionCategory *m_stopmotion_actions;
-    
+
     /** Action names that can be used in the slotDoAction() slot, with their i18n() names */
     QStringList m_action_names;
 
@@ -261,6 +263,7 @@ private:
     StatusBarMessageLabel *m_messageLabel;
     QActionGroup *m_clipTypeGroup;
     KActionCollection *m_effectsActionCollection;
+    KActionCollection *m_tracksActionCollection;
 
     bool m_findActivated;
     QString m_findString;
@@ -274,7 +277,7 @@ private:
     void connectDocumentInfo(KdenliveDoc *doc);
     void findAhead();
     void doOpenFile(const KUrl &url, KAutoSaveFile *stale);
-    void recoverFiles(QList<KAutoSaveFile *> staleFiles);
+    void recoverFiles(QList<KAutoSaveFile *> staleFiles, const KUrl &originUrl);
 
     /** @brief Loads static and dynamic plugins.
      *
@@ -412,7 +415,7 @@ private slots:
     void slotSelectAddTimelineTransition();
     void slotAddVideoEffect(QAction *result);
     void slotAddTransition(QAction *result);
-    void slotAddProjectClip(KUrl url);
+    void slotAddProjectClip(KUrl url, const QString &comment = QString());
     void slotAddProjectClipList(KUrl::List urls);
     void slotShowClipProperties(DocClipBase *clip);
     void slotShowClipProperties(QList <DocClipBase *>cliplist, QMap<QString, QString> commonproperties);
@@ -454,10 +457,14 @@ private slots:
     void slotResizeItemStart();
     void slotResizeItemEnd();
     void configureNotifications();
-    void slotInsertTrack(int ix = 0);
-    void slotDeleteTrack(int ix = 0);
+    void slotInsertTrack(int ix = -1);
+    void slotDeleteTrack(int ix = -1);
     /** @brief Shows the configure tracks dialog and updates transitions afterwards. */
     void slotConfigTrack(int ix = -1);
+    /** @brief Select all clips in active track. */
+    void slotSelectTrack();
+    /** @brief Select all clips in timeline. */
+    void slotSelectAllTracks();
     void slotGetNewLumaStuff();
     void slotGetNewTitleStuff();
     void slotGetNewRenderStuff();
@@ -478,7 +485,7 @@ private slots:
     void slotShowTimeline(bool show);
     void slotMaximizeCurrent(bool show);
     void slotTranscode(KUrl::List urls = KUrl::List());
-    void slotStabilize(KUrl::List urls = KUrl::List());
+    void slotStabilize();
     void slotTranscodeClip();
     /** @brief Archive project: creates a copy of the project file with all clips in a new folder. */
     void slotArchiveProject();
@@ -525,18 +532,6 @@ private slots:
 
     /** @brief The monitor informs that it needs (or not) to have frames sent by the renderer. */
     void slotMonitorRequestRenderFrame(bool request);
-    /** @brief Check if someone needs the render frame sent. */
-    void slotUpdateGfxScopeFrameRequest();
-    /** @brief Check if someone needs the render frame sent. */
-    void slotDoUpdateGfxScopeFrameRequest();
-    void slotUpdateAudioScopeFrameRequest();
-    void slotDoUpdateAudioScopeFrameRequest();
-    /** @brief When switching between monitors, update the visible scopes. */
-    void slotUpdateColorScopes();
-    /** @brief Active monitor deleted, clear scopes. */
-    void slotClearColorScopes();
-    /** @brief Switch current monitor to fullscreen. */
-    void slotSwitchFullscreen();
     /** @brief Open the stopmotion dialog. */
     void slotOpenStopmotion();
     /** @brief Implements all the actions that are int he ActionsCollection. */
@@ -551,6 +546,8 @@ private slots:
     void slotDisableProxies();
 
     void slotElapsedTime();
+    /** @brief Open the online services search dialog. */
+    void slotDownloadResources();
 
 signals:
     Q_SCRIPTABLE void abortRenderJob(const QString &url);
index c92b18c29dd67a3153c69bbf1aaf4556b1a217cd..e93e54190a5796e3287dbb41efbcf922155e7bb2 100644 (file)
@@ -19,9 +19,6 @@
 #include "mltdevicecapture.h"
 #include "kdenlivesettings.h"
 #include "definitions.h"
-//#include "recmonitor.h"
-//#include "renderer.h"
-#include "blackmagic/devices.h"
 
 #include <mlt++/Mlt.h>
 
@@ -51,12 +48,12 @@ static void consumer_gl_frame_show(mlt_consumer, MltDeviceCapture * self, mlt_fr
     self->showFrame(frame);
 }
 
-static void rec_consumer_frame_show(mlt_consumer, MltDeviceCapture * self, mlt_frame frame_ptr)
+/*static void rec_consumer_frame_show(mlt_consumer, MltDeviceCapture * self, mlt_frame frame_ptr)
 {
     Mlt::Frame frame(frame_ptr);
     if (!frame.is_valid()) return;
     self->gotCapturedFrame(frame);
-}
+}*/
 
 static void rec_consumer_frame_preview(mlt_consumer, MltDeviceCapture * self, mlt_frame frame_ptr)
 {
@@ -71,31 +68,35 @@ static void rec_consumer_frame_preview(mlt_consumer, MltDeviceCapture * self, ml
     }
 
     //TODO: connect record monitor to audio scopes
-    /*
+    
     if (self->analyseAudio) {
         self->showAudio(frame);
     }
-    */
+    
 }
 
 
-MltDeviceCapture::MltDeviceCapture(QString profile, VideoPreviewContainer *surface, QWidget *parent) :
-    AbstractRender("capture", parent),
+MltDeviceCapture::MltDeviceCapture(QString profile, VideoSurface *surface, QWidget *parent) :
+    AbstractRender(Kdenlive::recordMonitor, parent),
     doCapture(0),
     sendFrameForAnalysis(false),
-    analyseAudio(KdenliveSettings::monitor_audio()),
     processingImage(false),
     m_mltConsumer(NULL),
     m_mltProducer(NULL),
     m_mltProfile(NULL),
+    m_showFrameEvent(NULL),
     m_droppedFrames(0),
-    m_livePreview(KdenliveSettings::recording_preview()),
-    m_captureDisplayWidget(surface),
+    m_livePreview(KdenliveSettings::enable_recording_preview()),
     m_winid((int) surface->winId())
 {
+    m_captureDisplayWidget = surface;
+    analyseAudio = KdenliveSettings::monitor_audio();
     if (profile.isEmpty()) profile = KdenliveSettings::current_profile();
     buildConsumer(profile);
     connect(this, SIGNAL(unblockPreview()), this, SLOT(slotPreparePreview()));
+    m_droppedFramesTimer.setSingleShot(false);
+    m_droppedFramesTimer.setInterval(1000);
+    connect(&m_droppedFramesTimer, SIGNAL(timeout()), this, SLOT(slotCheckDroppedFrames()));
 }
 
 MltDeviceCapture::~MltDeviceCapture()
@@ -127,17 +128,18 @@ void MltDeviceCapture::buildConsumer(const QString &profileName)
         }
     }
     setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 1);
-
+    
+  
     if (m_winid == 0) {
         // OpenGL monitor
         m_mltConsumer = new Mlt::Consumer(*m_mltProfile, "sdl_audio");
         m_mltConsumer->set("preview_off", 1);
         m_mltConsumer->set("preview_format", mlt_image_rgb24);
-        m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) consumer_gl_frame_show);
+        m_showFrameEvent = m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) consumer_gl_frame_show);
     } else {
         m_mltConsumer = new Mlt::Consumer(*m_mltProfile, "sdl_preview");
         m_mltConsumer->set("window_id", m_winid);
-        m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) rec_consumer_frame_preview);
+        m_showFrameEvent = m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) rec_consumer_frame_preview);
     }
     //m_mltConsumer->set("resize", 1);
     //m_mltConsumer->set("terminate_on_pause", 1);
@@ -161,11 +163,24 @@ void MltDeviceCapture::buildConsumer(const QString &profileName)
     //m_mltConsumer->set("real_time", 0);
 }
 
+void MltDeviceCapture::pause()
+{   
+    if (m_mltConsumer) {
+          m_mltConsumer->set("refresh", 0);
+         //m_mltProducer->set_speed(0.0);
+         m_mltConsumer->purge();
+    }
+}
+
 void MltDeviceCapture::stop()
 {
+    m_droppedFramesTimer.stop();
     bool isPlaylist = false;
-    disconnect(this, SIGNAL(imageReady(QImage)), this, SIGNAL(frameUpdated(QImage)));
-    m_captureDisplayWidget->stop();
+    //disconnect(this, SIGNAL(imageReady(QImage)), this, SIGNAL(frameUpdated(QImage)));
+    //m_captureDisplayWidget->stop();
+    
+    if (m_showFrameEvent) delete m_showFrameEvent;
+    m_showFrameEvent = NULL;
     
     if (m_mltConsumer) {
         m_mltConsumer->set("refresh", 0);
@@ -209,9 +224,16 @@ void MltDeviceCapture::stop()
 }
 
 
-void MltDeviceCapture::doRefresh()
+void MltDeviceCapture::slotDoRefresh()
 {
-    if (m_mltConsumer) m_mltConsumer->set("refresh", 1);
+    QMutexLocker locker(&m_mutex);
+    if (!m_mltProducer)
+        return;
+    if (m_mltConsumer) {
+        if (m_mltConsumer->is_stopped()) m_mltConsumer->start();
+        m_mltConsumer->purge();
+        m_mltConsumer->set("refresh", 1);
+    }
 }
 
 
@@ -229,12 +251,12 @@ void MltDeviceCapture::emitFrameUpdated(Mlt::Frame& frame)
     }
     */
 
-    mlt_image_format format = mlt_image_rgb24;
+    mlt_image_format format = mlt_image_rgb24a;
     int width = 0;
     int height = 0;
     const uchar* image = frame.get_image(format, width, height);
-    QImage qimage(width, height, QImage::Format_ARGB32);
-    memcpy(qimage.bits(), image, width * height * 3);
+    QImage qimage(width, height, QImage::Format_ARGB32_Premultiplied);
+    memcpy(qimage.bits(), image, width * height * 4);
     emit frameUpdated(qimage.rgbSwapped());
 }
 
@@ -272,7 +294,6 @@ void MltDeviceCapture::showAudio(Mlt::Frame& frame)
     // So the vector is of size samples*channels.
     QVector<int16_t> sampleVector(samples*num_channels);
     memcpy(sampleVector.data(), data, samples*num_channels*sizeof(int16_t));
-
     if (samples > 0) {
         emit audioSamplesSignal(sampleVector, freq, num_channels, samples);
     }
@@ -302,10 +323,22 @@ bool MltDeviceCapture::slotStartPreview(const QString &producer, bool xmlFormat)
         m_mltConsumer = NULL;
         return 0;
     }
-    connect(this, SIGNAL(imageReady(QImage)), this, SIGNAL(frameUpdated(QImage)));
+    m_droppedFramesTimer.start();
+    //connect(this, SIGNAL(imageReady(QImage)), this, SIGNAL(frameUpdated(QImage)));
     return 1;
 }
 
+void MltDeviceCapture::slotCheckDroppedFrames()
+{
+    if (m_mltProducer) {
+        int dropped = m_mltProducer->get_int("dropped");
+        if (dropped > m_droppedFrames) {
+            m_droppedFrames = dropped;
+            emit droppedFrames(m_droppedFrames);
+        }
+    }
+}
+
 void MltDeviceCapture::gotCapturedFrame(Mlt::Frame& frame)
 {
     if (m_mltProducer) {
@@ -316,8 +349,8 @@ void MltDeviceCapture::gotCapturedFrame(Mlt::Frame& frame)
         }
     }
     m_frameCount++;
-    if (m_livePreview == 2) return;
-    if (m_livePreview == 0 && (m_frameCount % 10 > 0)) return;
+    if (!m_livePreview) return;
+    //if (m_livePreview == 0 && (m_frameCount % 10 > 0)) return;
     mlt_image_format format = mlt_image_rgb24;
     int width = 0;
     int height = 0;
@@ -326,7 +359,7 @@ void MltDeviceCapture::gotCapturedFrame(Mlt::Frame& frame)
     //memcpy(image.bits(), data, width * height * 3);
     QImage image((uchar *)data, width, height, QImage::Format_RGB888);
 
-    m_captureDisplayWidget->setImage(image);
+    //m_captureDisplayWidget->setImage(image);
 
     //TEST: is it better to process frame conversion ouside MLT???
     /*
@@ -381,7 +414,7 @@ void MltDeviceCapture::captureFrame(const QString &path)
     doCapture = 5;
 }
 
-bool MltDeviceCapture::slotStartCapture(const QString &params, const QString &path, const QString &playlist, int livePreview, bool xmlPlaylist)
+bool MltDeviceCapture::slotStartCapture(const QString &params, const QString &path, const QString &playlist, bool livePreview, bool xmlPlaylist)
 {
     stop();
     m_livePreview = livePreview;
@@ -391,12 +424,34 @@ bool MltDeviceCapture::slotStartCapture(const QString &params, const QString &pa
     char *tmp = qstrdup(m_activeProfile.toUtf8().constData());
     m_mltProfile = new Mlt::Profile(tmp);
     delete[] tmp;
-    m_mltProfile->get_profile()->is_explicit = 1;
-    kDebug()<<"-- CREATING CAP: "<<params<<", PATH: "<<path;
+    //m_mltProfile->get_profile()->is_explicit = 1;
+    
+    
+    /*kDebug()<<"-- CREATING CAP: "<<params<<", PATH: "<<path;
     tmp = qstrdup(QString("avformat:" + path).toUtf8().constData());
     m_mltConsumer = new Mlt::Consumer(*m_mltProfile, tmp);
     m_mltConsumer->set("real_time", -KdenliveSettings::mltthreads());
-    delete[] tmp;
+    delete[] tmp;*/
+    
+    m_mltConsumer = new Mlt::Consumer(*m_mltProfile, "multi");
+    if (m_mltConsumer == NULL || !m_mltConsumer->is_valid()) {
+        if (m_mltConsumer) {
+            delete m_mltConsumer;
+            m_mltConsumer = NULL;
+        }
+        return false;
+    }
+    
+    m_winid = (int) m_captureDisplayWidget->winId();
+    
+    // Create multi consumer setup
+    Mlt::Properties *renderProps = new Mlt::Properties;
+    renderProps->set("mlt_service", "avformat");
+    renderProps->set("target", path.toUtf8().constData());
+    renderProps->set("real_time", -KdenliveSettings::mltthreads());
+    renderProps->set("terminate_on_pause", 0);
+    renderProps->set("mlt_profile", m_activeProfile.toUtf8().constData());
+    
 
     QStringList paramList = params.split(" ", QString::SkipEmptyParts);
     char *tmp2;
@@ -405,21 +460,64 @@ bool MltDeviceCapture::slotStartCapture(const QString &params, const QString &pa
         QString value = paramList.at(i).section("=", 1, 1);
         if (value == "%threads") value = QString::number(QThread::idealThreadCount());
         tmp2 = qstrdup(value.toUtf8().constData());
-        m_mltConsumer->set(tmp, tmp2);
+        renderProps->set(tmp, tmp2);
         delete[] tmp;
         delete[] tmp2;
     }
+    mlt_properties consumerProperties = m_mltConsumer->get_properties();
+    mlt_properties_set_data(consumerProperties, "0", renderProps->get_properties(), 0, (mlt_destructor) mlt_properties_close, NULL);
     
-    if (m_mltConsumer == NULL || !m_mltConsumer->is_valid()) {
-        if (m_mltConsumer) {
-            delete m_mltConsumer;
-            m_mltConsumer = NULL;
+    if (m_livePreview) 
+    {
+        // user wants live preview
+        Mlt::Properties *previewProps = new Mlt::Properties;
+        QString videoDriver = KdenliveSettings::videodrivername();
+        if (!videoDriver.isEmpty()) {
+            if (videoDriver == "x11_noaccel") {
+                setenv("SDL_VIDEO_YUV_HWACCEL", "0", 1);
+                videoDriver = "x11";
+            } else {
+                unsetenv("SDL_VIDEO_YUV_HWACCEL");
+            }
         }
-        return false;
+        setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 1);
+        
+        if (m_winid == 0) {
+            // OpenGL monitor
+            previewProps->set("mlt_service", "sdl_audio");
+            previewProps->set("preview_off", 1);
+            previewProps->set("preview_format", mlt_image_rgb24);
+            previewProps->set("terminate_on_pause", 0);
+            m_showFrameEvent = m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) consumer_gl_frame_show);
+        } else {
+            previewProps->set("mlt_service", "sdl_preview");
+            previewProps->set("window_id", m_winid);
+            previewProps->set("terminate_on_pause", 0);
+            //m_showFrameEvent = m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) rec_consumer_frame_preview);
+        }
+        //m_mltConsumer->set("resize", 1);
+        previewProps->set("window_background", KdenliveSettings::window_background().name().toUtf8().constData());
+        QString audioDevice = KdenliveSettings::audiodevicename();
+        if (!audioDevice.isEmpty())
+            previewProps->set("audio_device", audioDevice.toUtf8().constData());
+
+        if (!videoDriver.isEmpty())
+            previewProps->set("video_driver", videoDriver.toUtf8().constData());
+
+        QString audioDriver = KdenliveSettings::audiodrivername();
+
+        if (!audioDriver.isEmpty())
+            previewProps->set("audio_driver", audioDriver.toUtf8().constData());
+        
+        previewProps->set("real_time", "0");
+        previewProps->set("mlt_profile", m_activeProfile.toUtf8().constData());
+        mlt_properties_set_data(consumerProperties, "1", previewProps->get_properties(), 0, (mlt_destructor) mlt_properties_close, NULL);
+        //m_showFrameEvent = m_mltConsumer->listen("consumer-frame-render", this, (mlt_listener) rec_consumer_frame_show);
+    }
+    else {
+        
     }
     
-    // FIXME: the event object returned by the listen gets leaked...
-    if (m_livePreview < 2) m_mltConsumer->listen("consumer-frame-render", this, (mlt_listener) rec_consumer_frame_show);
     tmp = qstrdup(playlist.toUtf8().constData());
     if (xmlPlaylist) {
         // create an xml producer
@@ -438,11 +536,13 @@ bool MltDeviceCapture::slotStartCapture(const QString &params, const QString &pa
     
     m_mltConsumer->connect(*m_mltProducer);
     if (m_mltConsumer->start() == -1) {
+        if (m_showFrameEvent) delete m_showFrameEvent;
+        m_showFrameEvent = NULL;
         delete m_mltConsumer;
         m_mltConsumer = NULL;
         return 0;
     }
-    m_captureDisplayWidget->start();
+    m_droppedFramesTimer.start();
     return 1;
 }
 
@@ -647,7 +747,7 @@ void MltDeviceCapture::uyvy2rgb(unsigned char *yuv_buffer, int width, int height
         rgb_ptr += 3;
     }
     //emit imageReady(image);
-    m_captureDisplayWidget->setImage(image);
+    //m_captureDisplayWidget->setImage(image);
     emit unblockPreview();
     //processingImage = false;
 }
index ba757335077180dc829706049bfcf3856c081604..b0004a31519c86c0b630394bd6779a39b207616b 100644 (file)
 namespace Mlt
 {
 class Consumer;
-class Playlist;
-class Tractor;
-class Transition;
 class Frame;
-class Field;
+class Event;
 class Producer;
-class Filter;
 class Profile;
-class Service;
 };
 
 class MltDeviceCapture: public AbstractRender
@@ -55,7 +50,7 @@ Q_OBJECT public:
     /** @brief Build a MLT Renderer
      *  @param winid The parent widget identifier (required for SDL display). Set to 0 for OpenGL rendering
      *  @param profile The MLT profile used for the capture (default one will be used if empty). */
-    MltDeviceCapture(QString profile, VideoPreviewContainer *surface, QWidget *parent = 0);
+    MltDeviceCapture(QString profile, VideoSurface *surface, QWidget *parent = 0);
 
     /** @brief Destroy the MLT Renderer. */
     ~MltDeviceCapture();
@@ -79,13 +74,13 @@ Q_OBJECT public:
     /** @brief Starts the MLT Video4Linux process.
      * @param surface The widget onto which the frame should be painted
      */
-    bool slotStartCapture(const QString &params, const QString &path, const QString &playlist, int livePreview, bool xmlPlaylist = true);
+    bool slotStartCapture(const QString &params, const QString &path, const QString &playlist, bool livePreview, bool xmlPlaylist = true);
     bool slotStartPreview(const QString &producer, bool xmlFormat = false);
     /** @brief A frame arrived from the MLT Video4Linux process. */
     void gotCapturedFrame(Mlt::Frame& frame);
     /** @brief Save current frame to file. */
     void captureFrame(const QString &path);
-    void doRefresh();
+    
     /** @brief This will add the video clip from path and add it in the overlay track. */
     void setOverlay(const QString &path);
 
@@ -94,26 +89,26 @@ Q_OBJECT public:
 
     /** @brief This will add a horizontal flip effect, easier to work when filming yourself. */
     void mirror(bool activate);
-
-    /** @brief This property is used to decide if the renderer should send audio data for monitoring. */
-    bool analyseAudio;
     
     /** @brief True if we are processing an image (yuv > rgb) when recording. */
     bool processingImage;
+    
+    void pause();
 
 private:
     Mlt::Consumer * m_mltConsumer;
     Mlt::Producer * m_mltProducer;
     Mlt::Profile *m_mltProfile;
+    Mlt::Event *m_showFrameEvent;
     QString m_activeProfile;
     int m_droppedFrames;
     /** @brief When true, images will be displayed on monitor while capturing. */
-    int m_livePreview;
+    bool m_livePreview;
     /** @brief Count captured frames, used to display only one in ten images while capturing. */
     int m_frameCount;
 
     /** @brief The surface onto which the captured frames should be painted. */
-    VideoPreviewContainer *m_captureDisplayWidget;
+    VideoSurface *m_captureDisplayWidget;
 
     /** @brief A human-readable description of this renderer. */
     int m_winid;
@@ -121,6 +116,10 @@ private:
     void uyvy2rgb(unsigned char *yuv_buffer, int width, int height);
 
     QString m_capturePath;
+    
+    QTimer m_droppedFramesTimer;
+    
+    QMutex m_mutex;
 
     /** @brief Build the MLT Consumer object with initial settings.
      *  @param profileName The MLT profile to use for the consumer */
@@ -130,15 +129,14 @@ private:
 private slots:
     void slotPreparePreview();
     void slotAllowPreview();
+    /** @brief When capturing, check every second for dropped frames. */
+    void slotCheckDroppedFrames();
   
 signals:
     /** @brief A frame's image has to be shown.
      *
      * Used in Mac OS X. */
     void showImageSignal(QImage);
-    
-    /** @brief This signal contains the audio of the current frame. */
-    void audioSamplesSignal(const QVector<int16_t>&, int freq, int num_channels, int num_samples);
 
     void frameSaved(const QString &);
     
@@ -152,6 +150,7 @@ public slots:
 
     /** @brief Stops the consumer. */
     void stop();
+    void slotDoRefresh();
 };
 
 #endif
index 7315bb921e692459e29dc2a308d785a2efc9d988..3a69d0f7e13926566876ab9f1aa7fe5a303c0504 100644 (file)
 #include <QVBoxLayout>
 
 
-Monitor::Monitor(QString name, MonitorManager *manager, QString profile, QWidget *parent) :
-    AbstractMonitor(parent),
+Monitor::Monitor(Kdenlive::MONITORID id, MonitorManager *manager, QString profile, QWidget *parent) :
+    AbstractMonitor(id, manager, parent),
     render(NULL),
-    m_name(name),
-    m_monitorManager(manager),
     m_currentClip(NULL),
     m_ruler(new SmallRuler(m_monitorManager)),
     m_overlay(NULL),
     m_scale(1),
     m_length(0),
     m_dragStarted(false),
-    m_monitorRefresh(NULL),
+    m_contextMenu(NULL),
     m_effectWidget(NULL),
     m_selectedClip(NULL),
     m_loopClipTransition(true),
@@ -65,10 +63,7 @@ Monitor::Monitor(QString name, MonitorManager *manager, QString profile, QWidget
     layout->setSpacing(0);
 
     // Video widget holder
-    m_videoBox = new VideoContainer(this);
-    m_videoBox->setContentsMargins(0, 0, 0, 0);
-    m_videoBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
-    layout->addWidget(m_videoBox, 10);
+    layout->addWidget(videoBox, 10);
     layout->addStretch();
 
     // Get base size for icons
@@ -77,13 +72,13 @@ Monitor::Monitor(QString name, MonitorManager *manager, QString profile, QWidget
     // Monitor ruler
     layout->addWidget(m_ruler);
     // Tool bar buttons
-    m_toolbar = new QToolBar(name, this);
+    m_toolbar = new QToolBar(this);
     m_toolbar->setIconSize(QSize(s, s));
 
     m_playIcon = KIcon("media-playback-start");
     m_pauseIcon = KIcon("media-playback-pause");
 
-    if (name != "chapter") {
+    if (id != Kdenlive::dvdMonitor) {
         m_toolbar->addAction(KIcon("kdenlive-zone-start"), i18n("Set zone start"), this, SLOT(slotSetZoneStart()));
         m_toolbar->addAction(KIcon("kdenlive-zone-end"), i18n("Set zone end"), this, SLOT(slotSetZoneEnd()));
     } else {
@@ -108,7 +103,7 @@ Monitor::Monitor(QString name, MonitorManager *manager, QString profile, QWidget
 
     playButton->setDefaultAction(m_playAction);
 
-    if (name != "chapter") {
+    if (id != Kdenlive::dvdMonitor) {
         QToolButton *configButton = new QToolButton(m_toolbar);
         m_configMenu = new QMenu(i18n("Misc..."), this);
         configButton->setIcon(KIcon("system-run"));
@@ -116,7 +111,7 @@ Monitor::Monitor(QString name, MonitorManager *manager, QString profile, QWidget
         configButton->setPopupMode(QToolButton::QToolButton::InstantPopup);
         m_toolbar->addWidget(configButton);
 
-        if (name == "clip") {
+        if (id == Kdenlive::clipMonitor) {
             m_markerMenu = new QMenu(i18n("Go to marker..."), this);
             m_markerMenu->setEnabled(false);
             m_configMenu->addMenu(m_markerMenu);
@@ -152,27 +147,25 @@ Monitor::Monitor(QString name, MonitorManager *manager, QString profile, QWidget
 
     bool monitorCreated = false;
 #ifdef Q_WS_MAC
-    createOpenGlWidget(m_videoBox, profile);
+    createOpenGlWidget(videoBox, profile);
     monitorCreated = true;
     //m_glWidget->setFixedSize(width, height);
 #elif defined(USE_OPENGL)
     if (KdenliveSettings::openglmonitors()) {
-        monitorCreated = createOpenGlWidget(m_videoBox, profile);
+        monitorCreated = createOpenGlWidget(videoBox, profile);
     }
 #endif
-    QVBoxLayout *lay = new QVBoxLayout;
-    lay->setContentsMargins(0, 0, 0, 0);
     if (!monitorCreated) {
-        m_monitorRefresh = new MonitorRefresh;
-        lay->addWidget(m_monitorRefresh);
-        m_videoBox->setLayout(lay);
-        render = new Render(m_name, (int) m_monitorRefresh->winId(), profile, this);
-        m_monitorRefresh->setRenderer(render);
+       createVideoSurface();
+        render = new Render(m_id, (int) videoSurface->winId(), profile, this);
+       connect(videoSurface, SIGNAL(refreshMonitor()), render, SLOT(doRefresh()));
     }
 #ifdef USE_OPENGL
     else if (m_glWidget) {
+       QVBoxLayout *lay = new QVBoxLayout;
+       lay->setContentsMargins(0, 0, 0, 0);
         lay->addWidget(m_glWidget);
-        m_videoBox->setLayout(lay);
+        videoBox->setLayout(lay);
     }
 #endif
 
@@ -182,7 +175,7 @@ Monitor::Monitor(QString name, MonitorManager *manager, QString profile, QWidget
     connect(render, SIGNAL(rendererStopped(int)), this, SLOT(rendererStopped(int)));
     connect(render, SIGNAL(rendererPosition(int)), this, SLOT(seekCursor(int)));
 
-    if (name != "clip") {
+    if (id != Kdenlive::clipMonitor) {
         connect(render, SIGNAL(rendererPosition(int)), this, SIGNAL(renderPosition(int)));
         connect(render, SIGNAL(durationChanged(int)), this, SIGNAL(durationChanged(int)));
         connect(m_ruler, SIGNAL(zoneChanged(QPoint)), this, SIGNAL(zoneUpdated(QPoint)));
@@ -190,12 +183,12 @@ Monitor::Monitor(QString name, MonitorManager *manager, QString profile, QWidget
         connect(m_ruler, SIGNAL(zoneChanged(QPoint)), this, SLOT(setClipZone(QPoint)));
     }
 
-    if (m_monitorRefresh) m_monitorRefresh->show();
+    if (videoSurface) videoSurface->show();
 
-    if (name == "project") {
-        m_effectWidget = new MonitorEditWidget(render, m_videoBox);
+    if (id == Kdenlive::projectMonitor) {
+        m_effectWidget = new MonitorEditWidget(render, videoBox);
         m_toolbar->addAction(m_effectWidget->getVisibilityAction());
-        lay->addWidget(m_effectWidget);
+        videoBox->layout()->addWidget(m_effectWidget);
         m_effectWidget->hide();
     }
 
@@ -216,24 +209,18 @@ Monitor::~Monitor()
     delete m_overlay;
     if (m_effectWidget)
         delete m_effectWidget;
-    delete m_monitorRefresh;
     delete render;
 }
 
 QWidget *Monitor::container()
 {
-    return m_videoBox;
-}
-
-const QString Monitor::name() const
-{
-    return m_name;
+    return videoBox;
 }
 
 #ifdef USE_OPENGL
 bool Monitor::createOpenGlWidget(QWidget *parent, const QString profile)
 {
-    render = new Render(m_name, 0, profile, this);
+    render = new Render(id(), 0, profile, this);
     m_glWidget = new VideoGLWidget(parent);
     if (m_glWidget == NULL) {
         // Creation failed, we are in trouble...
@@ -271,14 +258,16 @@ void Monitor::setupMenu(QMenu *goMenu, QAction *playZone, QAction *loopZone, QMe
     }
 
     //TODO: add save zone to timeline monitor when fixed
-    if (m_name == "clip") {
+    if (m_id == Kdenlive::clipMonitor) {
         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);
 
-    if (m_name != "clip") {
+    if (m_id != Kdenlive::clipMonitor) {
         QAction *splitView = m_contextMenu->addAction(KIcon("view-split-left-right"), i18n("Split view"), render, SLOT(slotSplitView(bool)));
         splitView->setCheckable(true);
         m_configMenu->addAction(splitView);
@@ -321,7 +310,7 @@ void Monitor::slotSetSizeOneToOne()
         height = height * 0.8;
     }
     kDebug() << "// MONITOR; set SIZE: " << width << ", " << height;
-    m_videoBox->setFixedSize(width, height);
+    videoBox->setFixedSize(width, height);
     updateGeometry();
     adjustSize();
     //m_ui.video_frame->setMinimumSize(0, 0);
@@ -341,7 +330,7 @@ void Monitor::slotSetSizeOneToTwo()
         height = height * 0.8;
     }
     kDebug() << "// MONITOR; set SIZE: " << width << ", " << height;
-    m_videoBox->setFixedSize(width, height);
+    videoBox->setFixedSize(width, height);
     updateGeometry();
     adjustSize();
     //m_ui.video_frame->setMinimumSize(0, 0);
@@ -350,7 +339,7 @@ void Monitor::slotSetSizeOneToTwo()
 
 void Monitor::resetSize()
 {
-    m_videoBox->setMinimumSize(0, 0);
+    videoBox->setMinimumSize(0, 0);
 }
 
 DocClipBase *Monitor::activeClip()
@@ -447,11 +436,11 @@ void Monitor::slotSetZoneEnd()
 void Monitor::mousePressEvent(QMouseEvent * event)
 {
     if (event->button() != Qt::RightButton) {
-        if (m_videoBox->underMouse() && (!m_overlay || !m_overlay->underMouse())) {
+        if (videoBox->geometry().contains(event->pos()) && (!m_overlay || !m_overlay->underMouse())) {
             m_dragStarted = true;
             m_DragStartPosition = event->pos();
         }
-    } else if (!m_effectWidget || !m_effectWidget->isVisible()) {
+    } else if (m_contextMenu && (!m_effectWidget || !m_effectWidget->isVisible())) {
         m_contextMenu->popup(event->globalPos());
     }
 }
@@ -462,20 +451,19 @@ void Monitor::resizeEvent(QResizeEvent *event)
     if (render && isVisible() && isActive()) render->doRefresh();
 }
 
-
 void Monitor::slotSwitchFullScreen()
 {
-    m_videoBox->switchFullScreen();
+    videoBox->switchFullScreen();
 }
 
 // virtual
 void Monitor::mouseReleaseEvent(QMouseEvent * event)
 {
-    if (m_dragStarted) {
-        if (m_videoBox->underMouse() && (!m_effectWidget || !m_effectWidget->isVisible())) {
+    if (m_dragStarted && event->button() != Qt::RightButton) {
+        if (videoBox->geometry().contains(event->pos()) && (!m_effectWidget || !m_effectWidget->isVisible())) {
             if (isActive()) slotPlay();
-            else activateMonitor();
-        } else QWidget::mouseReleaseEvent(event);
+            else slotActivateMonitor();
+        } //else event->ignore(); //QWidget::mouseReleaseEvent(event);
         m_dragStarted = false;
     }
 }
@@ -483,7 +471,6 @@ void Monitor::mouseReleaseEvent(QMouseEvent * event)
 // virtual
 void Monitor::mouseMoveEvent(QMouseEvent *event)
 {
-    // kDebug() << "// DRAG STARTED, MOUSE MOVED: ";
     if (!m_dragStarted || m_currentClip == NULL) return;
 
     if ((event->pos() - m_DragStartPosition).manhattanLength()
@@ -503,9 +490,9 @@ void Monitor::mouseMoveEvent(QMouseEvent *event)
         data.append(list.join(";").toUtf8());
         mimeData->setData("kdenlive/clip", data);
         drag->setMimeData(mimeData);
-        QPixmap pix = m_currentClip->thumbnail();
+        /*QPixmap pix = m_currentClip->thumbnail();
         drag->setPixmap(pix);
-        drag->setHotSpot(QPoint(0, 50));
+        drag->setHotSpot(QPoint(0, 50));*/
         drag->start(Qt::MoveAction);
 
         //Qt::DropAction dropAction;
@@ -545,6 +532,14 @@ void Monitor::wheelEvent(QWheelEvent * event)
     event->accept();
 }
 
+void Monitor::mouseDoubleClickEvent(QMouseEvent * event)
+{
+    if (!KdenliveSettings::openglmonitors()) {
+        videoBox->switchFullScreen();
+        event->accept();
+    }
+}
+
 void Monitor::slotMouseSeek(int eventDelta, bool fast)
 {
     if (fast) {
@@ -566,6 +561,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;
@@ -588,16 +589,6 @@ void Monitor::slotExtractCurrentFrame()
     }
 }
 
-bool Monitor::isActive() const
-{
-    return m_monitorManager->isActive(m_name);
-}
-
-bool Monitor::activateMonitor()
-{
-    return m_monitorManager->activateMonitor(m_name);
-}
-
 void Monitor::setTimePos(const QString &pos)
 {
     m_timePos->setValue(pos);
@@ -612,61 +603,64 @@ void Monitor::slotSeek()
 void Monitor::slotSeek(int pos)
 {
     if (render == NULL) return;
-    activateMonitor();
+    slotActivateMonitor();
     render->seekToFrame(pos);
 }
 
 void Monitor::checkOverlay()
 {
     if (m_overlay == NULL) return;
+    QString overlayText;
     int pos = m_ruler->position();
     QPoint zone = m_ruler->zone();
     if (pos == zone.x())
-        m_overlay->setOverlayText(i18n("In Point"));
+        overlayText = i18n("In Point");
     else if (pos == zone.y())
-        m_overlay->setOverlayText(i18n("Out Point"));
+        overlayText = i18n("Out Point");
     else {
         if (m_currentClip) {
-            QString markerComment = m_currentClip->markerComment(GenTime(pos, m_monitorManager->timecode().fps()));
-            if (markerComment.isEmpty())
-                m_overlay->setHidden(true);
-            else
-                m_overlay->setOverlayText(markerComment, false);
-        } else m_overlay->setHidden(true);
+            overlayText = m_currentClip->markerComment(GenTime(pos, m_monitorManager->timecode().fps()));
+           if (!overlayText.isEmpty()) {
+               m_overlay->setOverlayText(overlayText, false);
+               return;
+           }
+       }
     }
+    if (m_overlay->isVisible() && overlayText.isEmpty()) m_overlay->setOverlayText(QString(), false);
+    else m_overlay->setOverlayText(overlayText);
 }
 
 void Monitor::slotStart()
 {
-    activateMonitor();
+    slotActivateMonitor();
     render->play(0);
     render->seekToFrame(0);
 }
 
 void Monitor::slotEnd()
 {
-    activateMonitor();
+    slotActivateMonitor();
     render->play(0);
     render->seekToFrame(render->getLength());
 }
 
 void Monitor::slotZoneStart()
 {
-    activateMonitor();
+    slotActivateMonitor();
     render->play(0);
     render->seekToFrame(m_ruler->zone().x());
 }
 
 void Monitor::slotZoneEnd()
 {
-    activateMonitor();
+    slotActivateMonitor();
     render->play(0);
     render->seekToFrame(m_ruler->zone().y());
 }
 
 void Monitor::slotRewind(double speed)
 {
-    activateMonitor();
+    slotActivateMonitor();
     if (speed == 0) {
         double currentspeed = render->playSpeed();
         if (currentspeed >= 0) render->play(-2);
@@ -678,7 +672,7 @@ void Monitor::slotRewind(double speed)
 
 void Monitor::slotForward(double speed)
 {
-    activateMonitor();
+    slotActivateMonitor();
     if (speed == 0) {
         double currentspeed = render->playSpeed();
         if (currentspeed <= 1) render->play(2);
@@ -690,21 +684,21 @@ void Monitor::slotForward(double speed)
 
 void Monitor::slotRewindOneFrame(int diff)
 {
-    activateMonitor();
+    slotActivateMonitor();
     render->play(0);
     render->seekToFrameDiff(-diff);
 }
 
 void Monitor::slotForwardOneFrame(int diff)
 {
-    activateMonitor();
+    slotActivateMonitor();
     render->play(0);
     render->seekToFrameDiff(diff);
 }
 
 void Monitor::seekCursor(int pos)
 {
-    //activateMonitor();
+    //slotActivateMonitor();
     if (m_ruler->slotNewValue(pos)) {
         checkOverlay();
         m_timePos->setValue(pos);
@@ -737,14 +731,14 @@ void Monitor::stop()
 
 void Monitor::start()
 {
-    if (!isVisible()) return;
-    if (render) render->start();
+    if (!isVisible() || !isActive()) return;
+    if (render) render->doRefresh();// start();
 }
 
 void Monitor::refreshMonitor(bool visible)
 {
     if (visible && render) {
-        if (!activateMonitor()) {
+        if (!slotActivateMonitor()) {
             // the monitor was already active, simply refreshClipThumbnail
             render->doRefresh();
         }
@@ -761,16 +755,20 @@ void Monitor::refreshMonitor()
 void Monitor::pause()
 {
     if (render == NULL) return;
-    activateMonitor();
+    slotActivateMonitor();
     render->pause();
     //m_playAction->setChecked(true);
     m_playAction->setIcon(m_playIcon);
 }
 
+void Monitor::unpause()
+{
+}
+
 void Monitor::slotPlay()
 {
     if (render == NULL) return;
-    activateMonitor();
+    slotActivateMonitor();
     if (render->playSpeed() == 0.0) {
         m_playAction->setIcon(m_pauseIcon);
         render->switchPlay(true);
@@ -783,7 +781,7 @@ void Monitor::slotPlay()
 void Monitor::slotPlayZone()
 {
     if (render == NULL) return;
-    activateMonitor();
+    slotActivateMonitor();
     QPoint p = m_ruler->zone();
     render->playZone(GenTime(p.x(), m_monitorManager->timecode().fps()), GenTime(p.y(), m_monitorManager->timecode().fps()));
     //m_playAction->setChecked(true);
@@ -793,7 +791,7 @@ void Monitor::slotPlayZone()
 void Monitor::slotLoopZone()
 {
     if (render == NULL) return;
-    activateMonitor();
+    slotActivateMonitor();
     QPoint p = m_ruler->zone();
     render->loopZone(GenTime(p.x(), m_monitorManager->timecode().fps()), GenTime(p.y(), m_monitorManager->timecode().fps()));
     //m_playAction->setChecked(true);
@@ -804,7 +802,7 @@ void Monitor::slotLoopClip()
 {
     if (render == NULL || m_selectedClip == NULL)
         return;
-    activateMonitor();
+    slotActivateMonitor();
     render->loopZone(m_selectedClip->startPos(), m_selectedClip->endPos());
     //m_playAction->setChecked(true);
     m_playAction->setIcon(m_pauseIcon);
@@ -816,7 +814,7 @@ void Monitor::updateClipProducer(Mlt::Producer *prod)
    render->setProducer(prod, render->seekFramePosition());
 }
 
-void Monitor::slotSetClipProducer(DocClipBase *clip, QPoint zone, int position)
+void Monitor::slotSetClipProducer(DocClipBase *clip, QPoint zone, bool forceUpdate, int position)
 {
     if (render == NULL) return;
     if (clip == NULL && m_currentClip != NULL) {
@@ -826,10 +824,10 @@ void Monitor::slotSetClipProducer(DocClipBase *clip, QPoint zone, int position)
         render->setProducer(NULL, -1);
         return;
     }
-    
-    if (clip != m_currentClip) {
+
+    if (clip != m_currentClip || forceUpdate) {
         m_currentClip = clip;
-        if (m_currentClip) activateMonitor();
+        if (m_currentClip) slotActivateMonitor();
         updateMarkers(clip);
         Mlt::Producer *prod = NULL;
         if (clip) prod = clip->getCloneProducer();
@@ -839,7 +837,7 @@ void Monitor::slotSetClipProducer(DocClipBase *clip, QPoint zone, int position)
         }
     } else {
         if (m_currentClip) {
-            activateMonitor();
+            slotActivateMonitor();
             if (position == -1) position = render->seekFramePosition();
             render->seek(position);
         }
@@ -853,7 +851,7 @@ void Monitor::slotSetClipProducer(DocClipBase *clip, QPoint zone, int position)
 void Monitor::slotOpenFile(const QString &file)
 {
     if (render == NULL) return;
-    activateMonitor();
+    slotActivateMonitor();
     QDomDocument doc;
     QDomElement mlt = doc.createElement("mlt");
     doc.appendChild(mlt);
@@ -877,7 +875,7 @@ void Monitor::resetProfile(const QString &profile)
     m_timePos->updateTimeCode(m_monitorManager->timecode());
     if (render == NULL) return;
     if (!render->hasProfile(profile)) {
-        activateMonitor();
+        slotActivateMonitor();
         render->resetProfile(profile);
     }
     if (m_effectWidget)
@@ -912,7 +910,7 @@ void Monitor::slotSwitchMonitorInfo(bool show)
     KdenliveSettings::setDisplayMonitorInfo(show);
     if (show) {
         if (m_overlay) return;
-        if (m_monitorRefresh == NULL) {
+        if (videoSurface == NULL) {
             // Using OpenGL display
 #ifdef USE_OPENGL
             if (m_glWidget->layout()) delete m_glWidget->layout();
@@ -924,13 +922,13 @@ void Monitor::slotSwitchMonitorInfo(bool show)
             m_glWidget->setLayout(layout);
 #endif
         } else {
-            if (m_monitorRefresh->layout()) delete m_monitorRefresh->layout();
+            if (videoSurface->layout()) delete videoSurface->layout();
             m_overlay = new Overlay();
             connect(m_overlay, SIGNAL(editMarker()), this, SLOT(slotEditMarker()));
             QVBoxLayout *layout = new QVBoxLayout;
             layout->addStretch(10);
             layout->addWidget(m_overlay);
-            m_monitorRefresh->setLayout(layout);
+            videoSurface->setLayout(layout);
             m_overlay->raise();
             m_overlay->setHidden(true);
         }
@@ -990,9 +988,9 @@ void Monitor::slotSetSelectedClip(Transition* item)
 
 void Monitor::slotEffectScene(bool show)
 {
-    if (m_name == "project") {
-        if (m_monitorRefresh) {
-            m_monitorRefresh->setVisible(!show);
+    if (m_id == Kdenlive::projectMonitor) {
+        if (videoSurface) {
+            videoSurface->setVisible(!show);
         } else {
 #ifdef USE_OPENGL
             m_glWidget->setVisible(!show);
@@ -1004,6 +1002,7 @@ void Monitor::slotEffectScene(bool show)
         if (show) {
             m_effectWidget->getScene()->slotZoomFit();
         }
+        videoBox->setEnabled(show);
         render->doRefresh();
     }
 }
@@ -1045,20 +1044,11 @@ AbstractRender *Monitor::abstractRender()
     return render;
 }
 
-MonitorRefresh::MonitorRefresh(QWidget* parent) :
-    QWidget(parent)
-    , m_renderer(NULL)
+void Monitor::reloadProducer(const QString &id)
 {
-    // MonitorRefresh is used as container for the SDL display (it's window id is passed to SDL)
-    setAttribute(Qt::WA_PaintOnScreen);
-    setAttribute(Qt::WA_OpaquePaintEvent);
-    setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
-    //setAttribute(Qt::WA_NoSystemBackground);
-}
-
-void MonitorRefresh::setRenderer(Render* render)
-{
-    m_renderer = render;
+    if (!m_currentClip) return;
+    if (m_currentClip->getId() == id)
+        slotSetClipProducer(m_currentClip, m_currentClip->zone(), true);
 }
 
 
@@ -1075,146 +1065,41 @@ Overlay::Overlay(QWidget* parent) :
 // virtual
 void Overlay::mouseReleaseEvent ( QMouseEvent * event )
 {
-    event->accept();
+    event->ignore();
 }
 
 // virtual
 void Overlay::mousePressEvent( QMouseEvent * event )
 {
-    event->accept();
+    event->ignore();
 }
 
 // virtual
 void Overlay::mouseDoubleClickEvent ( QMouseEvent * event )
 {
     emit editMarker();
-    event->accept();
+    event->ignore();
 }
 
 void Overlay::setOverlayText(const QString &text, bool isZone)
 {
+    if (text.isEmpty()) {
+       QPalette p;
+       p.setColor(QPalette::Base, KdenliveSettings::window_background());
+       setPalette(p);
+       setText(QString());
+       repaint();
+       setHidden(true);
+       return;
+    }
     setHidden(true);
-    m_isZone = isZone;
     QPalette p;
     p.setColor(QPalette::Text, Qt::white);
-    if (m_isZone) p.setColor(QPalette::Base, QColor(200, 0, 0));
+    if (isZone) p.setColor(QPalette::Base, QColor(200, 0, 0));
     else p.setColor(QPalette::Base, QColor(0, 0, 200));
     setPalette(p);
     setText(' ' + text + ' ');
     setHidden(false);
-    update();
-}
-
-VideoContainer::VideoContainer(Monitor* parent) :
-    QFrame()
-    , m_monitor(parent)
-{
-    setFrameShape(QFrame::NoFrame);
-    setFocusPolicy(Qt::ClickFocus);
-    setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
-}
-
-// virtual
-void VideoContainer::mousePressEvent(QMouseEvent * event)
-{
-    if (m_monitor->underMouse()) event->setAccepted(false);
-}
-
-// virtual
-void VideoContainer::mouseReleaseEvent(QMouseEvent * event)
-{
-    if (m_monitor->underMouse()) event->setAccepted(false);
-    else {
-        if (m_monitor->isActive()) {
-            m_monitor->slotPlay();
-            event->accept();
-        }
-    }
-}
-
-// virtual
-void VideoContainer::mouseMoveEvent(QMouseEvent *event)
-{
-    if (m_monitor->underMouse()) event->setAccepted(false);
-}
-
-// virtual
-void VideoContainer::keyPressEvent(QKeyEvent *event)
-{
-    // Exit fullscreen with Esc key
-    if (event->key() == Qt::Key_Escape && isFullScreen()) {
-        switchFullScreen();
-        event->setAccepted(true);
-    } else event->setAccepted(false);
-}
-
-// virtual
-void VideoContainer::wheelEvent(QWheelEvent * event)
-{
-    if (m_monitor->underMouse()) event->setAccepted(false);
-    else {
-        m_monitor->slotMouseSeek(event->delta(), event->modifiers() == Qt::ControlModifier);
-        event->accept();
-    }
-}
-
-void VideoContainer::mouseDoubleClickEvent(QMouseEvent * event)
-{
-    Q_UNUSED(event)
-
-    if (!KdenliveSettings::openglmonitors())
-        switchFullScreen();
-}
-
-void VideoContainer::switchFullScreen()
-{
-    // TODO: disable screensaver?
-    Qt::WindowFlags flags = windowFlags();
-    if (!isFullScreen()) {
-        // Check if we ahave a multiple monitor setup
-        setUpdatesEnabled(false);
-#if QT_VERSION >= 0x040600
-        int monitors = QApplication::desktop()->screenCount();
-#else
-        int monitors = QApplication::desktop()->numScreens();
-#endif
-        if (monitors > 1) {
-            QRect screenres;
-            // Move monitor widget to the second screen (one screen for Kdenlive, the other one for the Monitor widget
-            int currentScreen = QApplication::desktop()->screenNumber(this);
-            if (currentScreen < monitors - 1)
-                screenres = QApplication::desktop()->screenGeometry(currentScreen + 1);
-            else
-                screenres = QApplication::desktop()->screenGeometry(currentScreen - 1);
-            move(QPoint(screenres.x(), screenres.y()));
-            resize(screenres.width(), screenres.height());
-        }
-
-        m_baseFlags = flags & (Qt::Window | Qt::SubWindow);
-        flags |= Qt::Window;
-        flags ^= Qt::SubWindow;
-        setWindowFlags(flags);
-#ifdef Q_WS_X11
-        // This works around a bug with Compiz
-        // as the window must be visible before we can set the state
-        show();
-        raise();
-        setWindowState(windowState() | Qt::WindowFullScreen);   // set
-#else
-        setWindowState(windowState() | Qt::WindowFullScreen);   // set
-        setUpdatesEnabled(true);
-        show();
-#endif
-    } else {
-        setUpdatesEnabled(false);
-        flags ^= (Qt::Window | Qt::SubWindow); //clear the flags...
-        flags |= m_baseFlags; //then we reset the flags (window and subwindow)
-        setWindowFlags(flags);
-        setWindowState(windowState()  ^ Qt::WindowFullScreen);   // reset
-        setUpdatesEnabled(true);
-        show();
-    }
-    m_monitor->pause();
 }
 
 
index ba949ff0417a35a427af682d44ce705c0d849861..0fe6d50ae7ddcfc07be0c67117dcb3935d7e4424 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "gentime.h"
 #include "renderer.h"
+#include "definitions.h"
 #include "timecodedisplay.h"
 #include "abstractmonitor.h"
 #ifdef USE_OPENGL
@@ -47,36 +48,6 @@ class MonitorEditWidget;
 class Monitor;
 class MonitorManager;
 
-class VideoContainer : public QFrame
-{
-    Q_OBJECT
-public:
-    VideoContainer(Monitor *parent = 0);
-    void switchFullScreen();
-
-protected:
-    virtual void mouseDoubleClickEvent(QMouseEvent * event);
-    virtual void mousePressEvent(QMouseEvent * event);
-    virtual void mouseReleaseEvent(QMouseEvent *event);
-    virtual void mouseMoveEvent(QMouseEvent *event);
-    void keyPressEvent(QKeyEvent *event);
-    virtual void wheelEvent(QWheelEvent * event);
-
-private:
-    Qt::WindowFlags m_baseFlags;
-    Monitor *m_monitor;
-};
-
-class MonitorRefresh : public QWidget
-{
-    Q_OBJECT
-public:
-    MonitorRefresh(QWidget *parent = 0);
-    void setRenderer(Render* render);
-
-private:
-    Render *m_renderer;
-};
 
 class Overlay : public QLabel
 {
@@ -85,9 +56,6 @@ public:
     Overlay(QWidget* parent = 0);
     void setOverlayText(const QString &, bool isZone = true);
 
-private:
-    bool m_isZone;
-
 protected:
     virtual void mouseDoubleClickEvent ( QMouseEvent * event );
     virtual void mousePressEvent ( QMouseEvent * event );
@@ -102,15 +70,14 @@ class Monitor : public AbstractMonitor
     Q_OBJECT
 
 public:
-    Monitor(QString name, MonitorManager *manager, QString profile = QString(), QWidget *parent = 0);
+    Monitor(Kdenlive::MONITORID id, MonitorManager *manager, QString profile = QString(), QWidget *parent = 0);
     ~Monitor();
     Render *render;
     AbstractRender *abstractRender();
     void resetProfile(const QString &profile);
-    const QString name() const;
     void resetSize();
-    bool isActive() const;
     void pause();
+    void unpause();
     void setupMenu(QMenu *goMenu, QAction *playZone, QAction *loopZone, QMenu *markerMenu = NULL, QAction *loopClip = NULL);
     const QString sceneList();
     DocClipBase *activeClip();
@@ -120,11 +87,13 @@ public:
     void updateMarkers(DocClipBase *source);
     MonitorEditWidget *getEffectEdit();
     QWidget *container();
+    void reloadProducer(const QString &id);
     QFrame *m_volumePopup;
 
 protected:
     virtual void mousePressEvent(QMouseEvent * event);
     virtual void mouseReleaseEvent(QMouseEvent * event);
+    virtual void mouseDoubleClickEvent(QMouseEvent * event);
     virtual void resizeEvent(QResizeEvent *event);
 
     /** @brief Move to another position on mouse wheel event.
@@ -142,15 +111,13 @@ protected:
     //virtual void paintEvent(QPaintEvent * event);
 
 private:
-    QString m_name;
-    MonitorManager *m_monitorManager;
+    Kdenlive::MONITORID m_name;
     DocClipBase *m_currentClip;
     SmallRuler *m_ruler;
     Overlay *m_overlay;
     double m_scale;
     int m_length;
     bool m_dragStarted;
-    MonitorRefresh *m_monitorRefresh;
     KIcon m_playIcon;
     KIcon m_pauseIcon;
     TimecodeDisplay *m_timePos;
@@ -198,17 +165,17 @@ private slots:
     void slotSetVolume(int volume);
     void slotShowVolume();
     void slotEditMarker();
+    void slotExtractCurrentZone();
 
 public slots:
     void slotOpenFile(const QString &);
-    void slotSetClipProducer(DocClipBase *clip, QPoint zone = QPoint(), int position = -1);
+    void slotSetClipProducer(DocClipBase *clip, QPoint zone = QPoint(), bool forceUpdate = false, int position = -1);
     void updateClipProducer(Mlt::Producer *prod);
     void refreshMonitor(bool visible);
     void refreshMonitor();
     void slotSeek(int pos);
     void stop();
     void start();
-    bool activateMonitor();
     void slotPlay();
     void slotPlayZone();
     void slotLoopZone();
@@ -251,6 +218,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 76109ba546a3774ea92e1d0936d87f5fecc84190..8e5bd1d77024ae19e38ff4b615412d6dcff72b57 100644 (file)
 MonitorEditWidget::MonitorEditWidget(Render* renderer, QWidget* parent) :
         QWidget(parent)
 {
+    setAutoFillBackground(true);
+    setAttribute(Qt::WA_PaintOnScreen, false);
+    setAttribute(Qt::WA_OpaquePaintEvent, false);
+    setContentsMargins(0, 0, 0, 0);
+    setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
     m_ui.setupUi(this);
-
     m_scene = new MonitorScene(renderer);
     m_view = new QGraphicsView(m_scene, m_ui.frameVideo);
+    m_view->setFrameShape(QFrame::NoFrame);
     m_view->setRenderHints(QFlags<QPainter::RenderHint>());
     m_view->scale(((double) renderer->renderWidth()) / renderer->frameRenderWidth(), 1.0);
     m_view->setMouseTracking(true);
index 81b5a2ad547bd7888b7a6ff3a4bfd45e5adabaf7..4b52c41493fbde30b2299923b4cad2bb6d4e0489 100644 (file)
@@ -60,7 +60,7 @@ public:
 private slots:
     /** @brief Sets the KdenliveSetting directupdate with true = update parameters (rerender frame) during mouse move (before mouse button is released) */
     void slotSetDirectUpdate(bool directUpdate);
-
+    
 private:
     Ui::MonitorEditWidget_UI m_ui;
     MonitorScene *m_scene;
index 1b0a7c6fb278400d20a2867947a0648408ea4681..09c6c1e149d46f761aab230ffc147251a0c3dbed 100644 (file)
@@ -28,6 +28,7 @@
 #include <QTimer>
 #include <KDebug>
 
+
 MonitorManager::MonitorManager(QWidget *parent) :
         QObject(parent),
         m_clipMonitor(NULL),
@@ -62,15 +63,26 @@ void MonitorManager::removeMonitor(AbstractMonitor *monitor)
     m_monitorsList.removeAll(monitor);
 }
 
-bool MonitorManager::activateMonitor(const QString &name)
+AbstractMonitor* MonitorManager::monitor(Kdenlive::MONITORID monitorName)
+{
+    AbstractMonitor *monitor = NULL;
+    for (int i = 0; i < m_monitorsList.size(); i++) {
+        if (m_monitorsList[i]->id() == monitorName) {
+           monitor = m_monitorsList[i];
+       }
+    }
+    return monitor;
+}
+
+bool MonitorManager::activateMonitor(Kdenlive::MONITORID name)
 {
     if (m_clipMonitor == NULL || m_projectMonitor == NULL)
         return false;
-    if (m_activeMonitor && m_activeMonitor->name() == name)
+    if (m_activeMonitor && m_activeMonitor->id() == name)
         return false;
     m_activeMonitor = NULL;
     for (int i = 0; i < m_monitorsList.count(); i++) {
-        if (m_monitorsList.at(i)->name() == name) {
+        if (m_monitorsList.at(i)->id() == name) {
             m_activeMonitor = m_monitorsList.at(i);
         }
         else m_monitorsList.at(i)->stop();
@@ -85,29 +97,28 @@ bool MonitorManager::activateMonitor(const QString &name)
     return (m_activeMonitor != NULL);
 }
 
-bool MonitorManager::isActive(const QString &name) const
+bool MonitorManager::isActive(Kdenlive::MONITORID id) const
 {
-    return m_activeMonitor ? m_activeMonitor->name() == name: false;
+    return m_activeMonitor ? m_activeMonitor->id() == id: false;
 }
 
 void MonitorManager::slotSwitchMonitors(bool activateClip)
 {
     if (activateClip)
-        activateMonitor("clip");
+        activateMonitor(Kdenlive::clipMonitor);
     else
-        activateMonitor("project");
+        activateMonitor(Kdenlive::projectMonitor);
 }
 
 void MonitorManager::stopActiveMonitor()
 {
     if (m_activeMonitor == m_clipMonitor) m_clipMonitor->pause();
-    else m_projectMonitor->pause();
+    else if (m_activeMonitor == m_projectMonitor) m_projectMonitor->pause();
 }
 
 void MonitorManager::slotPlay()
 {
-    if (m_activeMonitor == m_clipMonitor) m_clipMonitor->slotPlay();
-    else m_projectMonitor->slotPlay();
+    if (m_activeMonitor) m_activeMonitor->slotPlay();
 }
 
 void MonitorManager::slotPause()
@@ -118,7 +129,7 @@ void MonitorManager::slotPause()
 void MonitorManager::slotPlayZone()
 {
     if (m_activeMonitor == m_clipMonitor) m_clipMonitor->slotPlayZone();
-    else m_projectMonitor->slotPlayZone();
+    else if (m_activeMonitor == m_projectMonitor) m_projectMonitor->slotPlayZone();
 }
 
 void MonitorManager::slotLoopZone()
@@ -130,49 +141,49 @@ void MonitorManager::slotLoopZone()
 void MonitorManager::slotRewind(double speed)
 {
     if (m_activeMonitor == m_clipMonitor) m_clipMonitor->slotRewind(speed);
-    else m_projectMonitor->slotRewind(speed);
+    else if (m_activeMonitor == m_projectMonitor) m_projectMonitor->slotRewind(speed);
 }
 
 void MonitorManager::slotForward(double speed)
 {
     if (m_activeMonitor == m_clipMonitor) m_clipMonitor->slotForward(speed);
-    else m_projectMonitor->slotForward(speed);
+    else if (m_activeMonitor == m_projectMonitor) m_projectMonitor->slotForward(speed);
 }
 
 void MonitorManager::slotRewindOneFrame()
 {
     if (m_activeMonitor == m_clipMonitor) m_clipMonitor->slotRewindOneFrame();
-    else m_projectMonitor->slotRewindOneFrame();
+    else if (m_activeMonitor == m_projectMonitor) m_projectMonitor->slotRewindOneFrame();
 }
 
 void MonitorManager::slotForwardOneFrame()
 {
     if (m_activeMonitor == m_clipMonitor) m_clipMonitor->slotForwardOneFrame();
-    else m_projectMonitor->slotForwardOneFrame();
+    else if (m_activeMonitor == m_projectMonitor) m_projectMonitor->slotForwardOneFrame();
 }
 
 void MonitorManager::slotRewindOneSecond()
 {
     if (m_activeMonitor == m_clipMonitor) m_clipMonitor->slotRewindOneFrame(m_timecode.fps());
-    else m_projectMonitor->slotRewindOneFrame(m_timecode.fps());
+    else if (m_activeMonitor == m_projectMonitor) m_projectMonitor->slotRewindOneFrame(m_timecode.fps());
 }
 
 void MonitorManager::slotForwardOneSecond()
 {
     if (m_activeMonitor == m_clipMonitor) m_clipMonitor->slotForwardOneFrame(m_timecode.fps());
-    else m_projectMonitor->slotForwardOneFrame(m_timecode.fps());
+    else if (m_activeMonitor == m_projectMonitor) m_projectMonitor->slotForwardOneFrame(m_timecode.fps());
 }
 
 void MonitorManager::slotStart()
 {
     if (m_activeMonitor == m_clipMonitor) m_clipMonitor->slotStart();
-    else m_projectMonitor->slotStart();
+    else if (m_activeMonitor == m_projectMonitor) m_projectMonitor->slotStart();
 }
 
 void MonitorManager::slotEnd()
 {
     if (m_activeMonitor == m_clipMonitor) m_clipMonitor->slotEnd();
-    else m_projectMonitor->slotEnd();
+    else if (m_activeMonitor == m_projectMonitor) m_projectMonitor->slotEnd();
 }
 
 void MonitorManager::resetProfiles(Timecode tc)
@@ -186,17 +197,19 @@ void MonitorManager::slotResetProfiles()
 {
     if (m_projectMonitor == NULL || m_clipMonitor == NULL) return;
     blockSignals(true);
-    QString active = m_activeMonitor ? m_activeMonitor->name() : QString();
+    Kdenlive::MONITORID active = m_activeMonitor ? m_activeMonitor->id() : Kdenlive::noMonitor;
     m_clipMonitor->resetProfile(KdenliveSettings::current_profile());
     m_projectMonitor->resetProfile(KdenliveSettings::current_profile());
-    if (!active.isEmpty()) activateMonitor(active);
+    if (active != Kdenlive::noMonitor) activateMonitor(active);
     blockSignals(false);
     if (m_activeMonitor) m_activeMonitor->parentWidget()->raise();
     emit checkColorScopes();
 }
 
-void MonitorManager::slotRefreshCurrentMonitor()
+void MonitorManager::slotRefreshCurrentMonitor(const QString &id)
 {
+    // Clip producer was modified, check if clip is currently displayed in clip monitor
+    m_clipMonitor->reloadProducer(id);
     if (m_activeMonitor == m_clipMonitor) m_clipMonitor->refreshMonitor();
     else m_projectMonitor->refreshMonitor();
 }
@@ -204,11 +217,14 @@ void MonitorManager::slotRefreshCurrentMonitor()
 void MonitorManager::slotUpdateAudioMonitoring()
 {
     // if(...) added since they are 0x0 when the config wizard is running! --Granjow
-    if (m_clipMonitor) {
+    /*if (m_clipMonitor) {
         m_clipMonitor->render->analyseAudio = KdenliveSettings::monitor_audio();
     }
     if (m_projectMonitor) {
         m_projectMonitor->render->analyseAudio = KdenliveSettings::monitor_audio();
+    }*/
+    for (int i = 0; i < m_monitorsList.count(); i++) {
+        if (m_monitorsList.at(i)->abstractRender()) m_monitorsList.at(i)->abstractRender()->analyseAudio = KdenliveSettings::monitor_audio();
     }
 }
 
@@ -230,4 +246,9 @@ AbstractRender *MonitorManager::activeRenderer()
     return NULL;
 }
 
+void MonitorManager::slotSwitchFullscreen()
+{
+    if (m_activeMonitor) m_activeMonitor->slotSwitchFullScreen();
+}
+
 #include "monitormanager.moc"
index eb58634486ba0fa957173f7242ae62a170dcca49..880b6d1279a924390725468115922258b7a12e46 100644 (file)
@@ -39,6 +39,10 @@ public:
     void resetProfiles(Timecode tc);
     void stopActiveMonitor();
     AbstractRender *activeRenderer();
+    /** Searches for a monitor with the given name.
+       @return NULL, if no monitor could be found, or the monitor otherwise.
+    */
+    AbstractMonitor *monitor(Kdenlive::MONITORID monitorName);
     void updateScopeSource();
     void clearScopeSource();
 
@@ -46,8 +50,8 @@ public slots:
 
     /** @brief Activates a monitor.
      * @param name name of the monitor to activate */
-    bool activateMonitor(const QString &name = QString());
-    bool isActive(const QString &name) const;
+    bool activateMonitor(Kdenlive::MONITORID);
+    bool isActive(Kdenlive::MONITORID id) const;
     void slotPlay();
     void slotPause();
     void slotPlayZone();
@@ -61,6 +65,9 @@ public slots:
     void slotStart();
     void slotEnd();
     void slotResetProfiles();
+    
+    /** @brief Switch current monitor to fullscreen. */
+    void slotSwitchFullscreen();
 
     /** @brief Switches between project and clip monitor.
      * @ref activateMonitor
@@ -69,7 +76,7 @@ public slots:
     void slotUpdateAudioMonitoring();
 
 private slots:
-    void slotRefreshCurrentMonitor();
+    void slotRefreshCurrentMonitor(const QString &id);
 
 private:
     Monitor *m_clipMonitor;
index d0b9999ec99b11dbc1fd9cdf2803d3d4535d8e68..c42252376c2427d987d09037cb7979d2200e6b78 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 JobStatusMessage = Qt::UserRole + 7;
 const int itemHeight = 38;
 
 ProjectItem::ProjectItem(QTreeWidget * parent, DocClipBase *clip) :
@@ -105,15 +107,6 @@ int ProjectItem::clipMaxDuration() const
     return m_clip->getProperty("duration").toInt();
 }
 
-QStringList ProjectItem::names() const
-{
-    QStringList result;
-    result.append(text(0));
-    result.append(text(1));
-    result.append(text(2));
-    return result;
-}
-
 QDomElement ProjectItem::toXml() const
 {
     return m_clip->toXML();
@@ -165,8 +158,16 @@ DocClipBase *ProjectItem::referencedClip()
 
 void ProjectItem::slotSetToolTip()
 {
-    QString tip = "<b>";
+    QString tip;
     if (m_clip->isPlaceHolder()) tip.append(i18n("Missing") + " | ");
+    QString jobInfo = data(0, JobStatusMessage).toString();
+    if (!jobInfo.isEmpty()) {
+        tip.append(jobInfo + " | ");
+    }
+    if (hasProxy() && data(0, JobTypeRole).toInt() != PROXYJOB) {
+        tip.append(i18n("Proxy clip") + " | ");
+    }
+    tip.append("<b>");
     switch (m_clipType) {
     case AUDIO:
         tip.append(i18n("Audio clip") + "</b><br />" + clipUrl().path());
@@ -200,7 +201,6 @@ void ProjectItem::slotSetToolTip()
         tip.append(i18n("Unknown clip"));
         break;
     }
-
     setToolTip(0, tip);
 }
 
@@ -253,28 +253,48 @@ void ProjectItem::setProperties(const QMap < QString, QString > &attributes, con
     }
 }
 
-void ProjectItem::setProxyStatus(PROXYSTATUS status, int progress)
+void ProjectItem::setJobStatus(JOBTYPE jobType, CLIPJOBSTATUS status, int progress, const QString &statusMessage)
+{
+    setData(0, JobTypeRole, jobType);
+    if (progress > 0) setData(0, JobProgressRole, progress);
+    else {
+        setData(0, JobProgressRole, status);
+        if ((status == JOBABORTED || status == JOBCRASHED  || status == JOBDONE) || !statusMessage.isEmpty())
+            setData(0, JobStatusMessage, statusMessage);
+        slotSetToolTip();
+    }
+}
+
+void ProjectItem::setConditionalJobStatus(CLIPJOBSTATUS status, JOBTYPE requestedJobType)
 {
-    if (progress > 0) setData(0, ProxyRole, progress);
-    else setData(0, ProxyRole, status);
+    if (data(0, JobTypeRole).toInt() == requestedJobType) {
+        setData(0, JobProgressRole, status);
+    }
 }
 
 bool ProjectItem::hasProxy() const
 {
     if (m_clip == NULL) return false;
-    if (m_clip->getProperty("proxy").isEmpty() || m_clip->getProperty("proxy") == "-" || data(0, ProxyRole).toInt() == PROXYCRASHED) return false;
+    if (m_clip->getProperty("proxy").size() < 2 || data(0, JobProgressRole).toInt() == JOBCRASHED) return false;
     return true;
 }
 
 bool ProjectItem::isProxyReady() const
 {
-     return (data(0, ProxyRole).toInt() == PROXYDONE);
+     return (data(0, JobProgressRole).toInt() == JOBDONE);
+}
+
+bool ProjectItem::isJobRunning() const
+{
+    int s = data(0, JobProgressRole).toInt();
+    if (s == JOBWAITING || s == JOBWORKING || s > 0) return true;
+    return false;
 }
 
 bool ProjectItem::isProxyRunning() const
 {
-    int s = data(0, ProxyRole).toInt();
-    if (s == PROXYWAITING || s == CREATINGPROXY || s > 0) return true;
+    int s = data(0, JobProgressRole).toInt();
+    if ((s == JOBWORKING || s > 0) && data(0, JobTypeRole).toInt() == (int) PROXYJOB) return true;
     return false;
 }
 
index 64f009209f1776eea03af2575e674e2bc034ccda..c6fd3b4af01394e758b6a598d7535234627c60fc 100644 (file)
@@ -30,6 +30,8 @@
 
 #include "gentime.h"
 #include "definitions.h"
+#include "projecttree/abstractclipjob.h"
+
 
 class DocClipBase;
 
@@ -51,7 +53,6 @@ public:
      *
      * The clipId is used both to identify clips and folders (groups) */
     const QString &clipId() const;
-    QStringList names() const;
     const KUrl clipUrl() const;
     int clipMaxDuration() const;
     CLIPTYPE clipType() const;
@@ -63,12 +64,16 @@ 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(PROXYSTATUS status, int progress = 0);
+    /** \brief Set the status of the clip job. */
+    void setJobStatus(JOBTYPE jobType, CLIPJOBSTATUS status, int progress = 0, const QString &statusMessage = QString());
+    /** \brief Set the status of a clip job if it is of the specified job type. */
+    void setConditionalJobStatus(CLIPJOBSTATUS status, JOBTYPE requestedJobType);
     /** \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 d28a11892ea6b104212ebf2176ea0589c3594131..3ebba4c6fa5c00fbdd50808d05d28b4f40e27a63 100644 (file)
@@ -20,6 +20,9 @@
 #include "projectlist.h"
 #include "projectitem.h"
 #include "commands/addfoldercommand.h"
+#include "projecttree/proxyclipjob.h"
+#include "projecttree/cutclipjob.h"
+#include "projecttree/meltjob.h"
 #include "kdenlivesettings.h"
 #include "slideshowclip.h"
 #include "ui_colorclip_ui.h"
 #include "projectlistview.h"
 #include "timecodedisplay.h"
 #include "profilesdialog.h"
+#include "clipstabilize.h"
 #include "commands/editclipcommand.h"
 #include "commands/editclipcutcommand.h"
 #include "commands/editfoldercommand.h"
 #include "commands/addclipcutcommand.h"
 
 #include "ui_templateclip_ui.h"
+#include "ui_cutjobdialog_ui.h"
 
 #include <KDebug>
 #include <KAction>
 #include <KFileItem>
 #include <KApplication>
 #include <KStandardDirs>
+#include <KColorScheme>
+#include <KActionCollection>
+#include <KUrlRequester>
 
-#ifdef NEPOMUK
+#ifdef USE_NEPOMUK
 #include <nepomuk/global.h>
 #include <nepomuk/resourcemanager.h>
+#include <Nepomuk/Resource>
 //#include <nepomuk/tag.h>
 #endif
 
 #include <QtConcurrentRun>
 #include <QVBoxLayout>
 
+SmallInfoLabel::SmallInfoLabel(QWidget *parent) : QPushButton(parent)
+{
+    setFixedWidth(0);
+    setFlat(true);
+    
+    /*QString style = "QToolButton {background-color: %1;border-style: outset;border-width: 2px;
+     border-radius: 5px;border-color: beige;}";*/
+    KColorScheme scheme(palette().currentColorGroup(), KColorScheme::Window, KSharedConfig::openConfig(KdenliveSettings::colortheme()));
+    QColor bg = scheme.background(KColorScheme::LinkBackground).color();
+    QColor fg = scheme.foreground(KColorScheme::LinkText).color();
+    QString style = QString("QPushButton {padding:2px;background-color: rgb(%1, %2, %3);border-radius: 4px;border: none;color: rgb(%4, %5, %6)}").arg(bg.red()).arg(bg.green()).arg(bg.blue()).arg(fg.red()).arg(fg.green()).arg(fg.blue());
+    
+    bg = scheme.background(KColorScheme::ActiveBackground).color();
+    fg = scheme.foreground(KColorScheme::ActiveText).color();
+    style.append(QString("\nQPushButton:hover {padding:2px;background-color: rgb(%1, %2, %3);border-radius: 4px;border: none;color: rgb(%4, %5, %6)}").arg(bg.red()).arg(bg.green()).arg(bg.blue()).arg(fg.red()).arg(fg.green()).arg(fg.blue()));
+    
+    setStyleSheet(style);
+    m_timeLine = new QTimeLine(500, this);
+    QObject::connect(m_timeLine, SIGNAL(valueChanged(qreal)), this, SLOT(slotTimeLineChanged(qreal)));
+    QObject::connect(m_timeLine, SIGNAL(finished()), this, SLOT(slotTimeLineFinished()));
+    hide();
+}
+
+void SmallInfoLabel::slotTimeLineChanged(qreal value)
+{
+    setFixedWidth(qMin(value * 2, qreal(1.0)) * sizeHint().width());
+    update();
+}
+
+void SmallInfoLabel::slotTimeLineFinished()
+{
+    if (m_timeLine->direction() == QTimeLine::Forward) {
+        // Show
+        show();
+    } else {
+        // Hide
+        hide();
+        setText(QString());
+    }
+}
+
+void SmallInfoLabel::slotSetJobCount(int jobCount)
+{
+    if (jobCount > 0) {
+        // prepare animation
+        setText(i18np("%1 job", "%1 jobs", jobCount));
+        setToolTip(i18np("%1 pending job", "%1 pending jobs", jobCount));
+        
+        if (!(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects)) {
+            setFixedWidth(sizeHint().width());
+            show();
+            return;
+        }
+        
+        if (isVisible()) {
+            setFixedWidth(sizeHint().width());
+            update();
+            return;
+        }
+        
+        setFixedWidth(0);
+        show();
+        int wantedWidth = sizeHint().width();
+        setGeometry(-wantedWidth, 0, wantedWidth, height());
+        m_timeLine->setDirection(QTimeLine::Forward);
+        if (m_timeLine->state() == QTimeLine::NotRunning) {
+            m_timeLine->start();
+        }
+    }
+    else {
+        if (!(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects)) {
+            setFixedWidth(0);
+            hide();
+            return;
+        }
+        // hide
+        m_timeLine->setDirection(QTimeLine::Backward);
+        if (m_timeLine->state() == QTimeLine::NotRunning) {
+            m_timeLine->start();
+        }
+    }
+    
+}
+
+
 InvalidDialog::InvalidDialog(const QString &caption, const QString &message, bool infoOnly, QWidget *parent) : KDialog(parent)
 {
     setCaption(caption);
@@ -112,15 +206,18 @@ ProjectList::ProjectList(QWidget *parent) :
     m_commandStack(NULL),
     m_openAction(NULL),
     m_reloadAction(NULL),
-    m_stabilizeAction(NULL),
+    m_extractAudioAction(NULL),
     m_transcodeAction(NULL),
+    m_stabilizeAction(NULL),
     m_doc(NULL),
     m_refreshed(false),
     m_allClipsProcessed(false),
     m_thumbnailQueue(),
-    m_abortAllProxies(false),
+    m_abortAllJobs(false),
+    m_closing(false),
     m_invalidClipDialog(NULL)
 {
+    qRegisterMetaType<stringMap> ("stringMap");
     QVBoxLayout *layout = new QVBoxLayout;
     layout->setContentsMargins(0, 0, 0, 0);
     layout->setSpacing(0);
@@ -129,29 +226,63 @@ ProjectList::ProjectList(QWidget *parent) :
     QFrame *frame = new QFrame;
     frame->setFrameStyle(QFrame::NoFrame);
     QHBoxLayout *box = new QHBoxLayout;
+    box->setContentsMargins(0, 0, 0, 0);
+    
     KTreeWidgetSearchLine *searchView = new KTreeWidgetSearchLine;
-
     box->addWidget(searchView);
-    //int s = style()->pixelMetric(QStyle::PM_SmallIconSize);
-    //m_toolbar->setIconSize(QSize(s, s));
+    
+    // small info button for pending jobs
+    m_infoLabel = new SmallInfoLabel(this);
+    connect(this, SIGNAL(jobCount(int)), m_infoLabel, SLOT(slotSetJobCount(int)));
+    m_jobsMenu = new QMenu(this);
+    connect(m_jobsMenu, SIGNAL(aboutToShow()), this, SLOT(slotPrepareJobsMenu()));
+    QAction *cancelJobs = new QAction(i18n("Cancel All Jobs"), this);
+    cancelJobs->setCheckable(false);
+    connect(cancelJobs, SIGNAL(triggered()), this, SLOT(slotCancelJobs()));
+    connect(this, SIGNAL(checkJobProcess()), this, SLOT(slotCheckJobProcess()));
+    m_discardCurrentClipJobs = new QAction(i18n("Cancel Current Clip Jobs"), this);
+    m_discardCurrentClipJobs->setCheckable(false);
+    connect(m_discardCurrentClipJobs, SIGNAL(triggered()), this, SLOT(slotDiscardClipJobs()));
+    m_jobsMenu->addAction(cancelJobs);
+    m_jobsMenu->addAction(m_discardCurrentClipJobs);
+    m_infoLabel->setMenu(m_jobsMenu);
+    box->addWidget(m_infoLabel);
+       
+    int size = style()->pixelMetric(QStyle::PM_SmallIconSize);
+    QSize iconSize(size, size);
 
     m_addButton = new QToolButton;
     m_addButton->setPopupMode(QToolButton::MenuButtonPopup);
     m_addButton->setAutoRaise(true);
+    m_addButton->setIconSize(iconSize);
     box->addWidget(m_addButton);
 
     m_editButton = new QToolButton;
     m_editButton->setAutoRaise(true);
+    m_editButton->setIconSize(iconSize);
     box->addWidget(m_editButton);
 
     m_deleteButton = new QToolButton;
     m_deleteButton->setAutoRaise(true);
+    m_deleteButton->setIconSize(iconSize);
     box->addWidget(m_deleteButton);
     frame->setLayout(box);
     layout->addWidget(frame);
 
     m_listView = new ProjectListView;
     layout->addWidget(m_listView);
+    
+#if KDE_IS_VERSION(4,7,0)    
+    m_infoMessage = new KMessageWidget;
+    layout->addWidget(m_infoMessage);
+    m_infoMessage->setCloseButtonVisible(true);
+    //m_infoMessage->setWordWrap(true);
+    m_infoMessage->hide();
+    m_logAction = new QAction(i18n("Show Log"), this);
+    m_logAction->setCheckable(false);
+    connect(m_logAction, SIGNAL(triggered()), this, SLOT(slotShowJobLog()));
+#endif
+
     setLayout(layout);
     searchView->setTreeWidget(m_listView);
 
@@ -163,13 +294,21 @@ 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 *)));
-
+    
+    connect(this, SIGNAL(cancelRunningJob(const QString, stringMap )), this, SLOT(slotCancelRunningJob(const QString, stringMap)));
+    connect(this, SIGNAL(processLog(const QString, int , int, const QString)), this, SLOT(slotProcessLog(const QString, int , int, const QString)));
+    
+    connect(this, SIGNAL(updateJobStatus(const QString, int, int, const QString, const QString, const QString)), this, SLOT(slotUpdateJobStatus(const QString, int, int, const QString, const QString, const QString)));
+    
+    connect(this, SIGNAL(gotProxy(const QString)), this, SLOT(slotGotProxyForId(const QString)));
+    
     m_listViewDelegate = new ItemDelegate(m_listView);
     m_listView->setItemDelegate(m_listViewDelegate);
-#ifdef NEPOMUK
+#ifdef USE_NEPOMUK
     if (KdenliveSettings::activate_nepomuk()) {
         Nepomuk::ResourceManager::instance()->init();
         if (!Nepomuk::ResourceManager::instance()->initialized()) {
@@ -182,12 +321,23 @@ ProjectList::ProjectList(QWidget *parent) :
 
 ProjectList::~ProjectList()
 {
-    m_abortAllProxies = true;
+    m_abortAllJobs = true;
+    for (int i = 0; i < m_jobList.count(); i++) {
+        m_jobList.at(i)->setStatus(JOBABORTED);
+    }
+    m_closing = true;
     m_thumbnailQueue.clear();
+    m_jobThreads.waitForFinished();
+    m_jobThreads.clearFutures();
+    if (!m_jobList.isEmpty()) qDeleteAll(m_jobList);
+    m_jobList.clear();
     delete m_menu;
     m_listView->blockSignals(true);
     m_listView->clear();
     delete m_listViewDelegate;
+#if KDE_IS_VERSION(4,7,0)
+    delete m_infoMessage;
+#endif
 }
 
 void ProjectList::focusTree() const
@@ -239,18 +389,21 @@ void ProjectList::setupGeneratorMenu(const QHash<QString,QMenu*>& menus)
                QMenu* addMenu=menus.value("addMenu");
                menu->addMenu(addMenu);
                m_addButton->setMenu(menu);
-
-               m_menu->addMenu(addMenu);
                if (addMenu->isEmpty())
                        addMenu->setEnabled(false);
        }
-       if (menus.contains("transcodeMenu") && menus.value("transcodeMenu") ){
-               QMenu* transcodeMenu=menus.value("transcodeMenu");
-               m_menu->addMenu(transcodeMenu);
-               if (transcodeMenu->isEmpty())
-                       transcodeMenu->setEnabled(false);
-               m_transcodeAction = transcodeMenu;
+       if (menus.contains("extractAudioMenu") && menus.value("extractAudioMenu") ){
+               QMenu* extractAudioMenu = menus.value("extractAudioMenu");
+               m_menu->addMenu(extractAudioMenu);
+                m_extractAudioAction = extractAudioMenu;
        }
+       if (menus.contains("transcodeMenu") && menus.value("transcodeMenu") ){
+                QMenu* transcodeMenu = menus.value("transcodeMenu");
+                m_menu->addMenu(transcodeMenu);
+                if (transcodeMenu->isEmpty())
+                        transcodeMenu->setEnabled(false);
+                m_transcodeAction = transcodeMenu;
+        }
        if (menus.contains("stabilizeMenu") && menus.value("stabilizeMenu") ){
                QMenu* stabilizeMenu=menus.value("stabilizeMenu");
                m_menu->addMenu(stabilizeMenu);
@@ -411,7 +564,10 @@ void ProjectList::editClipSelection(QList<QTreeWidgetItem *> list)
         p.next();
         kDebug() << "Result: " << p.key() << " = " << p.value();
     }*/
-    emit showClipProperties(clipList, commonproperties);
+    if (clipList.isEmpty()) {
+        emit displayMessage(i18n("No available clip selected"), -2);        
+    }
+    else emit showClipProperties(clipList, commonproperties);
 }
 
 void ProjectList::slotOpenClip()
@@ -517,7 +673,7 @@ void ProjectList::slotReloadClip(const QString &id)
             continue;
         }
         item = static_cast <ProjectItem *>(selected.at(i));
-        if (item && !item->isProxyRunning()) {
+        if (item && !hasPendingJob(item, PROXYJOB)) {
             DocClipBase *clip = item->referencedClip();
             if (!clip || !clip->isClean() || m_render->isProcessing(item->clipId())) {
                 kDebug()<<"//// TRYING TO RELOAD: "<<item->clipId()<<", but it is busy";
@@ -640,6 +796,7 @@ void ProjectList::setRenderer(Render *projectRender)
 {
     m_render = projectRender;
     m_listView->setIconSize(QSize((ProjectItem::itemDefaultHeight() - 2) * m_render->dar(), ProjectItem::itemDefaultHeight() - 2));
+    connect(m_render, SIGNAL(requestProxy(QString)), this, SLOT(slotCreateProxy(QString)));
 }
 
 void ProjectList::slotClipSelected()
@@ -653,6 +810,7 @@ void ProjectList::slotClipSelected()
             m_deleteButton->defaultAction()->setEnabled(true);
             m_openAction->setEnabled(false);
             m_reloadAction->setEnabled(false);
+            m_extractAudioAction->setEnabled(false);
             m_transcodeAction->setEnabled(false);
             m_stabilizeAction->setEnabled(false);
         } else {
@@ -663,6 +821,7 @@ void ProjectList::slotClipSelected()
                 if (clip == NULL) kDebug() << "-----------ERROR";
                 SubProjectItem *sub = static_cast <SubProjectItem*>(item);
                 emit clipSelected(clip->referencedClip(), sub->zone());
+                m_extractAudioAction->setEnabled(false);
                 m_transcodeAction->setEnabled(false);
                 m_stabilizeAction->setEnabled(false);
                 m_reloadAction->setEnabled(false);
@@ -675,6 +834,7 @@ void ProjectList::slotClipSelected()
             m_editButton->defaultAction()->setEnabled(true);
             m_deleteButton->defaultAction()->setEnabled(true);
             m_reloadAction->setEnabled(true);
+            m_extractAudioAction->setEnabled(true);
             m_transcodeAction->setEnabled(true);
             m_stabilizeAction->setEnabled(true);
             if (clip && clip->clipType() == IMAGE && !KdenliveSettings::defaultimageapp().isEmpty()) {
@@ -698,6 +858,7 @@ void ProjectList::slotClipSelected()
         m_deleteButton->defaultAction()->setEnabled(false);
         m_openAction->setEnabled(false);
         m_reloadAction->setEnabled(false);
+        m_extractAudioAction->setEnabled(true);
         m_transcodeAction->setEnabled(false);
         m_stabilizeAction->setEnabled(false);
     }
@@ -710,7 +871,9 @@ void ProjectList::adjustProxyActions(ProjectItem *clip) const
         m_proxyAction->setEnabled(false);
         return;
     }
-    m_proxyAction->setEnabled(useProxy());
+    bool enabled = useProxy();
+    if (clip->referencedClip() && !clip->referencedClip()->getProperty("_missingsource").isEmpty()) enabled = false;
+    m_proxyAction->setEnabled(enabled);
     m_proxyAction->blockSignals(true);
     m_proxyAction->setChecked(clip->hasProxy());
     m_proxyAction->blockSignals(false);
@@ -731,9 +894,11 @@ void ProjectList::adjustTranscodeActions(ProjectItem *clip) const
 {
     if (clip == NULL || clip->type() != PROJECTCLIPTYPE || clip->clipType() == COLOR || clip->clipType() == TEXT || clip->clipType() == PLAYLIST || clip->clipType() == SLIDESHOW) {
         m_transcodeAction->setEnabled(false);
+        m_extractAudioAction->setEnabled(false);
         return;
     }
     m_transcodeAction->setEnabled(true);
+    m_extractAudioAction->setEnabled(true);
     QList<QAction *> transcodeActions = m_transcodeAction->actions();
     QStringList data;
     QString condition;
@@ -781,6 +946,11 @@ void ProjectList::slotUpdateClipProperties(ProjectItem *clip, QMap <QString, QSt
     if (!clip)
         return;
     clip->setProperties(properties);
+    if (properties.contains("proxy")) {
+        if (properties.value("proxy") == "-" || properties.value("proxy").isEmpty())
+            // this should only apply to proxy jobs
+            clip->setConditionalJobStatus(NOJOB, PROXYJOB);
+    }
     if (properties.contains("name")) {
         monitorItemEditing(false);
         clip->setText(0, properties.value("name"));
@@ -792,7 +962,7 @@ void ProjectList::slotUpdateClipProperties(ProjectItem *clip, QMap <QString, QSt
         monitorItemEditing(false);
         clip->setText(1, properties.value("description"));
         monitorItemEditing(true);
-#ifdef NEPOMUK
+#ifdef USE_NEPOMUK
         if (KdenliveSettings::activate_nepomuk() && (type == AUDIO || type == VIDEO || type == AV || type == IMAGE || type == PLAYLIST)) {
             // Use Nepomuk system to store clip description
             Nepomuk::Resource f(clip->clipUrl().path());
@@ -873,12 +1043,14 @@ void ProjectList::slotContextMenu(const QPoint &pos, QTreeWidgetItem *item)
     m_editButton->defaultAction()->setEnabled(enable);
     m_deleteButton->defaultAction()->setEnabled(enable);
     m_reloadAction->setEnabled(enable);
+    m_extractAudioAction->setEnabled(enable);
     m_transcodeAction->setEnabled(enable);
     m_stabilizeAction->setEnabled(enable);
     if (enable) {
         ProjectItem *clip = NULL;
         if (m_listView->currentItem()->type() == PROJECTSUBCLIPTYPE) {
             clip = static_cast <ProjectItem*>(item->parent());
+            m_extractAudioAction->setEnabled(false);
             m_transcodeAction->setEnabled(false);
             m_stabilizeAction->setEnabled(false);
             adjustProxyActions(clip);
@@ -891,6 +1063,7 @@ void ProjectList::slotContextMenu(const QPoint &pos, QTreeWidgetItem *item)
             // Display uses in timeline
             emit findInTimeline(clip->clipId());
         } else {
+            m_extractAudioAction->setEnabled(false);
             m_transcodeAction->setEnabled(false);
             m_stabilizeAction->setEnabled(false);
         }
@@ -941,7 +1114,7 @@ void ProjectList::slotRemoveClip()
         } else {
             ProjectItem *item = static_cast <ProjectItem *>(selected.at(i));
             ids << item->clipId();
-            if (item->numReferences() > 0 && KMessageBox::questionYesNo(kapp->activeWindow(), i18np("Delete clip <b>%2</b>?<br />This will also remove the clip in timeline", "Delete clip <b>%2</b>?<br />This will also remove its %1 clips in timeline", item->numReferences(), item->names().at(1)), i18n("Delete Clip"), KStandardGuiItem::yes(), KStandardGuiItem::no(), "DeleteAll") == KMessageBox::No) {
+            if (item->numReferences() > 0 && KMessageBox::questionYesNo(kapp->activeWindow(), i18np("Delete clip <b>%2</b>?<br />This will also remove the clip in timeline", "Delete clip <b>%2</b>?<br />This will also remove its %1 clips in timeline", item->numReferences(), item->text(1)), i18n("Delete Clip"), KStandardGuiItem::yes(), KStandardGuiItem::no(), "DeleteAll") == KMessageBox::No) {
                 KMessageBox::enableMessage("DeleteAll");
                 return;
             }
@@ -1000,7 +1173,7 @@ void ProjectList::slotDeleteClip(const QString &clipId)
         kDebug() << "/// Cannot find clip to delete";
         return;
     }
-    if (item->isProxyRunning()) m_abortProxy.append(item->referencedClip()->getProperty("proxy"));
+    deleteJobsForClip(clipId);
     m_listView->blockSignals(true);
     QTreeWidgetItem *newSelectedItem = m_listView->itemAbove(item);
     if (!newSelectedItem)
@@ -1026,9 +1199,9 @@ void ProjectList::editFolder(const QString folderName, const QString oldfolderNa
     m_doc->setModified(true);
 }
 
-void ProjectList::slotAddFolder()
+void ProjectList::slotAddFolder(const QString &name)
 {
-    AddFolderCommand *command = new AddFolderCommand(this, i18n("Folder"), QString::number(m_doc->clipManager()->getFreeFolderId()), true);
+    AddFolderCommand *command = new AddFolderCommand(this, name.isEmpty() ? i18n("Folder") : name, QString::number(m_doc->clipManager()->getFreeFolderId()), true);
     m_commandStack->push(command);
 }
 
@@ -1112,8 +1285,6 @@ void ProjectList::slotAddClip(DocClipBase *clip, bool getProperties)
         item = new ProjectItem(m_listView, clip);
     }
     if (item->data(0, DurationRole).isNull()) item->setData(0, DurationRole, i18n("Loading"));
-    QString proxy = clip->getProperty("proxy");
-    if (!proxy.isEmpty() && proxy != "-") slotCreateProxy(clip->getId());
     connect(clip, SIGNAL(createProxy(const QString &)), this, SLOT(slotCreateProxy(const QString &)));
     connect(clip, SIGNAL(abortProxy(const QString &, const QString &)), this, SLOT(slotAbortProxy(const QString, const QString)));
     if (getProperties) {
@@ -1128,18 +1299,21 @@ void ProjectList::slotAddClip(DocClipBase *clip, bool getProperties)
         resetThumbsProducer(clip);
         m_render->getFileProperties(e, clip->getId(), m_listView->iconSize().height(), true);
     }
-    else if (item->hasProxy() && !item->isProxyRunning()) {
+    // WARNING: code below triggers unnecessary reload of all proxy clips on document loading... is it useful in some cases?
+    /*else if (item->hasProxy() && !item->isJobRunning()) {
         slotCreateProxy(clip->getId());
-    }
-    clip->askForAudioThumbs();
+    }*/
     
     KUrl url = clip->fileURL();
-#ifdef NEPOMUK
-    if (!url.isEmpty() && KdenliveSettings::activate_nepomuk()) {
+#ifdef USE_NEPOMUK
+    if (!url.isEmpty() && KdenliveSettings::activate_nepomuk() && clip->getProperty("description").isEmpty()) {
         // if file has Nepomuk comment, use it
         Nepomuk::Resource f(url.path());
         QString annotation = f.description();
-        if (!annotation.isEmpty()) item->setText(1, annotation);
+        if (!annotation.isEmpty()) {
+            item->setText(1, annotation);
+            clip->setProperty("description", annotation);
+        }
         item->setText(2, QString::number(f.rating()));
     }
 #endif
@@ -1172,11 +1346,11 @@ void ProjectList::slotAddClip(DocClipBase *clip, bool getProperties)
 
 void ProjectList::slotGotProxy(const QString &proxyPath)
 {
-    if (proxyPath.isEmpty() || m_abortAllProxies) return;
+    if (proxyPath.isEmpty() || m_abortAllJobs) return;
     QTreeWidgetItemIterator it(m_listView);
     ProjectItem *item;
 
-    while (*it && !m_abortAllProxies) {
+    while (*it && !m_closing) {
         if ((*it)->type() == PROJECTCLIPTYPE) {
             item = static_cast <ProjectItem *>(*it);
             if (item->referencedClip()->getProperty("proxy") == proxyPath)
@@ -1186,9 +1360,16 @@ void ProjectList::slotGotProxy(const QString &proxyPath)
     }
 }
 
+void ProjectList::slotGotProxyForId(const QString id)
+{
+    if (m_closing) return;
+    ProjectItem *item = getItemById(id);
+    slotGotProxy(item);
+}
+
 void ProjectList::slotGotProxy(ProjectItem *item)
 {
-    if (item == NULL || !m_refreshed) return;
+    if (item == NULL) return;
     DocClipBase *clip = item->referencedClip();
     if (!clip || !clip->isClean() || m_render->isProcessing(item->clipId())) {
         // Clip is being reprocessed, abort
@@ -1214,16 +1395,23 @@ void ProjectList::slotGotProxy(ProjectItem *item)
 void ProjectList::slotResetProjectList()
 {
     m_listView->blockSignals(true);
-    m_abortAllProxies = true;
-    m_proxyThreads.waitForFinished();
-    m_proxyThreads.clearFutures();
+    m_abortAllJobs = true;
+    for (int i = 0; i < m_jobList.count(); i++) {
+        m_jobList.at(i)->setStatus(JOBABORTED);
+    }
+    m_closing = true;
+    m_jobThreads.waitForFinished();
+    m_jobThreads.clearFutures();
     m_thumbnailQueue.clear();
+    if (!m_jobList.isEmpty()) qDeleteAll(m_jobList);
+    m_jobList.clear();
     m_listView->clear();
     m_listView->setEnabled(true);
     emit clipSelected(NULL);
     m_refreshed = false;
     m_allClipsProcessed = false;
-    m_abortAllProxies = false;
+    m_abortAllJobs = false;
+    m_closing = false;
     m_listView->blockSignals(false);
 }
 
@@ -1247,7 +1435,10 @@ void ProjectList::getCachedThumbnail(ProjectItem *item)
             KIO::NetAccess::del(KUrl(cachedPixmap), this);
             requestClipThumbnail(item->clipId());
         }
-        else item->setData(0, Qt::DecorationRole, pix);
+        else {
+            processThumbOverlays(item, pix);
+            item->setData(0, Qt::DecorationRole, pix);
+        }
     }
     else {
         requestClipThumbnail(item->clipId());
@@ -1316,23 +1507,27 @@ void ProjectList::updateAllClips(bool displayRatioChanged, bool fpsChanged, QStr
         } else {
             item = static_cast <ProjectItem *>(*it);
             clip = item->referencedClip();
-            if (item->referencedClip()->getProducer() == NULL) {
+            if (clip->getProducer() == NULL) {
                 bool replace = false;
                 if (brokenClips.contains(item->clipId())) {
                     // if this is a proxy clip, disable proxy
-                    item->setProxyStatus(NOPROXY);
+                    item->setConditionalJobStatus(NOJOB, PROXYJOB);
+                    discardJobs(item->clipId(), PROXYJOB);
                     clip->setProperty("proxy", "-");
                     replace = true;
                 }
-                if (clip->isPlaceHolder() == false && !item->isProxyRunning()) {
+                if (clip->isPlaceHolder() == false && !hasPendingJob(item, PROXYJOB)) {
                     QDomElement xml = clip->toXML();
                     if (fpsChanged) {
                         xml.removeAttribute("out");
                         xml.removeAttribute("file_hash");
                         xml.removeAttribute("proxy_out");
                     }
-                    if (!replace) replace = xml.attribute("replace") == "1";
-                    if (replace) resetThumbsProducer(clip);
+                    if (!replace) replace = xml.attribute("_replaceproxy") == "1";
+                    xml.removeAttribute("_replaceproxy");
+                    if (replace) {
+                        resetThumbsProducer(clip);
+                    }
                     m_render->getFileProperties(xml, clip->getId(), m_listView->iconSize().height(), replace);
                 }
                 else if (clip->isPlaceHolder()) {
@@ -1349,13 +1544,14 @@ void ProjectList::updateAllClips(bool displayRatioChanged, bool fpsChanged, QStr
                     }
                 }
             } else {              
-                if (displayRatioChanged)
+                if (displayRatioChanged) {
                     requestClipThumbnail(clip->getId());
+                }
                 else if (item->data(0, Qt::DecorationRole).isNull()) {
                     getCachedThumbnail(item);
                 }
                 if (item->data(0, DurationRole).toString().isEmpty()) {
-                    item->changeDuration(item->referencedClip()->getProducer()->get_playtime());
+                    item->changeDuration(clip->getProducer()->get_playtime());
                 }
                 if (clip->isPlaceHolder()) {
                     QPixmap pixmap = qVariantValue<QPixmap>(item->data(0, Qt::DecorationRole));
@@ -1368,6 +1564,10 @@ void ProjectList::updateAllClips(bool displayRatioChanged, bool fpsChanged, QStr
                     p.end();
                     item->setData(0, Qt::DecorationRole, pixmap);
                 }
+                else if (clip->getProperty("_replaceproxy") == "1") {
+                    clip->setProperty("_replaceproxy", QString());
+                    slotCreateProxy(clip->getId());
+                }
             }
             item->setData(0, UsageRole, QString::number(item->numReferences()));
         }
@@ -1402,6 +1602,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)
@@ -1448,11 +1656,18 @@ void ProjectList::slotAddClip(const QList <QUrl> givenList, const QString &group
                         while (fileName.at(fileName.size() - 1).isDigit()) {
                             fileName.chop(1);
                         }
-
-                        m_doc->slotCreateSlideshowClipFile(fileName, pattern, count, m_timecode.reformatSeparators(KdenliveSettings::sequence_duration()),
-                                                           false, false, false,
-                                                           m_timecode.getTimecodeFromFrames(int(ceil(m_timecode.fps()))), QString(), 0,
-                                                           QString(), groupInfo.at(0), groupInfo.at(1));
+                        QMap <QString, QString> properties;
+                        properties.insert("name", fileName);
+                        properties.insert("resource", pattern);
+                        properties.insert("in", "0");
+                        QString duration = m_timecode.reformatSeparators(KdenliveSettings::sequence_duration());
+                        properties.insert("out", QString::number(m_doc->getFramePos(duration) * count));
+                        properties.insert("ttl", QString::number(m_doc->getFramePos(duration)));
+                        properties.insert("loop", QString::number(false));
+                        properties.insert("crop", QString::number(false));
+                        properties.insert("fade", QString::number(false));
+                        properties.insert("luma_duration", QString::number(m_doc->getFramePos(m_timecode.getTimecodeFromFrames(int(ceil(m_timecode.fps()))))));
+                        m_doc->slotCreateSlideshowClipFile(properties, groupInfo.at(0), groupInfo.at(1));
                         return;
                     }
                 }
@@ -1463,31 +1678,58 @@ void ProjectList::slotAddClip(const QList <QUrl> givenList, const QString &group
         for (int i = 0; i < givenList.count(); i++)
             list << givenList.at(i);
     }
+    QList <KUrl::List> foldersList;
 
     foreach(const KUrl & file, list) {
         // Check there is no folder here
         KMimeType::Ptr type = KMimeType::findByUrl(file);
         if (type->is("inode/directory")) {
-            // user dropped a folder
+            // user dropped a folder, import its files
             list.removeAll(file);
+            QDir dir(file.path());
+            QStringList result = dir.entryList(QDir::Files);
+            KUrl::List folderFiles;
+            folderFiles << file;
+            foreach(const QString & path, result) {
+                KUrl newFile = file;
+                newFile.addPath(path);
+                folderFiles.append(newFile);
+            }
+            if (folderFiles.count() > 1) foldersList.append(folderFiles);
         }
     }
 
-    if (list.isEmpty())
-        return;
-
-    if (givenList.isEmpty()) {
+    if (givenList.isEmpty() && !list.isEmpty()) {
         QStringList groupInfo = getGroup();
         m_doc->slotAddClipList(list, groupInfo.at(0), groupInfo.at(1));
-    } else {
+    } else if (!list.isEmpty()) {
         m_doc->slotAddClipList(list, groupName, groupId);
     }
+    
+    if (!foldersList.isEmpty()) {
+        // create folders 
+        for (int i = 0; i < foldersList.count(); i++) {
+            KUrl::List urls = foldersList.at(i);
+            KUrl folderUrl = urls.takeFirst();
+            QString folderName = folderUrl.fileName();
+            FolderProjectItem *folder = NULL;
+            if (!folderName.isEmpty()) {
+                folder = getFolderItemByName(folderName);
+                if (folder == NULL) {
+                    slotAddFolder(folderName);
+                    folder = getFolderItemByName(folderName);
+                }
+            }
+            if (folder)
+                m_doc->slotAddClipList(urls, folder->groupName(), folder->clipId());
+            else m_doc->slotAddClipList(urls);
+        }
+    }
 }
 
 void ProjectList::slotRemoveInvalidClip(const QString &id, bool replace)
 {
     ProjectItem *item = getItemById(id);
-    m_processingClips.removeAll(id);
     m_thumbnailQueue.removeAll(id);
     if (item) {
         item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsDropEnabled);
@@ -1529,7 +1771,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(PROXYCRASHED);
+        slotUpdateJobStatus(item, PROXYJOB, JOBCRASHED, i18n("Failed to create proxy for %1. check parameters", item->text(0)), "project_settings");
         QString path = item->referencedClip()->getProperty("proxy");
         KUrl proxyFolder(m_doc->projectFolder().path( KUrl::AddTrailingSlash) + "proxy/");
 
@@ -1546,7 +1788,6 @@ void ProjectList::slotRemoveInvalidProxy(const QString &id, bool durationError)
             item->referencedClip()->reloadThumbProducer();
         }
     }
-    m_processingClips.removeAll(id);
     m_thumbnailQueue.removeAll(id);
 }
 
@@ -1563,7 +1804,6 @@ void ProjectList::slotAddColorClip()
 
     TimecodeDisplay *t = new TimecodeDisplay(m_timecode);
     t->setValue(KdenliveSettings::color_duration());
-    t->setTimeCodeFormat(false);
     dia_ui.clip_durationBox->addWidget(t);
     dia_ui.clip_color->setColor(KdenliveSettings::colorclipcolor());
 
@@ -1588,10 +1828,22 @@ void ProjectList::slotAddSlideshowClip()
 
     if (dia->exec() == QDialog::Accepted) {
         QStringList groupInfo = getGroup();
-        m_doc->slotCreateSlideshowClipFile(dia->clipName(), dia->selectedPath(), dia->imageCount(), dia->clipDuration(),
-                                           dia->loop(), dia->crop(), dia->fade(),
-                                           dia->lumaDuration(), dia->lumaFile(), dia->softness(),
-                                           dia->animation(), groupInfo.at(0), groupInfo.at(1));
+        
+        QMap <QString, QString> properties;
+        properties.insert("name", dia->clipName());
+        properties.insert("resource", dia->selectedPath());
+        properties.insert("in", "0");
+        properties.insert("out", QString::number(m_doc->getFramePos(dia->clipDuration()) * dia->imageCount()));
+        properties.insert("ttl", QString::number(m_doc->getFramePos(dia->clipDuration())));
+        properties.insert("loop", QString::number(dia->loop()));
+        properties.insert("crop", QString::number(dia->crop()));
+        properties.insert("fade", QString::number(dia->fade()));
+        properties.insert("luma_duration", dia->lumaDuration());
+        properties.insert("luma_file", dia->lumaFile());
+        properties.insert("softness", QString::number(dia->softness()));
+        properties.insert("animation", dia->animation());
+        
+        m_doc->slotCreateSlideshowClipFile(properties, groupInfo.at(0), groupInfo.at(1));
     }
     delete dia;
 }
@@ -1656,12 +1908,15 @@ QStringList ProjectList::getGroup() const
 void ProjectList::setDocument(KdenliveDoc *doc)
 {
     m_listView->blockSignals(true);
-    m_abortAllProxies = true;
-    m_proxyThreads.waitForFinished();
-    m_proxyThreads.clearFutures();
+    m_abortAllJobs = true;
+    for (int i = 0; i < m_jobList.count(); i++) {
+        m_jobList.at(i)->setStatus(JOBABORTED);
+    }
+    m_closing = true;
+    m_jobThreads.waitForFinished();
+    m_jobThreads.clearFutures();
     m_thumbnailQueue.clear();
     m_listView->clear();
-    m_processingClips.clear();
     
     m_listView->setSortingEnabled(false);
     emit clipSelected(NULL);
@@ -1671,7 +1926,8 @@ void ProjectList::setDocument(KdenliveDoc *doc)
     m_timecode = doc->timecode();
     m_commandStack = doc->commandStack();
     m_doc = doc;
-    m_abortAllProxies = false;
+    m_abortAllJobs = false;
+    m_closing = false;
 
     QMap <QString, QString> flist = doc->clipManager()->documentFolderList();
     QStringList openedFolders = doc->getExpandedFolders();
@@ -1803,28 +2059,33 @@ void ProjectList::slotRefreshClipThumbnail(QTreeWidgetItem *it, bool update)
             return;
         }
         QPixmap pix;
+        QImage img;
         int height = m_listView->iconSize().height();
         int swidth = (int)(height  * m_render->frameRenderWidth() / m_render->renderHeight()+ 0.5);
         int dwidth = (int)(height  * m_render->dar() + 0.5);
         if (clip->clipType() == AUDIO)
             pix = KIcon("audio-x-generic").pixmap(QSize(dwidth, height));
         else if (clip->clipType() == IMAGE)
-            pix = QPixmap::fromImage(KThumb::getFrame(item->referencedClip()->getProducer(), 0, swidth, dwidth, height));
+            img = KThumb::getFrame(item->referencedClip()->getProducer(), 0, swidth, dwidth, height);
         else {
-            pix = item->referencedClip()->extractImage(frame, dwidth, height);
+            img = item->referencedClip()->extractImage(frame, dwidth, height);
         }
 
-        if (!pix.isNull()) {
+        if (!pix.isNull() || !img.isNull()) {
             monitorItemEditing(false);
+            if (!img.isNull()) {
+                pix = QPixmap::fromImage(img);
+                processThumbOverlays(item, pix);
+            }
             it->setData(0, Qt::DecorationRole, pix);
             monitorItemEditing(true);
             
-            QString clipId = item->getClipHash();
-            if (!clipId.isEmpty()) {
+            QString hash = item->getClipHash();
+            if (!hash.isEmpty() && !img.isNull()) {
                 if (!isSubItem)
-                    m_doc->cachePixmap(clipId, pix);
+                    m_doc->cacheImage(hash, img);
                 else
-                    m_doc->cachePixmap(clipId + '#' + QString::number(frame), pix);
+                    m_doc->cacheImage(hash + '#' + QString::number(frame), img);
             }
         }
         if (update)
@@ -1838,7 +2099,6 @@ void ProjectList::slotReplyGetFileProperties(const QString &clipId, Mlt::Produce
 {
     QString toReload;
     ProjectItem *item = getItemById(clipId);
-
     int queue = m_render->processingItems();
     if (item && producer) {
         monitorItemEditing(false);
@@ -1852,13 +2112,18 @@ void ProjectList::slotReplyGetFileProperties(const QString &clipId, Mlt::Produce
         }
         item->setProperties(properties, metadata);
         clip->setProducer(producer, replace);
-        clip->askForAudioThumbs();
 
         // Proxy stuff
         QString size = properties.value("frame_size");
-        if (!useProxy() && clip->getProperty("proxy").isEmpty()) setProxyStatus(item, NOPROXY);
-        if (useProxy() && generateProxy() && clip->getProperty("proxy") == "-") setProxyStatus(item, NOPROXY);
-        else if (useProxy() && !item->hasProxy() && !item->isProxyRunning()) {
+        if (!useProxy() && clip->getProperty("proxy").isEmpty()) {
+            item->setConditionalJobStatus(NOJOB, PROXYJOB);
+            discardJobs(clipId, PROXYJOB);
+        }
+        if (useProxy() && generateProxy() && clip->getProperty("proxy") == "-") {
+            item->setConditionalJobStatus(NOJOB, PROXYJOB);
+            discardJobs(clipId, PROXYJOB);
+        }
+        else if (useProxy() && !item->hasProxy() && !hasPendingJob(item, PROXYJOB)) {
             // proxy video and image clips
             int maxSize;
             CLIPTYPE t = item->clipType();
@@ -1890,7 +2155,8 @@ void ProjectList::slotReplyGetFileProperties(const QString &clipId, Mlt::Produce
     if (queue == 0) {
         monitorItemEditing(true);
         if (item && m_thumbnailQueue.isEmpty()) {
-            m_listView->setCurrentItem(item);
+            if (!item->hasProxy() || m_render->activeClipId() == item->clipId())
+                m_listView->setCurrentItem(item);
             bool updatedProfile = false;
             if (item->parent()) {
                 if (item->parent()->type() == PROJECTFOLDERTYPE)
@@ -1932,6 +2198,8 @@ bool ProjectList::adjustProjectProfileToItem(ProjectItem *item)
     QString size = item->referencedClip()->getProperty("frame_size");
     int width = size.section('x', 0, 0).toInt();
     int height = size.section('x', -1).toInt();
+    // Fix some avchd clips tht report a wrong size (1920x1088)
+    if (height == 1088) height = 1080;
     double fps = item->referencedClip()->getProperty("fps").toDouble();
     double par = item->referencedClip()->getProperty("aspect_ratio").toDouble();
     if (item->clipType() == IMAGE || item->clipType() == AV || item->clipType() == VIDEO) {
@@ -1999,26 +2267,27 @@ bool ProjectList::generateImageProxy() const
 
 void ProjectList::slotReplyGetImage(const QString &clipId, const QImage &img)
 {
-    QPixmap pix = QPixmap::fromImage(img);
-    setThumbnail(clipId, pix);
+    ProjectItem *item = getItemById(clipId);
+    if (item && !img.isNull()) {
+        QPixmap pix = QPixmap::fromImage(img);
+        processThumbOverlays(item, pix);
+        monitorItemEditing(false);
+        item->setData(0, Qt::DecorationRole, pix);
+        monitorItemEditing(true);
+        QString hash = item->getClipHash();
+        if (!hash.isEmpty()) m_doc->cacheImage(hash, img);
+    }
 }
 
 void ProjectList::slotReplyGetImage(const QString &clipId, const QString &name, int width, int height)
 {
-    QPixmap pix =  KIcon(name).pixmap(QSize(width, height));
-    setThumbnail(clipId, pix);
-}
-
-void ProjectList::setThumbnail(const QString &clipId, const QPixmap &pix)
-{
+    // For clips that have a generic icon (like audio clips...)
     ProjectItem *item = getItemById(clipId);
+    QPixmap pix =  KIcon(name).pixmap(QSize(width, height));
     if (item && !pix.isNull()) {
         monitorItemEditing(false);
         item->setData(0, Qt::DecorationRole, pix);
         monitorItemEditing(true);
-        //update();
-        QString clipId = item->getClipHash();
-        if (!clipId.isEmpty()) m_doc->cachePixmap(clipId, pix);
     }
 }
 
@@ -2075,6 +2344,19 @@ ProjectItem *ProjectList::getItemById(const QString &id)
     return NULL;
 }
 
+FolderProjectItem *ProjectList::getFolderItemByName(const QString &name)
+{
+    FolderProjectItem *item = NULL;
+    QList <QTreeWidgetItem *> hits = m_listView->findItems(name, Qt::MatchExactly, 0);
+    for (int i = 0; i < hits.count(); i++) {
+        if (hits.at(i)->type() == PROJECTFOLDERTYPE) {
+            item = static_cast<FolderProjectItem *>(hits.at(i));
+            break;
+        }
+    }
+    return item;
+}
+
 FolderProjectItem *ProjectList::getFolderItemById(const QString &id)
 {
     FolderProjectItem *item;
@@ -2099,6 +2381,7 @@ void ProjectList::slotSelectClip(const QString &ix)
         m_editButton->defaultAction()->setEnabled(true);
         m_deleteButton->defaultAction()->setEnabled(true);
         m_reloadAction->setEnabled(true);
+        m_extractAudioAction->setEnabled(true);
         m_transcodeAction->setEnabled(true);
         m_stabilizeAction->setEnabled(true);
         if (clip->clipType() == IMAGE && !KdenliveSettings::defaultimageapp().isEmpty()) {
@@ -2156,6 +2439,34 @@ KUrl::List ProjectList::getConditionalUrls(const QString &condition) const
     return result;
 }
 
+QStringList ProjectList::getConditionalIds(const QString &condition) const
+{
+    QStringList result;
+    ProjectItem *item;
+    QList<QTreeWidgetItem *> list = m_listView->selectedItems();
+    for (int i = 0; i < list.count(); i++) {
+        if (list.at(i)->type() == PROJECTFOLDERTYPE)
+            continue;
+        if (list.at(i)->type() == PROJECTSUBCLIPTYPE) {
+            // subitem
+            item = static_cast <ProjectItem*>(list.at(i)->parent());
+        } else {
+            item = static_cast <ProjectItem*>(list.at(i));
+        }
+        if (item == NULL || item->type() == COLOR || item->type() == SLIDESHOW || item->type() == TEXT)
+            continue;
+        DocClipBase *clip = item->referencedClip();
+        if (!condition.isEmpty()) {
+            if (condition.startsWith("vcodec") && !clip->hasVideoCodec(condition.section('=', 1, 1)))
+                continue;
+            else if (condition.startsWith("acodec") && !clip->hasAudioCodec(condition.section('=', 1, 1)))
+                continue;
+        }
+        result.append(item->clipId());
+    }
+    return result;
+}
+
 void ProjectList::regenerateTemplate(const QString &id)
 {
     ProjectItem *clip = getItemById(id);
@@ -2216,10 +2527,10 @@ void ProjectList::addClipCut(const QString &id, int in, int out, const QString d
             m_listView->scrollToItem(sub);
             m_listView->editItem(sub, 1);
         }
-        QPixmap p = clip->referencedClip()->extractImage(in, (int)(sub->sizeHint(0).height()  * m_render->dar()), sub->sizeHint(0).height() - 2);
-        sub->setData(0, Qt::DecorationRole, p);
-        QString clipId = clip->getClipHash();
-        if (!clipId.isEmpty()) m_doc->cachePixmap(clipId + '#' + QString::number(in), p);
+        QImage img = clip->referencedClip()->extractImage(in, (int)(sub->sizeHint(0).height()  * m_render->dar()), sub->sizeHint(0).height() - 2);
+        sub->setData(0, Qt::DecorationRole, QPixmap::fromImage(img));
+        QString hash = clip->getClipHash();
+        if (!hash.isEmpty()) m_doc->cacheImage(hash + '#' + QString::number(in), img);
         monitorItemEditing(true);
     }
     emit projectModified();
@@ -2312,10 +2623,19 @@ void ProjectList::slotAddOrUpdateSequence(const QString frameName)
         } else {
             // Create sequence
             QStringList groupInfo = getGroup();
-            m_doc->slotCreateSlideshowClipFile(fileName, pattern, count, m_timecode.reformatSeparators(KdenliveSettings::sequence_duration()),
-                                               false, false, false,
-                                               m_timecode.getTimecodeFromFrames(int(ceil(m_timecode.fps()))), QString(), 0,
-                                               QString(), groupInfo.at(0), groupInfo.at(1));
+            QMap <QString, QString> properties;
+            properties.insert("name", fileName);
+            properties.insert("resource", pattern);
+            properties.insert("in", "0");
+            QString duration = m_timecode.reformatSeparators(KdenliveSettings::sequence_duration());
+            properties.insert("out", QString::number(m_doc->getFramePos(duration) * count));
+            properties.insert("ttl", QString::number(m_doc->getFramePos(duration)));
+            properties.insert("loop", QString::number(false));
+            properties.insert("crop", QString::number(false));
+            properties.insert("fade", QString::number(false));
+            properties.insert("luma_duration", m_timecode.getTimecodeFromFrames(int(ceil(m_timecode.fps()))));
+                        
+            m_doc->slotCreateSlideshowClipFile(properties, groupInfo.at(0), groupInfo.at(1));
         }
     } else emit displayMessage(i18n("Sequence not found"), -2);
 }
@@ -2345,273 +2665,291 @@ 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 || hasPendingJob(item, PROXYJOB) || item->referencedClip()->isPlaceHolder()) return;
     QString path = item->referencedClip()->getProperty("proxy");
     if (path.isEmpty()) {
-        setProxyStatus(path, PROXYCRASHED);
+        slotUpdateJobStatus(item, PROXYJOB, JOBCRASHED, i18n("Failed to create proxy, empty path."));
         return;
     }
-    setProxyStatus(path, PROXYWAITING);
-    if (m_abortProxy.contains(path)) m_abortProxy.removeAll(path);
-    if (m_processingProxy.contains(path)) {
-        // Proxy is already being generated
-        return;
-    }
-    if (QFile::exists(path)) {
+    
+    if (QFileInfo(path).size() > 0) {
         // Proxy already created
-        setProxyStatus(path, PROXYDONE);
+        setJobStatus(item, PROXYJOB, JOBDONE);
         slotGotProxy(path);
         return;
     }
-    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();
-    m_proxyList.append(info);
-    if (m_proxyThreads.futures().isEmpty() || m_proxyThreads.futures().count() < KdenliveSettings::proxythreads()) m_proxyThreads.addFuture(QtConcurrent::run(this, &ProjectList::slotGenerateProxy));
+    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()));
+    if (job->isExclusive() && hasPendingJob(item, job->jobType)) {
+        delete job;
+        return;
+    }
+
+    m_jobList.append(job);
+    setJobStatus(item, job->jobType, JOBWAITING, 0, job->statusMessage());
+    slotCheckJobProcess();
 }
 
-void ProjectList::slotAbortProxy(const QString id, const QString path)
+void ProjectList::slotCutClipJob(const QString &id, QPoint zone)
 {
-    QTreeWidgetItemIterator it(m_listView);
     ProjectItem *item = getItemById(id);
-    setProxyStatus(item, NOPROXY);
-    slotGotProxy(item);
-    if (!path.isEmpty() && m_processingProxy.contains(path)) {
-        m_abortProxy << path;
-        setProxyStatus(path, NOPROXY);
+    if (!item|| item->referencedClip()->isPlaceHolder()) return;
+    QString source = item->clipUrl().path();
+    QString ext = source.section('.', -1);
+    QString dest = source.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 + 1;
+    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.extra_params->setVisible(false);
+    ui.add_clip->setChecked(KdenliveSettings::add_clip_cut());
+    ui.file_url->fileDialog()->setOperationMode(KFileDialog::Saving);
+    ui.extra_params->setMaximumHeight(QFontMetrics(font()).lineSpacing() * 5);
+    ui.file_url->setUrl(KUrl(dest));
+    ui.button_more->setIcon(KIcon("configure"));
+    ui.extra_params->setPlainText("-acodec copy -vcodec copy");
+    QString mess = i18n("Extracting %1 out of %2", timeOut, Timecode::getStringTimecode(max, clipFps, true));
+    ui.info_label->setText(mess);
+    if (d->exec() != QDialog::Accepted) {
+        delete d;
+        return;
     }
-}
-
-void ProjectList::slotGenerateProxy()
-{
-    while (!m_proxyList.isEmpty() && !m_abortAllProxies) {
-        emit projectModified();
-        PROXYINFO info = m_proxyList.takeFirst();
-        if (m_abortProxy.contains(info.dest)) {
-            m_abortProxy.removeAll(info.dest);
+    dest = ui.file_url->url().path();
+    bool acceptPath = dest != source;
+    if (acceptPath && QFileInfo(dest).size() > 0) {
+        // destination file olready exists, overwrite?
+        acceptPath = false;
+    }
+    while (!acceptPath) {
+        // Do not allow to save over original clip
+        if (dest == source) ui.info_label->setText("<b>" + i18n("You cannot overwrite original clip.") + "</b><br>" + mess);
+        else if (KMessageBox::questionYesNo(this, i18n("Overwrite file %1", dest)) == KMessageBox::Yes) break;
+        if (d->exec() != QDialog::Accepted) {
+            delete d;
             return;
         }
-
-        // Make sure proxy path is writable
-        QFile file(info.dest);
-        if (!file.open(QIODevice::WriteOnly)) {
-            setProxyStatus(info.dest, PROXYCRASHED);
-            m_processingProxy.removeAll(info.dest);
-            return;
+        dest = ui.file_url->url().path();
+        acceptPath = dest != source;
+        if (acceptPath && QFileInfo(dest).size() > 0) {
+            acceptPath = false;
         }
-        file.close();
-        QFile::remove(info.dest);
+    }
+    QString extraParams = ui.extra_params->toPlainText().simplified();
+    KdenliveSettings::setAdd_clip_cut(ui.add_clip->isChecked());
+    delete d;
+
+    QStringList jobParams;
+    jobParams << dest << item->clipUrl().path() << timeIn << timeOut << QString::number(duration) << QString::number(KdenliveSettings::add_clip_cut());
+    if (!extraParams.isEmpty()) jobParams << extraParams;
+    CutClipJob *job = new CutClipJob(item->clipType(), id, jobParams);
+    if (job->isExclusive() && hasPendingJob(item, job->jobType)) {
+        delete job;
+        return;
+    }
+    m_jobList.append(job);
+    setJobStatus(item, job->jobType, JOBWAITING, 0, job->statusMessage());
+
+    slotCheckJobProcess();
+}
+
+void ProjectList::slotTranscodeClipJob(const QString &condition, QString params, QString desc)
+{
+    QStringList existingFiles;
+    QStringList ids = getConditionalIds(condition);
+    QStringList destinations;
+    foreach(const QString &id, ids) {
+        ProjectItem *item = getItemById(id);
+        if (!item) continue;
+        QString newFile = params.section(' ', -1).replace("%1", item->clipUrl().path());
+        destinations << newFile;
+        if (QFile::exists(newFile)) existingFiles << newFile;
+    }
+    if (!existingFiles.isEmpty()) {
+        if (KMessageBox::warningContinueCancelList(this, i18n("The transcoding job will overwrite the following files:"), existingFiles) ==  KMessageBox::Cancel) return;
+    }
     
-        setProxyStatus(info.dest, CREATINGPROXY);
+    QDialog *d = new QDialog(this);
+    Ui::CutJobDialog_UI ui;
+    ui.setupUi(d);
+    d->setWindowTitle(i18n("Transcoding"));
+    ui.extra_params->setMaximumHeight(QFontMetrics(font()).lineSpacing() * 5);
+    if (ids.count() == 1) {
+        ui.file_url->setUrl(KUrl(destinations.first()));
+    }
+    else {
+        ui.destination_label->setVisible(false);
+        ui.file_url->setVisible(false);
+    }
+    ui.extra_params->setVisible(false);
+    d->adjustSize();
+    ui.button_more->setIcon(KIcon("configure"));
+    ui.add_clip->setChecked(KdenliveSettings::add_clip_cut());
+    ui.extra_params->setPlainText(params.simplified().section(" ", 0, -2));
+    QString mess = desc;
+    mess.append(" " + i18np("(%1 clip)", "(%1 clips)", ids.count()));
+    ui.info_label->setText(mess);
+    if (d->exec() != QDialog::Accepted) {
+        delete d;
+        return;
+    }
+    params = ui.extra_params->toPlainText().simplified();
+    KdenliveSettings::setAdd_clip_cut(ui.add_clip->isChecked());
     
-        // Get the list of clips that will need to get progress info
-        QTreeWidgetItemIterator it(m_listView);
-        QList <ProjectItem *> processingItems;
-        while (*it && !m_abortAllProxies) {
-            if ((*it)->type() == PROJECTCLIPTYPE) {
-                ProjectItem *item = static_cast <ProjectItem *>(*it);
-                if (item->referencedClip()->getProperty("proxy") == info.dest) {
-                    processingItems.append(item);
-                }
-            }
-            ++it;
+    foreach(const QString &id, ids) {
+        ProjectItem *item = getItemById(id);
+        if (!item || !item->referencedClip()) continue;
+        QString src = item->clipUrl().path();
+        QString dest;
+        if (ids.count() > 1) dest = params.section(' ', -1).replace("%1", src);
+        else dest = ui.file_url->url().path();
+        QStringList jobParams;
+        jobParams << dest << src << QString() << QString();
+        double clipFps = item->referencedClip()->getProperty("fps").toDouble();
+        if (clipFps == 0) clipFps = m_fps;
+        int max = item->clipMaxDuration();
+        QString duration = QString::number(max);
+        jobParams << duration;
+        jobParams << QString::number(KdenliveSettings::add_clip_cut());
+        jobParams << params;
+        CutClipJob *job = new CutClipJob(item->clipType(), id, jobParams);
+        if (job->isExclusive() && hasPendingJob(item, job->jobType)) {
+            delete job;
+            continue;
         }
+        m_jobList.append(job);
+        setJobStatus(item, job->jobType, JOBWAITING, 0, job->statusMessage());
+    }
+    delete d;
+    slotCheckJobProcess();
+    
+}
 
-        // Special case: playlist clips (.mlt or .kdenlive project files)
-        if (info.type == PLAYLIST) {
-            // change FFmpeg params to MLT format
-            QStringList parameters;
-            parameters << info.src;
-            parameters << "-consumer" << "avformat:" + info.dest;
-            QStringList params = m_doc->getDocumentProperty("proxyparams").simplified().split('-', QString::SkipEmptyParts);
-        
-            foreach(QString s, params) {
-                s = s.simplified();
-                if (s.count(' ') == 0) {
-                    s.append("=1");
-                }
-                else s.replace(' ', '=');
-                parameters << s;
+void ProjectList::slotCheckJobProcess()
+{        
+    if (!m_jobThreads.futures().isEmpty()) {
+        // Remove inactive threads
+        QList <QFuture<void> > futures = m_jobThreads.futures();
+        m_jobThreads.clearFutures();
+        for (int i = 0; i < futures.count(); i++)
+            if (!futures.at(i).isFinished()) {
+                m_jobThreads.addFuture(futures.at(i));
             }
-        
-            parameters.append(QString("real_time=-%1").arg(KdenliveSettings::mltthreads()));
-
-            //TODO: currently, when rendering an xml file through melt, the display ration is lost, so we enforce it manualy
-            double display_ratio = KdenliveDoc::getDisplayRatio(info.src);
-            parameters << "aspect=" + QString::number(display_ratio);
-
-            //kDebug()<<"TRANSCOD: "<<parameters;
-            QProcess myProcess;
-            myProcess.setProcessChannelMode(QProcess::MergedChannels);
-            myProcess.start(KdenliveSettings::rendererpath(), parameters);
-            myProcess.waitForStarted();
-            int result = -1;
-            int duration = 0;
-            while (myProcess.state() != QProcess::NotRunning) {
-                // building proxy file
-                if (m_abortProxy.contains(info.dest) || m_abortAllProxies) {
-                    myProcess.close();
-                    myProcess.waitForFinished();
-                    QFile::remove(info.dest);
-                    m_abortProxy.removeAll(info.dest);
-                    m_processingProxy.removeAll(info.dest);
-                    setProxyStatus(info.dest, NOPROXY);
-                    result = -2;
-                }
-                else {
-                    QString log = QString(myProcess.readAll());
-                    processLogInfo(processingItems, &duration, log);
-                }
-                myProcess.waitForFinished(500);
-            }
-            myProcess.waitForFinished();
-            m_processingProxy.removeAll(info.dest);
-            if (result == -1) result = myProcess.exitStatus();
-            if (result == 0) {
-                // proxy successfully created
-                setProxyStatus(info.dest, PROXYDONE);
-                slotGotProxy(info.dest);
-            }
-            else if (result == 1) {
-                // Proxy process crashed
-                QFile::remove(info.dest);
-                setProxyStatus(info.dest, PROXYCRASHED);
-            }
-            continue;
+    }
+    if (m_jobList.isEmpty()) return;
+    int count = 0;
+    m_jobMutex.lock();
+    for (int i = 0; i < m_jobList.count(); i++) {
+        if (m_jobList.at(i)->jobStatus == JOBWORKING || m_jobList.at(i)->jobStatus == JOBWAITING)
+            count ++;
+        else {
+            // remove finished jobs
+            AbstractClipJob *job = m_jobList.takeAt(i);
+            delete job;
+            i--;
         }
+    }
+
+    emit jobCount(count);
+    m_jobMutex.unlock();
     
-        if (info.type == IMAGE) {
-            // Image proxy
-            QImage i(info.src);
-            if (i.isNull()) {
-                // Cannot load image
-                setProxyStatus(info.dest, PROXYCRASHED);
-                continue;
-            }
-            QImage proxy;
-            // Images are scaled to profile size. 
-            //TODO: Make it be configurable?
-            if (i.width() > i.height()) proxy = i.scaledToWidth(m_render->frameRenderWidth());
-            else proxy = i.scaledToHeight(m_render->renderHeight());
-            if (info.exif > 1) {
-                // Rotate image according to exif data
-                QImage processed;
-                QMatrix matrix;
-
-                switch ( info.exif ) {
-                    case 2:
-                        matrix.scale( -1, 1 );
-                        break;
-                    case 3:
-                        matrix.rotate( 180 );
-                        break;
-                    case 4:
-                        matrix.scale( 1, -1 );
-                        break;
-                    case 5:
-                        matrix.rotate( 270 );
-                        matrix.scale( -1, 1 );
-                        break;
-                    case 6:
-                        matrix.rotate( 90 );
-                        break;
-                    case 7:
-                        matrix.rotate( 90 );
-                        matrix.scale( -1, 1 );
-                        break;
-                    case 8:
-                        matrix.rotate( 270 );
-                        break;
+    if (m_jobThreads.futures().isEmpty() || m_jobThreads.futures().count() < KdenliveSettings::proxythreads()) m_jobThreads.addFuture(QtConcurrent::run(this, &ProjectList::slotProcessJobs));
+}
+
+void ProjectList::slotAbortProxy(const QString id, const QString path)
+{
+    Q_UNUSED(path)
+
+    ProjectItem *item = getItemById(id);
+    if (!item) return;
+    if (!item->isProxyRunning()) slotGotProxy(item);
+    item->setConditionalJobStatus(NOJOB, PROXYJOB);
+    discardJobs(id, PROXYJOB);
+}
+
+void ProjectList::slotProcessJobs()
+{
+    while (!m_jobList.isEmpty() && !m_abortAllJobs) {
+        emit projectModified();
+        AbstractClipJob *job = NULL;
+        int count = 0;
+        m_jobMutex.lock();
+        for (int i = 0; i < m_jobList.count(); i++) {
+            if (m_jobList.at(i)->jobStatus == JOBWAITING) {
+                if (job == NULL) {
+                    m_jobList.at(i)->jobStatus = JOBWORKING;
+                    job = m_jobList.at(i);
                 }
-                processed = proxy.transformed( matrix );
-                processed.save(info.dest);
+                count++;
             }
-            else proxy.save(info.dest);
-            setProxyStatus(info.dest, PROXYDONE);
-            slotGotProxy(info.dest);
-            m_abortProxy.removeAll(info.dest);
-            m_processingProxy.removeAll(info.dest);
+            else if (m_jobList.at(i)->jobStatus == JOBWORKING)
+                count ++;
+        }
+        // Set jobs count
+        emit jobCount(count);
+        m_jobMutex.unlock();
+
+        if (job == NULL) {
+            break;
+        }
+        QString destination = job->destination();
+        // Check if the clip is still here
+        DocClipBase *currentClip = m_doc->clipManager()->getClipById(job->clipId());
+        //ProjectItem *processingItem = getItemById(job->clipId());
+        if (currentClip == NULL) {
+            job->setStatus(JOBDONE);
             continue;
         }
+        // Set clip status to started
+        emit processLog(job->clipId(), 0, job->jobType, job->statusMessage()); 
 
-        QStringList parameters;
-        parameters << "-i" << info.src;
-        QString params = m_doc->getDocumentProperty("proxyparams").simplified();
-        foreach(QString s, params.split(' '))
-        parameters << s;
-
-        // Make sure we don't block when proxy file already exists
-        parameters << "-y";
-        parameters << info.dest;
-        QProcess myProcess;
-        myProcess.setProcessChannelMode(QProcess::MergedChannels);
-        myProcess.start("ffmpeg", parameters);
-        myProcess.waitForStarted();
-        int result = -1;
-        int duration = 0;
-   
-        while (myProcess.state() != QProcess::NotRunning) {
-            // building proxy file
-            if (m_abortProxy.contains(info.dest) || m_abortAllProxies) {
-                myProcess.close();
-                myProcess.waitForFinished();
-                m_abortProxy.removeAll(info.dest);
-                m_processingProxy.removeAll(info.dest);
-                QFile::remove(info.dest);
-                if (!m_abortAllProxies) setProxyStatus(info.dest, NOPROXY);
-                result = -2;
-            
+        // Make sure destination path is writable
+        if (!destination.isEmpty()) {
+            QFile file(destination);
+            if (!file.open(QIODevice::WriteOnly)) {
+                emit updateJobStatus(job->clipId(), job->jobType, JOBCRASHED, i18n("Cannot write to path: %1", destination));
+                job->setStatus(JOBCRASHED);
+                continue;
             }
-            else {
-                QString log = QString(myProcess.readAll());
-                processLogInfo(processingItems, &duration, log);
+            file.close();
+            QFile::remove(destination);
+        }
+        connect(job, SIGNAL(jobProgress(QString, int, int)), this, SIGNAL(processLog(QString, int, int)));
+        connect(job, SIGNAL(cancelRunningJob(const QString, stringMap)), this, SIGNAL(cancelRunningJob(const QString, stringMap)));
+        connect(job, SIGNAL(gotFilterJobResults(QString,int, int, QString,stringMap)), this, SIGNAL(gotFilterJobResults(QString,int, int, QString,stringMap)));
+
+        if (job->jobType == MLTJOB) {
+            MeltJob *jb = static_cast<MeltJob *> (job);
+            jb->setProducer(currentClip->getProducer());
+        }
+        job->startJob();
+        if (job->jobStatus == JOBDONE) {
+            emit updateJobStatus(job->clipId(), job->jobType, JOBDONE);
+            //TODO: replace with more generic clip replacement framework
+            if (job->jobType == PROXYJOB) emit gotProxy(job->clipId());
+            if (job->addClipToProject()) {
+                emit addClip(destination, QString(), QString());
             }
-            myProcess.waitForFinished(500);
-        }
-        myProcess.waitForFinished();
-        m_abortProxy.removeAll(info.dest);
-        m_processingProxy.removeAll(info.dest);
-        if (result == -1) result = myProcess.exitStatus();
-        if (result == 0) {
-            // proxy successfully created
-            setProxyStatus(info.dest, PROXYDONE);
-            slotGotProxy(info.dest);
-        }
-        else if (result == 1) {
-            // Proxy process crashed
-            QFile::remove(info.dest);
-            setProxyStatus(info.dest, PROXYCRASHED);
+        } else if (job->jobStatus == JOBCRASHED || job->jobStatus == JOBABORTED) {
+            emit updateJobStatus(job->clipId(), job->jobType, job->jobStatus, job->errorMessage(), QString(), job->logDetails());
         }
     }
+    // Thread finished, cleanup & update count
+    QTimer::singleShot(200, this, SIGNAL(checkJobProcess()));
 }
 
 
-void ProjectList::processLogInfo(QList <ProjectItem *>items, int *duration, const QString &log)
-{
-    int progress;
-    if (*duration == 0) {
-        if (log.contains("Duration:")) {
-            QString data = log.section("Duration:", 1, 1).section(',', 0, 0).simplified();
-            QStringList numbers = data.split(':');
-            *duration = (int) (numbers.at(0).toInt() * 3600 + numbers.at(1).toInt() * 60 + numbers.at(2).toDouble());
-        }
-    }
-    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();
-        for (int i = 0; i < items.count(); i++)
-            setProxyStatus(items.at(i), CREATINGPROXY, (int) (100.0 * progress / (*duration)));
-    }
-}
-
 void ProjectList::updateProxyConfig()
 {
     ProjectItem *item;
@@ -2631,7 +2969,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() && !hasPendingJob(item, PROXYJOB)) {
                 DocClipBase *clip = item->referencedClip();
                 if (clip->getProperty("frame_size").section('x', 0, 0).toInt() > m_doc->getDocumentProperty("proxyminsize").toInt()) {
                     if (clip->getProperty("proxy").isEmpty()) {
@@ -2648,10 +2986,9 @@ void ProjectList::updateProxyConfig()
                 // remove proxy
                 QMap <QString, QString> newProps;
                 newProps.insert("proxy", QString());
-                newProps.insert("replace", "1");
                 // insert required duration for proxy
                 newProps.insert("proxy_out", item->referencedClip()->producerProperty("out"));
-                new EditClipCommand(this, item->clipId(), item->referencedClip()->properties(), newProps, true, command);
+                new EditClipCommand(this, item->clipId(), item->referencedClip()->currentProperties(newProps), newProps, true, command);
             }
         }
         else if (t == IMAGE && item->referencedClip() != NULL) {
@@ -2673,7 +3010,6 @@ void ProjectList::updateProxyConfig()
                 // remove proxy
                 QMap <QString, QString> newProps;
                 newProps.insert("proxy", QString());
-                newProps.insert("replace", "1");
                 new EditClipCommand(this, item->clipId(), item->referencedClip()->properties(), newProps, true, command);
             }
         }
@@ -2683,63 +3019,84 @@ void ProjectList::updateProxyConfig()
     else delete command;
 }
 
+void ProjectList::slotProcessLog(const QString id, int progress, int type, const QString message)
+{
+    ProjectItem *item = getItemById(id);
+    setJobStatus(item, (JOBTYPE) type, JOBWORKING, progress, message);
+}
+
 void ProjectList::slotProxyCurrentItem(bool doProxy, ProjectItem *itemToProxy)
 {
     QList<QTreeWidgetItem *> list;
     if (itemToProxy == NULL) list = m_listView->selectedItems();
     else list << itemToProxy;
+
+    // expand list (folders, subclips) to get real clips
     QTreeWidgetItem *listItem;
-    QUndoCommand *command = new QUndoCommand();
-    if (doProxy) command->setText(i18np("Add proxy clip", "Add proxy clips", list.count()));
-    else command->setText(i18np("Remove proxy clip", "Remove proxy clips", list.count()));
-    
-    // Make sure the proxy folder exists
-    QString proxydir = m_doc->projectFolder().path( KUrl::AddTrailingSlash) + "proxy/";
-    KStandardDirs::makeDir(proxydir);
-                
-    QMap <QString, QString> newProps;
-    QMap <QString, QString> oldProps;
-    if (!doProxy) newProps.insert("proxy", "-");
+    QList<ProjectItem *> clipList;
     for (int i = 0; i < list.count(); i++) {
         listItem = list.at(i);
         if (listItem->type() == PROJECTFOLDERTYPE) {
             for (int j = 0; j < listItem->childCount(); j++) {
                 QTreeWidgetItem *sub = listItem->child(j);
-                if (!list.contains(sub)) list.append(sub);
+                if (sub->type() == PROJECTCLIPTYPE) {
+                    ProjectItem *item = static_cast <ProjectItem*>(sub);
+                    if (!clipList.contains(item)) clipList.append(item);
+                }
             }
         }
         else if (listItem->type() == PROJECTSUBCLIPTYPE) {
             QTreeWidgetItem *sub = listItem->parent();
-            if (!list.contains(sub)) list.append(sub);
+            ProjectItem *item = static_cast <ProjectItem*>(sub);
+            if (!clipList.contains(item)) clipList.append(item);
         }
         else if (listItem->type() == PROJECTCLIPTYPE) {
             ProjectItem *item = static_cast <ProjectItem*>(listItem);
-            CLIPTYPE t = item->clipType();
-            if ((t == VIDEO || t == AV || t == UNKNOWN || t == IMAGE || t == PLAYLIST) && item->referencedClip()) {
-                if ((doProxy && item->hasProxy()) || (!doProxy && !item->hasProxy() && item->referencedClip()->getProducer() != NULL)) continue;
-                DocClipBase *clip = item->referencedClip();
-                if (!clip || !clip->isClean() || m_render->isProcessing(item->clipId())) {
-                    kDebug()<<"//// TRYING TO PROXY: "<<item->clipId()<<", but it is busy";
-                    continue;
-                }
+            if (!clipList.contains(item)) clipList.append(item);
+        }
+    }
+    
+    QUndoCommand *command = new QUndoCommand();
+    if (doProxy) command->setText(i18np("Add proxy clip", "Add proxy clips", clipList.count()));
+    else command->setText(i18np("Remove proxy clip", "Remove proxy clips", clipList.count()));
+    
+    // Make sure the proxy folder exists
+    QString proxydir = m_doc->projectFolder().path( KUrl::AddTrailingSlash) + "proxy/";
+    KStandardDirs::makeDir(proxydir);
                 
-                resetThumbsProducer(clip);
-                oldProps = clip->properties();
-                if (doProxy) {
-                    newProps.clear();
-                    QString path = proxydir + clip->getClipHash() + "." + (t == IMAGE ? "png" : m_doc->getDocumentProperty("proxyextension"));
-                    // insert required duration for proxy
-                    newProps.insert("proxy_out", clip->producerProperty("out"));
-                    newProps.insert("proxy", path);
-                    // We need to insert empty proxy so that undo will work
-                    oldProps.insert("proxy", QString());
-                }
-                else if (item->referencedClip()->getProducer() == NULL) {
-                    // Force clip reload
-                    newProps.insert("resource", item->referencedClip()->getProperty("resource"));
-                }
-                new EditClipCommand(this, item->clipId(), oldProps, newProps, true, command);
+    QMap <QString, QString> newProps;
+    QMap <QString, QString> oldProps;
+    if (!doProxy) newProps.insert("proxy", "-");
+    for (int i = 0; i < clipList.count(); i++) {
+        ProjectItem *item = clipList.at(i);
+        CLIPTYPE t = item->clipType();
+        if ((t == VIDEO || t == AV || t == UNKNOWN || t == IMAGE || t == PLAYLIST) && item->referencedClip()) {
+            if ((doProxy && item->hasProxy()) || (!doProxy && !item->hasProxy() && item->referencedClip()->getProducer() != NULL)) continue;
+            DocClipBase *clip = item->referencedClip();
+            if (!clip || !clip->isClean() || m_render->isProcessing(item->clipId())) {
+                kDebug()<<"//// TRYING TO PROXY: "<<item->clipId()<<", but it is busy";
+                continue;
+            }
+                
+            //oldProps = clip->properties();
+            if (doProxy) {
+                newProps.clear();
+                QString path = proxydir + clip->getClipHash() + "." + (t == IMAGE ? "png" : m_doc->getDocumentProperty("proxyextension"));
+                // insert required duration for proxy
+                newProps.insert("proxy_out", clip->producerProperty("out"));
+                newProps.insert("proxy", path);
+                // We need to insert empty proxy so that undo will work
+                //oldProps.insert("proxy", QString());
+            }
+            else if (item->referencedClip()->getProducer() == NULL) {
+                // Force clip reload
+                kDebug()<<"// CLIP HAD NULL PROD------------";
+                newProps.insert("resource", item->referencedClip()->getProperty("resource"));
             }
+            // We need to insert empty proxy so that undo will work
+            oldProps = clip->currentProperties(newProps);
+            if (doProxy) oldProps.insert("proxy", "-");
+            new EditClipCommand(this, item->clipId(), oldProps, newProps, true, command);
         }
     }
     if (command->childCount() > 0) {
@@ -2762,7 +3119,7 @@ void ProjectList::slotDeleteProxy(const QString proxyPath)
             if (item->referencedClip()->getProperty("proxy") == proxyPath) {
                 QMap <QString, QString> props;
                 props.insert("proxy", QString());
-                new EditClipCommand(this, item->clipId(), item->referencedClip()->properties(), props, true, proxyCommand);
+                new EditClipCommand(this, item->clipId(), item->referencedClip()->currentProperties(props), props, true, proxyCommand);
             
             }
         }
@@ -2775,27 +3132,27 @@ void ProjectList::slotDeleteProxy(const QString proxyPath)
     QFile::remove(proxyPath);
 }
 
-void ProjectList::setProxyStatus(const QString proxyPath, PROXYSTATUS status, int progress)
+void ProjectList::setJobStatus(ProjectItem *item, JOBTYPE jobType, CLIPJOBSTATUS status, int progress, const QString &statusMessage)
 {
-    if (proxyPath.isEmpty() || m_abortAllProxies) return;
-    QTreeWidgetItemIterator it(m_listView);
-    ProjectItem *item;
-    while (*it && !m_abortAllProxies) {
-        if ((*it)->type() == PROJECTCLIPTYPE) {
-            item = static_cast <ProjectItem *>(*it);
-            if (item->referencedClip()->getProperty("proxy") == proxyPath) {
-                setProxyStatus(item, status, progress);
-            }
+    if (item == NULL || (m_abortAllJobs && m_closing)) return;
+    monitorItemEditing(false);
+    item->setJobStatus(jobType, status, progress, statusMessage);
+    if (status == JOBCRASHED) {
+        DocClipBase *clip = item->referencedClip();
+        if (!clip) {
+            kDebug()<<"// PROXY CRASHED";
+        }
+        else if (clip->getProducer() == NULL && !clip->isPlaceHolder()) {
+            // disable proxy and fetch real clip
+            clip->setProperty("proxy", "-");
+            QDomElement xml = clip->toXML();
+            m_render->getFileProperties(xml, clip->getId(), m_listView->iconSize().height(), true);
+        }
+        else {
+            // Disable proxy for this clip
+            clip->setProperty("proxy", "-");
         }
-        ++it;
     }
-}
-
-void ProjectList::setProxyStatus(ProjectItem *item, PROXYSTATUS status, int progress)
-{
-    if (item == NULL) return;
-    monitorItemEditing(false);
-    item->setProxyStatus(status, progress);
     monitorItemEditing(true);
 }
 
@@ -2824,4 +3181,271 @@ QStringList ProjectList::expandedFolders() const
     return result;
 }
 
+void ProjectList::processThumbOverlays(ProjectItem *item, QPixmap &pix)
+{
+    if (item->hasProxy()) {
+        QPainter p(&pix);
+        QColor c(220, 220, 10, 200);
+        QRect r(0, 0, 12, 12);
+        p.fillRect(r, c);
+        QFont font = p.font();
+        font.setBold(true);
+        p.setFont(font);
+        p.setPen(Qt::black);
+        p.drawText(r, Qt::AlignCenter, i18nc("The first letter of Proxy, used as abbreviation", "P"));
+    }
+}
+
+void ProjectList::slotCancelJobs()
+{
+    m_abortAllJobs = true;
+    for (int i = 0; i < m_jobList.count(); i++) {
+        m_jobList.at(i)->setStatus(JOBABORTED);
+    }
+    m_jobThreads.waitForFinished();
+    m_jobThreads.clearFutures();
+    QUndoCommand *command = new QUndoCommand();
+    command->setText(i18np("Cancel job", "Cancel jobs", m_jobList.count()));
+    m_jobMutex.lock();
+    for (int i = 0; i < m_jobList.count(); i++) {
+        DocClipBase *currentClip = m_doc->clipManager()->getClipById(m_jobList.at(i)->clipId());
+        if (!currentClip) continue;
+        QMap <QString, QString> newProps = m_jobList.at(i)->cancelProperties();
+        if (newProps.isEmpty()) continue;
+        QMap <QString, QString> oldProps = currentClip->currentProperties(newProps);
+        new EditClipCommand(this, m_jobList.at(i)->clipId(), oldProps, newProps, true, command);
+    }
+    m_jobMutex.unlock();
+    if (command->childCount() > 0) {
+        m_doc->commandStack()->push(command);
+    }
+    else delete command;
+    if (!m_jobList.isEmpty()) qDeleteAll(m_jobList);
+    m_jobList.clear();
+    m_abortAllJobs = false;
+    m_infoLabel->slotSetJobCount(0);    
+}
+
+void ProjectList::slotCancelRunningJob(const QString id, stringMap newProps)
+{
+    if (newProps.isEmpty() || m_closing) return;
+    DocClipBase *currentClip = m_doc->clipManager()->getClipById(id);
+    if (!currentClip) return;
+    QMap <QString, QString> oldProps = currentClip->currentProperties(newProps);
+    if (newProps == oldProps) return;
+    QMapIterator<QString, QString> i(oldProps);
+    EditClipCommand *command = new EditClipCommand(this, id, oldProps, newProps, true);
+    m_commandStack->push(command);    
+}
+
+bool ProjectList::hasPendingJob(ProjectItem *item, JOBTYPE type)
+{
+    if (!item || !item->referencedClip() || m_abortAllJobs) return false;
+    AbstractClipJob *job;
+    QMutexLocker lock(&m_jobMutex);
+    for (int i = 0; i < m_jobList.count(); i++) {
+        if (m_abortAllJobs) break;
+        job = m_jobList.at(i);
+        if (job->clipId() == item->clipId() && job->jobType == type && (job->jobStatus == JOBWAITING || job->jobStatus == JOBWORKING)) return true;
+    }
+    
+    return false;
+}
+
+void ProjectList::deleteJobsForClip(const QString &clipId)
+{
+    QMutexLocker lock(&m_jobMutex);
+    for (int i = 0; i < m_jobList.count(); i++) {
+        if (m_jobList.at(i)->clipId() == clipId) {
+            m_jobList.at(i)->setStatus(JOBABORTED);
+        }
+    }
+}
+
+void ProjectList::slotUpdateJobStatus(const QString id, int type, int status, const QString label, const QString actionName, const QString details)
+{
+    ProjectItem *item = getItemById(id);
+    if (!item) return;
+    slotUpdateJobStatus(item, type, status, label, actionName, details);
+    
+}
+
+void ProjectList::slotUpdateJobStatus(ProjectItem *item, int type, int status, const QString &label, const QString &actionName, const QString details)
+{
+    item->setJobStatus((JOBTYPE) type, (CLIPJOBSTATUS) status);
+    if (status != JOBCRASHED) return;
+#if KDE_IS_VERSION(4,7,0)
+    m_infoMessage->animatedHide();
+    m_errorLog.clear();
+    m_infoMessage->setText(label);
+    m_infoMessage->setWordWrap(label.length() > 35);
+    m_infoMessage->setMessageType(KMessageWidget::Warning);
+    QList<QAction *> actions = m_infoMessage->actions();
+    for (int i = 0; i < actions.count(); i++) {
+        m_infoMessage->removeAction(actions.at(i));
+    }
+    
+    if (!actionName.isEmpty()) {
+        QAction *action = NULL;
+        QList< KActionCollection * > collections = KActionCollection::allCollections();
+        for (int i = 0; i < collections.count(); i++) {
+            KActionCollection *coll = collections.at(i);
+            action = coll->action(actionName);
+            if (action) break;
+        }
+        if (action) m_infoMessage->addAction(action);
+    }
+    if (!details.isEmpty()) {
+        m_errorLog = details;
+        m_infoMessage->addAction(m_logAction);
+    }
+    m_infoMessage->animatedShow();
+#endif
+}
+
+void ProjectList::slotShowJobLog()
+{
+#if KDE_IS_VERSION(4,7,0)
+    KDialog d(this);
+    d.setButtons(KDialog::Close);
+    QTextEdit t(&d);
+    t.setPlainText(m_errorLog);
+    t.setReadOnly(true);
+    d.setMainWidget(&t);
+    d.exec();
+#endif
+}
+
+QStringList ProjectList::getPendingJobs(const QString &id)
+{
+    QStringList result;
+    QMutexLocker lock(&m_jobMutex);
+    for (int i = 0; i < m_jobList.count(); i++) {
+        if (m_jobList.at(i)->clipId() == id && (m_jobList.at(i)->jobStatus == JOBWAITING || m_jobList.at(i)->jobStatus == JOBWORKING)) {
+            // discard this job
+            result << m_jobList.at(i)->description;
+        }
+    }   
+    return result;
+}
+
+void ProjectList::discardJobs(const QString &id, JOBTYPE type) {
+    QMutexLocker lock(&m_jobMutex);
+    for (int i = 0; i < m_jobList.count(); i++) {
+        if (m_jobList.at(i)->clipId() == id && (m_jobList.at(i)->jobType == type || type == NOJOBTYPE)) {
+            // discard this job
+            m_jobList.at(i)->setStatus(JOBABORTED);
+        }
+    }
+}
+
+void ProjectList::slotStartFilterJob(ItemInfo info, const QString&id, const QString&filterName, const QString&filterParams, const QString&finalFilterName, const QString&consumer, const QString&consumerParams, const QString&properties)
+{
+    ProjectItem *item = getItemById(id);
+    if (!item) return;
+    QStringList jobParams;
+    jobParams << QString::number(info.cropStart.frames(m_fps)) << QString::number((info.cropStart + info.cropDuration).frames(m_fps));
+    jobParams << QString() << filterName << filterParams << consumer << consumerParams << properties << QString::number(info.startPos.frames(m_fps)) << QString::number(info.track) << finalFilterName;
+    MeltJob *job = new MeltJob(item->clipType(), id, jobParams);
+    if (job->isExclusive() && hasPendingJob(item, job->jobType)) {
+        delete job;
+        return;
+    }
+    job->description = i18n("Filter %1", finalFilterName);
+    m_jobList.append(job);
+    setJobStatus(item, job->jobType, JOBWAITING, 0, job->statusMessage());
+    slotCheckJobProcess();
+}
+
+void ProjectList::startClipFilterJob(const QString &filterName, const QString &condition)
+{
+    QStringList ids = getConditionalIds(condition);
+    QString destination;
+    ProjectItem *item = getItemById(ids.at(0));
+    if (!item) {
+        emit displayMessage(i18n("Cannot find clip to process filter %1", filterName), -2);
+        return;
+    }
+    if (ids.count() == 1) {
+        destination = item->clipUrl().path();
+    }
+    else {
+        destination = item->clipUrl().directory();
+    }
+    ClipStabilize *d = new ClipStabilize(destination, ids.count(), filterName);
+    if (d->exec() == QDialog::Accepted) {
+        processClipJob(ids, d->destination(), d->autoAddClip(), d->params(), d->desc());
+    }
+    delete d;
+}
+
+void ProjectList::processClipJob(QStringList ids, const QString&destination, bool autoAdd, QStringList jobParams, const QString &description)
+{
+    QStringList preParams;
+    // in and out
+    preParams << QString::number(0) << QString::number(-1);
+    // producer params
+    preParams << jobParams.takeFirst();
+    // filter name
+    preParams << jobParams.takeFirst();
+    // filter params
+    preParams << jobParams.takeFirst();
+    // consumer
+    QString consumer = jobParams.takeFirst();
+    
+    foreach(const QString&id, ids) {
+        ProjectItem *item = getItemById(id);
+        if (!item) continue;
+        if (ids.count() == 1) {
+            consumer += ":" + destination;
+        }
+        else {
+            consumer += ":" + destination + item->clipUrl().fileName() + ".mlt";
+        }
+        preParams << consumer << jobParams;
+        
+        MeltJob *job = new MeltJob(item->clipType(), id, preParams);
+        if (autoAdd) {
+            job->setAddClipToProject(true);
+            kDebug()<<"// ADDING TRUE";
+        }
+        else kDebug()<<"// ADDING FALSE!!!";
+        if (job->isExclusive() && hasPendingJob(item, job->jobType)) {
+            delete job;
+            return;
+        }
+        job->description = description;
+        m_jobList.append(job);
+        setJobStatus(item, job->jobType, JOBWAITING, 0, job->statusMessage());
+    }
+    slotCheckJobProcess();
+}
+
+void ProjectList::slotPrepareJobsMenu()
+{
+    ProjectItem *item;
+    if (!m_listView->currentItem() || m_listView->currentItem()->type() == PROJECTFOLDERTYPE)
+        return;
+    if (m_listView->currentItem()->type() == PROJECTSUBCLIPTYPE)
+        item = static_cast <ProjectItem*>(m_listView->currentItem()->parent());
+    else
+        item = static_cast <ProjectItem*>(m_listView->currentItem());
+    if (item && (item->flags() & Qt::ItemIsDragEnabled)) {
+        QString id = item->clipId();
+        m_discardCurrentClipJobs->setData(id);
+        QStringList jobs = getPendingJobs(id);
+        m_discardCurrentClipJobs->setEnabled(!jobs.isEmpty());
+    } else {
+        m_discardCurrentClipJobs->setData(QString());
+        m_discardCurrentClipJobs->setEnabled(false);
+    }
+}
+
+void ProjectList::slotDiscardClipJobs()
+{
+    QString id = m_discardCurrentClipJobs->data().toString();
+    if (id.isEmpty()) return;
+    discardJobs(id);
+}
+
 #include "projectlist.moc"
index 24d1ba0cbfff2103d1a57fab19dda27b741ad0e3..bd04931dcb23227b251672ac937a85db1898d84e 100644 (file)
 #include <QFuture>
 #include <QFutureSynchronizer>
 #include <QListWidget>
+#include <QTimeLine>
+#include <QPushButton>
 
 #include <KTreeWidgetSearchLine>
 #include <KUrl>
 #include <KIcon>
+#include <kdeversion.h>
+
+#if KDE_IS_VERSION(4,7,0)
+#include <KMessageWidget>
+#endif
 
 #ifdef NEPOMUK
 #include <nepomuk/kratingpainter.h>
@@ -49,6 +56,7 @@
 #include "kdenlivesettings.h"
 #include "folderprojectitem.h"
 #include "subprojectitem.h"
+#include "projecttree/abstractclipjob.h"
 #include <kdialog.h>
 
 namespace Mlt
@@ -56,23 +64,34 @@ namespace Mlt
 class Producer;
 };
 
-struct PROXYINFO {
-    QString dest;
-    QString src;
-    CLIPTYPE type;
-    int exif;
-};
-
 class ProjectItem;
 class ProjectListView;
 class Render;
 class KdenliveDoc;
 class DocClipBase;
+class AbstractClipJob;
 
 const int NameRole = Qt::UserRole;
 const int DurationRole = NameRole + 1;
 const int UsageRole = NameRole + 2;
 
+class SmallInfoLabel: public QPushButton
+{
+    Q_OBJECT
+public:
+    SmallInfoLabel(QWidget *parent = 0);
+
+private:
+    QTimeLine* m_timeLine;
+
+public slots:
+    void slotSetJobCount(int jobCount);
+
+private slots:
+    void slotTimeLineChanged(qreal value);
+    void slotTimeLineFinished();
+};
+    
 class InvalidDialog: public KDialog
 {
     Q_OBJECT
@@ -91,7 +110,7 @@ class ItemDelegate: public QStyledItemDelegate
 public:
     ItemDelegate(QAbstractItemView* parent = 0): QStyledItemDelegate(parent) {
     }
-
+    
     /*void drawFocus(QPainter *, const QStyleOptionViewItem &, const QRect &) const {
     }*/
 
@@ -108,7 +127,8 @@ public:
             }
             const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1;
             QPixmap pixmap = qVariantValue<QPixmap>(index.data(Qt::DecorationRole));
-            painter->drawPixmap(r1.left() + textMargin, r1.top() + (r1.height() - pixmap.height()) / 2, pixmap);
+            QPoint pixmapPoint(r1.left() + textMargin, r1.top() + (r1.height() - pixmap.height()) / 2);
+            painter->drawPixmap(pixmapPoint, pixmap);
             int decoWidth = pixmap.width() + 2 * textMargin;
 
             QFont font = painter->font();
@@ -118,7 +138,7 @@ public:
             r1.adjust(decoWidth, 0, 0, -mid);
             QRect r2 = option.rect;
             r2.adjust(decoWidth, mid, 0, 0);
-            painter->drawText(r1, Qt::AlignLeft | Qt::AlignBottom , index.data().toString());
+            painter->drawText(r1, Qt::AlignLeft | Qt::AlignBottom, index.data().toString());
             font.setBold(false);
             painter->setFont(font);
             QString subText = index.data(DurationRole).toString();
@@ -128,46 +148,40 @@ public:
             QRectF bounding;
             painter->drawText(r2, Qt::AlignLeft | Qt::AlignVCenter , subText, &bounding);
             
-            int proxy = index.data(Qt::UserRole + 5).toInt();
-            if (proxy != 0) {
-                QRectF txtBounding;
-                QString proxyText;
-                QBrush brush;
-                QColor color;
-                if (proxy > 0) {
-                    proxyText = QString::number(proxy) + "% ";
-                    proxyText.append(i18n("Generating proxy ..."));
-                    brush = option.palette.highlight();
-                    color = option.palette.color(QPalette::HighlightedText);
-                    
-                }
-                else if (proxy == PROXYDONE) {
-                    proxyText = i18n("Proxy");
-                    brush = option.palette.mid();
-                    color = option.palette.color(QPalette::WindowText);
-                }
-                else {
-                    switch (proxy)  {
-                        case CREATINGPROXY:
-                            proxyText = i18n("Generating proxy ...");
-                            break;
-                        case PROXYWAITING:
-                            proxyText = i18n("Waiting proxy ...");
-                            break;
-                        case PROXYCRASHED:
-                        default:
-                            proxyText = i18n("Proxy crashed");
+            int jobProgress = index.data(Qt::UserRole + 5).toInt();
+            if (jobProgress != 0 && jobProgress != JOBDONE && jobProgress != JOBABORTED) {
+                if (jobProgress != JOBCRASHED) {
+                    // Draw job progress bar
+                    QColor color = option.palette.alternateBase().color();
+                    painter->setPen(Qt::NoPen);
+                    color.setAlpha(180);
+                    painter->setBrush(QBrush(color));
+                    QRect progress(pixmapPoint.x() + 1, pixmapPoint.y() + pixmap.height() - 9, pixmap.width() - 2, 8);
+                    painter->drawRect(progress);
+                    painter->setBrush(option.palette.text());
+                    if (jobProgress > 0) {
+                        progress.adjust(1, 1, 0, -1);
+                        progress.setWidth((pixmap.width() - 4) * jobProgress / 100);
+                        painter->drawRect(progress);
+                    } else if (jobProgress == JOBWAITING) {
+                        // Draw kind of a pause icon
+                        progress.adjust(1, 1, 0, -1);
+                        progress.setWidth(2);
+                        painter->drawRect(progress);
+                        progress.moveLeft(progress.right() + 2);
+                        painter->drawRect(progress);
+                    }
+                } else if (jobProgress == JOBCRASHED) {
+                    QString jobText = index.data(Qt::UserRole + 7).toString();
+                    if (!jobText.isEmpty()) {
+                        QRectF txtBounding = painter->boundingRect(r2, Qt::AlignRight | Qt::AlignVCenter, " " + jobText + " ");
+                        painter->setPen(Qt::NoPen);
+                        painter->setBrush(option.palette.highlight());
+                        painter->drawRoundedRect(txtBounding, 2, 2);
+                        painter->setPen(option.palette.highlightedText().color());
+                        painter->drawText(txtBounding, Qt::AlignCenter, jobText);
                     }
-                    brush = option.palette.highlight();
-                    color = option.palette.color(QPalette::HighlightedText);
                 }
-               
-                txtBounding = painter->boundingRect(r2, Qt::AlignRight | Qt::AlignVCenter, " " + proxyText + " ");
-                painter->setPen(Qt::NoPen);
-                painter->setBrush(brush);
-                painter->drawRoundedRect(txtBounding, 2, 2);
-                painter->setPen(option.palette.highlightedText().color());
-                painter->drawText(txtBounding, Qt::AlignHCenter | Qt::AlignVCenter , proxyText);
             }
             
             painter->restore();
@@ -207,6 +221,8 @@ public:
     void setupGeneratorMenu(const QHash<QString,QMenu*>& menus);
     QString currentClipUrl() const;
     KUrl::List getConditionalUrls(const QString &condition) const;
+    /** @brief Get a list of selected clip Id's that match a condition. */
+    QStringList getConditionalIds(const QString &condition) const;
     QDomDocument generateTemplateXml(QString data, const QString &replaceString);
     void cleanup();
     void trashUnusedClips();
@@ -239,9 +255,14 @@ public:
     QStringList expandedFolders() const;
     /** @brief Deselect all clips in project tree. */
     void clearSelection();
+    /** @brief Print required overlays over clip thumb (proxy, stabilized,...). */
+    void processThumbOverlays(ProjectItem *item, QPixmap &pix);
+    /** @brief Start an MLT process job. */
+    void startClipFilterJob(const QString &filterName, const QString &condition);
+    /** @brief Set current document for the project tree. */
+    void setDocument(KdenliveDoc *doc);
 
 public slots:
-    void setDocument(KdenliveDoc *doc);
     void updateAllClips(bool displayRatioChanged, bool fpsChanged, QStringList brokenClips);
     void slotReplyGetImage(const QString &clipId, const QImage &img);
     void slotReplyGetImage(const QString &clipId, const QString &name, int width, int height);
@@ -257,6 +278,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.
@@ -276,6 +298,13 @@ 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);
+    /** @brief Start transcoding selected clips. */
+    void slotTranscodeClipJob(const QString &condition, QString params, QString desc);
+    /** @brief Start an MLT process job. */
+    void slotStartFilterJob(ItemInfo, const QString&,const QString&,const QString&,const QString&,const QString&,const QString&,const QString&);
+    
 
 private:
     ProjectListView *m_listView;
@@ -288,8 +317,11 @@ private:
     ProjectItem *getItemById(const QString &id);
     QTreeWidgetItem *getAnyItemById(const QString &id);
     FolderProjectItem *getFolderItemById(const QString &id);
+    FolderProjectItem *getFolderItemByName(const QString &name);
     QAction *m_openAction;
     QAction *m_reloadAction;
+    QAction *m_discardCurrentClipJobs;
+    QMenu *m_extractAudioAction;
     QMenu *m_transcodeAction;
     QMenu *m_stabilizeAction;
     KdenliveDoc *m_doc;
@@ -305,16 +337,22 @@ private:
     QMap <QString, QDomElement> m_producerQueue;
     QList <QString> m_thumbnailQueue;
     QAction *m_proxyAction;
-    QStringList m_processingClips;
-    /** @brief Holds a list of proxy urls that should be aborted. */
-    QStringList m_abortProxy;
-    /** @brief Holds a list of proxy urls that are currently being created. */
-    QStringList m_processingProxy;
-    QMutex m_mutex;
-    bool m_abortAllProxies;
-    QList <PROXYINFO> m_proxyList;
-    QFutureSynchronizer<void> m_proxyThreads;
+    QMutex m_jobMutex;
+    bool m_abortAllJobs;
+    /** @brief We are cleaning up the project list, so stop processing signals. */
+    bool m_closing;
+    QList <AbstractClipJob *> m_jobList;
+    QFutureSynchronizer<void> m_jobThreads;
     InvalidDialog *m_invalidClipDialog;
+    QMenu *m_jobsMenu;
+    SmallInfoLabel *m_infoLabel;
+#if KDE_IS_VERSION(4,7,0)
+    KMessageWidget *m_infoMessage;
+    /** @brief A string containing the last error log for a clip job. */
+    QString m_errorLog;
+    /** @brief The action that will trigger the log dialog. */
+    QAction *m_logAction;
+#endif
     
     void requestClipThumbnail(const QString id);
 
@@ -338,19 +376,27 @@ 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(const QString proxyPath, PROXYSTATUS status, int progress = 0);
-    void setProxyStatus(ProjectItem *item, PROXYSTATUS status, int progress = 0);
-    /** @brief Process ffmpeg output to find out process progress. */
-    void processLogInfo(QList <ProjectItem *>items, int *duration, const QString &log);
+     * @param jobType The job type 
+     * @param status The job status (see definitions.h)
+     * @param progress The job progress (in percents)
+     * @param statusMessage The job info message */
+    void setJobStatus(ProjectItem *item, JOBTYPE jobType, CLIPJOBSTATUS status, int progress = 0, const QString &statusMessage = QString());
     void monitorItemEditing(bool enable);
-    /** @brief Set thumbnail for a project's clip. */
-    void setThumbnail(const QString &clipId, const QPixmap &pix);
     /** @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 a clip has a running or pending job process. */
+    bool hasPendingJob(ProjectItem *item, JOBTYPE type);
+    /** @brief Delete pending jobs for a clip. */
+    void deleteJobsForClip(const QString &clipId);
+    /** @brief Discard specific job type for a clip. */
+    void discardJobs(const QString &id, JOBTYPE type = NOJOBTYPE);
+    /** @brief Get the list of job names for current clip. */
+    QStringList getPendingJobs(const QString &id);
+    /** @brief Start an MLT process job. */
+    void processClipJob(QStringList ids, const QString&destination, bool autoAdd, QStringList jobParams, const QString &description);
 
 private slots:
     void slotClipSelected();
@@ -364,7 +410,7 @@ private slots:
     void slotContextMenu(const QPoint &pos, QTreeWidgetItem *item);
 
     /** @brief Creates an AddFolderCommand. */
-    void slotAddFolder();
+    void slotAddFolder(const QString &name = QString());
 
     /** @brief This is triggered when a clip description has been modified. */
     void slotItemEdited(QTreeWidgetItem *item, int column);
@@ -389,11 +435,30 @@ 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. */
+    void slotCancelRunningJob(const QString id, stringMap);
+    /** @brief Update a clip's job status. */
+    void slotProcessLog(const QString, int progress, int, const QString = QString());
+    /** @brief A clip job crashed, inform user. */
+    void slotUpdateJobStatus(const QString id, int type, int status, const QString label, const QString actionName, const QString details);
+    void slotUpdateJobStatus(ProjectItem *item, int type, int status, const QString &label, const QString &actionName = QString(), const QString details = QString());
+    /** @brief Display error log for last failed job. */
+    void slotShowJobLog();
+    /** @brief A proxy clip is ready. */
+    void slotGotProxyForId(const QString);
+    /** @brief Check if it is necessary to start a job thread. */
+    void slotCheckJobProcess();
+    /** @brief Fill the jobs menu with current clip's jobs. */
+    void slotPrepareJobsMenu();
+    /** @brief Discard all jobs for current clip. */
+    void slotDiscardClipJobs();
 
 signals:
-    void clipSelected(DocClipBase *, QPoint zone = QPoint());
+    void clipSelected(DocClipBase *, QPoint zone = QPoint(), bool forceUpdate = false);
     void receivedClipDuration(const QString &);
     void showClipProperties(DocClipBase *);
     void showClipProperties(QList <DocClipBase *>, QMap<QString, QString> commonproperties);
@@ -414,6 +479,16 @@ signals:
     void processNextThumbnail();
     /** @brief Activate the clip monitor. */
     void raiseClipMonitor();
+    /** @brief Set number of running jobs. */
+    void jobCount(int);
+    void cancelRunningJob(const QString, stringMap);
+    void processLog(const QString, int , int, const QString = QString());
+    void addClip(const QString, const QString &, const QString &);
+    void updateJobStatus(const QString, int, int, const QString label = QString(), const QString actionName = QString(), const QString details = QString());
+    void gotProxy(const QString);
+    void checkJobProcess();
+    /** @brief A Filter Job produced results, send them back to the clip. */
+    void gotFilterJobResults(const QString &id, int startPos, int track, const QString &filterName, stringMap params);
 };
 
 #endif
index e08fd4b743bfba42f63893c90c6e6526bae1478d..0ad67645bae895cdd2190563adec9441cd2576a2 100644 (file)
@@ -276,6 +276,7 @@ void ProjectListView::dropEvent(QDropEvent *event)
             const QList <QTreeWidgetItem *> list = selectedItems();
             ProjectItem *clone;
             foreach(QTreeWidgetItem *it, list) {
+                if (it->type() != PROJECTCLIPTYPE) continue;
                 QTreeWidgetItem *parent = it->parent();
                 if (parent/* && ((ProjectItem *) it)->clipId() < 10000*/)  {
                     kDebug() << "++ item parent: " << parent->text(1);
@@ -304,7 +305,15 @@ void ProjectListView::mousePressEvent(QMouseEvent *event)
         m_DragStartPosition = event->pos();
         m_dragStarted = true;
         /*QTreeWidgetItem *underMouse = itemAt(event->pos());
-        if (underMouse && underMouse->isSelected()) emit focusMonitor();*/
+        ProjectItem *item = static_cast<ProjectItem *>(underMouse);
+        if (item) {
+            QRect itemRect = visualItemRect(item);
+            if (item->underJobMenu(itemRect, event->pos())) {
+                emit display
+            }
+            
+            && underMouse->isSelected()) emit focusMonitor()
+        }*/
     }
     QTreeWidget::mousePressEvent(event);
 }
index 0504ba827552e0af64caa4553c26606a192fec7d..ddc8d146974d5063b46f689b44f1e3b9a59d17e6 100644 (file)
@@ -35,7 +35,7 @@
 #include <QDir>
 #include <kmessagebox.h>
 
-ProjectSettings::ProjectSettings(ProjectList *projectlist, QStringList lumas, int videotracks, int audiotracks, const QString projectPath, bool readOnlyTracks, bool savedProject, QWidget * parent) :
+ProjectSettings::ProjectSettings(ProjectList *projectlist, QMap <QString, QString> metadata, QStringList lumas, int videotracks, int audiotracks, const QString projectPath, bool readOnlyTracks, bool savedProject, QWidget * parent) :
     QDialog(parent), m_savedProject(savedProject), m_projectList(projectlist), m_lumas(lumas)
 {
     setupUi(this);
@@ -130,6 +130,26 @@ ProjectSettings::ProjectSettings(ProjectList *projectlist, QStringList lumas, in
         video_tracks->setEnabled(false);
         audio_tracks->setEnabled(false);
     }
+    
+    
+    // Metadata list
+    QTreeWidgetItem *item = new QTreeWidgetItem(metadata_list, QStringList() << i18n("Title"));
+    item->setData(0, Qt::UserRole, QString("meta.attr.title.markup"));
+    if (metadata.contains("meta.attr.title.markup")) item->setText(1, metadata.value("meta.attr.title.markup"));
+    item->setFlags(Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+    item = new QTreeWidgetItem(metadata_list, QStringList() << i18n("Author"));
+    item->setData(0, Qt::UserRole, QString("meta.attr.author.markup"));
+    if (metadata.contains("meta.attr.author.markup")) item->setText(1, metadata.value("meta.attr.author.markup"));
+    item->setFlags(Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+    item = new QTreeWidgetItem(metadata_list, QStringList() << i18n("Copyright"));
+    item->setData(0, Qt::UserRole, QString("meta.attr.copyright.markup"));
+    if (metadata.contains("meta.attr.copyright.markup")) item->setText(1, metadata.value("meta.attr.copyright.markup"));
+    item->setFlags(Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+    item = new QTreeWidgetItem(metadata_list, QStringList() << i18n("Year"));
+    item->setData(0, Qt::UserRole, QString("meta.attr.year.markup"));
+    if (metadata.contains("meta.attr.year.markup")) item->setText(1, metadata.value("meta.attr.year.markup"));
+    item->setFlags(Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+    
     slotUpdateDisplay();
     if (m_projectList != NULL) {
         slotUpdateFiles();
@@ -235,6 +255,9 @@ void ProjectSettings::slotUpdateFiles(bool cacheOnly)
     QTreeWidgetItem *texts = new QTreeWidgetItem(files_list, QStringList() << i18n("Text clips"));
     texts->setIcon(0, KIcon("text-plain"));
     texts->setExpanded(true);
+    QTreeWidgetItem *playlists = new QTreeWidgetItem(files_list, QStringList() << i18n("Playlist clips"));
+    playlists->setIcon(0, KIcon("video-mlt-playlist"));
+    playlists->setExpanded(true);
     QTreeWidgetItem *others = new QTreeWidgetItem(files_list, QStringList() << i18n("Other clips"));
     others->setIcon(0, KIcon("unknown"));
     others->setExpanded(true);
@@ -265,6 +288,9 @@ void ProjectSettings::slotUpdateFiles(bool cacheOnly)
             case IMAGE:
                 new QTreeWidgetItem(images, QStringList() << clip->fileURL().path());
                 break;
+            case PLAYLIST:
+                new QTreeWidgetItem(playlists, QStringList() << clip->fileURL().path());
+                break;
             case UNKNOWN:
                 new QTreeWidgetItem(others, QStringList() << clip->fileURL().path());
                 break;
@@ -438,6 +464,9 @@ QStringList ProjectSettings::extractPlaylistUrls(QString path)
         QString type = EffectsList::property(e, "mlt_service");
         if (type != "colour") {
             QString url = EffectsList::property(e, "resource");
+            if (type == "framebuffer") {
+                url = url.section('?', 0, 0);
+            }
             if (!url.isEmpty()) {
                 if (!url.startsWith('/')) url.prepend(root);
                 if (url.section('.', 0, -2).endsWith("/.all")) {
@@ -536,6 +565,22 @@ void ProjectSettings::slotUpdateProxyParams()
     proxyparams->setPlainText(params.section(';', 0, 0));
 }
 
+const QMap <QString, QString> ProjectSettings::metadata() const
+{
+    QMap <QString, QString> metadata;
+    for (int i = 0; i < metadata_list->topLevelItemCount(); i++)
+    {
+        QTreeWidgetItem *item = metadata_list->topLevelItem(i);
+        if (!item->text(1).simplified().isEmpty()) {
+            // Insert metadata entry
+            QString key = item->data(0, Qt::UserRole).toString();
+            QString value = item->text(1);
+            metadata.insert(key, value);
+        }
+    }
+    return metadata;
+}
+
 #include "projectsettings.moc"
 
 
index 5a0a93b16cf4516a1cbc057b81e746f0d32fbe41..04f5881b3814dda7129dacf7e8b3644d4bbb35b2 100644 (file)
@@ -32,7 +32,7 @@ class ProjectSettings : public QDialog, public Ui::ProjectSettings_UI
     Q_OBJECT
 
 public:
-    ProjectSettings(ProjectList *projectlist, QStringList lumas, int videotracks, int audiotracks, const QString projectPath, bool readOnlyTracks, bool unsavedProject, QWidget * parent = 0);
+    ProjectSettings(ProjectList *projectlist, QMap <QString, QString> metadata, QStringList lumas, int videotracks, int audiotracks, const QString projectPath, bool readOnlyTracks, bool unsavedProject, QWidget * parent = 0);
     QString selectedProfile() const;
     KUrl selectedFolder() const;
     QPoint tracks();
@@ -45,6 +45,7 @@ public:
     int proxyImageMinSize() const;
     QString proxyParams() const;
     QString proxyExtension() const;
+    const QMap <QString, QString> metadata() const;
     static QStringList extractPlaylistUrls(QString path);
     static QStringList extractSlideshowUrls(KUrl url);
 
diff --git a/src/projecttree/CMakeLists.txt b/src/projecttree/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ae5a822
--- /dev/null
@@ -0,0 +1,8 @@
+set(kdenlive_SRCS
+  ${kdenlive_SRCS}
+  projecttree/abstractclipjob.cpp
+  projecttree/proxyclipjob.cpp
+  projecttree/cutclipjob.cpp
+  projecttree/meltjob.cpp
+  PARENT_SCOPE
+)
diff --git a/src/projecttree/abstractclipjob.cpp b/src/projecttree/abstractclipjob.cpp
new file mode 100644 (file)
index 0000000..b1721f8
--- /dev/null
@@ -0,0 +1,103 @@
+/***************************************************************************
+ *                                                                         *
+ *   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 "abstractclipjob.h"
+#include "kdenlivesettings.h"
+#include "kdenlivedoc.h"
+
+#include <KDebug>
+#include <KLocale>
+
+
+AbstractClipJob::AbstractClipJob(JOBTYPE type, CLIPTYPE cType, const QString &id, QStringList) :
+        QObject(),
+        clipType(cType),
+        jobType(type),
+        jobStatus(NOJOB),
+        replaceClip(false),
+        m_clipId(id),
+        m_addClipToProject(false),
+        m_jobProcess(NULL)
+{
+}
+
+AbstractClipJob::~AbstractClipJob()
+{
+}
+
+
+bool AbstractClipJob::addClipToProject() const
+{
+    return m_addClipToProject;
+}
+
+void AbstractClipJob::setAddClipToProject(bool add)
+{
+    m_addClipToProject = add;
+}
+
+void AbstractClipJob::setStatus(CLIPJOBSTATUS status)
+{
+    jobStatus = status;
+}
+
+const QString AbstractClipJob::clipId() const
+{
+    return m_clipId;
+}
+
+const QString AbstractClipJob::errorMessage() const
+{
+    return m_errorMessage;
+}
+
+const QString AbstractClipJob::logDetails() const
+{
+    return m_logDetails;
+}
+
+void AbstractClipJob::startJob()
+{
+}
+
+const QString AbstractClipJob::destination() const
+{
+    return QString();
+}
+
+stringMap AbstractClipJob::cancelProperties()
+{
+    return QMap <QString, QString>();
+}
+
+void AbstractClipJob::processLogInfo()
+{
+}
+
+const QString AbstractClipJob::statusMessage()
+{
+    return QString();
+}
+
+bool AbstractClipJob::isExclusive()
+{
+    return true;
+}
+
diff --git a/src/projecttree/abstractclipjob.h b/src/projecttree/abstractclipjob.h
new file mode 100644 (file)
index 0000000..6123b3e
--- /dev/null
@@ -0,0 +1,71 @@
+/***************************************************************************
+ *                                                                         *
+ *   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 ABSTRACTCLIPJOB
+#define ABSTRACTCLIPJOB
+
+#include <QObject>
+#include <QProcess>
+
+#include "definitions.h"
+
+enum JOBTYPE { NOJOBTYPE = 0, PROXYJOB = 1, CUTJOB = 2, MLTJOB = 3};
+
+class AbstractClipJob : public QObject
+{
+    Q_OBJECT
+
+public:
+    AbstractClipJob(JOBTYPE type, CLIPTYPE cType, const QString &id, QStringList parameters);    virtual ~ AbstractClipJob();
+    CLIPTYPE clipType;
+    JOBTYPE jobType;
+    CLIPJOBSTATUS jobStatus;
+    QString description;
+    bool replaceClip;
+    const QString clipId() const;
+    const QString errorMessage() const;
+    const QString logDetails() const;
+    void setStatus(CLIPJOBSTATUS status);
+    virtual const QString destination() const;
+    virtual void startJob();
+    virtual stringMap cancelProperties();
+    virtual void processLogInfo();
+    virtual const QString statusMessage();
+    /** @brief Returns true if only one instance of this job can be run on a clip. */
+    virtual bool isExclusive();
+    bool addClipToProject() const;
+    void setAddClipToProject(bool add);
+    
+protected:
+    QString m_clipId;
+    QString m_errorMessage;
+    QString m_logDetails;
+    bool m_addClipToProject;
+    QProcess *m_jobProcess;
+    
+signals:
+    void jobProgress(QString, int, int);
+    void cancelRunningJob(const QString, stringMap);
+    void gotFilterJobResults(const QString &id, int startPos, int track, const QString &filterName, stringMap params);
+};
+
+
+#endif
+
diff --git a/src/projecttree/cutclipjob.cpp b/src/projecttree/cutclipjob.cpp
new file mode 100644 (file)
index 0000000..b13f5ba
--- /dev/null
@@ -0,0 +1,163 @@
+/***************************************************************************
+ *                                                                         *
+ *   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)
+{
+    jobStatus = JOBWAITING;
+    m_dest = parameters.at(0);
+    m_src = parameters.at(1);
+    m_start = parameters.at(2);
+    m_end = parameters.at(3);
+    if (m_start.isEmpty()) {
+        // this is a transcoding job
+        description = i18n("Transcode clip");
+    } else {
+        description = i18n("Cut clip");
+    }
+    m_jobDuration = parameters.at(4).toInt();
+    m_addClipToProject = parameters.at(5).toInt();
+    replaceClip = false;
+    if (parameters.count() == 7) m_cutExtraParams = parameters.at(6).simplified();
+}
+
+void CutClipJob::startJob()
+{
+    // Special case: playlist clips (.mlt or .kdenlive project files)
+    if (clipType == AV || clipType == AUDIO || clipType == VIDEO) {
+        QStringList parameters;
+        parameters << "-i" << m_src;
+        if (!m_start.isEmpty())
+            parameters << "-ss" << m_start <<"-t" << m_end;
+        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 CUT JOB: "<<parameters;
+        m_jobProcess->start("ffmpeg", parameters);
+        m_jobProcess->waitForStarted();
+        while (m_jobProcess->state() != QProcess::NotRunning) {
+            processLogInfo();
+            if (jobStatus == JOBABORTED) {
+                m_jobProcess->close();
+                m_jobProcess->waitForFinished();
+                QFile::remove(m_dest);
+            }
+            m_jobProcess->waitForFinished(400);
+        }
+        
+        if (jobStatus != JOBABORTED) {
+            int result = m_jobProcess->exitStatus();
+            if (result == QProcess::NormalExit) {
+                if (QFileInfo(m_dest).size() == 0) {
+                    // File was not created
+                    processLogInfo();
+                    m_errorMessage.append(i18n("Failed to create file."));
+                    setStatus(JOBCRASHED);
+                } else {
+                    setStatus(JOBDONE);
+                }
+            } else if (result == QProcess::CrashExit) {
+                // Proxy process crashed
+                QFile::remove(m_dest);
+                setStatus(JOBCRASHED);
+            }
+        }
+        delete m_jobProcess;
+        return;
+    } else {
+        m_errorMessage = i18n("Cannot process this clip type.");
+    }
+    setStatus(JOBCRASHED);
+    return;
+}
+
+void CutClipJob::processLogInfo()
+{
+    if (!m_jobProcess || m_jobDuration == 0 || jobStatus == JOBABORTED) return;
+    QString log = m_jobProcess->readAll();
+    if (!log.isEmpty()) m_logDetails.append(log + '\n');
+    int progress;
+    // Parse FFmpeg output
+    if (log.contains("frame=")) {
+        progress = log.section("frame=", 1, 1).simplified().section(' ', 0, 0).toInt();
+        emit jobProgress(m_clipId, (int) (100.0 * progress / m_jobDuration), jobType);
+    }
+    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();
+        emit jobProgress(m_clipId, (int) (100.0 * progress / m_jobDuration), jobType);
+    }
+}
+
+CutClipJob::~CutClipJob()
+{
+}
+
+const QString CutClipJob::destination() const
+{
+    return m_dest;
+}
+
+stringMap CutClipJob::cancelProperties()
+{
+    QMap <QString, QString> props;
+    return props;
+}
+
+const QString CutClipJob::statusMessage()
+{
+    QString statusInfo;
+    switch (jobStatus) {
+        case JOBWORKING:
+            if (m_start.isEmpty()) statusInfo = i18n("Transcoding clip");
+            else statusInfo = i18n("Extracting clip cut");
+            break;
+        case JOBWAITING:
+            if (m_start.isEmpty()) statusInfo = i18n("Waiting - transcode clip");
+            else statusInfo = i18n("Waiting - cut clip");
+            break;
+        default:
+            break;
+    }
+    return statusInfo;
+}
+
+bool CutClipJob::isExclusive()
+{
+    return false;
+}
+
diff --git a/src/projecttree/cutclipjob.h b/src/projecttree/cutclipjob.h
new file mode 100644 (file)
index 0000000..e76c54c
--- /dev/null
@@ -0,0 +1,53 @@
+/***************************************************************************
+ *                                                                         *
+ *   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;
+    void startJob();
+    stringMap cancelProperties();
+    void processLogInfo();
+    const QString statusMessage();
+    bool isExclusive();
+    
+private:
+    QString m_dest;
+    QString m_src;
+    QString m_start;
+    QString m_end;
+    QString m_cutExtraParams;
+    int m_jobDuration;   
+};
+
+#endif
diff --git a/src/projecttree/meltjob.cpp b/src/projecttree/meltjob.cpp
new file mode 100644 (file)
index 0000000..2587975
--- /dev/null
@@ -0,0 +1,201 @@
+/***************************************************************************
+ *                                                                         *
+ *   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 "meltjob.h"
+#include "kdenlivesettings.h"
+#include "kdenlivedoc.h"
+
+#include <KDebug>
+#include <KLocale>
+
+#include <mlt++/Mlt.h>
+
+
+static void consumer_frame_render(mlt_consumer, MeltJob * self, mlt_frame /*frame_ptr*/)
+{
+    // detect if the producer has finished playing. Is there a better way to do it?
+    self->emitFrameNumber();
+}
+
+MeltJob::MeltJob(CLIPTYPE cType, const QString &id, QStringList parameters) : AbstractClipJob(MLTJOB, cType, id, parameters), 
+    m_producer(NULL),
+    m_profile(NULL),
+    m_consumer(NULL),
+    m_length(0)
+{
+    jobStatus = JOBWAITING;
+    m_params = parameters;
+    description = i18n("Process clip");
+    QString consum = m_params.at(5);
+    if (consum.contains(":")) m_dest = consum.section(":", 1);
+}
+
+void MeltJob::setProducer(Mlt::Producer *producer)
+{
+    m_producer = producer;
+}
+
+void MeltJob::startJob()
+{
+    if (!m_producer) {
+        m_errorMessage.append(i18n("No producer for this clip."));
+        setStatus(JOBCRASHED);
+        return;
+    }
+    int in = m_params.takeFirst().toInt();
+    int out = m_params.takeFirst().toInt();
+    QString producerParams =m_params.takeFirst(); 
+    QString filter = m_params.takeFirst();
+    QString filterParams = m_params.takeFirst();
+    QString consumer = m_params.takeFirst();
+    kDebug()<<"consumer: "<<consumer;
+    if (consumer.contains(":")) m_dest = consumer.section(":", 1);
+    QString consumerParams = m_params.takeFirst();
+    
+    // optional params
+    QString properties;
+    if (!m_params.isEmpty()) properties = m_params.takeFirst();
+    int startPos = -1;
+    if (!m_params.isEmpty()) startPos = m_params.takeFirst().toInt();
+    int track = -1;
+    if (!m_params.isEmpty()) track = m_params.takeFirst().toInt();
+    QString finalFilter;
+    if (!m_params.isEmpty()) finalFilter = m_params.takeFirst();
+    else finalFilter = filter;
+
+    if (out != -1 && out <= in) {
+        m_errorMessage.append(i18n("Clip zone undefined (%1 - %2).", in, out));
+        setStatus(JOBCRASHED);
+        return;
+    }
+    
+    m_profile = m_producer->profile();
+
+    Mlt::Producer *prod;
+    if (out == -1) {
+        QString url = QString::fromUtf8(m_producer->get("resource"));
+        prod = new Mlt::Producer(*m_profile,  url.toUtf8().constData());
+    }
+    else 
+        prod = m_producer->cut(in, out);
+    QStringList list = producerParams.split(' ', QString::SkipEmptyParts);
+    foreach(QString data, list) {
+        if (data.contains('=')) {
+            prod->set(data.section('=', 0, 0).toUtf8().constData(), data.section('=', 1, 1).toUtf8().constData());
+        }
+    }
+
+    if (consumer.contains(":")) {
+        m_consumer = new Mlt::Consumer(*m_profile, consumer.section(":", 0, 0).toUtf8().constData(), consumer.section(":", 1).toUtf8().constData());
+    }
+    else {
+        m_consumer = new Mlt::Consumer(*m_profile, consumer.toUtf8().constData());
+    }
+    if (!m_consumer || !m_consumer->is_valid()) {
+        m_errorMessage.append(i18n("Cannot create consumer %1.", consumer));
+        setStatus(JOBCRASHED);
+        return;
+    }
+
+    //m_consumer->set("terminate_on_pause", 1 );
+    //m_consumer->set("eof", "pause" );
+    m_consumer->set("real_time", -KdenliveSettings::mltthreads() );
+
+    list = consumerParams.split(' ', QString::SkipEmptyParts);
+    foreach(QString data, list) {
+        if (data.contains('=')) {
+            kDebug()<<"// filter con: "<<data;
+            m_consumer->set(data.section('=', 0, 0).toUtf8().constData(), data.section('=', 1, 1).toUtf8().constData());
+        }
+    }
+    
+    Mlt::Filter mltFilter(*m_profile, filter.toUtf8().data());
+    list = filterParams.split(' ', QString::SkipEmptyParts);
+    foreach(QString data, list) {
+        if (data.contains('=')) {
+            kDebug()<<"// filter p: "<<data;
+            mltFilter.set(data.section('=', 0, 0).toUtf8().constData(), data.section('=', 1, 1).toUtf8().constData());
+        }
+    }
+    Mlt::Playlist playlist;
+    playlist.append(*prod);
+    m_length = prod->get_length();
+    m_consumer->connect(playlist);
+    prod->set_speed(0);
+    prod->seek(0);
+    prod->attach(mltFilter);
+    m_showFrameEvent = m_consumer->listen("consumer-frame-show", this, (mlt_listener) consumer_frame_render);
+    m_consumer->start();
+    prod->set_speed(1);
+    while (jobStatus != JOBABORTED && !m_consumer->is_stopped()) {
+        
+    }
+    m_consumer->stop();
+    QStringList wanted = properties.split(',', QString::SkipEmptyParts);
+    stringMap jobResults;
+    foreach(const QString key, wanted) {
+        QString value = mltFilter.get(key.toUtf8().constData());
+        jobResults.insert(key, value);
+    }
+    if (!jobResults.isEmpty()) emit gotFilterJobResults(m_clipId, startPos, track, finalFilter, jobResults);
+    setStatus(JOBDONE);
+    delete m_consumer;
+    delete prod;
+    return;
+}
+
+
+MeltJob::~MeltJob()
+{
+}
+
+const QString MeltJob::destination() const
+{
+    return m_dest;
+}
+
+stringMap MeltJob::cancelProperties()
+{
+    QMap <QString, QString> props;
+    return props;
+}
+
+const QString MeltJob::statusMessage()
+{
+    QString statusInfo;
+    switch (jobStatus) {
+        case JOBWORKING:
+            statusInfo = description;
+            break;
+        case JOBWAITING:
+            statusInfo = i18n("Waiting to process clip");
+            break;
+        default:
+            break;
+    }
+    return statusInfo;
+}
+
+void MeltJob::emitFrameNumber()
+{
+    if (m_consumer && m_length > 0) {
+        emit jobProgress(m_clipId, (int) (100 * m_consumer->position() / m_length), jobType);
+    }
+}
\ No newline at end of file
diff --git a/src/projecttree/meltjob.h b/src/projecttree/meltjob.h
new file mode 100644 (file)
index 0000000..040e9ef
--- /dev/null
@@ -0,0 +1,62 @@
+/***************************************************************************
+ *                                                                         *
+ *   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 MELTJOB
+#define MELTJOB
+
+#include <QObject>
+#include <QProcess>
+
+#include "abstractclipjob.h"
+
+namespace Mlt{
+        class Profile;
+        class Producer;
+        class Consumer;
+        class Filter;
+        class Event;
+};
+
+class MeltJob : public AbstractClipJob
+{
+    Q_OBJECT
+
+public:
+    MeltJob(CLIPTYPE cType, const QString &id, QStringList parameters);
+    virtual ~ MeltJob();
+    const QString destination() const;
+    void startJob();
+    stringMap cancelProperties();
+    bool addClipToProject;
+    const QString statusMessage();
+    void setProducer(Mlt::Producer *producer);
+    void emitFrameNumber();
+    
+private:
+    Mlt::Producer *m_producer;
+    Mlt::Profile *m_profile;
+    Mlt::Consumer *m_consumer;
+    Mlt::Event *m_showFrameEvent;
+    QStringList m_params;
+    QString m_dest;
+    int m_length;
+};
+
+#endif
diff --git a/src/projecttree/proxyclipjob.cpp b/src/projecttree/proxyclipjob.cpp
new file mode 100644 (file)
index 0000000..88a6ac9
--- /dev/null
@@ -0,0 +1,245 @@
+/***************************************************************************
+ *                                                                         *
+ *   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 "proxyclipjob.h"
+#include "kdenlivesettings.h"
+#include "kdenlivedoc.h"
+
+#include <KDebug>
+#include <KLocale>
+
+ProxyJob::ProxyJob(CLIPTYPE cType, const QString &id, QStringList parameters) : AbstractClipJob(PROXYJOB, cType, id, parameters),
+    m_jobDuration(0),
+    m_isFfmpegJob(true)
+{
+    jobStatus = JOBWAITING;
+    description = i18n("proxy");
+    m_dest = parameters.at(0);
+    m_src = parameters.at(1);
+    m_exif = parameters.at(2).toInt();
+    m_proxyParams = parameters.at(3);
+    m_renderWidth = parameters.at(4).toInt();
+    m_renderHeight = parameters.at(5).toInt();
+    replaceClip = true;
+}
+
+void ProxyJob::startJob()
+{
+    // Special case: playlist clips (.mlt or .kdenlive project files)
+    m_jobDuration = 0;
+    if (clipType == PLAYLIST) {
+        // change FFmpeg params to MLT format
+        m_isFfmpegJob = false;
+        QStringList mltParameters;
+        mltParameters << m_src;
+        mltParameters << "-consumer" << "avformat:" + m_dest;
+        QStringList params = m_proxyParams.split('-', QString::SkipEmptyParts);
+                
+        foreach(QString s, params) {
+            s = s.simplified();
+            if (s.count(' ') == 0) {
+                s.append("=1");
+            }
+            else s.replace(' ', '=');
+            mltParameters << s;
+        }
+        
+        mltParameters.append(QString("real_time=-%1").arg(KdenliveSettings::mltthreads()));
+
+        //TODO: currently, when rendering an xml file through melt, the display ration is lost, so we enforce it manualy
+        double display_ratio = KdenliveDoc::getDisplayRatio(m_src);
+        mltParameters << "aspect=" + QString::number(display_ratio);
+            
+        // Ask for progress reporting
+        mltParameters << "progress=1";
+
+       m_jobProcess = new QProcess;
+        m_jobProcess->setProcessChannelMode(QProcess::MergedChannels);
+        m_jobProcess->start(KdenliveSettings::rendererpath(), mltParameters);
+        m_jobProcess->waitForStarted();
+    }
+    else if (clipType == IMAGE) {
+        m_isFfmpegJob = false;
+        // Image proxy
+        QImage i(m_src);
+        if (i.isNull()) {
+           m_errorMessage.append(i18n("Cannot load image %1.", m_src));
+            setStatus(JOBCRASHED);
+           return;
+       }
+       
+        QImage proxy;
+        // Images are scaled to profile size. 
+        //TODO: Make it be configurable?
+        if (i.width() > i.height()) proxy = i.scaledToWidth(m_renderWidth);
+        else proxy = i.scaledToHeight(m_renderHeight);
+        if (m_exif > 1) {
+            // Rotate image according to exif data
+            QImage processed;
+            QMatrix matrix;
+
+            switch ( m_exif ) {
+                case 2:
+                   matrix.scale( -1, 1 );
+                    break;
+                case 3:
+                   matrix.rotate( 180 );
+                    break;
+                case 4:
+                   matrix.scale( 1, -1 );
+                    break;
+                case 5:
+                   matrix.rotate( 270 );
+                    matrix.scale( -1, 1 );
+                    break;
+                case 6:
+                   matrix.rotate( 90 );
+                    break;
+                case 7:
+                   matrix.rotate( 90 );
+                    matrix.scale( -1, 1 );
+                    break;
+                case 8:
+                   matrix.rotate( 270 );
+                    break;
+            }
+            processed = proxy.transformed( matrix );
+            processed.save(m_dest);
+        }
+        else proxy.save(m_dest);
+        setStatus(JOBDONE);
+       return;
+    }
+    else {
+        m_isFfmpegJob = true;
+       QStringList parameters;
+        parameters << "-i" << m_src;
+        QString params = m_proxyParams;
+        foreach(const QString &s, params.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);
+        m_jobProcess->start("ffmpeg", parameters, QIODevice::ReadOnly);
+        m_jobProcess->waitForStarted();
+    }
+    while (m_jobProcess->state() != QProcess::NotRunning) {
+        processLogInfo();
+        if (jobStatus == JOBABORTED) {
+            emit cancelRunningJob(m_clipId, cancelProperties());
+            m_jobProcess->close();
+            m_jobProcess->waitForFinished();
+            QFile::remove(m_dest);
+        }
+        m_jobProcess->waitForFinished(400);
+    }
+    
+    if (jobStatus != JOBABORTED) {
+        int result = m_jobProcess->exitStatus();
+        if (result == QProcess::NormalExit) {
+            if (QFileInfo(m_dest).size() == 0) {
+                // File was not created
+                processLogInfo();
+                m_errorMessage.append(i18n("Failed to create proxy clip."));
+                setStatus(JOBCRASHED);
+            }
+            else setStatus(JOBDONE);
+        }
+        else if (result == QProcess::CrashExit) {
+            // Proxy process crashed
+            QFile::remove(m_dest);
+            setStatus(JOBCRASHED);
+        }
+    }
+    
+    delete m_jobProcess;
+    return;
+}
+
+void ProxyJob::processLogInfo()
+{
+    if (!m_jobProcess || jobStatus == JOBABORTED) return;
+    QString log = m_jobProcess->readAll();
+    if (!log.isEmpty()) m_logDetails.append(log + '\n');
+    else return;
+    int progress;
+    if (m_isFfmpegJob) {
+        // Parse FFmpeg output
+        if (m_jobDuration == 0) {
+            if (log.contains("Duration:")) {
+                QString data = log.section("Duration:", 1, 1).section(',', 0, 0).simplified();
+                QStringList numbers = data.split(':');
+                m_jobDuration = (int) (numbers.at(0).toInt() * 3600 + numbers.at(1).toInt() * 60 + numbers.at(2).toDouble());
+            }
+        }
+        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();
+            emit jobProgress(m_clipId, (int) (100.0 * progress / m_jobDuration), jobType);
+        }
+    }
+    else {
+        // Parse MLT output
+        if (log.contains("percentage:")) {
+            progress = log.section(':', -1).simplified().toInt();
+            emit jobProgress(m_clipId, progress, jobType);
+        }
+    }
+}
+
+ProxyJob::~ProxyJob()
+{
+}
+
+const QString ProxyJob::destination() const
+{
+    return m_dest;
+}
+
+stringMap ProxyJob::cancelProperties()
+{
+    QMap <QString, QString> props;
+    props.insert("proxy", "-");
+    return props;
+}
+
+const QString ProxyJob::statusMessage()
+{
+    QString statusInfo;
+    switch (jobStatus) {
+        case JOBWORKING:
+            statusInfo = i18n("Creating proxy");
+            break;
+        case JOBWAITING:
+            statusInfo = i18n("Waiting - proxy");
+            break;
+        default:
+            break;
+    }
+    return statusInfo;
+}
+
diff --git a/src/projecttree/proxyclipjob.h b/src/projecttree/proxyclipjob.h
new file mode 100644 (file)
index 0000000..beca4b1
--- /dev/null
@@ -0,0 +1,55 @@
+/***************************************************************************
+ *                                                                         *
+ *   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 PROXYCLIPJOB
+#define PROXYCLIPJOB
+
+#include <QObject>
+#include <QProcess>
+
+#include "abstractclipjob.h"
+
+
+class ProxyJob : public AbstractClipJob
+{
+    Q_OBJECT
+
+public:
+    ProxyJob(CLIPTYPE cType, const QString &id, QStringList parameters);
+    virtual ~ ProxyJob();
+    const QString destination() const;
+    void startJob();
+    stringMap cancelProperties();
+    const QString statusMessage();
+    void processLogInfo();
+
+    
+private:
+    QString m_dest;
+    QString m_src;
+    int m_exif;
+    QString m_proxyParams;
+    int m_renderWidth;
+    int m_renderHeight;
+    int m_jobDuration;
+    bool m_isFfmpegJob;
+};
+
+#endif
index 9ec0c44257d70bde6ec5e3507112097dbadaa96d..474cf1146ff78b3ae8940916b488e0179f6c8946 100644 (file)
 #include <QDir>
 
 
-RecMonitor::RecMonitor(QString name, MonitorManager *manager, QWidget *parent) :
-    AbstractMonitor(parent),
-    m_name(name),
+RecMonitor::RecMonitor(Kdenlive::MONITORID name, MonitorManager *manager, QWidget *parent) :
+    AbstractMonitor(name, manager, parent),
     m_isCapturing(false),
     m_didCapture(false),
     m_isPlaying(false),
-    m_manager(manager),
     m_captureDevice(NULL),
     m_analyse(false)
 {
     setupUi(this);
 
-    video_frame->setAttribute(Qt::WA_PaintOnScreen);
+    //video_frame->setAttribute(Qt::WA_PaintOnScreen);
     device_selector->setCurrentIndex(KdenliveSettings::defaultcapture());
     connect(device_selector, SIGNAL(currentIndexChanged(int)), this, SLOT(slotVideoDeviceChanged(int)));
 
@@ -63,11 +61,9 @@ RecMonitor::RecMonitor(QString name, MonitorManager *manager, QWidget *parent) :
     QVBoxLayout *l = new QVBoxLayout;
     l->setContentsMargins(0, 0, 0, 0);
     l->setSpacing(0);
-    m_videoBox = new VideoPreviewContainer();
-    m_videoBox->setContentsMargins(0, 0, 0, 0);
-    m_videoBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
-    l->addWidget(m_videoBox);
+    l->addWidget(videoBox, 10);
     video_frame->setLayout(l);
+    createVideoSurface();
 
     QToolBar *toolbar = new QToolBar(this);
     QHBoxLayout *layout = new QHBoxLayout;
@@ -94,6 +90,23 @@ RecMonitor::RecMonitor(QString name, MonitorManager *manager, QWidget *parent) :
     connect(m_recAction, SIGNAL(triggered()), this, SLOT(slotRecord()));
     m_recAction->setCheckable(true);
 
+    rec_options->setIcon(KIcon("system-run"));
+    QMenu *menu = new QMenu(this);
+    m_addCapturedClip = new QAction(i18n("Add Captured File to Project"), this);
+    m_addCapturedClip->setCheckable(true);
+    m_addCapturedClip->setChecked(true);
+    menu->addAction(m_addCapturedClip);
+
+    rec_audio->setChecked(KdenliveSettings::v4l_captureaudio());
+    rec_video->setChecked(KdenliveSettings::v4l_capturevideo());
+
+    m_previewSettings = new QAction(i18n("Recording Preview"), this);
+    m_previewSettings->setCheckable(true);
+
+
+    rec_options->setMenu(menu);
+    menu->addAction(m_previewSettings);
+
     toolbar->addSeparator();
 
     QAction *configAction = toolbar->addAction(KIcon("configure"), i18n("Configure"));
@@ -125,11 +138,11 @@ RecMonitor::RecMonitor(QString name, MonitorManager *manager, QWidget *parent) :
     connect(m_captureProcess, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(slotProcessStatus(QProcess::ProcessState)));
     connect(m_captureProcess, SIGNAL(readyReadStandardError()), this, SLOT(slotReadDvgrabInfo()));
 
-    
+
     QString videoDriver = KdenliveSettings::videodrivername();
 #if QT_VERSION >= 0x040600
     QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
-    env.insert("SDL_WINDOWID", QString::number(video_frame->winId()));
+    env.insert("SDL_WINDOWID", QString::number(videoSurface->winId()));
     if (!videoDriver.isEmpty()) {
         if (videoDriver == "x11_noaccel") {
             env.insert("SDL_VIDEO_YUV_HWACCEL", "0");
@@ -139,7 +152,7 @@ RecMonitor::RecMonitor(QString name, MonitorManager *manager, QWidget *parent) :
     m_displayProcess->setProcessEnvironment(env);
 #else
     QStringList env = QProcess::systemEnvironment();
-    env << "SDL_WINDOWID=" + QString::number(video_frame->winId());
+    env << "SDL_WINDOWID=" + QString::number(videoSurface->winId());
     if (!videoDriver.isEmpty()) {
         if (videoDriver == "x11_noaccel") {
             env << "SDL_VIDEO_YUV_HWACCEL=0";
@@ -150,11 +163,10 @@ RecMonitor::RecMonitor(QString name, MonitorManager *manager, QWidget *parent) :
 #endif
     setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 1);
 
-    kDebug() << "/////// BUILDING MONITOR, ID: " << video_frame->winId();
+    kDebug() << "/////// BUILDING MONITOR, ID: " << videoSurface->winId();
     slotVideoDeviceChanged(device_selector->currentIndex());
-    recording_preview->setToolTip(i18n("Capture preview settings"));
-    recording_preview->setCurrentIndex(KdenliveSettings::recording_preview());
-    connect(recording_preview, SIGNAL(currentIndexChanged(int)), this, SLOT(slotChangeRecordingPreview(int)));
+    m_previewSettings->setChecked(KdenliveSettings::enable_recording_preview());
+    connect(m_previewSettings, SIGNAL(triggered(bool)), this, SLOT(slotChangeRecordingPreview(bool)));
 }
 
 RecMonitor::~RecMonitor()
@@ -165,9 +177,17 @@ RecMonitor::~RecMonitor()
     if (m_captureDevice) delete m_captureDevice;
 }
 
-const QString RecMonitor::name() const
+void RecMonitor::mouseDoubleClickEvent(QMouseEvent * event)
 {
-    return m_name;
+    if (!KdenliveSettings::openglmonitors() && videoBox && videoBox->isVisible()) {
+        videoBox->switchFullScreen();
+        event->accept();
+    }
+}
+
+void RecMonitor::slotSwitchFullScreen()
+{
+    videoBox->switchFullScreen();
 }
 
 void RecMonitor::stop()
@@ -177,6 +197,7 @@ void RecMonitor::stop()
 
 void RecMonitor::start()
 {
+    //slotStartPreview(true);
 }
 
 void RecMonitor::slotConfigure()
@@ -203,7 +224,9 @@ void RecMonitor::slotVideoDeviceChanged(int ix)
 {
     QString capturefile;
     QString capturename;
-    recording_preview->setHidden(ix != VIDEO4LINUX && ix != BLACKMAGIC);
+    m_previewSettings->setEnabled(ix == VIDEO4LINUX || ix == BLACKMAGIC);
+    rec_audio->setVisible(ix == VIDEO4LINUX);
+    rec_video->setVisible(ix == VIDEO4LINUX);
     m_fwdAction->setVisible(ix == FIREWIRE);
     m_discAction->setVisible(ix == FIREWIRE);
     m_rewAction->setVisible(ix == FIREWIRE);
@@ -211,15 +234,15 @@ void RecMonitor::slotVideoDeviceChanged(int ix)
     m_logger.setVisible(ix == BLACKMAGIC);
     if (m_captureDevice) {
         // MLT capture still running, abort
+        m_monitorManager->clearScopeSource();
         m_captureDevice->stop();
         delete m_captureDevice;
         m_captureDevice = NULL;
-        m_manager->clearScopeSource();
     }
 
     // The m_videoBox container has to be shown once before the MLT consumer is build, or preview will fail
-    m_videoBox->setHidden(ix != VIDEO4LINUX && ix != BLACKMAGIC);
-    m_videoBox->setHidden(true);
+    videoBox->setHidden(ix != VIDEO4LINUX && ix != BLACKMAGIC);
+    videoBox->setHidden(true);
     switch (ix) {
     case SCREENGRAB:
         m_discAction->setEnabled(false);
@@ -361,7 +384,9 @@ void RecMonitor::slotStopCapture()
 {
     // stop capture
     if (!m_isCapturing && !m_isPlaying) return;
-    m_videoBox->setHidden(true);
+    videoBox->setHidden(true);
+    rec_audio->setEnabled(true);
+    rec_video->setEnabled(true);
     switch (device_selector->currentIndex()) {
     case FIREWIRE:
         m_captureProcess->write("\e", 2);
@@ -379,7 +404,7 @@ void RecMonitor::slotStopCapture()
         if (m_captureDevice) {
             m_captureDevice->stop();
         }
-        recording_preview->setEnabled(true);
+        m_previewSettings->setEnabled(true);
         m_isCapturing = false;
         m_isPlaying = false;
         m_playAction->setEnabled(true);
@@ -388,7 +413,7 @@ void RecMonitor::slotStopCapture()
         slotSetInfoMessage(i18n("Capture stopped"));
         m_isCapturing = false;
         m_recAction->setChecked(false);
-        if (autoaddbox->isChecked() && !m_captureFile.isEmpty() && QFile::exists(m_captureFile.path())) {
+        if (m_addCapturedClip->isChecked() && !m_captureFile.isEmpty() && QFile::exists(m_captureFile.path())) {
             emit addProjectClip(m_captureFile);
             m_captureFile.clear();
         }
@@ -415,6 +440,8 @@ void RecMonitor::slotStartPreview(bool play)
         }
         return;
     }
+    slotActivateMonitor();
+    if (m_isPlaying) return;
     m_captureArgs.clear();
     m_displayArgs.clear();
     m_isPlaying = false;
@@ -424,7 +451,7 @@ void RecMonitor::slotStartPreview(bool play)
     QString producer;
     QStringList dvargs = KdenliveSettings::dvgrabextra().simplified().split(" ", QString::SkipEmptyParts);
     int ix = device_selector->currentIndex();
-    m_videoBox->setHidden(ix != VIDEO4LINUX && ix != BLACKMAGIC);
+    videoBox->setHidden(ix != VIDEO4LINUX && ix != BLACKMAGIC);
     switch (ix) {
     case FIREWIRE:
         switch (KdenliveSettings::firewireformat()) {
@@ -470,33 +497,33 @@ void RecMonitor::slotStartPreview(bool play)
         break;
     case VIDEO4LINUX:
         path = KStandardDirs::locateLocal("appdata", "profiles/video4linux");
-        m_manager->activateMonitor("record");
         buildMltDevice(path);
         profile = ProfilesDialog::getVideoProfile(path);
-        producer = QString("avformat-novalidate:video4linux2:%1?width:%2&height:%3&frame_rate:%4").arg(KdenliveSettings::video4vdevice()).arg(profile.width).arg(profile.height).arg((double) profile.frame_rate_num / profile.frame_rate_den);
-        if (!m_captureDevice->slotStartPreview(producer)) {
+        producer = getV4lXmlPlaylist(profile);
+
+        //producer = QString("avformat-novalidate:video4linux2:%1?width:%2&height:%3&frame_rate:%4").arg(KdenliveSettings::video4vdevice()).arg(profile.width).arg(profile.height).arg((double) profile.frame_rate_num / profile.frame_rate_den);
+        if (!m_captureDevice->slotStartPreview(producer, true)) {
             // v4l capture failed to start
             video_frame->setText(i18n("Failed to start Video4Linux,\ncheck your parameters..."));
-            m_videoBox->setHidden(true);
-            
+            videoBox->setHidden(true);
+
         } else {
             m_playAction->setEnabled(false);
             m_stopAction->setEnabled(true);
             m_isPlaying = true;
         }
-        
+
         break;
     case BLACKMAGIC:
         path = KdenliveSettings::current_profile();
-        m_manager->activateMonitor("record");
+        slotActivateMonitor();
         buildMltDevice(path);
-        profile = ProfilesDialog::getVideoProfile(path);
         producer = QString("decklink:%1").arg(KdenliveSettings::decklink_capturedevice());
         if (!m_captureDevice->slotStartPreview(producer)) {
             // v4l capture failed to start
             video_frame->setText(i18n("Failed to start Decklink,\ncheck your parameters..."));
-            m_videoBox->setHidden(true);
-            
+            videoBox->setHidden(true);
+
         } else {
             m_playAction->setEnabled(false);
             m_stopAction->setEnabled(true);
@@ -507,6 +534,9 @@ void RecMonitor::slotStartPreview(bool play)
         break;
     }
 
+    rec_audio->setEnabled(false);
+    rec_video->setEnabled(false);
+
     if (device_selector->currentIndex() == FIREWIRE) {
         kDebug() << "Capture: Running ffplay " << m_displayArgs.join(" ");
         m_displayProcess->start("ffplay", m_displayArgs);
@@ -518,6 +548,9 @@ void RecMonitor::slotStartPreview(bool play)
 
 void RecMonitor::slotRecord()
 {
+    rec_audio->setEnabled(false);
+    rec_video->setEnabled(false);
+
     if (m_captureProcess->state() == QProcess::NotRunning && device_selector->currentIndex() == FIREWIRE) {
         slotStartPreview();
     }
@@ -537,7 +570,11 @@ void RecMonitor::slotRecord()
         m_recAction->setChecked(true);
         QString extension = "mpg";
         if (device_selector->currentIndex() == SCREENGRAB) extension = "ogv"; //KdenliveSettings::screengrabextension();
-        else if (device_selector->currentIndex() == VIDEO4LINUX) extension = KdenliveSettings::v4l_extension();
+        else if (device_selector->currentIndex() == VIDEO4LINUX) {
+            // TODO: when recording audio only, allow configuration?
+            if (!rec_video->isChecked()) extension = "wav";
+            else extension = KdenliveSettings::v4l_extension();
+        }
         else if (device_selector->currentIndex() == BLACKMAGIC) extension = KdenliveSettings::decklink_extension();
         QString path = KUrl(m_capturePath).path(KUrl::AddTrailingSlash) + "capture0000." + extension;
         int i = 1;
@@ -554,24 +591,26 @@ void RecMonitor::slotRecord()
         QString playlist;
         QString v4lparameters;
         MltVideoProfile profile;
+        bool showPreview;
         QString capturename = KdenliveSettings::dvgrabfilename();
         if (capturename.isEmpty()) capturename = "capture";
 
         switch (device_selector->currentIndex()) {
         case VIDEO4LINUX:
+            slotActivateMonitor();
             path = KStandardDirs::locateLocal("appdata", "profiles/video4linux");
             profile = ProfilesDialog::getVideoProfile(path);
-            m_videoBox->setRatio((double) profile.display_aspect_num / profile.display_aspect_den);
+            //m_videoBox->setRatio((double) profile.display_aspect_num / profile.display_aspect_den);
             buildMltDevice(path);
-            playlist = QString("<mlt title=\"capture\"><producer id=\"producer0\" in=\"0\" out=\"99999\"><property name=\"mlt_type\">producer</property><property name=\"length\">100000</property><property name=\"eof\">pause</property><property name=\"resource\">video4linux2:%1?width:%2&amp;height:%3&amp;frame_rate:%4</property><property name=\"mlt_service\">avformat-novalidate</property></producer><playlist id=\"playlist0\"><entry producer=\"producer0\" in=\"0\" out=\"99999\"/></playlist>").arg(KdenliveSettings::video4vdevice()).arg(profile.width).arg(profile.height).arg((double) profile.frame_rate_num / profile.frame_rate_den);
+            playlist = getV4lXmlPlaylist(profile);
 
             v4lparameters = KdenliveSettings::v4l_parameters();
 
+            // TODO: when recording audio only, allow param configuration?
+            if (!rec_video->isChecked()) v4lparameters.clear();
+
             // Add alsa audio capture
-            if (KdenliveSettings::v4l_captureaudio()) {
-                playlist.append(QString("<producer id=\"producer1\" in=\"0\" out=\"99999\"><property name=\"mlt_type\">producer</property><property name=\"length\">100000</property><property name=\"eof\">pause</property><property name=\"resource\">alsa:%5</property><property name=\"audio_index\">0</property><property name=\"video_index\">-1</property><property name=\"mlt_service\">avformat</property></producer><playlist id=\"playlist1\"><entry producer=\"producer1\" in=\"0\" out=\"99999\"/></playlist>").arg(KdenliveSettings::v4l_alsadevicename()));
-            }
-            else {
+            if (!rec_audio->isChecked()) {
                 // if we do not want audio, make sure that we don't have audio encoding parameters
                 // this is required otherwise the MLT avformat consumer will not close properly
                 if (v4lparameters.contains("acodec")) {
@@ -598,58 +637,49 @@ void RecMonitor::slotRecord()
                     v4lparameters = QString(v4lparameters.section("acodec", 0, 0) + "an=1 " + endParam).simplified();
                 }
             }
-            
-
-            playlist.append("<tractor id=\"tractor0\" title=\"video0\" global_feed=\"1\" in=\"0\" out=\"99999\">");
 
-            playlist.append("<track producer=\"playlist0\"/>");            
+            showPreview = m_previewSettings->isChecked();
+            if (!rec_video->isChecked()) showPreview = false;
 
-            // Audio mix
-            if (KdenliveSettings::v4l_captureaudio()) {
-                playlist.append("<track producer=\"playlist1\"/>");
-                playlist.append("<transition id=\"transition0\" in=\"0\" out=\"0\"><property name=\"a_track\">0</property><property name=\"b_track\">1</property><property name=\"mlt_type\">transition</property><property name=\"mlt_service\">mix</property></transition>");
-            }
-
-            playlist.append("</tractor></mlt>");
-
-            if (m_captureDevice->slotStartCapture(v4lparameters, m_captureFile.path(), playlist, recording_preview->currentIndex())) {
-                m_videoBox->setHidden(false);
+            if (m_captureDevice->slotStartCapture(v4lparameters, m_captureFile.path(), playlist, showPreview)) {
+                videoBox->setHidden(false);
                 m_isCapturing = true;
                 m_recAction->setEnabled(false);
                 m_stopAction->setEnabled(true);
-                recording_preview->setEnabled(false);
+                m_previewSettings->setEnabled(false);
             }
             else {
-                video_frame->setText(i18n("Failed to start Video4Linux,\ncheck your parameters..."));                
-                m_videoBox->setHidden(true);
+                video_frame->setText(i18n("Failed to start Video4Linux,\ncheck your parameters..."));
+                videoBox->setHidden(true);
                 m_isCapturing = false;
             }
             break;
-            
+
         case BLACKMAGIC:
+            slotActivateMonitor();
             path = KdenliveSettings::current_profile();
             profile = ProfilesDialog::getVideoProfile(path);
-            m_videoBox->setRatio((double) profile.display_aspect_num / profile.display_aspect_den);
+            //m_videoBox->setRatio((double) profile.display_aspect_num / profile.display_aspect_den);
             buildMltDevice(path);
-               
+
             playlist = QString("<producer id=\"producer0\" in=\"0\" out=\"99999\"><property name=\"mlt_type\">producer</property><property name=\"length\">100000</property><property name=\"eof\">pause</property><property name=\"resource\">%1</property><property name=\"mlt_service\">decklink</property></producer>").arg(KdenliveSettings::decklink_capturedevice());
 
-            if (m_captureDevice->slotStartCapture(KdenliveSettings::decklink_parameters(), m_captureFile.path(), QString("decklink:%1").arg(KdenliveSettings::decklink_capturedevice()), recording_preview->currentIndex(), false)) {
-                m_videoBox->setHidden(false);
+            if (m_captureDevice->slotStartCapture(KdenliveSettings::decklink_parameters(), m_captureFile.path(), QString("decklink:%1").arg(KdenliveSettings::decklink_capturedevice()), m_previewSettings->isChecked(), false)) {
+                videoBox->setHidden(false);
                 m_isCapturing = true;
                 slotSetInfoMessage(i18n("Capturing to %1", m_captureFile.fileName()));
                 m_recAction->setEnabled(false);
                 m_stopAction->setEnabled(true);
-                recording_preview->setEnabled(false);
+                m_previewSettings->setEnabled(false);
             }
             else {
                 video_frame->setText(i18n("Failed to start Decklink,\ncheck your parameters..."));
                 slotSetInfoMessage(i18n("Failed to start capture"));
-                m_videoBox->setHidden(true);
+                videoBox->setHidden(true);
                 m_isCapturing = false;
             }
             break;
-            
+
         case SCREENGRAB:
             switch (KdenliveSettings::rmd_capture_type()) {
             case 0:
@@ -714,6 +744,25 @@ void RecMonitor::slotRecord()
     }
 }
 
+const QString RecMonitor::getV4lXmlPlaylist(MltVideoProfile profile) {
+
+    QString playlist = QString("<mlt title=\"capture\" LC_NUMERIC=\"C\"><profile description=\"v4l\" width=\"%1\" height=\"%2\" progressive=\"%3\" sample_aspect_num=\"%4\" sample_aspect_den=\"%5\" display_aspect_num=\"%6\" display_aspect_den=\"%7\" frame_rate_num=\"%8\" frame_rate_den=\"%9\" colorspace=\"%10\"/>").arg(profile.width).arg(profile.height).arg(profile.progressive).arg(profile.sample_aspect_num).arg(profile.sample_aspect_den).arg(profile.display_aspect_num).arg(profile.display_aspect_den).arg(profile.frame_rate_num).arg(profile.frame_rate_den).arg(profile.colorspace);
+
+    if (rec_video->isChecked()) {
+        playlist.append(QString("<producer id=\"producer0\" in=\"0\" out=\"999999\"><property name=\"mlt_type\">producer</property><property name=\"length\">1000000</property><property name=\"eof\">loop</property><property name=\"resource\">video4linux2:%1?width:%2&amp;height:%3&amp;frame_rate:%4</property><property name=\"mlt_service\">avformat-novalidate</property></producer><playlist id=\"playlist0\"><entry producer=\"producer0\" in=\"0\" out=\"999999\"/></playlist>").arg(KdenliveSettings::video4vdevice()).arg(profile.width).arg(profile.height).arg((double) profile.frame_rate_num / profile.frame_rate_den));
+    }
+
+    if (rec_audio->isChecked()) {
+        playlist.append(QString("<producer id=\"producer1\" in=\"0\" out=\"999999\"><property name=\"mlt_type\">producer</property><property name=\"length\">1000000</property><property name=\"eof\">loop</property><property name=\"resource\">alsa:%5</property><property name=\"audio_index\">0</property><property name=\"video_index\">-1</property><property name=\"mlt_service\">avformat-novalidate</property></producer><playlist id=\"playlist1\"><entry producer=\"producer1\" in=\"0\" out=\"999999\"/></playlist>").arg(KdenliveSettings::v4l_alsadevicename()));
+    }
+    playlist.append("<tractor id=\"tractor0\" title=\"video0\" global_feed=\"1\" in=\"0\" out=\"999999\">");
+    if (rec_video->isChecked()) playlist.append("<track producer=\"playlist0\"/>");
+    if (rec_audio->isChecked()) playlist.append("<track producer=\"playlist1\"/>");
+    playlist.append("</tractor></mlt>");
+
+    return playlist;
+}
+
 /*
 void RecMonitor::slotStartGrab(const QRect &rect) {
     rgnGrab->deleteLater();
@@ -748,7 +797,7 @@ void RecMonitor::slotProcessStatus(QProcess::ProcessState status)
     if (status == QProcess::NotRunning) {
         m_displayProcess->kill();
         if (m_isCapturing && device_selector->currentIndex() != FIREWIRE)
-            if (autoaddbox->isChecked() && !m_captureFile.isEmpty() && QFile::exists(m_captureFile.path())) {
+            if (m_addCapturedClip->isChecked() && !m_captureFile.isEmpty() && QFile::exists(m_captureFile.path())) {
                 emit addProjectClip(m_captureFile);
                 m_captureFile.clear();
             }
@@ -824,7 +873,7 @@ void RecMonitor::manageCapturedFiles()
                     if (QFile::rename(url.path(), newUrl)) {
                         url = KUrl(newUrl);
                     }
-                    
+
                 }
                 capturedFiles.append(url);
             }
@@ -843,9 +892,10 @@ void RecMonitor::manageCapturedFiles()
 }
 
 // virtual
-void RecMonitor::mousePressEvent(QMouseEvent * /*event*/)
+void RecMonitor::mousePressEvent(QMouseEvent *event)
 {
     if (m_freeSpace->underMouse()) slotUpdateFreeSpace();
+    else QWidget::mousePressEvent(event);//m_videoBox->mousePressEvent(event);
 }
 
 void RecMonitor::slotUpdateFreeSpace()
@@ -861,16 +911,15 @@ void RecMonitor::slotUpdateFreeSpace()
 void RecMonitor::refreshRecMonitor(bool visible)
 {
     if (visible) {
-        //if (!m_isActive) m_monitorManager->activateRecMonitor(m_name);
+        //if (!m_isActive) activateMonitor();
 
     }
 }
 
 void RecMonitor::slotPlay()
 {
-
-    //if (!m_isActive) m_monitorManager->activateRecMonitor(m_name);
-
+    /*if (m_isPlaying) slotStopCapture();
+    else slotStartPreview(true);*/
 }
 
 void RecMonitor::slotReadDvgrabInfo()
@@ -901,17 +950,24 @@ void RecMonitor::slotDroppedFrames(int dropped)
 void RecMonitor::buildMltDevice(const QString &path)
 {
     if (m_captureDevice == NULL) {
-        m_captureDevice = new MltDeviceCapture(path, m_videoBox, this);
+       m_monitorManager->updateScopeSource();
+        m_captureDevice = new MltDeviceCapture(path, videoSurface, this);
         connect(m_captureDevice, SIGNAL(droppedFrames(int)), this, SLOT(slotDroppedFrames(int)));
         m_captureDevice->sendFrameForAnalysis = m_analyse;
-        m_manager->updateScopeSource();
+        m_monitorManager->updateScopeSource();
     }
 }
 
-void RecMonitor::slotChangeRecordingPreview(int ix)
+void RecMonitor::slotChangeRecordingPreview(bool enable)
 {
-    KdenliveSettings::setRecording_preview(ix);
+    KdenliveSettings::setEnable_recording_preview(enable);
 }
 
+
+void RecMonitor::slotMouseSeek(int /*eventDelta*/, bool /*fast*/)
+{
+}
+
+
 #include "recmonitor.moc"
 
index 86cb0d97e286986f1894bc38b91f030fb32d28c6..aeb1029019af80e1a3c171c830a57e6320171f0c 100644 (file)
@@ -27,6 +27,7 @@
 #define RECMONITOR_H
 
 #include "abstractmonitor.h"
+#include "definitions.h"
 #include "ui_recmonitor_ui.h"
 
 #include <QToolBar>
@@ -51,19 +52,18 @@ class RecMonitor : public AbstractMonitor, public Ui::RecMonitor_UI
     Q_OBJECT
 
 public:
-    explicit RecMonitor(QString name, MonitorManager *manager, QWidget *parent = 0);
+    explicit RecMonitor(Kdenlive::MONITORID name, MonitorManager *manager, QWidget *parent = 0);
     virtual ~RecMonitor();
 
-    const QString name() const;
     AbstractRender *abstractRender();
     void analyseFrames(bool analyse);
     enum CAPTUREDEVICE {FIREWIRE = 0, VIDEO4LINUX = 1, SCREENGRAB = 2, BLACKMAGIC = 3};
 
 protected:
     virtual void mousePressEvent(QMouseEvent * event);
+    virtual void mouseDoubleClickEvent(QMouseEvent * event);
 
 private:
-    QString m_name;
     KDateTime m_captureTime;
     /** @brief Provide feedback about dvgrab operations */
     QLabel m_dvinfo;
@@ -97,13 +97,18 @@ private:
 
     MonitorManager *m_manager;
     MltDeviceCapture *m_captureDevice;
-    VideoPreviewContainer *m_videoBox;
+    VideoContainer *m_videoBox;
+    QAction *m_addCapturedClip;
+    QAction *m_previewSettings;
+    
     bool m_analyse;
     void checkDeviceAvailability();
     QPixmap mergeSideBySide(const QPixmap& pix, const QString &txt);
     void manageCapturedFiles();
     /** @brief Build MLT producer for device, using path as profile. */
     void buildMltDevice(const QString &path);
+    /** @brief Create string containing an XML playlist for v4l capture. */
+    const QString getV4lXmlPlaylist(MltVideoProfile profile);
 
 private slots:
     void slotStartPreview(bool play = true);
@@ -120,7 +125,7 @@ private slots:
     void slotSetInfoMessage(const QString &message);
     void slotDroppedFrames(int dropped);
     /** @brief Change setting for preview while recording. */
-    void slotChangeRecordingPreview(int ix);
+    void slotChangeRecordingPreview(bool enable);
 
 public slots:
     void refreshRecMonitor(bool visible);
@@ -129,6 +134,8 @@ public slots:
     void start();
     void slotStopCapture();
     void slotUpdateCaptureFolder(const QString &currentProjectFolder);
+    void slotMouseSeek(int eventDelta, bool fast);
+    void slotSwitchFullScreen();
 
 signals:
     void renderPosition(int);
index ea95bf535a42872f5748cb9c9f92997a1a4e78b1..13fb831f09aa90bdbce921cff816c71f4707cb28 100644 (file)
 #include "definitions.h"
 #include "slideshowclip.h"
 #include "profilesdialog.h"
+
+#ifdef USE_BLACKMAGIC
 #include "blackmagic/devices.h"
+#endif
 
 #include <mlt++/Mlt.h>
 
@@ -100,9 +103,8 @@ static void consumer_gl_frame_show(mlt_consumer, Render * self, mlt_frame frame_
     }
 }
 
-Render::Render(const QString & rendererName, int winid, QString profile, QWidget *parent) :
+Render::Render(Kdenlive::MONITORID rendererName, int winid, QString profile, QWidget *parent) :
     AbstractRender(rendererName, parent),
-    analyseAudio(KdenliveSettings::monitor_audio()),
     m_name(rendererName),
     m_mltConsumer(NULL),
     m_mltProducer(NULL),
@@ -116,13 +118,14 @@ Render::Render(const QString & rendererName, int winid, QString profile, QWidget
     m_blackClip(NULL),
     m_winid(winid)
 {
+    analyseAudio = KdenliveSettings::monitor_audio();
     if (profile.isEmpty()) profile = KdenliveSettings::current_profile();
     buildConsumer(profile);
     m_mltProducer = m_blackClip->cut(0, 1);
     m_mltConsumer->connect(*m_mltProducer);
     m_mltProducer->set_speed(0.0);
     m_refreshTimer.setSingleShot(true);
-    m_refreshTimer.setInterval(50);
+    m_refreshTimer.setInterval(70);
     connect(&m_refreshTimer, SIGNAL(timeout()), this, SLOT(refresh()));
 }
 
@@ -134,7 +137,7 @@ Render::~Render()
 
 
 void Render::closeMlt()
-{       
+{
     //delete m_osdTimer;
     m_requestList.clear();
     m_infoThread.waitForFinished();
@@ -200,7 +203,8 @@ void Render::buildConsumer(const QString &profileName)
     m_blackClip->set("id", "black");
     m_blackClip->set("mlt_type", "producer");
 
-    if (KdenliveSettings::external_display() && m_name != "clip") {
+    if (KdenliveSettings::external_display() && m_name != Kdenlive::clipMonitor) {
+#ifdef USE_BLACKMAGIC
         // Use blackmagic card for video output
         QMap< QString, QString > profileProperties = ProfilesDialog::getSettingsFromFile(profileName);
         int device = KdenliveSettings::blackmagic_output_device();
@@ -221,6 +225,7 @@ void Render::buildConsumer(const QString &profileName)
                 if (m_mltConsumer && m_mltConsumer->is_valid()) return;
             } else KMessageBox::informationList(qApp->activeWindow(), i18n("Your project's profile %1 is not compatible with the blackmagic output card. Please see supported profiles below. Switching to normal video display.", m_mltProfile->description()), BMInterface::supportedModes(KdenliveSettings::blackmagic_output_device()));
         }
+#endif
     }
     m_externalConsumer = false;
     QString videoDriver = KdenliveSettings::videodrivername();
@@ -355,7 +360,7 @@ int Render::resetProfile(const QString &profileName, bool dropSceneList)
     buildConsumer(profileName);
     double new_fps = m_mltProfile->fps();
     double new_dar = m_mltProfile->dar();
-    
+
     if (!dropSceneList) {
         // We need to recover our playlist
         if (current_fps != new_fps) {
@@ -442,7 +447,7 @@ QImage Render::extractFrame(int frame_position, QString path, int width, int hei
             else delete producer;
         }
     }
-    
+
     if (!m_mltProducer || !path.isEmpty()) {
         QImage pix(width, height, QImage::Format_RGB32);
         pix.fill(Qt::black);
@@ -584,13 +589,15 @@ void Render::getFileProperties(const QDomElement &xml, const QString &clipId, in
     m_requestList.removeAll(info);
     m_requestList.append(info);
     m_infoMutex.unlock();
-    if (!m_infoThread.isRunning())
+    if (!m_infoThread.isRunning()) {
         m_infoThread = QtConcurrent::run(this, &Render::processFileProperties);
+    }
 }
 
 void Render::forceProcessing(const QString &id)
 {
-    m_infoMutex.lock();
+    if (m_processingClipId == id) return;
+    QMutexLocker lock(&m_infoMutex);
     for (int i = 0; i < m_requestList.count(); i++) {
         requestClipInfo info = m_requestList.at(i);
         if (info.clipId == id) {
@@ -602,33 +609,29 @@ void Render::forceProcessing(const QString &id)
             }
         }
     }
-    m_infoMutex.unlock();
 }
 
 int Render::processingItems()
 {
-    m_infoMutex.lock();
+    QMutexLocker lock(&m_infoMutex);
     int count = m_requestList.count();
     if (!m_processingClipId.isEmpty()) {
         // one clip is currently processed
         count++;
     }
-    m_infoMutex.unlock();
     return count;
 }
 
 bool Render::isProcessing(const QString &id)
 {
     if (m_processingClipId == id) return true;
-    m_infoMutex.lock();
+    QMutexLocker lock(&m_infoMutex);
     for (int i = 0; i < m_requestList.count(); i++) {
         requestClipInfo info = m_requestList.at(i);
         if (info.clipId == id) {
-            m_infoMutex.unlock();
             return true;
         }
     }
-    m_infoMutex.unlock();
     return false;
 }
 
@@ -639,13 +642,21 @@ void Render::processFileProperties()
     while (!m_requestList.isEmpty()) {
         m_infoMutex.lock();
         info = m_requestList.takeFirst();
-        m_infoMutex.unlock();
         m_processingClipId = info.clipId;
+        m_infoMutex.unlock();
+
         QString path;
         bool proxyProducer;
         if (info.xml.hasAttribute("proxy") && info.xml.attribute("proxy") != "-") {
             path = info.xml.attribute("proxy");
-            proxyProducer = true;
+            // Check for missing proxies
+            if (QFileInfo(path).size() <= 0) {
+                // proxy is missing, re-create it
+                emit requestProxy(info.clipId);
+                proxyProducer = false;
+                path = info.xml.attribute("resource");
+            }
+            else proxyProducer = true;
         }
         else {
             path = info.xml.attribute("resource");
@@ -773,7 +784,7 @@ void Render::processFileProperties()
         int imageWidth = (int)((double) info.imageHeight * m_mltProfile->width() / m_mltProfile->height() + 0.5);
         int fullWidth = (int)((double) info.imageHeight * m_mltProfile->dar() + 0.5);
         int frameNumber = info.xml.attribute("thumbnail", "-1").toInt();
-        
+
         if ((!info.replaceProducer && info.xml.hasAttribute("file_hash")) || proxyProducer) {
             // Clip  already has all properties
             if (proxyProducer) {
@@ -782,9 +793,9 @@ void Render::processFileProperties()
                 Mlt::Frame *frame = producer->get_frame();
                 if (frame && frame->is_valid()) {
                     QImage img = KThumb::getFrame(frame, imageWidth, fullWidth, info.imageHeight);
-                    delete frame;
                     emit replyGetImage(info.clipId, img);
                 }
+                if (frame) delete frame;
             }
             m_processingClipId.clear();
             emit replyGetFileProperties(info.clipId, producer, stringMap(), stringMap(), info.replaceProducer);
@@ -794,9 +805,9 @@ void Render::processFileProperties()
         stringMap filePropertyMap;
         stringMap metadataPropertyMap;
         char property[200];
-        
+
         if (frameNumber > 0) producer->seek(frameNumber);
-        
+
         duration = duration > 0 ? duration : producer->get_playtime();
         filePropertyMap["duration"] = QString::number(duration);
         //kDebug() << "///////  PRODUCER: " << url.path() << " IS: " << producer->get_playtime();
@@ -846,9 +857,9 @@ void Render::processFileProperties()
                 }
             }
         }
-        
+
         // Get frame rate
-        int vindex = producer->get_int("video_index");     
+        int vindex = producer->get_int("video_index");
         if (vindex > -1) {
             snprintf(property, sizeof(property), "meta.media.%d.stream.frame_rate", vindex);
             if (producer->get(property))
@@ -915,6 +926,9 @@ void Render::processFileProperties()
             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++) {
                 snprintf(property, sizeof(property), "meta.media.%d.stream.type", ix);
@@ -1238,14 +1252,15 @@ const QString Render::sceneList()
     QString playlist;
     Mlt::Profile profile((mlt_profile) 0);
     Mlt::Consumer xmlConsumer(profile, "xml:kdenlive_playlist");
+    if (!xmlConsumer.is_valid()) return QString();
     m_mltProducer->optimise();
     xmlConsumer.set("terminate_on_pause", 1);
     Mlt::Producer prod(m_mltProducer->get_producer());
+    if (!prod.is_valid()) return QString();
     bool split = m_isSplitView;
     if (split) slotSplitView(false);
     xmlConsumer.connect(prod);
-    xmlConsumer.start();
-    while (!xmlConsumer.is_stopped()) {}
+    xmlConsumer.run();
     playlist = QString::fromUtf8(xmlConsumer.get("kdenlive_playlist"));
     if (split) slotSplitView(true);
     return playlist;
@@ -1256,10 +1271,11 @@ bool Render::saveSceneList(QString path, QDomElement kdenliveData)
     QFile file(path);
     QDomDocument doc;
     doc.setContent(sceneList(), false);
-    if (!kdenliveData.isNull()) {
+    if (doc.isNull()) return false;
+    QDomElement root = doc.documentElement();
+    if (!kdenliveData.isNull() && !root.isNull()) {
         // add Kdenlive specific tags
-        QDomNode mlt = doc.elementsByTagName("mlt").at(0);
-        mlt.appendChild(doc.importNode(kdenliveData, true));
+        root.appendChild(doc.importNode(kdenliveData, true));
     }
     if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
         kWarning() << "//////  ERROR writing to file: " << path;
@@ -1279,7 +1295,7 @@ void Render::saveZone(KUrl url, QString desc, QPoint zone)
     Mlt::Consumer xmlConsumer(*m_mltProfile, ("xml:" + url.path()).toUtf8().constData());
     m_mltProducer->optimise();
     xmlConsumer.set("terminate_on_pause", 1);
-    if (m_name == "clip") {
+    if (m_name == Kdenlive::clipMonitor) {
         Mlt::Producer *prod = m_mltProducer->cut(zone.x(), zone.y());
         Mlt::Playlist list;
         list.insert_at(0, prod, 0);
@@ -1409,19 +1425,19 @@ void Render::switchPlay(bool play)
         return;
     if (m_isZoneMode) resetZoneMode();
     if (play && m_mltProducer->get_speed() == 0.0) {
-        if (m_name == "clip" && m_mltConsumer->position() == m_mltProducer->get_out()) m_mltProducer->seek(0);
+        if (m_name == Kdenlive::clipMonitor && m_mltConsumer->position() == m_mltProducer->get_out()) m_mltProducer->seek(0);
         if (m_mltConsumer->is_stopped()) {
             m_mltConsumer->start();
         }
         m_mltProducer->set_speed(1.0);
-        m_mltConsumer->set("refresh", "1");
+        m_mltConsumer->set("refresh", 1);
     } else if (!play) {
         m_mltProducer->set_speed(0.0);
         m_mltConsumer->set("refresh", 0);
         m_mltProducer->seek(m_mltConsumer->position());
         if (!m_mltConsumer->is_stopped()) m_mltConsumer->stop();
         if (m_isZoneMode) resetZoneMode();
-        
+
         //emitConsumerStopped();
         /*m_mltConsumer->set("refresh", 0);
         m_mltConsumer->stop();
@@ -1474,6 +1490,7 @@ void Render::playZone(const GenTime & startTime, const GenTime & stopTime)
     m_mltProducer->seek((int)(startTime.frames(m_fps)));
     m_mltProducer->set_speed(1.0);
     m_mltConsumer->set("refresh", 1);
+    if (m_mltConsumer->is_stopped()) m_mltConsumer->start();
     m_isZoneMode = true;
 }
 
@@ -1490,7 +1507,6 @@ void Render::seekToFrame(int pos)
 {
     if (!m_mltProducer)
         return;
-    
     resetZoneMode();
     m_mltProducer->seek(pos);
     if (m_mltProducer->get_speed() == 0) {
@@ -1562,20 +1578,22 @@ int Render::seekFramePosition() const
     return 0;
 }
 
-const QString & Render::rendererName() const
-{
-    return m_name;
-}
-
 void Render::emitFrameUpdated(Mlt::Frame& frame)
 {
-    mlt_image_format format = mlt_image_rgb24;
+    mlt_image_format format = mlt_image_rgb24a;
+    int width = 0;
+    int height = 0;
+    const uchar* image = frame.get_image(format, width, height);
+    QImage qimage(width, height, QImage::Format_ARGB32_Premultiplied);
+    memcpy(qimage.scanLine(0), image, width * height * 4);
+
+    /*mlt_image_format format = mlt_image_rgb24;
     int width = 0;
     int height = 0;
     const uchar* image = frame.get_image(format, width, height);
     QImage qimage(width, height, QImage::Format_RGB888);
-    memcpy(qimage.bits(), image, width * height * 3);
-    emit frameUpdated(qimage);
+    memcpy(qimage.bits(), image, width * height * 3);*/
+    emit frameUpdated(qimage.rgbSwapped());
 }
 
 void Render::emitFrameNumber()
@@ -1589,7 +1607,7 @@ void Render::emitConsumerStopped()
     if (m_mltProducer) {
         double pos = m_mltProducer->position();
         if (m_isLoopMode) play(m_loopStart);
-        else if (m_isZoneMode) resetZoneMode();
+        //else if (m_isZoneMode) resetZoneMode();
         emit rendererStopped((int) pos);
     }
 }
@@ -1909,7 +1927,7 @@ Mlt::Tractor *Render::lockService()
     }
     service.lock();
     return new Mlt::Tractor(service);
-    
+
 }
 
 void Render::unlockService(Mlt::Tractor *tractor)
@@ -2796,7 +2814,7 @@ bool Render::mltEditEffect(int track, GenTime position, EffectsParameterList par
     service.lock();
     for (int j = 0; j < params.count(); j++) {
         filter->set((prefix + params.at(j).name()).toUtf8().constData(), params.at(j).value().toUtf8().constData());
-    }   
+    }
 
     delete clip;
     service.unlock();
@@ -3089,7 +3107,7 @@ void Render::mltChangeTrackState(int track, bool mute, bool blind)
         trackProducer.set("hide", 0);
     }
     if (audioMixingBroken) fixAudioMixing(tractor);
-    
+
     tractor.multitrack()->refresh();
     tractor.refresh();
     refresh();
@@ -4161,11 +4179,14 @@ QString Render::updateSceneListFps(double current_fps, double new_fps, QString s
             }
         }
     }
-    QDomElement tractor = doc.elementsByTagName("tractor").at(0).toElement();
-    int out = tractor.attribute("out").toInt();
-    out = factor * out + 0.5;
-    tractor.setAttribute("out", out);
-    emit durationChanged(out);
+    QDomElement root = doc.documentElement();
+    if (!root.isNull()) {
+        QDomElement tractor = root.firstChildElement("tractor");
+        int out = tractor.attribute("out").toInt();
+        out = factor * out + 0.5;
+        tractor.setAttribute("out", out);
+        emit durationChanged(out);
+    }
 
     //kDebug() << "///////////////////////////// " << out << " \n" << doc.toString() << "\n-------------------------";
     return doc.toString();
@@ -4186,6 +4207,48 @@ Mlt::Producer* Render::getProducer()
     return m_mltProducer;
 }
 
+const QString Render::activeClipId()
+{
+    if (m_mltProducer) return m_mltProducer->get("id");
+    return QString();
+}
+
+//static 
+bool Render::getBlackMagicDeviceList(KComboBox *devicelist)
+{
+    Mlt::Profile profile;
+    Mlt::Producer bm(profile, "decklink");
+    int found_devices = 0;
+    if (bm.is_valid()) found_devices = bm.get_int("devices");
+    if (found_devices <= 0) {
+       devicelist->setEnabled(false);
+       return false;
+    }
+    for (int i = 0; i < found_devices; i++) {
+       char *tmp = qstrdup(QString("device.%1").arg(i).toUtf8().constData());
+       devicelist->addItem(bm.get(tmp));
+       delete[] tmp;
+    }
+    return true;
+}
+
+bool Render::getBlackMagicOutputDeviceList(KComboBox *devicelist)
+{
+    Mlt::Profile profile;
+    Mlt::Consumer bm(profile, "decklink");
+    int found_devices = 0;
+    if (bm.is_valid()) found_devices = bm.get_int("devices");
+    if (found_devices <= 0) {
+       devicelist->setEnabled(false);
+       return false;
+    }
+    for (int i = 0; i < found_devices; i++) {
+       char *tmp = qstrdup(QString("device.%1").arg(i).toUtf8().constData());
+       devicelist->addItem(bm.get(tmp));
+       delete[] tmp;
+    }
+    return true;
+}
 
 #include "renderer.moc"
 
index 34a516ab56af55baf6f413648c65f839ae171e14..b7b53c7acc3a2532b25d8a2d6dd18caa41e87401 100644 (file)
@@ -48,6 +48,8 @@
 class QTimer;
 class QPixmap;
 
+class KComboBox;
+
 namespace Mlt
 {
 class Consumer;
@@ -99,7 +101,7 @@ Q_OBJECT public:
      *  @param rendererName A unique identifier for this renderer
      *  @param winid The parent widget identifier (required for SDL display). Set to 0 for OpenGL rendering
      *  @param profile The MLT profile used for the renderer (default one will be used if empty). */
-    Render(const QString &rendererName, int winid, QString profile = QString(), QWidget *parent = 0);
+    Render(Kdenlive::MONITORID rendererName, int winid, QString profile = QString(), QWidget *parent = 0);
 
     /** @brief Destroy the MLT Renderer. */
     virtual ~Render();
@@ -154,9 +156,6 @@ Q_OBJECT public:
 
     void saveZone(KUrl url, QString desc, QPoint zone);
 
-    /** @brief Returns the name of the renderer. */
-    const QString & rendererName() const;
-
     /** @brief Returns the speed at which the renderer is currently playing.
      *
      * It returns 0.0 when the renderer is not playing anything. */
@@ -173,8 +172,6 @@ Q_OBJECT public:
     /** @brief Returns the aspect ratio of the consumer. */
     double consumerRatio() const;
 
-    void doRefresh();
-
     /** @brief Saves current producer frame as an image. */
     void exportCurrentFrame(KUrl url, bool notify);
 
@@ -277,8 +274,6 @@ Q_OBJECT public:
     void showFrame(Mlt::Frame&);
 
     void showAudio(Mlt::Frame&);
-    /** @brief This property is used to decide if the renderer should send audio data for monitoring. */
-    bool analyseAudio;
     
     QList <int> checkTrackSequence(int);
     void sendFrameUpdate();
@@ -303,6 +298,10 @@ Q_OBJECT public:
     Mlt::Tractor *lockService();
     /** @brief Unlock the MLT service */
     void unlockService(Mlt::Tractor *tractor);
+    const QString activeClipId();
+    /** @brief Fill a combobox with the found blackmagic devices */
+    static bool getBlackMagicDeviceList(KComboBox *devicelist);
+    static bool getBlackMagicOutputDeviceList(KComboBox *devicelist);
 
 private:
 
@@ -310,7 +309,7 @@ private:
      *
      * Useful to identify the renderers by what they do - e.g. background
      * rendering, workspace monitor, etc. */
-    QString m_name;
+    Kdenlive::MONITORID m_name;
     Mlt::Consumer * m_mltConsumer;
     Mlt::Producer * m_mltProducer;
     Mlt::Profile *m_mltProfile;
@@ -407,6 +406,9 @@ signals:
      */
     void removeInvalidProxy(const QString &id, bool durationError);
     void refreshDocumentProducers(bool displayRatioChanged, bool fpsChanged);
+    /** @brief A proxy clip is missing, ask for creation. */
+    void requestProxy(QString);
+
 
     /** @brief A frame's image has to be shown.
      *
@@ -432,6 +434,8 @@ public slots:
     void slotSwitchFullscreen();
     void slotSetVolume(int volume);
     void seekToFrame(int pos);
+    /** @brief Starts a timer to query for a refresh. */
+    void doRefresh();
 };
 
 #endif
index 24132878933ba613eae9e7e05b3e4bbedc613049..2b0199c4830c382319cb98dd1ccc8820307e53a3 100644 (file)
@@ -47,6 +47,8 @@
 #include <QThread>
 #include <QScriptEngine>
 
+
+// Render profiles roles
 const int GroupRole = Qt::UserRole;
 const int ExtensionRole = GroupRole + 1;
 const int StandardRole = GroupRole + 2;
@@ -60,10 +62,74 @@ const int DefaultBitrateRole = GroupRole + 9;
 const int AudioBitratesRole = GroupRole + 10;
 const int DefaultAudioBitrateRole = GroupRole + 11;
 
+// Render job roles
+const int ParametersRole = Qt::UserRole + 1;
+const int TimeRole = Qt::UserRole + 2;
+const int ProgressRole = Qt::UserRole + 3;
+const int ExtraInfoRole = Qt::UserRole + 5;
+
+const int DirectRenderType = QTreeWidgetItem::Type;
+const int ScriptRenderType = QTreeWidgetItem::UserType;
+
+
 // Running job status
 const int WAITINGJOB = 0;
 const int RUNNINGJOB = 1;
 const int FINISHEDJOB = 2;
+const int FAILEDJOB = 3;
+const int ABORTEDJOB = 4;
+
+
+RenderJobItem::RenderJobItem(QTreeWidget * parent, const QStringList & strings, int type) : QTreeWidgetItem(parent, strings, type),
+    m_status(-1)
+{
+    setSizeHint(1, QSize(parent->columnWidth(1), parent->fontMetrics().height() * 3));
+    setStatus(WAITINGJOB);
+}
+
+void RenderJobItem::setStatus(int status)
+{
+    if (m_status == status) return;
+    m_status = status;
+    switch (status) {
+        case WAITINGJOB:
+            setIcon(0, KIcon("media-playback-pause"));
+            setData(1, Qt::UserRole, i18n("Waiting..."));
+            break;
+        case FINISHEDJOB:
+            setData(1, Qt::UserRole, i18n("Rendering finished"));
+            setIcon(0, KIcon("dialog-ok"));
+            setData(1, ProgressRole, 100);
+            break;
+        case FAILEDJOB:
+            setData(1, Qt::UserRole, i18n("Rendering crashed"));
+            setIcon(0, KIcon("dialog-close"));
+            setData(1, ProgressRole, 100);
+            break;
+        case ABORTEDJOB:
+            setData(1, Qt::UserRole, i18n("Rendering aborted"));
+            setIcon(0, KIcon("dialog-cancel"));
+            setData(1, ProgressRole, 100);
+        
+        default:
+            break;
+    }
+}
+
+int RenderJobItem::status() const
+{
+    return m_status;
+}
+
+void RenderJobItem::setMetadata(const QString &data)
+{
+    m_data = data;
+}
+
+const QString RenderJobItem::metadata() const
+{
+    return m_data;
+}
 
 
 RenderWidget::RenderWidget(const QString &projectfolder, bool enableProxy, MltVideoProfile profile, QWidget * parent) :
@@ -73,7 +139,16 @@ RenderWidget::RenderWidget(const QString &projectfolder, bool enableProxy, MltVi
         m_blockProcessing(false)
 {
     m_view.setupUi(this);
+    int size = style()->pixelMetric(QStyle::PM_SmallIconSize);
+    QSize iconSize(size, size);
+    
     setWindowTitle(i18n("Rendering"));
+    m_view.buttonDelete->setIconSize(iconSize);
+    m_view.buttonEdit->setIconSize(iconSize);
+    m_view.buttonSave->setIconSize(iconSize);
+    m_view.buttonInfo->setIconSize(iconSize);
+    m_view.buttonFavorite->setIconSize(iconSize);
+    
     m_view.buttonDelete->setIcon(KIcon("trash-empty"));
     m_view.buttonDelete->setToolTip(i18n("Delete profile"));
     m_view.buttonDelete->setEnabled(false);
@@ -91,11 +166,13 @@ RenderWidget::RenderWidget(const QString &projectfolder, bool enableProxy, MltVi
     m_view.buttonFavorite->setIcon(KIcon("favorites"));
     m_view.buttonFavorite->setToolTip(i18n("Copy profile to favorites"));
     
+    m_view.show_all_profiles->setToolTip(i18n("Show profiles with different framerate"));
+    
     m_view.advanced_params->setMaximumHeight(QFontMetrics(font()).lineSpacing() * 5);
     
     m_view.buttonRender->setEnabled(false);
     m_view.buttonGenerateScript->setEnabled(false);
-    m_view.rescale_box->setEnabled(false);
+    setRescaleEnabled(false);
     m_view.guides_box->setVisible(false);
     m_view.open_dvd->setVisible(false);
     m_view.create_chapter->setVisible(false);
@@ -174,12 +251,13 @@ RenderWidget::RenderWidget(const QString &projectfolder, bool enableProxy, MltVi
     connect(m_view.buttonClose, SIGNAL(clicked()), this, SLOT(hide()));
     connect(m_view.buttonClose2, SIGNAL(clicked()), this, SLOT(hide()));
     connect(m_view.buttonClose3, SIGNAL(clicked()), this, SLOT(hide()));
-    connect(m_view.rescale, SIGNAL(toggled(bool)), m_view.rescale_box, SLOT(setEnabled(bool)));
+    connect(m_view.rescale, SIGNAL(toggled(bool)), this, SLOT(setRescaleEnabled(bool)));
     connect(m_view.destination_list, SIGNAL(activated(int)), this, SLOT(refreshCategory()));
     connect(m_view.out_file, SIGNAL(textChanged(const QString &)), this, SLOT(slotUpdateButtons()));
     connect(m_view.out_file, SIGNAL(urlSelected(const KUrl &)), this, SLOT(slotUpdateButtons(const KUrl &)));
     connect(m_view.format_list, SIGNAL(currentRowChanged(int)), this, SLOT(refreshView()));
     connect(m_view.size_list, SIGNAL(currentRowChanged(int)), this, SLOT(refreshParams()));
+    connect(m_view.show_all_profiles, SIGNAL(stateChanged(int)), this, SLOT(refreshView()));
 
     connect(m_view.size_list, SIGNAL(itemDoubleClicked(QListWidgetItem *)), this, SLOT(slotEditItem(QListWidgetItem *)));
 
@@ -197,7 +275,7 @@ RenderWidget::RenderWidget(const QString &projectfolder, bool enableProxy, MltVi
 
     m_view.out_file->setMode(KFile::File);
 
-    m_view.running_jobs->setHeaderLabels(QStringList() << QString() << i18n("File") << i18n("Progress"));
+    m_view.running_jobs->setHeaderLabels(QStringList() << QString() << i18n("File"));
     m_jobsDelegate = new RenderViewDelegate(this);
     m_view.running_jobs->setItemDelegate(m_jobsDelegate);
 
@@ -205,11 +283,6 @@ RenderWidget::RenderWidget(const QString &projectfolder, bool enableProxy, MltVi
     header->setResizeMode(0, QHeaderView::Fixed);
     header->resizeSection(0, 30);
     header->setResizeMode(1, QHeaderView::Interactive);
-    header->setResizeMode(2, QHeaderView::Fixed);
-    header->resizeSection(1, width() * 2 / 3 - 15);
-    header->setResizeMode(2, QHeaderView::Interactive);
-    //header->setResizeMode(1, QHeaderView::Fixed);
-
 
     m_view.scripts_list->setHeaderLabels(QStringList() << QString() << i18n("Script Files"));
     m_scriptsDelegate = new RenderViewDelegate(this);
@@ -248,6 +321,9 @@ RenderWidget::~RenderWidget()
     m_view.scripts_list->clear();
     delete m_jobsDelegate;
     delete m_scriptsDelegate;
+#if KDE_IS_VERSION(4,7,0)
+    delete m_infoMessage;
+#endif
 }
 
 void RenderWidget::slotEditItem(QListWidgetItem *item)
@@ -752,7 +828,7 @@ void RenderWidget::slotPrepareExport(bool scriptExport)
 }
 
 
-void RenderWidget::slotExport(bool scriptExport, int zoneIn, int zoneOut, const QString &playlistPath, const QString &scriptPath, bool exportAudio)
+void RenderWidget::slotExport(bool scriptExport, int zoneIn, int zoneOut, const QMap <QString, QString> metadata, const QString &playlistPath, const QString &scriptPath, bool exportAudio)
 {
     QListWidgetItem *item = m_view.size_list->currentItem();
     if (!item) return;
@@ -818,6 +894,15 @@ void RenderWidget::slotExport(bool scriptExport, int zoneIn, int zoneOut, const
     else render_process_args << "-";
 
     QString renderArgs = m_view.advanced_params->toPlainText().simplified();
+    
+    // Project metadata
+    if (m_view.export_meta->isChecked()) {
+        QMap<QString, QString>::const_iterator i = metadata.constBegin();
+        while (i != metadata.constEnd()) {
+            renderArgs.append(QString(" %1=\"%2\"").arg(i.key()).arg(i.value()));
+            ++i;
+        }
+    }
 
     // Adjust frame scale
     int width;
@@ -953,34 +1038,40 @@ void RenderWidget::slotExport(bool scriptExport, int zoneIn, int zoneOut, const
     emit selectedRenderProfile(renderProps);
 
     // insert item in running jobs list
-    QTreeWidgetItem *renderItem;
+    RenderJobItem *renderItem = NULL;
     QList<QTreeWidgetItem *> existing = m_view.running_jobs->findItems(dest, Qt::MatchExactly, 1);
     if (!existing.isEmpty()) {
-        renderItem = existing.at(0);
-        if (renderItem->data(1, Qt::UserRole + 2).toInt() == RUNNINGJOB) {
+        renderItem = static_cast<RenderJobItem*> (existing.at(0));
+        if (renderItem->status() == RUNNINGJOB || renderItem->status() == WAITINGJOB) {
             KMessageBox::information(this, i18n("There is already a job writing file:<br /><b>%1</b><br />Abort the job if you want to overwrite it...", dest), i18n("Already running"));
             return;
         }
-        renderItem->setData(1, Qt::UserRole + 4, QString());
-    } else {
-        renderItem = new QTreeWidgetItem(m_view.running_jobs, QStringList() << QString() << dest << QString());
+        if (renderItem->type() != DirectRenderType) {
+            delete renderItem;
+            renderItem = NULL;
+        }
+        else {
+            renderItem->setData(1, ProgressRole, 0);
+            renderItem->setStatus(WAITINGJOB);
+            renderItem->setIcon(0, KIcon("media-playback-pause"));
+            renderItem->setData(1, Qt::UserRole, i18n("Waiting..."));
+            renderItem->setData(1, ParametersRole, dest);
+        }
     }
-    renderItem->setData(1, Qt::UserRole + 2, WAITINGJOB);
-    renderItem->setIcon(0, KIcon("media-playback-pause"));
-    renderItem->setData(1, Qt::UserRole, i18n("Waiting..."));
-    renderItem->setSizeHint(1, QSize(m_view.running_jobs->columnWidth(1), fontMetrics().height() * 2));
-    renderItem->setData(1, Qt::UserRole + 1, QTime::currentTime());
+    if (!renderItem) renderItem = new RenderJobItem(m_view.running_jobs, QStringList() << QString() << dest);    
+    renderItem->setData(1, TimeRole, QTime::currentTime());
 
     // Set rendering type
     if (group == "dvd") {
         if (m_view.open_dvd->isChecked()) {
             renderItem->setData(0, Qt::UserRole, group);
             if (renderArgs.contains("mlt_profile=")) {
+                //TODO: probably not valid anymore (no more MLT profiles in args)
                 // rendering profile contains an MLT profile, so pass it to the running jog item, useful for dvd
                 QString prof = renderArgs.section("mlt_profile=", 1, 1);
                 prof = prof.section(' ', 0, 0);
                 kDebug() << "// render profile: " << prof;
-                renderItem->setData(0, Qt::UserRole + 1, prof);
+                renderItem->setMetadata(prof);
             }
         }
     } else {
@@ -988,12 +1079,12 @@ void RenderWidget::slotExport(bool scriptExport, int zoneIn, int zoneOut, const
             renderItem->setData(0, Qt::UserRole, group);
             // pass the url
             QString url = m_view.size_list->currentItem()->data(ExtraRole).toString();
-            renderItem->setData(0, Qt::UserRole + 1, url);
+            renderItem->setMetadata(url);
         }
     }
-    renderItem->setData(1, Qt::UserRole + 3, render_process_args);
-    if (exportAudio == false) renderItem->setData(1, Qt::UserRole + 5, i18n("Video without audio track"));
-    else  renderItem->setData(1, Qt::UserRole + 5, QString());
+    renderItem->setData(1, ParametersRole, render_process_args);
+    if (exportAudio == false) renderItem->setData(1, ExtraInfoRole, i18n("Video without audio track"));
+    else  renderItem->setData(1, ExtraInfoRole, QString());
     m_view.running_jobs->setCurrentItem(renderItem);
     m_view.tabWidget->setCurrentIndex(1);
     checkRenderStatus();
@@ -1003,55 +1094,56 @@ void RenderWidget::checkRenderStatus()
 {
     // check if we have a job waiting to render
     if (m_blockProcessing) return;
-    QTreeWidgetItem *item = m_view.running_jobs->topLevelItem(0);
+    RenderJobItem* item = static_cast<RenderJobItem*> (m_view.running_jobs->topLevelItem(0));
+    
+    // Make sure no other rendering is running
     while (item) {
-        if (item->data(1, Qt::UserRole + 2).toInt() == RUNNINGJOB) return;
-        item = m_view.running_jobs->itemBelow(item);
+        if (item->status() == RUNNINGJOB) return;
+        item = static_cast<RenderJobItem*> (m_view.running_jobs->itemBelow(item));
     }
-    item = m_view.running_jobs->topLevelItem(0);
+    item = static_cast<RenderJobItem*> (m_view.running_jobs->topLevelItem(0));
     bool waitingJob = false;
+    
+    // Find first aiting job
     while (item) {
-        if (item->data(1, Qt::UserRole + 2).toInt() == WAITINGJOB) {
-            item->setData(1, Qt::UserRole + 1, QTime::currentTime());
+        if (item->status() == WAITINGJOB) {
+            item->setData(1, TimeRole, QTime::currentTime());
             waitingJob = true;
             startRendering(item);
             break;
         }
-        item = m_view.running_jobs->itemBelow(item);
+        item = static_cast<RenderJobItem*> (m_view.running_jobs->itemBelow(item));
     }
     if (waitingJob == false && m_view.shutdown->isChecked()) emit shutdown();
 }
 
-void RenderWidget::startRendering(QTreeWidgetItem *item)
+void RenderWidget::startRendering(RenderJobItem *item)
 {
-    if (item->data(1, Qt::UserRole + 4).isNull()) {
+    if (item->type() == DirectRenderType) {
         // Normal render process
-        if (QProcess::startDetached(m_renderer, item->data(1, Qt::UserRole + 3).toStringList()) == false) {
-            item->setData(1, Qt::UserRole + 2, FINISHEDJOB);
-            item->setData(1, Qt::UserRole, i18n("Rendering crashed"));
-            item->setIcon(0, KIcon("dialog-close"));
-            item->setData(2, Qt::UserRole, 100);
+        kDebug()<<"// Normal process";
+        if (QProcess::startDetached(m_renderer, item->data(1, ParametersRole).toStringList()) == false) {
+            item->setStatus(FAILEDJOB);
         } else {
             KNotification::event("RenderStarted", i18n("Rendering <i>%1</i> started", item->text(1)), QPixmap(), this);
         }
-    } else {
+    } else if (item->type() == ScriptRenderType){
         // Script item
-        if (QProcess::startDetached(item->data(1, Qt::UserRole + 3).toString()) == false) {
-            item->setData(1, Qt::UserRole + 2, FINISHEDJOB);
-            item->setData(1, Qt::UserRole, i18n("Rendering crashed"));
-            item->setIcon(0, KIcon("dialog-close"));
-            item->setData(2, Qt::UserRole, 100);
+        kDebug()<<"// SCRIPT process: "<<item->data(1, ParametersRole).toString();
+        if (QProcess::startDetached(item->data(1, ParametersRole).toString()) == false) {
+            item->setStatus(FAILEDJOB);
         }
     }
 }
 
+
 int RenderWidget::waitingJobsCount() const
 {
     int count = 0;
-    QTreeWidgetItem *item = m_view.running_jobs->topLevelItem(0);
+    RenderJobItem* item = static_cast<RenderJobItem*> (m_view.running_jobs->topLevelItem(0));
     while (item) {
-        if (item->data(1, Qt::UserRole + 2).toInt() == WAITINGJOB) count++;
-        item = m_view.running_jobs->itemBelow(item);
+        if (item->status() == WAITINGJOB) count++;
+        item = static_cast<RenderJobItem*>(m_view.running_jobs->itemBelow(item));
     }
     return count;
 }
@@ -1158,7 +1250,7 @@ void RenderWidget::refreshView()
         QListWidgetItem *dupItem = NULL;
         if ((sizeItem->data(GroupRole).toString() == group || sizeItem->data(GroupRole).toString().isEmpty()) && sizeItem->data(MetaGroupRole).toString() == destination) {
             std = sizeItem->data(StandardRole).toString();
-            if (!std.isEmpty()) {
+            if (!m_view.show_all_profiles->isChecked() && !std.isEmpty()) {
                 if ((std.contains("PAL", Qt::CaseInsensitive) && m_profile.frame_rate_num == 25 && m_profile.frame_rate_den == 1) ||
                     (std.contains("NTSC", Qt::CaseInsensitive) && m_profile.frame_rate_num == 30000 && m_profile.frame_rate_den == 1001))
                     dupItem = sizeItem->clone();
@@ -1170,7 +1262,7 @@ void RenderWidget::refreshView()
                 m_view.size_list->addItem(dupItem);
                 std = dupItem->data(ParamsRole).toString();
                 // Make sure the selected profile uses the same frame rate as project profile
-                if (std.contains("mlt_profile=")) {
+                if (!m_view.show_all_profiles->isChecked() && std.contains("mlt_profile=")) {
                     QString profile = std.section("mlt_profile=", 1, 1).section(' ', 0, 0);
                     MltVideoProfile p = ProfilesDialog::getVideoProfile(profile);
                     if (p.frame_rate_den > 0) {
@@ -1242,9 +1334,7 @@ void RenderWidget::refreshView()
             }
         }
     }
-    // m_view.size_list->sortItems();
     focusFirstVisibleItem();
-    m_view.size_list->setVisible(m_view.size_list->count() > 1 || m_view.format_list->count() <= 1);
     m_view.size_list->blockSignals(false);
     m_view.format_list->blockSignals(false);
     if (m_view.size_list->count() > 0) {
@@ -1299,10 +1389,10 @@ void RenderWidget::refreshParams()
     if (params.contains(" s=") || params.startsWith("s=") || destination == "audioonly") {
         // profile has a fixed size, do not allow resize
         m_view.rescale->setEnabled(false);
-        m_view.rescale_box->setEnabled(false);
+        setRescaleEnabled(false);
     } else {
         m_view.rescale->setEnabled(true);
-        m_view.rescale_box->setEnabled(m_view.rescale->isChecked());
+        setRescaleEnabled(m_view.rescale->isChecked());
     }
     KUrl url = filenameWithExtension(m_view.out_file->url(), extension);
     m_view.out_file->setUrl(url);
@@ -1655,29 +1745,27 @@ void RenderWidget::parseFile(QString exportFile, bool editable)
     }
 }
 
+
+
 void RenderWidget::setRenderJob(const QString &dest, int progress)
 {
-    QTreeWidgetItem *item;
+    RenderJobItem *item;
     QList<QTreeWidgetItem *> existing = m_view.running_jobs->findItems(dest, Qt::MatchExactly, 1);
-    if (!existing.isEmpty()) item = existing.at(0);
+    if (!existing.isEmpty()) item = static_cast<RenderJobItem*> (existing.at(0));
     else {
-        item = new QTreeWidgetItem(m_view.running_jobs, QStringList() << QString() << dest << QString());
-        item->setSizeHint(1, QSize(m_view.running_jobs->columnWidth(1), fontMetrics().height() * 2));
+        item = new RenderJobItem(m_view.running_jobs, QStringList() << QString() << dest);
         if (progress == 0) {
-            item->setData(1, Qt::UserRole + 2, WAITINGJOB);
-            item->setIcon(0, KIcon("media-playback-pause"));
-            item->setData(1, Qt::UserRole, i18n("Waiting..."));
+            item->setStatus(WAITINGJOB);
         }
     }
-    item->setData(2, Qt::UserRole, progress);
-    item->setData(1, Qt::UserRole + 2, RUNNINGJOB);
+    item->setData(1, ProgressRole, progress);
+    item->setStatus(RUNNINGJOB);
     if (progress == 0) {
         item->setIcon(0, KIcon("system-run"));
-        item->setSizeHint(1, QSize(m_view.running_jobs->columnWidth(1), fontMetrics().height() * 2));
-        item->setData(1, Qt::UserRole + 1, QTime::currentTime());
+        item->setData(1, TimeRole, QTime::currentTime());
         slotCheckJob();
     } else {
-        QTime startTime = item->data(1, Qt::UserRole + 1).toTime();
+        QTime startTime = item->data(1, TimeRole).toTime();
         int seconds = startTime.secsTo(QTime::currentTime());;
         const QString t = i18n("Estimated time %1", QTime().addSecs(seconds * (100 - progress) / progress).toString("hh:mm:ss"));
         item->setData(1, Qt::UserRole, t);
@@ -1686,44 +1774,37 @@ void RenderWidget::setRenderJob(const QString &dest, int progress)
 
 void RenderWidget::setRenderStatus(const QString &dest, int status, const QString &error)
 {
-    QTreeWidgetItem *item;
+    RenderJobItem *item;
     QList<QTreeWidgetItem *> existing = m_view.running_jobs->findItems(dest, Qt::MatchExactly, 1);
-    if (!existing.isEmpty()) item = existing.at(0);
+    if (!existing.isEmpty()) item = static_cast<RenderJobItem*> (existing.at(0));
     else {
-        item = new QTreeWidgetItem(m_view.running_jobs, QStringList() << QString() << dest << QString());
-        item->setSizeHint(1, QSize(m_view.running_jobs->columnWidth(1), fontMetrics().height() * 2));
+        item = new RenderJobItem(m_view.running_jobs, QStringList() << QString() << dest);
     }
-    item->setData(1, Qt::UserRole + 2, FINISHEDJOB);
     if (status == -1) {
         // Job finished successfully
-        item->setIcon(0, KIcon("dialog-ok"));
-        item->setData(2, Qt::UserRole, 100);
-        QTime startTime = item->data(1, Qt::UserRole + 1).toTime();
+        item->setStatus(FINISHEDJOB);
+        QTime startTime = item->data(1, TimeRole).toTime();
         int seconds = startTime.secsTo(QTime::currentTime());
         const QTime tm = QTime().addSecs(seconds);
         const QString t = i18n("Rendering finished in %1", tm.toString("hh:mm:ss"));
         item->setData(1, Qt::UserRole, t);
         QString itemGroup = item->data(0, Qt::UserRole).toString();
         if (itemGroup == "dvd") {
-            emit openDvdWizard(item->text(1), item->data(0, Qt::UserRole + 1).toString());
+            emit openDvdWizard(item->text(1), item->metadata());
         } else if (itemGroup == "websites") {
-            QString url = item->data(0, Qt::UserRole + 1).toString();
+            QString url = item->metadata();
             if (!url.isEmpty()) new KRun(url, this);
         }
     } else if (status == -2) {
         // Rendering crashed
-        item->setData(1, Qt::UserRole, i18n("Rendering crashed"));
-        item->setIcon(0, KIcon("dialog-close"));
-        item->setData(2, Qt::UserRole, 100);
+        item->setStatus(FAILEDJOB);
         m_view.error_log->append(i18n("<strong>Rendering of %1 crashed</strong><br />", dest));
         m_view.error_log->append(error);
         m_view.error_log->append("<hr />");
         m_view.error_box->setVisible(true);
     } else if (status == -3) {
         // User aborted job
-        item->setData(1, Qt::UserRole, i18n("Rendering aborted"));
-        item->setIcon(0, KIcon("dialog-cancel"));
-        item->setData(2, Qt::UserRole, 100);
+        item->setStatus(ABORTEDJOB);
     }
     slotCheckJob();
     checkRenderStatus();
@@ -1731,9 +1812,9 @@ void RenderWidget::setRenderStatus(const QString &dest, int status, const QStrin
 
 void RenderWidget::slotAbortCurrentJob()
 {
-    QTreeWidgetItem *current = m_view.running_jobs->currentItem();
+    RenderJobItem *current = static_cast<RenderJobItem*> (m_view.running_jobs->currentItem());
     if (current) {
-        if (current->data(1, Qt::UserRole + 2).toInt() == RUNNINGJOB)
+        if (current->status() == RUNNINGJOB)
             emit abortProcess(current->text(1));
         else {
             delete current;
@@ -1745,8 +1826,8 @@ void RenderWidget::slotAbortCurrentJob()
 
 void RenderWidget::slotStartCurrentJob()
 {
-    QTreeWidgetItem *current = m_view.running_jobs->currentItem();
-    if (current && current->data(1, Qt::UserRole + 2).toInt() == WAITINGJOB)
+    RenderJobItem *current = static_cast<RenderJobItem*> (m_view.running_jobs->currentItem());
+    if (current && current->status() == WAITINGJOB)
         startRendering(current);
     m_view.start_job->setEnabled(false);
 }
@@ -1754,35 +1835,36 @@ void RenderWidget::slotStartCurrentJob()
 void RenderWidget::slotCheckJob()
 {
     bool activate = false;
-    QTreeWidgetItem *current = m_view.running_jobs->currentItem();
+    RenderJobItem *current = static_cast<RenderJobItem*> (m_view.running_jobs->currentItem());
     if (current) {
-        if (current->data(1, Qt::UserRole + 2).toInt() == RUNNINGJOB) {
+        if (current->status() == RUNNINGJOB) {
             m_view.abort_job->setText(i18n("Abort Job"));
             m_view.start_job->setEnabled(false);
         } else {
             m_view.abort_job->setText(i18n("Remove Job"));
-            m_view.start_job->setEnabled(current->data(1, Qt::UserRole + 2).toInt() == WAITINGJOB);
+            m_view.start_job->setEnabled(current->status() == WAITINGJOB);
         }
         activate = true;
     }
     m_view.abort_job->setEnabled(activate);
+    /*
     for (int i = 0; i < m_view.running_jobs->topLevelItemCount(); i++) {
-        current = m_view.running_jobs->topLevelItem(i);
-        if (current == m_view.running_jobs->currentItem()) {
+        current = static_cast<RenderJobItem*>(m_view.running_jobs->topLevelItem(i));
+        if (current == static_cast<RenderJobItem*> (m_view.running_jobs->currentItem())) {
             current->setSizeHint(1, QSize(m_view.running_jobs->columnWidth(1), fontMetrics().height() * 3));
         } else current->setSizeHint(1, QSize(m_view.running_jobs->columnWidth(1), fontMetrics().height() * 2));
-    }
+    }*/
 }
 
 void RenderWidget::slotCLeanUpJobs()
 {
     int ix = 0;
-    QTreeWidgetItem *current = m_view.running_jobs->topLevelItem(ix);
+    RenderJobItem *current = static_cast<RenderJobItem*> (m_view.running_jobs->topLevelItem(ix));
     while (current) {
-        if (current->data(1, Qt::UserRole + 2).toInt() == FINISHEDJOB)
+        if (current->status() == FINISHEDJOB)
             delete current;
         else ix++;
-        current = m_view.running_jobs->topLevelItem(ix);
+        current = static_cast<RenderJobItem*>(m_view.running_jobs->topLevelItem(ix));
     }
     slotCheckJob();
 }
@@ -1802,24 +1884,27 @@ void RenderWidget::parseScriptFiles()
         QString renderer;
         QString melt;
         QFile file(scriptpath.path());
+        kDebug()<<"------------------\n"<<scriptpath.path();
         if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
             QTextStream stream(&file);
             while (!stream.atEnd()) {
                 QString line = stream.readLine();
+                kDebug()<<"# :"<<line;
                 if (line.startsWith("TARGET=")) {
                     target = line.section("TARGET=\"", 1);
                     target = target.section('"', 0, 0);
-                } else if (line.startsWith("RENDERER=\"")) {
-                    renderer = line.section("RENDERER=", 1);
+                } else if (line.startsWith("RENDERER=")) {
+                    renderer = line.section("RENDERER=\"", 1);
                     renderer = renderer.section('"', 0, 0);
-                } else if (line.startsWith("MELT=\"")) {
-                    melt = line.section("MELT=", 1);
+                } else if (line.startsWith("MELT=")) {
+                    melt = line.section("MELT=\"", 1);
                     melt = melt.section('"', 0, 0);
                 }
             }
             file.close();
         }
         if (target.isEmpty()) continue;
+        kDebug()<<"ScRIPT RENDERER: "<<renderer<<"\n++++++++++++++++++++++++++";
         item = new QTreeWidgetItem(m_view.scripts_list, QStringList() << QString() << scriptpath.fileName());
         if (!renderer.isEmpty() && renderer.contains('/') && !QFile::exists(renderer)) {
             item->setIcon(0, KIcon("dialog-cancel"));
@@ -1861,30 +1946,33 @@ void RenderWidget::slotCheckScript()
 
 void RenderWidget::slotStartScript()
 {
-    QTreeWidgetItem *item = m_view.scripts_list->currentItem();
+    RenderJobItem* item = static_cast<RenderJobItem*> (m_view.scripts_list->currentItem());
     if (item) {
+        kDebug() << "// STARTING SCRIPT: "<<item->text(1);
         QString destination = item->data(1, Qt::UserRole).toString();
         QString path = item->data(1, Qt::UserRole + 1).toString();
         // Insert new job in queue
-        QTreeWidgetItem *renderItem;
+        RenderJobItem *renderItem = NULL;
         QList<QTreeWidgetItem *> existing = m_view.running_jobs->findItems(destination, Qt::MatchExactly, 1);
         kDebug() << "------  START SCRIPT";
         if (!existing.isEmpty()) {
-            renderItem = existing.at(0);
-            if (renderItem->data(1, Qt::UserRole + 2).toInt() == RUNNINGJOB) {
+            renderItem = static_cast<RenderJobItem*> (existing.at(0));
+            if (renderItem->status() == RUNNINGJOB || renderItem->status() == WAITINGJOB) {
                 KMessageBox::information(this, i18n("There is already a job writing file:<br /><b>%1</b><br />Abort the job if you want to overwrite it...", destination), i18n("Already running"));
                 return;
             }
-        } else renderItem = new QTreeWidgetItem(m_view.running_jobs, QStringList() << QString() << destination << QString());
-        kDebug() << "------  START SCRIPT 2";
-        renderItem->setData(2, Qt::UserRole, 0);
-        renderItem->setData(1, Qt::UserRole + 2, WAITINGJOB);
+            else if (renderItem->type() != ScriptRenderType) {
+                delete renderItem;
+                renderItem = NULL;
+            }
+        }
+        if (!renderItem) renderItem = new RenderJobItem(m_view.running_jobs, QStringList() << QString() << destination, ScriptRenderType);
+        renderItem->setData(1, ProgressRole, 0);
+        renderItem->setStatus(WAITINGJOB);
         renderItem->setIcon(0, KIcon("media-playback-pause"));
         renderItem->setData(1, Qt::UserRole, i18n("Waiting..."));
-        renderItem->setSizeHint(1, QSize(m_view.running_jobs->columnWidth(1), fontMetrics().height() * 2));
-        renderItem->setData(1, Qt::UserRole + 1, QTime::currentTime());
-        renderItem->setData(1, Qt::UserRole + 3, path);
-        renderItem->setData(1, Qt::UserRole + 4, '1');
+        renderItem->setData(1, TimeRole, QTime::currentTime());
+        renderItem->setData(1, ParametersRole, path);
         checkRenderStatus();
         m_view.tabWidget->setCurrentIndex(1);
     }
@@ -1992,19 +2080,19 @@ bool RenderWidget::startWaitingRenderJobs()
 
     QTextStream outStream(&file);
     outStream << "#! /bin/sh" << "\n" << "\n";
-    QTreeWidgetItem *item = m_view.running_jobs->topLevelItem(0);
+    RenderJobItem *item = static_cast<RenderJobItem*> (m_view.running_jobs->topLevelItem(0));
     while (item) {
-        if (item->data(1, Qt::UserRole + 2).toInt() == WAITINGJOB) {
-            if (item->data(1, Qt::UserRole + 4).isNull()) {
+        if (item->status() == WAITINGJOB) {
+            if (item->type() == DirectRenderType) {
                 // Add render process for item
-                const QString params = item->data(1, Qt::UserRole + 3).toStringList().join(" ");
+                const QString params = item->data(1, ParametersRole).toStringList().join(" ");
                 outStream << m_renderer << " " << params << "\n";
-            } else {
+            } else if (item->type() == ScriptRenderType){
                 // Script item
-                outStream << item->data(1, Qt::UserRole + 3).toString() << "\n";
+                outStream << item->data(1, ParametersRole).toString() << "\n";
             }
         }
-        item = m_view.running_jobs->itemBelow(item);
+        item = static_cast<RenderJobItem*>(m_view.running_jobs->itemBelow(item));
     }
     // erase itself when rendering is finished
     outStream << "rm " << autoscriptFile << "\n" << "\n";
@@ -2035,7 +2123,8 @@ QString RenderWidget::getFreeScriptName(const QString &prefix)
 
 void RenderWidget::slotPlayRendering(QTreeWidgetItem *item, int)
 {
-    if (KdenliveSettings::defaultplayerapp().isEmpty() || item->data(1, Qt::UserRole + 2).toInt() != FINISHEDJOB) return;
+    RenderJobItem *renderItem = static_cast<RenderJobItem*> (item);
+    if (KdenliveSettings::defaultplayerapp().isEmpty() || renderItem->status() != FINISHEDJOB) return;
     KUrl::List urls;
     urls.append(KUrl(item->text(1)));
     KRun::run(KdenliveSettings::defaultplayerapp(), urls, this);
@@ -2131,3 +2220,11 @@ bool RenderWidget::proxyRendering()
 {
     return m_view.proxy_render->isChecked();
 }
+
+void RenderWidget::setRescaleEnabled(bool enable)
+{
+    for (int i = 0; i < m_view.rescale_box->layout()->count(); i++) {
+        if (m_view.rescale_box->itemAt(i)->widget()) m_view.rescale_box->itemAt(i)->widget()->setEnabled(enable);
+    }   
+}
+
index ea9b122a10bb32217077c48c880b4c8669dce238..dcaa4612131215f3162932392bb6a7d65cff350e 100644 (file)
@@ -47,68 +47,67 @@ public:
                const QModelIndex &index) const {
         if (index.column() == 1) {
             painter->save();
-            int factor = 2;
             QStyleOptionViewItemV4 opt(option);
             QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
             const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1;
             style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget);
 
-            if (option.state & QStyle::State_Selected) {
-                painter->setPen(option.palette.highlightedText().color());
-                factor = 3;
-            }// else painter->setPen(option.palette.color(QPalette::Text));
             QFont font = painter->font();
             font.setBold(true);
             painter->setFont(font);
             QRect r1 = option.rect;
             r1.adjust(0, textMargin, 0, - textMargin);
-            int mid = (int)((r1.height() / factor));
+            int mid = (int)((r1.height() / 2));
             r1.setBottom(r1.y() + mid);
-            painter->drawText(r1, Qt::AlignLeft | Qt::AlignBottom , index.data().toString());
-            r1.setBottom(r1.bottom() + mid);
-            r1.setTop(r1.bottom() - mid);
+            QRect bounding;
+            painter->drawText(r1, Qt::AlignLeft | Qt::AlignTop ,index.data().toString(), &bounding);
+            r1.moveTop(r1.bottom() - textMargin);
             font.setBold(false);
             painter->setFont(font);
-            painter->drawText(r1, Qt::AlignLeft | Qt::AlignVCenter , index.data(Qt::UserRole).toString());
-            if (factor > 2) {
-                r1.setBottom(r1.bottom() + mid);
+            painter->drawText(r1, Qt::AlignLeft | Qt::AlignTop , index.data(Qt::UserRole).toString());
+            int progress = index.data(Qt::UserRole + 3).toInt();
+            if (progress > 0 && progress < 100) {
+                // draw progress bar
+                QColor color = option.palette.alternateBase().color();
+                QColor fgColor = option.palette.text().color();
+                color.setAlpha(150);
+                fgColor.setAlpha(150);
+                painter->setBrush(QBrush(color));
+                painter->setPen(QPen(fgColor));
+                int width = qMin(200, r1.width() - 4);
+                QRect bgrect(r1.left() + 2, option.rect.bottom() - 6 - textMargin, width, 6);
+                painter->drawRoundedRect(bgrect, 3, 3);
+                painter->setBrush(QBrush(fgColor));
+                bgrect.adjust(2, 2, 0, -1);
+                painter->setPen(Qt::NoPen);
+                bgrect.setWidth((width - 2) * progress / 100);
+                painter->drawRect(bgrect);
+            } else {
+                r1.setBottom(opt.rect.bottom());
                 r1.setTop(r1.bottom() - mid);
-                painter->drawText(r1, Qt::AlignLeft | Qt::AlignVCenter , index.data(Qt::UserRole + 5).toString());
+                painter->drawText(r1, Qt::AlignLeft | Qt::AlignBottom , index.data(Qt::UserRole + 5).toString());
             }
             painter->restore();
-        } else if (index.column() == 2) {
-            // Set up a QStyleOptionProgressBar to precisely mimic the
-            // environment of a progress bar.
-            QStyleOptionViewItemV4 opt(option);
-            QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
-            style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget);
-
-            QStyleOptionProgressBar progressBarOption;
-            progressBarOption.state = option.state;
-            progressBarOption.direction = QApplication::layoutDirection();
-            QRect rect = option.rect;
-            int mid = rect.height() / 2;
-            rect.setTop(rect.top() + mid / 2);
-            rect.setHeight(mid);
-            progressBarOption.rect = rect;
-            progressBarOption.fontMetrics = QApplication::fontMetrics();
-            progressBarOption.minimum = 0;
-            progressBarOption.maximum = 100;
-            progressBarOption.textAlignment = Qt::AlignCenter;
-            progressBarOption.textVisible = true;
-
-            // Set the progress and text values of the style option.
-            int progress = index.data(Qt::UserRole).toInt();
-            progressBarOption.progress = progress < 0 ? 0 : progress;
-            progressBarOption.text = QString().sprintf("%d%%", progressBarOption.progress);
-
-            // Draw the progress bar onto the view.
-            QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption, painter);
         } else QStyledItemDelegate::paint(painter, option, index);
     }
 };
 
 
+class RenderJobItem: public QTreeWidgetItem
+{
+public:
+    explicit RenderJobItem(QTreeWidget * parent, const QStringList & strings, int type = QTreeWidgetItem::Type);
+    void setStatus(int status);
+    int status() const;
+    void setMetadata(const QString &data);
+    const QString metadata() const;
+    void render();
+
+private:
+    int m_status;
+    QString m_data;    
+};
+
 class RenderWidget : public QDialog
 {
     Q_OBJECT
@@ -141,7 +140,7 @@ protected:
     virtual QSize sizeHint() const;
 
 public slots:
-    void slotExport(bool scriptExport, int zoneIn, int zoneOut, const QString &playlistPath, const QString &scriptPath, bool exportAudio);
+    void slotExport(bool scriptExport, int zoneIn, int zoneOut, const QMap <QString, QString> metadata, const QString &playlistPath, const QString &scriptPath, bool exportAudio);
 
 private slots:
     void slotUpdateButtons(KUrl url);
@@ -178,6 +177,8 @@ private slots:
     void slotSwitchAspectRatio();
     /** @brief Update export audio label depending on current settings. */
     void slotUpdateAudioLabel(int ix);
+    /** @brief Enable / disable the rescale options. */
+    void setRescaleEnabled(bool enable);
 
 private:
     Ui::RenderWidget_UI m_view;
@@ -196,8 +197,9 @@ private:
     void parseFile(QString exportFile, bool editable);
     void updateButtons();
     KUrl filenameWithExtension(KUrl url, QString extension);
+    /** @brief Check if a job needs to be started. */
     void checkRenderStatus();
-    void startRendering(QTreeWidgetItem *item);
+    void startRendering(RenderJobItem *item);
     void saveProfile(QDomElement newprofile);
     QList <QListWidgetItem *> m_renderItems;
     QList <QListWidgetItem *> m_renderCategory;
diff --git a/src/scopes/CMakeLists.txt b/src/scopes/CMakeLists.txt
new file mode 100644 (file)
index 0000000..bd61d72
--- /dev/null
@@ -0,0 +1,10 @@
+
+add_subdirectory(colorscopes)
+add_subdirectory(audioscopes)
+
+set(kdenlive_SRCS
+  ${kdenlive_SRCS}
+  scopes/scopemanager.cpp
+  scopes/abstractscopewidget.cpp
+  PARENT_SCOPE
+)
similarity index 99%
rename from src/abstractscopewidget.cpp
rename to src/scopes/abstractscopewidget.cpp
index 0622bd97d72c0f325a3fc05b1ad50ead09dc6076..6d4b1c8ee7aea40b8492c33a8992d95421aa1f3f 100644 (file)
@@ -8,11 +8,12 @@
  *   (at your option) any later version.                                   *
  ***************************************************************************/
 
+#include "qtconcurrentrun.h"
+
 #include "abstractscopewidget.h"
 #include "renderer.h"
 #include "monitor.h"
 
-#include <QtConcurrentRun>
 #include <QFuture>
 #include <QColor>
 #include <QMenu>
@@ -62,7 +63,8 @@ AbstractScopeWidget::AbstractScopeWidget(bool trackMouse, QWidget *parent) :
         initialDimensionUpdateDone(false),
         m_requestForcedUpdate(false),
         m_rescaleMinDist(4),
-        m_rescaleVerticalThreshold(2.0f)
+        m_rescaleVerticalThreshold(2.0f),
+        m_rescaleActive(false)
 
 {
     m_scopePalette = QPalette();
@@ -427,7 +429,7 @@ void AbstractScopeWidget::slotHUDRenderingFinished(uint mseconds, uint oldFactor
         qDebug() << "Trying to start a new HUD thread for " << m_widgetName
                 << ". New frames/updates: " << m_newHUDFrames << "/" << m_newHUDUpdates;
 #endif
-        prodHUDThread();;
+        prodHUDThread();
     }
 }
 
@@ -531,7 +533,7 @@ void AbstractScopeWidget::slotResetRealtimeFactor(bool realtimeChecked)
     }
 }
 
-bool AbstractScopeWidget::autoRefreshEnabled()
+bool AbstractScopeWidget::autoRefreshEnabled() const
 {
     return m_aAutoRefresh->isChecked();
 }
similarity index 82%
rename from src/abstractscopewidget.h
rename to src/scopes/abstractscopewidget.h
index e518e1f08758eadf723c15101ce998e30ba79313..4fe726d959642f80bb16929b262e76175fe12eb2 100644 (file)
@@ -8,16 +8,28 @@
  *   (at your option) any later version.                                   *
  ***************************************************************************/
 
+
+
+#ifndef ABSTRACTSCOPEWIDGET_H
+#define ABSTRACTSCOPEWIDGET_H
+
+#include <QtCore>
+#include <QWidget>
+
+class QMenu;
 /**
-  This abstract widget is a proof that abstract things sometimes *are* useful.
+  \brief Abstract class for audio/colour scopes (receive data and paint it).
+
+  This abstract widget is a proof that abstract things sometimes \b *are* useful.
 
   The widget expects three layers which
-  * Will be painted on top of each other on each update
-  * Are rendered in a separate thread so that the UI is not blocked
-  * Are rendered only if necessary (e.g., if a layer does not depend
+  \li Will be painted on top of each other on each update
+  \li Are rendered in a separate thread so that the UI is not blocked
+  \li Are rendered only if necessary (e.g., if a layer does not depend
     on input images, it will not be re-rendered for incoming frames)
 
   The layer order is as follows:
+  \verbatim
      _____________________
     /                     \
    /      HUD Layer        \
@@ -33,6 +45,7 @@
    /   Background Layer    \
   /                         \
   ---------------------------
+  \endverbatim
 
   Colors of Scope Widgets are defined in here (and thus don't need to be
   re-defined in the implementation of the widget's .ui file).
   the comments on the unimplemented methods carefully. They are not only here
   for optical amusement, but also contain important information.
  */
-
-#ifndef ABSTRACTSCOPEWIDGET_H
-#define ABSTRACTSCOPEWIDGET_H
-
-#include <QtCore>
-#include <QWidget>
-
-class QMenu;
-
 class AbstractScopeWidget : public QWidget
 {
     Q_OBJECT
 
 public:
-    /** trackMouse enables mouse tracking; The variables m_mousePos and m_mouseWithinWidget will be set
-            if mouse tracking is enabled. See also signalMousePositionChanged(). */
+    /**
+      \param trackMouse enables mouse tracking; The variables m_mousePos and m_mouseWithinWidget will be set
+            if mouse tracking is enabled.
+      \see signalMousePositionChanged(): Emitted when mouse tracking is enabled
+      */
     AbstractScopeWidget(bool trackMouse = false, QWidget *parent = 0);
     virtual ~AbstractScopeWidget(); // Must be virtual because of inheritance, to avoid memory leaks
 
@@ -75,7 +82,9 @@ public:
 
     /** Tell whether this scope has auto-refresh enabled. Required for determining whether
         new data (e.g. an image frame) has to be delivered to this widget. */
-    bool autoRefreshEnabled();
+    bool autoRefreshEnabled() const;
+
+    bool needsSingleFrame();
 
     ///// Unimplemented /////
 
@@ -156,13 +165,20 @@ protected:
         that have to change together with the widget's size.  */
     virtual QRect scopeRect() = 0;
 
-    /** @brief HUD renderer. Must emit signalHUDRenderingFinished(). @see renderScope */
+    /** @brief HUD renderer. Must emit signalHUDRenderingFinished().
+        @see renderScope(uint). */
     virtual QImage renderHUD(uint accelerationFactor) = 0;
-    /** @brief Scope renderer. Must emit signalScopeRenderingFinished()
-        when calculation has finished, to allow multi-threading.
-        accelerationFactor hints how much faster than usual the calculation should be accomplished, if possible. */
+    /** @brief Rendering function for the scope layer.
+        This function \b must emit signalScopeRenderingFinished(), otherwise the scope
+        will not attempt to ever call this function again. This signal is required for multi-threading;
+        not emitting it on unused rendering function may increase performance.
+        @param accelerationFactor hints how much faster than usual the calculation should be accomplished, if possible.
+        @see renderHUD(uint) for the upper layer
+        @see renderBackground(uint) for the layer below
+         */
     virtual QImage renderScope(uint accelerationFactor) = 0;
-    /** @brief Background renderer. Must emit signalBackgroundRenderingFinished(). @see renderScope */
+    /** @brief Background renderer. Must emit signalBackgroundRenderingFinished().
+        @see renderScope(uint) */
     virtual QImage renderBackground(uint accelerationFactor) = 0;
 
     /** Must return true if the HUD layer depends on the input data.
@@ -198,17 +214,21 @@ protected:
     //    void raise(); // Called only when  manually calling the event -> useless
 
 
-protected slots:
+public slots:
     /** Forces an update of all layers. */
     void forceUpdate(bool doUpdate = true);
     void forceUpdateHUD();
     void forceUpdateScope();
     void forceUpdateBackground();
+
+protected slots:
     void slotAutoRefreshToggled(bool);
 
 signals:
-    /** mseconds represent the time taken for the calculation,
-        accelerationFactor is the acceleration factor that has been used for this calculation. */
+    /**
+      \param mseconds represents the time taken for the calculation.
+      \param accelerationFactor is the acceleration factor that has been used for this calculation.
+      */
     void signalHUDRenderingFinished(uint mseconds, uint accelerationFactor);
     void signalScopeRenderingFinished(uint mseconds, uint accelerationFactor);
     void signalBackgroundRenderingFinished(uint mseconds, uint accelerationFactor);
@@ -218,26 +238,27 @@ signals:
         This signal is typically connected to forceUpdateHUD(). */
     void signalMousePositionChanged();
 
-    /** Do we need the renderer to send its frames to us? */
+    /** Do we need the renderer to send its frames to us?
+        Emitted when auto-refresh is toggled. */
     void requestAutoRefresh(bool);
 
 private:
 
     /** Counts the number of data frames that have been rendered in the active monitor.
-      The frame number will be reset when the calculation starts for the current data set. */
+        The frame number will be reset when the calculation starts for the current data set. */
     QAtomicInt m_newHUDFrames;
     QAtomicInt m_newScopeFrames;
     QAtomicInt m_newBackgroundFrames;
 
     /** Counts the number of updates that, unlike new frames, force a recalculation
-      of the scope, like for example a resize event. */
+        of the scope, like for example a resize event. */
     QAtomicInt m_newHUDUpdates;
     QAtomicInt m_newScopeUpdates;
     QAtomicInt m_newBackgroundUpdates;
 
     /** The semaphores ensure that the QFutures for the HUD/Scope/Background threads cannot
-      be assigned a new thread while it is still running. (Could cause deadlocks and other
-      nasty things known from parallelism.) */
+        be assigned a new thread while it is still running. (Could cause deadlocks and other
+        nasty things known from parallelism.) */
     QSemaphore m_semaphoreHUD;
     QSemaphore m_semaphoreScope;
     QSemaphore m_semaphoreBackground;
@@ -273,11 +294,11 @@ private:
 protected slots:
     void customContextMenuRequested(const QPoint &pos);
     /** To be called when a new frame has been received.
-      The scope then decides whether and when it wants to recalculate the scope, depending
-      on whether it is currently visible and whether a calculation thread is already running. */
+        The scope then decides whether and when it wants to recalculate the scope, depending
+        on whether it is currently visible and whether a calculation thread is already running. */
     void slotRenderZoneUpdated();
     /** The following slots are called when rendering of a component has finished. They e.g. update
-      the widget and decide whether to immediately restart the calculation thread. */
+        the widget and decide whether to immediately restart the calculation thread. */
     void slotHUDRenderingFinished(uint mseconds, uint accelerationFactor);
     void slotScopeRenderingFinished(uint mseconds, uint accelerationFactor);
     void slotBackgroundRenderingFinished(uint mseconds, uint accelerationFactor);
diff --git a/src/scopes/audioscopes/CMakeLists.txt b/src/scopes/audioscopes/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ab18a4f
--- /dev/null
@@ -0,0 +1,10 @@
+set(kdenlive_SRCS
+  ${kdenlive_SRCS}
+  scopes/audioscopes/abstractaudioscopewidget.cpp
+  scopes/audioscopes/audiosignal.cpp
+  scopes/audioscopes/audiospectrum.cpp
+  scopes/audioscopes/ffttools.cpp
+  scopes/audioscopes/spectrogram.cpp
+  PARENT_SCOPE
+)
+
similarity index 93%
rename from src/audioscopes/abstractaudioscopewidget.cpp
rename to src/scopes/audioscopes/abstractaudioscopewidget.cpp
index 16b50681b4abb8ba6e8bd359e521346aa2ea2ef7..250000451e84b3ab1b20b15c054bc704c926344b 100644 (file)
@@ -36,7 +36,7 @@ AbstractAudioScopeWidget::AbstractAudioScopeWidget(bool trackMouse, QWidget *par
 {
 }
 
-void AbstractAudioScopeWidget::slotReceiveAudio(const QVector<int16_t> &sampleData, int freq, int num_channels, int num_samples)
+void AbstractAudioScopeWidget::slotReceiveAudio(QVector<int16_t> sampleData, int freq, int num_channels, int num_samples)
 {
 #ifdef DEBUG_AASW
     qDebug() << "Received audio for " << widgetName() << ".";
similarity index 89%
rename from src/audioscopes/abstractaudioscopewidget.h
rename to src/scopes/audioscopes/abstractaudioscopewidget.h
index b9c3430a99af5a6f4a59dfd58389c1b7dc2717c3..a3c352b7d50c7a401928fb3e893540ff182254f6 100644 (file)
 
 #include <stdint.h>
 
-#include "abstractscopewidget.h"
+#include "../abstractscopewidget.h"
 
 class QMenu;
 
 class Monitor;
 class Render;
 
+/**
+ \brief Abstract class for scopes analyzing audio samples.
+ */
 class AbstractAudioScopeWidget : public AbstractScopeWidget
 {
     Q_OBJECT
@@ -31,6 +34,9 @@ public:
     AbstractAudioScopeWidget(bool trackMouse = false, QWidget *parent = 0);
     virtual ~AbstractAudioScopeWidget();
 
+public slots:
+    void slotReceiveAudio(QVector<int16_t> sampleData, int freq, int num_channels, int num_samples);
+
 protected:
     /** @brief This is just a wrapper function, subclasses can use renderAudioScope. */
     virtual QImage renderScope(uint accelerationFactor);
@@ -51,9 +57,6 @@ private:
     QVector<int16_t> m_audioFrame;
     QAtomicInt m_newData;
 
-private slots:
-    void slotReceiveAudio(const QVector<int16_t>& sampleData, int freq, int num_channels, int num_samples);
-
 };
 
 #endif // ABSTRACTAUDIOSCOPEWIDGET_H
similarity index 75%
rename from src/audiosignal.cpp
rename to src/scopes/audioscopes/audiosignal.cpp
index 00c5946541c70f71cd954e46087e76acb7a9cc46..bc4f68f9a94b8e8b4e656537b01e74229287d9cd 100644 (file)
 #include "audiosignal.h"
 
 #include <KLocale>
+#include <KDebug>
 
 #include <QVBoxLayout>
-#include <QLabel>
 #include <QAction>
+#include <QMenu>
 #include <QPainter>
 #include <QDebug>
 #include <QList>
 
 #include <math.h>
 
-AudioSignal::AudioSignal(QWidget *parent): QWidget(parent)
+AudioSignal::AudioSignal(QWidget *parent): AbstractAudioScopeWidget(false, parent)
 {
-    //QVBoxLayout *vbox=new QVBoxLayout(this);
-    //label=new QLabel();
-    //vbox->addWidget(label);
     setMinimumHeight(10);
     setMinimumWidth(10);
     dbscale << 0 << -1 << -2 << -3 << -4 << -5 << -6 << -8 << -10 << -20 << -40 ;
-    setContextMenuPolicy(Qt::ActionsContextMenu);
-    m_aMonitoringEnabled = new QAction(i18n("Monitor audio signal"), this);
-    m_aMonitoringEnabled->setCheckable(true);
-    m_aMonitoringEnabled->setChecked(true);
-    connect(m_aMonitoringEnabled, SIGNAL(toggled(bool)), this, SLOT(slotSwitchAudioMonitoring(bool)));
+    m_menu->removeAction(m_aRealtime);
     connect(&m_timer,SIGNAL(timeout()),this,SLOT(slotNoAudioTimeout()));
-    addAction(m_aMonitoringEnabled);
+    init();
 }
 
 AudioSignal::~AudioSignal()
 {
-    delete m_aMonitoringEnabled;
 }
 
-bool AudioSignal::monitoringEnabled() const
+QImage AudioSignal::renderAudioScope(uint, const QVector<int16_t> audioFrame,
+                                     const int, const int num_channels, const int samples, const int)
 {
-    return m_aMonitoringEnabled->isChecked();
-}
-
-void AudioSignal::slotReceiveAudio(const QVector<int16_t>& data, int, int num_channels, int samples){
+    QTime start = QTime::currentTime();
 
     int num_samples = samples > 200 ? 200 : samples;
 
     QByteArray channels;
-    int num_oversample=0;
     for (int i = 0; i < num_channels; i++) {
         long val = 0;
-        double over1=0.0;
-        double over2=0.0;
         for (int s = 0; s < num_samples; s ++) {
-            int sample=abs(data[i+s*num_channels] / 128);
-            val += sample;
-            if (sample==128){
-                num_oversample++;
-            }else{
-                num_oversample=0;
-            }
-            //if 3 samples over max => 1 peak over 0 db (0db=40.0)
-            if (num_oversample>3){
-                over1=41.0/42.0*127;
-            }
-            // 10 samples @max => show max signal
-            if (num_oversample>10){
-                over2=127;
-            }
-
-
-
+            val += abs(audioFrame[i+s*num_channels] / 128);
         }
-        //max amplitude = 40/42, 3to10  oversamples=41, more then 10 oversamples=42 
-        if (over2>0.0){
-            channels.append(over2);            
-        } else if (over1>0.0){
-            channels.append(over1);            
-        }else
-            channels.append(val / num_samples*40.0/42.0);
+        channels.append(val / num_samples);
     }
-    showAudio(channels);
-    m_timer.start(1000);
-}
 
-void AudioSignal::slotNoAudioTimeout(){
-    peeks.fill(0);
-    showAudio(QByteArray(2,0));
-    m_timer.stop();
-}
-
-void AudioSignal::showAudio(const QByteArray arr)
-{
-    channels = arr;
     if (peeks.count()!=channels.count()){
         peeks=QByteArray(channels.count(),0);
         peekage=QByteArray(channels.count(),0);
     }
     for (int chan=0;chan<peeks.count();chan++)
     {
-        peekage[chan]=peekage[chan]+1;
-        if (  peeks.at(chan)<arr.at(chan) ||  peekage.at(chan)>50 )
+        peekage[chan] = peekage[chan]+1;
+        if (  peeks.at(chan)<channels.at(chan) ||  peekage.at(chan)>50 )
         {
             peekage[chan]=0;
-            peeks[chan]=arr[chan];
+            peeks[chan]=channels[chan];
         }
     }
-    update();
-}
-
-double AudioSignal::valueToPixel(double in)
-{
-       //in=0 -> return 0 (null length from max), in=127/127 return 1 (max length )
-       return 1.0- log10( in)/log10(1.0/127.0);
-}
 
-void AudioSignal::paintEvent(QPaintEvent* /*e*/)
-{
-    if (!m_aMonitoringEnabled->isChecked()) {
-        return;
-    }
-    QPainter p(this);
+    QImage image(m_scopeRect.size(), QImage::Format_ARGB32);
+    image.fill(Qt::transparent);
+    QPainter p(&image);
+    p.setPen(Qt::white);
+    p.setRenderHint(QPainter::TextAntialiasing, false);
+    p.setRenderHint(QPainter::Antialiasing, false);
+    
     int numchan = channels.size();
     bool horiz=width() > height();
     int dbsize=20;
@@ -144,7 +90,7 @@ void AudioSignal::paintEvent(QPaintEvent* /*e*/)
     for (int i = 0; i < numchan; i++) {
         //int maxx= (unsigned char)channels[i] * (horiz ? width() : height() ) / 127;
         double valpixel=valueToPixel((double)(unsigned char)channels[i]/127.0);
-        int maxx=  height()  * valpixel; 
+        int maxx=  height()  * valpixel;
         int xdelta= height()   /42 ;
         int _y2= (showdb?width()-dbsize:width () ) / numchan - 1  ;
         int _y1= (showdb?width()-dbsize:width() ) *i/numchan;
@@ -152,7 +98,7 @@ void AudioSignal::paintEvent(QPaintEvent* /*e*/)
         if (horiz){
             dbsize=9;
             showdb=height()>(dbsize);
-            maxx=width()*valpixel; 
+            maxx=width()*valpixel;
             xdelta = width() / 42;
             _y2=( showdb?height()-dbsize:height() ) / numchan - 1 ;
             _y1= (showdb?height()-dbsize:height() ) * i/numchan;
@@ -181,7 +127,7 @@ void AudioSignal::paintEvent(QPaintEvent* /*e*/)
             }
         }
         int xp=valueToPixel((double)peeks.at(i)/127.0)*(horiz?width():height())-2;
-        p.fillRect(horiz?xp:_y1,horiz?_y1:height()-xdelta-xp,horiz?3:_y2,horiz?_y2:3,QBrush(Qt::black,Qt::SolidPattern));
+        p.fillRect(horiz?xp:_y1,horiz?_y1:height()-xdelta-xp,horiz?3:_y2,horiz?_y2:3,QBrush(Qt::gray,Qt::SolidPattern));
 
     }
     if (showdb){
@@ -197,11 +143,87 @@ void AudioSignal::paintEvent(QPaintEvent* /*e*/)
         }
     }
     p.end();
+    emit signalScopeRenderingFinished((uint) start.elapsed(), 1);
+    return image;
 }
 
-void AudioSignal::slotSwitchAudioMonitoring(bool)
+QRect AudioSignal::scopeRect() { return QRect(0, 0, width(), height()); }
+
+QImage AudioSignal::renderHUD(uint) { return QImage(); }
+QImage AudioSignal::renderBackground(uint) { return QImage(); }
+
+void AudioSignal::slotReceiveAudio(QVector<int16_t> data, int, int num_channels, int samples)
 {
-    emit updateAudioMonitoring();
+
+    int num_samples = samples > 200 ? 200 : samples;
+
+    QByteArray channels;
+    int num_oversample=0;
+    for (int i = 0; i < num_channels; i++) {
+        long val = 0;
+        double over1=0.0;
+        double over2=0.0;
+        for (int s = 0; s < num_samples; s ++) {
+            int sample=abs(data[i+s*num_channels] / 128);
+            val += sample;
+            if (sample==128){
+                num_oversample++;
+            }else{
+                num_oversample=0;
+            }
+            //if 3 samples over max => 1 peak over 0 db (0db=40.0)
+            if (num_oversample>3){
+                over1=41.0/42.0*127;
+            }
+            // 10 samples @max => show max signal
+            if (num_oversample>10){
+                over2=127;
+            }
+
+
+
+        }
+        //max amplitude = 40/42, 3to10  oversamples=41, more then 10 oversamples=42
+        if (over2>0.0){
+            channels.append(over2);
+        } else if (over1>0.0){
+            channels.append(over1);
+        }else
+            channels.append(val / num_samples*40.0/42.0);
+    }
+    showAudio(channels);
+    m_timer.start(1000);
+}
+
+void AudioSignal::slotNoAudioTimeout(){
+    peeks.fill(0);
+    showAudio(QByteArray(2,0));
+    m_timer.stop();
+}
+
+void AudioSignal::showAudio(const QByteArray arr)
+{
+    channels = arr;
+    if (peeks.count()!=channels.count()){
+        peeks=QByteArray(channels.count(),0);
+        peekage=QByteArray(channels.count(),0);
+    }
+    for (int chan=0;chan<peeks.count();chan++)
+    {
+        peekage[chan]=peekage[chan]+1;
+        if (  peeks.at(chan)<arr.at(chan) ||  peekage.at(chan)>50 )
+        {
+            peekage[chan]=0;
+            peeks[chan]=arr[chan];
+        }
+    }
+    update();
+}
+
+double AudioSignal::valueToPixel(double in)
+{
+       //in=0 -> return 0 (null length from max), in=127/127 return 1 (max length )
+       return 1.0- log10( in)/log10(1.0/127.0);
 }
 
 #include "audiosignal.moc"
similarity index 72%
rename from src/audiosignal.h
rename to src/scopes/audioscopes/audiosignal.h
index 6cb9b071f963ffdea8bd4553c5656b58d82ea070..dd683850408be2aef2120efc3a37620c6c53c452 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef AUDIOSIGNAL_H
 #define AUDIOSIGNAL_H
 
+#include "scopes/audioscopes/abstractaudioscopewidget.h"
+
 #include <QByteArray>
 #include <QList>
 #include <QColor>
@@ -30,7 +32,7 @@ class QLabel;
 
 #include <stdint.h>
 
-class AudioSignal : public QWidget
+class AudioSignal : public AbstractAudioScopeWidget
 {
     Q_OBJECT
 public:
@@ -39,23 +41,27 @@ public:
     /** @brief Used for checking whether audio data needs to be delivered */
     bool monitoringEnabled() const;
 
+    QRect scopeRect();
+    QImage renderHUD(uint accelerationFactor);
+    QImage renderBackground(uint accelerationFactor);
+    QImage renderAudioScope(uint accelerationFactor, const QVector<int16_t> audioFrame, const int, const int num_channels, const int samples, const int);
+
+    QString widgetName() const { return "audioSignal"; }
+    bool isHUDDependingOnInput() const { return false; }
+    bool isScopeDependingOnInput() const { return true; }
+    bool isBackgroundDependingOnInput() const { return false; }
+
 private:
     double valueToPixel(double in);
-       QTimer m_timer;
-    QLabel* label;
+    QTimer m_timer;
     QByteArray channels,peeks,peekage;
-       QList<int> dbscale;
-    QAction *m_aMonitoringEnabled;
-
-protected:
-    void paintEvent(QPaintEvent*);
+    QList<int> dbscale;
 
 public slots:
     void showAudio(const QByteArray);
-    void slotReceiveAudio(const QVector<int16_t>&,int,int,int);
+    void slotReceiveAudio(QVector<int16_t>,int,int,int);
 private slots:
-     void slotSwitchAudioMonitoring(bool isOn);
-       void slotNoAudioTimeout();
+     void slotNoAudioTimeout();
 
 signals:
     void updateAudioMonitoring();
similarity index 95%
rename from src/audioscopes/audiospectrum.h
rename to src/scopes/audioscopes/audiospectrum.h
index 77308afa98e21f50cb1fb208ed708c9c39694c81..ca29fdb077dc6b778e8d5c9a2719cfe69d77e3c0 100644 (file)
@@ -8,11 +8,6 @@
  *   (at your option) any later version.                                   *
  ***************************************************************************/
 
-/**
-   Displays a spectral power distribution of audio samples.
-   The frequency distribution is calculated by means of a Fast Fourier Transformation.
-   For more information see Wikipedia:FFT and the code comments.
-*/
 
 #ifndef AUDIOSPECTRUM_H
 #define AUDIOSPECTRUM_H
 #include "ffttools.h"
 
 class AudioSpectrum_UI;
+
+/**
+   \brief Displays a spectral power distribution of audio samples.
+   The frequency distribution is calculated by means of a Fast Fourier Transformation.
+   For more information see Wikipedia:FFT and the code comments.
+
+   \todo Currently only supports one channel. Add support for multiple channels.
+*/
 class AudioSpectrum : public AbstractAudioScopeWidget {
     Q_OBJECT
 
diff --git a/src/scopes/colorscopes/CMakeLists.txt b/src/scopes/colorscopes/CMakeLists.txt
new file mode 100644 (file)
index 0000000..61624b3
--- /dev/null
@@ -0,0 +1,9 @@
+set(kdenlive_SRCS
+  ${kdenlive_SRCS}
+  scopes/colorscopes/abstractgfxscopewidget.cpp
+  scopes/colorscopes/histogram.cpp
+  scopes/colorscopes/rgbparade.cpp
+  scopes/colorscopes/vectorscope.cpp
+  scopes/colorscopes/waveform.cpp
+  PARENT_SCOPE
+)
similarity index 54%
rename from src/colorscopes/abstractgfxscopewidget.cpp
rename to src/scopes/colorscopes/abstractgfxscopewidget.cpp
index 94f90400a6bba3052219f05412a2269388d35a42..430b33190524f4507ba120523c55f2dface65162 100644 (file)
 
 const int REALTIME_FPS = 30;
 
-AbstractGfxScopeWidget::AbstractGfxScopeWidget(MonitorManager *manager, bool trackMouse, QWidget *parent) :
-        AbstractScopeWidget(trackMouse, parent),
-        m_manager(manager)
+AbstractGfxScopeWidget::AbstractGfxScopeWidget(bool trackMouse, QWidget *parent) :
+        AbstractScopeWidget(trackMouse, parent)
 {
-    m_activeRender = m_manager->activeRenderer();
-
-    bool b = true;
-    if (m_activeRender != NULL)
-        b &= connect(m_activeRender, SIGNAL(frameUpdated(QImage)), this, SLOT(slotRenderZoneUpdated(QImage)));
-    Q_ASSERT(b);
 }
 
 AbstractGfxScopeWidget::~AbstractGfxScopeWidget() { }
@@ -49,40 +42,13 @@ QImage AbstractGfxScopeWidget::renderScope(uint accelerationFactor)
 
 void AbstractGfxScopeWidget::mouseReleaseEvent(QMouseEvent *event)
 {
-    if (!m_aAutoRefresh->isChecked() && m_activeRender) {
-        m_activeRender->sendFrameUpdate();
-    }
     AbstractScopeWidget::mouseReleaseEvent(event);
+    emit signalFrameRequest(widgetName());
 }
 
 
 ///// Slots /////
 
-void AbstractGfxScopeWidget::slotActiveMonitorChanged()
-{
-    if (m_activeRender) {
-        if (m_activeRender == m_manager->activeRenderer()) return;
-        bool b = m_activeRender->disconnect(this);
-        Q_ASSERT(b);
-    }
-    m_activeRender = m_manager->activeRenderer();
-
-    if (m_activeRender) {
-#ifdef DEBUG_AGSW
-    qDebug() << "Active monitor has changed in " << widgetName() << ". Is the clip monitor active now? " << m_activeRender->name();
-#endif
-        bool b = connect(m_activeRender, SIGNAL(frameUpdated(QImage)), this, SLOT(slotRenderZoneUpdated(QImage)));
-        Q_ASSERT(b);
-    }
-
-    // Update the scope for the new monitor.
-    forceUpdate(true);
-}
-
-void AbstractGfxScopeWidget::slotClearMonitor()
-{
-    m_activeRender = NULL;
-}
 
 void AbstractGfxScopeWidget::slotRenderZoneUpdated(QImage frame)
 {
@@ -92,8 +58,8 @@ void AbstractGfxScopeWidget::slotRenderZoneUpdated(QImage frame)
 
 void AbstractGfxScopeWidget::slotAutoRefreshToggled(bool autoRefresh)
 {
-    if (autoRefresh && m_activeRender) {
-        m_activeRender->sendFrameUpdate();
+    if (autoRefresh) {
+        emit signalFrameRequest(widgetName());
     }
 }
 
similarity index 85%
rename from src/colorscopes/abstractgfxscopewidget.h
rename to src/scopes/colorscopes/abstractgfxscopewidget.h
index 5748dae51d3551fefde8b1c93a1390d972e37694..54e335ad9d3eeb40919e453878ef8b092cc47744 100644 (file)
 #define ABSTRACTGFXSCOPEWIDGET_H
 
 #include <QtCore>
+#include <QtCore/QString>
 #include <QWidget>
 
-#include "abstractscopewidget.h"
-#include "renderer.h"
+#include "../abstractscopewidget.h"
 
 class QMenu;
 
-class MonitorManager;
 
+/**
+\brief Abstract class for scopes analyzing image frames.
+*/
 class AbstractGfxScopeWidget : public AbstractScopeWidget
 {
     Q_OBJECT
 
 public:
-    AbstractGfxScopeWidget(MonitorManager *manager, bool trackMouse = false, QWidget *parent = 0);
+    AbstractGfxScopeWidget(bool trackMouse = false, QWidget *parent = 0);
     virtual ~AbstractGfxScopeWidget(); // Must be virtual because of inheritance, to avoid memory leaks
 
 protected:
     ///// Variables /////
 
-    MonitorManager *m_manager;
-    AbstractRender *m_activeRender;
-
     /** @brief Scope renderer. Must emit signalScopeRenderingFinished()
         when calculation has finished, to allow multi-threading.
         accelerationFactor hints how much faster than usual the calculation should be accomplished, if possible. */
@@ -51,14 +50,13 @@ public slots:
     /** @brief Must be called when the active monitor has shown a new frame.
       This slot must be connected in the implementing class, it is *not*
       done in this abstract class. */
-    void slotActiveMonitorChanged();
-    void slotClearMonitor();
+    void slotRenderZoneUpdated(QImage);
 
 protected slots:
     virtual void slotAutoRefreshToggled(bool autoRefresh);
 
-private slots:
-    void slotRenderZoneUpdated(QImage);
+signals:
+    void signalFrameRequest(const QString widgetName);
 
 };
 
similarity index 97%
rename from src/colorscopes/histogram.cpp
rename to src/scopes/colorscopes/histogram.cpp
index 9b5915a5bc9f64400a1105503f48ebb7d4498bba..99bb340365096f9281c0c0d1006d53a97e8340ad 100644 (file)
 #include <QTime>
 #include "colorcorrection/histogramgenerator.h"
 #include "histogram.h"
-#include "renderer.h"
 
-Histogram::Histogram(MonitorManager *manager, QWidget *parent) :
-    AbstractGfxScopeWidget(manager, false, parent)
+Histogram::Histogram(QWidget *parent) :
+    AbstractGfxScopeWidget(false, parent)
 {
     ui = new Ui::Histogram_UI();
     ui->setupUi(this);
similarity index 94%
rename from src/colorscopes/histogram.h
rename to src/scopes/colorscopes/histogram.h
index 19b86da2011838ebacc9424e74c50bd115180436..85a954a2994d5c6f83df3fc52dbefdd119b7c4f7 100644 (file)
 
 class HistogramGenerator;
 
+/**
+ *  \brief Displays the histogram of frames.
+ */
 class Histogram : public AbstractGfxScopeWidget {
     Q_OBJECT
 
 public:
-    Histogram(MonitorManager *manager, QWidget *parent = 0);
+    Histogram(QWidget *parent = 0);
     ~Histogram();
     QString widgetName() const;
 
similarity index 97%
rename from src/colorscopes/rgbparade.cpp
rename to src/scopes/colorscopes/rgbparade.cpp
index 18be787a095a4cc79d373efa6ea9d193e50168e2..f2583262127e9060718b01f084eb884eba3f1e56 100644 (file)
 #include <QPainter>
 #include <QRect>
 #include <QTime>
-#include "renderer.h"
 #include "rgbparade.h"
 #include "colorcorrection/rgbparadegenerator.h"
 
-RGBParade::RGBParade(MonitorManager *manager, QWidget *parent) :
-        AbstractGfxScopeWidget(manager, true, parent)
+RGBParade::RGBParade(QWidget *parent) :
+        AbstractGfxScopeWidget(true, parent)
 {
     ui = new Ui::RGBParade_UI();
     ui->setupUi(this);
similarity index 90%
rename from src/colorscopes/rgbparade.h
rename to src/scopes/colorscopes/rgbparade.h
index db178b20df9860bd2b9d5c390e5a4cb417d6f5ca..1d6a3c6dcf74085296e77e919a45aed2fbd9ea38 100644 (file)
 #include "abstractgfxscopewidget.h"
 #include "ui_rgbparade_ui.h"
 
-class Monitor;
 class QImage;
 class RGBParade_UI;
 class RGBParadeGenerator;
 
+/**
+ * \brief Displays the RGB waveform of a frame.
+ * This is the same as the Waveform, but for each colour channel separately.
+ */
 class RGBParade : public AbstractGfxScopeWidget
 {
 public:
-    RGBParade(MonitorManager *manager, QWidget *parent = 0);
+    RGBParade(QWidget *parent = 0);
     ~RGBParade();
     QString widgetName() const;
 
similarity index 99%
rename from src/colorscopes/vectorscope.cpp
rename to src/scopes/colorscopes/vectorscope.cpp
index 76a6e72226227078ded5468f5541ad6a3ff93ec2..55437fff8bd40ad4eb9eced662a5d7cc1a4f88b1 100644 (file)
@@ -20,7 +20,6 @@
 
 #include "colorplaneexport.h"
 #include "colortools.h"
-#include "renderer.h"
 #include "vectorscope.h"
 #include "colorcorrection/vectorscopegenerator.h"
 
@@ -42,8 +41,8 @@ const QPointF YPbPr_Mg(.331, .419);
 const QPointF YPbPr_Yl(-.5, .081);
 
 
-Vectorscope::Vectorscope(MonitorManager *manager, QWidget *parent) :
-    AbstractGfxScopeWidget(manager, true, parent),
+Vectorscope::Vectorscope(QWidget *parent) :
+    AbstractGfxScopeWidget(true, parent),
     m_gain(1)
 {
     ui = new Ui::Vectorscope_UI();
similarity index 94%
rename from src/colorscopes/vectorscope.h
rename to src/scopes/colorscopes/vectorscope.h
index de54440d5c5e5cde29d804aaf01446ab299afc98..adeba60ab5b2943da3efc1ea6aef7db02ff7d16d 100644 (file)
 
 class ColorPlaneExport;
 class ColorTools;
-class Render;
-class Monitor;
+
 class Vectorscope_UI;
 class VectorscopeGenerator;
 
 enum BACKGROUND_MODE { BG_NONE = 0, BG_YUV = 1, BG_CHROMA = 2, BG_YPbPr = 3 };
 
+/**
+   \brief Displays the vectorscope of a frame.
+
+   \see VectorscopeGenerator for more details about the vectorscope.
+   */
 class Vectorscope : public AbstractGfxScopeWidget {
     Q_OBJECT
 
 public:
-    Vectorscope(MonitorManager *manager, QWidget *parent = 0);
+    Vectorscope(QWidget *parent = 0);
     ~Vectorscope();
 
     QString widgetName() const;
similarity index 98%
rename from src/colorscopes/waveform.cpp
rename to src/scopes/colorscopes/waveform.cpp
index f8fec8b1493d450c6802013d00e7592f3726595d..9a567c2b203761db687d471d465e87dbeb7329b5 100644 (file)
@@ -17,7 +17,6 @@
 #include "kdenlivesettings.h"
 #include "profilesdialog.h"
 
-#include "renderer.h"
 #include "waveform.h"
 #include "colorcorrection/waveformgenerator.h"
 
@@ -25,8 +24,8 @@
 const QSize Waveform::m_textWidth(35,0);
 const int Waveform::m_paddingBottom(20);
 
-Waveform::Waveform(MonitorManager *manager, QWidget *parent) :
-    AbstractGfxScopeWidget(manager, true, parent)
+Waveform::Waveform(QWidget *parent) :
+    AbstractGfxScopeWidget(true, parent)
   ,ui(NULL)
 {
     ui = new Ui::Waveform_UI();
similarity index 90%
rename from src/colorscopes/waveform.h
rename to src/scopes/colorscopes/waveform.h
index ce0313979cc556575793b5343b34d6333526be8d..2455f81731e6f5573e1d12747456e604aa190686 100644 (file)
 class Waveform_UI;
 class WaveformGenerator;
 
+/**
+  \brief Displays the waveform of a frame.
+
+   For further explanations of the waveform see the WaveformGenerator class.
+*/
 class Waveform : public AbstractGfxScopeWidget {
     Q_OBJECT
 
 public:
-    Waveform(MonitorManager *manager, QWidget *parent = 0);
+    Waveform(QWidget *parent = 0);
     ~Waveform();
 
     virtual QString widgetName() const;
diff --git a/src/scopes/scopemanager.cpp b/src/scopes/scopemanager.cpp
new file mode 100644 (file)
index 0000000..a1fc141
--- /dev/null
@@ -0,0 +1,302 @@
+/***************************************************************************
+ *   Copyright (C) 2011 by Simon Andreas Eugster (simon.eu@gmail.com)      *
+ *   This file is part of kdenlive. See www.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.                                   *
+ ***************************************************************************/
+
+#include "scopemanager.h"
+
+#include <QDockWidget>
+
+#include "definitions.h"
+#include "monitormanager.h"
+#include "kdenlivesettings.h"
+
+//#define DEBUG_SM
+#ifdef DEBUG_SM
+#include <QtCore/QDebug>
+#endif
+
+ScopeManager::ScopeManager(MonitorManager *monitorManager) :
+    m_monitorManager(monitorManager),
+    m_lastConnectedRenderer(NULL)
+{
+    m_signalMapper = new QSignalMapper(this);
+
+    bool b = true;
+    b &= connect(m_monitorManager, SIGNAL(checkColorScopes()), this, SLOT(slotUpdateActiveRenderer()));
+    b &= connect(m_monitorManager, SIGNAL(clearScopes()), this, SLOT(slotClearColorScopes()));
+    b &= connect(m_signalMapper, SIGNAL(mapped(QString)), this, SLOT(slotRequestFrame(QString)));
+    Q_ASSERT(b);
+
+    slotUpdateActiveRenderer();
+}
+
+bool ScopeManager::addScope(AbstractAudioScopeWidget *audioScope, QDockWidget *audioScopeWidget)
+{
+    bool added = false;
+    int exists = false;
+    // Only add the scope if it does not exist yet in the list
+    for (int i = 0; i < m_audioScopes.size(); i++) {
+        if (m_audioScopes[i].scope == audioScope) {
+            exists = true;
+            break;
+        }
+    }
+    if (!exists) {
+        // Add scope to the list, set up signal/slot connections
+#ifdef DEBUG_SM
+        qDebug() << "Adding scope to scope manager: " << audioScope->widgetName();
+#endif
+
+        m_signalMapper->setMapping(audioScopeWidget, QString(audioScope->widgetName()));
+
+        AudioScopeData asd;
+        asd.scope = audioScope;
+        asd.scopeDockWidget = audioScopeWidget;
+        m_audioScopes.append(asd);
+
+        bool b = true;
+        b &= connect(audioScope, SIGNAL(requestAutoRefresh(bool)), this, SLOT(slotCheckActiveScopes()));
+//         b &= connect(audioScope, SIGNAL(signalFrameRequest(QString)), this, SLOT(slotRequestFrame(QString)));
+        if (audioScopeWidget != NULL) {
+            b &= connect(audioScopeWidget, SIGNAL(visibilityChanged(bool)), this, SLOT(slotCheckActiveScopes()));
+            b &= connect(audioScopeWidget, SIGNAL(visibilityChanged(bool)), m_signalMapper, SLOT(map()));
+        }
+        Q_ASSERT(b);
+
+        added = true;
+    }
+    return added;
+}
+bool ScopeManager::addScope(AbstractGfxScopeWidget *colorScope, QDockWidget *colorScopeWidget)
+{
+    bool added = false;
+    int exists = false;
+    for (int i = 0; i < m_colorScopes.size(); i++) {
+        if (m_colorScopes[i].scope == colorScope) {
+            exists = true;
+            break;
+        }
+    }
+    if (!exists) {
+#ifdef DEBUG_SM
+        qDebug() << "Adding scope to scope manager: " << colorScope->widgetName();
+#endif
+
+        m_signalMapper->setMapping(colorScopeWidget, QString(colorScope->widgetName()));
+
+        GfxScopeData gsd;
+        gsd.scope = colorScope;
+        gsd.scopeDockWidget = colorScopeWidget;
+        m_colorScopes.append(gsd);
+
+        bool b = true;
+        b &= connect(colorScope, SIGNAL(requestAutoRefresh(bool)), this, SLOT(slotCheckActiveScopes()));
+        b &= connect(colorScope, SIGNAL(signalFrameRequest(QString)), this, SLOT(slotRequestFrame(QString)));
+        if (colorScopeWidget != NULL) {
+            b &= connect(colorScopeWidget, SIGNAL(visibilityChanged(bool)), this, SLOT(slotCheckActiveScopes()));
+            b &= connect(colorScopeWidget, SIGNAL(visibilityChanged(bool)), m_signalMapper, SLOT(map()));
+        }
+        Q_ASSERT(b);
+
+        added = true;
+    }
+    return added;
+}
+
+
+void ScopeManager::slotDistributeAudio(QVector<int16_t> sampleData, int freq, int num_channels, int num_samples)
+{
+#ifdef DEBUG_SM
+    qDebug() << "ScopeManager: Starting to distribute audio.";
+#endif
+    for (int i = 0; i < m_audioScopes.size(); i++) {
+        // Distribute audio to all scopes that are visible and want to be refreshed
+        if (!m_audioScopes[i].scope->visibleRegion().isEmpty()) {
+            if (m_audioScopes[i].scope->autoRefreshEnabled()) {
+                m_audioScopes[i].scope->slotReceiveAudio(sampleData, freq, num_channels, num_samples);
+#ifdef DEBUG_SM
+                qDebug() << "ScopeManager: Distributed audio to " << m_audioScopes[i].scope->widgetName();
+#endif
+            }
+        }
+    }
+
+    checkActiveAudioScopes();
+}
+void ScopeManager::slotDistributeFrame(QImage image)
+{
+#ifdef DEBUG_SM
+    qDebug() << "ScopeManager: Starting to distribute frame.";
+#endif
+    for (int i = 0; i < m_colorScopes.size(); i++) {
+        if (!m_colorScopes[i].scope->visibleRegion().isEmpty()) {
+            if (m_colorScopes[i].scope->autoRefreshEnabled()) {
+                m_colorScopes[i].scope->slotRenderZoneUpdated(image);
+#ifdef DEBUG_SM
+                qDebug() << "ScopeManager: Distributed frame to " << m_colorScopes[i].scope->widgetName();
+#endif
+            } else if (m_colorScopes[i].singleFrameRequested) {
+                // Special case: Auto refresh is disabled, but user requested an update (e.g. by clicking).
+                // Force the scope to update.
+                m_colorScopes[i].singleFrameRequested = false;
+                m_colorScopes[i].scope->slotRenderZoneUpdated(image);
+                m_colorScopes[i].scope->forceUpdateScope();
+#ifdef DEBUG_SM
+                qDebug() << "ScopeManager: Distributed forced frame to " << m_colorScopes[i].scope->widgetName();
+#endif
+            }
+        }
+    }
+
+    checkActiveColourScopes();
+}
+
+
+void ScopeManager::slotRequestFrame(const QString widgetName)
+{
+#ifdef DEBUG_SM
+    qDebug() << "ScopeManager: New frame was requested by " << widgetName;
+#endif
+
+    // Search for the scope in the lists and tag it to trigger a forced update
+    // in the distribution slots
+    for (int i = 0; i < m_colorScopes.size(); i++) {
+        if (m_colorScopes[i].scope->widgetName() == widgetName) {
+            m_colorScopes[i].singleFrameRequested = true;
+            break;
+        }
+    }
+    for (int i = 0; i < m_audioScopes.size(); i++) {
+        if (m_audioScopes[i].scope->widgetName() == widgetName) {
+            m_audioScopes[i].singleFrameRequested = true;
+            break;
+        }
+    }
+    if (m_lastConnectedRenderer) m_lastConnectedRenderer->sendFrameUpdate();
+}
+
+
+void ScopeManager::slotClearColorScopes()
+{
+    m_lastConnectedRenderer = NULL;
+}
+
+
+void ScopeManager::slotUpdateActiveRenderer()
+{
+    bool b = true;
+
+    // Disconnect old connections
+    if (m_lastConnectedRenderer != NULL) {
+#ifdef DEBUG_SM
+        qDebug() << "Disconnected previous renderer: " << m_lastConnectedRenderer->name();
+#endif
+        b &= m_lastConnectedRenderer->disconnect(this);
+        Q_ASSERT(b);
+    }
+
+    m_lastConnectedRenderer = m_monitorManager->activeRenderer();
+
+    // Connect new renderer
+    if (m_lastConnectedRenderer != NULL) {
+        b &= connect(m_lastConnectedRenderer, SIGNAL(frameUpdated(QImage)),
+                this, SLOT(slotDistributeFrame(QImage)), Qt::UniqueConnection);
+        b &= connect(m_lastConnectedRenderer, SIGNAL(audioSamplesSignal(QVector<int16_t>,int,int,int)),
+                this, SLOT(slotDistributeAudio(QVector<int16_t>,int,int,int)), Qt::UniqueConnection);
+        Q_ASSERT(b);
+
+#ifdef DEBUG_SM
+        qDebug() << "Renderer connected to ScopeManager: " << m_lastConnectedRenderer->name();
+#endif
+
+        if (imagesAcceptedByScopes()) {
+#ifdef DEBUG_SM
+            qDebug() << "Some scopes accept images, triggering frame update.";
+#endif
+            m_lastConnectedRenderer->sendFrameUpdate();
+        }
+    }
+}
+
+
+void ScopeManager::slotCheckActiveScopes()
+{
+#ifdef DEBUG_SM
+    qDebug() << "Checking active scopes ...";
+#endif
+    checkActiveAudioScopes();
+    checkActiveColourScopes();
+}
+
+
+bool ScopeManager::audioAcceptedByScopes() const
+{
+    bool accepted = false;
+    for (int i = 0; i < m_audioScopes.size(); i++) {
+        if (!m_audioScopes[i].scope->visibleRegion().isEmpty() && m_audioScopes[i].scope->autoRefreshEnabled()) {
+            accepted = true;
+            break;
+        }
+    }
+#ifdef DEBUG_SM
+    qDebug() << "Any scope accepting audio? " << accepted;
+#endif
+    return accepted;
+}
+bool ScopeManager::imagesAcceptedByScopes() const
+{
+    bool accepted = false;
+    for (int i = 0; i < m_colorScopes.size(); i++) {
+        if (!m_colorScopes[i].scope->visibleRegion().isEmpty() && m_colorScopes[i].scope->autoRefreshEnabled()) {
+            accepted = true;
+            break;
+        }
+    }
+#ifdef DEBUG_SM
+    qDebug() << "Any scope accepting images? " << accepted;
+#endif
+    return accepted;
+}
+
+
+
+void ScopeManager::checkActiveAudioScopes()
+{
+    bool audioStillRequested = audioAcceptedByScopes();
+
+#ifdef DEBUG_SM
+    qDebug() << "ScopeManager: New audio data still requested? " << audioStillRequested;
+#endif
+
+    KdenliveSettings::setMonitor_audio(audioStillRequested);
+    m_monitorManager->slotUpdateAudioMonitoring();
+}
+void ScopeManager::checkActiveColourScopes()
+{
+    bool imageStillRequested = imagesAcceptedByScopes();
+
+#ifdef DEBUG_SM
+    qDebug() << "ScopeManager: New frames still requested? " << imageStillRequested;
+#endif
+
+    // Notify monitors whether frames are still required
+    Monitor *monitor;
+    monitor = static_cast<Monitor*>( m_monitorManager->monitor(Kdenlive::projectMonitor) );
+    if (monitor != NULL) { 
+       if (monitor->effectSceneDisplayed()) monitor->render->sendFrameForAnalysis = true;
+       else monitor->render->sendFrameForAnalysis = imageStillRequested;
+    }
+
+    monitor = static_cast<Monitor*>( m_monitorManager->monitor(Kdenlive::clipMonitor) );
+    if (monitor != NULL) { monitor->render->sendFrameForAnalysis = imageStillRequested; }
+
+    RecMonitor *recMonitor = static_cast<RecMonitor*>( m_monitorManager->monitor(Kdenlive::recordMonitor) );
+    if (recMonitor != NULL) { recMonitor->analyseFrames(imageStillRequested); }
+}
+
diff --git a/src/scopes/scopemanager.h b/src/scopes/scopemanager.h
new file mode 100644 (file)
index 0000000..3ad8320
--- /dev/null
@@ -0,0 +1,120 @@
+/***************************************************************************
+ *   Copyright (C) 2011 by Simon Andreas Eugster (simon.eu@gmail.com)      *
+ *   This file is part of kdenlive. See www.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.                                   *
+ ***************************************************************************/
+
+#ifndef SCOPEMANAGER_H
+#define SCOPEMANAGER_H
+
+#include <QtCore/QList>
+
+#include "scopes/audioscopes/abstractaudioscopewidget.h"
+#include "scopes/colorscopes/abstractgfxscopewidget.h"
+
+class QDockWidget;
+class MonitorManager;
+class AbstractRender;
+
+/**
+  \brief Manages communication between Scopes and Renderer
+
+  The scope manager handles the data transfer between the active Renderer and
+  all scopes that have been registered via ScopeManager::addScope(AbstractAudioScopeWidget, QDockWidget)
+  or ScopeManager::addScope(AbstractGfxScopeWidget, QDockWidget). It checks whether the renderer really
+  needs to send data (it does not, for example, if no scopes are visible).
+  */
+class ScopeManager : QObject
+{
+    Q_OBJECT
+
+    struct GfxScopeData {
+        AbstractGfxScopeWidget *scope;
+        QDockWidget *scopeDockWidget;
+        bool singleFrameRequested;
+        GfxScopeData() { singleFrameRequested = false; }
+    };
+
+    struct AudioScopeData {
+        AbstractAudioScopeWidget *scope;
+        QDockWidget *scopeDockWidget;
+        bool singleFrameRequested;
+        AudioScopeData() { singleFrameRequested = false; }
+    };
+
+public:
+    ScopeManager(MonitorManager *monitorManager);
+
+    /**
+      Adds a scope and sets up signal/slot connections to ensure that the scope
+      receives data when required.
+      \see addScope(AbstractGfxScopeWidget, QDockWidget)
+      */
+    bool addScope(AbstractAudioScopeWidget *audioScope, QDockWidget *audioScopeWidget = NULL);
+    /**
+      \see addScope(AbstractAudioScopeWidget, QDockWidget)
+      */
+    bool addScope(AbstractGfxScopeWidget *colorScope, QDockWidget *colorScopeWidget = NULL);
+
+private:
+    MonitorManager *m_monitorManager;
+    QList<AudioScopeData> m_audioScopes;
+    QList<GfxScopeData> m_colorScopes;
+
+    AbstractRender *m_lastConnectedRenderer;
+
+    QSignalMapper *m_signalMapper;
+
+    /**
+      Checks whether there is any scope accepting audio data, or if all of them are hidden
+      or if auto refresh is disabled.
+      \see imagesAcceptedByScopes(): Same for image data
+      */
+    bool audioAcceptedByScopes() const;
+    /**
+      \see audioAcceptedByScopes()
+      */
+    bool imagesAcceptedByScopes() const;
+
+
+    /**
+      Checks whether audio data is required, and notifies the renderer (enable or disable data sending).
+      \see checkActiveAudioScopes() for image data
+      */
+    void checkActiveAudioScopes();
+    /**
+      Checks whether any scope accepts frames, and notifies the renderer.
+      \see checkActiveAudioScopes() for audio data
+      */
+    void checkActiveColourScopes();
+
+private slots:
+    /**
+      Updates the signal/slot connection since the active renderer has changed.
+      */
+    void slotUpdateActiveRenderer();
+    /**
+      The scope source was deleted, clear it.
+      */
+    void slotClearColorScopes();
+    /**
+      \see checkActiveAudioScopes()
+      \see checkActiveColourScopes()
+      */
+    
+    void slotCheckActiveScopes();
+    void slotDistributeFrame(QImage image);
+    void slotDistributeAudio(QVector<int16_t> sampleData, int freq, int num_channels, int num_samples);
+    /**
+      Allows a scope to explicitly request a new frame, even if the scope's autoRefresh is disabled.
+      */
+    void slotRequestFrame(const QString widgetName);
+
+
+};
+
+#endif // SCOPEMANAGER_H
index c6492afa9a221aa0c3b02b2dafdb4a0fa6578c0e..848780b37f035555c684a948b9490d469204b6a3 100644 (file)
@@ -68,10 +68,8 @@ SlideshowClip::SlideshowClip(Timecode tc, QWidget * parent) :
     m_view.animation->addItem(i18n("Zoom"), "Zoom");
     m_view.animation->addItem(i18n("Zoom, low-pass"), "Zoom, low-pass");
 
-    m_view.clip_duration->setInputMask("");
-    m_view.clip_duration->setValidator(m_timecode.validator());
-    m_view.luma_duration->setInputMask("");
-    m_view.luma_duration->setValidator(m_timecode.validator());
+    m_view.clip_duration->setInputMask(m_timecode.mask());
+    m_view.luma_duration->setInputMask(m_timecode.mask());
     m_view.luma_duration->setText(m_timecode.getTimecodeFromFrames(int(ceil(m_timecode.fps()))));
     m_view.folder_url->setUrl(QDir::homePath());
 
@@ -159,6 +157,7 @@ void SlideshowClip::slotEnableLumaFile(int state)
 }
 
 // static
+//TODO: sequence begin
 int SlideshowClip::sequenceCount(KUrl file)
 {
     // find pattern
@@ -177,12 +176,13 @@ int SlideshowClip::sequenceCount(KUrl file)
 
     // Find number of digits in sequence
     int precision = fullSize - filter.size();
+    int firstFrame = file.fileName().section('.', 0, -2).right(precision).toInt();    
     QString folder = file.directory(KUrl::AppendTrailingSlash);
     // Check how many files we have
     QDir dir(folder);
     QString path;
     int gap = 0;
-    for (int i = 0; gap < 100; i++) {
+    for (int i = firstFrame; gap < 100; i++) {
         path = filter + QString::number(i).rightJustified(precision, '0', false) + ext;
         if (dir.exists(path)) {
             count ++;
@@ -219,12 +219,13 @@ void SlideshowClip::parseFolder()
         filter = filter.section('.', 0, -2);
         int fullSize = filter.size();
         while (filter.at(filter.size() - 1).isDigit()) {
-            filter.remove(filter.size() - 1, 1);
+            filter.chop(1);
         }
         int precision = fullSize - filter.size();
+        int firstFrame = m_view.pattern_url->url().fileName().section('.', 0, -2).right(precision).toInt();
         QString path;
         int gap = 0;
-        for (int i = 0; gap < 100; i++) {
+        for (int i = firstFrame; gap < 100; i++) {
             path = filter + QString::number(i).rightJustified(precision, '0', false) + ext;
             if (dir.exists(path)) {
                 result.append(path);
@@ -299,6 +300,7 @@ QString SlideshowClip::selectedPath()
     else url = m_view.pattern_url->url();
     QString path = selectedPath(url, m_view.method_mime->isChecked(), ".all." + m_view.image_type->itemData(m_view.image_type->currentIndex()).toString(), &list);
     m_count = list.count();
+    kDebug()<<"// SELECTED PATH: "<<path;
     return path;
 }
 
@@ -326,6 +328,7 @@ QString SlideshowClip::selectedPath(KUrl url, bool isMime, QString extension, QS
         QString ext = '.' + filter.section('.', -1);
         filter = filter.section('.', 0, -2);
         int fullSize = filter.size();
+       QString firstFrameData = filter;
 
         while (filter.at(filter.size() - 1).isDigit()) {
             filter.chop(1);
@@ -333,12 +336,13 @@ QString SlideshowClip::selectedPath(KUrl url, bool isMime, QString extension, QS
 
         // Find number of digits in sequence
         int precision = fullSize - filter.size();
+       int firstFrame = firstFrameData.right(precision).toInt();
 
         // Check how many files we have
         QDir dir(folder);
         QString path;
         int gap = 0;
-        for (int i = 0; gap < 100; i++) {
+        for (int i = firstFrame; gap < 100; i++) {
             path = filter + QString::number(i).rightJustified(precision, '0', false) + ext;
             if (dir.exists(path)) {
                 (*list).append(folder + path);
@@ -347,7 +351,8 @@ QString SlideshowClip::selectedPath(KUrl url, bool isMime, QString extension, QS
                 gap++;
             }
         }
-        extension = filter + "%." + QString::number(precision) + "d" + ext;
+        if (firstFrame > 0) extension = filter + "%" + QString::number(firstFrame).rightJustified(precision, '0', false) + "d" + ext;
+        else extension = filter + "%" + QString::number(precision) + "d" + ext;
     }
     kDebug() << "// FOUND " << (*list).count() << " items for " << url.path();
     return  folder + extension;
@@ -423,11 +428,7 @@ void SlideshowClip::slotUpdateDurationFormat(int ix)
         m_view.luma_duration_frames->setValue(m_timecode.getFrameCount(m_view.luma_duration->text()));
     } else {
         // switching to timecode format
-        m_view.clip_duration->setInputMask("");
-        m_view.clip_duration->setValidator(m_timecode.validator());
         m_view.clip_duration->setText(m_timecode.getTimecodeFromFrames(m_view.clip_duration_frames->value()));
-        m_view.luma_duration->setInputMask("");
-        m_view.luma_duration->setValidator(m_timecode.validator());
         m_view.luma_duration->setText(m_timecode.getTimecodeFromFrames(m_view.luma_duration_frames->value()));
     }
     m_view.clip_duration_frames->setHidden(!framesFormat);
@@ -440,16 +441,12 @@ void SlideshowClip::slotMethodChanged(bool active)
 {
     if (active) {
         // User wants mimetype image sequence
-        if (m_view.clip_duration->text().isEmpty()) {
-            m_view.clip_duration->setText(m_timecode.reformatSeparators(KdenliveSettings::image_duration()));
-        }
+        m_view.clip_duration->setText(m_timecode.reformatSeparators(KdenliveSettings::image_duration()));
         m_view.stackedWidget->setCurrentIndex(0);
         KdenliveSettings::setSlideshowbymime(true);
     } else {
         // User wants pattern image sequence
-        if (m_view.clip_duration->text().isEmpty()) {
-            m_view.clip_duration->setText(m_timecode.reformatSeparators(KdenliveSettings::sequence_duration()));
-        }
+        m_view.clip_duration->setText(m_timecode.reformatSeparators(KdenliveSettings::sequence_duration()));
         m_view.stackedWidget->setCurrentIndex(1);
         KdenliveSettings::setSlideshowbymime(false);
     }
@@ -474,6 +471,7 @@ QString SlideshowClip::animationToGeometry(const QString &animation, int &ttl)
     return geometry;
 }
 
+
 #include "slideshowclip.moc"
 
 
index bcf1893445ff004addb42ee7ba3855328e496a25..dce24f469c1299294d45ef41d24718abd556e7cb 100644 (file)
@@ -35,10 +35,13 @@ SmallRuler::SmallRuler(MonitorManager *manager, QWidget *parent) :
         ,m_scale(1)
         ,m_maxval(25)
         ,m_manager(manager)
+        ,m_overCursor(false)
 {
     m_zoneStart = 10;
     m_zoneEnd = 60;
-    m_zoneColor = KStatefulBrush(KColorScheme::View, KColorScheme::PositiveBackground, KSharedConfig::openConfig(KdenliveSettings::colortheme())).brush(this).color();
+    KSharedConfigPtr config = KSharedConfig::openConfig(KdenliveSettings::colortheme());
+    m_zoneBrush = KStatefulBrush(KColorScheme::View, KColorScheme::PositiveBackground, config);
+
     setMouseTracking(true);
     setMinimumHeight(10);
 }
@@ -111,11 +114,35 @@ void SmallRuler::mousePressEvent(QMouseEvent * event)
     } else emit seekRenderer((int) pos);
 }
 
+void SmallRuler::leaveEvent( QEvent * event )
+{
+    Q_UNUSED(event);
+    if (m_overCursor) {
+        m_overCursor = false;
+        update();
+    }
+}
+
 // virtual
 void SmallRuler::mouseMoveEvent(QMouseEvent * event)
 {
     const int pos = event->x() / m_scale;
-    if (event->buttons() & Qt::LeftButton) emit seekRenderer((int) pos);
+    if (event->button() == Qt::NoButton) {
+        if (qAbs(pos * m_scale - m_cursorPosition) < 6) {
+            if (!m_overCursor) {
+                m_overCursor = true;
+                update();
+            }
+        }
+        else if (m_overCursor) {
+            m_overCursor = false;
+            update();
+        }
+    }
+    if (event->buttons() & Qt::LeftButton) {
+        m_overCursor = true;
+        emit seekRenderer((int) pos);
+    }
     else {
         if (qAbs((pos - m_zoneStart) * m_scale) < 4) {
             setToolTip(i18n("Zone start: %1", m_manager->timecode().getTimecodeFromFrames(m_zoneStart)));
@@ -160,7 +187,9 @@ void SmallRuler::updatePixmap()
 
     const int zoneStart = (int)(m_zoneStart * m_scale);
     const int zoneEnd = (int)(m_zoneEnd * m_scale);
-    p.fillRect(zoneStart, height() / 2 - 1, zoneEnd - zoneStart, height() / 2, m_zoneColor);
+    p.setPen(Qt::NoPen);
+    p.setBrush(m_zoneBrush.brush(this));
+    p.drawRect(zoneStart, height() / 2 - 1, zoneEnd - zoneStart, height() / 2);
 
     // draw ruler
     p.setPen(palette().text().color());
@@ -197,8 +226,9 @@ void SmallRuler::paintEvent(QPaintEvent *e)
 
     // draw pointer
     QPolygon pa(3);
-    pa.setPoints(3, m_cursorPosition - 5, 10, m_cursorPosition + 5, 10, m_cursorPosition/*+0*/, 5);
-    p.setBrush(palette().text().color());
+    pa.setPoints(3, m_cursorPosition - 6, 10, m_cursorPosition + 6, 10, m_cursorPosition/*+0*/, 4);
+    if (m_overCursor) p.setBrush(palette().highlight());
+    else p.setBrush(palette().text().color());
     p.setPen(Qt::NoPen);
     p.drawPolygon(pa);
 }
index 621ce75120ec013b8aabd5f808f46ed8c009e1bd..9d71758870b908a21eca1b14ef18983607e1381d 100644 (file)
 #ifndef SMALLRULER_H
 #define SMALLRULER_H
 
+#include <KColorScheme>
 #include <QWidget>
 
 #include "monitormanager.h"
 
+
 class SmallRuler : public QWidget
 {
     Q_OBJECT
@@ -33,6 +35,7 @@ public:
     SmallRuler(MonitorManager *manager, QWidget *parent = 0);
     virtual void mousePressEvent(QMouseEvent * event);
     virtual void mouseMoveEvent(QMouseEvent * event);
+    virtual void leaveEvent( QEvent * event );
     void adjustScale(int maximum);
     void setZone(int start, int end);
     QPoint zone();
@@ -52,10 +55,12 @@ private:
     int m_maxval;
     int m_zoneStart;
     int m_zoneEnd;
-    QColor m_zoneColor;
+    KStatefulBrush m_zoneBrush;
     QList <int> m_markers;
     QPixmap m_pixmap;
     MonitorManager *m_manager;
+    /** @brief True is mouse is over the ruler cursor. */
+    bool m_overCursor;
     void updatePixmap();
 
 public slots:
index f3251fa68306078c26fa9a8a132928e4fa956507..1201eca687f838f40b4f977a69a812c4b5f12d3f 100644 (file)
@@ -16,7 +16,9 @@
  ***************************************************************************/
 
 #include "stopmotion.h"
+#ifdef USE_BLACKMAGIC
 #include "blackmagic/devices.h"
+#endif
 #ifdef USE_V4L
 #include "v4l/v4lcapture.h"
 #endif
@@ -91,8 +93,8 @@ void MyLabel::paintEvent(QPaintEvent* event)
 }
 
 
-StopmotionMonitor::StopmotionMonitor(QWidget *parent) :
-    AbstractMonitor(parent),
+StopmotionMonitor::StopmotionMonitor(MonitorManager *manager, QWidget *parent) :
+    AbstractMonitor(Kdenlive::stopmotionMonitor, manager, parent),
     m_captureDevice(NULL)
 {
 }
@@ -101,6 +103,10 @@ StopmotionMonitor::~StopmotionMonitor()
 {
 }
 
+void StopmotionMonitor::slotSwitchFullScreen()
+{
+}
+
 void StopmotionMonitor::setRender(MltDeviceCapture *render)
 {
     m_captureDevice = render;
@@ -111,9 +117,9 @@ AbstractRender *StopmotionMonitor::abstractRender()
     return m_captureDevice;
 }
 
-const QString StopmotionMonitor::name() const
+Kdenlive::MONITORID StopmotionMonitor::id() const
 {
-    return QString("stopmotion");
+    return Kdenlive::stopmotionMonitor;
 }
 
 
@@ -127,6 +133,14 @@ void StopmotionMonitor::start()
 {
 }
 
+void StopmotionMonitor::slotPlay()
+{
+}
+
+void StopmotionMonitor::slotMouseSeek(int /*eventDelta*/, bool /*fast*/)
+{
+}
+
 StopmotionWidget::StopmotionWidget(MonitorManager *manager, KUrl projectFolder, QList< QAction* > actions, QWidget* parent) :
     QDialog(parent)
     , Ui::Stopmotion_UI()
@@ -136,7 +150,7 @@ StopmotionWidget::StopmotionWidget(MonitorManager *manager, KUrl projectFolder,
     , m_animatedIndex(-1)
     , m_animate(false)
     , m_manager(manager)
-    , m_monitor(new StopmotionMonitor(this))
+    , m_monitor(new StopmotionMonitor(manager, this))
 {
     //setAttribute(Qt::WA_DeleteOnClose);
     //HACK: the monitor widget is hidden, it is just used to control the capturedevice from monitormanager
@@ -244,17 +258,14 @@ StopmotionWidget::StopmotionWidget(MonitorManager *manager, KUrl projectFolder,
     QVBoxLayout *layout = new QVBoxLayout;
     layout->setContentsMargins(0, 0, 0, 0);
     layout->setSpacing(0);
-    m_videoBox = new VideoPreviewContainer();
-    m_videoBox->setContentsMargins(0, 0, 0, 0);
-    m_videoBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
-    //m_videoBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
-    m_videoBox->setLineWidth(4);
-    layout->addWidget(m_videoBox);
-
+    m_monitor->videoBox->setLineWidth(4);
+    layout->addWidget(m_monitor->videoBox);
 
+#ifdef USE_BLACKMAGIC
     if (BMInterface::getBlackMagicDeviceList(capture_device)) {
         // Found a BlackMagic device
     }
+#endif
     if (QFile::exists(KdenliveSettings::video4vdevice())) {
 #ifdef USE_V4L
         // Video 4 Linux device detection
@@ -299,7 +310,7 @@ StopmotionWidget::StopmotionWidget(MonitorManager *manager, KUrl projectFolder,
         profilePath = KdenliveSettings::current_profile();
     }
 
-    m_captureDevice = new MltDeviceCapture(profilePath, m_videoBox, this);
+    m_captureDevice = new MltDeviceCapture(profilePath, m_monitor->videoSurface, this);
     m_captureDevice->sendFrameForAnalysis = KdenliveSettings::analyse_stopmotion();
     m_monitor->setRender(m_captureDevice);
     connect(m_captureDevice, SIGNAL(frameSaved(const QString &)), this, SLOT(slotNewThumb(const QString &)));
@@ -459,7 +470,7 @@ void StopmotionWidget::slotLive(bool isOn)
     capture_button->setEnabled(false);
     if (isOn) {
         m_frame_preview->setHidden(true);
-        m_videoBox->setHidden(false);
+        m_monitor->videoBox->setHidden(false);
         QLocale locale;
 
         MltVideoProfile profile;
@@ -484,13 +495,13 @@ void StopmotionWidget::slotLive(bool isOn)
         }
 
         if (m_captureDevice == NULL) {
-            m_captureDevice = new MltDeviceCapture(profilePath, m_videoBox, this);
+            m_captureDevice = new MltDeviceCapture(profilePath, m_monitor->videoSurface, this);
             m_captureDevice->sendFrameForAnalysis = KdenliveSettings::analyse_stopmotion();
             m_monitor->setRender(m_captureDevice);
             connect(m_captureDevice, SIGNAL(frameSaved(const QString &)), this, SLOT(slotNewThumb(const QString &)));
         }
 
-        m_manager->activateMonitor("stopmotion");
+        m_manager->activateMonitor(Kdenlive::stopmotionMonitor);
         QString producer = createProducer(profile, service, resource);
         if (m_captureDevice->slotStartPreview(producer, true)) {
             if (m_showOverlay->isChecked()) {
@@ -513,7 +524,7 @@ void StopmotionWidget::slotLive(bool isOn)
         live_button->setChecked(false);
         if (m_captureDevice) {
             m_captureDevice->stop();
-            m_videoBox->setHidden(true);
+            m_monitor->videoBox->setHidden(true);
             log_box->insertItem(-1, i18n("Stopped"));
             log_box->setCurrentIndex(0);
             //delete m_captureDevice;
@@ -882,6 +893,7 @@ void StopmotionWidget::slotSwitchMirror(bool isOn)
     if (m_captureDevice) m_captureDevice->mirror(isOn);
 }
 
+
 const QString StopmotionWidget::createProducer(MltVideoProfile profile, const QString &service, const QString &resource)
 {
     Q_UNUSED(profile)
index 3e115276c5d3102d80d2ca1b185f1fc518ce0a24..124b11670abbb1d3e18c4deed6678d4105a0d6b7 100644 (file)
@@ -19,6 +19,7 @@
 #define STOPMOTION_H
 
 #include "ui_stopmotion_ui.h"
+#include "definitions.h"
 
 #include <KUrl>
 #include <QLabel>
@@ -61,18 +62,21 @@ class StopmotionMonitor : public AbstractMonitor
 {
     Q_OBJECT
 public:
-    StopmotionMonitor(QWidget *parent);
+    StopmotionMonitor(MonitorManager *manager, QWidget *parent);
     ~StopmotionMonitor();
     AbstractRender *abstractRender();
-    const QString name() const;
+    Kdenlive::MONITORID id() const;
     void setRender(MltDeviceCapture *render);
 
 private:
     MltDeviceCapture *m_captureDevice;
 
 public slots:
-    virtual void stop();
-    virtual void start();
+    void stop();
+    void start();
+    void slotPlay();
+    void slotMouseSeek(int eventDelta, bool fast);
+    void slotSwitchFullScreen();
 
 signals:
     void stopCapture();
@@ -102,7 +106,7 @@ private:
     /** @brief Capture holder that will handle all video operation. */
     MltDeviceCapture *m_captureDevice;
 
-    VideoPreviewContainer *m_videoBox;
+    VideoContainer *m_videoBox;
 
     /** @brief Holds the name of the current sequence.
      * Files will be saved in project folder with name: sequence001.png */
index 89063dd33e6e9ed2ab88623cd639552dfaeaf2d0..08d524d13b274eabfa2bc52c8a39eb8e91b2a13d 100644 (file)
@@ -80,7 +80,6 @@ return frameNumber;
 */
 
 
-#include <QValidator>
 
 #include <KDebug>
 #include <KLocale>
@@ -89,7 +88,6 @@ return frameNumber;
 
 Timecode::Timecode(Formats format, double framesPerSecond)
 {
-    m_validator = new QRegExpValidator(0);
     setFormat(framesPerSecond, format);
 }
 
@@ -107,12 +105,6 @@ void Timecode::setFormat(double framesPerSecond, Formats format)
         m_dropFrames = round(m_realFps * .066666); //Number of frames to drop on the minute marks is the nearest integer to 6% of the framerate
         m_framesPer10Minutes = round(m_realFps * 600); //Number of frames per ten minutes
     }
-    QRegExp regExp;
-    if (m_dropFrameTimecode)
-        regExp.setPattern("^\\d{2}:\\d{2}:\\d{2};\\d{2}$");
-    else
-        regExp.setPattern("^\\d{2}:\\d{2}:\\d{2}:\\d{2}$");
-    m_validator->setRegExp(regExp);
 }
 
 double Timecode::fps() const
@@ -125,15 +117,20 @@ bool Timecode::df() const
     return m_dropFrameTimecode;
 }
 
-const QValidator *Timecode::validator() const
+const QString Timecode::mask(GenTime t) const
 {
-    return m_validator;
+    if (t < GenTime()) {
+        if (m_dropFrameTimecode) return "#99:99:99,99";
+        else return "#99:99:99:99";
+    }
+    if (m_dropFrameTimecode) return "99:99:99,99";
+    else return "99:99:99:99";
 }
 
 QString Timecode::reformatSeparators(QString duration) const
 {
     if (m_dropFrameTimecode)
-        return duration.replace(8, 1, ';');
+        return duration.replace(8, 1, ',');
     return duration.replace(8, 1, ':');
 }
 
@@ -145,31 +142,30 @@ int Timecode::getDisplayFrameCount(const QString &duration, bool frameDisplay) c
 
 int Timecode::getFrameCount(const QString &duration) const
 {
+    if (duration.isEmpty()) {
+        return 0;
+    }
+    int hours, minutes, seconds, frames;
+    int offset = 0;
+    if (duration.at(0) == '-') {
+        offset = 1;
+        hours = duration.mid(1, 2).toInt();
+    } else {
+        hours = duration.left(2).toInt();
+    }
+    minutes = duration.mid(3 + offset, 2).toInt();
+    seconds = duration.mid(6 + offset, 2).toInt();
+    frames = duration.right(2).toInt();
     if (m_dropFrameTimecode) {
-
         //CONVERT DROP FRAME TIMECODE TO A FRAME NUMBER
         //Code by David Heidelberger, adapted from Andrew Duncan
         //Given ints called hours, minutes, seconds, frames, and a double called framerate
 
-        //Get Hours, Minutes, Seconds, Frames from timecode
-        int hours, minutes, seconds, frames;
-
-        hours = duration.section(':', 0, 0).toInt();
-        minutes = duration.section(':', 1, 1).toInt();
-        if (duration.contains(';')) {
-            seconds = duration.section(';', 0, 0).section(':', 2, 2).toInt();
-            frames = duration.section(';', 1, 1).toInt();
-        } else {
-            //Handle Drop Frame timecode frame calculations, even if the timecode supplied uses incorrect "99:99:99:99" format instead of "99:99:99;99"
-            seconds = duration.section(':', 2, 2).toInt();
-            frames = duration.section(':', 3, 3).toInt();
-        }
-
         int totalMinutes = (60 * hours) + minutes; //Total number of minutes
         int frameNumber = ((m_displayedFramesPerSecond * 3600 * hours) + (m_displayedFramesPerSecond * 60 * minutes) + (m_displayedFramesPerSecond * seconds) + frames) - (m_dropFrames * (totalMinutes - floor(totalMinutes / 10)));
         return frameNumber;
     }
-    return (int)((duration.section(':', 0, 0).toInt()*3600.0 + duration.section(':', 1, 1).toInt()*60.0 + duration.section(':', 2, 2).toInt()) * m_realFps + duration.section(':', 3, 3).toInt());
+    return (int)((hours * 3600.0 + minutes * 60.0 + seconds) * m_realFps + frames);
 }
 
 QString Timecode::getDisplayTimecode(const GenTime & time, bool frameDisplay) const
@@ -214,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
 
@@ -225,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;
@@ -237,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;
 }
 
@@ -364,7 +365,7 @@ const QString Timecode::getTimecodeHH_MM_SS_HH(const GenTime & time) const
     text.append(':');
     text.append(QString::number(seconds).rightJustified(2, '0', false));
     if (m_dropFrameTimecode)
-        text.append(';');
+        text.append(',');
     else
         text.append(':');
     text.append(QString::number(hundredths).rightJustified(2, '0', false));
@@ -423,7 +424,7 @@ const QString Timecode::getTimecodeDropFrame(int framenumber) const
     text.append(QString::number(minutes).rightJustified(2, '0', false));
     text.append(':');
     text.append(QString::number(seconds).rightJustified(2, '0', false));
-    text.append(';');
+    text.append(',');
     text.append(QString::number(frames).rightJustified(2, '0', false));
 
     return text;
index 7c2d26921f7ac7bf7ef26e001fec18988e238047..35a6f41e87df791254ceb6f7950fe68e0cee2be7 100644 (file)
@@ -21,9 +21,6 @@
 
 #include "gentime.h"
 
-class QValidator;
-class QRegExpValidator;
-
 /**
 Handles the conversion of a GenTime into a nicely formatted string, taking into account things such as drop frame if necessary. Handles multiple formats, such as HH:MM:SS:FF, HH:MM:SS:F, All Frames, All Seconds, etc.
 
@@ -53,12 +50,12 @@ 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;
     bool df() const;
-    const QValidator *validator() const;
+    const QString mask(GenTime t = GenTime()) const;
     QString reformatSeparators(QString duration) const;
 
 private:
@@ -68,7 +65,6 @@ private:
     double m_realFps;
     double m_dropFrames;
     int m_framesPer10Minutes;
-    QRegExpValidator *m_validator;
 
     const QString getTimecodeHH_MM_SS_FF(const GenTime & time) const;
     const QString getTimecodeHH_MM_SS_FF(int frames) const;
index c4b77a4a3a15a9475583dfcd016965ff86accded..93cf6d84ea2cdbe779957dcf5d8dc3c611872217 100644 (file)
@@ -51,26 +51,26 @@ TimecodeDisplay::TimecodeDisplay(Timecode t, QWidget *parent)
     setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
     setAccelerated(true);
 
+    setValue(m_minimum);
+
     setTimeCodeFormat(KdenliveSettings::frametimecode(), true);
 
     connect(lineEdit(), SIGNAL(editingFinished()), this, SLOT(slotEditingFinished()));
-    connect(lineEdit(), SIGNAL(cursorPositionChanged(int, int)), this, SLOT(slotCursorPositionChanged(int, int)));
 }
 
 // virtual protected
 QAbstractSpinBox::StepEnabled TimecodeDisplay::stepEnabled () const
 {
     QAbstractSpinBox::StepEnabled result = QAbstractSpinBox::StepNone;
-    if (getValue() > m_minimum) result |= QAbstractSpinBox::StepDownEnabled;
-    if (m_maximum == -1 || getValue() < m_maximum) result |= QAbstractSpinBox::StepUpEnabled;
+    if (m_value > m_minimum) result |= QAbstractSpinBox::StepDownEnabled;
+    if (m_maximum == -1 || m_value < m_maximum) result |= QAbstractSpinBox::StepUpEnabled;
     return result;
 }
 
 // virtual
 void TimecodeDisplay::stepBy(int steps)
 {
-    int val = getValue();
-    val += steps;
+    int val = m_value + steps;
     setValue(val);
     emit editingFinished();
 }
@@ -78,16 +78,18 @@ void TimecodeDisplay::stepBy(int steps)
 void TimecodeDisplay::setTimeCodeFormat(bool frametimecode, bool init)
 {
     if (!init && m_frametimecode == frametimecode) return;
-    int val = getValue();
     m_frametimecode = frametimecode;
+    lineEdit()->clear();
     if (m_frametimecode) {
         QIntValidator *valid = new QIntValidator(lineEdit());
         valid->setBottom(0);
         lineEdit()->setValidator(valid);
+        lineEdit()->setInputMask(QString());
     } else {
-        lineEdit()->setValidator(m_timecode.validator());
+        lineEdit()->setValidator(0);
+        lineEdit()->setInputMask(m_timecode.mask());
     }
-    setValue(val);
+    setValue(m_value);
 }
 
 void TimecodeDisplay::slotUpdateTimeCodeFormat()
@@ -103,8 +105,10 @@ void TimecodeDisplay::updateTimeCode(Timecode t)
 
 void TimecodeDisplay::keyPressEvent(QKeyEvent *e)
 {
-    if (e->key() == Qt::Key_Return)
-        slotEditingFinished();
+    if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
+        e->setAccepted(true);
+        clearFocus();
+    }
     else
         QAbstractSpinBox::keyPressEvent(e);
 }
@@ -139,13 +143,12 @@ int TimecodeDisplay::minimum() const
 
 int TimecodeDisplay::getValue() const
 {
-    if (m_frametimecode) return lineEdit()->text().toInt();
-    else return m_timecode.getFrameCount(lineEdit()->text());
+    return m_value;
 }
 
 GenTime TimecodeDisplay::gentime() const
 {
-    return GenTime(getValue(), m_timecode.fps());
+    return GenTime(m_value, m_timecode.fps());
 }
 
 Timecode TimecodeDisplay::timecode() const
@@ -170,10 +173,8 @@ void TimecodeDisplay::setValue(int value)
         value = m_minimum;
     if (m_maximum > m_minimum && value > m_maximum)
         value = m_maximum;
-
-    if (value == getValue() && !lineEdit()->text().isEmpty()) return;
-    //downarrow->setEnabled(value > m_minimum);
-    //uparrow->setEnabled(m_maximum < m_minimum || value < m_maximum);
+    if (value == m_value && !lineEdit()->text().isEmpty()) return;
+    m_value = value;
 
     if (m_frametimecode)
         lineEdit()->setText(QString::number(value));
@@ -185,36 +186,15 @@ void TimecodeDisplay::setValue(int value)
 
 void TimecodeDisplay::setValue(GenTime value)
 {
-    setValue(m_timecode.getTimecode(value));
+    setValue((int) value.frames(m_timecode.fps()));
 }
 
-void TimecodeDisplay::slotCursorPositionChanged(int oldPos, int newPos)
-{
-    if (!lineEdit()->hasFocus()) return;
-    lineEdit()->blockSignals(true);
-    QString text = lineEdit()->text();
-
-    if (newPos < text.size() && !text.at(newPos).isDigit()) {
-        // char at newPos is a separator (':' or ';')
-
-        // make it possible move the cursor backwards at separators
-        if (newPos == oldPos - 1)
-            lineEdit()->setSelection(newPos, -1);
-        else
-            lineEdit()->setSelection(newPos + 2, -1);
-    } else if (newPos < text.size()) {
-        lineEdit()->setSelection(newPos + 1, -1);
-    } else {
-        lineEdit()->setSelection(newPos, -1);
-    }
-
-    lineEdit()->blockSignals(false);
-}
 
 void TimecodeDisplay::slotEditingFinished()
 {
-    clearFocus();
     lineEdit()->deselect();
+    if (m_frametimecode) setValue(lineEdit()->text().toInt());
+    else setValue(lineEdit()->text());
     emit editingFinished();
 }
 
index a18f757f08ddb464db497d33b7c06375be83bb61..484841da3c4d957310f1b06cb5fc3143086686b7 100644 (file)
@@ -83,6 +83,7 @@ private:
     bool m_frametimecode;
     int m_minimum;
     int m_maximum;
+    int m_value;
 
 public slots:
     /** @brief Sets the value.
@@ -99,11 +100,6 @@ public slots:
 private slots:
     void slotEditingFinished();
 
-    /** @brief Updates the selection when the cursor position changed.
-     * The digit after the cursor will be selected.
-     * This makes it easier to edit the timecode. */
-    void slotCursorPositionChanged(int oldPos, int newPos);
-
 signals:
     /**
      * Emitted every time the value changes (by calling setValue() or
index 0ebc42fd0992fedbbd2e91d63b42af00d48e559b..dc198f2e6d0132820fb4e1a593a5caf4fc5ec906 100644 (file)
@@ -171,7 +171,11 @@ QDomDocument TitleDocument::xml(QGraphicsRectItem* startv, QGraphicsRectItem* en
                 QColor fontcolor = cursor.charFormat().foreground().color();
                 content.setAttribute("font-color", colorToString(fontcolor));
                 if (!t->data(101).isNull()) content.setAttribute("font-outline", t->data(101).toDouble());
-                if (!t->data(102).isNull()) content.setAttribute("font-outline-color", colorToString(QColor(t->data(102).toString())));
+                if (!t->data(102).isNull()) {
+                    QVariant variant = t->data(102);
+                    QColor outlineColor = variant.value<QColor>();
+                    content.setAttribute("font-outline-color", colorToString(outlineColor));
+                }
             }
             if (!t->data(100).isNull()) {
                 QStringList effectParams = t->data(100).toStringList();
index 5a00bd44077f27038df4f335e848c44fc9fc666a..e1a87c4eaac84d12515f052561c6e11451fae7eb 100644 (file)
@@ -78,6 +78,33 @@ TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render
     setFont(KGlobalSettings::toolBarFont());
     frame_properties->setEnabled(false);
     frame_properties->setFixedHeight(frame_toolbar->height());
+    int size = style()->pixelMetric(QStyle::PM_SmallIconSize);
+    QSize iconSize(size, size);
+
+#if KDE_IS_VERSION(4,5,0)
+    rectBColor->setAlphaChannelEnabled(true);
+    delete rectBAlpha;
+    rectFColor->setAlphaChannelEnabled(true);
+    delete rectFAlpha;
+    fontColorButton->setAlphaChannelEnabled(true);
+    delete textAlpha;
+    textOutlineColor->setAlphaChannelEnabled(true);
+    delete textOutlineAlpha;
+    
+#else
+    rectBAlpha->setMinimum(0);
+    rectBAlpha->setMaximum(255);
+    rectBAlpha->setDecimals(0);
+    rectBAlpha->setValue(255);
+    rectBAlpha->setToolTip(i18n("Color opacity"));
+
+    rectFAlpha->setMinimum(0);
+    rectFAlpha->setMaximum(255);
+    rectFAlpha->setDecimals(0);
+    rectFAlpha->setValue(255);
+    rectFAlpha->setToolTip(i18n("Border opacity"));
+    connect(rectFAlpha, SIGNAL(valueChanged(qreal, bool)), this, SLOT(rectChanged()));
+    connect(rectBAlpha, SIGNAL(valueChanged(qreal, bool)), this, SLOT(rectChanged()));
 
     // Set combo sliders values
     textAlpha->setMinimum(0);
@@ -91,6 +118,9 @@ TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render
     textOutlineAlpha->setDecimals(0);
     textOutlineAlpha->setValue(255);
     textOutlineAlpha->setToolTip(i18n("Outline color opacity"));
+    connect(textAlpha, SIGNAL(valueChanged(qreal, bool)), this, SLOT(slotUpdateText()));
+    connect(textOutlineAlpha, SIGNAL(valueChanged(qreal, bool)), this, SLOT(slotUpdateText()));
+#endif
 
     textOutline->setMinimum(0);
     textOutline->setMaximum(200);
@@ -122,18 +152,6 @@ TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render
     itemrotatez->setValue(0);
     itemrotatez->setToolTip(i18n("Rotation around the Z axis"));
 
-    rectBAlpha->setMinimum(0);
-    rectBAlpha->setMaximum(255);
-    rectBAlpha->setDecimals(0);
-    rectBAlpha->setValue(255);
-    rectBAlpha->setToolTip(i18n("Color opacity"));
-
-    rectFAlpha->setMinimum(0);
-    rectFAlpha->setMaximum(255);
-    rectFAlpha->setDecimals(0);
-    rectFAlpha->setValue(255);
-    rectFAlpha->setToolTip(i18n("Border opacity"));
-
     rectLineWidth->setMinimum(0);
     rectLineWidth->setMaximum(100);
     rectLineWidth->setDecimals(0);
@@ -148,28 +166,23 @@ TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render
     splitter->setStretchFactor(0, 20);
 
     //If project is drop frame, set the input mask as such.
-    title_duration->setInputMask("");
-    title_duration->setValidator(m_tc.validator());
+    title_duration->setInputMask(m_tc.mask());
     title_duration->setText(m_tc.reformatSeparators(KdenliveSettings::title_duration()));
 
     connect(backgroundColor, SIGNAL(clicked()), this, SLOT(slotChangeBackground())) ;
     connect(backgroundAlpha, SIGNAL(valueChanged(qreal, bool)), this, SLOT(slotChangeBackground())) ;
 
-    connect(fontColorButton, SIGNAL(clicked()), this, SLOT(slotUpdateText())) ;
-    connect(textOutlineColor, SIGNAL(clicked()), this, SLOT(slotUpdateText())) ;
+    connect(fontColorButton, SIGNAL(changed(const QColor &)), this, SLOT(slotUpdateText())) ;
+    connect(textOutlineColor, SIGNAL(changed(const QColor &)), this, SLOT(slotUpdateText())) ;
     connect(font_family, SIGNAL(currentFontChanged(const QFont &)), this, SLOT(slotUpdateText())) ;
     connect(font_size, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateText())) ;
-    connect(textAlpha, SIGNAL(valueChanged(qreal, bool)), this, SLOT(slotUpdateText()));
     connect(textOutline, SIGNAL(valueChanged(qreal, bool)), this, SLOT(slotUpdateText()));
-    connect(textOutlineAlpha, SIGNAL(valueChanged(qreal, bool)), this, SLOT(slotUpdateText()));
     connect(font_weight_box, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateText()));
 
     connect(font_family, SIGNAL(editTextChanged(const QString &)), this, SLOT(slotFontText(const QString&)));
 
-    connect(rectFAlpha, SIGNAL(valueChanged(qreal, bool)), this, SLOT(rectChanged()));
-    connect(rectBAlpha, SIGNAL(valueChanged(qreal, bool)), this, SLOT(rectChanged()));
-    connect(rectFColor, SIGNAL(clicked()), this, SLOT(rectChanged()));
-    connect(rectBColor, SIGNAL(clicked()), this, SLOT(rectChanged()));
+    connect(rectFColor, SIGNAL(changed(const QColor &)), this, SLOT(rectChanged()));
+    connect(rectBColor, SIGNAL(changed(const QColor &)), this, SLOT(rectChanged()));
     connect(rectLineWidth, SIGNAL(valueChanged(qreal, bool)), this, SLOT(rectChanged()));
 
     /*connect(startViewportX, SIGNAL(valueChanged(int)), this, SLOT(setupViewports()));
@@ -246,6 +259,15 @@ TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render
     font_weight_box->setCurrentIndex(1);
     font_weight_box->blockSignals(false);
 
+    buttonFitZoom->setIconSize(iconSize);
+    buttonRealSize->setIconSize(iconSize);
+    buttonItalic->setIconSize(iconSize);
+    buttonUnder->setIconSize(iconSize);
+    buttonAlignCenter->setIconSize(iconSize);
+    buttonAlignLeft->setIconSize(iconSize);
+    buttonAlignRight->setIconSize(iconSize);
+    buttonAlignNone->setIconSize(iconSize);
+    
     buttonFitZoom->setIcon(KIcon("zoom-fit-best"));
     buttonRealSize->setIcon(KIcon("zoom-original"));
     buttonItalic->setIcon(KIcon("format-text-italic"));
@@ -322,6 +344,10 @@ TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render
     buttonUnselectAll->setDefaultAction(m_unselectAll);
     buttonUnselectAll->setEnabled(false);
 
+    zDown->setIconSize(iconSize);
+    zTop->setIconSize(iconSize);
+    zBottom->setIconSize(iconSize);
+    
     zDown->setIcon(KIcon("kdenlive-zindex-down"));
     zTop->setIcon(KIcon("kdenlive-zindex-top"));
     zBottom->setIcon(KIcon("kdenlive-zindex-bottom"));
@@ -333,8 +359,6 @@ TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render
     origin_y_top->setToolTip(i18n("Invert y axis and change 0 point"));
     rectBColor->setToolTip(i18n("Select fill color"));
     rectFColor->setToolTip(i18n("Select border color"));
-    rectBAlpha->setToolTip(i18n("Fill opacity"));
-    rectFAlpha->setToolTip(i18n("Border opacity"));
     zoom_slider->setToolTip(i18n("Zoom"));
     buttonRealSize->setToolTip(i18n("Original size (1:1)"));
     buttonFitZoom->setToolTip(i18n("Fit zoom"));
@@ -346,6 +370,13 @@ TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render
     buttonSelectImages->setToolTip(getTooltipWithShortcut(i18n("Select image items in current selection"), m_selectImages));
     buttonUnselectAll->setToolTip(getTooltipWithShortcut(i18n("Unselect all"), m_unselectAll));
 
+    itemhcenter->setIconSize(iconSize);
+    itemvcenter->setIconSize(iconSize);
+    itemtop->setIconSize(iconSize);
+    itembottom->setIconSize(iconSize);
+    itemright->setIconSize(iconSize);
+    itemleft->setIconSize(iconSize);
+    
     itemhcenter->setIcon(KIcon("kdenlive-align-hor"));
     itemhcenter->setToolTip(i18n("Align item horizontally"));
     itemvcenter->setIcon(KIcon("kdenlive-align-vert"));
@@ -364,8 +395,7 @@ TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render
     frame_toolbar->setLayout(layout);
     layout->setContentsMargins(0, 0, 0, 0);
     QToolBar *m_toolbar = new QToolBar("titleToolBar", this);
-    int s = style()->pixelMetric(QStyle::PM_SmallIconSize);
-    m_toolbar->setIconSize(QSize(s, s));
+    m_toolbar->setIconSize(iconSize);
 
     m_buttonCursor = m_toolbar->addAction(KIcon("transform-move"), QString());
     m_buttonCursor->setCheckable(true);
@@ -486,6 +516,7 @@ TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render
         templateBox->addItem(t.icon, t.name, t.file);
     }
     lastDocumentHash = QCryptographicHash::hash(xml().toString().toAscii(), QCryptographicHash::Md5).toHex();
+    adjustSize();
 }
 
 TitleWidget::~TitleWidget()
@@ -516,6 +547,12 @@ TitleWidget::~TitleWidget()
     delete m_signalMapper;
 }
 
+QSize TitleWidget::sizeHint() const
+{
+    // Make sure the widget has minimum size on opening
+    return QSize(200, 200);
+}
+
 //static
 QStringList TitleWidget::getFreeTitleInfo(const KUrl &projectUrl, bool isClone)
 {
@@ -852,13 +889,17 @@ void TitleWidget::slotNewRect(QGraphicsRectItem * rect)
     updateAxisButtons(rect); // back to default
 
     QColor f = rectFColor->color();
+#if not KDE_IS_VERSION(4,5,0)
     f.setAlpha(rectFAlpha->value());
+#endif
     QPen penf(f);
     penf.setWidth(rectLineWidth->value());
     penf.setJoinStyle(Qt::RoundJoin);
     rect->setPen(penf);
     QColor b = rectBColor->color();
+#if not KDE_IS_VERSION(4,5,0)
     b.setAlpha(rectBAlpha->value());
+#endif
     rect->setBrush(QBrush(b));
     rect->setZValue(m_count++);
     rect->setData(ZOOMFACTOR, 100);
@@ -879,15 +920,17 @@ void TitleWidget::slotNewText(QGraphicsTextItem *tt)
 
     tt->setFont(font);
     QColor color = fontColorButton->color();
+    QColor outlineColor = textOutlineColor->color();
+#if not KDE_IS_VERSION(4,5,0)    
     color.setAlpha(textAlpha->value());
+    outlineColor.setAlpha(textOutlineAlpha->value());
+#endif
     tt->setDefaultTextColor(color);
 
     QTextCursor cur(tt->document());
     cur.select(QTextCursor::Document);
     QTextBlockFormat format = cur.blockFormat();
     QTextCharFormat cformat = cur.charFormat();
-    QColor outlineColor = textOutlineColor->color();
-    outlineColor.setAlpha(textOutlineAlpha->value());
     double outlineWidth = textOutline->value() / 10.0;
 
     tt->setData(101, outlineWidth);
@@ -1504,10 +1547,12 @@ void TitleWidget::slotUpdateText()
     font.setUnderline(buttonUnder->isChecked());
     font.setWeight(font_weight_box->itemData(font_weight_box->currentIndex()).toInt());
     QColor color = fontColorButton->color();
-    color.setAlpha(textAlpha->value());
-
     QColor outlineColor = textOutlineColor->color();
+#if not KDE_IS_VERSION(4,5,0)
+    color.setAlpha(textAlpha->value());
     outlineColor.setAlpha(textOutlineAlpha->value());
+#endif
+
     double outlineWidth = textOutline->value() / 10.0;
 
     int i;
@@ -1562,13 +1607,17 @@ void TitleWidget::rectChanged()
         if (l.at(i)->type() == RECTITEM && !settingUp) {
             QGraphicsRectItem *rec = static_cast<QGraphicsRectItem *>(l.at(i));
             QColor f = rectFColor->color();
+#if not KDE_IS_VERSION(4,5,0)
             f.setAlpha(rectFAlpha->value());
+#endif
             QPen penf(f);
             penf.setWidth(rectLineWidth->value());
             penf.setJoinStyle(Qt::RoundJoin);
             rec->setPen(penf);
             QColor b = rectBColor->color();
+#if not KDE_IS_VERSION(4,5,0)
             b.setAlpha(rectBAlpha->value());
+#endif
             rec->setBrush(QBrush(b));
         }
     }
@@ -1909,18 +1958,31 @@ void TitleWidget::writeChoices()
     //titleConfig.writeEntry("font_size", font_size->value());
     titleConfig.writeEntry("font_pixel_size", font_size->value());
     titleConfig.writeEntry("font_color", fontColorButton->color());
-    titleConfig.writeEntry("font_alpha", textAlpha->value());
-    titleConfig.writeEntry("font_outline", textOutline->value());
     titleConfig.writeEntry("font_outline_color", textOutlineColor->color());
+#if KDE_IS_VERSION(4,5,0)
+    titleConfig.writeEntry("font_alpha", fontColorButton->color().alpha());
+    titleConfig.writeEntry("font_outline_alpha", textOutlineColor->color().alpha());
+#else
+    titleConfig.writeEntry("font_alpha", textAlpha->value());
     titleConfig.writeEntry("font_outline_alpha", textOutlineAlpha->value());
+#endif
+   
+    titleConfig.writeEntry("font_outline", textOutline->value());
     titleConfig.writeEntry("font_weight", font_weight_box->itemData(font_weight_box->currentIndex()).toInt());
     titleConfig.writeEntry("font_italic", buttonItalic->isChecked());
     titleConfig.writeEntry("font_underlined", buttonUnder->isChecked());
 
-    titleConfig.writeEntry("rect_foreground_color", rectFColor->color());
-    titleConfig.writeEntry("rect_foreground_alpha", rectFAlpha->value());
     titleConfig.writeEntry("rect_background_color", rectBColor->color());
+    titleConfig.writeEntry("rect_foreground_color", rectFColor->color());
+
+#if KDE_IS_VERSION(4,5,0)
+    titleConfig.writeEntry("rect_background_alpha", rectBColor->color().alpha());
+    titleConfig.writeEntry("rect_foreground_alpha", rectFColor->color().alpha());
+#else
     titleConfig.writeEntry("rect_background_alpha", rectBAlpha->value());
+    titleConfig.writeEntry("rect_foreground_alpha", rectFAlpha->value());
+#endif
+
     titleConfig.writeEntry("rect_line_width", rectLineWidth->value());
 
     titleConfig.writeEntry("background_color", backgroundColor->color());
@@ -1940,11 +2002,17 @@ void TitleWidget::readChoices()
     font_family->setCurrentFont(titleConfig.readEntry("font_family", font_family->currentFont()));
     font_size->setValue(titleConfig.readEntry("font_pixel_size", font_size->value()));
     m_scene->slotUpdateFontSize(font_size->value());
-    fontColorButton->setColor(titleConfig.readEntry("font_color", fontColorButton->color()));
+    QColor fontColor = QColor(titleConfig.readEntry("font_color", fontColorButton->color()));
+    QColor outlineColor = QColor(titleConfig.readEntry("font_outline_color", textOutlineColor->color()));
+#if KDE_IS_VERSION(4,5,0)
+    fontColor.setAlpha(titleConfig.readEntry("font_alpha", fontColor.alpha()));
+    outlineColor.setAlpha(titleConfig.readEntry("font_outline_alpha", outlineColor.alpha()));
+#else
     textAlpha->setValue(titleConfig.readEntry("font_alpha", textAlpha->value()));
-
-    textOutlineColor->setColor(titleConfig.readEntry("font_outline_color", textOutlineColor->color()));
     textOutlineAlpha->setValue(titleConfig.readEntry("font_outline_alpha", textOutlineAlpha->value()));
+#endif
+    fontColorButton->setColor(fontColor);
+    textOutlineColor->setColor(outlineColor);
     textOutline->setValue(titleConfig.readEntry("font_outline", textOutline->value()));
 
     int weight;
@@ -1954,10 +2022,19 @@ void TitleWidget::readChoices()
     buttonItalic->setChecked(titleConfig.readEntry("font_italic", buttonItalic->isChecked()));
     buttonUnder->setChecked(titleConfig.readEntry("font_underlined", buttonUnder->isChecked()));
 
-    rectFColor->setColor(titleConfig.readEntry("rect_foreground_color", rectFColor->color()));
+    QColor fgColor = QColor(titleConfig.readEntry("rect_foreground_color", rectFColor->color()));
+    QColor bgColor = QColor(titleConfig.readEntry("rect_background_color", rectBColor->color()));
+
+#if KDE_IS_VERSION(4,5,0)
+    fgColor.setAlpha(titleConfig.readEntry("rect_background_alpha", fgColor.alpha()));
+    bgColor.setAlpha(titleConfig.readEntry("rect_background_alpha", bgColor.alpha()));
+#else
     rectFAlpha->setValue(titleConfig.readEntry("rect_foreground_alpha", rectFAlpha->value()));
-    rectBColor->setColor(titleConfig.readEntry("rect_background_color", rectBColor->color()));
     rectBAlpha->setValue(titleConfig.readEntry("rect_background_alpha", rectBAlpha->value()));
+#endif
+    rectFColor->setColor(fgColor);
+    rectBColor->setColor(bgColor);
+
     rectLineWidth->setValue(titleConfig.readEntry("rect_line_width", rectLineWidth->value()));
 
     backgroundColor->setColor(titleConfig.readEntry("background_color", backgroundColor->color()));
@@ -2512,7 +2589,9 @@ void TitleWidget::prepareTools(QGraphicsItem *referenceItem)
             buttonItalic->blockSignals(true);
             buttonUnder->blockSignals(true);
             fontColorButton->blockSignals(true);
+#if not KDE_IS_VERSION(4,5,0)
             textAlpha->blockSignals(true);
+#endif
             buttonAlignLeft->blockSignals(true);
             buttonAlignRight->blockSignals(true);
             buttonAlignNone->blockSignals(true);
@@ -2529,8 +2608,10 @@ void TitleWidget::prepareTools(QGraphicsItem *referenceItem)
             QTextCursor cursor(i->document());
             cursor.select(QTextCursor::Document);
             QColor color = cursor.charFormat().foreground().color();
+#if not KDE_IS_VERSION(4,5,0)
             textAlpha->setValue(color.alpha());
             color.setAlpha(255);
+#endif
             fontColorButton->setColor(color);
 
             if (!i->data(101).isNull()) {
@@ -2540,13 +2621,16 @@ void TitleWidget::prepareTools(QGraphicsItem *referenceItem)
             }
             if (!i->data(102).isNull()) {
                 textOutlineColor->blockSignals(true);
+                QVariant variant = i->data(102);
+                color = variant.value<QColor>();
+#if not KDE_IS_VERSION(4,5,0)
                 textOutlineAlpha->blockSignals(true);
-                color = QColor(i->data(102).toString());
                 textOutlineAlpha->setValue(color.alpha());
                 color.setAlpha(255);
+                textOutlineAlpha->blockSignals(false);
+#endif
                 textOutlineColor->setColor(color);
                 textOutlineColor->blockSignals(false);
-                textOutlineAlpha->blockSignals(false);
             }
             QTextCursor cur = i->textCursor();
             QTextBlockFormat format = cur.blockFormat();
@@ -2561,7 +2645,9 @@ void TitleWidget::prepareTools(QGraphicsItem *referenceItem)
             buttonItalic->blockSignals(false);
             buttonUnder->blockSignals(false);
             fontColorButton->blockSignals(false);
+#if not KDE_IS_VERSION(4,5,0)
             textAlpha->blockSignals(false);
+#endif
             buttonAlignLeft->blockSignals(false);
             buttonAlignRight->blockSignals(false);
             buttonAlignNone->blockSignals(false);
@@ -2596,8 +2682,10 @@ void TitleWidget::prepareTools(QGraphicsItem *referenceItem)
                 toolBox->widget(1)->setEnabled(true);
                 toolBox->setCurrentIndex(0);*/
                 //toolBox->setItemEnabled(3, true);
+#if not KDE_IS_VERSION(4,5,0)                
                 rectFAlpha->setValue(rec->pen().color().alpha());
                 rectBAlpha->setValue(rec->brush().color().alpha());
+#endif
                 //kDebug() << rec->brush().color().alpha();
                 QColor fcol = rec->pen().color();
                 QColor bcol = rec->brush().color();
index a5892692e25a117ebe7e543bc913ffb3386b1532..5a42e1c306d88146c0101ac33f135e7dc77dfeac 100644 (file)
@@ -105,6 +105,7 @@ public:
 
 protected:
     virtual void resizeEvent(QResizeEvent * event);
+    virtual QSize sizeHint() const;
 
 private:
 
index 2e62176abfe454f5d4195db7c3d873c543fb0450..9d7d50e588b1c64f02fab1db42de253ce9203608 100644 (file)
 #include <QScrollBar>
 #include <QInputDialog>
 
-TrackView::TrackView(KdenliveDoc *doc, bool *ok, QWidget *parent) :
+TrackView::TrackView(KdenliveDoc *doc, QList <QAction*> actions, bool *ok, QWidget *parent) :
     QWidget(parent),
     m_scale(1.0),
     m_projectTracks(0),
     m_doc(doc),
     m_verticalZoom(1)
 {
-
+    m_trackActions << actions;
     setupUi(this);
 //    ruler_frame->setMaximumHeight();
 //    size_frame->setMaximumHeight();
@@ -62,12 +62,14 @@ TrackView::TrackView(KdenliveDoc *doc, bool *ok, QWidget *parent) :
     layout->setContentsMargins(m_trackview->frameWidth(), 0, 0, 0);
     layout->setSpacing(0);
     ruler_frame->setLayout(layout);
+    ruler_frame->setMaximumHeight(m_ruler->height());
     layout->addWidget(m_ruler);
 
     QHBoxLayout *sizeLayout = new QHBoxLayout;
     sizeLayout->setContentsMargins(0, 0, 0, 0);
     sizeLayout->setSpacing(0);
     size_frame->setLayout(sizeLayout);
+    size_frame->setMaximumHeight(m_ruler->height());
 
     QToolButton *butSmall = new QToolButton(this);
     butSmall->setIcon(KIcon("kdenlive-zoom-small"));
@@ -550,15 +552,13 @@ void TrackView::slotRebuildTrackHeaders()
         frame->setFixedHeight(1);
         headers_container->layout()->addWidget(frame);
         TrackInfo info = list.at(max - i - 1);
-        header = new HeaderTrack(i, info, height, headers_container);
+        header = new HeaderTrack(i, info, height, m_trackActions, headers_container);
         header->setPalette(p);
         header->setSelectedIndex(m_trackview->selectedTrack());
         connect(header, SIGNAL(switchTrackVideo(int)), m_trackview, SLOT(slotSwitchTrackVideo(int)));
         connect(header, SIGNAL(switchTrackAudio(int)), m_trackview, SLOT(slotSwitchTrackAudio(int)));
         connect(header, SIGNAL(switchTrackLock(int)), m_trackview, SLOT(slotSwitchTrackLock(int)));
         connect(header, SIGNAL(selectTrack(int)), m_trackview, SLOT(slotSelectTrack(int)));
-        connect(header, SIGNAL(deleteTrack(int)), this, SIGNAL(deleteTrack(int)));
-        connect(header, SIGNAL(insertTrack(int)), this, SIGNAL(insertTrack(int)));
         connect(header, SIGNAL(renameTrack(int, QString)), this, SLOT(slotRenameTrack(int, QString)));
         connect(header, SIGNAL(configTrack(int)), this, SIGNAL(configTrack(int)));
         connect(header, SIGNAL(addTrackInfo(const QDomElement, int)), m_trackview, SLOT(slotAddTrackEffect(const QDomElement, int)));
index 409f3f8c46fbc281932d46d04febb87216992c70..5b19ecdbfcb806cec2648a669b0da9532457035d 100644 (file)
@@ -51,7 +51,7 @@ class TrackView : public QWidget, public Ui::TimeLine_UI
     Q_OBJECT
 
 public:
-    explicit TrackView(KdenliveDoc *doc, bool *ok, QWidget *parent = 0);
+    explicit TrackView(KdenliveDoc *doc, QList <QAction *> actions, bool *ok, QWidget *parent = 0);
     virtual ~ TrackView();
     void setEditMode(const QString & editMode);
     const QString & editMode() const;
@@ -103,6 +103,8 @@ private:
     KdenliveDoc *m_doc;
     int m_verticalZoom;
     QString m_documentErrors;
+    QList <QAction *> m_trackActions;
+    
     void parseDocument(QDomDocument doc);
     int slotAddProjectTrack(int ix, QDomElement xml, bool locked, QDomNodeList producers);
     DocClipBase *getMissingProducer(const QString id) const;
@@ -141,8 +143,6 @@ signals:
     void mousePosition(int);
     void cursorMoved();
     void zoneMoved(int, int);
-    void insertTrack(int);
-    void deleteTrack(int);
     void configTrack(int);
     void updateTracksInfo();
     void setZoom(int);
index e1b89555370a15fee188b2336c22a8f7417a20c8..d9e931d2d9c3cefa920fdc772b1b75b80f8229b6 100644 (file)
@@ -306,11 +306,13 @@ OPERATIONTYPE Transition::operationMode(QPointF pos)
     return MOVE;
 }
 
+//static
 int Transition::itemHeight()
 {
     return (int) (KdenliveSettings::trackheight() / 3 * 2 - 1);
 }
 
+//static
 int Transition::itemOffset()
 {
     return (int) (KdenliveSettings::trackheight() / 3 * 2);
diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt
new file mode 100644 (file)
index 0000000..18ce9f9
--- /dev/null
@@ -0,0 +1,11 @@
+set(kdenlive_SRCS
+  ${kdenlive_SRCS}
+  utils/abstractservice.cpp
+  utils/freesound.cpp
+  utils/openclipart.cpp
+  utils/archiveorg.cpp
+  utils/resourcewidget.cpp
+  PARENT_SCOPE
+)
+
+
diff --git a/src/utils/abstractservice.cpp b/src/utils/abstractservice.cpp
new file mode 100644 (file)
index 0000000..47a919d
--- /dev/null
@@ -0,0 +1,70 @@
+/***************************************************************************
+ *   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 "abstractservice.h"
+
+#include <QObject>
+
+
+AbstractService::AbstractService(QListWidget *listWidget, QObject * parent) :
+        QObject(parent),
+        hasPreview(false),
+        hasMetadata(false),
+        inlineDownload(false),
+        serviceType(NOSERVICE),
+        m_listWidget(listWidget)
+{
+}
+
+AbstractService::~AbstractService()
+{
+}
+
+void AbstractService::slotStartSearch(const QString , int )
+{
+}
+
+OnlineItemInfo AbstractService::displayItemDetails(QListWidgetItem */*item*/)
+{
+    OnlineItemInfo info;
+    return info;
+}
+
+bool AbstractService::startItemPreview(QListWidgetItem *)
+{
+    return false;
+}
+
+void AbstractService::stopItemPreview(QListWidgetItem *)
+{
+}
+
+QString AbstractService::getExtension(QListWidgetItem *)
+{
+    return QString();
+}
+
+
+QString AbstractService::getDefaultDownloadName(QListWidgetItem *)
+{
+    return QString();
+}
+
diff --git a/src/utils/abstractservice.h b/src/utils/abstractservice.h
new file mode 100644 (file)
index 0000000..cf51473
--- /dev/null
@@ -0,0 +1,100 @@
+/***************************************************************************
+ *   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 ABSTRACTSERVICE_H
+#define ABSTRACTSERVICE_H
+
+
+#include <QListWidget>
+
+const int imageRole = Qt::UserRole;
+const int urlRole = Qt::UserRole + 1;
+const int downloadRole = Qt::UserRole + 2;
+const int durationRole = Qt::UserRole + 3;
+const int previewRole = Qt::UserRole + 4;
+const int authorRole = Qt::UserRole + 5;
+const int authorUrl = Qt::UserRole + 6;
+const int infoUrl = Qt::UserRole + 7;
+const int infoData = Qt::UserRole + 8;
+const int idRole = Qt::UserRole + 9;
+const int licenseRole = Qt::UserRole + 10;
+const int descriptionRole = Qt::UserRole + 11;
+
+enum SERVICETYPE { NOSERVICE = 0, FREESOUND = 1, OPENCLIPART = 2, ARCHIVEORG = 3 };
+
+struct OnlineItemInfo {
+    QString itemPreview;
+    QString itemName;
+    QString itemDownload;
+    QString itemId;
+    QString infoUrl;
+    QString license;
+    QString author;
+    QString authorUrl;
+    QString description;
+};
+
+
+class AbstractService : public QObject
+{
+    Q_OBJECT
+
+public:
+    AbstractService(QListWidget *listWidget, QObject * parent = 0);
+    ~AbstractService();
+    /** @brief Get file extension for currently selected item. */
+    virtual QString getExtension(QListWidgetItem *item);
+    /** @brief Get recommanded download file name. */
+    virtual QString getDefaultDownloadName(QListWidgetItem *item);
+        /** @brief Does this service provide a preview (for example preview a sound. */
+    bool hasPreview;
+    /** @brief Does this service provide meta info about the item. */
+    bool hasMetadata;
+    /** @brief Should we show the "import" button or does this service provide download urls in info browser. */
+    bool inlineDownload;
+    /** @brief The type for this service. */
+    SERVICETYPE serviceType;
+
+public slots:
+    virtual void slotStartSearch(const QString searchText, int page = 0);
+    virtual OnlineItemInfo displayItemDetails(QListWidgetItem *item);
+    virtual bool startItemPreview(QListWidgetItem *item);
+    virtual void stopItemPreview(QListWidgetItem *item);
+
+protected:
+    QListWidget *m_listWidget;
+    
+signals:
+    void searchInfo(const QString &);
+    void maxPages(int);
+    /** @brief Emit meta info for current item in formatted html. */
+    void gotMetaInfo(const QString);
+    /** @brief Emit some extra meta info (description, license). */
+    void gotMetaInfo(QMap <QString, QString> info);
+    /** @brief We have an url for current item's preview thumbnail. */
+    void gotThumb(const QString url);
+    /** @brief The requested search query is finished. */
+    void searchDone();
+};
+
+
+#endif
+
diff --git a/src/utils/archiveorg.cpp b/src/utils/archiveorg.cpp
new file mode 100644 (file)
index 0000000..86f9c7d
--- /dev/null
@@ -0,0 +1,238 @@
+/***************************************************************************
+ *   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 "archiveorg.h"
+
+#include <QPushButton>
+#include <QSpinBox>
+#include <QListWidget>
+#include <QDomDocument>
+#include <QApplication>
+
+#include <KDebug>
+#include "kdenlivesettings.h"
+#include <kio/job.h>
+#include <KLocale>
+
+#ifdef USE_QJSON
+#include <qjson/parser.h>
+#endif
+
+ArchiveOrg::ArchiveOrg(QListWidget *listWidget, QObject *parent) :
+        AbstractService(listWidget, parent),
+        m_previewProcess(new QProcess)
+{
+    serviceType = ARCHIVEORG;
+    hasPreview = false;
+    hasMetadata = true;
+    inlineDownload = true;
+    //connect(m_previewProcess, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(slotPreviewStatusChanged(QProcess::ProcessState)));
+}
+
+ArchiveOrg::~ArchiveOrg()
+{
+    if (m_previewProcess) delete m_previewProcess;
+}
+
+void ArchiveOrg::slotStartSearch(const QString searchText, int page)
+{
+    m_listWidget->clear();
+    QString uri = "http://www.archive.org/advancedsearch.php?q=";
+    uri.append(searchText);
+    uri.append("%20AND%20mediatype:movies");//MovingImage");
+    uri.append("&fl%5B%5D=creator&fl%5B%5D=description&fl%5B%5D=identifier&fl%5B%5D=licenseurl&fl%5B%5D=title");
+    uri.append("&rows=30");
+    if (page > 1) uri.append("&page=" + QString::number(page));
+    uri.append("&output=json"); //&callback=callback&save=yes#raw");
+
+    KJob* resolveJob = KIO::storedGet( KUrl(uri), KIO::NoReload, KIO::HideProgressInfo );
+    connect( resolveJob, SIGNAL( result( KJob* ) ), this, SLOT( slotShowResults( KJob* ) ) );
+}
+
+
+void ArchiveOrg::slotShowResults(KJob* job)
+{
+    if (job->error() != 0 ) return;
+    m_listWidget->blockSignals(true);
+    KIO::StoredTransferJob* storedQueryJob = static_cast<KIO::StoredTransferJob*>( job );
+#ifdef USE_QJSON
+    QJson::Parser parser;
+    bool ok;
+    //kDebug()<<"// GOT RESULT: "<<m_result;
+    QVariant data = parser.parse(storedQueryJob->data(), &ok);
+    QVariant sounds;
+    if (data.canConvert(QVariant::Map)) {
+        QMap <QString, QVariant> map = data.toMap();
+        QMap<QString, QVariant>::const_iterator i = map.constBegin();
+        while (i != map.constEnd()) {
+            if (i.key() == "response") {
+                sounds = i.value();
+                if (sounds.canConvert(QVariant::Map)) {
+                    QMap <QString, QVariant> soundsList = sounds.toMap();
+                    if (soundsList.contains("numFound")) emit searchInfo(i18np("Found %1 result", "Found %1 results", soundsList.value("numFound").toInt()));
+                    QList <QVariant> resultsList;
+                    if (soundsList.contains("docs")) {
+                        resultsList = soundsList.value("docs").toList();
+                    }
+                    
+                    for (int j = 0; j < resultsList.count(); j++) {
+                        if (resultsList.at(j).canConvert(QVariant::Map)) {
+                            QMap <QString, QVariant> soundmap = resultsList.at(j).toMap();
+                            if (soundmap.contains("title")) {
+                                QListWidgetItem *item = new   QListWidgetItem(soundmap.value("title").toString(), m_listWidget);
+                                item->setData(descriptionRole, soundmap.value("description").toString());
+                                item->setData(idRole, soundmap.value("identifier").toString());
+                                QString author = soundmap.value("creator").toString();
+                                item->setData(authorRole, author);
+                                if (author.startsWith("http")) item->setData(authorUrl, author);
+                                item->setData(infoUrl, "http://archive.org/details/" + soundmap.value("identifier").toString());
+                                item->setData(downloadRole, "http://archive.org/download/" + soundmap.value("identifier").toString());
+                                item->setData(licenseRole, soundmap.value("licenseurl").toString());                        
+                            }
+                        }
+                    }
+                }
+            }
+            ++i;
+        }
+    }
+#endif  
+    m_listWidget->blockSignals(false);
+    m_listWidget->setCurrentRow(0);
+    emit searchDone();
+}
+    
+
+OnlineItemInfo ArchiveOrg::displayItemDetails(QListWidgetItem *item)
+{
+    OnlineItemInfo info;
+    m_metaInfo.clear();
+    if (!item) {
+        return info;
+    }
+    info.itemPreview = item->data(previewRole).toString();
+    info.itemDownload = item->data(downloadRole).toString();
+    info.itemId = item->data(idRole).toInt();
+    info.itemName = item->text();
+    info.infoUrl = item->data(infoUrl).toString();
+    info.author = item->data(authorRole).toString();
+    info.authorUrl = item->data(authorUrl).toString();
+    info.license = item->data(licenseRole).toString();
+    info.description = item->data(descriptionRole).toString();
+    
+    m_metaInfo.insert("url", info.itemDownload);
+    m_metaInfo.insert("id", info.itemId);
+    
+    QString extraInfoUrl = item->data(downloadRole).toString();
+    if (!extraInfoUrl.isEmpty()) {
+        KJob* resolveJob = KIO::storedGet( KUrl(extraInfoUrl), KIO::NoReload, KIO::HideProgressInfo );
+        resolveJob->setProperty("id", info.itemId);
+        connect( resolveJob, SIGNAL( result( KJob* ) ), this, SLOT( slotParseResults( KJob* ) ) );
+    }
+    return info;
+}
+
+
+void ArchiveOrg::slotParseResults(KJob* job)
+{
+    KIO::StoredTransferJob* storedQueryJob = static_cast<KIO::StoredTransferJob*>( job );
+    QDomDocument doc;
+    doc.setContent(QString::fromUtf8(storedQueryJob->data()));
+    QDomNodeList links = doc.elementsByTagName("a");
+    QString html = QString("<style type=\"text/css\">tr.cellone {background-color: %1;}").arg(qApp->palette().alternateBase().color().name());
+    html += "</style><table width=\"100%\" cellspacing=\"0\" cellpadding=\"2\">";
+    QString link;
+    int ct = 0;
+    m_thumbsPath.clear();
+    for (int i = 0; i < links.count(); i++) {
+        QString href = links.at(i).toElement().attribute("href");
+        if (href.endsWith(".thumbs/")) {
+            // sub folder contains image thumbs, display one.
+            m_thumbsPath = m_metaInfo.value("url") + "/" + href;
+            KJob* thumbJob = KIO::storedGet( KUrl(m_thumbsPath), KIO::NoReload, KIO::HideProgressInfo );
+            thumbJob->setProperty("id", m_metaInfo.value("id"));
+            connect( thumbJob, SIGNAL( result( KJob* ) ), this, SLOT( slotParseThumbs( KJob* ) ) );
+        }
+        else if (!href.contains('/') && !href.endsWith(".xml")) {
+            link = m_metaInfo.value("url") + "/" + href;
+            ct++;
+            if (ct %2 == 0) {
+                html += "<tr class=\"cellone\">";
+            }
+            else html += "<tr>";
+            html += "<td>" + KUrl(link).fileName() + QString("</td><td><a href=\"%1\">%2</a></td><td><a href=\"%3\">%4</a></td></tr>").arg(link).arg(i18n("Preview")).arg(link + "_import").arg(i18n("Import"));
+        }
+    }
+    html += "</table>";
+    if (m_metaInfo.value("id") == job->property("id").toString()) emit gotMetaInfo(html);
+}
+
+
+bool ArchiveOrg::startItemPreview(QListWidgetItem *item)
+{    
+    if (!item) return false;
+    QString url = item->data(previewRole).toString();
+    if (url.isEmpty()) return false;
+    if (m_previewProcess && m_previewProcess->state() != QProcess::NotRunning) {
+        m_previewProcess->close();
+    }
+    m_previewProcess->start("ffplay", QStringList() << url << "-nodisp");
+    return true;
+}
+
+
+void ArchiveOrg::stopItemPreview(QListWidgetItem */*item*/)
+{    
+    if (m_previewProcess && m_previewProcess->state() != QProcess::NotRunning) {
+        m_previewProcess->close();
+    }
+}
+
+QString ArchiveOrg::getExtension(QListWidgetItem *item)
+{
+    if (!item) return QString();
+    return QString("*.") + item->text().section('.', -1);
+}
+
+
+QString ArchiveOrg::getDefaultDownloadName(QListWidgetItem *item)
+{
+    if (!item) return QString();
+    return item->text();
+}
+
+void ArchiveOrg::slotParseThumbs(KJob* job)
+{
+    KIO::StoredTransferJob* storedQueryJob = static_cast<KIO::StoredTransferJob*>( job );
+    QDomDocument doc;
+    doc.setContent(QString::fromUtf8(storedQueryJob->data()));
+    QDomNodeList links = doc.elementsByTagName("a");
+    if (links.isEmpty()) return;
+    for (int i = 0; i < links.count(); i++) {
+        QString href = links.at(i).toElement().attribute("href");
+        if (!href.contains('/') && i >= links.count() / 2) {
+            QString thumbUrl = m_thumbsPath + href;
+            if (m_metaInfo.value("id") == job->property("id").toString())
+                emit gotThumb(thumbUrl);
+            break;
+        }
+    }
+}
diff --git a/src/utils/archiveorg.h b/src/utils/archiveorg.h
new file mode 100644 (file)
index 0000000..51c558f
--- /dev/null
@@ -0,0 +1,65 @@
+/***************************************************************************
+ *   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 ARCHIVEORG_H
+#define ARCHIVEORG_H
+
+
+#include "abstractservice.h"
+
+#include <QProcess>
+#include <kio/jobclasses.h>
+
+
+class ArchiveOrg : public AbstractService
+{
+    Q_OBJECT
+
+public:
+    ArchiveOrg(QListWidget *listWidget, QObject * parent = 0);
+    ~ArchiveOrg();
+    virtual QString getExtension(QListWidgetItem *item);
+    virtual QString getDefaultDownloadName(QListWidgetItem *item);
+
+
+public slots:
+    virtual void slotStartSearch(const QString searchText, int page = 0);
+    virtual OnlineItemInfo displayItemDetails(QListWidgetItem *item);
+    virtual bool startItemPreview(QListWidgetItem *item);
+    virtual void stopItemPreview(QListWidgetItem *item);    
+
+private slots:
+    void slotShowResults(KJob* job);
+    void slotParseResults(KJob* job);
+    void slotParseThumbs(KJob* job);
+    
+private:
+    QMap <QString, QString> m_metaInfo;
+    QProcess *m_previewProcess;
+    QString m_thumbsPath;
+
+signals:
+    void addClip(KUrl, const QString &);
+};
+
+
+#endif
+
diff --git a/src/utils/freesound.cpp b/src/utils/freesound.cpp
new file mode 100644 (file)
index 0000000..c74054f
--- /dev/null
@@ -0,0 +1,248 @@
+/***************************************************************************
+ *   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 "freesound.h"
+
+#include <QPushButton>
+#include <QSpinBox>
+#include <QListWidget>
+#include <QDomDocument>
+#include <QApplication>
+
+#include <KDebug>
+#include "kdenlivesettings.h"
+#include <kio/job.h>
+#include <KLocale>
+
+#ifdef USE_QJSON
+#include <qjson/parser.h>
+#endif
+
+FreeSound::FreeSound(QListWidget *listWidget, QObject *parent) :
+        AbstractService(listWidget, parent),
+        m_previewProcess(new QProcess)
+{
+    serviceType = FREESOUND;
+    hasPreview = true;
+    hasMetadata = true;
+}
+
+FreeSound::~FreeSound()
+{
+    if (m_previewProcess) delete m_previewProcess;
+}
+
+void FreeSound::slotStartSearch(const QString searchText, int page)
+{
+    m_listWidget->clear();
+    QString uri = "http://www.freesound.org/api/sounds/search/?q=";
+    uri.append(searchText);
+    if (page > 1) uri.append("&p=" + QString::number(page));
+    uri.append("&api_key=a1772c8236e945a4bee30a64058dabf8");
+
+    KJob* resolveJob = KIO::storedGet( KUrl(uri), KIO::NoReload, KIO::HideProgressInfo );
+    connect( resolveJob, SIGNAL( result( KJob* ) ), this, SLOT( slotShowResults( KJob* ) ) );
+}
+
+
+void FreeSound::slotShowResults(KJob* job)
+{
+    if (job->error() != 0 ) return;
+    m_listWidget->blockSignals(true);
+    KIO::StoredTransferJob* storedQueryJob = static_cast<KIO::StoredTransferJob*>( job );
+#ifdef USE_QJSON
+    QJson::Parser parser;
+    bool ok;
+    //kDebug()<<"// GOT RESULT: "<<m_result;
+    QVariant data = parser.parse(storedQueryJob->data(), &ok);
+    QVariant sounds;
+    if (data.canConvert(QVariant::Map)) {
+        QMap <QString, QVariant> map = data.toMap();
+        QMap<QString, QVariant>::const_iterator i = map.constBegin();
+        while (i != map.constEnd()) {
+            if (i.key() == "num_results") emit searchInfo(i18np("Found %1 result", "Found %1 results", i.value().toInt()));
+            else if (i.key() == "num_pages") {
+                emit maxPages(i.value().toInt());
+            }
+            else if (i.key() == "sounds") {
+                sounds = i.value();
+                if (sounds.canConvert(QVariant::List)) {
+                    QList <QVariant> soundsList = sounds.toList();
+                    for (int j = 0; j < soundsList.count(); j++) {
+                        if (soundsList.at(j).canConvert(QVariant::Map)) {
+                            QMap <QString, QVariant> soundmap = soundsList.at(j).toMap();
+                            if (soundmap.contains("original_filename")) {
+                                QListWidgetItem *item = new   QListWidgetItem(soundmap.value("original_filename").toString(), m_listWidget);
+                                item->setData(imageRole, soundmap.value("waveform_m").toString());
+                                item->setData(infoUrl, soundmap.value("url").toString());
+                                item->setData(infoData, soundmap.value("ref").toString() + "?api_key=a1772c8236e945a4bee30a64058dabf8");
+                                item->setData(durationRole, soundmap.value("duration").toDouble());
+                                item->setData(idRole, soundmap.value("id").toInt());
+                                item->setData(previewRole, soundmap.value("preview-hq-mp3").toString());
+                                item->setData(downloadRole, soundmap.value("serve").toString() + "?api_key=a1772c8236e945a4bee30a64058dabf8");
+                                QVariant authorInfo = soundmap.value("user");
+                                if (authorInfo.canConvert(QVariant::Map)) {
+                                    QMap <QString, QVariant> authorMap = authorInfo.toMap();
+                                    if (authorMap.contains("username")) {
+                                        item->setData(authorRole, authorMap.value("username").toString());
+                                        item->setData(authorUrl, authorMap.value("url").toString());
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            ++i;
+        }
+    }
+#endif  
+    m_listWidget->blockSignals(false);
+    m_listWidget->setCurrentRow(0);
+    emit searchDone();
+}
+    
+
+OnlineItemInfo FreeSound::displayItemDetails(QListWidgetItem *item)
+{
+    OnlineItemInfo info;
+    m_metaInfo.clear();
+    if (!item) {
+        return info;
+    }
+    info.itemPreview = item->data(previewRole).toString();
+    info.itemDownload = item->data(downloadRole).toString();
+    info.itemId = item->data(idRole).toInt();
+    info.itemName = item->text();
+    info.infoUrl = item->data(infoUrl).toString();
+    info.author = item->data(authorRole).toString();
+    info.authorUrl = item->data(authorUrl).toString();
+    m_metaInfo.insert(i18n("Duration"), item->data(durationRole).toString());
+    info.license = item->data(licenseRole).toString();
+    info.description = item->data(descriptionRole).toString();
+    
+    QString extraInfoUrl = item->data(infoData).toString();
+    if (!extraInfoUrl.isEmpty()) {
+        KJob* resolveJob = KIO::storedGet( KUrl(extraInfoUrl), KIO::NoReload, KIO::HideProgressInfo );
+        connect( resolveJob, SIGNAL( result( KJob* ) ), this, SLOT( slotParseResults( KJob* ) ) );
+    }
+    emit gotThumb(item->data(imageRole).toString());
+    return info;
+}
+
+
+void FreeSound::slotParseResults(KJob* job)
+{
+#ifdef USE_QJSON
+    KIO::StoredTransferJob* storedQueryJob = static_cast<KIO::StoredTransferJob*>( job );
+    QJson::Parser parser;
+    bool ok;
+    int ct = 0;
+    QString html = QString("<style type=\"text/css\">tr.cellone {background-color: %1;}</style>").arg(qApp->palette().alternateBase().color().name());
+    
+    QVariant data = parser.parse(storedQueryJob->data(), &ok);
+    if (data.canConvert(QVariant::Map)) {
+        QMap <QString, QVariant> infos = data.toMap();
+        //if (m_currentId != infos.value("id").toInt()) return;
+        
+        html += "<table width=\"100%\" cellspacing=\"0\" cellpadding=\"2\">";
+    
+        if (m_metaInfo.contains(i18n("Duration"))) {
+            ct++;
+            if (ct %2 == 0) {
+                html += "<tr class=\"cellone\">";
+            }
+            else html += "<tr>";
+            html += "<td>" + i18n("Duration") + "</td><td>" + m_metaInfo.value(i18n("Duration")) + "</td></tr>";
+            m_metaInfo.remove(i18n("Duration"));
+        }
+        
+        if (infos.contains("samplerate")) {
+            ct++;
+            if (ct %2 == 0) {
+                html += "<tr class=\"cellone\">";
+            }
+            else html += "<tr>";
+            html += "<td>" + i18n("Samplerate") + "</td><td>" + QString::number(infos.value("samplerate").toDouble()) + "</td></tr>";
+        }
+        if (infos.contains("channels")) {
+            ct++;
+            if (ct %2 == 0) {
+                html += "<tr class=\"cellone\">";
+            }
+            else html += "<tr>";
+            html += "<td>" + i18n("Channels") + "</td><td>" + QString::number(infos.value("channels").toInt()) + "</td></tr>";
+        }
+        if (infos.contains("filesize")) {
+            ct++;
+            if (ct %2 == 0) {
+                html += "<tr class=\"cellone\">";
+            }
+            else html += "<tr>";
+            KIO::filesize_t fSize = infos.value("filesize").toDouble();
+            html += "<td>" + i18n("File size") + "</td><td>" + KIO::convertSize(fSize) + "</td></tr>";
+        }
+        if (infos.contains("license")) {
+            m_metaInfo.insert("license", infos.value("license").toString());
+        }
+        html +="</table>";
+        if (infos.contains("description")) {
+            m_metaInfo.insert("description", infos.value("description").toString());
+        }
+    }
+    emit gotMetaInfo(html);
+    emit gotMetaInfo(m_metaInfo);
+#endif    
+}
+
+
+bool FreeSound::startItemPreview(QListWidgetItem *item)
+{    
+    if (!item) return false;
+    QString url = item->data(previewRole).toString();
+    if (url.isEmpty()) return false;
+    if (m_previewProcess && m_previewProcess->state() != QProcess::NotRunning) {
+        m_previewProcess->close();
+    }
+    m_previewProcess->start("ffplay", QStringList() << url << "-nodisp");
+    return true;
+}
+
+
+void FreeSound::stopItemPreview(QListWidgetItem */*item*/)
+{    
+    if (m_previewProcess && m_previewProcess->state() != QProcess::NotRunning) {
+        m_previewProcess->close();
+    }
+}
+
+QString FreeSound::getExtension(QListWidgetItem *item)
+{
+    if (!item) return QString();
+    return QString("*.") + item->text().section('.', -1);
+}
+
+
+QString FreeSound::getDefaultDownloadName(QListWidgetItem *item)
+{
+    if (!item) return QString();
+    return item->text();
+}
diff --git a/src/utils/freesound.h b/src/utils/freesound.h
new file mode 100644 (file)
index 0000000..88251a0
--- /dev/null
@@ -0,0 +1,63 @@
+/***************************************************************************
+ *   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 FREESOUND_H
+#define FREESOUND_H
+
+
+#include "abstractservice.h"
+
+#include <QProcess>
+#include <kio/jobclasses.h>
+
+
+class FreeSound : public AbstractService
+{
+    Q_OBJECT
+
+public:
+    FreeSound(QListWidget *listWidget, QObject * parent = 0);
+    ~FreeSound();
+    virtual QString getExtension(QListWidgetItem *item);
+    virtual QString getDefaultDownloadName(QListWidgetItem *item);
+
+
+public slots:
+    virtual void slotStartSearch(const QString searchText, int page = 0);
+    virtual OnlineItemInfo displayItemDetails(QListWidgetItem *item);
+    virtual bool startItemPreview(QListWidgetItem *item);
+    virtual void stopItemPreview(QListWidgetItem *item);    
+
+private slots:
+    void slotShowResults(KJob* job);
+    void slotParseResults(KJob* job);
+    
+private:
+    QMap <QString, QString> m_metaInfo;
+    QProcess *m_previewProcess;
+
+signals:
+    void addClip(KUrl, const QString &);
+};
+
+
+#endif
+
diff --git a/src/utils/openclipart.cpp b/src/utils/openclipart.cpp
new file mode 100644 (file)
index 0000000..a120266
--- /dev/null
@@ -0,0 +1,121 @@
+/***************************************************************************
+ *   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 "openclipart.h"
+
+#include <QListWidget>
+#include <QDomDocument>
+
+#include <KDebug>
+#include <kio/job.h>
+#include <KIO/NetAccess>
+
+
+OpenClipArt::OpenClipArt(QListWidget *listWidget, QObject *parent) :
+        AbstractService(listWidget, parent)
+{
+    serviceType = OPENCLIPART;
+}
+
+OpenClipArt::~OpenClipArt()
+{
+}
+
+void OpenClipArt::slotStartSearch(const QString searchText, int page)
+{
+    m_listWidget->clear();
+    QString uri = "http://openclipart.org/api/search/?query=";
+    uri.append(searchText);
+    if (page > 1) uri.append("&page=" + QString::number(page));
+        
+    KJob* resolveJob = KIO::storedGet( KUrl(uri), KIO::NoReload, KIO::HideProgressInfo );
+    connect( resolveJob, SIGNAL( result( KJob* ) ), this, SLOT( slotShowResults( KJob* ) ) );
+}
+
+
+void OpenClipArt::slotShowResults(KJob* job)
+{
+    if (job->error() != 0 ) return;
+    m_listWidget->blockSignals(true);    
+    KIO::StoredTransferJob* storedQueryJob = static_cast<KIO::StoredTransferJob*>( job );
+    
+    QDomDocument doc;
+    doc.setContent(QString::fromAscii(storedQueryJob->data()));
+    QDomNodeList items = doc.documentElement().elementsByTagName("item");
+    for (int i = 0; i < items.count(); i++) {
+        QDomElement currentClip = items.at(i).toElement();
+        QDomElement title = currentClip.firstChildElement("title");
+        QListWidgetItem *item = new QListWidgetItem(title.firstChild().nodeValue(), m_listWidget);
+        QDomElement thumb = currentClip.firstChildElement("media:thumbnail");
+        item->setData(imageRole, thumb.attribute("url"));
+        QDomElement enclosure = currentClip.firstChildElement("enclosure");
+        item->setData(downloadRole, enclosure.attribute("url"));
+        QDomElement link = currentClip.firstChildElement("link");
+        item->setData(infoUrl, link.firstChild().nodeValue());
+        QDomElement license = currentClip.firstChildElement("cc:license");
+        item->setData(licenseRole, license.firstChild().nodeValue());
+        QDomElement desc = currentClip.firstChildElement("description");
+        item->setData(descriptionRole, desc.firstChild().nodeValue());
+        QDomElement author = currentClip.firstChildElement("dc:creator");
+        item->setData(authorRole, author.firstChild().nodeValue());
+        item->setData(authorUrl, QString("http://openclipart.org/user-detail/") + author.firstChild().nodeValue());
+    }        
+    m_listWidget->blockSignals(false);
+    m_listWidget->setCurrentRow(0);
+    emit searchDone();
+}
+    
+
+OnlineItemInfo OpenClipArt::displayItemDetails(QListWidgetItem *item)
+{
+    OnlineItemInfo info;
+    if (!item) {
+        return info;
+    }
+    info.itemPreview = item->data(previewRole).toString();
+    info.itemDownload = item->data(downloadRole).toString();
+    info.itemId = item->data(idRole).toInt();
+    info.itemName = item->text();
+    info.infoUrl = item->data(infoUrl).toString();
+    info.author = item->data(authorRole).toString();
+    info.authorUrl = item->data(authorUrl).toString();
+    info.license = item->data(licenseRole).toString();
+    info.description = item->data(descriptionRole).toString();
+    emit gotThumb(item->data(imageRole).toString());
+    return info;
+}
+
+QString OpenClipArt::getExtension(QListWidgetItem *item)
+{
+    if (!item) return QString();
+    QString url = item->data(downloadRole).toString();
+    return QString("*.") + url.section('.', -1);
+}
+
+QString OpenClipArt::getDefaultDownloadName(QListWidgetItem *item)
+{
+    if (!item) return QString();
+    QString url = item->data(downloadRole).toString();
+    QString path = item->text();
+    path.append("." + url.section('.', -1));
+    return path;
+}
+
diff --git a/src/utils/openclipart.h b/src/utils/openclipart.h
new file mode 100644 (file)
index 0000000..66f2556
--- /dev/null
@@ -0,0 +1,55 @@
+/***************************************************************************
+ *   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 OPENCLIPART_H
+#define OPENCLIPART_H
+
+
+#include "abstractservice.h"
+
+#include <QProcess>
+#include <kio/jobclasses.h>
+
+
+class OpenClipArt : public AbstractService
+{
+    Q_OBJECT
+
+public:
+    OpenClipArt(QListWidget *listWidget, QObject * parent = 0);
+    ~OpenClipArt();
+    virtual QString getExtension(QListWidgetItem *item);
+    virtual QString getDefaultDownloadName(QListWidgetItem *item);
+
+
+public slots:
+    virtual void slotStartSearch(const QString searchText, int page = 0);
+    virtual OnlineItemInfo displayItemDetails(QListWidgetItem *item);
+
+private slots:
+    void slotShowResults(KJob* job);
+
+};
+
+
+#endif
+
diff --git a/src/utils/resourcewidget.cpp b/src/utils/resourcewidget.cpp
new file mode 100644 (file)
index 0000000..cafd50a
--- /dev/null
@@ -0,0 +1,400 @@
+/***************************************************************************
+ *   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 "resourcewidget.h"
+#include "freesound.h"
+#include "openclipart.h"
+#include "archiveorg.h"
+
+#include <QPushButton>
+#include <QSpinBox>
+#include <QListWidget>
+#include <QAction>
+#include <QMenu>
+
+#include <KDebug>
+#include <kdeversion.h>
+#include "kdenlivesettings.h"
+#include <KGlobalSettings>
+#include <KMessageBox>
+#include <KFileDialog>
+#include <kio/job.h>
+#include <KIO/NetAccess>
+#include <Solid/Networking>
+#include <KRun>
+#if KDE_IS_VERSION(4,4,0)
+#include <KPixmapSequence>
+#include <KPixmapSequenceOverlayPainter>
+#endif
+#include <KFileItem>
+
+#ifdef USE_NEPOMUK
+#if KDE_IS_VERSION(4,6,0)
+#include <Nepomuk/Variant>
+#include <Nepomuk/Resource>
+#include <Nepomuk/ResourceManager>
+#include <Nepomuk/Vocabulary/NIE>
+#include <Nepomuk/Vocabulary/NCO>
+#include <Nepomuk/Vocabulary/NDO>
+#endif
+#endif
+
+ResourceWidget::ResourceWidget(const QString & folder, QWidget * parent) :
+        QDialog(parent),
+        m_folder(folder),
+        m_currentService(NULL)
+{
+    setFont(KGlobalSettings::toolBarFont());
+    setupUi(this);
+    setAttribute(Qt::WA_DeleteOnClose);
+#ifdef USE_QJSON
+    service_list->addItem(i18n("Freesound Audio Library"), FREESOUND);
+    service_list->addItem(i18n("Archive.org Video Library"), ARCHIVEORG);
+#endif
+    service_list->addItem(i18n("Open Clip Art Graphic Library"), OPENCLIPART);
+    setWindowTitle(i18n("Search Online Resources"));
+    info_browser->setStyleSheet(QString("QTextBrowser { background-color: transparent;}"));
+    connect(button_search, SIGNAL(clicked()), this, SLOT(slotStartSearch()));
+    connect(search_results, SIGNAL(currentRowChanged(int)), this, SLOT(slotUpdateCurrentSound()));
+    connect(button_preview, SIGNAL(clicked()), this, SLOT(slotPlaySound()));
+    connect(button_import, SIGNAL(clicked()), this, SLOT(slotSaveItem()));
+    connect(item_license, SIGNAL(leftClickedUrl(const QString &)), this, SLOT(slotOpenUrl(const QString &)));
+    connect(service_list, SIGNAL(currentIndexChanged(int)), this, SLOT(slotChangeService()));
+    if (Solid::Networking::status() == Solid::Networking::Unconnected) {
+        slotOffline();
+    }
+    connect(Solid::Networking::notifier(), SIGNAL(shouldConnect()), this, SLOT(slotOnline()));
+    connect(Solid::Networking::notifier(), SIGNAL(shouldDisconnect()), this, SLOT(slotOffline()));
+    connect(page_next, SIGNAL(clicked()), this, SLOT(slotNextPage()));
+    connect(page_prev, SIGNAL(clicked()), this, SLOT(slotPreviousPage()));
+    connect(page_number, SIGNAL(valueChanged(int)), this, SLOT(slotStartSearch(int)));
+    connect(info_browser, SIGNAL(anchorClicked(const QUrl &)), this, SLOT(slotOpenLink(const QUrl &)));
+    
+    m_autoPlay = new QAction(i18n("Auto Play"), this);
+    m_autoPlay->setCheckable(true);
+    QMenu *resourceMenu = new QMenu;
+    resourceMenu->addAction(m_autoPlay);
+    config_button->setMenu(resourceMenu);
+    config_button->setIcon(KIcon("configure"));
+
+#if KDE_IS_VERSION(4,4,0)
+    m_busyWidget = new KPixmapSequenceOverlayPainter(this);
+    m_busyWidget->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
+    m_busyWidget->setWidget(search_results->viewport());
+#endif
+    
+    sound_box->setEnabled(false);
+    search_text->setFocus();
+#ifdef USE_NEPOMUK
+#if KDE_IS_VERSION(4,6,0)    
+    Nepomuk::ResourceManager::instance()->init();
+#endif
+#endif
+    slotChangeService();
+}
+
+ResourceWidget::~ResourceWidget()
+{
+    if (m_currentService) delete m_currentService;
+    KIO::NetAccess::removeTempFile(m_tmpThumbFile);
+}
+
+void ResourceWidget::slotStartSearch(int page)
+{
+    page_number->blockSignals(true);
+    page_number->setValue(page);
+    page_number->blockSignals(false);
+#if KDE_IS_VERSION(4,4,0)
+    m_busyWidget->start();
+#endif
+    m_currentService->slotStartSearch(search_text->text(), page);
+}
+
+void ResourceWidget::slotUpdateCurrentSound()
+{
+    KIO::NetAccess::removeTempFile(m_tmpThumbFile);
+    if (!m_autoPlay->isChecked()) m_currentService->stopItemPreview(NULL);
+    item_license->clear();
+    m_title.clear();
+    m_image.clear();
+    m_desc.clear();
+    m_meta.clear();
+    QListWidgetItem *item = search_results->currentItem();
+    if (!item) {
+        sound_box->setEnabled(false);
+        return;
+    }
+    m_currentInfo = m_currentService->displayItemDetails(item);
+    
+    if (m_autoPlay->isChecked() && m_currentService->hasPreview) m_currentService->startItemPreview(item);
+    sound_box->setEnabled(true);
+    QString title = "<h3>" + m_currentInfo.itemName;
+    if (!m_currentInfo.infoUrl.isEmpty()) title += QString(" (<a href=\"%1\">%2</a>)").arg(m_currentInfo.infoUrl).arg(i18nc("the url link pointing to a web page", "link"));
+    title.append("</h3>");
+    
+    if (!m_currentInfo.authorUrl.isEmpty()) {
+        title += QString("<a href=\"%1\">").arg(m_currentInfo.authorUrl);
+        if (!m_currentInfo.author.isEmpty())
+            title.append(m_currentInfo.author);
+        else title.append(i18n("Author"));
+        title.append("</a><br />");
+    }
+    else if (!m_currentInfo.author.isEmpty())
+        title.append(m_currentInfo.author + "<br />");
+    else title.append("<br />");
+    
+    slotSetTitle(title);
+    if (!m_currentInfo.description.isEmpty()) slotSetDescription(m_currentInfo.description);
+    if (!m_currentInfo.license.isEmpty()) parseLicense(m_currentInfo.license);
+}
+
+
+void ResourceWidget::slotLoadThumb(const QString url)
+{
+    KUrl img(url);
+    if (img.isEmpty()) return;
+    if (KIO::NetAccess::exists(img, KIO::NetAccess::SourceSide, this)) {
+        if (KIO::NetAccess::download(img, m_tmpThumbFile, this)) {
+            slotSetImage(m_tmpThumbFile);
+            /*QPixmap pix(tmpFile);
+            
+            int newHeight = pix.height() * item_image->width() / pix.width();
+            if (newHeight > 200) {
+                item_image->setScaledContents(false);
+                //item_image->setFixedHeight(item_image->width());
+            }
+            else {
+                item_image->setScaledContents(true);
+                item_image->setFixedHeight(newHeight);
+            }
+            item_image->setPixmap(pix);*/
+        }
+    }
+}
+
+
+void ResourceWidget::slotDisplayMetaInfo(QMap <QString, QString> metaInfo)
+{
+    if (metaInfo.contains("license")) {
+        parseLicense(metaInfo.value("license"));
+    }
+    if (metaInfo.contains("description")) {
+        slotSetDescription(metaInfo.value("description"));
+    }
+}
+
+
+void ResourceWidget::slotPlaySound()
+{
+    if (!m_currentService) return;
+    bool started = m_currentService->startItemPreview(search_results->currentItem());
+    if (started) button_preview->setText(i18n("Preview"));
+    else button_preview->setText(i18n("Stop"));
+}
+
+
+void ResourceWidget::slotSaveItem(const QString originalUrl)
+{
+    //if (m_currentUrl.isEmpty()) return;
+    QListWidgetItem *item = search_results->currentItem();
+    if (!item) return;
+    QString path = m_folder;
+    QString ext;
+    if (!path.endsWith('/')) path.append('/');
+    if (!originalUrl.isEmpty()) {
+        path.append(KUrl(originalUrl).fileName());
+        ext = "*." + KUrl(originalUrl).fileName().section(".", -1);
+        m_currentInfo.itemDownload = originalUrl;
+    }
+    else {
+        path.append(m_currentService->getDefaultDownloadName(item));
+        ext = m_currentService->getExtension(search_results->currentItem());
+    }
+    QString saveUrl = KFileDialog::getSaveFileName(KUrl(path), ext);
+    KIO::UDSEntry entry;
+    KUrl srcUrl(m_currentInfo.itemDownload);
+    if (saveUrl.isEmpty() || !KIO::NetAccess::stat(srcUrl, entry, this)) return;
+    KIO::FileCopyJob * getJob = KIO::file_copy(srcUrl, KUrl(saveUrl), -1, KIO::Overwrite);
+    
+    KFileItem info(entry, srcUrl); 
+    getJob->setSourceSize(info.size());
+    getJob->setProperty("license", item_license->text());
+    getJob->setProperty("licenseurl", item_license->url());
+    getJob->setProperty("originurl", m_currentInfo.itemDownload);
+    if (!m_currentInfo.authorUrl.isEmpty()) getJob->setProperty("author", m_currentInfo.authorUrl);
+    else if (!m_currentInfo.author.isEmpty()) getJob->setProperty("author", m_currentInfo.author);
+    connect(getJob, SIGNAL(result(KJob*)), this, SLOT(slotGotFile(KJob*)));
+    getJob->start();
+}
+
+void ResourceWidget::slotGotFile(KJob *job)
+{
+    if (job->error() != 0 ) return;
+    KIO::FileCopyJob* copyJob = static_cast<KIO::FileCopyJob*>( job );
+    const KUrl filePath = copyJob->destUrl();
+#ifdef USE_NEPOMUK
+#if KDE_IS_VERSION(4,6,0)
+        Nepomuk::Resource res( filePath );
+        res.setProperty( Nepomuk::Vocabulary::NIE::license(), (Nepomuk::Variant) job->property("license") );
+        res.setProperty( Nepomuk::Vocabulary::NIE::licenseType(), (Nepomuk::Variant) job->property("licenseurl") );
+        res.setProperty( Nepomuk::Vocabulary::NDO::copiedFrom(), (Nepomuk::Variant) job->property("originurl") );
+        res.setProperty( Nepomuk::Vocabulary::NDO::copiedFrom(), (Nepomuk::Variant) job->property("originurl") );
+        res.setProperty( Nepomuk::Vocabulary::NCO::creator(), (Nepomuk::Variant) job->property("author") );
+        //res.setDescription(item_description->toPlainText());
+        //res.setProperty( Soprano::Vocabulary::NAO::description(), 
+#endif
+#endif
+        emit addClip(filePath, QString());
+}
+
+void ResourceWidget::slotOpenUrl(const QString &url)
+{
+    new KRun(KUrl(url), this);
+}
+
+void ResourceWidget::slotChangeService()
+{
+    if (m_currentService) {
+        delete m_currentService;
+        m_currentService = NULL;
+    }
+    SERVICETYPE service = (SERVICETYPE) service_list->itemData(service_list->currentIndex()).toInt();
+    if (service == FREESOUND) {
+        m_currentService = new FreeSound(search_results);
+    }
+    else if (service == OPENCLIPART) {
+        m_currentService = new OpenClipArt(search_results);
+    }
+    else if (service == ARCHIVEORG) {
+        m_currentService = new ArchiveOrg(search_results);
+    }
+
+    connect(m_currentService, SIGNAL(gotMetaInfo(const QString)), this, SLOT(slotSetMetadata(const QString)));
+    connect(m_currentService, SIGNAL(gotMetaInfo(QMap <QString, QString>)), this, SLOT(slotDisplayMetaInfo(QMap <QString, QString>)));
+    connect(m_currentService, SIGNAL(maxPages(int)), page_number, SLOT(setMaximum(int)));
+    connect(m_currentService, SIGNAL(searchInfo(QString)), search_info, SLOT(setText(QString)));
+    connect(m_currentService, SIGNAL(gotThumb(const QString)), this, SLOT(slotLoadThumb(const QString)));
+#if KDE_IS_VERSION(4,4,0)
+    connect(m_currentService, SIGNAL(searchDone()), m_busyWidget, SLOT(stop()));
+#endif
+    
+    button_preview->setVisible(m_currentService->hasPreview);
+    button_import->setVisible(!m_currentService->inlineDownload);
+    search_info->setText(QString());
+    if (!search_text->text().isEmpty()) slotStartSearch();
+}
+
+void ResourceWidget::slotOnline()
+{
+    button_search->setEnabled(true);
+    search_info->setText(QString());
+}
+
+void ResourceWidget::slotOffline()
+{
+    button_search->setEnabled(false);
+    search_info->setText(i18n("You need to be online\n for searching"));
+}
+
+void ResourceWidget::slotNextPage()
+{
+    int ix = page_number->value();
+    if (search_results->count() > 0) page_number->setValue(ix + 1);
+}
+
+void ResourceWidget::slotPreviousPage()
+{
+    int ix = page_number->value();
+    if (ix > 1) page_number->setValue(ix - 1);
+}
+
+void ResourceWidget::parseLicense(const QString &licenseUrl)
+{
+    QString licenseName;
+    if (licenseUrl.contains("/sampling+/"))
+        licenseName = "Sampling+";
+    else if (licenseUrl.contains("/by/"))
+        licenseName = "Attribution";
+    else if (licenseUrl.contains("/by-nd/"))
+        licenseName = "Attribution-NoDerivs";
+    else if (licenseUrl.contains("/by-nc-sa/"))
+        licenseName = "Attribution-NonCommercial-ShareAlike";
+    else if (licenseUrl.contains("/by-sa/"))
+        licenseName = "Attribution-ShareAlike";
+    else if (licenseUrl.contains("/by-nc/"))
+        licenseName = "Attribution-NonCommercial";
+    else if (licenseUrl.contains("/by-nc-nd/"))
+        licenseName = "Attribution-NonCommercial-NoDerivs";
+    else if (licenseUrl.contains("/publicdomain/zero/"))
+        licenseName = "Creative Commons 0";
+    else if (licenseUrl.endsWith("/publicdomain"))
+        licenseName = "Public Domain";
+    else licenseName = i18n("Unknown");
+    item_license->setText(licenseName);
+    item_license->setUrl(licenseUrl);
+}
+
+
+void ResourceWidget::slotOpenLink(const QUrl &url)
+{
+    QString path = url.toEncoded();
+    if (path.endsWith("_import")) {
+        path.chop(7);
+        // import file in Kdenlive
+        slotSaveItem(path);
+    }
+    else {
+        slotOpenUrl(path);
+    }
+}
+
+void ResourceWidget::slotSetDescription(const QString desc)
+{
+    m_desc = desc;
+    updateLayout();
+}
+
+void ResourceWidget::slotSetMetadata(const QString desc)
+{
+    m_meta = desc;
+    updateLayout();
+}
+
+void ResourceWidget::slotSetImage(const QString desc)
+{
+    m_image = QString("<img src=\"%1\" style=\"max-height:150px\" max-width=\"%2px\" />").arg(desc).arg((int) (info_browser->width() * 0.9));
+    updateLayout();
+}
+
+void ResourceWidget::slotSetTitle(const QString desc)
+{
+    m_title = desc;
+    updateLayout();
+}
+
+void ResourceWidget::updateLayout()
+{
+    QString content = m_title;
+    if (!m_image.isEmpty()) content.append(m_image + "<br clear=\"all\" />");
+    if (!m_desc.isEmpty()) content.append(m_desc);
+    if (!m_meta.isEmpty()) content.append(m_meta);
+    info_browser->setHtml(content);
+}
\ No newline at end of file
diff --git a/src/utils/resourcewidget.h b/src/utils/resourcewidget.h
new file mode 100644 (file)
index 0000000..ed25427
--- /dev/null
@@ -0,0 +1,92 @@
+/***************************************************************************
+ *   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 RESOURCEWIDGET_H
+#define RESOURCEWIDGET_H
+
+
+#include "ui_freesound_ui.h"
+#include "abstractservice.h"
+
+#include <QDialog>
+#include <QProcess>
+#include <kio/jobclasses.h>
+#include <kdeversion.h>
+
+
+#if KDE_IS_VERSION(4,4,0)
+class KPixmapSequenceOverlayPainter;
+#endif
+class QAction;
+
+class ResourceWidget : public QDialog, public Ui::FreeSound_UI
+{
+    Q_OBJECT
+
+public:
+    ResourceWidget(const QString & folder, QWidget * parent = 0);
+    ~ResourceWidget();
+
+
+private slots:
+    void slotStartSearch(int page = 0);
+    void slotUpdateCurrentSound();
+    void slotPlaySound();
+    void slotDisplayMetaInfo(QMap <QString, QString> metaInfo);
+    void slotSaveItem(const QString originalUrl = QString());
+    void slotOpenUrl(const QString &url);
+    void slotChangeService();
+    void slotOnline();
+    void slotOffline();
+    void slotNextPage();
+    void slotPreviousPage();
+    void slotOpenLink(const QUrl &url);
+    void slotLoadThumb(const QString url);
+    /** @brief A file download is finished */
+    void slotGotFile(KJob *job);
+    void slotSetMetadata(const QString desc);
+    void slotSetDescription(const QString desc);
+    void slotSetImage(const QString desc);
+    void slotSetTitle(const QString desc);
+
+private:
+    QString m_folder;
+    AbstractService *m_currentService;
+    void parseLicense(const QString &);
+    OnlineItemInfo m_currentInfo;
+#if KDE_IS_VERSION(4,4,0)
+    KPixmapSequenceOverlayPainter *m_busyWidget;
+#endif
+    QAction *m_autoPlay;
+    QString m_tmpThumbFile;
+    QString m_title;
+    QString m_image;
+    QString m_desc;
+    QString m_meta;
+    void updateLayout();
+   
+signals:
+    void addClip(KUrl, const QString &);
+};
+
+
+#endif
+
index 24966d7e752a4435c6ca5cd89fc569e59e252529..6782b662e65e590c0594179b8fdcecf794519c36 100644 (file)
@@ -6,15 +6,15 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>263</width>
-    <height>197</height>
+    <width>266</width>
+    <height>244</height>
    </rect>
   </property>
   <property name="windowTitle">
    <string>Dialog</string>
   </property>
-  <layout class="QGridLayout" name="gridLayout">
-   <item row="0" column="0" colspan="2">
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
     <widget class="QGroupBox" name="groupBox">
      <property name="title">
       <string/>
      <property name="flat">
       <bool>true</bool>
      </property>
-     <layout class="QHBoxLayout" name="horizontalLayout_2">
-      <property name="margin">
-       <number>0</number>
-      </property>
+     <layout class="QHBoxLayout" name="horizontalLayout">
       <item>
        <widget class="QLabel" name="label">
         <property name="text">
      </layout>
     </widget>
    </item>
-   <item row="1" column="0" colspan="2">
+   <item>
     <widget class="QCheckBox" name="compressed_archive">
      <property name="text">
       <string>Compressed archive</string>
      </property>
     </widget>
    </item>
-   <item row="2" column="0" colspan="2">
-    <layout class="QHBoxLayout" name="horizontalLayout">
+   <item>
+    <widget class="QCheckBox" name="proxy_only">
+     <property name="text">
+      <string>Archive only proxy clips when available</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
      <item>
       <widget class="QLabel" name="icon_info">
        <property name="sizePolicy">
      </item>
     </layout>
    </item>
-   <item row="3" column="0" colspan="2">
+   <item>
     <widget class="QLabel" name="project_files">
      <property name="text">
       <string/>
      </property>
     </widget>
    </item>
-   <item row="4" column="0" colspan="2">
+   <item>
     <widget class="QTreeWidget" name="files_list">
      <property name="alternatingRowColors">
       <bool>true</bool>
      </column>
     </widget>
    </item>
-   <item row="5" column="0">
-    <widget class="QProgressBar" name="progressBar">
-     <property name="value">
-      <number>0</number>
-     </property>
-    </widget>
-   </item>
-   <item row="5" column="1">
-    <widget class="QDialogButtonBox" name="buttonBox">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="standardButtons">
-      <set>QDialogButtonBox::Apply|QDialogButtonBox::Close</set>
-     </property>
-    </widget>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_3">
+     <item>
+      <widget class="QProgressBar" name="progressBar">
+       <property name="value">
+        <number>0</number>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QDialogButtonBox" name="buttonBox">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="standardButtons">
+        <set>QDialogButtonBox::Apply|QDialogButtonBox::Close</set>
+       </property>
+      </widget>
+     </item>
+    </layout>
    </item>
   </layout>
  </widget>
index 62bf44926720421bbfa33a49339fd9c64a7c4c6e..41cb747d8347e8de9b6844ed4e0f9bda8a4ce6f1 100644 (file)
@@ -6,26 +6,23 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>280</width>
-    <height>503</height>
+    <width>298</width>
+    <height>512</height>
    </rect>
   </property>
   <property name="windowTitle">
    <string>Clip Properties</string>
   </property>
   <layout class="QGridLayout" name="gridLayout_2">
-   <item row="7" column="1" colspan="2">
-    <spacer name="verticalSpacer_4">
-     <property name="orientation">
-      <enum>Qt::Vertical</enum>
+   <item row="0" column="0" colspan="4">
+    <widget class="QLabel" name="clip_thumb">
+     <property name="text">
+      <string>Image preview</string>
      </property>
-     <property name="sizeHint" stdset="0">
-      <size>
-       <width>20</width>
-       <height>17</height>
-      </size>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
      </property>
-    </spacer>
+    </widget>
    </item>
    <item row="1" column="0" colspan="4">
     <widget class="QLabel" name="label_path">
      </property>
     </widget>
    </item>
-   <item row="8" column="0" colspan="4">
-    <widget class="QDialogButtonBox" name="buttonBox">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="standardButtons">
-      <set>QDialogButtonBox::Apply|QDialogButtonBox::Close|QDialogButtonBox::Ok</set>
-     </property>
-    </widget>
-   </item>
-   <item row="0" column="0" colspan="4">
-    <widget class="QLabel" name="clip_thumb">
-     <property name="text">
-      <string>Image preview</string>
-     </property>
-     <property name="alignment">
-      <set>Qt::AlignCenter</set>
-     </property>
-    </widget>
-   </item>
-   <item row="6" column="0" colspan="4">
+   <item row="7" column="0" colspan="4">
     <widget class="QTabWidget" name="tabWidget">
      <property name="tabPosition">
       <enum>QTabWidget::South</enum>
      </widget>
     </widget>
    </item>
+   <item row="8" column="1" colspan="2">
+    <spacer name="verticalSpacer_4">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>17</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="9" column="0" colspan="4">
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Apply|QDialogButtonBox::Close|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+   <item row="6" column="0" colspan="4">
+    <widget class="KUrlLabel" name="clip_license">
+     <property name="text">
+      <string/>
+     </property>
+    </widget>
+   </item>
   </layout>
  </widget>
  <customwidgets>
-  <customwidget>
-   <class>KIntSpinBox</class>
-   <extends>QSpinBox</extends>
-   <header>knuminput.h</header>
-  </customwidget>
   <customwidget>
    <class>KDoubleNumInput</class>
    <extends>QWidget</extends>
    <header>knuminput.h</header>
   </customwidget>
   <customwidget>
-   <class>KLineEdit</class>
-   <extends>QLineEdit</extends>
-   <header>klineedit.h</header>
+   <class>KColorButton</class>
+   <extends>QPushButton</extends>
+   <header>kcolorbutton.h</header>
   </customwidget>
   <customwidget>
    <class>KComboBox</class>
    <header>kcombobox.h</header>
   </customwidget>
   <customwidget>
-   <class>KColorButton</class>
-   <extends>QPushButton</extends>
-   <header>kcolorbutton.h</header>
+   <class>KLineEdit</class>
+   <extends>QLineEdit</extends>
+   <header>klineedit.h</header>
+  </customwidget>
+  <customwidget>
+   <class>KUrlLabel</class>
+   <extends>QLabel</extends>
+   <header>kurllabel.h</header>
   </customwidget>
   <customwidget>
    <class>KRestrictedLine</class>
    <extends>KLineEdit</extends>
    <header>krestrictedline.h</header>
   </customwidget>
+  <customwidget>
+   <class>KIntSpinBox</class>
+   <extends>QSpinBox</extends>
+   <header>knuminput.h</header>
+  </customwidget>
  </customwidgets>
  <resources/>
  <connections>
diff --git a/src/widgets/clipstabilize_ui.ui b/src/widgets/clipstabilize_ui.ui
new file mode 100644 (file)
index 0000000..7510b0e
--- /dev/null
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ClipStabilize_UI</class>
+ <widget class="QDialog" name="ClipStabilize_UI">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>290</width>
+    <height>198</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0">
+    <widget class="QLabel" name="label_dest">
+     <property name="text">
+      <string>Destination</string>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="1" colspan="2">
+    <widget class="KUrlRequester" name="dest_url"/>
+   </item>
+   <item row="1" column="0" colspan="3">
+    <widget class="QLabel" name="label_3">
+     <property name="text">
+      <string>Options</string>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="0" colspan="3">
+    <widget class="QWidget" name="optionsbox" native="true">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Expanding" vsizetype="Maximum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+    </widget>
+   </item>
+   <item row="5" column="2">
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Abort|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="0" colspan="2">
+    <widget class="QCheckBox" name="auto_add">
+     <property name="text">
+      <string>Add clip to project</string>
+     </property>
+    </widget>
+   </item>
+   <item row="5" column="0" colspan="2">
+    <spacer name="horizontalSpacer">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>40</width>
+       <height>20</height>
+      </size>
+     </property>
+    </spacer>
+   </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>ClipStabilize_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>ClipStabilize_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>
index 371a78d15cd57e3f6ef7d332e31cda0265ecbb0a..08652d62d90d70a64798c8ec407b5d535c3a6eff 100644 (file)
@@ -7,7 +7,7 @@
     <x>0</x>
     <y>0</y>
     <width>405</width>
-    <height>545</height>
+    <height>479</height>
    </rect>
   </property>
   <layout class="QGridLayout" name="gridLayout_8">
@@ -39,7 +39,7 @@
      </item>
      <item>
       <property name="text">
-       <string>Video4Linux</string>
+       <string>FFmpeg</string>
       </property>
      </item>
      <item>
@@ -63,7 +63,7 @@
       </size>
      </property>
      <property name="currentIndex">
-      <number>1</number>
+      <number>0</number>
      </property>
      <widget class="QWidget" name="tab">
       <attribute name="title">
      </widget>
      <widget class="QWidget" name="tab_2">
       <attribute name="title">
-       <string>Video4Linux</string>
+       <string>FFmpeg</string>
       </attribute>
       <layout class="QGridLayout" name="gridLayout">
-       <item row="0" column="0" colspan="2">
+       <item row="1" column="0" colspan="2">
         <widget class="QLabel" name="label_30">
          <property name="text">
           <string>Detected devices</string>
          </property>
         </widget>
        </item>
-       <item row="0" column="4" colspan="4">
+       <item row="1" column="4" colspan="4">
         <widget class="KComboBox" name="kcfg_detectedv4ldevices"/>
        </item>
-       <item row="1" column="0" colspan="2">
+       <item row="2" column="0" colspan="2">
         <widget class="QLabel" name="label_14">
          <property name="text">
           <string>Video device</string>
          </property>
         </widget>
        </item>
-       <item row="1" column="4" colspan="4">
+       <item row="2" column="4" colspan="4">
         <widget class="KLineEdit" name="kcfg_video4vdevice">
          <property name="text">
           <string/>
          </property>
         </widget>
        </item>
-       <item row="2" column="0" colspan="2">
+       <item row="3" column="0" colspan="2">
         <widget class="QLabel" name="label_9">
          <property name="text">
           <string>Capture format</string>
          </property>
         </widget>
        </item>
-       <item row="2" column="4" colspan="4">
+       <item row="3" column="4" colspan="4">
         <widget class="KComboBox" name="kcfg_v4l_format"/>
        </item>
-       <item row="3" column="0">
+       <item row="4" column="0">
         <widget class="QLabel" name="label_6">
          <property name="text">
           <string>Size:</string>
          </property>
         </widget>
        </item>
-       <item row="3" column="4" colspan="4">
+       <item row="4" column="4" colspan="4">
         <widget class="QLabel" name="p_size">
          <property name="text">
           <string>720x576</string>
          </property>
         </widget>
        </item>
-       <item row="4" column="0" colspan="2">
+       <item row="5" column="0" colspan="2">
         <widget class="QLabel" name="label_4">
          <property name="text">
           <string>Frame rate:</string>
          </property>
         </widget>
        </item>
-       <item row="4" column="4" colspan="4">
+       <item row="5" column="4" colspan="4">
         <widget class="QLabel" name="p_fps">
          <property name="text">
           <string>25/1</string>
          </property>
         </widget>
        </item>
-       <item row="5" column="0" colspan="2">
+       <item row="6" column="0" colspan="2">
         <widget class="QLabel" name="label_23">
          <property name="text">
           <string>Pixel aspect ratio:</string>
          </property>
         </widget>
        </item>
-       <item row="5" column="4" colspan="4">
+       <item row="6" column="4" colspan="4">
         <widget class="QLabel" name="p_aspect">
          <property name="text">
           <string>59/54</string>
          </property>
         </widget>
        </item>
-       <item row="6" column="0" colspan="3">
+       <item row="7" column="0" colspan="3">
         <widget class="QLabel" name="label_31">
          <property name="text">
           <string>Display aspect ratio:</string>
          </property>
         </widget>
        </item>
-       <item row="6" column="4" colspan="4">
+       <item row="7" column="4" colspan="4">
         <widget class="QLabel" name="p_display">
          <property name="text">
           <string>4/3</string>
          </property>
         </widget>
        </item>
-       <item row="7" column="0" colspan="2">
+       <item row="8" column="0" colspan="2">
         <widget class="QLabel" name="label_32">
          <property name="text">
           <string>Colorspace</string>
          </property>
         </widget>
        </item>
-       <item row="7" column="4" colspan="4">
+       <item row="8" column="4" colspan="4">
         <widget class="QLabel" name="p_colorspace">
          <property name="text">
           <string/>
          </property>
         </widget>
        </item>
-       <item row="8" column="0" colspan="2">
+       <item row="9" column="0" colspan="2">
         <widget class="QLabel" name="p_progressive">
          <property name="text">
           <string>Interlaced</string>
          </property>
         </widget>
        </item>
-       <item row="8" column="4" colspan="2">
+       <item row="9" column="4" colspan="2">
         <spacer name="horizontalSpacer_5">
          <property name="orientation">
           <enum>Qt::Horizontal</enum>
          </property>
         </spacer>
        </item>
-       <item row="8" column="6" colspan="2">
+       <item row="9" column="6" colspan="2">
         <widget class="QPushButton" name="config_v4l">
          <property name="text">
           <string>Edit</string>
          </property>
         </widget>
        </item>
-       <item row="9" column="0" rowspan="4" colspan="8">
+       <item row="10" column="0" rowspan="4" colspan="8">
         <widget class="Line" name="line">
          <property name="orientation">
           <enum>Qt::Horizontal</enum>
          </property>
         </widget>
        </item>
-       <item row="13" column="0" colspan="4">
+       <item row="14" column="0" colspan="8">
         <widget class="QCheckBox" name="kcfg_v4l_captureaudio">
          <property name="text">
           <string>Capture audio (ALSA)</string>
          </property>
         </widget>
        </item>
-       <item row="14" column="0" colspan="8">
+       <item row="17" column="0" colspan="8">
         <widget class="Line" name="line_2">
          <property name="orientation">
           <enum>Qt::Horizontal</enum>
          </property>
         </widget>
        </item>
-       <item row="15" column="0" colspan="2">
+       <item row="18" column="0" colspan="2">
         <widget class="QLabel" name="label_24">
          <property name="sizePolicy">
           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
          </property>
         </widget>
        </item>
-       <item row="15" column="4">
+       <item row="18" column="4">
         <widget class="KComboBox" name="kcfg_v4l_profile">
          <property name="sizePolicy">
           <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
          </property>
         </widget>
        </item>
-       <item row="17" column="0" colspan="8">
+       <item row="20" column="0" colspan="8">
         <widget class="QPlainTextEdit" name="v4l_parameters">
-         <property name="sizePolicy">
-          <sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
-           <horstretch>0</horstretch>
-           <verstretch>0</verstretch>
-          </sizepolicy>
-         </property>
          <property name="readOnly">
           <bool>true</bool>
          </property>
         </widget>
        </item>
-       <item row="18" column="1" colspan="4">
+       <item row="21" column="1" colspan="4">
         <spacer name="verticalSpacer">
          <property name="orientation">
           <enum>Qt::Vertical</enum>
          </property>
         </spacer>
        </item>
-       <item row="13" column="4" colspan="4">
-        <widget class="KComboBox" name="kcfg_v4l_alsadevice">
-         <property name="enabled">
-          <bool>false</bool>
-         </property>
-         <property name="sizePolicy">
-          <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
-           <horstretch>0</horstretch>
-           <verstretch>0</verstretch>
-          </sizepolicy>
-         </property>
-        </widget>
-       </item>
-       <item row="15" column="7">
+       <item row="18" column="7">
         <widget class="QToolButton" name="v4l_manageprofile">
          <property name="text">
           <string>...</string>
          </property>
         </widget>
        </item>
-       <item row="15" column="6">
+       <item row="18" column="6">
         <widget class="QToolButton" name="v4l_showprofileinfo">
          <property name="text">
           <string>...</string>
          </property>
         </widget>
        </item>
+       <item row="15" column="0">
+        <widget class="QLabel" name="label_3">
+         <property name="text">
+          <string>Device</string>
+         </property>
+        </widget>
+       </item>
+       <item row="15" column="4" colspan="4">
+        <widget class="KComboBox" name="kcfg_v4l_alsadevice">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="0" colspan="8">
+        <widget class="QCheckBox" name="kcfg_v4l_capturevideo">
+         <property name="text">
+          <string>Capture video (Video4Linux2)</string>
+         </property>
+        </widget>
+       </item>
       </layout>
      </widget>
      <widget class="QWidget" name="tab_3">
   </layout>
  </widget>
  <customwidgets>
-  <customwidget>
-   <class>KIntSpinBox</class>
-   <extends>QSpinBox</extends>
-   <header>knuminput.h</header>
-  </customwidget>
   <customwidget>
    <class>KDoubleNumInput</class>
    <extends>QWidget</extends>
    <header>knuminput.h</header>
   </customwidget>
+  <customwidget>
+   <class>KComboBox</class>
+   <extends>QComboBox</extends>
+   <header>kcombobox.h</header>
+  </customwidget>
   <customwidget>
    <class>KLineEdit</class>
    <extends>QLineEdit</extends>
    <header>klineedit.h</header>
   </customwidget>
   <customwidget>
-   <class>KComboBox</class>
-   <extends>QComboBox</extends>
-   <header>kcombobox.h</header>
+   <class>KIntSpinBox</class>
+   <extends>QSpinBox</extends>
+   <header>knuminput.h</header>
   </customwidget>
   <customwidget>
    <class>KIntNumInput</class>
index 545608056a5a83a450603cee32ad6b209af3f3cc..41baee6572ed02d6af24a8618d886c3c78861513 100644 (file)
@@ -7,7 +7,7 @@
     <x>0</x>
     <y>0</y>
     <width>297</width>
-    <height>215</height>
+    <height>244</height>
    </rect>
   </property>
   <layout class="QGridLayout" name="gridLayout">
       <item row="0" column="0">
        <widget class="QLabel" name="label_9">
         <property name="text">
-         <string>Processing threads</string>
+         <string>Concurrent threads</string>
         </property>
        </widget>
       </item>
index 7b900cac1db4f0ffd71a8b8d7405b7f0f9fbd87d..35a06ac8b4ce55f4e15e249ad4bce924fd954e59 100644 (file)
@@ -6,55 +6,40 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>366</width>
-    <height>183</height>
+    <width>319</width>
+    <height>306</height>
    </rect>
   </property>
   <layout class="QGridLayout" name="gridLayout">
-   <property name="leftMargin">
-    <number>0</number>
-   </property>
-   <property name="topMargin">
-    <number>0</number>
-   </property>
-   <item row="0" column="0" colspan="3">
-    <widget class="QTreeWidget" name="profiles_list">
+   <item row="0" column="0" colspan="4">
+    <widget class="QListWidget" name="profiles_list">
      <property name="alternatingRowColors">
       <bool>true</bool>
      </property>
-     <property name="rootIsDecorated">
-      <bool>false</bool>
-     </property>
-     <property name="allColumnsShowFocus">
-      <bool>true</bool>
-     </property>
-     <column>
-      <property name="text">
-       <string>Name</string>
-      </property>
-     </column>
-     <column>
-      <property name="text">
-       <string>FFmpeg parameters</string>
-      </property>
-     </column>
     </widget>
    </item>
-   <item row="1" column="0">
+   <item row="2" column="0">
     <widget class="QPushButton" name="button_add">
      <property name="text">
       <string>Add Profile</string>
      </property>
     </widget>
    </item>
-   <item row="1" column="1">
+   <item row="2" column="1">
+    <widget class="QPushButton" name="button_update">
+     <property name="text">
+      <string>Update Profile</string>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="2">
     <widget class="QPushButton" name="button_delete">
      <property name="text">
       <string>Delete Profile</string>
      </property>
     </widget>
    </item>
-   <item row="1" column="2">
+   <item row="2" column="3">
     <spacer name="horizontalSpacer">
      <property name="orientation">
       <enum>Qt::Horizontal</enum>
      </property>
     </spacer>
    </item>
+   <item row="1" column="0" colspan="4">
+    <widget class="QGroupBox" name="profile_box">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="title">
+      <string/>
+     </property>
+     <layout class="QGridLayout" name="gridLayout_2">
+      <item row="0" column="0">
+       <widget class="QLabel" name="label">
+        <property name="text">
+         <string>Name</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="1" colspan="2">
+       <widget class="QLineEdit" name="profile_name"/>
+      </item>
+      <item row="1" column="0">
+       <widget class="QLabel" name="label_2">
+        <property name="text">
+         <string>Description</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="1" colspan="2">
+       <widget class="QLineEdit" name="profile_description"/>
+      </item>
+      <item row="2" column="0">
+       <widget class="QLabel" name="label_3">
+        <property name="text">
+         <string>Extension</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="1">
+       <widget class="QLineEdit" name="profile_extension"/>
+      </item>
+      <item row="2" column="2">
+       <widget class="QCheckBox" name="profile_audioonly">
+        <property name="text">
+         <string>Audio only</string>
+        </property>
+       </widget>
+      </item>
+      <item row="3" column="0" colspan="3">
+       <widget class="QLabel" name="label_4">
+        <property name="text">
+         <string>Parameters</string>
+        </property>
+       </widget>
+      </item>
+      <item row="4" column="0" colspan="3">
+       <widget class="QPlainTextEdit" name="profile_parameters"/>
+      </item>
+     </layout>
+    </widget>
+   </item>
   </layout>
  </widget>
  <resources/>
diff --git a/src/widgets/cutjobdialog_ui.ui b/src/widgets/cutjobdialog_ui.ui
new file mode 100644 (file)
index 0000000..3652fbc
--- /dev/null
@@ -0,0 +1,155 @@
+<?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>382</width>
+    <height>199</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Cut Clip</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0" colspan="2">
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <widget class="QLabel" name="info_label">
+       <property name="text">
+        <string/>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QToolButton" name="button_more">
+       <property name="toolTip">
+        <string>Configure job</string>
+       </property>
+       <property name="text">
+        <string>...</string>
+       </property>
+       <property name="checkable">
+        <bool>true</bool>
+       </property>
+       <property name="autoRaise">
+        <bool>false</bool>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item row="1" column="0">
+    <widget class="QLabel" name="destination_label">
+     <property name="text">
+      <string>Save to</string>
+     </property>
+    </widget>
+   </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="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="0" colspan="2">
+    <widget class="QTextEdit" name="extra_params">
+     <property name="toolTip">
+      <string/>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="0">
+    <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="5" 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>
+  <connection>
+   <sender>button_more</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>extra_params</receiver>
+   <slot>setVisible(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>17</x>
+     <y>16</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>123</x>
+     <y>131</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/src/widgets/fontval_ui.ui b/src/widgets/fontval_ui.ui
new file mode 100644 (file)
index 0000000..b1a4937
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Fontval_UI</class>
+ <widget class="QWidget" name="Fontval_UI">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>200</width>
+    <height>60</height>
+   </rect>
+  </property>
+  <layout class="QGridLayout">
+   <property name="margin">
+    <number>0</number>
+   </property>
+   <property name="spacing">
+    <number>0</number>
+   </property>
+   <item row="0" column="0">
+    <widget class="QLabel" name="name">
+     <property name="text">
+      <string>TextLabel</string>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="1">
+    <widget class="QFontComboBox" name="fontfamilywidget"/>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/widgets/freesound_ui.ui b/src/widgets/freesound_ui.ui
new file mode 100644 (file)
index 0000000..aab6824
--- /dev/null
@@ -0,0 +1,243 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>FreeSound_UI</class>
+ <widget class="QDialog" name="FreeSound_UI">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>424</width>
+    <height>391</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_2">
+   <item row="0" column="0" colspan="5">
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <widget class="QLabel" name="label_3">
+       <property name="text">
+        <string>Service</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QComboBox" name="service_list">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QToolButton" name="config_button">
+       <property name="text">
+        <string>...</string>
+       </property>
+       <property name="popupMode">
+        <enum>QToolButton::InstantPopup</enum>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item row="1" column="0" colspan="2">
+    <widget class="KLineEdit" name="search_text">
+     <property name="clickMessage">
+      <string/>
+     </property>
+     <property name="showClearButton" stdset="0">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="2" colspan="2">
+    <widget class="QPushButton" name="button_search">
+     <property name="text">
+      <string>Search</string>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="0" colspan="4">
+    <widget class="QListWidget" name="search_results">
+     <property name="alternatingRowColors">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="0">
+    <widget class="QPushButton" name="page_prev">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="text">
+      <string>&lt;&lt;</string>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="1" colspan="2">
+    <widget class="QSpinBox" name="page_number">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="minimum">
+      <number>1</number>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="3">
+    <widget class="QPushButton" name="page_next">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="text">
+      <string>&gt;&gt;</string>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="0" colspan="5">
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <item>
+      <widget class="QLabel" name="search_info">
+       <property name="text">
+        <string/>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QDialogButtonBox" name="ButtonBox">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="standardButtons">
+        <set>QDialogButtonBox::Close</set>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item row="1" column="4" rowspan="3">
+    <widget class="QGroupBox" name="sound_box">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="title">
+      <string/>
+     </property>
+     <layout class="QGridLayout" name="gridLayout">
+      <item row="5" column="1" colspan="2">
+       <widget class="QPushButton" name="button_import">
+        <property name="text">
+         <string>Import</string>
+        </property>
+       </widget>
+      </item>
+      <item row="5" column="0">
+       <widget class="QPushButton" name="button_preview">
+        <property name="text">
+         <string>Preview</string>
+        </property>
+       </widget>
+      </item>
+      <item row="4" column="0">
+       <widget class="QLabel" name="label">
+        <property name="text">
+         <string>License</string>
+        </property>
+       </widget>
+      </item>
+      <item row="4" column="1" colspan="2">
+       <widget class="KUrlLabel" name="item_license">
+        <property name="text">
+         <string/>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="0" colspan="3">
+       <widget class="QTextBrowser" name="info_browser">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="frameShape">
+         <enum>QFrame::NoFrame</enum>
+        </property>
+        <property name="openExternalLinks">
+         <bool>false</bool>
+        </property>
+        <property name="openLinks">
+         <bool>false</bool>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>KLineEdit</class>
+   <extends>QLineEdit</extends>
+   <header>klineedit.h</header>
+  </customwidget>
+  <customwidget>
+   <class>KUrlLabel</class>
+   <extends>QLabel</extends>
+   <header>kurllabel.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>ButtonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>FreeSound_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>FreeSound_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>
index 56296b394912d262366ab48239554a3a5b4dccb2..e720b3e3495b3dc792fb505b20747ee12d5821e1 100644 (file)
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>133</width>
-    <height>85</height>
+    <width>129</width>
+    <height>86</height>
    </rect>
   </property>
   <layout class="QGridLayout" name="gridLayout_3">
         <property name="minimumSize">
          <size>
           <width>0</width>
-          <height>16</height>
+          <height>20</height>
          </size>
         </property>
         <property name="maximumSize">
          <size>
           <width>16777215</width>
-          <height>16</height>
+          <height>20</height>
          </size>
         </property>
        </widget>
diff --git a/src/widgets/keywordval_ui.ui b/src/widgets/keywordval_ui.ui
new file mode 100644 (file)
index 0000000..b177dc0
--- /dev/null
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Keywordval_UI</class>
+ <widget class="QWidget" name="Keywordval_UI">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>194</width>
+    <height>42</height>
+   </rect>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <property name="verticalSpacing">
+    <number>0</number>
+   </property>
+   <property name="margin">
+    <number>0</number>
+   </property>
+   <item row="0" column="0" colspan="2">
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>Param</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <widget class="QLineEdit" name="lineeditwidget"/>
+   </item>
+   <item row="2" column="0">
+    <widget class="QComboBox" name="comboboxwidget"/>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
index 6cd8c3586e26229d13807e426a37fa77fa14fc5c..3eb70eb7f55bceccf68e73c40618e8f7b2adc4a5 100644 (file)
@@ -6,7 +6,7 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>800</width>
+    <width>822</width>
     <height>265</height>
    </rect>
   </property>
      <property name="selectionMode">
       <enum>QAbstractItemView::ExtendedSelection</enum>
      </property>
-     <property name="rootIsDecorated">
-      <bool>false</bool>
-     </property>
      <property name="itemsExpandable">
-      <bool>false</bool>
+      <bool>true</bool>
      </property>
      <property name="sortingEnabled">
       <bool>true</bool>
index 2b4bbf3ccfc8a12392db8d1bbb658190ab1bb0d3..c55ebb3589eefb9766cc2df5b49ca1e81d5212e1 100644 (file)
@@ -6,24 +6,38 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>337</width>
-    <height>523</height>
+    <width>345</width>
+    <height>524</height>
    </rect>
   </property>
   <property name="windowTitle">
    <string>Project Settings</string>
   </property>
   <layout class="QGridLayout" name="gridLayout_3">
-   <property name="leftMargin">
-    <number>0</number>
-   </property>
-   <property name="rightMargin">
-    <number>0</number>
-   </property>
-   <property name="bottomMargin">
-    <number>0</number>
-   </property>
-   <item row="0" column="0" colspan="2">
+   <item row="1" column="0">
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>334</width>
+       <height>484</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="2" column="0">
+    <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>
+   <item row="0" column="0">
     <widget class="QTabWidget" name="tabWidget">
      <property name="currentIndex">
       <number>0</number>
@@ -35,7 +49,7 @@
       <attribute name="title">
        <string>Settings</string>
       </attribute>
-      <layout class="QGridLayout" name="gridLayout_6">
+      <layout class="QGridLayout" name="gridLayout_5">
        <item row="0" column="0">
         <widget class="QLabel" name="label_4">
          <property name="text">
          </layout>
         </widget>
        </item>
-       <item row="6" column="0" colspan="4">
-        <widget class="QDialogButtonBox" name="buttonBox">
-         <property name="orientation">
-          <enum>Qt::Horizontal</enum>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="tab_3">
+      <attribute name="title">
+       <string>Metadata</string>
+      </attribute>
+      <layout class="QGridLayout" name="gridLayout_6">
+       <item row="0" column="0">
+        <widget class="QTreeWidget" name="metadata_list">
+         <property name="alternatingRowColors">
+          <bool>true</bool>
          </property>
-         <property name="standardButtons">
-          <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+         <property name="rootIsDecorated">
+          <bool>false</bool>
          </property>
-        </widget>
-       </item>
-       <item row="5" column="2">
-        <spacer name="verticalSpacer">
-         <property name="orientation">
-          <enum>Qt::Vertical</enum>
+         <property name="allColumnsShowFocus">
+          <bool>true</bool>
          </property>
-         <property name="sizeHint" stdset="0">
-          <size>
-           <width>20</width>
-           <height>40</height>
-          </size>
+         <property name="columnCount">
+          <number>2</number>
          </property>
-        </spacer>
+         <attribute name="headerVisible">
+          <bool>false</bool>
+         </attribute>
+         <column>
+          <property name="text">
+           <string>1</string>
+          </property>
+         </column>
+         <column>
+          <property name="text">
+           <string>2</string>
+          </property>
+         </column>
+        </widget>
        </item>
       </layout>
      </widget>
  </widget>
  <customwidgets>
   <customwidget>
-   <class>KIntSpinBox</class>
-   <extends>QSpinBox</extends>
-   <header>knuminput.h</header>
-  </customwidget>
-  <customwidget>
-   <class>KUrlRequester</class>
-   <extends>QFrame</extends>
-   <header>kurlrequester.h</header>
+   <class>KComboBox</class>
+   <extends>QComboBox</extends>
+   <header>kcombobox.h</header>
   </customwidget>
   <customwidget>
-   <class>KTreeWidgetSearchLine</class>
-   <extends>KLineEdit</extends>
-   <header>ktreewidgetsearchline.h</header>
+   <class>KLineEdit</class>
+   <extends>QLineEdit</extends>
+   <header>klineedit.h</header>
   </customwidget>
   <customwidget>
    <class>KPushButton</class>
    <header>kpushbutton.h</header>
   </customwidget>
   <customwidget>
-   <class>KLineEdit</class>
-   <extends>QLineEdit</extends>
-   <header>klineedit.h</header>
+   <class>KIntSpinBox</class>
+   <extends>QSpinBox</extends>
+   <header>knuminput.h</header>
   </customwidget>
   <customwidget>
-   <class>KComboBox</class>
-   <extends>QComboBox</extends>
-   <header>kcombobox.h</header>
+   <class>KTreeWidgetSearchLine</class>
+   <extends>KLineEdit</extends>
+   <header>ktreewidgetsearchline.h</header>
+  </customwidget>
+  <customwidget>
+   <class>KUrlRequester</class>
+   <extends>QFrame</extends>
+   <header>kurlrequester.h</header>
   </customwidget>
  </customwidgets>
  <resources/>
index 6194a34fbe87041c92e06b1f9aa482463c2ded43..3eb18358976e5ea2881e913c54924d8a6081157b 100644 (file)
@@ -6,15 +6,15 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>291</width>
-    <height>184</height>
+    <width>285</width>
+    <height>157</height>
    </rect>
   </property>
   <layout class="QGridLayout" name="gridLayout">
    <property name="margin">
     <number>0</number>
    </property>
-   <item row="0" column="0" colspan="4">
+   <item row="0" column="0" colspan="6">
     <widget class="QLabel" name="video_frame">
      <property name="text">
       <string>Not connected</string>
@@ -24,7 +24,7 @@
      </property>
     </widget>
    </item>
-   <item row="1" column="0" colspan="4">
+   <item row="1" column="0" colspan="6">
     <widget class="QFrame" name="control_frame_firewire">
      <property name="sizePolicy">
       <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
      </property>
     </widget>
    </item>
-   <item row="2" column="0">
-    <widget class="QCheckBox" name="autoaddbox">
-     <property name="text">
-      <string>Auto add</string>
-     </property>
-     <property name="checked">
-      <bool>true</bool>
-     </property>
-    </widget>
-   </item>
-   <item row="2" column="3">
+   <item row="2" column="5">
     <widget class="KComboBox" name="device_selector">
      <item>
       <property name="text">
@@ -65,7 +55,7 @@
      </item>
      <item>
       <property name="text">
-       <string>Video4Linux</string>
+       <string>FFmpeg</string>
       </property>
      </item>
      <item>
@@ -80,7 +70,7 @@
      </item>
     </widget>
    </item>
-   <item row="2" column="2">
+   <item row="2" column="4">
     <spacer name="horizontalSpacer">
      <property name="orientation">
       <enum>Qt::Horizontal</enum>
     </spacer>
    </item>
    <item row="2" column="1">
-    <widget class="QComboBox" name="recording_preview">
-     <item>
-      <property name="text">
-       <string>Quick preview</string>
-      </property>
-     </item>
-     <item>
-      <property name="text">
-       <string>Full preview</string>
-      </property>
-     </item>
-     <item>
-      <property name="text">
-       <string>No preview</string>
-      </property>
-     </item>
+    <widget class="QCheckBox" name="rec_video">
+     <property name="text">
+      <string>Video</string>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="2">
+    <widget class="QCheckBox" name="rec_audio">
+     <property name="text">
+      <string>Audio</string>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="0">
+    <widget class="QToolButton" name="rec_options">
+     <property name="text">
+      <string>...</string>
+     </property>
+     <property name="popupMode">
+      <enum>QToolButton::InstantPopup</enum>
+     </property>
+     <property name="autoRaise">
+      <bool>true</bool>
+     </property>
     </widget>
    </item>
   </layout>
index 76edaeca29e47f3484788fef8ef8f4ba2d132765..ee9e11b63bc4ee2414f0ab0a17e591bded07483c 100644 (file)
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>402</width>
-    <height>681</height>
+    <width>406</width>
+    <height>677</height>
    </rect>
   </property>
   <property name="windowTitle">
       <attribute name="title">
        <string>Render Project</string>
       </attribute>
-      <layout class="QGridLayout" name="gridLayout_7">
-       <item row="0" column="0" colspan="2">
+      <layout class="QGridLayout" name="gridLayout">
+       <item row="0" column="0">
         <widget class="QLabel" name="label_6">
          <property name="text">
           <string>Destination</string>
          </property>
         </widget>
        </item>
-       <item row="0" column="2" colspan="2">
+       <item row="0" column="3" colspan="2">
         <widget class="KComboBox" name="destination_list"/>
        </item>
-       <item row="1" column="0" colspan="2">
+       <item row="1" column="0">
         <widget class="QLabel" name="label">
          <property name="text">
           <string>Output file</string>
          </property>
         </widget>
        </item>
-       <item row="1" column="2" colspan="2">
+       <item row="1" column="3" colspan="2">
         <widget class="KUrlRequester" name="out_file"/>
        </item>
-       <item row="2" column="0">
-        <widget class="QToolButton" name="buttonInfo">
-         <property name="text">
-          <string>I</string>
-         </property>
-        </widget>
-       </item>
-       <item row="2" column="1" colspan="2">
-        <spacer name="horizontalSpacer_2">
-         <property name="orientation">
-          <enum>Qt::Horizontal</enum>
-         </property>
-         <property name="sizeHint" stdset="0">
-          <size>
-           <width>124</width>
-           <height>23</height>
-          </size>
-         </property>
-        </spacer>
-       </item>
-       <item row="2" column="3">
+       <item row="2" column="0" colspan="5">
         <layout class="QHBoxLayout" name="horizontalLayout_4">
+         <item>
+          <widget class="QToolButton" name="buttonInfo">
+           <property name="text">
+            <string>I</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QCheckBox" name="show_all_profiles">
+           <property name="text">
+            <string>Show all profiles</string>
+           </property>
+          </widget>
+         </item>
          <item>
           <widget class="QToolButton" name="buttonFavorite">
            <property name="text">
          </item>
         </layout>
        </item>
-       <item row="3" column="0" colspan="4">
+       <item row="3" column="0" colspan="5">
         <widget class="QSplitter" name="splitter_3">
          <property name="orientation">
           <enum>Qt::Vertical</enum>
          </widget>
         </widget>
        </item>
-       <item row="4" column="0" colspan="2">
+       <item row="4" column="0">
         <widget class="QLabel" name="label_5">
          <property name="text">
           <string>Scanning</string>
          </property>
         </widget>
        </item>
-       <item row="4" column="2">
+       <item row="4" column="3">
         <widget class="KComboBox" name="scanning_list">
          <item>
           <property name="text">
          </item>
         </widget>
        </item>
-       <item row="4" column="3" rowspan="4">
+       <item row="4" column="4" rowspan="4">
         <widget class="QGroupBox" name="groupBox">
          <property name="title">
           <string>Bitrate</string>
          </property>
         </widget>
        </item>
-       <item row="5" column="2">
+       <item row="5" column="3">
         <widget class="KIntNumInput" name="encoder_threads">
          <property name="minimum">
           <number>1</number>
          </property>
         </widget>
        </item>
-       <item row="6" column="0" colspan="3">
+       <item row="6" column="0" colspan="4">
         <widget class="QCheckBox" name="export_audio">
          <property name="text">
           <string>Export audio</string>
          </property>
         </widget>
        </item>
-       <item row="7" column="0" colspan="2">
+       <item row="7" column="0">
         <widget class="QCheckBox" name="checkTwoPass">
          <property name="text">
           <string>2 pass</string>
          </property>
         </widget>
        </item>
-       <item row="7" column="2">
+       <item row="7" column="3">
         <widget class="QCheckBox" name="proxy_render">
          <property name="text">
           <string>Render using proxy clips</string>
          </property>
         </widget>
        </item>
-       <item row="8" column="0" colspan="4">
-        <layout class="QHBoxLayout" name="horizontalLayout_2">
-         <item>
-          <widget class="QCheckBox" name="rescale">
-           <property name="text">
-            <string>Rescale</string>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <widget class="QGroupBox" name="rescale_box">
-           <property name="title">
-            <string/>
-           </property>
-           <property name="flat">
-            <bool>true</bool>
-           </property>
-           <property name="checkable">
-            <bool>false</bool>
-           </property>
-           <layout class="QGridLayout" name="gridLayout">
-            <property name="margin">
-             <number>0</number>
-            </property>
-            <item row="0" column="1">
-             <widget class="QLabel" name="label_8">
-              <property name="text">
-               <string>x</string>
-              </property>
-             </widget>
-            </item>
-            <item row="0" column="2">
-             <widget class="KIntNumInput" name="rescale_height">
-              <property name="minimum">
-               <number>0</number>
-              </property>
-             </widget>
-            </item>
-            <item row="0" column="3">
-             <widget class="QToolButton" name="rescale_keep">
-              <property name="text">
-               <string>...</string>
-              </property>
-              <property name="checkable">
-               <bool>true</bool>
-              </property>
-             </widget>
-            </item>
-            <item row="0" column="0">
-             <widget class="KIntNumInput" name="rescale_width">
-              <property name="minimum">
-               <number>0</number>
-              </property>
-             </widget>
-            </item>
-            <item row="0" column="4">
-             <spacer name="horizontalSpacer_5">
-              <property name="orientation">
-               <enum>Qt::Horizontal</enum>
-              </property>
-              <property name="sizeHint" stdset="0">
-               <size>
-                <width>40</width>
-                <height>20</height>
-               </size>
-              </property>
-             </spacer>
-            </item>
-           </layout>
-          </widget>
-         </item>
-        </layout>
+       <item row="8" column="0">
+        <widget class="QCheckBox" name="rescale">
+         <property name="text">
+          <string>Rescale</string>
+         </property>
+        </widget>
        </item>
-       <item row="9" column="0" colspan="4">
+       <item row="9" column="0" colspan="5">
         <widget class="QCheckBox" name="open_dvd">
          <property name="text">
           <string>Open Dvd wizard after rendering</string>
          </property>
         </widget>
        </item>
-       <item row="10" column="0" colspan="4">
+       <item row="10" column="0" colspan="5">
         <widget class="QCheckBox" name="create_chapter">
          <property name="text">
           <string>Create chapter file based on guides</string>
          </property>
         </widget>
        </item>
-       <item row="11" column="0" colspan="4">
+       <item row="11" column="0" colspan="5">
         <widget class="QCheckBox" name="open_browser">
          <property name="text">
           <string>Open browser window after export</string>
          </property>
         </widget>
        </item>
-       <item row="12" column="0" colspan="4">
+       <item row="12" column="0" colspan="5">
         <widget class="QCheckBox" name="play_after">
          <property name="text">
           <string>Play after render</string>
          </property>
         </widget>
        </item>
-       <item row="13" column="0" colspan="4">
+       <item row="13" column="0" colspan="5">
         <layout class="QHBoxLayout" name="horizontalLayout_5">
+         <item>
+          <widget class="QCheckBox" name="export_meta">
+           <property name="text">
+            <string>Export metadata</string>
+           </property>
+          </widget>
+         </item>
          <item>
           <widget class="QCheckBox" name="tc_overlay">
            <property name="sizePolicy">
          </item>
         </layout>
        </item>
-       <item row="14" column="0" colspan="4">
+       <item row="14" column="0" colspan="5">
         <layout class="QHBoxLayout" name="horizontalLayout">
          <item>
           <widget class="QRadioButton" name="render_full">
          </item>
         </layout>
        </item>
-       <item row="15" column="0" colspan="4">
+       <item row="15" column="0" colspan="5">
         <widget class="QGroupBox" name="guides_box">
          <property name="title">
           <string/>
          </layout>
         </widget>
        </item>
-       <item row="17" column="0" colspan="4">
+       <item row="16" column="0" colspan="5">
+        <widget class="QGroupBox" name="errorBox">
+         <property name="title">
+          <string/>
+         </property>
+         <layout class="QGridLayout" name="gridLayout_8">
+          <item row="0" column="0">
+           <widget class="QLabel" name="errorIcon">
+            <property name="text">
+             <string/>
+            </property>
+           </widget>
+          </item>
+          <item row="0" column="1">
+           <widget class="QLabel" name="errorLabel">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="text">
+             <string/>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item row="17" column="0" colspan="5">
         <layout class="QHBoxLayout" name="horizontalLayout_3">
          <item>
           <widget class="QPushButton" name="buttonRender">
          </item>
         </layout>
        </item>
-       <item row="16" column="0" colspan="4">
-        <widget class="QGroupBox" name="errorBox">
-         <property name="title">
-          <string/>
-         </property>
-         <layout class="QGridLayout" name="gridLayout_8">
-          <item row="0" column="0">
-           <widget class="QLabel" name="errorIcon">
-            <property name="text">
-             <string/>
-            </property>
-           </widget>
-          </item>
-          <item row="0" column="1">
-           <widget class="QLabel" name="errorLabel">
-            <property name="sizePolicy">
-             <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
-              <horstretch>0</horstretch>
-              <verstretch>0</verstretch>
-             </sizepolicy>
-            </property>
-            <property name="text">
-             <string/>
-            </property>
-           </widget>
-          </item>
-         </layout>
-        </widget>
+       <item row="8" column="1" colspan="4">
+        <layout class="QHBoxLayout" name="rescale_box">
+         <item>
+          <widget class="KIntNumInput" name="rescale_width">
+           <property name="minimum">
+            <number>0</number>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QLabel" name="label_8">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="text">
+            <string>x</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="KIntNumInput" name="rescale_height">
+           <property name="minimum">
+            <number>0</number>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QToolButton" name="rescale_keep">
+           <property name="text">
+            <string>...</string>
+           </property>
+           <property name="checkable">
+            <bool>true</bool>
+           </property>
+           <property name="autoRaise">
+            <bool>false</bool>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="horizontalSpacer_5">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+        </layout>
        </item>
       </layout>
      </widget>
           <property name="allColumnsShowFocus">
            <bool>true</bool>
           </property>
+          <property name="headerHidden">
+           <bool>true</bool>
+          </property>
           <property name="columnCount">
            <number>0</number>
           </property>
index c2b34e2ffc1b82bcc41c809fdb9c8809d0ae60c6..54a939f6713f54cd9af96d96a6288e7f4bac793e 100644 (file)
@@ -6,7 +6,7 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>290</width>
+    <width>294</width>
     <height>507</height>
    </rect>
   </property>
@@ -94,7 +94,7 @@
           <item row="0" column="0">
            <widget class="QLabel" name="label_5">
             <property name="text">
-             <string>Image name</string>
+             <string>First frame</string>
             </property>
            </widget>
           </item>
  </widget>
  <customwidgets>
   <customwidget>
-   <class>KIntSpinBox</class>
-   <extends>QSpinBox</extends>
-   <header>knuminput.h</header>
-  </customwidget>
-  <customwidget>
-   <class>KUrlRequester</class>
-   <extends>QFrame</extends>
-   <header>kurlrequester.h</header>
-  </customwidget>
-  <customwidget>
-   <class>KListWidget</class>
-   <extends>QListWidget</extends>
-   <header>klistwidget.h</header>
+   <class>KComboBox</class>
+   <extends>QComboBox</extends>
+   <header>kcombobox.h</header>
   </customwidget>
   <customwidget>
    <class>KLineEdit</class>
    <extends>QLineEdit</extends>
    <header>klineedit.h</header>
   </customwidget>
-  <customwidget>
-   <class>KComboBox</class>
-   <extends>QComboBox</extends>
-   <header>kcombobox.h</header>
-  </customwidget>
   <customwidget>
    <class>KRestrictedLine</class>
    <extends>KLineEdit</extends>
    <header>krestrictedline.h</header>
   </customwidget>
+  <customwidget>
+   <class>KIntSpinBox</class>
+   <extends>QSpinBox</extends>
+   <header>knuminput.h</header>
+  </customwidget>
+  <customwidget>
+   <class>KListWidget</class>
+   <extends>QListWidget</extends>
+   <header>klistwidget.h</header>
+  </customwidget>
+  <customwidget>
+   <class>KUrlRequester</class>
+   <extends>QFrame</extends>
+   <header>kurlrequester.h</header>
+  </customwidget>
  </customwidgets>
  <resources/>
  <connections>
index 777c855ac7e261312839ab1d8ba3b31c1e175ac0..b47e791c17d89d3ed5171d1f62b41c7817866cd3 100644 (file)
    </property>
    <item row="0" column="0">
     <widget class="QFrame" name="size_frame">
-     <property name="maximumSize">
-      <size>
-       <width>16777215</width>
-       <height>20</height>
-      </size>
-     </property>
      <property name="frameShape">
       <enum>QFrame::NoFrame</enum>
      </property>
        <verstretch>0</verstretch>
       </sizepolicy>
      </property>
-     <property name="maximumSize">
-      <size>
-       <width>16777215</width>
-       <height>24</height>
-      </size>
-     </property>
      <property name="frameShadow">
       <enum>QFrame::Raised</enum>
      </property>
@@ -92,7 +80,7 @@
        <rect>
         <x>0</x>
         <y>0</y>
-        <width>60</width>
+        <width>72</width>
         <height>153</height>
        </rect>
       </property>
index 5e4de84e545f4969edbf1f290558c8d49f28fd6d..79b91a313d2b731b2f2e93ac2e94bef7371008fc 100644 (file)
@@ -6,16 +6,10 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>640</width>
-    <height>480</height>
+    <width>1057</width>
+    <height>589</height>
    </rect>
   </property>
-  <property name="sizePolicy">
-   <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
-    <horstretch>0</horstretch>
-    <verstretch>0</verstretch>
-   </sizepolicy>
-  </property>
   <property name="windowTitle">
    <string>Title Clip</string>
   </property>
      </widget>
     </widget>
    </item>
+   <item row="3" column="0" colspan="2">
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <property name="topMargin">
+      <number>0</number>
+     </property>
+     <item>
+      <widget class="QToolButton" name="buttonFitZoom">
+       <property name="text">
+        <string>V</string>
+       </property>
+       <property name="autoRaise">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QToolButton" name="buttonRealSize">
+       <property name="text">
+        <string>V</string>
+       </property>
+       <property name="autoRaise">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="Line" name="line_8">
+       <property name="orientation">
+        <enum>Qt::Vertical</enum>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QSlider" name="zoom_slider">
+       <property name="minimumSize">
+        <size>
+         <width>100</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>150</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="minimum">
+        <number>1</number>
+       </property>
+       <property name="maximum">
+        <number>150</number>
+       </property>
+       <property name="pageStep">
+        <number>30</number>
+       </property>
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLabel" name="zoom_label">
+       <property name="text">
+        <string>x1</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="Line" name="line_7">
+       <property name="orientation">
+        <enum>Qt::Vertical</enum>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QCheckBox" name="displayBg">
+       <property name="text">
+        <string>Show background</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="Line" name="line_6">
+       <property name="orientation">
+        <enum>Qt::Vertical</enum>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLabel" name="label_22">
+       <property name="text">
+        <string>Template:</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QComboBox" name="templateBox"/>
+     </item>
+     <item>
+      <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>
+   </item>
    <item row="2" column="0" colspan="2">
     <widget class="QSplitter" name="splitter">
-     <property name="sizePolicy">
-      <sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
-       <horstretch>0</horstretch>
-       <verstretch>0</verstretch>
-      </sizepolicy>
-     </property>
      <property name="orientation">
       <enum>Qt::Horizontal</enum>
      </property>
      <widget class="QWidget" name="verticalLayoutWidget">
-      <layout class="QVBoxLayout" name="verticalLayout">
-       <item>
-        <widget class="QGraphicsView" name="graphicsView">
-         <property name="sizePolicy">
-          <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
-           <horstretch>0</horstretch>
-           <verstretch>0</verstretch>
-          </sizepolicy>
+      <layout class="QGridLayout" name="gridLayout_16">
+       <property name="horizontalSpacing">
+        <number>-1</number>
+       </property>
+       <item row="2" column="0">
+        <widget class="QToolButton" name="buttonSelectImages">
+         <property name="enabled">
+          <bool>false</bool>
+         </property>
+         <property name="text">
+          <string>I</string>
          </property>
         </widget>
        </item>
-       <item>
-        <widget class="QStackedWidget" name="bottomToolbarStack">
-         <property name="sizePolicy">
-          <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
-           <horstretch>0</horstretch>
-           <verstretch>0</verstretch>
-          </sizepolicy>
+       <item row="2" column="1">
+        <widget class="QToolButton" name="buttonSelectText">
+         <property name="enabled">
+          <bool>false</bool>
+         </property>
+         <property name="text">
+          <string>T</string>
          </property>
-         <widget class="QWidget" name="page_5">
-          <layout class="QGridLayout" name="bottomToolbarGridLayout">
-           <item row="0" column="0">
-            <widget class="QToolButton" name="buttonSelectAll">
-             <property name="whatsThis">
-              <string>Selects all items on the canvas.</string>
-             </property>
-             <property name="text">
-              <string>A</string>
-             </property>
-            </widget>
-           </item>
-           <item row="0" column="5">
-            <spacer name="spacerBottomStack">
-             <property name="orientation">
-              <enum>Qt::Horizontal</enum>
-             </property>
-             <property name="sizeHint" stdset="0">
-              <size>
-               <width>40</width>
-               <height>20</height>
-              </size>
-             </property>
-            </spacer>
-           </item>
-           <item row="0" column="2">
-            <widget class="QToolButton" name="buttonSelectText">
-             <property name="enabled">
-              <bool>false</bool>
-             </property>
-             <property name="text">
-              <string>T</string>
-             </property>
-            </widget>
-           </item>
-           <item row="0" column="4">
-            <widget class="QToolButton" name="buttonSelectImages">
-             <property name="enabled">
-              <bool>false</bool>
-             </property>
-             <property name="text">
-              <string>I</string>
-             </property>
-            </widget>
-           </item>
-           <item row="0" column="3">
-            <widget class="QToolButton" name="buttonSelectRects">
-             <property name="enabled">
-              <bool>false</bool>
-             </property>
-             <property name="text">
-              <string>R</string>
-             </property>
-            </widget>
-           </item>
-           <item row="0" column="1">
-            <widget class="QToolButton" name="buttonUnselectAll">
-             <property name="enabled">
-              <bool>false</bool>
-             </property>
-             <property name="text">
-              <string>N</string>
-             </property>
-            </widget>
-           </item>
-          </layout>
-         </widget>
         </widget>
        </item>
+       <item row="2" column="2">
+        <widget class="QToolButton" name="buttonUnselectAll">
+         <property name="enabled">
+          <bool>false</bool>
+         </property>
+         <property name="text">
+          <string>N</string>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="5">
+        <spacer name="spacerBottomStack">
+         <property name="orientation">
+          <enum>Qt::Horizontal</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>40</width>
+           <height>20</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item row="2" column="3">
+        <widget class="QToolButton" name="buttonSelectAll">
+         <property name="whatsThis">
+          <string>Selects all items on the canvas.</string>
+         </property>
+         <property name="text">
+          <string>A</string>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="4">
+        <widget class="QToolButton" name="buttonSelectRects">
+         <property name="enabled">
+          <bool>false</bool>
+         </property>
+         <property name="text">
+          <string>R</string>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="0" colspan="6">
+        <widget class="QGraphicsView" name="graphicsView"/>
+       </item>
       </layout>
      </widget>
      <widget class="QWidget" name="layoutWidget">
                 </property>
                </widget>
               </item>
+              <item row="1" column="1">
+               <widget class="QSpinBox" name="typewriter_start">
+                <property name="suffix">
+                 <string> frames</string>
+                </property>
+               </widget>
+              </item>
               <item row="2" column="0">
                <spacer name="verticalSpacer_2">
                 <property name="orientation">
                 </property>
                </spacer>
               </item>
-              <item row="1" column="1">
-               <widget class="QSpinBox" name="typewriter_start">
-                <property name="suffix">
-                 <string> frames</string>
-                </property>
-               </widget>
-              </item>
              </layout>
             </widget>
            </widget>
          </layout>
         </widget>
        </item>
+       <item row="3" column="1">
+        <widget class="KoSliderCombo" name="itemrotatex"/>
+       </item>
+       <item row="4" column="1">
+        <widget class="KoSliderCombo" name="itemrotatey"/>
+       </item>
+       <item row="5" column="1">
+        <widget class="KoSliderCombo" name="itemrotatez"/>
+       </item>
        <item row="8" column="0" colspan="2">
         <widget class="QTabWidget" name="tabWidget">
          <property name="sizePolicy">
-          <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+          <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
            <horstretch>0</horstretch>
            <verstretch>0</verstretch>
           </sizepolicy>
          </widget>
         </widget>
        </item>
-       <item row="3" column="1">
-        <widget class="KoSliderCombo" name="itemrotatex"/>
-       </item>
-       <item row="4" column="1">
-        <widget class="KoSliderCombo" name="itemrotatey"/>
-       </item>
-       <item row="5" column="1">
-        <widget class="KoSliderCombo" name="itemrotatez"/>
-       </item>
       </layout>
      </widget>
     </widget>
    </item>
-   <item row="3" column="0" colspan="2">
-    <layout class="QHBoxLayout" name="horizontalLayout">
-     <property name="topMargin">
-      <number>0</number>
-     </property>
-     <item>
-      <widget class="QToolButton" name="buttonFitZoom">
-       <property name="text">
-        <string>V</string>
-       </property>
-       <property name="autoRaise">
-        <bool>true</bool>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <widget class="QToolButton" name="buttonRealSize">
-       <property name="text">
-        <string>V</string>
-       </property>
-       <property name="autoRaise">
-        <bool>true</bool>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <widget class="Line" name="line_8">
-       <property name="orientation">
-        <enum>Qt::Vertical</enum>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <widget class="QSlider" name="zoom_slider">
-       <property name="minimumSize">
-        <size>
-         <width>100</width>
-         <height>0</height>
-        </size>
-       </property>
-       <property name="maximumSize">
-        <size>
-         <width>150</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="minimum">
-        <number>1</number>
-       </property>
-       <property name="maximum">
-        <number>150</number>
-       </property>
-       <property name="pageStep">
-        <number>30</number>
-       </property>
-       <property name="orientation">
-        <enum>Qt::Horizontal</enum>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <widget class="QLabel" name="zoom_label">
-       <property name="text">
-        <string>x1</string>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <widget class="Line" name="line_7">
-       <property name="orientation">
-        <enum>Qt::Vertical</enum>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <widget class="QCheckBox" name="displayBg">
-       <property name="text">
-        <string>Show background</string>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <widget class="Line" name="line_6">
-       <property name="orientation">
-        <enum>Qt::Vertical</enum>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <widget class="QLabel" name="label_22">
-       <property name="text">
-        <string>Template:</string>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <widget class="QComboBox" name="templateBox"/>
-     </item>
-     <item>
-      <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>
-   </item>
   </layout>
  </widget>
  <customwidgets>
index c86461f117f64392f7794024205085221f42b77e..b55745a5e7ffe8e367445b41fc26db7ba9492a72 100644 (file)
@@ -1,10 +1,18 @@
 [Desktop Entry]
 Type=Service
 Name=MLT Playlist
+Name[ca]=Llista de reproducció del MLT
 Name[cs]=Seznam skladeb MLT
 Name[da]=MLT-spilleliste
 Name[de]=MLT-Wiedergabeliste
+Name[el]=Λίστα αναπαραγωγής MLT
+Name[es]=Lista de reproducción de MLT
+Name[gl]=Lista de reprodución MLT
+Name[hu]=MLT lejátszólista
+Name[it]=Scaletta MLT
+Name[nb]=MLT-spilleliste
 Name[nl]=MLT-afspeellijst
+Name[pl]=Lista odtwarzania MLT
 Name[pt]=Lista de Reprodução MLT
 Name[pt_BR]=Lista de Reprodução MLT
 Name[sv]=MLT-spellista