]> cloud.milkyroute.net Git - dolphin.git/blob - src/panels/information/metadatawidget.cpp
the configuration menu should be shown also for multiple selections
[dolphin.git] / src / panels / information / metadatawidget.cpp
1 /***************************************************************************
2 * Copyright (C) 2008 by Sebastian Trueg <trueg@kde.org> *
3 * Copyright (C) 2009 by Peter Penz <peter.penz@gmx.at> *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
19 ***************************************************************************/
20
21 #include "metadatawidget.h"
22
23 #include <kconfig.h>
24 #include <kconfiggroup.h>
25 #include <kfileitem.h>
26 #include <kglobalsettings.h>
27 #include <klocale.h>
28
29 #include <QFontMetrics>
30 #include <QGridLayout>
31 #include <QLabel>
32 #include <QList>
33 #include <QString>
34
35 #include <config-nepomuk.h>
36 #ifdef HAVE_NEPOMUK
37 #define DISABLE_NEPOMUK_LEGACY
38
39 #include "commentwidget_p.h"
40 #include "nepomukmassupdatejob_p.h"
41 #include "taggingwidget_p.h"
42
43 #include <Nepomuk/KRatingWidget>
44 #include <Nepomuk/Resource>
45 #include <Nepomuk/ResourceManager>
46 #include <Nepomuk/Types/Property>
47 #include <Nepomuk/Variant>
48
49 #include <QMutex>
50 #include <QSpacerItem>
51 #include <QThread>
52 #endif
53
54 #include <kdebug.h>
55
56 class MetaDataWidget::Private
57 {
58 public:
59 struct Row
60 {
61 QLabel* label;
62 QWidget* infoWidget;
63 };
64
65 Private(MetaDataWidget* parent);
66 ~Private();
67
68 void addRow(QLabel* label, QWidget* infoWidget);
69 void removeMetaInfoRows();
70 void setRowVisible(QWidget* infoWidget, bool visible);
71
72 /**
73 * Initializes the configuration file "kmetainformationrc"
74 * with proper default settings for the first start in
75 * an uninitialized environment.
76 */
77 void initMetaInfoSettings();
78
79 /**
80 * Parses the configuration file "kmetainformationrc" and
81 * updates the visibility of all rows.
82 */
83 void updateRowsVisibility();
84
85 void slotLoadingFinished();
86 void slotRatingChanged(unsigned int rating);
87 void slotTagsChanged(const QList<Nepomuk::Tag>& tags);
88 void slotCommentChanged(const QString& comment);
89 void slotMetaDataUpdateDone();
90
91 /**
92 * Disables the metadata widget and starts the job that
93 * changes the meta data asynchronously. After the job
94 * has been finished, the metadata widget gets enabled again.
95 */
96 void startChangeDataJob(KJob* job);
97
98 MetaDataTypes m_hiddenData;
99 QList<KFileItem> m_fileItems;
100 QList<Row> m_rows;
101
102 QGridLayout* m_gridLayout;
103
104 QLabel* m_typeInfo;
105 QLabel* m_sizeLabel;
106 QLabel* m_sizeInfo;
107 QLabel* m_modifiedInfo;
108 QLabel* m_ownerInfo;
109 QLabel* m_permissionsInfo;
110
111 #ifdef HAVE_NEPOMUK
112 KRatingWidget* m_ratingWidget;
113 TaggingWidget* m_taggingWidget;
114 CommentWidget* m_commentWidget;
115
116 // shared data between the GUI-thread and
117 // the loader-thread (see LoadFilesThread):
118 QMutex m_mutex;
119 struct SharedData
120 {
121 int rating;
122 QString comment;
123 QList<Nepomuk::Tag> tags;
124 QList<QString> metaInfoLabels;
125 QList<QString> metaInfoValues;
126 QMap<KUrl, Nepomuk::Resource> files;
127 } m_sharedData;
128
129 /**
130 * Loads the meta data of files and writes
131 * the result into a shared data pool that
132 * can be used by the widgets in the GUI thread.
133 */
134 class LoadFilesThread : public QThread
135 {
136 public:
137 LoadFilesThread(SharedData* m_sharedData, QMutex* m_mutex);
138 virtual ~LoadFilesThread();
139 void loadFiles(const KUrl::List& urls);
140 virtual void run();
141
142 private:
143 /**
144 * Assures that the settings for the meta information
145 * are initialized with proper default values.
146 */
147 void initMetaInfoSettings(KConfigGroup& group);
148
149 /**
150 * Temporary helper method for KDE 4.3 as we currently don't get
151 * translated labels for Nepmok literals: Replaces camelcase labels
152 * like "fileLocation" by "File Location:".
153 */
154 QString tunedLabel(const QString& label) const;
155
156 private:
157 SharedData* m_sharedData;
158 QMutex* m_mutex;
159 KUrl::List m_urls;
160 bool m_canceled;
161 };
162
163 LoadFilesThread* m_loadFilesThread;
164 #endif
165
166 private:
167 MetaDataWidget* const q;
168 };
169
170 MetaDataWidget::Private::Private(MetaDataWidget* parent) :
171 m_hiddenData(None),
172 m_fileItems(),
173 m_rows(),
174 m_gridLayout(0),
175 m_typeInfo(0),
176 m_sizeLabel(0),
177 m_sizeInfo(0),
178 m_modifiedInfo(0),
179 m_ownerInfo(0),
180 m_permissionsInfo(0),
181 #ifdef HAVE_NEPOMUK
182 m_ratingWidget(0),
183 m_taggingWidget(0),
184 m_commentWidget(0),
185 m_loadFilesThread(0),
186 #endif
187 q(parent)
188 {
189 m_gridLayout = new QGridLayout(parent);
190 m_gridLayout->setMargin(0);
191
192 m_typeInfo = new QLabel(parent);
193 m_sizeLabel = new QLabel(parent);
194 m_sizeInfo = new QLabel(parent);
195 m_modifiedInfo = new QLabel(parent);
196 m_ownerInfo = new QLabel(parent);
197 m_permissionsInfo = new QLabel(parent);
198
199 addRow(new QLabel(i18nc("@label", "Type:"), parent), m_typeInfo);
200 addRow(m_sizeLabel, m_sizeInfo);
201 addRow(new QLabel(i18nc("@label", "Modified:"), parent), m_modifiedInfo);
202 addRow(new QLabel(i18nc("@label", "Owner:"), parent), m_ownerInfo);
203 addRow(new QLabel(i18nc("@label", "Permissions:"), parent), m_permissionsInfo);
204
205 #ifdef HAVE_NEPOMUK
206 if (Nepomuk::ResourceManager::instance()->init() == 0) {
207 const QFontMetrics fontMetrics(KGlobalSettings::smallestReadableFont());
208 m_ratingWidget = new KRatingWidget(parent);
209 m_ratingWidget->setFixedHeight(fontMetrics.height());
210 connect(m_ratingWidget, SIGNAL(ratingChanged(unsigned int)),
211 q, SLOT(slotRatingChanged(unsigned int)));
212
213 m_taggingWidget = new TaggingWidget(parent);
214 connect(m_taggingWidget, SIGNAL(tagsChanged(const QList<Nepomuk::Tag>&)),
215 q, SLOT(slotTagsChanged(const QList<Nepomuk::Tag>&)));
216
217 m_commentWidget = new CommentWidget(parent);
218 connect(m_commentWidget, SIGNAL(commentChanged(const QString&)),
219 q, SLOT(slotCommentChanged(const QString&)));
220
221 addRow(new QLabel(i18nc("@label", "Rating:"), parent), m_ratingWidget);
222 addRow(new QLabel(i18nc("@label", "Tags:"), parent), m_taggingWidget);
223 addRow(new QLabel(i18nc("@label", "Comment:"), parent), m_commentWidget);
224
225 m_loadFilesThread = new LoadFilesThread(&m_sharedData, &m_mutex);
226 connect(m_loadFilesThread, SIGNAL(finished()), q, SLOT(slotLoadingFinished()));
227 }
228
229 m_sharedData.rating = 0;
230 #endif
231
232 initMetaInfoSettings();
233 updateRowsVisibility();
234 }
235
236 MetaDataWidget::Private::~Private()
237 {
238 #ifdef HAVE_NEPOMUK
239 delete m_loadFilesThread;
240 #endif
241 }
242
243 void MetaDataWidget::Private::addRow(QLabel* label, QWidget* infoWidget)
244 {
245 Row row;
246 row.label = label;
247 row.infoWidget = infoWidget;
248 m_rows.append(row);
249
250 const QFont smallFont = KGlobalSettings::smallestReadableFont();
251 // use a brighter color for the label and a small font size
252 QPalette palette = label->palette();
253 QColor textColor = palette.color(QPalette::Text);
254 textColor.setAlpha(128);
255 palette.setColor(QPalette::WindowText, textColor);
256 label->setPalette(palette);
257 label->setFont(smallFont);
258 label->setWordWrap(true);
259 label->setAlignment(Qt::AlignTop | Qt::AlignRight);
260
261 QLabel* infoLabel = qobject_cast<QLabel*>(infoWidget);
262 if (infoLabel != 0) {
263 infoLabel->setFont(smallFont);
264 infoLabel->setWordWrap(true);
265 infoLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft);
266 }
267
268 // add the row to grid layout
269 const int rowIndex = m_rows.count();
270 m_gridLayout->addWidget(label, rowIndex, 0, Qt::AlignRight);
271 const int spacerWidth = QFontMetrics(smallFont).size(Qt::TextSingleLine, " ").width();
272 m_gridLayout->addItem(new QSpacerItem(spacerWidth, 1), rowIndex, 1);
273 m_gridLayout->addWidget(infoWidget, rowIndex, 2, Qt::AlignLeft);
274 }
275
276 void MetaDataWidget::Private::setRowVisible(QWidget* infoWidget, bool visible)
277 {
278 foreach (const Row& row, m_rows) {
279 if (row.infoWidget == infoWidget) {
280 row.label->setVisible(visible);
281 row.infoWidget->setVisible(visible);
282 return;
283 }
284 }
285 }
286
287
288 void MetaDataWidget::Private::initMetaInfoSettings()
289 {
290 KConfig config("kmetainformationrc", KConfig::NoGlobals);
291 KConfigGroup settings = config.group("Show");
292 if (!settings.readEntry("initialized", false)) {
293 // The resource file is read the first time. Assure
294 // that some meta information is disabled per default.
295
296 static const char* disabledProperties[] = {
297 "asText", "contentSize", "created", "depth", "description", "fileExtension",
298 "fileName", "fileSize", "hasTag", "isPartOf", "lastModified", "mimeType", "name",
299 "numericRating", "parentUrl", "permissions", "plainTextContent", "owner",
300 "sourceModified", "url",
301 0 // mandatory last entry
302 };
303
304 int i = 0;
305 while (disabledProperties[i] != 0) {
306 settings.writeEntry(disabledProperties[i], false);
307 ++i;
308 }
309
310 // mark the group as initialized
311 settings.writeEntry("initialized", true);
312 }
313 }
314
315 void MetaDataWidget::Private::updateRowsVisibility()
316 {
317 KConfig config("kmetainformationrc", KConfig::NoGlobals);
318 KConfigGroup settings = config.group("Show");
319 setRowVisible(m_typeInfo,
320 !(m_hiddenData & MetaDataWidget::TypeData) &&
321 settings.readEntry("type", true));
322 setRowVisible(m_sizeInfo,
323 !(m_hiddenData & MetaDataWidget::SizeData) &&
324 settings.readEntry("size", true));
325 setRowVisible(m_modifiedInfo,
326 !(m_hiddenData & MetaDataWidget::ModifiedData) &&
327 settings.readEntry("modified", true));
328 setRowVisible(m_ownerInfo,
329 !(m_hiddenData & MetaDataWidget::OwnerData) &&
330 settings.readEntry("owner", true));
331 setRowVisible(m_permissionsInfo,
332 !(m_hiddenData & MetaDataWidget::PermissionsData) &&
333 settings.readEntry("permissions", true));
334 #ifdef HAVE_NEPOMUK
335 if (Nepomuk::ResourceManager::instance()->init() == 0) {
336 setRowVisible(m_ratingWidget,
337 !(m_hiddenData & MetaDataWidget::RatingData) &&
338 settings.readEntry("rating", true));
339 setRowVisible(m_taggingWidget,
340 !(m_hiddenData & MetaDataWidget::TagsData) &&
341 settings.readEntry("tagging", true));
342 setRowVisible(m_commentWidget,
343 !(m_hiddenData & MetaDataWidget::CommentData) &&
344 settings.readEntry("comment", true));
345 }
346 #endif
347 }
348
349 void MetaDataWidget::Private::slotLoadingFinished()
350 {
351 #ifdef HAVE_NEPOMUK
352 QMutexLocker locker(&m_mutex);
353 m_ratingWidget->setRating(m_sharedData.rating);
354 m_commentWidget->setText(m_sharedData.comment);
355 m_taggingWidget->setTags(m_sharedData.tags);
356
357 // Show the remaining meta information as text. The number
358 // of required rows may very. Existing rows are reused to
359 // prevent flickering.
360 int index = 8; // TODO: don't hardcode this value here
361 const int rowCount = m_rows.count();
362 Q_ASSERT(rowCount >= index);
363
364 Q_ASSERT(m_sharedData.metaInfoLabels.count() == m_sharedData.metaInfoValues.count());
365 const int metaInfoCount = m_sharedData.metaInfoLabels.count();
366 for (int i = 0; i < metaInfoCount; ++i) {
367 if (index < rowCount) {
368 // adjust texts of the current row
369 m_rows[index].label->setText(m_sharedData.metaInfoLabels[i]);
370 QLabel* infoValueLabel = qobject_cast<QLabel*>(m_rows[index].infoWidget);
371 Q_ASSERT(infoValueLabel != 0);
372 infoValueLabel->setText(m_sharedData.metaInfoValues[i]);
373 } else {
374 // create new row
375 QLabel* infoLabel = new QLabel(m_sharedData.metaInfoLabels[i], q);
376 QLabel* infoValue = new QLabel(m_sharedData.metaInfoValues[i], q);
377 addRow(infoLabel, infoValue);
378 }
379 ++index;
380 }
381 if (metaInfoCount > 0) {
382 --index;
383 }
384
385 // remove rows that are not needed anymore
386 for (int i = rowCount - 1; i > index; --i) {
387 delete m_rows[i].label;
388 delete m_rows[i].infoWidget;
389 m_rows.pop_back();
390 }
391
392 emit q->loadingFinished();
393 #endif
394 }
395
396 void MetaDataWidget::Private::slotRatingChanged(unsigned int rating)
397 {
398 #ifdef HAVE_NEPOMUK
399 QMutexLocker locker(&m_mutex);
400 Nepomuk::MassUpdateJob* job =
401 Nepomuk::MassUpdateJob::rateResources(m_sharedData.files.values(), rating);
402 locker.unlock();
403 startChangeDataJob(job);
404 #endif
405 emit q->ratingChanged(rating);
406 }
407
408 void MetaDataWidget::Private::slotTagsChanged(const QList<Nepomuk::Tag>& tags)
409 {
410 #ifdef HAVE_NEPOMUK
411 m_taggingWidget->setTags(tags);
412
413 QMutexLocker locker(&m_mutex);
414 Nepomuk::MassUpdateJob* job =
415 Nepomuk::MassUpdateJob::tagResources(m_sharedData.files.values(), tags);
416 locker.unlock();
417 startChangeDataJob(job);
418 #endif
419 emit q->tagsChanged(tags);
420 }
421
422 void MetaDataWidget::Private::slotCommentChanged(const QString& comment)
423 {
424 #ifdef HAVE_NEPOMUK
425 QMutexLocker locker(&m_mutex);
426 Nepomuk::MassUpdateJob* job =
427 Nepomuk::MassUpdateJob::commentResources(m_sharedData.files.values(), comment);
428 locker.unlock();
429 startChangeDataJob(job);
430 #endif
431 emit q->commentChanged(comment);
432 }
433
434 void MetaDataWidget::Private::slotMetaDataUpdateDone()
435 {
436 q->setEnabled(true);
437 }
438
439 void MetaDataWidget::Private::startChangeDataJob(KJob* job)
440 {
441 connect(job, SIGNAL(result(KJob*)),
442 q, SLOT(slotMetaDataUpdateDone()));
443 q->setEnabled(false); // no updates during execution
444 job->start();
445 }
446
447 #ifdef HAVE_NEPOMUK
448 MetaDataWidget::Private::LoadFilesThread::LoadFilesThread(
449 MetaDataWidget::Private::SharedData* m_sharedData,
450 QMutex* m_mutex) :
451 m_sharedData(m_sharedData),
452 m_mutex(m_mutex),
453 m_urls(),
454 m_canceled(false)
455 {
456 }
457
458 MetaDataWidget::Private::LoadFilesThread::~LoadFilesThread()
459 {
460 // This thread may very well be deleted during execution. We need
461 // to protect it from crashes here.
462 m_canceled = true;
463 wait();
464 }
465
466 void MetaDataWidget::Private::LoadFilesThread::loadFiles(const KUrl::List& urls)
467 {
468 QMutexLocker locker(m_mutex);
469 m_urls = urls;
470 m_canceled = false;
471 start();
472 }
473
474 void MetaDataWidget::Private::LoadFilesThread::run()
475 {
476 QMutexLocker locker(m_mutex);
477 const KUrl::List urls = m_urls;
478 locker.unlock();
479
480 KConfig config("kmetainformationrc", KConfig::NoGlobals);
481 KConfigGroup settings = config.group("Show");
482
483 bool first = true;
484 unsigned int rating = 0;
485 QString comment;
486 QList<Nepomuk::Tag> tags;
487 QList<QString> metaInfoLabels;
488 QList<QString> metaInfoValues;
489 QMap<KUrl, Nepomuk::Resource> files;
490 foreach (const KUrl& url, urls) {
491 if (m_canceled) {
492 return;
493 }
494
495 Nepomuk::Resource file(url);
496 files.insert(url, file);
497
498 if (!first && (rating != file.rating())) {
499 rating = 0; // reset rating
500 } else if (first) {
501 rating = file.rating();
502 }
503
504 if (!first && (comment != file.description())) {
505 comment.clear(); // reset comment
506 } else if (first) {
507 comment = file.description();
508 }
509
510 if (!first && (tags != file.tags())) {
511 tags.clear(); // reset tags
512 } else if (first) {
513 tags = file.tags();
514 }
515
516 if (first && (urls.count() == 1)) {
517 // TODO: show shared meta informations instead
518 // of not showing anything on multiple selections
519 QHash<QUrl, Nepomuk::Variant> properties = file.properties();
520 QHash<QUrl, Nepomuk::Variant>::const_iterator it = properties.constBegin();
521 while (it != properties.constEnd()) {
522 Nepomuk::Types::Property prop(it.key());
523 if (settings.readEntry(prop.name(), true)) {
524 // TODO #1: use Nepomuk::formatValue(res, prop) if available
525 // instead of it.value().toString()
526 // TODO #2: using tunedLabel() is a workaround for KDE 4.3 (4.4?) until
527 // we get translated labels
528 metaInfoLabels.append(tunedLabel(prop.label()));
529 metaInfoValues.append(it.value().toString());
530 }
531 ++it;
532 }
533 }
534
535 first = false;
536 }
537
538 locker.relock();
539 m_sharedData->rating = rating;
540 m_sharedData->comment = comment;
541 m_sharedData->tags = tags;
542 m_sharedData->metaInfoLabels = metaInfoLabels;
543 m_sharedData->metaInfoValues = metaInfoValues;
544 m_sharedData->files = files;
545 }
546
547 QString MetaDataWidget::Private::LoadFilesThread::tunedLabel(const QString& label) const
548 {
549 QString tunedLabel;
550 const int labelLength = label.length();
551 if (labelLength > 0) {
552 tunedLabel.reserve(labelLength);
553 tunedLabel = label[0].toUpper();
554 for (int i = 1; i < labelLength; ++i) {
555 if (label[i].isUpper() && !label[i - 1].isSpace() && !label[i - 1].isUpper()) {
556 tunedLabel += ' ';
557 tunedLabel += label[i].toLower();
558 } else {
559 tunedLabel += label[i];
560 }
561 }
562 }
563 return tunedLabel + ':';
564 }
565
566 #endif // HAVE_NEPOMUK
567
568 MetaDataWidget::MetaDataWidget(QWidget* parent) :
569 QWidget(parent),
570 d(new Private(this))
571 {
572 }
573
574 MetaDataWidget::~MetaDataWidget()
575 {
576 delete d;
577 }
578
579 void MetaDataWidget::setItem(const KFileItem& item)
580 {
581 // update values for "type", "size", "modified",
582 // "owner" and "permissions" synchronously
583 d->m_sizeLabel->setText(i18nc("@label", "Size:"));
584 if (item.isDir()) {
585 d->m_typeInfo->setText(i18nc("@label", "Folder"));
586 d->setRowVisible(d->m_sizeInfo, false);
587 } else {
588 d->m_typeInfo->setText(item.mimeComment());
589 d->m_sizeInfo->setText(KIO::convertSize(item.size()));
590 d->setRowVisible(d->m_sizeInfo, true);
591 }
592 d->m_modifiedInfo->setText(item.timeString());
593 d->m_ownerInfo->setText(item.user());
594 d->m_permissionsInfo->setText(item.permissionsString());
595
596 setItems(KFileItemList() << item);
597 }
598
599 void MetaDataWidget::setItems(const KFileItemList& items)
600 {
601 d->m_fileItems = items;
602
603 if (items.count() > 1) {
604 // calculate the size of all items and show this
605 // information to the user
606 d->m_sizeLabel->setText(i18nc("@label", "Total Size:"));
607 d->setRowVisible(d->m_sizeInfo, true);
608
609 quint64 totalSize = 0;
610 foreach (const KFileItem& item, items) {
611 if (!item.isDir() && !item.isLink()) {
612 totalSize += item.size();
613 }
614 }
615 d->m_sizeInfo->setText(KIO::convertSize(totalSize));
616 }
617
618 #ifdef HAVE_NEPOMUK
619 if (Nepomuk::ResourceManager::instance()->init() == 0) {
620 QList<KUrl> urls;
621 foreach (const KFileItem& item, items) {
622 const KUrl url = item.nepomukUri();
623 if (url.isValid()) {
624 urls.append(url);
625 }
626 }
627 d->m_loadFilesThread->loadFiles(urls);
628 }
629 #endif
630 }
631
632 void MetaDataWidget::setItem(const KUrl& url)
633 {
634 KFileItem item(KFileItem::Unknown, KFileItem::Unknown, url);
635 item.refresh();
636 setItem(item);
637 }
638
639 void MetaDataWidget::setItems(const QList<KUrl>& urls)
640 {
641 KFileItemList items;
642 foreach (const KUrl& url, urls) {
643 KFileItem item(KFileItem::Unknown, KFileItem::Unknown, url);
644 item.refresh();
645 items.append(item);
646 }
647 setItems(items);
648 }
649
650 KFileItemList MetaDataWidget::items() const
651 {
652 return d->m_fileItems;
653 }
654
655 void MetaDataWidget::setHiddenData(MetaDataTypes data)
656 {
657 d->m_hiddenData = data;
658 d->updateRowsVisibility();
659 }
660
661 MetaDataWidget::MetaDataTypes MetaDataWidget::hiddenData() const
662 {
663 return d->m_hiddenData;
664 }
665
666 unsigned int MetaDataWidget::rating() const
667 {
668 #ifdef HAVE_NEPOMUK
669 QMutexLocker locker(&d->m_mutex);
670 return d->m_sharedData.rating;
671 #else
672 return 0;
673 #endif
674 }
675
676 QList<Nepomuk::Tag> MetaDataWidget::tags() const
677 {
678 #ifdef HAVE_NEPOMUK
679 QMutexLocker locker(&d->m_mutex);
680 return d->m_sharedData.tags;
681 #else
682 return QList<Nepomuk::Tag>();
683 #endif
684 }
685
686 QString MetaDataWidget::comment() const
687 {
688 #ifdef HAVE_NEPOMUK
689 QMutexLocker locker(&d->m_mutex);
690 return d->m_sharedData.comment;
691 #else
692 return QString();
693 #endif
694 }
695
696 #include "metadatawidget.moc"