+
+bool CustomTrackView::hasAudio(int track) const
+{
+ QRectF rect(0, (double)(track * m_tracksHeight + 1), (double) sceneRect().width(), (double)(m_tracksHeight - 1));
+ QList<QGraphicsItem *> collisions = scene()->items(rect, Qt::IntersectsItemBoundingRect);
+ QGraphicsItem *item;
+ for (int i = 0; i < collisions.count(); i++) {
+ item = collisions.at(i);
+ if (!item->isEnabled()) continue;
+ if (item->type() == AVWIDGET) {
+ ClipItem *clip = static_cast <ClipItem *>(item);
+ if (!clip->isVideoOnly() && (clip->clipType() == AUDIO || clip->clipType() == AV || clip->clipType() == PLAYLIST)) return true;
+ }
+ }
+ return false;
+}
+
+void CustomTrackView::slotAddTrackEffect(const QDomElement &effect, int ix)
+{
+
+ QUndoCommand *effectCommand = new QUndoCommand();
+ QString effectName;
+ if (effect.tagName() == "effectgroup") {
+ effectName = effect.attribute("name");
+ } else {
+ QDomElement namenode = effect.firstChildElement("name");
+ if (!namenode.isNull()) effectName = i18n(namenode.text().toUtf8().data());
+ else effectName = i18n("effect");
+ }
+ effectCommand->setText(i18n("Add %1", effectName));
+ if (effect.tagName() == "effectgroup") {
+ QDomNodeList effectlist = effect.elementsByTagName("effect");
+ for (int j = 0; j < effectlist.count(); j++) {
+ QDomElement trackeffect = effectlist.at(j).toElement();
+ if (trackeffect.attribute("unique", "0") != "0" && m_document->hasTrackEffect(m_document->tracksCount() - ix - 1, trackeffect.attribute("tag"), trackeffect.attribute("id")) != -1) {
+ emit displayMessage(i18n("Effect already present in track"), ErrorMessage);
+ continue;
+ }
+ new AddEffectCommand(this, m_document->tracksCount() - ix, GenTime(-1), trackeffect, true, effectCommand);
+ }
+ }
+ else {
+ if (effect.attribute("unique", "0") != "0" && m_document->hasTrackEffect(m_document->tracksCount() - ix - 1, effect.attribute("tag"), effect.attribute("id")) != -1) {
+ emit displayMessage(i18n("Effect already present in track"), ErrorMessage);
+ delete effectCommand;
+ return;
+ }
+ new AddEffectCommand(this, m_document->tracksCount() - ix, GenTime(-1), effect, true, effectCommand);
+ }
+
+ if (effectCommand->childCount() > 0) {
+ m_commandStack->push(effectCommand);
+ setDocumentModified();
+ }
+ else delete effectCommand;
+}
+
+
+EffectsParameterList CustomTrackView::getEffectArgs(const QDomElement &effect)
+{
+ EffectsParameterList parameters;
+ QLocale locale;
+ parameters.addParam("tag", effect.attribute("tag"));
+ //if (effect.hasAttribute("region")) parameters.addParam("region", effect.attribute("region"));
+ parameters.addParam("kdenlive_ix", effect.attribute("kdenlive_ix"));
+ parameters.addParam("kdenlive_info", effect.attribute("kdenlive_info"));
+ parameters.addParam("id", effect.attribute("id"));
+ if (effect.hasAttribute("src")) parameters.addParam("src", effect.attribute("src"));
+ if (effect.hasAttribute("disable")) parameters.addParam("disable", effect.attribute("disable"));
+ if (effect.hasAttribute("in")) parameters.addParam("in", effect.attribute("in"));
+ if (effect.hasAttribute("out")) parameters.addParam("out", effect.attribute("out"));
+ if (effect.attribute("id") == "region") {
+ QDomNodeList subeffects = effect.elementsByTagName("effect");
+ for (int i = 0; i < subeffects.count(); i++) {
+ QDomElement subeffect = subeffects.at(i).toElement();
+ int subeffectix = subeffect.attribute("region_ix").toInt();
+ parameters.addParam(QString("filter%1").arg(subeffectix), subeffect.attribute("id"));
+ parameters.addParam(QString("filter%1.tag").arg(subeffectix), subeffect.attribute("tag"));
+ parameters.addParam(QString("filter%1.kdenlive_info").arg(subeffectix), subeffect.attribute("kdenlive_info"));
+ QDomNodeList subparams = subeffect.elementsByTagName("parameter");
+ adjustEffectParameters(parameters, subparams, m_document->mltProfile(), QString("filter%1.").arg(subeffectix));
+ }
+ }
+
+ QDomNodeList params = effect.elementsByTagName("parameter");
+ adjustEffectParameters(parameters, params, m_document->mltProfile());
+
+ return parameters;
+}
+
+
+void CustomTrackView::adjustEffectParameters(EffectsParameterList ¶meters, QDomNodeList params, MltVideoProfile profile, const QString &prefix)
+{
+ QLocale locale;
+ for (int i = 0; i < params.count(); i++) {
+ QDomElement e = params.item(i).toElement();
+ QString paramname = prefix + e.attribute("name");
+ if (e.attribute("type") == "geometry" && !e.hasAttribute("fixed")) {
+ // effects with geometry param need in / out synced with the clip, request it...
+ parameters.addParam("_sync_in_out", "1");
+ }
+ if (e.attribute("type") == "simplekeyframe") {
+ QStringList values = e.attribute("keyframes").split(';', QString::SkipEmptyParts);
+ double factor = e.attribute("factor", "1").toDouble();
+ double offset = e.attribute("offset", "0").toDouble();
+ for (int j = 0; j < values.count(); j++) {
+ QString pos = values.at(j).section(':', 0, 0);
+ double val = (values.at(j).section(':', 1, 1).toDouble() - offset) / factor;
+ values[j] = pos + '=' + locale.toString(val);
+ }
+ // kDebug() << "/ / / /SENDING KEYFR:" << values;
+ parameters.addParam(paramname, values.join(";"));
+ /*parameters.addParam(e.attribute("name"), e.attribute("keyframes").replace(":", "="));
+ parameters.addParam("max", e.attribute("max"));
+ parameters.addParam("min", e.attribute("min"));
+ parameters.addParam("factor", e.attribute("factor", "1"));*/
+ } else if (e.attribute("type") == "keyframe") {
+ kDebug() << "/ / / /SENDING KEYFR EFFECT TYPE";
+ parameters.addParam("keyframes", e.attribute("keyframes"));
+ parameters.addParam("max", e.attribute("max"));
+ parameters.addParam("min", e.attribute("min"));
+ parameters.addParam("factor", e.attribute("factor", "1"));
+ parameters.addParam("offset", e.attribute("offset", "0"));
+ parameters.addParam("starttag", e.attribute("starttag", "start"));
+ parameters.addParam("endtag", e.attribute("endtag", "end"));
+ } else if (e.attribute("namedesc").contains(';')) {
+ QString format = e.attribute("format");
+ QStringList separators = format.split("%d", QString::SkipEmptyParts);
+ QStringList values = e.attribute("value").split(QRegExp("[,:;x]"));
+ QString neu;
+ QTextStream txtNeu(&neu);
+ if (values.size() > 0)
+ txtNeu << (int)values[0].toDouble();
+ for (int i = 0; i < separators.size() && i + 1 < values.size(); i++) {
+ txtNeu << separators[i];
+ txtNeu << (int)(values[i+1].toDouble());
+ }
+ parameters.addParam("start", neu);
+ } else {
+ if (e.attribute("factor", "1") != "1" || e.attribute("offset", "0") != "0") {
+ double fact;
+ if (e.attribute("factor").contains('%')) {
+ fact = ProfilesDialog::getStringEval(profile, e.attribute("factor"));
+ } else {
+ fact = e.attribute("factor", "1").toDouble();
+ }
+ double offset = e.attribute("offset", "0").toDouble();
+ parameters.addParam(paramname, locale.toString((e.attribute("value").toDouble() - offset) / fact));
+ } else {
+ parameters.addParam(paramname, e.attribute("value"));
+ }
+ }
+ }
+}
+
+
+void CustomTrackView::updateTrackNames(int track, bool added)
+{
+ QList <TrackInfo> tracks = m_document->tracksList();
+ int max = tracks.count();
+ int docTrack = max - track - 1;
+
+ // count number of tracks of each type
+ int videoTracks = 0;
+ int audioTracks = 0;
+ for (int i = max - 1; i >= 0; --i) {
+ TrackInfo info = tracks.at(i);
+ if (info.type == VIDEOTRACK)
+ videoTracks++;
+ else
+ audioTracks++;
+
+ if (i <= docTrack) {
+ QString type = (info.type == VIDEOTRACK ? "Video " : "Audio ");
+ int typeNumber = (info.type == VIDEOTRACK ? videoTracks : audioTracks);
+
+ if (added) {
+ if (i == docTrack || info.trackName == type + QString::number(typeNumber - 1)) {
+ info.trackName = type + QString::number(typeNumber);
+ m_document->setTrackType(i, info);
+ }
+ } else {
+ if (info.trackName == type + QString::number(typeNumber + 1)) {
+ info.trackName = type + QString::number(typeNumber);
+ m_document->setTrackType(i, info);
+ }
+ }
+ }
+ }
+ emit tracksChanged();
+}
+
+void CustomTrackView::updateTrackDuration(int track, QUndoCommand *command)
+{
+ Q_UNUSED(command)
+
+ QList<int> tracks;
+ if (track >= 0) {
+ tracks << m_document->tracksCount() - track - 1;
+ } else {
+ // negative track number -> update all tracks
+ for (int i = 0; i < m_document->tracksCount(); ++i)
+ tracks << i;
+ }
+ int t, duration;
+ for (int i = 0; i < tracks.count(); ++i) {
+ t = tracks.at(i);
+ // t + 1 because of black background track
+ duration = m_document->renderer()->mltTrackDuration(t + 1);
+ if (duration != m_document->trackDuration(t)) {
+ m_document->setTrackDuration(t, duration);
+
+ // update effects
+ EffectsList effects = m_document->getTrackEffects(t);
+ for (int j = 0; j < effects.count(); ++j) {
+ /* TODO
+ * - lookout for keyframable parameters and update them so all keyframes are in the new range (0 - duration)
+ * - update the effectstack if necessary
+ */
+ }
+ }
+ }
+}
+
+void CustomTrackView::slotRefreshThumbs(const QString &id, bool resetThumbs)
+{
+ QList<QGraphicsItem *> list = scene()->items();
+ ClipItem *clip = NULL;
+ for (int i = 0; i < list.size(); ++i) {
+ if (list.at(i)->type() == AVWIDGET) {
+ clip = static_cast <ClipItem *>(list.at(i));
+ if (clip->clipProducer() == id) {
+ clip->refreshClip(true, resetThumbs);
+ }
+ }
+ }
+}
+
+void CustomTrackView::adjustEffects(ClipItem* item, ItemInfo oldInfo, QUndoCommand* command)
+{
+ QMap<int, QDomElement> effects = item->adjustEffectsToDuration(m_document->width(), m_document->height(), oldInfo);
+
+ if (!effects.isEmpty()) {
+ QMap<int, QDomElement>::const_iterator i = effects.constBegin();
+ while (i != effects.constEnd()) {
+ new EditEffectCommand(this, m_document->tracksCount() - item->track(), item->startPos(), i.value(), item->effect(i.key()), i.value().attribute("kdenlive_ix").toInt(), true, true, command);
+ ++i;
+ }
+ }
+}
+
+
+void CustomTrackView::slotGotFilterJobResults(const QString &/*id*/, int startPos, int track, stringMap filterParams, stringMap extra)
+{
+ ClipItem *clip = getClipItemAt(GenTime(startPos, m_document->fps()), track);
+ if (clip == NULL) {
+ emit displayMessage(i18n("Cannot find clip for effect update %1.", extra.value("finalfilter")), ErrorMessage);
+ return;
+ }
+ QDomElement newEffect;
+ QDomElement effect = clip->getEffectAtIndex(clip->selectedEffectIndex());
+ if (effect.attribute("id") == extra.value("finalfilter")) {
+ newEffect = effect.cloneNode().toElement();
+ QMap<QString, QString>::const_iterator i = filterParams.constBegin();
+ while (i != filterParams.constEnd()) {
+ EffectsList::setParameter(newEffect, i.key(), i.value());
+ kDebug()<<"// RESULT FILTER: "<<i.key()<<"="<< i.value();
+ ++i;
+ }
+ EditEffectCommand *command = new EditEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), effect, newEffect, clip->selectedEffectIndex(), true, true);
+ m_commandStack->push(command);
+ emit clipItemSelected(clip);
+ }
+}
+
+
+void CustomTrackView::slotImportClipKeyframes(GRAPHICSRECTITEM type)
+{
+ ClipItem *item = NULL;
+ if (type == TRANSITIONWIDGET) {
+ // We want to import keyframes to a transition
+ if (!m_selectionGroup) {
+ emit displayMessage(i18n("You need to select one clip and one transition"), ErrorMessage);
+ return;
+ }
+ // Make sure there is no collision
+ QList<QGraphicsItem *> children = m_selectionGroup->childItems();
+ for (int i = 0; i < children.count(); i++) {
+ if (children.at(i)->type() == AVWIDGET) {
+ item = (ClipItem*) children.at(i);
+ break;
+ }
+ }
+ }
+ else {
+ // Import keyframes from current clip to its effect
+ if (m_dragItem) item = static_cast<ClipItem*> (m_dragItem);
+ }
+
+ if (!item) {
+ emit displayMessage(i18n("No clip found"), ErrorMessage);
+ return;
+ }
+ QMap <QString, QString> data = item->baseClip()->analysisData();
+ if (data.isEmpty()) {
+ emit displayMessage(i18n("No keyframe data found in clip"), ErrorMessage);
+ return;
+ }
+ QPointer<QDialog> d = new QDialog(this);
+ Ui::ImportKeyframesDialog_UI ui;
+ ui.setupUi(d);
+
+ // Set up data
+ int ix = 0;
+ QMap<QString, QString>::const_iterator i = data.constBegin();
+ while (i != data.constEnd()) {
+ ui.data_list->insertItem(ix, i.key());
+ ui.data_list->setItemData(ix, i.value(), Qt::UserRole);
+ ++i;
+ ix++;
+ }
+
+ if (d->exec() != QDialog::Accepted) {
+ delete d;
+ return;
+ }
+ QString keyframeData = ui.data_list->itemData(ui.data_list->currentIndex()).toString();
+
+ int offset = item->cropStart().frames(m_document->fps());
+ Mlt::Geometry geometry(keyframeData.toUtf8().data(), item->baseClip()->maxDuration().frames(m_document->fps()), m_document->mltProfile().width, m_document->mltProfile().height);
+ Mlt::Geometry newGeometry(QString().toUtf8().data(), item->baseClip()->maxDuration().frames(m_document->fps()), m_document->mltProfile().width, m_document->mltProfile().height);
+ Mlt::GeometryItem gitem;
+ geometry.fetch(&gitem, offset);
+ gitem.frame(0);
+ newGeometry.insert(gitem);
+ int pos = offset + 1;
+ while (!geometry.next_key(&gitem, pos)) {
+ pos = gitem.frame();
+ gitem.frame(pos - offset);
+ pos++;
+ newGeometry.insert(gitem);
+ }
+ QStringList keyframeList = QString(newGeometry.serialise()).split(';', QString::SkipEmptyParts);
+
+ QString result;
+ if (ui.import_position->isChecked()) {
+ if (ui.import_size->isChecked()) {
+ foreach(QString key, keyframeList) {
+ if (key.count(':') > 1) result.append(key.section(':', 0, 1));
+ else result.append(key);
+ result.append(';');
+ }
+ }
+ else {
+ foreach(QString key, keyframeList) {
+ result.append(key.section(':', 0, 0));
+ result.append(';');
+ }
+ }
+ }
+ else if (ui.import_size->isChecked()) {
+ foreach(QString key, keyframeList) {
+ result.append(key.section(':', 1, 1));
+ result.append(';');
+ }
+ }
+ emit importKeyframes(type, result, ui.limit_keyframes->isChecked() ? ui.max_keyframes->value() : -1);
+ delete d;
+}
+