--- /dev/null
+/*****************************************************************************
+ * Copyright (C) 2009 by Peter Penz <peter.penz@gmx.at> *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Library General Public *
+ * License version 2 as published by the Free Software Foundation. *
+ * *
+ * This library is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Library General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public License *
+ * along with this library; see the file COPYING.LIB. If not, write to *
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301, USA. *
+ *****************************************************************************/
+
+#include "kloadmetadatathread_p.h"
+
+#include <kconfig.h>
+#include <kconfiggroup.h>
+
+#include <nepomuk/variant.h>
+
+KLoadMetaDataThread::KLoadMetaDataThread() :
+ m_rating(0),
+ m_comment(),
+ m_tags(),
+ m_metaInfoLabels(),
+ m_metaInfoValues(),
+ m_files(),
+ m_urls(),
+ m_canceled(false)
+{
+}
+
+KLoadMetaDataThread::~KLoadMetaDataThread()
+{
+}
+
+void KLoadMetaDataThread::load(const KUrl::List& urls)
+{
+ m_urls = urls;
+ m_canceled = false;
+ start();
+}
+
+void KLoadMetaDataThread::cancelAndDelete()
+{
+ connect(this, SIGNAL(finished()), this, SLOT(slotFinished()));
+ m_canceled = true;
+ // Setting m_canceled to true will cancel KLoadMetaDataThread::run()
+ // as soon as possible. Afterwards the thread will delete itself
+ // asynchronously inside slotFinished().
+}
+
+void KLoadMetaDataThread::run()
+{
+ KConfig config("kmetainformationrc", KConfig::NoGlobals);
+ KConfigGroup settings = config.group("Show");
+
+ bool first = true;
+ unsigned int rating = 0;
+ foreach (const KUrl& url, m_urls) {
+ if (m_canceled) {
+ return;
+ }
+
+ Nepomuk::Resource file(url);
+ m_files.insert(url, file);
+
+ if (!first && (rating != file.rating())) {
+ rating = 0; // reset rating
+ } else if (first) {
+ rating = file.rating();
+ }
+
+ if (!first && (m_comment != file.description())) {
+ m_comment.clear(); // reset comment
+ } else if (first) {
+ m_comment = file.description();
+ }
+
+ if (!first && (m_tags != file.tags())) {
+ m_tags.clear(); // reset tags
+ } else if (first) {
+ m_tags = file.tags();
+ }
+
+ if (first && (m_urls.count() == 1)) {
+ // TODO: show shared meta information instead
+ // of not showing anything on multiple selections
+ QHash<QUrl, Nepomuk::Variant> properties = file.properties();
+ QHash<QUrl, Nepomuk::Variant>::const_iterator it = properties.constBegin();
+ while (it != properties.constEnd()) {
+ Nepomuk::Types::Property prop(it.key());
+ if (settings.readEntry(prop.name(), true)) {
+ // TODO #1: use Nepomuk::formatValue(res, prop) if available
+ // instead of it.value().toString()
+ // TODO #2: using tunedLabel() is a workaround for KDE 4.3 (4.4?) until
+ // we get translated labels
+ m_metaInfoLabels.append(tunedLabel(prop.label()));
+ m_metaInfoValues.append(it.value().toString());
+ }
+ ++it;
+ }
+ }
+
+ first = false;
+ }
+}
+
+int KLoadMetaDataThread::rating() const
+{
+ return m_rating;
+}
+
+QString KLoadMetaDataThread::comment() const
+{
+ return m_comment;
+}
+
+QList<Nepomuk::Tag> KLoadMetaDataThread::tags() const
+{
+ return m_tags;
+}
+
+QList<QString> KLoadMetaDataThread::metaInfoLabels() const
+{
+ return m_metaInfoLabels;
+}
+
+QList<QString> KLoadMetaDataThread::metaInfoValues() const
+{
+ return m_metaInfoValues;
+}
+
+QMap<KUrl, Nepomuk::Resource> KLoadMetaDataThread::files() const
+{
+ return m_files;
+}
+
+void KLoadMetaDataThread::slotFinished()
+{
+ deleteLater();
+}
+
+QString KLoadMetaDataThread::tunedLabel(const QString& label) const
+{
+ QString tunedLabel;
+ const int labelLength = label.length();
+ if (labelLength > 0) {
+ tunedLabel.reserve(labelLength);
+ tunedLabel = label[0].toUpper();
+ for (int i = 1; i < labelLength; ++i) {
+ if (label[i].isUpper() && !label[i - 1].isSpace() && !label[i - 1].isUpper()) {
+ tunedLabel += ' ';
+ tunedLabel += label[i].toLower();
+ } else {
+ tunedLabel += label[i];
+ }
+ }
+ }
+ return tunedLabel + ':';
+}
+
+#include "kloadmetadatathread_p.moc"
--- /dev/null
+/*****************************************************************************
+ * Copyright (C) 2009 by Peter Penz <peter.penz@gmx.at> *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Library General Public *
+ * License version 2 as published by the Free Software Foundation. *
+ * *
+ * This library is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Library General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public License *
+ * along with this library; see the file COPYING.LIB. If not, write to *
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301, USA. *
+ *****************************************************************************/
+
+#ifndef KLOADMETADATATHREAD_H
+#define KLOADMETADATATHREAD_H
+
+#define DISABLE_NEPOMUK_LEGACY
+#include <nepomuk/property.h>
+#include <nepomuk/tag.h>
+
+#include <kurl.h>
+#include <QList>
+#include <QThread>
+
+/**
+ * Loads the meta data of files that are
+ * required by the widget KMetaDataWidget.
+ */
+class KLoadMetaDataThread : public QThread
+{
+ Q_OBJECT
+
+public:
+ KLoadMetaDataThread();
+ virtual ~KLoadMetaDataThread();
+
+ /**
+ * Starts the thread and loads the meta data for
+ * the files given by \p urls. After receiving
+ * the signal finished(), the methods
+ * rating(), comment(), tags(), metaInfoLabels(),
+ * metaInfoValues() and files() return valid data.
+ */
+ void load(const KUrl::List& urls);
+
+ /**
+ * Cancels the thread and assures that the thread deletes
+ * itself as soon as the cancelling has been successful. In
+ * opposite to QThread::wait() the caller of cancelAndDelete()
+ * will not be blocked.
+ */
+ void cancelAndDelete();
+
+ /** @see QThread::run() */
+ virtual void run();
+
+ int rating() const;
+ QString comment() const;
+ QList<Nepomuk::Tag> tags() const;
+ QList<QString> metaInfoLabels() const;
+ QList<QString> metaInfoValues() const;
+ QMap<KUrl, Nepomuk::Resource> files() const;
+
+private slots:
+ void slotFinished();
+
+private:
+ /**
+ * Assures that the settings for the meta information
+ * are initialized with proper default values.
+ */
+ void initMetaInfoSettings(KConfigGroup& group);
+
+ /**
+ * Temporary helper method for KDE 4.3 as we currently don't get
+ * translated labels for Nepmok literals: Replaces camelcase labels
+ * like "fileLocation" by "File Location:".
+ */
+ QString tunedLabel(const QString& label) const;
+
+private:
+ int m_rating;
+ QString m_comment;
+ QList<Nepomuk::Tag> m_tags;
+ QList<QString> m_metaInfoLabels;
+ QList<QString> m_metaInfoValues;
+ QMap<KUrl, Nepomuk::Resource> m_files;
+
+ KUrl::List m_urls;
+ bool m_canceled;
+};
+#endif
#define DISABLE_NEPOMUK_LEGACY
#include "kcommentwidget_p.h"
+ #include "kloadmetadatathread_p.h"
#include "ktaggingwidget_p.h"
#include <nepomuk/kratingwidget.h>
#include <nepomuk/resource.h>
#include <nepomuk/resourcemanager.h>
#include <nepomuk/property.h>
+ #include <nepomuk/tag.h>
#include <nepomuk/variant.h>
#include "nepomukmassupdatejob_p.h"
#include <QMutex>
#include <QSpacerItem>
#include <QThread>
+#else
+ namespace Nepomuk
+ {
+ typedef int Tag;
+ }
#endif
class KMetaDataWidget::Private
void updateRowsVisibility();
void slotLoadingFinished();
+
void slotRatingChanged(unsigned int rating);
void slotTagsChanged(const QList<Nepomuk::Tag>& tags);
void slotCommentChanged(const QString& comment);
+
void slotMetaDataUpdateDone();
/**
KTaggingWidget* m_taggingWidget;
KCommentWidget* m_commentWidget;
- // shared data between the GUI-thread and
- // the loader-thread (see LoadFilesThread):
- QMutex m_mutex;
- struct SharedData
- {
- int rating;
- QString comment;
- QList<Nepomuk::Tag> tags;
- QList<QString> metaInfoLabels;
- QList<QString> metaInfoValues;
- QMap<KUrl, Nepomuk::Resource> files;
- } m_sharedData;
-
- /**
- * Loads the meta data of files and writes
- * the result into a shared data pool that
- * can be used by the widgets in the GUI thread.
- */
- class LoadFilesThread : public QThread
- {
- public:
- LoadFilesThread(SharedData* m_sharedData, QMutex* m_mutex);
- virtual ~LoadFilesThread();
- void loadFiles(const KUrl::List& urls);
- virtual void run();
-
- private:
- /**
- * Assures that the settings for the meta information
- * are initialized with proper default values.
- */
- void initMetaInfoSettings(KConfigGroup& group);
-
- /**
- * Temporary helper method for KDE 4.3 as we currently don't get
- * translated labels for Nepmok literals: Replaces camelcase labels
- * like "fileLocation" by "File Location:".
- */
- QString tunedLabel(const QString& label) const;
-
- private:
- SharedData* m_sharedData;
- QMutex* m_mutex;
- KUrl::List m_urls;
- bool m_canceled;
- };
+ QMap<KUrl, Nepomuk::Resource> m_files;
- LoadFilesThread* m_loadFilesThread;
+ KLoadMetaDataThread* m_loadMetaDataThread;
#endif
private:
m_ratingWidget(0),
m_taggingWidget(0),
m_commentWidget(0),
- m_loadFilesThread(0),
+ m_files(),
+ m_loadMetaDataThread(0),
#endif
q(parent)
{
addRow(new QLabel(i18nc("@label", "Rating:"), parent), m_ratingWidget);
addRow(new QLabel(i18nc("@label", "Tags:"), parent), m_taggingWidget);
addRow(new QLabel(i18nc("@label", "Comment:"), parent), m_commentWidget);
-
- m_loadFilesThread = new LoadFilesThread(&m_sharedData, &m_mutex);
- connect(m_loadFilesThread, SIGNAL(finished()), q, SLOT(slotLoadingFinished()));
}
-
- m_sharedData.rating = 0;
#endif
initMetaInfoSettings();
KMetaDataWidget::Private::~Private()
{
#ifdef HAVE_NEPOMUK
- delete m_loadFilesThread;
+ if (m_loadMetaDataThread != 0) {
+ disconnect(m_loadMetaDataThread, SIGNAL(finished()), q, SLOT(slotLoadingFinished()));
+ m_loadMetaDataThread->cancelAndDelete();
+ m_loadMetaDataThread = 0;
+ }
#endif
}
void KMetaDataWidget::Private::slotLoadingFinished()
{
#ifdef HAVE_NEPOMUK
- QMutexLocker locker(&m_mutex);
- m_ratingWidget->setRating(m_sharedData.rating);
- m_commentWidget->setText(m_sharedData.comment);
- m_taggingWidget->setTags(m_sharedData.tags);
+ Q_ASSERT(m_loadMetaDataThread != 0);
+ m_ratingWidget->setRating(m_loadMetaDataThread->rating());
+ m_commentWidget->setText(m_loadMetaDataThread->comment());
+ m_taggingWidget->setTags(m_loadMetaDataThread->tags());
// Show the remaining meta information as text. The number
// of required rows may very. Existing rows are reused to
const int rowCount = m_rows.count();
Q_ASSERT(rowCount >= index);
- Q_ASSERT(m_sharedData.metaInfoLabels.count() == m_sharedData.metaInfoValues.count());
- const int metaInfoCount = m_sharedData.metaInfoLabels.count();
+ Q_ASSERT(m_loadMetaDataThread->metaInfoLabels().count() == m_loadMetaDataThread->metaInfoValues().count());
+ const int metaInfoCount = m_loadMetaDataThread->metaInfoLabels().count();
for (int i = 0; i < metaInfoCount; ++i) {
+ const QList<QString> metaInfoLabels = m_loadMetaDataThread->metaInfoLabels();
+ const QList<QString> metaInfoValues = m_loadMetaDataThread->metaInfoValues();
if (index < rowCount) {
// adjust texts of the current row
- m_rows[index].label->setText(m_sharedData.metaInfoLabels[i]);
+ m_rows[index].label->setText(metaInfoLabels[i]);
QLabel* infoValueLabel = qobject_cast<QLabel*>(m_rows[index].infoWidget);
Q_ASSERT(infoValueLabel != 0);
- infoValueLabel->setText(m_sharedData.metaInfoValues[i]);
+ infoValueLabel->setText(metaInfoValues[i]);
} else {
// create new row
- QLabel* infoLabel = new QLabel(m_sharedData.metaInfoLabels[i], q);
- QLabel* infoValue = new QLabel(m_sharedData.metaInfoValues[i], q);
+ QLabel* infoLabel = new QLabel(metaInfoLabels[i], q);
+ QLabel* infoValue = new QLabel(metaInfoValues[i], q);
addRow(infoLabel, infoValue);
}
++index;
delete m_rows[i].infoWidget;
m_rows.pop_back();
}
+
+ m_files = m_loadMetaDataThread->files();
+
+ delete m_loadMetaDataThread;
+ m_loadMetaDataThread = 0;
#endif
+
q->updateGeometry();
}
void KMetaDataWidget::Private::slotRatingChanged(unsigned int rating)
{
#ifdef HAVE_NEPOMUK
- QMutexLocker locker(&m_mutex);
Nepomuk::MassUpdateJob* job =
- Nepomuk::MassUpdateJob::rateResources(m_sharedData.files.values(), rating);
- locker.unlock();
+ Nepomuk::MassUpdateJob::rateResources(m_files.values(), rating);
startChangeDataJob(job);
+#else
+ Q_UNUSED(rating);
#endif
}
#ifdef HAVE_NEPOMUK
m_taggingWidget->setTags(tags);
- QMutexLocker locker(&m_mutex);
Nepomuk::MassUpdateJob* job =
- Nepomuk::MassUpdateJob::tagResources(m_sharedData.files.values(), tags);
- locker.unlock();
+ Nepomuk::MassUpdateJob::tagResources(m_files.values(), tags);
startChangeDataJob(job);
+#else
+ Q_UNUSED(tags);
#endif
}
void KMetaDataWidget::Private::slotCommentChanged(const QString& comment)
{
#ifdef HAVE_NEPOMUK
- QMutexLocker locker(&m_mutex);
Nepomuk::MassUpdateJob* job =
- Nepomuk::MassUpdateJob::commentResources(m_sharedData.files.values(), comment);
- locker.unlock();
+ Nepomuk::MassUpdateJob::commentResources(m_files.values(), comment);
startChangeDataJob(job);
+#else
+ Q_UNUSED(comment);
#endif
}
void KMetaDataWidget::Private::slotMetaDataUpdateDone()
{
+#ifdef HAVE_NEPOMUK
q->setEnabled(true);
+#endif
}
+#ifdef HAVE_NEPOMUK
void KMetaDataWidget::Private::startChangeDataJob(KJob* job)
{
connect(job, SIGNAL(result(KJob*)),
q->setEnabled(false); // no updates during execution
job->start();
}
-
-#ifdef HAVE_NEPOMUK
-KMetaDataWidget::Private::LoadFilesThread::LoadFilesThread(
- KMetaDataWidget::Private::SharedData* m_sharedData,
- QMutex* m_mutex) :
- m_sharedData(m_sharedData),
- m_mutex(m_mutex),
- m_urls(),
- m_canceled(false)
-{
-}
-
-KMetaDataWidget::Private::LoadFilesThread::~LoadFilesThread()
-{
- // This thread may very well be deleted during execution. We need
- // to protect it from crashes here.
- m_canceled = true;
- wait();
-}
-
-void KMetaDataWidget::Private::LoadFilesThread::loadFiles(const KUrl::List& urls)
-{
- QMutexLocker locker(m_mutex);
- m_urls = urls;
- m_canceled = false;
- start();
-}
-
-void KMetaDataWidget::Private::LoadFilesThread::run()
-{
- QMutexLocker locker(m_mutex);
- const KUrl::List urls = m_urls;
- locker.unlock();
-
- KConfig config("kmetainformationrc", KConfig::NoGlobals);
- KConfigGroup settings = config.group("Show");
-
- bool first = true;
- unsigned int rating = 0;
- QString comment;
- QList<Nepomuk::Tag> tags;
- QList<QString> metaInfoLabels;
- QList<QString> metaInfoValues;
- QMap<KUrl, Nepomuk::Resource> files;
- foreach (const KUrl& url, urls) {
- if (m_canceled) {
- return;
- }
-
- Nepomuk::Resource file(url);
- files.insert(url, file);
-
- if (!first && (rating != file.rating())) {
- rating = 0; // reset rating
- } else if (first) {
- rating = file.rating();
- }
-
- if (!first && (comment != file.description())) {
- comment.clear(); // reset comment
- } else if (first) {
- comment = file.description();
- }
-
- if (!first && (tags != file.tags())) {
- tags.clear(); // reset tags
- } else if (first) {
- tags = file.tags();
- }
-
- if (first && (urls.count() == 1)) {
- // TODO: show shared meta information instead
- // of not showing anything on multiple selections
- QHash<QUrl, Nepomuk::Variant> properties = file.properties();
- QHash<QUrl, Nepomuk::Variant>::const_iterator it = properties.constBegin();
- while (it != properties.constEnd()) {
- Nepomuk::Types::Property prop(it.key());
- if (settings.readEntry(prop.name(), true)) {
- // TODO #1: use Nepomuk::formatValue(res, prop) if available
- // instead of it.value().toString()
- // TODO #2: using tunedLabel() is a workaround for KDE 4.3 (4.4?) until
- // we get translated labels
- metaInfoLabels.append(tunedLabel(prop.label()));
- metaInfoValues.append(it.value().toString());
- }
- ++it;
- }
- }
-
- first = false;
- }
-
- locker.relock();
- m_sharedData->rating = rating;
- m_sharedData->comment = comment;
- m_sharedData->tags = tags;
- m_sharedData->metaInfoLabels = metaInfoLabels;
- m_sharedData->metaInfoValues = metaInfoValues;
- m_sharedData->files = files;
-}
-
-QString KMetaDataWidget::Private::LoadFilesThread::tunedLabel(const QString& label) const
-{
- QString tunedLabel;
- const int labelLength = label.length();
- if (labelLength > 0) {
- tunedLabel.reserve(labelLength);
- tunedLabel = label[0].toUpper();
- for (int i = 1; i < labelLength; ++i) {
- if (label[i].isUpper() && !label[i - 1].isSpace() && !label[i - 1].isUpper()) {
- tunedLabel += ' ';
- tunedLabel += label[i].toLower();
- } else {
- tunedLabel += label[i];
- }
- }
- }
- return tunedLabel + ':';
-}
-
-#endif // HAVE_NEPOMUK
+#endif
KMetaDataWidget::KMetaDataWidget(QWidget* parent) :
QWidget(parent),
urls.append(url);
}
}
- d->m_loadFilesThread->loadFiles(urls);
+
+ if (d->m_loadMetaDataThread != 0) {
+ disconnect(d->m_loadMetaDataThread, SIGNAL(finished()), this, SLOT(slotLoadingFinished()));
+ d->m_loadMetaDataThread->cancelAndDelete();
+ }
+
+ d->m_loadMetaDataThread = new KLoadMetaDataThread();
+ connect(d->m_loadMetaDataThread, SIGNAL(finished()), this, SLOT(slotLoadingFinished()));
+ d->m_loadMetaDataThread->load(urls);
}
#endif
}
return d->m_visibleDataTypes;
}
+QSize KMetaDataWidget::sizeHint() const
+{
+ const int fixedWidth = 200;
+ int height = 0;
+ foreach (const Private::Row& row, d->m_rows) {
+ if (row.infoWidget != 0) {
+ int rowHeight = row.infoWidget->heightForWidth(fixedWidth / 2);
+ if (rowHeight <= 0) {
+ rowHeight = row.infoWidget->sizeHint().height();
+ }
+ height += rowHeight;
+ }
+ }
+ return QSize(fixedWidth, height);
+}
+
#include "kmetadatawidget.moc"