1 /***************************************************************************
2 * Copyright (C) 2008 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 ***************************************************************************/
20 #include "projectsettings.h"
21 #include "kdenlivesettings.h"
22 #include "profilesdialog.h"
23 #include "docclipbase.h"
24 #include "titlewidget.h"
25 #include "effectslist.h"
27 #include <KStandardDirs>
28 #include <KMessageBox>
30 #include <kio/directorysizejob.h>
31 #include <KIO/NetAccess>
34 #include <kmessagebox.h>
36 ProjectSettings::ProjectSettings(ProjectList *projectlist, QStringList lumas, int videotracks, int audiotracks, const QString projectPath, bool readOnlyTracks, bool savedProject, QWidget * parent) :
37 QDialog(parent), m_savedProject(savedProject), m_projectList(projectlist), m_lumas(lumas)
41 list_search->setListWidget(files_list);
43 QMap <QString, QString> profilesInfo = ProfilesDialog::getProfilesInfo();
44 QMapIterator<QString, QString> i(profilesInfo);
47 profiles_list->addItem(i.key(), i.value());
49 project_folder->setMode(KFile::Directory);
50 project_folder->setUrl(KUrl(projectPath));
51 QString currentProf = KdenliveSettings::current_profile();
53 for (int i = 0; i < profiles_list->count(); i++) {
54 if (profiles_list->itemData(i).toString() == currentProf) {
55 profiles_list->setCurrentIndex(i);
60 m_buttonOk = buttonBox->button(QDialogButtonBox::Ok);
61 //buttonOk->setEnabled(false);
62 audio_thumbs->setChecked(KdenliveSettings::audiothumbnails());
63 video_thumbs->setChecked(KdenliveSettings::videothumbnails());
64 audio_tracks->setValue(audiotracks);
65 video_tracks->setValue(videotracks);
67 video_tracks->setEnabled(false);
68 audio_tracks->setEnabled(false);
71 if (m_projectList != NULL) {
73 connect(clear_cache, SIGNAL(clicked()), this, SLOT(slotClearCache()));
74 connect(delete_unused, SIGNAL(clicked()), this, SLOT(slotDeleteUnused()));
75 } else tabWidget->widget(1)->setEnabled(false);
76 connect(profiles_list, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateDisplay()));
77 connect(project_folder, SIGNAL(textChanged(const QString &)), this, SLOT(slotUpdateButton(const QString &)));
80 void ProjectSettings::slotDeleteUnused()
83 QList <DocClipBase*> list = m_projectList->documentClipList();
84 for (int i = 0; i < list.count(); i++) {
85 DocClipBase *clip = list.at(i);
86 if (clip->numReferences() == 0 && clip->clipType() != SLIDESHOW) {
87 KUrl url = clip->fileURL();
88 if (!url.isEmpty()) toDelete << url.path();
91 toDelete.removeDuplicates();
93 // make sure our urls are not used in another clip
94 for (int i = 0; i < list.count(); i++) {
95 DocClipBase *clip = list.at(i);
96 if (clip->numReferences() > 0) {
97 KUrl url = clip->fileURL();
98 if (!url.isEmpty() && toDelete.contains(url.path())) toDelete.removeAll(url.path());
102 if (toDelete.count() == 0) {
103 // No physical url to delete, we only remove unused clips from project (color clips for example have no physical url)
104 if (KMessageBox::warningContinueCancel(this, i18n("This will remove all unused clips from your project."), i18n("Clean up project")) == KMessageBox::Cancel) return;
105 m_projectList->cleanup();
109 if (KMessageBox::warningYesNoList(this, i18n("This will remove the following files from your hard drive.\nThis action cannot be undone, only use if you know what you are doing.\nAre you sure you want to continue?"), toDelete, i18n("Delete unused clips")) != KMessageBox::Yes) return;
110 m_projectList->trashUnusedClips();
114 void ProjectSettings::slotClearCache()
116 buttonBox->setEnabled(false);
117 KIO::NetAccess::del(KUrl(project_folder->url().path(KUrl::AddTrailingSlash) + "thumbs/"), this);
118 KStandardDirs::makeDir(project_folder->url().path(KUrl::AddTrailingSlash) + "thumbs/");
119 buttonBox->setEnabled(true);
120 slotUpdateFiles(true);
123 void ProjectSettings::slotUpdateFiles(bool cacheOnly)
125 KIO::DirectorySizeJob * job = KIO::directorySize(project_folder->url().path(KUrl::AddTrailingSlash) + "thumbs/");
127 thumbs_count->setText(QString::number(job->totalFiles()));
128 thumbs_size->setText(KIO::convertSize(job->totalSize()));
130 if (cacheOnly) return;
133 KIO::filesize_t usedSize = 0;
134 KIO::filesize_t unUsedSize = 0;
135 QList <DocClipBase*> list = m_projectList->documentClipList();
138 // List all files that are used in the project. That also means:
139 // images included in slideshow and titles, files in playlist clips
140 // TODO: images used in luma transitions, files used for LADSPA effects?
142 QStringList allFiles;
144 for (int i = 0; i < list.count(); i++) {
145 DocClipBase *clip = list.at(i);
146 if (clip->clipType() == SLIDESHOW) {
147 // special case, list all images
148 QStringList files = extractSlideshowUrls(clip->fileURL());
150 } else if (!clip->fileURL().isEmpty()) allFiles.append(clip->fileURL().path());
151 if (clip->clipType() == TEXT) {
152 QStringList images = TitleWidget::extractImageList(clip->getProperty("xmldata"));
154 } else if (clip->clipType() == PLAYLIST) {
155 QStringList files = extractPlaylistUrls(clip->fileURL().path());
159 if (clip->numReferences() == 0) {
161 unUsedSize += clip->fileSize();
164 usedSize += clip->fileSize();
167 allFiles.removeDuplicates();
168 files_count->setText(QString::number(allFiles.count()));
169 files_list->addItems(allFiles);
170 used_count->setText(QString::number(used));
171 used_size->setText(KIO::convertSize(usedSize));
172 unused_count->setText(QString::number(unused));
173 unused_size->setText(KIO::convertSize(unUsedSize));
174 delete_unused->setEnabled(unused > 0);
177 void ProjectSettings::accept()
179 if (!m_savedProject && selectedProfile() != KdenliveSettings::current_profile())
180 if (KMessageBox::warningContinueCancel(this, i18n("Changing the profile of your project cannot be undone.\nIt is recommended to save your project before attempting this operation that might cause some corruption in transitions.\n Are you sure you want to proceed?"), i18n("Confirm profile change")) == KMessageBox::Cancel) return;
184 void ProjectSettings::slotUpdateDisplay()
186 QString currentProfile = profiles_list->itemData(profiles_list->currentIndex()).toString();
187 QMap< QString, QString > values = ProfilesDialog::getSettingsFromFile(currentProfile);
188 p_size->setText(values.value("width") + 'x' + values.value("height"));
189 p_fps->setText(values.value("frame_rate_num") + '/' + values.value("frame_rate_den"));
190 p_aspect->setText(values.value("sample_aspect_num") + '/' + values.value("sample_aspect_den"));
191 p_display->setText(values.value("display_aspect_num") + '/' + values.value("display_aspect_den"));
192 if (values.value("progressive").toInt() == 0) p_progressive->setText(i18n("Interlaced"));
193 else p_progressive->setText(i18n("Progressive"));
196 void ProjectSettings::slotUpdateButton(const QString &path)
198 if (path.isEmpty()) m_buttonOk->setEnabled(false);
200 m_buttonOk->setEnabled(true);
201 slotUpdateFiles(true);
205 QString ProjectSettings::selectedProfile() const
207 return profiles_list->itemData(profiles_list->currentIndex()).toString();
210 KUrl ProjectSettings::selectedFolder() const
212 return project_folder->url();
215 QPoint ProjectSettings::tracks()
218 p.setX(video_tracks->value());
219 p.setY(audio_tracks->value());
223 bool ProjectSettings::enableVideoThumbs() const
225 return video_thumbs->isChecked();
228 bool ProjectSettings::enableAudioThumbs() const
230 return audio_thumbs->isChecked();
234 QStringList ProjectSettings::extractPlaylistUrls(QString path)
239 if (!file.open(QIODevice::ReadOnly))
241 if (!doc.setContent(&file)) {
246 QString root = doc.documentElement().attribute("root");
247 if (!root.isEmpty() && !root.endsWith('/')) root.append('/');
248 QDomNodeList files = doc.elementsByTagName("producer");
249 for (int i = 0; i < files.count(); i++) {
250 QDomElement e = files.at(i).toElement();
251 QString type = EffectsList::property(e, "mlt_service");
252 if (type != "colour") {
253 QString url = EffectsList::property(e, "resource");
254 if (!url.isEmpty()) {
255 if (!url.startsWith('/')) url.prepend(root);
256 if (url.section('.', 0, -2).endsWith("/.all")) {
257 // slideshow clip, extract image urls
258 urls << extractSlideshowUrls(KUrl(url));
260 if (url.endsWith(".mlt") || url.endsWith(".kdenlive")) {
261 //TODO: Do something to avoid infinite loops if 2 files reference themselves...
262 urls << extractPlaylistUrls(url);
268 // luma files for transitions
269 files = doc.elementsByTagName("transition");
270 for (int i = 0; i < files.count(); i++) {
271 QDomElement e = files.at(i).toElement();
272 QString url = EffectsList::property(e, "luma");
273 if (!url.isEmpty()) {
274 if (!url.startsWith('/')) url.prepend(root);
284 QStringList ProjectSettings::extractSlideshowUrls(KUrl url)
287 QString path = url.directory(KUrl::AppendTrailingSlash);
288 QString ext = url.path().section('.', -1);
291 filters << "*." + ext;
292 dir.setNameFilters(filters);
293 QStringList result = dir.entryList(QDir::Files);
294 for (int j = 0; j < result.count(); j++) {
295 urls.append(path + result.at(j));
300 #include "projectsettings.moc"