clipcreationdialog.cpp 32.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
/*
Copyright (C) 2015  Jean-Baptiste Mardelle <jb@kdenlive.org>
This file is part of Kdenlive. See www.kdenlive.org.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License or (at your option) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor approved
10
by the membership of KDE e.V.), which shall act as a proxy
11
12
13
14
15
16
17
18
19
20
21
22
defined in Section 14 of version 3 of the license.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "clipcreationdialog.h"
23
#include "kdenlive_debug.h"
24
25
#include "kdenlivesettings.h"
#include "doc/kdenlivedoc.h"
26
#include "bin/bin.h"
27
#include "bin/bincommands.h"
Vincent Pinon's avatar
Vincent Pinon committed
28
#include "bin/projectclip.h"
29
#include "ui_colorclip_ui.h"
Vincent Pinon's avatar
Vincent Pinon committed
30
#include "ui_qtextclip_ui.h"
31
#include "timecodedisplay.h"
32
#include "titler/titlewidget.h"
33
#include "titletemplatedialog.h"
34
#include "project/dialogs/slideshowclip.h"
35
36

#include <KMessageBox>
37
#include <KRecentDirs>
38
#include <KFileWidget>
39
#include <KWindowConfig>
40
#include "klocalizedstring.h"
41

42
#include <QDir>
43
#include <QWindow>
44
#include <QUndoCommand>
45
#include <QStandardPaths>
46
#include <QPushButton>
47
48
#include <QDialog>
#include <QPointer>
49
#include <QMimeDatabase>
50

51
52
53
// static
QStringList ClipCreationDialog::getExtensions()
{
54
    // Build list of MIME types
55
    QStringList mimeTypes = QStringList() << QStringLiteral("application/x-kdenlive") << QStringLiteral("application/x-kdenlivetitle") << QStringLiteral("video/mlt-playlist") << QStringLiteral("text/plain");
56

57
    // Video MIMEs
58
    mimeTypes <<  QStringLiteral("video/x-flv") << QStringLiteral("application/vnd.rn-realmedia") << QStringLiteral("video/x-dv") << QStringLiteral("video/dv") << QStringLiteral("video/x-msvideo") << QStringLiteral("video/x-matroska") << QStringLiteral("video/mpeg") << QStringLiteral("video/ogg") << QStringLiteral("video/x-ms-wmv") << QStringLiteral("video/mp4") << QStringLiteral("video/quicktime") << QStringLiteral("video/webm") << QStringLiteral("video/3gpp") << QStringLiteral("video/mp2t");
59

60
    // Audio MIMEs
61
    mimeTypes << QStringLiteral("audio/x-flac") << QStringLiteral("audio/x-matroska") << QStringLiteral("audio/mp4") << QStringLiteral("audio/mpeg") << QStringLiteral("audio/x-mp3") << QStringLiteral("audio/ogg") << QStringLiteral("audio/x-wav") << QStringLiteral("audio/x-aiff") << QStringLiteral("audio/aiff") << QStringLiteral("application/ogg") << QStringLiteral("application/mxf") << QStringLiteral("application/x-shockwave-flash") << QStringLiteral("audio/ac3");
62

63
    // Image MIMEs
64
    mimeTypes << QStringLiteral("image/gif") << QStringLiteral("image/jpeg") << QStringLiteral("image/png") << QStringLiteral("image/x-tga") << QStringLiteral("image/x-bmp") << QStringLiteral("image/svg+xml") << QStringLiteral("image/tiff") << QStringLiteral("image/x-xcf") << QStringLiteral("image/x-xcf-gimp") << QStringLiteral("image/x-vnd.adobe.photoshop") << QStringLiteral("image/x-pcx") << QStringLiteral("image/x-exr") << QStringLiteral("image/x-portable-pixmap") << QStringLiteral("application/x-krita");
65
66
67

    QMimeDatabase db;
    QStringList allExtensions;
68
    foreach (const QString &mimeType, mimeTypes) {
69
70
71
72
73
        QMimeType mime = db.mimeTypeForName(mimeType);
        if (mime.isValid()) {
            allExtensions.append(mime.globPatterns());
        }
    }
74
    // process custom user extensions
75
    const QStringList customs = KdenliveSettings::addedExtensions().split(' ', QString::SkipEmptyParts);
76
    if (!customs.isEmpty()) {
77
        for (const QString &ext : customs) {
78
79
80
81
            if (ext.startsWith(QLatin1String("*."))) {
                allExtensions << ext;
            } else if (ext.startsWith(QLatin1String("."))) {
                allExtensions << QStringLiteral("*") + ext;
Laurent Montel's avatar
Laurent Montel committed
82
            } else if (!ext.contains(QLatin1Char('.'))) {
83
84
85
                allExtensions << QStringLiteral("*.") + ext;
            } else {
                //Unrecognized format
86
                qCDebug(KDENLIVE_LOG)<<"Unrecognized custom format: "<<ext;
87
88
89
            }
        }
    }
90
91
92
93
    allExtensions.removeDuplicates();
    return allExtensions;
}

94
//static
Laurent Montel's avatar
Add ref    
Laurent Montel committed
95
void ClipCreationDialog::createClipFromXml(KdenliveDoc *doc, QDomElement &xml, const QStringList &groupInfo, Bin *bin)
96
{
97
98
99
    //FIXME?
    Q_UNUSED(groupInfo)

100
    int id = bin->getFreeClipId();
101
    xml.setAttribute(QStringLiteral("id"), QString::number(id));
Jean-Baptiste Mardelle's avatar
Cleanup    
Jean-Baptiste Mardelle committed
102
    AddClipCommand *command = new AddClipCommand(bin, xml, QString::number(id), true);
103
104
105
    doc->commandStack()->push(command);
}

106
//static
Laurent Montel's avatar
Laurent Montel committed
107
void ClipCreationDialog::createColorClip(KdenliveDoc *doc, const QStringList &groupInfo, Bin *bin)
108
{
109
    QPointer<QDialog> dia = new QDialog(bin);
110
111
112
113
114
115
116
117
118
119
120
121
122
    Ui::ColorClip_UI dia_ui;
    dia_ui.setupUi(dia);
    dia->setWindowTitle(i18n("Color Clip"));
    dia_ui.clip_name->setText(i18n("Color Clip"));

    TimecodeDisplay *t = new TimecodeDisplay(doc->timecode());
    t->setValue(KdenliveSettings::color_duration());
    dia_ui.clip_durationBox->addWidget(t);
    dia_ui.clip_color->setColor(KdenliveSettings::colorclipcolor());

    if (dia->exec() == QDialog::Accepted) {
        QString color = dia_ui.clip_color->color().name();
        KdenliveSettings::setColorclipcolor(color);
123
        color = color.replace(0, 1, QStringLiteral("0x")) + "ff";
124
125
        // Everything is ready. create clip xml
        QDomDocument xml;
126
        QDomElement prod = xml.createElement(QStringLiteral("producer"));
127
        xml.appendChild(prod);
128
        prod.setAttribute(QStringLiteral("type"), (int) Color);
129
        int id = bin->getFreeClipId();
130
131
        prod.setAttribute(QStringLiteral("id"), QString::number(id));
        prod.setAttribute(QStringLiteral("in"), QStringLiteral("0"));
132
        prod.setAttribute(QStringLiteral("length"), doc->getFramePos(doc->timecode().getTimecode(t->gentime())));
133
        QMap <QString, QString> properties;
134
135
136
        properties.insert(QStringLiteral("resource"), color);
        properties.insert(QStringLiteral("kdenlive:clipname"), dia_ui.clip_name->text());
        properties.insert(QStringLiteral("mlt_service"), QStringLiteral("color"));
137
        if (!groupInfo.isEmpty()) {
138
            properties.insert(QStringLiteral("kdenlive:folderid"), groupInfo.at(0));
139
        }
140
        addXmlProperties(prod, properties);
Jean-Baptiste Mardelle's avatar
Cleanup    
Jean-Baptiste Mardelle committed
141
        AddClipCommand *command = new AddClipCommand(bin, xml.documentElement(), QString::number(id), true);
142
        doc->commandStack()->push(command);
143
144
145
146
147
    }
    delete t;
    delete dia;
}

Laurent Montel's avatar
Laurent Montel committed
148
void ClipCreationDialog::createQTextClip(KdenliveDoc *doc, const QStringList &groupInfo, Bin *bin, ProjectClip *clip)
Vincent Pinon's avatar
Vincent Pinon committed
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
{
    KSharedConfigPtr config = KSharedConfig::openConfig();
    KConfigGroup titleConfig(config, "TitleWidget");
    QPointer<QDialog> dia = new QDialog(bin);
    Ui::QTextClip_UI dia_ui;
    dia_ui.setupUi(dia);
    dia->setWindowTitle(i18n("Text Clip"));
    dia_ui.fgColor->setAlphaChannelEnabled(true);
    dia_ui.lineColor->setAlphaChannelEnabled(true);
    dia_ui.bgColor->setAlphaChannelEnabled(true);
    if (clip) {
        dia_ui.name->setText(clip->getProducerProperty(QStringLiteral("kdenlive:clipname")));
        dia_ui.text->setPlainText(clip->getProducerProperty(QStringLiteral("text")));
        dia_ui.fgColor->setColor(clip->getProducerProperty(QStringLiteral("fgcolour")));
        dia_ui.bgColor->setColor(clip->getProducerProperty(QStringLiteral("bgcolour")));
        dia_ui.pad->setValue(clip->getProducerProperty(QStringLiteral("pad")).toInt());
        dia_ui.lineColor->setColor(clip->getProducerProperty(QStringLiteral("olcolour")));
        dia_ui.lineWidth->setValue(clip->getProducerProperty(QStringLiteral("outline")).toInt());
        dia_ui.font->setCurrentFont(QFont(clip->getProducerProperty(QStringLiteral("family"))));
        dia_ui.fontSize->setValue(clip->getProducerProperty(QStringLiteral("size")).toInt());
        dia_ui.weight->setValue(clip->getProducerProperty(QStringLiteral("weight")).toInt());
        dia_ui.italic->setChecked(clip->getProducerProperty(QStringLiteral("style")) == QStringLiteral("italic"));
        dia_ui.duration->setText(doc->timecode().getTimecodeFromFrames(clip->getProducerProperty(QStringLiteral("out")).toInt()));
    } else {
        dia_ui.name->setText(i18n("Text Clip"));
        dia_ui.fgColor->setColor(titleConfig.readEntry(QStringLiteral("font_color")));
        dia_ui.bgColor->setColor(titleConfig.readEntry(QStringLiteral("background_color")));
        dia_ui.lineColor->setColor(titleConfig.readEntry(QStringLiteral("font_outline_color")));
        dia_ui.lineWidth->setValue(titleConfig.readEntry(QStringLiteral("font_outline")).toInt());
        dia_ui.font->setCurrentFont(QFont(titleConfig.readEntry(QStringLiteral("font_family"))));
        dia_ui.fontSize->setValue(titleConfig.readEntry(QStringLiteral("font_pixel_size")).toInt());
        dia_ui.weight->setValue(titleConfig.readEntry(QStringLiteral("font_weight")).toInt());
        dia_ui.italic->setChecked(titleConfig.readEntry(QStringLiteral("font_italic")).toInt());
        dia_ui.duration->setText(titleConfig.readEntry(QStringLiteral("title_duration")));
    }
    if (dia->exec() == QDialog::Accepted) {
        //KdenliveSettings::setColorclipcolor(color);
        QDomDocument xml;
        QDomElement prod = xml.createElement(QStringLiteral("producer"));
        xml.appendChild(prod);
        prod.setAttribute(QStringLiteral("type"), (int) QText);
190
        int id = bin->getFreeClipId();
Vincent Pinon's avatar
Vincent Pinon committed
191
        prod.setAttribute(QStringLiteral("id"), QString::number(id));
192

Vincent Pinon's avatar
Vincent Pinon committed
193
194
        prod.setAttribute(QStringLiteral("in"), QStringLiteral("0"));
        prod.setAttribute(QStringLiteral("out"), doc->timecode().getFrameCount(dia_ui.duration->text()));
195

Laurent Montel's avatar
Laurent Montel committed
196
        QMap<QString, QString> properties;
Vincent Pinon's avatar
Vincent Pinon committed
197
198
199
200
        properties.insert(QStringLiteral("kdenlive:clipname"), dia_ui.name->text());
        if (!groupInfo.isEmpty()) {
            properties.insert(QStringLiteral("kdenlive:folderid"), groupInfo.at(0));
        }
201

Vincent Pinon's avatar
Vincent Pinon committed
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
        properties.insert(QStringLiteral("mlt_service"), QStringLiteral("qtext"));
        properties.insert(QStringLiteral("out"), QString::number(doc->timecode().getFrameCount(dia_ui.duration->text())));
        properties.insert(QStringLiteral("length"), dia_ui.duration->text());
        //properties.insert(QStringLiteral("scale"), QStringLiteral("off"));
        //properties.insert(QStringLiteral("fill"), QStringLiteral("0"));
        properties.insert(QStringLiteral("text"), dia_ui.text->document()->toPlainText());
        properties.insert(QStringLiteral("fgcolour"), dia_ui.fgColor->color().name(QColor::HexArgb));
        properties.insert(QStringLiteral("bgcolour"), dia_ui.bgColor->color().name(QColor::HexArgb));
        properties.insert(QStringLiteral("olcolour"), dia_ui.lineColor->color().name(QColor::HexArgb));
        properties.insert(QStringLiteral("outline"), QString::number(dia_ui.lineWidth->value()));
        properties.insert(QStringLiteral("pad"), QString::number(dia_ui.pad->value()));
        properties.insert(QStringLiteral("family"), dia_ui.font->currentFont().family());
        properties.insert(QStringLiteral("size"), QString::number(dia_ui.fontSize->value()));
        properties.insert(QStringLiteral("style"), dia_ui.italic->isChecked() ? QStringLiteral("italic") : QStringLiteral("normal"));
        properties.insert(QStringLiteral("weight"), QString::number(dia_ui.weight->value()));
        if (clip) {
Laurent Montel's avatar
Laurent Montel committed
218
            QMap<QString, QString> oldProperties;
Vincent Pinon's avatar
Vincent Pinon committed
219
220
221
222
223
224
225
226
227
228
229
230
231
232
            oldProperties.insert(QStringLiteral("out"), clip->getProducerProperty(QStringLiteral("out")));
            oldProperties.insert(QStringLiteral("length"), clip->getProducerProperty(QStringLiteral("length")));
            oldProperties.insert(QStringLiteral("kdenlive:clipname"), clip->name());
            oldProperties.insert(QStringLiteral("ttl"), clip->getProducerProperty(QStringLiteral("ttl")));
            oldProperties.insert(QStringLiteral("loop"), clip->getProducerProperty(QStringLiteral("loop")));
            oldProperties.insert(QStringLiteral("crop"), clip->getProducerProperty(QStringLiteral("crop")));
            oldProperties.insert(QStringLiteral("fade"), clip->getProducerProperty(QStringLiteral("fade")));
            oldProperties.insert(QStringLiteral("luma_duration"), clip->getProducerProperty(QStringLiteral("luma_duration")));
            oldProperties.insert(QStringLiteral("luma_file"), clip->getProducerProperty(QStringLiteral("luma_file")));
            oldProperties.insert(QStringLiteral("softness"), clip->getProducerProperty(QStringLiteral("softness")));
            oldProperties.insert(QStringLiteral("animation"), clip->getProducerProperty(QStringLiteral("animation")));
            bin->slotEditClipCommand(clip->clipId(), oldProperties, properties);
        } else {
            addXmlProperties(prod, properties);
Jean-Baptiste Mardelle's avatar
Cleanup    
Jean-Baptiste Mardelle committed
233
            AddClipCommand *command = new AddClipCommand(bin, xml.documentElement(), QString::number(id), true);
Vincent Pinon's avatar
Vincent Pinon committed
234
235
236
237
238
239
            doc->commandStack()->push(command);
        }
    }
    delete dia;
}

240
//static
Laurent Montel's avatar
Laurent Montel committed
241
void ClipCreationDialog::createSlideshowClip(KdenliveDoc *doc, const QStringList &groupInfo, Bin *bin)
242
{
Laurent Montel's avatar
Laurent Montel committed
243
    QPointer<SlideshowClip> dia = new SlideshowClip(doc->timecode(), KRecentDirs::dir(QStringLiteral(":KdenliveSlideShowFolder")), nullptr, bin);
244
245
246

    if (dia->exec() == QDialog::Accepted) {
        // Ready, create xml
247
        KRecentDirs::add(QStringLiteral(":KdenliveSlideShowFolder"), QUrl::fromLocalFile(dia->selectedPath()).adjusted(QUrl::RemoveFilename).toLocalFile());
248
        QDomDocument xml;
249
        QDomElement prod = xml.createElement(QStringLiteral("producer"));
250
        xml.appendChild(prod);
251
252
253
        prod.setAttribute(QStringLiteral("in"), QStringLiteral("0"));
        prod.setAttribute(QStringLiteral("out"), QString::number(doc->getFramePos(dia->clipDuration()) * dia->imageCount() - 1));
        prod.setAttribute(QStringLiteral("type"), (int) SlideShow);
Laurent Montel's avatar
Laurent Montel committed
254
        QMap<QString, QString> properties;
255
256
257
258
259
260
        properties.insert(QStringLiteral("kdenlive:clipname"), dia->clipName());
        properties.insert(QStringLiteral("resource"), dia->selectedPath());
        properties.insert(QStringLiteral("ttl"), QString::number(doc->getFramePos(dia->clipDuration())));
        properties.insert(QStringLiteral("loop"), QString::number(dia->loop()));
        properties.insert(QStringLiteral("crop"), QString::number(dia->crop()));
        properties.insert(QStringLiteral("fade"), QString::number(dia->fade()));
261
        properties.insert(QStringLiteral("luma_duration"), QString::number(doc->getFramePos(dia->lumaDuration())));
262
263
264
        properties.insert(QStringLiteral("luma_file"), dia->lumaFile());
        properties.insert(QStringLiteral("softness"), QString::number(dia->softness()));
        properties.insert(QStringLiteral("animation"), dia->animation());
265
        if (!groupInfo.isEmpty()) {
266
            properties.insert(QStringLiteral("kdenlive:folderid"), groupInfo.at(0));
267
        }
268
        addXmlProperties(prod, properties);
269
        int id = bin->getFreeClipId();
Jean-Baptiste Mardelle's avatar
Cleanup    
Jean-Baptiste Mardelle committed
270
        AddClipCommand *command = new AddClipCommand(bin, xml.documentElement(), QString::number(id), true);
271
272
273
274
        doc->commandStack()->push(command);
    }
    delete dia;
}
275

Laurent Montel's avatar
Laurent Montel committed
276
void ClipCreationDialog::createTitleClip(KdenliveDoc *doc, const QStringList &groupInfo, const QString &templatePath, Bin *bin)
277
278
{
    // Make sure the titles folder exists
279
    QDir dir(doc->projectDataFolder() + QStringLiteral("/titles"));
280
281
    dir.mkpath(QStringLiteral("."));
    QPointer<TitleWidget> dia_ui = new TitleWidget(QUrl::fromLocalFile(templatePath), doc->timecode(), dir.absolutePath(), doc->renderer(), bin);
Laurent Montel's avatar
Laurent Montel committed
282
    QObject::connect(dia_ui.data(), &TitleWidget::requestBackgroundFrame, bin, &Bin::slotGetCurrentProjectImage);
283
284
285
    if (dia_ui->exec() == QDialog::Accepted) {
        // Ready, create clip xml
        QDomDocument xml;
286
        QDomElement prod = xml.createElement(QStringLiteral("producer"));
287
288
        xml.appendChild(prod);
        //prod.setAttribute("resource", imagePath);
289
        int id = bin->getFreeClipId();
290
        prod.setAttribute(QStringLiteral("id"), QString::number(id));
291

Laurent Montel's avatar
Laurent Montel committed
292
        QMap<QString, QString> properties;
293
294
        properties.insert(QStringLiteral("xmldata"), dia_ui->xml().toString());
        properties.insert(QStringLiteral("kdenlive:clipname"), i18n("Title clip"));
295
        if (!groupInfo.isEmpty()) {
296
            properties.insert(QStringLiteral("kdenlive:folderid"), groupInfo.at(0));
297
        }
298
        addXmlProperties(prod, properties);
299
300
301
302
        prod.setAttribute(QStringLiteral("type"), (int) Text);
        prod.setAttribute(QStringLiteral("transparency"), QStringLiteral("1"));
        prod.setAttribute(QStringLiteral("in"), QStringLiteral("0"));
        prod.setAttribute(QStringLiteral("out"), dia_ui->duration() - 1);
Jean-Baptiste Mardelle's avatar
Cleanup    
Jean-Baptiste Mardelle committed
303
        AddClipCommand *command = new AddClipCommand(bin, xml.documentElement(), QString::number(id), true);
304
305
306
307
        doc->commandStack()->push(command);
    }
    delete dia_ui;
}
308

Laurent Montel's avatar
Laurent Montel committed
309
void ClipCreationDialog::createTitleTemplateClip(KdenliveDoc *doc, const QStringList &groupInfo, Bin *bin)
310
311
{

312
    QPointer<TitleTemplateDialog> dia = new TitleTemplateDialog(doc->projectDataFolder(), QApplication::activeWindow());
313
314

    if (dia->exec() == QDialog::Accepted) {
315
        QString textTemplate = dia->selectedTemplate();
316
317
        // Create a cloned template clip
        QDomDocument xml;
318
        QDomElement prod = xml.createElement(QStringLiteral("producer"));
319
        xml.appendChild(prod);
320

Laurent Montel's avatar
Laurent Montel committed
321
        QMap<QString, QString> properties;
322
323
        properties.insert(QStringLiteral("resource"), textTemplate);
        properties.insert(QStringLiteral("kdenlive:clipname"), i18n("Template title clip"));
324
        if (!groupInfo.isEmpty()) {
325
            properties.insert(QStringLiteral("kdenlive:folderid"), groupInfo.at(0));
326
327
        }
        addXmlProperties(prod, properties);
328
        int id = bin->getFreeClipId();
329
        prod.setAttribute(QStringLiteral("id"), QString::number(id));
330
        prod.setAttribute(QStringLiteral("type"), (int) TextTemplate);
331
332
        prod.setAttribute(QStringLiteral("transparency"), QStringLiteral("1"));
        prod.setAttribute(QStringLiteral("in"), QStringLiteral("0"));
333
        prod.setAttribute(QStringLiteral("templatetext"), dia->selectedText());
334
335
336
337
338

        int duration = 0;
        QDomDocument titledoc;
        QFile txtfile(textTemplate);
        if (txtfile.open(QIODevice::ReadOnly) && titledoc.setContent(&txtfile)) {
339
340
            if (titledoc.documentElement().hasAttribute(QStringLiteral("duration"))) {
                duration = titledoc.documentElement().attribute(QStringLiteral("duration")).toInt();
341
342
            } else {
                // keep some time for backwards compatibility - 26/12/12
343
                duration = titledoc.documentElement().attribute(QStringLiteral("out")).toInt();
344
345
346
347
            }
        }
        txtfile.close();

348
349
350
        if (duration == 0) {
            duration = doc->getFramePos(KdenliveSettings::title_duration());
        }
351
352
        prod.setAttribute(QStringLiteral("duration"), duration - 1);
        prod.setAttribute(QStringLiteral("out"), duration - 1);
353

Jean-Baptiste Mardelle's avatar
Cleanup    
Jean-Baptiste Mardelle committed
354
        AddClipCommand *command = new AddClipCommand(bin, xml.documentElement(), QString::number(id), true);
355
356
357
358
359
        doc->commandStack()->push(command);
    }
    delete dia;
}

Laurent Montel's avatar
Laurent Montel committed
360
void ClipCreationDialog::addXmlProperties(QDomElement &producer, QMap<QString, QString> &properties)
361
362
363
364
{
    QMapIterator<QString, QString> i(properties);
    while (i.hasNext()) {
        i.next();
365
366
        QDomElement prop = producer.ownerDocument().createElement(QStringLiteral("property"));
        prop.setAttribute(QStringLiteral("name"), i.key());
367
368
369
370
371
372
        QDomText value = producer.ownerDocument().createTextNode(i.value());
        prop.appendChild(value);
        producer.appendChild(prop);
    }
}

Laurent Montel's avatar
Laurent Montel committed
373
void ClipCreationDialog::createClipsCommand(KdenliveDoc *doc, const QList<QUrl> &urls, const QStringList &groupInfo, Bin *bin, const QMap<QString, QString> &data)
374
375
{
    QUndoCommand *addClips = new QUndoCommand();
376

377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
    //TODO: check files on removable volume
    /*listRemovableVolumes();
    foreach(const QUrl &file, urls) {
        if (QFile::exists(file.path())) {
            //TODO check for duplicates
            if (!data.contains("bypassDuplicate") && !getClipByResource(file.path()).empty()) {
                if (KMessageBox::warningContinueCancel(QApplication::activeWindow(), i18n("Clip <b>%1</b><br />already exists in project, what do you want to do?", file.path()), i18n("Clip already exists")) == KMessageBox::Cancel)
                    continue;
            }
            if (isOnRemovableDevice(file) && !isOnRemovableDevice(m_doc->projectFolder())) {
                int answer = KMessageBox::warningYesNoCancel(QApplication::activeWindow(), i18n("Clip <b>%1</b><br /> is on a removable device, will not be available when device is unplugged", file.path()), i18n("File on a Removable Device"), KGuiItem(i18n("Copy file to project folder")), KGuiItem(i18n("Continue")), KStandardGuiItem::cancel(), QString("copyFilesToProjectFolder"));

                if (answer == KMessageBox::Cancel) continue;
                else if (answer == KMessageBox::Yes) {
                    // Copy files to project folder
                    QDir sourcesFolder(m_doc->projectFolder().toLocalFile());
                    sourcesFolder.cd("clips");
                    KIO::MkdirJob *mkdirJob = KIO::mkdir(QUrl::fromLocalFile(sourcesFolder.absolutePath()));
                    KJobWidgets::setWindow(mkdirJob, QApplication::activeWindow());
                    if (!mkdirJob->exec()) {
                        KMessageBox::sorry(QApplication::activeWindow(), i18n("Cannot create directory %1", sourcesFolder.absolutePath()));
                        continue;
                    }
                    //KIO::filesize_t m_requestedSize;
                    KIO::CopyJob *copyjob = KIO::copy(file, QUrl::fromLocalFile(sourcesFolder.absolutePath()));
                    //TODO: for some reason, passing metadata does not work...
                    copyjob->addMetaData("group", data.value("group"));
                    copyjob->addMetaData("groupId", data.value("groupId"));
                    copyjob->addMetaData("comment", data.value("comment"));
                    KJobWidgets::setWindow(copyjob, QApplication::activeWindow());
                    connect(copyjob, &KIO::CopyJob::copyingDone, this, &ClipManager::slotAddCopiedClip);
                    continue;
                }
            }*/
