1 /***************************************************************************
2 * Copyright (C) 2011 by Jean-Baptiste Mardelle (jb@kdenlive.org) *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
18 ***************************************************************************/
21 #include "archivewidget.h"
22 #include "titlewidget.h"
25 #include <KDiskFreeSpaceInfo>
26 #include <KUrlRequester>
27 #include <KFileDialog>
28 #include <KMessageBox>
30 #include <KIO/NetAccess>
33 #include <KApplication>
34 #include <kio/directorysizejob.h>
36 #include <QTreeWidget>
37 #include <QtConcurrentRun>
38 #include "projectsettings.h"
41 ArchiveWidget::ArchiveWidget(QString projectName, QDomDocument doc, QList <DocClipBase*> list, QStringList luma_list, QWidget * parent) :
45 m_name(projectName.section('.', 0, -2)),
47 m_abortArchive(false),
49 m_extractArchive(NULL)
51 setAttribute(Qt::WA_DeleteOnClose);
53 setWindowTitle(i18n("Archive Project"));
54 archive_url->setUrl(KUrl(QDir::homePath()));
55 connect(archive_url, SIGNAL(textChanged (const QString &)), this, SLOT(slotCheckSpace()));
56 connect(this, SIGNAL(archivingFinished(bool)), this, SLOT(slotArchivingFinished(bool)));
57 connect(this, SIGNAL(archiveProgress(int)), this, SLOT(slotArchivingProgress(int)));
60 QTreeWidgetItem *videos = new QTreeWidgetItem(files_list, QStringList() << i18n("Video clips"));
61 videos->setIcon(0, KIcon("video-x-generic"));
62 videos->setData(0, Qt::UserRole, "videos");
63 videos->setExpanded(false);
64 QTreeWidgetItem *sounds = new QTreeWidgetItem(files_list, QStringList() << i18n("Audio clips"));
65 sounds->setIcon(0, KIcon("audio-x-generic"));
66 sounds->setData(0, Qt::UserRole, "sounds");
67 sounds->setExpanded(false);
68 QTreeWidgetItem *images = new QTreeWidgetItem(files_list, QStringList() << i18n("Image clips"));
69 images->setIcon(0, KIcon("image-x-generic"));
70 images->setData(0, Qt::UserRole, "images");
71 images->setExpanded(false);
72 QTreeWidgetItem *slideshows = new QTreeWidgetItem(files_list, QStringList() << i18n("Slideshow clips"));
73 slideshows->setIcon(0, KIcon("image-x-generic"));
74 slideshows->setData(0, Qt::UserRole, "slideshows");
75 slideshows->setExpanded(false);
76 QTreeWidgetItem *texts = new QTreeWidgetItem(files_list, QStringList() << i18n("Text clips"));
77 texts->setIcon(0, KIcon("text-plain"));
78 texts->setData(0, Qt::UserRole, "texts");
79 texts->setExpanded(false);
80 QTreeWidgetItem *others = new QTreeWidgetItem(files_list, QStringList() << i18n("Other clips"));
81 others->setIcon(0, KIcon("unknown"));
82 others->setData(0, Qt::UserRole, "others");
83 others->setExpanded(false);
84 QTreeWidgetItem *lumas = new QTreeWidgetItem(files_list, QStringList() << i18n("Luma files"));
85 lumas->setIcon(0, KIcon("image-x-generic"));
86 lumas->setData(0, Qt::UserRole, "lumas");
87 lumas->setExpanded(false);
89 QTreeWidgetItem *proxies = new QTreeWidgetItem(files_list, QStringList() << i18n("Proxy clips"));
90 proxies->setIcon(0, KIcon("video-x-generic"));
91 proxies->setData(0, Qt::UserRole, "proxy");
92 proxies->setExpanded(false);
97 QStringList fileNames;
98 generateItems(lumas, luma_list);
100 QStringList slideUrls;
101 QStringList audioUrls;
102 QStringList videoUrls;
103 QStringList imageUrls;
104 QStringList otherUrls;
105 QStringList proxyUrls;
107 for (int i = 0; i < list.count(); i++) {
108 DocClipBase *clip = list.at(i);
109 CLIPTYPE t = clip->clipType();
110 if (t == SLIDESHOW) {
111 KUrl slideUrl = clip->fileURL();
112 //TODO: Slideshow files
113 slideUrls << slideUrl.path();
115 else if (t == IMAGE) imageUrls << clip->fileURL().path();
116 else if (t == TEXT) {
117 QStringList imagefiles = TitleWidget::extractImageList(clip->getProperty("xmldata"));
118 QStringList fonts = TitleWidget::extractFontList(clip->getProperty("xmldata"));
119 imageUrls << imagefiles;
121 } else if (t == PLAYLIST) {
122 QStringList files = ProjectSettings::extractPlaylistUrls(clip->fileURL().path());
125 else if (!clip->fileURL().isEmpty()) {
126 if (t == AUDIO) audioUrls << clip->fileURL().path();
128 videoUrls << clip->fileURL().path();
129 // Check if we have a proxy
130 QString proxy = clip->getProperty("proxy");
131 if (!proxy.isEmpty() && proxy != "-" && QFile::exists(proxy)) proxyUrls << proxy;
136 generateItems(sounds, audioUrls);
137 generateItems(videos, videoUrls);
138 generateItems(images, imageUrls);
139 generateItems(slideshows, slideUrls);
140 generateItems(others, otherUrls);
141 generateItems(proxies, proxyUrls);
143 allFonts.removeDuplicates();
147 // Hide unused categories, add item count
149 for (int i = 0; i < files_list->topLevelItemCount(); i++) {
150 QTreeWidgetItem *parentItem = files_list->topLevelItem(i);
151 int items = parentItem->childCount();
153 files_list->topLevelItem(i)->setHidden(true);
156 if (parentItem->data(0, Qt::UserRole).toString() == "slideshows")
158 // Special case: slideshows contain several files
159 for (int j = 0; j < items; j++) {
160 total += parentItem->child(j)->data(0, Qt::UserRole + 1).toStringList().count();
164 parentItem->setText(0, files_list->topLevelItem(i)->text(0) + " " + i18np("(%1 item)", "(%1 items)", items));
167 if (m_name.isEmpty()) m_name = i18n("Untitled");
168 compressed_archive->setText(compressed_archive->text() + " (" + m_name + ".tar.gz)");
169 project_files->setText(i18np("%1 file to archive, requires %2", "%1 files to archive, requires %2", total, KIO::convertSize(m_requestedSize)));
170 buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Archive"));
171 connect(buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(slotStartArchiving()));
172 buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
177 // Constructor for extract widget
178 ArchiveWidget::ArchiveWidget(const KUrl &url, QWidget * parent):
183 //setAttribute(Qt::WA_DeleteOnClose);
186 connect(this, SIGNAL(extractingFinished()), this, SLOT(slotExtractingFinished()));
187 connect(this, SIGNAL(showMessage(const QString &, const QString &)), this, SLOT(slotDisplayMessage(const QString &, const QString &)));
189 compressed_archive->setHidden(true);
190 project_files->setHidden(true);
191 files_list->setHidden(true);
192 label->setText(i18n("Extract to"));
193 setWindowTitle(i18n("Open Archived Project"));
194 archive_url->setUrl(KUrl(QDir::homePath()));
195 buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Extract"));
196 connect(buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(slotStartExtracting()));
197 buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
199 m_archiveThread = QtConcurrent::run(this, &ArchiveWidget::openArchiveForExtraction);
203 ArchiveWidget::~ArchiveWidget()
205 if (m_extractArchive) delete m_extractArchive;
208 void ArchiveWidget::slotDisplayMessage(const QString &icon, const QString &text)
210 icon_info->setPixmap(KIcon(icon).pixmap(16, 16));
211 text_info->setText(text);
214 void ArchiveWidget::openArchiveForExtraction()
216 emit showMessage("system-run", i18n("Opening archive..."));
217 m_extractArchive = new KTar(m_extractUrl.path());
218 if (!m_extractArchive->isOpen() && !m_extractArchive->open( QIODevice::ReadOnly )) {
219 emit showMessage("dialog-close", i18n("Cannot open archive file:\n %1", m_extractUrl.path()));
220 groupBox->setEnabled(false);
224 // Check that it is a kdenlive project archive
225 bool isProjectArchive = false;
226 QStringList files = m_extractArchive->directory()->entries();
227 for (int i = 0; i < files.count(); i++) {
228 if (files.at(i).endsWith(".kdenlive")) {
229 m_projectName = files.at(i);
230 isProjectArchive = true;
235 if (!isProjectArchive) {
236 emit showMessage("dialog-close", i18n("File %1\n is not an archived Kdenlive project", m_extractUrl.path()));
237 groupBox->setEnabled(false);
240 buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true);
241 emit showMessage("dialog-ok", i18n("Ready"));
244 void ArchiveWidget::done ( int r )
246 if (closeAccepted()) QDialog::done(r);
249 void ArchiveWidget::closeEvent ( QCloseEvent * e )
252 if (closeAccepted()) e->accept();
257 bool ArchiveWidget::closeAccepted()
259 if (!m_extractMode && !archive_url->isEnabled()) {
260 // Archiving in progress, should we stop?
261 if (KMessageBox::warningContinueCancel(this, i18n("Archiving in progress, do you want to stop it?"), i18n("Stop Archiving"), KGuiItem(i18n("Stop Archiving"))) != KMessageBox::Continue) {
264 if (m_copyJob) m_copyJob->kill();
270 void ArchiveWidget::generateItems(QTreeWidgetItem *parentItem, QStringList items)
272 QStringList filesList;
275 bool isSlideshow = parentItem->data(0, Qt::UserRole).toString() == "slideshows";
276 foreach(const QString & file, items) {
277 QTreeWidgetItem *item = new QTreeWidgetItem(parentItem, QStringList() << file);
278 fileName = KUrl(file).fileName();
280 // we store each slideshow in a separate subdirectory
281 item->setData(0, Qt::UserRole, ix);
284 QDir dir(slideUrl.directory(KUrl::AppendTrailingSlash));
285 if (slideUrl.fileName().startsWith(".all.")) {
286 // mimetype slideshow (for example *.png)
289 // TODO: improve jpeg image detection with extension like jpeg, requires change in MLT image producers
290 filters << "*." + slideUrl.fileName().section('.', -1);
291 dir.setNameFilters(filters);
292 QFileInfoList resultList = dir.entryInfoList(QDir::Files);
293 QStringList slideImages;
294 for (int i = 0; i < resultList.count(); i++) {
295 m_requestedSize += resultList.at(i).size();
296 slideImages << resultList.at(i).absoluteFilePath();
298 item->setData(0, Qt::UserRole + 1, slideImages);
301 // pattern url (like clip%.3d.png)
302 QStringList result = dir.entryList(QDir::Files);
303 QString filter = slideUrl.fileName();
304 QString ext = filter.section('.', -1);
305 filter = filter.section('%', 0, -2);
306 QString regexp = "^" + filter + "\\d+\\." + ext + "$";
308 QStringList slideImages;
309 QString directory = dir.absolutePath();
310 if (!directory.endsWith('/')) directory.append('/');
311 foreach(const QString & path, result) {
312 if (rx.exactMatch(path)) {
313 m_requestedSize += QFileInfo(directory + path).size();
314 slideImages << directory + path;
317 item->setData(0, Qt::UserRole + 1, slideImages);
320 else if (filesList.contains(fileName)) {
321 // we have 2 files with same name
323 QString newFileName = fileName.section('.', 0, -2) + "_" + QString::number(ix) + "." + fileName.section('.', -1);
324 while (filesList.contains(newFileName)) {
326 newFileName = fileName.section('.', 0, -2) + "_" + QString::number(ix) + "." + fileName.section('.', -1);
328 fileName = newFileName;
329 item->setData(0, Qt::UserRole, fileName);
332 m_requestedSize += QFileInfo(file).size();
333 filesList << fileName;
338 void ArchiveWidget::slotCheckSpace()
340 KDiskFreeSpaceInfo inf = KDiskFreeSpaceInfo::freeSpaceInfo( archive_url->url().path());
341 KIO::filesize_t freeSize = inf.available();;
342 if (freeSize > m_requestedSize) {
344 buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true);
345 slotDisplayMessage("dialog-ok", i18n("Available space on drive: %1", KIO::convertSize(freeSize)));
348 buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
349 slotDisplayMessage("dialog-close", i18n("Not enough space on drive, free space: %1", KIO::convertSize(freeSize)));
353 bool ArchiveWidget::slotStartArchiving(bool firstPass)
355 if (firstPass && (m_copyJob || m_archiveThread.isRunning())) {
356 // archiving in progress, abort
357 if (m_copyJob) m_copyJob->kill(KJob::EmitResult);
358 m_abortArchive = true;
361 bool isArchive = compressed_archive->isChecked();
362 if (!firstPass) m_copyJob = NULL;
365 m_abortArchive = false;
366 m_duplicateFiles.clear();
367 m_replacementList.clear();
368 m_foldersList.clear();
370 slotDisplayMessage("system-run", i18n("Archiving..."));
372 archive_url->setEnabled(false);
373 compressed_archive->setEnabled(false);
378 QTreeWidgetItem *parentItem;
379 bool isSlideshow = false;
380 for (int i = 0; i < files_list->topLevelItemCount(); i++) {
381 parentItem = files_list->topLevelItem(i);
382 if (parentItem->childCount() > 0 && !parentItem->isDisabled()) {
383 if (parentItem->data(0, Qt::UserRole).toString() == "slideshows") {
384 KUrl slideFolder(archive_url->url().path(KUrl::AddTrailingSlash) + "slideshows");
385 if (isArchive) m_foldersList.append("slideshows");
386 else KIO::NetAccess::mkdir(slideFolder, this);
389 files_list->setCurrentItem(parentItem);
390 if (!isSlideshow) parentItem->setDisabled(true);
391 destPath = parentItem->data(0, Qt::UserRole).toString() + "/";
392 destUrl = KUrl(archive_url->url().path(KUrl::AddTrailingSlash) + destPath);
393 QTreeWidgetItem *item;
394 for (int j = 0; j < parentItem->childCount(); j++) {
395 item = parentItem->child(j);
396 // Special case: slideshows
398 if (item->isDisabled()) {
401 destPath.append(item->data(0, Qt::UserRole).toString() + "/");
402 destUrl = KUrl(archive_url->url().path(KUrl::AddTrailingSlash) + destPath);
403 QStringList srcFiles = item->data(0, Qt::UserRole + 1).toStringList();
404 for (int k = 0; k < srcFiles.count(); k++) {
405 files << KUrl(srcFiles.at(k));
407 item->setDisabled(true);
408 if (parentItem->indexOfChild(item) == parentItem->childCount() - 1) {
409 // We have processed all slideshows
410 parentItem->setDisabled(true);
414 else if (item->data(0, Qt::UserRole).isNull()) {
415 files << KUrl(item->text(0));
418 // We must rename the destination file, since another file with same name exists
419 //TODO: monitor progress
421 m_filesList.insert(item->text(0), destPath + item->data(0, Qt::UserRole).toString());
423 else m_duplicateFiles.insert(KUrl(item->text(0)), KUrl(destUrl.path(KUrl::AddTrailingSlash) + item->data(0, Qt::UserRole).toString()));
430 if (destPath.isEmpty()) {
431 if (m_duplicateFiles.isEmpty()) return false;
432 QMapIterator<KUrl, KUrl> i(m_duplicateFiles);
435 KUrl startJobSrc = i.key();
436 KUrl startJobDst = i.value();
437 m_duplicateFiles.remove(startJobSrc);
438 KIO::CopyJob *job = KIO::copyAs(startJobSrc, startJobDst, KIO::HideProgressInfo);
439 connect(job, SIGNAL(result(KJob *)), this, SLOT(slotArchivingFinished(KJob *)));
440 connect(job, SIGNAL(processedSize(KJob *, qulonglong)), this, SLOT(slotArchivingProgress(KJob *, qulonglong)));
446 m_foldersList.append(destPath);
447 for (int i = 0; i < files.count(); i++) {
448 m_filesList.insert(files.at(i).path(), destPath + files.at(i).fileName());
450 slotArchivingFinished();
452 else if (files.isEmpty()) {
453 slotStartArchiving(false);
456 KIO::NetAccess::mkdir(destUrl, this);
457 m_copyJob = KIO::copy (files, destUrl, KIO::HideProgressInfo);
458 connect(m_copyJob, SIGNAL(result(KJob *)), this, SLOT(slotArchivingFinished(KJob *)));
459 connect(m_copyJob, SIGNAL(processedSize(KJob *, qulonglong)), this, SLOT(slotArchivingProgress(KJob *, qulonglong)));
462 progressBar->setValue(0);
463 buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Abort"));
468 void ArchiveWidget::slotArchivingFinished(KJob *job)
470 if (job == NULL || job->error() == 0) {
471 if (slotStartArchiving(false)) {
472 // We still have files to archive
475 else if (!compressed_archive->isChecked()) {
476 // Archiving finished
477 progressBar->setValue(100);
478 if (processProjectFile()) {
479 slotDisplayMessage("dialog-ok", i18n("Project was successfully archived."));
482 slotDisplayMessage("dialog-close", i18n("There was an error processing project file"));
484 } else processProjectFile();
488 slotDisplayMessage("dialog-close", i18n("There was an error while copying the files: %1", job->errorString()));
490 if (!compressed_archive->isChecked()) {
491 buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Archive"));
492 archive_url->setEnabled(true);
493 compressed_archive->setEnabled(true);
494 for (int i = 0; i < files_list->topLevelItemCount(); i++) {
495 files_list->topLevelItem(i)->setDisabled(false);
496 for (int j = 0; j < files_list->topLevelItem(i)->childCount(); j++)
497 files_list->topLevelItem(i)->child(j)->setDisabled(false);
502 void ArchiveWidget::slotArchivingProgress(KJob *, qulonglong size)
504 progressBar->setValue((int) 100 * size / m_requestedSize);
508 bool ArchiveWidget::processProjectFile()
511 QTreeWidgetItem *item;
512 bool isArchive = compressed_archive->isChecked();
514 for (int i = 0; i < files_list->topLevelItemCount(); i++) {
515 QTreeWidgetItem *parentItem = files_list->topLevelItem(i);
516 if (parentItem->childCount() > 0) {
517 destUrl = KUrl(archive_url->url().path(KUrl::AddTrailingSlash) + parentItem->data(0, Qt::UserRole).toString());
518 bool isSlideshow = parentItem->data(0, Qt::UserRole).toString() == "slideshows";
519 for (int j = 0; j < parentItem->childCount(); j++) {
520 item = parentItem->child(j);
521 KUrl src(item->text(0));
524 dest = KUrl(destUrl.path(KUrl::AddTrailingSlash) + item->data(0, Qt::UserRole).toString() + "/" + src.fileName());
526 else if (item->data(0, Qt::UserRole).isNull()) {
527 dest.addPath(src.fileName());
530 dest.addPath(item->data(0, Qt::UserRole).toString());
532 m_replacementList.insert(src, dest);
537 QDomElement mlt = m_doc.documentElement();
538 QString root = mlt.attribute("root") + "/";
540 // Adjust global settings
542 if (isArchive) basePath = "$CURRENTPATH";
543 else basePath = archive_url->url().path(KUrl::RemoveTrailingSlash);
544 mlt.setAttribute("root", basePath);
545 QDomElement project = mlt.firstChildElement("kdenlivedoc");
546 project.setAttribute("projectfolder", basePath);
548 // process kdenlive producers
549 QDomNodeList prods = mlt.elementsByTagName("kdenlive_producer");
550 for (int i = 0; i < prods.count(); i++) {
551 QDomElement e = prods.item(i).toElement();
552 if (e.isNull()) continue;
553 if (e.hasAttribute("resource")) {
554 KUrl src(e.attribute("resource"));
555 KUrl dest = m_replacementList.value(src);
556 if (!dest.isEmpty()) e.setAttribute("resource", dest.path());
558 if (e.hasAttribute("proxy") && e.attribute("proxy") != "-") {
559 KUrl src(e.attribute("proxy"));
560 KUrl dest = m_replacementList.value(src);
561 if (!dest.isEmpty()) e.setAttribute("proxy", dest.path());
565 // process mlt producers
566 prods = mlt.elementsByTagName("producer");
567 for (int i = 0; i < prods.count(); i++) {
568 QDomElement e = prods.item(i).toElement();
569 if (e.isNull()) continue;
570 QString src = EffectsList::property(e, "resource");
571 if (!src.isEmpty()) {
572 if (!src.startsWith('/')) src.prepend(root);
574 KUrl dest = m_replacementList.value(src);
575 if (!dest.isEmpty()) EffectsList::setProperty(e, "resource", dest.path());
579 // process mlt transitions (for luma files)
580 prods = mlt.elementsByTagName("transition");
582 for (int i = 0; i < prods.count(); i++) {
583 QDomElement e = prods.item(i).toElement();
584 if (e.isNull()) continue;
585 attribute = "resource";
586 QString src = EffectsList::property(e, attribute);
587 if (src.isEmpty()) attribute = "luma";
588 src = EffectsList::property(e, attribute);
589 if (!src.isEmpty()) {
590 if (!src.startsWith('/')) src.prepend(root);
592 KUrl dest = m_replacementList.value(src);
593 if (!dest.isEmpty()) EffectsList::setProperty(e, attribute, dest.path());
597 QString playList = m_doc.toString();
599 QString startString("\"");
600 startString.append(archive_url->url().path(KUrl::RemoveTrailingSlash));
601 QString endString("\"");
602 endString.append(basePath);
603 playList.replace(startString, endString);
604 startString = ">" + archive_url->url().path(KUrl::RemoveTrailingSlash);
605 endString = ">" + basePath;
606 playList.replace(startString, endString);
610 m_temp = new KTemporaryFile;
611 if (!m_temp->open()) KMessageBox::error(this, i18n("Cannot create temporary file"));
612 m_temp->write(playList.toUtf8());
614 m_archiveThread = QtConcurrent::run(this, &ArchiveWidget::createArchive);
618 QString path = archive_url->url().path(KUrl::AddTrailingSlash) + m_name + ".kdenlive";
620 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
621 kWarning() << "////// ERROR writing to file: " << path;
622 KMessageBox::error(this, i18n("Cannot write to file %1", path));
626 file.write(m_doc.toString().toUtf8());
627 if (file.error() != QFile::NoError) {
628 KMessageBox::error(this, i18n("Cannot write to file %1", path));
636 void ArchiveWidget::createArchive()
638 QFileInfo dirInfo(archive_url->url().path());
639 QString user = dirInfo.owner();
640 QString group = dirInfo.group();
641 KTar archive(archive_url->url().path(KUrl::AddTrailingSlash) + m_name + ".tar.gz", "application/x-gzip");
642 archive.open( QIODevice::WriteOnly );
645 foreach(const QString &path, m_foldersList) {
646 archive.writeDir(path, user, group);
651 QMapIterator<QString, QString> i(m_filesList);
652 while (i.hasNext()) {
654 archive.addLocalFile(i.key(), i.value());
655 emit archiveProgress((int) 100 * ix / m_filesList.count());
660 archive.addLocalFile(m_temp->fileName(), m_name + ".kdenlive");
661 bool result = archive.close();
663 emit archivingFinished(result);
666 void ArchiveWidget::slotArchivingFinished(bool result)
669 slotDisplayMessage("dialog-ok", i18n("Project was successfully archived."));
672 slotDisplayMessage("dialog-close", i18n("There was an error processing project file"));
674 progressBar->setValue(100);
675 buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Archive"));
676 archive_url->setEnabled(true);
677 compressed_archive->setEnabled(true);
678 for (int i = 0; i < files_list->topLevelItemCount(); i++) {
679 files_list->topLevelItem(i)->setDisabled(false);
680 for (int j = 0; j < files_list->topLevelItem(i)->childCount(); j++)
681 files_list->topLevelItem(i)->child(j)->setDisabled(false);
685 void ArchiveWidget::slotArchivingProgress(int p)
687 progressBar->setValue(p);
690 void ArchiveWidget::slotStartExtracting()
692 if (m_archiveThread.isRunning()) {
693 //TODO: abort extracting
696 QFileInfo f(m_extractUrl.path());
697 m_requestedSize = f.size();
698 KIO::NetAccess::mkdir(archive_url->url().path(KUrl::RemoveTrailingSlash), this);
699 slotDisplayMessage("system-run", i18n("Extracting..."));
700 buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Abort"));
701 m_progressTimer = new QTimer;
702 m_progressTimer->setInterval(800);
703 m_progressTimer->setSingleShot(false);
704 connect(m_progressTimer, SIGNAL(timeout()), this, SLOT(slotExtractProgress()));
705 m_archiveThread = QtConcurrent::run(this, &ArchiveWidget::doExtracting);
706 m_progressTimer->start();
709 void ArchiveWidget::slotExtractProgress()
711 KIO::DirectorySizeJob *job = KIO::directorySize(archive_url->url());
712 connect(job, SIGNAL(result(KJob*)), this, SLOT(slotGotProgress(KJob*)));
715 void ArchiveWidget::slotGotProgress(KJob* job)
718 KIO::DirectorySizeJob *j = static_cast <KIO::DirectorySizeJob *>(job);
719 progressBar->setValue((int) 100 * j->totalSize() / m_requestedSize);
724 void ArchiveWidget::doExtracting()
726 m_extractArchive->directory()->copyTo(archive_url->url().path(KUrl::AddTrailingSlash));
727 m_extractArchive->close();
728 emit extractingFinished();
731 QString ArchiveWidget::extractedProjectFile()
733 return archive_url->url().path(KUrl::AddTrailingSlash) + m_projectName;
736 void ArchiveWidget::slotExtractingFinished()
738 m_progressTimer->stop();
739 delete m_progressTimer;
740 // Process project file
741 QFile file(extractedProjectFile());
743 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
747 QString playList = file.readAll();
749 if (playList.isEmpty()) {
753 playList.replace("$CURRENTPATH", archive_url->url().path(KUrl::RemoveTrailingSlash));
754 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
755 kWarning() << "////// ERROR writing to file: ";
759 file.write(playList.toUtf8());
760 if (file.error() != QFile::NoError) {
768 KMessageBox::sorry(kapp->activeWindow(), i18n("Cannot open project file %1", extractedProjectFile()), i18n("Cannot open file"));