summaryrefslogtreecommitdiff
path: root/kdecore/kernel
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2012-06-25 18:42:22 (GMT)
committerChristian Mollekopf <chrigi_1@fastmail.fm>2012-06-25 18:42:22 (GMT)
commit43d35cfb36c924eede624f4a5c2fcb0dd7d698b6 (patch)
treeb7ac13bcf009d94cabb4c5afeee0825a4ce9da67 /kdecore/kernel
parentbf385f44f99d73263b1787daac7423599e69f024 (diff)
downloadlibcalendaring-43d35cfb36c924eede624f4a5c2fcb0dd7d698b6.tar.gz
kdecore import
commit 557c1267cbb5e352e1487c3dd468cd4a4cb63254 Merge: aed99b0 387e3c3 Author: David Faure <faure@kde.org> Date: Thu Jun 14 17:56:59 2012 +0200 Merge remote-tracking branch 'origin/KDE/4.8'
Diffstat (limited to 'kdecore/kernel')
-rw-r--r--kdecore/kernel/kaboutdata.cpp950
-rw-r--r--kdecore/kernel/kaboutdata.h980
-rw-r--r--kdecore/kernel/kauthorized.cpp380
-rw-r--r--kdecore/kernel/kauthorized.h95
-rw-r--r--kdecore/kernel/kcmdlineargs.cpp1618
-rw-r--r--kdecore/kernel/kcmdlineargs.h692
-rw-r--r--kdecore/kernel/kcomponentdata.cpp239
-rw-r--r--kdecore/kernel/kcomponentdata.h192
-rw-r--r--kdecore/kernel/kcomponentdata_p.h99
-rw-r--r--kdecore/kernel/kglobal.cpp356
-rw-r--r--kdecore/kernel/kglobal.h580
-rw-r--r--kdecore/kernel/kglobal_p.h61
-rw-r--r--kdecore/kernel/kkernel_mac.cpp213
-rw-r--r--kdecore/kernel/kkernel_mac.h61
-rw-r--r--kdecore/kernel/kkernel_win.cpp539
-rw-r--r--kdecore/kernel/kkernel_win.h67
-rw-r--r--kdecore/kernel/kstandarddirs.cpp2159
-rw-r--r--kdecore/kernel/kstandarddirs.h810
-rw-r--r--kdecore/kernel/kstandarddirs_unix.cpp106
-rw-r--r--kdecore/kernel/kstandarddirs_win.cpp113
-rw-r--r--kdecore/kernel/ktoolinvocation.cpp396
-rw-r--r--kdecore/kernel/ktoolinvocation.h398
-rw-r--r--kdecore/kernel/ktoolinvocation_win.cpp85
-rw-r--r--kdecore/kernel/ktoolinvocation_x11.cpp422
24 files changed, 11611 insertions, 0 deletions
diff --git a/kdecore/kernel/kaboutdata.cpp b/kdecore/kernel/kaboutdata.cpp
new file mode 100644
index 0000000..e49bddb
--- /dev/null
+++ b/kdecore/kernel/kaboutdata.cpp
@@ -0,0 +1,950 @@
+/*
+ * This file is part of the KDE Libraries
+ * Copyright (C) 2000 Espen Sand (espen@kde.org)
+ * Copyright (C) 2006 Nicolas GOUTTE <goutte@kde.org>
+ * Copyright (C) 2008 Friedrich W. H. Kossebau <kossebau@kde.org>
+ * Copyright (C) 2010 Teo Mrnjavac <teo@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 as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * 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 "kaboutdata.h"
+
+#include "kstandarddirs.h"
+#include "klocalizedstring.h"
+
+#include <QtCore/QFile>
+#include <QtCore/QTextIStream>
+#include <QtCore/QSharedData>
+#include <QtCore/QVariant>
+#include <QtCore/QList>
+#include <QHash>
+
+// -----------------------------------------------------------------------------
+// Design notes:
+//
+// These classes deal with a lot of text, some of which needs to be
+// marked for translation. Since at the time when these object and calls are
+// made the translation catalogs are usually still not initialized, the
+// translation has to be delayed. This is achieved by using KLocalizedString
+// for translatable strings. KLocalizedStrings are produced by ki18n* calls,
+// instead of the more usuall i18n* calls which produce QString by trying to
+// translate immediately.
+//
+// All the non-translatable string arguments to methods are taken QByteArray,
+// all the translatable are KLocalizedString. The getter methods always return
+// proper QString: the non-translatable strings supplied by the code are
+// treated with QString::fromUtf8(), those coming from the outside with
+// QTextCodec::toUnicode(), and translatable strings are finalized to QStrings
+// at the point of getter calls (i.e. delayed translation).
+// -----------------------------------------------------------------------------
+
+class KAboutPerson::Private
+{
+public:
+ KLocalizedString _name;
+ KLocalizedString _task;
+ QString _emailAddress;
+ QString _webAddress;
+ QString _ocsUsername;
+
+ QString _nameNoop;
+};
+
+KAboutPerson::KAboutPerson( const KLocalizedString &_name,
+ const KLocalizedString &_task,
+ const QByteArray &_emailAddress,
+ const QByteArray &_webAddress )
+ : d(new Private)
+{
+ d->_name = _name;
+ d->_task = _task;
+ d->_emailAddress = QString::fromUtf8(_emailAddress);
+ d->_webAddress = QString::fromUtf8(_webAddress);
+}
+
+KAboutPerson::KAboutPerson( const KLocalizedString &_name,
+ const KLocalizedString &_task,
+ const QByteArray &_emailAddress,
+ const QByteArray &_webAddress,
+ const QByteArray &_ocsUsername )
+ : d(new Private)
+{
+ d->_name = _name;
+ d->_task = _task;
+ d->_emailAddress = QString::fromUtf8(_emailAddress);
+ d->_webAddress = QString::fromUtf8(_webAddress);
+ d->_ocsUsername = QString::fromUtf8( _ocsUsername );
+}
+
+KAboutPerson::KAboutPerson( const QString &_name, const QString &_email )
+ : d(new Private)
+{
+ d->_nameNoop = _name;
+ d->_emailAddress = _email;
+}
+
+KAboutPerson::KAboutPerson(const KAboutPerson& other): d(new Private)
+{
+ *d = *other.d;
+}
+
+KAboutPerson::~KAboutPerson()
+{
+ delete d;
+}
+
+QString KAboutPerson::name() const
+{
+ if (!d->_nameNoop.isEmpty())
+ return d->_nameNoop;
+ return d->_name.toString();
+}
+
+QString KAboutPerson::task() const
+{
+ if (!d->_task.isEmpty())
+ return d->_task.toString();
+ return QString();
+}
+
+QString KAboutPerson::emailAddress() const
+{
+ return d->_emailAddress;
+}
+
+
+QString KAboutPerson::webAddress() const
+{
+ return d->_webAddress;
+}
+
+QString KAboutPerson::ocsUsername() const
+{
+ return d->_ocsUsername;
+}
+
+KAboutPerson &KAboutPerson::operator=(const KAboutPerson& other)
+{
+ *d = *other.d;
+ return *this;
+}
+
+
+
+class KAboutLicense::Private : public QSharedData
+{
+public:
+ Private( enum KAboutData::LicenseKey licenseType, const KAboutData *aboutData );
+ Private( const QString &pathToFile, const KAboutData *aboutData );
+ Private( const KLocalizedString &licenseText, const KAboutData *aboutData );
+ Private( const Private& other);
+public:
+ enum KAboutData::LicenseKey _licenseKey;
+ KLocalizedString _licenseText;
+ QString _pathToLicenseTextFile;
+ // needed for access to the possibly changing copyrightStatement()
+ const KAboutData * _aboutData;
+};
+
+KAboutLicense::Private::Private( enum KAboutData::LicenseKey licenseType, const KAboutData *aboutData )
+ : QSharedData(),
+ _licenseKey( licenseType ),
+ _aboutData( aboutData )
+{
+}
+
+KAboutLicense::Private::Private( const QString &pathToFile, const KAboutData *aboutData )
+ : QSharedData(),
+ _licenseKey( KAboutData::License_File ),
+ _pathToLicenseTextFile( pathToFile ),
+ _aboutData( aboutData )
+{
+}
+
+KAboutLicense::Private::Private( const KLocalizedString &licenseText, const KAboutData *aboutData )
+ : QSharedData(),
+ _licenseKey( KAboutData::License_Custom ),
+ _licenseText( licenseText ),
+ _aboutData( aboutData )
+{
+}
+
+KAboutLicense::Private::Private(const KAboutLicense::Private& other)
+ : QSharedData(other),
+ _licenseKey( other._licenseKey ),
+ _licenseText( other._licenseText ),
+ _pathToLicenseTextFile( other._pathToLicenseTextFile ),
+ _aboutData( other._aboutData )
+{}
+
+
+KAboutLicense::KAboutLicense( enum KAboutData::LicenseKey licenseType, const KAboutData *aboutData )
+ : d(new Private(licenseType,aboutData))
+{
+}
+
+KAboutLicense::KAboutLicense( const QString &pathToFile, const KAboutData *aboutData )
+ : d(new Private(pathToFile,aboutData))
+{
+}
+
+KAboutLicense::KAboutLicense( const KLocalizedString &licenseText, const KAboutData *aboutData )
+ : d(new Private(licenseText,aboutData))
+{
+}
+
+KAboutLicense::KAboutLicense(const KAboutLicense& other)
+ : d(other.d)
+{
+}
+
+KAboutLicense::~KAboutLicense()
+{}
+
+QString KAboutLicense::text() const
+{
+ QString result;
+
+ const QString lineFeed = QString::fromLatin1( "\n\n" );
+
+ if (d->_aboutData && !d->_aboutData->copyrightStatement().isEmpty()) {
+ result = d->_aboutData->copyrightStatement() + lineFeed;
+ }
+
+ bool knownLicense = false;
+ QString pathToFile;
+ switch ( d->_licenseKey )
+ {
+ case KAboutData::License_File:
+ pathToFile = d->_pathToLicenseTextFile;
+ break;
+ case KAboutData::License_GPL_V2:
+ knownLicense = true;
+ pathToFile = KStandardDirs::locate("data", QString::fromLatin1("LICENSES/GPL_V2"));
+ break;
+ case KAboutData::License_LGPL_V2:
+ knownLicense = true;
+ pathToFile = KStandardDirs::locate("data", QString::fromLatin1("LICENSES/LGPL_V2"));
+ break;
+ case KAboutData::License_BSD:
+ knownLicense = true;
+ pathToFile = KStandardDirs::locate("data", QString::fromLatin1("LICENSES/BSD"));
+ break;
+ case KAboutData::License_Artistic:
+ knownLicense = true;
+ pathToFile = KStandardDirs::locate("data", QString::fromLatin1("LICENSES/ARTISTIC"));
+ break;
+ case KAboutData::License_QPL_V1_0:
+ knownLicense = true;
+ pathToFile = KStandardDirs::locate("data", QString::fromLatin1("LICENSES/QPL_V1.0"));
+ break;
+ case KAboutData::License_GPL_V3:
+ knownLicense = true;
+ pathToFile = KStandardDirs::locate("data", QString::fromLatin1("LICENSES/GPL_V3"));
+ break;
+ case KAboutData::License_LGPL_V3:
+ knownLicense = true;
+ pathToFile = KStandardDirs::locate("data", QString::fromLatin1("LICENSES/LGPL_V3"));
+ break;
+ case KAboutData::License_Custom:
+ if (!d->_licenseText.isEmpty()) {
+ result = d->_licenseText.toString();
+ break;
+ }
+ // fall through
+ default:
+ result += i18n("No licensing terms for this program have been specified.\n"
+ "Please check the documentation or the source for any\n"
+ "licensing terms.\n");
+ }
+
+ if (knownLicense) {
+ result += i18n("This program is distributed under the terms of the %1.", name(KAboutData::ShortName));
+ if (!pathToFile.isEmpty()) {
+ result += lineFeed;
+ }
+ }
+
+ if (!pathToFile.isEmpty()) {
+ QFile file(pathToFile);
+ if (file.open(QIODevice::ReadOnly)) {
+ QTextStream str(&file);
+ result += str.readAll();
+ }
+ }
+
+ return result;
+}
+
+
+QString KAboutLicense::name(KAboutData::NameFormat formatName) const
+{
+ QString licenseShort;
+ QString licenseFull;
+
+ switch (d->_licenseKey) {
+ case KAboutData::License_GPL_V2:
+ licenseShort = i18nc("@item license (short name)","GPL v2");
+ licenseFull = i18nc("@item license","GNU General Public License Version 2");
+ break;
+ case KAboutData::License_LGPL_V2:
+ licenseShort = i18nc("@item license (short name)","LGPL v2");
+ licenseFull = i18nc("@item license","GNU Lesser General Public License Version 2");
+ break;
+ case KAboutData::License_BSD:
+ licenseShort = i18nc("@item license (short name)","BSD License");
+ licenseFull = i18nc("@item license","BSD License");
+ break;
+ case KAboutData::License_Artistic:
+ licenseShort = i18nc("@item license (short name)","Artistic License");
+ licenseFull = i18nc("@item license","Artistic License");
+ break;
+ case KAboutData::License_QPL_V1_0:
+ licenseShort = i18nc("@item license (short name)","QPL v1.0");
+ licenseFull = i18nc("@item license","Q Public License");
+ break;
+ case KAboutData::License_GPL_V3:
+ licenseShort = i18nc("@item license (short name)","GPL v3");
+ licenseFull = i18nc("@item license","GNU General Public License Version 3");
+ break;
+ case KAboutData::License_LGPL_V3:
+ licenseShort = i18nc("@item license (short name)","LGPL v3");
+ licenseFull = i18nc("@item license","GNU Lesser General Public License Version 3");
+ break;
+ case KAboutData::License_Custom:
+ case KAboutData::License_File:
+ licenseShort = licenseFull = i18nc("@item license","Custom");
+ break;
+ default:
+ licenseShort = licenseFull = i18nc("@item license","Not specified");
+ }
+
+ const QString result =
+ (formatName == KAboutData::ShortName ) ? licenseShort :
+ (formatName == KAboutData::FullName ) ? licenseFull :
+ QString();
+
+ return result;
+}
+
+
+KAboutLicense &KAboutLicense::operator=(const KAboutLicense& other)
+{
+ d = other.d;
+ return *this;
+}
+
+KAboutData::LicenseKey KAboutLicense::key() const
+{
+ return d->_licenseKey;
+}
+
+KAboutLicense KAboutLicense::byKeyword(const QString &rawKeyword)
+{
+ // Setup keyword->enum dictionary on first call.
+ // Use normalized keywords, by the algorithm below.
+ static QHash<QByteArray, KAboutData::LicenseKey> ldict;
+ if (ldict.isEmpty()) {
+ ldict.insert("gpl", KAboutData::License_GPL);
+ ldict.insert("gplv2", KAboutData::License_GPL_V2);
+ ldict.insert("gplv2+", KAboutData::License_GPL_V2);
+ ldict.insert("lgpl", KAboutData::License_LGPL);
+ ldict.insert("lgplv2", KAboutData::License_LGPL_V2);
+ ldict.insert("lgplv2+", KAboutData::License_LGPL_V2);
+ ldict.insert("bsd", KAboutData::License_BSD);
+ ldict.insert("artistic", KAboutData::License_Artistic);
+ ldict.insert("qpl", KAboutData::License_QPL);
+ ldict.insert("qplv1", KAboutData::License_QPL_V1_0);
+ ldict.insert("qplv10", KAboutData::License_QPL_V1_0);
+ ldict.insert("gplv3", KAboutData::License_GPL_V3);
+ ldict.insert("gplv3+", KAboutData::License_GPL_V3);
+ ldict.insert("lgplv3", KAboutData::License_LGPL_V3);
+ ldict.insert("lgplv3+", KAboutData::License_LGPL_V3);
+ }
+
+ // Normalize keyword.
+ QString keyword = rawKeyword;
+ keyword = keyword.toLower();
+ keyword.remove(QLatin1Char(' '));
+ keyword.remove(QLatin1Char('.'));
+
+ KAboutData::LicenseKey license = ldict.value(keyword.toLatin1(),
+ KAboutData::License_Custom);
+ return KAboutLicense(license, 0);
+}
+
+
+class KAboutData::Private
+{
+public:
+ Private()
+ : customAuthorTextEnabled(false)
+ {}
+ QByteArray _appName;
+ KLocalizedString _programName;
+ KLocalizedString _shortDescription;
+ QByteArray _catalogName;
+ KLocalizedString _copyrightStatement;
+ KLocalizedString _otherText;
+ QString _homepageAddress;
+ QList<KAboutPerson> _authorList;
+ QList<KAboutPerson> _creditList;
+ QList<KAboutLicense> _licenseList;
+ KLocalizedString translatorName;
+ KLocalizedString translatorEmail;
+ QString productName;
+ QString programIconName;
+ QVariant programLogo;
+ KLocalizedString customAuthorPlainText, customAuthorRichText;
+ bool customAuthorTextEnabled;
+
+ QString organizationDomain;
+ QByteArray _ocsProviderUrl;
+
+ // Everything dr.konqi needs, we store as utf-8, so we
+ // can just give it a pointer, w/o any allocations.
+ QByteArray _translatedProgramName; // ### I don't see it ever being translated, and I did not change that
+ QByteArray _version;
+ QByteArray _bugEmailAddress;
+};
+
+
+KAboutData::KAboutData( const QByteArray &_appName,
+ const QByteArray &_catalogName,
+ const KLocalizedString &_programName,
+ const QByteArray &_version,
+ const KLocalizedString &_shortDescription,
+ enum LicenseKey licenseType,
+ const KLocalizedString &_copyrightStatement,
+ const KLocalizedString &text,
+ const QByteArray &homePageAddress,
+ const QByteArray &bugsEmailAddress
+ )
+ : d(new Private)
+{
+ d->_appName = _appName;
+ int p = d->_appName.indexOf('/');
+ if (p >= 0) {
+ d->_appName = d->_appName.mid(p + 1);
+ }
+
+ d->_catalogName = _catalogName;
+ d->_programName = _programName;
+ if (!d->_programName.isEmpty()) // KComponentData("klauncher") gives empty program name
+ d->_translatedProgramName = _programName.toString(0).toUtf8();
+ d->_version = _version;
+ d->_shortDescription = _shortDescription;
+ d->_licenseList.append(KAboutLicense(licenseType,this));
+ d->_copyrightStatement = _copyrightStatement;
+ d->_otherText = text;
+ d->_homepageAddress = QString::fromLatin1(homePageAddress);
+ d->_bugEmailAddress = bugsEmailAddress;
+
+ if (d->_homepageAddress.contains(QLatin1String("http://"))) {
+ const int dot = d->_homepageAddress.indexOf(QLatin1Char('.'));
+ if (dot >= 0) {
+ d->organizationDomain = d->_homepageAddress.mid(dot + 1);
+ const int slash = d->organizationDomain.indexOf(QLatin1Char('/'));
+ if (slash >= 0)
+ d->organizationDomain.truncate(slash);
+ }
+ else {
+ d->organizationDomain = QString::fromLatin1("kde.org");
+ }
+ }
+ else {
+ d->organizationDomain = QString::fromLatin1("kde.org");
+ }
+}
+
+KAboutData::~KAboutData()
+{
+ delete d;
+}
+
+KAboutData::KAboutData(const KAboutData& other): d(new Private)
+{
+ *d = *other.d;
+ QList<KAboutLicense>::iterator it = d->_licenseList.begin(), itEnd = d->_licenseList.end();
+ for ( ; it != itEnd; ++it) {
+ KAboutLicense& al = *it;
+ al.d.detach();
+ al.d->_aboutData = this;
+ }
+}
+
+KAboutData &KAboutData::operator=(const KAboutData& other)
+{
+ if (this != &other) {
+ *d = *other.d;
+ QList<KAboutLicense>::iterator it = d->_licenseList.begin(), itEnd = d->_licenseList.end();
+ for ( ; it != itEnd; ++it) {
+ KAboutLicense& al = *it;
+ al.d.detach();
+ al.d->_aboutData = this;
+ }
+ }
+ return *this;
+}
+
+KAboutData &KAboutData::addAuthor( const KLocalizedString &name,
+ const KLocalizedString &task,
+ const QByteArray &emailAddress,
+ const QByteArray &webAddress )
+{
+ d->_authorList.append(KAboutPerson(name,task,emailAddress,webAddress));
+ return *this;
+}
+
+KAboutData &KAboutData::addAuthor( const KLocalizedString &name,
+ const KLocalizedString &task,
+ const QByteArray &emailAddress,
+ const QByteArray &webAddress,
+ const QByteArray &ocsUsername )
+{
+ d->_authorList.append(KAboutPerson(name,task,emailAddress,webAddress,ocsUsername));
+ return *this;
+}
+
+KAboutData &KAboutData::addCredit( const KLocalizedString &name,
+ const KLocalizedString &task,
+ const QByteArray &emailAddress,
+ const QByteArray &webAddress )
+{
+ d->_creditList.append(KAboutPerson(name,task,emailAddress,webAddress));
+ return *this;
+}
+
+KAboutData &KAboutData::addCredit( const KLocalizedString &name,
+ const KLocalizedString &task,
+ const QByteArray &emailAddress,
+ const QByteArray &webAddress,
+ const QByteArray &ocsUsername )
+{
+ d->_creditList.append(KAboutPerson(name,task,emailAddress,webAddress,ocsUsername));
+ return *this;
+}
+
+KAboutData &KAboutData::setTranslator( const KLocalizedString& name,
+ const KLocalizedString& emailAddress )
+{
+ d->translatorName = name;
+ d->translatorEmail = emailAddress;
+ return *this;
+}
+
+KAboutData &KAboutData::setLicenseText( const KLocalizedString &licenseText )
+{
+ d->_licenseList[0] = KAboutLicense(licenseText,this);
+ return *this;
+}
+
+KAboutData &KAboutData::addLicenseText( const KLocalizedString &licenseText )
+{
+ // if the default license is unknown, overwrite instead of append
+ KAboutLicense &firstLicense = d->_licenseList[0];
+ if (d->_licenseList.count() == 1 && firstLicense.d->_licenseKey == License_Unknown) {
+ firstLicense = KAboutLicense(licenseText,this);
+ } else {
+ d->_licenseList.append(KAboutLicense(licenseText,this));
+ }
+ return *this;
+}
+
+KAboutData &KAboutData::setLicenseTextFile( const QString &pathToFile )
+{
+ d->_licenseList[0] = KAboutLicense(pathToFile,this);
+ return *this;
+}
+
+KAboutData &KAboutData::addLicenseTextFile( const QString &pathToFile )
+{
+ // if the default license is unknown, overwrite instead of append
+ KAboutLicense &firstLicense = d->_licenseList[0];
+ if (d->_licenseList.count() == 1 && firstLicense.d->_licenseKey == License_Unknown) {
+ firstLicense = KAboutLicense(pathToFile,this);
+ } else {
+ d->_licenseList.append(KAboutLicense(pathToFile,this));
+ }
+ return *this;
+}
+
+KAboutData &KAboutData::setAppName( const QByteArray &_appName )
+{
+ d->_appName = _appName;
+ return *this;
+}
+
+KAboutData &KAboutData::setProgramName( const KLocalizedString &_programName )
+{
+ d->_programName = _programName;
+ translateInternalProgramName();
+ return *this;
+}
+
+KAboutData &KAboutData::setOcsProvider(const QByteArray &_ocsProviderUrl )
+{
+ d->_ocsProviderUrl = _ocsProviderUrl;
+ return *this;
+}
+
+KAboutData &KAboutData::setVersion( const QByteArray &_version )
+{
+ d->_version = _version;
+ return *this;
+}
+
+KAboutData &KAboutData::setShortDescription( const KLocalizedString &_shortDescription )
+{
+ d->_shortDescription = _shortDescription;
+ return *this;
+}
+
+KAboutData &KAboutData::setCatalogName( const QByteArray &_catalogName )
+{
+ d->_catalogName = _catalogName;
+ return *this;
+}
+
+KAboutData &KAboutData::setLicense( LicenseKey licenseKey)
+{
+ d->_licenseList[0] = KAboutLicense(licenseKey,this);
+ return *this;
+}
+
+KAboutData &KAboutData::addLicense( LicenseKey licenseKey)
+{
+ // if the default license is unknown, overwrite instead of append
+ KAboutLicense &firstLicense = d->_licenseList[0];
+ if (d->_licenseList.count() == 1 && firstLicense.d->_licenseKey == License_Unknown) {
+ firstLicense = KAboutLicense(licenseKey,this);
+ } else {
+ d->_licenseList.append(KAboutLicense(licenseKey,this));
+ }
+ return *this;
+}
+
+KAboutData &KAboutData::setCopyrightStatement( const KLocalizedString &_copyrightStatement )
+{
+ d->_copyrightStatement = _copyrightStatement;
+ return *this;
+}
+
+KAboutData &KAboutData::setOtherText( const KLocalizedString &_otherText )
+{
+ d->_otherText = _otherText;
+ return *this;
+}
+
+KAboutData &KAboutData::setHomepage( const QByteArray &_homepage )
+{
+ d->_homepageAddress = QString::fromLatin1(_homepage);
+ return *this;
+}
+
+KAboutData &KAboutData::setBugAddress( const QByteArray &_bugAddress )
+{
+ d->_bugEmailAddress = _bugAddress;
+ return *this;
+}
+
+KAboutData &KAboutData::setOrganizationDomain( const QByteArray &domain )
+{
+ d->organizationDomain = QString::fromLatin1(domain);
+ return *this;
+}
+
+KAboutData &KAboutData::setProductName( const QByteArray &_productName )
+{
+ d->productName = QString::fromUtf8(_productName);
+ return *this;
+}
+
+QString KAboutData::appName() const
+{
+ return QString::fromUtf8(d->_appName);
+}
+
+QString KAboutData::productName() const
+{
+ if (!d->productName.isEmpty())
+ return d->productName;
+ return appName();
+}
+
+QString KAboutData::programName() const
+{
+ if (!d->_programName.isEmpty())
+ return d->_programName.toString();
+ return QString();
+}
+
+/// @internal
+/// Return the program name. It is always pre-allocated.
+/// Needed for KCrash in particular.
+const char* KAboutData::internalProgramName() const
+{
+ return d->_translatedProgramName.constData();
+}
+
+/// @internal
+/// KCrash should call as few things as possible and should avoid e.g. malloc()
+/// because it may deadlock. Since i18n() needs it, when KLocale is available
+/// the i18n() call will be done here in advance.
+void KAboutData::translateInternalProgramName() const
+{
+ d->_translatedProgramName.clear();
+ if( KGlobal::locale())
+ d->_translatedProgramName = programName().toUtf8();
+}
+
+QString KAboutData::programIconName() const
+{
+ return d->programIconName.isEmpty() ? appName() : d->programIconName;
+}
+
+KAboutData &KAboutData::setProgramIconName( const QString &iconName )
+{
+ d->programIconName = iconName;
+ return *this;
+}
+
+QVariant KAboutData::programLogo() const
+{
+ return d->programLogo;
+}
+
+KAboutData &KAboutData::setProgramLogo(const QVariant& image)
+{
+ d->programLogo = image ;
+ return *this;
+}
+
+QString KAboutData::ocsProviderUrl() const
+{
+ if( !d->_ocsProviderUrl.isEmpty() )
+ return QString::fromUtf8( d->_ocsProviderUrl );
+ return QString();
+}
+
+QString KAboutData::version() const
+{
+ return QString::fromUtf8(d->_version);
+}
+
+/// @internal
+/// Return the untranslated and uninterpreted (to UTF8) string
+/// for the version information. Used in particular for KCrash.
+const char* KAboutData::internalVersion() const
+{
+ return d->_version.constData();
+}
+
+QString KAboutData::shortDescription() const
+{
+ if (!d->_shortDescription.isEmpty())
+ return d->_shortDescription.toString();
+ return QString();
+}
+
+QString KAboutData::catalogName() const
+{
+ if (!d->_catalogName.isEmpty())
+ return QString::fromUtf8(d->_catalogName);
+ // Fallback to appname for catalog name if empty.
+ return QString::fromUtf8(d->_appName);
+}
+
+QString KAboutData::homepage() const
+{
+ return d->_homepageAddress;
+}
+
+QString KAboutData::bugAddress() const
+{
+ return QString::fromUtf8(d->_bugEmailAddress);
+}
+
+QString KAboutData::organizationDomain() const
+{
+ return d->organizationDomain;
+}
+
+
+/// @internal
+/// Return the untranslated and uninterpreted (to UTF8) string
+/// for the bug mail address. Used in particular for KCrash.
+const char* KAboutData::internalBugAddress() const
+{
+ if (d->_bugEmailAddress.isEmpty())
+ return 0;
+ return d->_bugEmailAddress.constData();
+}
+
+QList<KAboutPerson> KAboutData::authors() const
+{
+ return d->_authorList;
+}
+
+QList<KAboutPerson> KAboutData::credits() const
+{
+ return d->_creditList;
+}
+
+#define NAME_OF_TRANSLATORS "Your names"
+#define EMAIL_OF_TRANSLATORS "Your emails"
+QList<KAboutPerson> KAboutData::translators() const
+{
+ QList<KAboutPerson> personList;
+
+ KLocale *tmpLocale = NULL;
+ if (KGlobal::locale()) {
+ // There could be many catalogs loaded into the global locale,
+ // e.g. in systemsettings. The tmp locale is needed to make sure we
+ // use the translators name from this aboutdata's catalog, rather than
+ // from any other loaded catalog.
+ tmpLocale = new KLocale(*KGlobal::locale());
+ tmpLocale->setActiveCatalog(catalogName());
+ }
+
+ QString translatorName;
+ if (!d->translatorName.isEmpty()) {
+ translatorName = d->translatorName.toString();
+ }
+ else {
+ translatorName = ki18nc("NAME OF TRANSLATORS", NAME_OF_TRANSLATORS).toString(tmpLocale);
+ }
+
+ QString translatorEmail;
+ if (!d->translatorEmail.isEmpty()) {
+ translatorEmail = d->translatorEmail.toString();
+ }
+ else {
+ translatorEmail = ki18nc("EMAIL OF TRANSLATORS", EMAIL_OF_TRANSLATORS).toString(tmpLocale);
+ }
+
+ delete tmpLocale;
+
+ if ( translatorName.isEmpty() || translatorName == QString::fromUtf8( NAME_OF_TRANSLATORS ) )
+ return personList;
+
+ const QStringList nameList(translatorName.split(QString(QLatin1Char(','))));
+
+ QStringList emailList;
+ if( !translatorEmail.isEmpty() && translatorEmail != QString::fromUtf8( EMAIL_OF_TRANSLATORS ) )
+ {
+ emailList = translatorEmail.split(QString(QLatin1Char(',')), QString::KeepEmptyParts);
+ }
+
+ QStringList::const_iterator nit;
+ QStringList::const_iterator eit = emailList.constBegin();
+
+ for( nit = nameList.constBegin(); nit != nameList.constEnd(); ++nit )
+ {
+ QString email;
+ if ( eit != emailList.constEnd() )
+ {
+ email = *eit;
+ ++eit;
+ }
+
+ personList.append( KAboutPerson( (*nit).trimmed(), email.trimmed() ) );
+ }
+
+ return personList;
+}
+
+QString KAboutData::aboutTranslationTeam()
+{
+ return i18nc("replace this with information about your translation team",
+ "<p>KDE is translated into many languages thanks to the work "
+ "of the translation teams all over the world.</p>"
+ "<p>For more information on KDE internationalization "
+ "visit <a href=\"http://l10n.kde.org\">http://l10n.kde.org</a></p>"
+ );
+}
+
+QString KAboutData::otherText() const
+{
+ if (!d->_otherText.isEmpty())
+ return d->_otherText.toString();
+ return QString();
+}
+
+QString KAboutData::license() const
+{
+ return d->_licenseList.at(0).text();
+}
+
+QString KAboutData::licenseName( NameFormat formatName ) const
+{
+ return d->_licenseList.at(0).name(formatName);
+}
+
+QList<KAboutLicense> KAboutData::licenses() const
+{
+ return d->_licenseList;
+}
+
+QString KAboutData::copyrightStatement() const
+{
+ if (!d->_copyrightStatement.isEmpty())
+ return d->_copyrightStatement.toString();
+ return QString();
+}
+
+QString KAboutData::customAuthorPlainText() const
+{
+ if (!d->customAuthorPlainText.isEmpty())
+ return d->customAuthorPlainText.toString();
+ return QString();
+}
+
+QString KAboutData::customAuthorRichText() const
+{
+ if (!d->customAuthorRichText.isEmpty())
+ return d->customAuthorRichText.toString();
+ return QString();
+}
+
+bool KAboutData::customAuthorTextEnabled() const
+{
+ return d->customAuthorTextEnabled;
+}
+
+KAboutData &KAboutData::setCustomAuthorText( const KLocalizedString &plainText,
+ const KLocalizedString &richText )
+{
+ d->customAuthorPlainText = plainText;
+ d->customAuthorRichText = richText;
+
+ d->customAuthorTextEnabled = true;
+
+ return *this;
+}
+
+KAboutData &KAboutData::unsetCustomAuthorText()
+{
+ d->customAuthorPlainText = KLocalizedString();
+ d->customAuthorRichText = KLocalizedString();
+
+ d->customAuthorTextEnabled = false;
+
+ return *this;
+}
+
diff --git a/kdecore/kernel/kaboutdata.h b/kdecore/kernel/kaboutdata.h
new file mode 100644
index 0000000..16861f4
--- /dev/null
+++ b/kdecore/kernel/kaboutdata.h
@@ -0,0 +1,980 @@
+/*
+ * This file is part of the KDE Libraries
+ * Copyright (C) 2000 Espen Sand (espen@kde.org)
+ * Copyright (C) 2008 Friedrich W. H. Kossebau <kossebau@kde.org>
+ * Copyright (C) 2010 Teo Mrnjavac <teo@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 as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ */
+
+#ifndef KABOUTDATA_H
+#define KABOUTDATA_H
+
+#include <kdecore_export.h>
+#include <klocale.h>
+// Qt
+#include <QtCore/QString>
+#include <QtCore/QSharedDataPointer>
+
+template <class T> class QList;
+class QVariant;
+class KAboutData;
+
+/**
+ * This class is used to store information about a person or developer.
+ * It can store the person's name, a task, an email address and a
+ * link to a home page. This class is intended for use in the
+ * KAboutData class, but it can be used elsewhere as well.
+ * Normally you should at least define the person's name.
+ * Creating a KAboutPerson object by yourself is relatively useless,
+ * but the KAboutData methods KAboutData::authors() and KAboutData::credits()
+ * return lists of KAboutPerson data objects which you can examine.
+ *
+ * Example usage within a main(), retrieving the list of people involved
+ * with a program and re-using data from one of them:
+ *
+ * @code
+ * KAboutData about("khello", "khello", ki18n("KHello"), "0.1",
+ * ki18n("A KDE version of Hello, world!"),
+ * KAboutData::License_LGPL,
+ * ki18n("Copyright (C) 2003 Developer"));
+ *
+ * about.addAuthor(ki18n("Joe Developer"), ki18n("developer"), "joe@host.com", 0);
+ * QList<KAboutPerson> people = about.authors();
+ * about.addCredit(people[0].name(), people[0].task());
+ * @endcode
+ *
+ * @note Instead of the more usual i18n calls, for translatable text the ki18n
+ * calls are used to produce KLocalizedStrings, which can delay the translation
+ * lookup. This is necessary because the translation catalogs are usually not
+ * yet initialized at the point where KAboutData is constructed.
+ *
+ * @bc KDE4
+ */
+class KDECORE_EXPORT KAboutPerson
+{
+ friend class KAboutData;
+public:
+ /**
+ * Convenience constructor
+ *
+ * @param name The name of the person.
+ *
+ * @param task The task of this person.
+ *
+ * @param emailAddress The email address of the person.
+ *
+ * @param webAddress Home page of the person.
+ */
+ explicit KAboutPerson( const KLocalizedString &name,
+ const KLocalizedString &task = KLocalizedString(),
+ const QByteArray &emailAddress = QByteArray(),
+ const QByteArray &webAddress = QByteArray() );
+
+ /**
+ * Convenience constructor with Open Collaboration Services data
+ *
+ * @param name The name of the person.
+ *
+ * @param task The task of this person.
+ *
+ * @param emailAddress The email address of the person.
+ *
+ * @param webAddress Home page of the person.
+ *
+ * @param ocsUsername Open Collaboration Services username of the person.
+ */
+ explicit KAboutPerson( const KLocalizedString &name,
+ const KLocalizedString &task,
+ const QByteArray &emailAddress,
+ const QByteArray &webAddress,
+ const QByteArray &ocsUsername ); //KDE5: merge into main ctor
+
+ /**
+ * Copy constructor. Performs a deep copy.
+ * @param other object to copy
+ */
+ KAboutPerson(const KAboutPerson& other);
+
+ ~KAboutPerson();
+
+ /**
+ * Assignment operator. Performs a deep copy.
+ * @param other object to copy
+ */
+ KAboutPerson& operator=(const KAboutPerson& other);
+
+
+ /**
+ * The person's name
+ * @return the person's name (can be QString(), if it has been
+ * constructed with an empty name)
+ */
+ QString name() const;
+
+ /**
+ * The person's task
+ * @return the person's task (can be QString(), if it has been
+ * constructed with an empty task)
+ */
+ QString task() const;
+
+ /**
+ * The person's email address
+ * @return the person's email address (can be QString(), if it has been
+ * constructed with an empty email)
+ */
+ QString emailAddress() const;
+
+ /**
+ * The home page or a relevant link
+ * @return the persons home page (can be QString(), if it has been
+ * constructed with an empty home page)
+ */
+ QString webAddress() const;
+
+ /**
+ * The person's Open Collaboration Services username
+ * @return the persons OCS username (can be QString(), if it has been
+ * constructed with an empty username)
+ */
+ QString ocsUsername() const;
+
+private:
+ /**
+ * @internal Used by KAboutData to construct translator data.
+ */
+ explicit KAboutPerson( const QString &name, const QString &email );
+
+ class Private;
+ Private *const d;
+};
+
+class KAboutLicense;
+
+// KDE5: refactor together with KComponentData.
+// Like changing all property names which contain Program or App.
+
+/**
+ * This class is used to store information about a program. It can store
+ * such values as version number, program name, home page, email address
+ * for bug reporting, multiple authors and contributors
+ * (using KAboutPerson), license and copyright information.
+ *
+ * Currently, the values set here are shown by the "About" box
+ * (see KAboutDialog), used by the bug report dialog (see KBugReport),
+ * and by the help shown on command line (see KCmdLineArgs).
+ * They are also used for the icon and the name of the program's windows.
+ *
+ * @note Instead of the more usual i18n calls, for translatable text the ki18n
+ * calls are used to produce KLocalizedStrings, which can delay the translation
+ * lookup. This is necessary because the translation catalogs are usually not
+ * yet initialized at the point where KAboutData is constructed.
+ *
+ * @short Holds information needed by the "About" box and other
+ * classes.
+ * @author Espen Sand (espen@kde.org), David Faure (faure@kde.org)
+ */
+class KDECORE_EXPORT KAboutData
+{
+ public:
+ /**
+ * Describes the license of the software.
+ */
+ enum LicenseKey // KDE5: move to KAboutLicense, cut License_ prefix
+ {
+ License_Custom = -2,
+ License_File = -1,
+ License_Unknown = 0,
+ License_GPL = 1,
+ License_GPL_V2 = 1,
+ License_LGPL = 2,
+ License_LGPL_V2 = 2,
+ License_BSD = 3,
+ License_Artistic = 4,
+ License_QPL = 5,
+ License_QPL_V1_0 = 5,
+ License_GPL_V3 = 6,
+ License_LGPL_V3 = 7
+ };
+
+ /**
+ * Format of the license name.
+ */
+ enum NameFormat // KDE5: move to KAboutLicense
+ {
+ ShortName,
+ FullName
+ };
+
+ public:
+ /**
+ * Constructor.
+ *
+ * @param appName The program name used internally. Example: "kedit"
+ *
+ * @param catalogName The translation catalog name; if null or empty, the
+ * @p appName will be used. You may want the catalog name to
+ * differ from program name, for example, when you want to group
+ * translations of several smaller utilities under the same catalog.
+ *
+ * @param programName A displayable program name string. This string
+ * should be marked for translation. Example: ki18n("KEdit")
+ *
+ * @param version The program version string.
+ *
+ * @param shortDescription A short description of what the program does.
+ * This string should be marked for translation.
+ * Example: ki18n("A simple text editor.")
+ *
+ * @param licenseType The license identifier. Use setLicenseText or
+ setLicenseTextFile if you use a license not predefined here.
+ *
+ * @param copyrightStatement A copyright statement, that can look like this:
+ * ki18n("Copyright (C) 1999-2000 Name"). The string specified here is
+ * taken verbatim; the author information from addAuthor is not used.
+ *
+ * @param otherText Some free form text, that can contain any kind of
+ * information. The text can contain newlines. This string
+ * should be marked for translation.
+ *
+ * @param homePageAddress The program homepage string.
+ * Start the address with "http://". "http://some.domain" is
+ * is correct, "some.domain" is not.
+ * IMPORTANT: if you set a home page address, this will change the "organization domain"
+ * of the application, which is used for automatic D-Bus registration.
+ * @see setOrganizationDomain
+ *
+ * @param bugsEmailAddress The bug report email address string.
+ * This defaults to the kde.org bug system.
+ *
+ */
+ KAboutData( const QByteArray &appName,
+ const QByteArray &catalogName,
+ const KLocalizedString &programName,
+ const QByteArray &version,
+ const KLocalizedString &shortDescription = KLocalizedString(),
+ enum LicenseKey licenseType = License_Unknown,
+ const KLocalizedString &copyrightStatement = KLocalizedString(),
+ const KLocalizedString &otherText = KLocalizedString(),
+ const QByteArray &homePageAddress = QByteArray(),
+ const QByteArray &bugsEmailAddress = "submit@bugs.kde.org"
+ );
+
+ /**
+ * Copy constructor. Performs a deep copy.
+ * @param other object to copy
+ */
+ KAboutData(const KAboutData& other);
+
+ /**
+ * Assignment operator. Performs a deep copy.
+ * @param other object to copy
+ */
+ KAboutData& operator=(const KAboutData& other);
+
+ ~KAboutData();
+
+ /**
+ * Defines an author.
+ *
+ * You can call this function as many times as you need. Each entry is
+ * appended to a list. The person in the first entry is assumed to be
+ * the leader of the project.
+ *
+ * @param name The developer's name. It should be marked for translation
+ * like this: ki18n("Developer Name")
+ *
+ * @param task What the person is responsible for. This text can contain
+ * newlines. It should be marked for translation like this:
+ * ki18n("Task description..."). Can be left empty.
+ *
+ * @param emailAddress An Email address where the person can be reached.
+ * Can be left empty.
+ *
+ * @param webAddress The person's homepage or a relevant link.
+ * Start the address with "http://". "http://some.domain" is
+ * correct, "some.domain" is not. Can be left empty.
+ *
+ */
+ KAboutData &addAuthor( const KLocalizedString &name,
+ const KLocalizedString &task = KLocalizedString(),
+ const QByteArray &emailAddress = QByteArray(),
+ const QByteArray &webAddress = QByteArray() );
+
+ /**
+ * Defines an author.
+ *
+ * You can call this function as many times as you need. Each entry is
+ * appended to a list. The person in the first entry is assumed to be
+ * the leader of the project.
+ *
+ * @param name The developer's name. It should be marked for translation
+ * like this: ki18n("Developer Name")
+ *
+ * @param task What the person is responsible for. This text can contain
+ * newlines. It should be marked for translation like this:
+ * ki18n("Task description..."). Can be left empty.
+ *
+ * @param emailAddress An Email address where the person can be reached.
+ * Can be left empty.
+ *
+ * @param webAddress The person's homepage or a relevant link.
+ * Start the address with "http://". "http://some.domain" is
+ * correct, "some.domain" is not. Can be left empty.
+ *
+ * @param ocsUsername The person's Open Collaboration Services username.
+ * The provider can be optionally specified with @see setOcsProvider.
+ *
+ */
+ KAboutData &addAuthor( const KLocalizedString &name,
+ const KLocalizedString &task,
+ const QByteArray &emailAddress,
+ const QByteArray &webAddress,
+ const QByteArray &ocsUsername ); //KDE5: merge with addAuthor
+
+ /**
+ * Defines a person that deserves credit.
+ *
+ * You can call this function as many times as you need. Each entry
+ * is appended to a list.
+ *
+ * @param name The person's name. It should be marked for translation
+ * like this: ki18n("Contributor Name")
+ *
+ * @param task What the person has done to deserve the honor. The
+ * text can contain newlines. It should be marked for
+ * translation like this: ki18n("Task description...")
+ * Can be left empty.
+ *
+ * @param emailAddress An email address when the person can be reached.
+ * Can be left empty.
+ *
+ * @param webAddress The person's homepage or a relevant link.
+ * Start the address with "http://". "http://some.domain" is
+ * is correct, "some.domain" is not. Can be left empty.
+ *
+ */
+ KAboutData &addCredit( const KLocalizedString &name,
+ const KLocalizedString &task = KLocalizedString(),
+ const QByteArray &emailAddress = QByteArray(),
+ const QByteArray &webAddress = QByteArray() );
+
+ /**
+ * Defines a person that deserves credit.
+ *
+ * You can call this function as many times as you need. Each entry
+ * is appended to a list.
+ *
+ * @param name The person's name. It should be marked for translation
+ * like this: ki18n("Contributor Name")
+ *
+ * @param task What the person has done to deserve the honor. The
+ * text can contain newlines. It should be marked for
+ * translation like this: ki18n("Task description...")
+ * Can be left empty.
+ *
+ * @param emailAddress An email address when the person can be reached.
+ * Can be left empty.
+ *
+ * @param webAddress The person's homepage or a relevant link.
+ * Start the address with "http://". "http://some.domain" is
+ * is correct, "some.domain" is not. Can be left empty.
+ *
+ * @param ocsUsername The person's Open Collaboration Services username.
+ * The provider can be optionally specified with @see setOcsProvider.
+ *
+ */
+ KAboutData &addCredit( const KLocalizedString &name,
+ const KLocalizedString &task,
+ const QByteArray &emailAddress,
+ const QByteArray &webAddress,
+ const QByteArray &ocsUsername ); //KDE5: merge with addCredit
+
+ /**
+ * @brief Sets the name(s) of the translator(s) of the GUI.
+ *
+ * Since this depends on the language, just use a dummy text marked for
+ * translation.
+ *
+ * The canonical use is:
+ *
+ * \code
+ * setTranslator(ki18nc("NAME OF TRANSLATORS", "Your names"),
+ * ki18nc("EMAIL OF TRANSLATORS", "Your emails"));
+ * \endcode
+ *
+ * The translator can then translate this dummy text with his name
+ * or with a list of names separated with ",".
+ * If there is no translation or the application is used with the
+ * default language, this function call is ignored.
+ *
+ * @param name the name(s) of the translator(s)
+ * @param emailAddress the email address(es) of the translator(s)
+ * @see KAboutTranslator
+ */
+ KAboutData &setTranslator( const KLocalizedString& name,
+ const KLocalizedString& emailAddress );
+
+ /**
+ * Defines a license text, which is marked for translation.
+ *
+ * Example:
+ * \code
+ * setLicenseText( ki18n("This is my license") );
+ * \endcode
+ *
+ * @param license The license text.
+ */
+ KAboutData &setLicenseText( const KLocalizedString &license );
+
+ /**
+ * Adds a license text, which is marked for translation.
+ *
+ * If there is only one unknown license set, e.g. by using the default
+ * parameter in the constructor, that one is replaced.
+ *
+ * Example:
+ * \code
+ * addLicenseText( ki18n("This is my license") );
+ * \endcode
+ *
+ * @param license The license text.
+ * @see setLicenseText, addLicense, addLicenseTextFile
+ * @since 4.1
+ */
+ KAboutData &addLicenseText( const KLocalizedString &license );
+
+ /**
+ * Defines a license text by pointing to a file where it resides.
+ * The file format has to be plain text in an encoding compatible to the locale.
+ *
+ * @param file Path to the file in the local filesystem containing the license text.
+ */
+ KAboutData &setLicenseTextFile( const QString &file );
+
+ /**
+ * Adds a license text by pointing to a file where it resides.
+ * The file format has to be plain text in an encoding compatible to the locale.
+ *
+ * If there is only one unknown license set, e.g. by using the default
+ * parameter in the constructor, that one is replaced.
+ *
+ * @param file Path to the file in the local filesystem containing the license text.
+ * @see addLicenseText, addLicense, setLicenseTextFile
+ * @since 4.1
+ */
+ KAboutData &addLicenseTextFile( const QString &file );
+
+ /**
+ * Defines the program name used internally.
+ *
+ * @param appName The application name. Example: "kate".
+ */
+ KAboutData &setAppName( const QByteArray &appName );
+
+ /**
+ * Defines the displayable program name string.
+ *
+ * @param programName The program name. This string should be
+ * marked for translation.
+ * Example: ki18n("Advanced Text Editor").
+ */
+ KAboutData &setProgramName( const KLocalizedString &programName );
+
+ /**
+ * Defines the program icon.
+ *
+ * Use this if you need to have an application icon
+ * whose name is different than the application name.
+ *
+ * @param iconName name of the icon. Example: "accessories-text-editor"
+ * @see programIconName()
+ * @since 4.1
+ */
+ KAboutData &setProgramIconName( const QString &iconName );
+
+ /**
+ * Defines the program logo.
+ *
+ * Use this if you need to have an application logo
+ * in AboutData other than the application icon.
+ *
+ * Because KAboutData is in kdecore it cannot use QImage directly,
+ * so this is a QVariant that should contain a QImage.
+ *
+ * @param image logo image.
+ * @see programLogo()
+ */
+ KAboutData &setProgramLogo(const QVariant& image);
+
+ /**
+ * Specifies an Open Collaboration Services provider by URL.
+ * A provider file must be available for the chosen provider.
+ *
+ * Use this if you need to override the default provider.
+ *
+ * If this method is not used, all the KAboutPerson OCS usernames
+ * will be used with the openDesktop.org entry from the default
+ * provider file.
+ *
+ * @param providerUrl The provider URL as defined in the provider file.
+ */
+ KAboutData &setOcsProvider( const QByteArray &providerUrl );
+
+ /**
+ * Defines the program version string.
+ *
+ * @param version The program version.
+ */
+ KAboutData &setVersion( const QByteArray &version );
+
+ /**
+ * Defines a short description of what the program does.
+ *
+ * @param shortDescription The program description. This string should
+ * be marked for translation. Example: ki18n("An advanced text
+ * editor with syntax highlighting support.").
+ */
+ KAboutData &setShortDescription( const KLocalizedString &shortDescription );
+
+ /**
+ * Defines the translation catalog that the program uses.
+ *
+ * @param catalogName The translation catalog name.
+ */
+ KAboutData &setCatalogName( const QByteArray &catalogName );
+
+ /**
+ * Defines the license identifier.
+ *
+ * @param licenseKey The license identifier.
+ * @see addLicenseText, setLicenseText, setLicenseTextFile
+ */
+ KAboutData &setLicense( LicenseKey licenseKey );
+
+ /**
+ * Adds a license identifier.
+ *
+ * If there is only one unknown license set, e.g. by using the default
+ * parameter in the constructor, that one is replaced.
+ *
+ * @param licenseKey The license identifier.
+ * @see setLicenseText, addLicenseText, addLicenseTextFile
+ * @since 4.1
+ */
+ KAboutData &addLicense( LicenseKey licenseKey );
+
+ /**
+ * Defines the copyright statement to show when displaying the license.
+ *
+ * @param copyrightStatement A copyright statement, that can look like
+ * this: ki18n("Copyright (C) 1999-2000 Name"). The string specified here is
+ * taken verbatim; the author information from addAuthor is not used.
+ */
+ KAboutData &setCopyrightStatement( const KLocalizedString &copyrightStatement );
+
+ /**
+ * Defines the additional text to show in the about dialog.
+ *
+ * @param otherText Some free form text, that can contain any kind of
+ * information. The text can contain newlines. This string
+ * should be marked for translation.
+ */
+ KAboutData &setOtherText( const KLocalizedString &otherText );
+
+ /**
+ * Defines the program homepage.
+ *
+ * @param homepage The program homepage string.
+ * Start the address with "http://". "http://kate.kde.org"
+ * is correct but "kate.kde.org" is not.
+ */
+ KAboutData &setHomepage( const QByteArray &homepage );
+
+ /**
+ * Defines the address where bug reports should be sent.
+ *
+ * @param bugAddress The bug report email address string.
+ * This defaults to the kde.org bug system.
+ */
+ KAboutData &setBugAddress( const QByteArray &bugAddress );
+
+ /**
+ * Defines the Internet domain of the organization that wrote this application.
+ * The domain is set to kde.org by default, or the domain of the homePageAddress constructor argument,
+ * if set.
+ *
+ * Make sure to call setOrganizationDomain if your product is developed out of the
+ * kde.org version-control system.
+ *
+ * Used by the automatic registration to D-Bus done by KApplication and KUniqueApplication.
+ *
+ * IMPORTANT: if the organization domain is set, the .desktop file that describes your
+ * application should have an entry like X-DBUS-ServiceName=reversed_domain.kmyapp
+ * For instance kwrite passes "http://www.kate-editor.org" as the homePageAddress so it needs
+ * X-DBUS-ServiceName=org.kate-editor.kwrite in its kwrite.desktop file.
+ *
+ * @param domain the domain name, for instance kde.org, koffice.org, kdevelop.org, etc.
+ */
+ KAboutData &setOrganizationDomain( const QByteArray &domain );
+
+ /**
+ * Defines the product name which will be used in the KBugReport dialog.
+ * By default it's the appName, but you can overwrite it here to provide
+ * support for special components e.g. in the form 'product/component',
+ * such as 'kontact/summary'.
+ *
+ * @param name The name of product
+ */
+ KAboutData &setProductName( const QByteArray &name );
+
+ /**
+ * Returns the application's internal name.
+ * @return the internal program name.
+ */
+ QString appName() const;
+
+ /**
+ * Returns the application's product name, which will be used in KBugReport
+ * dialog. By default it returns appName(), otherwise the one which is set
+ * with setProductName()
+ *
+ * @return the product name.
+ */
+ QString productName() const;
+
+ /**
+ * Returns the translated program name.
+ * @return the program name (translated).
+ */
+ QString programName() const;
+
+ /**
+ * Returns the domain name of the organization that wrote this application.
+ *
+ * Used by the automatic registration to D-Bus done by KApplication and KUniqueApplication.
+ */
+ QString organizationDomain() const;
+
+ /**
+ * @internal
+ * Provided for use by KCrash
+ */
+ const char* internalProgramName() const;
+
+ /**
+ * @internal
+ * Provided for use by KCrash
+ */
+ void translateInternalProgramName() const;
+
+ /**
+ * Returns the program's icon name.
+ *
+ * The default value is appName().
+ * Use setProgramIconName() if you need to have an icon
+ * whose name is different from the internal application name.
+ *
+ * @return the program's icon name.
+ * @see setProgramIconName()
+ * @since 4.1
+ */
+ QString programIconName() const;
+
+ /**
+ * Returns the program logo image.
+ *
+ * Because KAboutData is in kdecore it cannot use QImage directly,
+ * so this is a QVariant containing a QImage.
+ *
+ * @return the program logo data, or a null image if there is
+ * no custom application logo defined.
+ */
+ QVariant programLogo() const;
+
+ /**
+ * Returns the chosen Open Collaboration Services provider URL.
+ * @return the provider URL.
+ */
+ QString ocsProviderUrl() const;
+
+ /**
+ * Returns the program's version.
+ * @return the version string.
+ */
+ QString version() const;
+
+ /**
+ * @internal
+ * Provided for use by KCrash
+ */
+ const char* internalVersion() const;
+
+ /**
+ * Returns a short, translated description.
+ * @return the short description (translated). Can be
+ * QString() if not set.
+ */
+ QString shortDescription() const;
+
+ /**
+ * Returns the program's translation catalog name.
+ * @return the catalog name.
+ */
+ QString catalogName() const;
+
+ /**
+ * Returns the application homepage.
+ * @return the application homepage URL. Can be QString() if
+ * not set.
+ */
+ QString homepage() const;
+
+ /**
+ * Returns the email address for bugs.
+ * @return the email address where to report bugs.
+ */
+ QString bugAddress() const;
+
+ /**
+ * @internal
+ * Provided for use by KCrash
+ */
+ const char* internalBugAddress() const;
+
+ /**
+ * Returns a list of authors.
+ * @return author information (list of persons).
+ */
+ QList<KAboutPerson> authors() const;
+
+ /**
+ * Returns a list of persons who contributed.
+ * @return credit information (list of persons).
+ */
+ QList<KAboutPerson> credits() const;
+
+ /**
+ * Returns a list of translators.
+ * @return translators information (list of persons)
+ */
+ QList<KAboutPerson> translators() const;
+
+ /**
+ * Returns a message about the translation team.
+ * @return a message about the translation team
+ */
+ static QString aboutTranslationTeam();
+
+ /**
+ * Returns a translated, free form text.
+ * @return the free form text (translated). Can be QString() if not set.
+ */
+ QString otherText() const;
+
+ /**
+ * Returns the license. If the licenseType argument of the constructor has been
+ * used, any text defined by setLicenseText is ignored,
+ * and the standard text for the chosen license will be returned.
+ *
+ * @return The license text.
+ *
+ * @deprecated There could be multiple licenses, use licenses() instead.
+ */
+ QString license() const;
+
+ /**
+ * Returns the license name.
+ *
+ * @return The license name as a string.
+ *
+ * @deprecated There could be multiple licenses, use licenses() instead.
+ */
+ QString licenseName(NameFormat formatName) const;
+
+ /**
+ * Returns a list of licenses.
+ *
+ * @return licenses information (list of licenses)
+ * @since 4.1
+ */
+ QList<KAboutLicense> licenses() const;
+
+ /**
+ * Returns the copyright statement.
+ * @return the copyright statement. Can be QString() if not set.
+ */
+ QString copyrightStatement() const;
+
+ /**
+ * Returns the plain text displayed around the list of authors instead
+ * of the default message telling users to send bug reports to bugAddress().
+ *
+ * @return the plain text displayed around the list of authors instead
+ * of the default message. Can be QString().
+ */
+ QString customAuthorPlainText() const;
+
+ /**
+ * Returns the rich text displayed around the list of authors instead
+ * of the default message telling users to send bug reports to bugAddress().
+ *
+ * @return the rich text displayed around the list of authors instead
+ * of the default message. Can be QString().
+ */
+ QString customAuthorRichText() const;
+
+ /**
+ * Returns whether custom text should be displayed around the list of
+ * authors.
+ *
+ * @return whether custom text should be displayed around the list of
+ * authors.
+ */
+ bool customAuthorTextEnabled() const;
+
+ /**
+ * Sets the custom text displayed around the list of authors instead
+ * of the default message telling users to send bug reports to bugAddress().
+ *
+ * @param plainText The plain text.
+ * @param richText The rich text.
+ *
+ * Setting both to parameters to KLocalizedString() will cause no message to be
+ * displayed at all. Call unsetCustomAuthorText() to revert to the default
+ * message.
+ */
+ KAboutData &setCustomAuthorText(const KLocalizedString &plainText,
+ const KLocalizedString &richText);
+
+ /**
+ * Clears any custom text displayed around the list of authors and falls
+ * back to the default message telling users to send bug reports to
+ * bugAddress().
+ */
+ KAboutData &unsetCustomAuthorText();
+
+ private:
+
+ class Private;
+ Private *const d;
+};
+
+
+/**
+ * This class is used to store information about a license.
+ * The license can be one of some predefined, one given as text or one
+ * that can be loaded from a file. This class is used in the KAboutData class.
+ * Explicitly creating a KAboutLicense object is not possible.
+ * If the license is wanted for a KDE component having KAboutData object,
+ * use KAboutData::licenses() to get the licenses for that component.
+ * If the license is for a non-code resource and given by a keyword
+ * (e.g. in .desktop files), try using KAboutLicense::byKeyword().
+ *
+ * @note Instead of the more usual i18n calls, for translatable text the ki18n
+ * calls are used to produce KLocalizedStrings, which can delay the translation
+ * lookup. This is necessary because the translation catalogs are usually not
+ * yet initialized at the point where KAboutData is constructed.
+ */
+class KDECORE_EXPORT KAboutLicense
+{
+ friend class KAboutData;
+public:
+ /**
+ * Copy constructor. Performs a deep copy.
+ * @param other object to copy
+ */
+ KAboutLicense(const KAboutLicense& other);
+
+ ~KAboutLicense();
+
+ /**
+ * Assignment operator. Performs a deep copy.
+ * @param other object to copy
+ */
+ KAboutLicense& operator=(const KAboutLicense& other);
+
+
+ /**
+ * Returns the full license text. If the licenseType argument of the
+ * constructor has been used, any text defined by setLicenseText is ignored,
+ * and the standard text for the chosen license will be returned.
+ *
+ * @return The license text.
+ */
+ QString text() const;
+
+ /**
+ * Returns the license name.
+ *
+ * @return The license name as a string.
+ */
+ QString name(KAboutData::NameFormat formatName) const;
+
+ /**
+ * Returns the license key.
+ *
+ * @return The license key as element of KAboutData::LicenseKey enum.
+ * @since 4.1
+ */
+ KAboutData::LicenseKey key() const;
+
+ /**
+ * Fetch a known license by a keyword.
+ *
+ * Frequently the license data is provided by a terse keyword-like string,
+ * e.g. by a field in a .desktop file. Using this method, an application
+ * can get hold of a proper KAboutLicense object, providing that the
+ * license is one of the several known to KDE, and use it to present
+ * more human-readable information to the user.
+ *
+ * Keywords are matched by stripping all whitespace and lowercasing.
+ * The known keywords correspond to the KAboutData::LicenseKey enumeration,
+ * e.g. any of "LGPLV3", "LGPLv3", "LGPL v3" would match License_LGPL_V3.
+ * If there is no match for the keyword, a valid license object is still
+ * returned, with its name and text informing about a custom license,
+ * and its key equal to KAboutData::License_Custom.
+ *
+ * @param keyword The license keyword.
+ * @return The license object.
+ *
+ * @see KAboutData::LicenseKey
+ * @since 4.1
+ */
+ static KAboutLicense byKeyword(const QString &keyword);
+
+private:
+ /**
+ * @internal Used by KAboutData to construct a predefined license.
+ */
+ explicit KAboutLicense( enum KAboutData::LicenseKey licenseType, const KAboutData *aboutData );
+ /**
+ * @internal Used by KAboutData to construct license by given text
+ */
+ explicit KAboutLicense( const QString &pathToFile, const KAboutData *aboutData );
+ /**
+ * @internal Used by KAboutData to construct license by given text
+ */
+ explicit KAboutLicense( const KLocalizedString &licenseText, const KAboutData *aboutData );
+
+ class Private;
+ QSharedDataPointer<Private> d;
+};
+
+#endif
+
diff --git a/kdecore/kernel/kauthorized.cpp b/kdecore/kernel/kauthorized.cpp
new file mode 100644
index 0000000..f7d795a
--- /dev/null
+++ b/kdecore/kernel/kauthorized.cpp
@@ -0,0 +1,380 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
+ Copyright (C) 1998, 1999, 2000 Waldo Bastian <bastian@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 as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ 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 "kauthorized.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QRegExp>
+#include <QList>
+
+
+#include <QCoreApplication>
+#include <kglobal.h>
+#include <ksharedconfig.h>
+#include <kprotocolinfo.h>
+#include <kstandarddirs.h>
+#include <stdlib.h> // srand(), rand()
+#include <unistd.h>
+#include <netdb.h>
+#include <kurl.h>
+#include <kconfiggroup.h>
+
+#include <QMutex>
+#include <QMutexLocker>
+#include <QtCore/QBool>
+
+extern bool kde_kiosk_exception;
+
+
+class URLActionRule
+{
+ public:
+#define checkExactMatch(s, b) \
+ if (s.isEmpty()) b = true; \
+ else if (s[s.length()-1] == QLatin1Char('!')) \
+ { b = false; s.truncate(s.length()-1); } \
+ else b = true;
+#define checkStartWildCard(s, b) \
+ if (s.isEmpty()) b = true; \
+ else if (s[0] == QLatin1Char('*')) \
+ { b = true; s = s.mid(1); } \
+ else b = false;
+#define checkEqual(s, b) \
+ b = (s == QString::fromLatin1("="));
+
+ URLActionRule(const QByteArray &act,
+ const QString &bProt, const QString &bHost, const QString &bPath,
+ const QString &dProt, const QString &dHost, const QString &dPath,
+ bool perm)
+ : action(act),
+ baseProt(bProt), baseHost(bHost), basePath(bPath),
+ destProt(dProt), destHost(dHost), destPath(dPath),
+ permission(perm)
+ {
+ checkExactMatch(baseProt, baseProtWildCard);
+ checkStartWildCard(baseHost, baseHostWildCard);
+ checkExactMatch(basePath, basePathWildCard);
+ checkExactMatch(destProt, destProtWildCard);
+ checkStartWildCard(destHost, destHostWildCard);
+ checkExactMatch(destPath, destPathWildCard);
+ checkEqual(destProt, destProtEqual);
+ checkEqual(destHost, destHostEqual);
+ }
+
+ bool baseMatch(const KUrl &url, const QString &protClass) const
+ {
+ if (baseProtWildCard)
+ {
+ if ( !baseProt.isEmpty() && !url.protocol().startsWith(baseProt) &&
+ (protClass.isEmpty() || (protClass != baseProt)) )
+ return false;
+ }
+ else
+ {
+ if ( (url.protocol() != baseProt) &&
+ (protClass.isEmpty() || (protClass != baseProt)) )
+ return false;
+ }
+ if (baseHostWildCard)
+ {
+ if (!baseHost.isEmpty() && !url.host().endsWith(baseHost))
+ return false;
+ }
+ else
+ {
+ if (url.host() != baseHost)
+ return false;
+ }
+ if (basePathWildCard)
+ {
+ if (!basePath.isEmpty() && !url.path().startsWith(basePath))
+ return false;
+ }
+ else
+ {
+ if (url.path() != basePath)
+ return false;
+ }
+ return true;
+ }
+
+ bool destMatch(const KUrl &url, const QString &protClass, const KUrl &base, const QString &baseClass) const
+ {
+ if (destProtEqual)
+ {
+ if ( (url.protocol() != base.protocol()) &&
+ (protClass.isEmpty() || baseClass.isEmpty() || protClass != baseClass) )
+ return false;
+ }
+ else if (destProtWildCard)
+ {
+ if ( !destProt.isEmpty() && !url.protocol().startsWith(destProt) &&
+ (protClass.isEmpty() || (protClass != destProt)) )
+ return false;
+ }
+ else
+ {
+ if ( (url.protocol() != destProt) &&
+ (protClass.isEmpty() || (protClass != destProt)) )
+ return false;
+ }
+ if (destHostWildCard)
+ {
+ if (!destHost.isEmpty() && !url.host().endsWith(destHost))
+ return false;
+ }
+ else if (destHostEqual)
+ {
+ if (url.host() != base.host())
+ return false;
+ }
+ else
+ {
+ if (url.host() != destHost)
+ return false;
+ }
+ if (destPathWildCard)
+ {
+ if (!destPath.isEmpty() && !url.path().startsWith(destPath))
+ return false;
+ }
+ else
+ {
+ if (url.path() != destPath)
+ return false;
+ }
+ return true;
+ }
+
+ QByteArray action;
+ QString baseProt;
+ QString baseHost;
+ QString basePath;
+ QString destProt;
+ QString destHost;
+ QString destPath;
+ bool baseProtWildCard : 1;
+ bool baseHostWildCard : 1;
+ bool basePathWildCard : 1;
+ bool destProtWildCard : 1;
+ bool destHostWildCard : 1;
+ bool destPathWildCard : 1;
+ bool destProtEqual : 1;
+ bool destHostEqual : 1;
+ bool permission;
+};
+
+class KAuthorizedPrivate {
+public:
+ KAuthorizedPrivate()
+ : actionRestrictions( false ), blockEverything(false),mutex(QMutex::Recursive)
+ {
+ Q_ASSERT_X(QCoreApplication::instance(),"KAuthorizedPrivate()","There has to be an existing QCoreApplication::instance() pointer");
+
+ KSharedConfig::Ptr config = KGlobal::config();
+
+ Q_ASSERT_X(config,"KAuthorizedPrivate()","There has to be an existing KGlobal::config() pointer");
+ if (!config) {
+ blockEverything=true;
+ return;
+ }
+ actionRestrictions = config->hasGroup("KDE Action Restrictions" ) && !kde_kiosk_exception;
+ }
+
+ ~KAuthorizedPrivate()
+ {
+ }
+
+ bool actionRestrictions : 1;
+ bool blockEverything : 1;
+ QList<URLActionRule> urlActionRestrictions;
+ QMutex mutex;
+};
+
+Q_GLOBAL_STATIC(KAuthorizedPrivate,authPrivate)
+#define MY_D KAuthorizedPrivate *d=authPrivate();
+
+
+bool KAuthorized::authorize(const QString &genericAction)
+{
+ MY_D
+ if (d->blockEverything) return false;
+
+ if (!d->actionRestrictions)
+ return true;
+
+ KConfigGroup cg(KGlobal::config(), "KDE Action Restrictions");
+ return cg.readEntry(genericAction, true);
+}
+
+bool KAuthorized::authorizeKAction(const QString& action)
+{
+ MY_D
+ if (d->blockEverything) return false;
+ if (!d->actionRestrictions || action.isEmpty())
+ return true;
+
+ return authorize(QLatin1String("action/") + action);
+}
+
+bool KAuthorized::authorizeControlModule(const QString &menuId)
+{
+ if (menuId.isEmpty() || kde_kiosk_exception)
+ return true;
+ KConfigGroup cg(KGlobal::config(), "KDE Control Module Restrictions");
+ return cg.readEntry(menuId, true);
+}
+
+QStringList KAuthorized::authorizeControlModules(const QStringList &menuIds)
+{
+ KConfigGroup cg(KGlobal::config(), "KDE Control Module Restrictions");
+ QStringList result;
+ for(QStringList::ConstIterator it = menuIds.begin();
+ it != menuIds.end(); ++it)
+ {
+ if (cg.readEntry(*it, true))
+ result.append(*it);
+ }
+ return result;
+}
+
+static void initUrlActionRestrictions()
+{
+ MY_D
+ const QString Any;
+
+ d->urlActionRestrictions.clear();
+ d->urlActionRestrictions.append(
+ URLActionRule("open", Any, Any, Any, Any, Any, Any, true));
+ d->urlActionRestrictions.append(
+ URLActionRule("list", Any, Any, Any, Any, Any, Any, true));
+// TEST:
+// d->urlActionRestrictions.append(
+// URLActionRule("list", Any, Any, Any, Any, Any, Any, false));
+// d->urlActionRestrictions.append(
+// URLActionRule("list", Any, Any, Any, "file", Any, QDir::homePath(), true));
+ d->urlActionRestrictions.append(
+ URLActionRule("link", Any, Any, Any, QLatin1String(":internet"), Any, Any, true));
+ d->urlActionRestrictions.append(
+ URLActionRule("redirect", Any, Any, Any, QLatin1String(":internet"), Any, Any, true));
+
+ // We allow redirections to file: but not from internet protocols, redirecting to file:
+ // is very popular among io-slaves and we don't want to break them
+ d->urlActionRestrictions.append(
+ URLActionRule("redirect", Any, Any, Any, QLatin1String("file"), Any, Any, true));
+ d->urlActionRestrictions.append(
+ URLActionRule("redirect", QLatin1String(":internet"), Any, Any, QLatin1String("file"), Any, Any, false));
+
+ // local protocols may redirect everywhere
+ d->urlActionRestrictions.append(
+ URLActionRule("redirect", QLatin1String(":local"), Any, Any, Any, Any, Any, true));
+
+ // Anyone may redirect to about:
+ d->urlActionRestrictions.append(
+ URLActionRule("redirect", Any, Any, Any, QLatin1String("about"), Any, Any, true));
+
+ // Anyone may redirect to itself, cq. within it's own group
+ d->urlActionRestrictions.append(
+ URLActionRule("redirect", Any, Any, Any, QLatin1String("="), Any, Any, true));
+
+ d->urlActionRestrictions.append(
+ URLActionRule("redirect", QLatin1String("about"), Any, Any, Any, Any, Any, true));
+
+
+ KConfigGroup cg(KGlobal::config(), "KDE URL Restrictions");
+ int count = cg.readEntry("rule_count", 0);
+ QString keyFormat = QString::fromLatin1("rule_%1");
+ for(int i = 1; i <= count; i++)
+ {
+ QString key = keyFormat.arg(i);
+ const QStringList rule = cg.readEntry(key, QStringList());
+ if (rule.count() != 8)
+ continue;
+ const QByteArray action = rule[0].toLatin1();
+ QString refProt = rule[1];
+ QString refHost = rule[2];
+ QString refPath = rule[3];
+ QString urlProt = rule[4];
+ QString urlHost = rule[5];
+ QString urlPath = rule[6];
+ bool bEnabled = (rule[7].toLower() == QLatin1String("true"));
+
+ if (refPath.startsWith(QLatin1String("$HOME")))
+ refPath.replace(0, 5, QDir::homePath());
+ else if (refPath.startsWith(QLatin1Char('~')))
+ refPath.replace(0, 1, QDir::homePath());
+ if (urlPath.startsWith(QLatin1String("$HOME")))
+ urlPath.replace(0, 5, QDir::homePath());
+ else if (urlPath.startsWith(QLatin1Char('~')))
+ urlPath.replace(0, 1, QDir::homePath());
+
+ if (refPath.startsWith(QLatin1String("$TMP")))
+ refPath.replace(0, 4, KGlobal::dirs()->saveLocation("tmp"));
+ if (urlPath.startsWith(QLatin1String("$TMP")))
+ urlPath.replace(0, 4, KGlobal::dirs()->saveLocation("tmp"));
+
+ d->urlActionRestrictions.append(
+ URLActionRule( action, refProt, refHost, refPath, urlProt, urlHost, urlPath, bEnabled));
+ }
+}
+
+void KAuthorized::allowUrlAction(const QString &action, const KUrl &_baseURL, const KUrl &_destURL)
+{
+ MY_D
+ QMutexLocker locker((&d->mutex));
+ if (authorizeUrlAction(action, _baseURL, _destURL))
+ return;
+
+ d->urlActionRestrictions.append( URLActionRule
+ ( action.toLatin1(), _baseURL.protocol(), _baseURL.host(), _baseURL.path(KUrl::RemoveTrailingSlash),
+ _destURL.protocol(), _destURL.host(), _destURL.path(KUrl::RemoveTrailingSlash), true));
+}
+
+bool KAuthorized::authorizeUrlAction(const QString &action, const KUrl &_baseURL, const KUrl &_destURL)
+{
+ MY_D
+ QMutexLocker locker(&(d->mutex));
+ if (d->blockEverything) return false;
+
+ if (_destURL.isEmpty())
+ return true;
+
+ bool result = false;
+ if (d->urlActionRestrictions.isEmpty())
+ initUrlActionRestrictions();
+
+ KUrl baseURL(_baseURL);
+ baseURL.setPath(QDir::cleanPath(baseURL.path()));
+ QString baseClass = KProtocolInfo::protocolClass(baseURL.protocol());
+ KUrl destURL(_destURL);
+ destURL.setPath(QDir::cleanPath(destURL.path()));
+ QString destClass = KProtocolInfo::protocolClass(destURL.protocol());
+
+ foreach(const URLActionRule &rule, d->urlActionRestrictions) {
+ if ((result != rule.permission) && // No need to check if it doesn't make a difference
+ (action == QLatin1String(rule.action)) &&
+ rule.baseMatch(baseURL, baseClass) &&
+ rule.destMatch(destURL, destClass, baseURL, baseClass))
+ {
+ result = rule.permission;
+ }
+ }
+ return result;
+}
diff --git a/kdecore/kernel/kauthorized.h b/kdecore/kernel/kauthorized.h
new file mode 100644
index 0000000..bff66e1
--- /dev/null
+++ b/kdecore/kernel/kauthorized.h
@@ -0,0 +1,95 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
+ Copyright (c) 1998, 1999 Waldo Bastian <bastian@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 as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ 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.
+*/
+
+#ifndef KAUTHORIZED_H
+#define KAUTHORIZED_H
+
+#include <kdecore_export.h>
+
+class KUrl;
+class QString;
+class QStringList;
+
+/**
+* Extracted from kapplication (3.x). Kiosk authorization framework
+*/
+namespace KAuthorized
+{
+ /**
+ * Returns whether a certain action is authorized
+ * @param genericAction The name of a generic action
+ * @return true if the action is authorized
+ * @todo what are the generic actions?
+ */
+ KDE_EXPORT bool authorize(const QString& genericAction);
+
+ /**
+ * Returns whether a certain KAction is authorized.
+ *
+ * @param action The name of a KAction action. The name is prepended
+ * with "action/" before being passed to authorize()
+ * @return true if the KAction is authorized
+ */
+ KDE_EXPORT bool authorizeKAction(const QString& action);
+
+ /**
+ * Returns whether a certain URL related action is authorized.
+ *
+ * @param action The name of the action. Known actions are
+ * - list (may be listed (e.g. in file selection dialog)),
+ * - link (may be linked to),
+ * - open (may open) and
+ * - redirect (may be redirected to)
+ * @param baseUrl The url where the action originates from
+ * @param destUrl The object of the action
+ * @return true when the action is authorized, false otherwise.
+ */
+ KDE_EXPORT bool authorizeUrlAction(const QString& action, const KUrl& baseUrl, const KUrl& destUrl);
+
+ /**
+ * Allow a certain URL action. This can be useful if your application
+ * needs to ensure access to an application specific directory that may
+ * otherwise be subject to KIOSK restrictions.
+ * @param action The name of the action.
+ * @param baseUrl The url where the action originates from
+ * @param _destUrl The object of the action
+ */
+ KDE_EXPORT void allowUrlAction(const QString& action, const KUrl& baseUrl, const KUrl& _destUrl);
+
+ /**
+ * Returns whether access to a certain control module is authorized.
+ *
+ * @param menuId identifying the control module, e.g. kde-mouse.desktop
+ * @return true if access to the module is authorized, false otherwise.
+ */
+ KDE_EXPORT bool authorizeControlModule(const QString& menuId);
+
+ /**
+ * Returns which control modules from a given list are authorized for access.
+ *
+ * @param menuIds list of menu-ids of control modules;
+ * an example of a menu-id is kde-mouse.desktop.
+ * @return Those control modules for which access has been authorized.
+ */
+ KDE_EXPORT QStringList authorizeControlModules(const QStringList& menuIds);
+
+}
+
+#endif
diff --git a/kdecore/kernel/kcmdlineargs.cpp b/kdecore/kernel/kcmdlineargs.cpp
new file mode 100644
index 0000000..2da636f
--- /dev/null
+++ b/kdecore/kernel/kcmdlineargs.cpp
@@ -0,0 +1,1618 @@
+/*
+ Copyright (C) 1999 Waldo Bastian <bastian@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 "kcmdlineargs.h"
+#include <kdebug.h>
+
+#include <config.h>
+
+#include <sys/param.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <locale.h>
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QHash>
+#include <QtCore/QTextCodec>
+
+#include "kaboutdata.h"
+#include "klocale.h"
+#include "kdeversion.h"
+#include "kcomponentdata.h"
+#include "kglobal.h"
+#include "kurl.h"
+
+#include "kuitsemantics_p.h" // for escaping arguments in i18n
+
+// -----------------------------------------------------------------------------
+// Design notes:
+//
+// These classes deal with a lot of text, some of which needs to be
+// marked for translation. Since at the time when these object and calls are
+// made the translation catalogs are usually still not initialized, the
+// translation has to be delayed. This is achieved by using KLocalizedString
+// for translatable strings. KLocalizedStrings are produced by ki18n* calls,
+// instead of the more usuall i18n* calls which produce QString by trying to
+// translate immediately.
+//
+// All the non-translatable string arguments to methods are taken QByteArray,
+// all the translatable are KLocalizedString. The getter methods always return
+// proper QString: the non-translatable strings supplied by the code are
+// treated with QString::fromUtf8(), those coming from the outside with
+// QTextCodec::toUnicode(), and translatable strings are finalized to QStrings
+// at the point of getter calls (i.e. delayed translation).
+//
+// The code below uses locally defined s->decodeInput(QByteArray) and
+// s->encodeOutput(QString) calls to centralize the conversion of raw external
+// bytes (instead of QString::to/fromLocal8Bit(), QFile::decodeName, etc.)
+// -----------------------------------------------------------------------------
+
+#ifdef Q_WS_X11
+#define DISPLAY "DISPLAY"
+#elif defined(Q_WS_QWS)
+#define DISPLAY "QWS_DISPLAY"
+#else
+#define DISPLAY "NODISPLAY"
+#endif
+
+//
+// Helper classes
+//
+
+class KCmdLineParsedOptions : public QHash<QByteArray,QByteArray>
+{
+public:
+ KCmdLineParsedOptions() { }
+};
+
+class KCmdLineParsedArgs : public QList<QByteArray>
+{
+public:
+ KCmdLineParsedArgs() { }
+};
+
+
+class KCmdLineArgsList: public QList<KCmdLineArgs*>
+{
+public:
+ KCmdLineArgsList() { }
+ ~KCmdLineArgsList() {
+ while (count())
+ delete takeFirst();
+ }
+};
+
+//
+// KCmdLineOptions
+//
+
+class KCmdLineOptionsPrivate {
+ public:
+ QList<QByteArray> names;
+ QList<KLocalizedString> descriptions;
+ QStringList defaults;
+};
+
+KCmdLineOptions::KCmdLineOptions ()
+: d(new KCmdLineOptionsPrivate)
+{}
+
+KCmdLineOptions::~KCmdLineOptions ()
+{
+ delete d;
+}
+
+KCmdLineOptions::KCmdLineOptions (const KCmdLineOptions &options)
+: d(new KCmdLineOptionsPrivate(*(options.d)))
+{
+}
+
+KCmdLineOptions& KCmdLineOptions::operator= (const KCmdLineOptions &options)
+{
+ if (this != &options) {
+ *d = *(options.d);
+ }
+ return *this;
+}
+
+KCmdLineOptions &KCmdLineOptions::add (const QByteArray &name,
+ const KLocalizedString &description,
+ const QByteArray &defaultValue)
+{
+ d->names.append(name);
+ d->descriptions.append(description);
+ d->defaults.append(QString::fromUtf8(defaultValue));
+ return *this;
+}
+
+KCmdLineOptions &KCmdLineOptions::add (const KCmdLineOptions &other)
+{
+ d->names += other.d->names;
+ d->descriptions += other.d->descriptions;
+ d->defaults += other.d->defaults;
+ return *this;
+}
+
+//
+// KCmdLineArgs static data and methods
+//
+
+class KCmdLineArgsStatic {
+ public:
+
+ KCmdLineArgsList *argsList; // All options.
+ const KAboutData *about;
+
+ int all_argc; // The original argc
+ char **all_argv; // The original argv
+ char *appName;
+ bool parsed : 1; // Whether we have parsed the arguments since calling init
+ bool ignoreUnknown : 1; // Ignore unknown options and arguments
+ QByteArray mCwd; // Current working directory. Important for KUnqiueApp!
+ KCmdLineArgs::StdCmdLineArgs mStdargs;
+
+ KCmdLineOptions qt_options;
+ KCmdLineOptions kde_options;
+
+ KCmdLineArgsStatic ();
+
+ ~KCmdLineArgsStatic ();
+
+ QTextCodec *codec; // codec for converting raw input to QString
+
+ /**
+ * @internal
+ * Convertes raw command line argument data to proper QString.
+ *
+ * @param rawstr raw text
+ * @return properly decoded QString
+ */
+ static QString decodeInput(const QByteArray &rawstr);
+
+ /**
+ * @internal
+ * Convertes QString to raw command line output.
+ *
+ * @param str string to be encoded
+ * @return raw text
+ */
+ static QByteArray encodeOutput(const QString &str);
+
+ /**
+ * @internal
+ * Shell output with proper decoding.
+ */
+ void printQ(const QString &msg);
+
+ /**
+ * @internal
+ * Try to match given option in the list of options.
+ * Returns match status.
+ *
+ * @return:
+ * 0 - option not found.
+ * 1 - option found // -fork
+ * 2 - inverse option found ('no') // -nofork
+ * 3 - option + arg found // -fork now
+ *
+ * +4 - no more options follow // !fork
+ */
+ static int findOption(const KCmdLineOptions &options, QByteArray &opt,
+ QByteArray &opt_name, QString &def, bool &enabled);
+
+ /**
+ * @internal
+ *
+ * Checks what to do with a single option
+ */
+ static void findOption(const QByteArray &optv, const QByteArray &_opt,
+ int &i, bool _enabled, bool &moreOptions);
+
+ /**
+ * @internal
+ *
+ * Parse all arguments, verify correct syntax and put all arguments
+ * where they belong.
+ */
+ static void parseAllArgs();
+
+ /**
+ * @internal
+ *
+ * Remove named options.
+ *
+ * @param id The name of the options to be removed.
+ */
+ static void removeArgs(const QByteArray &id);
+};
+
+K_GLOBAL_STATIC(KCmdLineArgsStatic, s)
+
+KCmdLineArgsStatic::KCmdLineArgsStatic () {
+ // Global data
+ argsList = 0;
+ all_argc = 0;
+ all_argv = 0;
+ appName = 0;
+ mCwd.clear();
+ about = 0;
+ parsed = false;
+ ignoreUnknown = false;
+ mStdargs = 0;
+
+ // Text codec.
+ codec = QTextCodec::codecForLocale();
+
+ // Qt options
+ //FIXME: Check if other options are specific to Qt/X11
+#ifdef Q_WS_X11
+ qt_options.add("display <displayname>", ki18n("Use the X-server display 'displayname'"));
+#elif defined(Q_WS_QWS)
+ qt_options.add("display <displayname>", ki18n("Use the QWS display 'displayname'"));
+#else
+#endif
+ qt_options.add("session <sessionId>", ki18n("Restore the application for the given 'sessionId'"));
+ qt_options.add("cmap", ki18n("Causes the application to install a private color\nmap on an 8-bit display"));
+ qt_options.add("ncols <count>", ki18n("Limits the number of colors allocated in the color\ncube on an 8-bit display, if the application is\nusing the QApplication::ManyColor color\nspecification"));
+ qt_options.add("nograb", ki18n("tells Qt to never grab the mouse or the keyboard"));
+ qt_options.add("dograb", ki18n("running under a debugger can cause an implicit\n-nograb, use -dograb to override"));
+ qt_options.add("sync", ki18n("switches to synchronous mode for debugging"));
+ qt_options.add("fn");
+ qt_options.add("font <fontname>", ki18n("defines the application font"));
+ qt_options.add("bg");
+ qt_options.add("background <color>", ki18n("sets the default background color and an\napplication palette (light and dark shades are\ncalculated)"));
+ qt_options.add("fg");
+ qt_options.add("foreground <color>", ki18n("sets the default foreground color"));
+ qt_options.add("btn");
+ qt_options.add("button <color>", ki18n("sets the default button color"));
+ qt_options.add("name <name>", ki18n("sets the application name"));
+ qt_options.add("title <title>", ki18n("sets the application title (caption)"));
+ qt_options.add("testability", ki18n("load the testability framework"));
+#ifdef Q_WS_X11
+ qt_options.add("visual TrueColor", ki18n("forces the application to use a TrueColor visual on\nan 8-bit display"));
+ qt_options.add("inputstyle <inputstyle>", ki18n("sets XIM (X Input Method) input style. Possible\nvalues are onthespot, overthespot, offthespot and\nroot"));
+ qt_options.add("im <XIM server>", ki18n("set XIM server"));
+ qt_options.add("noxim", ki18n("disable XIM"));
+#endif
+#ifdef Q_WS_QWS
+ qt_options.add("qws", ki18n("forces the application to run as QWS Server"));
+#endif
+ qt_options.add("reverse", ki18n("mirrors the whole layout of widgets"));
+ qt_options.add("stylesheet <file.qss>", ki18n("applies the Qt stylesheet to the application widgets"));
+ qt_options.add("graphicssystem <system>", ki18n("use a different graphics system instead of the default one, options are raster and opengl (experimental)"));
+ // KDE options
+ kde_options.add("caption <caption>", ki18n("Use 'caption' as name in the titlebar"));
+ kde_options.add("icon <icon>", ki18n("Use 'icon' as the application icon"));
+ kde_options.add("config <filename>", ki18n("Use alternative configuration file"));
+ kde_options.add("nocrashhandler", ki18n("Disable crash handler, to get core dumps"));
+#ifdef Q_WS_X11
+ kde_options.add("waitforwm", ki18n("Waits for a WM_NET compatible windowmanager"));
+#endif
+ kde_options.add("style <style>", ki18n("sets the application GUI style"));
+ kde_options.add("geometry <geometry>", ki18n("sets the client geometry of the main widget - see man X for the argument format (usually WidthxHeight+XPos+YPos)"));
+#ifndef Q_WS_WIN
+ kde_options.add("smkey <sessionKey>"); // this option is obsolete and exists only to allow smooth upgrades from sessions
+#endif
+}
+
+KCmdLineArgsStatic::~KCmdLineArgsStatic ()
+{
+ delete argsList;
+ // KAboutData object is deleted by ~KCleanUpGlobalStatic.
+ //delete about;
+}
+
+//
+// KCmdLineArgs private data and methods
+//
+
+class KCmdLineArgsPrivate
+{
+ friend class KCmdLineArgsStatic;
+public:
+ KCmdLineArgsPrivate(const KCmdLineOptions &_options, const KLocalizedString &_name, const QByteArray &_id)
+ : options(_options)
+ , name(_name)
+ , id(_id)
+ , parsedOptionList(0)
+ , parsedArgList(0)
+ , isQt(id == "qt")
+ {
+ }
+ ~KCmdLineArgsPrivate()
+ {
+ delete parsedOptionList;
+ delete parsedArgList;
+ }
+ const KCmdLineOptions options;
+ const KLocalizedString name;
+ const QByteArray id;
+ KCmdLineParsedOptions *parsedOptionList;
+ KCmdLineParsedArgs *parsedArgList;
+ bool isQt;
+
+ /**
+ * @internal
+ *
+ * Set a boolean option
+ */
+ void setOption(const QByteArray &option, bool enabled);
+
+ /**
+ * @internal
+ *
+ * Set a string option
+ */
+ void setOption(const QByteArray &option, const QByteArray &value);
+
+ /**
+ * @internal
+ *
+ * Add an argument
+ */
+ void addArgument(const QByteArray &argument);
+
+ /**
+ * @internal
+ *
+ * Save to a stream.
+ */
+ void save( QDataStream &) const;
+
+ /**
+ * @internal
+ *
+ * Restore from a stream.
+ */
+ void load( QDataStream &);
+};
+
+//
+// Static functions
+//
+
+QString
+KCmdLineArgsStatic::decodeInput(const QByteArray &rawstr)
+{
+ return s->codec->toUnicode(rawstr);
+}
+
+QByteArray
+KCmdLineArgsStatic::encodeOutput(const QString &str)
+{
+ return s->codec->fromUnicode(str);
+}
+
+void
+KCmdLineArgsStatic::printQ(const QString &msg)
+{
+ fprintf(stdout, "%s", encodeOutput(msg).data());
+}
+
+void
+KCmdLineArgs::init(int _argc, char **_argv,
+ const QByteArray &_appname,
+ const QByteArray &_catalog,
+ const KLocalizedString &_programName,
+ const QByteArray &_version,
+ const KLocalizedString &_description,
+ StdCmdLineArgs stdargs)
+{
+ init(_argc, _argv,
+ new KAboutData(_appname, _catalog, _programName, _version, _description),
+ stdargs);
+}
+
+void
+KCmdLineArgs::initIgnore(int _argc, char **_argv, const QByteArray &_appname )
+{
+ init(_argc, _argv,
+ new KAboutData(_appname, 0, ki18n(_appname), "unknown", ki18n("KDE Application")));
+ s->ignoreUnknown = true;
+}
+
+void
+KCmdLineArgs::init(const KAboutData* ab)
+{
+ char **_argv = (char **) malloc(sizeof(char *));
+ _argv[0] = (char *) s->encodeOutput(ab->appName()).data();
+ init(1,_argv,ab, CmdLineArgNone);
+}
+
+
+void
+KCmdLineArgs::init(int _argc, char **_argv, const KAboutData *_about, StdCmdLineArgs stdargs)
+{
+ s->all_argc = _argc;
+ s->all_argv = _argv;
+
+ if (!s->all_argv)
+ {
+ fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
+ fprintf(stderr, "Passing null-pointer to 'argv' is not allowed.\n\n");
+
+ assert( 0 );
+ exit(255);
+ }
+
+ // Strip path from argv[0]
+ if (s->all_argc) {
+ char *p = strrchr(s->all_argv[0], QDir::separator().toAscii());
+ if (p)
+ s->appName = p+1;
+ else
+ s->appName = s->all_argv[0];
+ }
+
+ s->about = _about;
+ s->parsed = false;
+ s->mCwd = QDir::currentPath().toLocal8Bit(); //currentPath() uses fromLocal8Bit internally apparently
+ addStdCmdLineOptions(stdargs);
+}
+
+QString KCmdLineArgs::cwd()
+{
+ return QString::fromLocal8Bit(s->mCwd);
+}
+
+QString KCmdLineArgs::appName()
+{
+ if (!s->appName) return QString();
+ return s->decodeInput(s->appName);
+}
+
+/**
+ * Add Qt and KDE command line options to KCmdLineArgs.
+ */
+void KCmdLineArgs::addStdCmdLineOptions(StdCmdLineArgs stdargs) {
+ if (stdargs & KCmdLineArgs::CmdLineArgQt) {
+ KCmdLineArgs::addCmdLineOptions(s->qt_options, ki18n("Qt"), "qt");
+ }
+ if (stdargs & KCmdLineArgs::CmdLineArgKDE) {
+ KCmdLineArgs::addCmdLineOptions(s->kde_options, ki18n("KDE"), "kde");
+ }
+ s->mStdargs = stdargs;
+}
+
+void
+KCmdLineArgs::addCmdLineOptions( const KCmdLineOptions &options, const KLocalizedString &name,
+ const QByteArray &id, const QByteArray &afterId)
+{
+ if (!s->argsList)
+ s->argsList = new KCmdLineArgsList;
+
+ int pos = s->argsList->count();
+ // To make sure that the named options come before unnamed.
+ if (pos > 0 && !id.isEmpty() && s->argsList->last()->d->name.isEmpty())
+ pos--;
+
+ KCmdLineArgsList::Iterator args;
+ int i = 0;
+ for(args = s->argsList->begin(); args != s->argsList->end(); ++args, i++)
+ {
+ if (id == (*args)->d->id) {
+ return; // Options already present.
+ }
+
+ // Only check for afterId if it has been given non-empty, as the
+ // unnamed option group should come after all named groups.
+ if (!afterId.isEmpty() && afterId == (*args)->d->id)
+ pos = i+1;
+ }
+
+ Q_ASSERT( s->parsed == false ); // You must add _ALL_ cmd line options
+ // before accessing the arguments!
+ s->argsList->insert(pos, new KCmdLineArgs(options, name, id));
+}
+
+void
+KCmdLineArgs::saveAppArgs( QDataStream &ds)
+{
+ if (!s->parsed)
+ s->parseAllArgs();
+
+ // Remove Qt and KDE options.
+ s->removeArgs("qt");
+ s->removeArgs("kde");
+ s->removeArgs("kuniqueapp");
+
+ ds << s->mCwd;
+
+ uint count = s->argsList ? s->argsList->count() : 0;
+ ds << count;
+
+ if (!count) return;
+
+ KCmdLineArgsList::Iterator args;
+ for(args = s->argsList->begin(); args != s->argsList->end(); ++args)
+ {
+ ds << (*args)->d->id;
+ (*args)->d->save(ds);
+ }
+}
+
+void
+KCmdLineArgs::loadAppArgs( QDataStream &ds)
+{
+ s->parsed = true; // don't reparse argc/argv!
+
+ // Remove Qt and KDE options.
+ s->removeArgs("qt");
+ s->removeArgs("kde");
+ s->removeArgs("kuniqueapp");
+
+ KCmdLineArgsList::Iterator args;
+ if ( s->argsList ) {
+ for(args = s->argsList->begin(); args != s->argsList->end(); ++args)
+ {
+ (*args)->clear();
+ }
+ }
+
+ if (ds.atEnd())
+ return;
+
+ QByteArray qCwd;
+ ds >> qCwd;
+
+ s->mCwd = qCwd;
+
+ uint count;
+ ds >> count;
+
+ while(count--)
+ {
+ QByteArray id;
+ ds >> id;
+ Q_ASSERT( s->argsList );
+ bool found = false;
+ for(args = s->argsList->begin(); args != s->argsList->end(); ++args)
+ {
+ if ((*args)->d->id == id)
+ {
+ (*args)->d->load(ds);
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ kWarning() << "Argument definitions for" << id << "not found!";
+ // The next ds >> id will do nonsensical things...
+ }
+ }
+ s->parsed = true;
+}
+
+KCmdLineArgs *KCmdLineArgs::parsedArgs(const QByteArray &id)
+{
+ if (!s->argsList)
+ return 0;
+ KCmdLineArgsList::Iterator args = s->argsList->begin();
+ while(args != s->argsList->end())
+ {
+ if ((*args)->d->id == id)
+ {
+ if (!s->parsed)
+ s->parseAllArgs();
+ return *args;
+ }
+ ++args;
+ }
+
+ return 0;
+}
+
+void KCmdLineArgsStatic::removeArgs(const QByteArray &id)
+{
+ if (!s->argsList)
+ return;
+ KCmdLineArgsList::Iterator args = s->argsList->begin();
+ while(args != s->argsList->end())
+ {
+ if ((*args)->d->id == id)
+ {
+ if (!s->parsed)
+ s->parseAllArgs();
+ break;
+ }
+ ++args;
+ }
+
+ if (args != s->argsList->end()) {
+ KCmdLineArgs *a = *args;
+ s->argsList->erase(args);
+ delete a;
+ }
+}
+
+int
+KCmdLineArgsStatic::findOption(const KCmdLineOptions &options, QByteArray &opt,
+ QByteArray &opt_name, QString &def, bool &enabled)
+{
+ int result;
+ bool inverse;
+
+ for (int i = 0; i < options.d->names.size(); i++)
+ {
+ result = 0;
+ inverse = false;
+ opt_name = options.d->names[i];
+ if (opt_name.startsWith(':') || opt_name.isEmpty())
+ {
+ continue;
+ }
+ if (opt_name.startsWith('!'))
+ {
+ opt_name = opt_name.mid(1);
+ result = 4;
+ }
+ if (opt_name.startsWith("no") && !opt_name.contains('<')) // krazy:exclude=strings
+ {
+ opt_name = opt_name.mid(2);
+ inverse = true;
+ }
+
+ int len = opt.length();
+ if (opt == opt_name.left(len))
+ {
+ opt_name = opt_name.mid(len);
+ if (opt_name.isEmpty())
+ {
+ if (inverse)
+ return result+2;
+
+ if (options.d->descriptions[i].isEmpty())
+ {
+ i++;
+ if (i >= options.d->names.size())
+ return result+0;
+ QByteArray nextOption = options.d->names[i];
+ int p = nextOption.indexOf(' ');
+ if (p > 0)
+ nextOption = nextOption.left(p);
+ if (nextOption.startsWith('!'))
+ nextOption = nextOption.mid(1);
+ if (nextOption.startsWith("no") && !nextOption.contains('<')) // krazy:exclude=strings
+ {
+ nextOption = nextOption.mid(2);
+ enabled = !enabled;
+ }
+ result = findOption(options, nextOption, opt_name, def, enabled);
+ Q_ASSERT(result);
+ opt = nextOption;
+ return result;
+ }
+
+ return 1;
+ }
+ if (opt_name.startsWith(' '))
+ {
+ opt_name = opt_name.mid(1);
+ def = options.d->defaults[i];
+ return result+3;
+ }
+ }
+ }
+ return 0;
+}
+
+void
+KCmdLineArgsStatic::findOption(const QByteArray &optv, const QByteArray &_opt,
+ int &i, bool _enabled, bool &moreOptions)
+{
+ KCmdLineArgsList::Iterator args = s->argsList->begin();
+ QByteArray opt = _opt;
+ QByteArray opt_name;
+ QString def;
+ QByteArray argument;
+ int j = opt.indexOf('=');
+ if (j != -1)
+ {
+ argument = opt.mid(j+1);
+ opt = opt.left(j);
+ }
+
+ bool enabled = true;
+ int result = 0;
+ while (args != s->argsList->end())
+ {
+ enabled = _enabled;
+ result = findOption((*args)->d->options, opt, opt_name, def, enabled);
+ if (result) break;
+ ++args;
+ }
+ if ((args == s->argsList->end()) &&
+ (optv.startsWith('-') && !optv.startsWith("--"))) // krazy:exclude=strings
+ {
+ // Option not found check if it is a valid option
+ // in the style of -Pprinter1 or ps -aux
+ int p = 1;
+ while (true)
+ {
+ QByteArray singleCharOption = " "; // krazy:exclude=doublequote_chars
+ singleCharOption[0] = optv[p];
+ args = s->argsList->begin();
+ while (args != s->argsList->end())
+ {
+ enabled = _enabled;
+ result = findOption((*args)->d->options, singleCharOption,
+ opt_name, def, enabled);
+ if (result) break;
+ ++args;
+ }
+ if (args == s->argsList->end())
+ break; // Unknown argument
+
+ p++;
+ if (result == 1) // Single option
+ {
+ (*args)->d->setOption(singleCharOption, enabled);
+ if (p < optv.length())
+ continue; // Next option
+ else
+ return; // Finished
+ }
+ else if (result == 3) // This option takes an argument
+ {
+ if (argument.isEmpty())
+ {
+ argument = optv.mid(p);
+ }
+ (*args)->d->setOption(singleCharOption, argument);
+ return;
+ }
+ break; // Unknown argument
+ }
+ args = s->argsList->end();
+ result = 0;
+ }
+
+ if (args == s->argsList->end() || !result)
+ {
+ if (s->ignoreUnknown)
+ return;
+ KCmdLineArgs::enable_i18n();
+ KCmdLineArgs::usageError( i18n("Unknown option '%1'.", QString::fromLocal8Bit(_opt)));
+ }
+
+ if ((result & 4) != 0)
+ {
+ result &= ~4;
+ moreOptions = false;
+ }
+
+ if (result == 3) // This option takes an argument
+ {
+ if (!enabled)
+ {
+ if (s->ignoreUnknown)
+ return;
+ KCmdLineArgs::enable_i18n();
+ KCmdLineArgs::usageError( i18n("Unknown option '%1'.", QString::fromLocal8Bit(_opt)));
+ }
+ if (argument.isEmpty())
+ {
+ i++;
+ if (i >= s->all_argc)
+ {
+ KCmdLineArgs::enable_i18n();
+ KCmdLineArgs::usageError( i18nc("@info:shell %1 is cmdoption name","'%1' missing.", QString::fromLocal8Bit(opt_name)));
+ }
+ argument = s->all_argv[i];
+ }
+ (*args)->d->setOption(opt, argument);
+ }
+ else
+ {
+ (*args)->d->setOption(opt, enabled);
+ }
+}
+
+void
+KCmdLineArgsStatic::parseAllArgs()
+{
+ bool allowArgs = false;
+ bool inOptions = true;
+ bool everythingAfterArgIsArgs = false;
+ KCmdLineArgs *appOptions = s->argsList->last();
+ if (appOptions->d->id.isEmpty())
+ {
+ foreach(const QByteArray& name, appOptions->d->options.d->names)
+ {
+ everythingAfterArgIsArgs = everythingAfterArgIsArgs || name.startsWith("!+");
+ allowArgs = allowArgs || name.startsWith('+') || everythingAfterArgIsArgs;
+ }
+ }
+ for(int i = 1; i < s->all_argc; i++)
+ {
+ if (!s->all_argv[i])
+ continue;
+
+ if ((s->all_argv[i][0] == '-') && s->all_argv[i][1] && inOptions)
+ {
+ bool enabled = true;
+ QByteArray orig = s->all_argv[i];
+ QByteArray option = orig.mid(1);
+ if (option.startsWith('-'))
+ {
+ option = option.mid(1);
+ if (option.isEmpty())
+ {
+ inOptions = false;
+ continue;
+ }
+ }
+ if (option == "help")
+ {
+ KCmdLineArgs::usage();
+ }
+ else if (option.startsWith("help-")) // krazy:exclude=strings
+ {
+ KCmdLineArgs::usage(option.mid(5));
+ }
+#ifdef Q_WS_MAC
+ // skip the finder -psn_* hint
+ else if (option.startsWith("psn_")) // krazy:exclude=strings
+ {
+ continue;
+ }
+#endif
+ else if ((option == "version") || (option == "v"))
+ {
+ KCmdLineArgs::enable_i18n();
+ s->printQ(i18nc("@info:shell message on appcmd --version; do not translate 'Development Platform'"
+ "%3 application name, other %n version strings",
+ "Qt: %1\n"
+ "KDE Development Platform: %2\n"
+ "%3: %4\n",
+ QString::fromLatin1(qVersion()),
+ QString::fromLatin1(KDE_VERSION_STRING),
+ s->about->programName(), s->about->version()));
+ exit(0);
+ } else if (option == "license")
+ {
+ KCmdLineArgs::enable_i18n();
+ s->printQ(s->about->license());
+ s->printQ(QString::fromLatin1("\n"));
+ exit(0);
+ } else if (option == "author") {
+ KCmdLineArgs::enable_i18n();
+ if ( s->about ) {
+ const QList<KAboutPerson> authors = s->about->authors();
+ if ( !authors.isEmpty() ) {
+ QString authorlist;
+ for (QList<KAboutPerson>::ConstIterator it = authors.begin(); it != authors.end(); ++it ) {
+ QString email;
+ if ( !(*it).emailAddress().isEmpty() )
+ email = QString::fromLatin1(" &lt;") + (*it).emailAddress() + QLatin1String("&gt;");
+ authorlist += QString::fromLatin1(" ") + (*it).name() + email + QLatin1Char('\n');
+ }
+ s->printQ( i18nc("the 2nd argument is a list of name+address, one on each line","%1 was written by\n%2", QString(s->about->programName()) , authorlist ) );
+ }
+ } else {
+ s->printQ( i18n("This application was written by somebody who wants to remain anonymous.") );
+ }
+ if (s->about)
+ {
+ if (!s->about->customAuthorTextEnabled ())
+ {
+ if (s->about->bugAddress().isEmpty() || s->about->bugAddress() == QLatin1String("submit@bugs.kde.org") )
+ s->printQ( i18n( "Please use http://bugs.kde.org to report bugs.\n" ) );
+ else
+ s->printQ( i18n( "Please report bugs to %1.\n" , s->about->bugAddress()) );
+ }
+ else
+ {
+ s->printQ(s->about->customAuthorPlainText()+QLatin1Char('\n'));
+ }
+ }
+ exit(0);
+ } else {
+ if (option.startsWith("no")) // krazy:exclude=strings
+ {
+ bool noHasParameter=false;
+ foreach(const QByteArray& name, appOptions->d->options.d->names)
+ {
+ if (name.contains(option + QByteArray(" ")) && name.contains('<'))
+ {
+ noHasParameter=true;
+ break;
+ }
+ }
+ if (!noHasParameter)
+ {
+ option = option.mid(2);
+ enabled = false;
+ }
+ }
+ s->findOption(orig, option, i, enabled, inOptions);
+ }
+ }
+ else
+ {
+ // Check whether appOptions allows these arguments
+ if (!allowArgs)
+ {
+ if (s->ignoreUnknown)
+ continue;
+ KCmdLineArgs::enable_i18n();
+ KCmdLineArgs::usageError(i18n("Unexpected argument '%1'.", KuitSemantics::escape(s->decodeInput(s->all_argv[i]))));
+ }
+ else
+ {
+ appOptions->d->addArgument(s->all_argv[i]);
+ if (everythingAfterArgIsArgs)
+ inOptions = false;
+ }
+ }
+ }
+ s->parsed = true;
+}
+
+int & KCmdLineArgs::qtArgc()
+{
+ if (!s->argsList)
+ addStdCmdLineOptions(CmdLineArgKDE|CmdLineArgQt); // Lazy bastards!
+
+ static int qt_argc = -1;
+ if( qt_argc != -1 )
+ return qt_argc;
+
+ if (!(s->mStdargs & KCmdLineArgs::CmdLineArgQt))
+ {
+ qt_argc = 2;
+ return qt_argc;
+ }
+
+ KCmdLineArgs *args = parsedArgs("qt");
+ Q_ASSERT(args); // No qt options have been added!
+ if (!s->all_argv)
+ {
+ fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
+ fprintf(stderr, "Application has not called KCmdLineArgs::init(...).\n\n");
+
+ assert( 0 );
+ exit(255);
+ }
+
+ Q_ASSERT(s->all_argc >= (args->count()+1));
+ qt_argc = args->count() +1;
+ return qt_argc;
+}
+
+static char** s_qt_argv;
+
+char **
+KCmdLineArgs::qtArgv()
+{
+ if (!s->argsList)
+ addStdCmdLineOptions(CmdLineArgKDE|CmdLineArgQt); // Lazy bastards!
+
+ if( s_qt_argv != NULL )
+ return s_qt_argv;
+
+ if (!(s->mStdargs & KCmdLineArgs::CmdLineArgQt))
+ {
+ s_qt_argv = new char*[2];
+ s_qt_argv[0] = qstrdup(s->all_argc?s->all_argv[0]:"");
+ s_qt_argv[1] = 0;
+
+ return s_qt_argv;
+ }
+
+ KCmdLineArgs *args = parsedArgs("qt");
+ if (!args)
+ {
+ fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
+ fprintf(stderr, "The \"qt\" options have not be added to KCmdLineArgs!\n\n");
+
+ assert( 0 );
+ exit(255);
+ }
+ if (!s->all_argv)
+ {
+ fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
+ fprintf(stderr, "Application has not called KCmdLineArgs::init(...).\n\n");
+
+ assert( 0 );
+ exit(255);
+ }
+
+ int count=args->count();
+ s_qt_argv = new char*[ count + 2 ];
+ s_qt_argv[0] = qstrdup(s->all_argc?s->all_argv[0]:"");
+ int i = 0;
+ for(; i < count; i++)
+ {
+ s_qt_argv[i+1] = qstrdup(args->d->parsedArgList->at(i));
+ }
+ s_qt_argv[i+1] = 0;
+
+ return s_qt_argv;
+}
+
+const KAboutData *
+KCmdLineArgs::aboutData()
+{
+ return s->about;
+}
+
+void
+KCmdLineArgs::enable_i18n()
+{
+ // called twice or too late
+ if (KGlobal::hasLocale())
+ return;
+
+ if (!KGlobal::hasMainComponent()) {
+ KComponentData mainComponentData(s->about);
+ mainComponentData.config();
+ // mainComponentData is now the main component and won't disappear until KGlobal deletes it
+ }
+}
+
+void
+KCmdLineArgs::usageError(const QString &error)
+{
+ Q_ASSERT(KGlobal::hasLocale());
+ QByteArray localError = s->encodeOutput(error);
+ if (localError.endsWith('\n'))
+ localError.chop(1);
+ fprintf(stderr, "%s: %s\n", s->appName, localError.data());
+
+ QString tmp = i18n("Use --help to get a list of available command line options.");
+ localError = s->encodeOutput(tmp);
+ fprintf(stderr, "%s: %s\n", s->appName, localError.data());
+ exit(254);
+}
+
+void
+KCmdLineArgs::usage(const QByteArray &id)
+{
+ enable_i18n();
+ Q_ASSERT(s->argsList != 0); // It's an error to call usage(...) without
+ // having done addCmdLineOptions first!
+
+ QString optionFormatString = QString::fromLatin1(" %1 %2\n");
+ QString optionFormatStringDef = QString::fromLatin1(" %1 %2 [%3]\n");
+ QString tmp;
+ QString usage;
+
+ KCmdLineArgsList::Iterator args = --(s->argsList->end());
+
+ if ((*args)->d->id.isEmpty() && ((*args)->d->options.d->names.size() > 0) &&
+ !(*args)->d->options.d->names[0].startsWith('+'))
+ {
+ usage = i18n("[options] ")+usage;
+ }
+
+ while(true)
+ {
+ if (!(*args)->d->name.isEmpty())
+ {
+ usage = i18n("[%1-options]", (*args)->d->name.toString())+QLatin1Char(' ')+usage;
+ }
+ if (args == s->argsList->begin())
+ break;
+ --args;
+ }
+
+ KCmdLineArgs *appOptions = s->argsList->last();
+ if (appOptions->d->id.isEmpty())
+ {
+ const KCmdLineOptions &option = appOptions->d->options;
+ for (int i = 0; i < option.d->names.size(); i++)
+ {
+ QByteArray opt_name = option.d->names[i];
+ if (opt_name.startsWith('+'))
+ usage += QString::fromLatin1(opt_name.mid(1)) + QLatin1Char(' ');
+ else if ( opt_name.startsWith("!+") )
+ usage += QString::fromLatin1(opt_name.mid(2)) + QLatin1Char(' ');
+ }
+ }
+
+ s->printQ(i18n("Usage: %1 %2\n", QString::fromLocal8Bit(s->appName), KuitSemantics::escape(usage)));
+ s->printQ(QLatin1Char('\n')+s->about->shortDescription()+QLatin1Char('\n'));
+
+ s->printQ(i18n("\nGeneric options:\n"));
+ s->printQ(optionFormatString.arg(QString::fromLatin1("--help"), -25)
+ .arg(i18n("Show help about options")));
+
+ args = s->argsList->begin();
+ while(args != s->argsList->end())
+ {
+ if (!(*args)->d->name.isEmpty() && !(*args)->d->id.isEmpty())
+ {
+ QString option = QString::fromLatin1("--help-%1").arg(QString::fromLatin1((*args)->d->id));
+ QString desc = i18n("Show %1 specific options", (*args)->d->name.toString());
+
+ s->printQ(optionFormatString.arg(option, -25).arg(desc));
+ }
+ ++args;
+ }
+
+ s->printQ(optionFormatString.arg(QString::fromLatin1("--help-all"),-25).arg(i18n("Show all options")));
+ s->printQ(optionFormatString.arg(QString::fromLatin1("--author"),-25).arg(i18n("Show author information")));
+ s->printQ(optionFormatString.arg(QString::fromLatin1("-v, --version"),-25).arg(i18n("Show version information")));
+ s->printQ(optionFormatString.arg(QString::fromLatin1("--license"),-25).arg(i18n("Show license information")));
+ s->printQ(optionFormatString.arg(QString::fromLatin1("--"), -25).arg(i18n("End of options")));
+
+ args = s->argsList->begin(); // Sets current to 1st.
+
+ bool showAll = (id == "all");
+
+ if (!showAll)
+ {
+ while(args != s->argsList->end())
+ {
+ if (id == (*args)->d->id) break;
+ ++args;
+ }
+ }
+
+ while(args != s->argsList->end())
+ {
+ bool hasArgs = false;
+ bool hasOptions = false;
+ QString optionsHeader;
+ if (!(*args)->d->name.isEmpty())
+ optionsHeader = i18n("\n%1 options:\n", (*args)->d->name.toString());
+ else
+ optionsHeader = i18n("\nOptions:\n");
+
+ while (args != s->argsList->end())
+ {
+ const KCmdLineOptions &option = (*args)->d->options;
+ QByteArray opt;
+
+ for (int i = 0; i < option.d->names.size(); i++)
+ {
+ QString description;
+ QStringList dl;
+
+ QString descriptionFull;
+ if (!option.d->descriptions[i].isEmpty()) {
+ descriptionFull = option.d->descriptions[i].toString();
+ }
+
+ // Option header
+ if (option.d->names[i].startsWith(':'))
+ {
+ if (!descriptionFull.isEmpty())
+ {
+ optionsHeader = QLatin1Char('\n')+descriptionFull;
+ if (!optionsHeader.endsWith(QLatin1Char('\n')))
+ optionsHeader.append(QLatin1Char('\n'));
+ hasOptions = false;
+ }
+ continue;
+ }
+
+ // Free-form comment
+ if (option.d->names[i].isEmpty())
+ {
+ if (!descriptionFull.isEmpty())
+ {
+ tmp = QLatin1Char('\n')+descriptionFull;
+ if (!tmp.endsWith(QLatin1Char('\n')))
+ tmp.append(QLatin1Char('\n'));
+ s->printQ(tmp);
+ }
+ continue;
+ }
+
+ // Options
+ if (!descriptionFull.isEmpty())
+ {
+ dl = descriptionFull.split(QLatin1Char('\n'), QString::KeepEmptyParts);
+ description = dl.first();
+ dl.erase( dl.begin() );
+ }
+ QByteArray name = option.d->names[i];
+ if (name.startsWith('!'))
+ name = name.mid(1);
+
+ if (name.startsWith('+'))
+ {
+ if (!hasArgs)
+ {
+ s->printQ(i18n("\nArguments:\n"));
+ hasArgs = true;
+ }
+
+ name = name.mid(1);
+ if (name.startsWith('[') && name.endsWith(']'))
+ name = name.mid(1, name.length()-2);
+ s->printQ(optionFormatString.arg(QString::fromLocal8Bit(name), -25).arg(description));
+ }
+ else
+ {
+ if (!hasOptions)
+ {
+ s->printQ(optionsHeader);
+ hasOptions = true;
+ }
+
+ if ((name.length() == 1) || (name[1] == ' '))
+ name = '-'+name;
+ else
+ name = "--"+name;
+ if (descriptionFull.isEmpty())
+ {
+ opt = name + ", ";
+ }
+ else
+ {
+ opt = opt + name;
+ if (option.d->defaults[i].isEmpty())
+ {
+ s->printQ(optionFormatString.arg(QString::fromLatin1(opt), -25).arg(description));
+ }
+ else
+ {
+ s->printQ(optionFormatStringDef.arg(QString::fromLatin1(opt), -25)
+ .arg(description, option.d->defaults[i]));
+ }
+ opt.clear();
+ }
+ }
+ for(QStringList::Iterator it = dl.begin();
+ it != dl.end();
+ ++it)
+ {
+ s->printQ(optionFormatString.arg(QString(), -25).arg(*it));
+ }
+ }
+
+ ++args;
+ if (args == s->argsList->end() || !(*args)->d->name.isEmpty() || (*args)->d->id.isEmpty())
+ break;
+ }
+ if (!showAll) break;
+ }
+
+ exit(0);
+}
+
+//
+// Member functions
+//
+
+/**
+ * Constructor.
+ *
+ * The given arguments are assumed to be constants.
+ */
+KCmdLineArgs::KCmdLineArgs( const KCmdLineOptions &_options,
+ const KLocalizedString &_name,
+ const QByteArray &_id)
+ : d(new KCmdLineArgsPrivate(_options, _name, _id))
+{
+}
+
+/**
+ * Destructor.
+ */
+KCmdLineArgs::~KCmdLineArgs()
+{
+ if (!s.isDestroyed() && s->argsList)
+ s->argsList->removeAll(this);
+ delete d;
+}
+
+void
+KCmdLineArgs::setCwd( const QByteArray &cwd )
+{
+ s->mCwd = cwd;
+}
+
+void
+KCmdLineArgs::clear()
+{
+ delete d->parsedArgList; d->parsedArgList = 0;
+ delete d->parsedOptionList; d->parsedOptionList = 0;
+}
+
+void
+KCmdLineArgs::reset()
+{
+ delete s->argsList; s->argsList = 0;
+ s->parsed = false;
+}
+
+void
+KCmdLineArgsPrivate::save( QDataStream &ds) const
+{
+ if (parsedOptionList)
+ ds << (*(parsedOptionList));
+ else
+ ds << quint32(0);
+
+ if (parsedArgList)
+ ds << (*(parsedArgList));
+ else
+ ds << quint32(0);
+}
+
+void
+KCmdLineArgsPrivate::load( QDataStream &ds)
+{
+ if (!parsedOptionList) parsedOptionList = new KCmdLineParsedOptions;
+ if (!parsedArgList) parsedArgList = new KCmdLineParsedArgs;
+
+ ds >> (*(parsedOptionList));
+ ds >> (*(parsedArgList));
+
+ if (parsedOptionList->count() == 0)
+ {
+ delete parsedOptionList; parsedOptionList = 0;
+ }
+ if (parsedArgList->count() == 0)
+ {
+ delete parsedArgList; parsedArgList = 0;
+ }
+}
+
+void
+KCmdLineArgsPrivate::setOption(const QByteArray &opt, bool enabled)
+{
+ if (isQt)
+ {
+ // Qt does it own parsing.
+ QByteArray argString = "-"; // krazy:exclude=doublequote_chars
+ if( !enabled )
+ argString += "no";
+ argString += opt;
+ addArgument(argString);
+ }
+ if (!parsedOptionList) {
+ parsedOptionList = new KCmdLineParsedOptions;
+ }
+
+ if (enabled)
+ parsedOptionList->insert( opt, "t" ); // krazy:exclude=doublequote_chars
+ else
+ parsedOptionList->insert( opt, "f" ); // krazy:exclude=doublequote_chars
+}
+
+void
+KCmdLineArgsPrivate::setOption(const QByteArray &opt, const QByteArray &value)
+{
+ if (isQt)
+ {
+ // Qt does it's own parsing.
+ QByteArray argString = "-"; // krazy:exclude=doublequote_chars
+ argString += opt;
+ addArgument(argString);
+ addArgument(value);
+
+#if defined(Q_WS_X11) || defined(Q_WS_QWS)
+ // Hack coming up!
+ if (argString == "-display")
+ {
+ setenv(DISPLAY, value.data(), true);
+ }
+#endif
+ }
+ if (!parsedOptionList) {
+ parsedOptionList = new KCmdLineParsedOptions;
+ }
+
+ parsedOptionList->insertMulti( opt, value );
+}
+
+QString
+KCmdLineArgs::getOption(const QByteArray &_opt) const
+{
+ QByteArray opt = _opt;
+ QByteArray value;
+ if (d->parsedOptionList)
+ {
+ value = d->parsedOptionList->value(opt);
+ }
+ if (!value.isEmpty())
+ return QString::fromLocal8Bit(value);
+
+ // Look up the default.
+ QByteArray opt_name;
+ QString def;
+ bool dummy = true;
+ int result = s->findOption( d->options, opt, opt_name, def, dummy) & ~4;
+
+ if (result != 3)
+ {
+ fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
+ fprintf(stderr, "Application requests for getOption(\"%s\") but the \"%s\" option\n",
+ opt.data(), opt.data());
+ fprintf(stderr, "has never been specified via addCmdLineOptions( ... )\n\n");
+
+ Q_ASSERT( 0 );
+ exit(255);
+ }
+ return def;
+}
+
+QStringList
+KCmdLineArgs::getOptionList(const QByteArray &opt) const
+{
+ QStringList result;
+ if (!d->parsedOptionList)
+ return result;
+
+ while(true)
+ {
+ QByteArray value = d->parsedOptionList->take(opt);
+ if (value.isEmpty())
+ break;
+ result.prepend(QString::fromLocal8Bit(value));
+ }
+
+ // Reinsert items in dictionary
+ // WABA: This is rather silly, but I don't want to add restrictions
+ // to the API like "you can only call this function once".
+ // I can't access all items without taking them out of the list.
+ // So taking them out and then putting them back is the only way.
+ Q_FOREACH(const QString &str, result)
+ {
+ d->parsedOptionList->insertMulti(opt, str.toLocal8Bit());
+ }
+ return result;
+}
+
+bool
+KCmdLineArgs::isSet(const QByteArray &_opt) const
+{
+ // Look up the default.
+ QByteArray opt = _opt;
+ QByteArray opt_name;
+ QString def;
+ int result = 0;
+ KCmdLineArgsList::Iterator args = s->argsList->begin();
+ while (args != s->argsList->end())
+ {
+ bool dummy = true;
+ result = s->findOption((*args)->d->options, opt, opt_name, def, dummy) & ~4;
+ if (result) break;
+ ++args;
+ }
+
+ if (result == 0)
+ {
+ fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
+ fprintf(stderr, "Application requests for isSet(\"%s\") but the \"%s\" option\n",
+ opt.data(), opt.data());
+ fprintf(stderr, "has never been specified via addCmdLineOptions( ... )\n\n");
+
+ Q_ASSERT( 0 );
+ exit(255);
+ }
+
+ QByteArray value;
+ if (d->parsedOptionList)
+ {
+ value = d->parsedOptionList->value(opt);
+ }
+
+ if (!value.isEmpty())
+ {
+ if (result == 3)
+ return true;
+ else
+ return (value.at(0) == 't');
+ }
+
+ if (result == 3)
+ return false; // String option has 'false' as default.
+
+ // We return 'true' as default if the option was listed as '-nofork'
+ // We return 'false' as default if the option was listed as '-fork'
+ return (result == 2);
+}
+
+int
+KCmdLineArgs::count() const
+{
+ return d->parsedArgList?d->parsedArgList->count():0;
+}
+
+QString
+KCmdLineArgs::arg(int n) const
+{
+ if (!d->parsedArgList || (n >= (int) d->parsedArgList->count()))
+ {
+ fprintf(stderr, "\n\nFAILURE (KCmdLineArgs): Argument out of bounds\n");
+ fprintf(stderr, "Application requests for arg(%d) without checking count() first.\n",
+ n);
+
+ Q_ASSERT( 0 );
+ exit(255);
+ }
+
+ return QString::fromLocal8Bit(d->parsedArgList->at(n));
+}
+
+KUrl
+KCmdLineArgs::url(int n) const
+{
+ return makeURL( arg(n).toUtf8() );
+}
+
+KUrl KCmdLineArgs::makeURL(const QByteArray &_urlArg)
+{
+ const QString urlArg = QString::fromUtf8(_urlArg);
+ QFileInfo fileInfo(urlArg);
+ if (!fileInfo.isRelative()) { // i.e. starts with '/', on unix
+ KUrl result;
+ result.setPath(QDir::fromNativeSeparators(urlArg));
+ return result; // Absolute path.
+ }
+
+ if ( KUrl::isRelativeUrl(urlArg) || fileInfo.exists() ) {
+ KUrl result;
+ result.setPath(cwd()+QLatin1Char('/')+urlArg);
+ result.cleanPath();
+ return result; // Relative path
+ }
+
+ return KUrl(urlArg); // Argument is a URL
+}
+
+void
+KCmdLineArgsPrivate::addArgument(const QByteArray &argument)
+{
+ if (!parsedArgList)
+ parsedArgList = new KCmdLineParsedArgs;
+
+ parsedArgList->append(argument);
+}
+
+void
+KCmdLineArgs::addTempFileOption()
+{
+ KCmdLineOptions tmpopt;
+ tmpopt.add( "tempfile", ki18n("The files/URLs opened by the application will be deleted after use") );
+ KCmdLineArgs::addCmdLineOptions( tmpopt, ki18n("KDE-tempfile"), "kde-tempfile" );
+}
+
+bool KCmdLineArgs::isTempFileSet()
+{
+ KCmdLineArgs* args = KCmdLineArgs::parsedArgs( "kde-tempfile" );
+ return args && args->isSet( "tempfile" );
+}
+
+QStringList KCmdLineArgs::allArguments()
+{
+ QStringList lst;
+
+ for(int i = 0; i < s->all_argc; i++) {
+ char* arg = s->all_argv[i];
+ if (!arg)
+ continue;
+ lst.append(QString::fromLocal8Bit(arg));
+ }
+ return lst;
+}
diff --git a/kdecore/kernel/kcmdlineargs.h b/kdecore/kernel/kcmdlineargs.h
new file mode 100644
index 0000000..24a3769
--- /dev/null
+++ b/kdecore/kernel/kcmdlineargs.h
@@ -0,0 +1,692 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 Waldo Bastian <bastian@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.
+*/
+
+#ifndef KCMDLINEARGS_H
+#define KCMDLINEARGS_H
+
+#include <kdecore_export.h>
+#include <QtCore/QBool>
+
+#include <klocale.h>
+
+template <class T> class QList;
+class QString;
+class QStringList;
+class QByteArray;
+class QDataStream;
+class KUrl;
+
+class KCmdLineArgs;
+class KCmdLineArgsPrivate;
+class KCmdLineArgsStatic;
+class KCmdLineOptionsPrivate;
+
+/**
+ * @short Class that holds command line options.
+ *
+ * This class is intended to be used with the KCmdLineArgs class, which
+ * provides convenient and powerful command line argument parsing and
+ * handling functionality.
+ *
+ * @see KCmdLineArgs for additional usage information
+ */
+class KDECORE_EXPORT KCmdLineOptions
+{
+ friend class KCmdLineArgs;
+ friend class KCmdLineArgsStatic;
+
+ public:
+ /**
+ * Constructor.
+ */
+ KCmdLineOptions ();
+
+ /**
+ * Copy constructor.
+ */
+ KCmdLineOptions (const KCmdLineOptions &options);
+
+ /**
+ * Assignment operator.
+ */
+ KCmdLineOptions& operator= (const KCmdLineOptions &options);
+
+ /**
+ * Destructor.
+ */
+ ~KCmdLineOptions ();
+
+ /**
+ * Add command line option, by providing its name, description, and
+ * possibly a default value. These will print out when <i>myapp --help</i>
+ * is called on the command line.
+ *
+ * Note that a long option can only have one short (single character) alias
+ *
+ * @since 4.6 Note that the following does not apply to options that begin
+ * with "no" and expect a parameter, like "nooption4" in the example bellow.
+ *
+ * Note that if the option name begin with "no" that you will need to test
+ * for the name without the "no" and the result will be the inverse of what
+ * is specified. i.e. if "nofoo" is the name of the option and
+ * <i>myapp --nofoo</i> is called:
+ *
+ * @code
+ * KCmdLineArgs::parsedArgs()->isSet("foo"); // false
+ * @endcode
+ *
+ * Here are some more examples showing various features:
+ *
+ * @code
+ * KCmdLineOptions options;
+ * options.add("a", ki18n("A short binary option"));
+ * options.add("b \<file>", ki18n("A short option which takes an argument"));
+ * options.add("c \<speed>", ki18n("As above but with a default value"), "9600");
+ * options.add("option1", ki18n("A long binary option, off by default"));
+ * options.add("nooption2", ki18n("A long binary option, on by default"));
+ * options.add(":", ki18n("Extra options:"));
+ * options.add("option3 \<file>", ki18n("A long option which takes an argument"));
+ * options.add("nooption4 \<speed>", ki18n("A long option which takes an argument, defaulting to 9600"), "9600");
+ * options.add("d").add("option5", ki18n("A long option which has a short option as alias"));
+ * options.add("e").add("nooption6", ki18n("Another long option with an alias"));
+ * options.add("f").add("option7 \<speed>", ki18n("'--option7 speed' is the same as '-f speed'"));
+ * options.add("!option8 \<cmd>", ki18n("All options following this one will be treated as arguments"));
+ * options.add("+file", ki18n("A required argument 'file'"));
+ * options.add("+[arg1]", ki18n("An optional argument 'arg1'"));
+ * options.add("!+command", ki18n("A required argument 'command', that can contain multiple words, even starting with '-'"));
+ * options.add("", ki18n("Additional help text not associated with any particular option"));
+ * @endcode
+ *
+ * @param name option name
+ * @param description option description, made available for translation;
+ * can be left off
+ * @param defaultValue default option value, when the value is not specified
+ * on the command line; can be left off
+ */
+ KCmdLineOptions &add (const QByteArray &name,
+ const KLocalizedString &description = KLocalizedString(),
+ const QByteArray &defaultValue = QByteArray());
+
+ /**
+ * Add all options from another KCmdLineOptions object.
+ *
+ * @param options options to add
+ */
+ KCmdLineOptions &add (const KCmdLineOptions &options);
+
+ private:
+
+ KCmdLineOptionsPrivate *d; //krazy:exclude=dpointer (for operator=)
+};
+
+class KCmdLineArgsList;
+class KApplication;
+class KAboutData;
+
+/**
+ * @short A class for command-line argument handling.
+ *
+ * KCmdLineArgs provides simple access to the command-line arguments
+ * for an application. It takes into account Qt-specific options,
+ * KDE-specific options and application specific options.
+ *
+ * This class is used in %main() via the static method
+ * init().
+ *
+ * A typical %KDE application using %KCmdLineArgs should look like this:
+ *
+ * @code
+ * int main(int argc, char *argv[])
+ * {
+ * // Initialize command line args
+ * KCmdLineArgs::init(argc, argv, appName, programName, version, description);
+ *
+ * // Define the command line options using KCmdLineOptions
+ * KCmdLineOptions options;
+ * ....
+ *
+ * // Register the supported options
+ * KCmdLineArgs::addCmdLineOptions( options );
+ *
+ * // Add options from other components
+ * KUniqueApplication::addCmdLineOptions();
+ *
+ * ....
+ *
+ * // Create application object without passing 'argc' and 'argv' again.
+ * KUniqueApplication app;
+ *
+ * ....
+ *
+ * // Handle our own options/arguments
+ * // A KApplication will usually do this in main but this is not
+ * // necessary.
+ * // A KUniqueApplication might want to handle it in newInstance().
+ *
+ * KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ *
+ * // A binary option (on / off)
+ * if (args->isSet("some-option"))
+ * ....
+ *
+ * // An option which takes an additional argument
+ * QString anotherOptionArg = args->getOption("another-option");
+ *
+ * // Arguments (e.g. files to open)
+ * for(int i = 0; i < args->count(); i++) // Counting start at 0!
+ * {
+ * openFile( args->arg(i));
+ * // Or more convenient:
+ * // openUrl( args->url(i));
+ *
+ * }
+ *
+ * args->clear(); // Free up some memory.
+ * ....
+ * }
+ * @endcode
+ *
+ * The options that an application supports are configured using the
+ * KCmdLineOptions class. An example is shown below:
+ *
+ * @code
+ * KCmdLineOptions options;
+ * options.add("a", ki18n("A short binary option"));
+ * options.add("b \<file>", ki18n("A short option which takes an argument"));
+ * options.add("c \<speed>", ki18n("As above but with a default value"), "9600");
+ * options.add("option1", ki18n("A long binary option, off by default"));
+ * options.add("nooption2", ki18n("A long binary option, on by default"));
+ * options.add(":", ki18n("Extra options:"));
+ * options.add("option3 \<file>", ki18n("A long option which takes an argument"));
+ * options.add("option4 \<speed>", ki18n("A long option which takes an argument, defaulting to 9600"), "9600");
+ * options.add("d").add("option5", ki18n("A long option which has a short option as alias"));
+ * options.add("e").add("nooption6", ki18n("Another long option with an alias"));
+ * options.add("f").add("option7 \<speed>", ki18n("'--option7 speed' is the same as '-f speed'"));
+ * options.add("!option8 \<cmd>", ki18n("All options following this one will be treated as arguments"));
+ * options.add("+file", ki18n("A required argument 'file'"));
+ * options.add("+[arg1]", ki18n("An optional argument 'arg1'"));
+ * options.add("!+command", ki18n("A required argument 'command', that can contain multiple words, even starting with '-'"));
+ * options.add("", ki18n("Additional help text not associated with any particular option"));
+ * @endcode
+ *
+ * The ki18n calls are used for translation instead of the more usual i18n
+ * calls, because the translation needs to be delayed until after the
+ * message catalogs have been initialized.
+ *
+ * Note that a program should define the options before any arguments.
+ *
+ * When a long option has a short option as an alias, a program should
+ * only test for the long option.
+ *
+ * With the above options a command line could look like:
+ * @code
+ * myapp -a -c 4800 --display localhost:0.0 --nooption5 -d /tmp/file
+ * @endcode
+ *
+ * Long binary options can be in the form 'option' and 'nooption'.
+ * A command line may contain the same binary option multiple times,
+ * the last option determines the outcome:
+ * @code
+ * myapp --nooption4 --option4 --nooption4
+ * @endcode
+ * is the same as:
+ * @code
+ * myapp --nooption4
+ * @endcode
+ *
+ * If an option value is provided multiple times, normally only the last
+ * value is used:
+ * @code
+ * myapp -c 1200 -c 2400 -c 4800
+ * @endcode
+ * is usually the same as:
+ * @code
+ * myapp -c 4800
+ * @endcode
+ *
+ * However, an application can choose to use all values specified as well.
+ * As an example of this, consider that you may wish to specify a
+ * number of directories to use:
+ * @code
+ * myapp -I /usr/include -I /opt/kde/include -I /usr/X11/include
+ * @endcode
+ * When an application does this it should mention this in the description
+ * of the option. To access these options, use getOptionList()
+ *
+ * Tips for end-users:
+ *
+ * @li Single char options like "-a -b -c" may be combined into "-abc"
+ * @li The option "--foo bar" may also be written "--foo=bar"
+ * @li The option "-P lp1" may also be written "-P=lp1" or "-Plp1"
+ * @li The option "--foo bar" may also be written "-foo bar"
+ *
+ * @author Waldo Bastian
+ * @version 0.0.4
+ */
+class KDECORE_EXPORT KCmdLineArgs
+{
+ friend class KApplication;
+ friend class KCmdLineArgsList;
+ friend class KCmdLineArgsStatic;
+public:
+ // Static functions:
+
+ enum StdCmdLineArg {
+ CmdLineArgQt = 0x01,
+ CmdLineArgKDE = 0x02,
+ CmdLineArgsMask=0x03,
+ CmdLineArgNone = 0x00,
+ Reserved = 0xff
+ };
+ Q_DECLARE_FLAGS(StdCmdLineArgs, StdCmdLineArg)
+ /**
+ * Initialize class.
+ *
+ * This function should be called as the very first thing in
+ * your application.
+ * @param argc As passed to @p main(...).
+ * @param argv As passed to @p main(...).
+ * @param appname The untranslated name of your application. This should
+ * match with @p argv[0].
+ * @param catalog Translation catalog name, if empty @p appname will be used.
+ * @param programName A program name string to be used for display
+ * purposes. This string should be marked for translation.
+ * Example: ki18n("KEdit")
+ * @param version A version.
+ * @param description A short description of what your application is about.
+ * Also marked for translation.
+ * @param stdargs KDE/Qt or no default parameters
+ */
+ static void init(int argc, char **argv,
+ const QByteArray &appname,
+ const QByteArray &catalog,
+ const KLocalizedString &programName,
+ const QByteArray &version,
+ const KLocalizedString &description = KLocalizedString(),
+ StdCmdLineArgs stdargs=StdCmdLineArgs(CmdLineArgQt|CmdLineArgKDE));
+
+ /**
+ * Initialize class.
+ *
+ * This function should be called as the very first thing in
+ * your application. It uses KAboutData to replace some of the
+ * arguments that would otherwise be required.
+ *
+ * @param _argc As passed to @p main(...).
+ * @param _argv As passed to @p main(...).
+ * @param about A KAboutData object describing your program.
+ * @param stdargs KDE/Qt or no default parameters
+ */
+ static void init(int _argc,
+ char **_argv,
+ const KAboutData *about,
+ StdCmdLineArgs stdargs=StdCmdLineArgs(CmdLineArgQt|CmdLineArgKDE));
+ /**
+ * Initialize Class
+ *
+ * This function should be called as the very first thing in your
+ * application. This method will rarely be used, since it doesn't
+ * provide any argument parsing. It does provide access to the
+ * KAboutData information.
+ * This method is exactly the same as calling
+ * init(0,0, const KAboutData *about, CmdLineArgNone).
+ *
+ * @param about the about data.
+ * @see KAboutData
+ */
+ static void init(const KAboutData *about);
+
+ /**
+ * add standard Qt/KDE command-line args
+ */
+ static void addStdCmdLineOptions(StdCmdLineArgs stdargs=StdCmdLineArgs(CmdLineArgQt|CmdLineArgKDE));
+
+ /**
+ * Add options to your application.
+ *
+ * You must make sure that all possible options have been added before
+ * any class uses the command line arguments.
+ *
+ * The list of options should look like this:
+ *
+ * @code
+ * KCmdLineOptions options;
+ * options.add("option1 \<argument>", ki18n("Description 1"), "my_extra_arg");
+ * options.add("o");
+ * options.add("option2", ki18n("Description 2"));
+ * options.add("nooption3", ki18n("Description 3"));
+ * options.add("+file", ki18n("A required argument 'file'"));
+ * @endcode
+ *
+ * @li "option1" is an option that requires an additional argument,
+ * but if one is not provided, it uses "my_extra_arg".
+ * @li "option2" is an option that can be turned on. The default is off.
+ * @li "option3" is an option that can be turned off. The default is on.
+ * @li "o" does not have a description. It is an alias for the option
+ * that follows. In this case "option2".
+ * @li "+file" specifies an argument. The '+' is removed. If your program
+ * doesn't specify that it can use arguments your program will abort
+ * when an argument is passed to it. Note that the reverse is not
+ * true. If required, you must check yourself the number of arguments
+ * specified by the user:
+ * @code
+ * KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ * if (args->count() == 0) KCmdLineArgs::usage(i18n("No file specified"));
+ * @endcode
+ *
+ * In BNF:
+ * @code
+ * cmd = myapp [options] file
+ * options = (option)*
+ * option = --option1 \<argument> |
+ * (-o | --option2 | --nooption2) |
+ * ( --option3 | --nooption3 )
+ * @endcode
+ *
+ * Instead of "--option3" one may also use "-option3"
+ *
+ * Usage examples:
+ *
+ * @li "myapp --option1 test"
+ * @li "myapp" (same as "myapp --option1 my_extra_arg")
+ * @li "myapp --option2"
+ * @li "myapp --nooption2" (same as "myapp", since it is off by default)
+ * @li "myapp -o" (same as "myapp --option2")
+ * @li "myapp --nooption3"
+ * @li "myapp --option3 (same as "myapp", since it is on by default)
+ * @li "myapp --option2 --nooption2" (same as "myapp", because it
+ * option2 is off by default, and the last usage applies)
+ * @li "myapp /tmp/file"
+ *
+ * @param options A list of options that your code supplies.
+ * @param name the name of the option list, as displayed by
+ * the help output. Can be empty.
+ * @param id A name with which these options can be identified, can be empty.
+ * @param afterId The options are inserted after this set of options, can be empty.
+ */
+ static void addCmdLineOptions(const KCmdLineOptions &options,
+ const KLocalizedString &name = KLocalizedString(),
+ const QByteArray &id = QByteArray(),
+ const QByteArray &afterId = QByteArray());
+
+ /**
+ * Access parsed arguments.
+ *
+ * This function returns all command line arguments that your code
+ * handles. If unknown command-line arguments are encountered the program
+ * is aborted and usage information is shown.
+ *
+ * @param id The name of the options you are interested in, can be empty.
+ */
+ static KCmdLineArgs *parsedArgs(const QByteArray &id = QByteArray());
+
+ /**
+ * Get the CWD (Current Working Directory) associated with the
+ * current command line arguments.
+ *
+ * Typically this is needed in KUniqueApplication::newInstance()
+ * since the CWD of the process may be different from the CWD
+ * where the user started a second instance.
+ * @return the current working directory
+ **/
+ static QString cwd();
+
+ /**
+ * Get the appname according to argv[0].
+ * @return the name of the application
+ **/
+ static QString appName();
+
+ /**
+ * Print the usage help to stdout and exit.
+ *
+ * @param id if empty, print all options. If id is set, only print the
+ * option specified by id. The id is the value set by
+ * addCmdLineOptions().
+ **/
+ static void usage(const QByteArray &id = QByteArray());
+
+ /**
+ * Print an error to stderr and the usage help to stdout and exit.
+ * @param error the error to print
+ **/
+ static void usageError(const QString &error);
+
+ /**
+ * Enable i18n to be able to print a translated error message.
+ *
+ * N.B.: This function leaks memory, therefore you are expected to exit
+ * afterwards (e.g., by calling usage()).
+ **/
+ static void enable_i18n();
+
+ // Member functions:
+
+
+ /**
+ * Read out a string option.
+ *
+ * The option must have a corresponding KCmdLineOptions entry
+ * of the form:
+ * @code
+ * options.add("option \<argument>", ki18n("Description"), "default");
+ * @endcode
+ * You cannot test for the presence of an alias - you must always
+ * test for the full option.
+ *
+ * @param option The name of the option without '-'.
+ *
+ * @return The value of the option. If the option was not
+ * present on the command line the default is returned.
+ * If the option was present more than once, the value of the
+ * last occurrence is used.
+ */
+ QString getOption(const QByteArray &option) const;
+
+ /**
+ * Read out all occurrences of a string option.
+ *
+ * The option must have a corresponding KCmdLineOptions entry
+ * of the form:
+ * @code
+ * options.add("option \<argument>", ki18n("Description"), "default");
+ * @endcode
+ * You cannot test for the presence of an alias - you must always
+ * test for the full option.
+ *
+ * @param option The name of the option, without '-' or '-no'.
+ *
+ * @return A list of all option values. If no option was present
+ * on the command line, an empty list is returned.
+ */
+ QStringList getOptionList(const QByteArray &option) const;
+
+ /**
+ * Read out a boolean option or check for the presence of string option.
+ *
+ * @param option The name of the option without '-' or '-no'.
+ *
+ * @return The value of the option. It will be true if the option
+ * was specifically turned on in the command line, or if the option
+ * is turned on by default (in the KCmdLineOptions list) and was
+ * not specifically turned off in the command line. Equivalently,
+ * it will be false if the option was specifically turned off in
+ * the command line, or if the option is turned off by default (in
+ * the KCmdLineOptions list) and was not specifically turned on in
+ * the command line.
+ */
+ bool isSet(const QByteArray &option) const;
+
+ /**
+ * Read the number of arguments that aren't options (but,
+ * for example, filenames).
+ *
+ * @return The number of arguments that aren't options
+ */
+ int count() const;
+
+ /**
+ * Read out an argument.
+ *
+ * @param n The argument to read. 0 is the first argument.
+ * count()-1 is the last argument.
+ *
+ * @return n-th argument
+ */
+ QString arg(int n) const;
+
+ /**
+ * Read out an argument representing a URL.
+ *
+ * The argument can be
+ * @li an absolute filename
+ * @li a relative filename
+ * @li a URL
+ *
+ * @param n The argument to read. 0 is the first argument.
+ * count()-1 is the last argument.
+ *
+ * @return a URL representing the n'th argument.
+ */
+ KUrl url(int n) const;
+
+ /**
+ * Used by url().
+ * Made public for apps that don't use KCmdLineArgs
+ * @param urlArg the argument
+ * @return the url.
+ */
+ static KUrl makeURL( const QByteArray &urlArg );
+
+ /**
+ * Made public for apps that don't use KCmdLineArgs
+ * To be done before makeURL, to set the current working
+ * directory in case makeURL needs it.
+ * @param cwd the new working directory
+ */
+ static void setCwd( const QByteArray &cwd );
+
+ /**
+ * Clear all options and arguments.
+ */
+ void clear();
+
+ /**
+ * Reset all option definitions, i.e. cancel all addCmdLineOptions calls.
+ * Note that KApplication's options are removed too, you might want to
+ * call KApplication::addCmdLineOptions if you want them back.
+ *
+ * You usually don't want to call this method.
+ */
+ static void reset();
+
+ /**
+ * Load arguments from a stream.
+ */
+ static void loadAppArgs( QDataStream &);
+
+ /**
+ * @internal for KUniqueApplication only:
+ *
+ * Save all but the Qt and KDE arguments to a stream.
+ */
+ static void saveAppArgs( QDataStream &);
+
+ /**
+ * Add standard option --tempfile
+ */
+ static void addTempFileOption();
+
+ // this avoids having to know the "id" used by addTempFileOption
+ // but this approach doesn't scale well, we can't have 50 standard options here...
+ /**
+ * @return true if --tempfile was set
+ */
+ static bool isTempFileSet();
+
+ /**
+ * Returns the number of arguments returned by qtArgv()
+ *
+ * @see qtArgv
+ */
+ static int &qtArgc();
+
+ /**
+ * Returns command line options for consumption by Qt after parsing them in a way that
+ * is consistent with KDE's general command line handling. In particular this ensures
+ * that Qt command line options can be specified as either -option or --option and that
+ * any options specified after '--' will be ignored.
+ *
+ * @see qt_argc
+ */
+ static char **qtArgv();
+
+ /**
+ * Returns the list of command-line arguments.
+ * @since 4.6
+ */
+ static QStringList allArguments();
+
+ /**
+ * Returns the KAboutData for consumption by KComponentData
+ */
+ static const KAboutData *aboutData();
+
+protected:
+ /**
+ * @internal
+ * Constructor.
+ */
+ KCmdLineArgs( const KCmdLineOptions &_options, const KLocalizedString &_name,
+ const QByteArray &_id);
+
+ /**
+ * @internal use only.
+ *
+ * Use clear() if you want to free up some memory.
+ *
+ * Destructor.
+ */
+ ~KCmdLineArgs();
+
+private:
+
+ /**
+ * @internal for KApplication only
+ *
+ * Initialize class.
+ *
+ * This function should be called as the very first thing in
+ * your application.
+ * @param argc As passed to @p main(...).
+ * @param argv As passed to @p main(...).
+ * @param appname The untranslated name of your application. This should
+ * match with @p argv[0].
+ *
+ * This function makes KCmdLineArgs ignore all unknown options as well as
+ * all arguments.
+ */
+ static void initIgnore(int _argc, char **_argv, const QByteArray &_appname);
+
+ KCmdLineArgsPrivate *const d;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(KCmdLineArgs::StdCmdLineArgs)
+
+#endif
+
diff --git a/kdecore/kernel/kcomponentdata.cpp b/kdecore/kernel/kcomponentdata.cpp
new file mode 100644
index 0000000..c3b38a4
--- /dev/null
+++ b/kdecore/kernel/kcomponentdata.cpp
@@ -0,0 +1,239 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Torben Weis <weis@kde.org>
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+ Copyright (C) 2007 Bernhard Loos <nhuh.put@web.de>
+
+ 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 "kcomponentdata.h"
+#include "kcomponentdata_p.h"
+
+#include <QtCore/QCoreApplication>
+
+#include "kaboutdata.h"
+#include "kcmdlineargs.h"
+#include "kconfig.h"
+#include "kglobal.h"
+#include "kglobal_p.h"
+#include "klocale.h"
+#include "kconfiggroup.h"
+#include "kstandarddirs.h"
+#include <QtDebug>
+
+KComponentData::KComponentData()
+ : d(0)
+{
+}
+
+KComponentData::KComponentData(const KComponentData &rhs)
+ : d(rhs.d)
+{
+ if (d) {
+ d->ref();
+ }
+}
+
+KComponentData &KComponentData::operator=(const KComponentData &rhs)
+{
+ if (rhs.d != d) {
+ if (rhs.d) {
+ rhs.d->ref();
+ }
+ if (d) {
+ d->deref();
+ }
+ d = rhs.d;
+ }
+ return *this;
+}
+
+bool KComponentData::operator==(const KComponentData &rhs) const
+{
+ return d == rhs.d;
+}
+
+enum KdeLibraryPathsAdded {
+ NeedLazyInit,
+ LazyInitDone,
+ KdeLibraryPathsAddedDone
+};
+static KdeLibraryPathsAdded kdeLibraryPathsAdded = NeedLazyInit;
+
+KComponentData::KComponentData(const QByteArray &name, const QByteArray &catalog, MainComponentRegistration registerAsMain)
+ : d(new KComponentDataPrivate(KAboutData(name, catalog, KLocalizedString(), "", KLocalizedString())))
+{
+ Q_ASSERT(!name.isEmpty());
+
+ if (kdeLibraryPathsAdded == NeedLazyInit) {
+ kdeLibraryPathsAdded = LazyInitDone;
+ d->lazyInit(*this);
+ }
+
+ if (registerAsMain == RegisterAsMainComponent) {
+ KGlobal::newComponentData(*this);
+ }
+}
+
+KComponentData::KComponentData(const KAboutData *aboutData, MainComponentRegistration registerAsMain)
+ : d(new KComponentDataPrivate(*aboutData))
+{
+ Q_ASSERT(!aboutData->appName().isEmpty());
+
+ if (kdeLibraryPathsAdded == NeedLazyInit) {
+ kdeLibraryPathsAdded = LazyInitDone;
+ d->lazyInit(*this);
+ }
+
+ if (registerAsMain == RegisterAsMainComponent) {
+ KGlobal::newComponentData(*this);
+ }
+}
+
+KComponentData::KComponentData(const KAboutData &aboutData, MainComponentRegistration registerAsMain)
+ : d(new KComponentDataPrivate(aboutData))
+{
+ Q_ASSERT(!aboutData.appName().isEmpty());
+
+ if (kdeLibraryPathsAdded == NeedLazyInit) {
+ kdeLibraryPathsAdded = LazyInitDone;
+ d->lazyInit(*this);
+ }
+
+ if (registerAsMain == RegisterAsMainComponent) {
+ KGlobal::newComponentData(*this);
+ }
+}
+
+KComponentData::~KComponentData()
+{
+ if (d) {
+ d->deref();
+ d = 0;
+ }
+}
+
+bool KComponentData::isValid() const
+{
+ return (d != 0);
+}
+
+void KComponentDataPrivate::lazyInit(const KComponentData &component)
+{
+ if (dirs == 0) {
+ dirs = new KStandardDirs();
+ // install appdata resource type
+ dirs->addResourceType("appdata", "data", aboutData.appName() + QLatin1Char('/'), true);
+
+ configInit(component);
+
+ if (dirs->addCustomized(sharedConfig.data()))
+ sharedConfig->reparseConfiguration();
+ }
+
+#ifdef Q_OS_WIN
+ if (QCoreApplication::instance() && dirs && kdeLibraryPathsAdded != KdeLibraryPathsAddedDone) {
+#else
+ // the first KComponentData sets the KDE Qt plugin paths
+ if (dirs && kdeLibraryPathsAdded != KdeLibraryPathsAddedDone) {
+#endif
+ kdeLibraryPathsAdded = KdeLibraryPathsAddedDone;
+ const QStringList &plugins = dirs->resourceDirs("qtplugins");
+ QStringList::ConstIterator it = plugins.begin();
+ while (it != plugins.end()) {
+ QCoreApplication::addLibraryPath(*it);
+ ++it;
+ }
+ }
+}
+
+bool kde_kiosk_exception = false; // flag to disable kiosk restrictions
+bool kde_kiosk_admin = false;
+
+void KComponentDataPrivate::configInit(const KComponentData &component)
+{
+ Q_ASSERT(!sharedConfig);
+
+ if (!configName.isEmpty()) {
+ sharedConfig = KSharedConfig::openConfig(component, configName);
+
+ //FIXME: this is broken and I don't know how to repair it
+ // Check whether custom config files are allowed.
+ KConfigGroup cg(sharedConfig, "KDE Action Restrictions");
+ QString kioskException = cg.readEntry("kiosk_exception");
+ if (!cg.readEntry("custom_config", true)) {
+ sharedConfig = 0;
+ }
+ }
+
+ if (!sharedConfig) {
+ sharedConfig = KSharedConfig::openConfig(component);
+ }
+
+ // Check if we are excempt from kiosk restrictions
+ if (kde_kiosk_admin && !kde_kiosk_exception && !qgetenv("KDE_KIOSK_NO_RESTRICTIONS").isEmpty()) {
+ kde_kiosk_exception = true;
+ sharedConfig = 0;
+ configInit(component); // Reread...
+ }
+}
+
+KStandardDirs *KComponentData::dirs() const
+{
+ Q_ASSERT(d);
+ d->lazyInit(*this);
+
+ return d->dirs;
+}
+
+const KSharedConfig::Ptr &KComponentData::config() const
+{
+ Q_ASSERT(d);
+ d->lazyInit(*this);
+
+ return d->sharedConfig;
+}
+
+void KComponentData::setConfigName(const QString &configName)
+{
+ Q_ASSERT(d);
+ d->configName = configName;
+}
+
+const KAboutData *KComponentData::aboutData() const
+{
+ Q_ASSERT(d);
+ return &d->aboutData;
+}
+
+void KComponentData::setAboutData(const KAboutData &aboutData)
+{
+ d->aboutData = aboutData;
+}
+
+QString KComponentData::componentName() const
+{
+ Q_ASSERT(d);
+ return d->aboutData.appName();
+}
+
+QString KComponentData::catalogName() const
+{
+ Q_ASSERT(d);
+ return d->aboutData.catalogName();
+}
+
+void KComponentData::virtual_hook(int, void*)
+{ /*BASE::virtual_hook(id, data);*/ }
diff --git a/kdecore/kernel/kcomponentdata.h b/kdecore/kernel/kcomponentdata.h
new file mode 100644
index 0000000..a8ff6fa
--- /dev/null
+++ b/kdecore/kernel/kcomponentdata.h
@@ -0,0 +1,192 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Torben Weis <weis@kde.org>
+ Copyright (C) 2007 Matthias Kretz <kretz@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.
+*/
+#ifndef KCOMPONENTDATA_H
+#define KCOMPONENTDATA_H
+
+#include <kdecore_export.h>
+#include <ksharedconfig.h>
+
+class QByteArray;
+class QString;
+class KAboutData;
+class KStandardDirs;
+class KComponentDataPrivate;
+
+/**
+ * @short Per component data.
+ *
+ * This class holds a KAboutData object or only a component name, a KStandardDirs object and a
+ * KSharedConfig object. Those objects normally are different per component but the same per
+ * instance of one component.
+ *
+ * The application component data can always be accessed using KGlobal::mainComponent() (or the
+ * convenience function KGlobal::dirs() and KGlobal::config()) while the
+ * component data of the currently active component (mainly used for KParts) can be accessed using
+ * KGlobal::activeComponent().
+ *
+ * @author Torben Weis
+ * @author Matthias Kretz <kretz@kde.org>
+ */
+class KDECORE_EXPORT KComponentData // krazy:exclude=dpointer (implicitly shared)
+{
+public:
+ /**
+ * Creates an invalid KComponentData object.
+ *
+ * @see isValid()
+ */
+ KComponentData();
+
+ /**
+ * Copy constructor.
+ *
+ * It does not copy the data. The data is shared between the old and new objects.
+ */
+ KComponentData(const KComponentData&);
+
+ /**
+ * Assignment operator.
+ *
+ * It does not copy the data. The data is shared between the old and new objects.
+ *
+ * If the data of the left hand side object was only referenced
+ * from this object and no referenced KSharedConfig object needs
+ * it anymore, it is deleted
+ */
+ KComponentData &operator=(const KComponentData&);
+
+ /**
+ * Returns whether two KComponentData objects reference the same data.
+ */
+ bool operator==(const KComponentData&) const;
+
+ /**
+ * Returns whether two KComponentData objects do not reference the same data.
+ */
+ bool operator!=(const KComponentData &rhs) const { return !operator==(rhs); }
+
+ enum MainComponentRegistration {
+ RegisterAsMainComponent,
+ SkipMainComponentRegistration
+ };
+
+ /**
+ * Constructor.
+ *
+ * @param componentName the name of the component.
+ * @param catalogName the name of the translation catalog;
+ * if left empty @p componentName is used
+ * @param registerAsMain whether to register the component as the main component
+ * of the application. This has no effect, if the application
+ * already has a main component.
+ * @see KGlobal::mainComponent
+ */
+ explicit KComponentData(const QByteArray &componentName, const QByteArray &catalogName = QByteArray(),
+ MainComponentRegistration registerAsMain = RegisterAsMainComponent);
+
+ /**
+ * Constructor.
+ *
+ * A copy of the aboutData object is made.
+ *
+ * @param aboutData data about this component
+ * @param registerAsMain whether to register the component as the main component
+ * of the application. This has no effect, if the application
+ * already has a main component.
+ * @see KGlobal::mainComponent
+ *
+ * @see KAboutData
+ */
+ explicit KComponentData(const KAboutData &aboutData, MainComponentRegistration registerAsMain = RegisterAsMainComponent);
+ explicit KComponentData(const KAboutData *aboutData, MainComponentRegistration registerAsMain = RegisterAsMainComponent);
+
+ /**
+ * Destructor.
+ */
+ virtual ~KComponentData();
+
+ /**
+ * Returns whether this is a valid object.
+ *
+ * Don't call any functions on invalid objects, that will crash. Assignment (and of course
+ * destruction) is the only valid operation you may do.
+ */
+ bool isValid() const;
+
+ /**
+ * Returns the application standard dirs object.
+ * @return The KStandardDirs of the application.
+ */
+ KStandardDirs *dirs() const;
+
+ /**
+ * Returns the general config object ("appnamerc").
+ * @return the KConfig object for the component.
+ */
+ const KSharedConfig::Ptr &config() const; //krazy:exclude=constref
+
+ /**
+ * Returns the about data of this component.
+ *
+ * @return The about data of the component. If none has been set in the
+ * constructor but a component name was set, a default constructed
+ * KAboutData object is returned.
+ */
+ const KAboutData *aboutData() const;
+
+ /**
+ * Sets the about data of this component.
+ *
+ * @since 4.5
+ */
+ void setAboutData(const KAboutData &aboutData);
+
+ /**
+ * Returns the name of the component.
+ *
+ * @return The component name.
+ */
+ QString componentName() const;
+
+ /**
+ * Returns the name of the translation catalog.
+ *
+ * @return The catalog name.
+ */
+ QString catalogName() const;
+
+protected:
+ friend class KApplicationPrivate;
+
+ /**
+ * Set name of default config file.
+ * @param name the name of the default config file
+ */
+ void setConfigName(const QString &name);
+
+ /** Standard trick to add virtuals later. @internal */
+ virtual void virtual_hook( int id, void* data );
+
+private:
+ // Ref-counted data
+ KComponentDataPrivate* d;
+ friend class KComponentDataPrivate;
+};
+
+#endif // KCOMPONENTDATA_H
diff --git a/kdecore/kernel/kcomponentdata_p.h b/kdecore/kernel/kcomponentdata_p.h
new file mode 100644
index 0000000..9f06efe
--- /dev/null
+++ b/kdecore/kernel/kcomponentdata_p.h
@@ -0,0 +1,99 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@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.
+
+*/
+
+#ifndef KERNEL_KCOMPONENTDATA_P_H
+#define KERNEL_KCOMPONENTDATA_P_H
+
+#include "kcomponentdata.h"
+#include <QAtomicInt>
+#include <QtDebug>
+#include <QString>
+
+#include <kconfig.h>
+#include <kaboutdata.h>
+#include <kstandarddirs.h>
+#include <klocale.h>
+
+class KComponentDataPrivate
+{
+public:
+ KComponentDataPrivate(const KAboutData &aboutData_)
+ : dirs(0),
+ aboutData(aboutData_),
+ syncing(false),
+ refCount(1)
+ {
+ if (KGlobal::hasLocale()) {
+ KGlobal::locale()->insertCatalog(aboutData.catalogName());
+ shouldRemoveCatalog = true;
+ } else {
+ shouldRemoveCatalog = false;
+ }
+ }
+
+ ~KComponentDataPrivate()
+ {
+ refCount.fetchAndStoreOrdered(-0x00FFFFFF); //prevent a reentering of the dtor
+ if (shouldRemoveCatalog && KGlobal::hasLocale())
+ KGlobal::locale()->removeCatalog(aboutData.catalogName());
+
+ sharedConfig = 0; //delete the config object first, because it could access the standard dirs while syncing
+ delete dirs;
+ }
+
+ inline void ref()
+ {
+ refCount.ref();
+ //qDebug() << refCount - 1 << "->" << refCount << kBacktrace() << endl;
+ }
+
+ inline void deref()
+ {
+ const int refc = refCount.fetchAndAddOrdered(-1) - 1;
+ //qDebug() << refCount + 1 << "->" << refCount << kBacktrace() << endl;
+ if (refc == 0) {
+ delete this;
+ } else if (refc == 1 && sharedConfig && sharedConfig->componentData().d == this) { //sharedConfig has a reference to us
+ if (sharedConfig.count() == 1) { //we are the only class with a reference to the config object
+ delete this;
+ } else if (sharedConfig.count() > 0) { //there are other references to it.
+ sharedConfig->ref.deref(); //we don't have a reference to the config object anymore, but it has still a reference to us
+ //this breaks the circular dependencies
+ }
+ }
+ }
+
+ void lazyInit(const KComponentData &component);
+ void configInit(const KComponentData &component); //call this only from lazyInit()!
+
+ KStandardDirs *dirs;
+ KAboutData aboutData;
+ QString configName;
+ KSharedConfig::Ptr sharedConfig;
+ bool syncing;
+
+private:
+ bool shouldRemoveCatalog;
+ QAtomicInt refCount;
+ KComponentDataPrivate(const KComponentDataPrivate&);
+ KComponentDataPrivate &operator=(const KComponentDataPrivate&);
+};
+
+#endif // KERNEL_KCOMPONENTDATA_P_H
+// vim: sw=4 sts=4 et tw=100
diff --git a/kdecore/kernel/kglobal.cpp b/kdecore/kernel/kglobal.cpp
new file mode 100644
index 0000000..766cc0b
--- /dev/null
+++ b/kdecore/kernel/kglobal.cpp
@@ -0,0 +1,356 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Sirtaj Singh Kanq <taj@kde.org>
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+ Copyright (C) 2009 Olivier Goffart <ogoffart@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.
+*/
+
+/*
+ * kglobal.cpp -- Implementation of namespace KGlobal.
+ * Author: Sirtaj Singh Kang
+ * Generated: Sat May 1 02:08:43 EST 1999
+ */
+
+#undef KDE3_SUPPORT
+
+#include "kglobal.h"
+#include "kglobal_p.h"
+#include <QThread>
+
+#include <config.h>
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#include <QtCore/QList>
+#include <QtCore/QSet>
+
+#include <kaboutdata.h>
+#include <kconfig.h>
+#include <klocale.h>
+#include <kcharsets.h>
+#include <kstandarddirs.h>
+#include <kcomponentdata.h>
+#undef QT_NO_TRANSLATION
+#include <QtCore/QCoreApplication>
+#define QT_NO_TRANSLATION
+#include <QtCore/QDebug>
+#include <QtCore/QTextCodec>
+#include "kcmdlineargs.h"
+#include <unistd.h> // umask
+
+#ifndef NDEBUG
+#define MYASSERT(x) if (!x) \
+ qFatal("Fatal error: you need to have a KComponentData object before\n" \
+ "you do anything that requires it! Examples of this are config\n" \
+ "objects, standard directories or translations.");
+#else
+#define MYASSERT(x) /* nope */
+#endif
+
+// ~KConfig needs qrand(). qrand() depends on a Q_GLOBAL_STATIC. With this Q_CONSTRUCTOR_FUNCTION we
+// try to make qrand() live longer than any KConfig object.
+Q_CONSTRUCTOR_FUNCTION(qrand)
+
+typedef QSet<QString> KStringDict;
+mode_t s_umsk;
+
+class KGlobalPrivate
+{
+ public:
+ inline KGlobalPrivate()
+ : stringDict(0),
+ locale(0),
+ charsets(0),
+ localeIsFromFakeComponent(false)
+ {
+ // the umask is read here before any threads are created to avoid race conditions
+ mode_t tmp = 0;
+ s_umsk = umask(tmp);
+ umask(s_umsk);
+ }
+
+ inline ~KGlobalPrivate()
+ {
+ delete locale;
+ locale = 0;
+ delete charsets;
+ charsets = 0;
+ delete stringDict;
+ stringDict = 0;
+ }
+
+ KComponentData activeComponent;
+ KComponentData mainComponent; // holds a refcount
+ KStringDict *stringDict;
+ KLocale *locale;
+ KCharsets *charsets;
+ bool localeIsFromFakeComponent;
+ QStringList catalogsToInsert;
+
+ /**
+ * This component may be used in applications that doesn't have a
+ * main component (such as pure Qt applications).
+ */
+ static KComponentData initFakeComponent()
+ {
+ QString name = QCoreApplication::applicationName();
+ if(name.isEmpty() && QCoreApplication::instance())
+ name = qAppName();
+ if(name.isEmpty())
+ name = QString::fromLatin1("kde");
+ return KComponentData(name.toLatin1(), name.toLatin1(),
+ KComponentData::SkipMainComponentRegistration);
+ }
+};
+
+KCatalogLoader::KCatalogLoader(const QString &catalogName)
+{
+ KGlobal::insertCatalog(catalogName);
+}
+
+
+K_GLOBAL_STATIC(KGlobalPrivate, globalData)
+K_GLOBAL_STATIC_WITH_ARGS(KComponentData, fakeComponent, (KGlobalPrivate::initFakeComponent()))
+
+#define PRIVATE_DATA KGlobalPrivate *d = globalData
+
+KStandardDirs *KGlobal::dirs()
+{
+ PRIVATE_DATA;
+ return d->mainComponent.isValid() ? d->mainComponent.dirs() : fakeComponent->dirs();
+}
+
+KSharedConfig::Ptr KGlobal::config()
+{
+ PRIVATE_DATA;
+ return d->mainComponent.isValid() ? d->mainComponent.config() : fakeComponent->config();
+}
+
+const KComponentData &KGlobal::mainComponent()
+{
+ PRIVATE_DATA;
+ return d->mainComponent.isValid() ? d->mainComponent : *fakeComponent;
+}
+
+bool KGlobal::hasMainComponent()
+{
+ if (globalData.isDestroyed()) {
+ return false;
+ }
+ PRIVATE_DATA;
+ return d->mainComponent.isValid();
+}
+
+void KGlobal::insertCatalog(const QString& catalog)
+{
+ PRIVATE_DATA;
+ if (d->locale) {
+ locale()->insertCatalog(catalog);
+ } else {
+ d->catalogsToInsert.append(catalog);
+ }
+}
+
+KLocale *KGlobal::locale()
+{
+ PRIVATE_DATA;
+ if (d->locale == 0 || (d->localeIsFromFakeComponent && d->mainComponent.isValid() && d->mainComponent.config())) {
+ // If you hit the warning below, here's how to debug it in gdb:
+ // (gdb) set auto-solib-add on
+ // (gdb) b qt_message_output
+ // (gdb) run
+ // It will stop at the "-nograb" information.
+ // (gdb) b KLocalePrivate::KLocalePrivate
+ // (gdb) c
+ // And now it will stop at the first construction of the KLocale object, type bt or go up to find the
+ // guilty i18n call.
+ if (d->locale != 0) qDebug() << "KGlobal::locale::Warning your global KLocale is being recreated with a valid main component instead of a fake component, this usually means you tried to call i18n related functions before your main component was created. You should not do that since it most likely will not work";
+ delete d->locale;
+ d->locale = 0;
+ d->locale = new KLocale(mainComponent().catalogName());
+ d->localeIsFromFakeComponent = !d->mainComponent.isValid();
+ QTextCodec::setCodecForLocale(d->locale->codecForEncoding());
+ mainComponent().aboutData()->translateInternalProgramName();
+ QCoreApplication* coreApp = QCoreApplication::instance();
+ if (coreApp) { // testcase: kwrite --help: no qcore app
+ if (coreApp->thread() != QThread::currentThread()) {
+ qFatal("KGlobal::locale() must be called from the main thread before using i18n() in threads. KApplication takes care of this. If not using KApplication, call KGlobal::locale() during initialization.");
+ } else {
+ QCoreApplication::installTranslator(new KDETranslator(coreApp));
+ }
+ }
+ foreach(const QString &catalog, d->catalogsToInsert)
+ d->locale->insertCatalog(catalog);
+ d->catalogsToInsert.clear();
+ }
+ return d->locale;
+}
+
+bool KGlobal::hasLocale()
+{
+ if (globalData.isDestroyed()) {
+ return false;
+ }
+ PRIVATE_DATA;
+ return (d->locale != 0);
+}
+
+KCharsets *KGlobal::charsets()
+{
+ PRIVATE_DATA;
+ if (d->charsets == 0) {
+ d->charsets = new KCharsets;
+ }
+
+ return d->charsets;
+}
+
+mode_t KGlobal::umask()
+{
+ // Don't use PRIVATE_DATA here. This is called by ~KGlobalPrivate -> ~KConfig -> sync -> KSaveFile, so there's no KGlobalPrivate anymore.
+ return s_umsk;
+}
+
+KComponentData KGlobal::activeComponent()
+{
+ PRIVATE_DATA;
+ MYASSERT(d->activeComponent.isValid());
+ return d->activeComponent;
+}
+
+void KGlobal::setActiveComponent(const KComponentData &c)
+{
+ PRIVATE_DATA;
+ d->activeComponent = c;
+ if (c.isValid() && d->locale) {
+ locale()->setActiveCatalog(c.catalogName());
+ }
+}
+
+void KGlobal::newComponentData(const KComponentData &c)
+{
+ PRIVATE_DATA;
+ if (d->mainComponent.isValid()) {
+ return;
+ }
+ d->mainComponent = c;
+ KGlobal::setActiveComponent(c);
+}
+
+void KGlobal::setLocale(KLocale *newLocale, CopyCatalogs copy)
+{
+ PRIVATE_DATA;
+ if (copy == DoCopyCatalogs && d->locale)
+ locale()->copyCatalogsTo(newLocale);
+ delete d->locale;
+ d->locale = newLocale;
+}
+
+/**
+ * Create a static QString
+ *
+ * To be used inside functions(!) like:
+ * static const QString &myString = KGlobal::staticQString("myText");
+ */
+const QString &KGlobal::staticQString(const char *str)
+{
+ return staticQString(QLatin1String(str));
+}
+
+/**
+ * Create a static QString
+ *
+ * To be used inside functions(!) like:
+ * static const QString &myString = KGlobal::staticQString(i18n("My Text"));
+ */
+const QString &KGlobal::staticQString(const QString &str)
+{
+ PRIVATE_DATA;
+ if (!d->stringDict) {
+ d->stringDict = new KStringDict;
+ }
+
+ return *d->stringDict->insert(str);
+}
+
+QString KGlobal::caption()
+{
+ PRIVATE_DATA;
+ // Caption set from command line ?
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kde");
+ if (args && args->isSet("caption")) {
+ return args->getOption("caption");
+ } else {
+ // We have some about data ?
+ if (d->mainComponent.isValid() && d->mainComponent.aboutData()) {
+ return d->mainComponent.aboutData()->programName();
+ } else {
+ // Last resort : application name
+ return QCoreApplication::instance()->applicationName();
+ }
+ }
+}
+
+/**
+ * This counter indicates when to quit the application.
+ * It starts at 0, is incremented by KMainWindow, systray icons, running jobs, etc.
+ * and decremented again when those things are destroyed.
+ * This mechanism allows dialogs and jobs to outlive the last window closed
+ * e.g. a file copy for a file manager, or 'compacting folders on exit' for a mail client,
+ * the job progress widget with "keep open" checked, etc.
+ */
+static int s_refCount = 0;
+static bool s_allowQuit = false;
+
+void KGlobal::ref()
+{
+ ++s_refCount;
+ //kDebug() << "KGlobal::ref() : refCount = " << s_refCount;
+}
+
+void KGlobal::deref()
+{
+ --s_refCount;
+ //kDebug() << "KGlobal::deref() : refCount = " << s_refCount;
+ if (s_refCount <= 0 && s_allowQuit) {
+ QCoreApplication::instance()->quit();
+ }
+}
+
+void KGlobal::setAllowQuit(bool allowQuit)
+{
+ s_allowQuit = allowQuit;
+}
+
+#undef PRIVATE_DATA
+
+QObject* KGlobal::findDirectChild_helper(const QObject* parent, const QMetaObject& mo)
+{
+ if (!parent)
+ return 0;
+
+ const QObjectList &children = parent->children();
+ for (int i = 0; i < children.size(); ++i) {
+ QObject* obj = children.at(i);
+ if (mo.cast(obj)) {
+ return obj;
+ }
+ }
+ return 0;
+
+}
diff --git a/kdecore/kernel/kglobal.h b/kdecore/kernel/kglobal.h
new file mode 100644
index 0000000..5aa707e
--- /dev/null
+++ b/kdecore/kernel/kglobal.h
@@ -0,0 +1,580 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Sirtaj Singh Kanq <taj@kde.org>
+ Copyright (C) 2007 Matthias Kretz <kretz@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.
+*/
+#ifndef _KGLOBAL_H
+#define _KGLOBAL_H
+
+#include <kdecore_export.h>
+#include <QtCore/QAtomicPointer>
+#include <sys/types.h>
+#include <QtCore/QObject>
+
+//
+// WARNING!!
+// This code uses undocumented Qt API
+// Do not copy it to your application! Use only the functions that are here!
+// Otherwise, it could break when a new version of Qt ships.
+//
+
+class KComponentData;
+class KCharsets;
+class KConfig;
+class KLocale;
+class KStandardDirs;
+class KSharedConfig;
+template <typename T>
+class KSharedPtr;
+typedef KSharedPtr<KSharedConfig> KSharedConfigPtr;
+
+/// @cond InternalDocs
+
+/**
+ * @internal
+ */
+typedef void (*KdeCleanUpFunction)();
+
+/**
+ * @internal
+ *
+ * Helper class for K_GLOBAL_STATIC to clean up the object on library unload or application
+ * shutdown.
+ */
+class KCleanUpGlobalStatic
+{
+ public:
+ KdeCleanUpFunction func;
+
+ inline ~KCleanUpGlobalStatic() { func(); }
+};
+
+#ifdef Q_CC_MSVC
+/**
+ * @internal
+ *
+ * MSVC seems to give anonymous structs the same name which fails at link time. So instead we name
+ * the struct and hope that by adding the line number to the name it's unique enough to never clash.
+ */
+# define K_GLOBAL_STATIC_STRUCT_NAME(NAME) _k_##NAME##__LINE__
+#else
+/**
+ * @internal
+ *
+ * Make the struct of the K_GLOBAL_STATIC anonymous.
+ */
+# define K_GLOBAL_STATIC_STRUCT_NAME(NAME)
+#endif
+
+/// @endcond
+
+/**
+ * This macro makes it easy to use non-POD types as global statics.
+ * The object is created on first use and creation is threadsafe.
+ *
+ * The object is destructed on library unload or application exit.
+ * Be careful with calling other objects in the destructor of the class
+ * as you have to be sure that they (or objects they depend on) are not already destructed.
+ *
+ * @param TYPE The type of the global static object. Do not add a *.
+ * @param NAME The name of the function to get a pointer to the global static object.
+ *
+ * If you have code that might be called after the global object has been destroyed you can check
+ * for that using the isDestroyed() function.
+ *
+ * If needed (If the destructor of the global object calls other functions that depend on other
+ * global statics (e.g. KConfig::sync) your destructor has to be called before those global statics
+ * are destroyed. A Qt post routine does that.) you can also install a post routine (qAddPostRoutine) to clean up the object
+ * using the destroy() method. If you registered a post routine and the object is destroyed because
+ * of a lib unload you have to call qRemovePostRoutine!
+ *
+ * Example:
+ * @code
+ * class A {
+ * public:
+ * ~A();
+ * ...
+ * };
+ *
+ * K_GLOBAL_STATIC(A, globalA)
+ * // The above creates a new globally static variable named 'globalA' which you
+ * // can use as a pointer to an instance of A.
+ *
+ * void doSomething()
+ * {
+ * // The first time you access globalA a new instance of A will be created automatically.
+ * A *a = globalA;
+ * ...
+ * }
+ *
+ * void doSomethingElse()
+ * {
+ * if (globalA.isDestroyed()) {
+ * return;
+ * }
+ * A *a = globalA;
+ * ...
+ * }
+ *
+ * void installPostRoutine()
+ * {
+ * // A post routine can be used to delete the object when QCoreApplication destructs,
+ * // not adding such a post routine will delete the object normally at program unload
+ * qAddPostRoutine(globalA.destroy);
+ * }
+ *
+ * A::~A()
+ * {
+ * // When you install a post routine you have to remove the post routine from the destructor of
+ * // the class used as global static!
+ * qRemovePostRoutine(globalA.destroy);
+ * }
+ * @endcode
+ *
+ * A common case for the need of deletion on lib unload/app shutdown are Singleton classes. Here's
+ * an example how to do it:
+ * @code
+ * class MySingletonPrivate;
+ * class EXPORT_MACRO MySingleton
+ * {
+ * friend class MySingletonPrivate;
+ * public:
+ * static MySingleton *self();
+ * QString someFunction();
+ *
+ * private:
+ * MySingleton();
+ * ~MySingleton();
+ * };
+ * @endcode
+ * in the .cpp file:
+ * @code
+ * // This class will be instantiated and referenced as a singleton in this example
+ * class MySingletonPrivate
+ * {
+ * public:
+ * QString foo;
+ * MySingleton instance;
+ * };
+ *
+ * K_GLOBAL_STATIC(MySingletonPrivate, mySingletonPrivate)
+ *
+ * MySingleton *MySingleton::self()
+ * {
+ * // returns the singleton; automatically creates a new instance if that has not happened yet.
+ * return &mySingletonPrivate->instance;
+ * }
+ * QString MySingleton::someFunction()
+ * {
+ * // Refencing the singleton directly is possible for your convenience
+ * return mySingletonPrivate->foo;
+ * }
+ * @endcode
+ *
+ * Instead of the above you can use also the following pattern (ignore the name of the namespace):
+ * @code
+ * namespace MySingleton
+ * {
+ * EXPORT_MACRO QString someFunction();
+ * }
+ * @endcode
+ * in the .cpp file:
+ * @code
+ * class MySingletonPrivate
+ * {
+ * public:
+ * QString foo;
+ * };
+ *
+ * K_GLOBAL_STATIC(MySingletonPrivate, mySingletonPrivate)
+ *
+ * QString MySingleton::someFunction()
+ * {
+ * return mySingletonPrivate->foo;
+ * }
+ * @endcode
+ *
+ * Now code that wants to call someFunction() doesn't have to do
+ * @code
+ * MySingleton::self()->someFunction();
+ * @endcode
+ * anymore but instead:
+ * @code
+ * MySingleton::someFunction();
+ * @endcode
+ *
+ * @ingroup KDEMacros
+ */
+#define K_GLOBAL_STATIC(TYPE, NAME) K_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ())
+
+/**
+ * @overload
+ * This is the same as K_GLOBAL_STATIC, but can take arguments that are passed
+ * to the object's constructor
+ *
+ * @param TYPE The type of the global static object. Do not add a *.
+ * @param NAME The name of the function to get a pointer to the global static object.
+ * @param ARGS the list of arguments, between brackets
+ *
+ * Example:
+ * @code
+ * class A
+ * {
+ * public:
+ * A(const char *s, int i);
+ * ...
+ * };
+ *
+ * K_GLOBAL_STATIC_WITH_ARGS(A, globalA, ("foo", 0))
+ * // The above creates a new globally static variable named 'globalA' which you
+ * // can use as a pointer to an instance of A.
+ *
+ * void doSomething()
+ * {
+ * // The first time you access globalA a new instance of A will be created automatically.
+ * A *a = globalA;
+ * ...
+ * }
+ * @endcode
+ *
+ * @ingroup KDEMacros
+ */
+#define K_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS) \
+static QBasicAtomicPointer<TYPE > _k_static_##NAME = Q_BASIC_ATOMIC_INITIALIZER(0); \
+static bool _k_static_##NAME##_destroyed; \
+static struct K_GLOBAL_STATIC_STRUCT_NAME(NAME) \
+{ \
+ inline bool isDestroyed() const \
+ { \
+ return _k_static_##NAME##_destroyed; \
+ } \
+ inline bool exists() const \
+ { \
+ return _k_static_##NAME != 0; \
+ } \
+ inline operator TYPE*() \
+ { \
+ return operator->(); \
+ } \
+ inline TYPE *operator->() \
+ { \
+ if (!_k_static_##NAME) { \
+ if (isDestroyed()) { \
+ qFatal("Fatal Error: Accessed global static '%s *%s()' after destruction. " \
+ "Defined at %s:%d", #TYPE, #NAME, __FILE__, __LINE__); \
+ } \
+ TYPE *x = new TYPE ARGS; \
+ if (!_k_static_##NAME.testAndSetOrdered(0, x) \
+ && _k_static_##NAME != x ) { \
+ delete x; \
+ } else { \
+ static KCleanUpGlobalStatic cleanUpObject = { destroy }; \
+ } \
+ } \
+ return _k_static_##NAME; \
+ } \
+ inline TYPE &operator*() \
+ { \
+ return *operator->(); \
+ } \
+ static void destroy() \
+ { \
+ _k_static_##NAME##_destroyed = true; \
+ TYPE *x = _k_static_##NAME; \
+ _k_static_##NAME = 0; \
+ delete x; \
+ } \
+} NAME;
+
+/**
+ * This class is useful in libraries where you want to make sure that
+ * anyone that uses your library will get the correct catalog loaded.
+ * Just declare a static KCatalogLoader in the global namespace of one of
+ * your cpp files and that will load your catalog once
+ * the global klocale is created
+ *
+ * @param catalogName The name of your catalog
+ *
+ * @since 4.6.2
+ *
+ * Example:
+ * @code
+ * static const KCatalogLoader loader("libkdepim");
+ * @endcode
+ */
+class KDECORE_EXPORT KCatalogLoader
+{
+ public:
+ KCatalogLoader(const QString &catalogName);
+};
+
+/**
+ * Access to the KDE global objects.
+ * KGlobal provides you with pointers of many central
+ * objects that exist only once in the process. It is also
+ * responsible for managing instances of KStaticDeleterBase.
+ *
+ * @see KStaticDeleterBase
+ * @author Sirtaj Singh Kang (taj@kde.org)
+ */
+namespace KGlobal
+{
+
+ /**
+ * Returns the global component data. There is always at least
+ * one instance of a component in one application (in most
+ * cases the application itself).
+ * @return the global component data
+ */
+ KDECORE_EXPORT const KComponentData &mainComponent(); //krazy:exclude=constref (don't mess up ref-counting)
+
+ /**
+ * @internal
+ * Returns whether a main KComponentData is available.
+ */
+ KDECORE_EXPORT bool hasMainComponent();
+
+ /**
+ * Returns the application standard dirs object.
+ * @return the global standard dir object
+ */
+ KDECORE_EXPORT KStandardDirs *dirs();
+
+ /**
+ * Returns the general config object.
+ * @return the global configuration object.
+ */
+ KDECORE_EXPORT KSharedConfigPtr config();
+
+ /**
+ * Inserts the catalog in the main locale object if it exists.
+ * Otherwise the catalog name is stored and added once the main locale gets created
+ *
+ * @since 4.6
+ */
+ KDECORE_EXPORT void insertCatalog(const QString& catalog);
+
+ /**
+ * Returns the global locale object.
+ * @return the global locale object
+ *
+ * Note: in multi-threaded programs, you should call KGlobal::locale()
+ * in the main thread (e.g. in main(), after creating the QCoreApplication
+ * and setting the main component), to ensure that the initialization is
+ * done in the main thread. However KApplication takes care of this, so this
+ * is only needed when not using KApplication.
+ */
+ KDECORE_EXPORT KLocale *locale();
+ /**
+ * @internal
+ * Returns whether KGlobal has a valid KLocale object
+ */
+ KDECORE_EXPORT bool hasLocale();
+
+ /**
+ * The global charset manager.
+ * @return the global charset manager
+ */
+ KDECORE_EXPORT KCharsets *charsets();
+
+ /**
+ * Returns the umask of the process.
+ * @return the umask of the process
+ */
+ KDECORE_EXPORT mode_t umask();
+
+ /**
+ * Creates a static QString.
+ *
+ * To be used inside functions(!) like:
+ * @code
+ * static const QString &myString = KGlobal::staticQString("myText");
+ * @endcode
+ *
+ * @attention Do @b NOT use code such as:
+ * @code
+ * static QString myString = KGlobal::staticQString("myText");
+ * @endcode
+ * This creates a static object (instead of a static reference)
+ * and as you know static objects are EVIL.
+ * @param str the string to create
+ * @return the static string
+ */
+ KDECORE_EXPORT const QString& staticQString(const char *str); //krazy:exclude=constref (doesn't make sense otherwise)
+
+ /**
+ * Creates a static QString.
+ *
+ * To be used inside functions(!) like:
+ * @code
+ * static const QString &myString = KGlobal::staticQString(i18n("My Text"));
+ * @endcode
+ *
+ * @attention Do @b NOT use code such as:
+ * @code
+ * static QString myString = KGlobal::staticQString(i18n("myText"));
+ * @endcode
+ * This creates a static object (instead of a static reference)
+ * and as you know static objects are EVIL.
+ * @param str the string to create
+ * @return the static string
+ */
+ KDECORE_EXPORT const QString& staticQString(const QString &str); //krazy:exclude=constref (doesn't make sense otherwise)
+
+ /**
+ * Tells KGlobal about one more operations that should be finished
+ * before the application exits. The standard behavior is to exit on the
+ * "last window closed" event, but some events should outlive the last window closed
+ * (e.g. a file copy for a file manager, or 'compacting folders on exit' for a mail client),
+ * or simply any application with a system tray icon.
+ *
+ * We have some use cases that we want to take care of (the format is "action refcount"):
+ * - open window -> setAllowQuit(true) 1 ; close window 0 => EXIT
+ * - job start 1; job end 0 [don't exit yet]; open window -> setAllowQuit(true) 1 ; close window 0 => EXIT
+ * - job start 1; open window -> setAllowQuit(true) 2; close window 1; job end 0 => EXIT
+ * - job start 1; open window -> setAllowQuit(true) 2; job end 1; close window 0 => EXIT
+ * - open dialog 0; close dialog 0; => DO NOT EXIT
+ * - job start 1; job end 0; create two main objects 2; delete both main objects 0 => EXIT
+ * - open window -> setAllowQuit(true) 1; add systray icon 2; close window 1 => DO NOT EXIT
+ * - open window -> setAllowQuit(true) 1; add systray icon 2; remove systray icon 1; close window 0 => EXIT
+ * - unit test which opens and closes many windows: should call ref() to avoid subevent-loops quitting too early.
+ *
+ * Note that for this to happen you must call qApp->setQuitOnLastWindowClosed(false),
+ * in main() for instance.
+ */
+ KDECORE_EXPORT void ref();
+
+ /**
+ * Tells KGlobal that one operation such as those described in ref() just finished.
+ * This call makes the QApplication quit if the counter is back to 0.
+ */
+ KDECORE_EXPORT void deref();
+
+ /**
+ * If refcounting reaches 0 (or less), and @p allowQuit is true, the instance of the application
+ * will automatically be exited. Otherwise, the application will not exit automatically.
+ *
+ * This is used by KMainWindow to allow quitting after the first mainwindow is created,
+ * and is used by special applications like kfmclient, to allow quitting even though
+ * no mainwindow was created.
+ *
+ * However, don't try to call setAllowQuit(false) in applications, it doesn't make sense.
+ * If you find that the application quits too early when closing a window, then consider
+ * _what_ is making your application still alive to the user (like a systray icon or a D-Bus object)
+ * and use KGlobal::ref() + KGlobal::deref() in that object.
+ *
+ * @since 4.1.1
+ */
+ KDECORE_EXPORT void setAllowQuit(bool allowQuit);
+
+ /**
+ * The component currently active (useful in a multi-component
+ * application, such as a KParts application).
+ * Don't use this - it's mainly for KAboutDialog and KBugReport.
+ * @internal
+ */
+ KDECORE_EXPORT KComponentData activeComponent();
+
+ /**
+ * Set the active component for use by KAboutDialog and KBugReport.
+ * To be used only by a multi-component (KParts) application.
+ *
+ * @see activeComponent()
+ */
+ KDECORE_EXPORT void setActiveComponent(const KComponentData &d);
+
+ /**
+ * Returns a text for the window caption.
+ *
+ * This may be set by
+ * "-caption", otherwise it will be equivalent to the name of the
+ * executable.
+ * @return the text for the window caption
+ */
+ KDECORE_EXPORT QString caption();
+
+ /// @internal
+ KDECORE_EXPORT QObject* findDirectChild_helper(const QObject* parent, const QMetaObject& mo);
+
+ /**
+ * Returns the child of the given object that can be cast into type T, or 0 if there is no such object.
+ * Unlike QObject::findChild, the search is NOT performed recursively.
+ * @since 4.4
+ */
+ template<typename T>
+ inline T findDirectChild(const QObject* object) {
+ return static_cast<T>(findDirectChild_helper(object, (static_cast<T>(0))->staticMetaObject));
+ }
+
+ /**
+ * For setLocale
+ */
+ enum CopyCatalogs { DoCopyCatalogs, DontCopyCatalogs};
+
+ ///@internal
+ KDECORE_EXPORT void setLocale(KLocale *, CopyCatalogs copy = DoCopyCatalogs);
+}
+
+#ifdef KDE_SUPPORT
+/**
+ * @relates KGlobal
+ * A typesafe function to find the smaller of the two arguments.
+ * @deprecated, used qMin instead
+ */
+#define KMIN(a,b) qMin(a,b)
+/**
+ * @relates KGlobal
+ * A typesafe function to find the larger of the two arguments.
+ * @deprecated, used qMax instead
+ */
+#define KMAX(a,b) qMax(a,b)
+/**
+ * \relates KGlobal
+ * A typesafe function to determine the absolute value of the argument.
+ * @deprecated, used qAbs instead
+ */
+#define KABS(a) qAbs(a)
+/**
+ * @relates KGlobal
+ * A typesafe function that returns x if it's between low and high values.
+ * low if x is smaller than low and high if x is bigger than high.
+ * @deprecated, used qBound instead. Warning, the argument order differs.
+ */
+#define KCLAMP(x,low,high) qBound(low,x,high)
+
+#define kMin qMin
+#define kMax qMax
+#define kAbs qAbs
+
+/**
+ * @relates KGlobal
+ * A typesafe function that returns x if it's between low and high values.
+ * low if x is smaller than low and high if x is bigger than high.
+ * @deprecated, used qBound instead. Warning, the argument order differs.
+ */
+
+template<class T>
+inline KDE_DEPRECATED T kClamp( const T& x, const T& low, const T& high )
+{
+ if ( x < low ) return low;
+ else if ( high < x ) return high;
+ return x;
+}
+
+#endif
+
+#endif // _KGLOBAL_H
+
diff --git a/kdecore/kernel/kglobal_p.h b/kdecore/kernel/kglobal_p.h
new file mode 100644
index 0000000..7d210f0
--- /dev/null
+++ b/kdecore/kernel/kglobal_p.h
@@ -0,0 +1,61 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Sirtaj Singh Kanq <taj@kde.org>
+ Copyright (C) 2007 Matthias Kretz <kretz@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.
+*/
+
+#ifndef KGLOBAL_P_H
+#define KGLOBAL_P_H
+
+#include <kdecore_export.h>
+#include <QtCore/QAtomicPointer>
+
+class KComponentData;
+
+namespace KGlobal
+{
+ ///@internal
+ void newComponentData(const KComponentData &c);
+}
+
+#include "kglobal.h"
+#include "klocale.h"
+#undef QT_NO_TRANSLATION
+#include <QtCore/QTranslator>
+#define QT_NO_TRANSLATION
+
+class KDETranslator : public QTranslator
+{
+public:
+ KDETranslator(QObject *parent) : QTranslator(parent)
+ {
+ setObjectName(QLatin1String("kdetranslator"));
+ }
+
+ virtual QString translate(const char* context,
+ const char *sourceText,
+ const char* message) const
+ {
+ return KGlobal::locale()->translateQt(context, sourceText, message);
+ }
+
+ virtual bool isEmpty() const
+ {
+ return false;
+ }
+};
+
+#endif // KGLOBAL_P_H
diff --git a/kdecore/kernel/kkernel_mac.cpp b/kdecore/kernel/kkernel_mac.cpp
new file mode 100644
index 0000000..9753651
--- /dev/null
+++ b/kdecore/kernel/kkernel_mac.cpp
@@ -0,0 +1,213 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (C) 2008 Benjamin Reed <rangerrick@befunk.com>
+
+ 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 "kkernel_mac.h"
+
+#include <config.h>
+
+#ifdef Q_OS_MACX
+
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <crt_externs.h>
+#include <mach-o/dyld.h>
+
+#include <CoreFoundation/CFBundle.h>
+#include <CoreFoundation/CFString.h>
+#include <CoreFoundation/CFURL.h>
+#include <QtCore/QFile>
+#include <QtCore/QProcess>
+#include <QtCore/QStringList>
+#include <QtCore/qvarlengtharray.h>
+#include <kstandarddirs.h>
+#include <ksharedconfig.h>
+#include <kconfig.h>
+#include <kdebug.h>
+
+int timeout = 3000; // msec
+
+bool dbus_initialized = false;
+
+/**
+ qAppFileName() is not public in qt4/mac, so we need to redo it here
+*/
+
+QString convert_CFString_to_QString(CFStringRef str) {
+ CFIndex length = CFStringGetLength(str);
+ const UniChar *chars = CFStringGetCharactersPtr(str);
+ if (chars)
+ return QString(reinterpret_cast<const QChar *>(chars), length);
+
+ QVarLengthArray<UniChar> buffer(length);
+ CFStringGetCharacters(str, CFRangeMake(0, length), buffer.data());
+ return QString(reinterpret_cast<const QChar *>(buffer.constData()), length);
+}
+
+/**
+ Calling CoreFoundation APIs (which is unavoidable in Qt/Mac) has always had issues
+ on Mac OS X, but as of 10.5 is explicitly disallowed with an exception. As a
+ result, in the case where we would normally fork and then dlopen code, or continue
+ to run other code, we must now fork-and-exec.
+
+ See "CoreFoundation and fork()" at http://developer.apple.com/releasenotes/CoreFoundation/CoreFoundation.html
+*/
+
+void
+mac_fork_and_reexec_self()
+{
+ int argc = *_NSGetArgc();
+ char ** argv = *_NSGetArgv();
+ char * newargv[argc+2];
+ char progname[PATH_MAX];
+ uint32_t buflen = PATH_MAX;
+ _NSGetExecutablePath(progname, &buflen);
+ bool found_psn = false;
+
+ for (int i = 0; i < argc; i++) {
+ newargv[i] = argv[i];
+ }
+
+ newargv[argc] = "--nofork";
+ newargv[argc+1] = NULL;
+
+ int x_fork_result = fork();
+ switch(x_fork_result) {
+
+ case -1:
+#ifndef NDEBUG
+ fprintf(stderr, "Mac OS X workaround fork() failed!\n");
+#endif
+ ::_exit(255);
+ break;
+
+ case 0:
+ // Child
+ execvp(progname, newargv);
+ break;
+
+ default:
+ // Parent
+ _exit(0);
+ break;
+
+ }
+}
+
+/**
+ Set the D-Bus environment based on session bus socket
+*/
+
+bool mac_set_dbus_address(QString value)
+{
+ if (!value.isEmpty() && QFile::exists(value) && (QFile::permissions(value) & QFile::WriteUser)) {
+ value = QLatin1String("unix:path=") + value;
+ ::setenv("DBUS_SESSION_BUS_ADDRESS", value.toLocal8Bit(), 1);
+ kDebug() << "set session bus address to" << value;
+ return true;
+ }
+ return false;
+}
+
+/**
+ Make sure D-Bus is initialized, by any means necessary.
+*/
+
+void mac_initialize_dbus()
+{
+ if (dbus_initialized)
+ return;
+
+ QString dbusVar = QString::fromLocal8Bit(qgetenv("DBUS_SESSION_BUS_ADDRESS"));
+ if (!dbusVar.isEmpty()) {
+ dbus_initialized = true;
+ return;
+ }
+
+ dbusVar = QFile::decodeName(qgetenv("DBUS_LAUNCHD_SESSION_BUS_SOCKET"));
+ if (mac_set_dbus_address(dbusVar)) {
+ dbus_initialized = true;
+ return;
+ }
+
+ QString externalProc;
+ QStringList path = QFile::decodeName(qgetenv("KDEDIRS")).split(QLatin1Char(':')).replaceInStrings(QRegExp(QLatin1String("$")), QLatin1String("/bin"));
+ path << QFile::decodeName(qgetenv("PATH")).split(QLatin1Char(':')) << QLatin1String("/usr/local/bin");
+
+ for (int i = 0; i < path.size(); ++i) {
+ QString testLaunchctl = QString(path.at(i)).append(QLatin1String("/launchctl"));
+ if (QFile(testLaunchctl).exists()) {
+ externalProc = testLaunchctl;
+ break;
+ }
+ }
+
+ if (!externalProc.isEmpty()) {
+ QProcess qp;
+ qp.setTextModeEnabled(true);
+
+ qp.start(externalProc, QStringList() << QLatin1String("getenv") << QLatin1String("DBUS_LAUNCHD_SESSION_BUS_SOCKET"));
+ if (!qp.waitForFinished(timeout)) {
+ kDebug() << "error running" << externalProc << qp.errorString();
+ return;
+ }
+ if (qp.exitCode() != 0) {
+ kDebug() << externalProc << "unsuccessful:" << qp.readAllStandardError();
+ return;
+ }
+
+ QString line = QString::fromAscii(qp.readLine()).trimmed(); // read the first line
+ if (mac_set_dbus_address(line))
+ dbus_initialized = true; // hooray
+ }
+
+ if (dbus_initialized == false) {
+ kDebug() << "warning: unable to initialize D-Bus environment!";
+ }
+
+}
+
+QString mac_app_filename() {
+ static QString appFileName;
+ if (appFileName.isEmpty()) {
+ CFURLRef bundleURL = NULL;
+ CFBundleRef bundle = NULL;
+ CFStringRef bundlePath = NULL;
+
+ bundle = CFBundleGetMainBundle();
+ if (bundle) {
+ bundleURL = CFBundleCopyBundleURL(bundle);
+ bundlePath = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
+
+ if (bundleURL) {
+ CFRelease(bundleURL);
+ }
+
+ if (bundlePath) {
+ appFileName = convert_CFString_to_QString(bundlePath);
+ CFRelease(bundlePath);
+ }
+ }
+ }
+ return appFileName;
+}
+
+#endif
diff --git a/kdecore/kernel/kkernel_mac.h b/kdecore/kernel/kkernel_mac.h
new file mode 100644
index 0000000..ef594c0
--- /dev/null
+++ b/kdecore/kernel/kkernel_mac.h
@@ -0,0 +1,61 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2007 Christian Ehrlicher <ch.ehrlicher@gmx.de>
+
+ 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.
+*/
+
+#ifndef KKERNEL_MAC_H
+#define KKERNEL_MAC_H
+
+#include <QtCore/qglobal.h> // defines Q_OS_MACX
+
+#ifdef Q_OS_MACX
+
+#include <kdecore_export.h>
+#include <QtCore/QString>
+
+#include <CoreFoundation/CFString.h>
+
+/**
+ * @short Mac-specific functions needed in kdecore
+ * @author Benjamin Reed <rangerrick@befunk.com>
+ *
+ * This file provides some Mac-specific functions which
+ * are needed to work around OS issues.
+ */
+
+/**
+ * Convert a CFString to a QString.
+ * Don't export, is for internal kdelibs use only.
+ */
+QString convert_CFString_to_QString(CFStringRef str);
+
+/**
+ * Fork and reexec to work around CoreFoundation issues.
+ */
+KDECORE_EXPORT void mac_fork_and_reexec_self();
+
+/**
+ * Initialize D-Bus Mac-specific stuff if necessary.
+ */
+KDECORE_EXPORT void mac_initialize_dbus();
+
+/**
+ * Get the application name.
+ */
+KDECORE_EXPORT QString mac_app_filename();
+
+#endif // Q_OS_MACX
+#endif // KKERNEL_MAC_H
diff --git a/kdecore/kernel/kkernel_win.cpp b/kdecore/kernel/kkernel_win.cpp
new file mode 100644
index 0000000..2269de0
--- /dev/null
+++ b/kdecore/kernel/kkernel_win.cpp
@@ -0,0 +1,539 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (C) 2004 Jarosław Staniek <staniek@kde.org>
+ Copyright (C) 2007 Christian Ehrlicher <ch.ehrlicher@gmx.de>
+ Copyright (C) 2007 Bernhard Loos <nhuh.put@web.de>
+ Copyright (C) 2008-2009 Ralf Habacker <ralf.habacker@freenet.de>
+
+ 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 "kkernel_win.h"
+
+#include <config.h>
+#include <QtCore/QBool>
+#include <QtCore/QTextCodec>
+
+#ifdef Q_OS_WIN
+
+#include "kglobal.h"
+#include <klocale.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QString>
+#include <QtCore/QLibrary>
+
+#include <windows.h>
+#include <shellapi.h>
+#include <process.h>
+
+// console related includes
+#include <stdio.h>
+#include <fcntl.h>
+#include <io.h>
+#include <iostream>
+#include <fstream>
+#ifndef _USE_OLD_IOSTREAMS
+using namespace std;
+#endif
+
+#if defined(__MINGW32__)
+# define WIN32_CAST_CHAR (const WCHAR*)
+#else
+# define WIN32_CAST_CHAR (LPCWSTR)
+#endif
+
+#ifndef _WIN32_WCE
+static HINSTANCE kdecoreDllInstance = NULL;
+#else
+static HANDLE kdecoreDllInstance = NULL;
+#endif
+#ifdef KDELIBS_STATIC_LIBS
+static bool kde4prefixInitialized = false;
+#endif
+static wchar_t kde4prefixUtf16[MAX_PATH + 2] = L"";
+
+static QString *kde4Prefix = NULL;
+
+void initKde4prefixUtf16()
+{
+ //the path is C:\some\path\kde4\bin\kdecore.dll
+#ifndef _WIN32_WCE
+ GetModuleFileNameW(kdecoreDllInstance, kde4prefixUtf16, MAX_PATH + 1);
+#else
+ GetModuleFileNameW((HMODULE)kdecoreDllInstance, kde4prefixUtf16, MAX_PATH + 1);
+#endif
+ int bs1 = 0, bs2 = 0;
+
+ //we convert \ to / and remove \bin\kdecore.dll from the string
+ int pos;
+ for (pos = 0; pos < MAX_PATH + 1 && kde4prefixUtf16[pos] != 0; ++pos) {
+ if (kde4prefixUtf16[pos] == '\\') {
+ bs1 = bs2;
+ bs2 = pos;
+ kde4prefixUtf16[pos] = '/';
+ }
+ }
+ Q_ASSERT(bs1);
+ Q_ASSERT(pos < MAX_PATH + 1);
+ kde4prefixUtf16[bs1] = '/';
+ kde4prefixUtf16[bs1+1] = 0;
+}
+
+// can't use QCoreApplication::applicationDirPath() because sometimes we
+// don't have an instantiated QCoreApplication
+QString getKde4Prefix()
+{
+#ifdef _WIN32_WCE
+ if (kde4prefixInitialized)
+ return QString::fromUtf16((ushort*) kde4prefixUtf16);
+
+ QDir kde4prefixDir(QString::fromUtf16((ushort*) STATIC_INSTALL_PATH));
+ if (kde4prefixDir.exists()){
+ wcscpy(kde4prefixUtf16, STATIC_INSTALL_PATH);
+ kde4prefixUtf16[wcslen(kde4prefixUtf16)] = 0;
+ kde4prefixInitialized = true;
+ return QString::fromUtf16((ushort*) kde4prefixUtf16);
+ } else {
+ bool ok;
+ QString retval = getWin32RegistryValue(HKEY_LOCAL_MACHINE, "Software\\kde", "KDEDIRS", &ok);
+ if (!ok){
+ return QString();
+ } else {
+ retval = QDir::fromNativeSeparators(retval);
+ wcscpy(kde4prefixUtf16, retval.utf16());
+ kde4prefixUtf16[wcslen(kde4prefixUtf16)] = 0;
+ kde4prefixInitialized = true;
+ return retval;
+ }
+ }
+#else
+ // we can get called after DLL_PROCESS_DETACH!
+ return kde4Prefix ? *kde4Prefix : QString::fromUtf16((ushort*) kde4prefixUtf16);
+#endif
+}
+
+#ifndef KDELIBS_STATIC_LIBS
+/**
+ * The dll entry point - get the instance handle for GetModuleFleNameW
+ * Maybe also some special initialization / cleanup can be done here
+ **/
+extern "C"
+#ifndef _WIN32_WCE
+BOOL WINAPI DllMain ( HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpReserved)
+#else
+BOOL WINAPI DllMain ( HANDLE hinstDLL,DWORD fdwReason,LPVOID lpReserved)
+#endif
+{
+ switch ( fdwReason ) {
+ case DLL_PROCESS_ATTACH:
+ kdecoreDllInstance = hinstDLL;
+ initKde4prefixUtf16();
+ kde4Prefix = new QString( QString::fromUtf16((ushort*) kde4prefixUtf16) );
+ break;
+ case DLL_PROCESS_DETACH:
+ /* msdn:
+ When handling DLL_PROCESS_DETACH, a DLL should free resources such
+ as heap memory only if the DLL is being unloaded dynamically (the
+ lpReserved parameter is NULL). If the process is terminating (the
+ lpvReserved parameter is non-NULL), all threads in the process except
+ the current thread either have exited already or have been explicitly
+ terminated by a call to the ExitProcess function, which might leave
+ some process resources such as heaps in an inconsistent state. In this
+ case, it is not safe for the DLL to clean up the resources. Instead,
+ the DLL should allow the operating system to reclaim the memory.
+ */
+ if( lpReserved == NULL )
+ delete kde4Prefix;
+ kde4Prefix = 0;
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+#endif
+
+/**
+ \return a value from MS Windows native registry.
+ @param key is usually one of HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE
+ constants defined in WinReg.h.
+ @param subKey is a registry subkey defined as a path to a registry folder, eg.
+ "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"
+ ('\' delimiter must be used)
+ @param item is an item inside subKey or "" if default folder's value should be returned
+ @param ok if not null, will be set to true on success and false on failure
+*/
+QString getWin32RegistryValue ( HKEY key, const QString& subKey, const QString& item, bool *ok )
+{
+#define FAILURE \
+ { if (ok) \
+ *ok = false; \
+ return QString(); }
+
+ if ( subKey.isEmpty() )
+ FAILURE;
+ HKEY hKey;
+ TCHAR *lszValue;
+ DWORD dwType=REG_SZ;
+ DWORD dwSize;
+
+ if ( ERROR_SUCCESS!=RegOpenKeyExW ( key, WIN32_CAST_CHAR subKey.utf16(), 0, KEY_READ, &hKey ) )
+ FAILURE;
+
+ if ( ERROR_SUCCESS!=RegQueryValueExW ( hKey, WIN32_CAST_CHAR item.utf16(), NULL, NULL, NULL, &dwSize ) )
+ FAILURE;
+
+ lszValue = new TCHAR[dwSize];
+
+ if ( ERROR_SUCCESS!=RegQueryValueExW ( hKey, WIN32_CAST_CHAR item.utf16(), NULL, &dwType, ( LPBYTE ) lszValue, &dwSize ) ) {
+ delete [] lszValue;
+ FAILURE;
+ }
+ RegCloseKey ( hKey );
+
+ QString res = QString::fromUtf16 ( ( const ushort* ) lszValue );
+ delete [] lszValue;
+
+ if (ok)
+ *ok = true;
+
+ return res;
+}
+
+
+bool showWin32FilePropertyDialog ( const QString& fileName )
+{
+ QString path_ = QDir::convertSeparators ( QFileInfo ( fileName ).absoluteFilePath() );
+
+#ifndef _WIN32_WCE
+ SHELLEXECUTEINFOW execInfo;
+#else
+ SHELLEXECUTEINFO execInfo;
+#endif
+ memset ( &execInfo,0,sizeof ( execInfo ) );
+ execInfo.cbSize = sizeof ( execInfo );
+#ifndef _WIN32_WCE
+ execInfo.fMask = SEE_MASK_INVOKEIDLIST | SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI;
+#else
+ execInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI;
+#endif
+ const QString verb ( QLatin1String ( "properties" ) );
+ execInfo.lpVerb = WIN32_CAST_CHAR verb.utf16();
+ execInfo.lpFile = WIN32_CAST_CHAR path_.utf16();
+#ifndef _WIN32_WCE
+ return ShellExecuteExW ( &execInfo );
+#else
+ return ShellExecuteEx ( &execInfo );
+ //There is no native file property dialog in wince
+ // return false;
+#endif
+}
+
+// note: QLocale().name().left(2).toLatin1() returns the same
+
+QByteArray getWin32LocaleName()
+{
+ bool ok;
+ QString localeNumber = getWin32RegistryValue ( HKEY_CURRENT_USER,
+ QLatin1String("Control Panel\\International"),
+ QLatin1String("Locale"), &ok );
+ if ( !ok )
+ return QByteArray();
+ QString localeName = getWin32RegistryValue ( HKEY_LOCAL_MACHINE,
+ QLatin1String("SYSTEM\\CurrentControlSet\\Control\\Keyboard Layout\\DosKeybCodes"),
+ localeNumber, &ok );
+ if ( !ok )
+ return QByteArray();
+ return localeName.toLatin1();
+}
+
+/**
+ \return a value from MS Windows native registry for shell folder \a folder.
+*/
+QString getWin32ShellFoldersPath ( const QString& folder )
+{
+ return getWin32RegistryValue ( HKEY_CURRENT_USER,
+ QLatin1String("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"),
+ folder );
+}
+
+/**
+ kde and qt debug message printer using windows debug message port
+ */
+static void kMessageOutputDebugString(QtMsgType type, const char *msg)
+{
+ int BUFSIZE=4096;
+ char *buf = new char[BUFSIZE];
+ switch (type) {
+ case QtDebugMsg:
+ strlcpy(buf,"Debug:",BUFSIZE);
+ strlcat(buf,msg,BUFSIZE);
+ break;
+ case QtWarningMsg:
+ strlcpy(buf,"Warning:",BUFSIZE);
+ strlcat(buf,msg,BUFSIZE);
+ break;
+ case QtCriticalMsg:
+ strlcpy(buf,"Critical:",BUFSIZE);
+ strlcat(buf,msg,BUFSIZE);
+ break;
+ case QtFatalMsg:
+ strlcpy(buf,"Fatal:",BUFSIZE);
+ strlcat(buf,msg,BUFSIZE);
+ //abort();
+ break;
+ }
+ strlcat(buf,"\n",BUFSIZE);
+ OutputDebugStringW( (WCHAR*)QString::fromAscii(buf).utf16());
+ delete[] buf;
+}
+
+/**
+ kde and qt debug message printer using FILE pointer based output
+ */
+static void kMessageOutputFileIO(QtMsgType type, const char *msg)
+{
+ switch (type) {
+ case QtDebugMsg:
+ fprintf(stderr, "Debug: %s\n", msg);
+ break;
+ case QtWarningMsg:
+ fprintf(stderr, "Warning: %s\n", msg);
+ break;
+ case QtCriticalMsg:
+ fprintf(stderr, "Critical: %s\n", msg);
+ break;
+ case QtFatalMsg:
+ fprintf(stderr, "Fatal: %s\n", msg);
+ //abort();
+ }
+}
+
+/**
+ try to attach to the parents console
+ \return true if console has been attached, false otherwise
+*/
+typedef BOOL (WINAPI*attachConsolePtr)(DWORD dwProcessId);
+static attachConsolePtr attachConsole = 0;
+static bool attachConsoleResolved = false;
+static bool attachToConsole()
+{
+ if(!attachConsoleResolved) {
+ attachConsoleResolved = true;
+ attachConsole = (attachConsolePtr)QLibrary::resolve(QLatin1String("kernel32"), "AttachConsole");
+ }
+ return attachConsole ? attachConsole(~0U) != 0 : false;
+}
+
+/**
+ redirect stdout, stderr and
+ cout, wcout, cin, wcin, wcerr, cerr, wclog and clog to console
+*/
+static void redirectToConsole()
+{
+//FIXME: for wince we cannot set stdio buffers
+#ifndef _WIN32_WCE
+ int hCrt;
+ FILE *hf;
+ int i;
+
+ hCrt = _open_osfhandle((intptr_t) GetStdHandle(STD_INPUT_HANDLE),_O_TEXT);
+ if(hCrt != -1) {
+ hf = _fdopen( hCrt, "r" );
+ *stdin = *hf;
+ i = setvbuf( stdin, NULL, _IONBF, 0 );
+ }
+
+ hCrt = _open_osfhandle((intptr_t) GetStdHandle(STD_OUTPUT_HANDLE),_O_TEXT);
+ if(hCrt != -1) {
+ hf = _fdopen( hCrt, "w" );
+ *stdout = *hf;
+ i = setvbuf( stdout, NULL, _IONBF, 0 );
+ }
+
+ hCrt = _open_osfhandle((intptr_t) GetStdHandle(STD_ERROR_HANDLE),_O_TEXT);
+ if(hCrt != -1) {
+ hf = _fdopen( hCrt, "w" );
+ *stderr = *hf;
+ i = setvbuf( stderr, NULL, _IONBF, 0 );
+ }
+ // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
+ // point to console as well
+ ios::sync_with_stdio();
+#endif
+}
+
+#include <streambuf>
+
+/**
+ ios related debug message printer for win32
+*/
+class debug_streambuf: public std::streambuf
+{
+ public:
+ debug_streambuf(const char *prefix)
+ {
+ strcpy(buf,prefix);
+ index = rindex = strlen(buf);
+ }
+
+ protected:
+ virtual int overflow(int c = EOF)
+ {
+ if (c != EOF)
+ {
+ char cc = traits_type::to_char_type(c);
+ // @TODO: buffer size checking
+ buf[index++] = cc;
+ if (cc == '\n')
+ {
+ buf[index] = '\0';
+ OutputDebugStringW((WCHAR*)QString::fromAscii(buf).utf16());
+ index = rindex;
+ }
+ }
+ return traits_type::not_eof(c);
+ }
+ private:
+ char buf[4096];
+ int index, rindex;
+};
+
+/**
+ retrieve type of win32 subsystem from the executable header
+ \return type of win32 subsystem - the subsystem types are defined at http://msdn.microsoft.com/en-us/library/ms680339(VS.85).aspx
+*/
+static int subSystem()
+{
+#ifdef _WIN32_WCE
+ // there is only one subsystem on Windows CE
+ return IMAGE_SUBSYSTEM_WINDOWS_CE_GUI;
+#else
+ static int subSystem = -1;
+ if (subSystem > -1)
+ return subSystem;
+
+ // get base address of memory mapped executable
+ PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)GetModuleHandle(NULL);
+ PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS) ((char *)dosHeader + dosHeader->e_lfanew);
+ if (ntHeader->Signature != 0x00004550)
+ {
+ subSystem = IMAGE_SUBSYSTEM_UNKNOWN;
+ return subSystem;
+ }
+ subSystem = ntHeader->OptionalHeader.Subsystem;
+ return subSystem;
+#endif
+}
+
+/**
+ win32 debug and console output handling
+
+ source type of output
+ 1. kde/qt debug system - kDebug(), kWarning(), kFatal(), kError(), qDebug(), qWarning(), qFatal()
+ 2. ios - cout, wcout, wcerr, cerr, wclog and clog
+ 3. FILE * - stdout,stderr
+
+ application console ------------------ output -----------------
+ type available qt/kde-debug ios FILE *
+
+ cui yes console console console
+ cui no win32debug win32debug no output[1]
+
+ gui yes win32debug console console
+ gui no win32debug win32debug win32debug
+
+ win-ce no win32debug win32debug win32debug
+
+[1]no redirect solution for FILE * based output yet
+
+ TODO: report events to the windows event log system
+ http://msdn.microsoft.com/en-us/library/aa363680(VS.85).aspx
+*/
+
+/**
+ setup up debug output
+*/
+static class kMessageOutputInstaller {
+ public:
+ kMessageOutputInstaller() : stdoutBuffer("stdout:"), stderrBuffer("stderr:"), oldStdoutBuffer(0), oldStderrBuffer(0)
+ {
+ if (subSystem() == IMAGE_SUBSYSTEM_WINDOWS_CUI) {
+ if (attachToConsole()) {
+ // setup kde and qt level
+ qInstallMsgHandler(kMessageOutputFileIO);
+ // redirect ios and file io to console
+ redirectToConsole();
+ }
+ else {
+ // setup kde and qt level
+ qInstallMsgHandler(kMessageOutputDebugString);
+ // redirect ios to debug message port
+ oldStdoutBuffer = std::cout.rdbuf(&stdoutBuffer);
+ oldStderrBuffer = std::cerr.rdbuf(&stderrBuffer);
+ }
+ }
+ else if (subSystem() == IMAGE_SUBSYSTEM_WINDOWS_GUI) {
+ // setup kde and qt level
+ qInstallMsgHandler(kMessageOutputDebugString);
+ // try to get a console
+ if (attachToConsole()) {
+ redirectToConsole();
+ }
+ else {
+ // redirect ios to debug message port
+ oldStdoutBuffer = std::cout.rdbuf(&stdoutBuffer);
+ oldStderrBuffer = std::cerr.rdbuf(&stderrBuffer);
+ // TODO: redirect FILE * level to console, no idea how to do yet
+ }
+ } else if (subSystem() == IMAGE_SUBSYSTEM_WINDOWS_CE_GUI) {
+ // do not try to get a console on WinCE systems
+ qInstallMsgHandler(kMessageOutputDebugString);
+ oldStdoutBuffer = std::cout.rdbuf(&stdoutBuffer);
+ oldStderrBuffer = std::cerr.rdbuf(&stderrBuffer);
+ }
+ else
+ qWarning("unknown subsystem %d detected, could not setup qt message handler",subSystem());
+ }
+ ~kMessageOutputInstaller()
+ {
+ if (oldStdoutBuffer)
+ std::cout.rdbuf(oldStdoutBuffer);
+ if (oldStderrBuffer)
+ std::cerr.rdbuf(oldStderrBuffer);
+ }
+
+ private:
+ debug_streambuf stdoutBuffer;
+ debug_streambuf stderrBuffer;
+ std::streambuf* oldStdoutBuffer;
+ std::streambuf* oldStderrBuffer;
+
+} kMessageOutputInstallerInstance;
+
+
+bool isExecutable(const QString &file)
+{
+ return ( file.endsWith( QLatin1String( ".exe" ) ) ||
+ file.endsWith( QLatin1String( ".com" ) ) ||
+ file.endsWith( QLatin1String( ".bat" ) ) ||
+ file.endsWith( QLatin1String( ".sln" ) ) ||
+ file.endsWith( QLatin1String( ".lnk" ) ) );
+
+}
+
+#endif // Q_OS_WIN
diff --git a/kdecore/kernel/kkernel_win.h b/kdecore/kernel/kkernel_win.h
new file mode 100644
index 0000000..f26c668
--- /dev/null
+++ b/kdecore/kernel/kkernel_win.h
@@ -0,0 +1,67 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2007 Christian Ehrlicher <ch.ehrlicher@gmx.de>
+
+ 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.
+*/
+
+#ifndef KKERNEL_WIN_H
+#define KKERNEL_WIN_H
+
+#include <QtCore/QString>
+
+#ifdef Q_OS_WIN
+
+#include <windows.h>
+#include <kdecore_export.h>
+
+/**
+ * @short Windows-specific functions needed in kdecore
+ * @author Christian Ehrlicher <ch.ehrlicher@gmx.de>
+ *
+ * This file provides some Windows-specific functions which
+ * Qt do not provide access to.
+*/
+
+/**
+ \return a value from MS Windows native registry for shell folder \a folder.
+*/
+KDECORE_EXPORT QString getWin32ShellFoldersPath(const QString& folder);
+
+/**
+ Shows native MS Windows file property dialog for a file \a fileName.
+ Return true on success. Only works for local absolute paths.
+ Used by KPropertiesDialog, if possible.
+*/
+KDECORE_EXPORT bool showWin32FilePropertyDialog(const QString& fileName);
+
+/**
+ \return two-letter locale name (like "en" or "pl") taken from MS Windows native registry.
+ Useful when we don't want to rely on KSyCoCa.
+ Used e.g. by kbuildsycoca application.
+*/
+KDECORE_EXPORT QByteArray getWin32LocaleName();
+
+/**
+ \return true when the file is an executable on windows.
+*/
+KDECORE_EXPORT bool isExecutable(const QString &filename);
+
+/**
+ \return a value from MS Windows native registry.
+*/
+QString getWin32RegistryValue ( HKEY key, const QString& subKey, const QString& item, bool *ok = 0 );
+
+#endif // Q_OS_WIN
+#endif // KKERNEL_WIN_H
diff --git a/kdecore/kernel/kstandarddirs.cpp b/kdecore/kernel/kstandarddirs.cpp
new file mode 100644
index 0000000..9426ffc
--- /dev/null
+++ b/kdecore/kernel/kstandarddirs.cpp
@@ -0,0 +1,2159 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Sirtaj Singh Kang <taj@kde.org>
+ Copyright (C) 1999,2007 Stephan Kulow <coolo@kde.org>
+ Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
+ Copyright (C) 2009 David Faure <faure@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.
+*/
+
+/*
+ * Author: Stephan Kulow <coolo@kde.org> and Sirtaj Singh Kang <taj@kde.org>
+ * Generated: Thu Mar 5 16:05:28 EST 1998
+ */
+
+#include "kstandarddirs.h"
+#include "kconfig.h"
+#include "kconfiggroup.h"
+#include "kdebug.h"
+#include "kcomponentdata.h"
+#include "kshell.h"
+#include "kuser.h"
+#include "kde_file.h"
+#include "kkernel_win.h"
+#include "kkernel_mac.h"
+#include "klocale.h"
+
+#include <config.h>
+#include <config-prefix.h>
+#include <config-kstandarddirs.h>
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/param.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <grp.h>
+#ifdef Q_WS_WIN
+#include <windows.h>
+#ifdef _WIN32_WCE
+#include <basetyps.h>
+#endif
+#ifdef Q_WS_WIN64
+// FIXME: did not find a reliable way to fix with kdewin mingw header
+#define interface struct
+#endif
+#include <shlobj.h>
+#include <QtCore/QVarLengthArray>
+#endif
+
+#include <QtCore/QMutex>
+#include <QtCore/QRegExp>
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtCore/QSettings>
+
+class KStandardDirs::KStandardDirsPrivate
+{
+public:
+ KStandardDirsPrivate(KStandardDirs* qq)
+ : m_restrictionsActive(false),
+ m_checkRestrictions(true),
+ m_cacheMutex(QMutex::Recursive), // resourceDirs is recursive
+ q(qq)
+ { }
+
+ bool hasDataRestrictions(const QString &relPath) const;
+ QStringList resourceDirs(const char* type, const QString& subdirForRestrictions);
+ void createSpecialResource(const char*);
+
+ bool m_restrictionsActive : 1;
+ bool m_checkRestrictions : 1;
+ QMap<QByteArray, bool> m_restrictions;
+
+ QStringList xdgdata_prefixes;
+ QStringList xdgconf_prefixes;
+ QStringList m_prefixes;
+
+ // Directory dictionaries
+ QMap<QByteArray, QStringList> m_absolutes; // For each resource type, the list of absolute paths, from most local (most priority) to most global
+ QMap<QByteArray, QStringList> m_relatives; // Same with relative paths
+ // The search path is "all relative paths" < "all absolute paths", from most priority to least priority.
+
+ // Caches (protected by mutex in const methods, cf ctor docu)
+ QMap<QByteArray, QStringList> m_dircache;
+ QMap<QByteArray, QString> m_savelocations;
+ QMutex m_cacheMutex;
+
+ KStandardDirs* q;
+};
+
+/* If you add a new resource type here, make sure to
+ * 1) regenerate using "kdesdk/scripts/generate_string_table.pl types < tmpfile" with the data below in tmpfile.
+ * 2) update the KStandardDirs class documentation
+ * 3) update the list in kde-config.cpp
+
+data
+share/apps
+html
+share/doc/HTML
+icon
+share/icons
+config
+share/config
+pixmap
+share/pixmaps
+apps
+share/applnk
+sound
+share/sounds
+locale
+share/locale
+services
+share/kde4/services
+servicetypes
+share/kde4/servicetypes
+mime
+share/mimelnk
+cgi
+cgi-bin
+wallpaper
+share/wallpapers
+templates
+share/templates
+exe
+bin
+module
+%lib/kde4
+qtplugins
+%lib/kde4/plugins
+kcfg
+share/config.kcfg
+emoticons
+share/emoticons
+xdgdata-apps
+applications
+xdgdata-icon
+icons
+xdgdata-pixmap
+pixmaps
+xdgdata-dirs
+desktop-directories
+xdgdata-mime
+mime
+xdgconf-menu
+menus
+xdgconf-autostart
+autostart
+*/
+
+static const char types_string[] =
+ "data\0"
+ "share/apps\0"
+ "html\0"
+ "share/doc/HTML\0"
+ "icon\0"
+ "share/icons\0"
+ "config\0"
+ "share/config\0"
+ "pixmap\0"
+ "share/pixmaps\0"
+ "apps\0"
+ "share/applnk\0"
+ "sound\0"
+ "share/sounds\0"
+ "locale\0"
+ "share/locale\0"
+ "services\0"
+ "share/kde4/services\0"
+ "servicetypes\0"
+ "share/kde4/servicetypes\0"
+ "mime\0"
+ "share/mimelnk\0"
+ "cgi\0"
+ "cgi-bin\0"
+ "wallpaper\0"
+ "share/wallpapers\0"
+ "templates\0"
+ "share/templates\0"
+ "exe\0"
+ "bin\0"
+ "module\0"
+ "%lib/kde4\0"
+ "qtplugins\0"
+ "%lib/kde4/plugins\0"
+ "kcfg\0"
+ "share/config.kcfg\0"
+ "emoticons\0"
+ "share/emoticons\0"
+ "xdgdata-apps\0"
+ "applications\0"
+ "xdgdata-icon\0"
+ "icons\0"
+ "xdgdata-pixmap\0"
+ "pixmaps\0"
+ "xdgdata-dirs\0"
+ "desktop-directories\0"
+ "xdgdata-mime\0"
+ "xdgconf-menu\0"
+ "menus\0"
+ "xdgconf-autostart\0"
+ "autostart\0"
+ "\0";
+
+static const int types_indices[] = {
+ 0, 5, 16, 21, 36, 41, 53, 60,
+ 73, 80, 94, 99, 112, 118, 131, 138,
+ 151, 160, 180, 193, 217, 222, 236, 240,
+ 248, 258, 275, 285, 301, 305, 309, 316,
+ 326, 336, 354, 359, 377, 387, 403, 416,
+ 429, 442, 448, 463, 471, 484, 504, 217,
+ 517, 530, 536, 554, -1
+};
+
+static void tokenize(QStringList& token, const QString& str,
+ const QString& delim);
+
+KStandardDirs::KStandardDirs()
+ : d(new KStandardDirsPrivate(this))
+{
+ addKDEDefaults();
+}
+
+KStandardDirs::~KStandardDirs()
+{
+ delete d;
+}
+
+bool KStandardDirs::isRestrictedResource(const char *type, const QString& relPath) const
+{
+ if (!d->m_restrictionsActive)
+ return false;
+
+ if (d->m_restrictions.value(type, false))
+ return true;
+
+ if (strcmp(type, "data")==0 && d->hasDataRestrictions(relPath))
+ return true;
+
+ return false;
+}
+
+bool KStandardDirs::KStandardDirsPrivate::hasDataRestrictions(const QString &relPath) const
+{
+ QString key;
+ const int i = relPath.indexOf(QLatin1Char('/'));
+ if (i != -1)
+ key = QString::fromLatin1("data_") + relPath.left(i);
+ else
+ key = QString::fromLatin1("data_") + relPath;
+
+ return m_restrictions.value(key.toLatin1(), false);
+}
+
+
+QStringList KStandardDirs::allTypes() const
+{
+ QStringList list;
+ for (int i = 0; types_indices[i] != -1; i += 2)
+ list.append(QLatin1String(types_string + types_indices[i]));
+ // Those are added manually by addKDEDefaults
+ list.append(QString::fromLatin1("lib"));
+ //list.append(QString::fromLatin1("home")); // undocumented on purpose, said Waldo in r113855.
+
+ // Those are handled by resourceDirs() itself
+ list.append(QString::fromLatin1("socket"));
+ list.append(QString::fromLatin1("tmp"));
+ list.append(QString::fromLatin1("cache"));
+ // Those are handled by installPath()
+ list.append(QString::fromLatin1("include"));
+
+ // If you add anything here, make sure kde-config.cpp has a description for it.
+
+ return list;
+}
+
+static void priorityAdd(QStringList &prefixes, const QString& dir, bool priority)
+{
+ if (priority && !prefixes.isEmpty())
+ {
+ // Add in front but behind $KDEHOME
+ QStringList::iterator it = prefixes.begin();
+ it++;
+ prefixes.insert(it, dir);
+ }
+ else
+ {
+ prefixes.append(dir);
+ }
+}
+
+void KStandardDirs::addPrefix( const QString& _dir )
+{
+ addPrefix(_dir, false);
+}
+
+void KStandardDirs::addPrefix( const QString& _dir, bool priority )
+{
+ if (_dir.isEmpty())
+ return;
+
+ QString dir = _dir;
+ if (dir.at(dir.length() - 1) != QLatin1Char('/'))
+ dir += QLatin1Char('/');
+
+ if (!d->m_prefixes.contains(dir)) {
+ priorityAdd(d->m_prefixes, dir, priority);
+ d->m_dircache.clear();
+ }
+}
+
+void KStandardDirs::addXdgConfigPrefix( const QString& _dir )
+{
+ addXdgConfigPrefix(_dir, false);
+}
+
+void KStandardDirs::addXdgConfigPrefix( const QString& _dir, bool priority )
+{
+ if (_dir.isEmpty())
+ return;
+
+ QString dir = _dir;
+ if (dir.at(dir.length() - 1) != QLatin1Char('/'))
+ dir += QLatin1Char('/');
+
+ if (!d->xdgconf_prefixes.contains(dir)) {
+ priorityAdd(d->xdgconf_prefixes, dir, priority);
+ d->m_dircache.clear();
+ }
+}
+
+void KStandardDirs::addXdgDataPrefix( const QString& _dir )
+{
+ addXdgDataPrefix(_dir, false);
+}
+
+void KStandardDirs::addXdgDataPrefix( const QString& _dir, bool priority )
+{
+ if (_dir.isEmpty())
+ return;
+
+ QString dir = _dir;
+ if (dir.at(dir.length() - 1) != QLatin1Char('/'))
+ dir += QLatin1Char('/');
+
+ if (!d->xdgdata_prefixes.contains(dir)) {
+ priorityAdd(d->xdgdata_prefixes, dir, priority);
+ d->m_dircache.clear();
+ }
+}
+
+QString KStandardDirs::kfsstnd_prefixes()
+{
+ return d->m_prefixes.join(QString(QLatin1Char(KPATH_SEPARATOR)));
+}
+
+QString KStandardDirs::kfsstnd_xdg_conf_prefixes()
+{
+ return d->xdgconf_prefixes.join(QString(QLatin1Char(KPATH_SEPARATOR)));
+}
+
+QString KStandardDirs::kfsstnd_xdg_data_prefixes()
+{
+ return d->xdgdata_prefixes.join(QString(QLatin1Char(KPATH_SEPARATOR)));
+}
+
+#ifndef KDE_NO_DEPRECATED
+bool KStandardDirs::addResourceType( const char *type,
+ const QString& relativename,
+ bool priority )
+{
+ return addResourceType( type, 0, relativename, priority);
+}
+#endif
+
+bool KStandardDirs::addResourceType( const char *type,
+ const char *basetype,
+ const QString& relativename,
+ bool priority )
+{
+ if (relativename.isEmpty())
+ return false;
+
+ QString copy = relativename;
+ if (basetype)
+ copy = QLatin1Char('%') + QString::fromLatin1(basetype) + QLatin1Char('/') + relativename;
+
+ if (!copy.endsWith(QLatin1Char('/')))
+ copy += QLatin1Char('/');
+
+ QByteArray typeBa = type;
+ QStringList& rels = d->m_relatives[typeBa]; // find or insert
+
+ if (!rels.contains(copy)) {
+ if (priority)
+ rels.prepend(copy);
+ else
+ rels.append(copy);
+ // clean the caches
+ d->m_dircache.remove(typeBa);
+ d->m_savelocations.remove(typeBa);
+ return true;
+ }
+ return false;
+}
+
+bool KStandardDirs::addResourceDir( const char *type,
+ const QString& absdir,
+ bool priority)
+{
+ if (absdir.isEmpty() || !type)
+ return false;
+ // find or insert entry in the map
+ QString copy = absdir;
+ if (copy.at(copy.length() - 1) != QLatin1Char('/'))
+ copy += QLatin1Char('/');
+
+ QByteArray typeBa = type;
+ QStringList &paths = d->m_absolutes[typeBa];
+ if (!paths.contains(copy)) {
+ if (priority)
+ paths.prepend(copy);
+ else
+ paths.append(copy);
+ // clean the caches
+ d->m_dircache.remove(typeBa);
+ d->m_savelocations.remove(typeBa);
+ return true;
+ }
+ return false;
+}
+
+QString KStandardDirs::findResource( const char *type,
+ const QString& _filename ) const
+{
+ if (!QDir::isRelativePath(_filename))
+ return !KGlobal::hasLocale() ? _filename // absolute dirs are absolute dirs, right? :-/
+ : KGlobal::locale()->localizedFilePath(_filename); // -- almost.
+
+#if 0
+ kDebug(180) << "Find resource: " << type;
+ for (QStringList::ConstIterator pit = m_prefixes.begin();
+ pit != m_prefixes.end();
+ ++pit)
+ {
+ kDebug(180) << "Prefix: " << *pit;
+ }
+#endif
+
+ QString filename(_filename);
+#ifdef Q_OS_WIN
+ if(strcmp(type, "exe") == 0) {
+ if(!filename.endsWith(QLatin1String(".exe")))
+ filename += QLatin1String(".exe");
+ }
+#endif
+ const QString dir = findResourceDir(type, filename);
+ if (dir.isEmpty())
+ return dir;
+ else
+ return !KGlobal::hasLocale() ? dir + filename
+ : KGlobal::locale()->localizedFilePath(dir + filename);
+}
+
+static quint32 updateHash(const QString &file, quint32 hash)
+{
+ KDE_struct_stat buff;
+ if ((KDE::access(file, R_OK) == 0) && (KDE::stat(file, &buff) == 0) && (S_ISREG(buff.st_mode))) {
+ hash = hash + static_cast<quint32>(buff.st_ctime);
+ }
+ return hash;
+}
+
+quint32 KStandardDirs::calcResourceHash( const char *type,
+ const QString& filename,
+ SearchOptions options ) const
+{
+ quint32 hash = 0;
+
+ if (!QDir::isRelativePath(filename))
+ {
+ // absolute dirs are absolute dirs, right? :-/
+ return updateHash(filename, hash);
+ }
+ QStringList candidates = d->resourceDirs(type, filename);
+
+ foreach ( const QString& candidate, candidates )
+ {
+ hash = updateHash(candidate + filename, hash);
+ if ( !( options & Recursive ) && hash ) {
+ return hash;
+ }
+ }
+ return hash;
+}
+
+
+QStringList KStandardDirs::findDirs( const char *type,
+ const QString& reldir ) const
+{
+ QDir testdir;
+ QStringList list;
+ if (!QDir::isRelativePath(reldir))
+ {
+ testdir.setPath(reldir);
+ if (testdir.exists())
+ {
+ if (reldir.endsWith(QLatin1Char('/')))
+ list.append(reldir);
+ else
+ list.append(reldir+QLatin1Char('/'));
+ }
+ return list;
+ }
+
+ const QStringList candidates = d->resourceDirs(type, reldir);
+
+ for (QStringList::ConstIterator it = candidates.begin();
+ it != candidates.end(); ++it) {
+ testdir.setPath(*it + reldir);
+ if (testdir.exists())
+ list.append(testdir.absolutePath() + QLatin1Char('/'));
+ }
+
+ return list;
+}
+
+QString KStandardDirs::findResourceDir( const char *type,
+ const QString& _filename) const
+{
+#ifndef NDEBUG
+ if (_filename.isEmpty()) {
+ kWarning() << "filename for type " << type << " in KStandardDirs::findResourceDir is not supposed to be empty!!";
+ return QString();
+ }
+#endif
+
+ QString filename(_filename);
+#ifdef Q_OS_WIN
+ if(strcmp(type, "exe") == 0) {
+ if(!filename.endsWith(QLatin1String(".exe")))
+ filename += QLatin1String(".exe");
+ }
+#endif
+ const QStringList candidates = d->resourceDirs(type, filename);
+
+ for (QStringList::ConstIterator it = candidates.begin();
+ it != candidates.end(); ++it) {
+ if (exists(*it + filename)) {
+ return *it;
+ }
+ }
+
+#ifndef NDEBUG
+ if(false && strcmp(type, "locale"))
+ kDebug(180) << "KStdDirs::findResDir(): can't find \"" << filename << "\" in type \"" << type << "\".";
+#endif
+
+ return QString();
+}
+
+bool KStandardDirs::exists(const QString &fullPath)
+{
+#ifdef Q_OS_WIN
+ // access() and stat() give a stupid error message to the user
+ // if the path is not accessible at all (e.g. no disk in A:/ and
+ // we do stat("A:/.directory")
+ if (fullPath.endsWith(QLatin1Char('/')))
+ return QDir(fullPath).exists();
+ return QFileInfo(fullPath).exists();
+#else
+ KDE_struct_stat buff;
+ QByteArray cFullPath = QFile::encodeName(fullPath);
+ if (access(cFullPath, R_OK) == 0 && KDE_stat( cFullPath, &buff ) == 0) {
+ if (!fullPath.endsWith(QLatin1Char('/'))) {
+ if (S_ISREG( buff.st_mode ))
+ return true;
+ } else
+ if (S_ISDIR( buff.st_mode ))
+ return true;
+ }
+ return false;
+#endif
+}
+
+static void lookupDirectory(const QString& path, const QString &relPart,
+ const QRegExp &regexp,
+ QStringList& list,
+ QStringList& relList,
+ bool recursive, bool unique)
+{
+ const QString pattern = regexp.pattern();
+ if (recursive || pattern.contains(QLatin1Char('?')) || pattern.contains(QLatin1Char('*')))
+ {
+ if (path.isEmpty()) //for sanity
+ return;
+#ifdef Q_WS_WIN
+ QString path_ = path + QLatin1String( "*.*" );
+ WIN32_FIND_DATA findData;
+ HANDLE hFile = FindFirstFile( (LPWSTR)path_.utf16(), &findData );
+ if( hFile == INVALID_HANDLE_VALUE )
+ return;
+ do {
+ const int len = wcslen( findData.cFileName );
+ if (!( findData.cFileName[0] == '.' &&
+ findData.cFileName[1] == '\0' ) &&
+ !( findData.cFileName[0] == '.' &&
+ findData.cFileName[1] == '.' &&
+ findData.cFileName[2] == '\0' ) &&
+ ( findData.cFileName[len-1] != '~' ) ) {
+ QString fn = QString::fromUtf16( (const unsigned short*)findData.cFileName );
+ if (!recursive && !regexp.exactMatch(fn))
+ continue; // No match
+ QString pathfn = path + fn;
+ bool bIsDir = ( ( findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) == FILE_ATTRIBUTE_DIRECTORY );
+ if ( recursive ) {
+ if ( bIsDir ) {
+ lookupDirectory(pathfn + QLatin1Char('/'),
+ relPart + fn + QLatin1Char('/'),
+ regexp, list, relList, recursive, unique);
+ }
+ if (!regexp.exactMatch(fn))
+ continue; // No match
+ }
+ if ( !bIsDir )
+ {
+ if ( !unique || !relList.contains(relPart + fn) )
+ {
+ list.append( pathfn );
+ relList.append( relPart + fn );
+ }
+ }
+ }
+ } while( FindNextFile( hFile, &findData ) != 0 );
+ FindClose( hFile );
+#else
+ // We look for a set of files.
+ DIR *dp = opendir( QFile::encodeName(path));
+ if (!dp)
+ return;
+
+ assert(path.endsWith(QLatin1Char('/')));
+
+ struct dirent *ep;
+
+ while( ( ep = readdir( dp ) ) != 0L )
+ {
+ QString fn( QFile::decodeName(ep->d_name));
+ if (fn == QString::fromLatin1(".") || fn == QString::fromLatin1("..") || fn.at(fn.length() - 1) == QLatin1Char('~'))
+ continue;
+
+ if (!recursive && !regexp.exactMatch(fn))
+ continue; // No match
+
+ bool isDir;
+ bool isReg;
+
+ QString pathfn = path + fn;
+#ifdef HAVE_DIRENT_D_TYPE
+ isDir = ep->d_type == DT_DIR;
+ isReg = ep->d_type == DT_REG;
+
+ if (ep->d_type == DT_UNKNOWN || ep->d_type == DT_LNK)
+#endif
+ {
+ KDE_struct_stat buff;
+ if ( KDE::stat( pathfn, &buff ) != 0 ) {
+ kDebug(180) << "Error stat'ing " << pathfn << " : " << perror;
+ continue; // Couldn't stat (e.g. no read permissions)
+ }
+ isReg = S_ISREG (buff.st_mode);
+ isDir = S_ISDIR (buff.st_mode);
+ }
+
+ if ( recursive ) {
+ if ( isDir ) {
+ lookupDirectory(pathfn + QLatin1Char('/'), relPart + fn + QLatin1Char('/'), regexp, list, relList, recursive, unique);
+ }
+ if (!regexp.exactMatch(fn))
+ continue; // No match
+ }
+ if ( isReg )
+ {
+ if (!unique || !relList.contains(relPart + fn))
+ {
+ list.append( pathfn );
+ relList.append( relPart + fn );
+ }
+ }
+ }
+ closedir( dp );
+#endif
+ }
+ else
+ {
+ // We look for a single file.
+ QString fn = pattern;
+ QString pathfn = path + fn;
+ KDE_struct_stat buff;
+ if ( KDE::stat( pathfn, &buff ) != 0 )
+ return; // File not found
+ if ( S_ISREG( buff.st_mode))
+ {
+ if (!unique || !relList.contains(relPart + fn))
+ {
+ list.append( pathfn );
+ relList.append( relPart + fn );
+ }
+ }
+ }
+}
+
+static void lookupPrefix(const QString& prefix, const QString& relpath,
+ const QString& relPart,
+ const QRegExp &regexp,
+ QStringList& list,
+ QStringList& relList,
+ bool recursive, bool unique)
+{
+ if (relpath.isEmpty()) {
+ if (recursive)
+ Q_ASSERT(prefix != QLatin1String("/")); // we don't want to recursively list the whole disk!
+ lookupDirectory(prefix, relPart, regexp, list,
+ relList, recursive, unique);
+ return;
+ }
+ QString path;
+ QString rest;
+
+ int slash = relpath.indexOf(QLatin1Char('/'));
+ if (slash < 0)
+ rest = relpath.left(relpath.length() - 1);
+ else {
+ path = relpath.left(slash);
+ rest = relpath.mid(slash + 1);
+ }
+
+ if (prefix.isEmpty()) //for sanity
+ return;
+#ifndef Q_WS_WIN
+ // what does this assert check ?
+ assert(prefix.endsWith(QLatin1Char('/')));
+#endif
+ if (path.contains(QLatin1Char('*')) || path.contains(QLatin1Char('?'))) {
+
+ QRegExp pathExp(path, Qt::CaseSensitive, QRegExp::Wildcard);
+
+#ifdef Q_WS_WIN
+ QString prefix_ = prefix + QLatin1String( "*.*" );
+ WIN32_FIND_DATA findData;
+ HANDLE hFile = FindFirstFile( (LPWSTR)prefix_.utf16(), &findData );
+ if( hFile == INVALID_HANDLE_VALUE )
+ return;
+ do {
+ const int len = wcslen( findData.cFileName );
+ if (!( findData.cFileName[0] == '.' &&
+ findData.cFileName[1] == '\0' ) &&
+ !( findData.cFileName[0] == '.' &&
+ findData.cFileName[1] == '.' &&
+ findData.cFileName[2] == '\0' ) &&
+ ( findData.cFileName[len-1] != '~' ) ) {
+ const QString fn = QString::fromUtf16( (const unsigned short*)findData.cFileName );
+ if ( !pathExp.exactMatch(fn) )
+ continue; // No match
+ if ( ( findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) == FILE_ATTRIBUTE_DIRECTORY )
+ lookupPrefix(prefix + fn + QLatin1Char('/'),
+ rest, relPart + fn + QLatin1Char('/'),
+ regexp, list, relList, recursive, unique);
+ }
+ } while( FindNextFile( hFile, &findData ) != 0 );
+ FindClose( hFile );
+#else
+ DIR *dp = opendir( QFile::encodeName(prefix) );
+ if (!dp) {
+ return;
+ }
+
+ struct dirent *ep;
+
+ while( ( ep = readdir( dp ) ) != 0L )
+ {
+ QString fn( QFile::decodeName(ep->d_name));
+ if (fn == QLatin1String(".") || fn == QLatin1String("..") || fn.at(fn.length() - 1) == QLatin1Char('~'))
+ continue;
+
+ if ( !pathExp.exactMatch(fn) )
+ continue; // No match
+ QString rfn = relPart+fn;
+ fn = prefix + fn;
+
+ bool isDir;
+
+#ifdef HAVE_DIRENT_D_TYPE
+ isDir = ep->d_type == DT_DIR;
+
+ if (ep->d_type == DT_UNKNOWN || ep->d_type == DT_LNK)
+#endif
+ {
+ QString pathfn = path + fn;
+ KDE_struct_stat buff;
+ if ( KDE::stat( fn, &buff ) != 0 ) {
+ kDebug(180) << "Error stat'ing " << fn << " : " << perror;
+ continue; // Couldn't stat (e.g. no read permissions)
+ }
+ isDir = S_ISDIR (buff.st_mode);
+ }
+ if ( isDir )
+ lookupPrefix(fn + QLatin1Char('/'), rest, rfn + QLatin1Char('/'), regexp, list, relList, recursive, unique);
+ }
+
+ closedir( dp );
+#endif
+ } else {
+ // Don't stat, if the dir doesn't exist we will find out
+ // when we try to open it.
+ lookupPrefix(prefix + path + QLatin1Char('/'), rest,
+ relPart + path + QLatin1Char('/'), regexp, list,
+ relList, recursive, unique);
+ }
+}
+
+QStringList
+KStandardDirs::findAllResources( const char *type,
+ const QString& filter,
+ SearchOptions options,
+ QStringList &relList) const
+{
+ QString filterPath;
+ QString filterFile;
+
+ if ( !filter.isEmpty() )
+ {
+ int slash = filter.lastIndexOf(QLatin1Char('/'));
+ if (slash < 0) {
+ filterFile = filter;
+ } else {
+ filterPath = filter.left(slash + 1);
+ filterFile = filter.mid(slash + 1);
+ }
+ }
+
+ QStringList candidates;
+ if ( !QDir::isRelativePath(filter) ) // absolute path
+ {
+#ifdef Q_OS_WIN
+ candidates << filterPath.left(3); //e.g. "C:\"
+ filterPath = filterPath.mid(3);
+#else
+ candidates << QString::fromLatin1("/");
+ filterPath = filterPath.mid(1);
+#endif
+ }
+ else
+ {
+ candidates = d->resourceDirs(type, filter);
+ }
+
+ if (filterFile.isEmpty()) {
+ filterFile = QString(QLatin1Char('*'));
+ }
+
+ QRegExp regExp(filterFile, Qt::CaseSensitive, QRegExp::Wildcard);
+
+ QStringList list;
+ foreach ( const QString& candidate, candidates )
+ {
+ lookupPrefix(candidate, filterPath, QString(), regExp, list,
+ relList, options & Recursive, options & NoDuplicates);
+ }
+
+ return list;
+}
+
+QStringList
+KStandardDirs::findAllResources( const char *type,
+ const QString& filter,
+ SearchOptions options ) const
+{
+ QStringList relList;
+ return findAllResources(type, filter, options, relList);
+}
+
+// ####### KDE4: should this be removed, in favor of QDir::canonicalPath()?
+// aseigo: QDir::canonicalPath returns QString() if the dir doesn't exist
+// and this method is often used with the expectation for it to work
+// even if the directory doesn't exist. so ... no, we can't drop this
+// yet
+QString
+KStandardDirs::realPath(const QString &dirname)
+{
+#ifdef Q_WS_WIN
+ const QString strRet = realFilePath(dirname);
+ if (!strRet.endsWith(QLatin1Char('/')))
+ return strRet + QLatin1Char('/');
+ return strRet;
+#else
+ if (dirname.isEmpty() || (dirname.size() == 1 && dirname.at(0) == QLatin1Char('/')))
+ return dirname;
+
+ if (dirname.at(0) != QLatin1Char('/')) {
+ qWarning("realPath called with a relative path '%s', please fix", qPrintable(dirname));
+ return dirname;
+ }
+
+ char realpath_buffer[MAXPATHLEN + 1];
+ memset(realpath_buffer, 0, MAXPATHLEN + 1);
+
+ /* If the path contains symlinks, get the real name */
+ if (realpath( QFile::encodeName(dirname).constData(), realpath_buffer) != 0) {
+ // success, use result from realpath
+ int len = strlen(realpath_buffer);
+ realpath_buffer[len] = '/';
+ realpath_buffer[len+1] = 0;
+ return QFile::decodeName(realpath_buffer);
+ }
+
+ // Does not exist yet; resolve symlinks in parent dirs then.
+ // This ensures that once the directory exists, it will still be resolved
+ // the same way, so that the general rule that KStandardDirs always returns
+ // canonical paths stays true, and app code can compare paths more easily.
+ QString dir = dirname;
+ if (!dir.endsWith(QLatin1Char('/')))
+ dir += QLatin1Char('/');
+ QString relative;
+ while (!KStandardDirs::exists(dir)) {
+ //qDebug() << "does not exist:" << dir;
+ const int pos = dir.lastIndexOf(QLatin1Char('/'), -2);
+ Q_ASSERT(pos >= 0); // what? even "/" doesn't exist?
+ relative.prepend(dir.mid(pos+1)); // keep "subdir/"
+ dir = dir.left(pos+1);
+ Q_ASSERT(dir.endsWith(QLatin1Char('/')));
+ }
+ Q_ASSERT(!relative.isEmpty()); // infinite recursion ahead
+ if (!relative.isEmpty()) {
+ //qDebug() << "done, resolving" << dir << "and adding" << relative;
+ dir = realPath(dir) + relative;
+ }
+ return dir;
+#endif
+}
+
+// ####### KDE4: should this be removed, in favor of QDir::canonicalPath()?
+// aseigo: QDir::canonicalPath returns QString() if the dir doesn't exist
+// and this method is often used with the expectation for it to work
+// even if the directory doesn't exist. so ... no, we can't drop this
+// yet
+QString
+KStandardDirs::realFilePath(const QString &filename)
+{
+#ifdef Q_WS_WIN
+ LPCWSTR lpIn = (LPCWSTR)filename.utf16();
+ QVarLengthArray<WCHAR, MAX_PATH> buf(MAX_PATH);
+ DWORD len = GetFullPathNameW(lpIn, buf.size(), buf.data(), NULL);
+ if (len > (DWORD)buf.size()) {
+ buf.resize(len);
+ len = GetFullPathNameW(lpIn, buf.size(), buf.data(), NULL);
+ }
+ if (len == 0)
+ return QString();
+ return QString::fromUtf16((const unsigned short*)buf.data()).replace(QLatin1Char('\\'),QLatin1Char('/')).toLower();
+#else
+ char realpath_buffer[MAXPATHLEN + 1];
+ memset(realpath_buffer, 0, MAXPATHLEN + 1);
+
+ /* If the path contains symlinks, get the real name */
+ if (realpath( QFile::encodeName(filename).constData(), realpath_buffer) != 0) {
+ // success, use result from realpath
+ return QFile::decodeName(realpath_buffer);
+ }
+
+ return filename;
+#endif
+}
+
+
+void KStandardDirs::KStandardDirsPrivate::createSpecialResource(const char *type)
+{
+ char hostname[256];
+ hostname[0] = 0;
+ gethostname(hostname, 255);
+ const QString localkdedir = m_prefixes.first();
+ QString dir = localkdedir + QString::fromLatin1(type) + QLatin1Char('-') + QString::fromLocal8Bit(hostname);
+ char link[1024];
+ link[1023] = 0;
+ int result = readlink(QFile::encodeName(dir).constData(), link, 1023);
+ bool relink = (result == -1) && (errno == ENOENT);
+ if (result > 0)
+ {
+ link[result] = 0;
+ if (!QDir::isRelativePath(QFile::decodeName(link)))
+ {
+ KDE_struct_stat stat_buf;
+ int res = KDE::lstat(QFile::decodeName(link), &stat_buf);
+ if ((res == -1) && (errno == ENOENT))
+ {
+ relink = true;
+ }
+ else if ((res == -1) || (!S_ISDIR(stat_buf.st_mode)))
+ {
+ fprintf(stderr, "Error: \"%s\" is not a directory.\n", link);
+ relink = true;
+ }
+ else if (stat_buf.st_uid != getuid())
+ {
+ fprintf(stderr, "Error: \"%s\" is owned by uid %d instead of uid %d.\n", link, stat_buf.st_uid, getuid());
+ relink = true;
+ }
+ }
+ }
+#ifdef Q_WS_WIN
+ if (relink)
+ {
+ if (!makeDir(dir, 0700))
+ fprintf(stderr, "failed to create \"%s\"", qPrintable(dir));
+ else
+ result = readlink(QFile::encodeName(dir).constData(), link, 1023);
+ }
+#else //UNIX
+ if (relink)
+ {
+ QString srv = findExe(QLatin1String("lnusertemp"), installPath("libexec"));
+ if (srv.isEmpty())
+ srv = findExe(QLatin1String("lnusertemp"));
+ if (!srv.isEmpty())
+ {
+ if (system(QByteArray(QFile::encodeName(srv) + ' ' + type)) == -1) {
+ fprintf(stderr, "Error: unable to launch lnusertemp command" );
+ }
+ result = readlink(QFile::encodeName(dir).constData(), link, 1023);
+ }
+ }
+ if (result > 0)
+ {
+ link[result] = 0;
+ if (link[0] == '/')
+ dir = QFile::decodeName(link);
+ else
+ dir = QDir::cleanPath(dir + QFile::decodeName(link));
+ }
+#endif
+ q->addResourceDir(type, dir + QLatin1Char('/'), false);
+}
+
+QStringList KStandardDirs::resourceDirs(const char *type) const
+{
+ return d->resourceDirs(type, QString());
+}
+
+QStringList KStandardDirs::KStandardDirsPrivate::resourceDirs(const char* type, const QString& subdirForRestrictions)
+{
+ QMutexLocker lock(&m_cacheMutex);
+ const bool dataRestrictionActive = m_restrictionsActive
+ && (strcmp(type, "data") == 0)
+ && hasDataRestrictions(subdirForRestrictions);
+
+ QMap<QByteArray, QStringList>::const_iterator dirCacheIt = m_dircache.constFind(type);
+
+ QStringList candidates;
+
+ if (dirCacheIt != m_dircache.constEnd() && !dataRestrictionActive) {
+ //qDebug() << this << "resourceDirs(" << type << "), in cache already";
+ candidates = *dirCacheIt;
+ }
+ else // filling cache
+ {
+ //qDebug() << this << "resourceDirs(" << type << "), not in cache";
+ if (strcmp(type, "socket") == 0)
+ createSpecialResource(type);
+ else if (strcmp(type, "tmp") == 0)
+ createSpecialResource(type);
+ else if (strcmp(type, "cache") == 0)
+ createSpecialResource(type);
+
+ QDir testdir;
+
+ bool restrictionActive = false;
+ if (m_restrictionsActive) {
+ if (dataRestrictionActive)
+ restrictionActive = true;
+ if (m_restrictions.value("all", false))
+ restrictionActive = true;
+ else if (m_restrictions.value(type, false))
+ restrictionActive = true;
+ }
+
+ QStringList dirs;
+ dirs = m_relatives.value(type);
+ const QString typeInstallPath = installPath(type); // could be empty
+// better #ifdef incasesensitive_filesystem
+#ifdef Q_WS_WIN
+ const QString installdir = typeInstallPath.isEmpty() ? QString() : realPath(typeInstallPath).toLower();
+ const QString installprefix = installPath("kdedir").toLower();
+#else
+ const QString installdir = typeInstallPath.isEmpty() ? QString() : realPath(typeInstallPath);
+ const QString installprefix = installPath("kdedir");
+#endif
+ if (!dirs.isEmpty())
+ {
+ bool local = true;
+
+ for (QStringList::ConstIterator it = dirs.constBegin();
+ it != dirs.constEnd(); ++it)
+ {
+ if ((*it).startsWith(QLatin1Char('%'))) {
+ // grab the "data" from "%data/apps"
+ const int pos = (*it).indexOf(QLatin1Char('/'));
+ QString rel = (*it).mid(1, pos - 1);
+ QString rest = (*it).mid(pos + 1);
+ const QStringList basedirs = resourceDirs(rel.toUtf8().constData(), subdirForRestrictions);
+ for (QStringList::ConstIterator it2 = basedirs.begin();
+ it2 != basedirs.end(); ++it2)
+ {
+#ifdef Q_WS_WIN
+ const QString path = realPath( *it2 + rest ).toLower();
+#else
+ const QString path = realPath( *it2 + rest );
+#endif
+ testdir.setPath(path);
+ if ((local || testdir.exists()) && !candidates.contains(path))
+ candidates.append(path);
+ local = false;
+ }
+ }
+ }
+
+ const QStringList *prefixList = 0;
+ if (strncmp(type, "xdgdata-", 8) == 0)
+ prefixList = &(xdgdata_prefixes);
+ else if (strncmp(type, "xdgconf-", 8) == 0)
+ prefixList = &(xdgconf_prefixes);
+ else
+ prefixList = &m_prefixes;
+
+ for (QStringList::ConstIterator pit = prefixList->begin();
+ pit != prefixList->end();
+ ++pit)
+ {
+ if((*pit)!=installprefix||installdir.isEmpty())
+ {
+ for (QStringList::ConstIterator it = dirs.constBegin();
+ it != dirs.constEnd(); ++it)
+ {
+ if ((*it).startsWith(QLatin1Char('%')))
+ continue;
+#ifdef Q_WS_WIN
+ const QString path = realPath( *pit + *it ).toLower();
+#else
+ const QString path = realPath( *pit + *it );
+#endif
+ testdir.setPath(path);
+ if (local && restrictionActive)
+ continue;
+ if ((local || testdir.exists()) && !candidates.contains(path))
+ candidates.append(path);
+ }
+ local = false;
+ }
+ else
+ {
+ // we have a custom install path, so use this instead of <installprefix>/<relative dir>
+ testdir.setPath(installdir);
+ if(testdir.exists() && ! candidates.contains(installdir))
+ candidates.append(installdir);
+ }
+ }
+ }
+
+ // make sure we find the path where it's installed
+ if (!installdir.isEmpty()) {
+ bool ok = true;
+ foreach (const QString &s, candidates) {
+ if (installdir.startsWith(s)) {
+ ok = false;
+ break;
+ }
+ }
+ if (ok)
+ candidates.append(installdir);
+ }
+
+ dirs = m_absolutes.value(type);
+ if (!dirs.isEmpty())
+ for (QStringList::ConstIterator it = dirs.constBegin();
+ it != dirs.constEnd(); ++it)
+ {
+ testdir.setPath(*it);
+ if (testdir.exists()) {
+#ifdef Q_WS_WIN
+ const QString filename = realPath( *it ).toLower();
+#else
+ const QString filename = realPath( *it );
+#endif
+ if (!candidates.contains(filename)) {
+ candidates.append(filename);
+ }
+ }
+ }
+
+ // Insert result into the cache for next time.
+ // Exception: data_subdir restrictions are per-subdir, so we can't store such results
+ if (!dataRestrictionActive) {
+ //kDebug() << this << "Inserting" << type << candidates << "into dircache";
+ m_dircache.insert(type, candidates);
+ }
+ }
+
+#if 0
+ kDebug(180) << "found dirs for resource" << type << ":" << candidates;
+#endif
+
+ return candidates;
+}
+
+#ifdef Q_OS_WIN
+static QStringList executableExtensions()
+{
+ QStringList ret = QString::fromLocal8Bit(qgetenv("PATHEXT")).split(QLatin1Char(';'));
+ if (!ret.contains(QLatin1String(".exe"), Qt::CaseInsensitive)) {
+ // If %PATHEXT% does not contain .exe, it is either empty, malformed, or distorted in ways that we cannot support, anyway.
+ ret.clear();
+ ret << QLatin1String(".exe")
+ << QLatin1String(".com")
+ << QLatin1String(".bat")
+ << QLatin1String(".cmd");
+ }
+ return ret;
+}
+#endif
+
+QStringList KStandardDirs::systemPaths( const QString& pstr )
+{
+ QStringList tokens;
+ QString p = pstr;
+
+ if( p.isEmpty() )
+ {
+ p = QString::fromLocal8Bit( qgetenv( "PATH" ) );
+ }
+
+ QString delimiters(QLatin1Char(KPATH_SEPARATOR));
+ delimiters += QLatin1Char('\b');
+ tokenize( tokens, p, delimiters );
+
+ QStringList exePaths;
+
+ // split path using : or \b as delimiters
+ for( int i = 0; i < tokens.count(); i++ )
+ {
+ exePaths << KShell::tildeExpand( tokens[ i ] );
+ }
+
+ return exePaths;
+}
+
+#ifdef Q_WS_MAC
+static QString getBundle( const QString& path, bool ignore )
+{
+ //kDebug(180) << "getBundle(" << path << ", " << ignore << ") called";
+ QFileInfo info;
+ QString bundle = path;
+ bundle += QLatin1String(".app/Contents/MacOS/") + bundle.section(QLatin1Char('/'), -1);
+ info.setFile( bundle );
+ FILE *file;
+ if (file = fopen(info.absoluteFilePath().toUtf8().constData(), "r")) {
+ fclose(file);
+ struct stat _stat;
+ if ((stat(info.absoluteFilePath().toUtf8().constData(), &_stat)) < 0) {
+ return QString();
+ }
+ if ( ignore || (_stat.st_mode & S_IXUSR) ) {
+ if ( ((_stat.st_mode & S_IFMT) == S_IFREG) || ((_stat.st_mode & S_IFMT) == S_IFLNK) ) {
+ //kDebug(180) << "getBundle(): returning " << bundle;
+ return bundle;
+ }
+ }
+ }
+ return QString();
+}
+#endif
+
+static QString checkExecutable( const QString& path, bool ignoreExecBit )
+{
+#ifdef Q_WS_MAC
+ QString bundle = getBundle( path, ignoreExecBit );
+ if ( !bundle.isEmpty() ) {
+ //kDebug(180) << "findExe(): returning " << bundle;
+ return bundle;
+ }
+#endif
+ QFileInfo info( path );
+ QFileInfo orig = info;
+#if defined(Q_OS_DARWIN) || defined(Q_OS_MAC)
+ FILE *file;
+ if (file = fopen(orig.absoluteFilePath().toUtf8().constData(), "r")) {
+ fclose(file);
+ struct stat _stat;
+ if ((stat(orig.absoluteFilePath().toUtf8().constData(), &_stat)) < 0) {
+ return QString();
+ }
+ if ( ignoreExecBit || (_stat.st_mode & S_IXUSR) ) {
+ if ( ((_stat.st_mode & S_IFMT) == S_IFREG) || ((_stat.st_mode & S_IFMT) == S_IFLNK) ) {
+ orig.makeAbsolute();
+ return orig.filePath();
+ }
+ }
+ }
+ return QString();
+#else
+ if( info.exists() && info.isSymLink() )
+ info = QFileInfo( info.canonicalFilePath() );
+ if( info.exists() && ( ignoreExecBit || info.isExecutable() ) && info.isFile() ) {
+ // return absolute path, but without symlinks resolved in order to prevent
+ // problems with executables that work differently depending on name they are
+ // run as (for example gunzip)
+ orig.makeAbsolute();
+ return orig.filePath();
+ }
+ //kDebug(180) << "checkExecutable(): failed, returning empty string";
+ return QString();
+#endif
+}
+
+QString KStandardDirs::findExe( const QString& appname,
+ const QString& pstr,
+ SearchOptions options )
+{
+ //kDebug(180) << "findExe(" << appname << ", pstr, " << ignoreExecBit << ") called";
+
+#ifdef Q_OS_WIN
+ QStringList executable_extensions = executableExtensions();
+ if (!executable_extensions.contains(appname.section(QLatin1Char('.'), -1, -1, QString::SectionIncludeLeadingSep), Qt::CaseInsensitive)) {
+ QString found_exe;
+ foreach (const QString& extension, executable_extensions) {
+ found_exe = findExe(appname + extension, pstr, options);
+ if (!found_exe.isEmpty()) {
+ return found_exe;
+ }
+ }
+ return QString();
+ }
+#endif
+ QFileInfo info;
+
+ // absolute or relative path?
+ if (appname.contains(QDir::separator()))
+ {
+ //kDebug(180) << "findExe(): absolute path given";
+ QString path = checkExecutable(appname, options & IgnoreExecBit);
+ return path;
+ }
+
+ //kDebug(180) << "findExe(): relative path given";
+
+ QString p = installPath("libexec") + appname;
+ QString result = checkExecutable(p, options & IgnoreExecBit);
+ if (!result.isEmpty()) {
+ //kDebug(180) << "findExe(): returning " << result;
+ return result;
+ }
+
+ //kDebug(180) << "findExe(): checking system paths";
+ const QStringList exePaths = systemPaths( pstr );
+ for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); ++it)
+ {
+ p = (*it) + QLatin1Char('/');
+ p += appname;
+
+ // Check for executable in this tokenized path
+ result = checkExecutable(p, options & IgnoreExecBit);
+ if (!result.isEmpty()) {
+ //kDebug(180) << "findExe(): returning " << result;
+ return result;
+ }
+ }
+
+ // Not found in PATH, look into the KDE-specific bin dir ("exe" resource)
+ p = installPath("exe");
+ p += appname;
+ result = checkExecutable(p, options & IgnoreExecBit);
+ if (!result.isEmpty()) {
+ //kDebug(180) << "findExe(): returning " << result;
+ return result;
+ }
+
+ // If we reach here, the executable wasn't found.
+ // So return empty string.
+
+ //kDebug(180) << "findExe(): failed, nothing matched";
+ return QString();
+}
+
+int KStandardDirs::findAllExe( QStringList& list, const QString& appname,
+ const QString& pstr, SearchOptions options )
+{
+#ifdef Q_OS_WIN
+ QStringList executable_extensions = executableExtensions();
+ if (!executable_extensions.contains(appname.section(QLatin1Char('.'), -1, -1, QString::SectionIncludeLeadingSep), Qt::CaseInsensitive)) {
+ int total = 0;
+ foreach (const QString& extension, executable_extensions) {
+ total += findAllExe (list, appname + extension, pstr, options);
+ }
+ return total;
+ }
+#endif
+ QFileInfo info;
+ QString p;
+ list.clear();
+
+ const QStringList exePaths = systemPaths( pstr );
+ for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); ++it)
+ {
+ p = (*it) + QLatin1Char('/');
+ p += appname;
+
+#ifdef Q_WS_MAC
+ QString bundle = getBundle( p, (options & IgnoreExecBit) );
+ if ( !bundle.isEmpty() ) {
+ //kDebug(180) << "findExe(): returning " << bundle;
+ list.append( bundle );
+ }
+#endif
+
+ info.setFile( p );
+
+ if( info.exists() && ( ( options & IgnoreExecBit ) || info.isExecutable())
+ && info.isFile() ) {
+ list.append( p );
+ }
+ }
+
+ return list.count();
+}
+
+static inline QString equalizePath(QString &str)
+{
+#ifdef Q_WS_WIN
+ // filter pathes through QFileInfo to have always
+ // the same case for drive letters
+ QFileInfo f(str);
+ if (f.isAbsolute())
+ return f.absoluteFilePath();
+ else
+#endif
+ return str;
+}
+
+static void tokenize(QStringList& tokens, const QString& str,
+ const QString& delim)
+{
+ const int len = str.length();
+ QString token;
+
+ for(int index = 0; index < len; index++) {
+ if (delim.contains(str[index])) {
+ tokens.append(equalizePath(token));
+ token.clear();
+ } else {
+ token += str[index];
+ }
+ }
+ if (!token.isEmpty()) {
+ tokens.append(equalizePath(token));
+ }
+}
+
+#ifndef KDE_NO_DEPRECATED
+QString KStandardDirs::kde_default(const char *type)
+{
+ return QString(QLatin1Char('%')) + QString::fromLatin1(type) + QLatin1Char('/');
+}
+#endif
+
+QString KStandardDirs::saveLocation(const char *type,
+ const QString& suffix,
+ bool create) const
+{
+ QMutexLocker lock(&d->m_cacheMutex);
+ QString path = d->m_savelocations.value(type);
+ if (path.isEmpty())
+ {
+ QStringList dirs = d->m_relatives.value(type);
+ if (dirs.isEmpty() && (
+ (strcmp(type, "socket") == 0) ||
+ (strcmp(type, "tmp") == 0) ||
+ (strcmp(type, "cache") == 0) ))
+ {
+ (void) resourceDirs(type); // Generate socket|tmp|cache resource.
+ dirs = d->m_relatives.value(type); // Search again.
+ }
+ if (!dirs.isEmpty())
+ {
+ path = dirs.first();
+
+ if (path.startsWith(QLatin1Char('%'))) {
+ // grab the "data" from "%data/apps"
+ const int pos = path.indexOf(QLatin1Char('/'));
+ QString rel = path.mid(1, pos - 1);
+ QString rest = path.mid(pos + 1);
+ QString basepath = saveLocation(rel.toUtf8().constData());
+ path = basepath + rest;
+ } else
+
+ // Check for existence of typed directory + suffix
+ if (strncmp(type, "xdgdata-", 8) == 0) {
+ path = realPath( localxdgdatadir() + path ) ;
+ } else if (strncmp(type, "xdgconf-", 8) == 0) {
+ path = realPath( localxdgconfdir() + path );
+ } else {
+ path = realPath( localkdedir() + path );
+ }
+ }
+ else {
+ dirs = d->m_absolutes.value(type);
+ if (dirs.isEmpty()) {
+ qFatal("KStandardDirs: The resource type %s is not registered", type);
+ } else {
+ path = realPath(dirs.first());
+ }
+ }
+
+ d->m_savelocations.insert(type, path.endsWith(QLatin1Char('/')) ? path : path + QLatin1Char('/'));
+ }
+ QString fullPath = path + suffix;
+
+ KDE_struct_stat st;
+ if (KDE::stat(fullPath, &st) != 0 || !(S_ISDIR(st.st_mode))) {
+ if(!create) {
+#ifndef NDEBUG
+ // Too much noise from kbuildsycoca4 -- it's fine if this happens from KConfig
+ // when parsing global files without a local equivalent.
+ //kDebug(180) << QString("save location %1 doesn't exist").arg(fullPath);
+#endif
+ return fullPath;
+ }
+ if(!makeDir(fullPath, 0700)) {
+ return fullPath;
+ }
+ d->m_dircache.remove(type);
+ }
+ if (!fullPath.endsWith(QLatin1Char('/')))
+ fullPath += QLatin1Char('/');
+ return fullPath;
+}
+
+// KDE5: make the method const
+QString KStandardDirs::relativeLocation(const char *type, const QString &absPath)
+{
+ QString fullPath = absPath;
+ int i = absPath.lastIndexOf(QLatin1Char('/'));
+ if (i != -1) {
+ fullPath = realFilePath(absPath); // Normalize
+ }
+
+ const QStringList candidates = resourceDirs(type);
+
+ for (QStringList::ConstIterator it = candidates.begin();
+ it != candidates.end(); ++it) {
+ if (fullPath.startsWith(*it)) {
+ return fullPath.mid((*it).length());
+ }
+ }
+ return absPath;
+}
+
+
+bool KStandardDirs::makeDir(const QString& dir, int mode)
+{
+ // we want an absolute path
+ if (QDir::isRelativePath(dir))
+ return false;
+
+#ifdef Q_WS_WIN
+ return QDir().mkpath(dir);
+#else
+ QString target = dir;
+ uint len = target.length();
+
+ // append trailing slash if missing
+ if (dir.at(len - 1) != QLatin1Char('/'))
+ target += QLatin1Char('/');
+
+ QString base;
+ uint i = 1;
+
+ while( i < len )
+ {
+ KDE_struct_stat st;
+ int pos = target.indexOf(QLatin1Char('/'), i);
+ base += target.mid(i - 1, pos - i + 1);
+ QByteArray baseEncoded = QFile::encodeName(base);
+ // bail out if we encountered a problem
+ if (KDE_stat(baseEncoded, &st) != 0)
+ {
+ // Directory does not exist....
+ // Or maybe a dangling symlink ?
+ if (KDE_lstat(baseEncoded, &st) == 0)
+ (void)unlink(baseEncoded); // try removing
+
+ if (KDE_mkdir(baseEncoded, static_cast<mode_t>(mode)) != 0) {
+ baseEncoded.prepend( "trying to create local folder " );
+ perror(baseEncoded.constData());
+ return false; // Couldn't create it :-(
+ }
+ }
+ i = pos + 1;
+ }
+ return true;
+#endif
+}
+
+static QString readEnvPath(const char *env)
+{
+ QByteArray c_path;
+#ifndef _WIN32_WCE
+ c_path = qgetenv(env);
+ if (c_path.isEmpty())
+ return QString();
+#else
+ bool ok;
+ QString retval = getWin32RegistryValue(HKEY_LOCAL_MACHINE, "Software\\kde", "KDEDIRS", &ok);
+ if (!ok){
+ return QString();
+ } else {
+ c_path = retval.toAscii();
+ }
+#endif
+ return QDir::fromNativeSeparators(QFile::decodeName(c_path));
+}
+
+#ifdef __linux__
+static QString executablePrefix()
+{
+ char path_buffer[MAXPATHLEN + 1];
+ path_buffer[MAXPATHLEN] = 0;
+ int length = readlink ("/proc/self/exe", path_buffer, MAXPATHLEN);
+ if (length == -1)
+ return QString();
+
+ path_buffer[length] = '\0';
+
+ QString path = QFile::decodeName(path_buffer);
+
+ if(path.isEmpty())
+ return QString();
+
+ int pos = path.lastIndexOf(QLatin1Char('/')); // Skip filename
+ if(pos <= 0)
+ return QString();
+ pos = path.lastIndexOf(QLatin1Char('/'), pos - 1); // Skip last directory
+ if(pos <= 0)
+ return QString();
+
+ return path.left(pos);
+}
+#endif
+
+void KStandardDirs::addResourcesFrom_krcdirs()
+{
+ QString localFile = QDir::currentPath() + QLatin1String("/.krcdirs");
+ if (!QFile::exists(localFile))
+ return;
+
+ QSettings iniFile(localFile, QSettings::IniFormat);
+ iniFile.beginGroup(QString::fromLatin1("KStandardDirs"));
+ const QStringList resources = iniFile.allKeys();
+ foreach(const QString &key, resources)
+ {
+ QDir path(iniFile.value(key).toString());
+ if (!path.exists())
+ continue;
+
+ if(path.makeAbsolute())
+ addResourceDir(key.toAscii(), path.path(), false);
+ }
+}
+
+void KStandardDirs::addKDEDefaults()
+{
+ addResourcesFrom_krcdirs();
+
+ QStringList kdedirList;
+ // begin KDEDIRS
+ QString kdedirs = readEnvPath("KDEDIRS");
+
+ if (!kdedirs.isEmpty())
+ {
+ tokenize(kdedirList, kdedirs, QString(QLatin1Char(KPATH_SEPARATOR)));
+ }
+ kdedirList.append(installPath("kdedir"));
+
+ QString execPrefix(QFile::decodeName(EXEC_INSTALL_PREFIX));
+ if (!execPrefix.isEmpty() && !kdedirList.contains(execPrefix))
+ kdedirList.append(execPrefix);
+#ifdef __linux__
+ const QString linuxExecPrefix = executablePrefix();
+ if ( !linuxExecPrefix.isEmpty() )
+ kdedirList.append( linuxExecPrefix );
+#endif
+
+ // We treat root differently to prevent a "su" shell messing up the
+ // file permissions in the user's home directory.
+ QString localKdeDir = readEnvPath(getuid() ? "KDEHOME" : "KDEROOTHOME");
+ if (!localKdeDir.isEmpty()) {
+ if (!localKdeDir.endsWith(QLatin1Char('/')))
+ localKdeDir += QLatin1Char('/');
+ } else {
+ // TODO KDE5: make localKdeDir equal to localXdgDir (which is determined further below and
+ // defaults to ~/.config) + '/' + $KDECONFIG (which would default to e.g. "KDE")
+ // This would mean ~/.config/KDE/ by default, more xdg-compliant.
+
+#if defined(Q_WS_MACX)
+ localKdeDir = QDir::homePath() + QLatin1String("/Library/Preferences/KDE/");
+#elif defined(Q_WS_WIN)
+#ifndef _WIN32_WCE
+ WCHAR wPath[MAX_PATH+1];
+ if ( SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wPath) == S_OK) {
+ localKdeDir = QDir::fromNativeSeparators(QString::fromUtf16((const ushort *) wPath)) + QLatin1Char('/') + QString::fromLatin1(KDE_DEFAULT_HOME) + QLatin1Char('/');
+ } else {
+#endif
+ localKdeDir = QDir::homePath() + QLatin1Char('/') + QString::fromLatin1(KDE_DEFAULT_HOME) + QLatin1Char('/');
+#ifndef _WIN32_WCE
+ }
+#endif
+#else
+ localKdeDir = QDir::homePath() + QLatin1Char('/') + QString::fromLatin1(KDE_DEFAULT_HOME) + QLatin1Char('/');
+#endif
+ }
+
+ if (localKdeDir != QLatin1String("-/"))
+ {
+ localKdeDir = KShell::tildeExpand(localKdeDir);
+ addPrefix(localKdeDir);
+ }
+
+#ifdef Q_WS_MACX
+ // Adds the "Contents" directory of the current application bundle to
+ // the search path. This way bundled resources can be found.
+ QDir bundleDir(mac_app_filename());
+ if (bundleDir.dirName() == QLatin1String("MacOS")) { // just to be sure we're in a bundle
+ bundleDir.cdUp();
+ // now dirName should be "Contents". In there we can find our normal
+ // dir-structure, beginning with "share"
+ addPrefix(bundleDir.absolutePath());
+ }
+#endif
+
+ QStringList::ConstIterator end(kdedirList.end());
+ for (QStringList::ConstIterator it = kdedirList.constBegin();
+ it != kdedirList.constEnd(); ++it)
+ {
+ const QString dir = KShell::tildeExpand(*it);
+ addPrefix(dir);
+ }
+ // end KDEDIRS
+
+ // begin XDG_CONFIG_XXX
+ QStringList xdgdirList;
+ QString xdgdirs = readEnvPath("XDG_CONFIG_DIRS");
+ if (!xdgdirs.isEmpty())
+ {
+ tokenize(xdgdirList, xdgdirs, QString(QLatin1Char(KPATH_SEPARATOR)));
+ }
+ else
+ {
+ xdgdirList.clear();
+ xdgdirList.append(QString::fromLatin1("/etc/xdg"));
+#ifdef Q_WS_WIN
+ xdgdirList.append(installPath("kdedir") + QString::fromLatin1("etc/xdg"));
+#else
+ xdgdirList.append(QFile::decodeName(KDESYSCONFDIR "/xdg"));
+#endif
+ }
+
+ QString localXdgDir = readEnvPath("XDG_CONFIG_HOME");
+ if (!localXdgDir.isEmpty()) {
+ if (!localXdgDir.endsWith(QLatin1Char('/')))
+ localXdgDir += QLatin1Char('/');
+ } else {
+#ifdef Q_WS_MACX
+ localXdgDir = QDir::homePath() + QString::fromLatin1("/Library/Preferences/XDG/");
+#else
+ localXdgDir = QDir::homePath() + QString::fromLatin1("/.config/");
+#endif
+ }
+
+ localXdgDir = KShell::tildeExpand(localXdgDir);
+ addXdgConfigPrefix(localXdgDir);
+
+ for (QStringList::ConstIterator it = xdgdirList.constBegin();
+ it != xdgdirList.constEnd(); ++it)
+ {
+ QString dir = KShell::tildeExpand(*it);
+ addXdgConfigPrefix(dir);
+ }
+ // end XDG_CONFIG_XXX
+
+ // begin XDG_DATA_XXX
+ QStringList kdedirDataDirs;
+ for (QStringList::ConstIterator it = kdedirList.constBegin();
+ it != kdedirList.constEnd(); ++it) {
+ QString dir = *it;
+ if (!dir.endsWith(QLatin1Char('/')))
+ dir += QLatin1Char('/');
+ kdedirDataDirs.append(dir + QLatin1String("share/"));
+ }
+
+ xdgdirs = readEnvPath("XDG_DATA_DIRS");
+ if (!xdgdirs.isEmpty()) {
+ tokenize(xdgdirList, xdgdirs, QString(QLatin1Char(KPATH_SEPARATOR)));
+ // Ensure the kdedirDataDirs are in there too,
+ // otherwise resourceDirs() will add kdedir/share/applications/kde4
+ // as returned by installPath(), and that's incorrect.
+ Q_FOREACH(const QString& dir, kdedirDataDirs) {
+ if (!xdgdirList.contains(dir))
+ xdgdirList.append(dir);
+ }
+ } else {
+ xdgdirList = kdedirDataDirs;
+#ifndef Q_WS_WIN
+ xdgdirList.append(QString::fromLatin1("/usr/local/share/"));
+ xdgdirList.append(QString::fromLatin1("/usr/share/"));
+#endif
+ }
+
+ localXdgDir = readEnvPath("XDG_DATA_HOME");
+ if (!localXdgDir.isEmpty())
+ {
+ if (localXdgDir[localXdgDir.length()-1] != QLatin1Char('/'))
+ localXdgDir += QLatin1Char('/');
+ }
+ else
+ {
+ localXdgDir = QDir::homePath() + QLatin1String("/.local/share/");
+ }
+
+ localXdgDir = KShell::tildeExpand(localXdgDir);
+ addXdgDataPrefix(localXdgDir);
+
+ for (QStringList::ConstIterator it = xdgdirList.constBegin();
+ it != xdgdirList.constEnd(); ++it)
+ {
+ QString dir = KShell::tildeExpand(*it);
+ addXdgDataPrefix(dir);
+ }
+ // end XDG_DATA_XXX
+
+
+ addResourceType("lib", 0, "lib" KDELIBSUFF "/");
+
+ uint index = 0;
+ while (types_indices[index] != -1) {
+ addResourceType(types_string + types_indices[index], 0, types_string + types_indices[index+1], true);
+ index+=2;
+ }
+ addResourceType("exe", "lib", "kde4/libexec", true );
+
+ addResourceDir("home", QDir::homePath(), false);
+
+ addResourceType("autostart", "xdgconf-autostart", "/"); // merge them, start with xdg autostart
+ addResourceType("autostart", NULL, "share/autostart"); // KDE ones are higher priority
+}
+
+static QStringList lookupProfiles(const QString &mapFile)
+{
+ QStringList profiles;
+
+ if (mapFile.isEmpty() || !QFile::exists(mapFile))
+ {
+ profiles << QString::fromLatin1("default");
+ return profiles;
+ }
+
+ struct passwd *pw = getpwuid(geteuid());
+ if (!pw)
+ {
+ profiles << QString::fromLatin1("default");
+ return profiles; // Not good
+ }
+
+ QByteArray user = pw->pw_name;
+
+ gid_t sup_gids[512];
+ int sup_gids_nr = getgroups(512, sup_gids);
+
+ KConfig mapCfgFile(mapFile);
+ KConfigGroup mapCfg(&mapCfgFile, "Users");
+ if (mapCfg.hasKey(user.constData()))
+ {
+ profiles = mapCfg.readEntry(user.constData(), QStringList());
+ return profiles;
+ }
+
+ const KConfigGroup generalGrp(&mapCfgFile, "General");
+ const QStringList groups = generalGrp.readEntry("groups", QStringList());
+
+ const KConfigGroup groupsGrp(&mapCfgFile, "Groups");
+
+ for( QStringList::ConstIterator it = groups.begin();
+ it != groups.end(); ++it )
+ {
+ QByteArray grp = (*it).toUtf8();
+ // Check if user is in this group
+ struct group *grp_ent = getgrnam(grp);
+ if (!grp_ent) continue;
+ gid_t gid = grp_ent->gr_gid;
+ if (pw->pw_gid == gid)
+ {
+ // User is in this group --> add profiles
+ profiles += groupsGrp.readEntry(*it, QStringList());
+ }
+ else
+ {
+ for(int i = 0; i < sup_gids_nr; i++)
+ {
+ if (sup_gids[i] == gid)
+ {
+ // User is in this group --> add profiles
+ profiles += groupsGrp.readEntry(*it, QStringList());
+ break;
+ }
+ }
+ }
+ }
+
+ if (profiles.isEmpty())
+ profiles << QString::fromLatin1("default");
+ return profiles;
+}
+
+extern bool kde_kiosk_admin;
+
+bool KStandardDirs::addCustomized(KConfig *config)
+{
+ if (!d->m_checkRestrictions) // there are already customized entries
+ return false; // we just quit and hope they are the right ones
+
+ // save the numbers of config directories. If this changes,
+ // we will return true to give KConfig a chance to reparse
+ int configdirs = resourceDirs("config").count();
+
+ if (true)
+ {
+ // reading the prefixes in
+ QString group = QLatin1String("Directories");
+ KConfigGroup cg(config, group);
+
+ QString kioskAdmin = cg.readEntry("kioskAdmin");
+ if (!kioskAdmin.isEmpty() && !kde_kiosk_admin)
+ {
+ int i = kioskAdmin.indexOf(QLatin1Char(':'));
+ QString user = kioskAdmin.left(i);
+ QString host = kioskAdmin.mid(i+1);
+
+ KUser thisUser;
+ char hostname[ 256 ];
+ hostname[ 0 ] = '\0';
+ if (!gethostname( hostname, 255 ))
+ hostname[sizeof(hostname)-1] = '\0';
+
+ if ((user == thisUser.loginName()) &&
+ (host.isEmpty() || (host == QLatin1String(hostname))))
+ {
+ kde_kiosk_admin = true;
+ }
+ }
+
+ bool readProfiles = true;
+
+ if (kde_kiosk_admin && !qgetenv("KDE_KIOSK_NO_PROFILES").isEmpty())
+ readProfiles = false;
+
+ QString userMapFile = cg.readEntry("userProfileMapFile");
+ QString profileDirsPrefix = cg.readEntry("profileDirsPrefix");
+ if (!profileDirsPrefix.isEmpty() && !profileDirsPrefix.endsWith(QLatin1Char('/')))
+ profileDirsPrefix.append(QLatin1Char('/'));
+
+ QStringList profiles;
+ if (readProfiles)
+ profiles = lookupProfiles(userMapFile);
+ QString profile;
+
+ bool priority = false;
+ while(true)
+ {
+ KConfigGroup cg(config, group);
+ const QStringList list = cg.readEntry("prefixes", QStringList());
+ for (QStringList::ConstIterator it = list.begin(); it != list.end(); ++it)
+ {
+ addPrefix(*it, priority);
+ addXdgConfigPrefix(*it + QLatin1String("/etc/xdg"), priority);
+ addXdgDataPrefix(*it + QLatin1String("/share"), priority);
+ }
+ // If there are no prefixes defined, check if there is a directory
+ // for this profile under <profileDirsPrefix>
+ if (list.isEmpty() && !profile.isEmpty() && !profileDirsPrefix.isEmpty())
+ {
+ QString dir = profileDirsPrefix + profile;
+ addPrefix(dir, priority);
+ addXdgConfigPrefix(dir + QLatin1String("/etc/xdg"), priority);
+ addXdgDataPrefix(dir + QLatin1String("/share"), priority);
+ }
+
+ // iterating over all entries in the group Directories
+ // to find entries that start with dir_$type
+ const QMap<QString, QString> entries = config->entryMap(group);
+ for (QMap<QString, QString>::ConstIterator it2 = entries.begin();
+ it2 != entries.end(); ++it2)
+ {
+ const QString key = it2.key();
+ if (key.startsWith(QLatin1String("dir_"))) {
+ // generate directory list, there may be more than 1.
+ const QStringList dirs = (*it2).split(QString(QLatin1Char(',')));
+ QStringList::ConstIterator sIt(dirs.begin());
+ QString resType = key.mid(4);
+ for (; sIt != dirs.end(); ++sIt)
+ {
+ addResourceDir(resType.toLatin1(), *sIt, priority);
+ }
+ }
+ }
+ if (profiles.isEmpty())
+ break;
+ profile = profiles.back();
+ group = QString::fromLatin1("Directories-%1").arg(profile);
+ profiles.pop_back();
+ priority = true;
+ }
+ }
+
+ // Process KIOSK restrictions.
+ if (!kde_kiosk_admin || qgetenv("KDE_KIOSK_NO_RESTRICTIONS").isEmpty())
+ {
+ KConfigGroup cg(config, "KDE Resource Restrictions");
+ const QMap<QString, QString> entries = cg.entryMap();
+ for (QMap<QString, QString>::ConstIterator it2 = entries.begin();
+ it2 != entries.end(); ++it2)
+ {
+ const QString key = it2.key();
+ if (!cg.readEntry(key, true))
+ {
+ d->m_restrictionsActive = true;
+ const QByteArray cKey = key.toLatin1();
+ d->m_restrictions.insert(cKey, true);
+ d->m_dircache.remove(cKey);
+ d->m_savelocations.remove(cKey);
+ }
+ }
+ }
+
+ // check if the number of config dirs changed
+ bool configDirsChanged = (resourceDirs("config").count() != configdirs);
+ // If the config dirs changed, we check kiosk restrictions again.
+ d->m_checkRestrictions = configDirsChanged;
+ // return true if the number of config dirs changed: reparse config file
+ return configDirsChanged;
+}
+
+QString KStandardDirs::localkdedir() const
+{
+ // Return the prefix to use for saving
+ return d->m_prefixes.first();
+}
+
+QString KStandardDirs::localxdgdatadir() const
+{
+ // Return the prefix to use for saving
+ return d->xdgdata_prefixes.first();
+}
+
+QString KStandardDirs::localxdgconfdir() const
+{
+ // Return the prefix to use for saving
+ return d->xdgconf_prefixes.first();
+}
+
+
+// just to make code more readable without macros
+QString KStandardDirs::locate( const char *type,
+ const QString& filename, const KComponentData &cData)
+{
+ return cData.dirs()->findResource(type, filename);
+}
+
+QString KStandardDirs::locateLocal( const char *type,
+ const QString& filename, const KComponentData &cData)
+{
+ return locateLocal(type, filename, true, cData);
+}
+
+QString KStandardDirs::locateLocal( const char *type,
+ const QString& filename, bool createDir,
+ const KComponentData &cData)
+{
+ // try to find slashes. If there are some, we have to
+ // create the subdir first
+ int slash = filename.lastIndexOf(QLatin1Char('/')) + 1;
+ if (!slash) { // only one filename
+ return cData.dirs()->saveLocation(type, QString(), createDir) + filename;
+ }
+
+ // split path from filename
+ QString dir = filename.left(slash);
+ QString file = filename.mid(slash);
+ return cData.dirs()->saveLocation(type, dir, createDir) + file;
+}
+
+bool KStandardDirs::checkAccess(const QString& pathname, int mode)
+{
+ int accessOK = KDE::access( pathname, mode );
+ if ( accessOK == 0 )
+ return true; // OK, I can really access the file
+
+ // else
+ // if we want to write the file would be created. Check, if the
+ // user may write to the directory to create the file.
+ if ( (mode & W_OK) == 0 )
+ return false; // Check for write access is not part of mode => bail out
+
+
+ if (!KDE::access( pathname, F_OK)) // if it already exists
+ return false;
+
+ //strip the filename (everything until '/' from the end
+ QString dirName(pathname);
+ int pos = dirName.lastIndexOf(QLatin1Char('/'));
+ if ( pos == -1 )
+ return false; // No path in argument. This is evil, we won't allow this
+ else if ( pos == 0 ) // don't turn e.g. /root into an empty string
+ pos = 1;
+
+ dirName.truncate(pos); // strip everything starting from the last '/'
+
+ accessOK = KDE::access( dirName, W_OK );
+ // -?- Can I write to the accessed diretory
+ if ( accessOK == 0 )
+ return true; // Yes
+ else
+ return false; // No
+}
+
diff --git a/kdecore/kernel/kstandarddirs.h b/kdecore/kernel/kstandarddirs.h
new file mode 100644
index 0000000..c2b7b41
--- /dev/null
+++ b/kdecore/kernel/kstandarddirs.h
@@ -0,0 +1,810 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (C) 1999 Sirtaj Singh Kang <taj@kde.org>
+ Copyright (C) 1999 Stephan Kulow <coolo@kde.org>
+ Copyright (C) 1999 Waldo Bastian <bastian@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 as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ 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.
+*/
+
+#ifndef KSTANDARDDIRS_H
+#define KSTANDARDDIRS_H
+
+#include <QtCore/QStringList>
+#include <kglobal.h>
+#include <QtCore/QMap>
+
+class KConfig;
+
+/**
+ * @short Site-independent access to standard KDE directories.
+ * @author Stephan Kulow <coolo@kde.org> and Sirtaj Singh Kang <taj@kde.org>
+ *
+ * This is one of the most central classes in kdelibs: It knows where KDE-related files
+ * reside on the user's hard disk. It's meant to be the only one that knows --
+ * so applications and the end user don't have to.
+ *
+ * Applications should always refer to a file with a resource type.
+ * The application should leave it up to e.g.
+ * KStandardDirs::findResource("apps", "Home.desktop")
+ * to return the desired path <tt>/opt/kde/share/applnk/Home.desktop</tt>
+ * or ::locate("data", "kgame/background.jpg") to return
+ * <tt>/opt/kde/share/apps/kgame/background.jpg</tt>
+ *
+ * There are several toplevel prefixes under which files can be located.
+ * One of them is the kdelibs install location, one is the application
+ * install location, and one is <tt>$KDEHOME</tt>.
+ * Under these toplevel prefixes there are several well-defined suffixes
+ * where specific resource types can be found.
+ * For example, for the resource type @c "html" the suffixes could be
+ * @c share/doc/HTML and @c share/doc/kde/HTML.
+ * The search algorithm tries to locate the file under each prefix-suffix
+ * combination.
+ *
+ * It is also possible to register
+ * absolute paths that KStandardDirs looks up after not finding anything
+ * in the former steps. They can be useful if the user wants to provide
+ * specific directories that aren't in his <tt>$KDEHOME</tt> directory, for
+ * example for icons.
+ *
+ * <b>Standard resources that kdelibs allocates are:</b>
+ *
+ * @li @c apps - Applications menu (.desktop files).
+ * @li @c autostart - Autostart directories (both XDG and kde-specific)
+ * @li @c cache - Cached information (e.g. favicons, web-pages)
+ * @li @c cgi - CGIs to run from kdehelp.
+ * @li @c config - Configuration files.
+ * @li @c data - Where applications store data.
+ * @li @c emoticons - Emoticons themes
+ * @li @c exe - Executables in $prefix/bin. findExe() for a function that takes $PATH into account.
+ * @li @c html - HTML documentation.
+ * @li @c icon - Icons, see KIconLoader.
+ * @li @c kcfg - KConfigXT config files.
+ * @li @c lib - Libraries.
+ * @li @c locale - Translation files for KLocale.
+ * @li @c mime - Mime types defined by KDE-specific .desktop files.
+ * @li @c module - Module (dynamically loaded library).
+ * @li @c qtplugins - Qt plugins (dynamically loaded objects for Qt)
+ * @li @c services - Services.
+ * @li @c servicetypes - Service types.
+ * @li @c sound - Application sounds.
+ * @li @c templates - Templates for the "Create new file" functionality.
+ * @li @c wallpaper - Wallpapers.
+ * @li @c tmp - Temporary files (specific for both current host and current user)
+ * @li @c socket - UNIX Sockets (specific for both current host and current user)
+ * @li @c xdgconf-menu - Freedesktop.org standard location for menu layout (.menu) files.
+ * @li @c xdgdata-apps - Freedesktop.org standard location for application desktop files.
+ * @li @c xdgdata-dirs - Freedesktop.org standard location for menu descriptions (.directory files).
+ * @li @c xdgdata-mime - Freedesktop.org standard location for MIME type definitions.
+ * @li @c xdgdata-icon - Freedesktop.org standard location for icons.
+ * @li @c xdgdata-pixmap - Gnome-compatibility location for pixmaps.
+ *
+ * A type that is added by the class KApplication if you use it, is
+ * @c appdata. This one makes the use of the type data a bit easier as it
+ * appends the name of the application.
+ * So while you had to ::locate("data", "appname/filename") so you can
+ * also write ::locate("appdata", "filename") if your KApplication instance
+ * is called @c "appname" (as set via KApplication's constructor or KAboutData, if
+ * you use the global KStandardDirs object KGlobal::dirs()).
+ * Please note though that you cannot use the @c "appdata"
+ * type if you intend to use it in an applet for Kicker because 'appname' would
+ * be @c "Kicker" instead of the applet's name. Therefore, for applets, you've got
+ * to work around this by using ::locate("data", "appletname/filename").
+ *
+ * <b>KStandardDirs supports the following environment variables:</b>
+ *
+ * @li @c KDEDIRS - This may set an additional number of directory prefixes to
+ * search for resources. The directories should be separated
+ * by <tt>':'</tt>. The directories are searched in the order they are
+ * specified.
+ * @li @c KDEHOME - The directory where changes are saved to. This directory is
+ * used to search for resources first. If @c KDEHOME is not
+ * specified it defaults to @c "$HOME/.kde"
+ * @li @c KDEROOTHOME - Like KDEHOME, but used for the root user.
+ * If @c KDEROOTHOME is not set it defaults to the <tt>.kde</tt> directory in the
+ * home directory of root, usually @c "/root/.kde".
+ * Note that the setting of @c $HOME is ignored in this case.
+ *
+ * @see KGlobalSettings
+ *
+ *
+ * On The Usage Of 'locate' and 'locateLocal'
+ *
+ * Typical KDE applications use resource files in one out of
+ * three ways:
+ *
+ * 1) A resource file is read but is never written. A system
+ * default is supplied but the user can override this
+ * default in his local .kde directory:
+ *
+ * @code
+ * // Code example
+ * myFile = KStandardDirs::locate("appdata", "groups.lst");
+ * myData = myReadGroups(myFile); // myFile may be null
+ * @endcode
+ *
+ * 2) A resource file is read and written. If the user has no
+ * local version of the file the system default is used.
+ * The resource file is always written to the users local
+ * .kde directory.
+ *
+ * @code
+ * // Code example
+ * myFile = KStandardDirs::locate("appdata", "groups.lst")
+ * myData = myReadGroups(myFile);
+ * ...
+ * doSomething(myData);
+ * ...
+ * myFile = KStandardDirs::locateLocal("appdata", "groups.lst");
+ * myWriteGroups(myFile, myData);
+ * @endcode
+ *
+ * 3) A resource file is read and written. No system default
+ * is used if the user has no local version of the file.
+ * The resource file is always written to the users local
+ * .kde directory.
+ *
+ * @code
+ * // Code example
+ * myFile = KStandardDirs::locateLocal("appdata", "groups.lst");
+ * myData = myReadGroups(myFile);
+ * ...
+ * doSomething(myData);
+ * ...
+ * myFile = KStandardDirs::locateLocal("appdata", "groups.lst");
+ * myWriteGroups(myFile, myData);
+ * @endcode
+ **/
+class KDECORE_EXPORT KStandardDirs
+{
+public:
+ /**
+ * KStandardDirs' constructor. It just initializes the caches.
+ * Note that you should normally not call this, but use KGlobal::dirs()
+ * instead, in order to reuse the same KStandardDirs object as much as possible.
+ *
+ * Creating other KStandardDirs instances can be useful in other threads.
+ *
+ * Thread safety note: using a shared KStandardDirs instance (such as KGlobal::dirs())
+ * in multiple threads is thread-safe if you only call the readonly "lookup" methods
+ * (findExe, resourceDirs, findDirs, findResourceDir, findAllResources, saveLocation,
+ * relativeLocation). The methods that modify the object (all those starting with "add",
+ * basically all non-const methods) are obviously not thread-safe; set things up
+ * before creating threads.
+ */
+ KStandardDirs();
+
+ enum SearchOption { NoSearchOptions = 0,
+ Recursive = 1,
+ NoDuplicates = 2,
+ IgnoreExecBit = 4 };
+ Q_DECLARE_FLAGS( SearchOptions, SearchOption )
+
+ /**
+ * KStandardDirs' destructor.
+ */
+ virtual ~KStandardDirs();
+
+ /**
+ * Adds another search dir to front of the @p fsstnd list.
+ *
+ * @li When compiling kdelibs, the prefix is added to this.
+ * @li @c KDEDIRS is taken into account
+ * @li Additional dirs may be loaded from kdeglobals.
+ *
+ * @param dir The directory to append relative paths to.
+ */
+ void addPrefix( const QString& dir );
+
+ /**
+ * Adds another search dir to front of the @c XDG_CONFIG_XXX list
+ * of prefixes.
+ * This prefix is only used for resources that start with @c "xdgconf-"
+ *
+ * @param dir The directory to append relative paths to.
+ */
+ void addXdgConfigPrefix( const QString& dir );
+
+ /**
+ * Adds another search dir to front of the @c XDG_DATA_XXX list
+ * of prefixes.
+ * This prefix is only used for resources that start with @c "xdgdata-"
+ *
+ * @param dir The directory to append relative paths to.
+ */
+ void addXdgDataPrefix( const QString& dir );
+
+ /**
+ * Adds suffixes for types.
+ *
+ * You may add as many as you need, but it is advised that there
+ * is exactly one to make writing definite.
+ * All basic types are added by addKDEDefaults(),
+ * but for those you can add more relative paths as well.
+ *
+ * The later a suffix is added, the higher its priority. Note, that the
+ * suffix should end with / but doesn't have to start with one (as prefixes
+ * should end with one). So adding a suffix for app_pics would look
+ * like KGlobal::dirs()->addResourceType("app_pics", "data" ,"app/pics");
+ *
+ * @param type Specifies a short descriptive string to access
+ * files of this type.
+ * @param relativename Specifies a directory relative to the root
+ * of the KFSSTND.
+ * @param priority if true, the directory is added before any other,
+ * otherwise after
+ * @return true if successful, false otherwise.
+ *
+ * @deprecated, use addResourceType(type, 0, relativename, priority)
+ */
+#ifndef KDE_NO_DEPRECATED
+ KDE_DEPRECATED bool addResourceType( const char *type,
+ const QString& relativename, bool priority = true );
+#endif
+
+ /**
+ * Adds suffixes for types.
+ *
+ * You may add as many as you need, but it is advised that there
+ * is exactly one to make writing definite.
+ * All basic types are added by addKDEDefaults(),
+ * but for those you can add more relative paths as well.
+ *
+ * The later a suffix is added, the higher its priority. Note, that the
+ * suffix should end with / but doesn't have to start with one (as prefixes
+ * should end with one). So adding a suffix for app_pics would look
+ * like KGlobal::dirs()->addResourceType("app_pics", "data", "app/pics");
+ *
+ * @param type Specifies a short descriptive string to access
+ * files of this type.
+ * @param basetype Specifies an already known type, or 0 if none
+ * @param relativename Specifies a directory relative to the basetype
+ * @param priority if true, the directory is added before any other,
+ * otherwise after
+ * @return true if successful, false otherwise.
+ */
+ bool addResourceType( const char *type, const char *basetype,
+ const QString& relativename, bool priority = true );
+
+ /// @internal - just to avoid unwanted overload
+ bool addResourceType( const char *type, const char *basetype,
+ const char* relativename, bool priority = true )
+ {
+ return addResourceType(type, basetype, QLatin1String(relativename), priority);
+ }
+
+ /**
+ * Adds absolute path at the beginning of the search path for
+ * particular types (for example in case of icons where
+ * the user specifies extra paths).
+ *
+ * You shouldn't need this
+ * function in 99% of all cases besides adding user-given
+ * paths.
+ *
+ * @param type Specifies a short descriptive string to access files
+ * of this type.
+ * @param absdir Points to directory where to look for this specific
+ * type. Non-existent directories may be saved but pruned.
+ * @param priority if true, the directory is added before any other,
+ * otherwise after
+ * @return true if successful, false otherwise.
+ */
+ bool addResourceDir( const char *type,
+ const QString& absdir, bool priority = true );
+
+ /**
+ * Tries to find a resource in the following order:
+ * @li All PREFIX/\<relativename> paths (most recent first).
+ * @li All absolute paths (most recent first).
+ *
+ * The filename should be a filename relative to the base dir
+ * for resources. So is a way to get the path to libkdecore.la
+ * to findResource("lib", "libkdecore.la"). KStandardDirs will
+ * then look into the subdir lib of all elements of all prefixes
+ * ($KDEDIRS) for a file libkdecore.la and return the path to
+ * the first one it finds (e.g. /opt/kde/lib/libkdecore.la).
+ * You can use the program kde4-config to list all resource types:
+ * @code
+ * $ kde4-config --types
+ * @endcode
+ *
+ * Example:
+ * @code
+ * QString iconfilename=KGlobal::dirs()->findResource("icon",QString("oxygen/22x22/apps/ktip.png"));
+ * @endcode
+ *
+ * @param type The type of the wanted resource
+ * @param filename A relative filename of the resource.
+ *
+ * @return A full path to the filename specified in the second
+ * argument, or QString() if not found.
+ */
+ QString findResource( const char *type,
+ const QString& filename ) const;
+
+ /**
+ * Checks whether a resource is restricted as part of the KIOSK
+ * framework. When a resource is restricted it means that user-
+ * specific files in the resource are ignored.
+ *
+ * E.g. by restricting the @c "wallpaper" resource, only system-wide
+ * installed wallpapers will be found by this class. Wallpapers
+ * installed under the @c $KDEHOME directory will be ignored.
+ *
+ * @param type The type of the resource to check
+ * @param relPath A relative path in the resource.
+ *
+ * @return True if the resource is restricted.
+ */
+ bool isRestrictedResource( const char *type,
+ const QString& relPath=QString() ) const;
+
+ /**
+ * Returns a number that identifies this version of the resource.
+ * When a change is made to the resource this number will change.
+ *
+ * @param type The type of the wanted resource
+ * @param filename A relative filename of the resource.
+ * @param options If the flags includes Recursive,
+ * all resources are taken into account
+ * otherwise only the one returned by findResource().
+ *
+ * @return A number identifying the current version of the
+ * resource.
+ */
+ quint32 calcResourceHash( const char *type,
+ const QString& filename,
+ SearchOptions options = NoSearchOptions) const;
+
+ /**
+ * Tries to find all directories whose names consist of the
+ * specified type and a relative path. So
+ * findDirs("apps", "Settings") would return
+ * @li /home/joe/.kde/share/applnk/Settings/
+ * @li /opt/kde/share/applnk/Settings/
+ *
+ * (from the most local to the most global)
+ *
+ * Note that it appends @c / to the end of the directories,
+ * so you can use this right away as directory names.
+ *
+ * @param type The type of the base directory.
+ * @param reldir Relative directory.
+ *
+ * @return A list of matching directories, or an empty
+ * list if the resource specified is not found.
+ */
+ QStringList findDirs( const char *type,
+ const QString& reldir ) const;
+
+ /**
+ * Tries to find the directory the file is in.
+ * It works the same as findResource(), but it doesn't
+ * return the filename but the name of the directory.
+ *
+ * This way the application can access a couple of files
+ * that have been installed into the same directory without
+ * having to look for each file.
+ *
+ * findResourceDir("lib", "libkdecore.la") would return the
+ * path of the subdir libkdecore.la is found first in
+ * (e.g. /opt/kde/lib/)
+ *
+ * @param type The type of the wanted resource
+ * @param filename A relative filename of the resource.
+ * @return The directory where the file specified in the second
+ * argument is located, or QString() if the type
+ * of resource specified is unknown or the resource
+ * cannot be found.
+ */
+ QString findResourceDir( const char *type,
+ const QString& filename) const;
+
+
+ /**
+ * Tries to find all resources with the specified type.
+ *
+ * The function will look into all specified directories
+ * and return all filenames in these directories.
+ *
+ * The "most local" files are returned before the "more global" files.
+ *
+ * @param type The type of resource to locate directories for.
+ * @param filter Only accept filenames that fit to filter. The filter
+ * may consist of an optional directory and a QRegExp
+ * wildcard expression. E.g. <tt>"images\*.jpg"</tt>.
+ * Use QString() if you do not want a filter.
+ * @param options if the flags passed include Recursive, subdirectories
+ * will also be search; if NoDuplicates is passed then only entries with
+ * unique filenames will be returned eliminating duplicates.
+ *
+ * @return List of all the files whose filename matches the
+ * specified filter.
+ */
+ QStringList findAllResources( const char *type,
+ const QString& filter = QString(),
+ SearchOptions options = NoSearchOptions ) const;
+
+ /**
+ * Tries to find all resources with the specified type.
+ *
+ * The function will look into all specified directories
+ * and return all filenames (full and relative paths) in
+ * these directories.
+ *
+ * The "most local" files are returned before the "more global" files.
+ *
+ * @param type The type of resource to locate directories for. Can be icon,
+ * lib, pixmap, .... To get a complete list, call
+ * @code
+ * kde4-config --types
+ * @endcode
+ * @param filter Only accept filenames that fit to filter. The filter
+ * may consist of an optional directory and a QRegExp
+ * wildcard expression. E.g. <tt>"images\*.jpg"</tt>.
+ * Use QString() if you do not want a filter.
+ * @param options if the flags passed include Recursive, subdirectories
+ * will also be search; if NoDuplicates is passed then only entries with
+ * unique filenames will be returned eliminating duplicates.
+ *
+ * @param relPaths The list to store the relative paths into
+ * These can be used later to ::locate() the file
+ *
+ * @return List of all the files whose filename matches the
+ * specified filter.
+ */
+ QStringList findAllResources( const char *type,
+ const QString& filter,
+ SearchOptions options,
+ QStringList &relPaths) const;
+
+ /**
+ * Returns a QStringList list of pathnames in the system path.
+ *
+ * @param pstr The path which will be searched. If this is
+ * null (default), the @c $PATH environment variable will
+ * be searched.
+ *
+ * @return a QStringList list of pathnames in the system path.
+ */
+ static QStringList systemPaths( const QString& pstr=QString() );
+
+ /**
+ * Finds the executable in the system path.
+ *
+ * A valid executable must
+ * be a file and have its executable bit set.
+ *
+ * @param appname The name of the executable file for which to search.
+ * if this contains a path separator, it will be resolved
+ * according to the current working directory
+ * (shell-like behaviour).
+ * @param pathstr The path which will be searched. If this is
+ * null (default), the @c $PATH environment variable will
+ * be searched.
+ * @param options if the flags passed include IgnoreExecBit the path returned
+ * may not have the executable bit set.
+ *
+ * @return The path of the executable. If it was not found,
+ * it will return QString().
+ * @see findAllExe()
+ */
+ static QString findExe( const QString& appname,
+ const QString& pathstr = QString(),
+ SearchOptions options = NoSearchOptions );
+
+ /**
+ * Finds all occurrences of an executable in the system path.
+ *
+ * @param list will be filled with the pathnames of all the
+ * executables found. Will be empty if the executable
+ * was not found.
+ * @param appname the name of the executable for which to
+ * search.
+ * @param pathstr the path list which will be searched. If this
+ * is 0 (default), the @c $PATH environment variable will
+ * be searched.
+ * @param options if the flags passed include IgnoreExecBit the path returned
+ * may not have the executable bit set.
+ *
+ * @return The number of executables found, 0 if none were found.
+ *
+ * @see findExe()
+ */
+ static int findAllExe( QStringList& list, const QString& appname,
+ const QString& pathstr=QString(),
+ SearchOptions options = NoSearchOptions );
+
+ /**
+ * Reads customized entries out of the given config object and add
+ * them via addResourceDirs().
+ *
+ * @param config The object the entries are read from. This should
+ * contain global config files
+ * @return @c true if new config paths have been added
+ * from @p config.
+ **/
+ bool addCustomized(KConfig *config);
+
+ /**
+ * This function is used internally by almost all other function as
+ * it serves and fills the directories cache.
+ *
+ * @param type The type of resource
+ * @return The list of possible directories for the specified @p type.
+ * The function updates the cache if possible. If the resource
+ * type specified is unknown, it will return an empty list.
+ * Note, that the directories are assured to exist beside the save
+ * location, which may not exist, but is returned anyway.
+ */
+ QStringList resourceDirs(const char *type) const;
+
+ /**
+ * This function will return a list of all the types that KStandardDirs
+ * supports.
+ *
+ * @return All types that KDE supports
+ */
+ QStringList allTypes() const;
+
+ /**
+ * Finds a location to save files into for the given type
+ * in the user's home directory.
+ *
+ * @param type The type of location to return.
+ * @param suffix A subdirectory name.
+ * Makes it easier for you to create subdirectories.
+ * You can't pass filenames here, you _have_ to pass
+ * directory names only and add possible filename in
+ * that directory yourself. A directory name always has a
+ * trailing slash ('/').
+ * @param create If set, saveLocation() will create the directories
+ * needed (including those given by @p suffix).
+ *
+ * @return A path where resources of the specified type should be
+ * saved, or QString() if the resource type is unknown.
+ */
+ QString saveLocation(const char *type,
+ const QString& suffix = QString(),
+ bool create = true) const;
+
+ /**
+ * Converts an absolute path to a path relative to a certain
+ * resource.
+ *
+ * If "abs = ::locate(resource, rel)"
+ * then "rel = relativeLocation(resource, abs)" and vice versa.
+ *
+ * @param type The type of resource.
+ *
+ * @param absPath An absolute path to make relative.
+ *
+ * @return A relative path relative to resource @p type that
+ * will find @p absPath. If no such relative path exists, @p absPath
+ * will be returned unchanged.
+ */
+ QString relativeLocation(const char *type, const QString &absPath);
+
+ /**
+ * Recursively creates still-missing directories in the given path.
+ *
+ * The resulting permissions will depend on the current umask setting.
+ * <tt>permission = mode & ~umask</tt>.
+ *
+ * @param dir Absolute path of the directory to be made.
+ * @param mode Directory permissions.
+ * @return true if successful, false otherwise
+ */
+ static bool makeDir(const QString& dir, int mode = 0755);
+
+ /**
+ * This returns a default relative path for the standard KDE
+ * resource types. Below is a list of them so you get an idea
+ * of what this is all about.
+ *
+ * @li @c data - @c share/apps
+ * @li @c html - @c share/doc/HTML
+ * @li @c icon - @c share/icon
+ * @li @c config - @c share/config
+ * @li @c pixmap - @c share/pixmaps
+ * @li @c apps - @c share/applnk
+ * @li @c sound - @c share/sounds
+ * @li @c locale - @c share/locale
+ * @li @c services - @c share/kde4/services
+ * @li @c servicetypes - @c share/kde4/servicetypes
+ * @li @c mime - @c share/mimelnk
+ * @li @c cgi - @c cgi-bin
+ * @li @c wallpaper - @c share/wallpapers
+ * @li @c templates - @c share/templates
+ * @li @c exe - @c bin
+ * @li @c lib - @c lib[suffix]
+ * @li @c module - @c lib[suffix]/kde4
+ * @li @c qtplugins - @c lib[suffix]/kde4/plugins
+ * @li @c kcfg - @c share/config.kcfg
+ * @li @c emoticons - @c share/emoticons
+ * @li @c xdgdata-apps - @c applications
+ * @li @c xdgdata-icon - @c icons
+ * @li @c xdgdata-pixmap - @c pixmaps
+ * @li @c xdgdata-dirs - @c desktop-directories
+ * @li @c xdgdata-mime - @c mime
+ * @li @c xdgconf-menu - @c menus
+ *
+ * @returns Static default for the specified resource. You
+ * should probably be using locate() or locateLocal()
+ * instead.
+ * @see locate()
+ * @see locateLocal()
+ */
+#ifndef KDE_NO_DEPRECATED
+ static KDE_DEPRECATED QString kde_default(const char *type);
+#endif
+
+ /**
+ * @internal (for use by sycoca only)
+ */
+ QString kfsstnd_prefixes();
+
+ /**
+ * @internal (for use by sycoca only)
+ */
+ QString kfsstnd_xdg_conf_prefixes();
+
+ /**
+ * @internal (for use by sycoca only)
+ */
+ QString kfsstnd_xdg_data_prefixes();
+
+ /**
+ * Returns the toplevel directory in which KStandardDirs
+ * will store things. Most likely <tt>$HOME/.kde</tt>.
+ * Don't use this function if you can use locateLocal()
+ * @return the toplevel directory
+ */
+ QString localkdedir() const;
+
+ /**
+ * @return @c $XDG_DATA_HOME
+ * See also http://www.freedesktop.org/standards/basedir/draft/basedir-spec/basedir-spec.html
+ */
+ QString localxdgdatadir() const;
+
+ /**
+ * @return @c $XDG_CONFIG_HOME
+ * See also http://www.freedesktop.org/standards/basedir/draft/basedir-spec/basedir-spec.html
+ */
+ QString localxdgconfdir() const;
+
+ /**
+ * @return the path where type was installed to by kdelibs. This is an absolute path and only
+ * one out of many search paths
+ */
+ static QString installPath(const char *type);
+
+ /**
+ * Checks for existence and accessability of a file or directory.
+ * Faster than creating a QFileInfo first.
+ * @param fullPath the path to check. IMPORTANT: must end with a slash if expected to be a directory
+ * (and no slash for a file, obviously).
+ * @return @c true if the directory exists, @c false otherwise
+ */
+ static bool exists(const QString &fullPath);
+
+ /**
+ * Expands all symbolic links and resolves references to
+ * '/./', '/../' and extra '/' characters in @p dirname
+ * and returns the canonicalized absolute pathname.
+ * The resulting path will have no symbolic link, '/./'
+ * or '/../' components.
+ */
+ static QString realPath(const QString &dirname);
+
+ /**
+ * Expands all symbolic links and resolves references to
+ * '/./', '/../' and extra '/' characters in @p filename
+ * and returns the canonicalized absolute pathname.
+ * The resulting path will have no symbolic link, '/./'
+ * or '/../' components.
+ */
+ static QString realFilePath(const QString &filename);
+
+ /**
+ * This function is just for convenience. It simply calls
+ * instance->dirs()->\link KStandardDirs::findResource() findResource\endlink(type, filename).
+ *
+ * @param type The type of the wanted resource, see KStandardDirs
+ * @param filename A relative filename of the resource
+ * @param cData The KComponentData object
+ *
+ * @return A full path to the filename specified in the second
+ * argument, or QString() if not found
+ **/
+ static QString locate( const char *type, const QString& filename, const KComponentData &cData = KGlobal::mainComponent() );
+
+ /**
+ * This function is much like locate. However it returns a
+ * filename suitable for writing to. No check is made if the
+ * specified @p filename actually exists. Missing directories
+ * are created. If @p filename is only a directory, without a
+ * specific file, @p filename must have a trailing slash.
+ *
+ * @param type The type of the wanted resource, see KStandardDirs
+ * @param filename A relative filename of the resource
+ * @param cData The KComponentData object
+ *
+ * @return A full path to the filename specified in the second
+ * argument, or QString() if not found
+ **/
+ static QString locateLocal( const char *type, const QString& filename, const KComponentData &cData = KGlobal::mainComponent() );
+
+ /**
+ * This function is much like locate. No check is made if the
+ * specified filename actually exists. Missing directories
+ * are created if @p createDir is true. If @p filename is only
+ * a directory, without a specific file, @p filename must have
+ * a trailing slash.
+ *
+ * @param type The type of the wanted resource, see KStandardDirs
+ * @param filename A relative filename of the resource
+ * @param createDir If @c true, missing directories are created,
+ * if @c false, no directory is created
+ * @param cData The KComponentData object
+ *
+ * @return A full path to the filename specified in the second
+ * argument, or QString() if not found
+ **/
+ static QString locateLocal( const char *type, const QString& filename, bool createDir, const KComponentData &cData = KGlobal::mainComponent() );
+
+ /**
+ * Check, if a file may be accessed in a given mode.
+ * This is a wrapper around the access() system call.
+ * checkAccess() calls access() with the given parameters.
+ * If this is OK, checkAccess() returns true. If not, and W_OK
+ * is part of mode, it is checked if there is write access to
+ * the directory. If yes, checkAccess() returns true.
+ * In all other cases checkAccess() returns false.
+ *
+ * Other than access() this function EXPLICITLY ignores non-existent
+ * files if checking for write access.
+ *
+ * @param pathname The full path of the file you want to test
+ * @param mode The access mode, as in the access() system call.
+ * @return Whether the access is allowed, true = Access allowed
+ */
+ static bool checkAccess(const QString& pathname, int mode);
+
+private:
+ // Disallow assignment and copy-construction
+ KStandardDirs( const KStandardDirs& );
+ KStandardDirs& operator= ( const KStandardDirs& );
+
+ class KStandardDirsPrivate;
+ KStandardDirsPrivate* const d;
+
+ // Like their public counter parts but with an extra priority argument
+ // If priority is true, the directory is added directly after
+ // $KDEHOME/$XDG_DATA_HOME/$XDG_CONFIG_HOME
+ void addPrefix( const QString& dir, bool priority );
+ void addXdgConfigPrefix( const QString& dir, bool priority );
+ void addXdgDataPrefix( const QString& dir, bool priority );
+ void addKDEDefaults();
+
+ void addResourcesFrom_krcdirs();
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(KStandardDirs::SearchOptions)
+
+#endif // KSTANDARDDIRS_H
diff --git a/kdecore/kernel/kstandarddirs_unix.cpp b/kdecore/kernel/kstandarddirs_unix.cpp
new file mode 100644
index 0000000..f8646ea
--- /dev/null
+++ b/kdecore/kernel/kstandarddirs_unix.cpp
@@ -0,0 +1,106 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2007 Bernhard Loos <nhuh.put@web.de>
+
+ 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 "kstandarddirs.h"
+
+#include <config-prefix.h>
+#include <config.h>
+#include <QFile>
+
+QString KStandardDirs::installPath(const char *type)
+{
+ Q_ASSERT(type != NULL);
+
+ switch (type[0]) {
+ case 'a':
+ if (strcmp("apps", type) == 0)
+ return QFile::decodeName(APPLNK_INSTALL_DIR "/");
+ break;
+ case 'c':
+ if (strcmp("config", type) == 0)
+ return QFile::decodeName(CONFIG_INSTALL_DIR "/");
+ break;
+ case 'k':
+ if (strcmp("kcfg", type) == 0)
+ return QFile::decodeName(KCFG_INSTALL_DIR "/");
+ if (strcmp("kdedir", type) == 0)
+ return QFile::decodeName(KDEDIR "/");
+ break;
+ case 'd':
+ if (strcmp("data", type) == 0)
+ return QFile::decodeName(DATA_INSTALL_DIR "/");
+ break;
+ case 'e':
+ if (strcmp("exe", type) == 0)
+ return QFile::decodeName(BIN_INSTALL_DIR "/");
+ break;
+ case 'h':
+ if (strcmp("html", type) == 0)
+ return QFile::decodeName(HTML_INSTALL_DIR "/");
+ break;
+ case 'i':
+ if (strcmp("icon", type) == 0)
+ return QFile::decodeName(ICON_INSTALL_DIR "/");
+ if (strcmp("include", type) == 0)
+ return QFile::decodeName(INCLUDE_INSTALL_DIR "/");
+ break;
+ case 'l':
+ if (strcmp("lib", type) == 0)
+ return QFile::decodeName(LIB_INSTALL_DIR "/");
+ if (strcmp("libexec", type) == 0)
+ return QFile::decodeName(KDEDIR "/lib" KDELIBSUFF "/kde4/libexec/");
+ if (strcmp("locale", type) == 0)
+ return QFile::decodeName(LOCALE_INSTALL_DIR "/");
+ break;
+ case 'm':
+ if (strcmp("module", type) == 0)
+ return QFile::decodeName(PLUGIN_INSTALL_DIR "/");
+ if (strcmp("mime", type) == 0)
+ return QFile::decodeName(MIME_INSTALL_DIR "/");
+ break;
+ case 'q':
+ if (strcmp("qtplugins", type) == 0)
+ return QFile::decodeName(PLUGIN_INSTALL_DIR "/plugins/");
+ break;
+ case 's':
+ if (strcmp("services", type) == 0)
+ return QFile::decodeName(SERVICES_INSTALL_DIR "/");
+ if (strcmp("servicetypes", type) == 0)
+ return QFile::decodeName(SERVICETYPES_INSTALL_DIR "/");
+ if (strcmp("sound", type) == 0)
+ return QFile::decodeName(SOUND_INSTALL_DIR "/");
+ break;
+ case 't':
+ if (strcmp("templates", type) == 0)
+ return QFile::decodeName(TEMPLATES_INSTALL_DIR "/");
+ break;
+ case 'w':
+ if (strcmp("wallpaper", type) == 0)
+ return QFile::decodeName(WALLPAPER_INSTALL_DIR "/");
+ break;
+ case 'x':
+ if (strcmp("xdgconf-menu", type) == 0)
+ return QFile::decodeName(SYSCONF_INSTALL_DIR "/xdg/menus/");
+ if (strcmp("xdgdata-apps", type) == 0)
+ return QFile::decodeName(XDG_APPS_INSTALL_DIR "/");
+ if (strcmp("xdgdata-dirs", type) == 0)
+ return QFile::decodeName(XDG_DIRECTORY_INSTALL_DIR "/");
+ break;
+ }
+ return QString();
+}
diff --git a/kdecore/kernel/kstandarddirs_win.cpp b/kdecore/kernel/kstandarddirs_win.cpp
new file mode 100644
index 0000000..b47aa15
--- /dev/null
+++ b/kdecore/kernel/kstandarddirs_win.cpp
@@ -0,0 +1,113 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2007 Bernhard Loos <nhuh.put@web.de>
+ Copyright (C) 2008 Christian Ehrlicher <ch.ehrlicher@gmx.de>
+
+ 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 "kstandarddirs.h"
+
+#include <config-prefix.h>
+#include <config.h>
+#include "kkernel_win.h"
+
+QString getKde4Prefix();
+
+inline QString prefix() { return getKde4Prefix(); }
+inline QString share() { return getKde4Prefix() + QLatin1String("share/"); }
+inline QString kde_moduledir() { return getKde4Prefix() + QLatin1String("lib/kde4/"); }
+
+QString KStandardDirs::installPath(const char *type)
+{
+ Q_ASSERT(type != NULL);
+
+ switch (type[0]) {
+ case 'a':
+ if (strcmp("apps", type) == 0)
+ return share() + QLatin1String("applnk/");
+ break;
+ case 'c':
+ if (strcmp("config", type) == 0)
+ return share() + QLatin1String("config/");
+ break;
+ case 'k':
+ if (strcmp("kcfg", type) == 0)
+ return share() + QLatin1String("config.kcfg/");
+ if (strcmp("kdedir", type) == 0)
+ return prefix();
+ break;
+ case 'd':
+ if (strcmp("data", type) == 0)
+ return share() + QLatin1String("apps/");
+ break;
+ case 'e':
+ if (strcmp("exe", type) == 0)
+ return prefix() + QLatin1String("bin/");
+ break;
+ case 'h':
+ if (strcmp("html", type) == 0)
+ return share() + QLatin1String("doc/HTML/");
+ break;
+ case 'i':
+ if (strcmp("icon", type) == 0)
+ return share() + QLatin1String("icons/");
+ if (strcmp("include", type) == 0)
+ return prefix() + QLatin1String("include/");
+ break;
+ case 'l':
+ if (strcmp("lib", type) == 0)
+ return prefix() + QLatin1String("lib" KDELIBSUFF "/");
+ if (strcmp("libexec", type) == 0)
+ return prefix() + QLatin1String("lib" KDELIBSUFF "/kde4/libexec/");
+ if (strcmp("locale", type) == 0)
+ return share() + QLatin1String("locale/");
+ break;
+ case 'm':
+ if (strcmp("module", type) == 0)
+ return kde_moduledir();
+ if (strcmp("mime", type) == 0)
+ return share() + QLatin1String("mimelnk/");
+ break;
+ case 'q':
+ if (strcmp("qtplugins", type) == 0)
+ return kde_moduledir() + QLatin1String("plugins/");
+ break;
+ case 's':
+ if (strcmp("services", type) == 0)
+ return share() + QLatin1String("kde4/services/");
+ if (strcmp("servicetypes", type) == 0)
+ return share() + QLatin1String("kde4/servicetypes/");
+ if (strcmp("sound", type) == 0)
+ return share() + QLatin1String("sounds/");
+ break;
+ case 't':
+ if (strcmp("templates", type) == 0)
+ return share() + QLatin1String("templates/");
+ break;
+ case 'w':
+ if (strcmp("wallpaper", type) == 0)
+ return share() + QLatin1String("wallpapers/");
+ break;
+ case 'x':
+ if (strcmp("xdgconf-menu", type) == 0)
+ return share() + QLatin1String("xdg/menus/");
+ if (strcmp("xdgdata-apps", type) == 0)
+ return share() + QLatin1String("applications/kde4/");
+ if (strcmp("xdgdata-dirs", type) == 0)
+ return share() + QLatin1String("desktop-directories/");
+ break;
+ }
+ return QString();
+}
diff --git a/kdecore/kernel/ktoolinvocation.cpp b/kdecore/kernel/ktoolinvocation.cpp
new file mode 100644
index 0000000..73c8bc0
--- /dev/null
+++ b/kdecore/kernel/ktoolinvocation.cpp
@@ -0,0 +1,396 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2005 Brad Hards <bradh@frogmouth.net>
+ Copyright (C) 2006 Thiago Macieira <thiago@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 as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ 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 "ktoolinvocation.h"
+#include "klauncher_iface.h"
+#include "kdebug.h"
+#include "kglobal.h"
+#include "kstandarddirs.h"
+#include "kcomponentdata.h"
+#include "kurl.h"
+#include "kmessage.h"
+#include "kservice.h"
+#include <klockfile.h>
+#include <klocale.h>
+
+#include <QMutex>
+#include <QMutexLocker>
+#include <QCoreApplication>
+#include <QThread>
+
+#include <errno.h>
+
+
+KToolInvocation *KToolInvocation::self()
+{
+ K_GLOBAL_STATIC(KToolInvocation, s_self)
+ return s_self;
+}
+
+KToolInvocation::KToolInvocation() : QObject(0), d(0)
+{
+}
+
+KToolInvocation::~KToolInvocation()
+{
+}
+
+Q_GLOBAL_STATIC_WITH_ARGS(org::kde::KLauncher, klauncherIface,
+ (QString::fromLatin1("org.kde.klauncher"), QString::fromLatin1("/KLauncher"), QDBusConnection::sessionBus()))
+
+org::kde::KLauncher *KToolInvocation::klauncher()
+{
+ if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(QString::fromLatin1("org.kde.klauncher"))) {
+ kDebug(180) << "klauncher not running... launching kdeinit";
+ KToolInvocation::startKdeinit();
+ }
+ return ::klauncherIface();
+}
+
+static void printError(const QString& text, QString* error)
+{
+ if (error)
+ *error = text;
+ else
+ kError() << text << endl;
+}
+
+bool KToolInvocation::isMainThreadActive(QString* error)
+{
+ if (QCoreApplication::instance() && QCoreApplication::instance()->thread() != QThread::currentThread())
+ {
+ printError(i18n("Function must be called from the main thread."), error);
+ return false;
+ }
+
+ return true;
+}
+
+int KToolInvocation::startServiceInternal(const char *_function,
+ const QString& _name, const QStringList &URLs,
+ QString *error, QString *serviceName, int *pid,
+ const QByteArray& startup_id, bool noWait,
+ const QString& workdir)
+{
+ QString function = QLatin1String(_function);
+ org::kde::KLauncher *launcher = KToolInvocation::klauncher();
+ QDBusMessage msg = QDBusMessage::createMethodCall(launcher->service(),
+ launcher->path(),
+ launcher->interface(),
+ function);
+ msg << _name << URLs;
+ if (function == QLatin1String("kdeinit_exec_with_workdir"))
+ msg << workdir;
+#ifdef Q_WS_X11
+ // make sure there is id, so that user timestamp exists
+ QStringList envs;
+ QByteArray s = startup_id;
+ emit kapplication_hook(envs, s);
+ msg << envs;
+ msg << QString::fromLatin1(s);
+#else
+ msg << QStringList();
+ msg << QString();
+#endif
+ if( !function.startsWith( QLatin1String("kdeinit_exec") ) )
+ msg << noWait;
+
+ QDBusMessage reply = QDBusConnection::sessionBus().call(msg, QDBus::Block, INT_MAX);
+ if ( reply.type() != QDBusMessage::ReplyMessage )
+ {
+ QDBusReply<QString> replyObj(reply);
+ if (replyObj.error().type() == QDBusError::NoReply) {
+ printError(i18n("Error launching %1. Either KLauncher is not running anymore, or it failed to start the application.", _name), error);
+ } else {
+ const QString rpl = reply.arguments().count() > 0 ? reply.arguments().at(0).toString() : reply.errorMessage();
+ printError(i18n("KLauncher could not be reached via D-Bus. Error when calling %1:\n%2\n",function, rpl), error);
+ }
+ //qDebug() << reply;
+ return EINVAL;
+ }
+
+ if (noWait)
+ return 0;
+
+ Q_ASSERT(reply.arguments().count() == 4);
+ if (serviceName)
+ *serviceName = reply.arguments().at(1).toString();
+ if (error)
+ *error = reply.arguments().at(2).toString();
+ if (pid)
+ *pid = reply.arguments().at(3).toInt();
+ return reply.arguments().at(0).toInt();
+}
+
+#ifndef KDE_NO_DEPRECATED
+int
+KToolInvocation::startServiceByName( const QString& _name, const QString &URL,
+ QString *error, QString *serviceName, int *pid,
+ const QByteArray& startup_id, bool noWait )
+{
+ if (!isMainThreadActive(error))
+ return EINVAL;
+
+ QStringList URLs;
+ if (!URL.isEmpty())
+ URLs.append(URL);
+ return self()->startServiceInternal("start_service_by_name",
+ _name, URLs, error, serviceName, pid, startup_id, noWait);
+}
+#endif
+
+#ifndef KDE_NO_DEPRECATED
+int
+KToolInvocation::startServiceByName( const QString& _name, const QStringList &URLs,
+ QString *error, QString *serviceName, int *pid,
+ const QByteArray& startup_id, bool noWait )
+{
+ if (!isMainThreadActive(error))
+ return EINVAL;
+
+ return self()->startServiceInternal("start_service_by_name",
+ _name, URLs, error, serviceName, pid, startup_id, noWait);
+}
+#endif
+
+int
+KToolInvocation::startServiceByDesktopPath( const QString& _name, const QString &URL,
+ QString *error, QString *serviceName,
+ int *pid, const QByteArray& startup_id, bool noWait )
+{
+ if (!isMainThreadActive(error))
+ return EINVAL;
+
+ QStringList URLs;
+ if (!URL.isEmpty())
+ URLs.append(URL);
+ return self()->startServiceInternal("start_service_by_desktop_path",
+ _name, URLs, error, serviceName, pid, startup_id, noWait);
+}
+
+int
+KToolInvocation::startServiceByDesktopPath( const QString& _name, const QStringList &URLs,
+ QString *error, QString *serviceName, int *pid,
+ const QByteArray& startup_id, bool noWait )
+{
+ if (!isMainThreadActive(error))
+ return EINVAL;
+
+ return self()->startServiceInternal("start_service_by_desktop_path",
+ _name, URLs, error, serviceName, pid, startup_id, noWait);
+}
+
+int
+KToolInvocation::startServiceByDesktopName( const QString& _name, const QString &URL,
+ QString *error, QString *serviceName, int *pid,
+ const QByteArray& startup_id, bool noWait )
+{
+ if (!isMainThreadActive(error))
+ return EINVAL;
+
+ QStringList URLs;
+ if (!URL.isEmpty())
+ URLs.append(URL);
+ return self()->startServiceInternal("start_service_by_desktop_name",
+ _name, URLs, error, serviceName, pid, startup_id, noWait);
+}
+
+int
+KToolInvocation::startServiceByDesktopName( const QString& _name, const QStringList &URLs,
+ QString *error, QString *serviceName, int *pid,
+ const QByteArray& startup_id, bool noWait )
+{
+ if (!isMainThreadActive(error))
+ return EINVAL;
+
+ return self()->startServiceInternal("start_service_by_desktop_name",
+ _name, URLs, error, serviceName, pid, startup_id, noWait);
+}
+
+int
+KToolInvocation::kdeinitExec( const QString& name, const QStringList &args,
+ QString *error, int *pid, const QByteArray& startup_id )
+{
+ if (!isMainThreadActive(error))
+ return EINVAL;
+
+ return self()->startServiceInternal("kdeinit_exec",
+ name, args, error, 0, pid, startup_id, false);
+}
+
+
+int
+KToolInvocation::kdeinitExecWait( const QString& name, const QStringList &args,
+ QString *error, int *pid, const QByteArray& startup_id )
+{
+ if (!isMainThreadActive(error))
+ return EINVAL;
+
+ return self()->startServiceInternal("kdeinit_exec_wait",
+ name, args, error, 0, pid, startup_id, false);
+}
+
+void KToolInvocation::invokeHelp( const QString& anchor,
+ const QString& _appname,
+ const QByteArray& startup_id )
+{
+ if (!isMainThreadActive())
+ return;
+
+ KUrl url;
+ QString appname;
+ QString docPath;
+ if (_appname.isEmpty()) {
+ appname = QCoreApplication::instance()->applicationName();
+ } else
+ appname = _appname;
+
+ KService::Ptr service(KService::serviceByDesktopName(appname));
+ if (service) {
+ docPath = service->docPath();
+ }
+
+ if (!docPath.isEmpty()) {
+ url = KUrl(KUrl("help:/"), docPath);
+ } else {
+ url = QString::fromLatin1("help:/%1/index.html").arg(appname);
+ }
+
+ if (!anchor.isEmpty()) {
+ url.addQueryItem(QString::fromLatin1("anchor"), anchor);
+ }
+
+ // launch a browser for URIs not handled by khelpcenter
+ // (following KCMultiDialog::slotHelpClicked())
+ if (!(url.protocol() == QLatin1String("help") || url.protocol() == QLatin1String("man") || url.protocol() == QLatin1String("info"))) {
+ invokeBrowser(url.url());
+ return;
+ }
+
+ QDBusInterface *iface = new QDBusInterface(QLatin1String("org.kde.khelpcenter"),
+ QLatin1String("/KHelpCenter"),
+ QLatin1String("org.kde.khelpcenter.khelpcenter"),
+ QDBusConnection::sessionBus());
+ if ( !iface->isValid() )
+ {
+ QString error;
+#ifdef Q_WS_WIN
+ // startServiceByDesktopName() does not work yet; KRun:processDesktopExec returned 'KRun: syntax error in command "khelpcenter %u" , service "KHelpCenter" '
+ if (kdeinitExec(QLatin1String("khelpcenter"), QStringList() << url.url(), &error, 0, startup_id))
+#else
+ if (startServiceByDesktopName(QLatin1String("khelpcenter"), url.url(), &error, 0, 0, startup_id, false))
+#endif
+ {
+ KMessage::message(KMessage::Error,
+ i18n("Could not launch the KDE Help Center:\n\n%1", error),
+ i18n("Could not Launch Help Center"));
+ delete iface;
+ return;
+ }
+
+ delete iface;
+ iface = new QDBusInterface(QLatin1String("org.kde.khelpcenter"),
+ QLatin1String("/KHelpCenter"),
+ QLatin1String("org.kde.khelpcenter.khelpcenter"),
+ QDBusConnection::sessionBus());
+ }
+
+ iface->call(QString::fromLatin1("openUrl"), url.url(), startup_id );
+ delete iface;
+}
+
+void KToolInvocation::invokeMailer(const QString &address, const QString &subject, const QByteArray& startup_id)
+{
+ if (!isMainThreadActive())
+ return;
+
+ invokeMailer(address, QString(), QString(), subject, QString(), QString(),
+ QStringList(), startup_id );
+}
+
+void KToolInvocation::invokeMailer(const KUrl &mailtoURL, const QByteArray& startup_id, bool allowAttachments )
+{
+ if (!isMainThreadActive())
+ return;
+
+ QString address = mailtoURL.path();
+ QString subject;
+ QString cc;
+ QString bcc;
+ QString body;
+
+ const QStringList queries = mailtoURL.query().mid(1).split(QLatin1Char('&'));
+ const QChar comma = QChar::fromLatin1(',');
+ QStringList attachURLs;
+ for (QStringList::ConstIterator it = queries.begin(); it != queries.end(); ++it)
+ {
+ QString q = (*it).toLower();
+ if (q.startsWith(QLatin1String("subject=")))
+ subject = KUrl::fromPercentEncoding((*it).mid(8).toLatin1());
+ else
+ if (q.startsWith(QLatin1String("cc=")))
+ cc = cc.isEmpty()? KUrl::fromPercentEncoding((*it).mid(3).toLatin1()): cc + comma + KUrl::fromPercentEncoding((*it).mid(3).toLatin1());
+ else
+ if (q.startsWith(QLatin1String("bcc=")))
+ bcc = bcc.isEmpty()? KUrl::fromPercentEncoding((*it).mid(4).toLatin1()): bcc + comma + KUrl::fromPercentEncoding((*it).mid(4).toLatin1());
+ else
+ if (q.startsWith(QLatin1String("body=")))
+ body = KUrl::fromPercentEncoding((*it).mid(5).toLatin1());
+ else
+ if (allowAttachments && q.startsWith(QLatin1String("attach=")))
+ attachURLs.push_back(KUrl::fromPercentEncoding((*it).mid(7).toLatin1()));
+ else
+ if (allowAttachments && q.startsWith(QLatin1String("attachment=")))
+ attachURLs.push_back(KUrl::fromPercentEncoding((*it).mid(11).toLatin1()));
+ else
+ if (q.startsWith(QLatin1String("to=")))
+ address = address.isEmpty()? KUrl::fromPercentEncoding((*it).mid(3).toLatin1()): address + comma + KUrl::fromPercentEncoding((*it).mid(3).toLatin1());
+ }
+
+ invokeMailer( address, cc, bcc, subject, body, QString(), attachURLs, startup_id );
+}
+
+void KToolInvocation::startKdeinit()
+{
+ KComponentData inst( "startkdeinitlock" );
+ KLockFile lock( KStandardDirs::locateLocal("tmp", QString::fromLatin1("startkdeinitlock"), inst ));
+ if( lock.lock( KLockFile::NoBlockFlag ) != KLockFile::LockOK ) {
+ lock.lock();
+ if( QDBusConnection::sessionBus().interface()->isServiceRegistered(QString::fromLatin1("org.kde.klauncher")))
+ return; // whoever held the lock has already started it
+ }
+ // Try to launch kdeinit.
+ QString srv = KStandardDirs::findExe(QLatin1String("kdeinit4"));
+ if (srv.isEmpty())
+ return;
+// this is disabled because we are in kdecore
+// const bool gui = qApp && qApp->type() != QApplication::Tty;
+// if ( gui )
+// qApp->setOverrideCursor( Qt::WaitCursor );
+ QStringList args;
+#ifndef Q_WS_WIN
+ args += QString::fromLatin1("--suicide");
+#endif
+ QProcess::execute(srv, args);
+// if ( gui )
+// qApp->restoreOverrideCursor();
+}
+
+#include "ktoolinvocation.moc"
diff --git a/kdecore/kernel/ktoolinvocation.h b/kdecore/kernel/ktoolinvocation.h
new file mode 100644
index 0000000..6b01a40
--- /dev/null
+++ b/kdecore/kernel/ktoolinvocation.h
@@ -0,0 +1,398 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 1997-1999 Matthias Kalle Dalheimer <kalle@kde.org>
+ Copyright (c) 1997-2000 Matthias Ettrich <ettrich@troll.no>
+ Copyright (c) 1998-2005 Stephan Kulow <coolo@kde.org>
+ Copyright (c) 1999-2004 Waldo Bastian <bastian@kde.org>
+ Copyright (c) 2001-2005 Lubos Lunak <l.lunak@kde.org>
+ Copyright (C) 2008 Aaron Seigo <aseigo@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 as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ 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.
+*/
+
+#ifndef _KTOOLINVOCATION_H
+#define _KTOOLINVOCATION_H
+
+#include <kdecore_export.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QByteArray>
+#include <QtCore/QStringList>
+
+class OrgKdeKLauncherInterface;
+class KUrl;
+class KToolInvocationPrivate;
+
+/**
+ * KToolInvocation: for starting other programs
+ *
+ * @section desktopfiles Desktop files for startServiceBy
+ *
+ * The way a service gets started depends on the 'X-DBUS-StartupType'
+ * entry in the desktop file of the service:
+ *
+ * There are three possibilities:
+ * @li X-DBUS-StartupType=None (default)
+ * Always start a new service,
+ * don't wait till the service registers with D-Bus.
+ * @li X-DBUS-StartupType=Multi
+ * Always start a new service,
+ * wait until the service has registered with D-Bus.
+ * @li X-DBUS-StartupType=Unique
+ * Only start the service if it isn't already running,
+ * wait until the service has registered with D-Bus.
+ * The .desktop file can specify the name that the application will use when registering
+ * using X-DBUS-ServiceName=org.domain.mykapp. Otherwise org.kde.binaryname is assumed.
+ *
+ * @section thread Multi-threading
+ *
+ * The static members (apart from self()), have to be called from the QApplication main thread.
+ * Calls to members are only allowed if there is a Q(Core)Application object created
+ * If you call the members with signal/slot connections across threads, you can't use the return values
+ * If a function is called from the wrong thread and it has a return value -1 is returned
+ * Investigate if this is really needed or if D-Bus is threadsafe anyway
+ *
+ * For more details see <a
+ * href="http://techbase.kde.org/Development/Architecture/KDE4/Starting_Other_Programs#KToolInvocation::startServiceByDesktopPath">techbase</a>.
+ *
+ */
+class KDECORE_EXPORT KToolInvocation : public QObject
+{
+
+ Q_OBJECT
+private:
+ KToolInvocation();
+public:
+ // @internal
+ ~KToolInvocation();
+ static KToolInvocation *self();
+
+public Q_SLOTS:
+ /**
+ * Invokes the KHelpCenter HTML help viewer from docbook sources.
+ *
+ * @param anchor This has to be a defined anchor in your
+ * docbook sources. If empty the main index
+ * is loaded
+ * @param appname This allows you to show the help of another
+ * application. If empty the current name() is
+ * used
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ */
+
+ static void invokeHelp( const QString& anchor = QString(),
+ const QString& appname = QString(),
+ const QByteArray& startup_id = QByteArray());
+
+ /**
+ * Convenience method; invokes the standard email application.
+ *
+ * @param address The destination address
+ * @param subject Subject string. Can be QString().
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ */
+ static void invokeMailer( const QString &address, const QString &subject,
+ const QByteArray& startup_id = QByteArray() );
+
+ /**
+ * Invokes the standard email application.
+ *
+ * @param mailtoURL A mailto URL.
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ * @param allowAttachments whether attachments specified in mailtoURL should be honoured.
+ The default is false; do not honor requests for attachments.
+ */
+ static void invokeMailer( const KUrl &mailtoURL, const QByteArray& startup_id = QByteArray(),
+ bool allowAttachments = false );
+
+ /**
+ * Convenience method; invokes the standard email application.
+ *
+ * All parameters are optional.
+ *
+ * @param to The destination address.
+ * @param cc The Cc field
+ * @param bcc The Bcc field
+ * @param subject Subject string
+ * @param body A string containing the body of the mail (exclusive with messageFile)
+ * @param messageFile A file (URL) containing the body of the mail (exclusive with body) - currently unsupported
+ * @param attachURLs List of URLs to be attached to the mail.
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ */
+ static void invokeMailer(const QString &to, const QString &cc, const QString &bcc,
+ const QString &subject, const QString &body,
+ const QString &messageFile = QString(),
+ const QStringList &attachURLs = QStringList(),
+ const QByteArray& startup_id = QByteArray() );
+
+ /**
+ * Invokes the user's preferred browser.
+ * Note that you should only do this when you know for sure that the browser can
+ * handle the URL (i.e. its mimetype). In doubt, if the URL can point to an image
+ * or anything else than HTML, prefer to use new KRun( url ).
+ *
+ * See also <a
+ * href="http://techbase.kde.org/Development/Architecture/KDE4/Starting_Other_Programs#KToolInvocation::invokeBrowser>techbase</a>
+ * for a discussion of invokeBrowser vs KRun.
+ *
+ * @param url The destination address
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ */
+ static void invokeBrowser( const QString &url,
+ const QByteArray& startup_id = QByteArray() );
+
+ /**
+ * Invokes the standard terminal application.
+ *
+ * @param command the command to execute, can be empty.
+ * @param workdir the initial working directory, can be empty.
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ *
+ * @since 4.1
+ */
+ static void invokeTerminal(const QString &command,
+ const QString& workdir = QString(),
+ const QByteArray &startup_id = "");
+
+public:
+ /**
+ * Returns the D-Bus interface of the service launcher.
+ * The returned object is owned by KApplication, do not delete it!
+ */
+ static OrgKdeKLauncherInterface *klauncher();
+ // KDE5: remove this from the public API. Make it kdelibs-private, and provide
+ // replacements for setLaunchEnv and for "making sure kdeinit/klauncher is running".
+ // (We could do the last two without waiting, of course).
+
+ /**
+ * Starts a service based on the (translated) name of the service.
+ * E.g. "Web Browser"
+ *
+ * @param _name the name of the service
+ * @param URL if not empty this URL is passed to the service
+ * @param error On failure, error contains a description of the error
+ * that occurred. If the pointer is 0, the argument will be
+ * ignored
+ * @param serviceName On success, serviceName contains the DCOP name
+ * under which this service is available. If empty, the service does
+ * not provide DCOP services. If the pointer is 0 the argument
+ * will be ignored
+ * @param pid On success, the process id of the new service will be written
+ * here. If the pointer is 0, the argument will be ignored.
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ * @param noWait if set, the function does not wait till the service is running.
+ * @return an error code indicating success (== 0) or failure (> 0).
+ * @deprecated Use startServiceByDesktopName or startServiceByDesktopPath
+ */
+#ifndef KDE_NO_DEPRECATED
+ KDE_DEPRECATED static int startServiceByName( const QString& _name, const QString &URL,
+ QString *error=0, QString *serviceName=0, int *pid=0,
+ const QByteArray &startup_id = QByteArray(), bool noWait = false );
+#endif
+
+ /**
+ * Starts a service based on the (translated) name of the service.
+ * E.g. "Web Browser"
+ *
+ * @param _name the name of the service
+ * @param URLs if not empty these URLs will be passed to the service
+ * @param error On failure, @p error contains a description of the error
+ * that occurred. If the pointer is 0, the argument will be
+ * ignored
+ * @param serviceName On success, @p serviceName contains the DCOP name
+ * under which this service is available. If empty, the service does
+ * not provide DCOP services. If the pointer is 0 the argument
+ * will be ignored
+ * @param pid On success, the process id of the new service will be written
+ * here. If the pointer is 0, the argument will be ignored.
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ * @param noWait if set, the function does not wait till the service is running.
+ * @return an error code indicating success (== 0) or failure (> 0).
+ * @deprecated Use startServiceByDesktopName or startServiceByDesktopPath
+ */
+#ifndef KDE_NO_DEPRECATED
+ KDE_DEPRECATED static int startServiceByName( const QString& _name, const QStringList &URLs=QStringList(),
+ QString *error=0, QString *serviceName=0, int *pid=0,
+ const QByteArray &startup_id = QByteArray(), bool noWait = false );
+#endif
+
+ /**
+ * Starts a service based on the desktop path of the service.
+ * E.g. "Applications/konqueror.desktop" or "/home/user/bla/myfile.desktop"
+ *
+ * @param _name the path of the desktop file
+ * @param URL if not empty this URL is passed to the service
+ * @param error On failure, @p error contains a description of the error
+ * that occurred. If the pointer is 0, the argument will be
+ * ignored
+ * @param serviceName On success, @p serviceName contains the DCOP name
+ * under which this service is available. If empty, the service does
+ * not provide DCOP services. If the pointer is 0 the argument
+ * will be ignored
+ * @param pid On success, the process id of the new service will be written
+ * here. If the pointer is 0, the argument will be ignored.
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ * @param noWait if set, the function does not wait till the service is running.
+ * @return an error code indicating success (== 0) or failure (> 0).
+ */
+ static int startServiceByDesktopPath( const QString& _name, const QString &URL,
+ QString *error=0, QString *serviceName=0, int *pid = 0,
+ const QByteArray &startup_id = QByteArray(), bool noWait = false );
+
+ /**
+ * Starts a service based on the desktop path of the service.
+ * E.g. "Applications/konqueror.desktop" or "/home/user/bla/myfile.desktop"
+ *
+ * @param _name the path of the desktop file
+ * @param URLs if not empty these URLs will be passed to the service
+ * @param error On failure, @p error contains a description of the error
+ * that occurred. If the pointer is 0, the argument will be
+ * ignored * @param serviceName On success, @p serviceName contains the DCOP name
+ * under which this service is available. If empty, the service does
+ * not provide DCOP services. If the pointer is 0 the argument
+ * will be ignored
+ * @param pid On success, the process id of the new service will be written
+ * here. If the pointer is 0, the argument will be ignored.
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ * @param noWait if set, the function does not wait till the service is running.
+ * @return an error code indicating success (== 0) or failure (> 0).
+ */
+ static int startServiceByDesktopPath( const QString& _name, const QStringList &URLs=QStringList(),
+ QString *error=0, QString *serviceName=0, int *pid = 0,
+ const QByteArray &startup_id = QByteArray(), bool noWait = false );
+
+ /**
+ * Starts a service based on the desktop name of the service.
+ * E.g. "konqueror"
+ *
+ * @param _name the desktop name of the service
+ * @param URL if not empty this URL is passed to the service
+ * @param error On failure, @p error contains a description of the error
+ * that occurred. If the pointer is 0, the argument will be
+ * ignored
+ * @param serviceName On success, @p serviceName contains the D-Bus service name
+ * under which this service is available. If empty, the service does
+ * not provide D-Bus services. If the pointer is 0 the argument
+ * will be ignored
+ * @param pid On success, the process id of the new service will be written
+ * here. If the pointer is 0, the argument will be ignored.
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ * @param noWait if set, the function does not wait till the service is running.
+ * @return an error code indicating success (== 0) or failure (> 0).
+ */
+ static int startServiceByDesktopName( const QString& _name, const QString &URL,
+ QString *error=0, QString *serviceName=0, int *pid = 0,
+ const QByteArray &startup_id = QByteArray(), bool noWait = false );
+
+ /**
+ * Starts a service based on the desktop name of the service.
+ * E.g. "konqueror"
+ *
+ * @param _name the desktop name of the service
+ * @param URLs if not empty these URLs will be passed to the service
+ * @param error On failure, @p error contains a description of the error
+ * that occurred. If the pointer is 0, the argument will be
+ * ignored
+ * @param serviceName On success, @p serviceName contains the D-Bus service name
+ * under which this service is available. If empty, the service does
+ * not provide D-Bus services. If the pointer is 0 the argument
+ * will be ignored
+ * @param pid On success, the process id of the new service will be written
+ * here. If the pointer is 0, the argument will be ignored.
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ * @param noWait if set, the function does not wait till the service is running.
+ * @return an error code indicating success (== 0) or failure (> 0).
+ */
+ static int startServiceByDesktopName( const QString& _name, const QStringList &URLs=QStringList(),
+ QString *error=0, QString *serviceName=0, int *pid = 0,
+ const QByteArray &startup_id = QByteArray(), bool noWait = false );
+
+ /**
+ * Starts a program via kdeinit.
+ *
+ * program name and arguments are converted to according to the
+ * local encoding and passed as is to kdeinit.
+ *
+ * @param name Name of the program to start
+ * @param args Arguments to pass to the program
+ * @param error On failure, @p error contains a description of the error
+ * that occurred. If the pointer is 0, the argument will be
+ * ignored
+ * @param pid On success, the process id of the new service will be written
+ * here. If the pointer is 0, the argument will be ignored.
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ * @return an error code indicating success (== 0) or failure (> 0).
+ */
+ static int kdeinitExec( const QString& name, const QStringList &args=QStringList(),
+ QString *error=0, int *pid = 0, const QByteArray& startup_id = QByteArray() );
+
+ /**
+ * Starts a program via kdeinit and wait for it to finish.
+ *
+ * Like kdeinitExec(), but it waits till the program is finished.
+ * As such it behaves similar to the system(...) function.
+ *
+ * @param name Name of the program to start
+ * @param args Arguments to pass to the program
+ * @param error On failure, @p error contains a description of the error
+ * that occurred. If the pointer is 0, the argument will be
+ * ignored
+ * @param pid On success, the process id of the new service will be written
+ * here. If the pointer is 0, the argument will be ignored.
+ * @param startup_id for app startup notification, "0" for none,
+ * "" ( empty string ) is the default
+ * @return an error code indicating success (== 0) or failure (> 0).
+ */
+ static int kdeinitExecWait( const QString& name, const QStringList &args=QStringList(),
+ QString *error=0, int *pid = 0, const QByteArray& startup_id = QByteArray() );
+
+Q_SIGNALS:
+ /**
+ * Hook for KApplication in kdeui
+ * @internal
+ */
+ void kapplication_hook(QStringList& env , QByteArray& startup_id);
+
+private:
+ /**
+ * @internal
+ */
+ static void startKdeinit();
+
+ int startServiceInternal(const char *_function,
+ const QString& _name, const QStringList &URLs,
+ QString *error, QString *serviceName, int *pid,
+ const QByteArray& startup_id, bool noWait,
+ const QString& workdir = QString());
+ static bool isMainThreadActive(QString* error = 0);
+
+ KToolInvocationPrivate * const d;
+};
+
+#endif
+
diff --git a/kdecore/kernel/ktoolinvocation_win.cpp b/kdecore/kernel/ktoolinvocation_win.cpp
new file mode 100644
index 0000000..d6cf112
--- /dev/null
+++ b/kdecore/kernel/ktoolinvocation_win.cpp
@@ -0,0 +1,85 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (C) 2004-2008 Jarosław Staniek <staniek@kde.org>
+ Copyright (C) 2006 Ralf Habacker <ralf.habacker@freenet.de>
+
+ 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 "ktoolinvocation.h"
+#include <config.h>
+
+#include "kmessage.h"
+#include "klocale.h"
+#include "kurl.h"
+
+#include <QProcess>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QHash>
+#include <QtDBus/QtDBus>
+
+#include "windows.h"
+#include "shellapi.h"
+
+
+void KToolInvocation::invokeBrowser( const QString &url, const QByteArray& startup_id )
+{
+#ifndef _WIN32_WCE
+ QString sOpen = QString::fromLatin1("open");
+ ShellExecuteW(0, ( LPCWSTR )sOpen.utf16(), ( LPCWSTR )url.utf16(), 0, 0, SW_NORMAL);
+#else
+ SHELLEXECUTEINFO cShellExecuteInfo = {0};
+ cShellExecuteInfo.cbSize = sizeof(SHELLEXECUTEINFO);
+ cShellExecuteInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
+ cShellExecuteInfo.hwnd = NULL;
+ cShellExecuteInfo.lpVerb = L"Open";
+ cShellExecuteInfo.lpFile = ( LPCWSTR )url.utf16();
+ cShellExecuteInfo.nShow = SW_SHOWNORMAL;
+ ShellExecuteEx(&cShellExecuteInfo);
+#endif
+}
+
+void KToolInvocation::invokeMailer(const QString &_to, const QString &_cc, const QString &_bcc,
+ const QString &subject, const QString &body,
+ const QString & /*messageFile TODO*/, const QStringList &attachURLs,
+ const QByteArray& startup_id )
+{
+ KUrl url(QLatin1String("mailto:")+_to);
+ url.setQuery(QLatin1String("?subject=")+subject);
+ url.addQueryItem(QLatin1String("cc"), _cc);
+ url.addQueryItem(QLatin1String("bcc"), _bcc);
+ url.addQueryItem(QLatin1String("body"), body);
+ foreach (const QString& attachURL, attachURLs)
+ url.addQueryItem(QLatin1String("attach"), QLatin1String( KUrl::toPercentEncoding(attachURL) ));
+
+#ifndef _WIN32_WCE
+ QString sOpen = QLatin1String( "open" );
+ ShellExecuteW(0, ( LPCWSTR )sOpen.utf16(), ( LPCWSTR )url.url().utf16(), 0, 0, SW_NORMAL);
+#else
+ SHELLEXECUTEINFO cShellExecuteInfo = {0};
+ cShellExecuteInfo.cbSize = sizeof(SHELLEXECUTEINFO);
+ cShellExecuteInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
+ cShellExecuteInfo.hwnd = NULL;
+ cShellExecuteInfo.lpVerb = L"Open";
+ cShellExecuteInfo.lpFile = ( LPCWSTR )url.url().utf16();
+ cShellExecuteInfo.nShow = SW_SHOWNORMAL;
+ ShellExecuteEx(&cShellExecuteInfo);
+#endif
+}
+
+void KToolInvocation::invokeTerminal(const QString &command, const QString &workdir, const QByteArray &startup_id)
+{
+ //TODO
+}
diff --git a/kdecore/kernel/ktoolinvocation_x11.cpp b/kdecore/kernel/ktoolinvocation_x11.cpp
new file mode 100644
index 0000000..5168f2f
--- /dev/null
+++ b/kdecore/kernel/ktoolinvocation_x11.cpp
@@ -0,0 +1,422 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 1997,1998 Matthias Kalle Dalheimer <kalle@kde.org>
+ Copyright (c) 1999 Espen Sand <espen@kde.org>
+ Copyright (c) 2000-2004 Frerich Raabe <raabe@kde.org>
+ Copyright (c) 2003,2004 Oswald Buddenhagen <ossi@kde.org>
+ Copyright (c) 2006 Thiago Macieira <thiago@kde.org>
+ Copyright (C) 2008 Aaron Seigo <aseigo@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 as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ 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 <config.h>
+
+#include "ktoolinvocation.h"
+
+#include <kconfiggroup.h>
+#include <kmimetypetrader.h>
+
+#include "kcmdlineargs.h"
+#include "kconfig.h"
+#include "kcodecs.h"
+#include "kdebug.h"
+#include "kglobal.h"
+#include "kshell.h"
+#include "kmacroexpander.h"
+#include "klocale.h"
+#include "kstandarddirs.h"
+#include "kmessage.h"
+#include "kservice.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QProcess>
+#include <QtCore/QHash>
+#include <QtCore/QDebug>
+#include <QtCore/QBool>
+#include <QtCore/QFile>
+#include <QtDBus/QtDBus>
+
+static QStringList splitEmailAddressList( const QString & aStr )
+{
+ // This is a copy of KPIM::splitEmailAddrList().
+ // Features:
+ // - always ignores quoted characters
+ // - ignores everything (including parentheses and commas)
+ // inside quoted strings
+ // - supports nested comments
+ // - ignores everything (including double quotes and commas)
+ // inside comments
+
+ QStringList list;
+
+ if (aStr.isEmpty())
+ return list;
+
+ QString addr;
+ uint addrstart = 0;
+ int commentlevel = 0;
+ bool insidequote = false;
+
+ for (int index=0; index<aStr.length(); index++) {
+ // the following conversion to latin1 is o.k. because
+ // we can safely ignore all non-latin1 characters
+ switch (aStr[index].toLatin1()) {
+ case '"' : // start or end of quoted string
+ if (commentlevel == 0)
+ insidequote = !insidequote;
+ break;
+ case '(' : // start of comment
+ if (!insidequote)
+ commentlevel++;
+ break;
+ case ')' : // end of comment
+ if (!insidequote) {
+ if (commentlevel > 0)
+ commentlevel--;
+ else {
+ //kDebug() << "Error in address splitting: Unmatched ')'"
+ // << endl;
+ return list;
+ }
+ }
+ break;
+ case '\\' : // quoted character
+ index++; // ignore the quoted character
+ break;
+ case ',' :
+ if (!insidequote && (commentlevel == 0)) {
+ addr = aStr.mid(addrstart, index-addrstart);
+ if (!addr.isEmpty())
+ list += addr.simplified();
+ addrstart = index+1;
+ }
+ break;
+ }
+ }
+ // append the last address to the list
+ if (!insidequote && (commentlevel == 0)) {
+ addr = aStr.mid(addrstart, aStr.length()-addrstart);
+ if (!addr.isEmpty())
+ list += addr.simplified();
+ }
+ //else
+ // kDebug() << "Error in address splitting: "
+ // << "Unexpected end of address list"
+ // << endl;
+
+ return list;
+}
+
+#ifdef Q_WS_MAEMO_5
+// taken from QDesktopServices, which we cannot use here due to it being in QtGui
+inline static bool maemo5Launch(const QUrl &url)
+{
+ typedef bool (*Ptr_hildon_uri_open)(const char *, void *, void **);
+ static Ptr_hildon_uri_open hildon_uri_open = 0;
+
+ if (!hildon_uri_open) {
+ QLibrary lib(QLatin1String("libhildonmime"), 0, 0);
+ hildon_uri_open = (Ptr_hildon_uri_open)lib.resolve("hildon_uri_open");
+ }
+ if (hildon_uri_open)
+ return hildon_uri_open(url.toEncoded().constData(), 0, 0);
+ return false;
+}
+#endif
+
+void KToolInvocation::invokeMailer(const QString &_to, const QString &_cc, const QString &_bcc,
+ const QString &subject, const QString &body,
+ const QString & /*messageFile TODO*/, const QStringList &attachURLs,
+ const QByteArray& startup_id )
+{
+ if (!isMainThreadActive())
+ return;
+
+ KConfig config(QString::fromLatin1("emaildefaults"));
+ KConfigGroup defaultsGrp(&config, "Defaults");
+
+ QString group = defaultsGrp.readEntry("Profile","Default");
+
+ KConfigGroup profileGrp(&config, QString::fromLatin1("PROFILE_%1").arg(group) );
+ QString command = profileGrp.readPathEntry("EmailClient", QString());
+
+ QString to, cc, bcc;
+ if (command.isEmpty() || command == QLatin1String("kmail")
+ || command.endsWith(QLatin1String("/kmail")))
+ {
+ command = QLatin1String("kmail --composer -s %s -c %c -b %b --body %B --attach %A -- %t");
+ if ( !_to.isEmpty() )
+ {
+ KUrl url;
+ url.setProtocol(QLatin1String("mailto"));
+ url.setPath(_to);
+ to = QString::fromLatin1(url.toEncoded());
+ }
+ if ( !_cc.isEmpty() )
+ {
+ KUrl url;
+ url.setProtocol(QLatin1String("mailto"));
+ url.setPath(_cc);
+ cc = QString::fromLatin1(url.toEncoded());
+ }
+ if ( !_bcc.isEmpty() )
+ {
+ KUrl url;
+ url.setProtocol(QLatin1String("mailto"));
+ url.setPath(_bcc);
+ bcc = QString::fromLatin1(url.toEncoded());
+ }
+ } else {
+ to = _to;
+ cc = _cc;
+ bcc = _bcc;
+ if( !command.contains( QLatin1Char('%') ))
+ command += QLatin1String(" %u");
+ }
+
+ if (profileGrp.readEntry("TerminalClient", false))
+ {
+ KConfigGroup confGroup( KGlobal::config(), "General" );
+ QString preferredTerminal = confGroup.readPathEntry("TerminalApplication", QString::fromLatin1("konsole"));
+ command = preferredTerminal + QString::fromLatin1(" -e ") + command;
+ }
+
+ QStringList cmdTokens = KShell::splitArgs(command);
+ QString cmd = cmdTokens.takeFirst();
+
+ KUrl url;
+ //QStringList qry;
+ if (!to.isEmpty())
+ {
+ QStringList tos = splitEmailAddressList( to );
+ url.setPath( tos.first() );
+ tos.erase( tos.begin() );
+ for (QStringList::ConstIterator it = tos.constBegin(); it != tos.constEnd(); ++it)
+ url.addQueryItem(QString::fromLatin1("to"), *it);
+ //qry.append( "to=" + QLatin1String(KUrl::toPercentEncoding( *it ) ));
+ }
+ const QStringList ccs = splitEmailAddressList( cc );
+ for (QStringList::ConstIterator it = ccs.constBegin(); it != ccs.constEnd(); ++it)
+ url.addQueryItem(QString::fromLatin1("cc"), *it);
+ //qry.append( "cc=" + QLatin1String(KUrl::toPercentEncoding( *it ) ));
+ const QStringList bccs = splitEmailAddressList( bcc );
+ for (QStringList::ConstIterator it = bccs.constBegin(); it != bccs.constEnd(); ++it)
+ url.addQueryItem(QString::fromLatin1("bcc"), *it);
+ //qry.append( "bcc=" + QLatin1String(KUrl::toPercentEncoding( *it ) ));
+ for (QStringList::ConstIterator it = attachURLs.constBegin(); it != attachURLs.constEnd(); ++it)
+ url.addQueryItem(QString::fromLatin1("attach"), *it);
+ //qry.append( "attach=" + QLatin1String(KUrl::toPercentEncoding( *it ) ));
+ if (!subject.isEmpty())
+ url.addQueryItem(QString::fromLatin1("subject"), subject);
+ //qry.append( "subject=" + QLatin1String(KUrl::toPercentEncoding( subject ) ));
+ if (!body.isEmpty())
+ url.addQueryItem(QString::fromLatin1("body"), body);
+ //qry.append( "body=" + QLatin1String(KUrl::toPercentEncoding( body ) ));
+ //url.setQuery( qry.join( "&" ) );
+
+ if ( ! (to.isEmpty() && (!url.hasQuery())) )
+ url.setProtocol(QString::fromLatin1("mailto"));
+
+ QHash<QChar, QString> keyMap;
+ keyMap.insert(QLatin1Char('t'), to);
+ keyMap.insert(QLatin1Char('s'), subject);
+ keyMap.insert(QLatin1Char('c'), cc);
+ keyMap.insert(QLatin1Char('b'), bcc);
+ keyMap.insert(QLatin1Char('B'), body);
+ keyMap.insert(QLatin1Char('u'), url.url());
+
+ QString attachlist = attachURLs.join(QString::fromLatin1(","));
+ attachlist.prepend(QLatin1Char('\''));
+ attachlist.append(QLatin1Char('\''));
+ keyMap.insert(QLatin1Char('A'), attachlist);
+
+ for (QStringList::Iterator it = cmdTokens.begin(); it != cmdTokens.end(); )
+ {
+ if (*it == QLatin1String("%A"))
+ {
+ if (it == cmdTokens.begin()) // better safe than sorry ...
+ continue;
+ QStringList::ConstIterator urlit = attachURLs.begin();
+ QStringList::ConstIterator urlend = attachURLs.end();
+ if ( urlit != urlend )
+ {
+ QStringList::Iterator previt = it;
+ --previt;
+ *it = *urlit;
+ ++it;
+ while ( ++urlit != urlend )
+ {
+ cmdTokens.insert( it, *previt );
+ cmdTokens.insert( it, *urlit );
+ }
+ } else {
+ --it;
+ it = cmdTokens.erase( cmdTokens.erase( it ) );
+ }
+ } else {
+ *it = KMacroExpander::expandMacros(*it, keyMap);
+ ++it;
+ }
+ }
+
+ QString error;
+ // TODO this should check if cmd has a .desktop file, and use data from it, together
+ // with sending more ASN data
+ if (kdeinitExec(cmd, cmdTokens, &error, NULL, startup_id ))
+ {
+ KMessage::message(KMessage::Error,
+ i18n("Could not launch the mail client:\n\n%1", error),
+ i18n("Could not launch Mail Client"));
+ }
+}
+
+void KToolInvocation::invokeBrowser( const QString &url, const QByteArray& startup_id )
+{
+ if (!isMainThreadActive())
+ return;
+
+#ifdef Q_WS_MAEMO_5
+ if (maemo5Launch(url))
+ return;
+#endif
+ QStringList args;
+ args << url;
+ QString error;
+
+ // This method should launch a webbrowser, preferably without doing a mimetype
+ // check first, like KRun (i.e. kde-open) would do.
+
+ // In a KDE session, honour BrowserApplication if set, otherwise use preferred app for text/html if any,
+ // otherwise xdg-open, otherwise kde-open (which does a mimetype check first though).
+
+ // Outside KDE, call xdg-open if present, otherwise fallback to the above logic.
+
+ QString exe; // the binary we are going to launch.
+
+ const QString xdg_open = KStandardDirs::findExe(QString::fromLatin1("xdg-open"));
+ if (qgetenv("KDE_FULL_SESSION").isEmpty()) {
+ exe = xdg_open;
+ }
+
+ if (exe.isEmpty()) {
+ // We're in a KDE session (or there's no xdg-open installed)
+ KConfigGroup config(KGlobal::config(), "General");
+ const QString browserApp = config.readPathEntry("BrowserApplication", QString());
+ if (!browserApp.isEmpty()) {
+ exe = browserApp;
+ if (exe.startsWith(QLatin1Char('!'))) {
+ exe = exe.mid(1); // Literal command
+ QStringList cmdTokens = KShell::splitArgs(exe);
+ exe = cmdTokens.takeFirst();
+ args = cmdTokens + args;
+ } else {
+ // desktop file ID
+ KService::Ptr service = KService::serviceByStorageId(exe);
+ if (service) {
+ kDebug() << "Starting service" << service->entryPath();
+ if (startServiceByDesktopPath(service->entryPath(), args,
+ &error, 0, 0, startup_id)) {
+ KMessage::message(KMessage::Error,
+ // TODO: i18n("Could not launch %1:\n\n%2", exe, error),
+ i18n("Could not launch the browser:\n\n%1", error),
+ i18n("Could not launch Browser"));
+ }
+ return;
+ }
+ }
+ } else {
+ const KService::Ptr htmlApp = KMimeTypeTrader::self()->preferredService(QLatin1String("text/html"));
+ if (htmlApp) {
+ // WORKAROUND: For bugs 264562 and 265474:
+ // In order to correctly handle non-HTML urls we change the service
+ // desktop file name to "kfmclient.desktop" whenever the above query
+ // returns "kfmclient_html.desktop".Otherwise, the hard coded mime-type
+ // "text/html" mime-type parameter in the kfmclient_html will cause all
+ // URLs to be treated as if they are HTML page.
+ QString entryPath = htmlApp->entryPath();
+ if (entryPath.endsWith(QLatin1String("kfmclient_html.desktop"))) {
+ entryPath.remove(entryPath.length()-13, 5);
+ }
+ QString error;
+ int pid = 0;
+ int err = startServiceByDesktopPath(entryPath, url, &error, 0, &pid, startup_id);
+ if (err != 0) {
+ KMessage::message(KMessage::Error,
+ // TODO: i18n("Could not launch %1:\n\n%2", htmlApp->exec(), error),
+ i18n("Could not launch the browser:\n\n%1", error),
+ i18n("Could not launch Browser"));
+ } else { // success
+ return;
+ }
+ } else {
+ exe = xdg_open;
+ }
+ }
+ }
+
+ if (exe.isEmpty()) {
+ exe = QString::fromLatin1("kde-open"); // it's from kdebase-runtime, it has to be there.
+ }
+
+ kDebug(180) << "Using" << exe << "to open" << url;
+ if (kdeinitExec(exe, args, &error, NULL, startup_id ))
+ {
+ KMessage::message(KMessage::Error,
+ // TODO: i18n("Could not launch %1:\n\n%2", exe, error),
+ i18n("Could not launch the browser:\n\n%1", error),
+ i18n("Could not launch Browser"));
+ }
+}
+
+void KToolInvocation::invokeTerminal(const QString &command,
+ const QString &workdir,
+ const QByteArray &startup_id)
+{
+ if (!isMainThreadActive()) {
+ return;
+ }
+
+ KConfigGroup confGroup( KGlobal::config(), "General" );
+ QString exec = confGroup.readPathEntry("TerminalApplication", QString::fromLatin1("konsole"));
+
+ if (!command.isEmpty()) {
+ if (exec == QLatin1String("konsole")) {
+ exec += QString::fromLatin1(" --noclose");
+ } else if (exec == QLatin1String("xterm")) {
+ exec += QString::fromLatin1(" -hold");
+ }
+
+ exec += QString::fromLatin1(" -e ") + command;
+ }
+
+ QStringList cmdTokens = KShell::splitArgs(exec);
+ QString cmd = cmdTokens.takeFirst();
+
+ if (exec == QLatin1String("konsole") && !workdir.isEmpty()) {
+ cmdTokens << QString::fromLatin1("--workdir");
+ cmdTokens << workdir;
+ // For other terminals like xterm, we'll simply change the working
+ // directory before launching them, see below.
+ }
+
+ QString error;
+ if (self()->startServiceInternal("kdeinit_exec_with_workdir",
+ cmd, cmdTokens, &error, 0, NULL, startup_id, false, workdir)) {
+ KMessage::message(KMessage::Error,
+ i18n("Could not launch the terminal client:\n\n%1", error),
+ i18n("Could not launch Terminal Client"));
+ }
+}