Allow to provide custom widgets for meta data in a generic way.

By this it is possible that other applications like e. g. Gwenview provide custom widgets to change EXIF data directly within the meta data widget.

svn path=/trunk/KDE/kdebase/apps/; revision=1102834
This commit is contained in:
Peter Penz 2010-03-13 19:07:40 +00:00
parent 6b9c4f7b45
commit 5f54238912
2 changed files with 189 additions and 75 deletions

View file

@ -65,15 +65,16 @@ public:
struct Row struct Row
{ {
QLabel* label; QLabel* label;
QWidget* infoWidget; QLabel* defaultValueWidget;
QWidget* customValueWidget;
}; };
Private(KMetaDataWidget* parent); Private(KMetaDataWidget* parent);
~Private(); ~Private();
void addRow(QLabel* label, QWidget* infoWidget); void addRow(QLabel* label, QLabel* valueWidget);
void removeMetaInfoRows(); void setCustomValueWidget(int rowIndex, QWidget* valueWidget);
void setRowVisible(QWidget* infoWidget, bool visible); void setRowVisible(QWidget* valueWidget, bool visible);
/** /**
* Initializes the configuration file "kmetainformationrc" * Initializes the configuration file "kmetainformationrc"
@ -207,11 +208,12 @@ KMetaDataWidget::Private::~Private()
{ {
} }
void KMetaDataWidget::Private::addRow(QLabel* label, QWidget* infoWidget) void KMetaDataWidget::Private::addRow(QLabel* label, QLabel* valueWidget)
{ {
Row row; Row row;
row.label = label; row.label = label;
row.infoWidget = infoWidget; row.defaultValueWidget = valueWidget;
row.customValueWidget = 0;
m_rows.append(row); m_rows.append(row);
const QFont smallFont = KGlobalSettings::smallestReadableFont(); const QFont smallFont = KGlobalSettings::smallestReadableFont();
@ -227,34 +229,62 @@ void KMetaDataWidget::Private::addRow(QLabel* label, QWidget* infoWidget)
label->setWordWrap(true); label->setWordWrap(true);
label->setAlignment(Qt::AlignTop | Qt::AlignRight); label->setAlignment(Qt::AlignTop | Qt::AlignRight);
infoWidget->setForegroundRole(role); valueWidget->setForegroundRole(role);
QLabel* infoLabel = qobject_cast<QLabel*>(infoWidget); valueWidget->setFont(smallFont);
if (infoLabel != 0) { valueWidget->setWordWrap(true);
infoLabel->setFont(smallFont); valueWidget->setAlignment(Qt::AlignTop | Qt::AlignLeft);
infoLabel->setWordWrap(true);
infoLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft);
}
// add the row to grid layout // add the row to grid layout
const int rowIndex = m_rows.count(); const int rowIndex = m_rows.count() - 1;
m_gridLayout->addWidget(label, rowIndex, 0, Qt::AlignRight); m_gridLayout->addWidget(label, rowIndex, 0, Qt::AlignRight);
const int spacerWidth = QFontMetrics(smallFont).size(Qt::TextSingleLine, " ").width(); const int spacerWidth = QFontMetrics(smallFont).size(Qt::TextSingleLine, " ").width();
m_gridLayout->addItem(new QSpacerItem(spacerWidth, 1), rowIndex, 1); m_gridLayout->addItem(new QSpacerItem(spacerWidth, 1), rowIndex, 1);
m_gridLayout->addWidget(infoWidget, rowIndex, 2, Qt::AlignLeft); m_gridLayout->addWidget(valueWidget, rowIndex, 2, Qt::AlignLeft);
} }
void KMetaDataWidget::Private::setRowVisible(QWidget* infoWidget, bool visible) void KMetaDataWidget::Private::setCustomValueWidget(int rowIndex, QWidget* valueWidget)
{
Row& row = m_rows[rowIndex];
if (valueWidget == 0) {
// remove current custom value widget from the grid and replace it
// by the default value widget
if (row.customValueWidget != 0) {
row.customValueWidget->setVisible(false);
m_gridLayout->removeWidget(row.customValueWidget);
}
m_gridLayout->addWidget(row.defaultValueWidget, rowIndex, 2, Qt::AlignLeft);
row.defaultValueWidget->setVisible(true);
} else {
// remove the default value widget from the grid and replace it
// by the custom value widget
row.defaultValueWidget->setVisible(false);
m_gridLayout->removeWidget(row.defaultValueWidget);
m_gridLayout->addWidget(valueWidget, rowIndex, 2, Qt::AlignLeft);
valueWidget->setVisible(true);
}
row.customValueWidget = valueWidget;
}
void KMetaDataWidget::Private::setRowVisible(QWidget* valueWidget, bool visible)
{ {
foreach (const Row& row, m_rows) { foreach (const Row& row, m_rows) {
if (row.infoWidget == infoWidget) { const bool found = (row.defaultValueWidget == valueWidget) ||
(row.customValueWidget == valueWidget);
if (found) {
row.label->setVisible(visible); row.label->setVisible(visible);
row.infoWidget->setVisible(visible); if (row.customValueWidget != 0) {
row.customValueWidget->setVisible(visible);
row.defaultValueWidget->setVisible(false);
} else {
row.defaultValueWidget->setVisible(visible);
}
return; return;
} }
} }
} }
void KMetaDataWidget::Private::initMetaInfoSettings() void KMetaDataWidget::Private::initMetaInfoSettings()
{ {
const int currentVersion = 3; // increase version, if the blacklist of disabled const int currentVersion = 3; // increase version, if the blacklist of disabled
@ -369,7 +399,6 @@ void KMetaDataWidget::Private::slotLoadingFinished()
// Show the remaining meta information as text. The number // Show the remaining meta information as text. The number
// of required rows may very. Existing rows are reused to // of required rows may very. Existing rows are reused to
// prevent flickering. // prevent flickering.
const KNfoTranslator& nfo = KNfoTranslator::instance();
int rowIndex = m_fixedRowCount; int rowIndex = m_fixedRowCount;
const QHash<KUrl, Nepomuk::Variant> data = m_model->data(); const QHash<KUrl, Nepomuk::Variant> data = m_model->data();
@ -377,57 +406,39 @@ void KMetaDataWidget::Private::slotLoadingFinished()
foreach (const KUrl& key, keys) { foreach (const KUrl& key, keys) {
const Nepomuk::Variant value = data[key]; const Nepomuk::Variant value = data[key];
const QString itemLabel = nfo.translation(key); const QString itemLabel = q->label(key);
bool appliedData = false; const bool valueApplied = q->setValue(key, value);
if (m_nepomukActivated) { if (rowIndex >= m_rows.count()) {
const QString keyString = key.url(); // a new row must get created
if (keyString == QLatin1String("kfileitem#rating")) { QLabel* label = new QLabel(itemLabel, q);
m_ratingWidget->setRating(value.toInt()); QLabel* valueWidget = new QLabel(q);
appliedData = true; connect(valueWidget, SIGNAL(linkActivated(QString)),
} else if (keyString == QLatin1String("kfileitem#comment")) { q, SLOT(slotLinkActivated(QString)));
m_commentWidget->setText(value.toString()); addRow(label, valueWidget);
appliedData = true;
} else if (keyString == QLatin1String("kfileitem#tags")) {
QList<Nepomuk::Variant> variants = value.toVariantList();
QList<Nepomuk::Tag> tags;
foreach (const Nepomuk::Variant& variant, variants) {
const Nepomuk::Resource resource = variant.toResource();
tags.append(static_cast<Nepomuk::Tag>(resource));
}
m_taggingWidget->setTags(tags);
appliedData = true;
}
} }
if (!appliedData) { Q_ASSERT(m_rows[rowIndex].label != 0);
QString itemValue; Q_ASSERT(m_rows[rowIndex].defaultValueWidget != 0);
if (value.isString()) {
itemValue = value.toString();
}
if (rowIndex < m_rows.count()) { // set label
// adjust texts of the current row m_rows[rowIndex].label->setText(itemLabel);
m_rows[rowIndex].label->setText(itemLabel);
QLabel* infoValueLabel = qobject_cast<QLabel*>(m_rows[rowIndex].infoWidget); // set value
Q_ASSERT(infoValueLabel != 0); if (valueApplied) {
infoValueLabel->setText(itemValue); setCustomValueWidget(rowIndex, q->valueWidget(key));
} else { } else {
// create new row QLabel* valueWidget = m_rows[rowIndex].defaultValueWidget;
QLabel* infoLabel = new QLabel(itemLabel, q); valueWidget->setText(value.toString());
QLabel* infoValue = new QLabel(itemValue, q); setCustomValueWidget(rowIndex, 0);
connect(infoValue, SIGNAL(linkActivated(QString)),
q, SLOT(slotLinkActivated(QString)));
addRow(infoLabel, infoValue);
}
++rowIndex;
} }
++rowIndex;
} }
// remove rows that are not needed anymore // remove rows that are not needed anymore
for (int i = m_rows.count() - 1; i >= rowIndex; --i) { for (int i = m_rows.count() - 1; i >= rowIndex; --i) {
delete m_rows[i].label; delete m_rows[i].label;
delete m_rows[i].infoWidget; delete m_rows[i].defaultValueWidget;
m_rows.pop_back(); m_rows.pop_back();
} }
#endif #endif
@ -502,8 +513,6 @@ void KMetaDataWidget::Private::startChangeDataJob(KJob* job)
QList<KUrl> KMetaDataWidget::Private::sortedKeys(const QHash<KUrl, Nepomuk::Variant>& data) const QList<KUrl> KMetaDataWidget::Private::sortedKeys(const QHash<KUrl, Nepomuk::Variant>& data) const
{ {
const KNfoTranslator& nfo = KNfoTranslator::instance();
// Create a map, where the translated label prefixed with the // Create a map, where the translated label prefixed with the
// sort priority acts as key. The data of each entry is the URI // sort priority acts as key. The data of each entry is the URI
// of the data. By this the all URIs are sorted by the sort priority // of the data. By this the all URIs are sorted by the sort priority
@ -514,7 +523,7 @@ QList<KUrl> KMetaDataWidget::Private::sortedKeys(const QHash<KUrl, Nepomuk::Vari
const KUrl uri = hashIt.key(); const KUrl uri = hashIt.key();
QString key = q->model()->group(uri); QString key = q->model()->group(uri);
key += nfo.translation(uri); key += q->label(uri);
map.insert(key, uri); map.insert(key, uri);
++hashIt; ++hashIt;
@ -670,10 +679,15 @@ QSize KMetaDataWidget::sizeHint() const
d->m_gridLayout->spacing() * (d->m_rows.count() - 1); d->m_gridLayout->spacing() * (d->m_rows.count() - 1);
foreach (const Private::Row& row, d->m_rows) { foreach (const Private::Row& row, d->m_rows) {
if (row.infoWidget != 0) { QWidget* valueWidget = row.defaultValueWidget;
int rowHeight = row.infoWidget->heightForWidth(fixedWidth / 2); if (valueWidget != 0) {
if (row.customValueWidget != 0) {
valueWidget = row.customValueWidget;
}
int rowHeight = valueWidget->heightForWidth(fixedWidth / 2);
if (rowHeight <= 0) { if (rowHeight <= 0) {
rowHeight = row.infoWidget->sizeHint().height(); rowHeight = valueWidget->sizeHint().height();
} }
height += rowHeight; height += rowHeight;
} }
@ -682,6 +696,71 @@ QSize KMetaDataWidget::sizeHint() const
return QSize(fixedWidth, height); return QSize(fixedWidth, height);
} }
#ifdef HAVE_NEPOMUK
QString KMetaDataWidget::label(const KUrl& metaDataUri) const
{
QString label;
const QString uri = metaDataUri.url();
if (uri == QLatin1String("kfileitem#rating")) {
label = i18nc("@label", "Rating");
} else if (uri == QLatin1String("kfileitem#tags")) {
label = i18nc("@label", "Tags");
} else if (uri == QLatin1String("kfileitem#comment")) {
label = i18nc("@label", "Comment");
} else {
label = KNfoTranslator::instance().translation(metaDataUri);
}
return label;
}
QWidget* KMetaDataWidget::valueWidget(const KUrl& metaDataUri) const
{
QWidget* widget = 0;
if (d->m_nepomukActivated) {
const QString uri = metaDataUri.url();
if (uri == QLatin1String("kfileitem#rating")) {
widget = d->m_ratingWidget;
} else if (uri == QLatin1String("kfileitem#tags")) {
widget = d->m_taggingWidget;
} else if (uri == QLatin1String("kfileitem#comment")) {
widget = d->m_commentWidget;
}
}
return widget;
}
bool KMetaDataWidget::setValue(const KUrl& metaDataUri, const Nepomuk::Variant& value)
{
if (d->m_nepomukActivated) {
QWidget* widget = valueWidget(metaDataUri);
if (widget == d->m_ratingWidget) {
d->m_ratingWidget->setRating(value.toInt());
return true;
}
if (widget == d->m_taggingWidget) {
QList<Nepomuk::Variant> variants = value.toVariantList();
QList<Nepomuk::Tag> tags;
foreach (const Nepomuk::Variant& variant, variants) {
const Nepomuk::Resource resource = variant.toResource();
tags.append(static_cast<Nepomuk::Tag>(resource));
}
d->m_taggingWidget->setTags(tags);
return true;
}
if (widget == d->m_commentWidget) {
d->m_commentWidget->setText(value.toString());
return true;
}
}
return false;
}
#endif
bool KMetaDataWidget::event(QEvent* event) bool KMetaDataWidget::event(QEvent* event)
{ {
if (event->type() == QEvent::Polish) { if (event->type() == QEvent::Polish) {
@ -695,14 +774,6 @@ bool KMetaDataWidget::event(QEvent* event)
d->addRow(new QLabel(i18nc("@label", "Owner"), this), d->m_ownerInfo); d->addRow(new QLabel(i18nc("@label", "Owner"), this), d->m_ownerInfo);
d->addRow(new QLabel(i18nc("@label", "Permissions"), this), d->m_permissionsInfo); d->addRow(new QLabel(i18nc("@label", "Permissions"), this), d->m_permissionsInfo);
#ifdef HAVE_NEPOMUK
if (d->m_nepomukActivated) {
d->addRow(new QLabel(i18nc("@label", "Rating"), this), d->m_ratingWidget);
d->addRow(new QLabel(i18nc("@label", "Tags"), this), d->m_taggingWidget);
d->addRow(new QLabel(i18nc("@label", "Comment"), this), d->m_commentWidget);
}
#endif
// The current number of rows represents meta data, that will be shown for // The current number of rows represents meta data, that will be shown for
// all files. Dynamic meta data will be appended after those rows (see // all files. Dynamic meta data will be appended after those rows (see
// slotLoadingFinished()). // slotLoadingFinished()).

View file

@ -25,6 +25,12 @@
#include <QList> #include <QList>
#include <QWidget> #include <QWidget>
#include <config-nepomuk.h>
#ifdef HAVE_NEPOMUK
#define DISABLE_NEPOMUK_LEGACY
#include <nepomuk/variant.h>
#endif
class KMetaDataModel; class KMetaDataModel;
class KUrl; class KUrl;
@ -41,6 +47,16 @@ class KUrl;
* To show more than basic meta data, the meta data widget * To show more than basic meta data, the meta data widget
* must be provided with a meta data model * must be provided with a meta data model
* (see KMetaDataWidget::setModel()). * (see KMetaDataWidget::setModel()).
*
* Per default most meta data values are shown as labels.
* However it is possible to adjust KMetaDataWidget to use
* custom widgets for showing and modifying meta data (e. g.
* like done already for the rating, tags or comments). The
* following steps are necessary:
* - Derive a custom widget from KMetaDataWidget.
* - Create the custom widgets in the constructor.
* - Implement the methods valueWidget(), setValue() and
* (optionally) label() by accessing the custom widgets.
*/ */
class KMetaDataWidget : public QWidget class KMetaDataWidget : public QWidget
{ {
@ -138,6 +154,33 @@ Q_SIGNALS:
void urlActivated(const KUrl& url); void urlActivated(const KUrl& url);
protected: protected:
#ifdef HAVE_NEPOMUK
/**
* @return Translated string for the label of the meta data represented
* by \p metaDataUri. If no custom translation is provided, the
* base implementation must be invoked.
*/
virtual QString label(const KUrl& metaDataUri) const;
/**
* @return Pointer to the custom value-widget that should be used
* to show the meta data represented by \p metaDataUri. If 0
* is returned, the meta data will be shown inside a label
* as fallback. If no custom value widget is used for the
* given URI, the base implementation must be invoked.
*/
virtual QWidget* valueWidget(const KUrl& metaDataUri) const;
/**
* Sets the value of a custom value-widget to \p value. If the meta data
* represented by \p metaDataUri is not shown by a custom value-widget (see
* KMetaDataWidget::valueWidget()), then the base implementation must be
* invoked.
* @return True, if a custom value-widget is available, where the value got applied.
*/
virtual bool setValue(const KUrl& metaDataUri, const Nepomuk::Variant& value);
#endif
virtual bool event(QEvent* event); virtual bool event(QEvent* event);
private: private: