• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KIO

kfilemetadataprovider.cpp

Go to the documentation of this file.
00001 /*****************************************************************************
00002  * Copyright (C) 2010 by Peter Penz <peter.penz@gmx.at>                      *
00003  *                                                                           *
00004  * This library is free software; you can redistribute it and/or             *
00005  * modify it under the terms of the GNU Library General Public               *
00006  * License as published by the Free Software Foundation; either              *
00007  * version 2 of the License, or (at your option) any later version.          *
00008  *                                                                           *
00009  * This library is distributed in the hope that it will be useful,           *
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
00012  * Library General Public License for more details.                          *
00013  *                                                                           *
00014  * You should have received a copy of the GNU Library General Public License *
00015  * along with this library; see the file COPYING.LIB.  If not, write to      *
00016  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,      *
00017  * Boston, MA 02110-1301, USA.                                               *
00018  *****************************************************************************/
00019 
00020 #include "kfilemetadataprovider_p.h"
00021 
00022 #include <kfileitem.h>
00023 #include "knfotranslator_p.h"
00024 #include <klocale.h>
00025 #include <kurl.h>
00026 
00027 #ifndef KIO_NO_NEPOMUK
00028     #define DISABLE_NEPOMUK_LEGACY
00029     #include "nepomukmassupdatejob.h"
00030     #include "tagwidget.h"
00031     #include "kratingwidget.h"
00032     #include "resource.h"
00033     #include "resourcemanager.h"
00034 
00035     #include "kcommentwidget_p.h"
00036     #include "kloadfilemetadatathread_p.h"
00037 #else
00038     namespace Nepomuk
00039     {
00040         typedef int Tag;
00041     }
00042 #endif
00043 
00044 #include <QEvent>
00045 #include <QLabel>
00046 
00047 namespace {
00048     static QString plainText(const QString& richText)
00049     {
00050         QString plainText;
00051         plainText.reserve(richText.length());
00052 
00053         bool skip = false;
00054         for (int i = 0; i < richText.length(); ++i) {
00055             const QChar c = richText.at(i);
00056             if (c == QLatin1Char('<')) {
00057                 skip = true;
00058             } else if (c == QLatin1Char('>')) {
00059                 skip = false;
00060             } else if (!skip) {
00061                 plainText.append(c);
00062             }
00063         }
00064 
00065         return plainText;
00066     }
00067 }
00068 
00069 // The default size hint of QLabel tries to return a square size.
00070 // This does not work well in combination with layouts that use
00071 // heightForWidth(): In this case it is possible that the content
00072 // of a label might get clipped. By specifying a size hint
00073 // with a maximum width that is necessary to contain the whole text,
00074 // using heightForWidth() assures having a non-clipped text.
00075 class ValueWidget : public QLabel
00076 {
00077 public:
00078     explicit ValueWidget(QWidget* parent = 0);
00079     virtual QSize sizeHint() const;
00080 };
00081 
00082 ValueWidget::ValueWidget(QWidget* parent) :
00083     QLabel(parent)
00084 {
00085 }
00086 
00087 QSize ValueWidget::sizeHint() const
00088 {
00089     QFontMetrics metrics(font());
00090     // TODO: QLabel internally provides already a method sizeForWidth(),
00091     // that would be sufficient. However this method is not accessible, so
00092     // as workaround the tags from a richtext are removed manually here to
00093     // have a proper size hint.
00094     return metrics.size(Qt::TextSingleLine, plainText(text()));
00095 }
00096 
00097 
00098 
00099 class KFileMetaDataProvider::Private
00100 {
00101 
00102 public:
00103     Private(KFileMetaDataProvider* parent);
00104     ~Private();
00105 
00106     void slotLoadingFinished(QThread* finishedThread);
00107 
00108     void slotRatingChanged(unsigned int rating);
00109     void slotTagsChanged(const QList<Nepomuk::Tag>& tags);
00110     void slotCommentChanged(const QString& comment);
00111 
00112     void slotMetaDataUpdateDone();
00113     void slotTagClicked(const Nepomuk::Tag& tag);
00114     void slotLinkActivated(const QString& link);
00115 
00121     void startChangeDataJob(KJob* job);
00122 
00123 #ifndef KIO_NO_NEPOMUK
00124     QList<Nepomuk::Resource> resourceList() const;   
00125     QWidget* createRatingWidget(int rating, QWidget* parent);
00126     QWidget* createTagWidget(const QList<Nepomuk::Tag>& tags, QWidget* parent);
00127     QWidget* createCommentWidget(const QString& comment, QWidget* parent);
00128 #endif
00129     QWidget* createValueWidget(const QString& value, QWidget* parent);
00130 
00131     bool m_readOnly;
00132     bool m_nepomukActivated;
00133     QList<KFileItem> m_fileItems;
00134 
00135 #ifndef KIO_NO_NEPOMUK
00136     QHash<KUrl, Nepomuk::Variant> m_data;
00137 
00138     QList<KLoadFileMetaDataThread*> m_metaDataThreads;
00139     KLoadFileMetaDataThread* m_latestMetaDataThread;
00140 
00141     QWeakPointer<KRatingWidget> m_ratingWidget;
00142     QWeakPointer<Nepomuk::TagWidget> m_tagWidget;
00143     QWeakPointer<KCommentWidget> m_commentWidget;
00144 #endif
00145 
00146 private:
00147     KFileMetaDataProvider* const q;
00148 };
00149 
00150 KFileMetaDataProvider::Private::Private(KFileMetaDataProvider* parent) :
00151     m_readOnly(false),
00152     m_nepomukActivated(false),
00153     m_fileItems(),
00154 #ifndef KIO_NO_NEPOMUK
00155     m_data(),
00156     m_metaDataThreads(),
00157     m_latestMetaDataThread(0),
00158     m_ratingWidget(),
00159     m_tagWidget(),
00160     m_commentWidget(),
00161 #endif
00162     q(parent)
00163 {
00164 #ifndef KIO_NO_NEPOMUK
00165     m_nepomukActivated = (Nepomuk::ResourceManager::instance()->init() == 0);
00166 #endif
00167 }
00168 
00169 KFileMetaDataProvider::Private::~Private()
00170 {
00171 #ifndef KIO_NO_NEPOMUK
00172     foreach (KLoadFileMetaDataThread* thread, m_metaDataThreads) {
00173         disconnect(thread, SIGNAL(finished(QThread*)),
00174                    q, SLOT(slotLoadingFinished(QThread*)));
00175         thread->wait();
00176     }
00177 #endif
00178 }
00179 
00180 void KFileMetaDataProvider::Private::slotLoadingFinished(QThread* finishedThread)
00181 {
00182 #ifndef KIO_NO_NEPOMUK
00183     // The thread that has emitted the finished() signal
00184     // will get deleted and removed from m_metaDataThreads.
00185     const int threadsCount = m_metaDataThreads.count();
00186     for (int i = 0; i < threadsCount; ++i) {
00187         KLoadFileMetaDataThread* thread = m_metaDataThreads[i];
00188         if (thread == finishedThread) {
00189             m_metaDataThreads.removeAt(i);
00190             if (thread != m_latestMetaDataThread) {
00191                 // Ignore data of older threads, as the data got
00192                 // obsolete by m_latestMetaDataThread.
00193                 thread->deleteLater();
00194                 return;
00195             }
00196         }
00197     }
00198 
00199     m_data = m_latestMetaDataThread->data();
00200     m_latestMetaDataThread->deleteLater();
00201 
00202     if (m_fileItems.count() == 1) {
00203         // TODO: Handle case if remote URLs are used properly. isDir() does
00204         // not work, the modification date needs also to be adjusted...
00205         const KFileItem& item = m_fileItems.first();
00206 
00207         m_data.insert(KUrl("kfileitem#size"), KIO::convertSize(item.size()));
00208         m_data.insert(KUrl("kfileitem#type"), item.mimeComment());
00209         m_data.insert(KUrl("kfileitem#modified"), KGlobal::locale()->formatDateTime(item.time(KFileItem::ModificationTime), KLocale::FancyLongDate));
00210         m_data.insert(KUrl("kfileitem#owner"), item.user());
00211         m_data.insert(KUrl("kfileitem#permissions"), item.permissionsString());
00212     } else if (m_fileItems.count() > 1) {
00213         // Calculate the size of all items
00214         quint64 totalSize = 0;
00215         foreach (const KFileItem& item, m_fileItems) {
00216             if (!item.isDir() && !item.isLink()) {
00217                 totalSize += item.size();
00218             }
00219         }
00220         m_data.insert(KUrl("kfileitem#totalSize"), KIO::convertSize(totalSize));
00221     }
00222 #else
00223     Q_UNUSED(finishedThread)
00224 #endif
00225 
00226     emit q->loadingFinished();
00227 }
00228 
00229 
00230 void KFileMetaDataProvider::Private::slotRatingChanged(unsigned int rating)
00231 {
00232 #ifndef KIO_NO_NEPOMUK
00233     Nepomuk::MassUpdateJob* job = Nepomuk::MassUpdateJob::rateResources(resourceList(), rating);
00234     startChangeDataJob(job);
00235 #else
00236     Q_UNUSED(rating);
00237 #endif
00238 }
00239 
00240 void KFileMetaDataProvider::Private::slotTagsChanged(const QList<Nepomuk::Tag>& tags)
00241 {
00242 #ifndef KIO_NO_NEPOMUK
00243     if (!m_tagWidget.isNull()) {
00244         m_tagWidget.data()->setSelectedTags(tags);
00245 
00246         Nepomuk::MassUpdateJob* job = Nepomuk::MassUpdateJob::tagResources(resourceList(), tags);
00247         startChangeDataJob(job);
00248     }
00249 #else
00250     Q_UNUSED(tags);
00251 #endif
00252 }
00253 
00254 void KFileMetaDataProvider::Private::slotCommentChanged(const QString& comment)
00255 {
00256 #ifndef KIO_NO_NEPOMUK
00257     Nepomuk::MassUpdateJob* job = Nepomuk::MassUpdateJob::commentResources(resourceList(), comment);
00258     startChangeDataJob(job);
00259 #else
00260     Q_UNUSED(comment);
00261 #endif
00262 }
00263 
00264 void KFileMetaDataProvider::Private::slotTagClicked(const Nepomuk::Tag& tag)
00265 {
00266 #ifndef KIO_NO_NEPOMUK
00267     emit q->urlActivated(tag.resourceUri());
00268 #else
00269     Q_UNUSED(tag);
00270 #endif
00271 }
00272 
00273 void KFileMetaDataProvider::Private::slotLinkActivated(const QString& link)
00274 {
00275     emit q->urlActivated(KUrl(link));
00276 }
00277 
00278 void KFileMetaDataProvider::Private::startChangeDataJob(KJob* job)
00279 {
00280     connect(job, SIGNAL(result(KJob*)),
00281             q, SIGNAL(dataChangeFinished()));
00282     emit q->dataChangeStarted();
00283     job->start();
00284 }
00285 
00286 #ifndef KIO_NO_NEPOMUK
00287 QList<Nepomuk::Resource> KFileMetaDataProvider::Private::resourceList() const
00288 {
00289     QList<Nepomuk::Resource> list;
00290     foreach (const KFileItem& item, m_fileItems) {
00291         const KUrl url = item.nepomukUri();
00292         if(url.isValid())
00293             list.append(Nepomuk::Resource(url));
00294     }
00295     return list;
00296 }
00297 
00298 QWidget* KFileMetaDataProvider::Private::createRatingWidget(int rating, QWidget* parent)
00299 {
00300     KRatingWidget* ratingWidget = new KRatingWidget(parent);
00301     const Qt::Alignment align = (ratingWidget->layoutDirection() == Qt::LeftToRight) ?
00302                                 Qt::AlignLeft : Qt::AlignRight;
00303     ratingWidget->setAlignment(align);
00304     ratingWidget->setRating(rating);
00305     const QFontMetrics metrics(parent->font());
00306     ratingWidget->setPixmapSize(metrics.height());
00307 
00308     connect(ratingWidget, SIGNAL(ratingChanged(unsigned int)),
00309             q, SLOT(slotRatingChanged(unsigned int)));
00310 
00311     m_ratingWidget = ratingWidget;
00312 
00313     return ratingWidget;
00314 }
00315 
00316 QWidget* KFileMetaDataProvider::Private::createTagWidget(const QList<Nepomuk::Tag>& tags, QWidget* parent)
00317 {
00318     Nepomuk::TagWidget* tagWidget = new Nepomuk::TagWidget(parent);
00319     tagWidget->setModeFlags(Nepomuk::TagWidget::MiniMode);
00320     tagWidget->setSelectedTags(tags);
00321     tagWidget->setModeFlags(m_readOnly
00322                             ? Nepomuk::TagWidget::MiniMode | Nepomuk::TagWidget::ReadOnly
00323                             : Nepomuk::TagWidget::MiniMode);
00324 
00325     connect(tagWidget, SIGNAL(selectionChanged(QList<Nepomuk::Tag>)),
00326             q, SLOT(slotTagsChanged(QList<Nepomuk::Tag>)));
00327     connect(tagWidget, SIGNAL(tagClicked(Nepomuk::Tag)),
00328             q, SLOT(slotTagClicked(Nepomuk::Tag)));
00329 
00330     m_tagWidget = tagWidget;
00331 
00332     return tagWidget;
00333 }
00334 
00335 QWidget* KFileMetaDataProvider::Private::createCommentWidget(const QString& comment, QWidget* parent)
00336 {
00337     KCommentWidget* commentWidget = new KCommentWidget(parent);
00338     commentWidget->setText(comment);
00339     commentWidget->setReadOnly(m_readOnly);
00340 
00341     connect(commentWidget, SIGNAL(commentChanged(const QString&)),
00342             q, SLOT(slotCommentChanged(const QString&)));
00343 
00344     m_commentWidget = commentWidget;
00345 
00346     return commentWidget;
00347 }
00348 #endif
00349 
00350 QWidget* KFileMetaDataProvider::Private::createValueWidget(const QString& value, QWidget* parent)
00351 {
00352     ValueWidget* valueWidget = new ValueWidget(parent);
00353     valueWidget->setWordWrap(true);
00354     valueWidget->setAlignment(Qt::AlignTop | Qt::AlignLeft);
00355     valueWidget->setText(m_readOnly ? plainText(value) : value);
00356     connect(valueWidget, SIGNAL(linkActivated(QString)), q, SLOT(slotLinkActivated(QString)));
00357     return valueWidget;
00358 }
00359 
00360 KFileMetaDataProvider::KFileMetaDataProvider(QObject* parent) :
00361     QObject(parent),
00362     d(new Private(this))
00363 {
00364 }
00365 
00366 KFileMetaDataProvider::~KFileMetaDataProvider()
00367 {
00368     delete d;
00369 }
00370 
00371 void KFileMetaDataProvider::setItems(const KFileItemList& items)
00372 {
00373     d->m_fileItems = items;
00374 
00375 #ifndef KIO_NO_NEPOMUK
00376     if (items.isEmpty()) {
00377         return;
00378     }
00379     Q_PRIVATE_SLOT(d, void slotDataChangeStarted())
00380     Q_PRIVATE_SLOT(d, void slotDataChangeFinished())
00381     QList<KUrl> urls;
00382     foreach (const KFileItem& item, items) {
00383         const KUrl url = item.nepomukUri();
00384         if (url.isValid()) {
00385             urls.append(url);
00386         }
00387     }
00388 
00389     // Cancel all threads that have not emitted a finished() signal.
00390     // The deleting of those threads is done in slotLoadingFinished().
00391     foreach (KLoadFileMetaDataThread* thread, d->m_metaDataThreads) {
00392         thread->cancel();
00393     }
00394 
00395     // Create a new thread that will provide the meta data for the items
00396     d->m_latestMetaDataThread = new KLoadFileMetaDataThread();
00397     connect(d->m_latestMetaDataThread, SIGNAL(finished(QThread*)),
00398             this, SLOT(slotLoadingFinished(QThread*)));
00399     d->m_latestMetaDataThread->load(urls);
00400     d->m_metaDataThreads.append(d->m_latestMetaDataThread);
00401 #endif
00402 }
00403 
00404 QString KFileMetaDataProvider::label(const KUrl& metaDataUri) const
00405 {
00406     struct TranslationItem {
00407         const char* const key;
00408         const char* const context;
00409         const char* const value;
00410     };
00411 
00412     static const TranslationItem translations[] = {
00413         { "kfileitem#comment", I18N_NOOP2_NOSTRIP("@label", "Comment") },
00414         { "kfileitem#modified", I18N_NOOP2_NOSTRIP("@label", "Modified") },
00415         { "kfileitem#owner", I18N_NOOP2_NOSTRIP("@label", "Owner") },
00416         { "kfileitem#permissions", I18N_NOOP2_NOSTRIP("@label", "Permissions") },
00417         { "kfileitem#rating", I18N_NOOP2_NOSTRIP("@label", "Rating") },
00418         { "kfileitem#size", I18N_NOOP2_NOSTRIP("@label", "Size") },
00419         { "kfileitem#tags", I18N_NOOP2_NOSTRIP("@label", "Tags") },
00420         { "kfileitem#totalSize", I18N_NOOP2_NOSTRIP("@label", "Total Size") },
00421         { "kfileitem#type", I18N_NOOP2_NOSTRIP("@label", "Type") },
00422         { 0, 0, 0} // Mandatory last entry
00423     };
00424 
00425     static QHash<QString, QString> hash;
00426     if (hash.isEmpty()) {
00427         const TranslationItem* item = &translations[0];
00428         while (item->key != 0) {
00429             hash.insert(item->key, i18nc(item->context, item->value));
00430             ++item;
00431         }
00432     }
00433 
00434     QString value = hash.value(metaDataUri.url());
00435     if (value.isEmpty()) {
00436         value = KNfoTranslator::instance().translation(metaDataUri);
00437     }
00438 
00439     return value;
00440 }
00441 
00442 QString KFileMetaDataProvider::group(const KUrl& metaDataUri) const
00443 {
00444     QString group; // return value
00445 
00446     const QString uri = metaDataUri.url();
00447     if (uri == QLatin1String("kfileitem#type")) {
00448         group = QLatin1String("0FileItemA");
00449     } else if (uri == QLatin1String("kfileitem#size")) {
00450         group = QLatin1String("0FileItemB");
00451     } else if (uri == QLatin1String("http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#width")) {
00452         group = QLatin1String("0SizeA");
00453     } else if (uri == QLatin1String("http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#height")) {
00454         group = QLatin1String("0SizeB");
00455     }
00456 
00457     return group;
00458 }
00459 
00460 KFileItemList KFileMetaDataProvider::items() const
00461 {
00462     return d->m_fileItems;
00463 }
00464 
00465 void KFileMetaDataProvider::setReadOnly(bool readOnly)
00466 {
00467     d->m_readOnly = readOnly;
00468 }
00469 
00470 bool KFileMetaDataProvider::isReadOnly() const
00471 {
00472     return d->m_readOnly;
00473 }
00474 
00475 #ifndef KIO_NO_NEPOMUK
00476 QHash<KUrl, Nepomuk::Variant> KFileMetaDataProvider::data() const
00477 {
00478     return d->m_data;
00479 }
00480 
00481 QWidget* KFileMetaDataProvider::createValueWidget(const KUrl& metaDataUri,
00482                                                   const Nepomuk::Variant& value,
00483                                                   QWidget* parent) const
00484 {
00485     Q_ASSERT(parent != 0);
00486     QWidget* widget = 0;
00487 
00488     if (d->m_nepomukActivated) {
00489         const QString uri = metaDataUri.url();
00490         if (uri == QLatin1String("kfileitem#rating")) {
00491             widget = d->createRatingWidget(value.toInt(), parent);
00492         } else if (uri == QLatin1String("kfileitem#tags")) {
00493             const QList<Nepomuk::Variant> variants = value.toVariantList();
00494             QList<Nepomuk::Tag> tags;
00495             foreach (const Nepomuk::Variant& variant, variants) {
00496                 const Nepomuk::Resource resource = variant.toResource();
00497                 tags.append(static_cast<Nepomuk::Tag>(resource));
00498             }
00499 
00500             widget = d->createTagWidget(tags, parent);
00501         } else if (uri == QLatin1String("kfileitem#comment")) {
00502             widget = d->createCommentWidget(value.toString(), parent);
00503         }
00504     }
00505 
00506     if (widget == 0) {
00507         widget = d->createValueWidget(value.toString(), parent);
00508     }
00509 
00510     widget->setForegroundRole(parent->foregroundRole());
00511     widget->setFont(parent->font());
00512 
00513     return widget;
00514 }
00515 #endif
00516 
00517 #include "kfilemetadataprovider_p.moc"

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal