• Skip to content
  • Skip to link menu
KDE 4.7 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 <kfilemetadatareader_p.h>
00024 #include "knfotranslator_p.h"
00025 #include <klocale.h>
00026 #include <kstandarddirs.h>
00027 #include <kurl.h>
00028 
00029 #ifndef KIO_NO_NEPOMUK
00030     #define DISABLE_NEPOMUK_LEGACY
00031     #include "nepomukmassupdatejob.h"
00032     #include "tagwidget.h"
00033     #include "tag.h"
00034     #include "kratingwidget.h"
00035     #include "resource.h"
00036     #include "resourcemanager.h"
00037 
00038     #include "kcommentwidget_p.h"
00039 #else
00040     namespace Nepomuk
00041     {
00042         typedef int Tag;
00043     }
00044 #endif
00045 
00046 #include <QEvent>
00047 #include <QLabel>
00048 
00049 // Required includes for subDirectoriesCount():
00050 #ifdef Q_WS_WIN
00051     #include <QDir>
00052 #else
00053     #include <dirent.h>
00054     #include <QFile>
00055 #endif
00056 
00057 namespace {
00058     static QString plainText(const QString& richText)
00059     {
00060         QString plainText;
00061         plainText.reserve(richText.length());
00062 
00063         bool skip = false;
00064         for (int i = 0; i < richText.length(); ++i) {
00065             const QChar c = richText.at(i);
00066             if (c == QLatin1Char('<')) {
00067                 skip = true;
00068             } else if (c == QLatin1Char('>')) {
00069                 skip = false;
00070             } else if (!skip) {
00071                 plainText.append(c);
00072             }
00073         }
00074 
00075         return plainText;
00076     }
00077 }
00078 
00079 // The default size hint of QLabel tries to return a square size.
00080 // This does not work well in combination with layouts that use
00081 // heightForWidth(): In this case it is possible that the content
00082 // of a label might get clipped. By specifying a size hint
00083 // with a maximum width that is necessary to contain the whole text,
00084 // using heightForWidth() assures having a non-clipped text.
00085 class ValueWidget : public QLabel
00086 {
00087 public:
00088     explicit ValueWidget(QWidget* parent = 0);
00089     virtual QSize sizeHint() const;
00090 };
00091 
00092 ValueWidget::ValueWidget(QWidget* parent) :
00093     QLabel(parent)
00094 {
00095 }
00096 
00097 QSize ValueWidget::sizeHint() const
00098 {
00099     QFontMetrics metrics(font());
00100     // TODO: QLabel internally provides already a method sizeForWidth(),
00101     // that would be sufficient. However this method is not accessible, so
00102     // as workaround the tags from a richtext are removed manually here to
00103     // have a proper size hint.
00104     return metrics.size(Qt::TextSingleLine, plainText(text()));
00105 }
00106 
00107 
00108 
00109 class KFileMetaDataProvider::Private
00110 {
00111 
00112 public:
00113     Private(KFileMetaDataProvider* parent);
00114     ~Private();
00115 
00116     void slotLoadingFinished();
00117 
00118     void slotRatingChanged(unsigned int rating);
00119     void slotTagsChanged(const QList<Nepomuk::Tag>& tags);
00120     void slotCommentChanged(const QString& comment);
00121 
00122     void slotMetaDataUpdateDone();
00123     void slotTagClicked(const Nepomuk::Tag& tag);
00124     void slotLinkActivated(const QString& link);
00125 
00131     void startChangeDataJob(KJob* job);
00132 
00133 #ifndef KIO_NO_NEPOMUK
00134     QList<Nepomuk::Resource> resourceList() const;   
00135     QWidget* createRatingWidget(int rating, QWidget* parent);
00136     QWidget* createTagWidget(const QList<Nepomuk::Tag>& tags, QWidget* parent);
00137     QWidget* createCommentWidget(const QString& comment, QWidget* parent);
00138 #endif
00139     QWidget* createValueWidget(const QString& value, QWidget* parent);
00140 
00141     /*
00142      * @return The number of subdirectories for the directory \a path.
00143      */
00144     static int subDirectoriesCount(const QString &path);
00145 
00146     bool m_readOnly;
00147     bool m_nepomukActivated;
00148     QList<KFileItem> m_fileItems;
00149 
00150 #ifndef KIO_NO_NEPOMUK
00151     QHash<KUrl, Nepomuk::Variant> m_data;
00152 
00153     QList<KFileMetaDataReader*> m_metaDataReaders;
00154     KFileMetaDataReader* m_latestMetaDataReader;
00155 
00156     QWeakPointer<KRatingWidget> m_ratingWidget;
00157     QWeakPointer<Nepomuk::TagWidget> m_tagWidget;
00158     QWeakPointer<KCommentWidget> m_commentWidget;
00159 #endif
00160 
00161 private:
00162     KFileMetaDataProvider* const q;
00163 };
00164 
00165 KFileMetaDataProvider::Private::Private(KFileMetaDataProvider* parent) :
00166     m_readOnly(false),
00167     m_nepomukActivated(false),
00168     m_fileItems(),
00169 #ifndef KIO_NO_NEPOMUK
00170     m_data(),
00171     m_metaDataReaders(),
00172     m_latestMetaDataReader(0),
00173     m_ratingWidget(),
00174     m_tagWidget(),
00175     m_commentWidget(),
00176 #endif
00177     q(parent)
00178 {
00179 #ifndef KIO_NO_NEPOMUK
00180     m_nepomukActivated = (Nepomuk::ResourceManager::instance()->init() == 0);
00181 #endif
00182 }
00183 
00184 KFileMetaDataProvider::Private::~Private()
00185 {
00186 #ifndef KIO_NO_NEPOMUK
00187     qDeleteAll(m_metaDataReaders);
00188 #endif
00189 }
00190 
00191 void KFileMetaDataProvider::Private::slotLoadingFinished()
00192 {
00193 #ifndef KIO_NO_NEPOMUK
00194     KFileMetaDataReader* finishedMetaDataReader = qobject_cast<KFileMetaDataReader*>(q->sender());
00195     // The process that has emitted the finished() signal
00196     // will get deleted and removed from m_metaDataReaders.
00197     for (int i = 0; i < m_metaDataReaders.count(); ++i) {
00198         KFileMetaDataReader* metaDataReader = m_metaDataReaders[i];
00199         if (metaDataReader == finishedMetaDataReader) {
00200             m_metaDataReaders.removeAt(i);
00201             if (metaDataReader != m_latestMetaDataReader) {
00202                 // Ignore data of older processs, as the data got
00203                 // obsolete by m_latestMetaDataReader.
00204                 metaDataReader->deleteLater();
00205                 return;
00206             }
00207         }
00208     }
00209 
00210     m_data = m_latestMetaDataReader->metaData();
00211     m_latestMetaDataReader->deleteLater();
00212 
00213     if (m_fileItems.count() == 1) {
00214         // TODO: Handle case if remote URLs are used properly. isDir() does
00215         // not work, the modification date needs also to be adjusted...
00216         const KFileItem& item = m_fileItems.first();
00217 
00218         if (item.isDir()) {
00219             const int count = subDirectoriesCount(item.url().pathOrUrl());
00220             if (count == -1) {
00221                 m_data.insert(KUrl("kfileitem#size"), QString("Unknown"));
00222             } else {
00223                 const QString itemCountString = i18ncp("@item:intable", "%1 item", "%1 items", count);
00224                 m_data.insert(KUrl("kfileitem#size"), itemCountString);
00225             }
00226         } else {
00227             m_data.insert(KUrl("kfileitem#size"), KIO::convertSize(item.size()));
00228         }
00229         m_data.insert(KUrl("kfileitem#type"), item.mimeComment());
00230         m_data.insert(KUrl("kfileitem#modified"), KGlobal::locale()->formatDateTime(item.time(KFileItem::ModificationTime), KLocale::FancyLongDate));
00231         m_data.insert(KUrl("kfileitem#owner"), item.user());
00232         m_data.insert(KUrl("kfileitem#permissions"), item.permissionsString());
00233     } else if (m_fileItems.count() > 1) {
00234         // Calculate the size of all items
00235         quint64 totalSize = 0;
00236         foreach (const KFileItem& item, m_fileItems) {
00237             if (!item.isDir() && !item.isLink()) {
00238                 totalSize += item.size();
00239             }
00240         }
00241         m_data.insert(KUrl("kfileitem#totalSize"), KIO::convertSize(totalSize));
00242     }
00243 #endif
00244 
00245     emit q->loadingFinished();
00246 }
00247 
00248 void KFileMetaDataProvider::Private::slotRatingChanged(unsigned int rating)
00249 {
00250 #ifndef KIO_NO_NEPOMUK
00251     Nepomuk::MassUpdateJob* job = Nepomuk::MassUpdateJob::rateResources(resourceList(), rating);
00252     startChangeDataJob(job);
00253 #else
00254     Q_UNUSED(rating);
00255 #endif
00256 }
00257 
00258 void KFileMetaDataProvider::Private::slotTagsChanged(const QList<Nepomuk::Tag>& tags)
00259 {
00260 #ifndef KIO_NO_NEPOMUK
00261     if (!m_tagWidget.isNull()) {
00262         m_tagWidget.data()->setSelectedTags(tags);
00263 
00264         Nepomuk::MassUpdateJob* job = Nepomuk::MassUpdateJob::tagResources(resourceList(), tags);
00265         startChangeDataJob(job);
00266     }
00267 #else
00268     Q_UNUSED(tags);
00269 #endif
00270 }
00271 
00272 void KFileMetaDataProvider::Private::slotCommentChanged(const QString& comment)
00273 {
00274 #ifndef KIO_NO_NEPOMUK
00275     Nepomuk::MassUpdateJob* job = Nepomuk::MassUpdateJob::commentResources(resourceList(), comment);
00276     startChangeDataJob(job);
00277 #else
00278     Q_UNUSED(comment);
00279 #endif
00280 }
00281 
00282 void KFileMetaDataProvider::Private::slotTagClicked(const Nepomuk::Tag& tag)
00283 {
00284 #ifndef KIO_NO_NEPOMUK
00285     emit q->urlActivated(tag.resourceUri());
00286 #else
00287     Q_UNUSED(tag);
00288 #endif
00289 }
00290 
00291 void KFileMetaDataProvider::Private::slotLinkActivated(const QString& link)
00292 {
00293     emit q->urlActivated(KUrl(link));
00294 }
00295 
00296 void KFileMetaDataProvider::Private::startChangeDataJob(KJob* job)
00297 {
00298     connect(job, SIGNAL(result(KJob*)),
00299             q, SIGNAL(dataChangeFinished()));
00300     emit q->dataChangeStarted();
00301     job->start();
00302 }
00303 
00304 #ifndef KIO_NO_NEPOMUK
00305 QList<Nepomuk::Resource> KFileMetaDataProvider::Private::resourceList() const
00306 {
00307     QList<Nepomuk::Resource> list;
00308     foreach (const KFileItem& item, m_fileItems) {
00309         const KUrl url = item.nepomukUri();
00310         if(url.isValid())
00311             list.append(Nepomuk::Resource(url));
00312     }
00313     return list;
00314 }
00315 
00316 QWidget* KFileMetaDataProvider::Private::createRatingWidget(int rating, QWidget* parent)
00317 {
00318     KRatingWidget* ratingWidget = new KRatingWidget(parent);
00319     const Qt::Alignment align = (ratingWidget->layoutDirection() == Qt::LeftToRight) ?
00320                                 Qt::AlignLeft : Qt::AlignRight;
00321     ratingWidget->setAlignment(align);
00322     ratingWidget->setRating(rating);
00323     const QFontMetrics metrics(parent->font());
00324     ratingWidget->setPixmapSize(metrics.height());
00325 
00326     connect(ratingWidget, SIGNAL(ratingChanged(unsigned int)),
00327             q, SLOT(slotRatingChanged(unsigned int)));
00328 
00329     m_ratingWidget = ratingWidget;
00330 
00331     return ratingWidget;
00332 }
00333 
00334 QWidget* KFileMetaDataProvider::Private::createTagWidget(const QList<Nepomuk::Tag>& tags, QWidget* parent)
00335 {
00336     Nepomuk::TagWidget* tagWidget = new Nepomuk::TagWidget(parent);
00337     tagWidget->setModeFlags(m_readOnly
00338                             ? Nepomuk::TagWidget::MiniMode | Nepomuk::TagWidget::ReadOnly
00339                             : Nepomuk::TagWidget::MiniMode);
00340     tagWidget->setSelectedTags(tags);
00341 
00342     connect(tagWidget, SIGNAL(selectionChanged(QList<Nepomuk::Tag>)),
00343             q, SLOT(slotTagsChanged(QList<Nepomuk::Tag>)));
00344     connect(tagWidget, SIGNAL(tagClicked(Nepomuk::Tag)),
00345             q, SLOT(slotTagClicked(Nepomuk::Tag)));
00346 
00347     m_tagWidget = tagWidget;
00348 
00349     return tagWidget;
00350 }
00351 
00352 QWidget* KFileMetaDataProvider::Private::createCommentWidget(const QString& comment, QWidget* parent)
00353 {
00354     KCommentWidget* commentWidget = new KCommentWidget(parent);
00355     commentWidget->setText(comment);
00356     commentWidget->setReadOnly(m_readOnly);
00357 
00358     connect(commentWidget, SIGNAL(commentChanged(const QString&)),
00359             q, SLOT(slotCommentChanged(const QString&)));
00360 
00361     m_commentWidget = commentWidget;
00362 
00363     return commentWidget;
00364 }
00365 #endif
00366 
00367 QWidget* KFileMetaDataProvider::Private::createValueWidget(const QString& value, QWidget* parent)
00368 {
00369     ValueWidget* valueWidget = new ValueWidget(parent);
00370     valueWidget->setWordWrap(true);
00371     valueWidget->setAlignment(Qt::AlignTop | Qt::AlignLeft);
00372     valueWidget->setText(m_readOnly ? plainText(value) : value);
00373     connect(valueWidget, SIGNAL(linkActivated(QString)), q, SLOT(slotLinkActivated(QString)));
00374     return valueWidget;
00375 }
00376 
00377 KFileMetaDataProvider::KFileMetaDataProvider(QObject* parent) :
00378     QObject(parent),
00379     d(new Private(this))
00380 {
00381 }
00382 
00383 KFileMetaDataProvider::~KFileMetaDataProvider()
00384 {
00385     delete d;
00386 }
00387 
00388 void KFileMetaDataProvider::setItems(const KFileItemList& items)
00389 {
00390     d->m_fileItems = items;
00391 
00392 #ifndef KIO_NO_NEPOMUK
00393     if (items.isEmpty()) {
00394         return;
00395     }
00396     Q_PRIVATE_SLOT(d, void slotDataChangeStarted())
00397     Q_PRIVATE_SLOT(d, void slotDataChangeFinished())
00398     QList<KUrl> urls;
00399     foreach (const KFileItem& item, items) {
00400         const KUrl url = item.nepomukUri();
00401         if (url.isValid()) {
00402             urls.append(url);
00403         }
00404     }
00405 
00406     d->m_latestMetaDataReader = new KFileMetaDataReader(urls);
00407     connect(d->m_latestMetaDataReader, SIGNAL(finished()), this, SLOT(slotLoadingFinished()));
00408     d->m_metaDataReaders.append(d->m_latestMetaDataReader);
00409     d->m_latestMetaDataReader->start();
00410 #endif
00411 }
00412 
00413 QString KFileMetaDataProvider::label(const KUrl& metaDataUri) const
00414 {
00415     struct TranslationItem {
00416         const char* const key;
00417         const char* const context;
00418         const char* const value;
00419     };
00420 
00421     static const TranslationItem translations[] = {
00422         { "kfileitem#comment", I18N_NOOP2_NOSTRIP("@label", "Comment") },
00423         { "kfileitem#modified", I18N_NOOP2_NOSTRIP("@label", "Modified") },
00424         { "kfileitem#owner", I18N_NOOP2_NOSTRIP("@label", "Owner") },
00425         { "kfileitem#permissions", I18N_NOOP2_NOSTRIP("@label", "Permissions") },
00426         { "kfileitem#rating", I18N_NOOP2_NOSTRIP("@label", "Rating") },
00427         { "kfileitem#size", I18N_NOOP2_NOSTRIP("@label", "Size") },
00428         { "kfileitem#tags", I18N_NOOP2_NOSTRIP("@label", "Tags") },
00429         { "kfileitem#totalSize", I18N_NOOP2_NOSTRIP("@label", "Total Size") },
00430         { "kfileitem#type", I18N_NOOP2_NOSTRIP("@label", "Type") },
00431         { 0, 0, 0} // Mandatory last entry
00432     };
00433 
00434     static QHash<QString, QString> hash;
00435     if (hash.isEmpty()) {
00436         const TranslationItem* item = &translations[0];
00437         while (item->key != 0) {
00438             hash.insert(item->key, i18nc(item->context, item->value));
00439             ++item;
00440         }
00441     }
00442 
00443     QString value = hash.value(metaDataUri.url());
00444     if (value.isEmpty()) {
00445         value = KNfoTranslator::instance().translation(metaDataUri);
00446     }
00447 
00448     return value;
00449 }
00450 
00451 QString KFileMetaDataProvider::group(const KUrl& metaDataUri) const
00452 {
00453     QString group; // return value
00454 
00455     const QString uri = metaDataUri.url();
00456     if (uri == QLatin1String("kfileitem#type")) {
00457         group = QLatin1String("0FileItemA");
00458     } else if (uri == QLatin1String("kfileitem#size")) {
00459         group = QLatin1String("0FileItemB");
00460     } else if (uri == QLatin1String("http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#width")) {
00461         group = QLatin1String("0SizeA");
00462     } else if (uri == QLatin1String("http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#height")) {
00463         group = QLatin1String("0SizeB");
00464     }
00465 
00466     return group;
00467 }
00468 
00469 KFileItemList KFileMetaDataProvider::items() const
00470 {
00471     return d->m_fileItems;
00472 }
00473 
00474 void KFileMetaDataProvider::setReadOnly(bool readOnly)
00475 {
00476     d->m_readOnly = readOnly;
00477 }
00478 
00479 bool KFileMetaDataProvider::isReadOnly() const
00480 {
00481     return d->m_readOnly;
00482 }
00483 
00484 #ifndef KIO_NO_NEPOMUK
00485 QHash<KUrl, Nepomuk::Variant> KFileMetaDataProvider::data() const
00486 {
00487     return d->m_data;
00488 }
00489 
00490 QWidget* KFileMetaDataProvider::createValueWidget(const KUrl& metaDataUri,
00491                                                   const Nepomuk::Variant& value,
00492                                                   QWidget* parent) const
00493 {
00494     Q_ASSERT(parent != 0);
00495     QWidget* widget = 0;
00496 
00497     if (d->m_nepomukActivated) {
00498         const QString uri = metaDataUri.url();
00499         if (uri == QLatin1String("kfileitem#rating")) {
00500             widget = d->createRatingWidget(value.toInt(), parent);
00501         } else if (uri == QLatin1String("kfileitem#tags")) {
00502             const QStringList tagNames = value.toStringList();
00503             QList<Nepomuk::Tag> tags;
00504             foreach (const QString& tagName, tagNames) {
00505                 tags.append(Nepomuk::Tag(tagName));
00506             }
00507 
00508             widget = d->createTagWidget(tags, parent);
00509         } else if (uri == QLatin1String("kfileitem#comment")) {
00510             widget = d->createCommentWidget(value.toString(), parent);
00511         }
00512     }
00513 
00514     if (widget == 0) {
00515         widget = d->createValueWidget(value.toString(), parent);
00516     }
00517 
00518     widget->setForegroundRole(parent->foregroundRole());
00519     widget->setFont(parent->font());
00520 
00521     return widget;
00522 }
00523 #endif
00524 
00525 int KFileMetaDataProvider::Private::subDirectoriesCount(const QString& path)
00526 {
00527 #ifdef Q_WS_WIN
00528     QDir dir(path);
00529     return dir.entryList(QDir::AllEntries|QDir::NoDotAndDotDot|QDir::System).count();
00530 #else
00531     // Taken from kdelibs/kio/kio/kdirmodel.cpp
00532     // Copyright (C) 2006 David Faure <faure@kde.org>
00533 
00534     int count = -1;
00535     DIR* dir = ::opendir(QFile::encodeName(path));
00536     if (dir) {
00537         count = 0;
00538         struct dirent *dirEntry = 0;
00539         while ((dirEntry = ::readdir(dir))) { // krazy:exclude=syscalls
00540             if (dirEntry->d_name[0] == '.') {
00541                 if (dirEntry->d_name[1] == '\0') {
00542                     // Skip "."
00543                     continue;
00544                 }
00545                 if (dirEntry->d_name[1] == '.' && dirEntry->d_name[2] == '\0') {
00546                     // Skip ".."
00547                     continue;
00548                 }
00549             }
00550             ++count;
00551         }
00552         ::closedir(dir);
00553     }
00554     return count;
00555 #endif
00556 }
00557 
00558 #include "kfilemetadataprovider_p.moc"

KIO

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • 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.5
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