diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-24 18:42:24 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-24 18:42:24 +0000 |
commit | f508189682b6fba62e08feeb1596f682bad5fff9 (patch) | |
tree | 28aeb0e6c19386c385c1ce5edf8a92c1bca15281 /src/common/global | |
download | piklab-f508189682b6fba62e08feeb1596f682bad5fff9.tar.gz piklab-f508189682b6fba62e08feeb1596f682bad5fff9.zip |
Added KDE3 version of PikLab
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/piklab@1095639 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/common/global')
-rw-r--r-- | src/common/global/Makefile.am | 8 | ||||
-rw-r--r-- | src/common/global/about.cpp | 94 | ||||
-rw-r--r-- | src/common/global/about.h | 43 | ||||
-rw-r--r-- | src/common/global/generic_config.cpp | 241 | ||||
-rw-r--r-- | src/common/global/generic_config.h | 84 | ||||
-rw-r--r-- | src/common/global/global.h | 61 | ||||
-rw-r--r-- | src/common/global/global.pro | 8 | ||||
-rw-r--r-- | src/common/global/log.cpp | 154 | ||||
-rw-r--r-- | src/common/global/log.h | 134 | ||||
-rw-r--r-- | src/common/global/pfile.cpp | 89 | ||||
-rw-r--r-- | src/common/global/pfile.h | 66 | ||||
-rw-r--r-- | src/common/global/process.cpp | 193 | ||||
-rw-r--r-- | src/common/global/process.h | 138 | ||||
-rw-r--r-- | src/common/global/progress_monitor.cpp | 84 | ||||
-rw-r--r-- | src/common/global/progress_monitor.h | 46 | ||||
-rw-r--r-- | src/common/global/purl.cpp | 428 | ||||
-rw-r--r-- | src/common/global/purl.h | 136 | ||||
-rw-r--r-- | src/common/global/svn_revision/Makefile.am | 5 | ||||
-rwxr-xr-x | src/common/global/svn_revision/svn_revision.sh | 20 | ||||
-rw-r--r-- | src/common/global/xml_data_file.cpp | 160 | ||||
-rw-r--r-- | src/common/global/xml_data_file.h | 45 |
21 files changed, 2237 insertions, 0 deletions
diff --git a/src/common/global/Makefile.am b/src/common/global/Makefile.am new file mode 100644 index 0000000..a94b45c --- /dev/null +++ b/src/common/global/Makefile.am @@ -0,0 +1,8 @@ +INCLUDES = -I$(top_srcdir)/src $(all_includes) +METASOURCES = AUTO +SUBDIRS = svn_revision + +noinst_LTLIBRARIES = libglobal.la +libglobal_la_SOURCES = about.cpp generic_config.cpp log.cpp pfile.cpp \ + process.cpp progress_monitor.cpp purl.cpp xml_data_file.cpp +libglobal_la_LDFLAGS = $(all_libraries) diff --git a/src/common/global/about.cpp b/src/common/global/about.cpp new file mode 100644 index 0000000..33bfae9 --- /dev/null +++ b/src/common/global/about.cpp @@ -0,0 +1,94 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <[email protected]> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "about.h" + +#if defined(Q_WS_WIN) +# define SVN_REVISION "windows" +#else +# include "svn_revision/svn_revision.h" +#endif + +//--------------------------------------------------------------------------- +const char * const Piklab::URLS[Nb_UrlTypes] = { + "http://piklab.sourceforge.net", + "http://piklab.sourceforge.net/wiki/index.php/FAQ", + "http://sourceforge.net/tracker/?func=add&group_id=138852&atid=743140" +}; + +//----------------------------------------------------------------------------- +Piklab::OptionList::OptionList(const KCmdLineOptions *options) + : _options(0) +{ + for (uint i=0; options[i].name; i++) append(options[i]); +} + +const KCmdLineOptions *Piklab::OptionList::ptr() const +{ + delete[] _options; + _options = new KCmdLineOptions[count()+1]; + for (uint i=0; i<uint(count()); i++) { + _options[i] = *at(i); + Q_ASSERT( _options[i].name ); + } + _options[count()].name = 0; + return _options; +} + +//----------------------------------------------------------------------------- +void Piklab::init(KAboutData *about, int argc, char **argv, bool gui, const KCmdLineOptions *options) +{ + Q_ASSERT(about); +#if defined(NO_KDE) +# if defined(Q_OS_WIN) + printf("%s \"win32\": version %s\n", about->appName(), VERSION); +# else + printf("%s \"qt-only\": version %s (rev. %s)\n", about->appName(), VERSION, SVN_REVISION); +# endif + Q_UNUSED(gui); + Q_ASSERT( !gui ); +#else + printf("%s: version %s (rev. %s)\n", about->appName(), VERSION, SVN_REVISION); + if ( !gui ) KApplication::disableAutoDcopRegistration(); +#endif + KCmdLineArgs::init(argc, argv, about); + KCmdLineArgs::addCmdLineOptions(options); +#if defined(NO_KDE) +# if QT_VERSION<0x040000 + (void)new QApplication(argc, argv, QApplication::Tty); +# else + (void)new QCoreApplication(argc, argv); +# endif +#else + (void)new KApplication(gui, gui); +#endif +} + +//--------------------------------------------------------------------------- +Piklab::AboutData::AboutData(const char *executable, const char *name, + const char *description) + : KAboutData(executable, name, VERSION, description, KAboutData::License_GPL, + "(c) 2005-2007 Nicolas Hadacek\n(c) 2002-2005 Alain Gibaud\n(c) 2003-2004 Stephen Landamore\n(c) 2005 Lorenz Möenlechner and Matthias Kranz\n(c) 2001-2005 Craig Franklin", + 0, URLS[Homepage], URLS[BugReport]) +{ + addAuthor("Nicolas Hadacek", I18N_NOOP("Author and maintainer."), "[email protected]"); + addAuthor("Alain Gibaud", I18N_NOOP("Original author of PiKdev."), "[email protected]"); + addAuthor("Stephen Landamore", I18N_NOOP("LPLAB author (original microchip programmer support)."), "[email protected]"); + addAuthor("Craig Franklin", I18N_NOOP("Author of gputils"), "[email protected]"); + addAuthor("Sébastien Laoût", I18N_NOOP("Author of likeback"), "[email protected]"); + + addCredit("Brian C. Lane", I18N_NOOP("Original code for direct programming."), 0); + addCredit("Manwlis \"Manos\" Giannos", I18N_NOOP("Direct programming for PIC18F devices."), "[email protected]"); + addCredit("Sean A. Walberg", I18N_NOOP("Direct programming for 16F676/630."), "[email protected]"); + addCredit("Mirko Panciri", I18N_NOOP("Support for direct programmers with bidirectionnal buffers."), "[email protected]"); + addCredit("Keith Baker", I18N_NOOP("Direct programming for 16F73/74/76/77."), "[email protected]" ); + addCredit("Lorenz Möenlechner and Matthias Kranz", I18N_NOOP("USB support for ICD2 programmer."), "[email protected]"); + addCredit("Xiaofan Chen", I18N_NOOP("Test of PICkit2 and ICD2 programmer."), "[email protected]"); + addCredit("Homer Reid", I18N_NOOP("Direct programming for dsPICs is inspired from his program \"dspicprg\"."), "[email protected]"); + addCredit("Frank Damgaard", I18N_NOOP("Direct programming for 24C EEPROM is inspired from his program \"prog84\"."), "[email protected]"); +} diff --git a/src/common/global/about.h b/src/common/global/about.h new file mode 100644 index 0000000..e20ee46 --- /dev/null +++ b/src/common/global/about.h @@ -0,0 +1,43 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <[email protected]> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef ABOUT_H +#define ABOUT_H + +#include "global.h" + +namespace Piklab +{ +//----------------------------------------------------------------------------- +class OptionList : public QValueList<KCmdLineOptions> +{ +public: + OptionList() : _options(0) {} + OptionList(const KCmdLineOptions *options); + virtual ~OptionList() { delete[] _options; } + const KCmdLineOptions *ptr() const; + +private: + mutable KCmdLineOptions *_options; +}; + +//--------------------------------------------------------------------------- +enum UrlType { Homepage = 0, Support, BugReport, Nb_UrlTypes }; +extern const char * const URLS[Nb_UrlTypes]; +extern void init(KAboutData *about, int argc, char **argv, bool gui, const KCmdLineOptions *options); + +//--------------------------------------------------------------------------- +class AboutData : public KAboutData +{ +public: + AboutData(const char *executable, const char *name, const char *description); +}; + +} // namespace + +#endif diff --git a/src/common/global/generic_config.cpp b/src/common/global/generic_config.cpp new file mode 100644 index 0000000..841233b --- /dev/null +++ b/src/common/global/generic_config.cpp @@ -0,0 +1,241 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <[email protected]> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "generic_config.h" + +#include "global.h" + +#if defined(NO_KDE) +# include <qsettings.h> +class GenericConfigPrivate +{ +public: + GenericConfigPrivate(const QString &group) { _settings.beginGroup("/piklab/" + group); } + QSettings _settings; +}; +#else +# include <kapplication.h> +# include <kconfig.h> +class GenericConfigPrivate +{ +public: + GenericConfigPrivate(const QString &group) : _group(group) {} + ~GenericConfigPrivate() { kapp->config()->sync(); } + KConfig &config() { + KConfig *conf = kapp->config(); + conf->setGroup(_group); + return *conf; + } + +private: + QString _group; +}; +#endif + +GenericConfig::GenericConfig(const QString &group) + : _group(group) +{ + _d = new GenericConfigPrivate(group); +} + +GenericConfig::~GenericConfig() +{ + delete _d; +} + +void GenericConfig::rollback() +{ +#if defined(NO_KDE) + qWarning("Config rollback not supported"); +#else + _d->config().rollback(); +#endif +} + +QString GenericConfig::readEntry(const QString &key, const QString &def) const +{ +#if defined(NO_KDE) +# if QT_VERSION<0x040000 + return _d->_settings.readEntry(key, def); +# else + return _d->_settings.value(key, def).toString(); +# endif +#else + return _d->config().readEntry(key, def); +#endif +} +void GenericConfig::writeEntry(const QString &key, const QString &value) +{ +#if defined(NO_KDE) +# if QT_VERSION<0x040000 + _d->_settings.writeEntry(key, value); +# else + _d->_settings.setValue(key, value); +# endif +#else + _d->config().writeEntry(key, value); +#endif +} + +QStringList GenericConfig::readListEntry(const QString &key, const QStringList &defaultValues) const +{ +#if defined(NO_KDE) +# if QT_VERSION<0x040000 + if ( _d->_settings.readEntry(key).isNull() ) return defaultValues; + return _d->_settings.readListEntry(key); +# else + return _d->_settings.value(key, defaultValues).toStringList(); +# endif +#else + if ( !_d->config().hasKey(key) ) return defaultValues; + return _d->config().readListEntry(key); +#endif +} +void GenericConfig::writeEntry(const QString &key, const QStringList &value) +{ +#if defined(NO_KDE) +# if QT_VERSION<0x040000 + _d->_settings.writeEntry(key, value); +# else + _d->_settings.setValue(key, value); +# endif +#else + _d->config().writeEntry(key, value); +#endif +} + +QValueList<int> GenericConfig::readIntListEntry(const QString &key) const +{ +#if defined(NO_KDE) + QValueList<int> ilist; + QStringList list = readListEntry(key, QStringList()); + QStringList::const_iterator it; + for (it=list.begin(); it!=list.end(); ++it) { + bool ok; + int v = (*it).toInt(&ok); + if ( !ok ) return ilist; + ilist.append(v); + } + return ilist; +#else + return _d->config().readIntListEntry(key); +#endif +} +void GenericConfig::writeEntry(const QString &key, const QValueList<int> &value) +{ +#if defined(NO_KDE) + QStringList list; + QValueList<int>::const_iterator it; + for (it=value.begin(); it!=value.end(); ++it) list.append(QString::number(*it)); + writeEntry(key, list); +#else + _d->config().writeEntry(key, value); +#endif +} + +QSize GenericConfig::readSizeEntry(const QString &key, const QSize *def) const +{ +#if defined(NO_KDE) + QValueList<int> list = readIntListEntry(key); + if ( list.count()!=2 ) return *def; + return QSize(list[0], list[1]); +#else + return _d->config().readSizeEntry(key, def); +#endif +} +void GenericConfig::writeEntry(const QString &key, const QSize &value) +{ +#if defined(NO_KDE) + QValueList<int> ilist; + ilist.append(value.width()); + ilist.append(value.height()); + writeEntry(key, ilist); +#else + _d->config().writeEntry(key, value); +#endif +} + +bool GenericConfig::readBoolEntry(const QString &key, bool def) const +{ +#if defined(NO_KDE) +# if QT_VERSION<0x040000 + return _d->_settings.readBoolEntry(key, def); +# else + return _d->_settings.value(key, def).toBool(); +# endif +#else + return _d->config().readBoolEntry(key, def); +#endif +} +void GenericConfig::writeEntry(const QString &key, bool value) +{ +#if defined(NO_KDE) +# if QT_VERSION<0x040000 + _d->_settings.writeEntry(key, value); +# else + _d->_settings.setValue(key, value); +# endif +#else + _d->config().writeEntry(key, value); +#endif +} + +int GenericConfig::readIntEntry(const QString &key, int def) const +{ +#if defined(NO_KDE) +# if QT_VERSION<0x040000 + return _d->_settings.readNumEntry(key, def); +# else + return _d->_settings.value(key, def).toInt(); +# endif +#else + return _d->config().readNumEntry(key, def); +#endif +} +void GenericConfig::writeEntry(const QString &key, int value) +{ +#if defined(NO_KDE) +# if QT_VERSION<0x040000 + _d->_settings.writeEntry(key, value); +# else + _d->_settings.setValue(key, value); +# endif +#else + _d->config().writeEntry(key, value); +#endif +} + +void GenericConfig::deleteGroup(const QString &group) +{ +#if defined(NO_KDE) + Q_UNUSED(group); + // #### cannot do that... +#else + kapp->config()->deleteGroup(group); +#endif +} + +QVariant GenericConfig::readVariantEntry(const QString &key, const QVariant &defValue) const +{ + switch (defValue.type()) { + case QVariant::Bool: return QVariant(readBoolEntry(key, defValue.toBool()), 0); + case QVariant::UInt: return readUIntEntry(key, defValue.toUInt()); + default: break; + } + Q_ASSERT(false); + return QVariant(); +} + +void GenericConfig::writeEntry(const QString &key, const QVariant &v) +{ + switch (v.type()) { + case QVariant::Bool: writeEntry(key, v.toBool()); break; + case QVariant::UInt: writeEntry(key, v.toUInt()); break; + default: Q_ASSERT(false); break; + } +} diff --git a/src/common/global/generic_config.h b/src/common/global/generic_config.h new file mode 100644 index 0000000..70dfeaa --- /dev/null +++ b/src/common/global/generic_config.h @@ -0,0 +1,84 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <[email protected]> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef GENERIC_CONFIG_H +#define GENERIC_CONFIG_H + +#include <qvariant.h> +#include <qsize.h> + +#include "global.h" +#include "common/common/misc.h" + +class GenericConfigPrivate; + +class GenericConfig +{ +public: + GenericConfig(const QString &group); + ~GenericConfig(); + QString group() const { return _group; } + void rollback(); + + QString readEntry(const QString &key, const QString &def = QString::null) const; + void writeEntry(const QString &key, const QString &value); + void writeEntry(const QString &key, const QCString &value) { writeEntry(key, QString(value)); } + void writeEntry(const QString &key, const char *value) { writeEntry(key, QString(value)); } + QStringList readListEntry(const QString &key, const QStringList &defaultValues) const; + void writeEntry(const QString &key, const QStringList &value); + QValueList<int> readIntListEntry(const QString &key) const; + void writeEntry(const QString &key, const QValueList<int> &value); + QSize readSizeEntry(const QString &key, const QSize *def = 0) const; + void writeEntry(const QString &key, const QSize &value); + bool readBoolEntry(const QString &key, bool def) const; + void writeEntry(const QString &key, bool value); + int readIntEntry(const QString &key, int def = 0) const; + void writeEntry(const QString &key, int value); + uint readUIntEntry(const QString &key, uint def = 0) const { return qMax(0, readIntEntry(key, def)); } + void writeEntry(const QString &key, uint value) { writeEntry(key, int(value)); } + template <typename Enum> + Enum readEnumEntry(const QString &key, Enum def = Enum::Nb_Types) const { return Enum::fromKey(readEntry(key, def.key())); } + template <typename Enum> + void writeEnumEntry(const QString &key, Enum v) { writeEntry(key, v.key()); } + QVariant readVariantEntry(const QString &key, const QVariant &defValue) const; + void writeEntry(const QString &key, const QVariant &value); + + static void deleteGroup(const QString &group); + + struct ItemData { + const char *key, *label; + QVariant defValue; + }; + template <typename Type> + QVariant readVariantEntry(Type type) const { return readVariantEntry(type.data().key, type.data().defValue); } + template <typename Type> + void writeVariantEntry(Type type, const QVariant &value) { + Q_ASSERT( value.type()==type.data().defValue.type() ); + writeEntry(type.data().key, value); + } + +private: + QString _group; + GenericConfigPrivate *_d; +}; + +#define BEGIN_DECLARE_CONFIG(Type) \ + BEGIN_DECLARE_ENUM(Type) + +#define END_DECLARE_CONFIG(Type, group) \ + END_DECLARE_ENUM(Type, GenericConfig::ItemData) \ + inline QVariant readConfigEntry(Type type) { \ + GenericConfig config(group); \ + return config.readVariantEntry<Type>(type); \ + } \ + inline void writeConfigEntry(Type type, const QVariant &v) { \ + GenericConfig config(group); \ + config.writeVariantEntry<Type>(type, v); \ + } + +#endif diff --git a/src/common/global/global.h b/src/common/global/global.h new file mode 100644 index 0000000..72dab0e --- /dev/null +++ b/src/common/global/global.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <[email protected]> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef GLOBAL_H +#define GLOBAL_H + +#include <qglobal.h> + +#if QT_VERSION<0x040000 +# include <qapplication.h> +# include <qvaluelist.h> +# include <qvaluevector.h> +# include <qmemarray.h> +# include "common/common/qflags.h" +# define qMax QMAX +# define qMin QMIN +# include <qurl.h> +# define Q3Url QUrl +# include <qguardedptr.h> +#else +# include <qcoreapplication.h> +# include <Qt3Support/Q3ValueList> +# define QValueList Q3ValueList +# include <Qt3Support/Q3ValueVector> +# define QValueVector Q3ValueVector +# include <Qt3Support/Q3MemArray> +# define QMemArray Q3MemArray +# define qHeapSort qSort +# include <Qt3Support/Q3Url> +# include <Qt3Support/Q3MimeSourceFactory> +# define QMimeSourceFactory Q3MimeSourceFactory +# include <qpointer.h> +# define QGuardedPtr QPointer +#endif + +#if defined(NO_KDE) +# include "qt_config.h" +# include "common/nokde/nokde_kurl.h" +# include "common/nokde/nokde_klocale.h" +# include "common/nokde/nokde_kaboutdata.h" +# include "common/nokde/nokde_kcmdlineargs.h" +#else +# include "config.h" +# include <kapplication.h> +# include <klocale.h> +# include <kaboutdata.h> +# include <kcmdlineargs.h> +# include <ktempfile.h> +# include <kconfigbackend.h> +#endif + +#if defined(Q_OS_WIN) +# include <windows.h> +#endif + +#endif diff --git a/src/common/global/global.pro b/src/common/global/global.pro new file mode 100644 index 0000000..3756177 --- /dev/null +++ b/src/common/global/global.pro @@ -0,0 +1,8 @@ +STOPDIR = ../../.. +include($${STOPDIR}/lib.pro) + +TARGET = global +HEADERS += about.h generic_config.h log.h process.h purl.h pfile.h progress_monitor.h +SOURCES += about.cpp generic_config.cpp log.cpp process.cpp purl.cpp pfile.cpp progress_monitor.cpp + +unix:system(cd svn_revision && sh svn_revision.sh) diff --git a/src/common/global/log.cpp b/src/common/global/log.cpp new file mode 100644 index 0000000..cf85303 --- /dev/null +++ b/src/common/global/log.cpp @@ -0,0 +1,154 @@ +/*************************************************************************** + * Copyright (C) 2005 Nicolas Hadacek <[email protected]> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "log.h" + +#include <qeventloop.h> +#include "global.h" + +//----------------------------------------------------------------------------- +const Log::LineType::Data Log::LineType::DATA[Nb_Types] = { + { 0, 0, "red", false }, // error + { 0, 0, "red", false }, // soft error + { 0, 0, "orange", false }, // warning + { 0, 0, "black", false }, // normal + { 0, 0, "blue", false }, // info + { 0, 0, "black", true }, // command +}; + +const Log::DebugLevel::Data Log::DebugLevel::DATA[Nb_Types] = { + { "quiet", I18N_NOOP("No debug message"), 0, false }, + { "debug", I18N_NOOP("Normal debug messages"), "darkGreen", false }, + { "extra-debug", I18N_NOOP("Extra debug messages"), "darkGreen", false }, + { "max-debug", I18N_NOOP("Max debug messages"), "darkGreen", false }, + { "lowlevel-debug", I18N_NOOP("All debug messages"), "darkGreen", false } +}; + +//----------------------------------------------------------------------------- +Log::View::View() +{ + setDebugLevel(DebugLevel::Normal); + FOR_EACH(LineType, type) _modes[type.type()] = Show; +} + +void Log::View::setDebugLevel(DebugLevel level) +{ + _debugLevel = level; +} + +void Log::View::log(LineType type, const QString &text, Action action) +{ + if ( _modes[type.type()]==Show ) doLog(type, text, action); +} + +void Log::View::log(DebugLevel level, const QString &text, Action action) +{ + Q_ASSERT( level!=DebugLevel::Quiet ); + updateDebugLevel(); + if ( level<=_debugLevel ) doLog(level, text, action); +} + +void Log::View::logUserAbort() +{ + doLog(LineType::SoftError, i18n("Operation aborted by user."), Immediate); +} + +//----------------------------------------------------------------------------- +void Log::StringView::sorry(const QString &message, const QString &details) +{ + if ( details.isEmpty() ) _s += message; + else _s += message + ": " + details; +} + +bool Log::StringView::askContinue(const QString &message) +{ + log(LineType::Warning, message, Immediate); + return false; // always fail +} + +//----------------------------------------------------------------------------- +Log::Base::Base(Base *parent) + : _parent(0), _data(0) +{ + setParent(parent); +} + +void Log::Base::setParent(Base *parent) +{ + delete _data; + _parent = parent; + _data = (parent ? 0 : new LogData); +} + +Log::Base::~Base() +{ + delete _data; +} + +void Log::Base::setView(View *view) +{ + Q_ASSERT(_data); + _data->view = view; +} + +void Log::Base::logUserAbort() +{ + if ( view() ) view()->logUserAbort(); +} + +void Log::Base::log(LineType type, const QString &message, Action action) +{ + if ( type==LineType::Error ) setError(message); + if ( view() ) view()->log(type, message, action); +} + +void Log::Base::log(DebugLevel level, const QString &message, Action action) +{ + if ( view() ) view()->log(level, message, action); +} + +void Log::Base::appendToLastLine(const QString &text) +{ + if ( view() ) view()->appendToLastLine(text); +} + +void Log::Base::sorry(const QString &message, const QString &details) +{ + if ( view() ) view()->sorry(message, details); +} + +bool Log::Base::askContinue(const QString &message) +{ + if ( view()==0 ) return false; + return view()->askContinue(message); +} + +void Log::Base::clear() +{ + resetError(); + if ( view() ) view()->clear(); +} + +//----------------------------------------------------------------------------- +QString Log::KeyList::text() const +{ + QString text; + if ( !_title.isEmpty() ) text += _title + "\n"; + uint nb = 0; + for (uint i=0; i<uint(_keys.count()); i++) nb = qMax(nb, uint(_keys[i].length())); + for (uint i=0; i<uint(_keys.count()); i++) text += " " + _keys[i].leftJustify(nb+2) + _labels[i] + "\n"; + return text; +} + +void Log::KeyList::display(Generic &log) const +{ + if ( !_title.isEmpty() ) log.log(Log::LineType::Normal, _title); + uint nb = 0; + for (uint i=0; i<uint(_keys.count()); i++) nb = qMax(nb, uint(_keys[i].length())); + for (uint i=0; i<uint(_keys.count()); i++) log.log(Log::LineType::Normal, " " + _keys[i].leftJustify(nb+2) + _labels[i]); +} diff --git a/src/common/global/log.h b/src/common/global/log.h new file mode 100644 index 0000000..7383d57 --- /dev/null +++ b/src/common/global/log.h @@ -0,0 +1,134 @@ +/*************************************************************************** + * Copyright (C) 2005 Nicolas Hadacek <[email protected]> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef LOG_H +#define LOG_H + +#include <qstringlist.h> + +#include "common/common/key_enum.h" + +namespace Log +{ + // immediat visibily by calling processEvent... BEWARE of side effects + enum Action { Immediate, Delayed }; + enum ShowMode { DontShow, Show }; + struct LogData { + const char *key, *label, *color; + bool bold; + }; + BEGIN_DECLARE_ENUM(DebugLevel) + Quiet = 0, Normal, Extra, Max, LowLevel + END_DECLARE_ENUM(DebugLevel, LogData) + BEGIN_DECLARE_ENUM(LineType) + Error = 0, SoftError, Warning, Normal, Information, Command + END_DECLARE_ENUM(LineType, LogData) + +//----------------------------------------------------------------------------- +class Generic +{ +public: + virtual ~Generic() {} + virtual void log(LineType type, const QString &text, Action action = Immediate) = 0; + virtual void log(DebugLevel level, const QString &text, Action action = Immediate) = 0; + virtual void appendToLastLine(const QString &text) = 0; + virtual void sorry(const QString &message, const QString &details) = 0; + virtual bool askContinue(const QString &message) = 0; + virtual void clear() = 0; + virtual void logUserAbort() = 0; +}; + +class View : public Generic +{ +public: + View(); + ShowMode showMode(LineType type) const { return _modes[type.type()]; } + void setShowMode(LineType type, ShowMode mode) { _modes[type.type()] = mode; } + void setDebugLevel(DebugLevel level); + virtual void log(LineType type, const QString &text, Action action = Immediate); + virtual void log(DebugLevel level, const QString &text, Action action = Immediate); + virtual void logUserAbort(); + +protected: + ShowMode _modes[LineType::Nb_Types]; + DebugLevel _debugLevel; + + virtual void updateDebugLevel() {} + virtual void doLog(LineType type, const QString &text, Action action) = 0; + virtual void doLog(DebugLevel level, const QString &text, Action action) = 0; +}; + +//----------------------------------------------------------------------------- +class StringView : public View +{ +public: + StringView() {} + QString string() const { return _s; } + virtual void appendToLastLine(const QString &text) { _s += text; } + virtual void clear() { _s = QString::null; } + virtual void sorry(const QString &message, const QString &details); + virtual bool askContinue(const QString &message); + +private: + QString _s; + + virtual void doLog(LineType, const QString &text, Action) { _s += text + "\n"; } + virtual void doLog(DebugLevel, const QString &text, Action) { _s += text + "\n"; } +}; + +//----------------------------------------------------------------------------- +class Base : public Generic +{ +public: + Base(Base *parent = 0); + virtual ~Base(); + void setParent(Base *parent); + void setView(View *view); + View *view() { return logData()->view; } + + virtual void log(LineType type, const QString &message, Action action = Immediate); + virtual void log(DebugLevel level, const QString &message, Action action = Immediate); + virtual void appendToLastLine(const QString &text); + void setError(const QString &error) { logData()->error = error; } + virtual bool hasError() const { return !logData()->error.isNull(); } + virtual QString error() const { return logData()->error; } + virtual void resetError() { logData()->error = QString::null; } + virtual void sorry(const QString &message, const QString &details = QString::null); + virtual bool askContinue(const QString &message); + virtual void clear(); + void logUserAbort(); + +protected: + Base *_parent; + class LogData { + public: + LogData() : view(0) {} + QString error; + View *view; + }; + LogData *_data; + LogData *logData() { return _parent ? _parent->logData() : _data; } + const LogData *logData() const { return _parent ? _parent->logData() : _data; } +}; + +class KeyList { +public: + KeyList(const QString &title = QString::null) : _title(title) {} + void setTitle(const QString &title) { _title = title; } + void append(const QString &key, const QString &label) { _keys += key; _labels += label; } + QString text() const; + void display(Generic &log) const; + +private: + QString _title; + QStringList _keys, _labels; +}; + +} // namespace + +#endif diff --git a/src/common/global/pfile.cpp b/src/common/global/pfile.cpp new file mode 100644 index 0000000..71cee16 --- /dev/null +++ b/src/common/global/pfile.cpp @@ -0,0 +1,89 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <[email protected]> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "pfile.h" + +#include <qfile.h> + +//----------------------------------------------------------------------------- +PURL::FileBase::FileBase(Log::Generic &log, const QString &extension) + : _tmp(0), _file(0), _stream(0), _extension(extension), _log(log) +{} + +PURL::FileBase::~FileBase() +{ + delete _stream; + delete _file; + delete _tmp; +} + +const QFile *PURL::FileBase::qfile() const +{ + return (_tmp ? _tmp->file() : _file); +} + +QFile *PURL::FileBase::qfile() +{ + return (_tmp ? _tmp->file() : _file); +} + +void PURL::FileBase::flush() +{ + if ( qfile() ) qfile()->flush(); +} + +QTextStream &PURL::FileBase::stream() +{ + if ( _stream==0 ) _stream = new QTextStream(qfile()); + return *_stream; +} + +bool PURL::FileBase::hasError() const +{ + if ( qfile()==0 || !_error.isEmpty() ) return true; + return ( uint(qfile()->status())!=IO_Ok ); +} + +QString PURL::FileBase::errorString() const +{ + if ( _error.isEmpty() ) { + if ( qfile()==0 ) return i18n("File not open."); + else return qfile()->errorString(); + } + return _error; +} + +QStringList PURL::FileBase::readLines() +{ + QStringList lines; + for (;;) { + QString s = stream().readLine(); + if ( s.isNull() ) break; + lines.append(s); + } + return lines; +} + +QByteArray PURL::FileBase::readAll() +{ + if ( qfile() ) return qfile()->readAll(); + return QByteArray(); +} + +//----------------------------------------------------------------------------- +PURL::File::File(const Url &url, Log::Generic &log) + : FileBase(log, QString::null), _url(url) +{ + _file = new QFile; +} + +void PURL::File::setUrl(const Url &url) +{ + close(); + _url = url; +} diff --git a/src/common/global/pfile.h b/src/common/global/pfile.h new file mode 100644 index 0000000..d0955e7 --- /dev/null +++ b/src/common/global/pfile.h @@ -0,0 +1,66 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <[email protected]> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef PFILE_H +#define PFILE_H + +#include <qtextstream.h> +#include "purl.h" + +namespace PURL +{ +//----------------------------------------------------------------------------- +class FileBase +{ +public: + FileBase(Log::Generic &log, const QString &extension); + ~FileBase(); + QFile *qfile(); + const QFile *qfile() const; + QTextStream &stream(); + QString readText() { return stream().read(); } + QString readLine() { return stream().readLine(); } + QStringList readLines(); + QByteArray readAll(); + void appendText(const QString &text) { stream() << text; } + void flush(); + bool hasError() const; + QString errorString() const; + +protected: + KTempFile *_tmp; + QFile *_file; + QTextStream *_stream; + QString _error, _extension; + Log::Generic &_log; + +private: // disable copy constructor and operator = + FileBase(const FileBase &base); + FileBase &operator =(const FileBase &base); +}; + +//----------------------------------------------------------------------------- +class File : public FileBase +{ +public: + File(const Url &url, Log::Generic &log); + ~File() { close(); } + void setUrl(const Url &url); // close file too + Url url() const { return _url; } + bool openForWrite(); + bool openForRead(); + bool close(); + bool remove(); + +private: + Url _url; +}; + +} // namespace + +#endif diff --git a/src/common/global/process.cpp b/src/common/global/process.cpp new file mode 100644 index 0000000..7659eea --- /dev/null +++ b/src/common/global/process.cpp @@ -0,0 +1,193 @@ +/*************************************************************************** + * Copyright (C) 2005 Nicolas Hadacek <[email protected]> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "process.h" + +#include <qdatetime.h> + +#if defined(NO_KDE) +# include "common/nokde/nokde_kprocess.h" +#else +# include <kprocess.h> +#endif +#include "purl.h" +#include "common/common/synchronous.h" + +//---------------------------------------------------------------------------- +Process::State Process::runSynchronously(Base &process, RunActions actions, uint timeout) +{ + Synchronous sync(timeout); + QObject::connect(&process, SIGNAL(done(int)), &sync, SLOT(done())); + QObject::connect(&process, SIGNAL(requestSynchronousStop()), &sync, SLOT(done())); + if ( (actions & Start) && !process.start(0) ) return process.state(); + Q_ASSERT( process.isRunning() ); + if ( !sync.enterLoop() ) process.timeoutSlot(); + return process.state(); +} + +//---------------------------------------------------------------------------- +Process::Base::Base(QObject *parent, const char *name) + : QObject(parent, name), _state(Stopped) +{ + _process = new KProcess(this); + connect(_process, SIGNAL(processExited(KProcess *)), SLOT(exited())); + connect(_process, SIGNAL(receivedStdout(KProcess *, char *, int)), SLOT(receivedStdout(KProcess*, char *, int))); + connect(_process, SIGNAL(receivedStderr(KProcess *, char *, int)), SLOT(receivedStderr(KProcess*, char *, int))); + _timer = new QTimer(this); + connect(_timer, SIGNAL(timeout()), SLOT(timeoutSlot())); +} + +Process::Base::~Base() +{ + _process->kill(); +} + +QStringList Process::Base::arguments() const +{ + if ( _process==0 ) return QStringList(); +#if defined(NO_KDE) + return _process->args(); +#else + QStringList list; + const QValueList<QCString> &args = _process->args(); + for (uint i=0; i<args.count(); i++) list.append(args[i]); + return list; +#endif +} + +void Process::Base::setup(const QString &executable, const QStringList &options, bool withWine) +{ + _state = Stopped; + _timer->stop(); + _process->clearArguments(); + if (withWine) { + _process->setEnvironment("WINEDEBUG", "-all"); + *_process << QString("wine"); + } + *_process << executable; + *_process << options; +} + +bool Process::Base::start(uint timeout) +{ + _state = Stopped; + _timer->stop(); + _stdout = QString::null; + _stderr = QString::null; +#if defined(NO_KDE) + if ( !_process->start() ) { +#else + if ( !_process->start(KProcess::NotifyOnExit, KProcess::All) ) { +#endif + _state = StartFailed; + return false; + } + _state = Running; + if (timeout) _timer->start(timeout); + return true; +} + +void Process::Base::timeoutSlot() +{ + _state = Timedout; + _process->kill(); + emit timeout(); +} + +int Process::Base::exitCode() const +{ + return _process->exitStatus(); +} + +void Process::Base::exited() +{ + _state = Exited; + _timer->stop(); + emit done(exitCode()); +} + +bool Process::Base::isRunning() const +{ + return _process->isRunning(); +} + +void Process::Base::writeToStdin(const QString &s) +{ + QCString cs = s.latin1(); + _process->writeStdin(cs.data(), cs.length()); +} + +bool Process::Base::signal(int n) +{ + return _process->kill(n); +} + +void Process::Base::setWorkingDirectory(const PURL::Directory &dir) +{ + _process->setWorkingDirectory(dir.path()); +} + +void Process::Base::setUseShell(bool useShell) +{ + _process->setUseShell(useShell); +} + +bool Process::Base::isFilteredLine(const QString &line) +{ + // "wine" returns all those "libGL warning" that mess up the output... + return line.startsWith("libGL warning"); +} + +//---------------------------------------------------------------------------- +void Process::StringOutput::receivedStdout(KProcess*, char *data, int len) +{ + _stdout += QString::fromLatin1(data, len); + emit stdoutDataReceived(); +} + +void Process::StringOutput::receivedStderr(KProcess*, char *data, int len) +{ + _stderr += QString::fromLatin1(data, len); + emit stderrDataReceived(); +} + +//---------------------------------------------------------------------------- +void Process::LineBase::receivedStdout(KProcess*, char *data, int len) +{ + for (uint i=0; i<uint(len); i++) { + if ( data[i]=='\r' ) continue; + if ( data[i]=='\n' ) { + if ( !isFilteredLine(_stdout) ) addStdoutLine(_stdout); + _stdout = QString::null; + } else _stdout += QString::fromLatin1(data + i, 1); + } + if ( !_process->isRunning() && !isFilteredLine(_stdout) ) addStdoutLine(_stdout); + emit stdoutDataReceived(); +} + +void Process::LineBase::receivedStderr(KProcess*, char *data, int len) +{ + for (uint i=0; i<uint(len); i++) { + if ( data[i]=='\r' ) continue; + if ( data[i]=='\n' ) { + if ( !isFilteredLine(_stderr) ) addStderrLine(_stderr); + _stderr = QString::null; + } else _stderr += QString::fromLatin1(data + i, 1); + } + if ( !_process->isRunning() && !isFilteredLine(_stderr) ) addStderrLine(_stderr); + emit stderrDataReceived(); +} + +//---------------------------------------------------------------------------- +bool Process::LineOutput::start(uint timeout) +{ + _stdoutLines.clear(); + _stderrLines.clear(); + return Process::LineBase::start(timeout); +} + diff --git a/src/common/global/process.h b/src/common/global/process.h new file mode 100644 index 0000000..9c67149 --- /dev/null +++ b/src/common/global/process.h @@ -0,0 +1,138 @@ +/*************************************************************************** + * Copyright (C) 2005 Nicolas Hadacek <[email protected]> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef PROCESS_H +#define PROCESS_H + +#include <signal.h> +#include <qstringlist.h> +#include <qobject.h> +#include <qtimer.h> +class KProcess; + +#include "global.h" +namespace PURL { class Directory; } + +namespace Process +{ +enum State { Stopped, StartFailed, Running, Exited, Timedout }; +class Base; +enum RunAction { NoRunAction = 0, Start = 1 }; +Q_DECLARE_FLAGS(RunActions, RunAction) +Q_DECLARE_OPERATORS_FOR_FLAGS(RunActions) +extern State runSynchronously(Base &process, RunActions actions, uint timeout); // in ms (0 == no timeout) + +//---------------------------------------------------------------------------- +class Base : public QObject +{ +Q_OBJECT +public: + Base(QObject *parent, const char *name); + virtual ~Base(); + void setup(const QString &executable, const QStringList &options, bool withWine); + QStringList arguments() const; + void setWorkingDirectory(const PURL::Directory &dir); + void setUseShell(bool useShell); + virtual bool start(uint timeout); // in ms (0 == no timeout) + QString prettyCommand() const { return arguments().join(" "); } + void writeToStdin(const QString &s); + bool signal(int n); + bool isRunning() const; + State state() const { return _state; } + int exitCode() const; + +signals: + void requestSynchronousStop(); + void done(int code); + void timeout(); + void stdoutDataReceived(); + void stderrDataReceived(); + +protected slots: + void exited(); + void timeoutSlot(); + virtual void receivedStdout(KProcess*, char *buffer, int len) = 0; + virtual void receivedStderr(KProcess*, char *buffer, int len) = 0; + + friend State runSynchronously(Base &, RunActions, uint); + +protected: + State _state; + KProcess *_process; + QTimer *_timer; + QString _stdout, _stderr; + + static bool isFilteredLine(const QString &line); +}; + +//---------------------------------------------------------------------------- +class StringOutput : public Base +{ +Q_OBJECT +public: + StringOutput(QObject *parent = 0, const char *name = 0) : Base(parent, name) {} + QString sout() const { return _stdout; } + QString serr() const { return _stderr; } + +private slots: + virtual void receivedStdout(KProcess *, char *buffer, int len); + virtual void receivedStderr(KProcess *, char *buffer, int len); +}; + +//---------------------------------------------------------------------------- +class LineBase : public Base +{ +Q_OBJECT +public: + LineBase(QObject *parent = 0, const char *name = 0) : Base(parent, name) {} + +private slots: + virtual void receivedStdout(KProcess *, char *buffer, int len); + virtual void receivedStderr(KProcess *, char *buffer, int len); + +private: + virtual void addStdoutLine(const QString &line) = 0; + virtual void addStderrLine(const QString &line) = 0; +}; + +//---------------------------------------------------------------------------- +class LineOutput : public LineBase +{ +Q_OBJECT +public: + LineOutput(QObject *parent = 0, const char *name = 0) : LineBase(parent, name) {} + virtual bool start(uint timeout); + QStringList sout() const { return _stdoutLines; } + QStringList serr() const { return _stderrLines; } + +protected: + QStringList _stdoutLines, _stderrLines; + + virtual void addStdoutLine(const QString &line) { _stdoutLines += line; } + virtual void addStderrLine(const QString &line) { _stderrLines += line; } +}; + +//---------------------------------------------------------------------------- +class LineSignal : public LineBase +{ +Q_OBJECT +public: + LineSignal(QObject *parent = 0, const char *name = 0) : LineBase(parent, name) {} + +signals: + void logStdoutLine(const QString &line); + void logStderrLine(const QString &line); + +private: + virtual void addStdoutLine(const QString &line) { emit logStdoutLine(line); } + virtual void addStderrLine(const QString &line) { emit logStderrLine(line); } +}; + +} // namespace + +#endif diff --git a/src/common/global/progress_monitor.cpp b/src/common/global/progress_monitor.cpp new file mode 100644 index 0000000..fcd0cec --- /dev/null +++ b/src/common/global/progress_monitor.cpp @@ -0,0 +1,84 @@ +/*************************************************************************** + * Copyright (C) 2007 Nicolas Hadacek <[email protected]> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "progress_monitor.h" + +ProgressMonitor::ProgressMonitor(QObject* parent) + : QObject(parent, "progress_monitor") +{ + _current = _tasks.end(); +} + +void ProgressMonitor::clear() +{ + _tasks.clear(); + _current = _tasks.end(); + emit showProgress(false); +} + +void ProgressMonitor::appendTask(const QString &label, uint nbSteps) +{ + Task task; + task.label = label; + task.nbSteps = nbSteps; + task.nbDoneSteps = 0; + _tasks.append(task); +} + +void ProgressMonitor::insertTask(const QString &label, uint nbSteps) +{ + Task task; + task.label = label; + task.nbSteps = nbSteps; + task.nbDoneSteps = 0; + if ( _current==_tasks.end() ) _current = _tasks.prepend(task); + else _current = _tasks.insert(_current, task); + update(); +} + +uint ProgressMonitor::nbSteps() const +{ + uint nb = 0; + for (uint i=0; i<uint(_tasks.count()); i++) nb += _tasks[i].nbSteps; + return nb; +} + +uint ProgressMonitor::nbDoneSteps() const +{ + uint nb = 0; + for (uint i=0; i<uint(_tasks.count()); i++) nb += _tasks[i].nbDoneSteps; + return nb; +} + +void ProgressMonitor::update() +{ + QString label = (_current==_tasks.end() ? QString::null : (*_current).label); + emit setLabel(label); + emit setTotalProgress(nbSteps()); + emit setProgress(nbDoneSteps()); + emit showProgress(true); +} + +void ProgressMonitor::startNextTask() +{ + if ( _current==_tasks.end() ) _current = _tasks.begin(); + else ++_current; + Q_ASSERT( _current!=_tasks.end() ) ; + update(); +} + +void ProgressMonitor::addTaskProgress(uint nbSteps) +{ + Q_ASSERT( _current!=_tasks.end() ) ; + if ( _current==_tasks.end() ) return; + uint nb = (*_current).nbDoneSteps + nbSteps; + Q_ASSERT( nb<=(*_current).nbSteps ); + if ( nb>(*_current).nbSteps ) qDebug("%s %i+%i > %i", (*_current).label.latin1(), (*_current).nbDoneSteps, nbSteps, (*_current).nbSteps); + (*_current).nbDoneSteps = QMIN(nb, (*_current).nbSteps); + update(); +} diff --git a/src/common/global/progress_monitor.h b/src/common/global/progress_monitor.h new file mode 100644 index 0000000..bb905f7 --- /dev/null +++ b/src/common/global/progress_monitor.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2007 Nicolas Hadacek <[email protected]> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef PROGRESS_MONITOR_H +#define PROGRESS_MONITOR_H + +#include "global.h" + +class ProgressMonitor : public QObject +{ +Q_OBJECT +public: + ProgressMonitor(QObject *parent = 0); + void clear(); + void appendTask(const QString &label, uint nbSteps); + void insertTask(const QString &label, uint nbSteps); + void startNextTask(); + void addTaskProgress(uint nbSteps); + uint nbSteps() const; + uint nbDoneSteps() const; + +public slots: + void update(); + +signals: + void showProgress(bool show); + void setLabel(const QString &label); + void setTotalProgress(uint nbSteps); + void setProgress(uint nbSteps); + +private: + class Task { + public: + QString label; + uint nbSteps, nbDoneSteps; + }; + QValueList<Task> _tasks; + QValueList<Task>::iterator _current; +}; + +#endif diff --git a/src/common/global/purl.cpp b/src/common/global/purl.cpp new file mode 100644 index 0000000..6db2914 --- /dev/null +++ b/src/common/global/purl.cpp @@ -0,0 +1,428 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <[email protected]> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "purl.h" + +#include <qfileinfo.h> +#include <qdatetime.h> +#include <qdir.h> +#include <qregexp.h> +#include <qmap.h> +#if QT_VERSION<0x040000 +# include <qnetwork.h> +#endif + +#include "common/common/synchronous.h" +#include "process.h" + +#if !defined(NO_KDE) +# include <kio/netaccess.h> +# include <kfileitem.h> +# include <kconfigbackend.h> +#endif + +//----------------------------------------------------------------------------- +PURL::Http::Http(const QString &hostname) + : QHttp(hostname) +{ + connect(this, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)), + SLOT(responseHeaderReceivedSlot(const QHttpResponseHeader &))); +} + +//----------------------------------------------------------------------------- +class PURL::Private +{ +public: + QString convertWindowsFilepath(const QString &filepath); + +private: + QMap<char, QString> _winDrives; // drive -> unix path + QMap<QString, QString> _winPaths; // windows path -> unix path + + QString getWindowsDrivePath(char drive); + bool checkCachedPath(QString &filepath) const; + QString cachePath(const QString &origin, const QString &filepath); + QString convertWindowsShortFilepath(const QString &filepath); + QString findName(const QString &path, const QString &name); + static QString findName(const QString &filepath); +}; + +QString PURL::Private::getWindowsDrivePath(char drive) +{ +#if defined(Q_OS_UNIX) + if ( !_winDrives.contains(drive) ) { + QStringList args; + args += "-u"; + QString s; + s += drive; + args += s + ":\\"; + ::Process::StringOutput process; + process.setup("winepath", args, false); + ::Process::State state = ::Process::runSynchronously(process, ::Process::Start, 3000); + if ( state!=::Process::Exited ) qWarning("Error running \"winepath\" with \"%s\" (%i)", args.join(" ").latin1(), state); + s = process.sout() + process.serr(); + QDir dir(s.stripWhiteSpace()); + _winDrives[drive] = dir.canonicalPath(); + } + return _winDrives[drive]; +#else + return QString("%1:\\").arg(drive); +#endif +} + +bool PURL::Private::checkCachedPath(QString &filepath) const +{ + if ( !_winPaths.contains(filepath) ) return false; + filepath = _winPaths[filepath]; + return true; +} + +QString PURL::Private::cachePath(const QString &origin, const QString &filepath) +{ + _winPaths[origin] = filepath; + return filepath; +} + +QString PURL::Private::convertWindowsFilepath(const QString &filepath) +{ + // appears to be an absolute windows path + if ( filepath[0]=='\\' ) { + QString tmp = filepath; + if ( checkCachedPath(tmp) ) return tmp; + return cachePath(filepath, convertWindowsShortFilepath(tmp.replace('\\', "/"))); + } + // appears to be a windows path with a drive + if ( (filepath.length()>=2 && filepath[0].isLetter() && filepath[1]==':') ) { + QString tmp = filepath; + if ( checkCachedPath(tmp) ) return tmp; +#if QT_VERSION<0x040000 + tmp = getWindowsDrivePath(filepath[0]) + tmp.mid(2).replace('\\', "/"); +#else + tmp = getWindowsDrivePath(filepath[0].toLatin1()) + tmp.mid(2).replace('\\', "/"); +#endif + return cachePath(filepath, convertWindowsShortFilepath(tmp)); + } + return filepath; +} + +QString PURL::Private::findName(const QString &path, const QString &name) +{ + QString filepath = path + '/' + name; + if ( checkCachedPath(filepath) ) return filepath; + return cachePath(filepath, findName(filepath)); +} + +QString PURL::Private::findName(const QString &filepath) +{ + QFileInfo finfo(filepath); + if ( finfo.exists() || !finfo.dir().exists() ) return finfo.filePath(); + QStringList list = finfo.dir().entryList(QDir::All, QDir::Name); + // find if name is just in a different case + for (uint j=0; j<uint(list.count()); j++) { + if ( list[j].lower()!=finfo.fileName().lower() ) continue; + return finfo.dirPath() + '/' + list[j]; + } + // find if name is a shorted filename + QRegExp rexp("([^~]+)~(\\d+).*"); + if ( !rexp.exactMatch(finfo.fileName()) ) return finfo.filePath(); + QString start = rexp.cap(1).lower(); + uint index = rexp.cap(2).toUInt(); + uint k = 0; + for (uint j = 0; j<uint(list.count()); j++) { + if ( !list[j].lower().startsWith(start) ) continue; + k++; + if ( k==index ) return finfo.dirPath() + '/' + list[j]; + } + return finfo.filePath(); +} + +QString PURL::Private::convertWindowsShortFilepath(const QString &filepath) +{ + // apparently "winepath" cannot do that for us and it is a real pain too... + // we assume filepath is an absolute unix path + // first see if we know the dirpath + QFileInfo finfo(filepath); + QString path = finfo.dirPath(); + if ( checkCachedPath(path) ) return findName(path, finfo.fileName()); + + // otherwise go down the path + QStringList names = QStringList::split('/', filepath); + QString tmp; + for (uint i=0; i<uint(names.count()); i++) + tmp = findName(tmp, names[i]); + if ( filepath.endsWith("/") ) tmp += "/"; + return tmp; +} + +//----------------------------------------------------------------------------- +PURL::Private *PURL::Base::_private = 0; + +PURL::Base::Base(const QString &filepath) + : _relative(true) +{ + if ( !filepath.isEmpty() ) { + if ( _private==0 ) _private = new Private; +#if defined(Q_OS_UNIX) + QString tmp = _private->convertWindowsFilepath(filepath); +#else + QString tmp = filepath; +#endif + if ( tmp.startsWith("~") ) tmp = QDir::homeDirPath() + tmp.mid(1); + _relative = Q3Url::isRelativeUrl(tmp); +#if defined(Q_OS_UNIX) + if ( !tmp.startsWith("/") ) tmp = '/' + tmp; +#endif +#if defined(NO_KDE) + _url.setPath(tmp); +#else + _url = KURL::fromPathOrURL(tmp); +#endif + _url.cleanPath(); + } +} + +PURL::Base::Base(const KURL &url) + : _relative(false), _url(url) +{ + _url.cleanPath(); +} + +bool PURL::Base::isLocal() const +{ + return ( _url.protocol().isEmpty() || _url.protocol()=="file" ); +} + +bool PURL::Base::operator ==(const Base &url) const +{ + if ( _url.isEmpty() ) return url._url.isEmpty(); + return _url==url._url; +} + +QString PURL::Base::path(SeparatorType type) const +{ +#if defined(NO_KDE) + QString s = _url.dirPath(); + if ( !s.isEmpty() && !s.endsWith("/") ) s += '/'; +#else + QString s = _url.directory(false, false); +#endif + if ( type==WindowsSeparator ) { + for (uint i=0; i<uint(s.length()); i++) + if ( s[i]=='/' ) s[i] = '\\'; + } + return s; +} + +QString PURL::Base::unterminatedPath(SeparatorType type) const +{ +#if defined(NO_KDE) + QString s = _url.dirPath(); + if ( s.endsWith("/") ) s = s.mid(0, s.length()-1); +#else + QString s = _url.directory(true, false); +#endif + if ( type==WindowsSeparator ) { + for (uint i=0; i<uint(s.length()); i++) + if ( s[i]=='/' ) s[i] = '\\'; + } + return s; +} + +QString PURL::Base::pretty() const +{ +#if defined(NO_KDE) + QString s = _url.toString(); + if ( s.startsWith("://") ) return s.mid(3); + return s; +#else + return _url.prettyURL(0, KURL::StripFileProtocol); +#endif +} + +PURL::Directory PURL::Base::directory() const +{ + return Directory(path()); +} + +bool PURL::Base::isInto(const Directory &dir) const +{ + return path().startsWith(dir.path()); +} + +bool PURL::Base::httpUrlExists(bool *ok) const +{ +#if QT_VERSION<0x040000 + qInitNetworkProtocols(); +#endif + if (ok) *ok = false; + Http http(_url.host()); + Synchronous sync(500); + QObject::connect(&http, SIGNAL(done(bool)), &sync, SLOT(done())); + QFileInfo info(_url.fileName(false)); + http.head(_url.path()); + if ( !sync.enterLoop() ) return false; // timeout + if ( http.error()!=QHttp::NoError ) return false; + if (ok ) *ok = true; + return ( http._header.statusCode()==200 ); +} + +bool PURL::Base::exists(QDateTime *lastModified) const +{ + if ( isEmpty() ) return false; + if ( isLocal() ) { + QFileInfo fi(_url.path()); + if (lastModified) *lastModified = fi.lastModified(); + return fi.exists(); + } + if ( _url.protocol()=="http" ) return httpUrlExists(); +#if !defined(NO_KDE) + if (lastModified) { + KIO::UDSEntry uds; + if ( !KIO::NetAccess::stat(_url, uds, qApp->mainWidget()) ) return false; + KFileItem item(uds, _url); + lastModified->setTime_t(item.time(KIO::UDS_MODIFICATION_TIME)); + return true; + } else { + // assume file exists if ioslave cannot tell... + return KIO::NetAccess::exists(_url, true, qApp->mainWidget()); + } +#else + if (lastModified) lastModified->setTime_t(0); + // assume file exists + return true; +#endif +} + +//---------------------------------------------------------------------------- +PURL::Url PURL::Url::fromPathOrUrl(const QString &s) +{ + KURL kurl = KURL::fromPathOrURL(s); + if ( !kurl.protocol().isEmpty() && kurl.protocol()!="file" && kurl.protocol().length()!=1 ) return kurl; + return Url(s.startsWith("file://") ? s.mid(7) : s); +} + +PURL::Url::Url(const Directory &dir, const QString &filename, FileType type) + : Base(dir.path() + '/' + addExtension(filename, type)) +{} + +PURL::Url::Url(const Directory &dir, const QString &filepath) + : Base(dir.path() + '/' + filepath) +{} + +PURL::FileType PURL::Url::fileType() const +{ + QFileInfo info(filename()); + FOR_EACH(FileType, type) + for (uint i=0; type.data().extensions[i]; i++) + if ( info.extension(false).lower()==type.data().extensions[i] ) return type; + return Unknown; +} + +QString PURL::Url::basename() const +{ + QFileInfo info(_url.fileName(false)); + return info.baseName(true); +} + +QString PURL::Url::filename() const +{ + QFileInfo info(_url.fileName(false)); + return info.fileName(); +} + +QString PURL::Url::filepath(SeparatorType type) const +{ + return path(type) + filename(); +} + +PURL::Url PURL::Url::toExtension(const QString &extension) const +{ + QFileInfo info(filename()); + return Url(directory().path() + info.baseName(true) + '.' + extension); +} + +PURL::Url PURL::Url::appendExtension(const QString &extension) const +{ + QFileInfo info(filename()); + return Url(directory().path() + info.fileName() + '.' + extension); +} + +QString PURL::Url::relativeTo(const Directory &dir, SeparatorType type) const +{ + QString s = filepath(type); + if ( !isInto(dir) ) return s; + return s.right(s.length() - dir.path(type).length()); +} + +PURL::Url PURL::Url::toAbsolute(const Directory &dir) const +{ + if ( isRelative() ) return Url(dir, filepath()); + return *this; +} + +bool PURL::findExistingUrl(Url &url) +{ + if ( url.exists() ) return true; + QFileInfo info(url.filename()); + Url tmp = url.toExtension(info.extension(false).upper()); + if ( !tmp.exists() ) { + tmp = url.toExtension(info.extension(false).lower()); + if ( !tmp.exists() ) return false; + } + url = tmp; + return true; +} + +//----------------------------------------------------------------------------- +#if !defined(NO_KDE) +PURL::UrlList::UrlList(const KURL::List &list) +{ + KURL::List::const_iterator it; + for (it=list.begin(); it!=list.end(); ++it) append(*it); +} +#endif + +//----------------------------------------------------------------------------- +PURL::Directory::Directory(const QString &path) + : Base(path.isEmpty() ? QString::null : path + '/') +{} + +PURL::Directory PURL::Directory::up() const +{ + QDir dir(path()); + dir.cdUp(); + return PURL::Directory(dir.path()); +} + +PURL::Directory PURL::Directory::down(const QString &subPath) const +{ + Q_ASSERT( QDir::isRelativePath(subPath) ); + QDir dir(path()); + dir.cd(subPath); + return PURL::Directory(dir.path()); +} + +QStringList PURL::Directory::files(const QString &filter) const +{ + QDir dir(path()); + return dir.entryList(filter, QDir::Files); +} + +PURL::Url PURL::Directory::findMatchingFilename(const QString &filename) const +{ + QDir dir(path()); + QStringList files = dir.entryList(QDir::Files); + for (uint i=0; i<uint(files.count()); i++) + if ( files[i].lower()==filename.lower() ) return Url(*this, files[i]); + return Url(*this, filename); +} + +PURL::Directory PURL::Directory::current() +{ + return QDir::currentDirPath(); +} diff --git a/src/common/global/purl.h b/src/common/global/purl.h new file mode 100644 index 0000000..6cbf38b --- /dev/null +++ b/src/common/global/purl.h @@ -0,0 +1,136 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <[email protected]> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef PURL_H +#define PURL_H + +#include "common/global/global.h" +#if QT_VERSION<0x040000 +# include <qhttp.h> +#else +# include <QtNetwork/QHttp> +# include <QDateTime> +#endif +#include "common/global/log.h" +#include "common/common/purl_base.h" + +namespace PURL +{ +//---------------------------------------------------------------------------- +class Http : public QHttp +{ +Q_OBJECT +public: + Http(const QString &hostname); + QHttpResponseHeader _header; + +private slots: + void responseHeaderReceivedSlot(const QHttpResponseHeader &rh) { _header = rh; } +}; + +class Url; +class Directory; +class Private; + +enum SeparatorType { UnixSeparator, WindowsSeparator }; + +//---------------------------------------------------------------------------- +class Base +{ +public: + Base(const QString &filepath = QString::null); + Base(const KURL &url); + bool operator <(const Base &url) const { return _url<url._url; } + bool operator ==(const Base &url) const; + bool operator !=(const Base &url) const { return !(_url==url._url); } + const KURL &kurl() const { return _url; } + QString pretty() const; + bool isEmpty() const { return _url.isEmpty(); } + bool isLocal() const; + QString path(SeparatorType type = UnixSeparator) const; // with ending '/' unless empty path + QString unterminatedPath(SeparatorType type = UnixSeparator) const; // no ending '/' + Directory directory() const; + bool isInto(const Directory &dir) const; + bool isRelative() const { return _relative; } + bool exists(QDateTime *lastModified = 0) const; + +protected: + bool _relative; + KURL _url; + static Private *_private; + +private: + bool httpUrlExists(bool *ok = 0) const; +}; + +//---------------------------------------------------------------------------- +class Url : public Base +{ +public: + Url() {} + Url(const KURL &url) : Base(url) {} + // add correct extension if filename has no extension + Url(const Directory &path, const QString &filename, FileType type); + Url(const Directory &path, const QString &filepath); + static Url fromPathOrUrl(const QString &s); + + Url toFileType(FileType type) const { return toExtension(type.data().extensions[0]); } + Url toExtension(const QString &extension) const; + Url appendExtension(const QString &extension) const; + + const FileType::Data &data() const { return fileType().data(); } + FileType fileType() const; + QString basename() const; // filename without extension + QString filename() const; // filename without path + QString filepath(SeparatorType type = UnixSeparator) const; // filename with path + QString relativeTo(const Directory &dir, SeparatorType type = UnixSeparator) const; + Url toAbsolute(const Directory &dir) const; +#if !defined(NO_KDE) + bool isDosFile() const; + bool create(Log::Generic &log) const; // do not overwrite + bool write(const QString &text, Log::Generic &log) const; + bool copyTo(const Url &destination, Log::Generic &log) const; // do not overwrite + bool del(Log::Generic &log) const; +#endif + +private: + Url(const QString &filepath) : Base(filepath) {} +}; + +extern bool findExistingUrl(Url &url); // may transform extension's case if needed + +//---------------------------------------------------------------------------- +class UrlList : public QValueList<Url> +{ +public: + UrlList() {} + UrlList(const Url &url) { append(url); } + UrlList(const QValueList<Url> &list) : QValueList<Url>(list) {} +#if !defined(NO_KDE) + UrlList(const KURL::List &list); +#endif +}; + +//---------------------------------------------------------------------------- +class Directory : public Base +{ +public: + Directory(const QString &path = QString::null); + QStringList files(const QString &filter) const; + Url findMatchingFilename(const QString &filename) const; + Directory up() const; + Directory down(const QString &path) const; + static Directory current(); +#if !defined(NO_KDE) + bool create(Log::Generic &log) const; +#endif +}; + +} // namespace + +#endif diff --git a/src/common/global/svn_revision/Makefile.am b/src/common/global/svn_revision/Makefile.am new file mode 100644 index 0000000..f3d4ee4 --- /dev/null +++ b/src/common/global/svn_revision/Makefile.am @@ -0,0 +1,5 @@ +INCLUDES = -I$(top_srcdir)/src $(all_includes) +METASOURCES = AUTO + +all-local: + sh svn_revision.sh diff --git a/src/common/global/svn_revision/svn_revision.sh b/src/common/global/svn_revision/svn_revision.sh new file mode 100755 index 0000000..3590568 --- /dev/null +++ b/src/common/global/svn_revision/svn_revision.sh @@ -0,0 +1,20 @@ +if [ -d .svn ]; then + ( echo '// generated file'; + printf '#define SVN_REVISION "'; + (svnversion -n .); + echo '"' ) > svn_revision.h.new; + if [ ! -f svn_revision.h ]; then + mv -f svn_revision.h.new svn_revision.h; + else + if cmp svn_revision.h svn_revision.h.new; then + rm -f svn_revision.h.new; + else + mv -f svn_revision.h.new svn_revision.h; + fi + fi +fi +if [ ! -f svn_revision.h ]; then + ( echo '// generated file'; + echo '#define SVN_REVISION "distribution"'; ) > svn_revision.h; +fi + diff --git a/src/common/global/xml_data_file.cpp b/src/common/global/xml_data_file.cpp new file mode 100644 index 0000000..2464b34 --- /dev/null +++ b/src/common/global/xml_data_file.cpp @@ -0,0 +1,160 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <[email protected]> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "xml_data_file.h" + +#include <qfile.h> +#include <qstringlist.h> +#include <ksimpleconfig.h> +#include <klocale.h> +#include "common/global/pfile.h" + +XmlDataFile::XmlDataFile(const PURL::Url &url, const QString &name) + : _url(url), _name(name), _document(name) +{ + QDomElement root = _document.createElement(name); + _document.appendChild(root); +} + +bool XmlDataFile::load(QString &error) +{ + Log::StringView sview; + PURL::File file(_url, sview); + if ( !file.openForRead() ) { + error = i18n("Error opening file: %1").arg(sview.string()); + return false; + } + if ( !_document.setContent(file.qfile(), false, &error) ) return false; + if ( _document.doctype().name()!=_name + || _document.documentElement().nodeName()!=_name ) { + error = i18n("File is not of correct type."); + return false; + } + return true; +} + +bool XmlDataFile::save(QString &error) const +{ + Log::StringView sview; + PURL::File file(_url, sview); + bool ok = file.openForWrite(); + if (ok) { + QString s = _document.toString(2); + file.appendText(s); + ok = file.close(); + } + if ( !ok ) error = i18n("Error saving file: %1").arg(sview.string()); + return ok; +} + +QDomElement XmlDataFile::findChildElement(QDomElement parent, const QString &name) const +{ + QDomNodeList list = parent.elementsByTagName(name); + return list.item(0).toElement(); +} + +QDomElement XmlDataFile::createChildElement(QDomElement parent, const QString &name) +{ + QDomNodeList list = parent.elementsByTagName(name); + if ( list.count()==0 ) { + QDomElement element = _document.createElement(name); + parent.appendChild(element); + return element; + } + return list.item(0).toElement(); +} + +void XmlDataFile::removeChilds(QDomNode parent) const +{ + QDomNodeList list = parent.childNodes(); + for (uint i=0; i<list.count(); i++) + parent.removeChild(list.item(i)); +} + +QString XmlDataFile::value(const QString &group, const QString &key, const QString &defValue) const +{ + QDomElement root = _document.documentElement(); + QDomElement groupElement = findChildElement(root, group); + if ( groupElement.isNull() ) return defValue; + QDomElement element = findChildElement(groupElement, key); + if ( element.isNull() ) return defValue; + QDomText text = element.firstChild().toText(); + if ( text.isNull() ) return defValue; + return text.data(); +} + +void XmlDataFile::setValue(const QString &group, const QString &key, const QString &value) +{ + QDomElement root = _document.documentElement(); + QDomElement groupElement = createChildElement(root, group); + QDomElement element = createChildElement(groupElement, key); + removeChilds(element); + QDomText text = _document.createTextNode(value); + element.appendChild(text); +} + +QStringList XmlDataFile::listValues(const QString &group, const QString &key, const QStringList &defaultValues) const +{ + QStringList list; + QDomElement root = _document.documentElement(); + QDomElement groupElement = findChildElement(root, group); + if ( groupElement.isNull() ) return defaultValues; + QDomElement element = findChildElement(groupElement, key); + if ( element.isNull() ) return defaultValues; + QDomNodeList childs = element.childNodes(); + if ( childs.count()==1 ) { // legacy compatibility + QDomText text = element.firstChild().toText(); + if ( !text.isNull() ) return text.data(); + } + for (uint i=0; i<childs.count(); i++) { + QDomText text = childs.item(i).toElement().firstChild().toText(); + if ( text.isNull() ) continue; + list.append(text.data()); + } + return list; +} + +void XmlDataFile::appendListValue(const QString &group, const QString &key, const QString &value) +{ + QDomElement root = _document.documentElement(); + QDomElement groupElement = createChildElement(root, group); + QDomElement element = createChildElement(groupElement, key); + QDomElement item = _document.createElement("item"); + element.appendChild(item); + QDomText text = _document.createTextNode(value); + item.appendChild(text); +} + +void XmlDataFile::removeListValue(const QString &group, const QString &key, const QString &value) +{ + QDomElement root = _document.documentElement(); + QDomElement groupElement = createChildElement(root, group); + QDomElement element = createChildElement(groupElement, key); + QDomNodeList list = element.childNodes(); + for (uint i=0; i<list.count(); i++) { + QDomElement item = list.item(i).toElement(); + QDomText text = item.firstChild().toText(); + if ( text.isNull() || text.data()!=value ) continue; + element.removeChild(item); + break; + } +} + +void XmlDataFile::clearList(const QString &group, const QString &key) +{ + QDomElement root = _document.documentElement(); + QDomElement groupElement = createChildElement(root, group); + QDomElement element = createChildElement(groupElement, key); + groupElement.removeChild(element); +} + +void XmlDataFile::setListValues(const QString &group, const QString &key, const QStringList &values) +{ + clearList(group, key); + for (uint i=0; i<values.count(); i++) appendListValue(group, key, values[i]); +} diff --git a/src/common/global/xml_data_file.h b/src/common/global/xml_data_file.h new file mode 100644 index 0000000..dfcbc73 --- /dev/null +++ b/src/common/global/xml_data_file.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <[email protected]> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef XML_DATA_FILE_H +#define XML_DATA_FILE_H + +#include <qdom.h> + +#include "common/global/purl.h" + +class XmlDataFile +{ +public: + XmlDataFile(const PURL::Url &url, const QString &name); + virtual ~XmlDataFile() {} + PURL::Url url() const { return _url; } + virtual bool load(QString &error); + bool save(QString &error) const; + + QString value(const QString &group, const QString &key, const QString &defaultValue) const; + void setValue(const QString &group, const QString &key, const QString &value); + QStringList listValues(const QString &group, const QString &key, const QStringList &defaultValues) const; + void setListValues(const QString &group, const QString &key, const QStringList &values); + void appendListValue(const QString &group, const QString &key, const QString &value); + void removeListValue(const QString &group, const QString &key, const QString &value); + void clearList(const QString &group, const QString &key); + +protected: + PURL::Url _url; + +private: + QString _name; + QDomDocument _document; + + QDomElement findChildElement(QDomElement element, const QString &tag) const; + QDomElement createChildElement(QDomElement element, const QString &tag); + void removeChilds(QDomNode node) const; +}; + +#endif |