]> cloud.milkyroute.net Git - dolphin.git/blob - src/panels/information/kmetadatawidget.cpp
SVN_SILENT made messages (.desktop file)
[dolphin.git] / src / panels / information / kmetadatawidget.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 library is free software; you can redistribute it and/or *
6 * modify it under the terms of the GNU Library General Public *
7 * License version 2 as published by the Free Software Foundation. *
8 * *
9 * This library 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 GNU *
12 * Library General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU Library General Public License *
15 * along with this library; see the file COPYING.LIB. If not, write to *
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301, USA. *
18 *****************************************************************************/
19
20 #include "kmetadatawidget.h"
21
22 #include <kconfig.h>
23 #include <kconfiggroup.h>
24 #include <kfileitem.h>
25 #include <kglobalsettings.h>
26 #include <kglobal.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 "kcommentwidget_p.h"
40 #include "kloadmetadatathread_p.h"
41 #include "ktaggingwidget_p.h"
42
43 #include <nepomuk/kratingwidget.h>
44 #include <nepomuk/resource.h>
45 #include <nepomuk/resourcemanager.h>
46 #include <nepomuk/property.h>
47 #include <nepomuk/tag.h>
48 #include <nepomuk/variant.h>
49 #include "nepomukmassupdatejob_p.h"
50
51 #include <QMutex>
52 #include <QSpacerItem>
53 #include <QThread>
54 #else
55 namespace Nepomuk
56 {
57 typedef int Tag;
58 }
59 #endif
60
61 class KMetaDataWidget::Private
62 {
63 public:
64 struct Row
65 {
66 QLabel* label;
67 QWidget* infoWidget;
68 };
69
70 Private(KMetaDataWidget* parent);
71 ~Private();
72
73 void addRow(QLabel* label, QWidget* infoWidget);
74 void removeMetaInfoRows();
75 void setRowVisible(QWidget* infoWidget, bool visible);
76
77 /**
78 * Initializes the configuration file "kmetainformationrc"
79 * with proper default settings for the first start in
80 * an uninitialized environment.
81 */
82 void initMetaInfoSettings();
83
84 /**
85 * Parses the configuration file "kmetainformationrc" and
86 * updates the visibility of all rows.
87 */
88 void updateRowsVisibility();
89
90 void slotLoadingFinished();
91
92 void slotRatingChanged(unsigned int rating);
93 void slotTagsChanged(const QList<Nepomuk::Tag>& tags);
94 void slotCommentChanged(const QString& comment);
95
96 void slotMetaDataUpdateDone();
97
98 /**
99 * Disables the metadata widget and starts the job that
100 * changes the meta data asynchronously. After the job
101 * has been finished, the metadata widget gets enabled again.
102 */
103 void startChangeDataJob(KJob* job);
104
105 bool m_isSizeVisible;
106 MetaDataTypes m_visibleDataTypes;
107 QList<KFileItem> m_fileItems;
108 QList<Row> m_rows;
109
110 QGridLayout* m_gridLayout;
111
112 QLabel* m_typeInfo;
113 QLabel* m_sizeLabel;
114 QLabel* m_sizeInfo;
115 QLabel* m_modifiedInfo;
116 QLabel* m_ownerInfo;
117 QLabel* m_permissionsInfo;
118
119 #ifdef HAVE_NEPOMUK
120 KRatingWidget* m_ratingWidget;
121 KTaggingWidget* m_taggingWidget;
122 KCommentWidget* m_commentWidget;
123
124 QMap<KUrl, Nepomuk::Resource> m_files;
125
126 KLoadMetaDataThread* m_loadMetaDataThread;
127 #endif
128
129 private:
130 KMetaDataWidget* const q;
131 };
132
133 KMetaDataWidget::Private::Private(KMetaDataWidget* parent) :
134 m_isSizeVisible(true),
135 m_visibleDataTypes(TypeData | SizeData | ModifiedData | OwnerData |
136 PermissionsData | RatingData | TagsData | CommentData),
137 m_fileItems(),
138 m_rows(),
139 m_gridLayout(0),
140 m_typeInfo(0),
141 m_sizeLabel(0),
142 m_sizeInfo(0),
143 m_modifiedInfo(0),
144 m_ownerInfo(0),
145 m_permissionsInfo(0),
146 #ifdef HAVE_NEPOMUK
147 m_ratingWidget(0),
148 m_taggingWidget(0),
149 m_commentWidget(0),
150 m_files(),
151 m_loadMetaDataThread(0),
152 #endif
153 q(parent)
154 {
155 m_gridLayout = new QGridLayout(parent);
156 m_gridLayout->setMargin(0);
157
158 m_typeInfo = new QLabel(parent);
159 m_sizeLabel = new QLabel(parent);
160 m_sizeInfo = new QLabel(parent);
161 m_modifiedInfo = new QLabel(parent);
162 m_ownerInfo = new QLabel(parent);
163 m_permissionsInfo = new QLabel(parent);
164
165 addRow(new QLabel(i18nc("@label", "Type:"), parent), m_typeInfo);
166 addRow(m_sizeLabel, m_sizeInfo);
167 addRow(new QLabel(i18nc("@label", "Modified:"), parent), m_modifiedInfo);
168 addRow(new QLabel(i18nc("@label", "Owner:"), parent), m_ownerInfo);
169 addRow(new QLabel(i18nc("@label", "Permissions:"), parent), m_permissionsInfo);
170
171 #ifdef HAVE_NEPOMUK
172 if (Nepomuk::ResourceManager::instance()->init() == 0) {
173 const QFontMetrics fontMetrics(KGlobalSettings::smallestReadableFont());
174 m_ratingWidget = new KRatingWidget(parent);
175 m_ratingWidget->setFixedHeight(fontMetrics.height());
176 connect(m_ratingWidget, SIGNAL(ratingChanged(unsigned int)),
177 q, SLOT(slotRatingChanged(unsigned int)));
178
179 m_taggingWidget = new KTaggingWidget(parent);
180 connect(m_taggingWidget, SIGNAL(tagsChanged(const QList<Nepomuk::Tag>&)),
181 q, SLOT(slotTagsChanged(const QList<Nepomuk::Tag>&)));
182
183 m_commentWidget = new KCommentWidget(parent);
184 connect(m_commentWidget, SIGNAL(commentChanged(const QString&)),
185 q, SLOT(slotCommentChanged(const QString&)));
186
187 addRow(new QLabel(i18nc("@label", "Rating:"), parent), m_ratingWidget);
188 addRow(new QLabel(i18nc("@label", "Tags:"), parent), m_taggingWidget);
189 addRow(new QLabel(i18nc("@label", "Comment:"), parent), m_commentWidget);
190 }
191 #endif
192
193 initMetaInfoSettings();
194 updateRowsVisibility();
195 }
196
197 KMetaDataWidget::Private::~Private()
198 {
199 #ifdef HAVE_NEPOMUK
200 if (m_loadMetaDataThread != 0) {
201 disconnect(m_loadMetaDataThread, SIGNAL(finished()), q, SLOT(slotLoadingFinished()));
202 m_loadMetaDataThread->cancelAndDelete();
203 m_loadMetaDataThread = 0;
204 }
205 #endif
206 }
207
208 void KMetaDataWidget::Private::addRow(QLabel* label, QWidget* infoWidget)
209 {
210 Row row;
211 row.label = label;
212 row.infoWidget = infoWidget;
213 m_rows.append(row);
214
215 const QFont smallFont = KGlobalSettings::smallestReadableFont();
216 // use a brighter color for the label and a small font size
217 QPalette palette = label->palette();
218 QColor textColor = palette.color(QPalette::Text);
219 textColor.setAlpha(128);
220 palette.setColor(QPalette::WindowText, textColor);
221 label->setPalette(palette);
222 label->setFont(smallFont);
223 label->setWordWrap(true);
224 label->setAlignment(Qt::AlignTop | Qt::AlignRight);
225
226 QLabel* infoLabel = qobject_cast<QLabel*>(infoWidget);
227 if (infoLabel != 0) {
228 infoLabel->setFont(smallFont);
229 infoLabel->setWordWrap(true);
230 infoLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft);
231 }
232
233 // add the row to grid layout
234 const int rowIndex = m_rows.count();
235 m_gridLayout->addWidget(label, rowIndex, 0, Qt::AlignRight);
236 const int spacerWidth = QFontMetrics(smallFont).size(Qt::TextSingleLine, " ").width();
237 m_gridLayout->addItem(new QSpacerItem(spacerWidth, 1), rowIndex, 1);
238 m_gridLayout->addWidget(infoWidget, rowIndex, 2, Qt::AlignLeft);
239 }
240
241 void KMetaDataWidget::Private::setRowVisible(QWidget* infoWidget, bool visible)
242 {
243 foreach (const Row& row, m_rows) {
244 if (row.infoWidget == infoWidget) {
245 row.label->setVisible(visible);
246 row.infoWidget->setVisible(visible);
247 return;
248 }
249 }
250 }
251
252
253 void KMetaDataWidget::Private::initMetaInfoSettings()
254 {
255 KConfig config("kmetainformationrc", KConfig::NoGlobals);
256 KConfigGroup settings = config.group("Show");
257 if (!settings.readEntry("initialized", false)) {
258 // The resource file is read the first time. Assure
259 // that some meta information is disabled per default.
260
261 static const char* disabledProperties[] = {
262 "asText", "contentSize", "created", "depth", "description", "fileExtension",
263 "fileName", "fileSize", "hasTag", "isPartOf", "lastModified", "mimeType", "name",
264 "numericRating", "parentUrl", "permissions", "plainTextContent", "owner",
265 "sourceModified", "url",
266 0 // mandatory last entry
267 };
268
269 int i = 0;
270 while (disabledProperties[i] != 0) {
271 settings.writeEntry(disabledProperties[i], false);
272 ++i;
273 }
274
275 // mark the group as initialized
276 settings.writeEntry("initialized", true);
277 }
278 }
279
280 void KMetaDataWidget::Private::updateRowsVisibility()
281 {
282 KConfig config("kmetainformationrc", KConfig::NoGlobals);
283 KConfigGroup settings = config.group("Show");
284
285 setRowVisible(m_typeInfo,
286 (m_visibleDataTypes & KMetaDataWidget::TypeData) &&
287 settings.readEntry("type", true));
288
289 // Cache in m_isSizeVisible whether the size should be shown. This
290 // is necessary as the size is temporary hidden when the target
291 // file item is a directory.
292 m_isSizeVisible = (m_visibleDataTypes & KMetaDataWidget::SizeData) &&
293 settings.readEntry("size", true);
294 setRowVisible(m_sizeInfo, m_isSizeVisible);
295
296 setRowVisible(m_modifiedInfo,
297 (m_visibleDataTypes & KMetaDataWidget::ModifiedData) &&
298 settings.readEntry("modified", true));
299
300 setRowVisible(m_ownerInfo,
301 (m_visibleDataTypes & KMetaDataWidget::OwnerData) &&
302 settings.readEntry("owner", true));
303
304 setRowVisible(m_permissionsInfo,
305 (m_visibleDataTypes & KMetaDataWidget::PermissionsData) &&
306 settings.readEntry("permissions", true));
307
308 #ifdef HAVE_NEPOMUK
309 if (Nepomuk::ResourceManager::instance()->init() == 0) {
310 setRowVisible(m_ratingWidget,
311 (m_visibleDataTypes & KMetaDataWidget::RatingData) &&
312 settings.readEntry("rating", true));
313
314 setRowVisible(m_taggingWidget,
315 (m_visibleDataTypes & KMetaDataWidget::TagsData) &&
316 settings.readEntry("tags", true));
317
318 setRowVisible(m_commentWidget,
319 (m_visibleDataTypes & KMetaDataWidget::CommentData) &&
320 settings.readEntry("comment", true));
321 }
322 #endif
323 }
324
325 void KMetaDataWidget::Private::slotLoadingFinished()
326 {
327 #ifdef HAVE_NEPOMUK
328 Q_ASSERT(m_loadMetaDataThread != 0);
329 m_ratingWidget->setRating(m_loadMetaDataThread->rating());
330 m_commentWidget->setText(m_loadMetaDataThread->comment());
331 m_taggingWidget->setTags(m_loadMetaDataThread->tags());
332
333 // Show the remaining meta information as text. The number
334 // of required rows may very. Existing rows are reused to
335 // prevent flickering.
336 int index = 8; // TODO: don't hardcode this value here
337 const int rowCount = m_rows.count();
338 Q_ASSERT(rowCount >= index);
339
340 Q_ASSERT(m_loadMetaDataThread->metaInfoLabels().count() == m_loadMetaDataThread->metaInfoValues().count());
341 const int metaInfoCount = m_loadMetaDataThread->metaInfoLabels().count();
342 for (int i = 0; i < metaInfoCount; ++i) {
343 const QList<QString> metaInfoLabels = m_loadMetaDataThread->metaInfoLabels();
344 const QList<QString> metaInfoValues = m_loadMetaDataThread->metaInfoValues();
345 if (index < rowCount) {
346 // adjust texts of the current row
347 m_rows[index].label->setText(metaInfoLabels[i]);
348 QLabel* infoValueLabel = qobject_cast<QLabel*>(m_rows[index].infoWidget);
349 Q_ASSERT(infoValueLabel != 0);
350 infoValueLabel->setText(metaInfoValues[i]);
351 } else {
352 // create new row
353 QLabel* infoLabel = new QLabel(metaInfoLabels[i], q);
354 QLabel* infoValue = new QLabel(metaInfoValues[i], q);
355 addRow(infoLabel, infoValue);
356 }
357 ++index;
358 }
359 if (metaInfoCount > 0) {
360 --index;
361 }
362
363 // remove rows that are not needed anymore
364 for (int i = rowCount - 1; i > index; --i) {
365 delete m_rows[i].label;
366 delete m_rows[i].infoWidget;
367 m_rows.pop_back();
368 }
369
370 m_files = m_loadMetaDataThread->files();
371
372 delete m_loadMetaDataThread;
373 m_loadMetaDataThread = 0;
374 #endif
375
376 q->updateGeometry();
377 }
378
379 void KMetaDataWidget::Private::slotRatingChanged(unsigned int rating)
380 {
381 #ifdef HAVE_NEPOMUK
382 Nepomuk::MassUpdateJob* job =
383 Nepomuk::MassUpdateJob::rateResources(m_files.values(), rating);
384 startChangeDataJob(job);
385 #else
386 Q_UNUSED(rating);
387 #endif
388 }
389
390 void KMetaDataWidget::Private::slotTagsChanged(const QList<Nepomuk::Tag>& tags)
391 {
392 #ifdef HAVE_NEPOMUK
393 m_taggingWidget->setTags(tags);
394
395 Nepomuk::MassUpdateJob* job =
396 Nepomuk::MassUpdateJob::tagResources(m_files.values(), tags);
397 startChangeDataJob(job);
398 #else
399 Q_UNUSED(tags);
400 #endif
401 }
402
403 void KMetaDataWidget::Private::slotCommentChanged(const QString& comment)
404 {
405 #ifdef HAVE_NEPOMUK
406 Nepomuk::MassUpdateJob* job =
407 Nepomuk::MassUpdateJob::commentResources(m_files.values(), comment);
408 startChangeDataJob(job);
409 #else
410 Q_UNUSED(comment);
411 #endif
412 }
413
414 void KMetaDataWidget::Private::slotMetaDataUpdateDone()
415 {
416 #ifdef HAVE_NEPOMUK
417 q->setEnabled(true);
418 #endif
419 }
420
421 #ifdef HAVE_NEPOMUK
422 void KMetaDataWidget::Private::startChangeDataJob(KJob* job)
423 {
424 connect(job, SIGNAL(result(KJob*)),
425 q, SLOT(slotMetaDataUpdateDone()));
426 q->setEnabled(false); // no updates during execution
427 job->start();
428 }
429 #endif
430
431 KMetaDataWidget::KMetaDataWidget(QWidget* parent) :
432 QWidget(parent),
433 d(new Private(this))
434 {
435 }
436
437 KMetaDataWidget::~KMetaDataWidget()
438 {
439 delete d;
440 }
441
442 void KMetaDataWidget::setItem(const KFileItem& item)
443 {
444 // update values for "type", "size", "modified",
445 // "owner" and "permissions" synchronously
446 d->m_sizeLabel->setText(i18nc("@label", "Size:"));
447 if (item.isDir()) {
448 d->m_typeInfo->setText(i18nc("@label", "Folder"));
449 d->setRowVisible(d->m_sizeInfo, false);
450 } else {
451 d->m_typeInfo->setText(item.mimeComment());
452 d->m_sizeInfo->setText(KIO::convertSize(item.size()));
453 d->setRowVisible(d->m_sizeInfo, d->m_isSizeVisible);
454 }
455 d->m_modifiedInfo->setText(KGlobal::locale()->formatDateTime(item.time(KFileItem::ModificationTime), KLocale::FancyLongDate));
456 d->m_ownerInfo->setText(item.user());
457 d->m_permissionsInfo->setText(item.permissionsString());
458
459 setItems(KFileItemList() << item);
460 }
461
462 void KMetaDataWidget::setItems(const KFileItemList& items)
463 {
464 d->m_fileItems = items;
465
466 if (items.count() > 1) {
467 // calculate the size of all items and show this
468 // information to the user
469 d->m_sizeLabel->setText(i18nc("@label", "Total Size:"));
470 d->setRowVisible(d->m_sizeInfo, d->m_isSizeVisible);
471
472 quint64 totalSize = 0;
473 foreach (const KFileItem& item, items) {
474 if (!item.isDir() && !item.isLink()) {
475 totalSize += item.size();
476 }
477 }
478 d->m_sizeInfo->setText(KIO::convertSize(totalSize));
479 }
480
481 #ifdef HAVE_NEPOMUK
482 if (Nepomuk::ResourceManager::instance()->init() == 0) {
483 QList<KUrl> urls;
484 foreach (const KFileItem& item, items) {
485 const KUrl url = item.nepomukUri();
486 if (url.isValid()) {
487 urls.append(url);
488 }
489 }
490
491 if (d->m_loadMetaDataThread != 0) {
492 disconnect(d->m_loadMetaDataThread, SIGNAL(finished()), this, SLOT(slotLoadingFinished()));
493 d->m_loadMetaDataThread->cancelAndDelete();
494 }
495
496 d->m_loadMetaDataThread = new KLoadMetaDataThread();
497 connect(d->m_loadMetaDataThread, SIGNAL(finished()), this, SLOT(slotLoadingFinished()));
498 d->m_loadMetaDataThread->load(urls);
499 }
500 #endif
501 }
502
503 void KMetaDataWidget::setItem(const KUrl& url)
504 {
505 KFileItem item(KFileItem::Unknown, KFileItem::Unknown, url);
506 item.refresh();
507 setItem(item);
508 }
509
510 void KMetaDataWidget::setItems(const QList<KUrl>& urls)
511 {
512 KFileItemList items;
513 foreach (const KUrl& url, urls) {
514 KFileItem item(KFileItem::Unknown, KFileItem::Unknown, url);
515 item.refresh();
516 items.append(item);
517 }
518 setItems(items);
519 }
520
521 KFileItemList KMetaDataWidget::items() const
522 {
523 return d->m_fileItems;
524 }
525
526 void KMetaDataWidget::setVisibleDataTypes(MetaDataTypes data)
527 {
528 d->m_visibleDataTypes = data;
529 d->updateRowsVisibility();
530 }
531
532 KMetaDataWidget::MetaDataTypes KMetaDataWidget::visibleDataTypes() const
533 {
534 return d->m_visibleDataTypes;
535 }
536
537 QSize KMetaDataWidget::sizeHint() const
538 {
539 const int fixedWidth = 200;
540 int height = 0;
541 foreach (const Private::Row& row, d->m_rows) {
542 if (row.infoWidget != 0) {
543 int rowHeight = row.infoWidget->heightForWidth(fixedWidth / 2);
544 if (rowHeight <= 0) {
545 rowHeight = row.infoWidget->sizeHint().height();
546 }
547 height += rowHeight;
548 }
549 }
550 return QSize(fixedWidth, height);
551 }
552
553 #include "kmetadatawidget.moc"