Fix possible crash because of uninitialized video profile or opening invalid file
svn path=/branches/KDE4/; revision=2387
#include "mainwindow.h"
-KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup *undoGroup, MainWindow *parent): QObject(parent), m_render(NULL), m_url(url), m_projectFolder(projectFolder), m_commandStack(new QUndoStack(undoGroup)), m_modified(false), m_documentLoadingProgress(0), m_documentLoadingStep(0.0), m_startPos(0), m_zoom(7) {
+KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup *undoGroup, const QString &profileName, MainWindow *parent): QObject(parent), m_render(NULL), m_url(url), m_projectFolder(projectFolder), m_commandStack(new QUndoStack(undoGroup)), m_modified(false), m_documentLoadingProgress(0), m_documentLoadingStep(0.0), m_startPos(0), m_zoom(7), m_autosave(NULL) {
m_clipManager = new ClipManager(this);
if (!url.isEmpty()) {
QString tmpFile;
m_document.removeChild(infoXmlNode);
kDebug() << "Reading file: " << url.path() << ", found clips: " << producers.count();
- } else kWarning() << " NO KDENLIVE INFO FOUND IN FILE: " << url.path();
+ } else {
+ parent->slotGotProgressInfo(i18n("File %1 is not a Kdenlive project file."), 100);
+ kWarning() << " NO KDENLIVE INFO FOUND IN FILE: " << url.path();
+ m_document = createEmptyDocument();
+ setProfilePath(profileName);
+ }
KIO::NetAccess::removeTempFile(tmpFile);
} else {
KMessageBox::error(parent, KIO::NetAccess::lastErrorString());
+ parent->slotGotProgressInfo(i18n("File %1 is not a Kdenlive project file."), 100);
+ m_document = createEmptyDocument();
+ setProfilePath(profileName);
}
} else {
- // Creating new document
- QDomElement westley = m_document.createElement("westley");
- m_document.appendChild(westley);
-
- QDomElement tractor = m_document.createElement("tractor");
- tractor.setAttribute("id", "maintractor");
- QDomElement multitrack = m_document.createElement("multitrack");
- QDomElement playlist = m_document.createElement("playlist");
- playlist.setAttribute("id", "black_track");
- westley.appendChild(playlist);
-
-
- // create playlists
- int audiotracks = 2;
- int videotracks = 3;
- int total = audiotracks + videotracks + 1;
-
- for (int i = 1; i < total; i++) {
- QDomElement playlist = m_document.createElement("playlist");
- playlist.setAttribute("id", "playlist" + QString::number(i));
- westley.appendChild(playlist);
- }
-
- QDomElement track0 = m_document.createElement("track");
- track0.setAttribute("producer", "black_track");
- tractor.appendChild(track0);
-
- // create audio tracks
- for (int i = 1; i < audiotracks + 1; i++) {
- QDomElement track = m_document.createElement("track");
- track.setAttribute("producer", "playlist" + QString::number(i));
- track.setAttribute("hide", "video");
- tractor.appendChild(track);
- }
-
- // create video tracks
- for (int i = audiotracks + 1; i < total; i++) {
- QDomElement track = m_document.createElement("track");
- track.setAttribute("producer", "playlist" + QString::number(i));
- tractor.appendChild(track);
- }
-
- for (uint i = 2; i < total ; i++) {
- QDomElement transition = m_document.createElement("transition");
- transition.setAttribute("always_active", "1");
-
- QDomElement property = m_document.createElement("property");
- property.setAttribute("name", "a_track");
- QDomText value = m_document.createTextNode(QString::number(1));
- property.appendChild(value);
- transition.appendChild(property);
-
- property = m_document.createElement("property");
- property.setAttribute("name", "b_track");
- value = m_document.createTextNode(QString::number(i));
- property.appendChild(value);
- transition.appendChild(property);
-
- property = m_document.createElement("property");
- property.setAttribute("name", "mlt_service");
- value = m_document.createTextNode("mix");
- property.appendChild(value);
- transition.appendChild(property);
-
- property = m_document.createElement("property");
- property.setAttribute("name", "combine");
- value = m_document.createTextNode("1");
- property.appendChild(value);
- transition.appendChild(property);
-
- property = m_document.createElement("property");
- property.setAttribute("name", "internal_added");
- value = m_document.createTextNode("237");
- property.appendChild(value);
- transition.appendChild(property);
- tractor.appendChild(transition);
- }
- westley.appendChild(tractor);
+ m_document = createEmptyDocument();
+ setProfilePath(profileName);
}
m_scenelist = m_document.toString();
kDebug() << "KDEnnlive document, init timecode: " << m_fps;
m_autoSaveTimer = new QTimer(this);
m_autoSaveTimer->setSingleShot(true);
- QString directory = m_url.directory();
- QString fileName = m_url.fileName();
- m_recoveryUrl.setDirectory(directory);
- m_recoveryUrl.setFileName("~" + fileName);
connect(m_autoSaveTimer, SIGNAL(timeout()), this, SLOT(slotAutoSave()));
}
delete m_commandStack;
delete m_clipManager;
delete m_autoSaveTimer;
- if (!m_url.isEmpty()) {
- // remove backup file
- if (KIO::NetAccess::exists(m_recoveryUrl, KIO::NetAccess::SourceSide, NULL))
- KIO::NetAccess::del(m_recoveryUrl, NULL);
+ m_autosave->remove();
+}
+
+QDomDocument KdenliveDoc::createEmptyDocument() {
+ // Creating new document
+ QDomDocument doc;
+ QDomElement westley = doc.createElement("westley");
+ doc.appendChild(westley);
+
+ QDomElement tractor = doc.createElement("tractor");
+ tractor.setAttribute("id", "maintractor");
+ QDomElement multitrack = doc.createElement("multitrack");
+ QDomElement playlist = doc.createElement("playlist");
+ playlist.setAttribute("id", "black_track");
+ westley.appendChild(playlist);
+
+
+ // create playlists
+ const int audiotracks = 2;
+ const int videotracks = 3;
+ int total = audiotracks + videotracks + 1;
+
+ for (int i = 1; i < total; i++) {
+ QDomElement playlist = doc.createElement("playlist");
+ playlist.setAttribute("id", "playlist" + QString::number(i));
+ westley.appendChild(playlist);
}
+
+ QDomElement track0 = doc.createElement("track");
+ track0.setAttribute("producer", "black_track");
+ tractor.appendChild(track0);
+
+ // create audio tracks
+ for (int i = 1; i < audiotracks + 1; i++) {
+ QDomElement track = doc.createElement("track");
+ track.setAttribute("producer", "playlist" + QString::number(i));
+ track.setAttribute("hide", "video");
+ tractor.appendChild(track);
+ }
+
+ // create video tracks
+ for (int i = audiotracks + 1; i < total; i++) {
+ QDomElement track = doc.createElement("track");
+ track.setAttribute("producer", "playlist" + QString::number(i));
+ tractor.appendChild(track);
+ }
+
+ for (uint i = 2; i < total ; i++) {
+ QDomElement transition = doc.createElement("transition");
+ transition.setAttribute("always_active", "1");
+
+ QDomElement property = doc.createElement("property");
+ property.setAttribute("name", "a_track");
+ QDomText value = doc.createTextNode(QString::number(1));
+ property.appendChild(value);
+ transition.appendChild(property);
+
+ property = doc.createElement("property");
+ property.setAttribute("name", "b_track");
+ value = doc.createTextNode(QString::number(i));
+ property.appendChild(value);
+ transition.appendChild(property);
+
+ property = doc.createElement("property");
+ property.setAttribute("name", "mlt_service");
+ value = doc.createTextNode("mix");
+ property.appendChild(value);
+ transition.appendChild(property);
+
+ property = doc.createElement("property");
+ property.setAttribute("name", "combine");
+ value = doc.createTextNode("1");
+ property.appendChild(value);
+ transition.appendChild(property);
+
+ property = doc.createElement("property");
+ property.setAttribute("name", "internal_added");
+ value = doc.createTextNode("237");
+ property.appendChild(value);
+ transition.appendChild(property);
+ tractor.appendChild(transition);
+ }
+ westley.appendChild(tractor);
+ return doc;
}
+
void KdenliveDoc::syncGuides(QList <Guide *> guides) {
QDomDocument doc;
QDomElement e;
}
void KdenliveDoc::slotAutoSave() {
- if (m_render)
- m_render->saveSceneList(m_recoveryUrl.path(), documentInfoXml());
-
+ if (m_render) {
+ if (!m_autosave->isOpen() && !m_autosave->open(QIODevice::ReadWrite)) {
+ // show error: could not open the autosave file
+ kDebug() << "ERROR; CANNOT CREATE AUTOSAVE FILE";
+ }
+ kDebug() << "// AUTOSAVE FILE: " << m_autosave->fileName();
+ m_render->saveSceneList(m_autosave->fileName(), documentInfoXml());
+ }
}
void KdenliveDoc::setZoom(int factor) {
void KdenliveDoc::setUrl(KUrl url) {
m_url = url;
- QString directory = m_url.directory();
- QString fileName = m_url.fileName();
- m_recoveryUrl.setDirectory(directory);
- m_recoveryUrl.setFileName("~" + fileName);
}
void KdenliveDoc::setModified(bool mod) {
#include <QTimer>
#include <KUrl>
+#include <kautosavefile.h>
#include "gentime.h"
#include "timecode.h"
class KdenliveDoc: public QObject {
Q_OBJECT public:
- KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup *undoGroup, MainWindow *parent = 0);
+ KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup *undoGroup, const QString &profileName, MainWindow *parent = 0);
~KdenliveDoc();
QDomNodeList producersList();
double fps() const;
int width() const;
int height() const;
KUrl url() const;
+ KAutoSaveFile *m_autosave;
void backupMltPlaylist();
Timecode timecode() const;
QDomDocument toXml() const;
private:
KUrl m_url;
- KUrl m_recoveryUrl;
QDomDocument m_document;
QString m_projectName;
double m_fps;
double m_documentLoadingStep;
double m_documentLoadingProgress;
void convertDocument(double version);
+ QDomDocument createEmptyDocument();
public slots:
void slotCreateTextClip(QString group, const QString &groupId);
if (KdenliveSettings::openlastproject()) {
openLastFile();
- } else newFile();
+ } else {
+ /*QList<KAutoSaveFile *> staleFiles = KAutoSaveFile::allStaleFiles();
+ if (!staleFiles.isEmpty()) {
+ if (KMessageBox::questionYesNo(this, i18n("Auto-saved files exist. Do you want to recover them now?"), i18n("File Recovery"), KGuiItem(i18n("Recover")), KGuiItem(i18n("Don't recover"))) == KMessageBox::Yes) {
+ recoverFiles(staleFiles);
+ }
+ else newFile();
+ }
+ else*/
+ newFile();
+ }
activateShuttleDevice();
projectListDock->raise();
void MainWindow::slotConnectMonitors() {
m_projectList->setRenderer(m_clipMonitor->render);
- connect(m_projectList, SIGNAL(receivedClipDuration(int, int)), this, SLOT(slotSetClipDuration(int, int)));
+ connect(m_projectList, SIGNAL(receivedClipDuration(const QString &, int)), this, SLOT(slotSetClipDuration(const QString &, int)));
connect(m_projectList, SIGNAL(showClipProperties(DocClipBase *)), this, SLOT(slotShowClipProperties(DocClipBase *)));
connect(m_projectList, SIGNAL(getFileProperties(const QDomElement &, const QString &)), m_clipMonitor->render, SLOT(getFileProperties(const QDomElement &, const QString &)));
connect(m_clipMonitor->render, SIGNAL(replyGetImage(const QString &, int, const QPixmap &, int, int)), m_projectList, SLOT(slotReplyGetImage(const QString &, int, const QPixmap &, int, int)));
projectFolder = w->selectedFolder();
delete w;
}
- KdenliveDoc *doc = new KdenliveDoc(KUrl(), projectFolder, m_commandStack, this);
- doc->setProfilePath(profileName);
+ KdenliveDoc *doc = new KdenliveDoc(KUrl(), projectFolder, m_commandStack, profileName, this);
+ doc->m_autosave = new KAutoSaveFile(KUrl(), doc);
TrackView *trackView = new TrackView(doc, this);
m_timelineArea->addTab(trackView, KIcon("kdenlive"), doc->description());
if (m_timelineArea->count() == 1) {
void MainWindow::saveFileAs(const QString &outputFileName) {
m_projectMonitor->saveSceneList(outputFileName, m_activeDocument->documentInfoXml());
m_activeDocument->setUrl(KUrl(outputFileName));
+ if (m_activeDocument->m_autosave == NULL) {
+ m_activeDocument->m_autosave = new KAutoSaveFile(KUrl(outputFileName), this);
+ } else m_activeDocument->m_autosave->setManagedFile(KUrl(outputFileName));
setCaption(m_activeDocument->description());
m_timelineArea->setTabText(m_timelineArea->currentIndex(), m_activeDocument->description());
m_timelineArea->setTabToolTip(m_timelineArea->currentIndex(), m_activeDocument->url().path());
saveFileAs();
} else {
saveFileAs(m_activeDocument->url().path());
+ m_activeDocument->m_autosave->resize(0);
}
}
void MainWindow::openFile(const KUrl &url) {
// Check for backup file
- bool recovery = false;
- QString directory = url.directory();
- QString fileName = url.fileName();
- KUrl recoveryUrl;
- recoveryUrl.setDirectory(directory);
- recoveryUrl.setFileName("~" + fileName);
- if (KIO::NetAccess::exists(recoveryUrl, KIO::NetAccess::SourceSide, this)) {
- KFileItem bkup(KFileItem::Unknown, KFileItem::Unknown, recoveryUrl, true);
- KFileItem src(KFileItem::Unknown, KFileItem::Unknown, url, true);
- if (bkup.time(KFileItem::ModificationTime) > src.time(KFileItem::ModificationTime)) {
- // Backup file is more recent than source file, ask user for recovery
- if (KMessageBox::questionYesNo(this, i18n("A newer recovery file exists for <b>%1</b>\nOpen recovery file ?", url.fileName())) == KMessageBox::Yes) recovery = true;
+
+ QList<KAutoSaveFile *> staleFiles = KAutoSaveFile::staleFiles(url);
+ if (!staleFiles.isEmpty()) {
+ if (KMessageBox::questionYesNo(this,
+ i18n("Auto-saved files exist. Do you want to recover them now?"),
+ i18n("File Recovery"),
+ KGuiItem(i18n("Recover")), KGuiItem(i18n("Don't recover"))) == KMessageBox::Yes) {
+ recoverFiles(staleFiles);
+ return;
+ } else {
+ // remove the stale files
+ foreach(KAutoSaveFile *stale, staleFiles) {
+ stale->open(QIODevice::ReadWrite);
+ delete stale;
+ }
}
}
+ doOpenFile(url, NULL);
+}
- //TODO: get video profile from url before opening it
- /*MltVideoProfile prof = ProfilesDialog::getVideoProfile(KdenliveSettings::default_profile());
- if (prof.width == 0) prof = ProfilesDialog::getVideoProfile("dv_pal");
-
- KdenliveSettings::setCurrent_profile(prof.path);*/
+void MainWindow::doOpenFile(const KUrl &url, KAutoSaveFile *stale) {
KdenliveDoc *doc;
- if (recovery) {
- doc = new KdenliveDoc(recoveryUrl, KUrl(), m_commandStack, this);
- doc->setUrl(url);
+ doc = new KdenliveDoc(url, KUrl(), m_commandStack, QString(), this);
+ if (stale == NULL) {
+ stale = new KAutoSaveFile(url, doc);
+ doc->m_autosave = stale;
+ } else {
+ doc->m_autosave = stale;
+ doc->setUrl(stale->managedFile());
doc->setModified(true);
- } else doc = new KdenliveDoc(url, KUrl(), m_commandStack, this);
+ stale->setParent(doc);
+ }
connectDocumentInfo(doc);
TrackView *trackView = new TrackView(doc, this);
m_timelineArea->setCurrentIndex(m_timelineArea->addTab(trackView, KIcon("kdenlive"), doc->description()));
m_projectMonitor->refreshMonitor(true);
}
+void MainWindow::recoverFiles(QList<KAutoSaveFile *> staleFiles) {
+ foreach(KAutoSaveFile *stale, staleFiles) {
+ /*if (!stale->open(QIODevice::QIODevice::ReadOnly)) {
+ // show an error message; we could not steal the lockfile
+ // maybe another application got to the file before us?
+ delete stale;
+ continue;
+ }*/
+ kDebug() << "// OPENING RECOVERY: " << stale->fileName() << "\nMANAGED: " << stale->managedFile().path();
+ // the stalefiles also contain ".lock" files so we must ignore them... bug in KAutoSaveFile ?
+ if (!stale->fileName().endsWith(".lock")) doOpenFile(KUrl(stale->fileName()), stale);
+ else KIO::NetAccess::del(KUrl(stale->fileName()), this);
+ }
+}
+
void MainWindow::parseProfiles() {
//kdDebug()<<" + + YOUR MLT INSTALL WAS FOUND IN: "<< MLT_PREFIX <<endl;
KdenliveSettings::setCurrent_profile(profile);
KdenliveSettings::setProject_fps(m_activeDocument->fps());
setCaption(m_activeDocument->description());
- m_monitorManager->resetProfiles();
+ m_monitorManager->resetProfiles(m_activeDocument->timecode());
if (m_renderWidget) m_renderWidget->setDocumentStandard(m_activeDocument->getDocumentStandard());
- m_monitorManager->setTimecode(m_activeDocument->timecode());
m_timelineArea->setTabText(m_timelineArea->currentIndex(), m_activeDocument->description());
// We need to desactivate & reactivate monitors to get a refresh
}
KdenliveSettings::setCurrent_profile(doc->profilePath());
KdenliveSettings::setProject_fps(doc->fps());
- m_monitorManager->resetProfiles();
+ m_monitorManager->resetProfiles(doc->timecode());
m_projectList->setDocument(doc);
connect(m_projectList, SIGNAL(clipSelected(DocClipBase *)), m_clipMonitor, SLOT(slotSetXml(DocClipBase *)));
connect(trackView, SIGNAL(cursorMoved()), m_projectMonitor, SLOT(activateMonitor()));
trackView->projectView()->setContextMenu(m_timelineContextMenu, m_timelineContextClipMenu, m_timelineContextTransitionMenu);
m_activeTimeline = trackView;
if (m_renderWidget) m_renderWidget->setDocumentStandard(doc->getDocumentStandard());
- m_monitorManager->setTimecode(doc->timecode());
doc->setRenderer(m_projectMonitor->render);
m_commandStack->setActiveStack(doc->commandStack());
KdenliveSettings::setProject_display_ratio(doc->dar());
// create it :
KdenliveSettingsDialog* dialog = new KdenliveSettingsDialog(this);
connect(dialog, SIGNAL(settingsChanged(const QString&)), this, SLOT(updateConfiguration()));
- connect(dialog, SIGNAL(doResetProfile()), m_monitorManager, SLOT(resetProfiles()));
+ connect(dialog, SIGNAL(doResetProfile()), m_monitorManager, SLOT(slotResetProfiles()));
dialog->show();
if (page != -1) dialog->showPage(page, option);
}
#include <KUndoStack>
#include <KRecentFilesAction>
#include <KComboBox>
+#include <kautosavefile.h>
#include "effectslist.h"
#include "gentime.h"
void slotShuttleAction(int code);
void connectDocumentInfo(KdenliveDoc *doc);
void findAhead();
+ void doOpenFile(const KUrl &url, KAutoSaveFile *stale);
+ void recoverFiles(QList<KAutoSaveFile *> staleFiles);
public slots:
void openFile(const KUrl &url);
: QObject(parent) {
}
-void MonitorManager::setTimecode(Timecode tc) {
- m_timecode = tc;
-}
-
Timecode MonitorManager::timecode() {
return m_timecode;
}
else m_projectMonitor->slotEnd();
}
-void MonitorManager::resetProfiles() {
+void MonitorManager::resetProfiles(Timecode tc) {
+ m_timecode = tc;
+ slotResetProfiles();
+}
+
+void MonitorManager::slotResetProfiles() {
activateMonitor("clip");
m_clipMonitor->resetProfile();
activateMonitor("project");
MonitorManager(QWidget *parent = 0);
void initMonitors(Monitor *clipMonitor, Monitor *projectMonitor);
Timecode timecode();
- void setTimecode(Timecode tc);
void switchMonitors();
bool projectMonitorFocused();
+ void resetProfiles(Timecode tc);
public slots:
void activateMonitor(QString name = QString::null);
void slotForwardOneFrame();
void slotStart();
void slotEnd();
- void resetProfiles();
+ void slotResetProfiles();
private:
Monitor *m_clipMonitor;