411
412

    //TODO check folders
Laurent Montel's avatar
Laurent Montel committed
413
    /*QList< QList<QUrl> > foldersList;
414
415
416
417
418
419
420
421
422
    QMimeDatabase db;
    foreach(const QUrl & file, list) {
        // Check there is no folder here
        QMimeType type = db.mimeTypeForUrl(file);
        if (type.inherits("inode/directory")) {
            // user dropped a folder, import its files
            list.removeAll(file);
            QDir dir(file.path());
            QStringList result = dir.entryList(QDir::Files);
Laurent Montel's avatar
Laurent Montel committed
423
            QList<QUrl> folderFiles;
424
425
            folderFiles << file;
            foreach(const QString & path, result) {
426
                // TODO: create folder command
427
428
429
430
431
                folderFiles.append(QUrl::fromLocalFile(dir.absoluteFilePath(path)));
            }
            if (folderFiles.count() > 1) foldersList.append(folderFiles);
        }
    }*/
432

433
    foreach (const QUrl &file, urls) {
434
        QDomDocument xml;
435
        QDomElement prod = xml.createElement(QStringLiteral("producer"));
436
        xml.appendChild(prod);
Laurent Montel's avatar
Laurent Montel committed
437
        QMap<QString, QString> properties;
Vincent Pinon's avatar
Vincent Pinon committed
438
        properties.insert(QStringLiteral("resource"), file.toLocalFile());
439
        if (!groupInfo.isEmpty()) {
440
            properties.insert(QStringLiteral("kdenlive:folderid"), groupInfo.at(0));
441
        }
442
443
444
445
446
447
        // Merge data
        QMapIterator<QString, QString> i(data);
        while (i.hasNext()) {
            i.next();
            properties.insert(i.key(), i.value());
        }
448
        int id = bin->getFreeClipId();
449
        prod.setAttribute(QStringLiteral("id"), QString::number(id));
450
451
452
        QMimeDatabase db;
        QMimeType type = db.mimeTypeForUrl(file);
        if (type.name().startsWith(QLatin1String("image/"))) {
453
454
            prod.setAttribute(QStringLiteral("type"), (int) Image);
            prod.setAttribute(QStringLiteral("in"), 0);
455
            prod.setAttribute(QStringLiteral("length"), doc->getFramePos(KdenliveSettings::image_duration()));
456
457
458
            if (KdenliveSettings::autoimagetransparency()) {
                properties.insert(QStringLiteral("kdenlive:transparency"), QStringLiteral("1"));
            }
459
        } else if (type.inherits(QStringLiteral("application/x-kdenlivetitle"))) {
460
            // opening a title file
461
            QDomDocument txtdoc(QStringLiteral("titledocument"));
462
            QFile txtfile(file.toLocalFile());
463
464
            if (txtfile.open(QIODevice::ReadOnly) && txtdoc.setContent(&txtfile)) {
                txtfile.close();
465
                prod.setAttribute(QStringLiteral("type"), (int) Text);
466
                // extract embedded images
467
                QDomNodeList items = txtdoc.elementsByTagName(QStringLiteral("content"));
468
469
                for (int j = 0; j < items.count(); ++j) {
                    QDomElement content = items.item(j).toElement();
470
                    if (content.hasAttribute(QStringLiteral("base64"))) {
471
                        QString titlesFolder = doc->projectDataFolder() + QStringLiteral("/titles/");
472
                        QString path = TitleDocument::extractBase64Image(titlesFolder, content.attribute(QStringLiteral("base64")));
473
                        if (!path.isEmpty()) {
474
475
                            content.setAttribute(QStringLiteral("url"), path);
                            content.removeAttribute(QStringLiteral("base64"));
476
477
478
                        }
                    }
                }
479
                prod.setAttribute(QStringLiteral("in"), 0);
480
                int duration = 0;
481
482
483
484
                if (txtdoc.documentElement().hasAttribute(QStringLiteral("duration"))) {
                    duration = txtdoc.documentElement().attribute(QStringLiteral("duration")).toInt();
                } else if (txtdoc.documentElement().hasAttribute(QStringLiteral("out"))) {
                    duration = txtdoc.documentElement().attribute(QStringLiteral("out")).toInt();
485
                }
486
                if (duration <= 0) {
487
                    duration = doc->getFramePos(KdenliveSettings::title_duration()) - 1;
488
                }
489
490
491
492
                prod.setAttribute(QStringLiteral("duration"), duration);
                prod.setAttribute(QStringLiteral("out"), duration);
                txtdoc.documentElement().setAttribute(QStringLiteral("duration"), duration);
                txtdoc.documentElement().setAttribute(QStringLiteral("out"), duration);
493
                QString titleData = txtdoc.toString();
494
                prod.setAttribute(QStringLiteral("xmldata"), titleData);
495
496
497
498
            } else {
                txtfile.close();
            }
        }
499
        addXmlProperties(prod, properties);
Jean-Baptiste Mardelle's avatar
Cleanup    
Jean-Baptiste Mardelle committed
500
        new AddClipCommand(bin, xml.documentElement(), QString::number(id), true, addClips);
501
502
503
504
505
506
    }
    if (addClips->childCount() > 0) {
        addClips->setText(i18np("Add clip", "Add clips", addClips->childCount()));
        doc->commandStack()->push(addClips);
    }
}
507

