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