]> git.sesse.net Git - kdenlive/blob - src/clipproperties.cpp
Remove virtual keyword, fix include, fix indent
[kdenlive] / src / clipproperties.cpp
1 /***************************************************************************
2  *   Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org)        *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
18  ***************************************************************************/
19
20
21 #include "clipproperties.h"
22 #include "kdenlivesettings.h"
23 #include "kthumb.h"
24 #include "markerdialog.h"
25 #include "profilesdialog.h"
26
27 #include <KStandardDirs>
28 #include <KDebug>
29 #include <KFileItem>
30 #include <KFileDialog>
31 #include <kdeversion.h>
32 #include <KUrlLabel>
33 #include <KRun>
34
35 #ifdef USE_NEPOMUK
36 #if KDE_IS_VERSION(4,6,0)
37 #include <Nepomuk/Variant>
38 #include <Nepomuk/Resource>
39 #include <Nepomuk/ResourceManager>
40 #include <Nepomuk/Vocabulary/NIE>
41 #endif
42 #endif
43 #ifdef USE_NEPOMUKCORE
44 #include <Nepomuk2/Variant>
45 #include <Nepomuk2/Resource>
46 #include <Nepomuk2/ResourceManager>
47 #include <Nepomuk2/Vocabulary/NIE>
48 #endif
49
50
51 #include <QDir>
52 #include <QPainter>
53
54
55 static const int VIDEOTAB = 0;
56 static const int AUDIOTAB = 1;
57 static const int COLORTAB = 2;
58 static const int SLIDETAB = 3;
59 static const int IMAGETAB = 4;
60 static const int MARKERTAB = 5;
61 static const int METATAB = 6;
62 static const int ADVANCEDTAB = 7;
63
64
65 ClipProperties::ClipProperties(DocClipBase *clip, const Timecode &tc, double fps, QWidget * parent) :
66     QDialog(parent)
67   , m_clip(clip)
68   , m_tc(tc)
69   , m_fps(fps)
70   , m_count(0)
71   , m_clipNeedsRefresh(false)
72   , m_clipNeedsReLoad(false)
73   , m_proxyContainer(NULL)
74 {
75     setAttribute(Qt::WA_DeleteOnClose, true);
76     setFont(KGlobalSettings::toolBarFont());
77     m_view.setupUi(this);
78     
79     // force transparency is only for group properties, so hide it
80     m_view.clip_force_transparency->setHidden(true);
81     m_view.clip_transparency->setHidden(true);
82     
83     KUrl url = m_clip->fileURL();
84     m_view.clip_path->setText(url.path());
85     m_view.clip_description->setText(m_clip->description());
86     connect(m_view.clip_description, SIGNAL(textChanged(QString)), this, SLOT(slotModified()));
87
88     QMap <QString, QString> props = m_clip->properties();
89     m_view.clip_force_out->setHidden(true);
90     m_view.clip_out->setHidden(true);
91     
92     // New display aspect ratio support
93     if (props.contains("force_aspect_num") && props.value("force_aspect_num").toInt() > 0 &&
94             props.contains("force_aspect_den") && props.value("force_aspect_den").toInt() > 0) {
95         m_view.clip_force_ar->setChecked(true);
96         m_view.clip_ar_num->setEnabled(true);
97         m_view.clip_ar_den->setEnabled(true);
98         m_view.clip_ar_num->setValue(props.value("force_aspect_num").toInt());
99         m_view.clip_ar_den->setValue(props.value("force_aspect_den").toInt());
100     }
101     // Legacy support for pixel aspect ratio
102     else if (props.contains("force_aspect_ratio") && props.value("force_aspect_ratio").toDouble() > 0) {
103         m_view.clip_force_ar->setChecked(true);
104         m_view.clip_ar_num->setEnabled(true);
105         m_view.clip_ar_den->setEnabled(true);
106         if (props.contains("frame_size")) {
107             int width = props.value("force_aspect_ratio").toDouble() * props.value("frame_size").section('x', 0, 0).toInt();
108             int height = props.value("frame_size").section('x', 1, 1).toInt();
109             if (width > 0 && height > 0) {
110                 if ((width / height * 100) == 133) {
111                     width = 4;
112                     height = 3;
113                 }
114                 else if (int(width / height * 100) == 177) {
115                     width = 16;
116                     height = 9;
117                 }
118                 m_view.clip_ar_num->setValue(width);
119                 m_view.clip_ar_den->setValue(height);
120             }
121         }
122     }
123     connect(m_view.clip_force_ar, SIGNAL(toggled(bool)), this, SLOT(slotModified()));
124     connect(m_view.clip_ar_num, SIGNAL(valueChanged(int)), this, SLOT(slotModified()));
125     connect(m_view.clip_ar_den, SIGNAL(valueChanged(int)), this, SLOT(slotModified()));
126
127     if (props.contains("force_fps") && props.value("force_fps").toDouble() > 0) {
128         m_view.clip_force_framerate->setChecked(true);
129         m_view.clip_framerate->setEnabled(true);
130         m_view.clip_framerate->setValue(props.value("force_fps").toDouble());
131     }
132     connect(m_view.clip_force_framerate, SIGNAL(toggled(bool)), this, SLOT(slotModified()));
133     connect(m_view.clip_framerate, SIGNAL(valueChanged(double)), this, SLOT(slotModified()));
134     m_view.clip_progressive->addItem(i18n("Interlaced"), 0);
135     m_view.clip_progressive->addItem(i18n("Progressive"), 1);
136
137     if (props.contains("force_progressive")) {
138         m_view.clip_force_progressive->setChecked(true);
139         m_view.clip_progressive->setEnabled(true);
140         m_view.clip_progressive->setCurrentIndex(props.value("force_progressive").toInt());
141     }
142     connect(m_view.clip_force_progressive, SIGNAL(toggled(bool)), this, SLOT(slotModified()));
143     connect(m_view.clip_progressive, SIGNAL(currentIndexChanged(int)), this, SLOT(slotModified()));
144
145     m_view.clip_fieldorder->addItem(i18n("Bottom first"), 0);
146     m_view.clip_fieldorder->addItem(i18n("Top first"), 1);
147     if (props.contains("force_tff")) {
148         m_view.clip_force_fieldorder->setChecked(true);
149         m_view.clip_fieldorder->setEnabled(true);
150         m_view.clip_fieldorder->setCurrentIndex(props.value("force_tff").toInt());
151     }
152     connect(m_view.clip_force_fieldorder, SIGNAL(toggled(bool)), this, SLOT(slotModified()));
153     connect(m_view.clip_fieldorder, SIGNAL(currentIndexChanged(int)), this, SLOT(slotModified()));
154     
155     if (props.contains("threads") && props.value("threads").toInt() != 1) {
156         m_view.clip_force_threads->setChecked(true);
157         m_view.clip_threads->setEnabled(true);
158         m_view.clip_threads->setValue(props.value("threads").toInt());
159     }
160     connect(m_view.clip_force_threads, SIGNAL(toggled(bool)), this, SLOT(slotModified()));
161     connect(m_view.clip_threads, SIGNAL(valueChanged(int)), this, SLOT(slotModified()));
162
163     if (props.contains("video_index") && props.value("video_index").toInt() != 0) {
164         m_view.clip_force_vindex->setChecked(true);
165         m_view.clip_vindex->setEnabled(true);
166         m_view.clip_vindex->setValue(props.value("video_index").toInt());
167     }
168     connect(m_view.clip_force_vindex, SIGNAL(toggled(bool)), this, SLOT(slotModified()));
169     connect(m_view.clip_vindex, SIGNAL(valueChanged(int)), this, SLOT(slotModified()));
170
171     if (props.contains("audio_index") && props.value("audio_index").toInt() != 0) {
172         m_view.clip_force_aindex->setChecked(true);
173         m_view.clip_aindex->setEnabled(true);
174         m_view.clip_aindex->setValue(props.value("audio_index").toInt());
175     }
176     connect(m_view.clip_force_aindex, SIGNAL(toggled(bool)), this, SLOT(slotModified()));
177     connect(m_view.clip_aindex, SIGNAL(valueChanged(int)), this, SLOT(slotModified()));
178
179     if (props.contains("audio_max")) {
180         m_view.clip_aindex->setMaximum(props.value("audio_max").toInt());
181     }
182
183     if (props.contains("video_max")) {
184         m_view.clip_vindex->setMaximum(props.value("video_max").toInt());
185     }
186     
187     m_view.clip_colorspace->addItem(ProfilesDialog::getColorspaceDescription(601), 601);
188     m_view.clip_colorspace->addItem(ProfilesDialog::getColorspaceDescription(709), 709);
189     m_view.clip_colorspace->addItem(ProfilesDialog::getColorspaceDescription(240), 240);
190     if (props.contains("force_colorspace")) {
191         m_view.clip_force_colorspace->setChecked(true);
192         m_view.clip_colorspace->setEnabled(true);
193         m_view.clip_colorspace->setCurrentIndex(m_view.clip_colorspace->findData(props.value("force_colorspace").toInt()));
194     } else if (props.contains("colorspace")) {
195         m_view.clip_colorspace->setCurrentIndex(m_view.clip_colorspace->findData(props.value("colorspace").toInt()));
196     }
197     connect(m_view.clip_force_colorspace, SIGNAL(toggled(bool)), this, SLOT(slotModified()));
198     connect(m_view.clip_colorspace, SIGNAL(currentIndexChanged(int)), this, SLOT(slotModified()));
199     
200     if (props.contains("full_luma")) {
201         m_view.clip_full_luma->setChecked(true);
202     }
203     connect(m_view.clip_full_luma, SIGNAL(toggled(bool)), this, SLOT(slotModified()));
204
205     // Check for Metadata
206     QMap<QString, QStringList> meta = m_clip->metadata();
207     QMap<QString, QStringList>::const_iterator i = meta.constBegin();
208     while (i != meta.constEnd()) {
209         QStringList values = i.value();
210         QString parentName;
211         QString iconName;
212         if (values.count() > 1 && !values.at(1).isEmpty()) parentName = values.at(1);
213         else {
214             if (KdenliveSettings::ffmpegpath().endsWith("avconv")) {
215                 parentName = i18n("Libav");
216                 iconName = "meta_libav.png";
217             }
218             else {
219                 parentName = i18n("FFmpeg");
220                 iconName = "meta_ffmpeg.png";
221             }
222         }
223         QTreeWidgetItem *parent = NULL;
224         QList <QTreeWidgetItem *> matches = m_view.metadata_list->findItems(parentName, Qt::MatchExactly);
225         if (!matches.isEmpty()) parent = matches.at(0);
226         else {
227             if (parentName == "Magic Lantern") iconName = "meta_magiclantern.png";
228             parent = new QTreeWidgetItem(m_view.metadata_list, QStringList() << parentName);
229             if (!iconName.isEmpty()) {
230                 KIcon icon(KStandardDirs::locate("appdata", iconName));
231                 parent->setIcon(0, icon);
232             }
233         }
234         QTreeWidgetItem *metaitem = NULL;
235         if (parent) {
236             metaitem = new QTreeWidgetItem(parent);
237             parent->setExpanded(true);
238         }
239         else metaitem = new QTreeWidgetItem(m_view.metadata_list);
240         metaitem->setText(0, i.key()); //i18n(i.key().section('.', 2, 3).toUtf8().data()));
241         metaitem->setText(1, values.at(0));
242         ++i;
243     }
244
245     connect(m_view.clip_force_ar, SIGNAL(toggled(bool)), m_view.clip_ar_num, SLOT(setEnabled(bool)));
246     connect(m_view.clip_force_ar, SIGNAL(toggled(bool)), m_view.clip_ar_den, SLOT(setEnabled(bool)));
247     connect(m_view.clip_force_framerate, SIGNAL(toggled(bool)), m_view.clip_framerate, SLOT(setEnabled(bool)));
248     connect(m_view.clip_force_progressive, SIGNAL(toggled(bool)), m_view.clip_progressive, SLOT(setEnabled(bool)));
249     connect(m_view.clip_force_fieldorder, SIGNAL(toggled(bool)), m_view.clip_fieldorder, SLOT(setEnabled(bool)));
250     connect(m_view.clip_force_threads, SIGNAL(toggled(bool)), m_view.clip_threads, SLOT(setEnabled(bool)));
251     connect(m_view.clip_force_vindex, SIGNAL(toggled(bool)), m_view.clip_vindex, SLOT(setEnabled(bool)));
252     connect(m_view.clip_force_aindex, SIGNAL(toggled(bool)), m_view.clip_aindex, SLOT(setEnabled(bool)));
253     connect(m_view.clip_force_colorspace, SIGNAL(toggled(bool)), m_view.clip_colorspace, SLOT(setEnabled(bool)));
254
255     if (props.contains("audiocodec"))
256         new QTreeWidgetItem(m_view.clip_aproperties, QStringList() << i18n("Audio codec") << props.value("audiocodec"));
257
258     if (props.contains("channels"))
259         new QTreeWidgetItem(m_view.clip_aproperties, QStringList() << i18n("Channels") << props.value("channels"));
260
261     if (props.contains("frequency"))
262         new QTreeWidgetItem(m_view.clip_aproperties, QStringList() << i18n("Frequency") << props.value("frequency"));
263     
264
265     CLIPTYPE t = m_clip->clipType();
266     
267     if (props.contains("proxy") && props.value("proxy") != "-") {
268         KFileItem f(KFileItem::Unknown, KFileItem::Unknown, KUrl(props.value("proxy")), true);
269         QFrame* line = new QFrame();
270         line->setFrameShape(QFrame::HLine);
271         line->setFrameShadow(QFrame::Sunken);
272         m_proxyContainer = new QFrame();
273         m_proxyContainer->setFrameShape(QFrame::NoFrame);
274         QHBoxLayout *l = new QHBoxLayout;
275         l->addWidget(new QLabel(i18n("Proxy clip: %1", KIO::convertSize(f.size()))));
276         l->addStretch(5);
277         QPushButton *pb = new QPushButton(i18n("Delete proxy"));
278         l->addWidget(pb);
279         connect(pb, SIGNAL(clicked()), this, SLOT(slotDeleteProxy()));
280         m_proxyContainer->setLayout(l);
281         if (t == IMAGE) {
282             m_view.tab_image->layout()->addWidget(line);
283             m_view.tab_image->layout()->addWidget(m_proxyContainer);
284         }
285         else if (t == AUDIO) {
286             m_view.tab_audio->layout()->addWidget(line);
287             m_view.tab_audio->layout()->addWidget(m_proxyContainer);
288         }
289         else {
290             m_view.tab_video->layout()->addWidget(line);
291             m_view.tab_video->layout()->addWidget(m_proxyContainer);
292         }
293     }
294     
295     if (t != AUDIO && t != AV) {
296         m_view.clip_force_aindex->setEnabled(false);
297     }
298
299     if (t != VIDEO && t != AV) {
300         m_view.clip_force_vindex->setEnabled(false);
301     }
302
303     if (t == PLAYLIST)
304         m_view.tabWidget->setTabText(VIDEOTAB, i18n("Playlist"));
305
306     if (t == IMAGE) {
307         m_view.tabWidget->removeTab(SLIDETAB);
308         m_view.tabWidget->removeTab(COLORTAB);
309         m_view.tabWidget->removeTab(AUDIOTAB);
310         m_view.tabWidget->removeTab(VIDEOTAB);
311         if (props.contains("frame_size"))
312             m_view.image_size->setText(props.value("frame_size"));
313         if (props.contains("transparency"))
314             m_view.image_transparency->setChecked(props.value("transparency").toInt());
315         connect(m_view.image_transparency, SIGNAL(toggled(bool)), this, SLOT(slotModified()));
316         int width = 180.0 * KdenliveSettings::project_display_ratio();
317         if (width % 2 == 1) width++;
318         m_view.clip_thumb->setPixmap(QPixmap(url.path()).scaled(QSize(width, 180), Qt::KeepAspectRatio));
319     } else if (t == COLOR) {
320         m_view.clip_path->setEnabled(false);
321         m_view.tabWidget->removeTab(METATAB);
322         m_view.tabWidget->removeTab(IMAGETAB);
323         m_view.tabWidget->removeTab(SLIDETAB);
324         m_view.tabWidget->removeTab(AUDIOTAB);
325         m_view.tabWidget->removeTab(VIDEOTAB);
326         m_view.clip_thumb->setHidden(true);
327         m_view.clip_color->setColor(QColor('#' + props.value("colour").right(8).left(6)));
328         connect(m_view.clip_color, SIGNAL(changed(QColor)), this, SLOT(slotModified()));
329     } else if (t == SLIDESHOW) {
330         if (url.fileName().startsWith(".all.")) {
331             // the image sequence is defined by mimetype
332             m_view.clip_path->setText(url.directory());
333         } else {
334             // the image sequence is defined by pattern
335             m_view.slide_type_label->setHidden(true);
336             m_view.image_type->setHidden(true);
337             m_view.clip_path->setText(url.path());
338         }
339
340         m_view.tabWidget->removeTab(METATAB);
341         m_view.tabWidget->removeTab(IMAGETAB);
342         m_view.tabWidget->removeTab(COLORTAB);
343         m_view.tabWidget->removeTab(AUDIOTAB);
344         m_view.tabWidget->removeTab(VIDEOTAB);
345
346         //WARNING: Keep in sync with slideshowclip.cpp
347         m_view.image_type->addItem("JPG (*.jpg)", "jpg");
348         m_view.image_type->addItem("JPEG (*.jpeg)", "jpeg");
349         m_view.image_type->addItem("PNG (*.png)", "png");
350         m_view.image_type->addItem("BMP (*.bmp)", "bmp");
351         m_view.image_type->addItem("GIF (*.gif)", "gif");
352         m_view.image_type->addItem("TGA (*.tga)", "tga");
353         m_view.image_type->addItem("TIF (*.tif)", "tif");
354         m_view.image_type->addItem("TIFF (*.tiff)", "tiff");
355         m_view.image_type->addItem("Open EXR (*.exr)", "exr");
356         m_view.animation->addItem(i18n("None"), QString());
357         m_view.animation->addItem(i18n("Pan"), "Pan");
358         m_view.animation->addItem(i18n("Pan, low-pass"), "Pan, low-pass");
359         m_view.animation->addItem(i18n("Pan and zoom"), "Pan and zoom");
360         m_view.animation->addItem(i18n("Pan and zoom, low-pass"), "Pan and zoom, low-pass");
361         m_view.animation->addItem(i18n("Zoom"), "Zoom");
362         m_view.animation->addItem(i18n("Zoom, low-pass"), "Zoom, low-pass");
363
364         m_view.slide_loop->setChecked(props.value("loop").toInt());
365         m_view.slide_crop->setChecked(props.value("crop").toInt());
366         m_view.slide_fade->setChecked(props.value("fade").toInt());
367         m_view.luma_softness->setValue(props.value("softness").toInt());
368         if (!props.value("animation").isEmpty())
369             m_view.animation->setCurrentItem(props.value("animation"));
370         else
371             m_view.animation->setCurrentIndex(0);
372         QString path = props.value("resource");
373         QString ext = path.section('.', -1);
374         for (int i = 0; i < m_view.image_type->count(); ++i) {
375             if (m_view.image_type->itemData(i).toString() == ext) {
376                 m_view.image_type->setCurrentIndex(i);
377                 break;
378             }
379         }
380         m_view.slide_duration->setText(tc.getTimecodeFromFrames(props.value("ttl").toInt()));
381
382         m_view.slide_duration_format->addItem(i18n("hh:mm:ss:ff"));
383         m_view.slide_duration_format->addItem(i18n("Frames"));
384         connect(m_view.slide_duration_format, SIGNAL(activated(int)), this, SLOT(slotUpdateDurationFormat(int)));
385         m_view.slide_duration_frames->setHidden(true);
386         m_view.luma_duration_frames->setHidden(true);
387
388         parseFolder(false);
389
390         m_view.luma_duration->setText(tc.getTimecodeFromFrames(props.value("luma_duration").toInt()));
391         QString lumaFile = props.value("luma_file");
392
393         // Check for Kdenlive installed luma files
394         QStringList filters;
395         filters << "*.pgm" << "*.png";
396
397         QStringList customLumas = KGlobal::dirs()->findDirs("appdata", "lumas");
398         foreach(const QString & folder, customLumas) {
399             QStringList filesnames = QDir(folder).entryList(filters, QDir::Files);
400             foreach(const QString & fname, filesnames) {
401                 QString filePath = KUrl(folder).path(KUrl::AddTrailingSlash) + fname;
402                 m_view.luma_file->addItem(KIcon(filePath), fname, filePath);
403             }
404         }
405
406         // Check for MLT lumas
407         QString profilePath = KdenliveSettings::mltpath();
408         QString folder = profilePath.section('/', 0, -3);
409         folder.append("/lumas/PAL"); // TODO: cleanup the PAL / NTSC mess in luma files
410         QDir lumafolder(folder);
411         QStringList filesnames = lumafolder.entryList(filters, QDir::Files);
412         foreach(const QString & fname, filesnames) {
413             QString filePath = KUrl(folder).path(KUrl::AddTrailingSlash) + fname;
414             m_view.luma_file->addItem(KIcon(filePath), fname, filePath);
415         }
416
417         if (!lumaFile.isEmpty()) {
418             m_view.slide_luma->setChecked(true);
419             m_view.luma_file->setCurrentIndex(m_view.luma_file->findData(lumaFile));
420         } else m_view.luma_file->setEnabled(false);
421         slotEnableLuma(m_view.slide_fade->checkState());
422         slotEnableLumaFile(m_view.slide_luma->checkState());
423
424         connect(m_view.slide_fade, SIGNAL(toggled(bool)), this, SLOT(slotModified()));
425         connect(m_view.slide_luma, SIGNAL(toggled(bool)), this, SLOT(slotModified()));
426         connect(m_view.slide_loop, SIGNAL(toggled(bool)), this, SLOT(slotModified()));
427         connect(m_view.slide_crop, SIGNAL(toggled(bool)), this, SLOT(slotModified()));
428         connect(m_view.slide_duration, SIGNAL(textChanged(QString)), this, SLOT(slotModified()));
429         connect(m_view.slide_duration_frames, SIGNAL(valueChanged(int)), this, SLOT(slotModified()));
430         connect(m_view.luma_duration, SIGNAL(textChanged(QString)), this, SLOT(slotModified()));
431         connect(m_view.luma_softness, SIGNAL(valueChanged(int)), this, SLOT(slotModified()));
432         connect(m_view.luma_file, SIGNAL(currentIndexChanged(int)), this, SLOT(slotModified()));
433         connect(m_view.animation, SIGNAL(currentIndexChanged(int)), this, SLOT(slotModified()));
434
435
436         connect(m_view.slide_fade, SIGNAL(stateChanged(int)), this, SLOT(slotEnableLuma(int)));
437         connect(m_view.slide_luma, SIGNAL(stateChanged(int)), this, SLOT(slotEnableLumaFile(int)));
438         connect(m_view.image_type, SIGNAL(currentIndexChanged(int)), this, SLOT(parseFolder()));
439
440     } else if (t != AUDIO) {
441         m_view.tabWidget->removeTab(IMAGETAB);
442         m_view.tabWidget->removeTab(SLIDETAB);
443         m_view.tabWidget->removeTab(COLORTAB);
444
445         PropertiesViewDelegate *del1 = new PropertiesViewDelegate(this);
446         PropertiesViewDelegate *del2 = new PropertiesViewDelegate(this);
447         m_view.clip_vproperties->setItemDelegate(del1);
448         m_view.clip_aproperties->setItemDelegate(del2);
449         m_view.clip_aproperties->setStyleSheet(QString("QTreeWidget { background-color: transparent;}"));
450         m_view.clip_vproperties->setStyleSheet(QString("QTreeWidget { background-color: transparent;}"));
451         loadVideoProperties(props);
452         
453         m_view.clip_thumb->setMinimumSize(180 * KdenliveSettings::project_display_ratio(), 180);
454         
455         if (t == IMAGE || t == VIDEO || t == PLAYLIST) m_view.tabWidget->removeTab(AUDIOTAB);
456     } else {
457         m_view.tabWidget->removeTab(IMAGETAB);
458         m_view.tabWidget->removeTab(SLIDETAB);
459         m_view.tabWidget->removeTab(COLORTAB);
460         m_view.tabWidget->removeTab(VIDEOTAB);
461         m_view.clip_thumb->setHidden(true);
462     }
463
464     if (t != SLIDESHOW && t != COLOR) {
465         KFileItem f(KFileItem::Unknown, KFileItem::Unknown, url, true);
466         m_view.clip_filesize->setText(KIO::convertSize(f.size()));
467     } else {
468         m_view.clip_filesize->setHidden(true);
469         m_view.label_size->setHidden(true);
470     }
471     m_view.clip_duration->setInputMask(tc.mask());
472     m_view.clip_duration->setText(tc.getTimecode(m_clip->duration()));
473     if (t != IMAGE && t != COLOR && t != TEXT) m_view.clip_duration->setReadOnly(true);
474     else {
475         connect(m_view.clip_duration, SIGNAL(editingFinished()), this, SLOT(slotCheckMaxLength()));
476         connect(m_view.clip_duration, SIGNAL(textChanged(QString)), this, SLOT(slotModified()));
477     }
478
479     // markers
480     m_view.marker_new->setIcon(KIcon("document-new"));
481     m_view.marker_new->setToolTip(i18n("Add marker"));
482     m_view.marker_edit->setIcon(KIcon("document-properties"));
483     m_view.marker_edit->setToolTip(i18n("Edit marker"));
484     m_view.marker_delete->setIcon(KIcon("trash-empty"));
485     m_view.marker_delete->setToolTip(i18n("Delete marker"));
486     m_view.marker_save->setIcon(KIcon("document-save-as"));
487     m_view.marker_save->setToolTip(i18n("Save markers"));
488     m_view.marker_load->setIcon(KIcon("document-open"));
489     m_view.marker_load->setToolTip(i18n("Load markers"));
490     m_view.analysis_delete->setIcon(KIcon("trash-empty"));
491     m_view.analysis_delete->setToolTip(i18n("Delete analysis data"));
492     m_view.analysis_load->setIcon(KIcon("document-open"));
493     m_view.analysis_load->setToolTip(i18n("Load analysis data"));
494     m_view.analysis_save->setIcon(KIcon("document-save-as"));
495     m_view.analysis_save->setToolTip(i18n("Save analysis data"));
496
497     // Check for Nepomuk metadata
498 #ifdef USE_NEPOMUK
499
500 #if KDE_IS_VERSION(4,6,0)
501     if (!url.isEmpty()) {
502         Nepomuk::ResourceManager::instance()->init();
503         Nepomuk::Resource res( url.path() );
504         // Check if file has a license
505         if (res.hasProperty(Nepomuk::Vocabulary::NIE::license())) {
506             QString ltype = res.property(Nepomuk::Vocabulary::NIE::licenseType()).toString();
507             m_view.clip_license->setText(i18n("License: %1", res.property(Nepomuk::Vocabulary::NIE::license()).toString()));
508             if (ltype.startsWith("http")) {
509                 m_view.clip_license->setUrl(ltype);
510                 connect(m_view.clip_license, SIGNAL(leftClickedUrl(QString)), this, SLOT(slotOpenUrl(QString)));
511             }
512         }
513         else m_view.clip_license->setHidden(true);
514     }
515     else m_view.clip_license->setHidden(true);
516 #else
517     m_view.clip_license->setHidden(true);
518 #endif
519
520 #else
521
522 #ifdef USE_NEPOMUKCORE
523
524     if (!url.isEmpty()) {
525         Nepomuk2::ResourceManager::instance()->init();
526         Nepomuk2::Resource res( url.path() );
527         // Check if file has a license
528         if (res.hasProperty(Nepomuk2::Vocabulary::NIE::license())) {
529             QString ltype = res.property(Nepomuk2::Vocabulary::NIE::licenseType()).toString();
530             m_view.clip_license->setText(i18n("License: %1", res.property(Nepomuk2::Vocabulary::NIE::license()).toString()));
531             if (ltype.startsWith("http")) {
532                 m_view.clip_license->setUrl(ltype);
533                 connect(m_view.clip_license, SIGNAL(leftClickedUrl(QString)), this, SLOT(slotOpenUrl(QString)));
534             }
535         }
536         else m_view.clip_license->setHidden(true);
537     }
538     else m_view.clip_license->setHidden(true);
539 #else
540     m_view.clip_license->setHidden(true);
541 #endif
542
543 #endif
544
545     slotFillMarkersList(m_clip);
546     slotUpdateAnalysisData(m_clip);
547     
548     connect(m_view.marker_new, SIGNAL(clicked()), this, SLOT(slotAddMarker()));
549     connect(m_view.marker_edit, SIGNAL(clicked()), this, SLOT(slotEditMarker()));
550     connect(m_view.marker_delete, SIGNAL(clicked()), this, SLOT(slotDeleteMarker()));
551     connect(m_view.marker_save, SIGNAL(clicked()), this, SLOT(slotSaveMarkers()));
552     connect(m_view.marker_load, SIGNAL(clicked()), this, SLOT(slotLoadMarkers()));
553     connect(m_view.markers_list, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(slotEditMarker()));
554     
555     connect(m_view.analysis_delete, SIGNAL(clicked()), this, SLOT(slotDeleteAnalysis()));
556     connect(m_view.analysis_save, SIGNAL(clicked()), this, SLOT(slotSaveAnalysis()));
557     connect(m_view.analysis_load, SIGNAL(clicked()), this, SLOT(slotLoadAnalysis()));
558     
559     connect(this, SIGNAL(accepted()), this, SLOT(slotApplyProperties()));
560     connect(m_view.buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(slotApplyProperties()));
561     m_view.buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
562     
563     m_view.metadata_list->resizeColumnToContents(0);
564     m_view.clip_vproperties->resizeColumnToContents(0);
565     m_view.clip_aproperties->resizeColumnToContents(0);
566     adjustSize();
567 }
568
569
570 // Used for multiple clips editing
571 ClipProperties::ClipProperties(const QList <DocClipBase *> &cliplist, const Timecode &tc, const QMap <QString, QString> &commonproperties, QWidget * parent) :
572     QDialog(parent),
573     m_clip(NULL),
574     m_tc(tc),
575     m_fps(0),
576     m_count(0),
577     m_clipNeedsRefresh(false),
578     m_clipNeedsReLoad(false)
579 {
580     setFont(KGlobalSettings::toolBarFont());
581     m_view.setupUi(this);
582     QString title = windowTitle();
583     title.append(' ' + i18np("(%1 clip)", "(%1 clips)", cliplist.count()));
584     setWindowTitle(title);
585     QMap <QString, QString> props = cliplist.at(0)->properties();
586     m_old_props = commonproperties;
587
588     if (commonproperties.contains("force_aspect_num") && !commonproperties.value("force_aspect_num").isEmpty() && commonproperties.value("force_aspect_den").toInt() > 0) {
589         m_view.clip_force_ar->setChecked(true);
590         m_view.clip_ar_num->setEnabled(true);
591         m_view.clip_ar_den->setEnabled(true);
592         m_view.clip_ar_num->setValue(commonproperties.value("force_aspect_num").toInt());
593         m_view.clip_ar_den->setValue(commonproperties.value("force_aspect_den").toInt());
594     }
595
596     if (commonproperties.contains("force_fps") && !commonproperties.value("force_fps").isEmpty() && commonproperties.value("force_fps").toDouble() > 0) {
597         m_view.clip_force_framerate->setChecked(true);
598         m_view.clip_framerate->setEnabled(true);
599         m_view.clip_framerate->setValue(commonproperties.value("force_fps").toDouble());
600     }
601
602     if (commonproperties.contains("force_progressive") && !commonproperties.value("force_progressive").isEmpty()) {
603         m_view.clip_force_progressive->setChecked(true);
604         m_view.clip_progressive->setEnabled(true);
605         m_view.clip_progressive->setCurrentIndex(commonproperties.value("force_progressive").toInt());
606     }
607
608     if (commonproperties.contains("force_tff") && !commonproperties.value("force_tff").isEmpty()) {
609         m_view.clip_force_fieldorder->setChecked(true);
610         m_view.clip_fieldorder->setEnabled(true);
611         m_view.clip_fieldorder->setCurrentIndex(commonproperties.value("force_tff").toInt());
612     }
613     
614     if (commonproperties.contains("threads") && !commonproperties.value("threads").isEmpty() && commonproperties.value("threads").toInt() != 1) {
615         m_view.clip_force_threads->setChecked(true);
616         m_view.clip_threads->setEnabled(true);
617         m_view.clip_threads->setValue(commonproperties.value("threads").toInt());
618     }
619
620     if (commonproperties.contains("video_index") && !commonproperties.value("video_index").isEmpty() && commonproperties.value("video_index").toInt() != 0) {
621         m_view.clip_force_vindex->setChecked(true);
622         m_view.clip_vindex->setEnabled(true);
623         m_view.clip_vindex->setValue(commonproperties.value("video_index").toInt());
624     }
625
626     if (commonproperties.contains("audio_index") && !commonproperties.value("audio_index").isEmpty() && commonproperties.value("audio_index").toInt() != 0) {
627         m_view.clip_force_aindex->setChecked(true);
628         m_view.clip_aindex->setEnabled(true);
629         m_view.clip_aindex->setValue(commonproperties.value("audio_index").toInt());
630     }
631
632     if (props.contains("audio_max")) {
633         m_view.clip_aindex->setMaximum(props.value("audio_max").toInt());
634     }
635
636     if (props.contains("video_max")) {
637         m_view.clip_vindex->setMaximum(props.value("video_max").toInt());
638     }
639     
640     m_view.clip_colorspace->addItem(ProfilesDialog::getColorspaceDescription(601), 601);
641     m_view.clip_colorspace->addItem(ProfilesDialog::getColorspaceDescription(709), 709);
642     m_view.clip_colorspace->addItem(ProfilesDialog::getColorspaceDescription(240), 240);
643     
644     if (commonproperties.contains("force_colorspace") && !commonproperties.value("force_colorspace").isEmpty() && commonproperties.value("force_colorspace").toInt() != 0) {
645         m_view.clip_force_colorspace->setChecked(true);
646         m_view.clip_colorspace->setEnabled(true);
647         m_view.clip_colorspace->setCurrentIndex(m_view.clip_colorspace->findData(commonproperties.value("force_colorspace").toInt()));
648     }
649     
650     if (commonproperties.contains("full_luma") && !commonproperties.value("full_luma").isEmpty()) {
651         m_view.clip_full_luma->setChecked(true);
652     }
653     
654     if (commonproperties.contains("transparency")) {
655         // image transparency checkbox
656         int transparency = commonproperties.value("transparency").toInt();
657         if (transparency == 0) {
658             m_view.clip_force_transparency->setChecked(true);
659         }
660         else if (transparency == 1) {
661             m_view.clip_force_transparency->setChecked(true);
662             m_view.clip_transparency->setCurrentIndex(1);
663         }
664     }
665     else {
666         m_view.clip_force_transparency->setHidden(true);
667         m_view.clip_transparency->setHidden(true);
668     }
669     
670
671     connect(m_view.clip_force_transparency, SIGNAL(toggled(bool)), m_view.clip_transparency, SLOT(setEnabled(bool)));
672     connect(m_view.clip_force_ar, SIGNAL(toggled(bool)), m_view.clip_ar_num, SLOT(setEnabled(bool)));
673     connect(m_view.clip_force_ar, SIGNAL(toggled(bool)), m_view.clip_ar_den, SLOT(setEnabled(bool)));
674     connect(m_view.clip_force_progressive, SIGNAL(toggled(bool)), m_view.clip_progressive, SLOT(setEnabled(bool)));
675     connect(m_view.clip_force_threads, SIGNAL(toggled(bool)), m_view.clip_threads, SLOT(setEnabled(bool)));
676     connect(m_view.clip_force_vindex, SIGNAL(toggled(bool)), m_view.clip_vindex, SLOT(setEnabled(bool)));
677     connect(m_view.clip_force_aindex, SIGNAL(toggled(bool)), m_view.clip_aindex, SLOT(setEnabled(bool)));
678     connect(m_view.clip_force_out, SIGNAL(toggled(bool)), m_view.clip_out, SLOT(setEnabled(bool)));
679     connect(m_view.clip_force_colorspace, SIGNAL(toggled(bool)), m_view.clip_colorspace, SLOT(setEnabled(bool)));
680
681     m_view.tabWidget->removeTab(METATAB);
682     m_view.tabWidget->removeTab(MARKERTAB);
683     m_view.tabWidget->removeTab(IMAGETAB);
684     m_view.tabWidget->removeTab(SLIDETAB);
685     m_view.tabWidget->removeTab(COLORTAB);
686     m_view.tabWidget->removeTab(AUDIOTAB);
687     m_view.tabWidget->removeTab(VIDEOTAB);
688
689     m_view.clip_path->setHidden(true);
690     m_view.label_path->setHidden(true);
691     m_view.label_description->setHidden(true);
692     m_view.label_size->setHidden(true);
693     m_view.clip_filesize->setHidden(true);
694     m_view.clip_filesize->setHidden(true);
695     m_view.clip_path->setHidden(true);
696     m_view.clip_description->setHidden(true);
697     m_view.clip_thumb->setHidden(true);
698     m_view.label_duration->setHidden(true);
699     m_view.clip_duration->setHidden(true);
700
701     if (commonproperties.contains("out")) {
702         if (commonproperties.value("out").toInt() > 0) {
703             m_view.clip_force_out->setChecked(true);
704             m_view.clip_out->setText(m_tc.getTimecodeFromFrames(commonproperties.value("out").toInt()));
705         } else m_view.clip_out->setText(KdenliveSettings::image_duration());
706     } else {
707         m_view.clip_force_out->setHidden(true);
708         m_view.clip_out->setHidden(true);
709     }
710 }
711
712 ClipProperties::~ClipProperties()
713 {
714     QAbstractItemDelegate *del1 = m_view.clip_vproperties->itemDelegate();
715     delete del1;
716     QAbstractItemDelegate *del2 = m_view.clip_aproperties->itemDelegate();
717     delete del2;
718 }
719
720
721 void ClipProperties::loadVideoProperties(const QMap <QString, QString> &props)
722 {
723     m_view.clip_vproperties->clear();
724     if (props.contains("videocodec"))
725         new QTreeWidgetItem(m_view.clip_vproperties, QStringList() << i18n("Video codec") << props.value("videocodec"));
726     else if (props.contains("videocodecid"))
727         new QTreeWidgetItem(m_view.clip_vproperties, QStringList() << i18n("Video codec") << props.value("videocodecid"));
728
729     if (props.contains("frame_size"))
730         new QTreeWidgetItem(m_view.clip_vproperties, QStringList() << i18n("Frame size") << props.value("frame_size"));
731
732     if (props.contains("fps")) {
733         new QTreeWidgetItem(m_view.clip_vproperties, QStringList() << i18n("Frame rate") << props.value("fps"));
734         if (!m_view.clip_framerate->isEnabled()) m_view.clip_framerate->setValue(props.value("fps").toDouble());
735     }
736
737     if (props.contains("progressive")) {
738         int scanning = props.value("progressive").toInt();
739         QString txt = scanning == 1 ? i18n("Progressive") : i18n("Interlaced");
740         new QTreeWidgetItem(m_view.clip_vproperties, QStringList() << i18n("Scanning") << txt);
741     }
742
743     if (props.contains("aspect_ratio"))
744         new QTreeWidgetItem(m_view.clip_vproperties, QStringList() << i18n("Pixel aspect ratio") << props.value("aspect_ratio"));
745
746     if (props.contains("pix_fmt"))
747         new QTreeWidgetItem(m_view.clip_vproperties, QStringList() << i18n("Pixel format") << props.value("pix_fmt"));
748
749     if (props.contains("colorspace"))
750         new QTreeWidgetItem(m_view.clip_vproperties, QStringList() << i18n("Colorspace") << ProfilesDialog::getColorspaceDescription(props.value("colorspace").toInt()));
751 }
752
753 void ClipProperties::slotGotThumbnail(const QString &id, const QImage &img)
754 {
755     if (id != m_clip->getId()) return;
756     QPixmap framedPix(img.width(), img.height());
757     framedPix.fill(Qt::transparent);
758     QPainter p(&framedPix);
759     p.setRenderHint(QPainter::Antialiasing, true);
760     QPainterPath path;
761     path.addRoundedRect(0.5, 0.5, framedPix.width() - 1, framedPix.height() - 1, 4, 4);
762     p.setClipPath(path);
763     p.drawImage(0, 0, img);
764     p.end();
765     m_view.clip_thumb->setPixmap(framedPix);
766 }
767
768 void ClipProperties::slotApplyProperties()
769 {
770     if (m_clip != NULL) {
771         QMap <QString, QString> props = properties();
772         emit applyNewClipProperties(m_clip->getId(), m_clip->currentProperties(props), props, needsTimelineRefresh(), needsTimelineReload());
773         QTimer::singleShot(1000, this, SLOT(slotReloadVideoProperties()));
774         if (props.contains("force_aspect_num"))
775             QTimer::singleShot(1000, this, SLOT(slotReloadVideoThumb()));
776     }
777     m_view.buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
778 }
779
780 void ClipProperties::slotReloadVideoProperties()
781 {
782     if (m_clip == NULL) return;
783     loadVideoProperties(m_clip->properties());
784 }
785
786 void ClipProperties::slotReloadVideoThumb()
787 {
788     if (m_clip == NULL) return;
789     emit requestThumb(QString('?' + m_clip->getId()), QList<int>() << m_clip->getClipThumbFrame());
790 }
791
792 void ClipProperties::disableClipId(const QString &id)
793 {
794     if (m_clip && m_view.buttonBox->button(QDialogButtonBox::Ok)->isEnabled()) {
795         if (m_clip->getId() == id) {
796             // clip was removed from project, close this properties dialog
797             close();
798         }
799     }
800 }
801
802 void ClipProperties::slotModified()
803 {
804     m_view.buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true);
805 }
806
807
808 void ClipProperties::slotEnableLuma(int state)
809 {
810     bool enable = false;
811     if (state == Qt::Checked) enable = true;
812     m_view.luma_duration->setEnabled(enable);
813     m_view.luma_duration_frames->setEnabled(enable);
814     m_view.slide_luma->setEnabled(enable);
815     if (enable) {
816         m_view.luma_file->setEnabled(m_view.slide_luma->isChecked());
817     } else m_view.luma_file->setEnabled(false);
818     m_view.label_softness->setEnabled(m_view.slide_luma->isChecked() && enable);
819     m_view.luma_softness->setEnabled(m_view.label_softness->isEnabled());
820 }
821
822 void ClipProperties::slotEnableLumaFile(int state)
823 {
824     bool enable = false;
825     if (state == Qt::Checked) enable = true;
826     m_view.luma_file->setEnabled(enable);
827     m_view.luma_softness->setEnabled(enable);
828     m_view.label_softness->setEnabled(enable);
829 }
830
831 void ClipProperties::slotUpdateAnalysisData(DocClipBase *clip)
832 {
833     if (m_clip != clip) return;
834     m_view.analysis_list->clear();
835     QMap <QString, QString> analysis = clip->analysisData();
836     m_view.analysis_box->setHidden(analysis.isEmpty());
837     QMap<QString, QString>::const_iterator i = analysis.constBegin();
838     while (i != analysis.constEnd()) {
839         QStringList itemtext;
840         itemtext << i.key() << i.value();
841         (void) new QTreeWidgetItem(m_view.analysis_list, itemtext);
842         ++i;
843     }
844 }
845
846 void ClipProperties::slotFillMarkersList(DocClipBase *clip)
847 {
848     if (m_clip != clip) return;
849     m_view.markers_list->clear();
850     QList < CommentedTime > marks = m_clip->commentedSnapMarkers();
851     for (int count = 0; count < marks.count(); ++count) {
852         QString time = m_tc.getTimecode(marks[count].time());
853         QStringList itemtext;
854         itemtext << time << marks.at(count).comment();
855         QTreeWidgetItem *item = new QTreeWidgetItem(m_view.markers_list, itemtext);
856         item->setData(0, Qt::DecorationRole, CommentedTime::markerColor(marks.at(count).markerType()));
857     }
858 }
859
860 void ClipProperties::slotAddMarker()
861 {
862     CommentedTime marker(GenTime(), i18n("Marker"));
863     QPointer<MarkerDialog> d = new MarkerDialog(m_clip, marker,
864                                                 m_tc, i18n("Add Marker"), this);
865     if (d->exec() == QDialog::Accepted) {
866         QList <CommentedTime> markers;
867         markers << d->newMarker();
868         emit addMarkers(m_clip->getId(), markers);
869     }
870     delete d;
871 }
872
873 void ClipProperties::slotSaveMarkers()
874 {
875     emit saveMarkers(m_clip->getId());
876 }
877
878 void ClipProperties::slotLoadMarkers()
879 {
880     emit loadMarkers(m_clip->getId());
881 }
882
883 void ClipProperties::slotEditMarker()
884 {
885     QList < CommentedTime > marks = m_clip->commentedSnapMarkers();
886     int pos = m_view.markers_list->currentIndex().row();
887     if (pos < 0 || pos > marks.count() - 1) return;
888     MarkerDialog d(m_clip, marks.at(pos), m_tc, i18n("Edit Marker"), this);
889     if (d.exec() == QDialog::Accepted) {
890         QList <CommentedTime> markers;
891         markers << d.newMarker();
892         emit addMarkers(m_clip->getId(), markers);
893     }
894 }
895
896 void ClipProperties::slotDeleteMarker()
897 {
898     QList < CommentedTime > marks = m_clip->commentedSnapMarkers();
899     QList < CommentedTime > toDelete;
900     for (int i = 0; i < marks.count(); ++i) {
901         if (m_view.markers_list->topLevelItem(i)->isSelected()) {
902             CommentedTime marker = marks.at(i);
903             marker.setMarkerType(-1);
904             toDelete << marker;
905         }
906     }
907     emit addMarkers(m_clip->getId(), toDelete);
908 }
909
910 void ClipProperties::slotDeleteAnalysis()
911 {
912     QTreeWidgetItem *current = m_view.analysis_list->currentItem();
913     if (current) emit editAnalysis(m_clip->getId(), current->text(0), QString());
914 }
915
916 void ClipProperties::slotSaveAnalysis()
917 {
918     QString url = KFileDialog::getSaveFileName(KUrl("kfiledialog:///projectfolder"), "text/plain", this, i18n("Save Analysis Data"));
919     if (url.isEmpty()) return;
920     KSharedConfigPtr config = KSharedConfig::openConfig(url, KConfig::SimpleConfig);
921     KConfigGroup analysisConfig(config, "Analysis");
922     QTreeWidgetItem *current = m_view.analysis_list->currentItem();
923     analysisConfig.writeEntry(current->text(0), current->text(1));
924 }
925
926 void ClipProperties::slotLoadAnalysis()
927 {
928     QString url = KFileDialog::getOpenFileName(KUrl("kfiledialog:///projectfolder"), "text/plain", this, i18n("Open Analysis Data"));
929     if (url.isEmpty()) return;
930     KSharedConfigPtr config = KSharedConfig::openConfig(url, KConfig::SimpleConfig);
931     KConfigGroup transConfig(config, "Analysis");
932     // read the entries
933     QMap< QString, QString > profiles = transConfig.entryMap();
934     QMapIterator<QString, QString> i(profiles);
935     while (i.hasNext()) {
936         i.next();
937         emit editAnalysis(m_clip->getId(), i.key(), i.value());
938     }
939 }
940
941 const QString &ClipProperties::clipId() const
942 {
943     return m_clip->getId();
944 }
945
946 QMap <QString, QString> ClipProperties::properties()
947 {
948     QMap <QString, QString> props;
949     QLocale locale;
950     CLIPTYPE t = UNKNOWN;
951     if (m_clip != NULL) {
952         t = m_clip->clipType();
953         m_old_props = m_clip->properties();
954     }
955
956     int aspectNumerator = m_view.clip_ar_num->value();
957     int aspectDenominator = m_view.clip_ar_den->value();
958     if (m_view.clip_force_ar->isChecked()) {
959         if (aspectNumerator != m_old_props.value("force_aspect_num").toInt() ||
960                 aspectDenominator != m_old_props.value("force_aspect_den").toInt()) {
961             props["force_aspect_num"] = QString::number(aspectNumerator);
962             props["force_aspect_den"] = QString::number(aspectDenominator);
963             props["force_aspect_ratio"].clear();
964             m_clipNeedsRefresh = true;
965         }
966     } else {
967         if (m_old_props.contains("force_aspect_num") && !m_old_props.value("force_aspect_num").isEmpty()) {
968             props["force_aspect_num"].clear();
969             m_clipNeedsRefresh = true;
970         }
971         if (m_old_props.contains("force_aspect_den") && !m_old_props.value("force_aspect_den").isEmpty()) {
972             props["force_aspect_den"].clear();
973             m_clipNeedsRefresh = true;
974         }
975     }
976
977     double fps = m_view.clip_framerate->value();
978     if (m_view.clip_force_framerate->isChecked()) {
979         if (fps != m_old_props.value("force_fps").toDouble()) {
980             props["force_fps"] = locale.toString(fps);
981             m_clipNeedsRefresh = true;
982         }
983     } else if (m_old_props.contains("force_fps") && !m_old_props.value("force_fps").isEmpty()) {
984         props["force_fps"].clear();
985         m_clipNeedsRefresh = true;
986     }
987
988     int progressive = m_view.clip_progressive->currentIndex();
989     if (m_view.clip_force_progressive->isChecked()) {
990         if (!m_old_props.contains("force_progressive") || progressive != m_old_props.value("force_progressive").toInt()) {
991             props["force_progressive"] = QString::number(progressive);
992         }
993     } else if (m_old_props.contains("force_progressive") && !m_old_props.value("force_progressive").isEmpty()) {
994         props["force_progressive"].clear();
995     }
996
997     int fieldOrder = m_view.clip_fieldorder->currentIndex();
998     if (m_view.clip_force_fieldorder->isChecked()) {
999         if (!m_old_props.contains("force_tff") || fieldOrder != m_old_props.value("force_tff").toInt()) {
1000             props["force_tff"] = QString::number(fieldOrder);
1001         }
1002     } else if (m_old_props.contains("force_tff") && !m_old_props.value("force_tff").isEmpty()) {
1003         props["force_tff"].clear();
1004     }
1005
1006     int threads = m_view.clip_threads->value();
1007     if (m_view.clip_force_threads->isChecked()) {
1008         if (threads != m_old_props.value("threads").toInt()) {
1009             props["threads"] = QString::number(threads);
1010         }
1011     } else if (m_old_props.contains("threads") && !m_old_props.value("threads").isEmpty()) {
1012         props["threads"].clear();
1013     }
1014
1015     int vindex = m_view.clip_vindex->value();
1016     if (m_view.clip_force_vindex->isChecked()) {
1017         if (vindex != m_old_props.value("video_index").toInt()) {
1018             props["video_index"] = QString::number(vindex);
1019         }
1020     } else if (m_old_props.contains("video_index") && !m_old_props.value("video_index").isEmpty()) {
1021         props["video_index"].clear();
1022     }
1023
1024     int aindex = m_view.clip_aindex->value();
1025     if (m_view.clip_force_aindex->isChecked()) {
1026         if (aindex != m_old_props.value("audio_index").toInt()) {
1027             props["audio_index"] = QString::number(aindex);
1028         }
1029     } else if (m_old_props.contains("audio_index") && !m_old_props.value("audio_index").isEmpty()) {
1030         props["audio_index"].clear();
1031     }
1032     
1033     int colorspace = m_view.clip_colorspace->itemData(m_view.clip_colorspace->currentIndex()).toInt();
1034     if (m_view.clip_force_colorspace->isChecked()) {
1035         if (colorspace != m_old_props.value("force_colorspace").toInt()) {
1036             props["force_colorspace"] = QString::number(colorspace);
1037             m_clipNeedsRefresh = true;
1038         }
1039     } else if (m_old_props.contains("force_colorspace") && !m_old_props.value("force_colorspace").isEmpty()) {
1040         props["force_colorspace"].clear();
1041         m_clipNeedsRefresh = true;
1042     }
1043
1044     if (m_view.clip_full_luma->isChecked()) {
1045         props["full_luma"] = QString::number(1);
1046         m_clipNeedsRefresh = true;
1047     } else if (m_old_props.contains("full_luma") && !m_old_props.value("full_luma").isEmpty()) {
1048         props["full_luma"].clear();
1049         m_clipNeedsRefresh = true;
1050     }
1051     
1052     if (m_view.clip_force_transparency->isChecked()) {
1053         QString transp = QString::number(m_view.clip_transparency->currentIndex());
1054         if (transp != m_old_props.value("transparency")) props["transparency"] = transp;
1055     }
1056
1057     // If we adjust several clips, return now
1058     if (m_clip == NULL) {
1059         if (m_view.clip_out->isEnabled()) {
1060             int duration = m_tc.getFrameCount(m_view.clip_out->text());
1061             if (duration != m_old_props.value("out").toInt()) {
1062                 props["out"] = QString::number(duration - 1);
1063             }
1064         }
1065         return props;
1066     }
1067
1068     if (m_old_props.value("description") != m_view.clip_description->text())
1069         props["description"] = m_view.clip_description->text();
1070
1071     if (t == COLOR) {
1072         QString new_color = m_view.clip_color->color().name();
1073         if (new_color != QString('#' + m_old_props.value("colour").right(8).left(6))) {
1074             m_clipNeedsRefresh = true;
1075             props["colour"] = "0x" + new_color.right(6) + "ff";
1076         }
1077         int duration = m_tc.getFrameCount(m_view.clip_duration->text());
1078         if (duration != m_clip->duration().frames(m_fps)) {
1079             props["out"] = QString::number(duration - 1);
1080         }
1081     } else if (t == IMAGE) {
1082         if ((int) m_view.image_transparency->isChecked() != m_old_props.value("transparency").toInt()) {
1083             props["transparency"] = QString::number((int)m_view.image_transparency->isChecked());
1084             //m_clipNeedsRefresh = true;
1085         }
1086         int duration = m_tc.getFrameCount(m_view.clip_duration->text());
1087         if (duration != m_clip->duration().frames(m_fps)) {
1088             props["out"] = QString::number(duration - 1);
1089         }
1090     } else if (t == SLIDESHOW) {
1091         QString value = QString::number((int) m_view.slide_loop->isChecked());
1092         if (m_old_props.value("loop") != value) props["loop"] = value;
1093         value = QString::number((int) m_view.slide_crop->isChecked());
1094         if (m_old_props.value("crop") != value) props["crop"] = value;
1095         value = QString::number((int) m_view.slide_fade->isChecked());
1096         if (m_old_props.value("fade") != value) props["fade"] = value;
1097         value = QString::number((int) m_view.luma_softness->value());
1098         if (m_old_props.value("softness") != value) props["softness"] = value;
1099
1100         bool isMime = !(m_view.clip_path->text().contains('%'));
1101         if (isMime) {
1102             QString extension = "/.all." + m_view.image_type->itemData(m_view.image_type->currentIndex()).toString();
1103             QString new_path = m_view.clip_path->text() + extension;
1104             if (new_path != m_old_props.value("resource")) {
1105                 m_clipNeedsReLoad = true;
1106                 props["resource"] = new_path;
1107                 kDebug() << "////  SLIDE EDIT, NEW:" << new_path << ", OLD; " << m_old_props.value("resource");
1108             }
1109         }
1110         int duration;
1111         if (m_view.slide_duration_format->currentIndex() == 1) {
1112             // we are in frames mode
1113             duration = m_view.slide_duration_frames->value();
1114         } else duration = m_tc.getFrameCount(m_view.slide_duration->text());
1115         if (duration != m_old_props.value("ttl").toInt()) {
1116             m_clipNeedsRefresh = true;
1117             props["ttl"] = QString::number(duration);
1118             props["length"] = QString::number(duration * m_count);
1119         }
1120
1121         if (duration * m_count - 1 != m_old_props.value("out").toInt()) {
1122             m_clipNeedsRefresh = true;
1123             props["out"] = QString::number(duration * m_count - 1);
1124         }
1125         if (m_view.slide_fade->isChecked()) {
1126             int luma_duration;
1127             if (m_view.slide_duration_format->currentIndex() == 1) {
1128                 // we are in frames mode
1129                 luma_duration = m_view.luma_duration_frames->value();
1130             } else luma_duration = m_tc.getFrameCount(m_view.luma_duration->text());
1131             if (luma_duration != m_old_props.value("luma_duration").toInt()) {
1132                 m_clipNeedsRefresh = true;
1133                 props["luma_duration"] = QString::number(luma_duration);
1134             }
1135             QString lumaFile;
1136             if (m_view.slide_luma->isChecked())
1137                 lumaFile = m_view.luma_file->itemData(m_view.luma_file->currentIndex()).toString();
1138             if (lumaFile != m_old_props.value("luma_file")) {
1139                 m_clipNeedsRefresh = true;
1140                 props["luma_file"] = lumaFile;
1141             }
1142         } else {
1143             if (!m_old_props.value("luma_file").isEmpty()) {
1144                 props["luma_file"].clear();
1145             }
1146         }
1147
1148         QString animation = m_view.animation->itemData(m_view.animation->currentIndex()).toString();
1149         if (animation != m_old_props.value("animation")) {
1150             if (animation.isEmpty()) {
1151                 props["animation"].clear();
1152             } else {
1153                 props["animation"] = animation;
1154             }
1155             m_clipNeedsRefresh = true;
1156         }
1157     }
1158     return props;
1159 }
1160
1161 bool ClipProperties::needsTimelineRefresh() const
1162 {
1163     return m_clipNeedsRefresh;
1164 }
1165
1166 bool ClipProperties::needsTimelineReload() const
1167 {
1168     return m_clipNeedsReLoad;
1169 }
1170
1171
1172 void ClipProperties::parseFolder(bool reloadThumb)
1173 {
1174     QString path = m_view.clip_path->text();
1175     bool isMime = !(path.contains('%'));
1176     if (!isMime) path = KUrl(path).directory();
1177     QDir dir(path);
1178
1179     QStringList filters;
1180     QString extension;
1181
1182     if (isMime) {
1183         // TODO: improve jpeg image detection with extension like jpeg, requires change in MLT image producers
1184         filters << "*." + m_view.image_type->itemData(m_view.image_type->currentIndex()).toString();
1185         extension = "/.all." + m_view.image_type->itemData(m_view.image_type->currentIndex()).toString();
1186         dir.setNameFilters(filters);
1187     }
1188
1189     QStringList result = dir.entryList(QDir::Files);
1190
1191     if (!isMime) {
1192         int offset = 0;
1193         QString path = m_view.clip_path->text();
1194         if (path.contains('?')) {
1195             // New MLT syntax
1196             offset = m_view.clip_path->text().section(':', -1).toInt();
1197             path = path.section('?', 0, 0);
1198         }
1199         QString filter = KUrl(path).fileName();
1200         QString ext = filter.section('.', -1);
1201         filter = filter.section('%', 0, -2);
1202         QString regexp = '^' + filter + "\\d+\\." + ext + '$';
1203         QRegExp rx(regexp);
1204         QStringList entries;
1205         int ix;
1206         foreach(const QString & path, result) {
1207             if (rx.exactMatch(path)) {
1208                 if (offset > 0) {
1209                     // make sure our image is in the range we want (> begin)
1210                     ix = path.section(filter, 1).section('.', 0, 0).toInt();
1211                     if (ix < offset) continue;
1212                 }
1213                 entries << path;
1214             }
1215         }
1216         result = entries;
1217     }
1218
1219     m_count = result.count();
1220     m_view.buttonBox->button(QDialogButtonBox::Apply)->setEnabled(m_count > 0);
1221     if (m_count == 0) {
1222         // no images, do not accept that
1223         m_view.slide_info->setText(i18n("No image found"));
1224         m_view.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
1225         return;
1226     }
1227     m_view.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
1228     m_view.slide_info->setText(i18np("1 image found", "%1 images found", m_count));
1229     QMap <QString, QString> props = m_clip->properties();
1230     m_view.clip_duration->setText(m_tc.getTimecodeFromFrames(props.value("ttl").toInt() * m_count));
1231     if (reloadThumb) {
1232         int width = 180.0 * KdenliveSettings::project_display_ratio();
1233         if (width % 2 == 1) width++;
1234         QString filePath = m_view.clip_path->text();
1235         if (isMime) filePath.append(extension);
1236         QPixmap pix = m_clip->thumbProducer()->getImage(KUrl(filePath), 1, width, 180);
1237         m_view.clip_thumb->setPixmap(pix);
1238     }
1239 }
1240
1241 void ClipProperties::slotCheckMaxLength()
1242 {
1243     if (m_clip->maxDuration() == GenTime()) return;
1244     int duration = m_tc.getFrameCount(m_view.clip_duration->text());
1245     if (duration > m_clip->maxDuration().frames(m_fps)) {
1246         m_view.clip_duration->setText(m_tc.getTimecode(m_clip->maxDuration()));
1247     }
1248 }
1249
1250 void ClipProperties::slotUpdateDurationFormat(int ix)
1251 {
1252     bool framesFormat = ix == 1;
1253     if (framesFormat) {
1254         // switching to frames count, update widget
1255         m_view.slide_duration_frames->setValue(m_tc.getFrameCount(m_view.slide_duration->text()));
1256         m_view.luma_duration_frames->setValue(m_tc.getFrameCount(m_view.luma_duration->text()));
1257         m_view.slide_duration->setHidden(true);
1258         m_view.luma_duration->setHidden(true);
1259         m_view.slide_duration_frames->setHidden(false);
1260         m_view.luma_duration_frames->setHidden(false);
1261     } else {
1262         // switching to timecode format
1263         m_view.slide_duration->setText(m_tc.getTimecodeFromFrames(m_view.slide_duration_frames->value()));
1264         m_view.luma_duration->setText(m_tc.getTimecodeFromFrames(m_view.luma_duration_frames->value()));
1265         m_view.slide_duration_frames->setHidden(true);
1266         m_view.luma_duration_frames->setHidden(true);
1267         m_view.slide_duration->setHidden(false);
1268         m_view.luma_duration->setHidden(false);
1269     }
1270 }
1271
1272 void ClipProperties::slotDeleteProxy()
1273 {
1274     QString proxy = m_clip->getProperty("proxy");
1275     if (proxy.isEmpty()) return;
1276     emit deleteProxy(proxy);
1277     if (m_proxyContainer) delete m_proxyContainer;
1278 }
1279
1280 void ClipProperties::slotOpenUrl(const QString &url)
1281 {
1282     new KRun(KUrl(url), this);
1283 }
1284
1285 #include "clipproperties.moc"
1286
1287
1288