+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.
frei0r.facebl0r
frei0r.flippo
frei0r.glow
-frei0r.iirblur
+frei0r.IIRblur
frei0r.hqdn3d
frei0r.hueshift0r
frei0r.lenscorrection
resample
mono
-dynamictext
# Effects need extra GUI to create the resulting melt.xml with the corrected content
videostab
chroma.xml
crop.xml
dust.xml
+dynamictext.xml
freeze.xml
gamma.xml
grain.xml
- 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)
- 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
==========
==========
<!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>
--- /dev/null
+<!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>
<!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">
<!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>
<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>
#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} )
"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)
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
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
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
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)
${KDE4_KNEWSTUFF_LIBS}
${KDE4_KNOTIFYCONFIG_LIBRARY}
${KDE4_KROSSUI_LIBS}
+ ${KDE4_SOLID_LIBS}
${QT_LIBRARIES}
${LIBMLT_LIBRARY}
${LIBMLTPLUS_LIBRARY}
#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();
+}
#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
{
* @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() {};
/** @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. */
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
#include <KDebug>
#include <KApplication>
#include <kio/directorysizejob.h>
+#if KDE_IS_VERSION(4,7,0)
+#include <KMessageWidget>
+#endif
#include <QTreeWidget>
#include <QtConcurrentRun>
m_doc(doc),
m_abortArchive(false),
m_extractMode(false),
- m_extractArchive(NULL)
+ m_extractArchive(NULL),
+ m_missingClips(0)
{
setAttribute(Qt::WA_DeleteOnClose);
setupUi(this);
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"));
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");
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
buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Archive"));
connect(buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(slotStartArchiving()));
buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
-
+
slotCheckSpace();
}
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"));
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);
}
}
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..."));
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)
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)) {
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);
slotDisplayMessage("system-run", i18n("Archiving..."));
repaint();
archive_url->setEnabled(false);
+ proxy_only->setEnabled(false);
compressed_archive->setEnabled(false);
}
KUrl::List files;
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++) {
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;
}
}
// 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);
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);
}
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();
+}
+
#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;
* @author Jean-Baptiste Mardelle
*/
+#if KDE_IS_VERSION(4,7,0)
+ class KMessageWidget;
+#endif
+
class ArchiveWidget : public QDialog, public Ui::ArchiveWidget_UI
{
Q_OBJECT
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 );
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();
+++ /dev/null
-set(kdenlive_SRCS
- ${kdenlive_SRCS}
- audioscopes/abstractaudioscopewidget.cpp
- audioscopes/audiospectrum.cpp
- audioscopes/ffttools.cpp
- audioscopes/spectrogram.cpp
- PARENT_SCOPE
-)
#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__
#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);
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)
/** @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;
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)));
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()
* 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);
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;
{
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)
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();
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)
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;
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);
}
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()));
}
}
-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)
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);
* @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);
int getFreeClipId();
int getFreeFolderId();
int lastClipId() const;
- void startAudioThumbsGeneration();
- void endAudioThumbsGeneration(const QString &requestedId);
void askForAudioThumb(const QString &id);
QString projectFolder() const;
void clearUnusedProducers();
/** 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 */
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;
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 &);
void missingClip(const QString &);
void availableClip(const QString &);
void checkAllClips(bool displayRatioChanged, bool fpsChanged, QStringList brokenClips);
+ void displayMessage(const QString &, int);
};
#endif
#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>
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"));
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++;
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 {
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()));
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();
}
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);
}
if (m_proxyContainer) delete m_proxyContainer;
}
+void ClipProperties::slotOpenUrl(const QString &url)
+{
+ new KRun(KUrl(url), this);
+}
+
#include "clipproperties.moc"
void slotApplyProperties();
void slotModified();
void slotDeleteProxy();
+ void slotOpenUrl(const QString &url);
private:
Ui::ClipProperties_UI m_view;
--- /dev/null
+/***************************************************************************
+ * 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"
+
+
--- /dev/null
+/***************************************************************************
+ * 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
+
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()));
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);
}
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();
}
if (m_transcodeProcess.state() != QProcess::NotRunning) {
m_transcodeProcess.close();
}
+#if KDE_IS_VERSION(4,7,0)
+ delete m_infoMessage;
+#endif
}
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);
}
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);
}
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);
}
}
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);
}
{
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()) {
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)
#include "ui_cliptranscode_ui.h"
#include <KUrl>
+#include <kdeversion.h>
+#if KDE_IS_VERSION(4,7,0)
+#include <KMessageWidget>
+#endif
#include <QProcess>
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);
};
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
+++ /dev/null
-set(kdenlive_SRCS
- ${kdenlive_SRCS}
- colorscopes/abstractgfxscopewidget.cpp
- colorscopes/histogram.cpp
- colorscopes/rgbparade.cpp
- colorscopes/vectorscope.cpp
- colorscopes/waveform.cpp
- PARENT_SCOPE
-)
#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;
{
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();
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)
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)
{
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)
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;
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;
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;
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);
}
// 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;
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);
emit clipItemSelected(clip, ix);
}
}
+ else emit displayMessage(i18n("Cannot find clip to update effect"), ErrorMessage);
setDocumentModified();
}
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());
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) {
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++) {
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++) {
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) {
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;
}
+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());
+ }
+
+}
+
+
* @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
* @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);
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();
#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 };
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;
m_videoOnlyProducer(NULL),
m_snapMarkers(QList < CommentedTime >()),
m_duration(),
- m_audioTimer(NULL),
m_thumbProd(NULL),
m_audioThumbCreated(false),
m_id(id),
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);
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;
}
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
}
// virtual
-QDomElement DocClipBase::toXML() const
+QDomElement DocClipBase::toXML(bool hideTemporaryProperties) const
{
QDomDocument doc;
QDomElement clip = doc.createElement("producer");
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);
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*********************************************";
}
}*/
- qDeleteAll(m_toDeleteProducers);
- m_toDeleteProducers.clear();
- m_replaceMutex.unlock();
+ if (!isClean()) {
+ qDeleteAll(m_toDeleteProducers);
+ m_toDeleteProducers.clear();
+ m_replaceMutex.unlock();
+ }
}
bool DocClipBase::isClean() const
m_thumbProd->setProducer(producer);
}
else m_thumbProd->setProducer(producer);
+ getAudioThumbs();
}
bool updated = false;
if (id.contains('_')) {
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;
}
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);
}
/** Returns the internal unique id of the clip. */
const QString &getId() const;
+ bool hasAudioThumb() const;
//KThumb *thumbCreator;
bool audioThumbCreated() const;
/*void getClipMainThumb();*/
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;
* 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;
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
/** 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;
/** 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);
public slots:
void updateAudioThumbnail(const audioByteArray& data);
- bool slotGetAudioThumbs();
QList < CommentedTime > commentedSnapMarkers() const;
GenTime findNextSnapMarker(const GenTime & currTime);
GenTime findPreviousSnapMarker(const GenTime & currTime);
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);
const int CLIPPLACEHOLDER = 2;
const int CLIPWRONGDURATION = 3;
const int PROXYMISSING = 4;
+const int SOURCEMISSING = 5;
const int LUMAMISSING = 10;
const int LUMAOK = 11;
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();
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();
- 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();
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());
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;
}
}
- 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");
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;
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"));
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
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]+(&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]+(&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()
QList <QDomElement> m_missingClips;
QStringList m_safeImages;
QStringList m_safeFonts;
+
+ void fixClipItem(QTreeWidgetItem *child, QDomNodeList producers, QDomNodeList infoproducers, QDomNodeList trans);
};
#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)
{}
// 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);
#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);
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);
{
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 { \
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);
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();
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);
}
}
#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"
{
};
+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) :
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");
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
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);
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)));
#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:
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;
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)
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();
} 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())
{
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;
+ }
+ }
+}
+
/** @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 &);
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
//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"));
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;
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();
}
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"
/** @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);
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
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)));
geom->insert(item2);
}
}
-
emit parameterChanged();
}
#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),
//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()
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);
}
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"
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);
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);
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);
# 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
[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
[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
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
[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
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
[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
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
[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
[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
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),
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
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, "");
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);
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
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();
}
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());
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();
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");
}
-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);
}
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()));
}
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)
}
}
+const QMap <QString, QString> KdenliveDoc::metadata() const
+{
+ return m_documentMetadata;
+}
+
+void KdenliveDoc::setMetadata(const QMap <QString, QString> meta)
+{
+ m_documentMetadata = meta;
+}
+
#include "kdenlivedoc.moc"
{
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;
*
* 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);
* 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;
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;
/** @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);
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);
<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>
#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>
#include <kde_file.h>
#include <KIO/NetAccess>
#include <kdeversion.h>
+#include <KMessageBox>
#include <QDir>
#include <QTimer>
}
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();
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)));
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()) {
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);
}
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());
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);
}
}
}
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()
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
delete w;
}
+
#include "kdenlivesettingsdialog.moc"
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();
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
<?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" />
<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>
<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" />
#include <QStylePainter>
#include <QApplication>
+const int margin = 5;
+const int cursorWidth = 6;
KeyframeHelper::KeyframeHelper(QWidget *parent) :
QWidget(parent),
m_position(0),
m_scale(0),
m_movingKeyframe(false),
- m_lineHeight(10),
+ m_lineHeight(9),
m_drag(false),
m_hoverKeyframe(-1)
{
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());
}
}
}
- 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);
}
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++) {
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();
}
{
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
return;
}
// add new keyframe
- emit addKeyframe((int)(event->x() / m_scale));
+ emit addKeyframe((int)(xPos / m_scale));
}
}
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;
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);
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
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
}
}
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);
}
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;
#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";
}
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();
}
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
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)
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);
// 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);
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;
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;
#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
#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);
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);
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 ..."));
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");
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);
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
/*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)
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);
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()));
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()) {
delete m_clipMonitor;
delete m_shortcutRemoveFocus;
delete[] m_transitions;
+ delete m_monitorManager;
+ delete m_scopeManager;
Mlt::Factory::close();
}
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)));
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)));
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"));
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"));
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()));
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");
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()));
addClips->addAction(addTitleClip);
addClips->addAction(addTitleTemplateClip);
addClips->addAction(addFolderButton);
+ addClips->addAction(downloadResources);
addClips->addAction(reloadClip);
addClips->addAction(proxyClip);
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())
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
connectDocument(trackView, doc);
} else
m_timelineArea->setTabBarHidden(false);
- m_monitorManager->activateMonitor("clip");
+ m_monitorManager->activateMonitor(Kdenlive::clipMonitor);
m_closeAction->setEnabled(m_timelineArea->count() > 1);
}
// 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());
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;
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
delete m_stopmotion;
m_stopmotion = NULL;
}
-
+
m_timer.start();
KProgressDialog progressDialog(this, i18n("Loading project"), i18n("Loading project"));
progressDialog.setAllowCancel(false);
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);
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);
}
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();
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)) {
}*/
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);
}
}
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) {
m_activeDocument->setModified();
slotUpdateProxySettings();
}
+ m_activeDocument->setMetadata(w->metadata());
}
delete w;
}
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)));
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 &)));
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)));
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)));
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)));
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();
#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);
}
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();
}
// 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()));
// Update list of transcoding profiles
loadTranscoders();
- loadStabilize();
+ loadStabilize();
#ifdef USE_JOGSHUTTLE
activateShuttleDevice();
#endif
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)
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)
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);
}
}
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();
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);
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++)
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()));
+ }
}
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
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)
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);
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()
}
}
}
-
+
// Do we want proxy rendering
if (m_projectList->useProxy() && !m_renderWidget->proxyRendering()) {
QString root = doc.documentElement().attribute("root");
}
}
}
-
+
/*QMapIterator<QString, QString> i(proxies);
while (i.hasNext()) {
i.next();
}*/
}
playlistContent = doc.toString();
-
+
// Do save scenelist
QFile file(playlistPath);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
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)
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() );
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 ) );
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;
}
}
-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()
{
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
class DocClipBase;
class Render;
class Transition;
+class ScopeManager;
class Histogram;
class Vectorscope;
class Waveform;
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;
/** 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;
/** 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;
StatusBarMessageLabel *m_messageLabel;
QActionGroup *m_clipTypeGroup;
KActionCollection *m_effectsActionCollection;
+ KActionCollection *m_tracksActionCollection;
bool m_findActivated;
QString m_findString;
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.
*
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);
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();
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();
/** @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. */
void slotDisableProxies();
void slotElapsedTime();
+ /** @brief Open the online services search dialog. */
+ void slotDownloadResources();
signals:
Q_SCRIPTABLE void abortRenderJob(const QString &url);
#include "mltdevicecapture.h"
#include "kdenlivesettings.h"
#include "definitions.h"
-//#include "recmonitor.h"
-//#include "renderer.h"
-#include "blackmagic/devices.h"
#include <mlt++/Mlt.h>
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)
{
}
//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()
}
}
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);
//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);
}
-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);
+ }
}
}
*/
- 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());
}
// 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);
}
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) {
}
}
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;
//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???
/*
doCapture = 5;
}
-bool MltDeviceCapture::slotStartCapture(const QString ¶ms, const QString &path, const QString &playlist, int livePreview, bool xmlPlaylist)
+bool MltDeviceCapture::slotStartCapture(const QString ¶ms, const QString &path, const QString &playlist, bool livePreview, bool xmlPlaylist)
{
stop();
m_livePreview = livePreview;
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;
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
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;
}
rgb_ptr += 3;
}
//emit imageReady(image);
- m_captureDisplayWidget->setImage(image);
+ //m_captureDisplayWidget->setImage(image);
emit unblockPreview();
//processingImage = false;
}
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
/** @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();
/** @brief Starts the MLT Video4Linux process.
* @param surface The widget onto which the frame should be painted
*/
- bool slotStartCapture(const QString ¶ms, const QString &path, const QString &playlist, int livePreview, bool xmlPlaylist = true);
+ bool slotStartCapture(const QString ¶ms, 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);
/** @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;
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 */
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 &);
/** @brief Stops the consumer. */
void stop();
+ void slotDoRefresh();
};
#endif
#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),
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
// 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 {
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"));
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);
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
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)));
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();
}
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...
}
//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);
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);
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);
void Monitor::resetSize()
{
- m_videoBox->setMinimumSize(0, 0);
+ videoBox->setMinimumSize(0, 0);
}
DocClipBase *Monitor::activeClip()
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());
}
}
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;
}
}
// virtual
void Monitor::mouseMoveEvent(QMouseEvent *event)
{
- // kDebug() << "// DRAG STARTED, MOUSE MOVED: ";
if (!m_dragStarted || m_currentClip == NULL) return;
if ((event->pos() - m_DragStartPosition).manhattanLength()
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;
event->accept();
}
+void Monitor::mouseDoubleClickEvent(QMouseEvent * event)
+{
+ if (!KdenliveSettings::openglmonitors()) {
+ videoBox->switchFullScreen();
+ event->accept();
+ }
+}
+
void Monitor::slotMouseSeek(int eventDelta, bool fast)
{
if (fast) {
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;
}
}
-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);
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);
void Monitor::slotForward(double speed)
{
- activateMonitor();
+ slotActivateMonitor();
if (speed == 0) {
double currentspeed = render->playSpeed();
if (currentspeed <= 1) render->play(2);
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);
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();
}
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);
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);
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);
{
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);
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) {
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();
}
} else {
if (m_currentClip) {
- activateMonitor();
+ slotActivateMonitor();
if (position == -1) position = render->seekFramePosition();
render->seek(position);
}
void Monitor::slotOpenFile(const QString &file)
{
if (render == NULL) return;
- activateMonitor();
+ slotActivateMonitor();
QDomDocument doc;
QDomElement mlt = doc.createElement("mlt");
doc.appendChild(mlt);
m_timePos->updateTimeCode(m_monitorManager->timecode());
if (render == NULL) return;
if (!render->hasProfile(profile)) {
- activateMonitor();
+ slotActivateMonitor();
render->resetProfile(profile);
}
if (m_effectWidget)
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();
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);
}
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);
if (show) {
m_effectWidget->getScene()->slotZoomFit();
}
+ videoBox->setEnabled(show);
render->doRefresh();
}
}
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);
}
// 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();
}
#include "gentime.h"
#include "renderer.h"
+#include "definitions.h"
#include "timecodedisplay.h"
#include "abstractmonitor.h"
#ifdef USE_OPENGL
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
{
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 );
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();
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.
//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;
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();
/** @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
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);
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;
#include <QTimer>
#include <KDebug>
+
MonitorManager::MonitorManager(QWidget *parent) :
QObject(parent),
m_clipMonitor(NULL),
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();
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()
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()
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)
{
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();
}
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();
}
}
return NULL;
}
+void MonitorManager::slotSwitchFullscreen()
+{
+ if (m_activeMonitor) m_activeMonitor->slotSwitchFullScreen();
+}
+
#include "monitormanager.moc"
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();
/** @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();
void slotStart();
void slotEnd();
void slotResetProfiles();
+
+ /** @brief Switch current monitor to fullscreen. */
+ void slotSwitchFullscreen();
/** @brief Switches between project and clip monitor.
* @ref activateMonitor
void slotUpdateAudioMonitoring();
private slots:
- void slotRefreshCurrentMonitor();
+ void slotRefreshCurrentMonitor(const QString &id);
private:
Monitor *m_clipMonitor;
#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) :
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();
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());
tip.append(i18n("Unknown clip"));
break;
}
-
setToolTip(0, tip);
}
}
}
-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;
}
#include "gentime.h"
#include "definitions.h"
+#include "projecttree/abstractclipjob.h"
+
class DocClipBase;
*
* 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;
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;
#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);
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);
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);
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()) {
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
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);
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()
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";
{
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()
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 {
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);
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()) {
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);
}
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);
{
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;
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"));
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());
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);
// Display uses in timeline
emit findInTimeline(clip->clipId());
} else {
+ m_extractAudioAction->setEnabled(false);
m_transcodeAction->setEnabled(false);
m_stabilizeAction->setEnabled(false);
}
} 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;
}
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)
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);
}
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) {
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
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)
}
}
+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
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);
}
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());
} 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()) {
}
}
} 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));
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()));
}
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)
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;
}
}
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);
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/");
item->referencedClip()->reloadThumbProducer();
}
}
- m_processingClips.removeAll(id);
m_thumbnailQueue.removeAll(id);
}
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());
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;
}
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);
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();
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)
{
QString toReload;
ProjectItem *item = getItemById(clipId);
-
int queue = m_render->processingItems();
if (item && producer) {
monitorItemEditing(false);
}
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();
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)
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) {
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);
}
}
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;
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()) {
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);
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();
} 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);
}
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;
}
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()) {
// 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) {
// 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);
}
}
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) {
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);
}
}
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);
}
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"
#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>
#include "kdenlivesettings.h"
#include "folderprojectitem.h"
#include "subprojectitem.h"
+#include "projecttree/abstractclipjob.h"
#include <kdialog.h>
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
public:
ItemDelegate(QAbstractItemView* parent = 0): QStyledItemDelegate(parent) {
}
-
+
/*void drawFocus(QPainter *, const QStyleOptionViewItem &, const QRect &) const {
}*/
}
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();
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();
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();
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();
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);
/** @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.
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;
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;
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);
/** @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();
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);
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);
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
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);
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);
}
#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);
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();
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);
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;
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")) {
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"
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();
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);
--- /dev/null
+set(kdenlive_SRCS
+ ${kdenlive_SRCS}
+ projecttree/abstractclipjob.cpp
+ projecttree/proxyclipjob.cpp
+ projecttree/cutclipjob.cpp
+ projecttree/meltjob.cpp
+ PARENT_SCOPE
+)
--- /dev/null
+/***************************************************************************
+ * *
+ * 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;
+}
+
--- /dev/null
+/***************************************************************************
+ * *
+ * 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
+
--- /dev/null
+/***************************************************************************
+ * *
+ * 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;
+}
+
--- /dev/null
+/***************************************************************************
+ * *
+ * 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
--- /dev/null
+/***************************************************************************
+ * *
+ * 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
--- /dev/null
+/***************************************************************************
+ * *
+ * 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
--- /dev/null
+/***************************************************************************
+ * *
+ * 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;
+}
+
--- /dev/null
+/***************************************************************************
+ * *
+ * 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
#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)));
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;
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"));
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");
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";
#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()
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()
void RecMonitor::start()
{
+ //slotStartPreview(true);
}
void RecMonitor::slotConfigure()
{
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);
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);
{
// 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);
if (m_captureDevice) {
m_captureDevice->stop();
}
- recording_preview->setEnabled(true);
+ m_previewSettings->setEnabled(true);
m_isCapturing = false;
m_isPlaying = false;
m_playAction->setEnabled(true);
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();
}
}
return;
}
+ slotActivateMonitor();
+ if (m_isPlaying) return;
m_captureArgs.clear();
m_displayArgs.clear();
m_isPlaying = false;
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()) {
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);
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);
void RecMonitor::slotRecord()
{
+ rec_audio->setEnabled(false);
+ rec_video->setEnabled(false);
+
if (m_captureProcess->state() == QProcess::NotRunning && device_selector->currentIndex() == FIREWIRE) {
slotStartPreview();
}
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;
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&height:%3&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")) {
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:
}
}
+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&height:%3&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();
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();
}
if (QFile::rename(url.path(), newUrl)) {
url = KUrl(newUrl);
}
-
+
}
capturedFiles.append(url);
}
}
// 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()
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()
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"
#define RECMONITOR_H
#include "abstractmonitor.h"
+#include "definitions.h"
#include "ui_recmonitor_ui.h"
#include <QToolBar>
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;
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);
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);
void start();
void slotStopCapture();
void slotUpdateCaptureFolder(const QString ¤tProjectFolder);
+ void slotMouseSeek(int eventDelta, bool fast);
+ void slotSwitchFullScreen();
signals:
void renderPosition(int);
#include "definitions.h"
#include "slideshowclip.h"
#include "profilesdialog.h"
+
+#ifdef USE_BLACKMAGIC
#include "blackmagic/devices.h"
+#endif
#include <mlt++/Mlt.h>
}
}
-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),
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()));
}
void Render::closeMlt()
-{
+{
//delete m_osdTimer;
m_requestList.clear();
m_infoThread.waitForFinished();
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();
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();
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) {
else delete producer;
}
}
-
+
if (!m_mltProducer || !path.isEmpty()) {
QImage pix(width, height, QImage::Format_RGB32);
pix.fill(Qt::black);
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) {
}
}
}
- 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;
}
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");
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) {
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);
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();
}
}
}
-
+
// 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))
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);
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;
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;
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);
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();
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;
}
{
if (!m_mltProducer)
return;
-
resetZoneMode();
m_mltProducer->seek(pos);
if (m_mltProducer->get_speed() == 0) {
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()
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);
}
}
}
service.lock();
return new Mlt::Tractor(service);
-
+
}
void Render::unlockService(Mlt::Tractor *tractor)
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();
trackProducer.set("hide", 0);
}
if (audioMixingBroken) fixAudioMixing(tractor);
-
+
tractor.multitrack()->refresh();
tractor.refresh();
refresh();
}
}
}
- 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();
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"
class QTimer;
class QPixmap;
+class KComboBox;
+
namespace Mlt
{
class Consumer;
* @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();
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. */
/** @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);
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();
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:
*
* 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;
*/
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.
*
void slotSwitchFullscreen();
void slotSetVolume(int volume);
void seekToFrame(int pos);
+ /** @brief Starts a timer to query for a refresh. */
+ void doRefresh();
};
#endif
#include <QThread>
#include <QScriptEngine>
+
+// Render profiles roles
const int GroupRole = Qt::UserRole;
const int ExtensionRole = GroupRole + 1;
const int StandardRole = GroupRole + 2;
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) :
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);
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);
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 *)));
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);
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);
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)
}
-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;
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;
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 {
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();
{
// 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;
}
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();
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) {
}
}
}
- // 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) {
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);
}
}
+
+
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);
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();
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;
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);
}
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();
}
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"));
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);
}
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";
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);
{
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);
+ }
+}
+
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
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);
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;
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;
--- /dev/null
+
+add_subdirectory(colorscopes)
+add_subdirectory(audioscopes)
+
+set(kdenlive_SRCS
+ ${kdenlive_SRCS}
+ scopes/scopemanager.cpp
+ scopes/abstractscopewidget.cpp
+ PARENT_SCOPE
+)
* (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>
initialDimensionUpdateDone(false),
m_requestForcedUpdate(false),
m_rescaleMinDist(4),
- m_rescaleVerticalThreshold(2.0f)
+ m_rescaleVerticalThreshold(2.0f),
+ m_rescaleActive(false)
{
m_scopePalette = QPalette();
qDebug() << "Trying to start a new HUD thread for " << m_widgetName
<< ". New frames/updates: " << m_newHUDFrames << "/" << m_newHUDUpdates;
#endif
- prodHUDThread();;
+ prodHUDThread();
}
}
}
}
-bool AbstractScopeWidget::autoRefreshEnabled()
+bool AbstractScopeWidget::autoRefreshEnabled() const
{
return m_aAutoRefresh->isChecked();
}
* (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 \
/ 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
/** 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 /////
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.
// 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);
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;
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);
--- /dev/null
+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
+)
+
{
}
-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() << ".";
#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
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);
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
#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;
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;
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;
}
}
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){
}
}
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"
#ifndef AUDIOSIGNAL_H
#define AUDIOSIGNAL_H
+#include "scopes/audioscopes/abstractaudioscopewidget.h"
+
#include <QByteArray>
#include <QList>
#include <QColor>
#include <stdint.h>
-class AudioSignal : public QWidget
+class AudioSignal : public AbstractAudioScopeWidget
{
Q_OBJECT
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();
* (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
--- /dev/null
+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
+)
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() { }
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)
{
void AbstractGfxScopeWidget::slotAutoRefreshToggled(bool autoRefresh)
{
- if (autoRefresh && m_activeRender) {
- m_activeRender->sendFrameUpdate();
+ if (autoRefresh) {
+ emit signalFrameRequest(widgetName());
}
}
#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. */
/** @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);
};
#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);
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;
#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);
#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;
#include "colorplaneexport.h"
#include "colortools.h"
-#include "renderer.h"
#include "vectorscope.h"
#include "colorcorrection/vectorscopegenerator.h"
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();
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;
#include "kdenlivesettings.h"
#include "profilesdialog.h"
-#include "renderer.h"
#include "waveform.h"
#include "colorcorrection/waveformgenerator.h"
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();
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;
--- /dev/null
+/***************************************************************************
+ * 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); }
+}
+
--- /dev/null
+/***************************************************************************
+ * 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
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());
}
// static
+//TODO: sequence begin
int SlideshowClip::sequenceCount(KUrl file)
{
// find pattern
// 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 ++;
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);
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;
}
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);
// 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);
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;
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);
{
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);
}
return geometry;
}
+
#include "slideshowclip.moc"
,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);
}
} 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)));
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());
// 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);
}
#ifndef SMALLRULER_H
#define SMALLRULER_H
+#include <KColorScheme>
#include <QWidget>
#include "monitormanager.h"
+
class SmallRuler : public QWidget
{
Q_OBJECT
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();
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:
***************************************************************************/
#include "stopmotion.h"
+#ifdef USE_BLACKMAGIC
#include "blackmagic/devices.h"
+#endif
#ifdef USE_V4L
#include "v4l/v4lcapture.h"
#endif
}
-StopmotionMonitor::StopmotionMonitor(QWidget *parent) :
- AbstractMonitor(parent),
+StopmotionMonitor::StopmotionMonitor(MonitorManager *manager, QWidget *parent) :
+ AbstractMonitor(Kdenlive::stopmotionMonitor, manager, parent),
m_captureDevice(NULL)
{
}
{
}
+void StopmotionMonitor::slotSwitchFullScreen()
+{
+}
+
void StopmotionMonitor::setRender(MltDeviceCapture *render)
{
m_captureDevice = render;
return m_captureDevice;
}
-const QString StopmotionMonitor::name() const
+Kdenlive::MONITORID StopmotionMonitor::id() const
{
- return QString("stopmotion");
+ return Kdenlive::stopmotionMonitor;
}
{
}
+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()
, 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
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
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 &)));
capture_button->setEnabled(false);
if (isOn) {
m_frame_preview->setHidden(true);
- m_videoBox->setHidden(false);
+ m_monitor->videoBox->setHidden(false);
QLocale locale;
MltVideoProfile profile;
}
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()) {
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;
if (m_captureDevice) m_captureDevice->mirror(isOn);
}
+
const QString StopmotionWidget::createProducer(MltVideoProfile profile, const QString &service, const QString &resource)
{
Q_UNUSED(profile)
#define STOPMOTION_H
#include "ui_stopmotion_ui.h"
+#include "definitions.h"
#include <KUrl>
#include <QLabel>
{
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();
/** @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 */
*/
-#include <QValidator>
#include <KDebug>
#include <KLocale>
Timecode::Timecode(Formats format, double framesPerSecond)
{
- m_validator = new QRegExpValidator(0);
setFormat(framesPerSecond, 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
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, ':');
}
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
//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
}
int seconds = (int)(frames / fps);
+ int frms = frames % (int) (fps + 0.5);
int minutes = seconds / 60;
seconds = seconds % 60;
int hours = minutes / 60;
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;
}
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));
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;
#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.
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:
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;
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();
}
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()
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);
}
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
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));
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();
}
bool m_frametimecode;
int m_minimum;
int m_maximum;
+ int m_value;
public slots:
/** @brief Sets the value.
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
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();
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);
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);
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);
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()));
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"));
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"));
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"));
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"));
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);
templateBox->addItem(t.icon, t.name, t.file);
}
lastDocumentHash = QCryptographicHash::hash(xml().toString().toAscii(), QCryptographicHash::Md5).toHex();
+ adjustSize();
}
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)
{
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);
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);
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;
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));
}
}
//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());
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;
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()));
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);
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()) {
}
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();
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);
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();
protected:
virtual void resizeEvent(QResizeEvent * event);
+ virtual QSize sizeHint() const;
private:
#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();
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"));
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)));
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;
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;
void mousePosition(int);
void cursorMoved();
void zoneMoved(int, int);
- void insertTrack(int);
- void deleteTrack(int);
void configTrack(int);
void updateTracksInfo();
void setZoom(int);
return MOVE;
}
+//static
int Transition::itemHeight()
{
return (int) (KdenliveSettings::trackheight() / 3 * 2 - 1);
}
+//static
int Transition::itemOffset()
{
return (int) (KdenliveSettings::trackheight() / 3 * 2);
--- /dev/null
+set(kdenlive_SRCS
+ ${kdenlive_SRCS}
+ utils/abstractservice.cpp
+ utils/freesound.cpp
+ utils/openclipart.cpp
+ utils/archiveorg.cpp
+ utils/resourcewidget.cpp
+ PARENT_SCOPE
+)
+
+
--- /dev/null
+/***************************************************************************
+ * 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();
+}
+
--- /dev/null
+/***************************************************************************
+ * 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
+
--- /dev/null
+/***************************************************************************
+ * 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;
+ }
+ }
+}
--- /dev/null
+/***************************************************************************
+ * 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
+
--- /dev/null
+/***************************************************************************
+ * 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();
+}
--- /dev/null
+/***************************************************************************
+ * 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
+
--- /dev/null
+/***************************************************************************
+ * 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;
+}
+
--- /dev/null
+/***************************************************************************
+ * 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
+
--- /dev/null
+/***************************************************************************
+ * 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
--- /dev/null
+/***************************************************************************
+ * 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
+
<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>
<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>
--- /dev/null
+<?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>
<x>0</x>
<y>0</y>
<width>405</width>
- <height>545</height>
+ <height>479</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_8">
</item>
<item>
<property name="text">
- <string>Video4Linux</string>
+ <string>FFmpeg</string>
</property>
</item>
<item>
</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>
<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>
<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/>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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><<</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>>></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>
<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>
--- /dev/null
+<?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>
<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>
<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>
<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/>
<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>
</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">
</item>
<item>
<property name="text">
- <string>Video4Linux</string>
+ <string>FFmpeg</string>
</property>
</item>
<item>
</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>
<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>
<rect>
<x>0</x>
<y>0</y>
- <width>290</width>
+ <width>294</width>
<height>507</height>
</rect>
</property>
<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>
</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>
<rect>
<x>0</x>
<y>0</y>
- <width>60</width>
+ <width>72</width>
<height>153</height>
</rect>
</property>
<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>
[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