[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [kdelibs/frameworks] /: Merge remote-tracking branch 'origin/KDE/4.10' into frameworks
From:       David Faure <faure+bluesystems () kde ! org>
Date:       2012-12-01 9:36:44
Message-ID: 20121201093644.D9B77A6091 () git ! kde ! org
[Download RAW message or body]

Git commit 14890a3e8ee2284fe14a23186ffb57ac54eebccd by David Faure.
Committed on 01/12/2012 at 10:36.
Pushed by dfaure into branch 'frameworks'.

Merge remote-tracking branch 'origin/KDE/4.10' into frameworks

Conflicts:
	CMakeLists.txt [version]
	kdecore/services/kmimetype.cpp [gone, kio/global.cpp has the change]
	kio/kio/kdirlister.cpp [watchedWhileInCache]
	kio/kio/kprotocolmanager.cpp [KMimeType->QMimeType]
	kio/misc/kpac/kpactest.pac [,kded -> .kded5]
	kio/misc/kpac/kpactest2.pac [,kded -> .kded5]
	kio/tests/krununittest.cpp [kstddirs/qstandardpaths]

M  +12   -6    kio/kio/kdirlister.cpp
M  +4    -0    kio/kio/kdirlister_p.h
M  +19   -1    kio/kio/kprotocolmanager.cpp
M  +72   -3    kio/tests/kdirlistertest.cpp
M  +1    -0    kio/tests/kdirlistertest.h
M  +6    -1    kio/tests/krununittest.cpp
A  +1    -1    staging/kservice/src/sycoca/ksycoca.cpp     [License: LGPL (v2)]

http://commits.kde.org/kdelibs/14890a3e8ee2284fe14a23186ffb57ac54eebccd

diff --cc kio/kio/kdirlister.cpp
index a7153dc,d7de137..6c88a31
--- a/kio/kio/kdirlister.cpp
+++ b/kio/kio/kdirlister.cpp
@@@ -746,26 -744,31 +751,27 @@@ void KDirListerCache::updateDirectory( 
      }
  }
  
 -bool KDirListerCache::checkUpdate( const QString& _dir )
 +bool KDirListerCache::checkUpdate(const QUrl& _dir)
  {
 -  if ( !itemsInUse.contains(_dir) )
 -  {
 -    DirItem *item = itemsCached[_dir];
 -    if ( item && item->complete )
 -    {
 -      // Stop watching items once they are only in the cache and not used anymore.
 -      // We'll trigger an update when listing that dir again later.
 -      item->complete = false;
 -      item->watchedWhileInCache = false;
 -      item->decAutoUpdate();
 -      // Hmm, this debug output might include login/password from the _dir URL.
 -      //kDebug(7004) << "directory " << _dir << " not in use, marked dirty.";
 +    QString dir = _dir.toString();
 +    if (!itemsInUse.contains(dir)) {
 +        DirItem *item = itemsCached[dir];
 +        if (item && item->complete) {
 +            item->complete = false;
++            item->watchedWhileInCache = false;
 +            item->decAutoUpdate();
 +            // Hmm, this debug output might include login/password from the _dir \
URL.  +            //kDebug(7004) << "directory " << _dir << " not in use, marked \
dirty.";  +        }
 +        //else
 +        //kDebug(7004) << "aborted, directory " << _dir << " not in cache.";
 +        return false;
 +    } else {
 +        return true;
      }
 -    //else
 -      //kDebug(7004) << "aborted, directory " << _dir << " not in cache.";
 -
 -    return false;
 -  }
 -  else
 -    return true;
  }
  
 -KFileItem KDirListerCache::itemForUrl( const KUrl& url ) const
 +KFileItem KDirListerCache::itemForUrl( const QUrl& url ) const
  {
      KFileItem *item = findByUrl( 0, url );
      if (item) {
diff --cc kio/kio/kdirlister_p.h
index 48d8e39,a78cc3c..5b1e037
--- a/kio/kio/kdirlister_p.h
+++ b/kio/kio/kdirlister_p.h
@@@ -394,8 -393,11 +395,11 @@@ private
      // this directory is up-to-date
      bool complete;
  
+     // the directory is watched while being in the cache (useful for proper \
incAutoUpdate/decAutoUpdate count) +     bool watchedWhileInCache;
+ 
      // the complete url of this directory
 -    KUrl url;
 +    QUrl url;
  
      // the local path, with symlinks resolved, so that KDirWatch works
      QString m_canonicalPath;
diff --cc kio/kio/kprotocolmanager.cpp
index 657fab8,f8ed48a..79c3000
--- a/kio/kio/kprotocolmanager.cpp
+++ b/kio/kio/kprotocolmanager.cpp
@@@ -59,7 -54,6 +59,8 @@@
  #include <kio/slaveconfig.h>
  #include <kio/ioslave_defaults.h>
  #include <kio/http_slave_defaults.h>
 +#include <qstandardpaths.h>
++#include <qmimedatabase.h>
  
  #define QL1S(x)   QLatin1String(x)
  #define QL1C(x)   QLatin1Char(x)
@@@ -1215,10 -1190,26 +1216,27 @@@ QString KProtocolManager::protocolForAr
              }
          }
      }
