From dc7e3f5fd8909bc0f6638786cdfd9d44637bfe2f Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Mardelle Date: Sun, 5 Jun 2011 21:54:05 +0000 Subject: [PATCH] Backup project file everytime it is saved, backup files can be browsed and opened from the Project menu. svn path=/trunk/kdenlive/; revision=5664 --- src/CMakeLists.txt | 1 + src/customtrackview.cpp | 14 ++++ src/customtrackview.h | 2 + src/kdenlivedoc.cpp | 131 ++++++++++++++++++++++++++++++++- src/kdenlivedoc.h | 8 +- src/kdenliveui.rc | 3 +- src/mainwindow.cpp | 61 ++++++++++++++- src/mainwindow.h | 8 ++ src/widgets/backupdialog_ui.ui | 88 ++++++++++++++++++++++ 9 files changed, 310 insertions(+), 6 deletions(-) create mode 100644 src/widgets/backupdialog_ui.ui diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f0072341..a17eec70 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -136,6 +136,7 @@ kde4_add_ui_files(kdenlive_UI widgets/monitoreditwidget_ui.ui widgets/archivewidget_ui.ui widgets/manageencodingprofile_ui.ui + widgets/backupdialog_ui.ui ) set(kdenlive_SRCS diff --git a/src/customtrackview.cpp b/src/customtrackview.cpp index ab56e401..6594e844 100644 --- a/src/customtrackview.cpp +++ b/src/customtrackview.cpp @@ -6693,3 +6693,17 @@ void CustomTrackView::adjustEffects(ClipItem* item, ItemInfo oldInfo, QUndoComma } } } + + +void CustomTrackView::saveTimelinePreview(const QString path) +{ + QRect viewrect = viewport()->rect(); + QImage img(viewrect.width(), viewrect.height(), QImage::Format_ARGB32_Premultiplied); + img.fill(palette().base().color().rgb()); + QPainter painter(&img); + render(&painter); + painter.end(); + img = img.scaledToWidth(600, Qt::SmoothTransformation); + img.save(path); +} + diff --git a/src/customtrackview.h b/src/customtrackview.h index 1de28076..0c47b3ef 100644 --- a/src/customtrackview.h +++ b/src/customtrackview.h @@ -267,6 +267,8 @@ public slots: * @param offsetList The list of points that should also snap (for example when movin a clip, start and end points should snap * @param skipSelectedItems if true, the selected item start and end points will not be added to snap list */ void updateSnapPoints(AbstractClipItem *selected, QList offsetList = QList (), bool skipSelectedItems = false); + /** @brief Save a snapshot image of current timeline view */ + void saveTimelinePreview(const QString path); protected: virtual void drawBackground(QPainter * painter, const QRectF & rect); diff --git a/src/kdenlivedoc.cpp b/src/kdenlivedoc.cpp index b33eccc3..7a4b9482 100644 --- a/src/kdenlivedoc.cpp +++ b/src/kdenlivedoc.cpp @@ -509,7 +509,7 @@ void KdenliveDoc::slotAutoSave() kDebug() << "ERROR; CANNOT CREATE AUTOSAVE FILE"; } kDebug() << "// AUTOSAVE FILE: " << m_autosave->fileName(); - saveSceneList(m_autosave->fileName(), m_render->sceneList(), QStringList()); + saveSceneList(m_autosave->fileName(), m_render->sceneList(), QStringList(), true); } } @@ -660,7 +660,7 @@ QDomDocument KdenliveDoc::xmlSceneList(const QString &scene, const QStringList e return sceneList; } -bool KdenliveDoc::saveSceneList(const QString &path, const QString &scene, const QStringList expandedFolders) +bool KdenliveDoc::saveSceneList(const QString &path, const QString &scene, const QStringList expandedFolders, bool autosave) { QDomDocument sceneList = xmlSceneList(scene, expandedFolders); if (sceneList.isNull()) { @@ -668,8 +668,11 @@ bool KdenliveDoc::saveSceneList(const QString &path, const QString &scene, const 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)); @@ -683,6 +686,9 @@ bool KdenliveDoc::saveSceneList(const QString &path, const QString &scene, const return false; } file.close(); + if (!autosave) { + cleanupBackupFiles(); + } return true; } @@ -1576,5 +1582,124 @@ double KdenliveDoc::getDisplayRatio(const QString &path) return 0; } +void KdenliveDoc::backupLastSavedVersion(const QString &path) +{ + // Ensure backup folder exists + 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(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() +{ + KUrl backupFile = m_projectFolder; + backupFile.addPath(".backup/"); + QDir dir(backupFile.path()); + QString projectFile = url().fileName().section('.', 0, -2); + 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: "< 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" diff --git a/src/kdenlivedoc.h b/src/kdenlivedoc.h index 3392519a..e3b914a7 100644 --- a/src/kdenlivedoc.h +++ b/src/kdenlivedoc.h @@ -115,7 +115,7 @@ Q_OBJECT public: /** @brief Returns the project file xml. */ QDomDocument xmlSceneList(const QString &scene, const QStringList expandedFolders); /** @brief Saves the project file xml to a file. */ - bool saveSceneList(const QString &path, const QString &scene, const QStringList expandedFolders); + bool saveSceneList(const QString &path, const QString &scene, const QStringList expandedFolders, bool autosave = false); int tracksCount() const; TrackInfo trackInfoAt(int ix) const; void insertTrack(int ix, TrackInfo type); @@ -161,6 +161,8 @@ Q_OBJECT public: QStringList getExpandedFolders(); /** @brief Read the display ratio from an xml project file. */ static double getDisplayRatio(const QString &path); + /** @brief Backup the project file */ + void backupLastSavedVersion(const QString &path); private: KUrl m_url; @@ -199,6 +201,8 @@ private: /** @brief Updates the project folder location entry in the kdenlive file dialogs to point to the current project folder. */ void updateProjectFolderPlacesEntry(); + /** @brief Only keep some backup files, delete some */ + void cleanupBackupFiles(); public slots: void slotCreateXmlClip(const QString &name, const QDomElement xml, QString group, const QString &groupId); @@ -234,6 +238,8 @@ signals: void docModified(bool); void selectLastAddedClip(const QString &); void guidesUpdated(); + /** @brief When creating a backup file, also save a thumbnail of current timeline */ + void saveTimelinePreview(const QString path); }; #endif diff --git a/src/kdenliveui.rc b/src/kdenliveui.rc index 5a7eb602..e676813c 100644 --- a/src/kdenliveui.rc +++ b/src/kdenliveui.rc @@ -1,6 +1,6 @@ - + Extra Toolbar @@ -49,6 +49,7 @@ + Tool diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 7ebd9990..f9918685 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -146,7 +146,8 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString & m_jogShuttle(NULL), #endif /* NO_JOGSHUTTLE */ m_findActivated(false), - m_stopmotion(NULL) + m_stopmotion(NULL), + m_backup_ui(NULL) { qRegisterMetaType > (); // Create DBus interface @@ -1161,6 +1162,10 @@ void MainWindow::setupActions() collection.addAction("project_settings", projectAction); connect(projectAction, SIGNAL(triggered(bool)), this, SLOT(slotEditProjectSettings())); + KAction* backupAction = new KAction(KIcon("edit-undo"), i18n("Open Backup File"), this); + collection.addAction("open_backup", backupAction); + connect(backupAction, SIGNAL(triggered(bool)), this, SLOT(slotOpenBackupDialog())); + KAction* projectRender = new KAction(KIcon("media-record"), i18n("Render"), this); collection.addAction("project_render", projectRender); projectRender->setShortcut(Qt::CTRL + Qt::Key_Return); @@ -2457,6 +2462,7 @@ void MainWindow::connectDocument(TrackView *trackView, KdenliveDoc *doc) //cha connect(doc, SIGNAL(docModified(bool)), this, SLOT(slotUpdateDocumentState(bool))); connect(doc, SIGNAL(guidesUpdated()), this, SLOT(slotGuidesUpdated())); + connect(doc, SIGNAL(saveTimelinePreview(const QString)), trackView->projectView(), SLOT(saveTimelinePreview(const QString))); connect(m_notesWidget, SIGNAL(textChanged()), doc, SLOT(setModified())); connect(trackView->projectView(), SIGNAL(clipItemSelected(ClipItem*, int, bool)), m_effectStack, SLOT(slotClipItemSelected(ClipItem*, int))); @@ -4259,6 +4265,59 @@ void MainWindow::slotArchiveProject() } +void MainWindow::slotOpenBackupDialog() +{ + QDialog *dia = new QDialog(this); + m_backup_ui = new Ui::BackupDialog_UI; + m_backup_ui->setupUi(dia); + dia->setWindowTitle(i18n("Backup Files")); + KUrl backupFile = m_activeDocument->projectFolder(); + backupFile.addPath(".backup/"); + QDir dir(backupFile.path()); + QString projectFile = m_activeDocument->url().fileName().section('.', 0, -2); + 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); + QStringList results; + QListWidgetItem *item; + for (int i = 0; i < resultList.count(); i++) { + item = new QListWidgetItem(resultList.at(i).lastModified().toString(Qt::DefaultLocaleLongDate), m_backup_ui->backup_list); + item->setData(Qt::UserRole, resultList.at(i).absoluteFilePath()); + } + connect(m_backup_ui->backup_list, SIGNAL(currentRowChanged(int)), this, SLOT(slotDisplayBackupPreview())); + m_backup_ui->backup_list->setCurrentRow(0); + m_backup_ui->backup_list->setMinimumHeight(QFontMetrics(font()).lineSpacing() * 12); + if (dia->exec() == QDialog::Accepted) { + QString requestedBackup = m_backup_ui->backup_list->currentItem()->data(Qt::UserRole).toString(); + KUrl currentUrl = m_activeDocument->url(); + m_activeDocument->backupLastSavedVersion(currentUrl.path()); + closeCurrentDocument(false); + doOpenFile(KUrl(requestedBackup), NULL); + m_activeDocument->setUrl(currentUrl); + setCaption(m_activeDocument->description()); + } + delete dia; + delete m_backup_ui; + m_backup_ui = NULL; +} + +void MainWindow::slotDisplayBackupPreview() +{ + QString path = m_backup_ui->backup_list->currentItem()->data(Qt::UserRole).toString(); + QPixmap pix(path + ".png"); + m_backup_ui->backup_preview->setPixmap(pix); +} + + #include "mainwindow.moc" #ifdef DEBUG_MAINW diff --git a/src/mainwindow.h b/src/mainwindow.h index f4d0d3b4..6bc6f7df 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -46,6 +46,7 @@ #include "dvdwizard.h" #include "stopmotion/stopmotion.h" #include "noteswidget.h" +#include "ui_backupdialog_ui.h" class KdenliveDoc; class TrackView; @@ -305,6 +306,9 @@ private: StopmotionWidget *m_stopmotion; + /** @brief UI for backup dialog. */ + Ui::BackupDialog_UI *m_backup_ui; + public slots: /** @brief Prepares opening @param url. * @@ -540,6 +544,10 @@ private slots: void slotUpdateProxySettings(); /** @brief Insert current project's timecode into the notes widget. */ void slotInsertNotesTimecode(); + /** @brief Open the project's backupdialog. */ + void slotOpenBackupDialog(); + /** @brief Display chosen backup thumbnail. */ + void slotDisplayBackupPreview(); signals: Q_SCRIPTABLE void abortRenderJob(const QString &url); }; diff --git a/src/widgets/backupdialog_ui.ui b/src/widgets/backupdialog_ui.ui new file mode 100644 index 00000000..0467ba73 --- /dev/null +++ b/src/widgets/backupdialog_ui.ui @@ -0,0 +1,88 @@ + + + BackupDialog_UI + + + + 0 + 0 + 485 + 216 + + + + Dialog + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Open + + + + + + + true + + + + + + + QFrame::Box + + + + + + + + + + + KListWidget + QListWidget +
klistwidget.h
+
+
+ + + + buttonBox + accepted() + BackupDialog_UI + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + BackupDialog_UI + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
-- 2.39.2