]> git.sesse.net Git - kdenlive/blob - src/effectstack/collapsibleeffect.cpp
Start work on effect groups
[kdenlive] / src / effectstack / collapsibleeffect.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 "collapsibleeffect.h"
22
23 #include "ui_listval_ui.h"
24 #include "ui_boolval_ui.h"
25 #include "ui_wipeval_ui.h"
26 #include "ui_urlval_ui.h"
27 #include "ui_keywordval_ui.h"
28 #include "ui_fontval_ui.h"
29 #include "complexparameter.h"
30 #include "geometryval.h"
31 #include "positionedit.h"
32 #include "projectlist.h"
33 #include "effectslist.h"
34 #include "kdenlivesettings.h"
35 #include "profilesdialog.h"
36 #include "kis_curve_widget.h"
37 #include "kis_cubic_curve.h"
38 #include "choosecolorwidget.h"
39 #include "geometrywidget.h"
40 #include "colortools.h"
41 #include "doubleparameterwidget.h"
42 #include "cornerswidget.h"
43 #include "dragvalue.h"
44 #include "beziercurve/beziersplinewidget.h"
45 #ifdef USE_QJSON
46 #include "rotoscoping/rotowidget.h"
47 #endif
48
49 #include <QInputDialog>
50 #include <QDialog>
51 #include <QMenu>
52 #include <QVBoxLayout>
53 #include <KDebug>
54 #include <KGlobalSettings>
55 #include <KLocale>
56 #include <KMessageBox>
57 #include <KStandardDirs>
58 #include <KFileDialog>
59 #include <KUrlRequester>
60
61 class Boolval: public QWidget, public Ui::Boolval_UI
62 {
63 };
64
65 class Listval: public QWidget, public Ui::Listval_UI
66 {
67 };
68
69 class Wipeval: public QWidget, public Ui::Wipeval_UI
70 {
71 };
72
73 class Urlval: public QWidget, public Ui::Urlval_UI
74 {
75 };
76
77 class Keywordval: public QWidget, public Ui::Keywordval_UI
78 {
79 };
80
81 class Fontval: public QWidget, public Ui::Fontval_UI
82 {
83 };
84
85 QMap<QString, QImage> CollapsibleEffect::iconCache;
86
87 void clearLayout(QLayout *layout)
88 {
89     QLayoutItem *item;
90     while((item = layout->takeAt(0))) {
91         if (item->layout()) {
92             clearLayout(item->layout());
93             delete item->layout();
94         }
95         if (item->widget()) {
96             delete item->widget();
97         }
98         delete item;
99     }
100 }
101
102 MySpinBox::MySpinBox(QWidget * parent):
103     QSpinBox(parent)
104 {
105     setFocusPolicy(Qt::StrongFocus);
106 }
107
108 void MySpinBox::focusInEvent(QFocusEvent*)
109 {
110      setFocusPolicy(Qt::WheelFocus);
111 }
112
113 void MySpinBox::focusOutEvent(QFocusEvent*)
114 {
115      setFocusPolicy(Qt::StrongFocus);
116 }
117
118
119 CollapsibleEffect::CollapsibleEffect(QDomElement effect, QDomElement original_effect, ItemInfo info, int ix, EffectMetaInfo *metaInfo, bool lastEffect, bool isGroup, QWidget * parent) :
120         QWidget(parent),
121         m_paramWidget(NULL),
122         m_effect(effect),
123         m_original_effect(original_effect),
124         m_lastEffect(lastEffect),
125         m_isGroup(isGroup),
126         m_active(false)
127 {
128     //setMouseTracking(true);
129     setupUi(this);
130     frame->setBackgroundRole(QPalette::Midlight);
131     frame->setAutoFillBackground(true);
132     setFont(KGlobalSettings::smallestReadableFont());
133    
134     buttonUp->setIcon(KIcon("go-up"));
135     buttonUp->setToolTip(i18n("Move effect up"));
136     if (!lastEffect) {
137         buttonDown->setIcon(KIcon("go-down"));
138         buttonDown->setToolTip(i18n("Move effect down"));
139     }
140     buttonDel->setIcon(KIcon("edit-delete"));
141     buttonDel->setToolTip(i18n("Delete effect"));
142
143     buttonUp->setVisible(false);
144     buttonDown->setVisible(false);
145     buttonDel->setVisible(false);
146     
147     /*buttonReset->setIcon(KIcon("view-refresh"));
148     buttonReset->setToolTip(i18n("Reset effect"));*/
149     //checkAll->setToolTip(i18n("Enable/Disable all effects"));
150     //buttonShowComments->setIcon(KIcon("help-about"));
151     //buttonShowComments->setToolTip(i18n("Show additional information for the parameters"));
152     m_menu = new QMenu;
153     m_menu->addAction(KIcon("view-refresh"), i18n("Reset effect"), this, SLOT(slotResetEffect()));
154     m_menu->addAction(KIcon("document-save"), i18n("Save effect"), this, SLOT(slotSaveEffect()));
155     
156     if (!m_isGroup) {
157         QDomElement namenode = m_effect.firstChildElement("name");
158         if (namenode.isNull()) return;
159         title->setText(i18n(namenode.text().toUtf8().data()));
160         QString type = m_effect.attribute("type", QString());
161         KIcon icon;
162         if (type == "audio") icon = KIcon("kdenlive-show-audio");
163         else if (m_effect.attribute("tag") == "region") icon = KIcon("kdenlive-mask-effect");
164         else if (type == "custom") icon = KIcon("kdenlive-custom-effect");
165         else icon = KIcon("kdenlive-show-video");
166         title->setIcon(icon);
167         m_menu->addAction(KIcon("folder-new"), i18n("Create Group"), this, SLOT(slotCreateGroup()));
168         setupWidget(info, ix, metaInfo);
169     }
170     else {
171         setAcceptDrops(true);
172         title->setText(i18n("Effect Group"));
173         title->setIcon(KIcon("folder"));
174     }
175     
176     title->setMenu(m_menu);
177     
178     if (m_effect.attribute("disable") == "1") {
179         enabledBox->setCheckState(Qt::Unchecked);
180         title->setEnabled(false);
181     }
182     else {
183         enabledBox->setCheckState(Qt::Checked);
184     }
185
186     connect(collapseButton, SIGNAL(clicked()), this, SLOT(slotSwitch()));
187     connect(enabledBox, SIGNAL(toggled(bool)), this, SLOT(slotEnable(bool)));
188     connect(buttonUp, SIGNAL(clicked()), this, SLOT(slotEffectUp()));
189     connect(buttonDown, SIGNAL(clicked()), this, SLOT(slotEffectDown()));
190     connect(buttonDel, SIGNAL(clicked()), this, SLOT(slotDeleteEffect()));
191
192     Q_FOREACH( QSpinBox * sp, findChildren<QSpinBox*>() ) {
193         sp->installEventFilter( this );
194         sp->setFocusPolicy( Qt::StrongFocus );
195     }
196     Q_FOREACH( KComboBox * cb, findChildren<KComboBox*>() ) {
197         cb->installEventFilter( this );
198         cb->setFocusPolicy( Qt::StrongFocus );
199     }
200     Q_FOREACH( QProgressBar * cb, findChildren<QProgressBar*>() ) {
201         cb->installEventFilter( this );
202         cb->setFocusPolicy( Qt::StrongFocus );
203     }
204 }
205
206 CollapsibleEffect::~CollapsibleEffect()
207 {
208     if (m_paramWidget) delete m_paramWidget;
209     delete m_menu;
210 }
211
212 void CollapsibleEffect::slotCreateGroup()
213 {
214     emit createGroup(m_paramWidget->index());
215 }
216
217 bool CollapsibleEffect::eventFilter( QObject * o, QEvent * e ) 
218 {
219     if (e->type() == QEvent::Wheel) {
220         QWheelEvent *we = static_cast<QWheelEvent *>(e);
221         if (we->modifiers() != Qt::NoModifier) {
222             e->accept();
223             return false;
224         }
225         if (qobject_cast<QAbstractSpinBox*>(o)) {
226             if(qobject_cast<QAbstractSpinBox*>(o)->focusPolicy() == Qt::WheelFocus)
227             {
228                 e->accept();
229                 return false;
230             }
231             else
232             {
233                 e->ignore();
234                 return true;
235             }
236         }
237         if (qobject_cast<KComboBox*>(o)) {
238             if(qobject_cast<KComboBox*>(o)->focusPolicy() == Qt::WheelFocus)
239             {
240                 e->accept();
241                 return false;
242             }
243             else
244             {
245                 e->ignore();
246                 return true;
247             }
248         }
249         if (qobject_cast<QProgressBar*>(o)) {
250             if(qobject_cast<QProgressBar*>(o)->focusPolicy() == Qt::WheelFocus)
251             {
252                 e->accept();
253                 return false;
254             }
255             else
256             {
257                 e->ignore();
258                 return true;
259             }
260         }
261     }
262     return QWidget::eventFilter(o, e);
263 }
264
265 QDomElement CollapsibleEffect::effect() const
266 {
267     return m_effect;
268 }
269
270 void CollapsibleEffect::setActive(bool activate)
271 {
272     m_active = activate;
273     frame->setBackgroundRole(m_active ? QPalette::Mid : QPalette::Midlight);
274     frame->setAutoFillBackground(activate);
275 }
276
277 void CollapsibleEffect::mouseDoubleClickEvent ( QMouseEvent * event )
278 {
279     if (frame->underMouse() && collapseButton->isEnabled()) slotSwitch();
280     QWidget::mouseDoubleClickEvent(event);
281 }
282
283 void CollapsibleEffect::mousePressEvent ( QMouseEvent *event )
284 {
285     if (!m_active) emit activateEffect(m_paramWidget->index());
286     QWidget::mousePressEvent(event);
287 }
288
289 void CollapsibleEffect::enterEvent ( QEvent * event )
290 {
291     if (m_paramWidget == NULL || m_paramWidget->index() > 0) buttonUp->setVisible(true);
292     if (!m_lastEffect) buttonDown->setVisible(true);
293     buttonDel->setVisible(true);
294     if (!m_active) frame->setBackgroundRole(QPalette::Midlight);
295     frame->setAutoFillBackground(true);
296     QWidget::enterEvent(event);
297 }
298
299 void CollapsibleEffect::leaveEvent ( QEvent * event )
300 {
301     buttonUp->setVisible(false);
302     buttonDown->setVisible(false);
303     buttonDel->setVisible(false);
304     if (!m_active) frame->setAutoFillBackground(false);
305     QWidget::leaveEvent(event);
306 }
307
308 void CollapsibleEffect::slotEnable(bool enable)
309 {
310     title->setEnabled(enable);
311     m_effect.setAttribute("disable", enable ? 0 : 1);
312     if (enable || KdenliveSettings::disable_effect_parameters()) {
313         widgetFrame->setEnabled(enable);
314     }
315     emit effectStateChanged(!enable, m_paramWidget->index());
316 }
317
318 void CollapsibleEffect::slotDeleteEffect()
319 {
320     emit deleteEffect(m_effect, m_paramWidget->index());
321 }
322
323 void CollapsibleEffect::slotEffectUp()
324 {
325     emit changeEffectPosition(m_paramWidget->index(), true);
326 }
327
328 void CollapsibleEffect::slotEffectDown()
329 {
330     emit changeEffectPosition(m_paramWidget->index(), false);
331 }
332
333 void CollapsibleEffect::slotSaveEffect()
334 {
335     QString name = QInputDialog::getText(this, i18n("Save Effect"), i18n("Name for saved effect: "));
336     if (name.isEmpty()) return;
337     QString path = KStandardDirs::locateLocal("appdata", "effects/", true);
338     path = path + name + ".xml";
339     if (QFile::exists(path)) if (KMessageBox::questionYesNo(this, i18n("File %1 already exists.\nDo you want to overwrite it?", path)) == KMessageBox::No) return;
340
341     QDomDocument doc;
342     QDomElement effect = m_effect.cloneNode().toElement();
343     doc.appendChild(doc.importNode(effect, true));
344     effect = doc.firstChild().toElement();
345     effect.removeAttribute("kdenlive_ix");
346     effect.setAttribute("id", name);
347     effect.setAttribute("type", "custom");
348     QDomElement effectname = effect.firstChildElement("name");
349     effect.removeChild(effectname);
350     effectname = doc.createElement("name");
351     QDomText nametext = doc.createTextNode(name);
352     effectname.appendChild(nametext);
353     effect.insertBefore(effectname, QDomNode());
354     QDomElement effectprops = effect.firstChildElement("properties");
355     effectprops.setAttribute("id", name);
356     effectprops.setAttribute("type", "custom");
357
358     QFile file(path);
359     if (file.open(QFile::WriteOnly | QFile::Truncate)) {
360         QTextStream out(&file);
361         out << doc.toString();
362     }
363     file.close();
364     emit reloadEffects();
365 }
366
367 void CollapsibleEffect::slotResetEffect()
368 {
369     emit resetEffect(m_paramWidget->index());
370 }
371
372 void CollapsibleEffect::slotSwitch()
373 {
374     bool enable = !widgetFrame->isVisible();
375     slotShow(enable);
376 }
377
378 void CollapsibleEffect::slotShow(bool show)
379 {
380     widgetFrame->setVisible(show);
381     if (show) {
382         collapseButton->setArrowType(Qt::DownArrow);
383         m_original_effect.removeAttribute("k_collapsed");
384     }
385     else {
386         collapseButton->setArrowType(Qt::RightArrow);
387         m_original_effect.setAttribute("k_collapsed", 1);
388     }
389 }
390
391 void CollapsibleEffect::addGroupEffect(CollapsibleEffect *effect)
392 {
393     QVBoxLayout *vbox = static_cast<QVBoxLayout *>(widgetFrame->layout());
394     if (vbox == NULL) {
395         vbox = new QVBoxLayout();
396         vbox->setContentsMargins(10, 0, 0, 0);
397         vbox->setSpacing(2);
398         widgetFrame->setLayout(vbox);
399     }
400     vbox->addWidget(effect);
401 }
402
403 int CollapsibleEffect::index() const
404 {
405     if (m_paramWidget) return m_paramWidget->index();
406     return 0;
407 }
408
409 int CollapsibleEffect::effectIndex() const
410 {
411     if (m_effect.isNull()) return -1;
412     return m_effect.attribute("kdenlive_ix").toInt();
413 }
414
415 void CollapsibleEffect::updateWidget(ItemInfo info, int index, QDomElement effect, EffectMetaInfo *metaInfo)
416 {
417     if (m_paramWidget) {
418         // cleanup
419         delete m_paramWidget;
420         m_paramWidget = NULL;
421     }
422     m_effect = effect;
423     setupWidget(info, index, metaInfo);
424 }
425
426 void CollapsibleEffect::setupWidget(ItemInfo info, int index, EffectMetaInfo *metaInfo)
427 {
428     if (m_effect.isNull()) {
429 //         kDebug() << "// EMPTY EFFECT STACK";
430         return;
431     }
432
433     if (m_effect.attribute("tag") == "region") {
434         QVBoxLayout *vbox = new QVBoxLayout(widgetFrame);
435         vbox->setContentsMargins(0, 0, 0, 0);
436         vbox->setSpacing(2);
437         QDomNodeList effects =  m_effect.elementsByTagName("effect");
438         QDomNodeList origin_effects =  m_original_effect.elementsByTagName("effect");
439         QWidget *container = new QWidget(widgetFrame);
440         vbox->addWidget(container);
441         m_paramWidget = new ParameterContainer(m_effect.toElement(), info, metaInfo, index, container);
442         for (int i = 0; i < effects.count(); i++) {
443             CollapsibleEffect *coll = new CollapsibleEffect(effects.at(i).toElement(), origin_effects.at(i).toElement(), info, i, metaInfo, container);
444             m_subParamWidgets.append(coll);
445             //container = new QWidget(widgetFrame);
446             vbox->addWidget(coll);
447             //p = new ParameterContainer(effects.at(i).toElement(), info, isEffect, container);
448         }
449         
450     }
451     else {
452         m_paramWidget = new ParameterContainer(m_effect, info, metaInfo, index, widgetFrame);
453         if (m_effect.firstChildElement("parameter").isNull()) {
454             // Effect has no parameter, don't allow expand
455             collapseButton->setEnabled(false);
456             widgetFrame->setVisible(false);            
457         }
458     }
459     if (collapseButton->isEnabled()) slotShow(!m_effect.hasAttribute("k_collapsed"));
460     connect (m_paramWidget, SIGNAL(parameterChanged(const QDomElement, const QDomElement, int)), this, SIGNAL(parameterChanged(const QDomElement, const QDomElement, int)));
461     
462     connect(m_paramWidget, SIGNAL(startFilterJob(QString,QString,QString,QString,QString,QString)), this, SIGNAL(startFilterJob(QString,QString,QString,QString,QString,QString)));
463     
464     connect (this, SIGNAL(syncEffectsPos(int)), m_paramWidget, SIGNAL(syncEffectsPos(int)));
465     connect (this, SIGNAL(effectStateChanged(bool)), m_paramWidget, SIGNAL(effectStateChanged(bool)));
466     connect (m_paramWidget, SIGNAL(checkMonitorPosition(int)), this, SIGNAL(checkMonitorPosition(int)));
467     connect (m_paramWidget, SIGNAL(seekTimeline(int)), this, SIGNAL(seekTimeline(int)));
468     
469     
470 }
471
472 void CollapsibleEffect::updateTimecodeFormat()
473 {
474     m_paramWidget->updateTimecodeFormat();
475     if (!m_subParamWidgets.isEmpty()) {
476         // we have a group
477         for (int i = 0; i < m_subParamWidgets.count(); i++)
478             m_subParamWidgets.at(i)->updateTimecodeFormat();
479     }
480 }
481
482 void CollapsibleEffect::slotSyncEffectsPos(int pos)
483 {
484     emit syncEffectsPos(pos);
485 }
486
487 void CollapsibleEffect::dragEnterEvent(QDragEnterEvent *event)
488 {
489     if (event->mimeData()->hasFormat("kdenlive/effectslist"))
490         event->acceptProposedAction();
491 }
492
493 void CollapsibleEffect::dropEvent(QDropEvent *event)
494 {
495     const QString effects = QString::fromUtf8(event->mimeData()->data("kdenlive/effectslist"));
496     //event->acceptProposedAction();
497     QDomDocument doc;
498     doc.setContent(effects, true);
499     const QDomElement e = doc.documentElement();
500     int ix = e.attribute("kdenlive_ix").toInt();
501     emit moveEffect(ix, this);
502     event->setDropAction(Qt::MoveAction);
503     event->accept();
504 }
505
506 ParameterContainer::ParameterContainer(QDomElement effect, ItemInfo info, EffectMetaInfo *metaInfo, int index, QWidget * parent) :
507         m_index(index),
508         m_keyframeEditor(NULL),
509         m_geometryWidget(NULL),
510         m_metaInfo(metaInfo),
511         m_effect(effect)
512 {
513     m_in = info.cropStart.frames(KdenliveSettings::project_fps());
514     m_out = (info.cropStart + info.cropDuration).frames(KdenliveSettings::project_fps()) - 1;
515
516     QDomNodeList namenode = effect.childNodes(); //elementsByTagName("parameter");
517     
518     QDomElement e = effect.toElement();
519     int minFrame = e.attribute("start").toInt();
520     int maxFrame = e.attribute("end").toInt();
521     // In transitions, maxFrame is in fact one frame after the end of transition
522     if (maxFrame > 0) maxFrame --;
523
524     bool disable = effect.attribute("disable") == "1" && KdenliveSettings::disable_effect_parameters();
525     parent->setEnabled(!disable);
526
527     bool stretch = true;
528     m_vbox = new QVBoxLayout(parent);
529     m_vbox->setContentsMargins(0, 0, 0, 0);
530     m_vbox->setSpacing(2);
531
532     for (int i = 0; i < namenode.count() ; i++) {
533         QDomElement pa = namenode.item(i).toElement();
534         if (pa.tagName() != "parameter") continue;
535         QDomElement na = pa.firstChildElement("name");
536         QDomElement commentElem = pa.firstChildElement("comment");
537         QString type = pa.attribute("type");
538         QString paramName = na.isNull() ? pa.attribute("name") : i18n(na.text().toUtf8().data());
539         QString comment;
540         if (!commentElem.isNull())
541             comment = i18n(commentElem.text().toUtf8().data());
542         QWidget * toFillin = new QWidget(parent);
543         QString value = pa.attribute("value").isNull() ?
544                         pa.attribute("default") : pa.attribute("value");
545
546
547         /** See effects/README for info on the different types */
548
549         if (type == "double" || type == "constant") {
550             double min;
551             double max;
552             if (pa.attribute("min").contains('%'))
553                 min = ProfilesDialog::getStringEval(m_metaInfo->profile, pa.attribute("min"), m_metaInfo->frameSize);
554             else
555                 min = pa.attribute("min").toDouble();
556             if (pa.attribute("max").contains('%'))
557                 max = ProfilesDialog::getStringEval(m_metaInfo->profile, pa.attribute("max"), m_metaInfo->frameSize);
558             else
559                 max = pa.attribute("max").toDouble();
560
561             DoubleParameterWidget *doubleparam = new DoubleParameterWidget(paramName, value.toDouble(), min, max,
562                     pa.attribute("default").toDouble(), comment, -1, pa.attribute("suffix"), pa.attribute("decimals").toInt(), parent);
563             doubleparam->setFocusPolicy(Qt::StrongFocus);
564             m_vbox->addWidget(doubleparam);
565             m_valueItems[paramName] = doubleparam;
566             connect(doubleparam, SIGNAL(valueChanged(double)), this, SLOT(slotCollectAllParameters()));
567             connect(this, SIGNAL(showComments(bool)), doubleparam, SLOT(slotShowComment(bool)));
568         } else if (type == "list") {
569             Listval *lsval = new Listval;
570             lsval->setupUi(toFillin);
571             lsval->list->setFocusPolicy(Qt::StrongFocus);
572             QStringList listitems = pa.attribute("paramlist").split(';');
573             if (listitems.count() == 1) {
574                 // probably custom effect created before change to ';' as separator
575                 listitems = pa.attribute("paramlist").split(",");
576             }
577             QDomElement list = pa.firstChildElement("paramlistdisplay");
578             QStringList listitemsdisplay;
579             if (!list.isNull()) {
580                 listitemsdisplay = i18n(list.text().toUtf8().data()).split(',');
581             } else {
582                 listitemsdisplay = i18n(pa.attribute("paramlistdisplay").toUtf8().data()).split(',');
583             }
584             if (listitemsdisplay.count() != listitems.count())
585                 listitemsdisplay = listitems;
586             lsval->list->setIconSize(QSize(30, 30));
587             for (int i = 0; i < listitems.count(); i++) {
588                 lsval->list->addItem(listitemsdisplay.at(i), listitems.at(i));
589                 QString entry = listitems.at(i);
590                 if (!entry.isEmpty() && (entry.endsWith(".png") || entry.endsWith(".pgm"))) {
591                     if (!CollapsibleEffect::iconCache.contains(entry)) {
592                         QImage pix(entry);
593                         CollapsibleEffect::iconCache[entry] = pix.scaled(30, 30);
594                     }
595                     lsval->list->setItemIcon(i, QPixmap::fromImage(CollapsibleEffect::iconCache[entry]));
596                 }
597             }
598             if (!value.isEmpty()) lsval->list->setCurrentIndex(listitems.indexOf(value));
599             lsval->name->setText(paramName);
600             lsval->labelComment->setText(comment);
601             lsval->widgetComment->setHidden(true);
602             m_valueItems[paramName] = lsval;
603             connect(lsval->list, SIGNAL(currentIndexChanged(int)) , this, SLOT(slotCollectAllParameters()));
604             if (!comment.isEmpty())
605                 connect(this, SIGNAL(showComments(bool)), lsval->widgetComment, SLOT(setVisible(bool)));
606             m_uiItems.append(lsval);
607         } else if (type == "bool") {
608             Boolval *bval = new Boolval;
609             bval->setupUi(toFillin);
610             bval->checkBox->setCheckState(value == "0" ? Qt::Unchecked : Qt::Checked);
611             bval->name->setText(paramName);
612             bval->labelComment->setText(comment);
613             bval->widgetComment->setHidden(true);
614             m_valueItems[paramName] = bval;
615             connect(bval->checkBox, SIGNAL(stateChanged(int)) , this, SLOT(slotCollectAllParameters()));
616             if (!comment.isEmpty())
617                 connect(this, SIGNAL(showComments(bool)), bval->widgetComment, SLOT(setVisible(bool)));
618             m_uiItems.append(bval);
619         } else if (type == "complex") {
620             ComplexParameter *pl = new ComplexParameter;
621             pl->setupParam(effect, pa.attribute("name"), 0, 100);
622             m_vbox->addWidget(pl);
623             m_valueItems[paramName+"complex"] = pl;
624             connect(pl, SIGNAL(parameterChanged()), this, SLOT(slotCollectAllParameters()));
625         } else if (type == "geometry") {
626             if (KdenliveSettings::on_monitor_effects()) {
627                 m_geometryWidget = new GeometryWidget(m_metaInfo->monitor, m_metaInfo->timecode, 0, true, effect.hasAttribute("showrotation"), parent);
628                 m_geometryWidget->setFrameSize(m_metaInfo->frameSize);
629                 m_geometryWidget->slotShowScene(!disable);
630                 // connect this before setupParam to make sure the monitor scene shows up at startup
631                 connect(m_geometryWidget, SIGNAL(checkMonitorPosition(int)), this, SIGNAL(checkMonitorPosition(int)));
632                 connect(m_geometryWidget, SIGNAL(parameterChanged()), this, SLOT(slotCollectAllParameters()));
633                 if (minFrame == maxFrame)
634                     m_geometryWidget->setupParam(pa, m_in, m_out);
635                 else
636                     m_geometryWidget->setupParam(pa, minFrame, maxFrame);
637                 m_vbox->addWidget(m_geometryWidget);
638                 m_valueItems[paramName+"geometry"] = m_geometryWidget;
639                 connect(m_geometryWidget, SIGNAL(seekToPos(int)), this, SIGNAL(seekTimeline(int)));
640                 connect(this, SIGNAL(syncEffectsPos(int)), m_geometryWidget, SLOT(slotSyncPosition(int)));
641                 connect(this, SIGNAL(effectStateChanged(bool)), m_geometryWidget, SLOT(slotShowScene(bool)));
642             } else {
643                 Geometryval *geo = new Geometryval(m_metaInfo->profile, m_metaInfo->timecode, m_metaInfo->frameSize, 0);
644                 if (minFrame == maxFrame)
645                     geo->setupParam(pa, m_in, m_out);
646                 else
647                     geo->setupParam(pa, minFrame, maxFrame);
648                 m_vbox->addWidget(geo);
649                 m_valueItems[paramName+"geometry"] = geo;
650                 connect(geo, SIGNAL(parameterChanged()), this, SLOT(slotCollectAllParameters()));
651                 connect(geo, SIGNAL(seekToPos(int)), this, SIGNAL(seekTimeline(int)));
652                 connect(this, SIGNAL(syncEffectsPos(int)), geo, SLOT(slotSyncPosition(int)));
653             }
654         } else if (type == "addedgeometry") {
655             // this is a parameter that should be linked to the geometry widget, for example rotation, shear, ...
656             if (m_geometryWidget) m_geometryWidget->addParameter(pa);
657         } else if (type == "keyframe" || type == "simplekeyframe") {
658             // keyframe editor widget
659             if (m_keyframeEditor == NULL) {
660                 KeyframeEdit *geo;
661                 if (pa.attribute("widget") == "corners") {
662                     // we want a corners-keyframe-widget
663                     CornersWidget *corners = new CornersWidget(m_metaInfo->monitor, pa, m_in, m_out, m_metaInfo->timecode, e.attribute("active_keyframe", "-1").toInt(), parent);
664                     corners->slotShowScene(!disable);
665                     connect(corners, SIGNAL(checkMonitorPosition(int)), this, SIGNAL(checkMonitorPosition(int)));
666                     connect(this, SIGNAL(effectStateChanged(bool)), corners, SLOT(slotShowScene(bool)));
667                     connect(this, SIGNAL(syncEffectsPos(int)), corners, SLOT(slotSyncPosition(int)));
668                     geo = static_cast<KeyframeEdit *>(corners);
669                 } else {
670                     geo = new KeyframeEdit(pa, m_in, m_out, m_metaInfo->timecode, e.attribute("active_keyframe", "-1").toInt());
671                 }
672                 m_vbox->addWidget(geo);
673                 m_valueItems[paramName+"keyframe"] = geo;
674                 m_keyframeEditor = geo;
675                 connect(geo, SIGNAL(parameterChanged()), this, SLOT(slotCollectAllParameters()));
676                 connect(geo, SIGNAL(seekToPos(int)), this, SIGNAL(seekTimeline(int)));
677                 connect(this, SIGNAL(showComments(bool)), geo, SIGNAL(showComments(bool)));
678             } else {
679                 // we already have a keyframe editor, so just add another column for the new param
680                 m_keyframeEditor->addParameter(pa);
681             }
682         } else if (type == "color") {
683             if (value.startsWith('#'))
684                 value = value.replace('#', "0x");
685             ChooseColorWidget *choosecolor = new ChooseColorWidget(paramName, value, parent);
686             m_vbox->addWidget(choosecolor);
687             m_valueItems[paramName] = choosecolor;
688             connect(choosecolor, SIGNAL(displayMessage(const QString&, int)), this, SIGNAL(displayMessage(const QString&, int)));
689             connect(choosecolor, SIGNAL(modified()) , this, SLOT(slotCollectAllParameters()));
690         } else if (type == "position") {
691             int pos = value.toInt();
692             if (effect.attribute("id") == "fadein" || effect.attribute("id") == "fade_from_black") {
693                 pos = pos - m_in;
694             } else if (effect.attribute("id") == "fadeout" || effect.attribute("id") == "fade_to_black") {
695                 // fadeout position starts from clip end
696                 pos = m_out - pos;
697             }
698             PositionEdit *posedit = new PositionEdit(paramName, pos, 0, m_out - m_in, m_metaInfo->timecode);
699             m_vbox->addWidget(posedit);
700             m_valueItems[paramName+"position"] = posedit;
701             connect(posedit, SIGNAL(parameterChanged()), this, SLOT(slotCollectAllParameters()));
702         } else if (type == "curve") {
703             KisCurveWidget *curve = new KisCurveWidget(parent);
704             curve->setMaxPoints(pa.attribute("max").toInt());
705             QList<QPointF> points;
706             int number = EffectsList::parameter(e, pa.attribute("number")).toInt();
707             QString inName = pa.attribute("inpoints");
708             QString outName = pa.attribute("outpoints");
709             int start = pa.attribute("min").toInt();
710             for (int j = start; j <= number; j++) {
711                 QString in = inName;
712                 in.replace("%i", QString::number(j));
713                 QString out = outName;
714                 out.replace("%i", QString::number(j));
715                 points << QPointF(EffectsList::parameter(e, in).toDouble(), EffectsList::parameter(e, out).toDouble());
716             }
717             if (!points.isEmpty())
718                 curve->setCurve(KisCubicCurve(points));
719             MySpinBox *spinin = new MySpinBox();
720             spinin->setRange(0, 1000);
721             MySpinBox *spinout = new MySpinBox();
722             spinout->setRange(0, 1000);
723             curve->setupInOutControls(spinin, spinout, 0, 1000);
724             m_vbox->addWidget(curve);
725             m_vbox->addWidget(spinin);
726             m_vbox->addWidget(spinout);
727
728             connect(curve, SIGNAL(modified()), this, SLOT(slotCollectAllParameters()));
729             m_valueItems[paramName] = curve;
730
731             QString depends = pa.attribute("depends");
732             if (!depends.isEmpty())
733                 meetDependency(paramName, type, EffectsList::parameter(e, depends));
734         } else if (type == "bezier_spline") {
735             BezierSplineWidget *widget = new BezierSplineWidget(value, parent);
736             stretch = false;
737             m_vbox->addWidget(widget);
738             m_valueItems[paramName] = widget;
739             connect(widget, SIGNAL(modified()), this, SLOT(slotCollectAllParameters()));
740             QString depends = pa.attribute("depends");
741             if (!depends.isEmpty())
742                 meetDependency(paramName, type, EffectsList::parameter(e, depends));
743 #ifdef USE_QJSON
744         } else if (type == "roto-spline") {
745             RotoWidget *roto = new RotoWidget(value, m_metaInfo->monitor, info, m_metaInfo->timecode, parent);
746             roto->slotShowScene(!disable);
747             connect(roto, SIGNAL(valueChanged()), this, SLOT(slotCollectAllParameters()));
748             connect(roto, SIGNAL(checkMonitorPosition(int)), this, SIGNAL(checkMonitorPosition(int)));
749             connect(roto, SIGNAL(seekToPos(int)), this, SIGNAL(seekTimeline(int)));
750             connect(this, SIGNAL(syncEffectsPos(int)), roto, SLOT(slotSyncPosition(int)));
751             connect(this, SIGNAL(effectStateChanged(bool)), roto, SLOT(slotShowScene(bool)));
752             m_vbox->addWidget(roto);
753             m_valueItems[paramName] = roto;
754 #endif
755         } else if (type == "wipe") {
756             Wipeval *wpval = new Wipeval;
757             wpval->setupUi(toFillin);
758             wipeInfo w = getWipeInfo(value);
759             switch (w.start) {
760             case UP:
761                 wpval->start_up->setChecked(true);
762                 break;
763             case DOWN:
764                 wpval->start_down->setChecked(true);
765                 break;
766             case RIGHT:
767                 wpval->start_right->setChecked(true);
768                 break;
769             case LEFT:
770                 wpval->start_left->setChecked(true);
771                 break;
772             default:
773                 wpval->start_center->setChecked(true);
774                 break;
775             }
776             switch (w.end) {
777             case UP:
778                 wpval->end_up->setChecked(true);
779                 break;
780             case DOWN:
781                 wpval->end_down->setChecked(true);
782                 break;
783             case RIGHT:
784                 wpval->end_right->setChecked(true);
785                 break;
786             case LEFT:
787                 wpval->end_left->setChecked(true);
788                 break;
789             default:
790                 wpval->end_center->setChecked(true);
791                 break;
792             }
793             wpval->start_transp->setValue(w.startTransparency);
794             wpval->end_transp->setValue(w.endTransparency);
795             m_valueItems[paramName] = wpval;
796             connect(wpval->end_up, SIGNAL(clicked()), this, SLOT(slotCollectAllParameters()));
797             connect(wpval->end_down, SIGNAL(clicked()), this, SLOT(slotCollectAllParameters()));
798             connect(wpval->end_left, SIGNAL(clicked()), this, SLOT(slotCollectAllParameters()));
799             connect(wpval->end_right, SIGNAL(clicked()), this, SLOT(slotCollectAllParameters()));
800             connect(wpval->end_center, SIGNAL(clicked()), this, SLOT(slotCollectAllParameters()));
801             connect(wpval->start_up, SIGNAL(clicked()), this, SLOT(slotCollectAllParameters()));
802             connect(wpval->start_down, SIGNAL(clicked()), this, SLOT(slotCollectAllParameters()));
803             connect(wpval->start_left, SIGNAL(clicked()), this, SLOT(slotCollectAllParameters()));
804             connect(wpval->start_right, SIGNAL(clicked()), this, SLOT(slotCollectAllParameters()));
805             connect(wpval->start_center, SIGNAL(clicked()), this, SLOT(slotCollectAllParameters()));
806             connect(wpval->start_transp, SIGNAL(valueChanged(int)), this, SLOT(slotCollectAllParameters()));
807             connect(wpval->end_transp, SIGNAL(valueChanged(int)), this, SLOT(slotCollectAllParameters()));
808             //wpval->title->setTitle(na.toElement().text());
809             m_uiItems.append(wpval);
810         } else if (type == "url") {
811             Urlval *cval = new Urlval;
812             cval->setupUi(toFillin);
813             cval->label->setText(paramName);
814             cval->urlwidget->fileDialog()->setFilter(ProjectList::getExtensions());
815             m_valueItems[paramName] = cval;
816             cval->urlwidget->setUrl(KUrl(value));
817             connect(cval->urlwidget, SIGNAL(returnPressed()) , this, SLOT(slotCollectAllParameters()));
818             connect(cval->urlwidget, SIGNAL(urlSelected(const KUrl&)) , this, SLOT(slotCollectAllParameters()));
819             m_uiItems.append(cval);
820         } else if (type == "keywords") {
821             Keywordval* kval = new Keywordval;
822             kval->setupUi(toFillin);
823             kval->label->setText(paramName);
824             kval->lineeditwidget->setText(value);
825             QDomElement klistelem = pa.firstChildElement("keywords");
826             QDomElement kdisplaylistelem = pa.firstChildElement("keywordsdisplay");
827             QStringList keywordlist;
828             QStringList keyworddisplaylist;
829             if (!klistelem.isNull()) {
830                 keywordlist = klistelem.text().split(';');
831                 keyworddisplaylist = i18n(kdisplaylistelem.text().toUtf8().data()).split(';');
832             }
833             if (keyworddisplaylist.count() != keywordlist.count()) {
834                 keyworddisplaylist = keywordlist;
835             }
836             for (int i = 0; i < keywordlist.count(); i++) {
837                 kval->comboboxwidget->addItem(keyworddisplaylist.at(i), keywordlist.at(i));
838             }
839             // Add disabled user prompt at index 0
840             kval->comboboxwidget->insertItem(0, i18n("<select a keyword>"), "");
841             kval->comboboxwidget->model()->setData( kval->comboboxwidget->model()->index(0,0), QVariant(Qt::NoItemFlags), Qt::UserRole -1);
842             kval->comboboxwidget->setCurrentIndex(0);
843             m_valueItems[paramName] = kval;
844             connect(kval->lineeditwidget, SIGNAL(editingFinished()) , this, SLOT(collectAllParameters()));
845             connect(kval->comboboxwidget, SIGNAL(activated (const QString&)), this, SLOT(collectAllParameters()));
846             m_uiItems.append(kval);
847         } else if (type == "fontfamily") {
848             Fontval* fval = new Fontval;
849             fval->setupUi(toFillin);
850             fval->name->setText(paramName);
851             fval->fontfamilywidget->setCurrentFont(QFont(value));
852             m_valueItems[paramName] = fval;
853             connect(fval->fontfamilywidget, SIGNAL(currentFontChanged(const QFont &)), this, SLOT(collectAllParameters())) ;
854             m_uiItems.append(fval);
855         } else if (type == "filterjob") {
856             QVBoxLayout *l= new QVBoxLayout(toFillin);
857             QPushButton *button = new QPushButton(paramName, toFillin);
858             l->addWidget(button);
859             m_valueItems[paramName] = button;
860             connect(button, SIGNAL(pressed()), this, SLOT(slotStartFilterJobAction()));   
861         } else {
862             delete toFillin;
863             toFillin = NULL;
864         }
865
866         if (toFillin)
867             m_vbox->addWidget(toFillin);
868     }
869
870     if (stretch)
871         m_vbox->addStretch();
872
873     if (m_keyframeEditor)
874         m_keyframeEditor->checkVisibleParam();
875
876     // Make sure all doubleparam spinboxes have the same width, looks much better
877     QList<DoubleParameterWidget *> allWidgets = findChildren<DoubleParameterWidget *>();
878     int minSize = 0;
879     for (int i = 0; i < allWidgets.count(); i++) {
880         if (minSize < allWidgets.at(i)->spinSize()) minSize = allWidgets.at(i)->spinSize();
881     }
882     for (int i = 0; i < allWidgets.count(); i++) {
883         allWidgets.at(i)->setSpinSize(minSize);
884     }
885 }
886
887 ParameterContainer::~ParameterContainer()
888 {
889     //clearLayout(m_vbox);
890     delete m_vbox;
891 }
892
893 void ParameterContainer::meetDependency(const QString& name, QString type, QString value)
894 {
895     if (type == "curve") {
896         KisCurveWidget *curve = (KisCurveWidget*)m_valueItems[name];
897         if (curve) {
898             int color = value.toInt();
899             curve->setPixmap(QPixmap::fromImage(ColorTools::rgbCurvePlane(curve->size(), (ColorTools::ColorsRGB)(color == 3 ? 4 : color), 0.8)));
900         }
901     } else if (type == "bezier_spline") {
902         BezierSplineWidget *widget = (BezierSplineWidget*)m_valueItems[name];
903         if (widget) {
904             widget->setMode((BezierSplineWidget::CurveModes)((int)(value.toDouble() * 10)));
905         }
906     }
907 }
908
909 wipeInfo ParameterContainer::getWipeInfo(QString value)
910 {
911     wipeInfo info;
912     // Convert old geometry values that used a comma as separator
913     if (value.contains(',')) value.replace(',','/');
914     QString start = value.section(';', 0, 0);
915     QString end = value.section(';', 1, 1).section('=', 1, 1);
916     if (start.startsWith("-100%/0"))
917         info.start = LEFT;
918     else if (start.startsWith("100%/0"))
919         info.start = RIGHT;
920     else if (start.startsWith("0%/100%"))
921         info.start = DOWN;
922     else if (start.startsWith("0%/-100%"))
923         info.start = UP;
924     else
925         info.start = CENTER;
926
927     if (start.count(':') == 2)
928         info.startTransparency = start.section(':', -1).toInt();
929     else
930         info.startTransparency = 100;
931
932     if (end.startsWith("-100%/0"))
933         info.end = LEFT;
934     else if (end.startsWith("100%/0"))
935         info.end = RIGHT;
936     else if (end.startsWith("0%/100%"))
937         info.end = DOWN;
938     else if (end.startsWith("0%/-100%"))
939         info.end = UP;
940     else
941         info.end = CENTER;
942
943     if (end.count(':') == 2)
944         info.endTransparency = end.section(':', -1).toInt();
945     else
946         info.endTransparency = 100;
947
948     return info;
949 }
950
951 void ParameterContainer::updateTimecodeFormat()
952 {
953     if (m_keyframeEditor)
954         m_keyframeEditor->updateTimecodeFormat();
955
956     QDomNodeList namenode = m_effect.elementsByTagName("parameter");
957     for (int i = 0; i < namenode.count() ; i++) {
958         QDomNode pa = namenode.item(i);
959         QDomElement na = pa.firstChildElement("name");
960         QString type = pa.attributes().namedItem("type").nodeValue();
961         QString paramName = na.isNull() ? pa.attributes().namedItem("name").nodeValue() : i18n(na.text().toUtf8().data());
962
963         if (type == "geometry") {
964             if (KdenliveSettings::on_monitor_effects()) {
965                 if (m_geometryWidget) m_geometryWidget->updateTimecodeFormat();
966             } else {
967                 Geometryval *geom = ((Geometryval*)m_valueItems[paramName+"geometry"]);
968                 geom->updateTimecodeFormat();
969             }
970             break;
971         } else if (type == "position") {
972             PositionEdit *posi = ((PositionEdit*)m_valueItems[paramName+"position"]);
973             posi->updateTimecodeFormat();
974             break;
975 #ifdef USE_QJSON
976         } else if (type == "roto-spline") {
977             RotoWidget *widget = static_cast<RotoWidget *>(m_valueItems[paramName]);
978             widget->updateTimecodeFormat();
979 #endif
980         }
981     }
982 }
983
984 void ParameterContainer::slotCollectAllParameters()
985 {
986     if (m_valueItems.isEmpty() || m_effect.isNull()) return;
987     QLocale locale;
988     locale.setNumberOptions(QLocale::OmitGroupSeparator);
989     const QDomElement oldparam = m_effect.cloneNode().toElement();
990     //QDomElement newparam = oldparam.cloneNode().toElement();
991     QDomNodeList namenode = m_effect.elementsByTagName("parameter");
992
993     for (int i = 0; i < namenode.count() ; i++) {
994         QDomNode pa = namenode.item(i);
995         QDomElement na = pa.firstChildElement("name");
996         QString type = pa.attributes().namedItem("type").nodeValue();
997         QString paramName = na.isNull() ? pa.attributes().namedItem("name").nodeValue() : i18n(na.text().toUtf8().data());
998         if (type == "complex")
999             paramName.append("complex");
1000         else if (type == "position")
1001             paramName.append("position");
1002         else if (type == "geometry")
1003             paramName.append("geometry");
1004         else if (type == "keyframe")
1005             paramName.append("keyframe");
1006         if (type != "simplekeyframe" && type != "fixed" && type != "addedgeometry" && !m_valueItems.contains(paramName)) {
1007             kDebug() << "// Param: " << paramName << " NOT FOUND";
1008             continue;
1009         }
1010
1011         QString setValue;
1012         if (type == "double" || type == "constant") {
1013             DoubleParameterWidget *doubleparam = (DoubleParameterWidget*)m_valueItems.value(paramName);
1014             setValue = locale.toString(doubleparam->getValue());
1015         } else if (type == "list") {
1016             KComboBox *box = ((Listval*)m_valueItems.value(paramName))->list;
1017             setValue = box->itemData(box->currentIndex()).toString();
1018         } else if (type == "bool") {
1019             QCheckBox *box = ((Boolval*)m_valueItems.value(paramName))->checkBox;
1020             setValue = box->checkState() == Qt::Checked ? "1" : "0" ;
1021         } else if (type == "color") {
1022             ChooseColorWidget *choosecolor = ((ChooseColorWidget*)m_valueItems.value(paramName));
1023             setValue = choosecolor->getColor();
1024         } else if (type == "complex") {
1025             ComplexParameter *complex = ((ComplexParameter*)m_valueItems.value(paramName));
1026             namenode.item(i) = complex->getParamDesc();
1027         } else if (type == "geometry") {
1028             if (KdenliveSettings::on_monitor_effects()) {
1029                 if (m_geometryWidget) namenode.item(i).toElement().setAttribute("value", m_geometryWidget->getValue());
1030             } else {
1031                 Geometryval *geom = ((Geometryval*)m_valueItems.value(paramName));
1032                 namenode.item(i).toElement().setAttribute("value", geom->getValue());
1033             }
1034         } else if (type == "addedgeometry") {
1035             namenode.item(i).toElement().setAttribute("value", m_geometryWidget->getExtraValue(namenode.item(i).toElement().attribute("name")));
1036         } else if (type == "position") {
1037             PositionEdit *pedit = ((PositionEdit*)m_valueItems.value(paramName));
1038             int pos = pedit->getPosition();
1039             setValue = QString::number(pos);
1040             if (m_effect.attribute("id") == "fadein" || m_effect.attribute("id") == "fade_from_black") {
1041                 // Make sure duration is not longer than clip
1042                 /*if (pos > m_out) {
1043                     pos = m_out;
1044                     pedit->setPosition(pos);
1045                 }*/
1046                 EffectsList::setParameter(m_effect, "in", QString::number(m_in));
1047                 EffectsList::setParameter(m_effect, "out", QString::number(m_in + pos));
1048                 setValue.clear();
1049             } else if (m_effect.attribute("id") == "fadeout" || m_effect.attribute("id") == "fade_to_black") {
1050                 // Make sure duration is not longer than clip
1051                 /*if (pos > m_out) {
1052                     pos = m_out;
1053                     pedit->setPosition(pos);
1054                 }*/
1055                 EffectsList::setParameter(m_effect, "in", QString::number(m_out - pos));
1056                 EffectsList::setParameter(m_effect, "out", QString::number(m_out));
1057                 setValue.clear();
1058             }
1059         } else if (type == "curve") {
1060             KisCurveWidget *curve = ((KisCurveWidget*)m_valueItems.value(paramName));
1061             QList<QPointF> points = curve->curve().points();
1062             QString number = pa.attributes().namedItem("number").nodeValue();
1063             QString inName = pa.attributes().namedItem("inpoints").nodeValue();
1064             QString outName = pa.attributes().namedItem("outpoints").nodeValue();
1065             int off = pa.attributes().namedItem("min").nodeValue().toInt();
1066             int end = pa.attributes().namedItem("max").nodeValue().toInt();
1067             EffectsList::setParameter(m_effect, number, QString::number(points.count()));
1068             for (int j = 0; (j < points.count() && j + off <= end); j++) {
1069                 QString in = inName;
1070                 in.replace("%i", QString::number(j + off));
1071                 QString out = outName;
1072                 out.replace("%i", QString::number(j + off));
1073                 EffectsList::setParameter(m_effect, in, locale.toString(points.at(j).x()));
1074                 EffectsList::setParameter(m_effect, out, locale.toString(points.at(j).y()));
1075             }
1076             QString depends = pa.attributes().namedItem("depends").nodeValue();
1077             if (!depends.isEmpty())
1078                 meetDependency(paramName, type, EffectsList::parameter(m_effect, depends));
1079         } else if (type == "bezier_spline") {
1080             BezierSplineWidget *widget = (BezierSplineWidget*)m_valueItems.value(paramName);
1081             setValue = widget->spline();
1082             QString depends = pa.attributes().namedItem("depends").nodeValue();
1083             if (!depends.isEmpty())
1084                 meetDependency(paramName, type, EffectsList::parameter(m_effect, depends));
1085 #ifdef USE_QJSON
1086         } else if (type == "roto-spline") {
1087             RotoWidget *widget = static_cast<RotoWidget *>(m_valueItems.value(paramName));
1088             setValue = widget->getSpline();
1089 #endif
1090         } else if (type == "wipe") {
1091             Wipeval *wp = (Wipeval*)m_valueItems.value(paramName);
1092             wipeInfo info;
1093             if (wp->start_left->isChecked())
1094                 info.start = LEFT;
1095             else if (wp->start_right->isChecked())
1096                 info.start = RIGHT;
1097             else if (wp->start_up->isChecked())
1098                 info.start = UP;
1099             else if (wp->start_down->isChecked())
1100                 info.start = DOWN;
1101             else if (wp->start_center->isChecked())
1102                 info.start = CENTER;
1103             else
1104                 info.start = LEFT;
1105             info.startTransparency = wp->start_transp->value();
1106
1107             if (wp->end_left->isChecked())
1108                 info.end = LEFT;
1109             else if (wp->end_right->isChecked())
1110                 info.end = RIGHT;
1111             else if (wp->end_up->isChecked())
1112                 info.end = UP;
1113             else if (wp->end_down->isChecked())
1114                 info.end = DOWN;
1115             else if (wp->end_center->isChecked())
1116                 info.end = CENTER;
1117             else
1118                 info.end = RIGHT;
1119             info.endTransparency = wp->end_transp->value();
1120
1121             setValue = getWipeString(info);
1122         } else if ((type == "simplekeyframe" || type == "keyframe") && m_keyframeEditor) {
1123             QDomElement elem = pa.toElement();
1124             QString realName = i18n(na.toElement().text().toUtf8().data());
1125             QString val = m_keyframeEditor->getValue(realName);
1126             elem.setAttribute("keyframes", val);
1127
1128             if (m_keyframeEditor->isVisibleParam(realName))
1129                 elem.setAttribute("intimeline", "1");
1130             else if (elem.hasAttribute("intimeline"))
1131                 elem.removeAttribute("intimeline");
1132         } else if (type == "url") {
1133             KUrlRequester *req = ((Urlval*)m_valueItems.value(paramName))->urlwidget;
1134             setValue = req->url().path();
1135         } else if (type == "keywords"){
1136             QLineEdit *line = ((Keywordval*)m_valueItems.value(paramName))->lineeditwidget;
1137             QComboBox *combo = ((Keywordval*)m_valueItems.value(paramName))->comboboxwidget;
1138             if(combo->currentIndex())
1139             {
1140                 QString comboval = combo->itemData(combo->currentIndex()).toString();
1141                 line->insert(comboval);
1142                 combo->setCurrentIndex(0);
1143             }
1144             setValue = line->text();
1145         } else if (type == "fontfamily") {
1146             QFontComboBox* fontfamily = ((Fontval*)m_valueItems.value(paramName))->fontfamilywidget;
1147             setValue = fontfamily->currentFont().family();
1148         }
1149         if (!setValue.isNull())
1150             pa.attributes().namedItem("value").setNodeValue(setValue);
1151
1152     }
1153     emit parameterChanged(oldparam, m_effect, m_index);
1154 }
1155
1156 QString ParameterContainer::getWipeString(wipeInfo info)
1157 {
1158
1159     QString start;
1160     QString end;
1161     switch (info.start) {
1162     case LEFT:
1163         start = "-100%/0%:100%x100%";
1164         break;
1165     case RIGHT:
1166         start = "100%/0%:100%x100%";
1167         break;
1168     case DOWN:
1169         start = "0%/100%:100%x100%";
1170         break;
1171     case UP:
1172         start = "0%/-100%:100%x100%";
1173         break;
1174     default:
1175         start = "0%/0%:100%x100%";
1176         break;
1177     }
1178     start.append(':' + QString::number(info.startTransparency));
1179
1180     switch (info.end) {
1181     case LEFT:
1182         end = "-100%/0%:100%x100%";
1183         break;
1184     case RIGHT:
1185         end = "100%/0%:100%x100%";
1186         break;
1187     case DOWN:
1188         end = "0%/100%:100%x100%";
1189         break;
1190     case UP:
1191         end = "0%/-100%:100%x100%";
1192         break;
1193     default:
1194         end = "0%/0%:100%x100%";
1195         break;
1196     }
1197     end.append(':' + QString::number(info.endTransparency));
1198     return QString(start + ";-1=" + end);
1199 }
1200
1201 int ParameterContainer::index() const
1202 {
1203     return m_index;
1204 }
1205
1206 void ParameterContainer::slotStartFilterJobAction()
1207 {
1208     QDomNodeList namenode = m_effect.elementsByTagName("parameter");
1209     for (int i = 0; i < namenode.count() ; i++) {
1210         QDomElement pa = namenode.item(i).toElement();
1211         QString type = pa.attribute("type");
1212         if (type == "filterjob") {
1213             emit startFilterJob(pa.attribute("filtertag"), pa.attribute("filterparams"), pa.attribute("finalfilter"), pa.attribute("consumer"), pa.attribute("consumerparams"), pa.attribute("wantedproperties"));
1214             kDebug()<<" - - -PROPS:\n"<<pa.attribute("filtertag")<<"-"<< pa.attribute("filterparams")<<"-"<< pa.attribute("consumer")<<"-"<< pa.attribute("consumerparams")<<"-"<< pa.attribute("wantedproperties");
1215             break;
1216         }
1217     }
1218 }
1219