-     return d->protocolForArchiveMimetypes.value(mimeType);
+     const QString prot = d->protocolForArchiveMimetypes.value(mimeType);
+     if (!prot.isEmpty())
+         return prot;
+ 
+     // Check parent mimetypes
 -    KMimeType::Ptr mime = KMimeType::mimeType(mimeType);
 -    if (mime) {
 -        const QStringList parentMimeTypes = mime->allParentMimeTypes();
++    QMimeDatabase db;
++    QMimeType mime = db.mimeTypeForName(mimeType);
++    if (mime.isValid()) {
++        const QStringList parentMimeTypes = mime.allAncestors();
+         Q_FOREACH(const QString& parentMimeType, parentMimeTypes) {
+             const QString res = \
d->protocolForArchiveMimetypes.value(parentMimeType); +             if \
(!res.isEmpty()) { +                 return res;
+             }
+         }
+     }
+ 
+     return QString();
  }
  
 -QString KProtocolManager::charsetFor(const KUrl& url)
 +QString KProtocolManager::charsetFor(const QUrl& url)
  {
      return KIO::SlaveConfig::self()->configData(url.scheme(), url.host(), \
QLatin1String("Charset"));  }
diff --cc kio/tests/kdirlistertest.cpp
index 25ca4da,b574816..77bb379
--- a/kio/tests/kdirlistertest.cpp
+++ b/kio/tests/kdirlistertest.cpp
@@@ -29,9 -29,8 +29,10 @@@ QTEST_MAIN(KDirListerTest
  #include "kiotesthelper.h"
  #include <kio/deletejob.h>
  #include <kdirwatch.h>
 +#include <kprotocolinfo.h>
  #include <kio/job.h>
  #include <kio/copyjob.h>
++#include <qurlpathinfo.h>
  
  #define WORKAROUND_BROKEN_INOTIFY 0
  
@@@ -872,6 -871,68 +873,68 @@@ void KDirListerTest::testOpenAndStop(
      disconnect(&m_dirLister, 0, this, 0);
  }
  
+ // A bug in the decAutoUpdate/incAutoUpdate logic made KDirLister stop watching a \
directory for changes, + // and never watch it again when opening it from the cache.
+ void KDirListerTest::testBug211472()
+ {
+     m_items.clear();
+ 
 -    KTempDir newDir;
 -    const QString path = newDir.name() + "newsubdir/";
++    QTemporaryDir newDir;
++    const QString path = newDir.path() + "/newsubdir/";
+     QDir().mkdir(path);
+     MyDirLister dirLister;
+     connect(&dirLister, SIGNAL(newItems(KFileItemList)), this, \
SLOT(slotNewItems(KFileItemList))); + 
 -    dirLister.openUrl(KUrl(path));
++    dirLister.openUrl(QUrl::fromLocalFile(path));
+     QVERIFY(QTest::kWaitForSignal(&dirLister, SIGNAL(completed()), 1000));
+     QVERIFY(dirLister.isFinished());
+     QVERIFY(m_items.isEmpty());
+ 
+     if (true) {
+         // This block is required to trigger bug 211472.
+ 
+         // Go 'up' to the parent of 'newsubdir'.
 -        dirLister.openUrl(KUrl(newDir.name()));
++        dirLister.openUrl(QUrl::fromLocalFile(newDir.path()));
+         QVERIFY(QTest::kWaitForSignal(&dirLister, SIGNAL(completed()), 1000));
+         QVERIFY(dirLister.isFinished());
+         QVERIFY(!m_items.isEmpty());
+         m_items.clear();
+ 
+         // Create a file in 'newsubdir' while we are listing its parent dir.
+         createTestFile(path + "newFile-1");
+         // At this point, newsubdir is not used, so it's moved to the cache.
+         // This happens in checkUpdate, called when receiving a notification for \
the cached dir, +         // this is why this unittest needs to create a test file in \
the subdir. +         QTest::qWait(1000);
+         QVERIFY(m_items.isEmpty());
+ 
+         // Return to 'newsubdir'. It will be emitted from the cache, then an update \
                will happen.
 -        dirLister.openUrl(KUrl(path));
++        dirLister.openUrl(QUrl::fromLocalFile(path));
+         QVERIFY(QTest::kWaitForSignal(&dirLister, SIGNAL(completed()), 1000));
+         QVERIFY(QTest::kWaitForSignal(&dirLister, SIGNAL(completed()), 1000));
+         QVERIFY(dirLister.isFinished());
+         QCOMPARE(m_items.count(), 1);
+         m_items.clear();
+     }
+ 
+     // Now try to create a second file in 'newsubdir' and verify that the
+     // dir lister notices it.
+     QTest::qWait(1000); // We need a 1s timestamp difference on the dir, otherwise \
FAM won't notice anything. + 
+     createTestFile(path + "newFile-2");
+ 
+     int numTries = 0;
+     // Give time for KDirWatch to notify us
+     while (m_items.isEmpty()) {
+         QVERIFY(++numTries < 10);
+         QTest::qWait(200);
+     }
+     QCOMPARE(m_items.count(), 1);
+ 
 -    newDir.unlink();
++    newDir.remove();
+     QVERIFY(QTest::kWaitForSignal(&dirLister, SIGNAL(clear()), 1000));
+ }
+ 
  void KDirListerTest::testRedirection()
  {
      m_items.clear();
@@@ -955,7 -1013,7 +1018,7 @@@ void KDirListerTest::slotRefreshItems2(
  void KDirListerTest::testDeleteCurrentDir()
  {
      // ensure m_dirLister holds the items.
--    m_dirLister.openUrl(KUrl(path()), KDirLister::NoFlags);
++    m_dirLister.openUrl(QUrl::fromLocalFile(path()), KDirLister::NoFlags);
      connect(&m_dirLister, SIGNAL(completed()), this, SLOT(exitLoop()));
      enterLoop();
      disconnect(&m_dirLister, SIGNAL(completed()), this, SLOT(exitLoop()));
@@@ -968,8 -1026,14 +1031,14 @@@
      enterLoop();
      QCOMPARE(m_dirLister.spyClear.count(), 1);
      QCOMPARE(m_dirLister.spyClearKUrl.count(), 0);
-     QCOMPARE(m_dirLister.spyItemsDeleted.count(), 1);
-     QCOMPARE(m_dirLister.spyItemsDeleted[0][0].value<KFileItemList>().count(), 1);
 -    KUrl::List deletedUrls;
++    QList<QUrl> deletedUrls;
+     for (int i = 0; i < m_dirLister.spyItemsDeleted.count(); ++i)
+         deletedUrls += \
m_dirLister.spyItemsDeleted[i][0].value<KFileItemList>().urlList(); +     //kDebug() \
                << deletedUrls;
 -    KUrl currentDirUrl = QUrl::fromLocalFile(path());
 -    currentDirUrl.adjustPath(KUrl::RemoveTrailingSlash);
++    QUrl currentDirUrl = QUrl::fromLocalFile(path());
++    QUrlPathInfo::adjustPath(currentDirUrl, QUrlPathInfo::StripTrailingSlash);
+     // Sometimes I get ("current/subdir", "current") here, but that seems ok.
+     QVERIFY(deletedUrls.contains(currentDirUrl));
  }
  
  int KDirListerTest::fileCount() const
diff --cc kio/tests/krununittest.cpp
index 314da79,b58033f..334a4be
--- a/kio/tests/krununittest.cpp
+++ b/kio/tests/krununittest.cpp
@@@ -129,14 -122,19 +129,19 @@@ void KRunUnitTest::testProcessDesktopEx
      process.setShellCommand("");
      const QString shellPath = process.program().at(0);
  
+     // Arch moved /bin/date to /usr/bin/date...
 -    const QString datePath = KStandardDirs::findExe("date");
++    const QString datePath = QStandardPaths::findExecutable("date");
+ 
      for (int su = 0; su < 2; su++)
          for (int te = 0; te < 2; te++)
              for (int ex = 0; ex < 2; ex++) {
                  int pt = ex+te*2+su*4;
                  QString exe;
                  if (pt == 4 || pt == 5)
 -                    exe = KStandardDirs::findExe("kdesu");
 +                    exe = QStandardPaths::findExecutable("kdesu");
-                 const QString result = \
QString::fromLatin1(rslts[pt]).replace("/bin/sh", shellPath); +                 const \
QString result = QString::fromLatin1(rslts[pt]) +                     \
.replace("/bin/sh", shellPath) +                     .replace("/bin/date", datePath);
                  checkPDE( execs[ex], terms[te], sus[su], l0, false, exe + result);
              }
  }
diff --cc staging/kservice/src/sycoca/ksycoca.cpp
index b75e2ce,0000000..3754cad
mode 100644,000000..100644
--- a/staging/kservice/src/sycoca/ksycoca.cpp
+++ b/staging/kservice/src/sycoca/ksycoca.cpp
@@@ -1,626 -1,0 +1,626 @@@
 +/*  This file is part of the KDE libraries
 + *  Copyright (C) 1999-2000 Waldo Bastian <bastian@kde.org>
 + *  Copyright (C) 2005-2009 David Faure <faure@kde.org>
 + *  Copyright (C) 2008 Hamish Rodda <rodda@kde.org>
 + *
 + *  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 "ksycoca.h"
 +#include "ksycoca_p.h"
 +#include "ksycocatype.h"
 +#include "ksycocafactory.h"
 +#include "kmemfile_p.h"
 +#include "kconfiggroup.h"
 +#include "ksharedconfig.h"
 +
 +#include <qstandardpaths.h>
 +#include <QtCore/QDataStream>
 +#include <QtCore/QCoreApplication>
 +#include <QtCore/QFile>
 +#include <QtCore/QBuffer>
 +#include <QProcess>
 +#include <QtDBus/QtDBus>
 +
 +#include <stdlib.h>
 +#include <fcntl.h>
 +
 +#include "ksycocadevices_p.h"
 +
 +// TODO: remove mmap() from kdewin32 and use QFile::mmap() when needed
 +#ifdef Q_OS_WIN
 +#undef HAVE_MMAP
 +#endif
 +/**
 + * Sycoca file version number.
 + * If the existing file is outdated, it will not get read
 + * but instead we'll ask kded to regenerate a new one...
 + */
- #define KSYCOCA_VERSION 210
++#define KSYCOCA_VERSION 212
 +
 +/**
 + * Sycoca file name, used internally (by kbuildsycoca)
 + */
 +#define KSYCOCA_FILENAME "ksycoca5"
 +
 +#if HAVE_MADVISE || HAVE_MMAP
 +#include <sys/mman.h> // This #include was checked when looking for posix_madvise
 +#endif
 +
 +#ifndef MAP_FAILED
 +#define MAP_FAILED ((void *) -1)
 +#endif
 +
 +static bool s_autoRebuild = true;
 +
 +// The following limitations are in place:
 +// Maximum length of a single string: 8192 bytes
 +// Maximum length of a string list: 1024 strings
 +// Maximum number of entries: 8192
 +//
 +// The purpose of these limitations is to limit the impact
 +// of database corruption.
 +
 +
 +Q_DECLARE_OPERATORS_FOR_FLAGS(KSycocaPrivate::BehaviorsIfNotFound)
 +
 +KSycocaPrivate::KSycocaPrivate()
 +    : databaseStatus( DatabaseNotOpen ),
 +      readError( false ),
 +      timeStamp( 0 ),
 +      m_databasePath(),
 +      updateSig( 0 ),
 +      sycoca_size(0),
 +      sycoca_mmap(0),
 +      m_mmapFile(0),
 +      m_device(0)
 +{
 +#ifdef Q_OS_WIN
 +    /*
 +      on windows we use KMemFile (QSharedMemory) to avoid problems
 +      with mmap (can't delete a mmap'd file)
 +    */
 +    m_sycocaStrategy = StrategyMemFile;
 +#else
 +    m_sycocaStrategy = StrategyMmap;
 +#endif
 +    KConfigGroup config(KSharedConfig::openConfig(), "KSycoca");
 +    setStrategyFromString(config.readEntry("strategy"));
 +}
 +
 +void KSycocaPrivate::setStrategyFromString(const QString& strategy) {
 +    if (strategy == QLatin1String("mmap"))
 +        m_sycocaStrategy = StrategyMmap;
 +    else if (strategy == QLatin1String("file"))
 +        m_sycocaStrategy = StrategyFile;
 +    else if (strategy == QLatin1String("sharedmem"))
 +        m_sycocaStrategy = StrategyMemFile;
 +    else if (!strategy.isEmpty())
 +        qWarning() << "Unknown sycoca strategy:" << strategy;
 +}
 +
 +bool KSycocaPrivate::tryMmap()
 +{
 +#if HAVE_MMAP
 +    Q_ASSERT(!m_databasePath.isEmpty());
 +    m_mmapFile = new QFile(m_databasePath);
 +    const bool canRead = m_mmapFile->open(QIODevice::ReadOnly);
 +    Q_ASSERT(canRead);
 +    if (!canRead)
 +        return false;
 +    fcntl(m_mmapFile->handle(), F_SETFD, FD_CLOEXEC);
 +    sycoca_size = m_mmapFile->size();
 +    sycoca_mmap = (const char *) mmap(0, sycoca_size,
 +                                      PROT_READ, MAP_SHARED,
 +                                      m_mmapFile->handle(), 0);
 +    /* POSIX mandates only MAP_FAILED, but we are paranoid so check for
 +       null pointer too.  */
 +    if (sycoca_mmap == (const char*) MAP_FAILED || sycoca_mmap == 0) {
 +        qDebug().nospace() << "mmap failed. (length = " << sycoca_size << ")";
 +        sycoca_mmap = 0;
 +        return false;
 +    } else {
 +#if HAVE_MADVISE
 +        (void) posix_madvise((void*)sycoca_mmap, sycoca_size, POSIX_MADV_WILLNEED);
 +#endif // HAVE_MADVISE
 +        return true;
 +    }
 +#endif // HAVE_MMAP
 +    return false;
 +}
 +
 +int KSycoca::version()
 +{
 +   return KSYCOCA_VERSION;
 +}
 +
 +class KSycocaSingleton
 +{
 +public:
 +    KSycocaSingleton() { }
 +    ~KSycocaSingleton() { }
 +
 +    bool hasSycoca() const {
 +        return m_threadSycocas.hasLocalData();
 +    }
 +    KSycoca* sycoca() {
 +        if (!m_threadSycocas.hasLocalData())
 +            m_threadSycocas.setLocalData(new KSycoca);
 +        return m_threadSycocas.localData();
 +    }
 +    void setSycoca(KSycoca* s) {
 +        m_threadSycocas.setLocalData(s);
 +    }
 +
 +private:
 +    QThreadStorage<KSycoca*> m_threadSycocas;
 +};
 +
 +Q_GLOBAL_STATIC(KSycocaSingleton, ksycocaInstance)
 +
 +// Read-only constructor
 +KSycoca::KSycoca()
 +  : d(new KSycocaPrivate)
 +{
 +    QDBusConnection::sessionBus().connect(QString(), QString(),
 +                                          QString::fromLatin1("org.kde.KSycoca"),
 +                                          \
QString::fromLatin1("notifyDatabaseChanged"),  +                                      \
this, SLOT(notifyDatabaseChanged(QStringList)));  +}
 +
 +bool KSycocaPrivate::openDatabase(bool openDummyIfNotFound)
 +{
 +    Q_ASSERT(databaseStatus == DatabaseNotOpen);
 +
 +    delete m_device; m_device = 0;
 +    QString path = KSycoca::absoluteFilePath();
 +
 +    bool canRead = QFileInfo(path).isReadable();
 +    qDebug() << "Trying to open ksycoca from" << path;
 +    if (!canRead) {
 +        path = KSycoca::absoluteFilePath(KSycoca::GlobalDatabase);
 +        if (!path.isEmpty()) {
 +            qDebug() << "Trying to open global ksycoca from " << path;
 +            canRead = QFileInfo(path).isReadable();
 +        }
 +    }
 +
 +    bool result = true;
 +    if (canRead) {
 +        m_databasePath = path;
 +        checkVersion();
 +    } else { // No database file
 +        //qDebug() << "Could not open ksycoca";
 +        m_databasePath.clear();
 +        databaseStatus = NoDatabase;
 +        if (openDummyIfNotFound) {
 +            // We open a dummy database instead.
 +            //qDebug() << "No database, opening a dummy one.";
 +
 +            m_sycocaStrategy = StrategyDummyBuffer;
 +            QDataStream* str = stream();
 +            *str << qint32(KSYCOCA_VERSION);
 +            *str << qint32(0);
 +        } else {
 +            result = false;
 +        }
 +    }
 +    return result;
 +}
 +
 +KSycocaAbstractDevice* KSycocaPrivate::device()
 +{
 +    if (m_device)
 +        return m_device;
 +
 +    Q_ASSERT(!m_databasePath.isEmpty());
 +
 +    KSycocaAbstractDevice* device = m_device;
 +    if (m_sycocaStrategy == StrategyDummyBuffer) {
 +        device = new KSycocaBufferDevice;
 +        device->device()->open(QIODevice::ReadOnly); // can't fail
 +    } else {
 +#if HAVE_MMAP
 +        if (m_sycocaStrategy == StrategyMmap && tryMmap()) {
 +            device = new KSycocaMmapDevice(sycoca_mmap,
 +                                           sycoca_size);
 +            if (!device->device()->open(QIODevice::ReadOnly)) {
 +                delete device; device = 0;
 +            }
 +        }
 +#endif
 +#ifndef QT_NO_SHAREDMEMORY
 +        if (!device && m_sycocaStrategy == StrategyMemFile) {
 +            device = new KSycocaMemFileDevice(m_databasePath);
 +            if (!device->device()->open(QIODevice::ReadOnly)) {
 +                delete device; device = 0;
 +            }
 +        }
 +#endif
 +        if (!device) {
 +            device = new KSycocaFileDevice(m_databasePath);
 +            if (!device->device()->open(QIODevice::ReadOnly)) {
 +                qWarning() << "Couldn't open" << m_databasePath << "even though it \
is readable? Impossible.";  +                //delete device; device = 0; // this \
would crash in the return statement...  +            }
 +        }
 +    }
 +    if (device) {
 +        m_device = device;
 +    }
 +    return m_device;
 +}
 +
 +QDataStream*& KSycocaPrivate::stream()
 +{
 +    if (!m_device) {
 +        if (databaseStatus == DatabaseNotOpen) {
 +            checkDatabase(KSycocaPrivate::IfNotFoundRecreate | \
KSycocaPrivate::IfNotFoundOpenDummy);  +        }
 +
 +        device(); // create m_device
 +    }
 +
 +    return m_device->stream();
 +}
 +
 +// Read-write constructor - only for KBuildSycoca
 +KSycoca::KSycoca( bool /* dummy */ )
 +  : d(new KSycocaPrivate)
 +{
 +    // This instance was not created by the singleton, but by a direct call to new!
 +    ksycocaInstance()->setSycoca(this);
 +}
 +
 +KSycoca * KSycoca::self()
 +{
 +    KSycoca* s = ksycocaInstance()->sycoca();
 +    Q_ASSERT(s);
 +    return s;
 +}
 +
 +KSycoca::~KSycoca()
 +{
 +    d->closeDatabase();
 +    delete d;
 +    //if (ksycocaInstance.exists()
 +    //    && ksycocaInstance->self == this)
 +    //    ksycocaInstance->self = 0;
 +}
 +
 +bool KSycoca::isAvailable()
 +{
 +    return self()->d->checkDatabase(KSycocaPrivate::IfNotFoundDoNothing/* don't \
open dummy db if not found */);  +}
 +
 +void KSycocaPrivate::closeDatabase()
 +{
 +    delete m_device;
 +    m_device = 0;
 +
 +    // It is very important to delete all factories here
 +    // since they cache information about the database file
 +    // But other threads might be using them, so this class is
 +    // refcounted, and deleted when the last thread is done with them
 +    qDeleteAll(m_factories);
 +    m_factories.clear();
 +#if HAVE_MMAP
 +    if (sycoca_mmap) {
 +        //QBuffer *buf = static_cast<QBuffer*>(device);
 +        //buf->buffer().clear();
 +        // Solaris has munmap(char*, size_t) and everything else should
 +        // be happy with a char* for munmap(void*, size_t)
 +        munmap(const_cast<char*>(sycoca_mmap), sycoca_size);
 +        sycoca_mmap = 0;
 +    }
 +    delete m_mmapFile; m_mmapFile = 0;
 +#endif
 +
 +    databaseStatus = DatabaseNotOpen;
 +    timeStamp = 0;
 +}
 +
 +void KSycoca::addFactory( KSycocaFactory *factory )
 +{
 +    d->addFactory(factory);
 +}
 +
 +#ifndef KDE_NO_DEPRECATED
 +bool KSycoca::isChanged(const char *type)
 +{
 +    return self()->d->changeList.contains(QString::fromLatin1(type));
 +}
 +#endif
 +
 +void KSycoca::notifyDatabaseChanged(const QStringList &changeList)
 +{
 +    d->changeList = changeList;
 +    //qDebug() << QThread::currentThread() << "got a notifyDatabaseChanged signal" \
<< changeList;  +    // kbuildsycoca tells us the database file changed
 +    // Close the database and forget all about what we knew
 +    // The next call to any public method will recreate
 +    // everything that's needed.
 +    d->closeDatabase();
 +
 +    // Now notify applications
 +#ifndef KDE_NO_DEPRECATED
 +    emit databaseChanged();
 +#endif
 +    emit databaseChanged(changeList);
 +}
 +
 +QDataStream * KSycoca::findEntry(int offset, KSycocaType &type)
 +{
 +   QDataStream* str = stream();
 +   Q_ASSERT(str);
 +   //qDebug() << QString("KSycoca::_findEntry(offset=%1)").arg(offset,8,16);
 +   str->device()->seek(offset);
 +   qint32 aType;
 +   *str >> aType;
 +   type = KSycocaType(aType);
 +   //qDebug() << QString("KSycoca::found type %1").arg(aType);
 +   return str;
 +}
 +
 +KSycocaFactoryList* KSycoca::factories()
 +{
 +    return d->factories();
 +}
 +
 +// Warning, checkVersion rewinds to the beginning of stream().
 +bool KSycocaPrivate::checkVersion()
 +{
 +    QDataStream *m_str = device()->stream();
 +    Q_ASSERT(m_str);
 +    m_str->device()->seek(0);
 +    qint32 aVersion;
 +    *m_str >> aVersion;
 +    if ( aVersion < KSYCOCA_VERSION ) {
 +        qDebug() << "Found version" << aVersion << ", expecting version" << \
KSYCOCA_VERSION << "or higher.";  +        databaseStatus = BadVersion;
 +        return false;
 +    } else {
 +        databaseStatus = DatabaseOK;
 +        return true;
 +    }
 +}
 +
 +// If it returns true, we have a valid database and the stream has rewinded to the \
beginning  +// and past the version number.
 +bool KSycocaPrivate::checkDatabase(BehaviorsIfNotFound ifNotFound)
 +{
 +    if (databaseStatus == DatabaseOK) {
 +        if (checkVersion()) // we know the version is ok, but we must rewind the \
stream anyway  +            return true;
 +    }
 +
 +    closeDatabase(); // close the dummy one
 +
 +    // We can only use the installed ksycoca file if kded is running,
 +    // since kded is what keeps the file uptodate.
 +    QDBusConnectionInterface* bus = QDBusConnection::sessionBus().interface();
 +    const bool kdedRunning = \
bus->isServiceRegistered(QString::fromLatin1("org.kde.kded5")) ||  +                  \
qAppName() == "kbuildsycoca5";  +
 +    // Check if new database already available
 +    if (kdedRunning && openDatabase(ifNotFound & IfNotFoundOpenDummy)) {
 +        if (checkVersion()) {
 +            // Database exists, and version is ok.
 +            return true;
 +        }
 +    }
 +
 +    if (ifNotFound & IfNotFoundRecreate) {
 +        // Ask kded to rebuild ksycoca
 +        // (so that it's not only built, but also kept up-to-date...)
 +        bool justStarted = false;
 +        if (!bus->isServiceRegistered(QLatin1String("org.kde.kded5"))) {
 +            // kded isn't even running: start it
 +            QDBusReply<void> reply = \
bus->startService(QLatin1String("org.kde.kded5"));  +            if \
(!reply.isValid()) {  +                qWarning() << "Couldn't start kded5 from \
org.kde.kded5.service:" << reply.error();  +            }
 +            //qDebug() << "kded5 registered";
 +            justStarted = true;
 +        } else {
 +            //qDebug() << "kded5 found";
 +        }
 +
 +        QDBusInterface sycoca(QLatin1String("org.kde.kded5"), \
QLatin1String("/kbuildsycoca"));  +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
 +        if (QStandardPaths::isTestModeEnabled()) {
 +            if (!justStarted) {
 +                const QDBusReply<bool> testMode = \
sycoca.call(QLatin1String("isTestModeEnabled"));  +                if \
(!testMode.value()) {  +                    qWarning() << "This unit test uses \
ksycoca, it needs to be run in a separate DBus session, so that kded can be started \
in 'test mode'.";  +                    qWarning() << "KSycoca updates will very \
likely fail unless you do that.";  +                    qWarning() << "`eval \
dbus-launch` ; make test";  +                    // Idea for the future: move \
kbuildsycoca stuff to its own kded module, and use  +                    // the same \
module with a different name, for test mode.  +                    // On the other \
hand, the use of other kded modules (cookies, timezone, etc.)  +                    \
// is also better separated from the user's kded anyway.  +                }
 +            }
 +            sycoca.call(QLatin1String("enableTestMode"));
 +            Q_ASSERT(QDBusReply<bool>(sycoca.call(QLatin1String("isTestModeEnabled"))).value());
  +        }
 +#else
 +        Q_UNUSED(justStarted);
 +#endif
 +
 +        //qDebug() << "We have no database.... asking kded to create it";
 +        sycoca.call(QLatin1String("recreate"));
 +
 +        closeDatabase(); // close the dummy one
 +
 +        // Ok, the new database should be here now, open it.
 +        if (!openDatabase(ifNotFound & IfNotFoundOpenDummy)) {
 +            qDebug() << "Still no database...";
 +            return false; // Still no database - uh oh
 +        }
 +        if (!checkVersion()) {
 +            qDebug() << "Still outdated...";
 +            return false; // Still outdated - uh oh
 +        }
 +        return true;
 +    }
 +
 +    return false;
 +}
 +
 +QDataStream * KSycoca::findFactory(KSycocaFactoryId id)
 +{
 +    // Ensure we have a valid database (right version, and rewinded to beginning)
 +    if (!d->checkDatabase(KSycocaPrivate::IfNotFoundRecreate)) {
 +        return 0;
 +    }
 +
 +    QDataStream* str = stream();
 +    Q_ASSERT(str);
 +
 +    qint32 aId;
 +    qint32 aOffset;
 +    while(true) {
 +        *str >> aId;
 +        if (aId == 0) {
 +            qWarning() << "Error, KSycocaFactory (id =" << int(id) << ") not \
found!";  +            break;
 +        }
 +        *str >> aOffset;
 +        if (aId == id) {
 +            //qDebug() << "KSycoca::findFactory(" << id << ") offset " << aOffset;
 +            str->device()->seek(aOffset);
 +            return str;
 +        }
 +    }
 +    return 0;
 +}
 +
 +QString KSycoca::kfsstnd_prefixes()
 +{
 +    // do not try to launch kbuildsycoca from here; this code is also called by \
kbuildsycoca.  +   if (!d->checkDatabase(KSycocaPrivate::IfNotFoundDoNothing))
 +       return QString();
 +   QDataStream* str = stream();
 +   Q_ASSERT(str);
 +   qint32 aId;
 +   qint32 aOffset;
 +   // skip factories offsets
 +   while(true)
 +   {
 +      *str >> aId;
 +      if ( aId )
 +        *str >> aOffset;
 +      else
 +        break; // just read 0
 +   }
 +   // We now point to the header
 +   QString prefixes;
 +   KSycocaEntry::read(*str, prefixes);
 +   *str >> d->timeStamp;
 +   KSycocaEntry::read(*str, d->language);
 +   *str >> d->updateSig;
 +   KSycocaEntry::read(*str, d->allResourceDirs);
 +   return prefixes;
 +}
 +
 +quint32 KSycoca::timeStamp()
 +{
 +   if (!d->timeStamp)
 +      (void) kfsstnd_prefixes();
 +   return d->timeStamp;
 +}
 +
 +quint32 KSycoca::updateSignature()
 +{
 +   if (!d->timeStamp)
 +      (void) kfsstnd_prefixes();
 +   return d->updateSig;
 +}
 +
 +QString KSycoca::absoluteFilePath(DatabaseType type)
 +{
 +    if (type == GlobalDatabase) {
 +        QString path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, \
QString::fromLatin1("kde5/services/" KSYCOCA_FILENAME));  +        if \
(path.isEmpty())  +            return \
QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + \
QString::fromLatin1("/kde5/services/" KSYCOCA_FILENAME);  +        return path;
 +    }
 +
 +    const QByteArray ksycoca_env = qgetenv("KDESYCOCA");
 +    if (ksycoca_env.isEmpty()) {
 +        return QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) \
+ QLatin1Char('/') + QString::fromLatin1(KSYCOCA_FILENAME);  +    } else {
 +        return QFile::decodeName(ksycoca_env);
 +    }
 +}
 +
 +QString KSycoca::language()
 +{
 +   if (d->language.isEmpty())
 +      (void) kfsstnd_prefixes();
 +   return d->language;
 +}
 +
 +QStringList KSycoca::allResourceDirs()
 +{
 +   if (!d->timeStamp)
 +      (void) kfsstnd_prefixes();
 +   return d->allResourceDirs;
 +}
 +
 +void KSycoca::flagError()
 +{
 +    qWarning() << "ERROR: KSycoca database corruption!";
 +    KSycocaPrivate* d = ksycocaInstance()->sycoca()->d;
 +    if (d->readError)
 +        return;
 +    d->readError = true;
 +    if (s_autoRebuild) {
 +        // Rebuild the damned thing.
 +        if (QProcess::execute(QStandardPaths::findExecutable(QString::fromLatin1(KBUILDSYCOCA_EXENAME))) \
!= 0)  +            qWarning("ERROR: Running %s failed", KBUILDSYCOCA_EXENAME);
 +        // Old comment, maybe not true anymore:
 +        // Do not wait until the DBUS signal from kbuildsycoca here.
 +        // It deletes m_str which is a problem when flagError is called during the \
KSycocaFactory ctor...  +    }
 +}
 +
 +bool KSycoca::isBuilding()
 +{
 +    return false;
 +}
 +
 +void KSycoca::disableAutoRebuild()
 +{
 +   s_autoRebuild = false;
 +}
 +
 +QDataStream*& KSycoca::stream()
 +{
 +    return d->stream();
 +}
 +
 +void KSycoca::clearCaches()
 +{
 +#if QT_VERSION >= QT_VERSION_CHECK(5,1,0)
 +    if (ksycocaInstance.exists() && ksycocaInstance()->hasSycoca())
 +#else
 +    if (ksycocaInstance() && ksycocaInstance()->hasSycoca())
 +#endif
 +        ksycocaInstance()->sycoca()->d->closeDatabase();
 +}
 +
 +#include "ksycoca.moc"


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic