#include "kdenlivesettings.h"
#include "renderer.h"
#include "clipmanager.h"
-#include "titlewidget.h"
+#include "widgets/titlewidget.h"
#include "mainwindow.h"
#include "documentchecker.h"
#include "documentvalidator.h"
-#include "kdenlive-config.h"
+#include "config-kdenlive.h"
#include "initeffects.h"
#include <KDebug>
#include <KStandardDirs>
#include <KMessageBox>
#include <KProgressDialog>
-#include <KLocale>
+#include <KLocalizedString>
#include <KFileDialog>
#include <KIO/NetAccess>
#include <KIO/CopyJob>
+#include <KIO/JobUiDelegate>
#include <KApplication>
#include <KGlobal>
#include <KBookmarkManager>
#include <QFile>
#include <QInputDialog>
#include <QDomImplementation>
+#include <QUndoGroup>
+#include <QTimer>
+#include <QUndoStack>
#include <mlt++/Mlt.h>
-const double DOCUMENTVERSION = 0.86;
+#include "locale.h"
-KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup *undoGroup, QString profileName, QMap <QString, QString> properties, const QPoint tracks, Render *render, KTextEdit *notes, MainWindow *parent, KProgressDialog *progressDialog) :
+
+const double DOCUMENTVERSION = 0.88;
+
+KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup *undoGroup, const QString &profileName, const QMap <QString, QString>& properties, const QMap <QString, QString>& metadata, const QPoint &tracks, Render *render, KTextEdit *notes, bool *openBackup, MainWindow *parent, KProgressDialog *progressDialog) :
QObject(parent),
m_autosave(NULL),
m_url(url),
m_modified(false),
m_projectFolder(projectFolder)
{
+ // init m_profile struct
+ m_profile.frame_rate_num = 0;
+ m_profile.frame_rate_den = 0;
+ m_profile.width = 0;
+ m_profile.height = 0;
+ m_profile.progressive = 0;
+ m_profile.sample_aspect_num = 0;
+ m_profile.sample_aspect_den = 0;
+ m_profile.display_aspect_num = 0;
+ m_profile.display_aspect_den = 0;
+ m_profile.colorspace = 0;
+
m_clipManager = new ClipManager(this);
m_autoSaveTimer = new QTimer(this);
m_autoSaveTimer->setSingleShot(true);
+ connect(m_clipManager, SIGNAL(displayMessage(QString,int)), parent, SLOT(slotGotProgressInfo(QString,int)));
bool success = false;
// init default document properties
- m_documentProperties["zoom"] = "7";
- m_documentProperties["verticalzoom"] = "1";
- m_documentProperties["zonein"] = "0";
+ m_documentProperties["zoom"] = '7';
+ m_documentProperties["verticalzoom"] = '1';
+ m_documentProperties["zonein"] = '0';
m_documentProperties["zoneout"] = "100";
m_documentProperties["enableproxy"] = QString::number((int) KdenliveSettings::enableproxy());
m_documentProperties["proxyparams"] = KdenliveSettings::proxyparams();
m_documentProperties["proxyminsize"] = QString::number(KdenliveSettings::proxyminsize());
m_documentProperties["generateimageproxy"] = QString::number((int) KdenliveSettings::generateimageproxy());
m_documentProperties["proxyimageminsize"] = QString::number(KdenliveSettings::proxyimageminsize());
-
+#if QT_VERSION >= 0x040700
+ m_documentProperties["documentid"] = QString::number(QDateTime::currentMSecsSinceEpoch());
+#else
+ QDateTime date = QDateTime::currentDateTime();
+ m_documentProperties["documentid"] = QString::number(date.toTime_t());
+#endif
+
// Load properties
QMapIterator<QString, QString> i(properties);
while (i.hasNext()) {
m_documentProperties[i.key()] = i.value();
}
+ // Load metadata
+ QMapIterator<QString, QString> j(metadata);
+ while (j.hasNext()) {
+ j.next();
+ m_documentMetadata[j.key()] = j.value();
+ }
+
+ if (QLocale().decimalPoint() != QLocale::system().decimalPoint()) {
+ setlocale(LC_NUMERIC, "");
+ QLocale systemLocale = QLocale::system();
+ systemLocale.setNumberOptions(QLocale::OmitGroupSeparator);
+ QLocale::setDefault(systemLocale);
+ // locale conversion might need to be redone
+ initEffects::parseEffectFiles(setlocale(LC_NUMERIC, NULL));
+ }
+
+ *openBackup = false;
+
if (!url.isEmpty()) {
QString tmpFile;
success = KIO::NetAccess::download(url.path(), tmpFile, parent);
- if (!success) // The file cannot be opened
- KMessageBox::error(parent, KIO::NetAccess::lastErrorString());
+ if (!success) {
+ // The file cannot be opened
+ if (KMessageBox::warningContinueCancel(parent, i18n("Cannot open the project file, error is:\n%1\nDo you want to open a backup file?", KIO::NetAccess::lastErrorString()), i18n("Error opening file"), KGuiItem(i18n("Open Backup"))) == KMessageBox::Continue) {
+ *openBackup = true;
+ }
+ //KMessageBox::error(parent, KIO::NetAccess::lastErrorString());
+ }
else {
QFile file(tmpFile);
QString errorMsg;
- QDomImplementation impl;
- impl.setInvalidDataPolicy(QDomImplementation::DropInvalidChars);
- success = m_document.setContent(&file, false, &errorMsg);
+ int line;
+ int col;
+ QDomImplementation::setInvalidDataPolicy(QDomImplementation::DropInvalidChars);
+ success = m_document.setContent(&file, false, &errorMsg, &line, &col);
file.close();
- KIO::NetAccess::removeTempFile(tmpFile);
- if (!success) // It is corrupted
- KMessageBox::error(parent, errorMsg);
- else {
+ if (!success) {
+ // It is corrupted
+ int answer = KMessageBox::warningYesNoCancel (parent, i18n("Cannot open the project file, error is:\n%1 (line %2, col %3)\nDo you want to open a backup file?", errorMsg, line, col), i18n("Error opening file"), KGuiItem(i18n("Open Backup")), KGuiItem(i18n("Recover")));
+ if (answer == KMessageBox::Yes) {
+ *openBackup = true;
+ }
+ else if (answer == KMessageBox::No) {
+ // Try to recover broken file produced by Kdenlive 0.9.4
+ if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ int correction = 0;
+ QString playlist = file.readAll();
+ while (!success && correction < 2) {
+ int errorPos = 0;
+ line--;
+ col = col - 2;
+ for (int j = 0; j < line && errorPos < playlist.length(); j++) {
+ errorPos = playlist.indexOf("\n", errorPos);
+ errorPos++;
+ }
+ errorPos += col;
+ if (errorPos >= playlist.length()) break;
+ playlist.remove(errorPos, 1);
+ line = 0;
+ col = 0;
+ success = m_document.setContent(playlist, false, &errorMsg, &line, &col);
+ correction++;
+ }
+ if (!success) {
+ KMessageBox::sorry(parent, i18n("Cannot recover this project file"));
+ }
+ else {
+ // Document was modified, ask for backup
+ QDomElement mlt = m_document.documentElement();
+ QDomElement info = mlt.firstChildElement("kdenlivedoc");
+ if (!info.isNull()) info.setAttribute("modified", 1);
+ }
+ }
+ }
+ }
+ if (success) {
parent->slotGotProgressInfo(i18n("Validating"), 0);
qApp->processEvents();
- DocumentValidator validator(m_document);
+ DocumentValidator validator(m_document, url);
success = validator.isProject();
if (!success) {
// It is not a project file
parent->slotGotProgressInfo(i18n("File %1 is not a Kdenlive project file", m_url.path()), 100);
+ if (KMessageBox::warningContinueCancel(parent, i18n("File %1 is not a valid project file.\nDo you want to open a backup file?", m_url.path()), i18n("Error opening file"), KGuiItem(i18n("Open Backup"))) == KMessageBox::Continue) {
+ *openBackup = true;
+ }
} else {
/*
* Validate the file against the current version (upgrade
QDomElement mlt = m_document.firstChildElement("mlt");
QDomElement infoXml = mlt.firstChildElement("kdenlivedoc");
+ // Set profile, fps, etc for the document
+ setProfilePath(infoXml.attribute("profile"));
+
// Check embedded effects
QDomElement customeffects = infoXml.firstChildElement("customeffects");
if (!customeffects.isNull() && customeffects.hasChildNodes()) {
if (e.tagName() == "trackinfo") {
TrackInfo projectTrack;
if (e.attribute("type") == "audio")
- projectTrack.type = AUDIOTRACK;
+ projectTrack.type = AudioTrack;
else
- projectTrack.type = VIDEOTRACK;
+ projectTrack.type = VideoTrack;
projectTrack.isMute = e.attribute("mute").toInt();
projectTrack.isBlind = e.attribute("blind").toInt();
projectTrack.isLocked = e.attribute("locked").toInt();
projectTrack.trackName = e.attribute("trackname");
+ projectTrack.effectsList = EffectsList(true);
m_tracksList.append(projectTrack);
}
}
}
QStringList expandedFolders;
QDomNodeList folders = m_document.elementsByTagName("folder");
- for (int i = 0; i < folders.count(); i++) {
+ for (int i = 0; i < folders.count(); ++i) {
e = folders.item(i).cloneNode().toElement();
if (e.hasAttribute("opened")) expandedFolders.append(e.attribute("id"));
m_clipManager->addFolder(e.attribute("id"), e.attribute("name"));
progressDialog->show();
qApp->processEvents();
- for (int i = 0; i < infomax; i++) {
+ for (int i = 0; i < infomax; ++i) {
e = infoproducers.item(i).cloneNode().toElement();
QString prodId = e.attribute("id");
if (!e.isNull() && prodId != "black" && !prodId.startsWith("slowmotion")) {
int maxchild = markerslist.count();
for (int k = 0; k < maxchild; k++) {
e = markerslist.at(k).toElement();
- if (e.tagName() == "marker")
- m_clipManager->getClipById(e.attribute("id"))->addSnapMarker(GenTime(e.attribute("time").toDouble()), e.attribute("comment"));
+ if (e.tagName() == "marker") {
+ CommentedTime marker(GenTime(e.attribute("time").toDouble()), e.attribute("comment"), e.attribute("type").toInt());
+ DocClipBase *baseClip = m_clipManager->getClipById(e.attribute("id"));
+ if (baseClip) baseClip->addSnapMarker(marker);
+ else kDebug()<< " / / Warning, missing clip: "<< e.attribute("id");
+ }
}
infoXml.removeChild(markers);
}
m_projectFolder = KUrl(infoXml.attribute("projectfolder"));
QDomElement docproperties = infoXml.firstChildElement("documentproperties");
QDomNamedNodeMap props = docproperties.attributes();
- for (int i = 0; i < props.count(); i++)
+ for (int i = 0; i < props.count(); ++i)
m_documentProperties.insert(props.item(i).nodeName(), props.item(i).nodeValue());
- setProfilePath(infoXml.attribute("profile"));
+ docproperties = infoXml.firstChildElement("documentmetadata");
+ props = docproperties.attributes();
+ for (int i = 0; i < props.count(); ++i)
+ m_documentMetadata.insert(props.item(i).nodeName(), props.item(i).nodeValue());
+
if (validator.isModified()) setModified(true);
kDebug() << "Reading file: " << url.path() << ", found clips: " << producers.count();
}
}
}
}
+ KIO::NetAccess::removeTempFile(tmpFile);
}
}
-
+
// Something went wrong, or a new file was requested: create a new project
if (!success) {
- m_url = KUrl();
+ m_url.clear();
setProfilePath(profileName);
m_document = createEmptyDocument(tracks.x(), tracks.y());
}
- // Set the video profile (empty == default)
- KdenliveSettings::setCurrent_profile(profilePath());
-
// Ask to create the project directory if it does not exist
if (!QFile::exists(m_projectFolder.path())) {
int create = KMessageBox::questionYesNo(parent, i18n("Project directory %1 does not exist. Create it?", m_projectFolder.path()));
// Make sure that the necessary folders exist
KStandardDirs::makeDir(m_projectFolder.path(KUrl::AddTrailingSlash) + "titles/");
KStandardDirs::makeDir(m_projectFolder.path(KUrl::AddTrailingSlash) + "thumbs/");
- KStandardDirs::makeDir(m_projectFolder.path(KUrl::AddTrailingSlash) + "ladspa/");
KStandardDirs::makeDir(m_projectFolder.path(KUrl::AddTrailingSlash) + "proxy/");
updateProjectFolderPlacesEntry();
//kDebug() << "// SETTING SCENE LIST:\n\n" << m_document.toString();
connect(m_autoSaveTimer, SIGNAL(timeout()), this, SLOT(slotAutoSave()));
+ connect(m_render, SIGNAL(addClip(KUrl,stringMap)), this, SLOT(slotAddClipFile(KUrl,stringMap)));
}
KdenliveDoc::~KdenliveDoc()
int KdenliveDoc::setSceneList()
{
- m_render->resetProfile(KdenliveSettings::current_profile());
+ m_render->resetProfile(KdenliveSettings::current_profile(), true);
if (m_render->setSceneList(m_document.toString(), m_documentProperties.value("position").toInt()) == -1) {
// INVALID MLT Consumer, something is wrong
return -1;
// Tracks are added «backwards», so we need to reverse the track numbering
// mbt 331: http://www.kdenlive.org/mantis/view.php?id=331
// Better default names for tracks: Audio 1 etc. instead of blank numbers
- for (int i = 0; i < audiotracks; i++) {
+ for (int i = 0; i < audiotracks; ++i) {
TrackInfo audioTrack;
- audioTrack.type = AUDIOTRACK;
+ audioTrack.type = AudioTrack;
audioTrack.isMute = false;
audioTrack.isBlind = true;
audioTrack.isLocked = false;
audioTrack.trackName = QString("Audio ") + QString::number(audiotracks - i);
audioTrack.duration = 0;
+ audioTrack.effectsList = EffectsList(true);
m_tracksList.append(audioTrack);
}
- for (int i = 0; i < videotracks; i++) {
+ for (int i = 0; i < videotracks; ++i) {
TrackInfo videoTrack;
- videoTrack.type = VIDEOTRACK;
+ videoTrack.type = VideoTrack;
videoTrack.isMute = false;
videoTrack.isBlind = false;
videoTrack.isLocked = false;
videoTrack.trackName = QString("Video ") + QString::number(videotracks - i);
videoTrack.duration = 0;
+ videoTrack.effectsList = EffectsList(true);
m_tracksList.append(videoTrack);
}
return createEmptyDocument(m_tracksList);
}
-QDomDocument KdenliveDoc::createEmptyDocument(QList <TrackInfo> tracks)
+QDomDocument KdenliveDoc::createEmptyDocument(const QList <TrackInfo> &tracks)
{
// Creating new document
QDomDocument doc;
QDomElement mlt = doc.createElement("mlt");
+ mlt.setAttribute("LC_NUMERIC", "");
doc.appendChild(mlt);
-
-
+
// Create black producer
// For some unknown reason, we have to build the black producer here and not in renderer.cpp, otherwise
// the composite transitions with the black track are corrupted.
property = doc.createElement("property");
property.setAttribute("name", "aspect_ratio");
- value = doc.createTextNode(QString::number(0.0));
+ value = doc.createTextNode(QString::number(0));
property.appendChild(value);
blk.appendChild(property);
QDomElement tractor = doc.createElement("tractor");
tractor.setAttribute("id", "maintractor");
- QDomElement multitrack = doc.createElement("multitrack");
+ //QDomElement multitrack = doc.createElement("multitrack");
QDomElement playlist = doc.createElement("playlist");
playlist.setAttribute("id", "black_track");
mlt.appendChild(playlist);
// create playlists
int total = tracks.count() + 1;
- for (int i = 1; i < total; i++) {
+ for (int i = 1; i < total; ++i) {
QDomElement playlist = doc.createElement("playlist");
playlist.setAttribute("id", "playlist" + QString::number(i));
mlt.appendChild(playlist);
tractor.appendChild(track0);
// create audio and video tracks
- for (int i = 1; i < total; i++) {
+ for (int i = 1; i < total; ++i) {
QDomElement track = doc.createElement("track");
track.setAttribute("producer", "playlist" + QString::number(i));
- if (tracks.at(i - 1).type == AUDIOTRACK) {
+ if (tracks.at(i - 1).type == AudioTrack) {
track.setAttribute("hide", "video");
} else if (tracks.at(i - 1).isBlind)
track.setAttribute("hide", "video");
tractor.appendChild(track);
}
- for (int i = 2; i < total ; i++) {
+ for (int i = 2; i < total ; ++i) {
QDomElement transition = doc.createElement("transition");
transition.setAttribute("always_active", "1");
}
-void KdenliveDoc::syncGuides(QList <Guide *> guides)
+void KdenliveDoc::syncGuides(const QList <Guide *> &guides)
{
m_guidesXml.clear();
QDomElement guideNode = m_guidesXml.createElement("guides");
m_guidesXml.appendChild(guideNode);
QDomElement e;
- for (int i = 0; i < guides.count(); i++) {
+ for (int i = 0; i < guides.count(); ++i) {
e = m_guidesXml.createElement("guide");
e.setAttribute("time", guides.at(i)->position().ms() / 1000);
e.setAttribute("comment", guides.at(i)->label());
return QPoint(m_documentProperties.value("zonein").toInt(), m_documentProperties.value("zoneout").toInt());
}
-QDomDocument KdenliveDoc::xmlSceneList(const QString &scene, const QStringList expandedFolders)
+QDomDocument KdenliveDoc::xmlSceneList(const QString &scene, const QStringList &expandedFolders)
{
QDomDocument sceneList;
sceneList.setContent(scene, true);
return sceneList;
}
+ // Set playlist audio volume to 100%
+ QDomElement tractor = mlt.firstChildElement("tractor");
+ if (!tractor.isNull()) {
+ QDomNodeList props = tractor.elementsByTagName("property");
+ for (int i = 0; i < props.count(); ++i) {
+ if (props.at(i).toElement().attribute("name") == "meta.volume") {
+ props.at(i).firstChild().setNodeValue("1");
+ break;
+ }
+ }
+ }
+
QDomElement addedXml = sceneList.createElement("kdenlivedoc");
mlt.appendChild(addedXml);
int maxEffects = effects.count();
kDebug() << "// FOUD " << maxEffects << " EFFECTS+++++++++++++++++++++";
QMap <QString, QString> effectIds;
- for (int i = 0; i < maxEffects; i++) {
+ for (int i = 0; i < maxEffects; ++i) {
QDomNode m = effects.at(i);
QDomNodeList params = m.childNodes();
QString id;
}
docproperties.setAttribute("position", m_render->seekPosition().frames(m_fps));
addedXml.appendChild(docproperties);
+
+ QDomElement docmetadata = sceneList.createElement("documentmetadata");
+ QMapIterator<QString, QString> j(m_documentMetadata);
+ while (j.hasNext()) {
+ j.next();
+ docmetadata.setAttribute(j.key(), j.value());
+ }
+ addedXml.appendChild(docmetadata);
QDomElement docnotes = sceneList.createElement("documentnotes");
QDomText value = sceneList.createTextNode(m_notesWidget->toHtml());
QDomElement tracksinfo = sceneList.createElement("tracksinfo");
foreach(const TrackInfo & info, m_tracksList) {
QDomElement trackinfo = sceneList.createElement("trackinfo");
- if (info.type == AUDIOTRACK) trackinfo.setAttribute("type", "audio");
+ if (info.type == AudioTrack) trackinfo.setAttribute("type", "audio");
trackinfo.setAttribute("mute", info.isMute);
trackinfo.setAttribute("blind", info.isBlind);
trackinfo.setAttribute("locked", info.isLocked);
// Save project clips
QDomElement e;
QList <DocClipBase*> list = m_clipManager->documentClipList();
- for (int i = 0; i < list.count(); i++) {
- e = list.at(i)->toXML();
+ for (int i = 0; i < list.count(); ++i) {
+ e = list.at(i)->toXML(true);
e.setTagName("kdenlive_producer");
addedXml.appendChild(sceneList.importNode(e, true));
QList < CommentedTime > marks = list.at(i)->commentedSnapMarkers();
marker.setAttribute("time", marks.at(j).time().ms() / 1000);
marker.setAttribute("comment", marks.at(j).comment());
marker.setAttribute("id", e.attribute("id"));
+ marker.setAttribute("type", marks.at(j).markerType());
markers.appendChild(marker);
}
}
return sceneList;
}
-bool KdenliveDoc::saveSceneList(const QString &path, const QString &scene, const QStringList expandedFolders, bool autosave)
+bool KdenliveDoc::saveSceneList(const QString &path, const QString &scene, const QStringList &expandedFolders, bool autosave)
{
QDomDocument sceneList = xmlSceneList(scene, expandedFolders);
if (sceneList.isNull()) {
file.close();
if (!autosave) {
cleanupBackupFiles();
+ QFileInfo info(file);
+ QString fileName = KUrl(path).fileName().section('.', 0, -2);
+ fileName.append('-' + m_documentProperties.value("documentid"));
+ fileName.append(info.lastModified().toString("-yyyy-MM-dd-hh-mm"));
+ fileName.append(".kdenlive.png");
+ KUrl backupFile = m_projectFolder;
+ backupFile.addPath(".backup/");
+ backupFile.addPath(fileName);
+ emit saveTimelinePreview(backupFile.path());
}
return true;
}
KStandardDirs::makeDir(url.path());
KStandardDirs::makeDir(url.path(KUrl::AddTrailingSlash) + "titles/");
KStandardDirs::makeDir(url.path(KUrl::AddTrailingSlash) + "thumbs/");
- if (KMessageBox::questionYesNo(kapp->activeWindow(), i18n("You have changed the project folder. Do you want to copy the cached data from %1 to the new folder %2?").arg(m_projectFolder.path(), url.path())) == KMessageBox::Yes) moveProjectData(url);
+ if (KMessageBox::questionYesNo(kapp->activeWindow(), i18n("You have changed the project folder. Do you want to copy the cached data from %1 to the new folder %2?", m_projectFolder.path(), url.path())) == KMessageBox::Yes) moveProjectData(url);
m_projectFolder = url;
updateProjectFolderPlacesEntry();
}
-void KdenliveDoc::moveProjectData(KUrl url)
+void KdenliveDoc::moveProjectData(const KUrl &url)
{
QList <DocClipBase*> list = m_clipManager->documentClipList();
- //TODO: Also move ladspa effects files
- for (int i = 0; i < list.count(); i++) {
+ KUrl::List cacheUrls;
+ for (int i = 0; i < list.count(); ++i) {
DocClipBase *clip = list.at(i);
- if (clip->clipType() == TEXT) {
+ if (clip->clipType() == Text) {
// the image for title clip must be moved
KUrl oldUrl = clip->fileURL();
KUrl newUrl = KUrl(url.path(KUrl::AddTrailingSlash) + "titles/" + oldUrl.fileName());
KUrl oldVideoThumbUrl = KUrl(m_projectFolder.path(KUrl::AddTrailingSlash) + "thumbs/" + hash + ".png");
KUrl oldAudioThumbUrl = KUrl(m_projectFolder.path(KUrl::AddTrailingSlash) + "thumbs/" + hash + ".thumb");
if (KIO::NetAccess::exists(oldVideoThumbUrl, KIO::NetAccess::SourceSide, 0)) {
- KUrl newUrl = KUrl(url.path(KUrl::AddTrailingSlash) + "thumbs/" + hash + ".png");
- KIO::Job *job = KIO::copy(oldVideoThumbUrl, newUrl);
- KIO::NetAccess::synchronousRun(job, 0);
+ cacheUrls << oldVideoThumbUrl;
}
if (KIO::NetAccess::exists(oldAudioThumbUrl, KIO::NetAccess::SourceSide, 0)) {
- KUrl newUrl = KUrl(url.path(KUrl::AddTrailingSlash) + "thumbs/" + hash + ".thumb");
- KIO::Job *job = KIO::copy(oldAudioThumbUrl, newUrl);
- if (KIO::NetAccess::synchronousRun(job, 0)) clip->refreshThumbUrl();
+ cacheUrls << oldAudioThumbUrl;
}
}
+ if (!cacheUrls.isEmpty()) {
+ KIO::Job *job = KIO::copy(cacheUrls, KUrl(url.path(KUrl::AddTrailingSlash) + "thumbs/"));
+ job->ui()->setWindow(kapp->activeWindow());
+ KIO::NetAccess::synchronousRun(job, 0);
+ }
}
const QString &KdenliveDoc::profilePath() const
bool KdenliveDoc::setProfilePath(QString path)
{
- if (path.isEmpty()) path = KdenliveSettings::default_profile();
- if (path.isEmpty()) path = "dv_pal";
+ if (path.isEmpty())
+ path = KdenliveSettings::default_profile();
+ if (path.isEmpty())
+ path = QLatin1String("dv_pal");
m_profile = ProfilesDialog::getVideoProfile(path);
double current_fps = m_fps;
if (m_profile.path.isEmpty()) {
m_height = m_profile.height;
kDebug() << "Kdenlive document, init timecode from path: " << path << ", " << m_fps;
m_timecode.setFormat(m_fps);
+ KdenliveSettings::setCurrent_profile(m_profile.path);
return (current_fps != m_fps);
}
emit progressInfo(QString(), -1);
}*/
-void KdenliveDoc::checkProjectClips(bool displayRatioChanged)
+void KdenliveDoc::checkProjectClips(bool displayRatioChanged, bool fpsChanged)
{
if (m_render == NULL) return;
- m_clipManager->resetProducersList(m_render->producersList(), displayRatioChanged);
+ m_clipManager->resetProducersList(m_render->producersList(), displayRatioChanged, fpsChanged);
}
Render *KdenliveDoc::renderer()
return m_render;
}
-void KdenliveDoc::updateClip(const QString id)
+void KdenliveDoc::updateClip(const QString &id)
{
emit updateClipDisplay(id);
}
-int KdenliveDoc::getFramePos(QString duration)
+int KdenliveDoc::getFramePos(const QString &duration)
{
return m_timecode.getFrameCount(duration);
}
QString result = "unnamed";
QDomNodeList prods = producersList();
int ct = prods.count();
- for (int i = 0; i < ct ; i++) {
+ for (int i = 0; i < ct ; ++i) {
QDomElement e = prods.item(i).toElement();
if (e.attribute("id") != "black" && e.attribute("id") == id) {
result = e.attribute("name");
return m_url;
}
-void KdenliveDoc::setUrl(KUrl url)
+void KdenliveDoc::setUrl(const KUrl &url)
{
m_url = url;
}
return m_url.fileName() + " / " + m_profile.description;
}
-bool KdenliveDoc::addClip(QDomElement elem, QString clipId, bool createClipItem)
+bool KdenliveDoc::addClip(QDomElement elem, const QString &clipId, bool createClipItem)
{
const QString producerId = clipId.section('_', 0, 0);
DocClipBase *clip = m_clipManager->getClipById(producerId);
elem.setAttribute("id", producerId);
QString path = elem.attribute("resource");
QString extension;
- if (elem.attribute("type").toInt() == SLIDESHOW) {
+ if (elem.attribute("type").toInt() == SlideShow) {
extension = KUrl(path).fileName();
path = KUrl(path).directory();
}
-
- if (path.isEmpty() == false && QFile::exists(path) == false && elem.attribute("type").toInt() != TEXT && !elem.hasAttribute("placeholder")) {
+ if (elem.hasAttribute("_missingsource")) {
+ // Clip has proxy but missing original source
+ }
+ else if (path.isEmpty() == false && QFile::exists(path) == false && elem.attribute("type").toInt() != Text && !elem.hasAttribute("placeholder")) {
kDebug() << "// FOUND MISSING CLIP: " << path << ", TYPE: " << elem.attribute("type").toInt();
const QString size = elem.attribute("file_size");
const QString hash = elem.attribute("file_hash");
else
action = (KMessageBox::ButtonCode) KMessageBox::questionYesNoCancel(kapp->activeWindow(), i18n("Clip <b>%1</b><br />is invalid, what do you want to do?", path), i18n("File not found"), KGuiItem(i18n("Search automatically")), KGuiItem(i18n("Keep as placeholder")));
} else {
- if (elem.attribute("type").toInt() == SLIDESHOW) {
+ if (elem.attribute("type").toInt() == SlideShow) {
int res = KMessageBox::questionYesNoCancel(kapp->activeWindow(), i18n("Clip <b>%1</b><br />is invalid or missing, what do you want to do?", path), i18n("File not found"), KGuiItem(i18n("Search manually")), KGuiItem(i18n("Keep as placeholder")));
if (res == KMessageBox::Yes)
newpath = KFileDialog::getExistingDirectory(KUrl("kfiledialog:///clipfolder"), kapp->activeWindow(), i18n("Looking for %1", path));
elem.setAttribute("placeholder", '1');
}
if (!newpath.isEmpty()) {
- if (elem.attribute("type").toInt() == SLIDESHOW)
+ if (elem.attribute("type").toInt() == SlideShow)
newpath.append('/' + extension);
elem.setAttribute("resource", newpath);
setNewClipResource(clipId, newpath);
{
QDomNodeList prods = m_document.elementsByTagName("producer");
int maxprod = prods.count();
- for (int i = 0; i < maxprod; i++) {
+ for (int i = 0; i < maxprod; ++i) {
QDomNode m = prods.at(i);
QString prodId = m.toElement().attribute("id");
if (prodId == id || prodId.startsWith(id + '_')) {
QByteArray fileData;
QByteArray fileHash;
QStringList filesAndDirs = dir.entryList(QDir::Files | QDir::Readable);
- for (int i = 0; i < filesAndDirs.size() && foundFileName.isEmpty(); i++) {
+ for (int i = 0; i < filesAndDirs.size() && foundFileName.isEmpty(); ++i) {
QFile file(dir.absoluteFilePath(filesAndDirs.at(i)));
if (file.open(QIODevice::ReadOnly)) {
if (QString::number(file.size()) == matchSize) {
kDebug() << filesAndDirs.at(i) << file.size() << fileHash.toHex();
}
filesAndDirs = dir.entryList(QDir::Dirs | QDir::Readable | QDir::Executable | QDir::NoDotAndDotDot);
- for (int i = 0; i < filesAndDirs.size() && foundFileName.isEmpty(); i++) {
+ for (int i = 0; i < filesAndDirs.size() && foundFileName.isEmpty(); ++i) {
foundFileName = searchFileRecursively(dir.absoluteFilePath(filesAndDirs.at(i)), matchSize, matchHash);
if (!foundFileName.isEmpty())
break;
return foundFileName;
}
-bool KdenliveDoc::addClipInfo(QDomElement elem, QDomElement orig, QString clipId)
+bool KdenliveDoc::addClipInfo(QDomElement elem, QDomElement orig, const QString &clipId)
{
DocClipBase *clip = m_clipManager->getClipById(clipId);
if (clip == NULL) {
} else {
QMap <QString, QString> properties;
QDomNamedNodeMap attributes = elem.attributes();
- for (int i = 0; i < attributes.count(); i++) {
+ for (int i = 0; i < attributes.count(); ++i) {
QString attrname = attributes.item(i).nodeName();
if (attrname != "resource")
properties.insert(attrname, attributes.item(i).nodeValue());
- kDebug() << attrname << " = " << attributes.item(i).nodeValue();
+ //kDebug() << attrname << " = " << attributes.item(i).nodeValue();
}
clip->setProperties(properties);
emit addProjectClip(clip, false);
QMap<QString, QString> meta;
for (QDomNode m = orig.firstChild(); !m.isNull(); m = m.nextSibling()) {
QString name = m.toElement().attribute("name");
- if (name.startsWith("meta.attr"))
- meta.insert(name.section('.', 2, 3), m.firstChild().nodeValue());
+ if (name.startsWith("meta.attr")) {
+ if (name.endsWith(".markup")) name = name.section('.', 0, -2);
+ meta.insert(name.section('.', 2, -1), m.firstChild().nodeValue());
+ }
}
if (!meta.isEmpty()) {
if (clip == NULL)
emit signalDeleteProjectClip(clipId);
}
-void KdenliveDoc::slotAddClipList(const KUrl::List urls, const QString group, const QString &groupId)
+void KdenliveDoc::slotAddClipList(const KUrl::List &urls, const stringMap &data)
{
- m_clipManager->slotAddClipList(urls, group, groupId);
+ m_clipManager->slotAddClipList(urls, data);
//emit selectLastAddedClip(QString::number(m_clipManager->lastClipId()));
setModified(true);
}
-void KdenliveDoc::slotAddClipFile(const KUrl url, const QString group, const QString &groupId)
+void KdenliveDoc::slotAddClipFile(const KUrl &url, const stringMap &data)
{
- m_clipManager->slotAddClipFile(url, group, groupId);
+ m_clipManager->slotAddClipFile(url, data);
emit selectLastAddedClip(QString::number(m_clipManager->lastClipId()));
setModified(true);
}
return m_clipManager->getClipById(clipId);
}
-void KdenliveDoc::slotCreateXmlClip(const QString &name, const QDomElement xml, QString group, const QString &groupId)
+void KdenliveDoc::slotCreateXmlClip(const QString &name, const QDomElement &xml, const QString &group, const QString &groupId)
{
m_clipManager->slotAddXmlClipFile(name, xml, group, groupId);
setModified(true);
emit selectLastAddedClip(QString::number(m_clipManager->lastClipId()));
}
-void KdenliveDoc::slotCreateColorClip(const QString &name, const QString &color, const QString &duration, QString group, const QString &groupId)
+void KdenliveDoc::slotCreateColorClip(const QString &name, const QString &color, const QString &duration, const QString &group, const QString &groupId)
{
m_clipManager->slotAddColorClipFile(name, color, duration, group, groupId);
setModified(true);
emit selectLastAddedClip(QString::number(m_clipManager->lastClipId()));
}
-void KdenliveDoc::slotCreateSlideshowClipFile(const QString name, const QString path, int count, const QString duration,
- const bool loop, const bool crop, const bool fade,
- const QString &luma_duration, const QString &luma_file, const int softness,
- const QString &animation, QString group, const QString &groupId)
+void KdenliveDoc::slotCreateSlideshowClipFile(const QMap <QString, QString> &properties, const QString &group, const QString &groupId)
{
- m_clipManager->slotAddSlideshowClipFile(name, path, count, duration, loop,
- crop, fade, luma_duration,
- luma_file, softness,
- animation, group, groupId);
+ m_clipManager->slotAddSlideshowClipFile(properties, group, groupId);
setModified(true);
emit selectLastAddedClip(QString::number(m_clipManager->lastClipId()));
}
{
QString titlesFolder = projectFolder().path(KUrl::AddTrailingSlash) + "titles/";
KStandardDirs::makeDir(titlesFolder);
- TitleWidget *dia_ui = new TitleWidget(templatePath, m_timecode, titlesFolder, m_render, kapp->activeWindow());
+ QPointer<TitleWidget> dia_ui = new TitleWidget(templatePath, m_timecode, titlesFolder, m_render, kapp->activeWindow());
if (dia_ui->exec() == QDialog::Accepted) {
- m_clipManager->slotAddTextClipFile(i18n("Title clip"), dia_ui->outPoint(), dia_ui->xml().toString(), group, groupId);
+ m_clipManager->slotAddTextClipFile(i18n("Title clip"), dia_ui->duration(), dia_ui->xml().toString(), group, groupId);
setModified(true);
emit selectLastAddedClip(QString::number(m_clipManager->lastClipId()));
}
delete dia_ui;
}
-void KdenliveDoc::slotCreateTextTemplateClip(QString group, const QString &groupId, KUrl path)
+void KdenliveDoc::slotCreateTextTemplateClip(const QString &group, const QString &groupId, KUrl path)
{
QString titlesFolder = projectFolder().path(KUrl::AddTrailingSlash) + "titles/";
if (path.isEmpty()) {
int KdenliveDoc::trackDuration(int ix)
{
- return m_tracksList.at(ix).duration;
+ return m_tracksList.at(ix).duration;
}
void KdenliveDoc::setTrackDuration(int ix, int duration)
m_tracksList[ix].duration = duration;
}
-void KdenliveDoc::insertTrack(int ix, TrackInfo type)
+void KdenliveDoc::insertTrack(int ix, const TrackInfo &type)
{
if (ix == -1) m_tracksList << type;
else m_tracksList.insert(ix, type);
m_tracksList.removeAt(ix);
}
-void KdenliveDoc::setTrackType(int ix, TrackInfo type)
+void KdenliveDoc::setTrackType(int ix, const TrackInfo &type)
{
if (ix < 0 || ix >= m_tracksList.count()) {
kWarning() << "SET Track Type outisde of range";
int audio = 0;
int video = 0;
foreach(const TrackInfo & info, m_tracksList) {
- if (info.type == VIDEOTRACK) video++;
+ if (info.type == VideoTrack) video++;
else audio++;
}
return QPoint(video, audio);
}
-void KdenliveDoc::cachePixmap(const QString &fileId, const QPixmap &pix) const
-{
- pix.save(m_projectFolder.path(KUrl::AddTrailingSlash) + "thumbs/" + fileId + ".png");
-}
-
-QString KdenliveDoc::getLadspaFile() const
+void KdenliveDoc::cacheImage(const QString &fileId, const QImage &img) const
{
- int ct = 0;
- QString counter = QString::number(ct).rightJustified(5, '0', false);
- while (QFile::exists(m_projectFolder.path(KUrl::AddTrailingSlash) + "ladspa/" + counter + ".ladspa")) {
- ct++;
- counter = QString::number(ct).rightJustified(5, '0', false);
- }
- return m_projectFolder.path(KUrl::AddTrailingSlash) + "ladspa/" + counter + ".ladspa";
+ img.save(m_projectFolder.path(KUrl::AddTrailingSlash) + "thumbs/" + fileId + ".png");
}
bool KdenliveDoc::checkDocumentClips(QDomNodeList infoproducers)
{
DocumentChecker d(infoproducers, m_document);
- return (d.hasMissingClips() == false);
+ return (d.hasErrorInClips() == false);
/* int clipType;
QDomElement e;
QString id;
QString resource;
QList <QDomElement> missingClips;
- for (int i = 0; i < infoproducers.count(); i++) {
+ for (int i = 0; i < infoproducers.count(); ++i) {
e = infoproducers.item(i).toElement();
clipType = e.attribute("type").toInt();
if (clipType == COLOR) continue;
// Init parameter value & keyframes if required
QDomNodeList params = effect.elementsByTagName("parameter");
- for (int i = 0; i < params.count(); i++) {
+ for (int i = 0; i < params.count(); ++i) {
QDomElement e = params.item(i).toElement();
// Check if this effect has a variable parameter
- if (e.attribute("default").startsWith('%')) {
+ if (e.attribute("default").contains('%')) {
double evaluatedValue = ProfilesDialog::getStringEval(m_profile, e.attribute("default"));
e.setAttribute("default", evaluatedValue);
if (e.hasAttribute("value") && e.attribute("value").startsWith('%')) {
m_tracksList[ix].effectsList.append(effect);
}
-void KdenliveDoc::removeTrackEffect(int ix, QDomElement effect)
+void KdenliveDoc::removeTrackEffect(int ix, const QDomElement &effect)
{
if (ix < 0 || ix >= m_tracksList.count()) {
kWarning() << "Remove Track effect outisde of range";
return;
}
- QString index;
- QString toRemove = effect.attribute("kdenlive_ix");
+ int index;
+ int toRemove = effect.attribute("kdenlive_ix").toInt();
for (int i = 0; i < m_tracksList.at(ix).effectsList.count(); ++i) {
- index = m_tracksList.at(ix).effectsList.at(i).attribute("kdenlive_ix");
+ index = m_tracksList.at(ix).effectsList.at(i).attribute("kdenlive_ix").toInt();
if (toRemove == index) {
- m_tracksList[ix].effectsList.removeAt(i);
- i--;
- } else if (index.toInt() > toRemove.toInt()) {
- m_tracksList[ix].effectsList.item(i).setAttribute("kdenlive_ix", index.toInt() - 1);
+ m_tracksList[ix].effectsList.removeAt(toRemove);
+ break;
}
}
}
kWarning() << "Set Track effect outisde of range";
return;
}
- if (effectIndex < 0 || effectIndex > (m_tracksList.at(trackIndex).effectsList.count() - 1) || effect.isNull()) {
+ if (effectIndex <= 0 || effectIndex > (m_tracksList.at(trackIndex).effectsList.count()) || effect.isNull()) {
kDebug() << "Invalid effect index: " << effectIndex;
return;
}
- effect.setAttribute("kdenlive_ix", effectIndex + 1);
- m_tracksList[trackIndex].effectsList.replace(effectIndex, effect);
+ m_tracksList[trackIndex].effectsList.removeAt(effect.attribute("kdenlive_ix").toInt());
+ effect.setAttribute("kdenlive_ix", effectIndex);
+ m_tracksList[trackIndex].effectsList.insert(effect);
+ //m_tracksList[trackIndex].effectsList.updateEffect(effect);
+}
+
+void KdenliveDoc::enableTrackEffects(int trackIndex, const QList <int> &effectIndexes, bool disable)
+{
+ if (trackIndex < 0 || trackIndex >= m_tracksList.count()) {
+ kWarning() << "Set Track effect outisde of range";
+ return;
+ }
+ EffectsList list = m_tracksList.at(trackIndex).effectsList;
+ QDomElement effect;
+ for (int i = 0; i < effectIndexes.count(); ++i) {
+ effect = list.itemFromIndex(effectIndexes.at(i));
+ if (!effect.isNull()) effect.setAttribute("disable", (int) disable);
+ }
}
const EffectsList KdenliveDoc::getTrackEffects(int ix)
return QDomElement();
}
EffectsList list = m_tracksList.at(trackIndex).effectsList;
- if (effectIndex > list.count() - 1 || effectIndex < 0 || list.at(effectIndex).isNull()) return QDomElement();
- return list.at(effectIndex).cloneNode().toElement();
+ if (effectIndex > list.count() || effectIndex < 1 || list.itemFromIndex(effectIndex).isNull()) return QDomElement();
+ return list.itemFromIndex(effectIndex).cloneNode().toElement();
}
-bool KdenliveDoc::saveCustomEffects(QDomNodeList customeffects)
+int KdenliveDoc::hasTrackEffect(int trackIndex, const QString &tag, const QString &id) const
+{
+ if (trackIndex < 0 || trackIndex >= m_tracksList.count()) {
+ kWarning() << "Get Track effect outisde of range";
+ return -1;
+ }
+ EffectsList list = m_tracksList.at(trackIndex).effectsList;
+ return list.hasEffect(tag, id);
+}
+
+bool KdenliveDoc::saveCustomEffects(const QDomNodeList &customeffects)
{
QDomElement e;
QStringList importedEffects;
int maxchild = customeffects.count();
- for (int i = 0; i < maxchild; i++) {
+ for (int i = 0; i < maxchild; ++i) {
e = customeffects.at(i).toElement();
- QString id = e.attribute("id");
- QString tag = e.attribute("tag");
+ const QString id = e.attribute("id");
+ const QString tag = e.attribute("tag");
if (!id.isEmpty()) {
// Check if effect exists or save it
if (MainWindow::customEffects.hasEffect(tag, id) == -1) {
}
}
}
- if (!importedEffects.isEmpty()) KMessageBox::informationList(kapp->activeWindow(), i18n("The following effects were imported from the project:"), importedEffects);
+ if (!importedEffects.isEmpty())
+ KMessageBox::informationList(kapp->activeWindow(), i18n("The following effects were imported from the project:"), importedEffects);
return (!importedEffects.isEmpty());
}
const QString file = KStandardDirs::locateLocal("data", "kfileplaces/bookmarks.xml");
KBookmarkManager *bookmarkManager = KBookmarkManager::managerForFile(file, "kfilePlaces");
+ if (!bookmarkManager) return;
KBookmarkGroup root = bookmarkManager->root();
+
KBookmark bookmark = root.first();
QString kdenliveName = KGlobal::mainComponent().componentName();
void KdenliveDoc::backupLastSavedVersion(const QString &path)
{
// Ensure backup folder exists
+ if (path.isEmpty()) return;
QFile file(path);
KUrl backupFile = m_projectFolder;
backupFile.addPath(".backup/");
KIO::NetAccess::mkdir(backupFile, kapp->activeWindow());
QString fileName = KUrl(path).fileName().section('.', 0, -2);
QFileInfo info(file);
+ fileName.append('-' + m_documentProperties.value("documentid"));
fileName.append(info.lastModified().toString("-yyyy-MM-dd-hh-mm"));
fileName.append(".kdenlive");
backupFile.addPath(fileName);
- emit saveTimelinePreview(backupFile.path() + ".png");
-
if (file.exists()) {
// delete previous backup if it was done less than 60 seconds ago
QFile::remove(backupFile.path());
if (!QFile::copy(path, backupFile.path())) {
KMessageBox::information(kapp->activeWindow(), i18n("Cannot create backup copy:\n%1", backupFile.path()));
}
- }
+ }
}
void KdenliveDoc::cleanupBackupFiles()
backupFile.addPath(".backup/");
QDir dir(backupFile.path());
QString projectFile = url().fileName().section('.', 0, -2);
+ projectFile.append('-' + m_documentProperties.value("documentid"));
projectFile.append("-??");
projectFile.append("??");
projectFile.append("-??");
QStringList dayList;
QStringList weekList;
QStringList oldList;
- for (int i = 0; i < resultList.count(); i++) {
+ for (int i = 0; i < resultList.count(); ++i) {
if (d.secsTo(resultList.at(i).lastModified()) < 3600) {
// files created in the last hour
hourList.append(resultList.at(i).absoluteFilePath());
for (int i = 0; i < hourList.count(); i += step) {
kDebug()<<"REMOVE AT: "<<i<<", COUNT: "<<hourList.count();
hourList.removeAt(i);
- i--;
+ --i;
}
} else hourList.clear();
if (dayList.count() > 20) {
int step = dayList.count() / 10;
for (int i = 0; i < dayList.count(); i += step) {
dayList.removeAt(i);
- i--;
+ --i;
}
} else dayList.clear();
if (weekList.count() > 20) {
int step = weekList.count() / 10;
for (int i = 0; i < weekList.count(); i += step) {
weekList.removeAt(i);
- i--;
+ --i;
}
} else weekList.clear();
if (oldList.count() > 20) {
int step = oldList.count() / 10;
for (int i = 0; i < oldList.count(); i += step) {
oldList.removeAt(i);
- i--;
+ --i;
}
} else oldList.clear();
}
}
+const QMap <QString, QString> KdenliveDoc::metadata() const
+{
+ return m_documentMetadata;
+}
+
+void KdenliveDoc::setMetadata(const QMap<QString, QString> &meta)
+{
+ setModified(true);
+ m_documentMetadata = meta;
+}
+
#include "kdenlivedoc.moc"