#include "documentchecker.h"
#include "documentvalidator.h"
#include "kdenlive-config.h"
+#include "initeffects.h"
#include <KDebug>
#include <KStandardDirs>
#include <KMessageBox>
+#include <KProgressDialog>
#include <KLocale>
#include <KFileDialog>
#include <KIO/NetAccess>
#include <KIO/CopyJob>
#include <KApplication>
+#include <KGlobal>
+#include <KBookmarkManager>
+#include <KBookmark>
+#include <KStandardDirs>
#include <QCryptographicHash>
#include <QFile>
#include <mlt++/Mlt.h>
-const double DOCUMENTVERSION = 0.85;
+const double DOCUMENTVERSION = 0.86;
-KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup *undoGroup, QString profileName, const QPoint tracks, Render *render, MainWindow *parent) :
- QObject(parent),
- m_autosave(NULL),
- m_url(url),
- m_render(render),
- m_commandStack(new QUndoStack(undoGroup)),
- m_modified(false),
- m_projectFolder(projectFolder)
+KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup *undoGroup, QString profileName, QMap <QString, QString> properties, const QPoint tracks, Render *render, KTextEdit *notes, bool *openBackup, MainWindow *parent, KProgressDialog *progressDialog) :
+ QObject(parent),
+ m_autosave(NULL),
+ m_url(url),
+ m_render(render),
+ m_notesWidget(notes),
+ m_commandStack(new QUndoStack(undoGroup)),
+ m_modified(false),
+ m_projectFolder(projectFolder)
{
m_clipManager = new ClipManager(this);
m_autoSaveTimer = new QTimer(this);
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["proxyextension"] = KdenliveSettings::proxyextension();
+ m_documentProperties["generateproxy"] = QString::number((int) KdenliveSettings::generateproxy());
+ 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()) {
+ i.next();
+ m_documentProperties[i.key()] = i.value();
+ }
+ *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;
file.close();
KIO::NetAccess::removeTempFile(tmpFile);
- if (!success) // It is corrupted
- KMessageBox::error(parent, errorMsg);
+ if (!success) {
+ // It is corrupted
+ if (KMessageBox::warningContinueCancel(parent, i18n("Cannot open the project file, error is:\n%1\nDo you want to open a backup file?", errorMsg), i18n("Error opening file"), KGuiItem(i18n("Open Backup"))) == KMessageBox::Continue) {
+ *openBackup = true;
+ }
+ //KMessageBox::error(parent, errorMsg);
+ }
else {
parent->slotGotProgressInfo(i18n("Validating"), 0);
+ qApp->processEvents();
DocumentValidator validator(m_document);
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
success = validator.validate(DOCUMENTVERSION);
if (success) { // Let the validator handle error messages
parent->slotGotProgressInfo(i18n("Check missing clips"), 0);
+ qApp->processEvents();
QDomNodeList infoproducers = m_document.elementsByTagName("kdenlive_producer");
success = checkDocumentClips(infoproducers);
if (success) {
+ if (m_document.documentElement().attribute("modified") == "1") setModified(true);
parent->slotGotProgressInfo(i18n("Loading"), 0);
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()) {
+ parent->slotGotProgressInfo(i18n("Importing project effects"), 0);
+ qApp->processEvents();
+ if (saveCustomEffects(customeffects.childNodes())) parent->slotReloadEffects();
+ }
+
QDomElement e;
+ // Read notes
+ QDomElement notesxml = infoXml.firstChildElement("documentnotes");
+ if (!notesxml.isNull()) m_notesWidget->setText(notesxml.firstChild().nodeValue());
// Build tracks
QDomElement tracksinfo = infoXml.firstChildElement("tracksinfo");
}
mlt.removeChild(tracksinfo);
}
-
- QDomNodeList folders = m_document.elementsByTagName("folder");
+ QStringList expandedFolders;
+ QDomNodeList folders = m_document.elementsByTagName("folder");
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"));
}
+ m_documentProperties["expandedfolders"] = expandedFolders.join(";");
const int infomax = infoproducers.count();
QDomNodeList producers = m_document.elementsByTagName("producer");
const int max = producers.count();
+ if (!progressDialog) {
+ progressDialog = new KProgressDialog(parent, i18n("Loading project"), i18n("Adding clips"));
+ progressDialog->setAllowCancel(false);
+ } else {
+ progressDialog->setLabelText(i18n("Adding clips"));
+ }
+ progressDialog->progressBar()->setMaximum(infomax);
+ progressDialog->show();
+ qApp->processEvents();
+
for (int i = 0; i < infomax; i++) {
e = infoproducers.item(i).cloneNode().toElement();
QString prodId = e.attribute("id");
// Get MLT's original producer properties
QDomElement orig;
for (int j = 0; j < max; j++) {
- QDomElement o = producers.item(j).cloneNode().toElement();
- QString origId = o.attribute("id").section('_', 0, 0);
+ QDomNode o = producers.item(j);
+ QString origId = o.attributes().namedItem("id").nodeValue().section('_', 0, 0);
if (origId == prodId) {
- orig = o;
+ orig = o.cloneNode().toElement();
break;
}
}
+
if (!addClipInfo(e, orig, prodId)) {
// The user manually aborted the loading.
success = false;
break;
}
}
+ if (i % 10 == 0)
+ progressDialog->progressBar()->setValue(i);
}
if (success) {
QDomNamedNodeMap props = docproperties.attributes();
for (int i = 0; i < props.count(); i++)
m_documentProperties.insert(props.item(i).nodeName(), props.item(i).nodeValue());
- setProfilePath(infoXml.attribute("profile"));
- setModified(validator.isModified());
+
+ if (validator.isModified()) setModified(true);
kDebug() << "Reading file: " << url.path() << ", found clips: " << producers.count();
}
}
}
}
}
-
+
// 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()));
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()));
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;
audioTrack.isBlind = true;
audioTrack.isLocked = false;
audioTrack.trackName = QString("Audio ") + QString::number(audiotracks - i);
+ audioTrack.duration = 0;
m_tracksList.append(audioTrack);
}
videoTrack.isBlind = false;
videoTrack.isLocked = false;
videoTrack.trackName = QString("Video ") + QString::number(videotracks - i);
+ videoTrack.duration = 0;
m_tracksList.append(videoTrack);
}
return createEmptyDocument(m_tracksList);
QDomDocument doc;
QDomElement mlt = doc.createElement("mlt");
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.
kDebug() << "ERROR; CANNOT CREATE AUTOSAVE FILE";
}
kDebug() << "// AUTOSAVE FILE: " << m_autosave->fileName();
- QString doc;
- if (KdenliveSettings::dropbframes()) {
- KdenliveSettings::setDropbframes(false);
- m_clipManager->updatePreviewSettings();
- doc = m_render->sceneList();
- KdenliveSettings::setDropbframes(true);
- m_clipManager->updatePreviewSettings();
- } else doc = m_render->sceneList();
- saveSceneList(m_autosave->fileName(), doc);
+ saveSceneList(m_autosave->fileName(), m_render->sceneList(), QStringList(), true);
}
}
return QPoint(m_documentProperties.value("zonein").toInt(), m_documentProperties.value("zoneout").toInt());
}
-bool KdenliveDoc::saveSceneList(const QString &path, const QString &scene)
+QDomDocument KdenliveDoc::xmlSceneList(const QString &scene, const QStringList expandedFolders)
{
QDomDocument sceneList;
sceneList.setContent(scene, true);
QDomElement mlt = sceneList.firstChildElement("mlt");
if (mlt.isNull() || !mlt.hasChildNodes()) {
- //Make sure we don't save if scenelist is corrupted
- KMessageBox::error(kapp->activeWindow(), i18n("Cannot write to file %1, scene list is corrupted.", path));
- return false;
+ //scenelist is corrupted
+ return sceneList;
}
+
QDomElement addedXml = sceneList.createElement("kdenlivedoc");
mlt.appendChild(addedXml);
+ // check if project contains custom effects to embed them in project file
+ QDomNodeList effects = mlt.elementsByTagName("filter");
+ int maxEffects = effects.count();
+ kDebug() << "// FOUD " << maxEffects << " EFFECTS+++++++++++++++++++++";
+ QMap <QString, QString> effectIds;
+ for (int i = 0; i < maxEffects; i++) {
+ QDomNode m = effects.at(i);
+ QDomNodeList params = m.childNodes();
+ QString id;
+ QString tag;
+ for (int j = 0; j < params.count(); j++) {
+ QDomElement e = params.item(j).toElement();
+ if (e.attribute("name") == "kdenlive_id") {
+ id = e.firstChild().nodeValue();
+ }
+ if (e.attribute("name") == "tag") {
+ tag = e.firstChild().nodeValue();
+ }
+ if (!id.isEmpty() && !tag.isEmpty()) effectIds.insert(id, tag);
+ }
+ }
+ QDomDocument customeffects = initEffects::getUsedCustomEffects(effectIds);
+ addedXml.appendChild(sceneList.importNode(customeffects.documentElement(), true));
+
QDomElement markers = sceneList.createElement("markers");
addedXml.setAttribute("version", DOCUMENTVERSION);
addedXml.setAttribute("kdenliveversion", VERSION);
docproperties.setAttribute("position", m_render->seekPosition().frames(m_fps));
addedXml.appendChild(docproperties);
+ QDomElement docnotes = sceneList.createElement("documentnotes");
+ QDomText value = sceneList.createTextNode(m_notesWidget->toHtml());
+ docnotes.appendChild(value);
+ addedXml.appendChild(docnotes);
+
// Add profile info
QDomElement profileinfo = sceneList.createElement("profileinfo");
profileinfo.setAttribute("description", m_profile.description);
QDomElement folder = sceneList.createElement("folder");
folder.setAttribute("id", f.key());
folder.setAttribute("name", f.value());
+ if (expandedFolders.contains(f.key())) folder.setAttribute("opened", "1");
addedXml.appendChild(folder);
}
addedXml.appendChild(sceneList.importNode(m_clipManager->groupsXml(), true));
//wes.appendChild(doc.importNode(kdenliveData, true));
+ return sceneList;
+}
+bool KdenliveDoc::saveSceneList(const QString &path, const QString &scene, const QStringList expandedFolders, bool autosave)
+{
+ QDomDocument sceneList = xmlSceneList(scene, expandedFolders);
+ if (sceneList.isNull()) {
+ //Make sure we don't save if scenelist is corrupted
+ KMessageBox::error(kapp->activeWindow(), i18n("Cannot write to file %1, scene list is corrupted.", path));
+ return false;
+ }
+
+ // Backup current version
+ if (!autosave) backupLastSavedVersion(path);
QFile file(path);
+
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
kWarning() << "////// ERROR writing to file: " << path;
KMessageBox::error(kapp->activeWindow(), i18n("Cannot write to file %1", path));
return false;
}
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(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);
m_projectFolder = url;
+
+ updateProjectFolderPlacesEntry();
}
void KdenliveDoc::moveProjectData(KUrl url)
if (path.isEmpty()) path = KdenliveSettings::default_profile();
if (path.isEmpty()) path = "dv_pal";
m_profile = ProfilesDialog::getVideoProfile(path);
- bool current_fps = m_fps;
+ double current_fps = m_fps;
if (m_profile.path.isEmpty()) {
// Profile not found, use embedded profile
QDomElement profileInfo = m_document.elementsByTagName("profileinfo").at(0).toElement();
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()
+void KdenliveDoc::checkProjectClips(bool displayRatioChanged, bool fpsChanged)
{
if (m_render == NULL) return;
- m_clipManager->resetProducersList(m_render->producersList());
-}
-
-void KdenliveDoc::updatePreviewSettings()
-{
- m_clipManager->updatePreviewSettings();
- m_render->updatePreviewSettings();
- QList <Mlt::Producer *> prods = m_render->producersList();
- m_clipManager->resetProducersList(m_render->producersList());
- qDeleteAll(prods);
- prods.clear();
+ m_clipManager->resetProducersList(m_render->producersList(), displayRatioChanged, fpsChanged);
}
Render *KdenliveDoc::renderer()
if (createClipItem) {
emit addProjectClip(clip);
- //qApp->processEvents();
}
return true;
}
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)
+ 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)
{
m_clipManager->slotAddSlideshowClipFile(name, path, count, duration, loop,
crop, fade, luma_duration,
{
QString titlesFolder = projectFolder().path(KUrl::AddTrailingSlash) + "titles/";
if (path.isEmpty()) {
- path = KFileDialog::getOpenUrl(KUrl(titlesFolder), "*.kdenlivetitle", kapp->activeWindow(), i18n("Enter Template Path"));
+ path = KFileDialog::getOpenUrl(KUrl(titlesFolder), "application/x-kdenlivetitle", kapp->activeWindow(), i18n("Enter Template Path"));
}
if (path.isEmpty()) return;
m_tracksList[ix].isBlind = hide; // !m_tracksList.at(ix).isBlind;
}
+int KdenliveDoc::trackDuration(int ix)
+{
+ 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)
{
if (ix == -1) m_tracksList << type;
bool KdenliveDoc::checkDocumentClips(QDomNodeList infoproducers)
{
DocumentChecker d(infoproducers, m_document);
- return (d.hasMissingClips() == false);
+ return (d.hasErrorInClips() == false);
/* int clipType;
QDomElement e;
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('%')) {
//break;
}
}
+
+ if (effect.attribute("id") == "crop") {
+ // default use_profile to 1 for clips with proxies to avoid problems when rendering
+ if (e.attribute("name") == "use_profile" && getDocumentProperty("enableproxy") == "1")
+ e.setAttribute("value", "1");
+ }
}
m_tracksList[ix].effectsList.append(effect);
return list.at(effectIndex).cloneNode().toElement();
}
+bool KdenliveDoc::saveCustomEffects(QDomNodeList customeffects)
+{
+ QDomElement e;
+ QStringList importedEffects;
+ int maxchild = customeffects.count();
+ for (int i = 0; i < maxchild; i++) {
+ e = customeffects.at(i).toElement();
+ QString id = e.attribute("id");
+ QString tag = e.attribute("tag");
+ if (!id.isEmpty()) {
+ // Check if effect exists or save it
+ if (MainWindow::customEffects.hasEffect(tag, id) == -1) {
+ QDomDocument doc;
+ doc.appendChild(doc.importNode(e, true));
+ QString path = KStandardDirs::locateLocal("appdata", "effects/", true);
+ path += id + ".xml";
+ if (!QFile::exists(path)) {
+ importedEffects << id;
+ QFile file(path);
+ if (file.open(QFile::WriteOnly | QFile::Truncate)) {
+ QTextStream out(&file);
+ out << doc.toString();
+ }
+ }
+ }
+ }
+ }
+ if (!importedEffects.isEmpty()) KMessageBox::informationList(kapp->activeWindow(), i18n("The following effects were imported from the project:"), importedEffects);
+ return (!importedEffects.isEmpty());
+}
+
+void KdenliveDoc::updateProjectFolderPlacesEntry()
+{
+ /*
+ * For similar and more code have a look at kfileplacesmodel.cpp and the included files:
+ * http://websvn.kde.org/trunk/KDE/kdelibs/kfile/kfileplacesmodel.cpp?view=markup
+ */
+
+ const QString file = KStandardDirs::locateLocal("data", "kfileplaces/bookmarks.xml");
+ KBookmarkManager *bookmarkManager = KBookmarkManager::managerForFile(file, "kfilePlaces");
+ KBookmarkGroup root = bookmarkManager->root();
+ KBookmark bookmark = root.first();
+
+ QString kdenliveName = KGlobal::mainComponent().componentName();
+ KUrl documentLocation = m_projectFolder;
+
+ bool exists = false;
+
+ while (!bookmark.isNull()) {
+ // UDI not empty indicates a device
+ QString udi = bookmark.metaDataItem("UDI");
+ QString appName = bookmark.metaDataItem("OnlyInApp");
+
+ if (udi.isEmpty() && appName == kdenliveName && bookmark.text() == i18n("Project Folder")) {
+ if (bookmark.url() != documentLocation) {
+ bookmark.setUrl(documentLocation);
+ bookmarkManager->emitChanged(root);
+ }
+ exists = true;
+ break;
+ }
+
+ bookmark = root.next(bookmark);
+ }
+
+ // if entry does not exist yet (was not found), well, create it then
+ if (!exists) {
+ bookmark = root.addBookmark(i18n("Project Folder"), documentLocation, "folder-favorites");
+ // Make this user selectable ?
+ bookmark.setMetaDataItem("OnlyInApp", kdenliveName);
+ bookmarkManager->emitChanged(root);
+ }
+}
+
+QStringList KdenliveDoc::getExpandedFolders()
+{
+ QStringList result = m_documentProperties.value("expandedfolders").split(';');
+ // this property is only needed once when opening project, so clear it now
+ m_documentProperties.remove("expandedfolders");
+ return result;
+}
+
+// static
+double KdenliveDoc::getDisplayRatio(const QString &path)
+{
+ QFile file(path);
+ QDomDocument doc;
+ if (!file.open(QIODevice::ReadOnly)) {
+ kWarning() << "ERROR, CANNOT READ: " << path;
+ return 0;
+ }
+ if (!doc.setContent(&file)) {
+ kWarning() << "ERROR, CANNOT READ: " << path;
+ file.close();
+ return 0;
+ }
+ file.close();
+ QDomNodeList list = doc.elementsByTagName("profile");
+ if (list.isEmpty()) return 0;
+ QDomElement profile = list.at(0).toElement();
+ double den = profile.attribute("display_aspect_den").toDouble();
+ if (den > 0) return profile.attribute("display_aspect_num").toDouble() / den;
+ return 0;
+}
+
+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);
+
+ 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()
+{
+ KUrl backupFile = m_projectFolder;
+ 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("-??");
+ projectFile.append("-??");
+ projectFile.append("-??");
+ projectFile.append("-??.kdenlive");
+
+ QStringList filter;
+ backupFile.addPath(projectFile);
+ filter << projectFile;
+ dir.setNameFilters(filter);
+ QFileInfoList resultList = dir.entryInfoList(QDir::Files, QDir::Time);
+
+ QDateTime d = QDateTime::currentDateTime();
+ QStringList hourList;
+ QStringList dayList;
+ QStringList weekList;
+ QStringList oldList;
+ 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());
+ }
+ else if (d.secsTo(resultList.at(i).lastModified()) < 43200) {
+ // files created in the day
+ dayList.append(resultList.at(i).absoluteFilePath());
+ }
+ else if (d.daysTo(resultList.at(i).lastModified()) < 8) {
+ // files created in the week
+ weekList.append(resultList.at(i).absoluteFilePath());
+ }
+ else {
+ // older files
+ oldList.append(resultList.at(i).absoluteFilePath());
+ }
+ }
+ if (hourList.count() > 20) {
+ int step = hourList.count() / 10;
+ for (int i = 0; i < hourList.count(); i += step) {
+ kDebug()<<"REMOVE AT: "<<i<<", COUNT: "<<hourList.count();
+ hourList.removeAt(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--;
+ }
+ } 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--;
+ }
+ } 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--;
+ }
+ } else oldList.clear();
+
+ QString f;
+ while (hourList.count() > 0) {
+ f = hourList.takeFirst();
+ QFile::remove(f);
+ QFile::remove(f + ".png");
+ }
+ while (dayList.count() > 0) {
+ f = dayList.takeFirst();
+ QFile::remove(f);
+ QFile::remove(f + ".png");
+ }
+ while (weekList.count() > 0) {
+ f = weekList.takeFirst();
+ QFile::remove(f);
+ QFile::remove(f + ".png");
+ }
+ while (oldList.count() > 0) {
+ f = oldList.takeFirst();
+ QFile::remove(f);
+ QFile::remove(f + ".png");
+ }
+}
+
#include "kdenlivedoc.moc"