X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Farchivewidget.cpp;h=363781df6423abef52f85f0cde8c52e71ce24da4;hb=908927829e52521336659b61364e9cfd06595b86;hp=78692d354cd0356a76e38eb6410250447ff32170;hpb=b10fa39bf67665a52d9d8ac49e1649748b89c27f;p=kdenlive diff --git a/src/archivewidget.cpp b/src/archivewidget.cpp index 78692d35..363781df 100644 --- a/src/archivewidget.cpp +++ b/src/archivewidget.cpp @@ -26,56 +26,71 @@ #include #include #include -#include +#include #include - +#include #include +#include +#include + #include +#include #include "projectsettings.h" -ArchiveWidget::ArchiveWidget(QDomDocument doc, QList list, QStringList luma_list, QWidget * parent) : +ArchiveWidget::ArchiveWidget(QString projectName, QDomDocument doc, QList list, QStringList luma_list, QWidget * parent) : QDialog(parent), m_requestedSize(0), m_copyJob(NULL), - m_doc(doc) + m_name(projectName.section('.', 0, -2)), + m_doc(doc), + m_abortArchive(false), + m_extractMode(false), + m_extractArchive(NULL) { + setAttribute(Qt::WA_DeleteOnClose); setupUi(this); setWindowTitle(i18n("Archive Project")); archive_url->setUrl(KUrl(QDir::homePath())); connect(archive_url, SIGNAL(textChanged (const QString &)), this, SLOT(slotCheckSpace())); - + connect(this, SIGNAL(archivingFinished(bool)), this, SLOT(slotArchivingFinished(bool))); + connect(this, SIGNAL(archiveProgress(int)), this, SLOT(slotArchivingProgress(int))); // Setup categories QTreeWidgetItem *videos = new QTreeWidgetItem(files_list, QStringList() << i18n("Video clips")); videos->setIcon(0, KIcon("video-x-generic")); - videos->setData(0, Qt::UserRole, i18n("videos")); + videos->setData(0, Qt::UserRole, "videos"); videos->setExpanded(false); QTreeWidgetItem *sounds = new QTreeWidgetItem(files_list, QStringList() << i18n("Audio clips")); sounds->setIcon(0, KIcon("audio-x-generic")); - sounds->setData(0, Qt::UserRole, i18n("sounds")); + sounds->setData(0, Qt::UserRole, "sounds"); sounds->setExpanded(false); QTreeWidgetItem *images = new QTreeWidgetItem(files_list, QStringList() << i18n("Image clips")); images->setIcon(0, KIcon("image-x-generic")); - images->setData(0, Qt::UserRole, i18n("images")); + images->setData(0, Qt::UserRole, "images"); images->setExpanded(false); QTreeWidgetItem *slideshows = new QTreeWidgetItem(files_list, QStringList() << i18n("Slideshow clips")); slideshows->setIcon(0, KIcon("image-x-generic")); - slideshows->setData(0, Qt::UserRole, i18n("slideshows")); + slideshows->setData(0, Qt::UserRole, "slideshows"); slideshows->setExpanded(false); QTreeWidgetItem *texts = new QTreeWidgetItem(files_list, QStringList() << i18n("Text clips")); texts->setIcon(0, KIcon("text-plain")); - texts->setData(0, Qt::UserRole, i18n("texts")); + texts->setData(0, Qt::UserRole, "texts"); texts->setExpanded(false); QTreeWidgetItem *others = new QTreeWidgetItem(files_list, QStringList() << i18n("Other clips")); others->setIcon(0, KIcon("unknown")); - others->setData(0, Qt::UserRole, i18n("others")); + others->setData(0, Qt::UserRole, "others"); others->setExpanded(false); QTreeWidgetItem *lumas = new QTreeWidgetItem(files_list, QStringList() << i18n("Luma files")); lumas->setIcon(0, KIcon("image-x-generic")); - lumas->setData(0, Qt::UserRole, i18n("lumas")); + lumas->setData(0, Qt::UserRole, "lumas"); lumas->setExpanded(false); - + + QTreeWidgetItem *proxies = new QTreeWidgetItem(files_list, QStringList() << i18n("Proxy clips")); + proxies->setIcon(0, KIcon("video-x-generic")); + proxies->setData(0, Qt::UserRole, "proxy"); + proxies->setExpanded(false); + // process all files QStringList allFonts; KUrl::List fileUrls; @@ -87,36 +102,43 @@ ArchiveWidget::ArchiveWidget(QDomDocument doc, QList list, QStrin QStringList videoUrls; QStringList imageUrls; QStringList otherUrls; + QStringList proxyUrls; for (int i = 0; i < list.count(); i++) { DocClipBase *clip = list.at(i); - if (clip->clipType() == SLIDESHOW) { - QStringList subfiles = ProjectSettings::extractSlideshowUrls(clip->fileURL()); - foreach(const QString & file, subfiles) { - kDebug()<<"SLIDE: "<fileURL().isEmpty()) { - if (clip->clipType() == AUDIO) audioUrls << clip->fileURL().path(); - else videoUrls << clip->fileURL().path(); + CLIPTYPE t = clip->clipType(); + if (t == SLIDESHOW) { + KUrl slideUrl = clip->fileURL(); + //TODO: Slideshow files + slideUrls << slideUrl.path(); } - if (clip->clipType() == TEXT) { + else if (t == IMAGE) imageUrls << clip->fileURL().path(); + else if (t == TEXT) { QStringList imagefiles = TitleWidget::extractImageList(clip->getProperty("xmldata")); QStringList fonts = TitleWidget::extractFontList(clip->getProperty("xmldata")); imageUrls << imagefiles; allFonts << fonts; - } else if (clip->clipType() == PLAYLIST) { + } else if (t == PLAYLIST) { QStringList files = ProjectSettings::extractPlaylistUrls(clip->fileURL().path()); otherUrls << files; } + else if (!clip->fileURL().isEmpty()) { + if (t == AUDIO) audioUrls << clip->fileURL().path(); + else { + videoUrls << clip->fileURL().path(); + // Check if we have a proxy + QString proxy = clip->getProperty("proxy"); + if (!proxy.isEmpty() && proxy != "-" && QFile::exists(proxy)) proxyUrls << proxy; + } + } } generateItems(sounds, audioUrls); generateItems(videos, videoUrls); generateItems(images, imageUrls); - //generateItems(slideshows, slideUrls); + generateItems(slideshows, slideUrls); generateItems(others, otherUrls); + generateItems(proxies, proxyUrls); #if QT_VERSION >= 0x040500 allFonts.removeDuplicates(); @@ -127,17 +149,26 @@ ArchiveWidget::ArchiveWidget(QDomDocument doc, QList list, QStrin // Hide unused categories, add item count int total = 0; for (int i = 0; i < files_list->topLevelItemCount(); i++) { - int items = files_list->topLevelItem(i)->childCount(); + QTreeWidgetItem *parentItem = files_list->topLevelItem(i); + int items = parentItem->childCount(); if (items == 0) { files_list->topLevelItem(i)->setHidden(true); } else { - total += items; - files_list->topLevelItem(i)->setText(0, files_list->topLevelItem(i)->text(0) + " " + i18n("(%1 items)", items)); + if (parentItem->data(0, Qt::UserRole).toString() == "slideshows") + { + // Special case: slideshows contain several files + for (int j = 0; j < items; j++) { + total += parentItem->child(j)->data(0, Qt::UserRole + 1).toStringList().count(); + } + } + else total += items; + parentItem->setText(0, files_list->topLevelItem(i)->text(0) + " " + i18np("(%1 item)", "(%1 items)", items)); } } - - project_files->setText(i18n("%1 files to archive, requires %2", total, KIO::convertSize(m_requestedSize))); + if (m_name.isEmpty()) m_name = i18n("Untitled"); + compressed_archive->setText(compressed_archive->text() + " (" + m_name + ".tar.gz)"); + project_files->setText(i18np("%1 file to archive, requires %2", "%1 files to archive, requires %2", total, KIO::convertSize(m_requestedSize))); buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Archive")); connect(buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(slotStartArchiving())); buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false); @@ -145,18 +176,150 @@ ArchiveWidget::ArchiveWidget(QDomDocument doc, QList list, QStrin slotCheckSpace(); } +// Constructor for extract widget +ArchiveWidget::ArchiveWidget(const KUrl &url, QWidget * parent): + QDialog(parent), + m_extractMode(true), + m_extractUrl(url) +{ + //setAttribute(Qt::WA_DeleteOnClose); + + setupUi(this); + connect(this, SIGNAL(extractingFinished()), this, SLOT(slotExtractingFinished())); + connect(this, SIGNAL(showMessage(const QString &, const QString &)), this, SLOT(slotDisplayMessage(const QString &, const QString &))); + + compressed_archive->setHidden(true); + project_files->setHidden(true); + files_list->setHidden(true); + label->setText(i18n("Extract to")); + setWindowTitle(i18n("Open Archived Project")); + archive_url->setUrl(KUrl(QDir::homePath())); + buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Extract")); + connect(buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(slotStartExtracting())); + buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false); + adjustSize(); + m_archiveThread = QtConcurrent::run(this, &ArchiveWidget::openArchiveForExtraction); +} + + ArchiveWidget::~ArchiveWidget() { + if (m_extractArchive) delete m_extractArchive; +} + +void ArchiveWidget::slotDisplayMessage(const QString &icon, const QString &text) +{ + icon_info->setPixmap(KIcon(icon).pixmap(16, 16)); + text_info->setText(text); +} + +void ArchiveWidget::openArchiveForExtraction() +{ + emit showMessage("system-run", i18n("Opening archive...")); + m_extractArchive = new KTar(m_extractUrl.path()); + if (!m_extractArchive->isOpen() && !m_extractArchive->open( QIODevice::ReadOnly )) { + emit showMessage("dialog-close", i18n("Cannot open archive file:\n %1", m_extractUrl.path())); + groupBox->setEnabled(false); + return; + } + + // Check that it is a kdenlive project archive + bool isProjectArchive = false; + QStringList files = m_extractArchive->directory()->entries(); + for (int i = 0; i < files.count(); i++) { + if (files.at(i).endsWith(".kdenlive")) { + m_projectName = files.at(i); + isProjectArchive = true; + break; + } + } + + if (!isProjectArchive) { + emit showMessage("dialog-close", i18n("File %1\n is not an archived Kdenlive project", m_extractUrl.path())); + groupBox->setEnabled(false); + return; + } + buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true); + emit showMessage("dialog-ok", i18n("Ready")); +} + +void ArchiveWidget::done ( int r ) +{ + if (closeAccepted()) QDialog::done(r); +} + +void ArchiveWidget::closeEvent ( QCloseEvent * e ) +{ + + if (closeAccepted()) e->accept(); + else e->ignore(); } + +bool ArchiveWidget::closeAccepted() +{ + if (!m_extractMode && !archive_url->isEnabled()) { + // Archiving in progress, should we stop? + if (KMessageBox::warningContinueCancel(this, i18n("Archiving in progress, do you want to stop it?"), i18n("Stop Archiving"), KGuiItem(i18n("Stop Archiving"))) != KMessageBox::Continue) { + return false; + } + if (m_copyJob) m_copyJob->kill(); + } + return true; +} + + void ArchiveWidget::generateItems(QTreeWidgetItem *parentItem, QStringList items) { QStringList filesList; QString fileName; + int ix = 0; + bool isSlideshow = parentItem->data(0, Qt::UserRole).toString() == "slideshows"; foreach(const QString & file, items) { QTreeWidgetItem *item = new QTreeWidgetItem(parentItem, QStringList() << file); fileName = KUrl(file).fileName(); - if (filesList.contains(fileName)) { + if (isSlideshow) { + // we store each slideshow in a separate subdirectory + item->setData(0, Qt::UserRole, ix); + ix++; + KUrl slideUrl(file); + QDir dir(slideUrl.directory(KUrl::AppendTrailingSlash)); + if (slideUrl.fileName().startsWith(".all.")) { + // mimetype slideshow (for example *.png) + QStringList filters; + QString extension; + // TODO: improve jpeg image detection with extension like jpeg, requires change in MLT image producers + filters << "*." + slideUrl.fileName().section('.', -1); + dir.setNameFilters(filters); + QFileInfoList resultList = dir.entryInfoList(QDir::Files); + QStringList slideImages; + for (int i = 0; i < resultList.count(); i++) { + m_requestedSize += resultList.at(i).size(); + slideImages << resultList.at(i).absoluteFilePath(); + } + item->setData(0, Qt::UserRole + 1, slideImages); + } + else { + // pattern url (like clip%.3d.png) + QStringList result = dir.entryList(QDir::Files); + QString filter = slideUrl.fileName(); + QString ext = filter.section('.', -1); + filter = filter.section('%', 0, -2); + QString regexp = "^" + filter + "\\d+\\." + ext + "$"; + QRegExp rx(regexp); + QStringList slideImages; + QString directory = dir.absolutePath(); + if (!directory.endsWith('/')) directory.append('/'); + foreach(const QString & path, result) { + if (rx.exactMatch(path)) { + m_requestedSize += QFileInfo(directory + path).size(); + slideImages << directory + path; + } + } + item->setData(0, Qt::UserRole + 1, slideImages); + } + } + else if (filesList.contains(fileName)) { // we have 2 files with same name int ix = 0; QString newFileName = fileName.section('.', 0, -2) + "_" + QString::number(ix) + "." + fileName.section('.', -1); @@ -167,8 +330,10 @@ void ArchiveWidget::generateItems(QTreeWidgetItem *parentItem, QStringList items fileName = newFileName; item->setData(0, Qt::UserRole, fileName); } - filesList << fileName; - m_requestedSize += QFileInfo(file).size(); + if (!isSlideshow) { + m_requestedSize += QFileInfo(file).size(); + filesList << fileName; + } } } @@ -179,72 +344,122 @@ void ArchiveWidget::slotCheckSpace() if (freeSize > m_requestedSize) { // everything is ok buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true); - icon_info->setPixmap(KIcon("dialog-ok").pixmap(16, 16)); - text_info->setText(i18n("Available space on drive: %1", KIO::convertSize(freeSize))); + slotDisplayMessage("dialog-ok", i18n("Available space on drive: %1", KIO::convertSize(freeSize))); } else { buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false); - icon_info->setPixmap(KIcon("dialog-close").pixmap(16, 16)); - text_info->setText(i18n("Not enough space on drive, free space: %1", KIO::convertSize(freeSize))); + slotDisplayMessage("dialog-close", i18n("Not enough space on drive, free space: %1", KIO::convertSize(freeSize))); } } bool ArchiveWidget::slotStartArchiving(bool firstPass) { - if (firstPass && m_copyJob) { + if (firstPass && (m_copyJob || m_archiveThread.isRunning())) { // archiving in progress, abort - m_copyJob->kill(KJob::EmitResult); + if (m_copyJob) m_copyJob->kill(KJob::EmitResult); + m_abortArchive = true; return true; } + bool isArchive = compressed_archive->isChecked(); if (!firstPass) m_copyJob = NULL; else { //starting archiving + m_abortArchive = false; m_duplicateFiles.clear(); m_replacementList.clear(); + m_foldersList.clear(); + m_filesList.clear(); + slotDisplayMessage("system-run", i18n("Archiving...")); + repaint(); + archive_url->setEnabled(false); + compressed_archive->setEnabled(false); } KUrl::List files; KUrl destUrl; + QString destPath; + QTreeWidgetItem *parentItem; + bool isSlideshow = false; for (int i = 0; i < files_list->topLevelItemCount(); i++) { - if (files_list->topLevelItem(i)->childCount() > 0 && !files_list->topLevelItem(i)->isDisabled()) { - files_list->setCurrentItem(files_list->topLevelItem(i)); - files_list->topLevelItem(i)->setDisabled(true); - destUrl = KUrl(archive_url->url().path(KUrl::AddTrailingSlash) + files_list->topLevelItem(i)->data(0, Qt::UserRole).toString()); - KIO::NetAccess::mkdir(destUrl, this); + parentItem = files_list->topLevelItem(i); + if (parentItem->childCount() > 0 && !parentItem->isDisabled()) { + if (parentItem->data(0, Qt::UserRole).toString() == "slideshows") { + KUrl slideFolder(archive_url->url().path(KUrl::AddTrailingSlash) + "slideshows"); + if (isArchive) m_foldersList.append("slideshows"); + else KIO::NetAccess::mkdir(slideFolder, this); + isSlideshow = true; + } + files_list->setCurrentItem(parentItem); + if (!isSlideshow) parentItem->setDisabled(true); + destPath = parentItem->data(0, Qt::UserRole).toString() + "/"; + destUrl = KUrl(archive_url->url().path(KUrl::AddTrailingSlash) + destPath); QTreeWidgetItem *item; - for (int j = 0; j < files_list->topLevelItem(i)->childCount(); j++) { - item = files_list->topLevelItem(i)->child(j); - if (item->data(0, Qt::UserRole).isNull()) { + for (int j = 0; j < parentItem->childCount(); j++) { + item = parentItem->child(j); + // Special case: slideshows + if (isSlideshow) { + if (item->isDisabled()) { + continue; + } + destPath.append(item->data(0, Qt::UserRole).toString() + "/"); + destUrl = KUrl(archive_url->url().path(KUrl::AddTrailingSlash) + destPath); + QStringList srcFiles = item->data(0, Qt::UserRole + 1).toStringList(); + for (int k = 0; k < srcFiles.count(); k++) { + files << KUrl(srcFiles.at(k)); + } + item->setDisabled(true); + if (parentItem->indexOfChild(item) == parentItem->childCount() - 1) { + // We have processed all slideshows + parentItem->setDisabled(true); + } + break; + } + else if (item->data(0, Qt::UserRole).isNull()) { files << KUrl(item->text(0)); } else { // We must rename the destination file, since another file with same name exists //TODO: monitor progress - m_duplicateFiles.insert(KUrl(item->text(0)), KUrl(destUrl.path(KUrl::AddTrailingSlash) + item->data(0, Qt::UserRole).toString())); + if (isArchive) { + m_filesList.insert(item->text(0), destPath + item->data(0, Qt::UserRole).toString()); + } + else m_duplicateFiles.insert(KUrl(item->text(0)), KUrl(destUrl.path(KUrl::AddTrailingSlash) + item->data(0, Qt::UserRole).toString())); } } break; } } - if (destUrl.isEmpty()) { + if (destPath.isEmpty()) { if (m_duplicateFiles.isEmpty()) return false; QMapIterator i(m_duplicateFiles); - KUrl startJob; if (i.hasNext()) { i.next(); - startJob = i.key(); - KIO::CopyJob *job = KIO::copyAs(startJob, i.value(), KIO::HideProgressInfo); + KUrl startJobSrc = i.key(); + KUrl startJobDst = i.value(); + m_duplicateFiles.remove(startJobSrc); + KIO::CopyJob *job = KIO::copyAs(startJobSrc, startJobDst, KIO::HideProgressInfo); connect(job, SIGNAL(result(KJob *)), this, SLOT(slotArchivingFinished(KJob *))); connect(job, SIGNAL(processedSize(KJob *, qulonglong)), this, SLOT(slotArchivingProgress(KJob *, qulonglong))); - m_duplicateFiles.remove(startJob); } return true; } - m_copyJob = KIO::copy (files, destUrl, KIO::HideProgressInfo); - connect(m_copyJob, SIGNAL(result(KJob *)), this, SLOT(slotArchivingFinished(KJob *))); - connect(m_copyJob, SIGNAL(processedSize(KJob *, qulonglong)), this, SLOT(slotArchivingProgress(KJob *, qulonglong))); - + if (isArchive) { + m_foldersList.append(destPath); + for (int i = 0; i < files.count(); i++) { + m_filesList.insert(files.at(i).path(), destPath + files.at(i).fileName()); + } + slotArchivingFinished(); + } + else if (files.isEmpty()) { + slotStartArchiving(false); + } + else { + KIO::NetAccess::mkdir(destUrl, this); + m_copyJob = KIO::copy (files, destUrl, KIO::HideProgressInfo); + connect(m_copyJob, SIGNAL(result(KJob *)), this, SLOT(slotArchivingFinished(KJob *))); + connect(m_copyJob, SIGNAL(processedSize(KJob *, qulonglong)), this, SLOT(slotArchivingProgress(KJob *, qulonglong))); + } if (firstPass) { progressBar->setValue(0); buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Abort")); @@ -254,32 +469,35 @@ bool ArchiveWidget::slotStartArchiving(bool firstPass) void ArchiveWidget::slotArchivingFinished(KJob *job) { - if (job->error() == 0) { + if (job == NULL || job->error() == 0) { if (slotStartArchiving(false)) { // We still have files to archive return; } - else { + else if (!compressed_archive->isChecked()) { // Archiving finished progressBar->setValue(100); if (processProjectFile()) { - icon_info->setPixmap(KIcon("dialog-ok").pixmap(16, 16)); - text_info->setText(i18n("Project was successfully archived.")); + slotDisplayMessage("dialog-ok", i18n("Project was successfully archived.")); } else { - icon_info->setPixmap(KIcon("dialog-close").pixmap(16, 16)); - text_info->setText(i18n("There was an error processing project file")); + slotDisplayMessage("dialog-close", i18n("There was an error processing project file")); } - } + } else processProjectFile(); } else { m_copyJob = NULL; - icon_info->setPixmap(KIcon("dialog-close").pixmap(16, 16)); - text_info->setText(i18n("There was an error while copying the files: %1", job->errorString())); + slotDisplayMessage("dialog-close", i18n("There was an error while copying the files: %1", job->errorString())); } - buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Archive")); - for (int i = 0; i < files_list->topLevelItemCount(); i++) { - files_list->topLevelItem(i)->setDisabled(false); + if (!compressed_archive->isChecked()) { + buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Archive")); + archive_url->setEnabled(true); + compressed_archive->setEnabled(true); + for (int i = 0; i < files_list->topLevelItemCount(); i++) { + files_list->topLevelItem(i)->setDisabled(false); + for (int j = 0; j < files_list->topLevelItem(i)->childCount(); j++) + files_list->topLevelItem(i)->child(j)->setDisabled(false); + } } } @@ -293,14 +511,21 @@ bool ArchiveWidget::processProjectFile() { KUrl destUrl; QTreeWidgetItem *item; + bool isArchive = compressed_archive->isChecked(); + for (int i = 0; i < files_list->topLevelItemCount(); i++) { - if (files_list->topLevelItem(i)->childCount() > 0) { - destUrl = KUrl(archive_url->url().path(KUrl::AddTrailingSlash) + files_list->topLevelItem(i)->data(0, Qt::UserRole).toString()); - for (int j = 0; j < files_list->topLevelItem(i)->childCount(); j++) { - item = files_list->topLevelItem(i)->child(j); + QTreeWidgetItem *parentItem = files_list->topLevelItem(i); + if (parentItem->childCount() > 0) { + destUrl = KUrl(archive_url->url().path(KUrl::AddTrailingSlash) + parentItem->data(0, Qt::UserRole).toString()); + bool isSlideshow = parentItem->data(0, Qt::UserRole).toString() == "slideshows"; + for (int j = 0; j < parentItem->childCount(); j++) { + item = parentItem->child(j); KUrl src(item->text(0)); KUrl dest = destUrl; - if (item->data(0, Qt::UserRole).isNull()) { + if (isSlideshow) { + dest = KUrl(destUrl.path(KUrl::AddTrailingSlash) + item->data(0, Qt::UserRole).toString() + "/" + src.fileName()); + } + else if (item->data(0, Qt::UserRole).isNull()) { dest.addPath(src.fileName()); } else { @@ -310,9 +535,19 @@ bool ArchiveWidget::processProjectFile() } } } - // process kdenlive producers - + QDomElement mlt = m_doc.documentElement(); + QString root = mlt.attribute("root") + "/"; + + // Adjust global settings + QString basePath; + if (isArchive) basePath = "$CURRENTPATH"; + else basePath = archive_url->url().path(KUrl::RemoveTrailingSlash); + mlt.setAttribute("root", basePath); + QDomElement project = mlt.firstChildElement("kdenlivedoc"); + project.setAttribute("projectfolder", basePath); + + // process kdenlive producers QDomNodeList prods = mlt.elementsByTagName("kdenlive_producer"); for (int i = 0; i < prods.count(); i++) { QDomElement e = prods.item(i).toElement(); @@ -322,19 +557,77 @@ bool ArchiveWidget::processProjectFile() KUrl dest = m_replacementList.value(src); if (!dest.isEmpty()) e.setAttribute("resource", dest.path()); } + if (e.hasAttribute("proxy") && e.attribute("proxy") != "-") { + KUrl src(e.attribute("proxy")); + KUrl dest = m_replacementList.value(src); + if (!dest.isEmpty()) e.setAttribute("proxy", dest.path()); + } + } + + // process mlt producers + prods = mlt.elementsByTagName("producer"); + for (int i = 0; i < prods.count(); i++) { + QDomElement e = prods.item(i).toElement(); + if (e.isNull()) continue; + QString src = EffectsList::property(e, "resource"); + if (!src.isEmpty()) { + if (!src.startsWith('/')) src.prepend(root); + KUrl srcUrl(src); + KUrl dest = m_replacementList.value(src); + if (!dest.isEmpty()) EffectsList::setProperty(e, "resource", dest.path()); + } + } + + // process mlt transitions (for luma files) + prods = mlt.elementsByTagName("transition"); + QString attribute; + for (int i = 0; i < prods.count(); i++) { + QDomElement e = prods.item(i).toElement(); + if (e.isNull()) continue; + attribute = "resource"; + QString src = EffectsList::property(e, attribute); + if (src.isEmpty()) attribute = "luma"; + src = EffectsList::property(e, attribute); + if (!src.isEmpty()) { + if (!src.startsWith('/')) src.prepend(root); + KUrl srcUrl(src); + KUrl dest = m_replacementList.value(src); + if (!dest.isEmpty()) EffectsList::setProperty(e, attribute, dest.path()); + } + } + + QString playList = m_doc.toString(); + if (isArchive) { + QString startString("\""); + startString.append(archive_url->url().path(KUrl::RemoveTrailingSlash)); + QString endString("\""); + endString.append(basePath); + playList.replace(startString, endString); + startString = ">" + archive_url->url().path(KUrl::RemoveTrailingSlash); + endString = ">" + basePath; + playList.replace(startString, endString); } - QString path = archive_url->url().path(KUrl::AddTrailingSlash) + "project.kdenlive"; + if (isArchive) { + m_temp = new KTemporaryFile; + if (!m_temp->open()) KMessageBox::error(this, i18n("Cannot create temporary file")); + m_temp->write(playList.toUtf8()); + m_temp->close(); + m_archiveThread = QtConcurrent::run(this, &ArchiveWidget::createArchive); + return true; + } + + QString path = archive_url->url().path(KUrl::AddTrailingSlash) + m_name + ".kdenlive"; 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)); + KMessageBox::error(this, i18n("Cannot write to file %1", path)); return false; } file.write(m_doc.toString().toUtf8()); if (file.error() != QFile::NoError) { - KMessageBox::error(kapp->activeWindow(), i18n("Cannot write to file %1", path)); + KMessageBox::error(this, i18n("Cannot write to file %1", path)); file.close(); return false; } @@ -342,3 +635,140 @@ bool ArchiveWidget::processProjectFile() return true; } +void ArchiveWidget::createArchive() +{ + QFileInfo dirInfo(archive_url->url().path()); + QString user = dirInfo.owner(); + QString group = dirInfo.group(); + KTar archive(archive_url->url().path(KUrl::AddTrailingSlash) + m_name + ".tar.gz", "application/x-gzip"); + archive.open( QIODevice::WriteOnly ); + + // Create folders + foreach(const QString &path, m_foldersList) { + archive.writeDir(path, user, group); + } + + // Add files + int ix = 0; + QMapIterator i(m_filesList); + while (i.hasNext()) { + i.next(); + archive.addLocalFile(i.key(), i.value()); + emit archiveProgress((int) 100 * ix / m_filesList.count()); + ix++; + } + + // Add project file + archive.addLocalFile(m_temp->fileName(), m_name + ".kdenlive"); + bool result = archive.close(); + delete m_temp; + emit archivingFinished(result); +} + +void ArchiveWidget::slotArchivingFinished(bool result) +{ + if (result) { + slotDisplayMessage("dialog-ok", i18n("Project was successfully archived.")); + } + else { + slotDisplayMessage("dialog-close", i18n("There was an error processing project file")); + } + progressBar->setValue(100); + buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Archive")); + archive_url->setEnabled(true); + compressed_archive->setEnabled(true); + for (int i = 0; i < files_list->topLevelItemCount(); i++) { + files_list->topLevelItem(i)->setDisabled(false); + for (int j = 0; j < files_list->topLevelItem(i)->childCount(); j++) + files_list->topLevelItem(i)->child(j)->setDisabled(false); + } +} + +void ArchiveWidget::slotArchivingProgress(int p) +{ + progressBar->setValue(p); +} + +void ArchiveWidget::slotStartExtracting() +{ + if (m_archiveThread.isRunning()) { + //TODO: abort extracting + return; + } + QFileInfo f(m_extractUrl.path()); + m_requestedSize = f.size(); + KIO::NetAccess::mkdir(archive_url->url().path(KUrl::RemoveTrailingSlash), this); + slotDisplayMessage("system-run", i18n("Extracting...")); + buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Abort")); + m_progressTimer = new QTimer; + m_progressTimer->setInterval(800); + m_progressTimer->setSingleShot(false); + connect(m_progressTimer, SIGNAL(timeout()), this, SLOT(slotExtractProgress())); + m_archiveThread = QtConcurrent::run(this, &ArchiveWidget::doExtracting); + m_progressTimer->start(); +} + +void ArchiveWidget::slotExtractProgress() +{ + KIO::DirectorySizeJob *job = KIO::directorySize(archive_url->url()); + connect(job, SIGNAL(result(KJob*)), this, SLOT(slotGotProgress(KJob*))); +} + +void ArchiveWidget::slotGotProgress(KJob* job) +{ + if (!job->error()) { + KIO::DirectorySizeJob *j = static_cast (job); + progressBar->setValue((int) 100 * j->totalSize() / m_requestedSize); + } + job->deleteLater(); +} + +void ArchiveWidget::doExtracting() +{ + m_extractArchive->directory()->copyTo(archive_url->url().path(KUrl::AddTrailingSlash)); + m_extractArchive->close(); + emit extractingFinished(); +} + +QString ArchiveWidget::extractedProjectFile() +{ + return archive_url->url().path(KUrl::AddTrailingSlash) + m_projectName; +} + +void ArchiveWidget::slotExtractingFinished() +{ + m_progressTimer->stop(); + delete m_progressTimer; + // Process project file + QFile file(extractedProjectFile()); + bool error = false; + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + error = true; + } + else { + QString playList = file.readAll(); + file.close(); + if (playList.isEmpty()) { + error = true; + } + else { + playList.replace("$CURRENTPATH", archive_url->url().path(KUrl::RemoveTrailingSlash)); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + kWarning() << "////// ERROR writing to file: "; + error = true; + } + else { + file.write(playList.toUtf8()); + if (file.error() != QFile::NoError) { + error = true; + } + file.close(); + } + } + } + if (error) { + KMessageBox::sorry(kapp->activeWindow(), i18n("Cannot open project file %1", extractedProjectFile()), i18n("Cannot open file")); + reject(); + } + else accept(); +}