Laurent Montel's avatar
Laurent Montel committed
508
void ClipCreationDialog::createClipsCommand(KdenliveDoc *doc, const QStringList &groupInfo, Bin *bin)
509
{
Laurent Montel's avatar
Laurent Montel committed
510
    QList<QUrl> list;
511
    QString allExtensions = getExtensions().join(QLatin1Char(' '));
512
    QString dialogFilter = allExtensions + QLatin1Char('|') + i18n("All Supported Files") + QStringLiteral("\n*|") + i18n("All Files");
513
514
515
516
517
518
519
520
521
522
523
    QCheckBox *b = new QCheckBox(i18n("Import image sequence"));
    b->setChecked(KdenliveSettings::autoimagesequence());
    QCheckBox *c = new QCheckBox(i18n("Transparent background for images"));
    c->setChecked(KdenliveSettings::autoimagetransparency());
    QFrame *f = new QFrame();
    f->setFrameShape(QFrame::NoFrame);
    QHBoxLayout *l = new QHBoxLayout;
    l->addWidget(b);
    l->addWidget(c);
    l->addStretch(5);
    f->setLayout(l);
524
    QString clipFolder = KRecentDirs::dir(QStringLiteral(":KdenliveClipFolder"));
525
526
527
    if (clipFolder.isEmpty()) {
        clipFolder = QDir::homePath();
    }
528
    QDialog *dlg = new QDialog((QWidget *) doc->parent());
529
530
531
532
533
534
535
536
537
538
539
540
    KFileWidget *fileWidget = new KFileWidget(QUrl::fromLocalFile(clipFolder), dlg);
    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(fileWidget);
    fileWidget->setCustomWidget(f);
    fileWidget->okButton()->show();
    fileWidget->cancelButton()->show();
    QObject::connect(fileWidget->okButton(), &QPushButton::clicked, fileWidget, &KFileWidget::slotOk);
    QObject::connect(fileWidget, &KFileWidget::accepted, fileWidget, &KFileWidget::accept);
    QObject::connect(fileWidget, &KFileWidget::accepted, dlg, &QDialog::accept);
    QObject::connect(fileWidget->cancelButton(), &QPushButton::clicked, dlg, &QDialog::reject);
    dlg->setLayout(layout);
    fileWidget->setFilter(dialogFilter);
541
    fileWidget->setMode(KFile::Files | KFile::ExistingOnly | KFile::LocalOnly);
542
    KSharedConfig::Ptr conf = KSharedConfig::openConfig();
543
544
545
546
547
    QWindow *handle = dlg->windowHandle();
    if (handle && conf->hasGroup("FileDialogSize")) {
        KWindowConfig::restoreWindowSize(handle, conf->group("FileDialogSize"));
        dlg->resize(handle->size());
    }
548
    if (dlg->exec() == QDialog::Accepted) {
549
        KdenliveSettings::setAutoimagetransparency(c->isChecked());
550
        list = fileWidget->selectedUrls();
551
        if (!list.isEmpty()) {
Laurent Montel's avatar
Laurent Montel committed
552
            KRecentDirs::add(QStringLiteral(":KdenliveClipFolder"), list.constFirst().adjusted(QUrl::RemoveFilename).toLocalFile());
553
        }
Nicolas Carion's avatar
Nicolas Carion committed
554
        if (b->isChecked() && list.count() >= 1) {
555
556
            // Check for image sequence
            QUrl url = list.at(0);
557
            QString fileName = url.fileName().section(QLatin1Char('.'), 0, -2);
558
559
560
561
            if (fileName.at(fileName.size() - 1).isDigit()) {
                KFileItem item(url);
                if (item.mimetype().startsWith(QLatin1String("image"))) {
                    // import as sequence if we found more than one image in the sequence
562
563
564
565
                    QStringList patternlist;
                    QString pattern = SlideshowClip::selectedPath(url, false, QString(), &patternlist);
                    qCDebug(KDENLIVE_LOG) << " / // IMPORT PATTERN: " << pattern << " COUNT: " << patternlist.count();
                    int count = patternlist.count();
566
                    if (count > 1) {
567
568
                        delete fileWidget;
                        delete dlg;
569
                        // get image sequence base name
570
                        while (fileName.size() > 0 && fileName.at(fileName.size() - 1).isDigit()) {
571
572
573
                            fileName.chop(1);
                        }
                        QDomDocument xml;
574
                        QDomElement prod = xml.createElement(QStringLiteral("producer"));
575
                        xml.appendChild(prod);
576
                        prod.setAttribute(QStringLiteral("in"), QStringLiteral("0"));
577
                        QString duration = doc->timecode().reformatSeparators(KdenliveSettings::sequence_duration());
578
                        prod.setAttribute(QStringLiteral("out"), QString::number(doc->getFramePos(duration) * count));
Laurent Montel's avatar
Laurent Montel committed
579
                        QMap<QString, QString> properties;
580
581
582
583
584
585
586
                        properties.insert(QStringLiteral("resource"), pattern);
                        properties.insert(QStringLiteral("kdenlive:clipname"), fileName);
                        properties.insert(QStringLiteral("ttl"), QString::number(doc->getFramePos(duration)));
                        properties.insert(QStringLiteral("loop"), QString::number(false));
                        properties.insert(QStringLiteral("crop"), QString::number(false));
                        properties.insert(QStringLiteral("fade"), QString::number(false));
                        properties.insert(QStringLiteral("luma_duration"), QString::number(doc->getFramePos(doc->timecode().getTimecodeFromFrames(int(ceil(doc->timecode().fps()))))));
587
                        if (!groupInfo.isEmpty()) {
588
                            properties.insert(QStringLiteral("kdenlive:folderid"), groupInfo.at(0));
589
                        }
590
                        addXmlProperties(prod, properties);
591
                        int id = bin->getFreeClipId();
Jean-Baptiste Mardelle's avatar
Cleanup    
Jean-Baptiste Mardelle committed
592
                        AddClipCommand *command = new AddClipCommand(bin, xml.documentElement(), QString::number(id), true);
593
594
595
596
597
598
599
                        doc->commandStack()->push(command);
                        return;
                    }
                }
            }
        }
    }
600
    KConfigGroup group = conf->group("FileDialogSize");
601
602
603
    if (handle) {
        KWindowConfig::saveWindowSize(handle, group);
    }
604

605
606
    delete fileWidget;
    delete dlg;
607
    if (!list.isEmpty()) {
608
        ClipCreationDialog::createClipsCommand(doc, list, groupInfo, bin);
609
    }
610
}
611

Laurent Montel's avatar
Laurent Montel committed
612
void ClipCreationDialog::createClipsCommand(Bin *bin, const QDomElement &producer, const QString &id, QUndoCommand *command)
613
{
Jean-Baptiste Mardelle's avatar
Cleanup    
Jean-Baptiste Mardelle committed
614
    new AddClipCommand(bin, producer, id, true, command);
615
}
616