KDELibs4Support

kfilemetadatawidget.cpp
1 /*****************************************************************************
2  * Copyright (C) 2008-2010 by Sebastian Trueg <[email protected]> *
3  * Copyright (C) 2009-2010 by Peter Penz <[email protected]> *
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 as published by the Free Software Foundation; either *
8  * version 2 of the License, or (at your option) any later version. *
9  * *
10  * This library 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 GNU *
13  * Library General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU Library General Public License *
16  * along with this library; see the file COPYING.LIB. If not, write to *
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
18  * Boston, MA 02110-1301, USA. *
19  *****************************************************************************/
20 
21 #include "kfilemetadatawidget.h"
22 
23 #include <kconfig.h>
24 #include <kconfiggroup.h>
25 #include <klocalizedstring.h>
26 
27 #include <QGridLayout>
28 #include <QLabel>
29 #include <QSet>
30 #include <QString>
31 #include <QTimer>
32 
33 #include <config-kdelibs4support.h>
34 #if ! KIO_NO_NEPOMUK
35 #define DISABLE_NEPOMUK_LEGACY
36 
37 #include <property.h>
38 #include <tag.h>
39 
40 #include <QSpacerItem>
41 
42 #include "kfilemetadataprovider_p.h"
43 #endif
44 
45 class Q_DECL_HIDDEN KFileMetaDataWidget::Private
46 {
47 public:
48  struct Row {
49  QLabel *label;
50  QWidget *value;
51  };
52 
53  Private(KFileMetaDataWidget *parent);
54  ~Private();
55 
56  /**
57  * Initializes the configuration file "kmetainformationrc"
58  * with proper default settings for the first start in
59  * an uninitialized environment.
60  */
61  void initMetaInfoSettings();
62 
63  /**
64  * Parses the configuration file "kmetainformationrc" and
65  * updates the visibility of all rows that got their data
66  * from KFileItem.
67  */
68  void updateFileItemRowsVisibility();
69 
70  void deleteRows();
71 
72  void slotLoadingFinished();
73  void slotLinkActivated(const QString &link);
74  void slotDataChangeStarted();
75  void slotDataChangeFinished();
76 
77 #if ! KIO_NO_NEPOMUK
78  QList<QUrl> sortedKeys(const QHash<QUrl, Nepomuk::Variant> &data) const;
79 
80  /**
81  * @return True, if at least one of the file items \a m_fileItems has
82  * a valid Nepomuk URI.
83  */
84  bool hasNepomukUris() const;
85 #endif
86 
87  QList<Row> m_rows;
88 #if ! KIO_NO_NEPOMUK
89  KFileMetaDataProvider *m_provider;
90 #endif
91  QGridLayout *m_gridLayout;
92 
93 private:
94  KFileMetaDataWidget *const q;
95 };
96 
97 KFileMetaDataWidget::Private::Private(KFileMetaDataWidget *parent) :
98  m_rows(),
99 #if ! KIO_NO_NEPOMUK
100  m_provider(0),
101 #endif
102  m_gridLayout(nullptr),
103  q(parent)
104 {
105  initMetaInfoSettings();
106 
107 #if ! KIO_NO_NEPOMUK
108  // TODO: If KFileMetaDataProvider might get a public class in future KDE releases,
109  // the following code should be moved into KFileMetaDataWidget::setModel():
110  m_provider = new KFileMetaDataProvider(q);
111  connect(m_provider, SIGNAL(loadingFinished()), q, SLOT(slotLoadingFinished()));
112  connect(m_provider, SIGNAL(urlActivated(QUrl)), q, SIGNAL(urlActivated(QUrl)));
113 #endif
114 }
115 
116 KFileMetaDataWidget::Private::~Private()
117 {
118 }
119 
120 void KFileMetaDataWidget::Private::initMetaInfoSettings()
121 {
122  const int currentVersion = 3; // increase version, if the blacklist of disabled
123  // properties should be updated
124 
125  KConfig config("kmetainformationrc", KConfig::NoGlobals);
126  if (config.group("Misc").readEntry("version", 0) < currentVersion) {
127  // The resource file is read the first time. Assure
128  // that some meta information is disabled per default.
129 
130  // clear old info
131  config.deleteGroup("Show");
132  KConfigGroup settings = config.group("Show");
133 
134  static const char *const disabledProperties[] = {
135  "http://www.semanticdesktop.org/ontologies/2007/01/19/nie#comment",
136  "http://www.semanticdesktop.org/ontologies/2007/01/19/nie#contentSize",
137  "http://www.semanticdesktop.org/ontologies/2007/01/19/nie#depends",
138  "http://www.semanticdesktop.org/ontologies/2007/01/19/nie#isPartOf",
139  "http://www.semanticdesktop.org/ontologies/2007/01/19/nie#lastModified",
140  "http://www.semanticdesktop.org/ontologies/2007/01/19/nie#mimeType",
141  "http://www.semanticdesktop.org/ontologies/2007/01/19/nie#plainTextContent",
142  "http://www.semanticdesktop.org/ontologies/2007/01/19/nie#url",
143  "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#averageBitrate",
144  "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#channels",
145  "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#fileName",
146  "http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#apertureValue",
147  "http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#exposureBiasValue",
148  "http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#exposureTime",
149  "http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#flash",
150  "http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#focalLength",
151  "http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#focalLengthIn35mmFilm",
152  "http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#isoSpeedRatings",
153  "http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#make",
154  "http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#meteringMode",
155  "http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#model",
156  "http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#orientation",
157  "http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#whiteBalance",
158  "http://www.semanticdesktop.org/ontologies/2007/08/15/nao#description",
159  "http://www.semanticdesktop.org/ontologies/2007/08/15/nao#hasTag",
160  "http://www.semanticdesktop.org/ontologies/2007/08/15/nao#lastModified",
161  "http://www.semanticdesktop.org/ontologies/2007/08/15/nao#numericRating",
162  "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
163  "kfileitem#owner",
164  "kfileitem#permissions",
165  nullptr // mandatory last entry
166  };
167 
168  for (int i = 0; disabledProperties[i] != nullptr; ++i) {
169  settings.writeEntry(disabledProperties[i], false);
170  }
171 
172  // mark the group as initialized
173  config.group("Misc").writeEntry("version", currentVersion);
174  }
175 }
176 
177 void KFileMetaDataWidget::Private::deleteRows()
178 {
179  foreach (const Row &row, m_rows) {
180  delete row.label;
181  delete row.value;
182  }
183  m_rows.clear();
184 }
185 
186 void KFileMetaDataWidget::Private::slotLoadingFinished()
187 {
188 #if ! KIO_NO_NEPOMUK
189  deleteRows();
190 
191  if (!hasNepomukUris()) {
192  q->updateGeometry();
193  emit q->metaDataRequestFinished(m_provider->items());
194  return;
195  }
196 
197  if (m_gridLayout == 0) {
198  m_gridLayout = new QGridLayout(q);
199  m_gridLayout->setContentsMargins(0, 0, 0, 0);
200  m_gridLayout->setSpacing(q->fontMetrics().height() / 4);
201  }
202 
203  QHash<QUrl, Nepomuk::Variant> data = m_provider->data();
204 
205  // Remove all items, that are marked as hidden in kmetainformationrc
206  KConfig config("kmetainformationrc", KConfig::NoGlobals);
207  KConfigGroup settings = config.group("Show");
209  while (it != data.end()) {
210  const QString uriString = it.key().url();
211  if (!settings.readEntry(uriString, true) ||
212  !Nepomuk::Types::Property(it.key()).userVisible()) {
213  it = data.erase(it);
214  } else {
215  ++it;
216  }
217  }
218 
219  // Iterate through all remaining items embed the label
220  // and the value as new row in the widget
221  int rowIndex = 0;
222  const QList<QUrl> keys = sortedKeys(data);
223  foreach (const QUrl &key, keys) {
224  const Nepomuk::Variant value = data[key];
225  QString itemLabel = m_provider->label(key);
226  itemLabel.append(QLatin1Char(':'));
227 
228  // Create label
229  QLabel *label = new QLabel(itemLabel, q);
231  label->setForegroundRole(q->foregroundRole());
232  label->setFont(q->font());
233  label->setWordWrap(true);
234  label->setAlignment(Qt::AlignTop | Qt::AlignRight);
235 
236  // Create value-widget
237  QWidget *valueWidget = m_provider->createValueWidget(key, value, q);
238 
239  // Add the label and value-widget to grid layout
240  m_gridLayout->addWidget(label, rowIndex, 0, Qt::AlignRight);
241  const int spacerWidth = QFontMetrics(q->font()).size(Qt::TextSingleLine, " ").width();
242  m_gridLayout->addItem(new QSpacerItem(spacerWidth, 1), rowIndex, 1);
243  m_gridLayout->addWidget(valueWidget, rowIndex, 2, Qt::AlignLeft);
244 
245  // Remember the label and value-widget as row
246  Row row;
247  row.label = label;
248  row.value = valueWidget;
249  m_rows.append(row);
250 
251  ++rowIndex;
252  }
253 #endif
254 
255  q->updateGeometry();
256 #if ! KIO_NO_NEPOMUK
257  emit q->metaDataRequestFinished(m_provider->items());
258 #endif
259 }
260 
261 void KFileMetaDataWidget::Private::slotLinkActivated(const QString &link)
262 {
263  const QUrl url(link);
264  if (url.isValid()) {
265  emit q->urlActivated(url);
266  }
267 }
268 
269 void KFileMetaDataWidget::Private::slotDataChangeStarted()
270 {
271  q->setEnabled(false);
272 }
273 
274 void KFileMetaDataWidget::Private::slotDataChangeFinished()
275 {
276  q->setEnabled(true);
277 }
278 
279 #if ! KIO_NO_NEPOMUK
280 QList<QUrl> KFileMetaDataWidget::Private::sortedKeys(const QHash<QUrl, Nepomuk::Variant> &data) const
281 {
282  // Create a map, where the translated label prefixed with the
283  // sort priority acts as key. The data of each entry is the URI
284  // of the data. By this the all URIs are sorted by the sort priority
285  // and sub sorted by the translated labels.
288  while (hashIt != data.constEnd()) {
289  const QUrl uri = hashIt.key();
290 
291  QString key = m_provider->group(uri);
292  key += m_provider->label(uri);
293 
294  map.insert(key, uri);
295  ++hashIt;
296  }
297 
298  // Apply the URIs from the map to the list that will get returned.
299  // The list will then be alphabetically ordered by the translated labels of the URIs.
301  QMap<QString, QUrl>::const_iterator mapIt = map.constBegin();
302  while (mapIt != map.constEnd()) {
303  list.append(mapIt.value());
304  ++mapIt;
305  }
306 
307  return list;
308 }
309 
310 bool KFileMetaDataWidget::Private::hasNepomukUris() const
311 {
312  foreach (const KFileItem &fileItem, m_provider->items()) {
313  if (fileItem.nepomukUri().isValid()) {
314  return true;
315  }
316  }
317  return false;
318 }
319 #endif
320 
321 KFileMetaDataWidget::KFileMetaDataWidget(QWidget *parent) :
322  QWidget(parent),
323  d(new Private(this))
324 {
325 }
326 
327 KFileMetaDataWidget::~KFileMetaDataWidget()
328 {
329  delete d;
330 }
331 
333 {
334 #if KIO_NO_NEPOMUK
335  Q_UNUSED(items)
336 #else
337  d->m_provider->setItems(items);
338 #endif
339 }
340 
341 KFileItemList KFileMetaDataWidget::items() const
342 {
343 #if ! KIO_NO_NEPOMUK
344  return d->m_provider->items();
345 #else
346  return KFileItemList();
347 #endif
348 }
349 
351 {
352 #if KIO_NO_NEPOMUK
353  Q_UNUSED(readOnly)
354 #else
355  d->m_provider->setReadOnly(readOnly);
356 #endif
357 }
358 
359 bool KFileMetaDataWidget::isReadOnly() const
360 {
361 #if ! KIO_NO_NEPOMUK
362  return d->m_provider->isReadOnly();
363 #else
364  return true;
365 #endif
366 }
367 
369 {
370  if (d->m_gridLayout == nullptr) {
371  return QWidget::sizeHint();
372  }
373 
374  // Calculate the required width for the labels and values
375  int leftWidthMax = 0;
376  int rightWidthMax = 0;
377  int rightWidthAverage = 0;
378  foreach (const Private::Row &row, d->m_rows) {
379  const QWidget *valueWidget = row.value;
380  const int rightWidth = valueWidget->sizeHint().width();
381  rightWidthAverage += rightWidth;
382  if (rightWidth > rightWidthMax) {
383  rightWidthMax = rightWidth;
384  }
385 
386  const int leftWidth = row.label->sizeHint().width();
387  if (leftWidth > leftWidthMax) {
388  leftWidthMax = leftWidth;
389  }
390  }
391 
392  // Some value widgets might return a very huge width for the size hint.
393  // Limit the maximum width to the double width of the overall average
394  // to assure a less messed layout.
395  if (d->m_rows.count() > 1) {
396  rightWidthAverage /= d->m_rows.count();
397  if (rightWidthMax > rightWidthAverage * 2) {
398  rightWidthMax = rightWidthAverage * 2;
399  }
400  }
401 
402  // Based on the available width calculate the required height
403  int height = d->m_gridLayout->margin() * 2 + d->m_gridLayout->spacing() * (d->m_rows.count() - 1);
404  foreach (const Private::Row &row, d->m_rows) {
405  const QWidget *valueWidget = row.value;
406  const int rowHeight = qMax(row.label->heightForWidth(leftWidthMax),
407  valueWidget->heightForWidth(rightWidthMax));
408  height += rowHeight;
409  }
410 
411  const int width = d->m_gridLayout->margin() * 2 + leftWidthMax +
412  d->m_gridLayout->spacing() + rightWidthMax;
413 
414  return QSize(width, height);
415 }
416 
417 bool KFileMetaDataWidget::event(QEvent *event)
418 {
419  return QWidget::event(event);
420 }
421 
422 #include "moc_kfilemetadatawidget.cpp"
void append(const T &value)
QString readEntry(const char *key, const char *aDefault=nullptr) const
void writeEntry(const char *key, const char *value, WriteConfigFlags pFlags=Normal)
AlignTop
QHash::iterator erase(QHash::iterator pos)
TextSingleLine
QHash::iterator begin()
virtual bool event(QEvent *event) override
int width() const const
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
Shows the meta data of one or more file items.
QHash::const_iterator constBegin() const const
QHash::const_iterator constEnd() const const
const Key key(const T &value) const const
void setReadOnly(bool readOnly)
If set to true, data such as the comment, tag or rating cannot be changed by the user.
KSharedConfigPtr config()
Returns the general config object.
Definition: kglobal.cpp:102
QSize size(int flags, const QString &text, int tabStops, int *tabArray) const const
QString label(StandardShortcut id)
Definition: netaccess.h:36
virtual int heightForWidth(int w) const const
QSize sizeHint() const override
void updateGeometry()
void setItems(const KFileItemList &items)
Sets the items for which the meta data should be shown.
QFuture< void > map(Sequence &sequence, MapFunctor function)
QString & append(QChar ch)
QHash::iterator end()
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Thu Sep 21 2023 03:59:16 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.