]>
cloud.milkyroute.net Git - dolphin.git/blob - 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> *
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. *
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. *
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 ***************************************************************************/
21 #include "metadatawidget.h"
23 #include <kfileitem.h>
24 #include <kglobalsettings.h>
27 #include <QFontMetrics>
28 #include <QGridLayout>
33 #include <config-nepomuk.h>
35 #define DISABLE_NEPOMUK_LEGACY
37 #include "commentwidget_p.h"
38 #include "nepomukmassupdatejob_p.h"
39 #include "taggingwidget_p.h"
42 #include <kconfiggroup.h>
44 #include <Nepomuk/KRatingWidget>
45 #include <Nepomuk/Resource>
46 #include <Nepomuk/Types/Property>
47 #include <Nepomuk/Variant>
49 #include <Soprano/Vocabulary/Xesam>
51 #include <QSpacerItem>
55 class MetaDataWidget::Private
64 Private(MetaDataWidget
* parent
);
67 void addRow(QLabel
* label
, QWidget
* infoWidget
);
68 void removeMetaInfoRows();
69 void setRowVisible(QWidget
* infoWidget
, bool visible
);
71 void slotLoadingFinished();
72 void slotRatingChanged(unsigned int rating
);
73 void slotTagsChanged(const QList
<Nepomuk::Tag
>& tags
);
74 void slotCommentChanged(const QString
& comment
);
75 void slotMetaDataUpdateDone();
78 * Disables the metadata widget and starts the job that
79 * changes the meta data asynchronously. After the job
80 * has been finished, the metadata widget gets enabled again.
82 void startChangeDataJob(KJob
* job
);
86 QGridLayout
* m_gridLayout
;
91 QLabel
* m_modifiedInfo
;
93 QLabel
* m_permissionsInfo
;
96 KRatingWidget
* m_ratingWidget
;
97 TaggingWidget
* m_taggingWidget
;
98 CommentWidget
* m_commentWidget
;
100 // shared data between the GUI-thread and
101 // the loader-thread (see LoadFilesThread):
107 QList
<Nepomuk::Tag
> tags
;
108 QList
<QString
> metaInfoLabels
;
109 QList
<QString
> metaInfoValues
;
110 QMap
<KUrl
, Nepomuk::Resource
> files
;
114 * Loads the meta data of files and writes
115 * the result into a shared data pool that
116 * can be used by the widgets in the GUI thread.
118 class LoadFilesThread
: public QThread
121 LoadFilesThread(SharedData
* m_sharedData
, QMutex
* m_mutex
);
122 virtual ~LoadFilesThread();
123 void loadFiles(const KUrl::List
& urls
);
128 * Assures that the settings for the meta information
129 * are initialized with proper default values.
131 void initMetaInfoSettings(KConfigGroup
& group
);
134 * Temporary helper method for KDE 4.3 as we currently don't get
135 * translated labels for Nepmok literals: Replaces camelcase labels
136 * like "fileLocation" by "File Location:".
138 QString
tunedLabel(const QString
& label
) const;
141 SharedData
* m_sharedData
;
147 LoadFilesThread
* m_loadFilesThread
;
151 MetaDataWidget
* const q
;
154 MetaDataWidget::Private::Private(MetaDataWidget
* parent
) :
162 m_permissionsInfo(0),
167 m_loadFilesThread(0),
171 m_gridLayout
= new QGridLayout(parent
);
172 m_gridLayout
->setMargin(0);
174 m_typeInfo
= new QLabel(parent
);
175 m_sizeLabel
= new QLabel(parent
);
176 m_sizeInfo
= new QLabel(parent
);
177 m_modifiedInfo
= new QLabel(parent
);
178 m_ownerInfo
= new QLabel(parent
);
179 m_permissionsInfo
= new QLabel(parent
);
181 const QFontMetrics
fontMetrics(KGlobalSettings::smallestReadableFont());
182 m_ratingWidget
= new KRatingWidget(parent
);
183 m_ratingWidget
->setFixedHeight(fontMetrics
.height());
184 connect(m_ratingWidget
, SIGNAL(ratingChanged(unsigned int)),
185 q
, SLOT(slotRatingChanged(unsigned int)));
187 m_taggingWidget
= new TaggingWidget(parent
);
188 connect(m_taggingWidget
, SIGNAL(tagsChanged(const QList
<Nepomuk::Tag
>&)),
189 q
, SLOT(slotTagsChanged(const QList
<Nepomuk::Tag
>&)));
191 m_commentWidget
= new CommentWidget(parent
);
192 connect(m_commentWidget
, SIGNAL(commentChanged(const QString
&)),
193 q
, SLOT(slotCommentChanged(const QString
&)));
196 addRow(new QLabel(i18nc("@label", "Type:"), parent
), m_typeInfo
);
197 addRow(m_sizeLabel
, m_sizeInfo
);
198 addRow(new QLabel(i18nc("@label", "Modified:"), parent
), m_modifiedInfo
);
199 addRow(new QLabel(i18nc("@label", "Owner:"), parent
), m_ownerInfo
);
200 addRow(new QLabel(i18nc("@label", "Permissions:"), parent
), m_permissionsInfo
);
202 addRow(new QLabel(i18nc("@label", "Rating:"), parent
), m_ratingWidget
);
203 addRow(new QLabel(i18nc("@label", "Tags:"), parent
), m_taggingWidget
);
204 addRow(new QLabel(i18nc("@label", "Comment:"), parent
), m_commentWidget
);
206 m_sharedData
.rating
= 0;
207 m_loadFilesThread
= new LoadFilesThread(&m_sharedData
, &m_mutex
);
208 connect(m_loadFilesThread
, SIGNAL(finished()), q
, SLOT(slotLoadingFinished()));
212 MetaDataWidget::Private::~Private()
215 delete m_loadFilesThread
;
219 void MetaDataWidget::Private::addRow(QLabel
* label
, QWidget
* infoWidget
)
223 row
.infoWidget
= infoWidget
;
226 const QFont smallFont
= KGlobalSettings::smallestReadableFont();
227 // use a brighter color for the label and a small font size
228 QPalette palette
= label
->palette();
229 QColor textColor
= palette
.color(QPalette::Text
);
230 textColor
.setAlpha(128);
231 palette
.setColor(QPalette::WindowText
, textColor
);
232 label
->setPalette(palette
);
233 label
->setFont(smallFont
);
234 label
->setWordWrap(true);
235 label
->setAlignment(Qt::AlignTop
| Qt::AlignRight
);
237 QLabel
* infoLabel
= qobject_cast
<QLabel
*>(infoWidget
);
238 if (infoLabel
!= 0) {
239 infoLabel
->setFont(smallFont
);
240 infoLabel
->setWordWrap(true);
241 infoLabel
->setAlignment(Qt::AlignTop
| Qt::AlignLeft
);
244 // add the row to grid layout
245 const int rowIndex
= m_rows
.count();
246 m_gridLayout
->addWidget(label
, rowIndex
, 0, Qt::AlignRight
);
247 const int spacerWidth
= QFontMetrics(smallFont
).size(Qt::TextSingleLine
, " ").width();
248 m_gridLayout
->addItem(new QSpacerItem(spacerWidth
, 1), rowIndex
, 1);
249 m_gridLayout
->addWidget(infoWidget
, rowIndex
, 2, Qt::AlignLeft
);
252 void MetaDataWidget::Private::setRowVisible(QWidget
* infoWidget
, bool visible
)
254 foreach (const Row
& row
, m_rows
) {
255 if (row
.infoWidget
== infoWidget
) {
256 row
.label
->setVisible(visible
);
257 row
.infoWidget
->setVisible(visible
);
263 void MetaDataWidget::Private::slotLoadingFinished()
266 QMutexLocker
locker(&m_mutex
);
267 m_ratingWidget
->setRating(m_sharedData
.rating
);
268 m_commentWidget
->setText(m_sharedData
.comment
);
269 m_taggingWidget
->setTags(m_sharedData
.tags
);
271 // Show the remaining meta information as text. The number
272 // of required rows may very. Existing rows are reused to
273 // prevent flickering.
274 int index
= 8; // TODO: don't hardcode this value here
275 const int rowCount
= m_rows
.count();
276 Q_ASSERT(rowCount
>= index
);
278 Q_ASSERT(m_sharedData
.metaInfoLabels
.count() == m_sharedData
.metaInfoValues
.count());
279 const int metaInfoCount
= m_sharedData
.metaInfoLabels
.count();
280 for (int i
= 0; i
< metaInfoCount
; ++i
) {
281 if (index
< rowCount
) {
282 // adjust texts of the current row
283 m_rows
[index
].label
->setText(m_sharedData
.metaInfoLabels
[i
]);
284 QLabel
* infoValueLabel
= qobject_cast
<QLabel
*>(m_rows
[index
].infoWidget
);
285 Q_ASSERT(infoValueLabel
!= 0);
286 infoValueLabel
->setText(m_sharedData
.metaInfoValues
[i
]);
289 QLabel
* infoLabel
= new QLabel(m_sharedData
.metaInfoLabels
[i
], q
);
290 QLabel
* infoValue
= new QLabel(m_sharedData
.metaInfoValues
[i
], q
);
291 addRow(infoLabel
, infoValue
);
295 if (metaInfoCount
> 0) {
299 // remove rows that are not needed anymore
300 for (int i
= rowCount
- 1; i
> index
; --i
) {
301 delete m_rows
[i
].label
;
302 delete m_rows
[i
].infoWidget
;
308 void MetaDataWidget::Private::slotRatingChanged(unsigned int rating
)
311 QMutexLocker
locker(&m_mutex
);
312 Nepomuk::MassUpdateJob
* job
=
313 Nepomuk::MassUpdateJob::rateResources(m_sharedData
.files
.values(), rating
);
315 startChangeDataJob(job
);
321 void MetaDataWidget::Private::slotTagsChanged(const QList
<Nepomuk::Tag
>& tags
)
324 QMutexLocker
locker(&m_mutex
);
325 Nepomuk::MassUpdateJob
* job
=
326 Nepomuk::MassUpdateJob::tagResources(m_sharedData
.files
.values(), tags
);
328 startChangeDataJob(job
);
334 void MetaDataWidget::Private::slotCommentChanged(const QString
& comment
)
337 QMutexLocker
locker(&m_mutex
);
338 Nepomuk::MassUpdateJob
* job
=
339 Nepomuk::MassUpdateJob::commentResources(m_sharedData
.files
.values(), comment
);
341 startChangeDataJob(job
);
347 void MetaDataWidget::Private::slotMetaDataUpdateDone()
352 void MetaDataWidget::Private::startChangeDataJob(KJob
* job
)
354 connect(job
, SIGNAL(result(KJob
*)),
355 q
, SLOT(slotMetaDataUpdateDone()));
356 q
->setEnabled(false); // no updates during execution
361 MetaDataWidget::Private::LoadFilesThread::LoadFilesThread(
362 MetaDataWidget::Private::SharedData
* m_sharedData
,
364 m_sharedData(m_sharedData
),
371 MetaDataWidget::Private::LoadFilesThread::~LoadFilesThread()
373 // This thread may very well be deleted during execution. We need
374 // to protect it from crashes here.
379 void MetaDataWidget::Private::LoadFilesThread::loadFiles(const KUrl::List
& urls
)
381 QMutexLocker
locker(m_mutex
);
387 void MetaDataWidget::Private::LoadFilesThread::run()
389 QMutexLocker
locker(m_mutex
);
390 const KUrl::List urls
= m_urls
;
393 KConfig
config("kmetainformationrc", KConfig::NoGlobals
);
394 KConfigGroup settings
= config
.group("Show");
395 initMetaInfoSettings(settings
);
398 unsigned int rating
= 0;
400 QList
<Nepomuk::Tag
> tags
;
401 QList
<QString
> metaInfoLabels
;
402 QList
<QString
> metaInfoValues
;
403 QMap
<KUrl
, Nepomuk::Resource
> files
;
404 foreach (const KUrl
& url
, urls
) {
409 Nepomuk::Resource
file(url
, Soprano::Vocabulary::Xesam::File());
410 files
.insert(url
, file
);
412 if (!first
&& (rating
!= file
.rating())) {
413 rating
= 0; // reset rating
415 rating
= file
.rating();
418 if (!first
&& (comment
!= file
.description())) {
419 comment
.clear(); // reset comment
421 comment
= file
.description();
424 if (!first
&& (tags
!= file
.tags())) {
425 tags
.clear(); // reset tags
430 if (first
&& (urls
.count() == 1)) {
431 // TODO: show shared meta informations instead
432 // of not showing anything on multiple selections
433 QHash
<QUrl
, Nepomuk::Variant
> properties
= file
.properties();
434 QHash
<QUrl
, Nepomuk::Variant
>::const_iterator it
= properties
.constBegin();
435 while (it
!= properties
.constEnd()) {
436 Nepomuk::Types::Property
prop(it
.key());
437 if (true /*settings.readEntry(prop.name(), true)*/) {
438 // TODO #1: use Nepomuk::formatValue(res, prop) if available
439 // instead of it.value().toString()
440 // TODO #2: using tunedLabel() is a workaround for KDE 4.3 until
441 // we get translated labels
442 metaInfoLabels
.append(tunedLabel(prop
.label()));
443 metaInfoValues
.append(it
.value().toString());
453 m_sharedData
->rating
= rating
;
454 m_sharedData
->comment
= comment
;
455 m_sharedData
->tags
= tags
;
456 m_sharedData
->metaInfoLabels
= metaInfoLabels
;
457 m_sharedData
->metaInfoValues
= metaInfoValues
;
458 m_sharedData
->files
= files
;
461 void MetaDataWidget::Private::LoadFilesThread::initMetaInfoSettings(KConfigGroup
& group
)
463 if (!group
.readEntry("initialized", false)) {
464 // The resource file is read the first time. Assure
465 // that some meta information is disabled per default.
467 static const char* disabledProperties
[] = {
468 "asText", "contentSize", "depth", "fileExtension",
469 "fileName", "fileSize", "isPartOf", "mimetype", "name",
470 "parentUrl", "plainTextContent", "sourceModified",
472 0 // mandatory last entry
476 while (disabledProperties
[i
] != 0) {
477 group
.writeEntry(disabledProperties
[i
], false);
481 // mark the group as initialized
482 group
.writeEntry("initialized", true);
486 QString
MetaDataWidget::Private::LoadFilesThread::tunedLabel(const QString
& label
) const
489 const int labelLength
= label
.length();
490 if (labelLength
> 0) {
491 tunedLabel
.reserve(labelLength
);
492 tunedLabel
= label
[0].toUpper();
493 for (int i
= 1; i
< labelLength
; ++i
) {
494 if (label
[i
].isUpper() && !label
[i
- 1].isSpace() && !label
[i
- 1].isUpper()) {
496 tunedLabel
+= label
[i
].toLower();
498 tunedLabel
+= label
[i
];
502 return tunedLabel
+ ':';
505 #endif // HAVE_NEPOMUK
507 MetaDataWidget::MetaDataWidget(QWidget
* parent
) :
513 MetaDataWidget::~MetaDataWidget()
518 void MetaDataWidget::setItem(const KFileItem
& item
)
520 // update values for "type", "size", "modified",
521 // "owner" and "permissions" synchronously
522 d
->m_sizeLabel
->setText(i18nc("@label", "Size:"));
524 d
->m_typeInfo
->setText(i18nc("@label", "Folder"));
525 d
->setRowVisible(d
->m_sizeInfo
, false);
527 d
->m_typeInfo
->setText(item
.mimeComment());
528 d
->m_sizeInfo
->setText(KIO::convertSize(item
.size()));
529 d
->setRowVisible(d
->m_sizeInfo
, true);
531 d
->m_modifiedInfo
->setText(item
.timeString());
532 d
->m_ownerInfo
->setText(item
.user());
533 d
->m_permissionsInfo
->setText(item
.permissionsString());
535 setItems(KFileItemList() << item
);
538 void MetaDataWidget::setItems(const KFileItemList
& items
)
540 if (items
.count() > 1) {
541 // calculate the size of all items and show this
542 // information to the user
543 d
->m_sizeLabel
->setText(i18nc("@label", "Total Size:"));
544 d
->setRowVisible(d
->m_sizeInfo
, true);
546 quint64 totalSize
= 0;
547 foreach (const KFileItem
& item
, items
) {
548 if (!item
.isDir() && !item
.isLink()) {
549 totalSize
+= item
.size();
552 d
->m_sizeInfo
->setText(KIO::convertSize(totalSize
));
557 foreach (const KFileItem
& item
, items
) {
558 const KUrl url
= item
.nepomukUri();
563 d
->m_loadFilesThread
->loadFiles(urls
);
567 #include "metadatawidget.moc"