diff options
Diffstat (limited to 'src/common')
104 files changed, 12482 insertions, 0 deletions
diff --git a/src/common/Makefile.am b/src/common/Makefile.am new file mode 100644 index 0000000..da1638b --- /dev/null +++ b/src/common/Makefile.am @@ -0,0 +1,4 @@ +INCLUDES = -I$(top_srcdir)/src $(all_includes) +METASOURCES = AUTO + +SUBDIRS = common global port cli gui diff --git a/src/common/cli/Makefile.am b/src/common/cli/Makefile.am new file mode 100644 index 0000000..2225bc0 --- /dev/null +++ b/src/common/cli/Makefile.am @@ -0,0 +1,7 @@ +INCLUDES = -I$(top_srcdir)/src $(all_includes) +METASOURCES = AUTO + +noinst_LTLIBRARIES = libcli.la +libcli_la_LDFLAGS = $(all_libraries) +libcli_la_SOURCES = cli_purl.cpp cli_pfile.cpp cli_global.cpp cli_log.cpp \ + cli_main.cpp diff --git a/src/common/cli/cli.pro b/src/common/cli/cli.pro new file mode 100644 index 0000000..20bb3b7 --- /dev/null +++ b/src/common/cli/cli.pro @@ -0,0 +1,6 @@ +STOPDIR = ../../.. +include($${STOPDIR}/lib.pro) + +TARGET = cli +HEADERS += cli_global.h cli_log.h cli_main.h +SOURCES += cli_global.cpp cli_log.cpp cli_purl.cpp cli_pfile.cpp cli_main.cpp diff --git a/src/common/cli/cli_global.cpp b/src/common/cli/cli_global.cpp new file mode 100644 index 0000000..4d58bdd --- /dev/null +++ b/src/common/cli/cli_global.cpp @@ -0,0 +1,37 @@ +/*************************************************************************** + * Copyright (C) 2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 "cli_global.h" + +#include <qdir.h> + +#include "common/global/purl.h" +#include "cli_log.h" + +bool CLI::_force = false; +bool CLI::_isInteractive = false; +CLI::View *CLI::_view = 0; +CLI::MainBase *CLI::_main = 0; + +CLI::ExitCode CLI::errorExit(const QString &message, ExitCode code) +{ + Q_ASSERT( code!=OK ); + _view->log(Log::LineType::SoftError, message); + return code; +} + +CLI::ExitCode CLI::okExit(const QString &message) +{ + _view->log(Log::LineType::Information, message); + return OK; +} + +PURL::Directory CLI::runDirectory() +{ + return PURL::Directory(QDir::currentDirPath()); +} diff --git a/src/common/cli/cli_global.h b/src/common/cli/cli_global.h new file mode 100644 index 0000000..b90f36e --- /dev/null +++ b/src/common/cli/cli_global.h @@ -0,0 +1,33 @@ +/*************************************************************************** + * Copyright (C) 2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 CLI_GLOBAL_H +#define CLI_GLOBAL_H + +#include <qstring.h> +namespace PURL { class Directory; } + +namespace CLI +{ + +class View; +class MainBase; +enum ExitCode { EXITING = 1, OK = 0, ARG_ERROR = -1, NOT_SUPPORTED_ERROR = -2, + FILE_ERROR = -3, EXEC_ERROR = -4 }; +extern ExitCode errorExit(const QString &message, ExitCode code); +extern ExitCode okExit(const QString &message); +extern PURL::Directory runDirectory(); + +extern bool _force; +extern bool _isInteractive; +extern View *_view; +extern MainBase *_main; + +} // namespace + +#endif diff --git a/src/common/cli/cli_log.cpp b/src/common/cli/cli_log.cpp new file mode 100644 index 0000000..603d5f8 --- /dev/null +++ b/src/common/cli/cli_log.cpp @@ -0,0 +1,74 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 "cli_log.h" + +#include "common/global/global.h" +#include "cli_global.h" + +void CLI::View::doLog(Log::LineType type, const QString &text, Log::Action) +{ + QString s = text + "\n"; + switch (type.type()) { + case Log::LineType::Error: + case Log::LineType::SoftError: s = "Error: " + s; break; + case Log::LineType::Warning: s = "Warning: " + s; break; + default: break; + } +#if QT_VERSION<0x040000 + if ( type==Log::LineType::Error || type==Log::LineType::SoftError ) fprintf(stderr, "%s", s.latin1()); + else fprintf(stdout, "%s", s.latin1()); +#else + QByteArray ba = s.toLatin1(); + if ( type==Log::LineType::Error || type==Log::LineType::SoftError ) fprintf(stderr, "%s", ba.constData()); + else fprintf(stdout, "%s", ba.constData()); +#endif +} + +void CLI::View::doLog(Log::DebugLevel, const QString &text, Log::Action) +{ + QString s = text + "\n"; +#if QT_VERSION<0x040000 + fprintf(stdout, "%s", s.latin1()); +#else + QByteArray ba = s.toLatin1(); + fprintf(stdout, "%s", ba.constData()); +#endif +} + +void CLI::View::appendToLastLine(const QString &text) +{ +#if QT_VERSION<0x040000 + fprintf(stdout, "%s", text.latin1()); +#else + QByteArray ba = text.toLatin1(); + fprintf(stdout, "%s", ba.constData()); +#endif +} + +void CLI::View::sorry(const QString &message, const QString &details) +{ + if ( details.isEmpty() ) log(Log::LineType::Error, message, Log::Immediate); + else log(Log::LineType::Error, message + " (" + details + ")", Log::Immediate); +} + +bool CLI::View::askContinue(const QString &message) +{ + log(Log::LineType::Warning, message + " " + (_force ? i18n("*yes*") : i18n("*no*")), Log::Immediate); + if (_force) return true; + if ( !_isInteractive ) return false; // always fail + // #### TODO + return false; +} + +void CLI::View::logUserAbort() +{ + if ( !_isInteractive ) return; + return; + //Log::View::logUserAbort(); +} diff --git a/src/common/cli/cli_log.h b/src/common/cli/cli_log.h new file mode 100644 index 0000000..2fa83dc --- /dev/null +++ b/src/common/cli/cli_log.h @@ -0,0 +1,33 @@ +/*************************************************************************** + * Copyright (C) 2005 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 CLI_LOG_H +#define CLI_LOG_H + +#include "common/global/log.h" + +namespace CLI +{ + +class View : public Log::View +{ +public: + virtual void appendToLastLine(const QString &text); + virtual void clear() {} + virtual void sorry(const QString &message, const QString &details); + virtual bool askContinue(const QString &message); + virtual void logUserAbort(); + +private: + virtual void doLog(Log::LineType type, const QString &text, Log::Action action); + virtual void doLog(Log::DebugLevel level, const QString &text, Log::Action action); +}; + +} // namespace + +#endif diff --git a/src/common/cli/cli_main.cpp b/src/common/cli/cli_main.cpp new file mode 100644 index 0000000..7d75dbb --- /dev/null +++ b/src/common/cli/cli_main.cpp @@ -0,0 +1,208 @@ +/*************************************************************************** + * Copyright (C) 2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 "cli_main.h" + +#include "cli_log.h" +#include "common/global/about.h" + +//----------------------------------------------------------------------------- +const CLI::CommandData *CLI::findCommandData(const QString &command) +{ + for (uint i=0; NORMAL_COMMAND_DATA[i].name; i++) + if ( NORMAL_COMMAND_DATA[i].name==command ) return &NORMAL_COMMAND_DATA[i]; + if ( !_isInteractive) return 0; + for (uint i=0; INTERACTIVE_COMMAND_DATA[i].name; i++) + if ( INTERACTIVE_COMMAND_DATA[i].name==command ) return &INTERACTIVE_COMMAND_DATA[i]; + return 0; +} + +CLI::ExitCode CLI::findCommand(const QString &s) +{ + if ( s.isEmpty() ) return errorExit(i18n("No command specified"), ARG_ERROR); + const CommandData *data = findCommandData(s); + if ( data==0 ) return errorExit(i18n("Unknown command: %1").arg(s), ARG_ERROR); + return OK; +} + +//----------------------------------------------------------------------------- +bool CLI::isPropertyList(const QString &s) +{ + for (uint i=0; PROPERTY_DATA[i].name; i++) + if ( s==PROPERTY_DATA[i].list ) return true; + return false; +} + +bool CLI::isProperty(const QString &s) +{ + for (uint i=0; PROPERTY_DATA[i].name; i++) + if ( s==PROPERTY_DATA[i].name ) return true; + return false; +} + +//----------------------------------------------------------------------------- +const KCmdLineOptions STANDARD_OPTIONS[] = { + { "c", 0, 0 }, + { "command <name>", I18N_NOOP("Perform the requested command."), 0 }, + { "command-list", I18N_NOOP("Return the list of recognized commands."), 0 }, + { "debug", I18N_NOOP("Display debug messages."), 0 }, + { "extra-debug", I18N_NOOP("Display extra debug messages."), 0 }, + { "max-debug", I18N_NOOP("Display all debug messages."), 0 }, + { "lowlevel-debug", I18N_NOOP("Display low level debug messages."), 0 }, + { "quiet", I18N_NOOP("Do not display messages."), 0 }, + KCmdLineLastOption +}; + +const KCmdLineOptions FORCE_OPTIONS[] = { + { "f", 0, 0 }, + { "force", I18N_NOOP("Overwrite files and answer \"yes\" to questions."), 0 }, + KCmdLineLastOption +}; + +const KCmdLineOptions INTERACTIVE_OPTIONS[] = { + { "i", 0, 0 }, + { "cli", I18N_NOOP("Interactive mode"), 0 }, + KCmdLineLastOption +}; + +CLI::OptionList::OptionList(Properties properties) +{ + init(properties); +} + +CLI::OptionList::OptionList(Properties properties, const KCmdLineOptions *options) +{ + init(properties); + for (uint i=0; options[i].name; i++) append(options[i]); +} + +void CLI::OptionList::init(Properties properties) +{ + for (uint i=0; STANDARD_OPTIONS[i].name; i++) append(STANDARD_OPTIONS[i]); + if ( properties & HasForce ) for (uint i=0; FORCE_OPTIONS[i].name; i++) append(FORCE_OPTIONS[i]); + if ( properties & HasInteractiveMode ) for (uint i=0; INTERACTIVE_OPTIONS[i].name; i++) append(INTERACTIVE_OPTIONS[i]); +} + +CLI::ExitCode CLI::commandList() +{ + Log::KeyList keys(i18n("Supported commands:")); + for (uint i=0; NORMAL_COMMAND_DATA[i].name; i++) + keys.append(NORMAL_COMMAND_DATA[i].name, i18n(NORMAL_COMMAND_DATA[i].help)); + if (_isInteractive) { + for (uint i=0; INTERACTIVE_COMMAND_DATA[i].name; i++) + keys.append(INTERACTIVE_COMMAND_DATA[i].name, i18n(INTERACTIVE_COMMAND_DATA[i].help)); + } + keys.display(*_view); + return OK; +} + +CLI::ExitCode CLI::propertyList() +{ + Log::KeyList keys; + for (uint i=0; PROPERTY_DATA[i].name; i++) + keys.append(PROPERTY_DATA[i].name, i18n(PROPERTY_DATA[i].help)); + keys.display(*_view); + return OK; +} + +//----------------------------------------------------------------------------- +CLI::MainBase::MainBase(Properties properties) + : QObject(0, "main"), _properties(properties) +{ + Q_ASSERT( _main==0 ); + _main = this; + _view = new View; + setView(_view); +} + +void CLI::MainBase::init() +{ + _args = KCmdLineArgs::parsedArgs(); + if ( _properties & HasInteractiveMode ) _isInteractive = _args->isSet("cli"); + if ( _properties & HasForce ) _force = _args->isSet("force"); + FOR_EACH(Log::DebugLevel, level) if ( _args->isSet(level.key()) ) _view->setDebugLevel(level); +} + +CLI::OptionList CLI::MainBase::optionList(const char *fileDescription) const +{ + OptionList list(_properties, OPTIONS); + KCmdLineOptions opt; + for (uint i=0; PROPERTY_DATA[i].name; i++) { + opt.description = 0; + opt.def = 0; + if ( PROPERTY_DATA[i].help==0 ) { + Q_ASSERT( QString(PROPERTY_DATA[i].name)!=PROPERTY_DATA[i].optName ); + opt.name = PROPERTY_DATA[i].name; // alias + list.append(opt); + } else { + if ( PROPERTY_DATA[i].optName==0 ) continue; // interactive only + if ( PROPERTY_DATA[i].alias ) { + opt.name = PROPERTY_DATA[i].alias; + list.append(opt); + } + opt.name = PROPERTY_DATA[i].optName; + opt.description = PROPERTY_DATA[i].help; + list.append(opt); + if ( PROPERTY_DATA[i].list ) { + opt.name = PROPERTY_DATA[i].list; + opt.description = PROPERTY_DATA[i].listHelp; + list.append(opt); + } + } + } + if (fileDescription) { + opt.name = "+[file]"; + opt.description = fileDescription; + opt.def = 0; + } + list.append(opt); + return list; +} + +CLI::ExitCode CLI::MainBase::list(const QString &command) +{ + if ( command=="command-list" ) return commandList(); + if ( command=="property-list" ) return propertyList(); + return ARG_ERROR; +} + +CLI::ExitCode CLI::MainBase::doRun() +{ + init(); + + // process set options + for (uint i=0; PROPERTY_DATA[i].name; i++) { + if ( PROPERTY_DATA[i].optName==0 ) continue; // alias or interactive only + if ( !_args->isSet(PROPERTY_DATA[i].name) ) continue; + QString option = _args->getOption(PROPERTY_DATA[i].name); + ExitCode code = executeSetCommand(PROPERTY_DATA[i].name, option); + if ( code!=OK ) return code; + log(Log::LineType::Information, QString("%1: %2").arg(PROPERTY_DATA[i].name).arg(executeGetCommand(PROPERTY_DATA[i].name))); + } + + // process default lists + if ( _args->isSet("command-list") ) return list("command-list"); + for (uint i=0; PROPERTY_DATA[i].name; i++) { + if ( PROPERTY_DATA[i].list==0 ) continue; + if ( _args->isSet(PROPERTY_DATA[i].list) ) return list(PROPERTY_DATA[i].list); + } + + bool interactive; + ExitCode code = prepareRun(interactive); + if ( code!=OK || interactive ) return code; + + // find command + QString command = _args->getOption("command"); + code = findCommand(command); + if ( code!=OK ) return code; + + // execute command + code = prepareCommand(command); + if ( code!=OK ) return code; + return executeCommand(command); +} diff --git a/src/common/cli/cli_main.h b/src/common/cli/cli_main.h new file mode 100644 index 0000000..9b54c70 --- /dev/null +++ b/src/common/cli/cli_main.h @@ -0,0 +1,82 @@ +/*************************************************************************** + * Copyright (C) 2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 CLI_MAIN_H +#define CLI_MAIN_H + +#include "common/global/about.h" +#include "common/global/log.h" +#include "cli_global.h" + +namespace CLI +{ +//----------------------------------------------------------------------------- +enum Property { NoProperty = 0, HasForce = 1, HasInteractiveMode = 2 }; +Q_DECLARE_FLAGS(Properties, Property) +Q_DECLARE_OPERATORS_FOR_FLAGS(Properties) + +extern const KCmdLineOptions OPTIONS[]; +//----------------------------------------------------------------------------- +struct CommandData { + const char *name; + int properties; + const char *help; +}; +extern const CommandData NORMAL_COMMAND_DATA[]; +extern const CommandData INTERACTIVE_COMMAND_DATA[]; +extern const CommandData *findCommandData(const QString &command); +extern ExitCode findCommand(const QString &s); +extern ExitCode commandList(); + +//----------------------------------------------------------------------------- +struct PropertyData +{ + const char *name, *optName, *alias, *help, *list, *listHelp; +}; +extern const PropertyData PROPERTY_DATA[]; +extern bool isPropertyList(const QString &s); +extern bool isProperty(const QString &s); +extern ExitCode propertyList(); + +//----------------------------------------------------------------------------- +class OptionList : public Piklab::OptionList +{ +public: + OptionList(Properties properties); + OptionList(Properties properties, const KCmdLineOptions *options); + +private: + void init(Properties properties); +}; + +//----------------------------------------------------------------------------- +class MainBase : public QObject, public Log::Base +{ +Q_OBJECT +public: + MainBase(Properties properties); + virtual OptionList optionList(const char *fileDescription) const; + virtual ExitCode doRun(); + virtual ExitCode list(const QString &listName); + virtual ExitCode prepareCommand(const QString &command) = 0; + virtual ExitCode executeCommand(const QString &command) = 0; + virtual ExitCode executeSetCommand(const QString &property, const QString &value) = 0; + virtual QString executeGetCommand(const QString &property) = 0; + +protected: + Properties _properties; + KCmdLineArgs *_args; + +private: + virtual ExitCode prepareRun(bool &interactive) = 0; + virtual void init(); +}; + +} // namespace + +#endif diff --git a/src/common/cli/cli_pfile.cpp b/src/common/cli/cli_pfile.cpp new file mode 100644 index 0000000..96add3a --- /dev/null +++ b/src/common/cli/cli_pfile.cpp @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 "common/global/pfile.h" + +#include <qfile.h> + +//----------------------------------------------------------------------------- +bool PURL::File::openForWrite() +{ + close(); + _file->setName(url().filepath()); + if ( !_file->open(IO_WriteOnly) ) { + _error = i18n("Could not open file for writing."); + _log.sorry(_error, i18n("File: %1").arg(_file->name())); + return false; + } + return true; +} + +bool PURL::File::close() +{ + _file->close(); + return ( uint(_file->status())==IO_Ok ); +} + +bool PURL::File::openForRead() +{ + close(); + _file->setName(_url.filepath()); + if ( !_file->open(IO_ReadOnly) ) { + _error = i18n("Could not open file for reading."); + _log.sorry(_error, i18n("File: %1").arg(_file->name())); + return false; + } + return true; +} + +bool PURL::File::remove() +{ + return _file->remove(); +} diff --git a/src/common/cli/cli_purl.cpp b/src/common/cli/cli_purl.cpp new file mode 100644 index 0000000..e52c977 --- /dev/null +++ b/src/common/cli/cli_purl.cpp @@ -0,0 +1,9 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 "common/global/purl.h" diff --git a/src/common/common.pro b/src/common/common.pro new file mode 100644 index 0000000..aa219c1 --- /dev/null +++ b/src/common/common.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS = common nokde global port cli diff --git a/src/common/common/Makefile.am b/src/common/common/Makefile.am new file mode 100644 index 0000000..0f68067 --- /dev/null +++ b/src/common/common/Makefile.am @@ -0,0 +1,9 @@ +INCLUDES = -I$(top_srcdir)/src $(all_includes) +METASOURCES = AUTO + +noinst_LTLIBRARIES = libcommon.la +libcommon_la_SOURCES = bitvalue.cpp group.cpp misc.cpp number.cpp purl_base.cpp \ + storage.cpp synchronous.cpp version_data.cpp +libcommon_la_LDFLAGS = $(all_libraries) + + diff --git a/src/common/common/bitvalue.cpp b/src/common/common/bitvalue.cpp new file mode 100644 index 0000000..16d5ef0 --- /dev/null +++ b/src/common/common/bitvalue.cpp @@ -0,0 +1,30 @@ +/*************************************************************************** + * Copyright (C) 2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 "bitvalue.h" + +const uint GenericValue::INVALID = 0xFFFFFFFFU; + +BitValue BitValue::XORn(uint n) const +{ + uint nb = nbBits(_value); + uint mask = maxValue(NumberBase::Bin, n); + uint res = 0x0; + for (uint i=0; i<nb; i +=n) { + res ^= (_value >> i) & mask; + //qDebug("%i %s %s", i, toHexLabel((value>>i) & mask, 4).latin1(), toHexLabel(res, 4).latin1()); + } + return res; +} + +BitValue BitValue::XNORn(uint n) const +{ + BitValue res = XORn(n); + BitValue mask = maxValue(NumberBase::Bin, n); + return res.complementInMask(mask); +} diff --git a/src/common/common/bitvalue.h b/src/common/common/bitvalue.h new file mode 100644 index 0000000..d3ef9fe --- /dev/null +++ b/src/common/common/bitvalue.h @@ -0,0 +1,129 @@ +/*************************************************************************** + * Copyright (C) 2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 BITVALUE_H +#define BITVALUE_H + +#include "number.h" +#include "range.h" + +//---------------------------------------------------------------------------- +class GenericValue +{ +public: + GenericValue(uint value) : _value(value) {} + + bool operator <(GenericValue v) const { CRASH_ASSERT(_value!=INVALID); return _value<v._value; } + bool operator >(GenericValue v) const { CRASH_ASSERT(_value!=INVALID); return _value>v._value; } + bool operator <=(GenericValue v) const { CRASH_ASSERT(_value!=INVALID); return _value<=v._value; } + bool operator >=(GenericValue v) const { CRASH_ASSERT(_value!=INVALID); return _value>=v._value; } + bool operator ==(GenericValue v) const { return _value==v._value; } + bool operator !=(GenericValue v) const { return _value!=v._value; } + + bool bit(uint index) const { return (_value >> index) & 0x1; } + uchar nybble(uint index) const { return (_value >> (4*index)) & 0xF; } + uchar byte(uint index) const { return (_value >> (8*index)) & 0xFF; } + uint toUInt() const { return _value; } + +protected: + static const uint INVALID; + uint _value; + +private: + friend QDataStream &operator <<(QDataStream &s, GenericValue v); + friend QDataStream &operator >>(QDataStream &s, GenericValue &v); +}; + +inline QDataStream &operator <<(QDataStream &s, GenericValue v) { s << v._value; return s; } +inline QDataStream &operator >>(QDataStream &s, GenericValue &v) { s >> v._value; return s; } + +inline QString toLabel(GenericValue v) { return QString::number(v.toUInt()); } +inline QString toLabel(NumberBase base, GenericValue v, uint nbChars) { return toLabel(base, v.toUInt(), nbChars); } +inline QString toHexLabel(GenericValue v, uint nbChars) { return toHexLabel(v.toUInt(), nbChars); } +inline QString toHex(GenericValue v, uint nbChars) { return toHex(v.toUInt(), nbChars); } +inline QString toHexLabelAbs(GenericValue v) { return ::toHexLabelAbs(v.toUInt()); } + +//---------------------------------------------------------------------------- +class Address : public GenericValue +{ +public: + Address(uint value = INVALID) : GenericValue(value) {} + bool isValid() const { return ( _value!=INVALID ); } + + Address &operator ++() { CRASH_ASSERT(_value!=INVALID); _value++; return *this; } + Address &operator ++(int) { CRASH_ASSERT(_value!=INVALID); _value++; return *this; } + Address operator +(int dec) const { CRASH_ASSERT(_value!=INVALID); return _value + dec; } + Address &operator +=(int dec) { CRASH_ASSERT(_value!=INVALID);_value += dec; return *this; } + Address &operator --() { CRASH_ASSERT(_value!=INVALID); _value--; return *this; } + Address &operator --(int) { CRASH_ASSERT(_value!=INVALID); _value--; return *this; } + Address operator -(int dec) const { CRASH_ASSERT(_value!=INVALID);return _value - dec; } + Address &operator -=(int dec) { CRASH_ASSERT(_value!=INVALID);_value -= dec; return *this; } + int operator -(Address a) const { CRASH_ASSERT(_value!=INVALID && a._value!=INVALID); return _value - a._value; } +}; + +class AddressRange : public GenericRange<Address> +{ +public: + AddressRange() {} + AddressRange(Address s, Address e) { start = s; end = e; } + virtual bool isEmpty() const { return !start.isValid() || !end.isValid() || end<=start; } +}; + +typedef GenericRangeVector<Address, AddressRange> AddressRangeVector; + +//---------------------------------------------------------------------------- +class BitValue : public GenericValue +{ +public: + BitValue(uint value = INVALID) : GenericValue(value) {} + bool isInitialized() const { return ( _value!=INVALID ); } + + BitValue operator |(BitValue v) const { return _value | v._value; } + BitValue operator <<(uint shift) const { return _value << shift; } + BitValue operator >>(uint shift) const { return _value >> shift; } + BitValue operator +(BitValue v) const { return _value + v._value; } + + BitValue &operator |=(BitValue v) { _value |= v._value; return *this; } + BitValue &operator <<=(uint shift) { _value <<= shift; return *this; } + BitValue &operator >>=(uint shift) { _value >>= shift; return *this; } + BitValue &operator +=(BitValue v) { _value += v._value; return *this; } + + BitValue XORn(uint n) const; // XOR between groups of n bits inside value + BitValue XNORn(uint n) const; // XORn then NOT on n bits + + BitValue maskWith(BitValue mask) const { return _value & mask._value; } + bool isInside(BitValue v) const { return ( (_value & v._value)==_value ); } + BitValue complementInMask(BitValue mask) const { return mask._value & ~_value; } + BitValue twoComplement() const { return -_value; } + BitValue clearMaskBits(BitValue mask) const { return _value & ~mask._value; } + bool isOverlapping(BitValue v) const { return ( _value & v._value ); } + + class const_iterator { + public: + const_iterator() {} + bool operator !=(const_iterator it) const { return ( _current!=it._current ); } + BitValue operator *() const { return BitValue(_current); } + const_iterator &operator ++() { + do { + if ( _current==_value+1 ) _current = INVALID; + if ( _current==INVALID ) break; + _current++; + } while ( (_current & _value)!=_current ); + return *this; + } + private: + const_iterator(uint value, uint current) : _value(value), _current(current) {} + uint _value, _current; + friend class BitValue; + }; + const_iterator begin() const { return const_iterator(_value, 0); } + const_iterator end() const { return const_iterator(_value, INVALID); } + +}; + +#endif diff --git a/src/common/common/common.pro b/src/common/common/common.pro new file mode 100644 index 0000000..3451c92 --- /dev/null +++ b/src/common/common/common.pro @@ -0,0 +1,6 @@ +STOPDIR = ../../.. +include($${STOPDIR}/lib.pro) + +TARGET = common +HEADERS += qflags.h misc.h group.h storage.h synchronous.h purl_base.h number.h bitvalue.h key_enum.h version_data.h +SOURCES += misc.cpp group.cpp storage.cpp synchronous.cpp purl_base.cpp number.cpp bitvalue.cpp version_data.cpp diff --git a/src/common/common/group.cpp b/src/common/common/group.cpp new file mode 100644 index 0000000..2a0610f --- /dev/null +++ b/src/common/common/group.cpp @@ -0,0 +1,71 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 "group.h" + +//----------------------------------------------------------------------------- +const Group::Support::Data Group::Support::DATA[Nb_Types] = { + { "not_supported", I18N_NOOP("Not Supported") }, + { "untested", I18N_NOOP("Untested") }, + { "tested", I18N_NOOP("Tested") } +}; + +Group::Base::Base() + : _gui(0), _initialized(false) +{} + +Group::Base::ConstIterator Group::Base::begin() const +{ + const_cast<Base &>(*this).checkInitSupported(); + return _devices.begin(); +} + +Group::Base::ConstIterator Group::Base::end() const +{ + const_cast<Base &>(*this).checkInitSupported(); + return _devices.end(); +} + +void Group::Base::addDevice(const QString &name, const Device::Data *data, Support support) +{ + _devices[name].data = data; + _devices[name].support = support; +} + +Group::Base::Data Group::Base::deviceData(const QString &device) const +{ + const_cast<Base &>(*this).checkInitSupported(); + return _devices[device]; +} + +QValueVector<QString> Group::Base::supportedDevices() const +{ + const_cast<Base &>(*this).checkInitSupported(); + QValueVector<QString> names; + for (ConstIterator it=begin(); it!=end(); ++it) names.append(it.key()); + return names; +} + +uint Group::Base::count() const +{ + const_cast<Base &>(*this).checkInitSupported(); + return _devices.count(); +} + +void Group::Base::init() +{ + _initialized = false; +} + +void Group::Base::checkInitSupported() +{ + if (_initialized) return; + _initialized = true; + _devices.clear(); + initSupported(); +} diff --git a/src/common/common/group.h b/src/common/common/group.h new file mode 100644 index 0000000..2a87674 --- /dev/null +++ b/src/common/common/group.h @@ -0,0 +1,82 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 GROUP_H +#define GROUP_H + +#include <qstringlist.h> +#include <qmap.h> + +#include "common/global/global.h" +#include "key_enum.h" +namespace Device { class Data; } + +namespace Group +{ +//----------------------------------------------------------------------------- +class BaseGui; +BEGIN_DECLARE_ENUM(Support) + None = 0, Untested, Tested +END_DECLARE_ENUM_STD(Support) + +//----------------------------------------------------------------------------- +class Base +{ +public: + class Data { + public: + Data() : data(0), support(Support::None) {} + const Device::Data *data; + Support support; + }; + typedef QMap<QString, Data>::ConstIterator ConstIterator; + + Base(); + virtual ~Base() {} + virtual QString name() const = 0; + virtual QString label() const = 0; + ConstIterator begin() const; + ConstIterator end() const; + Data deviceData(const QString &device) const; + bool isSupported(const QString &device) const { return deviceData(device).support!=Support::None; } + QValueVector<QString> supportedDevices() const; + uint count() const; + const BaseGui *gui() const { return _gui; } + void checkInitSupported(); + +protected: + virtual void init(); + virtual void addDevice(const QString &name, const Device::Data *data, Support support); + virtual void initSupported() = 0; + + QMap<QString, Data> _devices; + +private: + const BaseGui *_gui; + bool _initialized; + + template <class GroupType> friend class Lister; +}; + +//----------------------------------------------------------------------------- +class BaseGui +{ +public: + BaseGui() : _group(0) {} + virtual ~BaseGui() {} + const Base &group() const { return *_group; } + +private: + const Base *_group; + + template <class GroupType> friend class Lister; +}; + +} // namespace + +#endif diff --git a/src/common/common/key_enum.h b/src/common/common/key_enum.h new file mode 100644 index 0000000..504ca56 --- /dev/null +++ b/src/common/common/key_enum.h @@ -0,0 +1,107 @@ +/*************************************************************************** + * Copyright (C) 2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 KEY_ENUM_H +#define KEY_ENUM_H + +#include <qdatastream.h> + +#include "misc.h" +#include "common/global/global.h" + +class GenericEnum +{ +public: + GenericEnum(uint value) : _value(value) {} + bool operator ==(GenericEnum e) const { return _value==e._value; } + bool operator !=(GenericEnum e) const { return _value!=e._value; } + bool operator <(GenericEnum e) const { return _value<e._value; } + bool operator <=(GenericEnum e) const { return _value<=e._value; } + bool operator >(GenericEnum e) const { return _value>e._value; } + bool operator >=(GenericEnum e) const { return _value>=e._value; } + GenericEnum &operator ++() { _value++; return *this; } + +protected: + uint _value; + +private: + friend QDataStream &operator >>(QDataStream &s, GenericEnum &e); + friend QDataStream &operator <<(QDataStream &s, const GenericEnum &e); +}; + +inline QDataStream &operator <<(QDataStream &s, const GenericEnum &e) +{ + s << e._value; + return s; +} +inline QDataStream &operator >>(QDataStream &s, GenericEnum &e) +{ + s >> e._value; + return s; +} + +#define BEGIN_DECLARE_ENUM(Enum) \ +class Enum : public GenericEnum \ +{ \ +public: \ + enum Type { + +#define DECLARE_DATA \ +public: \ + static Type fromKey(const QString &key) { \ + for (uint i=0; i<Nb_Types; i++) \ + if ( key==DATA[i].key ) return Type(i); \ + return Type(Nb_Types); \ + } \ + const Data &data() const { \ + CRASH_ASSERT( _value!=Nb_Types ); \ + return DATA[_value]; \ + } \ + const char *key() const { \ + if ( _value==Nb_Types ) return 0; \ + Q_ASSERT(DATA[_value].key); \ + return DATA[_value].key; \ + } \ + QString label() const { \ + CRASH_ASSERT( _value!=Nb_Types ); \ + Q_ASSERT(DATA[_value].label); \ + return i18n(DATA[_value].label); \ + } \ + private: \ + static const Data DATA[Nb_Types]; \ + +#define DECLARE_ENUM_CLASS(Enum) \ +public: \ + Enum(Type value = Type(0)) : GenericEnum(value) { Q_ASSERT( value>=0 && value<=Type(Nb_Types)); } \ + Type type() const { return Type(_value); } \ +}; + +#define END_DECLARE_ENUM(Enum, EnumData) \ + , Nb_Types \ + }; \ + typedef EnumData Data; \ + DECLARE_DATA \ + DECLARE_ENUM_CLASS(Enum) \ + +#define END_DECLARE_ENUM_STD(Enum) \ + , Nb_Types \ + }; \ + struct Data { \ + const char *key, *label; \ + }; \ + DECLARE_DATA \ + DECLARE_ENUM_CLASS(Enum) + +#define END_DECLARE_ENUM_NO_DATA(Enum) \ + , Nb_Types \ + }; \ + DECLARE_ENUM_CLASS(Enum) + +#define FOR_EACH(Enum, e) for(Enum e; e<Enum::Type(Enum::Nb_Types); ++e) + +#endif diff --git a/src/common/common/lister.h b/src/common/common/lister.h new file mode 100644 index 0000000..35413e8 --- /dev/null +++ b/src/common/common/lister.h @@ -0,0 +1,71 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 LISTER_H +#define LISTER_H + +#include "group.h" + +namespace Group +{ +//----------------------------------------------------------------------------- +template <class GroupType> +class Lister +{ +public: + typedef typename QMap<QString, const GroupType *>::ConstIterator ConstIterator; + ConstIterator begin() const { return ConstIterator(_groups.begin()); } + ConstIterator end() const { return ConstIterator(_groups.end()); } + + virtual ~Lister() { + for (ConstIterator it=begin(); it!=end(); ++it) delete it.data(); + } + + QValueVector<QString> supportedDevices() const { + QValueVector<QString> names; + for (ConstIterator it=begin(); it!=end(); ++it) { + QValueVector<QString> gnames = it.data()->supportedDevices(); + for (uint k=0; k<uint(gnames.count()); k++) names.append(gnames[k]); + } + return names; + } + + uint count() const { + uint nb = 0; + for (ConstIterator it=begin(); it!=end(); ++it) nb += it.data()->count(); + return nb; + } + + bool isSupported(const QString &device) const { + for (ConstIterator it=begin(); it!=end(); ++it) + if ( it.data()->isSupported(device) ) return true; + return false; + } + + const GroupType *group(const QString &name) const { + if ( _groups.contains(name) ) return _groups[name]; + return 0; + } + +protected: + void addGroup(GroupType *group, BaseGui *gui) { + Q_ASSERT(group); + group->_gui = gui; + if (gui) gui->_group = group; + group->init(); + Q_ASSERT( !_groups.contains(group->name()) ); + _groups.insert(group->name(), group); + } + +private: + QMap<QString, const GroupType *> _groups; +}; + +} // namespace + +#endif diff --git a/src/common/common/misc.cpp b/src/common/common/misc.cpp new file mode 100644 index 0000000..1974024 --- /dev/null +++ b/src/common/common/misc.cpp @@ -0,0 +1,72 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 "misc.h" + +#include <unistd.h> + +#include <qregexp.h> +#include <qtimer.h> + +#include "number.h" + +//----------------------------------------------------------------------------- +uchar bin2bcd(uchar bin) +{ + char h = bin / 10; + char l = bin % 10; + return (h*16) + l; +} + +uchar bcd2bin(uchar bcd) +{ + char h = bcd / 16; + char l = bcd % 16; + return (h*10) + l; +} + +QString escapeXml(const QString &cs) +{ + QString s; + for (uint i=0; i<uint(cs.length()); i++) { + if ( cs[i]=='<' ) s += "<"; + else if ( cs[i]=='>' ) s += ">"; + else s += cs[i]; + } + return s; +} + +QString htmlTableRow(const QString &title, const QString &value) +{ + return "<tr><td>" + title + ":</td><td>" + value + "</td></tr>"; +} + +void crash(const char *assert, const char *file, int line) +{ + qDebug("CRASH_ASSERT: \"%s\" in %s (%d)", assert, file, line); + int * ptr = 0; + (*ptr)++; +} + +bool checkAvailable(const QByteArray &data, uint offset, uint nbBytes) +{ + return ( offset+nbBytes<=uint(data.size()) ); +} + +Q_UINT32 getULong(const QByteArray &data, uint offset, uint nbBytes, bool *ok) +{ + Q_ASSERT( nbBytes<=8 ); + if ( !checkAvailable(data, offset, nbBytes) ) { + if (ok) *ok = false; + return 0; + } + if (ok) *ok = true; + Q_UINT32 r = 0; + for (uint i=0; i<nbBytes; i++) r += Q_UINT8(data[offset+i]) << (8*i); + return r; +} diff --git a/src/common/common/misc.h b/src/common/common/misc.h new file mode 100644 index 0000000..f8f92f6 --- /dev/null +++ b/src/common/common/misc.h @@ -0,0 +1,39 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 MISC_H +#define MISC_H + +#include <qstring.h> + +inline QString repeat(const char *r, uint nb) +{ + QString s; + for (uint i=0; i<nb; i++) s += r; + return s; +} + +inline QString stripEndingWhiteSpaces(const QString &s) { + int k = s.length()-1; + for (; k>=0; k--) if ( s[k]!=' ' ) break; + return s.mid(0, k+1); +} + +extern uchar bin2bcd(uchar bin); +extern uchar bcd2bin(uchar bcd); +inline bool XOR(bool b1, bool b2) { return ( (!b1 && b2) || (b1 && !b2) ); } + +extern bool checkAvailable(const QByteArray &data, uint offset, uint nbBytes); +extern Q_UINT32 getULong(const QByteArray &data, uint offset, uint nbBytes, bool *ok); + +extern QString escapeXml(const QString &s); +extern QString htmlTableRow(const QString &title, const QString &value); +extern void crash(const char *assert, const char *file, int line); +#define CRASH_ASSERT(x) ((x) ? void(0) : crash(#x, __FILE__, __LINE__)) + +#endif diff --git a/src/common/common/number.cpp b/src/common/common/number.cpp new file mode 100644 index 0000000..12fcac0 --- /dev/null +++ b/src/common/common/number.cpp @@ -0,0 +1,201 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 "number.h" + +#include "common/global/global.h" +#include "misc.h" +#if !defined(NO_KDE) +# include <kglobal.h> +#endif + +//----------------------------------------------------------------------------- +const NumberBase::Data NumberBase::DATA[Nb_Types] = { + { 10, "", I18N_NOOP("Decimal"), "dec" }, + { 16, "0x", I18N_NOOP("Hexadecimal"), "hex" }, + { 2, "0b", I18N_NOOP("Binary"), "bin" }, + { 8, "o", I18N_NOOP("Octal"), "oct" }, + { 256, "", I18N_NOOP("String"), "str" } +}; + +char toChar(NumberBase base, uint value) +{ + Q_ASSERT( value<base.data().base ); + if ( value>=base.data().base ) qDebug("toChar %u (%u)", value, base.data().base); + if ( base==NumberBase::String ) { + if ( !isprint(value) ) return '.'; + return value; + } + if ( value<=9 ) return '0' + value; + return 'A' + value - 10; +} + +QString toString(NumberBase base, ulong value, uint nbChars) +{ + ulong tmp = value; + QString s; + s.fill(0, nbChars); + for (uint i=0; i<nbChars; i++) { + s[nbChars-i-1] = toChar(base, uint(value % base.data().base)); + value /= base.data().base; + } + Q_ASSERT( value==0 ); + if ( value!=0 ) qDebug("toString %s nbChars=%u", toLabel(base, tmp, ::nbChars(base, tmp)).latin1(), nbChars); + return s; +} + +QString toLabel(NumberBase base, ulong value, uint nbChars) +{ + if ( base==NumberBase::String ) return "\'" + toString(base, value, nbChars) + "\'"; + return base.data().prefix + toString(base, value, nbChars); +} + +uint nbChars(NumberBase base, ulong value) +{ + uint nb = 1; + for (;;) { + value /= base.data().base; + if ( value==0 ) break; + nb++; + } + return nb; +} + +ulong maxValue(NumberBase base, uint nbChars) +{ + uint v = 1; + for (uint i=0; i<nbChars; i++) v *= base.data().base; + return v - 1; +} + +ulong fromString(NumberBase base, const QCString &s, bool *ok) +{ + return fromString(base, s.data(), s.length(), ok); +} +ulong fromString(NumberBase base, const QString &s, bool *ok) +{ +#if QT_VERSION<0x040000 + return fromString(base, s.latin1(), s.length(), ok); +#else + QByteArray a = s.toLatin1(); + return fromString(base, a.data(), a.count(), ok); +#endif +} + +ulong fromLabel(NumberBase base, const QString &s, bool *ok) +{ +#if QT_VERSION<0x040000 + return fromLabel(base, s.latin1(), s.length(), ok); +#else + QByteArray a = s.toLatin1(); + return fromLabel(base, a.data(), a.count(), ok); +#endif +} + +ulong fromLabel(NumberBase base, const QString &s, uint nbChars, bool *ok) +{ + if ( uint(s.length())!=nbChars+strlen(base.data().prefix) ) { + if (ok) *ok = false; + return 0; + } + return fromLabel(base, s, ok); +} + +ulong fromLabel(NumberBase base, const char *s, uint size, bool *ok) +{ + if (ok) *ok = false; + if ( s==0 ) return 0; + uint psize = (base==NumberBase::String ? 1 : strlen(base.data().prefix)); + uint ssize = (base==NumberBase::String ? 1 : 0); + if ( size<=(psize+ssize) ) return 0; + if ( base==NumberBase::String ) { + if ( s[0]=='"' ) { + if ( s[size-1]!='"' ) return 0; + } else if ( s[0]=='\'' ) { + if ( s[size-1]!='\'' ) return 0; + } else return 0; + } else for (uint i=0; i<psize; i++) if ( s[i]!=base.data().prefix[i] ) return 0; + return fromString(base, s+psize, size-psize-ssize, ok); +} + +ulong fromAnyLabel(const QString &s, bool *ok) +{ + uint v = 0; + bool bok = false; + FOR_EACH(NumberBase, base) { + v = fromLabel(base, s.lower(), &bok); + if (bok) break; + } + if ( !bok ) v = fromString(NumberBase::Dec, s, &bok); + if ( !bok ) { + if (ok) *ok = false; + return 0; + } + if (ok) *ok = true; + return v; +} + +uint fromChar(NumberBase base, char c, bool *ok) +{ + uint v = 0; + if ( base==NumberBase::String ) { + if (ok) *ok = true; + return c; + } + if ( c>='0' && c<='9' ) v = c - '0'; + else if ( c>='A' && c<'Z' ) v = 10 + c - 'A'; + else if ( c>='a' && c<'z' ) v = 10 + c - 'a'; + else { + if (ok) *ok = false; + return 0; + } + if (ok) *ok = ( v<base.data().base ); + return v; +} + +ulong fromString(NumberBase base, const char *s, uint size, bool *ok) +{ + if (ok) *ok = false; + if ( s==0 || size==0 ) return 0; + ulong v = 0; + for (uint i=0; i<size; i++) { + v *= base.data().base; + bool bok; + v += fromChar(base, s[i], &bok); + if ( !bok ) return 0; + } + if (ok) *ok = true; + return v; +} + +QString toLabels(NumberBase base, const QMemArray<uint> &values, uint nbChars) +{ + QString s = "["; + for (uint i=0; i<values.count(); i++) { + if ( i!=0 ) s += ' '; + s += toLabel(base, values[i], nbChars); + } + s += "]"; + return s; +} + +QString formatNumber(ulong v) +{ +#if defined(NO_KDE) + return QString::number(v); +#else + return KGlobal::locale()->formatNumber(v, 0); +#endif +} + +QByteArray toAscii(const QString &s) +{ + QByteArray a(s.length()); + for (uint i=0; i<uint(s.length()); i++) a[i] = s[i].latin1(); + return a; +} diff --git a/src/common/common/number.h b/src/common/common/number.h new file mode 100644 index 0000000..f4dae79 --- /dev/null +++ b/src/common/common/number.h @@ -0,0 +1,92 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 NUMBER_H +#define NUMBER_H + +#include <ctype.h> + +#include "common/global/global.h" +#include "key_enum.h" + +//---------------------------------------------------------------------------- +struct NumberBaseData { + uint base; + const char *prefix, *label,* key; +}; + +BEGIN_DECLARE_ENUM(NumberBase) + Dec = 0, Hex, Bin, Oct, String +END_DECLARE_ENUM(NumberBase, NumberBaseData) + +extern uint nbChars(NumberBase base, ulong value); +extern ulong maxValue(NumberBase base, uint nbChars); +inline uint convertNbChars(uint nb, NumberBase from, NumberBase to) { return nbChars(to, maxValue(from, nb)); } + +extern char toChar(NumberBase base, uint value); +extern QString toString(NumberBase base, ulong value, uint nbChars); +extern QString toLabel(NumberBase base, ulong value, uint nbChars); +extern QString toLabels(NumberBase base, const QMemArray<ulong> &values, uint nbChars); + +extern uint fromChar(NumberBase base, char c, bool *ok); +extern ulong fromString(NumberBase base, const char *s, uint size, bool *ok); +extern ulong fromString(NumberBase base, const QString &s, bool *ok); +extern ulong fromLabel(NumberBase base, const QString &s, bool *ok); +extern ulong fromLabel(NumberBase base, const QString &s, uint nbChars, bool *ok); +extern ulong fromLabel(NumberBase base, const char *s, uint size, bool *ok); + +extern ulong fromAnyLabel(const QString &s, bool *ok); + +//---------------------------------------------------------------------------- +inline QString toHex(ulong value, uint nbChars) { return toString(NumberBase::Hex, value, nbChars); } +inline QString toHexLabel(ulong value, uint nbChars) { return toLabel(NumberBase::Hex, value, nbChars); } +inline QString toHexLabelAbs(ulong value) { return toLabel(NumberBase::Hex, value, nbChars(NumberBase::Hex, value)); } + +inline uint fromHex(char c, bool *ok) { return fromChar(NumberBase::Hex, c, ok); } +inline uint fromHex(QChar c, bool *ok) { return fromChar(NumberBase::Hex, c.latin1(), ok); } +inline ulong fromHex(const char *s, uint size, bool *ok) { return fromString(NumberBase::Hex, s, size, ok); } +inline ulong fromHex(const QString &s, bool *ok) { return fromString(NumberBase::Hex, s, ok); } +inline ulong fromHexLabel(const QString &s, bool *ok) { return fromLabel(NumberBase::Hex, s, ok); } +inline ulong fromHexLabel(const QString &s, uint nbChars, bool *ok) { return fromLabel(NumberBase::Hex, s, nbChars, ok); } +inline ulong fromHexLabel(const char *s, uint size, bool *ok) { return fromLabel(NumberBase::Hex, s, size, ok); } + +//---------------------------------------------------------------------------- +inline uint nbBits(ulong value) { return nbChars(NumberBase::Bin, value); } +inline uint nbBitsToNbChars(uint nbBits) { return nbBits/4 + (nbBits%4 ? 1 : 0); } +inline uint nbBitsToNbBytes(uint nbBits) { return nbBits/8 + (nbBits%8 ? 1 : 0); } +inline uint nbChars(ulong value) { return nbBitsToNbChars(nbBits(value)); } +inline uint nbBytes(ulong value) { return nbBitsToNbBytes(nbBits(value)); } + +//---------------------------------------------------------------------------- +extern QString formatNumber(ulong v); +extern QByteArray toAscii(const QString &s); + +//---------------------------------------------------------------------------- +enum PrintMode { PrintAlphaNum, PrintEscapeAll }; +inline QString toPrintable(char c, PrintMode mode) +{ + if ( mode==PrintAlphaNum && isalnum(c) ) return QChar(c); + return "\\" + toHex(uchar(c), 2); +} +inline QString toPrintable(const char *data, uint size, PrintMode mode) +{ + QString s; + for (uint i=0; i<size; i++) s += toPrintable(data[i], mode); + return s; +} +inline QString toPrintable(const QString &s, PrintMode mode) +{ + QByteArray a = toAscii(s); + return toPrintable(a.data(), a.count(), mode); +} +inline QString toPrintable(const QMemArray<uchar> &data, PrintMode mode) +{ + return toPrintable((const char *)data.data(), data.size(), mode); +} + +#endif diff --git a/src/common/common/purl_base.cpp b/src/common/common/purl_base.cpp new file mode 100644 index 0000000..2493322 --- /dev/null +++ b/src/common/common/purl_base.cpp @@ -0,0 +1,133 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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_base.h" + +#include "common/global/global.h" +#include <qfileinfo.h> + +#include "data/xpms/project.xpm" +#include "data/xpms/sourcefile.xpm" +#include "data/xpms/includefile.xpm" +#include "data/xpms/objectfile.xpm" + +const PURL::ToolType::Data PURL::ToolType::DATA[Nb_Types] = { + { "assembler", I18N_NOOP("Assembler") }, + { "compiler", I18N_NOOP("Compiler") } +}; + +const PURL::SourceFamily::Data PURL::SourceFamily::DATA[Nb_Types] = { + { ToolType::Assembler, "asm", I18N_NOOP("Assembler"), Inc }, + { ToolType::Compiler, "c", I18N_NOOP("C Compiler"), CHeader }, + { ToolType::Compiler, "jal", I18N_NOOP("JAL Compiler"), Nb_FileTypes }, + { ToolType::Compiler, "cpp", I18N_NOOP("C++ Compiler"), CHeader }, + { ToolType::Compiler, "basic", I18N_NOOP("Basic Compiler"), Nb_FileTypes } +}; + +const PURL::FileType::Data PURL::FileType::DATA[Nb_Types] = { + { "AsmGPAsm", Source, Editable, SourceFamily::Asm, I18N_NOOP("Assembler File"), { "asm", "src", "pic", 0 }, sourcefile_xpm, 0, "XPicAsm" }, + { "AsmPIC30", Source, Editable, SourceFamily::Asm, I18N_NOOP("Assembler File for PIC30"), { "s", 0 }, sourcefile_xpm, 0, "XPicAsm" }, + { "AsmPICC", Source, Editable, SourceFamily::Asm, I18N_NOOP("Assembler File for PICC"), { "as", 0 }, sourcefile_xpm, 0, "XPicAsm" }, + { "Inc", Header, Editable, SourceFamily::Asm, I18N_NOOP("Include File"), { "inc", 0 }, includefile_xpm, 0, "XPicAsm" }, + { "CSource", Source, Editable, SourceFamily::C, I18N_NOOP("C Source File"), { "c", 0 }, 0, "text/x-csrc", "C" }, + { "CppSource", Source, Editable, SourceFamily::C, I18N_NOOP("C++ Source File"), { "cpp", "cxx", 0 }, 0, "text/x-c++src", "C++" }, + { "CHeader", Header, Editable, SourceFamily::C, I18N_NOOP("C Header File"), { "h", 0 }, 0, "text/x-chdr", "C" }, + { "JalSource", Source, Editable, SourceFamily::JAL, I18N_NOOP("JAL File"), { "jal", 0}, sourcefile_xpm, 0, "XPicJal" }, + { "BasicSource", Source, Editable, SourceFamily::Basic, I18N_NOOP("Basic Source File"), { "bas", 0 }, sourcefile_xpm, 0, "FreeBASIC" }, + + { "Object", LinkerObject, Editable | ReadOnly, SourceFamily::Nb_Types, I18N_NOOP("Object File"), { "o", "obj", 0 }, objectfile_xpm, 0, 0 }, + { "Library", LinkerObject, Editable | ReadOnly, SourceFamily::Nb_Types, I18N_NOOP("Library File"), { "a", "lib", 0 }, objectfile_xpm, 0, 0 }, + + { "Lkr", LinkerScript, Editable, SourceFamily::Nb_Types, I18N_NOOP("Linker Script"), { "lkr", 0 }, includefile_xpm, 0, 0 }, + { "Gld", LinkerScript, Editable, SourceFamily::Nb_Types, I18N_NOOP("Linker Script for PIC30"), { "gld", 0 }, includefile_xpm, 0, 0 }, + + { "Hex", Nb_FileGroups, Editable, SourceFamily::Nb_Types, I18N_NOOP("Hex File"), { "hex", 0 }, 0, "text/x-hex", 0 }, + { "Elf", Nb_FileGroups, ReadOnly, SourceFamily::Nb_Types, I18N_NOOP("Elf File"), { "elf", 0 }, 0, 0, 0 }, + { "Project", Nb_FileGroups, NoProperty, SourceFamily::Nb_Types, I18N_NOOP("Project File"), { "piklab", 0 }, project_xpm, 0, 0 }, + { "Lst", Nb_FileGroups, Editable | ReadOnly, SourceFamily::Nb_Types, I18N_NOOP("List File"), { "lst", 0 }, 0, "text/plain", 0 }, + { "Map", Nb_FileGroups, Editable | ReadOnly, SourceFamily::Nb_Types, I18N_NOOP("Map File"), { "map", 0 }, 0, "text/plain", 0 }, + { "Cod", Nb_FileGroups, ReadOnly, SourceFamily::Nb_Types, I18N_NOOP("COD File"), { "cod", 0 }, 0, 0, 0 }, + { "Coff", Nb_FileGroups, Editable | ReadOnly, SourceFamily::Nb_Types, I18N_NOOP("COFF File"), { "cof", 0 }, 0, "application/x-object", "XCoffDisasm" }, + + { "", Nb_FileGroups, NoProperty, SourceFamily::Nb_Types, I18N_NOOP("Unknown File"), { 0 }, 0, 0, 0 }, + { "", Nb_FileGroups, NoProperty, SourceFamily::Nb_Types, I18N_NOOP("Pikdev Project File"), { "pikprj", 0 }, 0, 0, 0 } +}; + +QString PURL::addExtension(const QString &filename, FileType type) +{ + QFileInfo info(filename); + if ( !info.extension().isEmpty() ) return filename; + return filename + '.' + extension(type); +} + +QString PURL::extension(FileType type) +{ + return type.data().extensions[0]; +} + +QString PURL::extensions(FileType type) +{ + Q_ASSERT( type!=PURL::Nb_FileTypes ); + QString s; + for (uint i=0; type.data().extensions[i]; i++) { + if ( i!=0 ) s += ' '; + s += QString("*.") + type.data().extensions[i]; + } + return s; +} + +QString PURL::filter(FileType type) +{ + //if ( hasMimetype(type) ) return DATA[type].mimetype; // #### we cannot mix mimetype and regular filters in KFileDialog... + QString s = extensions(type); + return s + ' ' + s.upper() + '|' + type.label() + " (" + s + ")"; +} + +QString PURL::extensions(FileGroup group) +{ + QString e; + FOR_EACH(FileType, type) { + if ( type.data().group!=group ) continue; + if ( type!=FileType::Type(0) ) e += ' '; + QString s = extensions(type); + e += s + ' ' + s.upper(); + } + return e; +} + +QString PURL::sourceFilter(FilterType type) +{ + QString f = extensions(Source) + ' ' + extensions(Header) + '|' + i18n("All Source Files"); + if ( type==CompleteFilter) { + FOR_EACH(FileType, type) { + if ( !(type.data().properties & (Source | Header)) ) continue; + f += '\n' + filter(type); + } + } + return f; +} + +QString PURL::objectFilter(FilterType type) +{ + QString f = extensions(Object) + ' ' + extensions(Library) + '|' + i18n("All Object Files"); + if ( type==CompleteFilter ) { + f += '\n' + filter(Object); + f += '\n' + filter(Library); + } + return f; +} + +QString PURL::projectFilter(FilterType type) +{ + QString f = extensions(Project) + ' ' + extensions(PikdevProject) + '|' + i18n("Project Files"); + if ( type==CompleteFilter ) { + f += '\n' + filter(Project); + f += '\n' + filter(PikdevProject); + } + return f; +} diff --git a/src/common/common/purl_base.h b/src/common/common/purl_base.h new file mode 100644 index 0000000..7a7e4ea --- /dev/null +++ b/src/common/common/purl_base.h @@ -0,0 +1,79 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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_BASE_H +#define PURL_BASE_H + +#include "common/global/global.h" +#include "common/common/key_enum.h" + +//---------------------------------------------------------------------------- +namespace PURL +{ +BEGIN_DECLARE_ENUM(ToolType) + Assembler = 0, Compiler +END_DECLARE_ENUM_STD(ToolType) + +enum FileTypeEnum { + AsmGPAsm = 0, AsmPIC30, AsmPICC, Inc, CSource, CppSource, CHeader, JalSource, BasicSource, + Object, Library, Lkr, Gld, Hex, Elf, Project, Lst, Map, Cod, Coff, + Unknown, PikdevProject, + Nb_FileTypes +}; + +struct SourceFamilyData { + ToolType toolType; + const char *key, *label; + FileTypeEnum headerType; +}; +BEGIN_DECLARE_ENUM(SourceFamily) + Asm = 0, C, JAL, Cpp, Basic +END_DECLARE_ENUM(SourceFamily, SourceFamilyData) + +enum FileGroup { Source = 0, Header, LinkerScript, LinkerObject, Nb_FileGroups }; + +enum FileProperty { NoProperty = 0, Editable = 1, ReadOnly = 2 }; +Q_DECLARE_FLAGS(FileProperties, FileProperty) +Q_DECLARE_OPERATORS_FOR_FLAGS(FileProperties) + +struct FileTypeData { + const char *key; + FileGroup group; + FileProperties properties; + SourceFamily sourceFamily; + const char *label; + const char *extensions[10]; + const char **xpm_icon; + const char *mimetype; + const char *highlightModeName; +}; +#ifndef Q_MOC_RUN // needed because MOC does not expand defines... +class FileType : public GenericEnum +{ +public: + typedef FileTypeEnum Type; + enum { Nb_Types = Nb_FileTypes }; + typedef FileTypeData Data; +DECLARE_DATA +DECLARE_ENUM_CLASS(FileType) +#endif + +// add correct extension if filename has no extension +extern QString addExtension(const QString &filename, FileType type); +extern QString extension(FileType type); +extern QString extensions(FileType type); +extern QString filter(FileType type); +enum FilterType { SimpleFilter, CompleteFilter }; +extern QString sourceFilter(FilterType type); +extern QString objectFilter(FilterType type); +extern QString projectFilter(FilterType type); +extern QString extensions(FileGroup group); + +} // namespace + +#endif diff --git a/src/common/common/qflags.h b/src/common/common/qflags.h new file mode 100644 index 0000000..4858ce4 --- /dev/null +++ b/src/common/common/qflags.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2005 Trolltech AS. All rights reserved. +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ +#ifndef QFLAGS_H +#define QFLAGS_H + +#include <qglobal.h> + +class QFlag +{ + int i; +public: + inline QFlag(int i); + inline operator int() const { return i; } +}; + +inline QFlag::QFlag(int ai) : i(ai) {} + +template<typename Enum> +class QFlags +{ + typedef void **Zero; + int i; +public: + typedef Enum enum_type; + inline QFlags(const QFlags &f) : i(f.i) {} + inline QFlags(Enum f) : i(f) {} + inline QFlags(Zero = 0) : i(0) {} + inline QFlags(QFlag f) : i(f) {} + + inline QFlags &operator=(const QFlags &f) { i = f.i; return *this; } + inline QFlags &operator&=(int mask) { i &= mask; return *this; } + inline QFlags &operator&=(uint mask) { i &= mask; return *this; } + inline QFlags &operator|=(QFlags f) { i |= f.i; return *this; } + inline QFlags &operator|=(Enum f) { i |= f; return *this; } + inline QFlags &operator^=(QFlags f) { i ^= f.i; return *this; } + inline QFlags &operator^=(Enum f) { i ^= f; return *this; } + + + inline operator int() const { return i;} + + inline QFlags operator|(QFlags f) const { QFlags g; g.i = i | f.i; return g; } + inline QFlags operator|(Enum f) const { QFlags g; g.i = i | f; return g; } + inline QFlags operator^(QFlags f) const { QFlags g; g.i = i ^ f.i; return g; } + inline QFlags operator^(Enum f) const { QFlags g; g.i = i ^ f; return g; } + inline QFlags operator&(int mask) const { QFlags g; g.i = i & mask; return g; } + inline QFlags operator&(uint mask) const { QFlags g; g.i = i & mask; return g; } + inline QFlags operator&(Enum f) const { QFlags g; g.i = i & f; return g; } + inline QFlags operator~() const { QFlags g; g.i = ~i; return g; } + + inline bool operator!() const { return !i; } +}; + +#define Q_DECLARE_FLAGS(Flags, Enum)\ +typedef QFlags<Enum> Flags; +#define Q_DECLARE_OPERATORS_FOR_FLAGS(Flags) \ +inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, Flags::enum_type f2) \ +{ return QFlags<Flags::enum_type>(f1) | f2; } \ +inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, QFlags<Flags::enum_type> f2) \ +{ return f2 | f1; } + +#endif diff --git a/src/common/common/range.h b/src/common/common/range.h new file mode 100644 index 0000000..e07cb68 --- /dev/null +++ b/src/common/common/range.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 RANGE_H +#define RANGE_H + +#include "common/global/global.h" + +//----------------------------------------------------------------------------- +template <typename Type> +class GenericRange +{ +public: + virtual ~GenericRange() {} + virtual bool isEmpty() const = 0; + bool contains(Type v) const { return !isEmpty() && v>=start && v<=end; } + + Type start, end; +}; + +class Range : public GenericRange<uint> +{ +public: + Range() { start = 0; end = 0; } + Range(uint s, uint e) { start = s; end = e; } + virtual bool isEmpty() const { return end<=start; } +}; + +template <typename Type> +inline QDataStream &operator >>(QDataStream &s, GenericRange<Type> &r) { s >> r.start >> r.end; return s; } +template <typename Type> +inline QDataStream &operator <<(QDataStream &s, const GenericRange<Type> &r) { s << r.start << r.end; return s; } +template <typename Type> +inline bool operator ==(const GenericRange<Type> &r1, const GenericRange<Type> &r2) { return ( r1.start==r2.start && r1.end==r2.end ); } + +template <typename Type, typename RangeType> +class GenericRangeVector : public QValueVector<RangeType> +{ +public: + GenericRangeVector() {} + GenericRangeVector(const RangeType &range) { append(range); } + bool isEmpty() const { + uint nb = this->count(); + for (uint i=0; i<nb; i++) if ( !this->at(i).isEmpty() ) return false; + return true; + } + bool contains(Type v) const { + uint nb = this->count(); + for (uint i=0; i<nb; i++) if ( this->at(i).contains(v) ) return true; + return false; + } +}; + +typedef GenericRangeVector<uint, Range> RangeVector; + +#endif diff --git a/src/common/common/storage.cpp b/src/common/common/storage.cpp new file mode 100644 index 0000000..00137b8 --- /dev/null +++ b/src/common/common/storage.cpp @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 "storage.h" + +#include <qtimer.h> + +//---------------------------------------------------------------------------- +void GenericStorage::delayedChanged() +{ + if (_dirty) return; + _dirty = true; + QTimer::singleShot(0, this, SLOT(changedSlot())); +} + +void GenericStorage::changedSlot() +{ + _dirty = false; + emit changed(); +} + +//---------------------------------------------------------------------------- +void GenericViewProxy::addStorage(GenericStorage &storage) +{ + connect(&storage, SIGNAL(changed()), SLOT(changed())); +} + +void GenericViewProxy::changed() +{ + _view.updateView(); +} + +GenericView::GenericView(GenericStorage &storage) +{ + _proxy = new GenericViewProxy(*this); + _proxy->addStorage(storage); +} diff --git a/src/common/common/storage.h b/src/common/common/storage.h new file mode 100644 index 0000000..b61123a --- /dev/null +++ b/src/common/common/storage.h @@ -0,0 +1,85 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 STORAGE_H +#define STORAGE_H + +#include "common/global/global.h" +#include <qobject.h> + +//----------------------------------------------------------------------------- +template <class Type> +class Fifo +{ +public: + Fifo() {} + void clear() { _list.clear(); } + uint count() const { return _list.count(); } + void put(Type type) { _list.append(type); } + Type get() { + Type t = _list.first(); + _list.pop_front(); + return t; + } + +private: + QValueList<Type> _list; +}; + +//---------------------------------------------------------------------------- +class GenericStorage : public QObject +{ +Q_OBJECT +public: + GenericStorage(QObject *parent = 0, const char *name = 0) : QObject(parent, name), _dirty(false) {} + +signals: + void changed(); + +protected: + // emit changed() only after a return to the GUI loop and only one time + void delayedChanged(); + +private slots: + void changedSlot(); + +private: + bool _dirty; +}; + +//---------------------------------------------------------------------------- +class GenericView; + +class GenericViewProxy : public QObject +{ +Q_OBJECT +public: + GenericViewProxy(GenericView &view) : _view(view) {} + void addStorage(GenericStorage &storage); + +private slots: + void changed(); + +private: + GenericView &_view; +}; + +class GenericView +{ +public: + GenericView(GenericStorage &storage); + virtual ~GenericView() { delete _proxy; } + virtual void updateView() = 0; + +private: + GenericViewProxy *_proxy; + + friend class GenericViewProxy; +}; + +#endif diff --git a/src/common/common/streamer.h b/src/common/common/streamer.h new file mode 100644 index 0000000..93d1421 --- /dev/null +++ b/src/common/common/streamer.h @@ -0,0 +1,59 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 STREAMER_H +#define STREAMER_H + +#include <qdatastream.h> +#include <qtextstream.h> + +#include "common/global/global.h" +#include "common/common/number.h" + +template <class DataType> +class DataStreamer +{ +public: + uint toCppString(const QValueList<DataType *> &list, QTextStream &s) { + QByteArray a; +#if QT_VERSION<0x040000 + QDataStream ds(a, IO_WriteOnly); +#else + QDataStream ds(&a, QIODevice::WriteOnly); +#endif + for (uint i=0; i<uint(list.count()); i++) ds << *list[i]; + s << "\""; + for (uint i=0; i<uint(a.count()); i++) { + if ( i!=0 && (i%40)==0 ) s << "\"" << endl << "\""; + s << "\\x" << toChar(NumberBase::Hex, uchar(a[i])/16) << toChar(NumberBase::Hex, uchar(a[i])%16); + } + s << "\""; + return a.count(); + } + + QValueList<DataType *> fromCppString(const char *data, uint size) { + QByteArray a; + a.setRawData(data, size); +#if QT_VERSION<0x040000 + QDataStream ds(a, IO_ReadOnly); +#else + QDataStream ds(&a, QIODevice::ReadOnly); +#endif + QValueList<DataType *> list; + for (;;) { + if ( ds.atEnd() ) break; + DataType *data = new DataType; + ds >> *data; + list.append(data); + } + a.resetRawData(data, size); + return list; + } +}; + +#endif diff --git a/src/common/common/synchronous.cpp b/src/common/common/synchronous.cpp new file mode 100644 index 0000000..f392103 --- /dev/null +++ b/src/common/common/synchronous.cpp @@ -0,0 +1,58 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 "synchronous.h" + +#include "common/global/global.h" +#if QT_VERSION<0x040000 +# include <qwidget.h> +#endif + +Synchronous::Synchronous(uint timeout) +{ + connect(&_timer, SIGNAL(timeout()), SLOT(done())); + if (timeout) _timer.start(timeout, true); +#if QT_VERSION>=0x040000 + _loop = new QEventLoop(this); +#endif +} + +#if QT_VERSION<0x040000 +// uplifted from kdelibs... +void qt_enter_modal(QWidget *widget); +void qt_leave_modal(QWidget *widget); +#endif + +bool Synchronous::enterLoop() +{ +#if QT_VERSION<0x040000 + QWidget *dummy = 0; + if ( qApp->type()!=QApplication::Tty ) { + dummy = new QWidget(0, 0, WType_Dialog | WShowModal); + dummy->setFocusPolicy(QWidget::NoFocus); + qt_enter_modal(dummy); + } + QApplication::eventLoop()->enterLoop(); + if ( qApp->type()!=QApplication::Tty ) { + qt_leave_modal(dummy); + delete dummy; + } +#else + _loop->exec(); +#endif + return _timer.isActive(); +} + +void Synchronous::done() +{ +#if QT_VERSION<0x040000 + QApplication::eventLoop()->exitLoop(); +#else + _loop->exit(); +#endif +} diff --git a/src/common/common/synchronous.h b/src/common/common/synchronous.h new file mode 100644 index 0000000..e855e38 --- /dev/null +++ b/src/common/common/synchronous.h @@ -0,0 +1,32 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 SYNCHRONOUS_H +#define SYNCHRONOUS_H + +#include <qtimer.h> +#include <qeventloop.h> + +class Synchronous : public QObject +{ +Q_OBJECT +public: + Synchronous(uint timeout = 0); // timeout is ms (0 == no timeout) + bool enterLoop(); // return false on timeout + +public slots: + void done(); + +private: + QTimer _timer; +#if QT_VERSION>=0x040000 + QEventLoop *_loop; +#endif +}; + +#endif diff --git a/src/common/common/version_data.cpp b/src/common/common/version_data.cpp new file mode 100644 index 0000000..481ba1a --- /dev/null +++ b/src/common/common/version_data.cpp @@ -0,0 +1,55 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 "version_data.h" + +#include <qregexp.h> + +#include "number.h" + +VersionData VersionData::fromString(const QString &s) +{ + VersionData vd; + QRegExp re("([0-9]+)\\.([0-9]+)\\.([0-9]+)(.*)"); + if ( !re.exactMatch(s) ) return vd; + vd._valid = true; + vd._majorNum = re.cap(1).toUInt(); + vd._minorNum = re.cap(2).toUInt(); + vd._dotNum = re.cap(3).toUInt(); + vd._sub = re.cap(4); + return vd; +} + +VersionData VersionData::fromHexString(const QString &s) +{ + VersionData vd; + if ( s.length()!=6 ) return vd; + vd._valid = true; + vd._majorNum = ::fromString(NumberBase::Hex, s.mid(0, 2), 0); + vd._minorNum = ::fromString(NumberBase::Hex, s.mid(2, 2), 0); + vd._dotNum = ::fromString(NumberBase::Hex, s.mid(4, 2), 0); + return vd; +} + +QString VersionData::pretty() const +{ + if ( !isValid() ) return "---"; + return QString::number(_majorNum) + '.' + QString::number(_minorNum) + '.' + QString::number(_dotNum) + _sub; +} + +QString VersionData::prettyWithoutDot() const +{ + if ( !isValid() ) return "---"; + return QString::number(_majorNum) + '.' + QString::number(_minorNum); +} + +uint VersionData::toUInt() const +{ + Q_ASSERT(_valid); + return (_majorNum << 16) | (_minorNum << 8) | _dotNum; +} diff --git a/src/common/common/version_data.h b/src/common/common/version_data.h new file mode 100644 index 0000000..2571631 --- /dev/null +++ b/src/common/common/version_data.h @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 VERSION_DATA_H +#define VERSION_DATA_H + +#include "common/global/global.h" + +class VersionData +{ +public: + static VersionData fromString(const QString &s); + static VersionData fromHexString(const QString &s); + +public: + VersionData() : _valid(false) {} + VersionData(uchar majorNum, uchar minorNum, uchar dotNum) + : _valid(true), _majorNum(majorNum), _minorNum(minorNum), _dotNum(dotNum) {} + bool isValid() const { return _valid; } + void clear() { _valid = false; } + uchar majorNum() const { return _majorNum; } + uchar minorNum() const { return _minorNum; } + uchar dotNum() const { return _dotNum; } + QString sub() const { return _sub; } + VersionData toWithoutDot() const { return VersionData(_majorNum, _minorNum, 0); } + QString pretty() const; + QString prettyWithoutDot() const; + uint toUInt() const; + bool operator <(const VersionData &vd) const { return toUInt()<vd.toUInt(); } + bool operator <=(const VersionData &vd) const { return toUInt()<=vd.toUInt(); } + bool operator >(const VersionData &vd) const { return toUInt()>vd.toUInt(); } + bool operator >=(const VersionData &vd) const { return toUInt()>=vd.toUInt(); } + bool operator ==(const VersionData &vd) const { return toUInt()==vd.toUInt(); } + bool operator !=(const VersionData &vd) const { return toUInt()!=vd.toUInt(); } + +private: + bool _valid; + uchar _majorNum, _minorNum, _dotNum; + QString _sub; +}; + +#endif 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 <hadacek@kde.org> * + * * + * 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."), "hadacek@kde.org"); + addAuthor("Alain Gibaud", I18N_NOOP("Original author of PiKdev."), "alain.gibaud@free.fr"); + addAuthor("Stephen Landamore", I18N_NOOP("LPLAB author (original microchip programmer support)."), "webmaster@landamore.com"); + addAuthor("Craig Franklin", I18N_NOOP("Author of gputils"), "craigfranklin@users.sourceforge.net"); + addAuthor("Sébastien Laoût", I18N_NOOP("Author of likeback"), "slaout@linux62.org"); + + addCredit("Brian C. Lane", I18N_NOOP("Original code for direct programming."), 0); + addCredit("Manwlis \"Manos\" Giannos", I18N_NOOP("Direct programming for PIC18F devices."), "mgiannos2000@yahoo.gr"); + addCredit("Sean A. Walberg", I18N_NOOP("Direct programming for 16F676/630."), "sean@ertw.com"); + addCredit("Mirko Panciri", I18N_NOOP("Support for direct programmers with bidirectionnal buffers."), "mirko.panciri@adept.it"); + addCredit("Keith Baker", I18N_NOOP("Direct programming for 16F73/74/76/77."), "susyzygy@pubnix.org" ); + addCredit("Lorenz Möenlechner and Matthias Kranz", I18N_NOOP("USB support for ICD2 programmer."), "icd2linux@hcilab.org"); + addCredit("Xiaofan Chen", I18N_NOOP("Test of PICkit2 and ICD2 programmer."), "xiaofanc@gmail.com"); + addCredit("Homer Reid", I18N_NOOP("Direct programming for dsPICs is inspired from his program \"dspicprg\"."), "homer@homerreid.com"); + addCredit("Frank Damgaard", I18N_NOOP("Direct programming for 24C EEPROM is inspired from his program \"prog84\"."), "frda@post3.tele.dk"); +} 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 <hadacek@kde.org> * + * * + * 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 <hadacek@kde.org> * + * * + * 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 <hadacek@kde.org> * + * * + * 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 <hadacek@kde.org> * + * * + * 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 <hadacek@kde.org> * + * * + * 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 <hadacek@kde.org> * + * * + * 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 <hadacek@kde.org> * + * * + * 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 <hadacek@kde.org> * + * * + * 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 <hadacek@kde.org> * + * * + * 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 <hadacek@kde.org> * + * * + * 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 <hadacek@kde.org> * + * * + * 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 <hadacek@kde.org> * + * * + * 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 <hadacek@kde.org> * + * * + * 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 <hadacek@kde.org> * + * * + * 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 <hadacek@kde.org> * + * * + * 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 <hadacek@kde.org> * + * * + * 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 diff --git a/src/common/gui/Makefile.am b/src/common/gui/Makefile.am new file mode 100644 index 0000000..c4bb948 --- /dev/null +++ b/src/common/gui/Makefile.am @@ -0,0 +1,7 @@ +INCLUDES = -I$(top_srcdir)/src $(all_includes) +METASOURCES = AUTO +libcommonui_la_LDFLAGS = $(all_libraries) +noinst_LTLIBRARIES = libcommonui.la +libcommonui_la_SOURCES = container.cpp dialog.cpp editlistbox.cpp \ + hexword_gui.cpp list_view.cpp misc_gui.cpp number_gui.cpp pfile_ext.cpp purl_ext.cpp \ + purl_gui.cpp list_container.cpp diff --git a/src/common/gui/config_widget.h b/src/common/gui/config_widget.h new file mode 100644 index 0000000..abfafab --- /dev/null +++ b/src/common/gui/config_widget.h @@ -0,0 +1,107 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2004 Alain Gibaud <alain.gibaud@free.fr> * + * * + * 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 CONFIG_WIDGET_H +#define CONFIG_WIDGET_H + +#include <qpixmap.h> +#include <qcheckbox.h> +#include <qvaluevector.h> +#include <qvariant.h> + +#include "container.h" + +//----------------------------------------------------------------------------- +class ConfigWidget : public Container +{ +Q_OBJECT +public: + ConfigWidget(QWidget *parent = 0) : Container(parent) {} + virtual QString title() const { return QString::null; } + virtual QString header() const { return QString::null; } + virtual QPixmap pixmap() const { return QPixmap(); } + +public slots: + virtual void loadConfig() = 0; + virtual void saveConfig() = 0; +}; + +//----------------------------------------------------------------------------- +template <typename Type> +class BaseConfigWidget +{ +public: + BaseConfigWidget(ConfigWidget *widget) { + _widgets.resize(Type::Nb_Types); + for(Type type; type<Type::Nb_Types; ++type) _widgets[type.type()] = createWidget(type, widget); + } + void loadConfig() { + for(Type type; type<Type::Nb_Types; ++type) load(type, _widgets[type.type()]); + } + void saveConfig() { + for(Type type; type<Type::Nb_Types; ++type) save(type, _widgets[type.type()]); + } + void setDefault() { + for(Type type; type<Type::Nb_Types; ++type) setDefault(type, _widgets[type.type()]); + } + +private: + QValueVector<QWidget *> _widgets; + + static QWidget *createWidget(Type type, ConfigWidget *widget) { + QWidget *w = 0; + uint row = widget->numRows(); + switch (type.data().defValue.type()) { + case QVariant::Bool: + w = new QCheckBox(type.label(), widget); + widget->addWidget(w, row,row, 0,1); + break; + default: Q_ASSERT(false); break; + } + return w; + } + void load(Type type, QWidget *widget) const { + switch (type.data().defValue.type()) { + case QVariant::Bool: + static_cast<QCheckBox *>(widget)->setChecked(readConfigEntry(type).toBool()); + break; + default: Q_ASSERT(false); break; + } + } + void save(Type type, QWidget *widget) { + switch (type.data().defValue.type()) { + case QVariant::Bool: + writeConfigEntry(type, QVariant(static_cast<QCheckBox *>(widget)->isChecked(), 0)); + break; + default: Q_ASSERT(false); break; + } + } + void setDefault(Type type, QWidget *widget) const { + switch (type.data().defValue.type()) { + case QVariant::Bool: + static_cast<QCheckBox *>(widget)->setChecked(type.data().defValue.toBool()); + break; + default: Q_ASSERT(false); break; + } + } +}; + +//----------------------------------------------------------------------------- +#define BEGIN_DECLARE_CONFIG_WIDGET(ConfigType, ConfigWidgetType) \ +class ConfigWidgetType : public ::ConfigWidget, public BaseConfigWidget<ConfigType> \ +{ \ +public: \ + ConfigWidgetType() : BaseConfigWidget<ConfigType>(this) {} \ + virtual void loadConfig() { BaseConfigWidget<ConfigType>::loadConfig(); } \ + virtual void saveConfig() { BaseConfigWidget<ConfigType>::saveConfig(); } \ + +#define END_DECLARE_CONFIG_WIDGET \ +}; + +#endif diff --git a/src/common/gui/container.cpp b/src/common/gui/container.cpp new file mode 100644 index 0000000..881e265 --- /dev/null +++ b/src/common/gui/container.cpp @@ -0,0 +1,80 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 "container.h" + +#include "misc_gui.h" + +//---------------------------------------------------------------------------- +Container::Container(QWidget *parent, Type type) + : QFrame(parent), _type(type) +{ + initLayout(); +} + +Container::Container(QWidgetStack *stack, uint index, Type type) + : QFrame(stack), _type(type) +{ + initLayout(); + stack->addWidget(this, index); +} + +Container::Container(QTabWidget *tabw, const QString &title, Type type) + : QFrame(tabw), _type(type) +{ + initLayout(); + tabw->addTab(this, title); +} + +void Container::setFrame(Type type) +{ + _type = type; + switch (type) { + case Flat: + setMargin(parent() && parent()->inherits("QTabWidget") ? 10 : 0); + setFrameStyle(QFrame::NoFrame); + break; + case Sunken: + setMargin(10); + setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); + break; + } +} + +void Container::initLayout() +{ + _topLayout = new QGridLayout(this, 1, 1, 0, 10); + _gridLayout = new QGridLayout(1, 1, 10); + _topLayout->addLayout(_gridLayout, 0, 0); + _topLayout->setRowStretch(1, 1); + setFrame(_type); +} + +void Container::addWidget(QWidget *w, uint startRow, uint endRow, uint startCol, uint endCol, int alignment) +{ + Q_ASSERT( startRow<=endRow ); + Q_ASSERT( startCol<=endCol ); + w->show(); + _gridLayout->addMultiCellWidget(w, startRow, endRow, startCol, endCol, alignment); +} + +void Container::addLayout(QLayout *l, uint startRow, uint endRow, uint startCol, uint endCol, int alignment) +{ + Q_ASSERT( startRow<=endRow ); + Q_ASSERT( startCol<=endCol ); + _gridLayout->addMultiCellLayout(l, startRow, endRow, startCol, endCol, alignment); +} + +//---------------------------------------------------------------------------- +ButtonContainer::ButtonContainer(const QString &title, QWidget *parent) + : Container(parent, Sunken) +{ + _button = new PopupButton(title, this); + addWidget(_button, 0,0, 0,1); + setColStretch(2, 1); +} diff --git a/src/common/gui/container.h b/src/common/gui/container.h new file mode 100644 index 0000000..d718c6f --- /dev/null +++ b/src/common/gui/container.h @@ -0,0 +1,58 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 CONTAINER_H +#define CONTAINER_H + +#include <qframe.h> +#include <qwidgetstack.h> +#include <qtabwidget.h> +#include <qlayout.h> + +class PopupButton; + +//---------------------------------------------------------------------------- +class Container : public QFrame +{ +Q_OBJECT +public: + enum Type { Flat, Sunken }; + Container(QWidget *parent = 0, Type type = Flat); + Container(QWidgetStack *stack, uint index, Type type = Flat); + Container(QTabWidget *tabw, const QString &title, Type type = Flat); + void addWidget(QWidget *widget, uint startRow, uint endRow, uint startCol, uint endCol, int alignment = 0); + void addLayout(QLayout *layout, uint startRow, uint endRow, uint startCol, uint endCol, int alignment = 0); + uint numRows() const { return _gridLayout->numRows(); } + uint numCols() const { return _gridLayout->numCols(); } + void setFrame(Type type); + void setMargin(uint margin) { _topLayout->setMargin(margin); } + void setRowSpacing(uint row, uint spacing) { _gridLayout->setRowSpacing(row, spacing); } + void setColSpacing(uint col, uint spacing) { _gridLayout->setColSpacing(col, spacing); } + void setRowStretch(uint row, uint stretch) { _gridLayout->setRowStretch(row, stretch); } + void setColStretch(uint col, uint stretch) { _gridLayout->setColStretch(col, stretch); } + +private: + Type _type; + QGridLayout *_topLayout, *_gridLayout; + + void initLayout(); +}; + +//---------------------------------------------------------------------------- +class ButtonContainer : public Container +{ +Q_OBJECT +public: + ButtonContainer(const QString &title, QWidget *parent); + PopupButton &button() { return *_button; } + +private: + PopupButton *_button; +}; + +#endif diff --git a/src/common/gui/dialog.cpp b/src/common/gui/dialog.cpp new file mode 100644 index 0000000..650b086 --- /dev/null +++ b/src/common/gui/dialog.cpp @@ -0,0 +1,199 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 "dialog.h" + +#include <qheader.h> +#include <qtimer.h> +#include <qlabel.h> +#include <qwidgetstack.h> +#include <ktextedit.h> + +#include "misc_gui.h" + +//----------------------------------------------------------------------------- +Dialog::Dialog(QWidget *parent, const char *name, bool modal, + const QString &caption, int buttonMask, ButtonCode defaultButton, + bool separator, const QSize &defaultSize) + : KDialogBase(parent, name, modal, caption, buttonMask, defaultButton, separator), + _defaultSize(defaultSize) +{ + BusyCursor::start(); + Q_ASSERT(name); + QWidget *main = new QWidget(this); + setMainWidget(main); + + QTimer::singleShot(0, this, SLOT(updateSize())); +} + +Dialog::Dialog(DialogType type, const QString &caption, int buttonMask, ButtonCode defaultButton, + QWidget *parent, const char *name, bool modal, bool separator, const QSize &defaultSize) + : KDialogBase(type, caption, buttonMask, defaultButton, parent, name, modal, separator), + _defaultSize(defaultSize) +{ + BusyCursor::start(); + Q_ASSERT(name); + QTimer::singleShot(0, this, SLOT(updateSize())); +} + +Dialog::~Dialog() +{ + GuiConfig gc; + gc.writeEntry(QString(name()) + "_size", size()); +} + +void Dialog::updateSize() +{ + GuiConfig gc; + resize(gc.readSizeEntry(QString(name()) + "_size", &_defaultSize)); + BusyCursor::stop(); +} + +//----------------------------------------------------------------------------- +TreeListDialog::Item::Item(const QString &label, QWidget *page, const QString &title, QListView *listview) + : KListViewItem(listview, label), _page(page), _title(title) +{} +TreeListDialog::Item::Item(const QString &label, QWidget *page, const QString &title, QListViewItem *item) + : KListViewItem(item, label), _page(page), _title(title) +{} + +TreeListDialog::TreeListDialog(QWidget *parent, const char *name, bool modal, + const QString &caption, int buttonMask, ButtonCode defaultButton, + bool separator) + : Dialog(parent, name, modal, caption, buttonMask, defaultButton, separator) +{ + QVBoxLayout *top = new QVBoxLayout(mainWidget(), 0, 10); + + // list view + QValueList<int> widths; + widths += 80; + widths += 500; + Splitter *splitter = new Splitter(widths, Horizontal, mainWidget(), name); + top->addWidget(splitter); + _listView = new KListView(splitter); + connect(_listView, SIGNAL(currentChanged(QListViewItem *)), SLOT(currentChanged(QListViewItem *))); + _listView->setAllColumnsShowFocus(true); + _listView->setRootIsDecorated(true); + _listView->setSorting(0); + _listView->addColumn(QString::null); + _listView->header()->hide(); + _listView->setResizeMode(QListView::LastColumn); + + // pages + _frame = new QFrame(splitter); + QVBoxLayout *vbox = new QVBoxLayout(_frame, 10, 10); + _titleBox = new QHBoxLayout(vbox); + _label = new QLabel(_frame); + _titleBox->addWidget(_label); + _stack = new QWidgetStack(_frame); + connect(_stack, SIGNAL(aboutToShow(QWidget *)), SIGNAL(aboutToShowPage(QWidget *))); + vbox->addWidget(_stack); + vbox->addStretch(1); +} + +QWidget *TreeListDialog::addPage(const QStringList &labels) +{ + Q_ASSERT( !labels.isEmpty() ); + + QWidget *page = 0; + QListViewItem *item = 0; + QListViewItemIterator it(_listView); + for (; it.current(); ++it) { + if ( it.current()->text(0)==labels[0] ) { + item = it.current(); + break; + } + } + if ( item==0 ) { + page = new QWidget(_stack); + connect(page, SIGNAL(destroyed(QObject *)), SLOT(pageDestroyed(QObject *))); + _stack->addWidget(page); + item = new Item(labels[0], page, labels[0], _listView); + item->setOpen(true); + bool last = ( labels.count()==1 ); + item->setSelectable(last); + } + for (uint i=1; i<labels.count(); i++) { + QListViewItem *parent = item; + item = 0; + QListViewItemIterator iti(parent); + for (; it.current(); ++it) { + if ( it.current()->text(0)==labels[i] ) { + item = it.current(); + break; + } + } + if ( item==0 ) { + page = new QWidget(_stack); + connect(page, SIGNAL(destroyed(QObject *)), SLOT(pageDestroyed(QObject *))); + _stack->addWidget(page); + item = new Item(labels[i], page, labels[i], parent); + item->setOpen(true); + bool last = ( labels.count()==i+1 ); + item->setSelectable(last); + } + } + + return page; +} + +void TreeListDialog::currentChanged(QListViewItem *lvitem) +{ + if ( lvitem==0 ) return; + Item *item = static_cast<Item *>(lvitem); + _listView->ensureItemVisible(item); + _label->setText(item->_title); + _stack->raiseWidget(item->_page); +} + +void TreeListDialog::showPage(QWidget *page) +{ + QListViewItemIterator it(_listView); + for (; it.current(); ++it) { + Item *item = static_cast<Item *>(it.current()); + if ( item->_page==page ) { + _listView->setCurrentItem(item); + currentChanged(item); + break; + } + } +} + +int TreeListDialog::pageIndex(QWidget *page) const +{ + return _stack->id(page); +} + +int TreeListDialog::activePageIndex() const +{ + const Item *item = static_cast<const Item *>(_listView->currentItem()); + if ( item==0 ) return -1; + return pageIndex(item->_page); +} + +void TreeListDialog::pageDestroyed(QObject *object) +{ + QListViewItemIterator it(_listView); + for (; it.current(); ++it) { + Item *item = static_cast<Item *>(it.current()); + if ( item->_page!=object ) continue; + delete item; + break; + } +} + +//----------------------------------------------------------------------------- +TextEditorDialog::TextEditorDialog(const QString &text, const QString &caption, + bool wrapAtWidgetWidth, QWidget *parent) + : Dialog(parent, "text_editor_dialog", true, caption, Close, Close, false, QSize(200, 100)) +{ + KTextEdit *w = new KTextEdit(text, QString::null, this); + w->setReadOnly(true); + w->setWordWrap(wrapAtWidgetWidth ? QTextEdit::WidgetWidth : QTextEdit::NoWrap); + setMainWidget(w); +} diff --git a/src/common/gui/dialog.h b/src/common/gui/dialog.h new file mode 100644 index 0000000..1227a7d --- /dev/null +++ b/src/common/gui/dialog.h @@ -0,0 +1,77 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 DIALOG_H +#define DIALOG_H + +#include <qlayout.h> +#include <kdialogbase.h> +#include <klistview.h> + +//----------------------------------------------------------------------------- +class Dialog : public KDialogBase +{ +Q_OBJECT +public: + Dialog(QWidget *parent, const char *name, bool modal, + const QString &caption, int buttonMask, ButtonCode defaultButton, bool separator, + const QSize &defaultSize = QSize()); + Dialog(DialogType type, const QString &caption, + int buttonMask, ButtonCode defaultButton, QWidget *parent, const char *name, + bool modal, bool separator, const QSize &defaultSize = QSize()); + virtual ~Dialog(); + +private slots: + void updateSize(); + +private: + QSize _defaultSize; +}; + +//----------------------------------------------------------------------------- +class TreeListDialog : public Dialog +{ +Q_OBJECT +public: + TreeListDialog(QWidget *parent, const char *name, bool modal, + const QString &caption, int buttonMask, ButtonCode defaultButton, bool separator); + QWidget *addPage(const QStringList &labels); + void showPage(QWidget *page); + int activePageIndex() const; + int pageIndex(QWidget *page) const; + +protected slots: + virtual void currentChanged(QListViewItem *item); + void pageDestroyed(QObject *page); + +protected: + QFrame *_frame; + KListView *_listView; + QHBoxLayout *_titleBox; + QLabel *_label; + QWidgetStack *_stack; + + class Item : public KListViewItem { + public: + Item(const QString &label, QWidget *page, const QString &title, QListView *listview); + Item(const QString &label, QWidget *page, const QString &title, QListViewItem *item); + QWidget *_page; + QString _title; + }; +}; + +//----------------------------------------------------------------------------- +class TextEditorDialog : public Dialog +{ +Q_OBJECT +public: + TextEditorDialog(const QString &text, const QString &caption, + bool wrapAtWidgetWidth, QWidget *parent); +}; + +#endif diff --git a/src/common/gui/editlistbox.cpp b/src/common/gui/editlistbox.cpp new file mode 100644 index 0000000..1d2916d --- /dev/null +++ b/src/common/gui/editlistbox.cpp @@ -0,0 +1,340 @@ +/* Copyright (C) 2000 David Faure <faure@kde.org>, Alexander Neundorf <neundorf@kde.org> + 2000, 2002 Carsten Pfeiffer <pfeiffer@kde.org> + Copyright (C) 2006-2007 Nicolas Hadacek <hadacek@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 "editlistbox.h" + +#include <qstringlist.h> +#include <qlabel.h> +#include <qheader.h> + +#include <kdialog.h> +#include <klocale.h> +#include <kapplication.h> +#include <knotifyclient.h> +#include <kiconloader.h> +#include <kstdguiitem.h> + +EditListBox::EditListBox(uint nbColumns, QWidget *parent, const char *name, Mode mode, Buttons buttons) + : QFrame(parent, name), _mode(mode), _buttons(buttons) +{ + m_lineEdit = new KLineEdit; + init(nbColumns, m_lineEdit); +} + +EditListBox::EditListBox(uint nbColumns, QWidget *view, KLineEdit *lineEdit, QWidget *parent, const char *name, + Mode mode, Buttons buttons) + : QFrame(parent, name), _mode(mode), _buttons(buttons) +{ + m_lineEdit = lineEdit; + init(nbColumns, view); +} + +void EditListBox::init(uint nbColumns, QWidget *view) +{ + _addButton = 0; + _removeButton = 0; + _moveUpButton = 0; + _moveDownButton = 0; + _removeAllButton = 0; + _resetButton = 0; + setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding)); + + QGridLayout *grid = new QGridLayout(this, 1, 1, 0, KDialog::spacingHint()); + uint row = 0; + if (view) { + QHBoxLayout *hbox = new QHBoxLayout(KDialog::spacingHint()); + grid->addMultiCellLayout(hbox, row,row, 0,1); + if (m_lineEdit) { + KIconLoader loader; + QIconSet iconset = loader.loadIcon("locationbar_erase", KIcon::Toolbar); + KPushButton *button = new KPushButton(iconset, QString::null, this); + connect(button, SIGNAL(clicked()), SLOT(clearEdit())); + hbox->addWidget(button); + } + view->reparent( this, QPoint(0,0) ); + hbox->addWidget(view); + row++; + } + _listView= new KListView(this); + for (uint i=0; i<nbColumns; i++) _listView->addColumn(QString::null); + _listView->header()->hide(); + _listView->setSorting(-1); + _listView->setResizeMode(KListView::LastColumn); + _listView->setColumnWidthMode(nbColumns-1, KListView::Maximum); + grid->addWidget(_listView, row, 0); + QVBoxLayout *vbox = new QVBoxLayout(10); + grid->addLayout(vbox, row, 1); + _buttonsLayout = new QVBoxLayout(10); + vbox->addLayout(_buttonsLayout); + vbox->addStretch(1); + + setButtons(_buttons); + + if (m_lineEdit) { + connect(m_lineEdit,SIGNAL(textChanged(const QString&)),this,SLOT(typedSomething(const QString&))); + m_lineEdit->setTrapReturnKey(true); + connect(m_lineEdit,SIGNAL(returnPressed()),this,SLOT(addItem())); + } + connect(_listView, SIGNAL(selectionChanged()), SLOT(selectionChanged())); + + // maybe supplied lineedit has some text already + typedSomething(m_lineEdit ? m_lineEdit->text() : QString::null); +} + +void EditListBox::setButtons(Buttons buttons) +{ + _buttons = buttons; + + delete _addButton; + _addButton = 0; + if ( buttons & Add ) { +#if KDE_VERSION < KDE_MAKE_VERSION(3,4,0) + _addButton = new KPushButton(KGuiItem(i18n("Add"), "edit_add"), this); +#else + _addButton = new KPushButton(KStdGuiItem::add(), this); +#endif + _addButton->setEnabled(false); + _addButton->show(); + connect(_addButton, SIGNAL(clicked()), SLOT(addItem())); + _buttonsLayout->addWidget(_addButton); + } + + delete _removeButton; + _removeButton = 0; + if ( buttons & Remove ) { + _removeButton = new KPushButton(KGuiItem(i18n("Remove"), "clear"), this); + _removeButton->setEnabled(false); + _removeButton->show(); + connect(_removeButton, SIGNAL(clicked()), SLOT(removeItem())); + _buttonsLayout->addWidget(_removeButton); + } + + delete _removeAllButton; + _removeAllButton = 0; + if ( buttons & RemoveAll ) { + _removeAllButton = new KPushButton(KGuiItem(i18n("Remove All"), "delete"), this); + _removeAllButton->show(); + connect(_removeAllButton, SIGNAL(clicked()), SLOT(clear())); + _buttonsLayout->addWidget(_removeAllButton); + } + + delete _moveUpButton; + _moveUpButton = 0; + delete _moveDownButton; + _moveDownButton = 0; + if ( buttons & UpDown ) { + _moveUpButton = new KPushButton(KGuiItem(i18n("Move &Up"), "up"), this); + _moveUpButton->setEnabled(false); + _moveUpButton->show(); + connect(_moveUpButton, SIGNAL(clicked()), SLOT(moveItemUp())); + _buttonsLayout->addWidget(_moveUpButton); + _moveDownButton = new KPushButton(KGuiItem(i18n("Move &Down"), "down"), this); + _moveDownButton->setEnabled(false); + _moveDownButton->show(); + connect(_moveDownButton, SIGNAL(clicked()), SLOT(moveItemDown())); + _buttonsLayout->addWidget(_moveDownButton); + } + + delete _resetButton; + _resetButton = 0; + if ( buttons & Reset ) { + _resetButton = new KPushButton(KStdGuiItem::reset(), this); + _resetButton->show(); + connect(_resetButton, SIGNAL(clicked()), SIGNAL(reset())); + _buttonsLayout->addWidget(_resetButton); + } +} + +void EditListBox::typedSomething(const QString& text) +{ + QListViewItem *item = _listView->selectedItem(); + if (item) { + if( selectedText()!=text ) { + item->setText(textColumn(), text); + emit changed(); + } + } + updateButtons(); +} + +void EditListBox::moveItemUp() +{ + QListViewItem *item = _listView->selectedItem(); + if ( item==0 || item->itemAbove()==0 ) return; + item->itemAbove()->moveItem(item); + updateButtons(); + emit changed(); +} + +void EditListBox::moveItemDown() +{ + QListViewItem *item = _listView->selectedItem(); + if ( item==0 || item->itemBelow()==0 ) return; + item->moveItem(item->itemBelow()); + updateButtons(); + emit changed(); +} + +void EditListBox::addItem() +{ + // when m_checkAtEntering is true, the add-button is disabled, but this + // slot can still be called through Key_Return/Key_Enter. So we guard + // against this. + if ( !_addButton || !_addButton->isEnabled() || m_lineEdit==0 ) return; + + addItem(m_lineEdit->text()); +} + +void EditListBox::addItem(const QString &text) +{ + bool alreadyInList(false); + //if we didn't check for dupes at the inserting we have to do it now + if ( _mode==DuplicatesDisallowed ) alreadyInList = _listView->findItem(text, textColumn()); + + if (m_lineEdit) { + bool block = m_lineEdit->signalsBlocked(); + m_lineEdit->blockSignals(true); + m_lineEdit->clear(); + m_lineEdit->blockSignals(block); + } + _listView->clearSelection(); + + if (!alreadyInList) { + QListViewItem *item = createItem(); + item->setText(textColumn(), text); + if ( _listView->lastItem() ) item->moveItem(_listView->lastItem()); + emit changed(); + emit added(text); + } + updateButtons(); +} + +void EditListBox::clearEdit() +{ + _listView->clearSelection(); + if (m_lineEdit) { + m_lineEdit->clear(); + m_lineEdit->setFocus(); + } + updateButtons(); +} + +void EditListBox::removeItem() +{ + QListViewItem *item = _listView->selectedItem(); + if (item) { + QString text = item->text(textColumn()); + delete item; + emit changed(); + emit removed(text); + updateButtons(); + } +} + +void EditListBox::selectionChanged() +{ + if (m_lineEdit) m_lineEdit->setText(selectedText()); + updateButtons(); +} + +void EditListBox::clear() +{ + _listView->clear(); + if (m_lineEdit) { + m_lineEdit->clear(); + m_lineEdit->setFocus(); + } + updateButtons(); + emit changed(); +} + +uint EditListBox::count() const +{ + uint nb = 0; + QListViewItemIterator it(_listView); + for (; it.current(); ++it) nb++; + return nb; +} + +const QListViewItem *EditListBox::item(uint i) const +{ + uint k = 0; + QListViewItemIterator it(_listView); + for (; it.current(); ++it) { + if ( k==i ) return it.current(); + k++; + } + return 0; +} + +QStringList EditListBox::texts() const +{ + QStringList list; + QListViewItemIterator it(_listView); + for (; it.current(); ++it) list.append(it.current()->text(textColumn())); + return list; +} + +void EditListBox::setTexts(const QStringList& items) +{ + _listView->clear(); + for (int i=items.count()-1; i>=0; i--) { + QListViewItem *item = createItem(); + item->setText(textColumn(), items[i]); + } + if (m_lineEdit) m_lineEdit->clear(); + updateButtons(); +} + +void EditListBox::updateButtons() +{ + QListViewItem *item = _listView->selectedItem(); + if (_addButton) { + if ( m_lineEdit==0 ) _addButton->setEnabled(true); + else { + QString text = m_lineEdit->text(); + if ( _mode!=DuplicatesCheckedAtEntering ) _addButton->setEnabled(!text.isEmpty()); + else if ( text.isEmpty() ) _addButton->setEnabled(false); + else _addButton->setEnabled(!_listView->findItem(text, textColumn())); + } + } + if (_removeButton) _removeButton->setEnabled(item); + if (_moveUpButton) _moveUpButton->setEnabled(item && item->itemAbove()); + if (_moveDownButton) _moveDownButton->setEnabled(item && item->itemBelow()); + if (_removeAllButton) _removeAllButton->setEnabled(_listView->firstChild()); +} + +void EditListBox::setEditText(const QString &text) +{ + _listView->clearSelection(); + if (m_lineEdit) m_lineEdit->setText(text); + updateButtons(); +} + +QListViewItem *EditListBox::createItem() +{ + return new KListViewItem(_listView); +} + +QString EditListBox::selectedText() const +{ + QListViewItem *item = _listView->selectedItem(); + if ( item==0 ) return QString::null; + return item->text(textColumn()); +} diff --git a/src/common/gui/editlistbox.h b/src/common/gui/editlistbox.h new file mode 100644 index 0000000..c259278 --- /dev/null +++ b/src/common/gui/editlistbox.h @@ -0,0 +1,95 @@ +/* Copyright (C) 2000 David Faure <faure@kde.org>, Alexander Neundorf <neundorf@kde.org> + Copyright (C) 2006-2007 Nicolas Hadacek <hadacek@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 EDITLISTBOX_H +#define EDITLISTBOX_H + +#include <qlayout.h> +#include <klineedit.h> +#include <kpushbutton.h> +#include <klistview.h> + +#include "common/common/qflags.h" + +//---------------------------------------------------------------------------- +// modified KEditListBox (beyond recognition) +// * support for duplicated items +// * use KStdGuiItem for buttons +// * support for New, Clear, Reset buttons +// * use KListView +class EditListBox : public QFrame +{ +Q_OBJECT + public: + enum Mode { DuplicatesDisallowed, DuplicatesAllowed, DuplicatesCheckedAtEntering }; + enum Button { Add = 1, Remove = 2, UpDown = 4, RemoveAll = 8, Reset = 16 }; + Q_DECLARE_FLAGS(Buttons, Button) + + EditListBox(uint nbColumns, QWidget *parent = 0, const char *name = 0, Mode mode = DuplicatesDisallowed, + Buttons buttons = Buttons(Add|Remove|RemoveAll|UpDown) ); + EditListBox(uint nbColumns, QWidget *view, KLineEdit *lineEdit, QWidget *parent = 0, const char *name = 0, + Mode mode = DuplicatesDisallowed, Buttons buttons = Buttons(Add|Remove|RemoveAll|UpDown) ); + void setTexts(const QStringList& items); + QStringList texts() const; + uint count() const; + QString text(uint i) const { return item(i)->text(textColumn()); } + const QListViewItem *item(uint i) const; + Buttons buttons() const { return _buttons; } + void setButtons(Buttons buttons); + void setEditText(const QString &text); + void addItem(const QString &text); + + signals: + void reset(); + void changed(); + void added( const QString & text ); + void removed( const QString & text ); + + public slots: + void clear(); + + protected slots: + virtual void moveItemUp(); + virtual void moveItemDown(); + virtual void clearEdit(); + virtual void addItem(); + virtual void removeItem(); + void selectionChanged(); + void typedSomething(const QString& text); + + protected: + KListView *_listView; + + virtual QListViewItem *createItem(); + virtual uint textColumn() const { return 0; } + QString selectedText() const; + + private: + Mode _mode; + Buttons _buttons; + QVBoxLayout *_buttonsLayout; + KLineEdit *m_lineEdit; + KPushButton *_addButton, *_removeButton, *_moveUpButton, *_moveDownButton, + *_removeAllButton, *_resetButton; + + void init(uint nbColumns, QWidget *view); + void updateButtons(); +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(EditListBox::Buttons) + +#endif diff --git a/src/common/gui/hexword_gui.cpp b/src/common/gui/hexword_gui.cpp new file mode 100644 index 0000000..d794a11 --- /dev/null +++ b/src/common/gui/hexword_gui.cpp @@ -0,0 +1,136 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003-2004 Alain Gibaud <alain.gibaud@free.fr> * + * * + * 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 "hexword_gui.h" + +#include <qtimer.h> + +#include "common/gui/number_gui.h" +#include "common/common/misc.h" + +//----------------------------------------------------------------------------- +HexValueValidator::HexValueValidator(uint nbChars, QObject *parent) + : QValidator(parent, "hex_value_validator"), _nbChars(nbChars) {} + +QValidator::State HexValueValidator::validate(QString &input, int &) const +{ + if ( input.length()==0 ) return Acceptable; + if ( input.length()>_nbChars ) return Invalid; + for (uint i=0; i<input.length(); i++) + if ( !isxdigit(input[i].latin1()) && input[i]!='-' ) return Invalid; + return Acceptable; +} + +//----------------------------------------------------------------------------- +GenericHexWordEditor::GenericHexWordEditor(uint nbChars, bool hasBlankValue, QWidget *parent) + : KLineEdit(parent, "hex_word_editor"), _nbChars(nbChars), _hasBlankValue(hasBlankValue) +{ + setFocusPolicy(ClickFocus); + setValidator(new HexValueValidator(nbChars, this)); + connect(this, SIGNAL(textChanged(const QString &)), SLOT(slotTextChanged())); + setFrame(false); +} + +void GenericHexWordEditor::slotTextChanged() +{ + if ( text().length()!=_nbChars ) return; + if ( changeValue() ) emit moveNext(); +} + +bool GenericHexWordEditor::changeValue() +{ + if ( !isValid() ) return false; + QString s = text(); + BitValue v = blankValue(); + if ( s!=QString(repeat("-", _nbChars)) ) { + s = s.leftJustify(_nbChars, '0', true); + for (uint i=0; i<_nbChars; i++) + if ( !isxdigit(s[i].latin1()) ) s[i] = '0'; + v = normalizeWord(fromHex(s, 0)); + setText(toHex(v, _nbChars)); + } + if ( v==word() ) return false; + setWord(v); + emit modified(); + return true; +} + +void GenericHexWordEditor::set() +{ + blockSignals(true); + setEnabled(isValid()); + if ( !isValid() ) clear(); + else { + BitValue value = word(); + if ( _hasBlankValue && value==blankValue() ) setText(repeat("-", _nbChars)); + else setText(toHex(normalizeWord(value), _nbChars)); + } + blockSignals(false); +} + +bool GenericHexWordEditor::event(QEvent *e) +{ + switch (e->type()) { + case QEvent::FocusOut: + changeValue(); + break; + case QEvent::FocusIn: + QTimer::singleShot(0, this, SLOT(selectAll())); // ugly but it works + break; + case QEvent::KeyPress: + switch ( static_cast<QKeyEvent *>(e)->key() ) { + case Key_Next: + emit moveNextPage(); + return true; + case Key_Tab: + case Key_Enter: + case Key_Return: + emit moveNext(); + return true; + case Key_Prior: + emit movePrevPage(); + return true; + case Key_BackTab: + emit movePrev(); + return true; + case Key_Down: + emit moveDown(); + return true; + case Key_Up: + emit moveUp(); + return true; + case Key_Home: + emit moveFirst(); + return true; + case Key_End: + emit moveLast(); + return true; + case Key_Right: + if ( cursorPosition()!=int(text().length()) ) break; + emit moveNext(); + return true; + case Key_Left: + if ( cursorPosition()!=0 ) break; + emit movePrev(); + return true; + } + default: break; + } + return QLineEdit::event(e); +} + +QSize GenericHexWordEditor::sizeHint() const +{ + return QSize(maxCharWidth(NumberBase::Hex, font()) * (_nbChars+1), fontMetrics().height()); +} + +QSize GenericHexWordEditor::minimumSizeHint() const +{ + return QSize(maxCharWidth(NumberBase::Hex, font()) * (_nbChars+1), fontMetrics().height()); +} diff --git a/src/common/gui/hexword_gui.h b/src/common/gui/hexword_gui.h new file mode 100644 index 0000000..5da6840 --- /dev/null +++ b/src/common/gui/hexword_gui.h @@ -0,0 +1,88 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003-2004 Alain Gibaud <alain.gibaud@free.fr> * + * * + * 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 HEXWORD_GUI_H +#define HEXWORD_GUI_H + +#include <qvalidator.h> +#include <klineedit.h> + +#include "common/common/bitvalue.h" + +//----------------------------------------------------------------------------- +class HexValueValidator : public QValidator +{ +Q_OBJECT +public: + HexValueValidator(uint nbChars, QObject *parent); + virtual State validate(QString &input, int &pos) const; + +private: + uint _nbChars; +}; + +//----------------------------------------------------------------------------- +class GenericHexWordEditor : public KLineEdit +{ +Q_OBJECT +public: + GenericHexWordEditor(uint nbChars, bool hasBlankValue, QWidget *parent); + virtual QSize sizeHint() const; + virtual QSize minimumSizeHint() const; + +signals: + void modified(); + void moveNext(); + void movePrev(); + void moveUp(); + void moveDown(); + void moveFirst(); + void moveLast(); + void moveNextPage(); + void movePrevPage(); + +private slots: + bool changeValue(); + void slotTextChanged(); + +protected: + uint _nbChars; + bool _hasBlankValue; + + virtual bool isValid() const = 0; + virtual BitValue mask() const = 0; + virtual BitValue normalizeWord(BitValue value) const = 0; + virtual bool event(QEvent *e); + virtual void set(); + virtual BitValue word() const = 0; + virtual void setWord(BitValue value) = 0; + virtual BitValue blankValue() const = 0; +}; + +//----------------------------------------------------------------------------- +class HexWordEditor : public GenericHexWordEditor +{ +Q_OBJECT +public: + HexWordEditor(uint nbChars, QWidget *parent) : GenericHexWordEditor(nbChars, false, parent) {} + void setValue(BitValue word) { _word = word; set(); } + BitValue value() const { return _word; } + +protected: + BitValue _word; + + virtual bool isValid() const { return true; } + virtual BitValue mask() const { return maxValue(NumberBase::Hex, _nbChars); } + virtual BitValue normalizeWord(BitValue value) const { return value.maskWith(mask()); } + virtual BitValue word() const { return _word; } + virtual void setWord(BitValue value) { _word = value; } + virtual BitValue blankValue() const { return 0; } +}; + +#endif diff --git a/src/common/gui/key_gui.h b/src/common/gui/key_gui.h new file mode 100644 index 0000000..fb8a9f5 --- /dev/null +++ b/src/common/gui/key_gui.h @@ -0,0 +1,125 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 KEY_GUI_H +#define KEY_GUI_H + +#include <qcombobox.h> +#include <qwidgetstack.h> +#include <qpopupmenu.h> + +#include "common/gui/misc_gui.h" +#include "common/common/misc.h" + +//----------------------------------------------------------------------------- +template <typename KeyType, typename Type, typename WidgetType> +class KeyWidget +{ +public: + typedef QMapConstIterator<KeyType, int> ConstIterator; + +public: + KeyWidget(QWidget *parent) { _widget = new WidgetType(parent); } + virtual ~KeyWidget() { delete _widget; } + virtual WidgetType *widget() { return _widget; } + virtual void clear() { _ids.clear(); } + ConstIterator begin() const { return _ids.begin(); } + ConstIterator end() const { return _ids.end(); } + uint count() const { return _ids.count(); } + void appendItem(const KeyType &key, Type type) { + CRASH_ASSERT( !_ids.contains(key) ); + _ids[key] = append(type); + } + KeyType currentItem() const { return key(currentId()); } + void setCurrentItem(const KeyType &key) { + if ( _ids.contains(key) ) setCurrentId(_ids[key]); + } + bool contains(const KeyType &key) const { return _ids.contains(key); } + Type item(const KeyType &key) const { + CRASH_ASSERT( _ids.contains(key) ); + return get(_ids[key]); + } + Type item(ConstIterator it) const { + CRASH_ASSERT( it!=end() ); + return get(it.data()); + } + KeyType key(int id) const { + for (ConstIterator it=begin(); it!=end(); it++) + if ( it.data()==id ) return it.key(); + return KeyType(); + } + +protected: + virtual int append(Type type) = 0; + virtual int currentId() const = 0; + virtual void setCurrentId(int id) = 0; + virtual Type get(int id) const = 0; + + QWidget *_parent; + QMap<KeyType, int> _ids; + WidgetType *_widget; +}; + +//----------------------------------------------------------------------------- +template <typename KeyType> +class KeyComboBox : public KeyWidget<KeyType, QString, QComboBox> +{ +public: + typedef KeyWidget<KeyType, QString, QComboBox> ParentType; + KeyComboBox(QWidget *parent = 0) : ParentType(parent) {} + virtual void clear() { + ParentType::clear(); + ParentType::_widget->clear(); + } + void fixMinimumWidth() { + ParentType::_widget->setMinimumWidth(ParentType::_widget->sizeHint().width()); + } + +protected: + virtual int append(QString label) { ParentType::_widget->insertItem(label); return ParentType::_widget->count()-1; } + virtual int currentId() const { return ParentType::_widget->currentItem(); } + virtual void setCurrentId(int id) { ParentType::_widget->setCurrentItem(id); } + virtual QString get(int id) const { return ParentType::_widget->text(id); } +}; + +//----------------------------------------------------------------------------- +template <typename KeyType> +class KeyWidgetStack : public KeyWidget<KeyType, QWidget *, QWidgetStack> +{ +public: + typedef KeyWidget<KeyType, QWidget *, QWidgetStack> ParentType; + KeyWidgetStack(QWidget *parent = 0) : ParentType(parent) {} + +protected: + virtual int append(QWidget *widget) { return ParentType::_widget->addWidget(widget); } + virtual int currentId() const { return ParentType::_widget->id(ParentType::_widget->visibleWidget()); } + virtual void setCurrentId(int id) { ParentType::_widget->raiseWidget(id); } + virtual QWidget *get(int id) const { return ParentType::_widget->widget(id); } +}; + +//----------------------------------------------------------------------------- +template <typename KeyType> +class KeyPopupButton : public KeyWidget<KeyType, QString, PopupButton> +{ +public: + typedef KeyWidget<KeyType, QString, PopupButton> ParentType; + KeyPopupButton(QWidget *parent = 0) : ParentType(parent) {} + +protected: + virtual int append(QString label) { return ParentType::_widget->appendItem(label, QPixmap()); } + virtual QString get(int id) const { return ParentType::_widget->popup()->text(id); } + +private: + // disabled + QString currentItem() const; + void setCurrentItem(const QString &key); + virtual int currentId() const { return 0; } + virtual void setCurrentId(int) {} +}; + +#endif diff --git a/src/common/gui/list_container.cpp b/src/common/gui/list_container.cpp new file mode 100644 index 0000000..0103175 --- /dev/null +++ b/src/common/gui/list_container.cpp @@ -0,0 +1,95 @@ +/*************************************************************************** + * Copyright (C) 2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 "list_container.h" + +//---------------------------------------------------------------------------- +PopupContainer::PopupContainer(const QString &title, QWidget *parent, const char *name) + : KPopupMenu(parent, name) +{ + if ( !title.isEmpty() ) insertTitle(title); +} + +ListContainer *PopupContainer::appendBranch(const QString &title) +{ + PopupContainer *branch = new PopupContainer(title, this); + insertItem(title, branch); + return branch; +} + +ListContainer *PopupContainer::appendBranch(const QPixmap &pixmap, const QString &title) +{ + PopupContainer *branch = new PopupContainer(title, this); + insertItem(pixmap, title, branch); + return branch; +} + +void PopupContainer::appendItem(const QPixmap &icon, const QString &label, uint id, ItemState state) +{ + insertItem(icon, label, id); + switch (state) { + case Normal: break; + case Checked: setItemChecked(id, true); break; + case UnChecked: setItemChecked(id, false); break; + case Disabled: setItemEnabled(id, false); break; + } +} + +//---------------------------------------------------------------------------- +ListViewItemContainer::ListViewItemContainer(const QString &title, KListView *parent) + : KListViewItem(parent, title), _parent(0), _column(0) +{ + _ids = new QMap<const QListViewItem *, uint>; +} + +ListViewItemContainer::ListViewItemContainer(const QString &title, ListViewItemContainer *parent) + : KListViewItem(parent, title), _parent(parent), _column(0) +{ + _ids = parent->_ids; +} + +ListViewItemContainer::~ListViewItemContainer() +{ + if ( _parent==0 ) delete _ids; +} + +ListContainer *ListViewItemContainer::appendBranch(const QString &title) +{ + ListViewItemContainer *branch = new ListViewItemContainer(title, this); + branch->setColumn(_column); + branch->setSelectable(false); + // append instead of prepend + QListViewItem *litem=firstChild(); + while ( litem && litem->nextSibling() ) litem = litem->nextSibling(); + if (litem) branch->moveItem(litem); + return branch; +} + +void ListViewItemContainer::appendItem(const QPixmap &icon, const QString &title, uint id, ItemState state) +{ + QListViewItem *item = 0; + if ( state==Normal || state==Disabled ) { + item = new KListViewItem(this); + item->setText(_column, title); + } else { + item = new QCheckListItem(this, title, QCheckListItem::CheckBox); + static_cast<QCheckListItem *>(item)->setState(state==Checked ? QCheckListItem::On : QCheckListItem::Off); + } + item->setPixmap(_column, icon); + item->setSelectable(state==Normal); + // append instead of prepend + QListViewItem *litem=firstChild(); + while ( litem && litem->nextSibling() ) litem = litem->nextSibling(); + if (litem) item->moveItem(litem); + (*_ids)[item] = id; +} + +int ListViewItemContainer::id(const QListViewItem *item) const +{ + return (_ids->contains(item) ? int((*_ids)[item]) : -1); +} diff --git a/src/common/gui/list_container.h b/src/common/gui/list_container.h new file mode 100644 index 0000000..b70db57 --- /dev/null +++ b/src/common/gui/list_container.h @@ -0,0 +1,55 @@ +/*************************************************************************** + * Copyright (C) 2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 LIST_CONTAINER_H +#define LIST_CONTAINER_H + +#include <kpopupmenu.h> +#include <klistview.h> + +//---------------------------------------------------------------------------- +class ListContainer +{ +public: + virtual ~ListContainer() {} + virtual ListContainer *appendBranch(const QString &title) = 0; + enum ItemState { Normal, Checked, UnChecked, Disabled }; + void appendItem(const QString &label, uint id, ItemState state) { appendItem(QPixmap(), label, id, state); } + virtual void appendItem(const QPixmap &icon, const QString &label, uint id, ItemState state) = 0; +}; + +//---------------------------------------------------------------------------- +class PopupContainer : public KPopupMenu, public ListContainer +{ +Q_OBJECT +public: + PopupContainer(const QString &title, QWidget *parent = 0, const char *name = 0); + virtual ListContainer *appendBranch(const QString &title); + virtual ListContainer *appendBranch(const QPixmap &icon, const QString &title); + virtual void appendItem(const QPixmap &icon, const QString &label, uint id, ItemState state); +}; + +//---------------------------------------------------------------------------- +class ListViewItemContainer : public KListViewItem, public ListContainer +{ +public: + ListViewItemContainer(const QString &title, KListView *parent); + ListViewItemContainer(const QString &title, ListViewItemContainer *parent); + virtual ~ListViewItemContainer(); + void setColumn(uint column) { _column = column; } + virtual ListContainer *appendBranch(const QString &title); + virtual void appendItem(const QPixmap &icon, const QString &label, uint id, ItemState state); + int id(const QListViewItem* item) const; // -1 if not known + +private: + ListViewItemContainer *_parent; + uint _column; + QMap<const QListViewItem *, uint> *_ids; +}; + +#endif diff --git a/src/common/gui/list_view.cpp b/src/common/gui/list_view.cpp new file mode 100644 index 0000000..c9434f3 --- /dev/null +++ b/src/common/gui/list_view.cpp @@ -0,0 +1,221 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 1992-2003 Trolltech AS. * + * * + * 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 "list_view.h" + +#include <qapplication.h> +#include <qpainter.h> +#include <qlineedit.h> +#include <qheader.h> +#include <qmetaobject.h> +#include <qvariant.h> + +//---------------------------------------------------------------------------- +ListView::ListView(QWidget *parent, const char *name) + : KListView(parent, name) +{ + QToolTip::remove(this); + _tooltip = new ListViewToolTip(this); +} + +ListView::~ListView() +{ + delete _tooltip; +} + +QString ListView::tooltip(const QListViewItem &, int) const +{ + return QString::null; +} + +void ListView::clear() +{ + _editItems.clear(); + KListView::clear(); +} + +bool ListView::eventFilter(QObject *o, QEvent *e) +{ + QValueList<EditListViewItem *>::const_iterator it; + for (it=_editItems.begin(); it!=_editItems.end(); ++it) { + for (uint i=0; i<(*it)->_editWidgets.count(); i++) { + if ( (*it)->_editWidgets[i]==o ) { + //qDebug("event %i", e->type()); + switch (e->type()) { + case QEvent::KeyPress: { + QKeyEvent *ke = static_cast<QKeyEvent *>(e); + switch (ke->key()) { + case Key_Enter: + case Key_Return: + (*it)->renameDone(true); + return true; + case Key_Escape: + (*it)->removeEditBox(); + return true; + } + break; + } + case QEvent::FocusOut: { + //qDebug("focus out %i %i=%i", qApp->focusWidget(), focusWidget(), (*it)->_editWidgets[i]); + if ( qApp->focusWidget() && focusWidget()==(*it)->_editWidgets[i] ) break; + //qDebug("ext"); + QCustomEvent *e = new QCustomEvent(9999); + QApplication::postEvent(o, e); + return true; + } + case 9999: + (*it)->renameDone(false); + return true; + default: + //qDebug(" ignored"); + break; + } + } + } + } + return KListView::eventFilter(o, e); +} + +void ListView::stopRenaming(bool force) +{ + QValueList<EditListViewItem *>::const_iterator it; + for (it=_editItems.begin(); it!=_editItems.end(); ++it) + if ( (*it)->isRenaming() ) (*it)->renameDone(force); +} + +//---------------------------------------------------------------------------- +void ListViewToolTip::maybeTip(const QPoint &p) +{ + if ( _listView==0 ) return; + const QListViewItem* item = _listView->itemAt(p); + if ( item==0 ) return; + QRect rect = _listView->itemRect(item); + if ( !rect.isValid() ) return; + int col = _listView->header()->sectionAt(p.x()); + QString text = _listView->tooltip(*item, col); + if ( !text.isEmpty() ) { + int hpos = _listView->header()->sectionPos(col); + rect.setLeft(hpos); + rect.setRight(hpos + _listView->header()->sectionSize(col)); + tip(rect, text); + } +} + +//---------------------------------------------------------------------------- +EditListViewItem::EditListViewItem(ListView *list) + : KListViewItem(list), _renaming(false) +{ + setRenameEnabled(0, true); + list->_editItems.append(this); +} + +EditListViewItem::EditListViewItem(KListViewItem *item) + : KListViewItem(item), _renaming(false) +{ + setRenameEnabled(0, true); + static_cast<ListView *>(listView())->_editItems.append(this); +} + +EditListViewItem::~EditListViewItem() +{ + if ( listView() ) static_cast<ListView *>(listView())->_editItems.remove(this); + for (uint i=0; i<_editWidgets.count(); i++) delete _editWidgets[i]; +} + +void EditListViewItem::paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int align) +{ + if ( column<int(_editWidgets.count()) && _editWidgets[column] ) + p->fillRect(0, 0, width, height(), cg.color(QColorGroup::Background)); + else KListViewItem::paintCell(p, cg, column, width, align); +} + +void EditListViewItem::startRename() +{ + if ( !renameEnabled(0) ) return; + QListView *lv = listView(); + if ( !lv ) return; + KListViewItem::startRename(0); + if (renameBox) { + renameBox->removeEventFilter(lv); + renameBox->hide(); + lv->removeChild(renameBox); + } + _renaming = true; + _editWidgets.resize(lv->columns()); + for (uint i=0; i<_editWidgets.count(); i++) { + QRect r = lv->itemRect(this); + r = QRect(lv->viewportToContents(r.topLeft()), r.size()); + r.setLeft(lv->header()->sectionPos(i)); + r.setWidth(lv->header()->sectionSize(i) - 1); + if ( i==0 ) r.setLeft(r.left() + lv->itemMargin() + (depth() + (lv->rootIsDecorated() ? 1 : 0)) * lv->treeStepSize() - 1); + if ( (lv->contentsX() + lv->visibleWidth())<(r.x() + r.width()) ) + lv->scrollBy((r.x() + r.width() ) - ( lv->contentsX() + lv->visibleWidth() ), 0); + if ( r.width()>lv->visibleWidth() ) r.setWidth(lv->visibleWidth()); + + _editWidgets[i] = editWidgetFactory(i); + if ( _editWidgets[i]==0 ) continue; + _editWidgets[i]->installEventFilter(lv); + lv->addChild(_editWidgets[i], r.x(), r.y()); + uint w = QMIN(r.width(), _editWidgets[i]->sizeHint().width()); + _editWidgets[i]->resize(w, r.height()); + lv->viewport()->setFocusProxy(_editWidgets[i]); + _editWidgets[i]->setFocus(); + _editWidgets[i]->show(); + } +} + +void EditListViewItem::removeEditBox() +{ + QListView *lv = listView(); + if ( !lv ) return; + _renaming = false; + bool resetFocus = false; + for (uint i=0; i<_editWidgets.count(); i++) { + if ( lv->viewport()->focusProxy()==_editWidgets[i] ) resetFocus = true; + delete _editWidgets[i]; + } + _editWidgets.clear(); + delete renameBox; + renameBox = 0; + if (resetFocus) { + lv->viewport()->setFocusProxy(lv); + lv->setFocus(); + } +} + +void EditListViewItem::editDone(int col, const QWidget *edit) +{ + if ( edit->metaObject()->findProperty("text", true)!=-1 ) + emit listView()->itemRenamed(this, col, edit->property("text").toString()); + else if ( edit->metaObject()->findProperty("currentText", true)!=-1 ) + emit listView()->itemRenamed(this, col, edit->property("currentText").toString()); +} + +void EditListViewItem::renameDone(bool force) +{ + QListView *lv = listView(); + if ( !lv || !_renaming ) return; + _renaming = false; + for (uint i=0; i<_editWidgets.count(); i++) { + if ( !force && !alwaysAcceptEdit(i) ) continue; + emit lv->itemRenamed(this, i); + if ( _editWidgets[i] ) editDone(i, _editWidgets[i]); + } + removeEditBox(); +} + +int EditListViewItem::width(const QFontMetrics &fm, const QListView *lv, int col) const +{ + int w = KListViewItem::width(fm, lv, col); + QWidget *edit = editWidgetFactory(col); + if ( edit==0 ) return w; + w = QMAX(w, edit->sizeHint().width()); + delete edit; + return w; +} diff --git a/src/common/gui/list_view.h b/src/common/gui/list_view.h new file mode 100644 index 0000000..09ca984 --- /dev/null +++ b/src/common/gui/list_view.h @@ -0,0 +1,93 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 LIST_VIEW_H +#define LIST_VIEW_H + +#include <qtooltip.h> +#include <qvaluevector.h> +#define private public +#define protected public +#include <klistview.h> +#undef private +#undef protected + +//----------------------------------------------------------------------------- +class EditListViewItem; +class ListViewToolTip; + +class ListView : public KListView +{ +Q_OBJECT +public: + ListView(QWidget *parent = 0, const char *name = 0); + virtual ~ListView(); + virtual void clear(); + void stopRenaming(bool force); + virtual QString tooltip(const QListViewItem &item, int column) const; + +public slots: + void cancelRenaming() { stopRenaming(false); } + void finishRenaming() { stopRenaming(true); } + +protected: + virtual bool eventFilter(QObject *o, QEvent *e); + +private: + ListViewToolTip *_tooltip; + QValueList<EditListViewItem *> _editItems; + + friend class EditListViewItem; +}; + +//----------------------------------------------------------------------------- +class ListViewToolTip : public QToolTip +{ +public: + ListViewToolTip(ListView *parent) + : QToolTip(parent->viewport()), _listView(parent) {} + +protected: + virtual void maybeTip(const QPoint &p); + +private: + ListView *_listView; +}; + +//----------------------------------------------------------------------------- +class EditListViewItem : public KListViewItem +{ +public: + EditListViewItem(ListView *list); + EditListViewItem(KListViewItem *item); + virtual ~EditListViewItem(); + void startRename(); + bool isRenaming() const { return _renaming; } + +protected: + virtual QWidget *editWidgetFactory(int col) const = 0; + virtual bool alwaysAcceptEdit(int col) const = 0; + virtual int width(const QFontMetrics &fm, const QListView *lv, int c) const; + virtual void editDone(int col, const QWidget *editWidget); + virtual void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int align); + +private: + bool _renaming; + QValueVector<QWidget *> _editWidgets; + + virtual void activate() { startRename(); } + virtual void startRename(int) { startRename(); } + virtual void okRename(int) { renameDone(true); } + virtual void cancelRename(int) { renameDone(false); } + void renameDone(bool force); + void removeEditBox(); + + friend class ListView; +}; + +#endif diff --git a/src/common/gui/misc_gui.cpp b/src/common/gui/misc_gui.cpp new file mode 100644 index 0000000..00f4997 --- /dev/null +++ b/src/common/gui/misc_gui.cpp @@ -0,0 +1,234 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 "misc_gui.h" + +#include <qapplication.h> +#include <qpushbutton.h> +#include <qtimer.h> +#include <qwidgetstack.h> +#include <qobjectlist.h> +#include <qpainter.h> +#include <qheader.h> +#include <qmetaobject.h> +#include <qvariant.h> +#include <qpopupmenu.h> + +#include <kcursor.h> +#include <kiconloader.h> +#include <kmessagebox.h> +#include <kaction.h> +#include <ktabbar.h> + +#include "dialog.h" +#include "common/common/number.h" +#include "common/common/misc.h" +#include "common/gui/number_gui.h" + +//----------------------------------------------------------------------------- +bool BusyCursor::_overridePaused = false; + +void BusyCursor::start() +{ + QApplication::setOverrideCursor(KCursor::waitCursor(), true); +} + +void BusyCursor::stop() +{ + QApplication::restoreOverrideCursor(); +} + +void BusyCursor::pause() +{ + _overridePaused = QApplication::overrideCursor(); + stop(); +} + +void BusyCursor::restore() +{ + if (_overridePaused) start(); +} + +//----------------------------------------------------------------------------- +void MessageBox::information(const QString &text, Log::ShowMode show, const QString &dontShowAgainName) +{ + if ( show==Log::DontShow ) return; + BusyCursor::pause(); + KMessageBox::information(qApp->mainWidget(), text, QString::null, dontShowAgainName, KMessageBox::Notify | KMessageBox::AllowLink); + BusyCursor::restore(); +} + +void MessageBox::detailedSorry(const QString &text, const QString &details, Log::ShowMode show) +{ + if ( show==Log::DontShow ) return; + BusyCursor::pause(); + if ( details.isEmpty() ) KMessageBox::sorry(qApp->mainWidget(), text, QString::null, KMessageBox::Notify | KMessageBox::AllowLink); + else KMessageBox::detailedSorry(qApp->mainWidget(), text, details, QString::null, KMessageBox::Notify | KMessageBox::AllowLink); + BusyCursor::restore(); +} + +bool MessageBox::askContinue(const QString &text, const KGuiItem &buttonContinue, const QString &caption) +{ + ::BusyCursor::pause(); + int res = KMessageBox::warningContinueCancel(qApp->mainWidget(), text, caption, buttonContinue); + ::BusyCursor::restore(); + return ( res==KMessageBox::Continue ); +} + +bool MessageBox::questionYesNo(const QString &text, const KGuiItem &yesButton,const KGuiItem &noButton, const QString &caption) +{ + ::BusyCursor::pause(); + int res = KMessageBox::questionYesNo(qApp->mainWidget(), text, caption, yesButton, noButton); + ::BusyCursor::restore(); + return ( res==KMessageBox::Yes ); +} + +MessageBox::Result MessageBox::questionYesNoCancel(const QString &text, const KGuiItem &yesButton, const KGuiItem &noButton, + const QString &caption) +{ + ::BusyCursor::pause(); + int res = KMessageBox::questionYesNoCancel(qApp->mainWidget(), text, caption, yesButton, noButton); + ::BusyCursor::restore(); + if ( res==KMessageBox::Yes ) return Yes; + if ( res==KMessageBox::No ) return No; + return Cancel; +} + +void MessageBox::text(const QString &text, Log::ShowMode show) +{ + if ( show==Log::DontShow ) return; + BusyCursor::pause(); + TextEditorDialog dialog(text, QString::null, false, qApp->mainWidget()); + dialog.exec(); + BusyCursor::restore(); +} + +//---------------------------------------------------------------------------- +PopupButton::PopupButton(QWidget *parent, const char *name) + : KPushButton(parent, name) +{ + init(); +} + +PopupButton::PopupButton(const QString &text, QWidget *parent, const char *name) + : KPushButton(text, parent, name) +{ + init(); +} + +void PopupButton::init() +{ + _separator = false; + setFlat(true); + QPopupMenu *popup = new QPopupMenu(this); + connect(popup, SIGNAL(activated(int)), SIGNAL(activated(int))); + setPopup(popup); +} + +void PopupButton::appendAction(KAction *action) +{ + if ( _separator && popup()->count()!=0 ) popup()->insertSeparator(); + _separator = false; + action->plug(popup()); +} + +void PopupButton::appendAction(const QString &label, const QString &icon, + QObject *receiver, const char *slot) +{ + appendAction(new KAction(label, icon, 0, receiver, slot, (KActionCollection *)0)); +} + +int PopupButton::appendItem(const QString &label, const QString &icon, int id) +{ + KIconLoader loader; + QPixmap pixmap = loader.loadIcon(icon, KIcon::Small); + return appendItem(label, pixmap, id); +} + +int PopupButton::appendItem(const QString &label, const QPixmap &icon, int id) +{ + if ( _separator && popup()->count()!=0 ) popup()->insertSeparator(); + _separator = false; + return popup()->insertItem(icon, label, id); +} + +//----------------------------------------------------------------------------- +Splitter::Splitter(const QValueList<int> &defaultSizes, Orientation o, QWidget *parent, const char *name) + : QSplitter(o, parent, name), _defaultSizes(defaultSizes) +{ + Q_ASSERT(name); + setOpaqueResize(true); + QTimer::singleShot(0, this, SLOT(updateSizes())); +} + +Splitter::~Splitter() +{ + GuiConfig gc; + gc.writeEntry(QString(name()) + "_sizes", sizes()); +} + +void Splitter::updateSizes() +{ + GuiConfig gc; + QValueList<int> sizes = gc.readIntListEntry(QString(name()) + "_sizes"); + for (uint i=sizes.count(); i<_defaultSizes.count(); i++) sizes.append(_defaultSizes[i]); + setSizes(sizes); +} + +//----------------------------------------------------------------------------- +TabBar::TabBar(QWidget *parent, const char *name) + : KTabBar(parent, name), _ignoreWheelEvent(false) +{} + +void TabBar::wheelEvent(QWheelEvent *e) +{ + if (_ignoreWheelEvent) QApplication::sendEvent(parent(), e); // #### not sure why ignoring is not enough... + else KTabBar::wheelEvent(e); +} + +TabWidget::TabWidget(QWidget *parent, const char *name) + : KTabWidget(parent, name) +{ + setTabBar(new TabBar(this)); +} + +void TabWidget::setIgnoreWheelEvent(bool ignore) +{ + static_cast<TabBar *>(tabBar())->_ignoreWheelEvent = ignore; +} + +void TabWidget::wheelEvent(QWheelEvent *e) +{ + if (static_cast<TabBar *>(tabBar())->_ignoreWheelEvent) e->ignore(); + else KTabWidget::wheelEvent(e); +} + +void TabWidget::setTabBar(TabBar *tabbar) +{ + KTabWidget::setTabBar(tabbar); + connect(tabBar(), SIGNAL(contextMenu( int, const QPoint & )), SLOT(contextMenu( int, const QPoint & ))); + connect(tabBar(), SIGNAL(mouseDoubleClick( int )), SLOT(mouseDoubleClick( int ))); + connect(tabBar(), SIGNAL(mouseMiddleClick( int )), SLOT(mouseMiddleClick( int ))); + connect(tabBar(), SIGNAL(initiateDrag( int )), SLOT(initiateDrag( int ))); + connect(tabBar(), SIGNAL(testCanDecode(const QDragMoveEvent *, bool & )), SIGNAL(testCanDecode(const QDragMoveEvent *, bool & ))); + connect(tabBar(), SIGNAL(receivedDropEvent( int, QDropEvent * )), SLOT(receivedDropEvent( int, QDropEvent * ))); + connect(tabBar(), SIGNAL(moveTab( int, int )), SLOT(moveTab( int, int ))); + connect(tabBar(), SIGNAL(closeRequest( int )), SLOT(closeRequest( int ))); + connect(tabBar(), SIGNAL(wheelDelta( int )), SLOT(wheelDelta( int ))); +} + +//----------------------------------------------------------------------------- +ComboBox::ComboBox(QWidget *parent, const char *name) + : QComboBox(parent, name), _ignoreWheelEvent(false) +{} + +void ComboBox::wheelEvent(QWheelEvent *e) +{ + if (_ignoreWheelEvent) QApplication::sendEvent(parent(), e); // #### not sure why ignoring is not enough... + else QComboBox::wheelEvent(e); +} diff --git a/src/common/gui/misc_gui.h b/src/common/gui/misc_gui.h new file mode 100644 index 0000000..2d58569 --- /dev/null +++ b/src/common/gui/misc_gui.h @@ -0,0 +1,164 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 MISC_GUI_H +#define MISC_GUI_H + +#include <qlayout.h> +#include <qsplitter.h> +#include <qvaluevector.h> +#include <qvalidator.h> +#include <qcombobox.h> +#include <qwidgetstack.h> + +#include <klocale.h> +#include <kpushbutton.h> +#include <ktabwidget.h> +#include <ktabbar.h> +#include <kstdguiitem.h> +#include <klineedit.h> +class KAction; + +#include "common/global/generic_config.h" +#include "common/global/log.h" +#include "common/common/number.h" + +//----------------------------------------------------------------------------- +class BusyCursor +{ +public: + BusyCursor() { start(); } + ~BusyCursor() { stop(); } + static void start(); + static void stop(); + static void pause(); + static void restore(); + +private: + static bool _overridePaused; +}; + +//----------------------------------------------------------------------------- +namespace MessageBox +{ +extern void information(const QString &text, Log::ShowMode show, const QString &dontShowAgainName = QString::null); +extern void detailedSorry(const QString &text, const QString &details, Log::ShowMode show); +inline void sorry(const QString &text, Log::ShowMode show) { detailedSorry(text, QString::null, show); } +extern bool askContinue(const QString &text, const KGuiItem &continueButton = KStdGuiItem::cont(), + const QString &caption = i18n("Warning")); +extern bool questionYesNo(const QString &text, const KGuiItem &yesButton, const KGuiItem &noButton, + const QString &caption = i18n("Warning")); +enum Result { Yes, No, Cancel }; +extern Result questionYesNoCancel(const QString &text, const KGuiItem &yesButton, const KGuiItem &noButton, + const QString &caption = i18n("Warning")); +extern void text(const QString &text, Log::ShowMode show); +} + +//---------------------------------------------------------------------------- +class PopupButton : public KPushButton +{ +Q_OBJECT +public: + PopupButton(QWidget *parent = 0, const char *name = 0); + PopupButton(const QString &text, QWidget *parent = 0, const char *name = 0); + void appendAction(KAction *action); + void appendAction(const QString &label, const QString &icon = QString::null, + QObject *receiver = 0, const char *slot = 0); + int appendItem(const QString &label, uint id) { return appendItem(label, QPixmap(), id); } + int appendItem(const QString &label, const QString &icon, int id = -1); + int appendItem(const QString &label, const QPixmap &icon, int id = -1); + void appendSeparator() { _separator = true; } + +signals: + void activated(int id); + +private: + bool _separator; + + void init(); +}; + +//----------------------------------------------------------------------------- +class Splitter : public QSplitter +{ +Q_OBJECT +public: + Splitter(const QValueList<int> &defaultSizes, Orientation orientation, + QWidget *parent, const char *name); + virtual ~Splitter(); + +private slots: + void updateSizes(); + +private: + QValueList<int> _defaultSizes; +}; + +//----------------------------------------------------------------------------- +class GuiConfig : public GenericConfig +{ +public: + GuiConfig() : GenericConfig("gui") {} +}; + +//----------------------------------------------------------------------------- +class SeparatorWidget : public QFrame +{ +Q_OBJECT +public: + SeparatorWidget(QWidget *parent) : QFrame(parent, "separator") { + setFrameStyle(QFrame::Panel | QFrame::Sunken); + setMargin(2); + setFixedHeight(2*2); + } +}; + +//----------------------------------------------------------------------------- +class TabBar : public KTabBar +{ +Q_OBJECT +public: + TabBar(QWidget *parent = 0, const char *name = 0); + +protected: + virtual void wheelEvent(QWheelEvent *e); + +private: + bool _ignoreWheelEvent; + + friend class TabWidget; +}; + +class TabWidget : public KTabWidget +{ +Q_OBJECT +public: + TabWidget(QWidget *parent = 0, const char *name = 0); + void setIgnoreWheelEvent(bool ignore); + +protected: + virtual void wheelEvent(QWheelEvent *e); + void setTabBar(TabBar *tabbar); +}; + +//----------------------------------------------------------------------------- +class ComboBox : public QComboBox +{ +Q_OBJECT +public: + ComboBox(QWidget *parent = 0, const char *name = 0); + void setIgnoreWheelEvent(bool ignore) { _ignoreWheelEvent = ignore; } + +protected: + virtual void wheelEvent(QWheelEvent *e); + +private: + bool _ignoreWheelEvent; +}; + +#endif diff --git a/src/common/gui/number_gui.cpp b/src/common/gui/number_gui.cpp new file mode 100644 index 0000000..d855407 --- /dev/null +++ b/src/common/gui/number_gui.cpp @@ -0,0 +1,72 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 "number_gui.h" + +#include <qfontmetrics.h> + +//----------------------------------------------------------------------------- +uint maxCharWidth(const QString &s, const QFont &font) +{ + QFontMetrics fm(font); + uint w = 0; + for (uint i=0; i<uint(s.length()); i++) + w = QMAX(w, uint(fm.width(s[i]))); + return w; +} + +uint maxCharWidth(NumberBase base, const QFont &font) +{ + QString s; + for (uint i=0; i<base.data().base; i++) s += toChar(base, i); + return maxCharWidth(s, font); +} + +uint maxLabelWidth(NumberBase base, uint nbChars, const QFont &font) +{ + uint w = maxStringWidth(base, nbChars, font); + QFontMetrics fm(font); + if ( base==NumberBase::String ) return w + 2 * fm.width("\""); + return w + fm.width(base.data().prefix); +} + +//----------------------------------------------------------------------------- +NumberLineEdit::NumberLineEdit(QWidget *parent, const char *name) + : KLineEdit(parent, name) +{ + connect(this, SIGNAL(textChanged(const QString &)), SLOT(textChangedSlot())); +} + +NumberLineEdit::NumberLineEdit(const QString &text, QWidget *parent, const char *name) + : KLineEdit(text, parent, name) +{ + connect(this, SIGNAL(textChanged(const QString &)), SLOT(textChangedSlot())); +} + +QValidator::State validateNumber(const QString &input) +{ + if ( input.isEmpty() ) return QValidator::Intermediate; + bool ok; + (void)fromAnyLabel(input, &ok); + if (ok) return QValidator::Acceptable; + FOR_EACH(NumberBase, base) + if ( input==base.data().prefix ) return QValidator::Intermediate; + if ( input[0]=='\"' ) return QValidator::Intermediate; + if ( input[0]=='\'' ) return QValidator::Intermediate; + return QValidator::Invalid; +} + +void NumberLineEdit::textChangedSlot() +{ + QValidator::State state = validateNumber(text()); + switch (state) { + case QValidator::Acceptable: unsetColor(); break; + case QValidator::Intermediate: setColor(QColor("#FF9900")); break; + case QValidator::Invalid: setColor(red); break; + } +} diff --git a/src/common/gui/number_gui.h b/src/common/gui/number_gui.h new file mode 100644 index 0000000..f910820 --- /dev/null +++ b/src/common/gui/number_gui.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 NUMBER_GUI_H +#define NUMBER_GUI_H + +#include <qvalidator.h> +#include <klineedit.h> + +#include "common/common/number.h" + +//----------------------------------------------------------------------------- +extern uint maxCharWidth(const QString &s, const QFont &font); +extern uint maxCharWidth(NumberBase base, const QFont &font); +inline uint maxStringWidth(NumberBase base, uint nbChars, const QFont &font) { return nbChars * maxCharWidth(base, font); } +extern uint maxLabelWidth(NumberBase base, uint nbChars, const QFont &font); + +extern QValidator::State validateNumber(const QString &s); + +//----------------------------------------------------------------------------- +class NumberLineEdit : public KLineEdit +{ +Q_OBJECT +public: + NumberLineEdit(QWidget *parent = 0, const char *name = 0); + NumberLineEdit(const QString &text, QWidget *parent = 0, const char *name = 0); + uint value(bool *ok = 0) const { return fromAnyLabel(text(), ok); } + void setColor(const QColor &color) { setPaletteForegroundColor(color); } + void unsetColor() { unsetPalette(); } + +private slots: + void textChangedSlot(); +}; + +#endif diff --git a/src/common/gui/pfile_ext.cpp b/src/common/gui/pfile_ext.cpp new file mode 100644 index 0000000..d42de16 --- /dev/null +++ b/src/common/gui/pfile_ext.cpp @@ -0,0 +1,114 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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_ext.h" + +#include <qfile.h> +#include <kio/netaccess.h> +#include <ktempfile.h> +#include "common/gui/misc_gui.h" + +//----------------------------------------------------------------------------- +bool PURL::File::openForWrite() +{ + close(); + if (_tmp) delete _tmp; + _tmp = new KTempFile(QString::null, _extension); + _tmp->setAutoDelete(true); + if ( _tmp->status()!=0 ) { + _error = i18n("Could not create temporary file."); + _log.sorry(_error, i18n("File: %1").arg(_tmp->name())); + return false; + } + return true; +} + +bool PURL::File::close() +{ + if (_tmp) _tmp->close(); + else _file->close(); + bool ok = (_tmp ? _tmp->status() : _file->status())==IO_Ok; + if ( !_file->name().isEmpty() ) { + KIO::NetAccess::removeTempFile(_file->name()); + _file->setName(QString::null); + } + delete _stream; + _stream = 0; + if ( ok && _tmp && !_url.isEmpty() && !KIO::NetAccess::upload(_tmp->name(), _url.kurl(), qApp->mainWidget()) ) { + _error = KIO::NetAccess::lastErrorString(); + ok = false; + _log.sorry(i18n("Could not save file."), errorString()); + } + delete _tmp; + _tmp = 0; + return ok; +} + +bool PURL::File::openForRead() +{ + close(); + QString tmp; + if ( !KIO::NetAccess::download(_url.kurl(), tmp, qApp->mainWidget()) ) { + _error = KIO::NetAccess::lastErrorString(); + _log.sorry(i18n("Could not open file for reading."), errorString()); + return false; + } + _file->setName(tmp); + if ( !_file->open(IO_ReadOnly) ) { + _error = i18n("Could not open temporary file."); + _log.sorry(_error, i18n("File: %1").arg(_file->name())); + return false; + } + return true; +} + +bool PURL::File::remove() +{ + close(); + if ( !_url.isEmpty() ) return _url.del(_log); + return false; +} + +//----------------------------------------------------------------------------- +PURL::TempFile::TempFile(Log::Generic &log, const QString &extension) + : FileBase(log, extension) +{} + +PURL::Url PURL::TempFile::url() const +{ + return (_tmp ? Url::fromPathOrUrl(_tmp->name()) : Url()); +} + +bool PURL::TempFile::close() +{ + delete _stream; + _stream = 0; + if (_tmp) { + _tmp->close(); + if ( _tmp->status()!=IO_Ok ) { + _error = i18n("Could not write to temporary file."); + _log.sorry(_error, i18n("File: %1").arg(_tmp->name())); + return false; + } + } + return true; +} + +bool PURL::TempFile::openForWrite() +{ + close(); + if (_tmp) delete _tmp; + _tmp = new KTempFile(QString::null, _extension); + _tmp->setAutoDelete(true); + if ( _tmp->status()!=0 ) { + _error = i18n("Could not create temporary file."); + _log.sorry(_error, i18n("File: %1").arg(_tmp->name())); + return false; + } + return true; +} diff --git a/src/common/gui/pfile_ext.h b/src/common/gui/pfile_ext.h new file mode 100644 index 0000000..14c007a --- /dev/null +++ b/src/common/gui/pfile_ext.h @@ -0,0 +1,29 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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_EXT_H +#define PFILE_EXT_H + +#include "common/global/pfile.h" + +namespace PURL +{ + +class TempFile : public FileBase +{ +public: + TempFile(Log::Generic &log, const QString &extension = QString::null); + ~TempFile() { close(); } + Url url() const; + bool close(); + bool openForWrite(); +}; + +} // namespace + +#endif diff --git a/src/common/gui/purl_ext.cpp b/src/common/gui/purl_ext.cpp new file mode 100644 index 0000000..5d69d05 --- /dev/null +++ b/src/common/gui/purl_ext.cpp @@ -0,0 +1,111 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 "common/global/purl.h" + +#include <qfile.h> +#include <qapplication.h> +#include <kio/netaccess.h> +#include <kfileitem.h> +#include <ktempfile.h> +#include <kconfigbackend.h> + +#include "common/global/pfile.h" + +bool PURL::Url::copyTo(const Url &destination, Log::Generic &log) const +{ +//#if defined(NO_KDE) +// Synchronous sync; +// if ( sync.op().copy(_url.filepath(), destination.filepath()) && sync.execute() ) { +// if ( show==Log::Show ) ConsoleView::sorry(i18n("Could not copy file"), sync.error()); +// return false; +// } +//#else + // do not overwrite + bool ok = KIO::NetAccess::file_copy(_url, destination._url, -1, false, false, qApp->mainWidget()); + if ( !ok ) log.sorry(i18n("Could not copy file"), KIO::NetAccess::lastErrorString()); + return ok; +//#endif +} + +bool PURL::Url::create(Log::Generic &log) const +{ +//#if defined(NO_KDE) +// QByteArray a; +// Synchronous sync; +// if ( sync.op().put(a, _url.filepath()) && sync.execute() ) { +// if ( show==Log::Show ) ConsoleView::sorry(i18n("Could not create file"), sync.error()); +// return false; +// } +//#else + // assume file do no exist if ioslave cannot tell... + if ( KIO::NetAccess::exists(_url, false, qApp->mainWidget()) ) return true; + KTempFile tmp; + tmp.setAutoDelete(true); + // do not overwrite + bool ok = KIO::NetAccess::file_copy(tmp.name(), _url, -1, false, false, qApp->mainWidget()); + if ( !ok ) log.sorry(i18n("Could not create file"), KIO::NetAccess::lastErrorString()); +//#endif + return ok; +} + +bool PURL::Url::write(const QString &text, Log::Generic &log) const +{ + File file(*this, log); + if ( !file.openForWrite() ) return false; + file.stream() << text; + return file.close(); +} + +bool PURL::Url::del(Log::Generic &log) const +{ +//#if defined(NO_KDE) +// Synchronous sync; +// if ( sync.op().remove(_url.filepath()) && sync.execute() ) { +// if ( show==Log::Show ) ConsoleView::sorry(i18n("Could not delete file"), sync.error()); +// return false; +// } +//#else + bool ok = KIO::NetAccess::del(_url, qApp->mainWidget()); + if ( !ok ) log.sorry(i18n("Could not delete file."), KIO::NetAccess::lastErrorString()); + return ok; +//#endif +} + +bool PURL::Url::isDosFile() const +{ + Log::Base log; + File file(*this, log); + if( !file.openForRead() ) return false; + int oldc = 0; + for (;;) { + int c = file.qfile()->getch(); + if ( c==-1 ) break; + if( c=='\n' && oldc=='\r' ) return true; + oldc = c; + } + return false; +} + +//----------------------------------------------------------------------------- +bool PURL::Directory::create(Log::Generic &log) const +{ +//#if defined(NO_KDE) +// Synchronous sync; +// if ( sync.op().mkdir(_url.filepath()) && sync.execute() ) { +// if ( show==Log::Show ) ConsoleView::sorry(i18n("Could not create directory"), sync.error()); +// return false; +// } +//#else + // assume dir do no exist if ioslave cannot tell... + if ( KIO::NetAccess::exists(_url, false, qApp->mainWidget()) ) return true; + bool ok = KIO::NetAccess::mkdir(_url, qApp->mainWidget()); + if ( !ok ) log.sorry(i18n("Could not create directory"), KIO::NetAccess::lastErrorString()); +//#endif + return ok; +} diff --git a/src/common/gui/purl_gui.cpp b/src/common/gui/purl_gui.cpp new file mode 100644 index 0000000..d81fdb6 --- /dev/null +++ b/src/common/gui/purl_gui.cpp @@ -0,0 +1,151 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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_gui.h" + +#include <qlayout.h> +#include <kiconloader.h> +#include <kpushbutton.h> +#include <krun.h> +#include <kfiledialog.h> +#include <kdirselectdialog.h> + +#include "misc_gui.h" + +//----------------------------------------------------------------------------- +PURL::Url PURL::getOpenUrl(const QString &startDir, const QString &filter, + QWidget *widget, const QString &caption) +{ + return KFileDialog::getOpenURL(startDir, filter, widget, caption); +} + +PURL::UrlList PURL::getOpenUrls(const QString &startDir, const QString &filter, + QWidget *widget, const QString &caption) +{ + return KFileDialog::getOpenURLs(startDir, filter, widget, caption); +} + +PURL::Url PURL::getSaveUrl(const QString &startDir, const QString &filter, + QWidget *widget, const QString &caption, + SaveAction action) +{ + Url url = KFileDialog::getSaveURL(startDir, filter, widget, caption); + if ( url.isEmpty() ) return Url(); + switch (action) { + case NoSaveAction: break; + case AskOverwrite: + if ( url.exists() ) { + if ( !MessageBox::askContinue(i18n("File \"%1\" already exists. Overwrite ?").arg(url.pretty())) ) return Url(); + } + break; + case CancelIfExists: + if ( url.exists() ) return Url(); + break; + } + return url; +} + +PURL::Directory PURL::getExistingDirectory(const QString &startDir, QWidget *widget, + const QString &caption) +{ + KURL kurl = KDirSelectDialog::selectDirectory(startDir, false, widget, caption); + if ( kurl.isEmpty() ) return Directory(); + return Directory(kurl.path(1)); +} + +QPixmap PURL::icon(FileType type) +{ + if (type.data().xpm_icon) return QPixmap(type.data().xpm_icon); + if ( hasMimetype(type) ) return KMimeType::mimeType(type.data().mimetype)->pixmap(KIcon::Small); + return QPixmap(); +} + +bool PURL::hasMimetype(FileType type) +{ + if ( type.data().mimetype==0 ) return false; + KMimeType::Ptr ptr = KMimeType::mimeType(type.data().mimetype); + return ( ptr!=KMimeType::defaultMimeTypePtr() ); +} + +//----------------------------------------------------------------------------- +PURL::Label::Label(const QString &url, const QString &text, + QWidget *parent, const char *name) + : KURLLabel(url, text, parent, name) +{ + connect(this, SIGNAL(leftClickedURL()), SLOT(urlClickedSlot())); +} + +void PURL::Label::urlClickedSlot() +{ + (void)new KRun(url()); +} + +//----------------------------------------------------------------------------- +PURL::BaseWidget::BaseWidget(QWidget *parent, const char *name) + : QWidget(parent, name) +{ + init(); +} + +PURL::BaseWidget::BaseWidget(const QString &defaultDir, QWidget *parent, const char *name) + : QWidget(parent, name), _defaultDir(defaultDir) +{ + init(); +} + +void PURL::BaseWidget::init() +{ + QHBoxLayout *top = new QHBoxLayout(this, 0, 10); + + _edit = new KLineEdit(this); + connect(_edit, SIGNAL(textChanged(const QString &)), SIGNAL(changed())); + top->addWidget(_edit); + KIconLoader loader; + QIconSet iconset = loader.loadIcon("fileopen", KIcon::Toolbar); + QPushButton *button = new KPushButton(iconset, QString::null, this); + connect(button, SIGNAL(clicked()), SLOT(buttonClicked())); + top->addWidget(button); +} + +//---------------------------------------------------------------------------- +void PURL::DirectoryWidget::buttonClicked() +{ + Directory dir = getExistingDirectory(_defaultDir, this, i18n("Select Directory")); + if ( dir.isEmpty() ) return; + _edit->setText(dir.path()); + emit changed(); +} + +//---------------------------------------------------------------------------- +PURL::DirectoriesWidget::DirectoriesWidget(const QString &title, QWidget *parent, const char *name) + : QVGroupBox(title, parent, name) +{ + init(QString::null); +} + +PURL::DirectoriesWidget::DirectoriesWidget(const QString &title, const QString &defaultDir, QWidget *parent, const char *name) + : QVGroupBox(title, parent, name) +{ + init(defaultDir); +} + +void PURL::DirectoriesWidget::init(const QString &defaultDir) +{ + DirectoryWidget *edit = new DirectoryWidget(defaultDir); + _editListBox = new EditListBox(1, edit, edit->lineEdit(), this, "directories_editlistbox"); + connect(_editListBox, SIGNAL(changed()), SIGNAL(changed())); +} + +//---------------------------------------------------------------------------- +void PURL::UrlWidget::buttonClicked() +{ + Url url = getOpenUrl(_defaultDir, _filter, this, i18n("Select File")); + if ( url.isEmpty() ) return; + _edit->setText(url.filepath()); + emit changed(); +} diff --git a/src/common/gui/purl_gui.h b/src/common/gui/purl_gui.h new file mode 100644 index 0000000..a11bedf --- /dev/null +++ b/src/common/gui/purl_gui.h @@ -0,0 +1,120 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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_GUI_H +#define PURL_GUI_H + +#include <qvgroupbox.h> +#include <klineedit.h> +#include <klocale.h> +#include <kurllabel.h> + +#include "common/global/purl.h" +#include "editlistbox.h" + +namespace PURL +{ +//----------------------------------------------------------------------------- +extern bool hasMimetype(FileType type); +extern QPixmap icon(FileType type); +extern Directory getExistingDirectory(const QString &startDir, QWidget *widget, const QString &caption); +extern Url getOpenUrl(const QString &startDir, const QString &filter, QWidget *widget, + const QString &caption); +extern UrlList getOpenUrls(const QString &startDir, const QString &filter, QWidget *widget, + const QString &caption); +enum SaveAction { NoSaveAction, AskOverwrite, CancelIfExists }; +extern Url getSaveUrl(const QString &startDir, const QString &filter, QWidget *widget, + const QString &caption, SaveAction action); + +//----------------------------------------------------------------------------- +class Label : public KURLLabel +{ +Q_OBJECT +public: + Label(const QString &url, const QString &text, QWidget *parent = 0, const char *name = 0); + +private slots: + void urlClickedSlot(); +}; + +//----------------------------------------------------------------------------- +class BaseWidget : public QWidget +{ +Q_OBJECT +public: + BaseWidget(QWidget *parent = 0, const char *name = 0); + BaseWidget(const QString &defaultDir, QWidget *parent = 0, const char *name = 0); + KLineEdit *lineEdit() { return _edit; } + +signals: + void changed(); + +protected slots: + virtual void buttonClicked() = 0; + +protected: + QString _defaultDir; + KLineEdit *_edit; + + void init(); +}; + +//----------------------------------------------------------------------------- +class DirectoryWidget : public BaseWidget +{ +Q_OBJECT +public: + DirectoryWidget(QWidget *parent = 0, const char *name = 0) : BaseWidget(parent, name) {} + DirectoryWidget(const QString &defaultDir, QWidget *parent = 0, const char *name = 0) : BaseWidget(defaultDir, parent, name) {} + void setDirectory(const Directory &dir) { _edit->setText(dir.path()); } + Directory directory() const { return _edit->text(); } + +protected slots: + virtual void buttonClicked(); +}; + +//----------------------------------------------------------------------------- +class DirectoriesWidget : public QVGroupBox +{ +Q_OBJECT +public: + DirectoriesWidget(const QString &title, QWidget *parent = 0, const char *name = 0); + DirectoriesWidget(const QString &title, const QString &defaultDir, QWidget *parent = 0, const char *name = 0); + void setDirectories(const QStringList &dirs) { _editListBox->setTexts(dirs); } + QStringList directories() const { return _editListBox->texts(); } + +signals: + void changed(); + +private: + EditListBox *_editListBox; + void init(const QString &defaultDir); +}; + +//----------------------------------------------------------------------------- +class UrlWidget : public BaseWidget +{ +Q_OBJECT +public: + UrlWidget(const QString &filter, QWidget *parent = 0, const char *name = 0) + : BaseWidget(parent, name), _filter(filter) {} + UrlWidget(const QString &defaultDir, const QString &filter, QWidget *parent = 0, const char *name = 0) + : BaseWidget(defaultDir, parent, name), _filter(filter) {} + Url url() const { return PURL::Url::fromPathOrUrl(_edit->text()); } + void setUrl(const Url &url) { _edit->setText(url.filepath()); } + +protected slots: + virtual void buttonClicked(); + +private: + QString _filter; +}; + +} // namespace + +#endif diff --git a/src/common/nokde/nokde.pro b/src/common/nokde/nokde.pro new file mode 100644 index 0000000..aa92599 --- /dev/null +++ b/src/common/nokde/nokde.pro @@ -0,0 +1,8 @@ +STOPDIR = ../../.. +include($${STOPDIR}/lib.pro) + +TARGET = nokde +HEADERS += nokde_klocale.h nokde_kaboutdata.h nokde_kcmdlineargs.h nokde_kprocess.h +SOURCES += nokde_klocale.cpp nokde_kaboutdata.cpp nokde_kcmdlineargs.cpp nokde_kprocess.cpp +win32:HEADERS += win32_utils.h +win32:SOURCES += win32_utils.c
\ No newline at end of file diff --git a/src/common/nokde/nokde_kaboutdata.cpp b/src/common/nokde/nokde_kaboutdata.cpp new file mode 100644 index 0000000..21b6917 --- /dev/null +++ b/src/common/nokde/nokde_kaboutdata.cpp @@ -0,0 +1,469 @@ +// modified from KDE 3.4 for Windows port (Nicolas Hadacek) + +/* + * This file is part of the KDE Libraries + * Copyright (C) 2000 Espen Sand (espen@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 "nokde_kaboutdata.h" +//#include <kstandarddirs.h> +#include <qfile.h> +#include <qtextstream.h> +#include <qstringlist.h> + +QString +KAboutPerson::name() const +{ + return QString::fromUtf8(mName); +} + +QString +KAboutPerson::task() const +{ + if (mTask && *mTask) + return i18n(mTask); + else + return QString::null; +} + +QString +KAboutPerson::emailAddress() const +{ + return QString::fromUtf8(mEmailAddress); +} + + +QString +KAboutPerson::webAddress() const +{ + return QString::fromUtf8(mWebAddress); +} + + +KAboutTranslator::KAboutTranslator(const QString & name, + const QString & emailAddress) +{ + mName=name; + mEmail=emailAddress; +} + +QString KAboutTranslator::name() const +{ + return mName; +} + +QString KAboutTranslator::emailAddress() const +{ + return mEmail; +} + +class KAboutDataPrivate +{ +public: + KAboutDataPrivate() + : translatorName("_: NAME OF TRANSLATORS\nYour names") + , translatorEmail("_: EMAIL OF TRANSLATORS\nYour emails") + , productName(0) +// , programLogo(0) + {} + ~KAboutDataPrivate() + { +// delete programLogo; + } + const char *translatorName; + const char *translatorEmail; + const char *productName; +// QImage* programLogo; +}; + + + +KAboutData::KAboutData( const char *appName, + const char *programName, + const char *version, + const char *shortDescription, + int licenseType, + const char *copyrightStatement, + const char *text, + const char *homePageAddress, + const char *bugsEmailAddress + ) : + mProgramName( programName ), + mVersion( version ), + mShortDescription( shortDescription ), + mLicenseKey( licenseType ), + mCopyrightStatement( copyrightStatement ), + mOtherText( text ), + mHomepageAddress( homePageAddress ), + mBugEmailAddress( bugsEmailAddress ), + mLicenseText (0) +{ + d = new KAboutDataPrivate; + + if( appName ) { + const char *p = strrchr(appName, '/'); + if( p ) + mAppName = p+1; + else + mAppName = appName; + } else + mAppName = 0; +} + +KAboutData::~KAboutData() +{ + if (mLicenseKey == License_File) + delete [] mLicenseText; + delete d; +} + +void +KAboutData::addAuthor( const char *name, const char *task, + const char *emailAddress, const char *webAddress ) +{ + mAuthorList.append(KAboutPerson(name,task,emailAddress,webAddress)); +} + +void +KAboutData::addCredit( const char *name, const char *task, + const char *emailAddress, const char *webAddress ) +{ + mCreditList.append(KAboutPerson(name,task,emailAddress,webAddress)); +} + +void +KAboutData::setTranslator( const char *name, const char *emailAddress) +{ + d->translatorName=name; + d->translatorEmail=emailAddress; +} + +void +KAboutData::setLicenseText( const char *licenseText ) +{ + mLicenseText = licenseText; + mLicenseKey = License_Custom; +} + +void +KAboutData::setLicenseTextFile( const QString &file ) +{ + mLicenseText = qstrdup(QFile::encodeName(file)); + mLicenseKey = License_File; +} + +void +KAboutData::setAppName( const char *appName ) +{ + mAppName = appName; +} + +void +KAboutData::setProgramName( const char* programName ) +{ + mProgramName = programName; +} + +void +KAboutData::setVersion( const char* version ) +{ + mVersion = version; +} + +void +KAboutData::setShortDescription( const char *shortDescription ) +{ + mShortDescription = shortDescription; +} + +void +KAboutData::setLicense( LicenseKey licenseKey) +{ + mLicenseKey = licenseKey; +} + +void +KAboutData::setCopyrightStatement( const char *copyrightStatement ) +{ + mCopyrightStatement = copyrightStatement; +} + +void +KAboutData::setOtherText( const char *otherText ) +{ + mOtherText = otherText; +} + +void +KAboutData::setHomepage( const char *homepage ) +{ + mHomepageAddress = homepage; +} + +void +KAboutData::setBugAddress( const char *bugAddress ) +{ + mBugEmailAddress = bugAddress; +} + +void +KAboutData::setProductName( const char *productName ) +{ + d->productName = productName; +} + +const char * +KAboutData::appName() const +{ + return mAppName; +} + +const char * +KAboutData::productName() const +{ + if (d->productName) + return d->productName; + else + return appName(); +} + +QString +KAboutData::programName() const +{ + if (mProgramName && *mProgramName) + return i18n(mProgramName); + else + return QString::null; +} +/* +QImage +KAboutData::programLogo() const +{ + return d->programLogo ? (*d->programLogo) : QImage(); +} + +void +KAboutData::setProgramLogo(const QImage& image) +{ + if (!d->programLogo) + d->programLogo = new QImage( image ); + else + *d->programLogo = image; +} +*/ +QString +KAboutData::version() const +{ + return QString::fromLatin1(mVersion); +} + +QString +KAboutData::shortDescription() const +{ + if (mShortDescription && *mShortDescription) + return i18n(mShortDescription); + else + return QString::null; +} + +QString +KAboutData::homepage() const +{ + return QString::fromLatin1(mHomepageAddress); +} + +QString +KAboutData::bugAddress() const +{ + return QString::fromLatin1(mBugEmailAddress); +} + +const QValueList<KAboutPerson> +KAboutData::authors() const +{ + return mAuthorList; +} + +const QValueList<KAboutPerson> +KAboutData::credits() const +{ + return mCreditList; +} + +const QValueList<KAboutTranslator> +KAboutData::translators() const +{ + QValueList<KAboutTranslator> personList; + + if(d->translatorName == 0) + return personList; + + QStringList nameList; + QStringList emailList; + + QString names = i18n(d->translatorName); + if(names != QString::fromUtf8(d->translatorName)) + { +#if QT_VERSION < 0x040000 + nameList = QStringList::split(',',names); +#else + nameList = names.split(',', QString::SkipEmptyParts); +#endif + } + + + if(d->translatorEmail) + { + QString emails = i18n(d->translatorEmail); + + if(emails != QString::fromUtf8(d->translatorEmail)) + { +#if QT_VERSION < 0x040000 + emailList = QStringList::split(',',emails,true); +#else + emailList = emails.split(','); +#endif + } + } + + + QStringList::Iterator nit; + QStringList::Iterator eit=emailList.begin(); + + for(nit = nameList.begin(); nit != nameList.end(); ++nit) + { + QString email; + if(eit != emailList.end()) + { + email=*eit; + ++eit; + } + + QString name=*nit; + +#if QT_VERSION < 0x040000 + personList.append(KAboutTranslator(name.stripWhiteSpace(), email.stripWhiteSpace())); +#else + personList.append(KAboutTranslator(name.trimmed(), email.trimmed())); +#endif + } + + return personList; +} + +QString +KAboutData::aboutTranslationTeam() +{ + return i18n("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 http://i18n.kde.org</p>"); +} + +QString +KAboutData::otherText() const +{ + if (mOtherText && *mOtherText) + return i18n(mOtherText); + else + return QString::null; +} + + +QString +KAboutData::license() const +{ + QString result; + if (!copyrightStatement().isEmpty()) + result = copyrightStatement() + "\n\n"; + + QString l; + QString f; + switch ( mLicenseKey ) + { + case License_File: + f = QFile::decodeName(mLicenseText); + break; + case License_GPL_V2: + l = "GPL v2"; + f = locate("data", "LICENSES/GPL_V2"); + break; + case License_LGPL_V2: + l = "LGPL v2"; + f = locate("data", "LICENSES/LGPL_V2"); + break; + case License_BSD: + l = "BSD License"; + f = locate("data", "LICENSES/BSD"); + break; + case License_Artistic: + l = "Artistic License"; + f = locate("data", "LICENSES/ARTISTIC"); + break; + case License_QPL_V1_0: + l = "QPL v1.0"; + f = locate("data", "LICENSES/QPL_V1.0"); + break; + case License_Custom: + if (mLicenseText && *mLicenseText) + return( i18n(mLicenseText) ); + // 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"); + return result; + } + + if (!l.isEmpty()) + result += i18n("This program is distributed under the terms of the %1.").arg( l ); + + if (!f.isEmpty()) + { + QFile file(f); +#if QT_VERSION < 0x040000 + if (file.open(IO_ReadOnly)) +#else + if (file.open(QIODevice::ReadOnly)) +#endif + { + result += '\n'; + result += '\n'; + QTextStream str(&file); +#if QT_VERSION < 0x040000 + result += str.read(); +#else + result += str.readAll(); +#endif + } + } + + return result; +} + +QString +KAboutData::copyrightStatement() const +{ + if (mCopyrightStatement && *mCopyrightStatement) + return i18n(mCopyrightStatement); + else + return QString::null; +} diff --git a/src/common/nokde/nokde_kaboutdata.h b/src/common/nokde/nokde_kaboutdata.h new file mode 100644 index 0000000..13076d4 --- /dev/null +++ b/src/common/nokde/nokde_kaboutdata.h @@ -0,0 +1,571 @@ +// modified from KDE 3.4 for Windows port (Nicolas Hadacek) + +/* + * This file is part of the KDE Libraries + * Copyright (C) 2000 Espen Sand (espen@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 <qglobal.h> +#if QT_VERSION < 0x040000 +# include <qvaluelist.h> +#else +# include <Qt3Support/Q3ValueList> +# define QValueList Q3ValueList +# include <QStringList> +#endif +#include <qstring.h> +//#include <qimage.h> + +#include "nokde_klocale.h" + +#ifndef _KABOUTDATA_H_ +#define _KABOUTDATA_H_ + +class KAboutPersonPrivate; +class KAboutDataPrivate; + +/** + * This structure 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. + * + * Example Usage within a main(): + * + * KAboutData about("khello", I18N_NOOP("KHello"), "0.1", + * I18N_NOOP("A KDE version of Hello, world!"), + * KAboutData::License_LGPL, + * I18N_NOOP("Copyright (c) 2003 Developer")); + * + * about.addAuthor("Joe Developer", I18N_NOOP("developer"), "joe@host.com", 0); + * about.addCredit("Joe User", I18N_NOOP("A lot of bug reports"), + * "joe.user@host.org", 0); + * KCmdLineArgs::init(argc, argv, &about); + */ +class KDECORE_EXPORT KAboutPerson +{ +public: + /** + * Convenience constructor + * + * @param name The name of the person. + * + * @param task The task of this person. This string should be + * marked for translation, e.g. + * I18N_NOOP("Task description....") + * + * @param emailAddress The email address of the person. + * + * @param webAddress Home page of the person. + */ + KAboutPerson( const char *name, const char *task, + const char *emailAddress, const char *webAddress ) + { + mName = name; + mTask = task; + mEmailAddress = emailAddress; + mWebAddress = webAddress; + } + /** + * @internal + * Don't use. Required by QValueList + */ + KAboutPerson() {} + + /** + * The person's name + * @return the person's name (can be QString::null, if it has been + * constructed with a null name) + */ + QString name() const; + + /** + * The person's task + * @return the person's task (can be QString::null, if it has been + * constructed with a null task) + */ + QString task() const; + + /** + * The person's email address + * @return the person's email address (can be QString::null, if it has been + * constructed with a null email) + */ + QString emailAddress() const; + + /** + * The home page or a relevant link + * @return the persons home page (can be QString::null, if it has been + * constructed with a null home page) + */ + QString webAddress() const; + +private: + const char *mName; + const char *mTask; + const char *mEmailAddress; + const char *mWebAddress; + + KAboutPersonPrivate *d; +}; + +class KAboutTranslatorPrivate; +/** + * This structure is used to store information about a translator. + * It can store the translator's name and an email address. + * 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 translator's name. + * + * It's not possible to use KAboutPerson for this, because + * KAboutPerson stores internally only const char* pointers, but the + * translator information is generated dynamically from the translation + * of a dummy string. +*/ +class KDECORE_EXPORT KAboutTranslator +{ +public: + /** + * Convenience constructor + * + * @param name The name of the person. + * + * @param emailAddress The email address of the person. + */ + KAboutTranslator(const QString & name=QString::null, + const QString & emailAddress=QString::null); + + /** + * The translator's name + * @return the translators's name (can be QString::null, if it has been + * constructed with a null name) + */ + QString name() const; + + /** + * The translator's email + * @return the translator's email address (can be QString::null, if it has been + * constructed with a null email) + */ + QString emailAddress() const; + +private: + QString mName; + QString mEmail; + KAboutTranslatorPrivate* d; +}; + + +/** + * 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). + * + * @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: + /** + * Descibes the license of the software. + */ + enum LicenseKey + { + 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 + }; + + public: + /** + * Constructor. + * + * @param appName The program name used internally. Example: "kedit" + * + * @param programName A displayable program name string. This string + * should be marked for translation. Example: I18N_NOOP("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: I18N_NOOP("A simple text editor.") + * + * @param licenseType The license identifier. Use setLicenseText if + * you use a license not predefined here. + * + * @param copyrightStatement A copyright statement, that can look like this: + * "(c) 1999-2000, Name". The string specified here is not modified + * in any manner. The author information from addAuthor is not + * used. + * + * @param text 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. + * + * @param bugsEmailAddress The bug report email address string. + * This defaults to the kde.org bug system. + * + */ + KAboutData( const char *appName, + const char *programName, + const char *version, + const char *shortDescription = 0, + int licenseType = License_Unknown, + const char *copyrightStatement = 0, + const char *text = 0, + const char *homePageAddress = 0, + const char *bugsEmailAddress = "submit@bugs.kde.org" + ); + + ~KAboutData(); + + /** + * Defines an author. You can call this function as many times 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 in UTF-8 encoding. + * + * @param task What the person is responsible for. This text can contain + * newlines. It should be marked for translation like this: + * I18N_NOOP("Task description..."). Can be 0. + * + * @param emailAddress An Email address where the person can be reached. + * Can be 0. + * + * @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 0. + * + */ + void addAuthor( const char *name, + const char *task=0, + const char *emailAddress=0, + const char *webAddress=0 ); + + /** + * Defines a person that deserves credit. You can call this function + * as many times you need. Each entry is appended to a list. + * + * @param name The person's name in UTF-8 encoding. + * + * @param task What the person has done to deserve the honor. The + * text can contain newlines. It should be marked for + * translation like this: I18N_NOOP("Task description...") + * Can be 0. + * + * @param emailAddress An Email address when the person can be reached. + * Can be 0. + * + * @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 0. + * + */ + void addCredit( const char *name, + const char *task=0, + const char *emailAddress=0, + const char *webAddress=0 ); + + /** + * Sets the name of the translator of the gui. Since this depends + * on the language, just use a dummy text marked for translation. + * + * For example: + * \code + * setTranslator(I18N_NOOP("_: NAME OF TRANSLATORS\\nYour names") + * ,I18N_NOOP("_: EMAIL OF TRANSLATORS\\nYour 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. + * + * Note: If you are using the default KDE automake environment, + * there is no need to use this function, because the two + * default strings above are added to the applications po file + * automatically. + * + * @param name the name of the translator + * @param emailAddress the email address of the translator + * @see KAboutTranslator + */ + void setTranslator(const char* name, const char* emailAddress); + + /** + * Defines a license text. + * + * The text will be translated if it got marked for + * translations with the I18N_NOOP() macro. + * + * Example: + * \code + * setLicenseText( I18N_NOOP("This is my license")); + * \endcode + * + * NOTE: No copy of the text is made. + * + * @param license The license text in utf8 encoding. + */ + void setLicenseText( const char *license ); + + /** + * Defines a license text. + * + * @param file File containing the license text. + */ + void setLicenseTextFile( const QString &file ); + + /** + * Defines the program name used internally. + * + * @param appName The application name. Example: "kate". + */ + void setAppName( const char *appName ); + + /** + * Defines the displayable program name string. + * + * @param programName The program name. This string should be + * marked for translation. + * Example: I18N_NOOP("Advanced Text Editor"). + */ + void setProgramName( const char* programName ); + + /** + * Defines the program logo. + * Use this if you need to have application logo + * in AboutData other than application icon. + * + * @param image logo image. + * @see programLogo() + * @since 3.4 + */ +// void setProgramLogo(const QImage& image); + + /** + * Defines the program version string. + * + * @param version The program version. + */ + void setVersion( const char* version ); + + /** + * Defines a short description of what the program does. + * + * @param shortDescription The program description This string should be marked + * for translation. Example: I18N_NOOP("An advanced text editor + * with syntax highlithing support."). + */ + void setShortDescription( const char *shortDescription ); + + /** + * Defines the license identifier. + * + * @param licenseKey The license identifier. + */ + void setLicense( LicenseKey licenseKey); + + /** + * Defines the copyright statement to show when displaying the license. + * + * @param copyrightStatement A copyright statement, that can look like + * this: "(c) 1999-2000, Name". The string specified here is not + * modified in any manner. The author information from addAuthor + * is not used. + */ + void setCopyrightStatement( const char *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. + */ + void setOtherText( const char *otherText ); + + /** + * Defines the program homepage. + * + * @param homepage The program homepage string. + * Start the address with "http://". "http://kate.kde.org" is + * is correct, "kde.kde.org" is not. + */ + void setHomepage( const char *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. + */ + void setBugAddress( const char *bugAddress ); + + /** + * Defines the product name wich 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. 'product/component' like + * 'kontact/summary'. + * + * @param name The name of product + */ + void setProductName( const char *name ); + + /** + * Returns the application's internal name. + * @return the internal program name. + */ + const char *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. + */ + const char *productName() const; + + /** + * Returns the translated program name. + * @return the program name (translated). + */ + QString programName() const; + + /** + * Returns the program logo image. + * @return the program logo data or null image if there is + * no custom application logo defined. + * @since 3.4 + */ +// QImage programLogo() const; + + /** + * Returns the program's version. + * @return the version string. + */ + QString version() const; + + /** + * Returns a short, translated description. + * @return the short description (translated). Can be + * QString::null if not set. + */ + QString shortDescription() const; + + /** + * Returns the application homepage. + * @return the application homepage URL. Can be QString::null if + * not set. + */ + QString homepage() const; + + /** + * Returns the email address for bugs. + * @return the email address where to report bugs. + */ + QString bugAddress() const; + + /** + * Returns a list of authors. + * @return author information (list of persons). + */ + const QValueList<KAboutPerson> authors() const; + + /** + * Returns a list of persons who contributed. + * @return credit information (list of persons). + */ + const QValueList<KAboutPerson> credits() const; + + /** + * Returns a list of translators. + * @return translators information (list of persons) + */ + const QValueList<KAboutTranslator> 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::null 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. + */ + QString license() const; + + /** + * Returns the copyright statement. + * @return the copyright statement. Can be QString::null if not set. + */ + QString copyrightStatement() const; + + private: + const char *mAppName; + const char *mProgramName; + const char *mVersion; + const char *mShortDescription; + int mLicenseKey; + const char *mCopyrightStatement; + const char *mOtherText; + const char *mHomepageAddress; + const char *mBugEmailAddress; + QValueList<KAboutPerson> mAuthorList; + QValueList<KAboutPerson> mCreditList; + const char *mLicenseText; + + KAboutDataPrivate *d; +}; + +#endif + diff --git a/src/common/nokde/nokde_kcmdlineargs.cpp b/src/common/nokde/nokde_kcmdlineargs.cpp new file mode 100644 index 0000000..7f026fe --- /dev/null +++ b/src/common/nokde/nokde_kcmdlineargs.cpp @@ -0,0 +1,1329 @@ +// modified from KDE 3.4 for Windows port (Nicolas Hadacek) + +/* + 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 <config.h> + +#include <sys/param.h> + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif + +#include <qdir.h> +#include <qfile.h> +#include <qurl.h> + +#include <qstringlist.h> +#if QT_VERSION<0x040000 +# include <qasciidict.h> +# include <qstrlist.h> +#else +# include <Qt3Support/Q3StrList> +# define QGList Q3GList +# define QStrList Q3StrList +# include <Qt3Support/Q3AsciiDict> +# define QGDict Q3GDict +# define QAsciiDict Q3AsciiDict +# include <Qt3Support/Q3PtrCollection> +# define QPtrCollection Q3PtrCollection +#endif + + +#include "nokde_kcmdlineargs.h" +#include "nokde_kaboutdata.h" +#include "nokde_klocale.h" +//#include <kapplication.h> +//#include <kglobal.h> +//#include <kstringhandler.h> +//#include <kstaticdeleter.h> + +#ifdef Q_WS_X11 +#define DISPLAY "DISPLAY" +#elif defined(Q_WS_QWS) +#define DISPLAY "QWS_DISPLAY" +#endif + +#ifdef Q_WS_WIN +#include <win32_utils.h> +#endif + +template class QAsciiDict<QCString>; +template class QPtrList<KCmdLineArgs>; + +class KCmdLineParsedOptions : public QAsciiDict<QCString> +{ +public: + KCmdLineParsedOptions() + : QAsciiDict<QCString>( 7 ) { } + + // WABA: Huh? + // The compiler doesn't find KCmdLineParsedOptions::write(s) by itself ??? + // WABA: No, because there is another write function that hides the + // write function in the base class even though this function has a + // different signature. (obscure C++ feature) + QDataStream& save( QDataStream &s) const + { return QGDict::write(s); } + + QDataStream& load( QDataStream &s) + { return QGDict::read(s); } + +protected: + virtual QDataStream& write( QDataStream &s, QPtrCollection::Item data) const + { + QCString *str = (QCString *) data; + s << (*str); + return s; + } + + virtual QDataStream& read( QDataStream &s, QPtrCollection::Item &item) + { + QCString *str = new QCString; + s >> (*str); + item = (void *)str; + return s; + } + +}; + +class KCmdLineParsedArgs : public QStrList +{ +public: + KCmdLineParsedArgs() + : QStrList( true ) { } + QDataStream& save( QDataStream &s) const + { return QGList::write(s); } + + QDataStream& load( QDataStream &s) + { return QGList::read(s); } +}; + + +class KCmdLineArgsList: public QPtrList<KCmdLineArgs> +{ +public: + KCmdLineArgsList() { } +}; + +KCmdLineArgsList *KCmdLineArgs::argsList = 0; +int KCmdLineArgs::argc = 0; +char **KCmdLineArgs::argv = 0; +char *KCmdLineArgs::mCwd = 0; +//static KStaticDeleter <char> mCwdd; +const KAboutData *KCmdLineArgs::about = 0; +bool KCmdLineArgs::parsed = false; +bool KCmdLineArgs::ignoreUnknown = false; + +// +// Static functions +// + +void +KCmdLineArgs::init(int _argc, char **_argv, const char *_appname, const char* programName, + const char *_description, const char *_version, bool noKApp) +{ + init(_argc, _argv, + new KAboutData(_appname, programName, _version, _description), + noKApp); +} + +void +KCmdLineArgs::init(int _argc, char **_argv, const char *_appname, + const char *_description, const char *_version, bool noKApp) +{ + init(_argc, _argv, + new KAboutData(_appname, _appname, _version, _description), + noKApp); +} + +void +KCmdLineArgs::initIgnore(int _argc, char **_argv, const char *_appname ) +{ + init(_argc, _argv, + new KAboutData(_appname, _appname, "unknown", "KDE Application", false)); + ignoreUnknown = true; +} + +void +KCmdLineArgs::init(const KAboutData* ab) +{ + char **_argv = (char **) malloc(sizeof(char *)); + _argv[0] = (char *) ab->appName(); + init(1,_argv,ab, true); +} + + +void +KCmdLineArgs::init(int _argc, char **_argv, const KAboutData *_about, bool /*noKApp*/) +{ + argc = _argc; + argv = _argv; + + if (!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 (argc) { + char *p = strrchr( argv[0], '/'); + if (p) + argv[0] = p+1; + } + + about = _about; + parsed = false; + mCwd = /*mCwdd.setObject(mCwd, */new char [PATH_MAX+1];//, true); + getcwd(mCwd, PATH_MAX); +#ifdef Q_WS_WIN + win32_slashify(mCwd, PATH_MAX); +#endif +// if (!noKApp) +// KApplication::addCmdLineOptions(); +} + +QString KCmdLineArgs::cwd() +{ + return QFile::decodeName(QCString(mCwd)); +} + +const char * KCmdLineArgs::appName() +{ + if (!argc) return 0; + return argv[0]; +} + +void +KCmdLineArgs::addCmdLineOptions( const KCmdLineOptions *options, const char *name, + const char *id, const char *afterId) +{ + if (!argsList) + argsList = new KCmdLineArgsList(); + + int pos = argsList->count(); + + if (pos && id && argsList->last() && !argsList->last()->name) + pos--; + + KCmdLineArgs *args; + int i = 0; + for(args = argsList->first(); args; args = argsList->next(), i++) + { + if (!id && !args->id) + return; // Options already present. + + if (id && args->id && (::qstrcmp(id, args->id) == 0)) + return; // Options already present. + + if (afterId && args->id && (::qstrcmp(afterId, args->id) == 0)) + pos = i+1; + } + + assert( parsed == false ); // You must add _ALL_ cmd line options + // before accessing the arguments! + args = new KCmdLineArgs(options, name, id); + argsList->insert(pos, args); +} + +void +KCmdLineArgs::saveAppArgs( QDataStream &ds) +{ + if (!parsed) + parseAllArgs(); + + // Remove Qt and KDE options. + removeArgs("qt"); + removeArgs("kde"); + + QCString qCwd = mCwd; + ds << qCwd; + + uint count = argsList ? argsList->count() : 0; + ds << count; + + if (!count) return; + + KCmdLineArgs *args; + for(args = argsList->first(); args; args = argsList->next()) + { + ds << QCString(args->id); + args->save(ds); + } +} + +void +KCmdLineArgs::loadAppArgs( QDataStream &ds) +{ + // Remove Qt and KDE options. + removeArgs("qt"); + removeArgs("kde"); + + KCmdLineArgs *args; + if ( argsList ) { + for(args = argsList->first(); args; args = argsList->next()) + { + args->clear(); + } + } + + if (ds.atEnd()) + return; + + QCString qCwd; + ds >> qCwd; + delete [] mCwd; + + mCwd = /*mCwdd.setObject(mCwd, */new char[qCwd.length()+1];//, true); + strncpy(mCwd, qCwd.data(), qCwd.length()+1); + + uint count; + ds >> count; + + while(count--) + { + QCString id; + ds >> id; + assert( argsList ); + for(args = argsList->first(); args; args = argsList->next()) + { + if (args->id == id) + { + args->load(ds); + break; + } + } + } + parsed = true; +} + +KCmdLineArgs *KCmdLineArgs::parsedArgs(const char *id) +{ + KCmdLineArgs *args = argsList ? argsList->first() : 0; + while(args) + { + if ((id && ::qstrcmp(args->id, id) == 0) || (!id && !args->id)) + { + if (!parsed) + parseAllArgs(); + return args; + } + args = argsList->next(); + } + + return args; +} + +void KCmdLineArgs::removeArgs(const char *id) +{ + KCmdLineArgs *args = argsList ? argsList->first() : 0; + while(args) + { + if (args->id && id && ::qstrcmp(args->id, id) == 0) + { + if (!parsed) + parseAllArgs(); + break; + } + args = argsList->next(); + } + + if (args) + delete args; +} + +/* + * @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, QCString &opt, + const char *&opt_name, const char *&def, bool &enabled) +{ + int result; + bool inverse; + int len = opt.length(); + while(options && options->name) + { + result = 0; + inverse = false; + opt_name = options->name; + if ((opt_name[0] == ':') || (opt_name[0] == 0)) + { + options++; + continue; + } + + if (opt_name[0] == '!') + { + opt_name++; + result = 4; + } + if ((opt_name[0] == 'n') && (opt_name[1] == 'o')) + { + opt_name += 2; + inverse = true; + } + if (strncmp(opt.data(), opt_name, len) == 0) + { + opt_name += len; + if (!opt_name[0]) + { + if (inverse) + return result+2; + + if (!options->description) + { + options++; + if (!options->name) + return result+0; + QCString nextOption = options->name; +# if QT_VERSION<0x040000 + int p = nextOption.find(' '); +#else + int p = QString(nextOption).indexOf(' '); +#endif + if (p > 0) + nextOption = nextOption.left(p); + if (strncmp(nextOption.data(), "no", 2) == 0) + { + nextOption = nextOption.mid(2); + enabled = !enabled; + } + result = findOption(options, nextOption, opt_name, def, enabled); + assert(result); + opt = nextOption; + return result; + } + + return 1; + } + if (opt_name[0] == ' ') + { + opt_name++; + def = options->def; + return result+3; + } + } + + options++; + } + return 0; +} + + +void +KCmdLineArgs::findOption(const char *_opt, QCString opt, int &i, bool _enabled, bool &moreOptions) +{ + KCmdLineArgs *args = argsList->first(); + const char *opt_name; + const char *def; + QCString argument; +# if QT_VERSION<0x040000 + int j = opt.find('='); +#else + int j = QString(opt).indexOf('='); +#endif + if (j != -1) + { + argument = opt.mid(j+1); + opt = opt.left(j); + } + + bool enabled = true; + int result = 0; + while (args) + { + enabled = _enabled; + result = ::findOption(args->options, opt, opt_name, def, enabled); + if (result) break; + args = argsList->next(); + } + if (!args && (_opt[0] == '-') && _opt[1] && (_opt[1] != '-')) + { + // Option not found check if it is a valid option + // in the style of -Pprinter1 or ps -aux + int p = 1; + while (true) + { + QCString singleCharOption = " "; + singleCharOption[0] = _opt[p]; + args = argsList->first(); + while (args) + { + enabled = _enabled; + result = ::findOption(args->options, singleCharOption, opt_name, def, enabled); + if (result) break; + args = argsList->next(); + } + if (!args) + break; // Unknown argument + + p++; + if (result == 1) // Single option + { + args->setOption(singleCharOption, enabled); + if (_opt[p]) + continue; // Next option + else + return; // Finished + } + else if (result == 3) // This option takes an argument + { + if (argument.isEmpty()) + { + argument = _opt+p; + } + args->setOption(singleCharOption, argument.data()); + return; + } + break; // Unknown argument + } + args = 0; + result = 0; + } + + if (!args || !result) + { + if (ignoreUnknown) + return; + enable_i18n(); + usage( i18n("Unknown option '%1'.").arg(QString::fromLocal8Bit(_opt))); + } + + if ((result & 4) != 0) + { + result &= ~4; + moreOptions = false; + } + + if (result == 3) // This option takes an argument + { + if (!enabled) + { + if (ignoreUnknown) + return; + enable_i18n(); + usage( i18n("Unknown option '%1'.").arg(QString::fromLocal8Bit(_opt))); + } + if (argument.isEmpty()) + { + i++; + if (i >= argc) + { + enable_i18n(); + usage( i18n("'%1' missing.").arg( opt_name)); + } + argument = argv[i]; + } + args->setOption(opt, argument.data()); + } + else + { + args->setOption(opt, enabled); + } +} + +void +KCmdLineArgs::printQ(const QString &msg) +{ +# if QT_VERSION<0x040000 + QCString localMsg = msg.local8Bit(); +#else + QCString localMsg = msg.toLocal8Bit(); +#endif + fprintf(stdout, "%s", localMsg.data()); +} + +void +KCmdLineArgs::parseAllArgs() +{ + bool allowArgs = false; + bool inOptions = true; + bool everythingAfterArgIsArgs = false; + KCmdLineArgs *appOptions = argsList->last(); + if (!appOptions->id) + { + const KCmdLineOptions *option = appOptions->options; + while(option && option->name) + { + if (option->name[0] == '+') + allowArgs = true; + if ( option->name[0] == '!' && option->name[1] == '+' ) + { + allowArgs = true; + everythingAfterArgIsArgs = true; + } + option++; + } + } + for(int i = 1; i < argc; i++) + { + if (!argv[i]) + continue; + + if ((argv[i][0] == '-') && argv[i][1] && inOptions) + { + bool enabled = true; + const char *option = &argv[i][1]; + const char *orig = argv[i]; + if (option[0] == '-') + { + option++; + argv[i]++; + if (!option[0]) + { + inOptions = false; + continue; + } + } + if (::qstrcmp(option, "help") == 0) + { + usage(0); + } + else if (strncmp(option, "help-",5) == 0) + { + usage(option+5); + } + else if ( (::qstrcmp(option, "version") == 0) || + (::qstrcmp(option, "v") == 0)) + { + printQ( QString("Qt: %1\n").arg(qVersion())); +// printQ( QString("KDE: %1\n").arg(KDE_VERSION_STRING)); + printQ( QString("%1: %2\n"). + arg(about->programName()).arg(about->version())); + exit(0); + } else if ( (::qstrcmp(option, "license") == 0) ) + { + enable_i18n(); + printQ( about->license() ); + printQ( "\n" ); + exit(0); + } else if ( ::qstrcmp( option, "author") == 0 ) { + enable_i18n(); + if ( about ) { + const QValueList<KAboutPerson> authors = about->authors(); + if ( !authors.isEmpty() ) { + QString authorlist; + for (QValueList<KAboutPerson>::ConstIterator it = authors.begin(); it != authors.end(); ++it ) { + QString email; + if ( !(*it).emailAddress().isEmpty() ) + email = " <" + (*it).emailAddress() + ">"; + authorlist += QString(" ") + (*it).name() + email + "\n"; + } + printQ( i18n("the 2nd argument is a list of name+address, one on each line","%1 was written by\n%2").arg ( QString(about->programName()) ).arg( authorlist ) ); + } + } else { + printQ( i18n("%1 was written by somebody who wants to remain anonymous.").arg(about->programName()) ); + } + if (!about->bugAddress().isEmpty()) + { + if (about->bugAddress() == "submit@bugs.kde.org") + printQ( i18n( "Please use http://bugs.kde.org to report bugs, do not mail the authors directly.\n" ) ); + else + printQ( i18n( "Please use %1 to report bugs, do not mail the authors directly.\n" ).arg(about->bugAddress()) ); + } + exit(0); + } else { + if ((option[0] == 'n') && (option[1] == 'o')) + { + option += 2; + enabled = false; + } + findOption(orig, option, i, enabled, inOptions); + } + } + else + { + // Check whether appOptions allows these arguments + if (!allowArgs) + { + if (ignoreUnknown) + continue; + enable_i18n(); + usage( i18n("Unexpected argument '%1'.").arg(QString::fromLocal8Bit(argv[i]))); + } + else + { + appOptions->addArgument(argv[i]); + if (everythingAfterArgIsArgs) + inOptions = false; + } + } + } + parsed = true; +} + +/** + * For KApplication only: + * + * Return argc + */ +int * +KCmdLineArgs::qt_argc() +{ +// if (!argsList) +// KApplication::addCmdLineOptions(); // Lazy bastards! + + static int qt_argc = -1; + if( qt_argc != -1 ) + return &qt_argc; + + KCmdLineArgs *args = parsedArgs("qt"); + assert(args); // No qt options have been added! + if (!argv) + { + fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n"); + fprintf(stderr, "Application has not called KCmdLineArgs::init(...).\n\n"); + + assert( 0 ); + exit(255); + } + + assert(argc >= (args->count()+1)); + qt_argc = args->count() +1; + return &qt_argc; +} + +/** + * For KApplication only: + * + * Return argv + */ +char *** +KCmdLineArgs::qt_argv() +{ +// if (!argsList) +// KApplication::addCmdLineOptions(); // Lazy bastards! + + static char** qt_argv; + if( qt_argv != NULL ) + return &qt_argv; + + KCmdLineArgs *args = parsedArgs("qt"); + assert(args); // No qt options have been added! + if (!argv) + { + fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n"); + fprintf(stderr, "Application has not called KCmdLineArgs::init(...).\n\n"); + + assert( 0 ); + exit(255); + } + + qt_argv = new char*[ args->count() + 2 ]; + qt_argv[ 0 ] = qstrdup( appName()); + int i = 0; + for(; i < args->count(); i++) + { + qt_argv[i+1] = qstrdup((char *) args->arg(i)); + } + qt_argv[i+1] = 0; + + return &qt_argv; +} + +void +KCmdLineArgs::enable_i18n() +{ + // called twice or too late +/* if (KGlobal::_locale) + return; + + if (!KGlobal::_instance) { + KInstance *instance = new KInstance(about); + (void) instance->config(); + // Don't delete instance! + }*/ +} + +void +KCmdLineArgs::usage(const QString &error) +{ +// assert(KGlobal::_locale); +# if QT_VERSION<0x040000 + QCString localError = error.local8Bit(); +#else + QCString localError = error.toLocal8Bit(); +#endif + if (localError[error.length()-1] == '\n') + localError = localError.left(error.length()-1); + fprintf(stderr, "%s: %s\n", argv[0], localError.data()); + + QString tmp = i18n("Use --help to get a list of available command line options."); +# if QT_VERSION<0x040000 + localError = tmp.local8Bit(); +#else + localError = tmp.toLocal8Bit(); +#endif + fprintf(stderr, "%s: %s\n", argv[0], localError.data()); + exit(254); +} + +void +KCmdLineArgs::usage(const char *id) +{ + enable_i18n(); + assert(argsList != 0); // It's an error to call usage(...) without + // having done addCmdLineOptions first! + + QString optionFormatString = " %1 %2\n"; + QString optionFormatStringDef = " %1 %2 [%3]\n"; + QString optionHeaderString = i18n("\n%1:\n"); + QString tmp; + QString usage; + + KCmdLineArgs *args = argsList->last(); + + if (!(args->id) && (args->options) && + (args->options->name) && (args->options->name[0] != '+')) + { + usage = i18n("[options] ")+usage; + } + + while(args) + { + if (args->name) + { + usage = i18n("[%1-options]").arg(args->name)+" "+usage; + } + args = argsList->prev(); + } + + KCmdLineArgs *appOptions = argsList->last(); + if (!appOptions->id) + { + const KCmdLineOptions *option = appOptions->options; + while(option && option->name) + { + if (option->name[0] == '+') + usage = usage + (option->name+1) + " "; + else if ( option->name[0] == '!' && option->name[1] == '+' ) + usage = usage + (option->name+2) + " "; + + option++; + } + } + + printQ(i18n("Usage: %1 %2\n").arg(argv[0]).arg(usage)); + printQ("\n"+about->shortDescription()+"\n"); + + printQ(optionHeaderString.arg(i18n("Generic options"))); + printQ(optionFormatString.arg("--help", -25).arg(i18n("Show help about options"))); + + args = argsList->first(); + while(args) + { + if (args->name && args->id) + { + QString option = QString("--help-%1").arg(args->id); + QString desc = i18n("Show %1 specific options").arg(args->name); + + printQ(optionFormatString.arg(option, -25).arg(desc)); + } + args = argsList->next(); + } + + printQ(optionFormatString.arg("--help-all",-25).arg(i18n("Show all options"))); + printQ(optionFormatString.arg("--author",-25).arg(i18n("Show author information"))); + printQ(optionFormatString.arg("-v, --version",-25).arg(i18n("Show version information"))); + printQ(optionFormatString.arg("--license",-25).arg(i18n("Show license information"))); + printQ(optionFormatString.arg("--", -25).arg(i18n("End of options"))); + + args = argsList->first(); // Sets current to 1st. + + bool showAll = id && (::qstrcmp(id, "all") == 0); + + if (!showAll) + { + while(args) + { + if (!id && !args->id) break; + if (id && (::qstrcmp(args->id, id) == 0)) break; + args = argsList->next(); + } + } + + while(args) + { + bool hasArgs = false; + bool hasOptions = false; + QString optionsHeader; + if (args->name) + optionsHeader = optionHeaderString.arg(i18n("%1 options").arg(QString::fromLatin1(args->name))); + else + optionsHeader = i18n("\nOptions:\n"); + + while (args) + { + const KCmdLineOptions *option = args->options; + QCString opt = ""; +// + while(option && option->name) + { + QString description; + QString descriptionRest; + QStringList dl; + + // Option header + if (option->name[0] == ':') + { + if (option->description) + { + optionsHeader = "\n"+i18n(option->description); + if (!optionsHeader.endsWith("\n")) + optionsHeader.append("\n"); + hasOptions = false; + } + option++; + continue; + } + + // Free-form comment + if (option->name[0] == 0) + { + if (option->description) + { + QString tmp = "\n"+i18n(option->description); + if (!tmp.endsWith("\n")) + tmp.append("\n"); + printQ(tmp); + } + option++; + continue; + } + + // Options + if (option->description) + { + description = i18n(option->description); +# if QT_VERSION<0x040000 + dl = QStringList::split("\n", description, true); +#else + dl = description.split("\n"); +#endif + description = dl.first(); + dl.erase( dl.begin() ); + } + QCString name = option->name; + if (name[0] == '!') + name = name.mid(1); + + if (name[0] == '+') + { + if (!hasArgs) + { + printQ(i18n("\nArguments:\n")); + hasArgs = true; + } + + name = name.mid(1); + if ((name[0] == '[') && (name[name.length()-1] == ']')) + name = name.mid(1, name.length()-2); + printQ(optionFormatString.arg(QString(name), -25) + .arg(description)); + } + else + { + if (!hasOptions) + { + printQ(optionsHeader); + hasOptions = true; + } + + if ((name.length() == 1) || (name[1] == ' ')) + name = "-"+name; + else + name = "--"+name; + if (!option->description) + { + opt = name + ", "; + } + else + { + opt = opt + name; + if (!option->def) + { + printQ(optionFormatString.arg(QString(opt), -25) + .arg(description)); + } + else + { + printQ(optionFormatStringDef.arg(QString(opt), -25) + .arg(description).arg(option->def)); + } + opt = ""; + } + } + for(QStringList::Iterator it = dl.begin(); + it != dl.end(); + ++it) + { + printQ(optionFormatString.arg("", -25).arg(*it)); + } + + option++; + } + args = argsList->next(); + if (!args || args->name || !args->id) break; + } + if (!showAll) break; + } + + exit(254); +} + +// +// Member functions +// + +/** + * Constructor. + * + * The given arguments are assumed to be constants. + */ +KCmdLineArgs::KCmdLineArgs( const KCmdLineOptions *_options, + const char *_name, const char *_id) + : options(_options), name(_name), id(_id) +{ + parsedOptionList = 0; + parsedArgList = 0; + isQt = (::qstrcmp(id, "qt") == 0); +} + +/** + * Destructor. + */ +KCmdLineArgs::~KCmdLineArgs() +{ + delete parsedOptionList; + delete parsedArgList; + if (argsList) + argsList->removeRef(this); +} + +void +KCmdLineArgs::clear() +{ + delete parsedArgList; + parsedArgList = 0; + delete parsedOptionList; + parsedOptionList = 0; +} + +void +KCmdLineArgs::reset() +{ + if ( argsList ) { + argsList->setAutoDelete( true ); + argsList->clear(); + delete argsList; + argsList = 0; + } + parsed = false; +} + +void +KCmdLineArgs::save( QDataStream &ds) const +{ + uint count = 0; + if (parsedOptionList) + parsedOptionList->save( ds ); + else + ds << count; + + if (parsedArgList) + parsedArgList->save( ds ); + else + ds << count; +} + +void +KCmdLineArgs::load( QDataStream &ds) +{ + if (!parsedOptionList) parsedOptionList = new KCmdLineParsedOptions; + if (!parsedArgList) parsedArgList = new KCmdLineParsedArgs; + + parsedOptionList->load( ds ); + parsedArgList->load( ds ); + + if (parsedOptionList->count() == 0) + { + delete parsedOptionList; + parsedOptionList = 0; + } + if (parsedArgList->count() == 0) + { + delete parsedArgList; + parsedArgList = 0; + } +} + +void +KCmdLineArgs::setOption(const QCString &opt, bool enabled) +{ + if (isQt) + { + // Qt does it own parsing. + QCString arg = "-"; + if( !enabled ) + arg += "no"; + arg += opt; + addArgument(arg); + } + if (!parsedOptionList) { + parsedOptionList = new KCmdLineParsedOptions; + parsedOptionList->setAutoDelete(true); + } + + if (enabled) + parsedOptionList->replace( opt, new QCString("t") ); + else + parsedOptionList->replace( opt, new QCString("f") ); +} + +void +KCmdLineArgs::setOption(const QCString &opt, const char *value) +{ + if (isQt) + { + // Qt does it's own parsing. + QCString arg = "-"; + arg += opt; + addArgument(arg); + addArgument(value); + +#ifdef Q_WS_X11 + // Hack coming up! + if (arg == "-display") + { + setenv(DISPLAY, value, true); + } +#endif + } + if (!parsedOptionList) { + parsedOptionList = new KCmdLineParsedOptions; + parsedOptionList->setAutoDelete(true); + } + + parsedOptionList->insert( opt, new QCString(value) ); +} + +QCString +KCmdLineArgs::getOption(const char *_opt) const +{ + QCString *value = 0; + if (parsedOptionList) + { + value = parsedOptionList->find(_opt); + } + + if (value) + return (*value); + + // Look up the default. + const char *opt_name; + const char *def; + bool dummy = true; + QCString opt = _opt; + int result = ::findOption( 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, _opt); + fprintf(stderr, "has never been specified via addCmdLineOptions( ... )\n\n"); + + assert( 0 ); + exit(255); + } + return QCString(def); +} + +QCStringList +KCmdLineArgs::getOptionList(const char *_opt) const +{ + QCStringList result; + if (!parsedOptionList) + return result; + + while(true) + { + QCString *value = parsedOptionList->take(_opt); + if (!value) + break; + result.prepend(*value); + delete 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. + for(QCStringList::ConstIterator it=result.begin(); + it != result.end(); + ++it) + { + parsedOptionList->insert(_opt, new QCString(*it)); + } + return result; +} + +bool +KCmdLineArgs::isSet(const char *_opt) const +{ + // Look up the default. + const char *opt_name; + const char *def; + bool dummy = true; + QCString opt = _opt; + int result = ::findOption( options, opt, opt_name, def, dummy) & ~4; + + if (result == 0) + { + fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n"); + fprintf(stderr, "Application requests for isSet(\"%s\") but the \"%s\" option\n", + _opt, _opt); + fprintf(stderr, "has never been specified via addCmdLineOptions( ... )\n\n"); + + assert( 0 ); + exit(255); + } + + QCString *value = 0; + if (parsedOptionList) + { + value = parsedOptionList->find(opt); + } + + if (value) + { + if (result == 3) + return true; + else + return ((*value)[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 +{ + if (!parsedArgList) + return 0; + return parsedArgList->count(); +} + +const char * +KCmdLineArgs::arg(int n) const +{ + if (!parsedArgList || (n >= (int) 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); + + assert( 0 ); + exit(255); + } + + return parsedArgList->at(n); +} + +KURL +KCmdLineArgs::url(int n) const +{ + return makeURL( arg(n) ); +} + +KURL KCmdLineArgs::makeURL(const char *_urlArg) +{ + QString urlArg = QFile::decodeName(_urlArg); + if (!QDir::isRelativePath(urlArg)) + { + //KURL result; + //result.setPath(urlArg); + //return result; // Absolute path. + return urlArg; + } +# if QT_VERSION<0x040000 + if ( !QUrl::isRelativeUrl(urlArg) ) +#else + if ( !QUrl(urlArg).isRelative() ) +#endif + //return KURL(urlArg); // Argument is a URL + return urlArg; + +// KURL result; +// result.setPath( cwd()+"/"+urlArg ); +// result.cleanPath(); +// return result; // Relative path + return cwd() + "/" + urlArg; +} + +void +KCmdLineArgs::addArgument(const char *argument) +{ + if (!parsedArgList) + parsedArgList = new KCmdLineParsedArgs; + + parsedArgList->append(argument); +} + +static const KCmdLineOptions kde_tempfile_option[] = +{ + { "tempfile", I18N_NOOP("The files/URLs opened by the application will be deleted after use"), 0}, + KCmdLineLastOption +}; + +void +KCmdLineArgs::addTempFileOption() +{ + KCmdLineArgs::addCmdLineOptions( kde_tempfile_option, "KDE-tempfile", "kde-tempfile" ); +} + +bool KCmdLineArgs::isTempFileSet() +{ + KCmdLineArgs* args = KCmdLineArgs::parsedArgs( "kde-tempfile" ); + if ( args ) + return args->isSet( "tempfile" ); + return false; +} diff --git a/src/common/nokde/nokde_kcmdlineargs.h b/src/common/nokde/nokde_kcmdlineargs.h new file mode 100644 index 0000000..8b79b62 --- /dev/null +++ b/src/common/nokde/nokde_kcmdlineargs.h @@ -0,0 +1,701 @@ +// modified from KDE 3.4 for Windows port (Nicolas Hadacek) + +/* 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 "nokde_klocale.h" +#include "nokde_kurl.h" + +# if QT_VERSION<0x040000 +# include <qptrlist.h> +# include <qvaluelist.h> +#else +# include <Qt3Support/Q3CString> +# define QCString Q3CString +# include <Qt3Support/Q3PtrList> +# define QPtrList Q3PtrList +# include <Qt3Support/Q3ValueList> +# define QValueList Q3ValueList +#endif +# include <qstring.h> + +typedef QValueList<QCString> QCStringList; + +/** + * @short Structure 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 + */ +struct KDECORE_EXPORT KCmdLineOptions +{ + /** + * The name of the argument as it should be called on the command line and + * appear in <i>myapp --help</i>. + * + * Note that if this option starts 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 + */ + const char *name; + /** + * The text description of the option as should appear in + * <i>myapp --help</i>. This value should be wrapped with I18N_NOOP(). + */ + const char *description; + /** + * The default value for the option, if it is not specified on the + * command line. + */ + const char *def; // Default +}; + +#define KCmdLineLastOption { 0, 0, 0 } + +class KCmdLineArgsList; +class KApplication; +class KUniqueApplication; +class KCmdLineParsedOptions; +class KCmdLineParsedArgs; +class KAboutData; +class KCmdLineArgsPrivate; + +/** + * @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, description, version); + * + * // Tell which options are supported + * 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 + * QCString anotherOptionArg = args->getOption("another-option"); + * + * // Arguments (e.g. files to open) + * for(int i = 0; i < args->count(); i++) // Counting start at 0! + * { + * // don't forget to convert to Unicode! + * openFile( QFile::decodeName( 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 + * static const KCmdLineOptions options[] = + * { + * { "a", I18N_NOOP("A short binary option"), 0 }, + * { "b \<file>", I18N_NOOP("A short option which takes an argument"), 0 }, + * { "c \<speed>", I18N_NOOP("As above but with a default value"), "9600" }, + * { "option1", I18N_NOOP("A long binary option, off by default"), 0 }, + * { "nooption2", I18N_NOOP("A long binary option, on by default"), 0 }, + * { ":", I18N_NOOP("Extra options:"), 0 }, + * { "option3 \<file>", I18N_NOOP("A long option which takes an argument"), 0 }, + * { "option4 \<speed>", I18N_NOOP("A long option which takes an argument, defaulting to 9600"), "9600" }, + * { "d", 0, 0 }, + * { "option5", I18N_NOOP("A long option which has a short option as alias"), 0 }, + * { "e", 0, 0 }, + * { "nooption6", I18N_NOOP("Another long option with an alias"), 0 }, + * { "f", 0, 0 }, + * { "option7 \<speed>", I18N_NOOP("'--option7 speed' is the same as '-f speed'"), 0 }, + * { "!option8 \<cmd>", I18N_NOOP("All options following this one will be treated as arguments"), 0 }, + * { "+file", I18N_NOOP("A required argument 'file'"), 0 }, + * { "+[arg1]", I18N_NOOP("An optional argument 'arg1'"), 0 }, + * { "!+command", I18N_NOOP("A required argument 'command', that can contain multiple words, even starting with '-'"), 0 }, + * { "", I18N_NOOP("Additional help text not associated with any particular option") 0 }, + * KCmdLineLastOption // End of options. + * }; + * \endcode + * + * The I18N_NOOP macro is used to indicate that these strings should be + * marked for translation. The actual translation is done by KCmdLineArgs. + * You can't use i18n() here because we are setting up a static data + * structure and can't do translations at compile time. + * + * 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 KUniqueApplication; + friend class QPtrList<KCmdLineArgs>; +public: + // Static functions: + + /** + * 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 programName A program name string to be used for display + * purposes. This string should be marked for + * translation. Example: I18N_NOOP("KEdit") + * @param _description A short description of what your application is about. + * @param _version A version. + * @param noKApp Set this true to not add commandline options for + * QApplication / KApplication + * + * @since 3.2 + */ + static void init(int _argc, char **_argv, const char *_appname, + const char* programName, const char *_description, + const char *_version, bool noKApp = false); + /** + * @deprecated + * You should convert any calls to this method to use the one + * above, by adding in the program name to be used for display + * purposes. Do not forget to mark it for translation using I18N_NOOP. + */ + static void init(int _argc, char **_argv, + const char *_appname, const char *_description, + const char *_version, bool noKApp = false) KDE_DEPRECATED; + + /** + * 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 noKApp Set this true to not add commandline options for + * QApplication / KApplication + */ + static void init(int _argc, char **_argv, + const KAboutData *about, bool noKApp = false); + + /** + * 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, true). + * + * @param about the about data. + * \see KAboutData + */ + static void init(const KAboutData *about); + + /** + * 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 + * static KCmdLineOptions options[] = + * { + * { "option1 \<argument>", I18N_NOOP("Description 1"), "my_extra_arg" }, + * { "o", 0, 0 }, + * { "option2", I18N_NOOP("Description 2"), 0 }, + * { "nooption3", I18N_NOOP("Description 3"), 0 }, + * KCmdLineLastOption + * } + * \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, can be 0. + * @param id A name with which these options can be identified, can be 0. + * @param afterId The options are inserted after this set of options, can be 0. + */ + static void addCmdLineOptions( const KCmdLineOptions *options, + const char *name=0, const char *id = 0, + const char *afterId=0); + + /** + * 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 0. + */ + static KCmdLineArgs *parsedArgs(const char *id=0); + + /** + * 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 const char *appName(); + + /** + * Print the usage help to stdout and exit. + * + * @param id if 0, print all options. If id is set, only print the + * option specified by id. The id is the value set by + * #ref addCmdLineOptions(). + **/ + static void usage(const char *id = 0); + + /** + * Print an error to stderr and the usage help to stdout and exit. + * @param error the error to print + **/ + static void usage(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 + * { "option \<argument>", I18N_NOOP("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 the value of the + * last occurrence is used. + */ + QCString getOption(const char *option) const; + + /** + * Read out all occurrences of a string option. + * + * The option must have a corresponding KCmdLineOptions entry + * of the form: + * \code + * { "option \<argument>", I18N_NOOP("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. + */ + QCStringList getOptionList(const char *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 char *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 A @p const @p char @p * pointer to the n'th argument. + */ + const char *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 char * 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( char * cwd ) { mCwd = 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 &); + + /** + * Add standard option --tempfile + * @since 3.4 + */ + 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 + * @since 3.4 + */ + static bool isTempFileSet(); + +protected: + /** + * @internal + * Constructor. + */ + KCmdLineArgs( const KCmdLineOptions *_options, const char *_name, + const char *_id); + + /** + * @internal use only. + * + * Use clear() if you want to free up some memory. + * + * Destructor. + */ + ~KCmdLineArgs(); + +private: + /** + * @internal + * + * Checks what to do with a single option + */ + static void findOption(const char *_opt, QCString 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 for KApplication only: + * + * Return argc + */ + static int *qt_argc(); + + /** + * @internal for KApplication only: + * + * Return argv + */ + + static char ***qt_argv(); + + /** + * @internal + * + * Remove named options. + * + * @param id The name of the options to be removed. + */ + static void removeArgs(const char *id); + + /** + * @internal for KUniqueApplication only: + * + * Save all but the Qt and KDE arguments to a stream. + */ + static void saveAppArgs( QDataStream &); + + /** + * @internal + * + * Set a boolean option + */ + void setOption(const QCString &option, bool enabled); + + /** + * @internal + * + * Set a string option + */ + void setOption(const QCString &option, const char *value); + + /** + * @internal + * + * Add an argument + */ + void addArgument(const char *argument); + + /** + * @internal + * + * Save to a stream. + */ + void save( QDataStream &) const; + + /** + * @internal + * + * Restore from a stream. + */ + void load( QDataStream &); + + /** + * @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 char *_appname); + + static void printQ(const QString &msg); + + const KCmdLineOptions *options; + const char *name; + const char *id; + KCmdLineParsedOptions *parsedOptionList; + KCmdLineParsedArgs *parsedArgList; + bool isQt; + + static KCmdLineArgsList *argsList; // All options. + static const KAboutData *about; + + static int argc; // The original argc + static char **argv; // The original argv + static bool parsed; // Whether we have parsed the arguments since calling init + static bool ignoreUnknown; // Ignore unknown options and arguments + static char *mCwd; // Current working directory. Important for KUnqiueApp! + static bool parseArgs; + + KCmdLineArgsPrivate *d; +}; + +#endif + diff --git a/src/common/nokde/nokde_klocale.cpp b/src/common/nokde/nokde_klocale.cpp new file mode 100644 index 0000000..e30ba2f --- /dev/null +++ b/src/common/nokde/nokde_klocale.cpp @@ -0,0 +1,4 @@ +#include "nokde_klocale.h" + +QString i18n(const QString &, const QString &text) { return text; } +QString locate(const QString &, const QString &) { return QString::null; } diff --git a/src/common/nokde/nokde_klocale.h b/src/common/nokde/nokde_klocale.h new file mode 100644 index 0000000..a1cf720 --- /dev/null +++ b/src/common/nokde/nokde_klocale.h @@ -0,0 +1,17 @@ +#ifndef NOKDE_KLOCALE_H +#define NOKDE_KLOCALE_H + +#undef KDECORE_EXPORT +#define KDECORE_EXPORT + +#undef KDE_DEPRECATED +#define KDE_DEPRECATED + +#undef I18N_NOOP +#define I18N_NOOP(x) (x) +#include <qstring.h> +inline QString i18n(const QString &text) { return text; } +extern QString i18n(const QString &index, const QString &text); +extern QString locate(const QString &, const QString &); + +#endif diff --git a/src/common/nokde/nokde_kprocess.cpp b/src/common/nokde/nokde_kprocess.cpp new file mode 100644 index 0000000..92c8968 --- /dev/null +++ b/src/common/nokde/nokde_kprocess.cpp @@ -0,0 +1,100 @@ +#include "nokde_kprocess.h" + +#if QT_VERSION<0x040000 +# include <qprocess.h> +# define Q3Process QProcess +#else +# include <Qt3Support/Q3Process> +#endif + +#if defined(Q_OS_UNIX) +# include <signal.h> +#endif + +KProcess::KProcess(QObject *parent, const char *name) + : QObject(parent, name) +{ + _process = new Q3Process(this); + connect(_process, SIGNAL(processExited()), SLOT(processExitedSlot())); + connect(_process, SIGNAL(readyReadStdout()), SLOT(readyReadStdoutSlot())); + connect(_process, SIGNAL(readyReadStderr()), SLOT(readyReadStderrSlot())); +} + +bool KProcess::start() +{ + _process->setArguments(_arguments); + QStringList env; + if ( !_environment.isEmpty() ) { + for (uint i=0; environ[i]; i++) env += environ[i]; + env += _environment; + } + return _process->start(env.isEmpty() ? 0 : &env); +} + +void KProcess::processExitedSlot() +{ + readyReadStdoutSlot(); + readyReadStderrSlot(); + emit processExited(this); +} + +void KProcess::readyReadStdoutSlot() +{ + QByteArray a = _process->readStdout(); + emit receivedStdout(this, a.data(), a.count()); +} + +void KProcess::readyReadStderrSlot() +{ + QByteArray a = _process->readStderr(); + emit receivedStderr(this, a.data(), a.count()); +} + +bool KProcess::writeStdin(const char *buffer, int len) +{ +#if QT_VERSION<0x040000 + QByteArray a; + a.assign(buffer, len); +#else + QByteArray a(buffer, len); +#endif + _process->writeToStdin(a); + return true; +} + +bool KProcess::kill() +{ + _process->kill(); + return true; +} + +bool KProcess::kill(int n) +{ +#if defined(Q_OS_UNIX) + return ( ::kill(_process->processIdentifier(), n)!=-1 ); +#elif defined(Q_OS_WIN) + // #### impossible to do ?? + return false; +#endif +} + +int KProcess::exitStatus() const +{ + return _process->exitStatus(); +} + +bool KProcess::isRunning() const +{ + return _process->isRunning(); +} + +void KProcess::setWorkingDirectory(const QDir &dir) +{ + return _process->setWorkingDirectory(dir); +} + +void KProcess::setUseShell(bool useShell) +{ + // ### TODO: just issue "/bin/sh" "-c" "command" + Q_ASSERT(false); +} diff --git a/src/common/nokde/nokde_kprocess.h b/src/common/nokde/nokde_kprocess.h new file mode 100644 index 0000000..59ff73c --- /dev/null +++ b/src/common/nokde/nokde_kprocess.h @@ -0,0 +1,51 @@ +#ifndef _KPROCESS_H_ +#define _KPROCESS_H_ + +#include <qdir.h> +#include "common/global/global.h" +#include "common/common/synchronous.h" +#if QT_VERSION<0x040000 +class QProcess; +#else +class Q3Process; +#endif + +class KProcess : public QObject +{ +Q_OBJECT +public: + KProcess(QObject *parent = 0, const char *name = 0); + void clearArguments() { _arguments.clear(); } + KProcess &operator<< (const QString &arg) { _arguments += arg; return *this; } + KProcess &operator<< (const QStringList &args) { _arguments += args; return *this; } + QStringList args() const { return _arguments; } + void setEnvironment(const QString &name, const QString &value) { _environment += name + "=" + value; } + bool start(); + bool writeStdin(const char *buffer, int len); + bool kill(); + bool kill(int n); + int exitStatus() const; + bool isRunning() const; + void setWorkingDirectory(const QDir &dir); + void setUseShell(bool useShell); + +signals: + void processExited(KProcess *process); + void receivedStdout(KProcess *process, char *buffer, int len); + void receivedStderr(KProcess *process, char *buffer, int len); + +private slots: + void processExitedSlot(); + void readyReadStdoutSlot(); + void readyReadStderrSlot(); + +private: +#if QT_VERSION<0x040000 + QProcess *_process; +#else + Q3Process *_process; +#endif + QStringList _arguments,_environment; +}; + +#endif diff --git a/src/common/nokde/nokde_kurl.h b/src/common/nokde/nokde_kurl.h new file mode 100644 index 0000000..202c46d --- /dev/null +++ b/src/common/nokde/nokde_kurl.h @@ -0,0 +1,32 @@ +#ifndef _KURL_H_ +#define _KURL_H_ + +#include <qfile.h> + +#include "common/global/global.h" + +class KURL : public Q3Url +{ +public: + KURL() {} + KURL(const QString &s) : Q3Url(s) {} + void cleanPath() {} + bool isEmpty() const { return toString(false, false).isEmpty(); } + QString fileName(bool b) const { Q_UNUSED(b); Q_ASSERT(!b); return Q3Url::fileName(); } + static KURL fromPathOrURL(const QString &s) { return KURL(s); } +#if QT_VERSION>=0x040000 + bool operator <(const KURL &url) const { return path()<url.path(); } + bool operator ==(const KURL &url) const { return path()==url.path(); } + bool operator !=(const KURL &url) const { return path()!=url.path(); } +#endif +}; + +// ### DUMMY +class KTempFile +{ +public: + const QFile *file() const { return 0; } + QFile *file() { return 0; } +}; + +#endif diff --git a/src/common/nokde/win32_utils.c b/src/common/nokde/win32_utils.c new file mode 100644 index 0000000..975261e --- /dev/null +++ b/src/common/nokde/win32_utils.c @@ -0,0 +1,81 @@ +/* + This file is part of the KDE libraries + Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl> + + 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. +*/ + +// helper functions + +#include "win32_utils.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <signal.h> + +//--------------------------------------------- +#define _fcopy_BUFLEN 1024*32 +int fcopy(const char *src, const char *dest) +{ + static char _fcopy_buf[_fcopy_BUFLEN]; //not reentrant! + FILE *in, *out; + int c_in=0, c_out=0; + int res=0; + + in=fopen(src, "rb"); + if (!in) + return fcopy_src_err; + out=fopen(dest, "wb"); + if (!out) + return fcopy_dest_err; + while (!feof(in) && !ferror(in) && !ferror(out)) { + c_in=fread(_fcopy_buf, 1, _fcopy_BUFLEN, in); + if (ferror(in) || c_in==0) { + break; + } + c_out=fwrite(_fcopy_buf, 1, c_in, out); + if (ferror(out) || c_in!=c_out) { + break; + } + } + + if (ferror(in)) { + res=fcopy_src_err; + } + else if (ferror(out)) { + res=fcopy_dest_err; + } + else if (c_in!=c_out) { + res=fcopy_dest_err; + } + fclose(in); + fclose(out); + return res; +} + +KDEWIN32_EXPORT +void win32_slashify(char *path, int maxlen) +{ + int len = 0; + if (!path) + return; + for (; *path && len < maxlen ; path++) + if ( *path == '\\' ) + *path = '/'; +} + diff --git a/src/common/nokde/win32_utils.h b/src/common/nokde/win32_utils.h new file mode 100644 index 0000000..cc5e110 --- /dev/null +++ b/src/common/nokde/win32_utils.h @@ -0,0 +1,97 @@ +/* + This file is part of the KDE libraries + Copyright (C) 2004-2005 Jaroslaw Staniek <js@iidea.pl> + + 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 KDE_WIN32_UTILS_H +#define KDE_WIN32_UTILS_H + +#include <windows.h> + +//#include <kdecore/kdelibs_export.h> +#define KDEWIN32_EXPORT + +#ifdef __cplusplus +#include <qstring.h> + +extern "C" { +#endif + +#define fcopy_src_err -1 +#define fcopy_dest_err -2 + +/** + Copies @p src file to @p dest file. + @return 0 on success, fcopy_src_err on source file error, + fcopy_dest_err on destination file error. +*/ +KDEWIN32_EXPORT int fcopy(const char *src, const char *dest); + +/** + Converts all backslashes to slashes in @p path. + Converting is stopped on a null character or at @p maxlen character. +*/ +KDEWIN32_EXPORT void win32_slashify(char *path, int maxlen); + +#ifdef __cplusplus +} + +/** + \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 +*/ +KDEWIN32_EXPORT QString getWin32RegistryValue(HKEY key, const QString& subKey, + const QString& item, bool *ok = 0); + +/** + \return a value from MS Windows native registry for shell folder \a folder. +*/ +inline QString getWin32ShellFoldersPath(const QString& folder) { + return getWin32RegistryValue(HKEY_CURRENT_USER, + "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", 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. +*/ +KDEWIN32_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. +*/ +KDEWIN32_EXPORT +QCString getWin32LocaleName(); + +/*! Temporary solutiuon + \return a KFileDialog-compatible filter string converted to QFileDialog compatible one. + This is temporary solution for kdelibs/win32... */ +KDEWIN32_EXPORT QString convertKFileDialogFilterToQFileDialogFilter(const QString& filter); + +#endif //__cplusplus + +#endif diff --git a/src/common/port/Makefile.am b/src/common/port/Makefile.am new file mode 100644 index 0000000..d1d2ce8 --- /dev/null +++ b/src/common/port/Makefile.am @@ -0,0 +1,7 @@ +INCLUDES = -I$(top_srcdir)/src $(all_includes) +METASOURCES = AUTO + +noinst_LTLIBRARIES = libport.la +libport_la_SOURCES = parallel.cpp port.cpp serial.cpp usb_port.cpp \ + port_base.cpp +libport_la_LDFLAGS = $(all_libraries) diff --git a/src/common/port/parallel.cpp b/src/common/port/parallel.cpp new file mode 100644 index 0000000..22b6a4c --- /dev/null +++ b/src/common/port/parallel.cpp @@ -0,0 +1,247 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003-2004 Alain Gibaud <alain.gibaud@free.fr> * + * Copyright (C) 2002-2003 Stephen Landamore <stephen@landamore.com> * + * * + * 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 "parallel.h" + +#include "common/global/global.h" +#if defined(HAVE_PPDEV) +# include <linux/ppdev.h> +# include <linux/parport.h> +# include <fcntl.h> +# include <sys/ioctl.h> +# include <unistd.h> // needed on some system +# include <errno.h> +#elif defined(HAVE_PPBUS) +# include <sys/param.h> +# include <machine/cpufunc.h> +# include <dev/ppbus/ppi.h> +# include <dev/ppbus/ppbconf.h> +# include <fcntl.h> +# include <unistd.h> +# include <errno.h> +#endif +#include "common/common/misc.h" + +//----------------------------------------------------------------------------- +QStringList *Port::Parallel::_list = 0; + +Port::IODirs Port::Parallel::probe(const QString &device) +{ +#if defined(HAVE_PPDEV) + int fd = ::open(device.latin1(), O_RDWR); + if ( fd<0) return NoIO; + if ( ioctl(fd, PPCLAIM)<0 ) { + ::close(fd) ; + return In; + } + ioctl(fd, PPRELEASE); + ::close(fd); + return (In | Out); +#elif defined(HAVE_PPBUS) + int fd = ::open(device.latin1(), O_RDWR); + if ( fd<0 ) return NoIO; + ::close(fd); + return In | Out; // #### can we detect read-only ? +#else + return NoIO; +#endif +} + +QStringList Port::Parallel::deviceList() +{ + QStringList list; +#if defined(HAVE_PPDEV) + // standard parport in user space + for(int i = 0; i<8; ++i) list.append(QString("/dev/parport%1").arg(i)); + // new devfs parport flavour + for(int i = 0; i<8; ++i) list.append(QString("/dev/parports/%1").arg(i)); +#elif defined(HAVE_PPBUS) + // FreeBSD + for(int i = 0; i<8; ++i) list.append(QString("/dev/ppi%1").arg(i)); +#endif + return list; +} + +const QStringList &Port::Parallel::probedDeviceList() +{ + if ( _list==0 ) { + QStringList all = deviceList(); + _list = new QStringList; + for (uint i=0; i<uint(all.count()); i++) + if( probe(all[i]) & (In | Out) ) _list->append(all[i]); + } + return *_list; +} + +bool Port::Parallel::isAvailable() +{ +#if defined(HAVE_PPDEV) || defined(HAVE_PPBUS) + return true; +#else + return false; +#endif +} + +//----------------------------------------------------------------------------- +const Port::Parallel::PPinData Port::Parallel::PIN_DATA[Nb_Pins] = { + { Control, 0x01, Out, "/DS" }, // !strobe + { Data, 0x01, Out, "D0" }, // data 0 + { Data, 0x02, Out, "D1" }, // data 1 + { Data, 0x04, Out, "D2" }, // data 2 + { Data, 0x08, Out, "D3" }, // data 3 + { Data, 0x10, Out, "D4" }, // data 4 + { Data, 0x20, Out, "D5" }, // data 5 + { Data, 0x40, Out, "D6" }, // data 6 + { Data, 0x80, Out, "D7" }, // data 7 + { Status, 0x40, In, "/ACK" }, // !ack + { Status, 0x80, In, "BUSY" }, // busy + { Status, 0x20, In, "PAPER" }, // pout + { Status, 0x10, In, "SELin" }, // select + { Control, 0x02, Out, "LF" }, // !feed + { Status, 0x08, In, "/ERROR" }, // !error + { Control, 0x04, Out, "PRIME" }, // !init + { Control, 0x08, Out, "SELout" }, // !si + { Nb_RequestTypes, 0x00, NoIO, "GND" }, // GND + { Nb_RequestTypes, 0x00, NoIO, "GND" }, // GND + { Nb_RequestTypes, 0x00, NoIO, "GND" }, // GND + { Nb_RequestTypes, 0x00, NoIO, "GND" }, // GND + { Nb_RequestTypes, 0x00, NoIO, "GND" }, // GND + { Nb_RequestTypes, 0x00, NoIO, "GND" }, // GND + { Nb_RequestTypes, 0x00, NoIO, "GND" }, // GND + { Nb_RequestTypes, 0x00, NoIO, "GND" } // GND +}; + +QValueVector<Port::PinData> Port::Parallel::pinData(IODir dir) const +{ + QValueVector<PinData> v; + for (uint i=0; i<Nb_Pins; i++) { + if ( PIN_DATA[i].dir!=dir ) continue; + PinData pd = { i, PIN_DATA[i].label }; + v.append(pd); + } + return v; +} + +bool Port::Parallel::isGroundPin(uint pin) const +{ + return ( PIN_DATA[pin].label==QString("GND") ); +} + +Port::IODir Port::Parallel::ioDir(uint pin) const +{ + return PIN_DATA[pin].dir; +} + +const Port::Parallel::RequestData Port::Parallel::REQUEST_DATA[Nb_RequestTypes] = { +#if defined(HAVE_PPDEV) + { PPRCONTROL, PPWCONTROL }, + { PPRSTATUS, 0 }, + { PPRDATA, PPWDATA } +#elif defined(HAVE_PPBUS) + { PPIGCTRL, PPISCTRL }, + { PPIGSTATUS, 0 }, + { PPIGDATA, PPISDATA } +#else + { 0, 0 }, + { 0, 0 }, + { 0, 0 } +#endif +}; + +Port::Parallel::Parallel(const QString &device, Log::Base &base) + : Base(base), _fd(-1), _device(device) +{ + for (uint i=0; i<Nb_RequestTypes; i++) _images[i] = 0; +} + +bool Port::Parallel::internalOpen() +{ +#if defined(HAVE_PPDEV) + _fd = ::open(_device.latin1(), O_RDWR); + if ( _fd<0 ) { + setSystemError(i18n("Could not open device \"%1\"").arg(_device)); + return false; + } + if ( ioctl(_fd, PPCLAIM)<0 ) { + setSystemError(i18n("Could not claim device \"%1\": check it is read/write enabled").arg(_device)); + return false; + } +#elif defined(HAVE_PPBUS) + _fd = ::open(_device.latin1(), O_RDWR); + if ( _fd<0 ) { + setSystemError(i18n("Could not open device \"%1\"").arg(_device)); + return false; + } +#endif + return true; +} + +void Port::Parallel::internalClose() +{ + if ( _fd<0 ) return; +#if defined(HAVE_PPDEV) + ioctl(_fd, PPRELEASE); + ::close(_fd); +#elif defined(HAVE_PPBUS) + ::close(_fd); +#endif + _fd = -1; +} + +bool Port::Parallel::setPinOn(uint pin, bool on, LogicType type) +{ + if ( _fd<0 ) return false; +#if defined(HAVE_PPDEV) || defined(HAVE_PPBUS) + Q_ASSERT( pin<Nb_Pins ); + Q_ASSERT( PIN_DATA[pin].dir==Out ); + RequestType rtype = PIN_DATA[pin].rType; + Q_ASSERT( rtype!=Nb_RequestTypes ); + uchar mask = PIN_DATA[pin].mask; + uchar c = (XOR(type==NegativeLogic, on) ? _images[rtype] | mask : _images[rtype] & ~mask); + int request = REQUEST_DATA[rtype].write; + Q_ASSERT( request!=0 ); + if ( ioctl(_fd, request, &c)<0 ) { + setSystemError(i18n("Error setting pin %1 to %2").arg(PIN_DATA[pin].label).arg(on)); + return false; + } + _images[rtype] = c; +#endif + return true; +} + +bool Port::Parallel::readPin(uint pin, LogicType type, bool &value) +{ + if ( _fd<0 ) return false; +#if defined(HAVE_PPDEV) || defined(HAVE_PPBUS) + Q_ASSERT( pin<Nb_Pins ); + Q_ASSERT( PIN_DATA[pin].dir==In ); + RequestType rtype = PIN_DATA[pin].rType; + Q_ASSERT( rtype!=Nb_RequestTypes ); + int request = REQUEST_DATA[rtype].read; + Q_ASSERT( request!=0 ); + uchar c = 0; + if ( ioctl(_fd, request, &c)<0 ) { + setSystemError(i18n("Error reading bit on pin %1").arg(PIN_DATA[pin].label)); + return false; + } + _images[rtype] = c; + value = (type==NegativeLogic ? ~c : c ) & PIN_DATA[pin].mask; +#endif + return true; +} + +void Port::Parallel::setSystemError(const QString &message) +{ +#if defined(HAVE_PPDEV) || defined(HAVE_PPBUS) + log(Log::LineType::Error, message + QString(" (errno=%1).").arg(strerror(errno))); +#else + Q_UNUSED(message); +#endif +} diff --git a/src/common/port/parallel.h b/src/common/port/parallel.h new file mode 100644 index 0000000..1473db0 --- /dev/null +++ b/src/common/port/parallel.h @@ -0,0 +1,70 @@ +/*************************************************************************** + * Copyright (C) 2005 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003-2004 Alain Gibaud <alain.gibaud@free.fr> * + * Copyright (C) 2002-2003 Stephen Landamore <stephen@landamore.com> * + * * + * 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 PARALLEL_H +#define PARALLEL_H + +#include "port_base.h" +#if defined(Q_OS_WIN) +# undef ERROR +#endif + +namespace Port +{ + +class Parallel : public Base +{ +public: + Parallel(const QString &device, Log::Base &base); + virtual ~Parallel() { close(); } + virtual Description description() const { return Description(PortType::Parallel, _device); } + + static IODirs probe(const QString &device); + static const QStringList &probedDeviceList(); + static bool isAvailable(); + + enum Pin { DS = 0, D0, D1, D2, D3, D4, D5, D6, D7, ACK, BUSY, PAPER, SELin, + LF, ERROR, PRIME, SELout, P18, P19, P20, P21, P22, P23, P24, P25, + Nb_Pins }; + enum RequestType { Control = 0, Status, Data, Nb_RequestTypes }; + struct PPinData { + RequestType rType; + uchar mask; + IODir dir; + const char *label; + }; + static const PPinData PIN_DATA[Nb_Pins]; + virtual bool setPinOn(uint pin, bool on, LogicType type); + virtual bool readPin(uint pin, LogicType type, bool &value); + virtual QValueVector<PinData> pinData(IODir dir) const; + virtual bool isGroundPin(uint pin) const; + virtual uint groundPin() const { return P25; } + virtual IODir ioDir(uint pin) const; + +private: + int _fd; + QString _device; + struct RequestData { + int read, write; + }; + static const RequestData REQUEST_DATA[Nb_RequestTypes]; + uchar _images[Nb_RequestTypes]; + + static QStringList *_list; + static QStringList deviceList(); + + virtual bool internalOpen(); + virtual void internalClose(); + virtual void setSystemError(const QString &message); +}; + +} // namespace + +#endif diff --git a/src/common/port/port.cpp b/src/common/port/port.cpp new file mode 100644 index 0000000..c56c120 --- /dev/null +++ b/src/common/port/port.cpp @@ -0,0 +1,98 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 "port.h" + +#if defined(Q_WS_WIN) +# include <sys/timeb.h> +#else +# include <sys/time.h> +#endif + +#include "common/global/global.h" +#include "serial.h" +#include "parallel.h" +#include "usb_port.h" + +//----------------------------------------------------------------------------- +void getTime(int &sec, int &usec) +{ +#if defined (Q_OS_WIN) + struct _timeb tb; + _ftime (&tb); + sec = tb.time; + usec = tb.millitm * 1000 + 500; +#else + struct timeval tv; + gettimeofday(&tv, 0); + usec = tv.tv_usec; + sec = tv.tv_sec; +#endif +} + +void Port::msleep(uint ms) +{ + usleep(ms*1000); +} + +// from Brian C Lane's code +// works better than usleep +void Port::usleep(uint us) +{ + if ( us==0 ) return; + int tsec, tusec; + getTime(tsec, tusec); + int usec = (tusec + us) % 1000000; + int sec = tsec + (tusec + us) / 1000000; + for (;;) { + getTime(tsec, tusec); + if ( tsec>sec ) return; + if ( tsec==sec && tusec>usec ) return; + } +} + +//----------------------------------------------------------------------------- +const PortType::Data PortType::DATA[Nb_Types] = { + { I18N_NOOP("Serial Port"), "serial", true }, + { I18N_NOOP("Parallel Port"), "parallel", true }, + { I18N_NOOP("USB Port"), "usb", false } +}; + +const char * const Port::IO_DIR_NAMES[3] = { "no_io", "in", "out" }; + +QStringList Port::probedDeviceList(PortType type) +{ + if ( !isAvailable(type) ) return QStringList(); + switch (type.type()) { + case PortType::Serial: return Serial::probedDeviceList(); + case PortType::Parallel: return Parallel::probedDeviceList(); + case PortType::USB: return USB::probedDeviceList(); + case PortType::Nb_Types: break; + } + return QStringList(); +} + +bool Port::isAvailable(PortType type) +{ + switch (type.type()) { + case PortType::Serial: return Serial::isAvailable(); + case PortType::Parallel: return Parallel::isAvailable(); + case PortType::USB: return USB::isAvailable(); + case PortType::Nb_Types: break; + } + return false; +} + +PortType Port::findType(const QString &portDevice) +{ + FOR_EACH(PortType, type) { + if ( !type.data().withDevice ) continue; + if ( probedDeviceList(type).contains(portDevice) ) return type; + } + return PortType::Nb_Types; +} diff --git a/src/common/port/port.h b/src/common/port/port.h new file mode 100644 index 0000000..f385deb --- /dev/null +++ b/src/common/port/port.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 PORT_H +#define PORT_H + +#include <qstringlist.h> + +#include "common/global/global.h" +#include "common/common/key_enum.h" + +//----------------------------------------------------------------------------- +struct PortTypeData { + const char *label, *key; + bool withDevice; +}; + +BEGIN_DECLARE_ENUM(PortType) + Serial = 0, Parallel, USB +END_DECLARE_ENUM(PortType, PortTypeData) + +namespace Port +{ +//----------------------------------------------------------------------------- +extern void msleep(uint ms); // in milliseconds +extern void usleep(uint us); // in microseconds + +//----------------------------------------------------------------------------- + class Description { + public: + Description() : type(PortType::Nb_Types) {} + Description(PortType ptype, const QString &pdevice) : type(ptype), device(pdevice) {} + PortType type; + QString device; + }; + + enum IODir { NoIO = 0, In = 1, Out = 2 }; + extern const char * const IO_DIR_NAMES[3]; + Q_DECLARE_FLAGS(IODirs, IODir) + Q_DECLARE_OPERATORS_FOR_FLAGS(IODirs) + extern QStringList probedDeviceList(PortType type); + extern PortType findType(const QString &device); + extern bool isAvailable(PortType type); + struct PinData { + uint pin; + const char *label; + }; + enum LogicType { PositiveLogic, NegativeLogic }; +} // namespace + +#endif diff --git a/src/common/port/port.pro b/src/common/port/port.pro new file mode 100644 index 0000000..f09414b --- /dev/null +++ b/src/common/port/port.pro @@ -0,0 +1,10 @@ +STOPDIR = ../../.. +include($${STOPDIR}/lib.pro) + +TARGET = port +HEADERS += port.h port_base.h parallel.h serial.h usb_port.h +SOURCES += port.cpp port_base.cpp parallel.cpp serial.cpp usb_port.cpp +contains(DEFINES, HAVE_USB) { + win32:INCLUDEPATH += $${LIBUSB_PATH}\include +} + diff --git a/src/common/port/port_base.cpp b/src/common/port/port_base.cpp new file mode 100644 index 0000000..7528eeb --- /dev/null +++ b/src/common/port/port_base.cpp @@ -0,0 +1,127 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 "port_base.h" + +#include "common/global/global.h" +#include "common/common/misc.h" +#include "common/common/number.h" + +bool Port::Base::open() +{ + close(); + resetError(); + _closing = false; + return internalOpen(); +} + +void Port::Base::close() +{ + _closing = true; + internalClose(); +} + +bool Port::Base::send(const char *data, uint size, uint timeout) +{ + log(Log::DebugLevel::LowLevel, QString("Sending: \"%1\"").arg(toPrintable(data, size, PrintAlphaNum))); + return internalSend(data, size, timeout); +} + +bool Port::Base::receive(uint size, QString &s, uint timeout) +{ + QMemArray<uchar> a; + if ( !receive(size, a, timeout) ) return false; + s.fill(0, size); + for (uint i=0; i<size; i++) s[i] = a[i]; + return true; +} + +bool Port::Base::receive(uint size, QMemArray<uchar> &a, uint timeout) +{ + a.resize(size); + bool ok = internalReceive(size, (char *)a.data(), timeout); + if (ok) log(Log::DebugLevel::LowLevel, QString("Received: \"%1\"").arg(toPrintable(a, PrintAlphaNum))); + return ok; +} + +bool Port::Base::receiveChar(char &c, uint timeout) +{ + if ( !internalReceive(1, &c, timeout) ) return false; + log(Log::DebugLevel::LowLevel, QString("Received: \"%1\"").arg(toPrintable(c, PrintAlphaNum))); + return true; +} + +bool Port::Base::setPinOn(uint, bool, LogicType) +{ + qFatal("setPinOn not implemented"); + return false; +} +bool Port::Base::readPin(uint, LogicType, bool &) +{ + qFatal("readPin not implemented"); + return 0; +} +QValueVector<Port::PinData> Port::Base::pinData(IODir) const +{ + qFatal("pinData not implemented"); + return QValueVector<PinData>(); +} +bool Port::Base::isGroundPin(uint) const +{ + qFatal("isGroundPin not implemented"); + return false; +} +uint Port::Base::groundPin() const +{ + qFatal("groundPin not implemented"); + return 0; +} +Port::IODir Port::Base::ioDir(uint) const +{ + qFatal("ioType not implemented"); + return NoIO; +} + +void Port::Base::log(Log::LineType lineType, const QString &message) +{ + if ( lineType==Log::LineType::Error && _closing ) return; + Log::Base::log(lineType, description().type.label() + ": " + message); + if ( lineType==Log::LineType::Error ) close(); +} + +void Port::Base::log(Log::DebugLevel level, const QString &message) +{ + Log::Base::log(level, description().type.label() + ": " + message); +} + +void Port::Base::logData(const QString &) +{ +/* + QString vs; + for (uint i=0; i<s.length(); i++) { + char c = s[i]; + switch (c) { + case '\r': vs += "\\r"; break; + case '\n': vs += "\\n"; break; + case '<': vs += "<"; break; + case '>': vs += ">"; break; + default: { + if ( c>=32 && c<=126 ) vs += c; + else { + QString tmp; + tmp.sprintf("\\x%02x", c); + vs += tmp; + } + break; + } + } + } + qDebug("%s", vs.latin1()); +*/ + //log(Log::Debug, vs); +} diff --git a/src/common/port/port_base.h b/src/common/port/port_base.h new file mode 100644 index 0000000..3ae4787 --- /dev/null +++ b/src/common/port/port_base.h @@ -0,0 +1,59 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 PORT_BASE_H +#define PORT_BASE_H + +#include "port.h" +#include "common/global/log.h" + +namespace Port +{ + +class Base : public Log::Base +{ +public: + Base(Log::Base &base) : Log::Base(&base) {} + virtual PortType type() const { return description().type; } + virtual Description description() const = 0; + bool open(); + void close(); + + virtual void log(Log::LineType kind, const QString &message); + virtual void log(Log::DebugLevel level, const QString &message); + void logData(const QString &s); + + enum { DEFAULT_TIMEOUT = 3000 }; // 3s + bool sendChar(char c, uint timeout = DEFAULT_TIMEOUT) { return send(&c, 1, timeout); } + bool send(const char *data, uint size, uint timeout = DEFAULT_TIMEOUT); + bool send(const QMemArray<uchar> &a, uint timeout = DEFAULT_TIMEOUT) { return send((const char *)a.data(), a.count(), timeout); } + bool receiveChar(char &c, uint timeout = DEFAULT_TIMEOUT); + bool receive(uint size, QString &s, uint timeout = DEFAULT_TIMEOUT); + bool receive(uint size, QMemArray<uchar> &a, uint timeout = DEFAULT_TIMEOUT); + + virtual bool setPinOn(uint pin, bool on, LogicType type); + virtual bool readPin(uint pin, LogicType type, bool &value); + virtual QValueVector<PinData> pinData(IODir dir) const; + virtual bool isGroundPin(uint pin) const; + virtual uint groundPin() const; + virtual IODir ioDir(uint pin) const; + +protected: + virtual bool internalOpen() = 0; + virtual void internalClose() = 0; + virtual bool internalSend(const char *, uint, uint) { qFatal("Not implemented"); return false; } + virtual bool internalReceive(uint, char *, uint) { qFatal("Not implemented"); return false; } + virtual void setSystemError(const QString &message) = 0; + +private: + bool _closing; +}; + +} // namespace + +#endif diff --git a/src/common/port/serial.cpp b/src/common/port/serial.cpp new file mode 100644 index 0000000..b370d22 --- /dev/null +++ b/src/common/port/serial.cpp @@ -0,0 +1,523 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003-2004 Alain Gibaud <alain.gibaud@free.fr> * + * Copyright (C) 2002-2003 Stephen Landamore <stephen@landamore.com> * + * * + * 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 "serial.h" + +#ifdef Q_OS_UNIX +# include <stdio.h> +# include <fcntl.h> +# include <sys/time.h> +# include <sys/types.h> +# include <sys/stat.h> +# include <sys/ioctl.h> +# include <errno.h> +# include <unistd.h> // needed on some system +#endif +#include <qdatetime.h> + +//----------------------------------------------------------------------------- +QStringList *Port::Serial::_list = 0; +#if defined(Q_OS_UNIX) +const Port::Serial::Handle Port::Serial::INVALID_HANDLE = -1; +#elif defined(Q_OS_WIN) +const Port::Serial::Handle Port::Serial::INVALID_HANDLE = INVALID_HANDLE_VALUE; +#endif + +Port::Serial::Handle Port::Serial::openHandle(const QString &device, IODirs dirs) +{ +#if defined(Q_OS_UNIX) + // open non blocking: avoid missing DCD (comment from xwisp2) + int mode = O_NOCTTY | O_NONBLOCK; + if ( dirs & In ) { + if ( dirs & Out ) mode |= O_RDWR; + else mode |= O_RDONLY; + } else mode |= O_WRONLY; + return ::open(device.latin1(), mode); +#elif defined(Q_OS_WIN) + int mode = 0; + if ( dirs & In ) mode |= GENERIC_READ; + if ( dirs & Out ) mode |= GENERIC_WRITE; + return CreateFileA(device.latin1(), mode, 0, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL); +#endif +} + +void Port::Serial::closeHandle(Handle handle) +{ +#if defined(Q_OS_UNIX) + ::close(handle); +#elif defined(Q_OS_WIN) + CloseHandle(handle); +#endif +} + +Port::IODirs Port::Serial::probe(const QString &device) +{ + Handle handle = openHandle(device, In); + if ( handle==INVALID_HANDLE ) return NoIO; + closeHandle(handle); + handle = openHandle(device, In | Out); + if ( handle==INVALID_HANDLE ) return In; + closeHandle(handle); + return (In | Out); +} + +QStringList Port::Serial::deviceList() +{ + QStringList list; +#if defined(Q_OS_UNIX) + // standard serport in user space + for (uint i=0; i<8; i++) list.append(QString("/dev/ttyS%1").arg(i)); + // new devfs serport flavour + for (uint i=0; i<8; i++) list.append(QString("/dev/tts/%1").arg(i)); + // standard USB serport in user space + for (uint i=0; i<8; i++) list.append(QString("/dev/ttyUSB%1").arg(i)); + // new devfs USB serport flavour + for (uint i=0; i<8; i++) list.append(QString("/dev/usb/tts/%1").arg(i)); + // FreeBSD + for (uint i=0; i<8; i++) list.append(QString("/dev/ttyd%1").arg(i)); + // Slackware 11 devfs USB Serial port support. + for (uint i=0; i<8; i++) list.append(QString("/dev/tts/USB%1").arg(i)); + // MacOSX devfs USB Serial port support. + list.append("/dev/tty.usbserial"); +#elif defined(Q_OS_WIN) + for (uint i=1; i<10; i++) list.append(QString("COM%1").arg(i)); +#endif + return list; +} + +const QStringList &Port::Serial::probedDeviceList() +{ + if ( _list==0 ) { + QStringList all = deviceList(); + _list = new QStringList; + for (uint i=0; i<uint(all.count()); i++) + if( probe(all[i]) & (In | Out) ) _list->append(all[i]); + } + return *_list; +} + +//----------------------------------------------------------------------------- +const uint Port::Serial::SPEED_VALUES[Nb_Speeds] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, + 57600, 115200 +}; +const Port::Serial::SpeedData Port::Serial::SPEED_DATA[Nb_Speeds] = { +#if defined(Q_OS_UNIX) + { true, B0 }, { true, B50 }, { true, B75 }, { true, B110 }, + { true, B134 }, { true, B150 }, { true, B200 }, { true, B300 }, + { true, B600 }, { true, B1200 }, { true, B1800 }, { true, B2400 }, + { true, B4800 }, { true, B9600 }, { true, B19200 }, { true, B38400 }, + { true, B57600 }, { true, B115200 } +#elif defined(Q_OS_WIN) + { false, 0 }, { false, 0 }, { false, 0 }, { true, CBR_110 }, + { false, 0 }, { false, 0 }, { false, 0 }, { true, CBR_300 }, + { true, CBR_600 }, { true, CBR_1200 }, { false, 0 }, { true, CBR_2400 }, + { true, CBR_4800 }, { true, CBR_9600 }, { true, CBR_19200 }, { true, CBR_38400 }, + { true, CBR_57600 }, { true, CBR_115200 } +#endif +}; + +const Port::Serial::SPinData Port::Serial::PIN_DATA[Nb_Pins] = { + { In, "DCD" }, { In, "RX" }, { Out, "TX" }, { Out, "DTR" }, + { NoIO, "GND" }, { In, "DSR" }, { Out, "RTS" }, { In, "CTS" }, + { Out, "RI" } +}; + +QValueVector<Port::PinData> Port::Serial::pinData(IODir dir) const +{ + QValueVector<PinData> v; + for (uint i=0; i<Nb_Pins; i++) { + if ( PIN_DATA[i].dir!=dir ) continue; + PinData pd = { i, PIN_DATA[i].label }; + v.append(pd); + } + return v; +} +bool Port::Serial::isGroundPin(uint pin) const +{ + return ( PIN_DATA[pin].label==QString("GND") ); +} + +Port::IODir Port::Serial::ioDir(uint pin) const +{ + return PIN_DATA[pin].dir; +} + +Port::Serial::Serial(const QString &device, Properties properties, Log::Base &base) + : Base(base), _device(device), _properties(properties), _fd(INVALID_HANDLE) +{} + +bool Port::Serial::getParameters(Parameters ¶meters) +{ + if ( _fd==INVALID_HANDLE ) return false; +#if defined(Q_OS_UNIX) + if ( tcgetattr(_fd, ¶meters)<0 ) { +#elif defined(Q_OS_WIN) + if ( !GetCommState(_fd, ¶meters.dcb) || !GetCommTimeouts(_fd, ¶meters.comtmo) ) { +#endif + setSystemError(i18n("Could not get file descriptor parameters")); + return false; + } + return true; +} + +bool Port::Serial::setParameters(const Parameters ¶meters) +{ + if ( _fd==INVALID_HANDLE ) return false; +#if defined(Q_OS_UNIX) + if ( tcsetattr(_fd, TCSANOW, ¶meters)<0 ) { +#elif defined(Q_OS_WIN) + Parameters tmp = parameters; + if ( !SetCommState(_fd, &tmp.dcb) || !SetCommTimeouts(_fd, &tmp.comtmo) ) { +#endif + setSystemError(i18n("Could not set file descriptor parameters")); + return false; + } + return true; +} + +bool Port::Serial::internalOpen() +{ + _fd = openHandle(_device, In | Out); + if ( _fd==INVALID_HANDLE ) { + setSystemError(i18n("Could not open device \"%1\" read-write").arg(_device)); + return false; + } + if ( !getParameters(_oldParameters) ) return false; // save configuration +#if defined(Q_OS_UNIX) + if ( _properties & Blocking ) { + int flags = fcntl(_fd, F_GETFL, 0); + if ( fcntl(_fd, F_SETFL, flags & ~O_NONBLOCK)<0 ) { + setSystemError(i18n("Could not modify file descriptor flags")); + return false; + } + } +#endif + return flush(DEFAULT_TIMEOUT); +} + +void Port::Serial::internalClose() +{ + if ( _fd==INVALID_HANDLE ) return; + if ( _properties & NeedFlush ) flush(0); + if ( _properties & NeedBreak ) doBreak(1); + setParameters(_oldParameters); + closeHandle(_fd); + _fd = INVALID_HANDLE; +} + +bool Port::Serial::internalSend(const char *data, uint size, uint timeout) +{ + if ( _fd==INVALID_HANDLE ) return false; + QTime time; + time.start(); + for (uint todo=size; todo!=0; ) { +#if defined(Q_OS_UNIX) + int res = write(_fd, data+size-todo, todo); + if ( res<0 && errno!=EAGAIN ) { +#elif defined(Q_OS_WIN) + DWORD res = 0; + if ( WriteFile(_fd, data+size-todo, todo, &res, NULL)==0 ) { +#endif + setSystemError(i18n("Error sending data")); + return false; + } + if ( res>0 ) todo -= res; + else { + if ( uint(time.elapsed())>timeout ) { + log(Log::LineType::Error, i18n("Timeout sending data (%1/%2 bytes sent).").arg(size-todo).arg(size)); + return false; + } + msleep(1); + } + } + if ( (_properties & NeedDrain) && !drain(timeout) ) return false; + return true; +} + +bool Port::Serial::internalReceive(uint size, char *data, uint timeout) +{ + if ( _fd==INVALID_HANDLE ) return false; + QTime time; + time.start(); + for(uint todo=size; todo!=0; ) { +#if defined(Q_OS_UNIX) + // this help reduce CPU usage. It also prevents blocking if the serial cable is disconnected + fd_set rfd; + FD_ZERO(&rfd); + FD_SET(_fd, &rfd); + struct timeval tv; + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout%1000)*1000; + int res = select(_fd+1, &rfd, 0, 0, &tv); + if ( res<0 ) { + setSystemError(i18n("Error receiving data")); + return false; + } + if ( res==0 ) { + log(Log::LineType::Error, i18n("Timeout waiting for data.")); + return false; + } + res = read(_fd, data+size-todo, todo); + if ( res<0 && errno!=EAGAIN ) { +#elif defined(Q_OS_WIN) + DWORD res = 0; + if ( ReadFile(_fd, data+size-todo, todo, &res, NULL)==0 ) { +#endif + setSystemError(i18n("Error receiving data")); + return false; + } + if ( res>0 ) todo -= res; + else { + if ( uint(time.elapsed())>timeout ) { + log(Log::LineType::Error, i18n("Timeout receiving data (%1/%2 bytes received).").arg(size-todo).arg(size)); + return false; + } + msleep(1); + } + } + return true; +} + +bool Port::Serial::drain(uint timeout) +{ + if ( _fd==INVALID_HANDLE ) return false; +#if defined(Q_OS_UNIX) + // tcdrain will block if the serial cable is disconnected + // so we first check for data in output buffer... + QTime time; + time.start(); + for (;;) { + int nb; + if ( ioctl(_fd, TIOCOUTQ, &nb)==-1 ) { + setSystemError(i18n("Error checking for data in output buffer")); + return false; + } + if ( nb==0 ) break; + if ( uint(time.elapsed())>timeout ) { + _fd = INVALID_HANDLE; // otherwise close blocks... + log(Log::LineType::Error, i18n("Timeout sending data (%1 bytes left).").arg(nb)); + return false; + } + } + if ( tcdrain(_fd)<0 ) { + setSystemError(i18n("Error while draining")); + return false; + } +#endif + return true; +} + +bool Port::Serial::flush(uint timeout) +{ + if ( _fd==INVALID_HANDLE ) return false; + if ( (_properties & NeedDrain) && !drain(timeout) ) return false; +#if defined(Q_OS_UNIX) + if ( tcflush(_fd, TCIFLUSH)<0 ) { +#elif defined(Q_OS_WIN) + if ( FlushFileBuffers(_fd)==0 || PurgeComm(_fd, PURGE_TXABORT)==0 + || PurgeComm(_fd, PURGE_RXABORT)==0 || PurgeComm(_fd, PURGE_TXCLEAR)==0 + || PurgeComm(_fd, PURGE_RXCLEAR)==0 ) { +#endif + setSystemError(i18n("Could not flush device")); + return false; + } + return true; +} + +bool Port::Serial::internalSetPinOn(Pin pin, bool on) +{ +#if defined(Q_OS_UNIX) + int bit = 0; + switch (pin) { + case TX: return ( ioctl(_fd, on ? TIOCSBRK : TIOCCBRK, 0)>=0 ); + case DTR: bit = TIOCM_DTR; break; + case RTS: bit = TIOCM_RTS; break; + case RI: bit = TIOCM_RI; break; + default: Q_ASSERT(false); return false; + } + return ( ioctl(_fd, on ? TIOCMBIS : TIOCMBIC, &bit)>=0 ); +#elif defined(Q_OS_WIN) + DWORD func = 0; + switch (pin) { + case TX: func = (on ? SETBREAK : CLRBREAK); break; + case DTR: func = (on ? SETDTR : CLRDTR); break; + case RTS: func = (on ? SETRTS : CLRRTS); break; + case RI: // #### not possible with Win32 API ?? + default: Q_ASSERT(false); return false; + } + return ( EscapeCommFunction(_fd, func)!=0 ); +#endif +} + +bool Port::Serial::setPinOn(uint pin, bool on, LogicType type) +{ + if ( _fd==INVALID_HANDLE ) return false; + if ( type==NegativeLogic ) on = !on; + Q_ASSERT( pin<Nb_Pins ); + Q_ASSERT( PIN_DATA[pin].dir==Out ); + if ( !internalSetPinOn(Pin(pin), on) ) { + setSystemError(i18n("Error setting bit %1 of serial port to %2").arg(PIN_DATA[pin].label).arg(on)); + return false; + } + return true; +} + +bool Port::Serial::internalReadPin(Pin pin, LogicType type, bool &value) +{ +#if defined(Q_OS_UNIX) + int bits; + if ( ioctl(_fd, TIOCMGET, &bits)<0 ) return false; + int mask = 0; + switch (pin) { + case DCD: mask = TIOCM_CD; break; + case RX : mask = TIOCM_SR; break; + case DSR: mask = TIOCM_DSR; break; + case CTS: mask = TIOCM_CTS; break; + default: Q_ASSERT(false); return false; + } + value = ((type==NegativeLogic ? ~bits : bits) & mask); + return true; +#elif defined(Q_OS_WIN) + DWORD status; + if ( GetCommModemStatus(_fd, &status)==0 ) return false; + switch (pin) { + case DCD: value = (status & MS_RLSD_ON); break; + case DSR: value = (status & MS_DSR_ON); break; + case CTS: value = (status & MS_CTS_ON); break; + case RX: // not possible with Win32 API ?? + default: Q_ASSERT(false); return false; + } + if ( type==NegativeLogic) value = !value; + return true; +#endif +} + + bool Port::Serial::readPin(uint pin, LogicType type, bool &value) +{ + if ( _fd==INVALID_HANDLE ) return false; + Q_ASSERT( pin<Nb_Pins ); + Q_ASSERT( PIN_DATA[pin].dir==In ); + if ( !internalReadPin(Pin(pin), type, value) ) { + setSystemError(i18n("Error reading serial pin %1").arg(PIN_DATA[pin].label)); + return false; + } + return true; +} + +bool Port::Serial::setMode(InputFlags inputFlags, ControlFlags controlFlags, Speed speed, uint readTimeout) +{ + Q_ASSERT (SPEED_DATA[speed].supported ); + if ( !flush(0) ) return false; + Parameters parameters; + if ( !getParameters(parameters) ) return false; +#if defined(Q_OS_UNIX) + cfsetispeed(¶meters, SPEED_DATA[speed].flag); + cfsetospeed(¶meters, SPEED_DATA[speed].flag); + parameters.c_cflag &= ~(CSIZE|PARENB|PARODD|HUPCL|CSTOPB); + int cflags = 0; + if ( controlFlags & ByteSize8 ) cflags |= CS8; + if ( controlFlags & HardwareFlowControl ) cflags |= CRTSCTS; + if ( controlFlags & EnableReceiver ) cflags |= CREAD; + if ( controlFlags & IgnoreControlLines ) cflags |= CLOCAL; + parameters.c_cflag |= cflags; + parameters.c_iflag &= ~(ISTRIP|INPCK|IGNCR|INLCR|ICRNL|IXOFF|IXON); + int iflags = 0; + if ( inputFlags & IgnoreBreak ) iflags |= IGNBRK; + if ( inputFlags & IgnoreParity ) iflags |= IGNPAR; + parameters.c_iflag |= iflags; + parameters.c_oflag &= ~OPOST; + parameters.c_lflag &= ~(ICANON|ECHO|ECHONL|ISIG|IEXTEN|TOSTOP); + parameters.c_cc[VMIN] = 0; // wait for 1 char or timeout + parameters.c_cc[VTIME] = readTimeout/100; // wait in deciseconds +#elif defined(Q_OS_WIN) + if ( controlFlags & EnableReceiver ) ; // #### not sure what to do + if ( controlFlags & IgnoreControlLines ) ; // #### not sure what to do + setHardwareFlowControl(parameters, (controlFlags & HardwareFlowControl)); + if ( inputFlags & IgnoreParity ) parameters.dcb.Parity = NOPARITY; + parameters.dcb.StopBits = ONESTOPBIT; + if ( controlFlags & ByteSize8 ) parameters.dcb.ByteSize = 8; + parameters.dcb.BaudRate = SPEED_DATA[speed].flag; + parameters.comtmo.ReadIntervalTimeout = MAXDWORD; + parameters.comtmo.ReadTotalTimeoutMultiplier = MAXDWORD; + parameters.comtmo.ReadTotalTimeoutConstant = readTimeout; + parameters.comtmo.WriteTotalTimeoutMultiplier = 1; + parameters.comtmo.WriteTotalTimeoutConstant = readTimeout; +#endif + return setParameters(parameters); + // need flush ?? +} + +bool Port::Serial::doBreak(uint duration) +{ + if ( !flush(0) ) return false; +#if defined(Q_OS_UNIX) + if ( ioctl(_fd, TIOCSBRK)<0 ) { +#elif defined(Q_OS_WIN) + if ( SetCommBreak(_fd)==0 ) { +#endif + setSystemError(i18n("Error setting up break")); + return false; + } + msleep(duration); +#if defined(Q_OS_UNIX) + if ( ioctl(_fd, TIOCCBRK) ) { +#elif defined(Q_OS_WIN) + if ( ClearCommBreak(_fd)==0 ) { +#endif + setSystemError(i18n("Error clearing up break")); + return false; + } + msleep(1); + return flush(0); +} + +void Port::Serial::setHardwareFlowControl(Parameters ¶meters, bool on) +{ +#if defined(Q_OS_UNIX) + if (on) parameters.c_cflag |= CRTSCTS; + else parameters.c_cflag &= ~CRTSCTS; + parameters.c_cc[VMIN] = 0; // #### needed ? + parameters.c_cc[VTIME] = 0; // #### needed ? +#elif defined(Q_OS_WIN) + // #### not sure about that + parameters.dcb.fParity = on; + parameters.dcb.fOutxCtsFlow = on; + parameters.dcb.fOutxDsrFlow = on; + parameters.dcb.fDtrControl = (on ? DTR_CONTROL_ENABLE : DTR_CONTROL_DISABLE); + parameters.dcb.fDsrSensitivity = on; + parameters.dcb.fTXContinueOnXoff = on; + parameters.dcb.fOutX = on; + parameters.dcb.fInX = on; + parameters.dcb.fNull = on; + parameters.dcb.fRtsControl = (on ? RTS_CONTROL_ENABLE : RTS_CONTROL_DISABLE); + parameters.dcb.fAbortOnError = on; +#endif +} + +bool Port::Serial::setHardwareFlowControl(bool on) +{ + Parameters parameters; + if ( !getParameters(parameters) ) return false; + setHardwareFlowControl(parameters, on); + return setParameters(parameters); +} + +void Port::Serial::setSystemError(const QString &message) +{ +#if defined(Q_OS_UNIX) + log(Log::LineType::Error, message + QString(" (errno=%1)").arg(strerror(errno))); +#elif defined(Q_OS_WIN) + LPVOID lpMsgBuf; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL); + log(Log::LineType::Error, message + QString(" (last error=%1 %2)").arg(GetLastError()).arg((const char *)(LPCTSTR)lpMsgBuf)); + LocalFree(lpMsgBuf); +#endif +} diff --git a/src/common/port/serial.h b/src/common/port/serial.h new file mode 100644 index 0000000..b2911e6 --- /dev/null +++ b/src/common/port/serial.h @@ -0,0 +1,113 @@ +/*************************************************************************** + * Copyright (C) 2005 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003-2004 Alain Gibaud <alain.gibaud@free.fr> * + * Copyright (C) 2002-2003 Stephen Landamore <stephen@landamore.com> * + * * + * 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 SERIAL_H +#define SERIAL_H + +#include "common/global/global.h" +#ifdef Q_OS_UNIX +# include <termios.h> +#elif defined(Q_OS_WIN) +# include <io.h> +#endif +#include "port_base.h" + +namespace Port +{ + +class Serial : public Base +{ +public: + enum Speed { S0 = 0, S50, S75, S110, S134, S150, S200, S300, S600, S1200, + S1800, S2400, S4800, S9600, S19200, S38400, S57600, S115200, + Nb_Speeds }; + static const uint SPEED_VALUES[Nb_Speeds]; + struct SpeedData { + bool supported; + uint flag; + }; + static const SpeedData SPEED_DATA[Nb_Speeds]; + + enum Property { NoProperty = 0, NeedDrain = 1, NeedFlush = 2, NeedBreak = 4, + Blocking = 8 }; + Q_DECLARE_FLAGS(Properties, Property) + + Serial(const QString &device, Properties properties, Log::Base &base); + virtual ~Serial() { close(); } + virtual Description description() const { return Description(PortType::Serial, _device); } + + static const QStringList &probedDeviceList(); + static IODirs probe(const QString &device); + static bool isAvailable() { return true; } + + enum InputFlag { NoInputFlag = 0, IgnoreBreak = 1, IgnoreParity = 2 }; + Q_DECLARE_FLAGS(InputFlags, InputFlag) + enum ControlFlag { NoControlFlag = 0, ByteSize8 = 1, HardwareFlowControl = 2, + EnableReceiver = 4, IgnoreControlLines = 8 }; + Q_DECLARE_FLAGS(ControlFlags, ControlFlag) + bool setMode(InputFlags inputFlags, ControlFlags controlFlags, Speed speed, uint readTimeout); // in ms + bool drain(uint timeout); + bool flush(uint timeout); + bool doBreak(uint duration); // in ms + bool setHardwareFlowControl(bool on); + + enum Pin { DCD = 0, RX, TX, DTR, SG, DSR, RTS, CTS, RI, Nb_Pins }; + struct SPinData { + IODir dir; + const char *label; + }; + static const SPinData PIN_DATA[Nb_Pins]; + virtual bool setPinOn(uint pin, bool on, LogicType type); + virtual bool readPin(uint pin, LogicType type, bool &value); + virtual QValueVector<PinData> pinData(IODir dir) const; + virtual bool isGroundPin(uint pin) const; + virtual uint groundPin() const { return SG; } + virtual IODir ioDir(uint pin) const; + +private: + QString _device; + Properties _properties; +#if defined(Q_OS_UNIX) + typedef int Handle; + typedef termios Parameters; +#elif defined(Q_OS_WIN) + typedef HANDLE Handle; + struct Parameters { + DCB dcb; + COMMTIMEOUTS comtmo; + }; +#endif + Handle _fd; + Parameters _oldParameters; + + bool setParameters(const Parameters ¶meters); + bool getParameters(Parameters ¶meters); + virtual bool internalOpen(); + virtual void internalClose(); + virtual bool internalSend(const char *data, uint size, uint timeout); + virtual bool internalReceive(uint size, char *data, uint timeout); + virtual void setSystemError(const QString &message); + bool internalSetPinOn(Pin pin, bool on); + bool internalReadPin(Pin pin, LogicType type, bool &value); + + static const Handle INVALID_HANDLE; + static Handle openHandle(const QString &device, IODirs dirs); + static void closeHandle(Handle handle); + static QStringList *_list; + static QStringList deviceList(); + static void setHardwareFlowControl(Parameters ¶meters, bool on); +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(Serial::Properties) +Q_DECLARE_OPERATORS_FOR_FLAGS(Serial::InputFlags) +Q_DECLARE_OPERATORS_FOR_FLAGS(Serial::ControlFlags) + +} // namespace + +#endif diff --git a/src/common/port/usb_port.cpp b/src/common/port/usb_port.cpp new file mode 100644 index 0000000..392b483 --- /dev/null +++ b/src/common/port/usb_port.cpp @@ -0,0 +1,411 @@ +/*************************************************************************** + * Copyright (C) 2005 Lorenz Mösenlechner & Matthias Kranz * + * <icd2linux@hcilab.org> * + * Copyright (C) 2003-2005 Orion Sky Lawlor <olawlor@acm.org> * + * Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 "usb_port.h" + +#ifdef HAVE_USB +# include <usb.h> +#endif +#include <qdatetime.h> + +#include "common/common/version_data.h" +#include "common/common/number.h" + +//----------------------------------------------------------------------------- +class Port::USB::Private +{ +public: +#ifdef HAVE_USB + Private() : _interface(0) {} + const usb_interface_descriptor *_interface; +#endif +}; + +bool Port::USB::_initialized = false; + +void Port::USB::initialize() +{ + if (_initialized) return; + _initialized = true; +#ifdef HAVE_USB + usb_init(); + VersionData vd = VersionData::fromString(LIBUSB_VERSION); + QString s = QString("libusb %1").arg(vd.pretty()); + if ( vd<VersionData(0, 1, 8) ) qWarning("%s: may be too old (you need at least version 0.1.8)", s.latin1()); +#endif +} + +bool Port::USB::isAvailable() +{ +#ifdef HAVE_USB + return true; +#else + return false; +#endif +} + +usb_bus *Port::USB::getBusses() +{ + initialize(); +#ifdef HAVE_USB + // refresh libusb structures + usb_find_busses(); + usb_find_devices(); + return usb_get_busses(); +#else + return 0; +#endif +} + +bool Port::USB::findBulk(const struct usb_device *dev) +{ + initialize(); +#ifdef HAVE_USB + int configuration = -1, interface = -1, altsetting = -1, bulk_endpoint = -1; + // walk through the possible configs, etc. + qDebug("This device has %d possible configuration(s).", dev->descriptor.bNumConfigurations); + for (int c=0; c<dev->descriptor.bNumConfigurations; c++) { + qDebug("Looking at configuration %d...This configuration has %d interfaces.", c, dev->config[c].bNumInterfaces); + for(int i=0; i<dev->config[c].bNumInterfaces; i++) { + qDebug(" Looking at interface %d...This interface has %d altsettings.", i, dev->config[c].interface[i].num_altsetting); + for (int a=0; a < dev->config[c].interface[i].num_altsetting; a++) { + qDebug(" Looking at altsetting %d...This altsetting has %d endpoints.", a, dev->config[c].interface[i].altsetting[a].bNumEndpoints); + for (int e=0; e < dev->config[c].interface[i].altsetting[a].bNumEndpoints; e++) { + QString s; + s.sprintf(" Endpoint %d: Address %02xh, attributes %02xh ", e, dev->config[c].interface[i].altsetting[a].endpoint[e].bEndpointAddress, dev->config[c].interface[i].altsetting[a].endpoint[e].bmAttributes); + uchar attribs = (dev->config[c].interface[i].altsetting[a].endpoint[e].bmAttributes & 3); + switch (attribs) { + case 0: s += "(Control) "; break; + case 1: s += "(Isochronous) "; break; + case 2: s += "(Bulk) "; + /* Found the correct configuration, interface etc... it has bulk endpoints! */ + configuration=c; + interface=i; + altsetting=a; + break; + case 3: s += "(Interrupt) "; break; + default: s += "ERROR! Got an illegal value in endpoint bmAttributes"; + } + if ( attribs!=0 ) { + uchar dir = (dev->config[c].interface[i].altsetting[a].endpoint[e].bEndpointAddress & 0x80); + switch (dir) { + case 0x00: s += "(Out)"; + // Do nothing in this case + break; + case 0x80: s += "(In)"; + if ((dev->config[c].interface[i].altsetting[a].endpoint[e].bmAttributes & 0x03) == 2) /* Make sure it's a *bulk* endpoint */ { + // Found the correct endpoint to use for bulk transfer; use its ADDRESS + bulk_endpoint=dev->config[c].interface[i].altsetting[a].endpoint[e].bEndpointAddress; + } + break; + default: s += "ERROR! Got an illegal value in endpoint bEndpointAddress"; + } + } + qDebug("%s", s.latin1()); + } + } + } + } + if (bulk_endpoint<0) { + qDebug("No valid interface found!"); + return false; + } +#endif + return true; +} + +QStringList Port::USB::probedDeviceList() +{ + initialize(); + QStringList list; +#ifdef HAVE_USB + usb_init(); // needed ? + for (usb_bus *bus=getBusses(); bus; bus=bus->next) { + for (struct usb_device *dev=bus->devices; dev; dev=dev->next) { + if ( dev->descriptor.idVendor==0 ) continue; // controller + list.append(QString("Vendor Id: %1 - Product Id: %2") + .arg(toLabel(NumberBase::Hex, dev->descriptor.idVendor, 4)).arg(toLabel(NumberBase::Hex, dev->descriptor.idProduct, 4))); + } + } +#endif + return list; +} + +struct usb_device *Port::USB::findDevice(uint vendorId, uint productId) +{ + initialize(); +#ifdef HAVE_USB + for (usb_bus *bus=getBusses(); bus; bus=bus->next) { + for (struct usb_device *dev=bus->devices; dev; dev=dev->next) { + if ( dev->descriptor.idVendor==vendorId && dev->descriptor.idProduct==productId ) + return dev; + } + } +#else + Q_UNUSED(vendorId); Q_UNUSED(productId); + qDebug("USB support disabled"); +#endif + return 0; +} + +//----------------------------------------------------------------------------- +const char * const Port::USB::ENDPOINT_MODE_NAMES[Nb_EndpointModes] = { + "bulk", "interrupt", "control", "isochronous" +}; + +Port::USB::USB(Log::Base &base, uint vendorId, uint productId, uint config, uint interface) + : Base(base), _vendorId(vendorId), _productId(productId), + _config(config), _interface(interface), _handle(0), _device(0) +{ + Q_ASSERT( config>=1 ); + _private = new Private; + initialize(); +} + +Port::USB::~USB() +{ + close(); + delete _private; +} + +void Port::USB::setSystemError(const QString &message) +{ +#ifdef HAVE_USB + log(Log::LineType::Error, message + QString(" (err=%1).").arg(usb_strerror())); +#else + log(Log::LineType::Error, message); +#endif +} + +void Port::USB::tryToDetachDriver() +{ + // try to detach an already existing driver... (linux only) +#if defined(LIBUSB_HAS_GET_DRIVER_NP) && LIBUSB_HAS_GET_DRIVER_NP + log(Log::DebugLevel::Extra, "find if there is already an installed driver"); + char dname[256] = ""; + if ( usb_get_driver_np(_handle, _interface, dname, 255)<0 ) return; + log(Log::DebugLevel::Normal, QString(" a driver \"%1\" is already installed...").arg(dname)); +# if defined(LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP) && LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP + usb_detach_kernel_driver_np(_handle, _interface); + log(Log::DebugLevel::Normal, " try to detach it..."); + if ( usb_get_driver_np(_handle, _interface, dname, 255)<0 ) return; + log(Log::DebugLevel::Normal, " failed to detach it"); +# endif +#endif +} + +bool Port::USB::internalOpen() +{ +#ifdef HAVE_USB + _device = findDevice(_vendorId, _productId); + if ( _device==0 ) { + log(Log::LineType::Error, i18n("Could not find USB device (vendor=%1 product=%2).") + .arg(toLabel(NumberBase::Hex, _vendorId, 4)).arg(toLabel(NumberBase::Hex, _productId, 4))); + return false; + } + log(Log::DebugLevel::Extra, QString("found USB device as \"%1\" on bus \"%2\"").arg(_device->filename).arg(_device->bus->dirname)); + _handle = usb_open(_device); + if ( _handle==0 ) { + setSystemError(i18n("Error opening USB device.")); + return false; + } +// windows: usb_reset takes about 7-10 seconds to re-enumerate the device... +// BSD : not implemented in libusb... +# if !defined(Q_OS_BSD4) && !defined(Q_OS_WIN) + if ( usb_reset(_handle)<0 ) { + setSystemError(i18n("Error resetting USB device.")); + return false; + } +# endif + usb_close(_handle); + _handle = usb_open(_device); + if ( _handle==0 ) { + setSystemError(i18n("Error opening USB device.")); + return false; + } + tryToDetachDriver(); + uint i = 0; + for (; i<_device->descriptor.bNumConfigurations; i++) + if ( _config==_device->config[i].bConfigurationValue ) break; + if ( i==_device->descriptor.bNumConfigurations ) { + uint old = _config; + i = 0; + _config = _device->config[i].bConfigurationValue; + log(Log::LineType::Warning, i18n("Configuration %1 not present: using %2").arg(old).arg(_config)); + } + const usb_config_descriptor &configd = _device->config[i]; + if ( usb_set_configuration(_handle, _config)<0 ) { + setSystemError(i18n("Error setting USB configuration %1.").arg(_config)); + return false; + } + for (i=0; i<configd.bNumInterfaces; i++) + if ( _interface==configd.interface[i].altsetting[0].bInterfaceNumber ) break; + if ( i==configd.bNumInterfaces ) { + uint old = _interface; + i = 0; + _interface = configd.interface[i].altsetting[0].bInterfaceNumber; + log(Log::LineType::Warning, i18n("Interface %1 not present: using %2").arg(old).arg(_interface)); + } + _private->_interface = &(configd.interface[i].altsetting[0]); + if ( usb_claim_interface(_handle, _interface)<0 ) { + setSystemError(i18n("Could not claim USB interface %1").arg(_interface)); + return false; + } + log(Log::DebugLevel::Max, QString("alternate setting is %1").arg(_private->_interface->bAlternateSetting)); + log(Log::DebugLevel::Max, QString("USB bcdDevice: %1").arg(toHexLabel(_device->descriptor.bcdDevice, 4))); + return true; +#else + log(Log::LineType::Error, i18n("USB support disabled")); + return false; +#endif +} + +void Port::USB::internalClose() +{ + if ( _handle==0 ) return; +#ifdef HAVE_USB + usb_release_interface(_handle, _interface); + usb_close(_handle); + _private->_interface = 0; +#endif + _device = 0; + _handle = 0; +} + +bool Port::USB::sendControlMessage(const ControlMessageData &data) +{ + if ( hasError() ) return false; +#ifdef HAVE_USB + QString s = data.bytes; + uint length = strlen(data.bytes) / 2; + QByteArray ba(length); + for (uint i=0; i<length; i++) + ba[i] = fromString(NumberBase::Hex, s.mid(2*i, 2), 0); + int res = usb_control_msg(_handle, data.type, data.request, data.value, 0, ba.data(), length, 1000); // 1s + if ( res<0 ) { + setSystemError(i18n("Error sending control message to USB port.")); + return false; + } +#endif + return true; +} + +uint timeout(uint size) +{ + return qMax(size*5, uint(1000)); // 5ms per byte or 1s +} + + +Port::USB::EndpointMode Port::USB::endpointMode(uint ep) const +{ +#ifdef HAVE_USB + uint index = ep & USB_ENDPOINT_ADDRESS_MASK; + Q_ASSERT(_private->_interface); + const usb_endpoint_descriptor *ued = _private->_interface->endpoint + index; + Q_ASSERT(ued); + switch (ued->bmAttributes & USB_ENDPOINT_TYPE_MASK) { + case USB_ENDPOINT_TYPE_BULK: return Bulk; + case USB_ENDPOINT_TYPE_INTERRUPT: return Interrupt; + case USB_ENDPOINT_TYPE_ISOCHRONOUS: return Isochronous; + case USB_ENDPOINT_TYPE_CONTROL: return Control; + default: break; + } +#endif + Q_ASSERT(false); + return Nb_EndpointModes; +} + +Port::IODir Port::USB::endpointDir(uint ep) const +{ +#ifdef HAVE_USB + switch (ep & USB_ENDPOINT_DIR_MASK) { + case USB_ENDPOINT_IN: return In; + case USB_ENDPOINT_OUT: return Out; + default: break; + } +#endif + Q_ASSERT(false); + return NoIO; +} + +bool Port::USB::write(uint ep, const char *data, uint size) +{ + if ( hasError() ) return false; +#ifdef HAVE_USB + IODir dir = endpointDir(ep); + EndpointMode mode = endpointMode(ep); + log(Log::DebugLevel::LowLevel, QString("write to endpoint %1 (%2 - %3) %4 chars: \"%5\"") + .arg(toHexLabel(ep, 2)).arg(ENDPOINT_MODE_NAMES[mode]).arg(IO_DIR_NAMES[dir]).arg(size).arg(toPrintable(data, size, PrintEscapeAll))); + Q_ASSERT( dir==Out ); + QTime time; + time.start(); + int todo = size; + for (;;) { + int res = 0; + //qDebug("write ep=%i todo=%i/%i", ep, todo, size); + if ( mode==Interrupt ) res = usb_interrupt_write(_handle, ep, (char *)data + size - todo, todo, timeout(todo)); + else res = usb_bulk_write(_handle, ep, (char *)data + size - todo, todo, timeout(todo)); + //qDebug("res: %i", res); + if ( res==todo ) break; + if ( uint(time.elapsed())>3000 ) { // 3 s + if ( res<0 ) setSystemError(i18n("Error sending data (ep=%1 res=%2)").arg(toHexLabel(ep, 2)).arg(res)); + else log(Log::LineType::Error, i18n("Timeout: only some data sent (%1/%2 bytes).").arg(size-todo).arg(size)); + return false; + } + if ( res==0 ) log(Log::DebugLevel::Normal, i18n("Nothing sent: retrying...")); + if ( res>0 ) todo -= res; + msleep(100); + } +#else + Q_UNUSED(ep); Q_UNUSED(data); Q_UNUSED(size); +#endif + return true; +} + +bool Port::USB::read(uint ep, char *data, uint size, bool *poll) +{ + if ( hasError() ) return false; +#ifdef HAVE_USB + IODir dir = endpointDir(ep); + EndpointMode mode = endpointMode(ep); + log(Log::DebugLevel::LowLevel, QString("read from endpoint %1 (%2 - %3) %4 chars") + .arg(toHexLabel(ep, 2)).arg(ENDPOINT_MODE_NAMES[mode]).arg(IO_DIR_NAMES[dir]).arg(size)); + Q_ASSERT( dir==In ); + QTime time; + time.start(); + int todo = size; + for (;;) { + int res = 0; + //qDebug("read ep=%i size=%i", ep, todo); + if ( mode==Interrupt ) res = usb_interrupt_read(_handle, ep, data + size - todo, todo, timeout(todo)); + else res = usb_bulk_read(_handle, ep, data + size - todo, todo, timeout(todo)); + //qDebug("res: %i", res); + if ( res==todo ) break; + if ( uint(time.elapsed())>3000 ) { // 3 s: seems to help icd2 in some case (?) + if ( res<0 ) setSystemError(i18n("Error receiving data (ep=%1 res=%2)").arg(toHexLabel(ep, 2)).arg(res)); + else log(Log::LineType::Error, i18n("Timeout: only some data received (%1/%2 bytes).").arg(size-todo).arg(size)); + return false; + } + if ( res==0 ) { + if (poll) { + *poll = false; + return true; + } else log(Log::DebugLevel::Normal, i18n("Nothing received: retrying...")); + } + if ( res>0 ) todo -= res; + msleep(100); + } + if (poll) *poll = true; +#else + Q_UNUSED(ep); Q_UNUSED(data); Q_UNUSED(size); +#endif + return true; +} diff --git a/src/common/port/usb_port.h b/src/common/port/usb_port.h new file mode 100644 index 0000000..73961cc --- /dev/null +++ b/src/common/port/usb_port.h @@ -0,0 +1,70 @@ +/*************************************************************************** + * Copyright (C) 2005 Lorenz Mösenlechner & Matthias Kranz * + * <icd2linux@hcilab.org> * + * Copyright (C) 2005 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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 USB_PORT_H +#define USB_PORT_H + +#include "port_base.h" +#if defined(Q_OS_WIN) +#undef interface +#endif +struct usb_dev_handle; +struct usb_device; +struct usb_bus; + +namespace Port +{ + +class USB : public Base +{ +public: + USB(Log::Base &base, uint vendorId, uint productId, uint config, uint interface); + virtual ~USB(); + virtual Description description() const { return Description(PortType::USB, QString::null); } + + static struct usb_device *findDevice(uint vendorId, uint productId); + static bool isAvailable(); + static QStringList probedDeviceList(); + + struct ControlMessageData { + int type, request, value; + const char *bytes; + }; + bool sendControlMessage(const ControlMessageData &data); + enum EndpointMode { Bulk = 0, Interrupt, Control, Isochronous, Nb_EndpointModes }; + static const char * const ENDPOINT_MODE_NAMES[Nb_EndpointModes]; + EndpointMode endpointMode(uint ep) const; + IODir endpointDir(uint ep) const; + +protected: + bool write(uint endPoint, const char *data, uint size); + bool read(uint endPoint, char *data, uint size, bool *poll = 0); + +private: + class Private; + Private *_private; + uint _vendorId, _productId, _config, _interface; + usb_dev_handle *_handle; + usb_device *_device; + + virtual bool internalOpen(); + virtual void internalClose(); + virtual void setSystemError(const QString &message); + void tryToDetachDriver(); + + static bool _initialized; + static void initialize(); + static usb_bus *getBusses(); + static bool findBulk(const struct usb_device *device); +}; + +} // namespace + +#endif |