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.contains(url.path())) toDelete << url.path();
92 // make sure our urls are not used in another clip
93 for (int i = 0; i < list.count(); i++) {
94 DocClipBase *clip = list.at(i);
95 if (clip->numReferences() > 0) {
96 KUrl url = clip->fileURL();
97 if (!url.isEmpty() && toDelete.contains(url.path())) toDelete.removeAll(url.path());
101 if (toDelete.count() == 0) {
102 // No physical url to delete, we only remove unused clips from project (color clips for example have no physical url)
103 if (KMessageBox::warningContinueCancel(this, i18n("This will remove all unused clips from your project."), i18n("Clean up project")) == KMessageBox::Cancel) return;
104 m_projectList->cleanup();
108 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;
109 m_projectList->trashUnusedClips();
113 void ProjectSettings::slotClearCache()
115 buttonBox->setEnabled(false);
116 KIO::NetAccess::del(KUrl(project_folder->url().path(KUrl::AddTrailingSlash) + "thumbs/"), this);
117 KStandardDirs::makeDir(project_folder->url().path(KUrl::AddTrailingSlash) + "thumbs/");
118 buttonBox->setEnabled(true);
119 slotUpdateFiles(true);
122 void ProjectSettings::slotUpdateFiles(bool cacheOnly)
124 KIO::DirectorySizeJob * job = KIO::directorySize(project_folder->url().path(KUrl::AddTrailingSlash) + "thumbs/");
126 thumbs_count->setText(QString::number(job->totalFiles()));
127 thumbs_size->setText(KIO::convertSize(job->totalSize()));
129 if (cacheOnly) return;
132 KIO::filesize_t usedSize = 0;
133 KIO::filesize_t unUsedSize = 0;
134 QList <DocClipBase*> list = m_projectList->documentClipList();
137 // List all files that are used in the project. That also means:
138 // images included in slideshow and titles, files in playlist clips
139 // TODO: images used in luma transitions, files used for LADSPA effects?
141 QStringList allFiles;
143 for (int i = 0; i < list.count(); i++) {
144 DocClipBase *clip = list.at(i);
145 if (clip->clipType() == SLIDESHOW) {
146 // special case, list all images
147 QStringList files = extractSlideshowUrls(clip->fileURL());
149 } else if (!clip->fileURL().isEmpty()) allFiles.append(clip->fileURL().path());
150 if (clip->clipType() == TEXT) {
151 QStringList images = TitleWidget::extractImageList(clip->getProperty("xmldata"));
153 } else if (clip->clipType() == PLAYLIST) {
154 QStringList files = extractPlaylistUrls(clip->fileURL().path());
158 if (clip->numReferences() == 0) {
160 unUsedSize += clip->fileSize();
163 usedSize += clip->fileSize();
166 #if QT_VERSION >= 0x040500
167 allFiles.removeDuplicates();
169 files_count->setText(QString::number(allFiles.count()));
170 files_list->addItems(allFiles);
171 used_count->setText(QString::number(used));
172 used_size->setText(KIO::convertSize(usedSize));
173 unused_count->setText(QString::number(unused));
174 unused_size->setText(KIO::convertSize(unUsedSize));
175 delete_unused->setEnabled(unused > 0);
178 void ProjectSettings::accept()
180 if (!m_savedProject && selectedProfile() != KdenliveSettings::current_profile())
181 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;
185 void ProjectSettings::slotUpdateDisplay()
187 QString currentProfile = profiles_list->itemData(profiles_list->currentIndex()).toString();
188 QMap< QString, QString > values = ProfilesDialog::getSettingsFromFile(currentProfile);
189 p_size->setText(values.value("width") + 'x' + values.value("height"));
190 p_fps->setText(values.value("frame_rate_num") + '/' + values.value("frame_rate_den"));
191 p_aspect->setText(values.value("sample_aspect_num") + '/' + values.value("sample_aspect_den"));
192 p_display->setText(values.value("display_aspect_num") + '/' + values.value("display_aspect_den"));
193 if (values.value("progressive").toInt() == 0) p_progressive->setText(i18n("Interlaced"));
194 else p_progressive->setText(i18n("Progressive"));
197 void ProjectSettings::slotUpdateButton(const QString &path)
199 if (path.isEmpty()) m_buttonOk->setEnabled(false);
201 m_buttonOk->setEnabled(true);
202 slotUpdateFiles(true);
206 QString ProjectSettings::selectedProfile() const
208 return profiles_list->itemData(profiles_list->currentIndex()).toString();
211 KUrl ProjectSettings::selectedFolder() const
213 return project_folder->url();
216 QPoint ProjectSettings::tracks()
219 p.setX(video_tracks->value());
220 p.setY(audio_tracks->value());
224 bool ProjectSettings::enableVideoThumbs() const
226 return video_thumbs->isChecked();
229 bool ProjectSettings::enableAudioThumbs() const
231 return audio_thumbs->isChecked();
235 QStringList ProjectSettings::extractPlaylistUrls(QString path)
240 if (!file.open(QIODevice::ReadOnly))
242 if (!doc.setContent(&file)) {
247 QString root = doc.documentElement().attribute("root");
248 if (!root.isEmpty() && !root.endsWith('/')) root.append('/');
249 QDomNodeList files = doc.elementsByTagName("producer");
250 for (int i = 0; i < files.count(); i++) {
251 QDomElement e = files.at(i).toElement();
252 QString type = EffectsList::property(e, "mlt_service");
253 if (type != "colour") {
254 QString url = EffectsList::property(e, "resource");
255 if (!url.isEmpty()) {
256 if (!url.startsWith('/')) url.prepend(root);
257 if (url.section('.', 0, -2).endsWith("/.all")) {
258 // slideshow clip, extract image urls
259 urls << extractSlideshowUrls(KUrl(url));
261 if (url.endsWith(".mlt") || url.endsWith(".kdenlive")) {
262 //TODO: Do something to avoid infinite loops if 2 files reference themselves...
263 urls << extractPlaylistUrls(url);
269 // luma files for transitions
270 files = doc.elementsByTagName("transition");
271 for (int i = 0; i < files.count(); i++) {
272 QDomElement e = files.at(i).toElement();
273 QString url = EffectsList::property(e, "luma");
274 if (!url.isEmpty()) {
275 if (!url.startsWith('/')) url.prepend(root);
285 QStringList ProjectSettings::extractSlideshowUrls(KUrl url)
288 QString path = url.directory(KUrl::AppendTrailingSlash);
289 QString ext = url.path().section('.', -1);
292 filters << "*." + ext;
293 dir.setNameFilters(filters);
294 QStringList result = dir.entryList(QDir::Files);
295 for (int j = 0; j < result.count(); j++) {
296 urls.append(path + result.at(j));
301 #include "projectsettings.moc"