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 #if QT_VERSION >= 0x040500
144 allFonts.removeDuplicates();
149 // Hide unused categories, add item count
151 for (int i = 0; i < files_list->topLevelItemCount(); i++) {
152 QTreeWidgetItem *parentItem = files_list->topLevelItem(i);
153 int items = parentItem->childCount();
155 files_list->topLevelItem(i)->setHidden(true);
158 if (parentItem->data(0, Qt::UserRole).toString() == "slideshows")
160 // Special case: slideshows contain several files
161 for (int j = 0; j < items; j++) {
162 total += parentItem->child(j)->data(0, Qt::UserRole + 1).toStringList().count();
166 parentItem->setText(0, files_list->topLevelItem(i)->text(0) + " " + i18np("(%1 item)", "(%1 items)", items));
169 if (m_name.isEmpty()) m_name = i18n("Untitled");
170 compressed_archive->setText(compressed_archive->text() + " (" + m_name + ".tar.gz)");
171 project_files->setText(i18np("%1 file to archive, requires %2", "%1 files to archive, requires %2", total, KIO::convertSize(m_requestedSize)));
172 buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Archive"));
173 connect(buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(slotStartArchiving()));
174 buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
179 // Constructor for extract widget
180 ArchiveWidget::ArchiveWidget(const KUrl &url, QWidget * parent):
185 //setAttribute(Qt::WA_DeleteOnClose);
188 connect(this, SIGNAL(extractingFinished()), this, SLOT(slotExtractingFinished()));
189 connect(this, SIGNAL(showMessage(const QString &, const QString &)), this, SLOT(slotDisplayMessage(const QString &, const QString &)));
191 compressed_archive->setHidden(true);
192 project_files->setHidden(true);
193 files_list->setHidden(true);
194 label->setText(i18n("Extract to"));
195 setWindowTitle(i18n("Open Archived Project"));
196 archive_url->setUrl(KUrl(QDir::homePath()));
197 buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Extract"));
198 connect(buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(slotStartExtracting()));
199 buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
201 m_archiveThread = QtConcurrent::run(this, &ArchiveWidget::openArchiveForExtraction);
205 ArchiveWidget::~ArchiveWidget()
207 if (m_extractArchive) delete m_extractArchive;
210 void ArchiveWidget::slotDisplayMessage(const QString &icon, const QString &text)
212 icon_info->setPixmap(KIcon(icon).pixmap(16, 16));
213 text_info->setText(text);
216 void ArchiveWidget::openArchiveForExtraction()
218 emit showMessage("system-run", i18n("Opening archive..."));
219 m_extractArchive = new KTar(m_extractUrl.path());
220 if (!m_extractArchive->isOpen() && !m_extractArchive->open( QIODevice::ReadOnly )) {
221 emit showMessage("dialog-close", i18n("Cannot open archive file:\n %1", m_extractUrl.path()));
222 groupBox->setEnabled(false);
226 // Check that it is a kdenlive project archive
227 bool isProjectArchive = false;
228 QStringList files = m_extractArchive->directory()->entries();
229 for (int i = 0; i < files.count(); i++) {
230 if (files.at(i).endsWith(".kdenlive")) {
231 m_projectName = files.at(i);
232 isProjectArchive = true;
237 if (!isProjectArchive) {
238 emit showMessage("dialog-close", i18n("File %1\n is not an archived Kdenlive project", m_extractUrl.path()));
239 groupBox->setEnabled(false);
242 buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true);
243 emit showMessage("dialog-ok", i18n("Ready"));
246 void ArchiveWidget::done ( int r )
248 if (closeAccepted()) QDialog::done(r);
251 void ArchiveWidget::closeEvent ( QCloseEvent * e )
254 if (closeAccepted()) e->accept();
259 bool ArchiveWidget::closeAccepted()
261 if (!m_extractMode && !archive_url->isEnabled()) {
262 // Archiving in progress, should we stop?
263 if (KMessageBox::warningContinueCancel(this, i18n("Archiving in progress, do you want to stop it?"), i18n("Stop Archiving"), KGuiItem(i18n("Stop Archiving"))) != KMessageBox::Continue) {
266 if (m_copyJob) m_copyJob->kill();
272 void ArchiveWidget::generateItems(QTreeWidgetItem *parentItem, QStringList items)
274 QStringList filesList;
277 bool isSlideshow = parentItem->data(0, Qt::UserRole).toString() == "slideshows";
278 foreach(const QString & file, items) {
279 QTreeWidgetItem *item = new QTreeWidgetItem(parentItem, QStringList() << file);
280 fileName = KUrl(file).fileName();
282 // we store each slideshow in a separate subdirectory
283 item->setData(0, Qt::UserRole, ix);
286 QDir dir(slideUrl.directory(KUrl::AppendTrailingSlash));
287 if (slideUrl.fileName().startsWith(".all.")) {
288 // mimetype slideshow (for example *.png)
291 // TODO: improve jpeg image detection with extension like jpeg, requires change in MLT image producers
292 filters << "*." + slideUrl.fileName().section('.', -1);
293 dir.setNameFilters(filters);
294 QFileInfoList resultList = dir.entryInfoList(QDir::Files);
295 QStringList slideImages;
296 for (int i = 0; i < resultList.count(); i++) {
297 m_requestedSize += resultList.at(i).size();
298 slideImages << resultList.at(i).absoluteFilePath();
300 item->setData(0, Qt::UserRole + 1, slideImages);
303 // pattern url (like clip%.3d.png)
304 QStringList result = dir.entryList(QDir::Files);
305 QString filter = slideUrl.fileName();
306 QString ext = filter.section('.', -1);
307 filter = filter.section('%', 0, -2);
308 QString regexp = "^" + filter + "\\d+\\." + ext + "$";
310 QStringList slideImages;
311 QString directory = dir.absolutePath();
312 if (!directory.endsWith('/')) directory.append('/');
313 foreach(const QString & path, result) {
314 if (rx.exactMatch(path)) {
315 m_requestedSize += QFileInfo(directory + path).size();
316 slideImages << directory + path;
319 item->setData(0, Qt::UserRole + 1, slideImages);
322 else if (filesList.contains(fileName)) {
323 // we have 2 files with same name
325 QString newFileName = fileName.section('.', 0, -2) + "_" + QString::number(ix) + "." + fileName.section('.', -1);
326 while (filesList.contains(newFileName)) {
328 newFileName = fileName.section('.', 0, -2) + "_" + QString::number(ix) + "." + fileName.section('.', -1);
330 fileName = newFileName;
331 item->setData(0, Qt::UserRole, fileName);
334 m_requestedSize += QFileInfo(file).size();
335 filesList << fileName;
340 void ArchiveWidget::slotCheckSpace()
342 KDiskFreeSpaceInfo inf = KDiskFreeSpaceInfo::freeSpaceInfo( archive_url->url().path());
343 KIO::filesize_t freeSize = inf.available();;
344 if (freeSize > m_requestedSize) {
346 buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true);
347 slotDisplayMessage("dialog-ok", i18n("Available space on drive: %1", KIO::convertSize(freeSize)));
350 buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
351 slotDisplayMessage("dialog-close", i18n("Not enough space on drive, free space: %1", KIO::convertSize(freeSize)));
355 bool ArchiveWidget::slotStartArchiving(bool firstPass)
357 if (firstPass && (m_copyJob || m_archiveThread.isRunning())) {
358 // archiving in progress, abort
359 if (m_copyJob) m_copyJob->kill(KJob::EmitResult);
360 m_abortArchive = true;
363 bool isArchive = compressed_archive->isChecked();
364 if (!firstPass) m_copyJob = NULL;
367 m_abortArchive = false;
368 m_duplicateFiles.clear();
369 m_replacementList.clear();
370 m_foldersList.clear();
372 slotDisplayMessage("system-run", i18n("Archiving..."));
374 archive_url->setEnabled(false);
375 compressed_archive->setEnabled(false);
380 QTreeWidgetItem *parentItem;
381 bool isSlideshow = false;
382 for (int i = 0; i < files_list->topLevelItemCount(); i++) {
383 parentItem = files_list->topLevelItem(i);
384 if (parentItem->childCount() > 0 && !parentItem->isDisabled()) {
385 if (parentItem->data(0, Qt::UserRole).toString() == "slideshows") {
386 KUrl slideFolder(archive_url->url().path(KUrl::AddTrailingSlash) + "slideshows");
387 if (isArchive) m_foldersList.append("slideshows");
388 else KIO::NetAccess::mkdir(slideFolder, this);
391 files_list->setCurrentItem(parentItem);
392 if (!isSlideshow) parentItem->setDisabled(true);
393 destPath = parentItem->data(0, Qt::UserRole).toString() + "/";
394 destUrl = KUrl(archive_url->url().path(KUrl::AddTrailingSlash) + destPath);
395 QTreeWidgetItem *item;
396 for (int j = 0; j < parentItem->childCount(); j++) {
397 item = parentItem->child(j);
398 // Special case: slideshows
400 if (item->isDisabled()) {
403 destPath.append(item->data(0, Qt::UserRole).toString() + "/");
404 destUrl = KUrl(archive_url->url().path(KUrl::AddTrailingSlash) + destPath);
405 QStringList srcFiles = item->data(0, Qt::UserRole + 1).toStringList();
406 for (int k = 0; k < srcFiles.count(); k++) {
407 files << KUrl(srcFiles.at(k));
409 item->setDisabled(true);
410 if (parentItem->indexOfChild(item) == parentItem->childCount() - 1) {
411 // We have processed all slideshows
412 parentItem->setDisabled(true);
416 else if (item->data(0, Qt::UserRole).isNull()) {
417 files << KUrl(item->text(0));
420 // We must rename the destination file, since another file with same name exists
421 //TODO: monitor progress
423 m_filesList.insert(item->text(0), destPath + item->data(0, Qt::UserRole).toString());
425 else m_duplicateFiles.insert(KUrl(item->text(0)), KUrl(destUrl.path(KUrl::AddTrailingSlash) + item->data(0, Qt::UserRole).toString()));
432 if (destPath.isEmpty()) {
433 if (m_duplicateFiles.isEmpty()) return false;
434 QMapIterator<KUrl, KUrl> i(m_duplicateFiles);
437 KUrl startJobSrc = i.key();
438 KUrl startJobDst = i.value();
439 m_duplicateFiles.remove(startJobSrc);
440 KIO::CopyJob *job = KIO::copyAs(startJobSrc, startJobDst, KIO::HideProgressInfo);
441 connect(job, SIGNAL(result(KJob *)), this, SLOT(slotArchivingFinished(KJob *)));
442 connect(job, SIGNAL(processedSize(KJob *, qulonglong)), this, SLOT(slotArchivingProgress(KJob *, qulonglong)));
448 m_foldersList.append(destPath);
449 for (int i = 0; i < files.count(); i++) {
450 m_filesList.insert(files.at(i).path(), destPath + files.at(i).fileName());
452 slotArchivingFinished();
454 else if (files.isEmpty()) {
455 slotStartArchiving(false);
458 KIO::NetAccess::mkdir(destUrl, this);
459 m_copyJob = KIO::copy (files, destUrl, KIO::HideProgressInfo);
460 connect(m_copyJob, SIGNAL(result(KJob *)), this, SLOT(slotArchivingFinished(KJob *)));
461 connect(m_copyJob, SIGNAL(processedSize(KJob *, qulonglong)), this, SLOT(slotArchivingProgress(KJob *, qulonglong)));
464 progressBar->setValue(0);
465 buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Abort"));
470 void ArchiveWidget::slotArchivingFinished(KJob *job)
472 if (job == NULL || job->error() == 0) {
473 if (slotStartArchiving(false)) {
474 // We still have files to archive
477 else if (!compressed_archive->isChecked()) {
478 // Archiving finished
479 progressBar->setValue(100);
480 if (processProjectFile()) {
481 slotDisplayMessage("dialog-ok", i18n("Project was successfully archived."));
484 slotDisplayMessage("dialog-close", i18n("There was an error processing project file"));
486 } else processProjectFile();
490 slotDisplayMessage("dialog-close", i18n("There was an error while copying the files: %1", job->errorString()));
492 if (!compressed_archive->isChecked()) {
493 buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Archive"));
494 archive_url->setEnabled(true);
495 compressed_archive->setEnabled(true);
496 for (int i = 0; i < files_list->topLevelItemCount(); i++) {
497 files_list->topLevelItem(i)->setDisabled(false);
498 for (int j = 0; j < files_list->topLevelItem(i)->childCount(); j++)
499 files_list->topLevelItem(i)->child(j)->setDisabled(false);
504 void ArchiveWidget::slotArchivingProgress(KJob *, qulonglong size)
506 progressBar->setValue((int) 100 * size / m_requestedSize);
510 bool ArchiveWidget::processProjectFile()
513 QTreeWidgetItem *item;
514 bool isArchive = compressed_archive->isChecked();
516 for (int i = 0; i < files_list->topLevelItemCount(); i++) {
517 QTreeWidgetItem *parentItem = files_list->topLevelItem(i);
518 if (parentItem->childCount() > 0) {
519 destUrl = KUrl(archive_url->url().path(KUrl::AddTrailingSlash) + parentItem->data(0, Qt::UserRole).toString());
520 bool isSlideshow = parentItem->data(0, Qt::UserRole).toString() == "slideshows";
521 for (int j = 0; j < parentItem->childCount(); j++) {
522 item = parentItem->child(j);
523 KUrl src(item->text(0));
526 dest = KUrl(destUrl.path(KUrl::AddTrailingSlash) + item->data(0, Qt::UserRole).toString() + "/" + src.fileName());
528 else if (item->data(0, Qt::UserRole).isNull()) {
529 dest.addPath(src.fileName());
532 dest.addPath(item->data(0, Qt::UserRole).toString());
534 m_replacementList.insert(src, dest);
539 QDomElement mlt = m_doc.documentElement();
540 QString root = mlt.attribute("root") + "/";
542 // Adjust global settings
544 if (isArchive) basePath = "$CURRENTPATH";
545 else basePath = archive_url->url().path(KUrl::RemoveTrailingSlash);
546 mlt.setAttribute("root", basePath);
547 QDomElement project = mlt.elementsByTagName("kdenlivedoc").at(0).toElement();
548 project.setAttribute("projectfolder", basePath);
550 // process kdenlive producers
551 QDomNodeList prods = mlt.elementsByTagName("kdenlive_producer");
552 for (int i = 0; i < prods.count(); i++) {
553 QDomElement e = prods.item(i).toElement();
554 if (e.isNull()) continue;
555 if (e.hasAttribute("resource")) {
556 KUrl src(e.attribute("resource"));
557 KUrl dest = m_replacementList.value(src);
558 if (!dest.isEmpty()) e.setAttribute("resource", dest.path());
560 if (e.hasAttribute("proxy") && e.attribute("proxy") != "-") {
561 KUrl src(e.attribute("proxy"));
562 KUrl dest = m_replacementList.value(src);
563 if (!dest.isEmpty()) e.setAttribute("proxy", dest.path());
567 // process mlt producers
568 prods = mlt.elementsByTagName("producer");
569 for (int i = 0; i < prods.count(); i++) {
570 QDomElement e = prods.item(i).toElement();
571 if (e.isNull()) continue;
572 QString src = EffectsList::property(e, "resource");
573 if (!src.isEmpty()) {
574 if (!src.startsWith('/')) src.prepend(root);
576 KUrl dest = m_replacementList.value(src);
577 if (!dest.isEmpty()) EffectsList::setProperty(e, "resource", dest.path());
581 // process mlt transitions (for luma files)
582 prods = mlt.elementsByTagName("transition");
584 for (int i = 0; i < prods.count(); i++) {
585 QDomElement e = prods.item(i).toElement();
586 if (e.isNull()) continue;
587 attribute = "resource";
588 QString src = EffectsList::property(e, attribute);
589 if (src.isEmpty()) attribute = "luma";
590 src = EffectsList::property(e, attribute);
591 if (!src.isEmpty()) {
592 if (!src.startsWith('/')) src.prepend(root);
594 KUrl dest = m_replacementList.value(src);
595 if (!dest.isEmpty()) EffectsList::setProperty(e, attribute, dest.path());
599 QString playList = m_doc.toString();
601 QString startString("\"");
602 startString.append(archive_url->url().path(KUrl::RemoveTrailingSlash));
603 QString endString("\"");
604 endString.append(basePath);
605 playList.replace(startString, endString);
606 startString = ">" + archive_url->url().path(KUrl::RemoveTrailingSlash);
607 endString = ">" + basePath;
608 playList.replace(startString, endString);
612 m_temp = new KTemporaryFile;
613 if (!m_temp->open()) KMessageBox::error(this, i18n("Cannot create temporary file"));
614 m_temp->write(playList.toUtf8());
616 m_archiveThread = QtConcurrent::run(this, &ArchiveWidget::createArchive);
620 QString path = archive_url->url().path(KUrl::AddTrailingSlash) + m_name + ".kdenlive";
622 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
623 kWarning() << "////// ERROR writing to file: " << path;
624 KMessageBox::error(this, i18n("Cannot write to file %1", path));
628 file.write(m_doc.toString().toUtf8());
629 if (file.error() != QFile::NoError) {
630 KMessageBox::error(this, i18n("Cannot write to file %1", path));
638 void ArchiveWidget::createArchive()
640 QFileInfo dirInfo(archive_url->url().path());
641 QString user = dirInfo.owner();
642 QString group = dirInfo.group();
643 KTar archive(archive_url->url().path(KUrl::AddTrailingSlash) + m_name + ".tar.gz", "application/x-gzip");
644 archive.open( QIODevice::WriteOnly );
647 foreach(const QString &path, m_foldersList) {
648 archive.writeDir(path, user, group);
653 QMapIterator<QString, QString> i(m_filesList);
654 while (i.hasNext()) {
656 archive.addLocalFile(i.key(), i.value());
657 emit archiveProgress((int) 100 * ix / m_filesList.count());
662 archive.addLocalFile(m_temp->fileName(), m_name + ".kdenlive");
663 bool result = archive.close();
665 emit archivingFinished(result);
668 void ArchiveWidget::slotArchivingFinished(bool result)
671 slotDisplayMessage("dialog-ok", i18n("Project was successfully archived."));
674 slotDisplayMessage("dialog-close", i18n("There was an error processing project file"));
676 progressBar->setValue(100);
677 buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Archive"));
678 archive_url->setEnabled(true);
679 compressed_archive->setEnabled(true);
680 for (int i = 0; i < files_list->topLevelItemCount(); i++) {
681 files_list->topLevelItem(i)->setDisabled(false);
682 for (int j = 0; j < files_list->topLevelItem(i)->childCount(); j++)
683 files_list->topLevelItem(i)->child(j)->setDisabled(false);
687 void ArchiveWidget::slotArchivingProgress(int p)
689 progressBar->setValue(p);
692 void ArchiveWidget::slotStartExtracting()
694 if (m_archiveThread.isRunning()) {
695 //TODO: abort extracting
698 QFileInfo f(m_extractUrl.path());
699 m_requestedSize = f.size();
700 KIO::NetAccess::mkdir(archive_url->url().path(KUrl::RemoveTrailingSlash), this);
701 slotDisplayMessage("system-run", i18n("Extracting..."));
702 buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Abort"));
703 m_progressTimer = new QTimer;
704 m_progressTimer->setInterval(800);
705 m_progressTimer->setSingleShot(false);
706 connect(m_progressTimer, SIGNAL(timeout()), this, SLOT(slotExtractProgress()));
707 m_archiveThread = QtConcurrent::run(this, &ArchiveWidget::doExtracting);
708 m_progressTimer->start();
711 void ArchiveWidget::slotExtractProgress()
713 KIO::DirectorySizeJob *job = KIO::directorySize(archive_url->url());
714 connect(job, SIGNAL(result(KJob*)), this, SLOT(slotGotProgress(KJob*)));
717 void ArchiveWidget::slotGotProgress(KJob* job)
720 KIO::DirectorySizeJob *j = static_cast <KIO::DirectorySizeJob *>(job);
721 progressBar->setValue((int) 100 * j->totalSize() / m_requestedSize);
726 void ArchiveWidget::doExtracting()
728 m_extractArchive->directory()->copyTo(archive_url->url().path(KUrl::AddTrailingSlash));
729 m_extractArchive->close();
730 emit extractingFinished();
733 QString ArchiveWidget::extractedProjectFile()
735 return archive_url->url().path(KUrl::AddTrailingSlash) + m_projectName;
738 void ArchiveWidget::slotExtractingFinished()
740 m_progressTimer->stop();
741 delete m_progressTimer;
742 // Process project file
743 QFile file(extractedProjectFile());
745 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
749 QString playList = file.readAll();
751 if (playList.isEmpty()) {
755 playList.replace("$CURRENTPATH", archive_url->url().path(KUrl::RemoveTrailingSlash));
756 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
757 kWarning() << "////// ERROR writing to file: ";
761 file.write(playList.toUtf8());
762 if (file.error() != QFile::NoError) {
770 KMessageBox::sorry(kapp->activeWindow(), i18n("Cannot open project file %1", extractedProjectFile()), i18n("Cannot open file"));