#include "kdenlivesettings.h"
#include "profilesdialog.h"
#include "docclipbase.h"
+#include "widgets/titlewidget.h"
+#include "effectslist.h"
#include <KStandardDirs>
#include <KMessageBox>
#include <KDebug>
#include <kio/directorysizejob.h>
#include <KIO/NetAccess>
+#include <KTemporaryFile>
+#include <KFileDialog>
#include <QDir>
#include <kmessagebox.h>
-ProjectSettings::ProjectSettings(ProjectList *projectlist, int videotracks, int audiotracks, const QString projectPath, bool readOnlyTracks, bool savedProject, QWidget * parent) :
- QDialog(parent), m_savedProject(savedProject), m_projectList(projectlist)
+ProjectSettings::ProjectSettings(ProjectList *projectlist, QMap <QString, QString> metadata, const QStringList &lumas, int videotracks, int audiotracks, const QString &projectPath, bool readOnlyTracks, bool savedProject, QWidget * parent) :
+ QDialog(parent), m_savedProject(savedProject), m_projectList(projectlist), m_lumas(lumas)
{
setupUi(this);
- list_search->setListWidget(files_list);
+ list_search->setTreeWidget(files_list);
QMap <QString, QString> profilesInfo = ProfilesDialog::getProfilesInfo();
QMapIterator<QString, QString> i(profilesInfo);
project_folder->setUrl(KUrl(projectPath));
QString currentProf = KdenliveSettings::current_profile();
- for (int i = 0; i < profiles_list->count(); i++) {
+ for (int i = 0; i < profiles_list->count(); ++i) {
if (profiles_list->itemData(i).toString() == currentProf) {
profiles_list->setCurrentIndex(i);
break;
video_thumbs->setChecked(KdenliveSettings::videothumbnails());
audio_tracks->setValue(audiotracks);
video_tracks->setValue(videotracks);
+ connect(generate_proxy, SIGNAL(toggled(bool)), proxy_minsize, SLOT(setEnabled(bool)));
+ connect(generate_imageproxy, SIGNAL(toggled(bool)), proxy_imageminsize, SLOT(setEnabled(bool)));
+ QString proxyparameters;
+ QString proxyextension;
+ if (projectlist) {
+ enable_proxy->setChecked(projectlist->getDocumentProperty("enableproxy").toInt());
+ generate_proxy->setChecked(projectlist->getDocumentProperty("generateproxy").toInt());
+ proxy_minsize->setValue(projectlist->getDocumentProperty("proxyminsize").toInt());
+ proxyparameters = projectlist->getDocumentProperty("proxyparams");
+ generate_imageproxy->setChecked(projectlist->getDocumentProperty("generateimageproxy").toInt());
+ proxy_imageminsize->setValue(projectlist->getDocumentProperty("proxyimageminsize").toInt());
+ proxyextension = projectlist->getDocumentProperty("proxyextension");
+ }
+ else {
+ enable_proxy->setChecked(KdenliveSettings::enableproxy());
+ generate_proxy->setChecked(KdenliveSettings::generateproxy());
+ proxy_minsize->setValue(KdenliveSettings::proxyminsize());
+ proxyparameters = KdenliveSettings::proxyparams();
+ generate_imageproxy->setChecked(KdenliveSettings::generateimageproxy());
+ proxy_imageminsize->setValue(KdenliveSettings::proxyimageminsize());
+ proxyextension = KdenliveSettings::proxyextension();
+
+ }
+
+ proxy_minsize->setEnabled(generate_proxy->isChecked());
+ proxy_imageminsize->setEnabled(generate_imageproxy->isChecked());
+
+
+ // load proxy profiles
+ KConfig conf("encodingprofiles.rc", KConfig::CascadeConfig, "appdata");
+ KConfigGroup group(&conf, "proxy");
+ QMap <QString, QString> values = group.entryMap();
+ QMapIterator<QString, QString> k(values);
+ int ix = -1;
+ while (k.hasNext()) {
+ k.next();
+ if (!k.key().isEmpty()) {
+ QString params = k.value().section(';', 0, 0);
+ QString extension = k.value().section(';', 1, 1);
+ if (ix == -1 && ((params == proxyparameters && extension == proxyextension) || (proxyparameters.isEmpty() || proxyextension.isEmpty()))) {
+ // this is the current profile
+ ix = proxy_profile->count();
+ }
+ proxy_profile->addItem(k.key(), k.value());
+ }
+ }
+ if (ix == -1) {
+ // Current project proxy settings not found
+ ix = proxy_profile->count();
+ proxy_profile->addItem(i18n("Current Settings"), QString(proxyparameters + ';' + proxyextension));
+ }
+ proxy_profile->setCurrentIndex(ix);
+ slotUpdateProxyParams();
+
+ // Proxy GUI stuff
+ proxy_showprofileinfo->setIcon(KIcon("help-about"));
+ connect(proxy_profile, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateProxyParams()));
+ proxyparams->setVisible(false);
+ proxyparams->setMaximumHeight(QFontMetrics(font()).lineSpacing() * 5);
+ connect(proxy_showprofileinfo, SIGNAL(clicked(bool)), proxyparams, SLOT(setVisible(bool)));
+
if (readOnlyTracks) {
video_tracks->setEnabled(false);
audio_tracks->setEnabled(false);
}
+
+
+ // Metadata list
+ QTreeWidgetItem *item = new QTreeWidgetItem(metadata_list, QStringList() << i18n("Title"));
+ item->setData(0, Qt::UserRole, QString("meta.attr.title.markup"));
+ if (metadata.contains("meta.attr.title.markup")) {
+ item->setText(1, metadata.value("meta.attr.title.markup"));
+ metadata.remove("meta.attr.title.markup");
+ }
+ item->setFlags(Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ item = new QTreeWidgetItem(metadata_list, QStringList() << i18n("Author"));
+ item->setData(0, Qt::UserRole, QString("meta.attr.author.markup"));
+ if (metadata.contains("meta.attr.author.markup")) {
+ item->setText(1, metadata.value("meta.attr.author.markup"));
+ metadata.remove("meta.attr.author.markup");
+ }
+ else if (metadata.contains("meta.attr.artist.markup")) {
+ item->setText(0, i18n("Artist"));
+ item->setData(0, Qt::UserRole, QString("meta.attr.artist.markup"));
+ item->setText(1, metadata.value("meta.attr.artist.markup"));
+ metadata.remove("meta.attr.artist.markup");
+ }
+ item->setFlags(Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ item = new QTreeWidgetItem(metadata_list, QStringList() << i18n("Copyright"));
+ item->setData(0, Qt::UserRole, QString("meta.attr.copyright.markup"));
+ if (metadata.contains("meta.attr.copyright.markup")) {
+ item->setText(1, metadata.value("meta.attr.copyright.markup"));
+ metadata.remove("meta.attr.copyright.markup");
+ }
+ item->setFlags(Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ item = new QTreeWidgetItem(metadata_list, QStringList() << i18n("Year"));
+ item->setData(0, Qt::UserRole, QString("meta.attr.year.markup"));
+ if (metadata.contains("meta.attr.year.markup")) {
+ item->setText(1, metadata.value("meta.attr.year.markup"));
+ metadata.remove("meta.attr.year.markup");
+ }
+ else if (metadata.contains("meta.attr.date.markup")) {
+ item->setText(0, i18n("Date"));
+ item->setData(0, Qt::UserRole, QString("meta.attr.date.markup"));
+ item->setText(1, metadata.value("meta.attr.date.markup"));
+ metadata.remove("meta.attr.date.markup");
+ }
+ item->setFlags(Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+
+ QMap<QString, QString>::const_iterator meta = metadata.constBegin();
+ while (meta != metadata.constEnd()) {
+ item = new QTreeWidgetItem(metadata_list, QStringList() << meta.key().section('.', 2,2));
+ item->setData(0, Qt::UserRole, meta.key());
+ item->setText(1, meta.value());
+ item->setFlags(Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ ++meta;
+ }
+
+ connect(add_metadata, SIGNAL(clicked()), this, SLOT(slotAddMetadataField()));
+ connect(delete_metadata, SIGNAL(clicked()), this, SLOT(slotDeleteMetadataField()));
+ add_metadata->setIcon(KIcon("list-add"));
+ delete_metadata->setIcon(KIcon("list-remove"));
+
slotUpdateDisplay();
if (m_projectList != NULL) {
slotUpdateFiles();
connect(clear_cache, SIGNAL(clicked()), this, SLOT(slotClearCache()));
connect(delete_unused, SIGNAL(clicked()), this, SLOT(slotDeleteUnused()));
+ connect(delete_proxies, SIGNAL(clicked()), this, SLOT(slotDeleteProxies()));
} else tabWidget->widget(1)->setEnabled(false);
connect(profiles_list, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateDisplay()));
- connect(project_folder, SIGNAL(textChanged(const QString &)), this, SLOT(slotUpdateButton(const QString &)));
+ connect(project_folder, SIGNAL(textChanged(QString)), this, SLOT(slotUpdateButton(QString)));
+ connect(button_export, SIGNAL(clicked()), this, SLOT(slotExportToText()));
}
void ProjectSettings::slotDeleteUnused()
{
QStringList toDelete;
QList <DocClipBase*> list = m_projectList->documentClipList();
- for (int i = 0; i < list.count(); i++) {
+ for (int i = 0; i < list.count(); ++i) {
DocClipBase *clip = list.at(i);
- if (clip->numReferences() == 0 && clip->clipType() != SLIDESHOW) {
+ if (clip->numReferences() == 0 && clip->clipType() != SlideShow) {
KUrl url = clip->fileURL();
- if (!url.isEmpty()) toDelete << url.path();
+ if (!url.isEmpty() && !toDelete.contains(url.path())) toDelete << url.path();
}
}
- toDelete.removeDuplicates();
// make sure our urls are not used in another clip
- for (int i = 0; i < list.count(); i++) {
+ for (int i = 0; i < list.count(); ++i) {
DocClipBase *clip = list.at(i);
if (clip->numReferences() > 0) {
KUrl url = clip->fileURL();
slotUpdateFiles(true);
}
+void ProjectSettings::slotDeleteProxies()
+{
+ if (KMessageBox::warningContinueCancel(this, i18n("Deleting proxy clips will disable proxies for this project.")) != KMessageBox::Continue) return;
+ buttonBox->setEnabled(false);
+ enable_proxy->setChecked(false);
+ emit disableProxies();
+ KIO::NetAccess::del(KUrl(project_folder->url().path(KUrl::AddTrailingSlash) + "proxy/"), this);
+ KStandardDirs::makeDir(project_folder->url().path(KUrl::AddTrailingSlash) + "proxy/");
+ buttonBox->setEnabled(true);
+ slotUpdateFiles(true);
+}
+
void ProjectSettings::slotUpdateFiles(bool cacheOnly)
{
- KIO::DirectorySizeJob * job = KIO::directorySize(project_folder->url().path(KUrl::AddTrailingSlash) + "thumbs/");
+ KIO::DirectorySizeJob *job = KIO::directorySize(project_folder->url().path(KUrl::AddTrailingSlash) + "thumbs/");
job->exec();
thumbs_count->setText(QString::number(job->totalFiles()));
thumbs_size->setText(KIO::convertSize(job->totalSize()));
+ job = KIO::directorySize(project_folder->url().path(KUrl::AddTrailingSlash) + "proxy/");
+ job->exec();
+ proxy_count->setText(QString::number(job->totalFiles()));
+ proxy_size->setText(KIO::convertSize(job->totalSize()));
delete job;
if (cacheOnly) return;
int unused = 0;
files_list->clear();
// List all files that are used in the project. That also means:
- // images included in slideshow
- // TODO: images included in titles, images used in luma transitions, files used in playlist clips, files used for LADSPA effects
+ // images included in slideshow and titles, files in playlist clips
+ // TODO: images used in luma transitions?
- QStringList allFiles;
- for (int i = 0; i < list.count(); i++) {
+ // Setup categories
+ QTreeWidgetItem *videos = new QTreeWidgetItem(files_list, QStringList() << i18n("Video clips"));
+ videos->setIcon(0, KIcon("video-x-generic"));
+ videos->setExpanded(true);
+ QTreeWidgetItem *sounds = new QTreeWidgetItem(files_list, QStringList() << i18n("Audio clips"));
+ sounds->setIcon(0, KIcon("audio-x-generic"));
+ sounds->setExpanded(true);
+ QTreeWidgetItem *images = new QTreeWidgetItem(files_list, QStringList() << i18n("Image clips"));
+ images->setIcon(0, KIcon("image-x-generic"));
+ images->setExpanded(true);
+ QTreeWidgetItem *slideshows = new QTreeWidgetItem(files_list, QStringList() << i18n("Slideshow clips"));
+ slideshows->setIcon(0, KIcon("image-x-generic"));
+ slideshows->setExpanded(true);
+ QTreeWidgetItem *texts = new QTreeWidgetItem(files_list, QStringList() << i18n("Text clips"));
+ texts->setIcon(0, KIcon("text-plain"));
+ texts->setExpanded(true);
+ QTreeWidgetItem *playlists = new QTreeWidgetItem(files_list, QStringList() << i18n("Playlist clips"));
+ playlists->setIcon(0, KIcon("video-mlt-playlist"));
+ playlists->setExpanded(true);
+ QTreeWidgetItem *others = new QTreeWidgetItem(files_list, QStringList() << i18n("Other clips"));
+ others->setIcon(0, KIcon("unknown"));
+ others->setExpanded(true);
+ int count = 0;
+ QStringList allFonts;
+ foreach(const QString & file, m_lumas) {
+ count++;
+ new QTreeWidgetItem(images, QStringList() << file);
+ }
+
+ for (int i = 0; i < list.count(); ++i) {
DocClipBase *clip = list.at(i);
- if (clip->clipType() == SLIDESHOW) {
- // special case, list all images
- QString path = clip->fileURL().directory();
- QString ext = clip->fileURL().path().section('.', -1);
- QDir dir(path);
- QStringList filters;
- filters << "*." + ext;
- dir.setNameFilters(filters);
- QStringList result = dir.entryList(QDir::Files);
- for (int j = 0; j < result.count(); j++) {
- allFiles.append(path + result.at(j));
+ if (clip->clipType() == SlideShow) {
+ QStringList subfiles = extractSlideshowUrls(clip->fileURL());
+ foreach(const QString & file, subfiles) {
+ count++;
+ new QTreeWidgetItem(slideshows, QStringList() << file);
}
- } else if (!clip->fileURL().isEmpty()) allFiles.append(clip->fileURL().path());
+ } else if (!clip->fileURL().isEmpty()) {
+ //allFiles.append(clip->fileURL().path());
+ switch (clip->clipType()) {
+ case Text:
+ new QTreeWidgetItem(texts, QStringList() << clip->fileURL().path());
+ break;
+ case Audio:
+ new QTreeWidgetItem(sounds, QStringList() << clip->fileURL().path());
+ break;
+ case Image:
+ new QTreeWidgetItem(images, QStringList() << clip->fileURL().path());
+ break;
+ case Playlist:
+ new QTreeWidgetItem(playlists, QStringList() << clip->fileURL().path());
+ break;
+ case Unknown:
+ new QTreeWidgetItem(others, QStringList() << clip->fileURL().path());
+ break;
+ default:
+ new QTreeWidgetItem(videos, QStringList() << clip->fileURL().path());
+ break;
+ }
+ count++;
+ }
+ if (clip->clipType() == Text) {
+ QStringList imagefiles = TitleWidget::extractImageList(clip->getProperty("xmldata"));
+ QStringList fonts = TitleWidget::extractFontList(clip->getProperty("xmldata"));
+ foreach(const QString & file, imagefiles) {
+ count++;
+ new QTreeWidgetItem(images, QStringList() << file);
+ }
+ allFonts << fonts;
+ } else if (clip->clipType() == Playlist) {
+ QStringList files = extractPlaylistUrls(clip->fileURL().path());
+ foreach(const QString & file, files) {
+ count++;
+ new QTreeWidgetItem(others, QStringList() << file);
+ }
+ }
if (clip->numReferences() == 0) {
unused++;
usedSize += clip->fileSize();
}
}
- allFiles.removeDuplicates();
- files_count->setText(QString::number(allFiles.count()));
- files_list->addItems(allFiles);
+ allFonts.removeDuplicates();
+ // Hide unused categories
+ for (int i = 0; i < files_list->topLevelItemCount(); ++i) {
+ if (files_list->topLevelItem(i)->childCount() == 0) {
+ files_list->topLevelItem(i)->setHidden(true);
+ }
+ }
+ files_count->setText(QString::number(count));
+ fonts_list->addItems(allFonts);
+ if (allFonts.isEmpty()) {
+ fonts_list->setHidden(true);
+ label_fonts->setHidden(true);
+ }
used_count->setText(QString::number(used));
used_size->setText(KIO::convertSize(usedSize));
unused_count->setText(QString::number(unused));
void ProjectSettings::slotUpdateDisplay()
{
+ QLocale locale;
QString currentProfile = profiles_list->itemData(profiles_list->currentIndex()).toString();
QMap< QString, QString > values = ProfilesDialog::getSettingsFromFile(currentProfile);
p_size->setText(values.value("width") + 'x' + values.value("height"));
p_fps->setText(values.value("frame_rate_num") + '/' + values.value("frame_rate_den"));
p_aspect->setText(values.value("sample_aspect_num") + '/' + values.value("sample_aspect_den"));
p_display->setText(values.value("display_aspect_num") + '/' + values.value("display_aspect_den"));
- if (values.value("progressive").toInt() == 0) p_progressive->setText(i18n("Interlaced"));
- else p_progressive->setText(i18n("Progressive"));
+ if (values.value("progressive").toInt() == 0) {
+ p_progressive->setText(i18n("Interlaced (%1 fields per second)",
+ locale.toString((double)2 * values.value("frame_rate_num").toInt() / values.value("frame_rate_den").toInt(), 'f', 2)));
+ } else {
+ p_progressive->setText(i18n("Progressive"));
+ }
+ p_colorspace->setText(ProfilesDialog::getColorspaceDescription(values.value("colorspace").toInt()));
}
void ProjectSettings::slotUpdateButton(const QString &path)
return project_folder->url();
}
-QPoint ProjectSettings::tracks()
+QPoint ProjectSettings::tracks() const
{
QPoint p;
p.setX(video_tracks->value());
return audio_thumbs->isChecked();
}
+bool ProjectSettings::useProxy() const
+{
+ return enable_proxy->isChecked();
+}
+
+bool ProjectSettings::generateProxy() const
+{
+ return generate_proxy->isChecked();
+}
+
+bool ProjectSettings::generateImageProxy() const
+{
+ return generate_imageproxy->isChecked();
+}
+
+int ProjectSettings::proxyMinSize() const
+{
+ return proxy_minsize->value();
+}
+
+int ProjectSettings::proxyImageMinSize() const
+{
+ return proxy_imageminsize->value();
+}
+
+QString ProjectSettings::proxyParams() const
+{
+ QString params = proxy_profile->itemData(proxy_profile->currentIndex()).toString();
+ return params.section(';', 0, 0);
+}
+
+QString ProjectSettings::proxyExtension() const
+{
+ QString params = proxy_profile->itemData(proxy_profile->currentIndex()).toString();
+ return params.section(';', 1, 1);
+}
+
+//static
+QStringList ProjectSettings::extractPlaylistUrls(const QString &path)
+{
+ QStringList urls;
+ QDomDocument doc;
+ QFile file(path);
+ if (!file.open(QIODevice::ReadOnly))
+ return urls;
+ if (!doc.setContent(&file)) {
+ file.close();
+ return urls;
+ }
+ file.close();
+ QString root = doc.documentElement().attribute("root");
+ if (!root.isEmpty() && !root.endsWith('/')) root.append('/');
+ QDomNodeList files = doc.elementsByTagName("producer");
+ for (int i = 0; i < files.count(); ++i) {
+ QDomElement e = files.at(i).toElement();
+ QString type = EffectsList::property(e, "mlt_service");
+ if (type != "colour") {
+ QString url = EffectsList::property(e, "resource");
+ if (type == "framebuffer") {
+ url = url.section('?', 0, 0);
+ }
+ if (!url.isEmpty()) {
+ if (!url.startsWith('/')) url.prepend(root);
+ if (url.section('.', 0, -2).endsWith("/.all")) {
+ // slideshow clip, extract image urls
+ urls << extractSlideshowUrls(KUrl(url));
+ } else urls << url;
+ if (url.endsWith(".mlt") || url.endsWith(".kdenlive")) {
+ //TODO: Do something to avoid infinite loops if 2 files reference themselves...
+ urls << extractPlaylistUrls(url);
+ }
+ }
+ }
+ }
+
+ // luma files for transitions
+ files = doc.elementsByTagName("transition");
+ for (int i = 0; i < files.count(); ++i) {
+ QDomElement e = files.at(i).toElement();
+ QString url = EffectsList::property(e, "luma");
+ if (!url.isEmpty()) {
+ if (!url.startsWith('/')) url.prepend(root);
+ urls << url;
+ }
+ }
+
+ return urls;
+}
+
+
+//static
+QStringList ProjectSettings::extractSlideshowUrls(const KUrl &url)
+{
+ QStringList urls;
+ QString path = url.directory(KUrl::AppendTrailingSlash);
+ QString ext = url.path().section('.', -1);
+ QDir dir(path);
+ if (url.path().contains(".all.")) {
+ // this is a mime slideshow, like *.jpeg
+ QStringList filters;
+ filters << "*." + ext;
+ dir.setNameFilters(filters);
+ QStringList result = dir.entryList(QDir::Files);
+ urls.append(path + filters.at(0) + " (" + i18np("1 image found", "%1 images found", result.count()) + ')');
+ } else {
+ // this is a pattern slideshow, like sequence%4d.jpg
+ QString filter = url.fileName();
+ QString ext = filter.section('.', -1);
+ filter = filter.section('%', 0, -2);
+ QString regexp = '^' + filter + "\\d+\\." + ext + '$';
+ QRegExp rx(regexp);
+ int count = 0;
+ QStringList result = dir.entryList(QDir::Files);
+ foreach(const QString & path, result) {
+ if (rx.exactMatch(path)) count++;
+ }
+ urls.append(url.path() + " (" + i18np("1 image found", "%1 images found", count) + ')');
+ }
+ return urls;
+}
+
+void ProjectSettings::slotExportToText()
+{
+ QString savePath = KFileDialog::getSaveFileName(project_folder->url(), "text/plain", this);
+ if (savePath.isEmpty()) return;
+ QString data;
+ data.append(i18n("Project folder: %1", project_folder->url().path()) + '\n');
+ data.append(i18n("Project profile: %1", profiles_list->currentText()) + '\n');
+ data.append(i18n("Total clips: %1 (%2 used in timeline).", files_count->text(), used_count->text()) + "\n\n");
+ for (int i = 0; i < files_list->topLevelItemCount(); ++i) {
+ if (files_list->topLevelItem(i)->childCount() > 0) {
+ data.append('\n' + files_list->topLevelItem(i)->text(0) + ":\n\n");
+ for (int j = 0; j < files_list->topLevelItem(i)->childCount(); j++) {
+ data.append(files_list->topLevelItem(i)->child(j)->text(0) + '\n');
+ }
+ }
+ }
+ KTemporaryFile tmpfile;
+ if (!tmpfile.open()) {
+ kWarning() << "///// CANNOT CREATE TMP FILE in: " << tmpfile.fileName();
+ return;
+ }
+ QFile xmlf(tmpfile.fileName());
+ if (!xmlf.open(QIODevice::WriteOnly))
+ return;
+ xmlf.write(data.toUtf8());
+ if (xmlf.error() != QFile::NoError) {
+ xmlf.close();
+ return;
+ }
+ xmlf.close();
+ KIO::NetAccess::upload(tmpfile.fileName(), savePath, 0);
+}
+
+void ProjectSettings::slotUpdateProxyParams()
+{
+ QString params = proxy_profile->itemData(proxy_profile->currentIndex()).toString();
+ proxyparams->setPlainText(params.section(';', 0, 0));
+}
+
+const QMap <QString, QString> ProjectSettings::metadata() const
+{
+ QMap <QString, QString> metadata;
+ for (int i = 0; i < metadata_list->topLevelItemCount(); ++i)
+ {
+ QTreeWidgetItem *item = metadata_list->topLevelItem(i);
+ if (!item->text(1).simplified().isEmpty()) {
+ // Insert metadata entry
+ QString key = item->data(0, Qt::UserRole).toString();
+ if (key.isEmpty()) key = "meta.attr." + item->text(0).simplified() + ".markup";
+ QString value = item->text(1);
+ metadata.insert(key, value);
+ }
+ }
+ return metadata;
+}
+
+void ProjectSettings::slotAddMetadataField()
+{
+ QTreeWidgetItem *item = new QTreeWidgetItem(metadata_list, QStringList() << i18n("field_name"));
+ item->setFlags(Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+}
+
+void ProjectSettings::slotDeleteMetadataField()
+{
+ QTreeWidgetItem *item = metadata_list->currentItem();
+ if (item) delete item;
+}
+
#include "projectsettings.moc"