diff options
Diffstat (limited to 'src')
37 files changed, 16003 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..fa3fa5c --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,73 @@ + ################################################# +# +# (C) 2010-2011 Serghei Amelian +# serghei (DOT) amelian (AT) gmail.com +# +# Improvements and feedback are welcome +# +# This file is released under GPL >= 2 +# +################################################# + +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${TQT_INCLUDE_DIRS} + ${DBUS_INCLUDE_DIRS} +) + +link_directories( + ${TQT_LIBRARY_DIRS} +) + + +##### install headers ########################### + +install( FILES + tqdbuserror.h tqdbusmessage.h tqdbusconnection.h + tqdbusvariant.h tqdbusobject.h tqdbusproxy.h + tqdbusmacros.h tqdbusdata.h tqdbusdatalist.h + tqdbusdatamap.h tqdbusobjectpath.h tqdbusunixfd.h + tqdbusdataconverter.h + DESTINATION ${INCLUDE_INSTALL_DIR} ) + + +##### dbus-1-tqt (shared) ######################### + +tde_add_library( dbus-1-tqt SHARED AUTOMOC + SOURCES ${dbus_tqt_MOCS} + tqdbusconnection.cpp tqdbuserror.cpp tqdbusintegrator.cpp + tqdbusmarshall.cpp tqdbusmessage.cpp tqdbusserver.cpp + tqdbusproxy.cpp tqdbusdata.cpp tqdbusdatalist.cpp + tqdbusobjectpath.cpp tqdbusunixfd.cpp + tqdbusdataconverter.cpp + VERSION 0.0.0 + LINK ${TQT_LIBRARIES} ${DBUS_LIBRARIES} + DESTINATION ${LIB_INSTALL_DIR} +) + + +##### dbusxml2qt3 (executable) ################## + +tde_add_executable( dbusxml2qt3 + SOURCES + tools/dbusxml2qt3/classgen.cpp + tools/dbusxml2qt3/main.cpp + tools/dbusxml2qt3/methodgen.cpp + LINK ${TQT_LIBRARIES} + DESTINATION ${BIN_INSTALL_DIR} +) + + +##### add apidox targets ############ + +add_custom_target( apidox + COMMAND test -d ${APIDOX_DIRECTORY} || mkdir -p ${APIDOX_DIRECTORY} + COMMAND doxygen ${CMAKE_BINARY_DIR}/dbus-1-tqt.Doxyfile + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + ) + +add_custom_target( install-apidox + COMMAND "./install_apidox" "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" "${APIDOX_HTML_DIRECTORY}" + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/cmake/" + ) diff --git a/src/tools/dbusxml2qt3/LICENSE b/src/tools/dbusxml2qt3/LICENSE new file mode 100644 index 0000000..1edf08c --- /dev/null +++ b/src/tools/dbusxml2qt3/LICENSE @@ -0,0 +1,18 @@ +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. diff --git a/src/tools/dbusxml2qt3/classgen.cpp b/src/tools/dbusxml2qt3/classgen.cpp new file mode 100644 index 0000000..12051c0 --- /dev/null +++ b/src/tools/dbusxml2qt3/classgen.cpp @@ -0,0 +1,1091 @@ +/* +* Copyright (C) 2007 Kevin Krammer <kevin.krammer@gmx.at> +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ + +// TQt includes +#include <tqdom.h> +#include <tqfile.h> +#include <tqstringlist.h> +#include <tqtextstream.h> + +// local includes +#include "classgen.h" +#include "methodgen.h" + +class Set : public TQMap<TQString, bool> +{ +public: + void insertString(const TQString& key) + { + insert(key, true); + } + + void removeString(const TQString& key) + { + erase(key); + } + + void insertStringList(const TQStringList& list) + { + TQStringList::const_iterator it = list.begin(); + TQStringList::const_iterator endIt = list.end(); + for (; it != endIt; ++it) + { + insert(*it, true); + } + } +}; + +static void writeFileHeader(TQTextStream& stream) +{ + stream << "// File autogenerated" << endl; + stream << endl; +} + +static void writeFileFooter(TQTextStream& stream) +{ + stream << "// End of File" << endl; + stream << endl; +} + +static void openIncludeGuard(const TQString& className, TQTextStream& stream) +{ + stream << "#if !defined(" << className.upper() << "_H_INCLUDED)" << endl; + stream << "#define " << className.upper() << "_H_INCLUDED" << endl; + stream << endl; +} + +static void closeIncludeGuard(const TQString& className, TQTextStream& stream) +{ + stream << "#endif //" << className.upper() << "_H_INCLUDED" << endl; + stream << endl; +} + +static void openNamespaces(const TQStringList& namespaces, TQTextStream& stream) +{ + TQStringList::const_iterator it = namespaces.begin(); + TQStringList::const_iterator endIt = namespaces.end(); + for (; it != endIt; ++it) + { + stream << "namespace " << *it << endl; + stream << "{" << endl; + } + stream << endl; +} + +static void closeNamespaces(const TQStringList& namespaces, TQTextStream& stream) +{ + TQStringList::const_iterator it = namespaces.end(); + TQStringList::const_iterator endIt = namespaces.end(); + for (--it; it != endIt; --it) + { + stream << "}; // namespace " << *it << endl; + stream << endl; + } +} + +static void writeIncludes(const TQString& description, const TQStringList& includes, + TQTextStream& stream) +{ + if (includes.isEmpty()) return; + + stream << "// " << description << " includes" << endl; + + TQStringList::const_iterator it = includes.begin(); + TQStringList::const_iterator endIt = includes.end(); + for (;it != endIt; ++it) + { + stream << "#include " << *it << endl; + } + + stream << endl; +} + +static void extractHeaderIncludes(const Method& method, + TQMap<TQString, Set>& includes) +{ + TQValueList<Argument>::const_iterator it = method.arguments.begin(); + TQValueList<Argument>::const_iterator endIt = method.arguments.end(); + for (; it != endIt; ++it) + { + if ((*it).headerIncludes.isEmpty()) continue; + + TQMap<TQString, TQStringList>::const_iterator mapIt = + (*it).headerIncludes.begin(); + TQMap<TQString, TQStringList>::const_iterator mapEndIt = + (*it).headerIncludes.end(); + + for (; mapIt != mapEndIt; ++mapIt) + { + includes[mapIt.key()].insertStringList(mapIt.data()); + } + } +} + +static void extractForwardDeclarations(const Method& method, Set& forwards) +{ + TQValueList<Argument>::const_iterator it = method.arguments.begin(); + TQValueList<Argument>::const_iterator endIt = method.arguments.end(); + for (; it != endIt; ++it) + { + if ((*it).forwardDeclarations.isEmpty()) continue; + + forwards.insertStringList((*it).forwardDeclarations); + } +} + +static void writeHeaderIncludes(const Class& classData, Class::Role role, + TQTextStream& stream) +{ + TQMap<TQString, Set> includes; + Set forwards; + + TQValueList<Method>::const_iterator it = classData.methods.begin(); + TQValueList<Method>::const_iterator endIt = classData.methods.end(); + for (; it != endIt; ++it) + { + if ((*it).arguments.isEmpty()) continue; + + extractHeaderIncludes(*it, includes); + extractForwardDeclarations(*it, forwards); + } + + it = classData.msignals.begin(); + endIt = classData.msignals.end(); + for (; it != endIt; ++it) + { + if ((*it).arguments.isEmpty()) continue; + + extractHeaderIncludes(*it, includes); + extractForwardDeclarations(*it, forwards); + } + + + TQValueList<Property>::const_iterator propertyIt = classData.properties.begin(); + TQValueList<Property>::const_iterator propertyEndIt = classData.properties.end(); + for (; propertyIt != propertyEndIt; ++propertyIt) + { + if (!(*propertyIt).headerIncludes.isEmpty()) + { + TQMap<TQString, TQStringList>::const_iterator mapIt = + (*propertyIt).headerIncludes.begin(); + TQMap<TQString, TQStringList>::const_iterator mapEndIt = + (*propertyIt).headerIncludes.end(); + + for (; mapIt != mapEndIt; ++mapIt) + { + includes[mapIt.key()].insertStringList(mapIt.data()); + } + } + + if (!(*propertyIt).forwardDeclarations.isEmpty()) + { + forwards.insertStringList((*propertyIt).forwardDeclarations); + } + } + + switch (role) + { + case Class::Interface: + includes["tqdbus"].insertString("<tqdbusobject.h>"); + forwards.insertString("class TQT_DBusError"); + forwards.insertString("class TQDomElement"); + if (!classData.msignals.isEmpty()) + forwards.insertString("class TQString"); + if (!classData.asyncMethods.isEmpty()) + { + includes["TQt"].insertString("<tqmap.h>"); + forwards.erase("template <typename K, typename V> class TQMap"); + + includes["tqdbus"].insertString("<tqdbusmessage.h>"); + forwards.erase("class TQT_DBusMessage"); + } + break; + + case Class::Proxy: + includes["TQt"].insertString("<tqobject.h>"); + forwards.insertString("class TQT_DBusConnection"); + forwards.insertString("class TQT_DBusError"); + forwards.insertString("class TQT_DBusMessage"); + forwards.insertString("class TQT_DBusProxy"); + forwards.insertString("class TQString"); + if (!classData.properties.isEmpty()) + forwards.insertString("class TQT_DBusVariant"); + if (!classData.asyncMethods.isEmpty()) + { + includes["TQt"].insertString("<tqmap.h>"); + forwards.erase("template <typename K, typename V> class TQMap"); + } + break; + + case Class::Node: + includes["tqdbus"].insertString("<tqdbusobject.h>"); + forwards.insertString("class TQT_DBusConnection"); + forwards.insertString("class TQString"); + break; + } + + includes["tqdbus"].insertString("<tqdbuserror.h>"); + + if (!includes["TQt"].isEmpty()) + writeIncludes("TQt", includes["TQt"].keys(), stream); + + if (!includes["tqdbus"].isEmpty()) + writeIncludes("TQt D-Bus", includes["tqdbus"].keys(), stream); + + if (!includes["local"].isEmpty()) + writeIncludes("local", includes["local"].keys(), stream); + + stream << "// forward declarations" << endl; + Set::const_iterator setIt = forwards.begin(); + Set::const_iterator setEndIt = forwards.end(); + for (; setIt != setEndIt; ++setIt) + { + stream << setIt.key() << ";" << endl; + } + stream << endl; +} + +static void extractSourceIncludes(const Method& method, + TQMap<TQString, Set>& includes) +{ + TQValueList<Argument>::const_iterator it = method.arguments.begin(); + TQValueList<Argument>::const_iterator endIt = method.arguments.end(); + for (; it != endIt; ++it) + { + if ((*it).sourceIncludes.isEmpty()) continue; + + TQMap<TQString, TQStringList>::const_iterator mapIt = + (*it).sourceIncludes.begin(); + TQMap<TQString, TQStringList>::const_iterator mapEndIt = + (*it).sourceIncludes.end(); + + for (; mapIt != mapEndIt; ++mapIt) + { + includes[mapIt.key()].insertStringList(mapIt.data()); + } + } +} + +static void writeSourceIncludes(const Class& classData, Class::Role role, + TQTextStream& stream) +{ + TQMap<TQString, Set> includes; + + TQValueList<Method>::const_iterator it = classData.methods.begin(); + TQValueList<Method>::const_iterator endIt = classData.methods.end(); + for (; it != endIt; ++it) + { + if ((*it).arguments.isEmpty()) continue; + + extractSourceIncludes(*it, includes); + } + + it = classData.msignals.begin(); + endIt = classData.msignals.end(); + for (; it != endIt; ++it) + { + if ((*it).arguments.isEmpty()) continue; + + extractSourceIncludes(*it, includes); + } + + TQValueList<Property>::const_iterator propertyIt = classData.properties.begin(); + TQValueList<Property>::const_iterator propertyEndIt = classData.properties.end(); + for (; propertyIt != propertyEndIt; ++propertyIt) + { + if ((*propertyIt).sourceIncludes.isEmpty()) continue; + + TQMap<TQString, TQStringList>::const_iterator mapIt = + (*propertyIt).sourceIncludes.begin(); + TQMap<TQString, TQStringList>::const_iterator mapEndIt = + (*propertyIt).sourceIncludes.end(); + + for (; mapIt != mapEndIt; ++mapIt) + { + includes[mapIt.key()].insertStringList(mapIt.data()); + } + } + + switch (role) + { + case Class::Interface: + includes["TQt"].insertString("<tqdom.h>"); + includes["tqdbus"].insertString("<tqdbuserror.h>"); + includes["tqdbus"].insertString("<tqdbusmessage.h>"); + break; + + case Class::Proxy: + includes["tqdbus"].insertString("<tqdbuserror.h>"); + includes["tqdbus"].insertString("<tqdbusmessage.h>"); + includes["tqdbus"].insertString("<tqdbusproxy.h>"); + if (!classData.properties.isEmpty()) + { + includes["tqdbus"].insertString("<tqdbusconnection.h>"); + includes["tqdbus"].insertString("<tqdbusvariant.h>"); + } + break; + + case Class::Node: + includes["TQt"].insertString("<tqdom.h>"); + includes["TQt"].insertString("<tqmap.h>"); + includes["tqdbus"].insertString("<tqdbusconnection.h>"); + includes["tqdbus"].insertString("<tqdbusmessage.h>"); + break; + } + + if (!includes["TQt"].isEmpty()) + writeIncludes("TQt", includes["TQt"].keys(), stream); + + if (!includes["tqdbus"].isEmpty()) + writeIncludes("TQt D-Bus", includes["tqdbus"].keys(), stream); + + if (!includes["local"].isEmpty()) + writeIncludes("local", includes["local"].keys(), stream); + + stream << endl; +} + +static void writeInterfaceIncludes(const TQValueList<Class> interfaces, + TQTextStream& stream) +{ + stream << "// interface classes includes" << endl; + + TQValueList<Class>::const_iterator it = interfaces.begin(); + TQValueList<Class>::const_iterator endIt = interfaces.end(); + for (; it != endIt; ++it) + { + stream << "#include \"" << (*it).name.lower() << ".h\"" << endl; + } + + stream << "#include \"introspectableinterface.h\"" << endl; + + stream << endl; +} + +static void openClassDeclaration(const Class& classData, + Class::Role role, TQTextStream& stream) +{ + switch (role) + { + case Class::Interface: + stream << "class " << classData.name << " : public TQT_DBusObjectBase" + << endl; + stream << "{" << endl; + stream << "public:" << endl; + stream << " virtual ~" << classData.name << "() {}" << endl; + stream << endl; + stream << " static void buildIntrospectionData(TQDomElement& interfaceElement);" << endl; + break; + + case Class::Proxy: + stream << "class " << classData.name << " : public TQObject" << endl; + stream << "{" << endl; + stream << " Q_OBJECT" << endl; + stream << " " << endl; + stream << "public:" << endl; + stream << " " << classData.name + << "(const TQString& service, const TQString& path, TQObject* parent = 0, const char* name = 0);" << endl; + stream << endl; + + stream << " virtual ~" << classData.name << "();" << endl; + stream << endl; + + stream << " void setConnection(const TQT_DBusConnection& connection);" + << endl; + break; + + case Class::Node: + stream << "class " << classData.name << " : public TQT_DBusObjectBase" + << endl; + stream << "{" << endl; + stream << "public:" << endl; + stream << " " << classData.name << "();" << endl; + stream << endl; + stream << " virtual ~" << classData.name << "();" << endl; + stream << endl; + stream << " bool registerObject(const TQT_DBusConnection& connection, " + << "const TQString& path);" << endl; + stream << endl; + stream << " void unregisterObject();" << endl; + stream << endl; + stream << "protected:" << endl; + stream << " virtual TQT_DBusObjectBase* createInterface(" + << "const TQString& interfaceName) = 0;" << endl; + stream << endl; + stream << "protected: // usually no need to reimplement" << endl; + stream << " virtual bool handleMethodCall(const TQT_DBusMessage& message);" << endl; + stream << endl; + stream << "private:" << endl; + stream << " class Private;" << endl; + stream << " Private* m_private;" << endl; + break; + } + + stream << endl; +} + +static void closeClassDeclaration(const Class& classData, Class::Role role, + TQTextStream& stream) +{ + switch (role) + { + case Class::Interface: + break; + + case Class::Proxy: + stream << "private: // Hiding copy constructor and assignment operator" << endl; + stream << " " << classData.name << "(const " + << classData.name << "&);" << endl; + stream << " " << classData.name << "& operator=(const " + << classData.name << "&);" << endl; + break; + + case Class::Node: + stream << "private: // Hiding copy constructor and assignment operator" << endl; + stream << " " << classData.name << "(const " + << classData.name << "&);" << endl; + stream << " " << classData.name << "& operator=(const " + << classData.name << "&);" << endl; + break; + } + stream << "}; // class " << classData.name << endl; + stream << endl; +} + +static void writeMethodDeclarations(const Class& classData, Class::Role role, + TQTextStream& stream) +{ + if (role == Class::Interface && !classData.asyncReplyMethods.isEmpty()) + { + stream << "public:" << endl; + + TQValueList<Method>::const_iterator it = + classData.asyncReplyMethods.begin(); + TQValueList<Method>::const_iterator endIt = + classData.asyncReplyMethods.end(); + for (; it != endIt; ++it) + { + Method method = *it; + method.name += "AsyncReply"; + + stream << " virtual void "; + MethodGenerator::writeMethodDeclaration(method, false, false, stream); + + stream << " virtual void " << (*it).name + << "AsyncError(int asyncCallId, const TQT_DBusError& error);" + << endl; + stream << endl; + } + } + + if (!classData.methods.isEmpty() || !classData.asyncMethods.isEmpty()) + { + bool pureVirtual = true; + switch (role) + { + case Class::Interface: + pureVirtual = true; + stream << "protected:" << endl; + break; + + case Class::Proxy: + pureVirtual = false; + stream << "public:" << endl; + break; + + case Class::Node: // no variable methods + break; + } + + TQValueList<Method>::const_iterator it = classData.methods.begin(); + TQValueList<Method>::const_iterator endIt = classData.methods.end(); + for (; it != endIt; ++it) + { + if ((*it).async) continue; + + stream << " virtual bool "; + MethodGenerator::writeMethodDeclaration(*it, pureVirtual, true, stream); + } + + it = classData.asyncMethods.begin(); + endIt = classData.asyncMethods.end(); + for (; it != endIt; ++it) + { + Method method = *it; + method.name += "Async"; + + switch (role) + { + case Class::Interface: + stream << " virtual void "; + MethodGenerator::writeMethodDeclaration(method, pureVirtual, false, stream); + break; + + case Class::Proxy: + stream << " virtual bool "; + MethodGenerator::writeMethodDeclaration(method, pureVirtual, true, stream); + break; + + case Class::Node: // no async methods + break; + } + } + } + + if (!classData.properties.isEmpty()) + { + bool pureVirtual = true; + bool skip = false; + switch (role) + { + case Class::Interface: + tqWarning("Properties not yet supported for interfaces"); + skip = true; + pureVirtual = true; + break; + + case Class::Proxy: + pureVirtual = false; + stream << "public:" << endl; + stream << " virtual void setDBusProperty(const TQString& name," + << " const TQT_DBusVariant& variant, TQT_DBusError& error);" + << endl; + stream << " virtual TQT_DBusVariant getDBusProperty(const TQString& name, TQT_DBusError& error) const;" << endl; + stream << endl; + break; + + case Class::Node: // no node properties + skip = true; + break; + } + + if (!skip) + { + TQValueList<Property>::const_iterator it = classData.properties.begin(); + TQValueList<Property>::const_iterator endIt = classData.properties.end(); + for (; it != endIt; ++it) + { + MethodGenerator::writePropertyDeclaration(*it, pureVirtual, stream); + } + } + } + + switch (role) + { + case Class::Interface: + if (!classData.methods.isEmpty() || !classData.asyncMethods.isEmpty()) + { + stream << "protected: // implement sending replies" << endl; + stream << " virtual void handleMethodReply(const TQT_DBusMessage& reply) = 0;" << endl; + stream << endl; + stream << "protected: // usually no need to reimplement" << endl; + stream << " virtual bool handleMethodCall(const TQT_DBusMessage& message);" << endl; + } + else + { + stream << "protected: // no methods to handle" << endl; + stream << " virtual bool handleMethodCall(const TQT_DBusMessage&) { return false; }" << endl; + } + break; + + case Class::Proxy: + { + if (!classData.msignals.isEmpty()) + { + stream << "protected slots: // usually no need to reimplement" << endl; + stream << " virtual void slotHandleDBusSignal(const TQT_DBusMessage& message);" << endl; + stream << endl; + } + + if (!classData.asyncReplySignals.isEmpty()) + { + if (classData.msignals.isEmpty()) + { + stream << "protected slots: // usually no need to reimplement" << endl; + } + stream << " virtual void slotHandleAsyncReply(int id, const TQT_DBusMessage& message);" << endl; + stream << endl; + } + + stream << "protected:" << endl; + stream << " TQT_DBusProxy* m_baseProxy;" << endl; + + if (!classData.asyncMethods.isEmpty()) + { + stream << endl; + stream << " TQMap<int, TQString> m_asyncCalls;" << endl; + } + + break; + } + + case Class::Node: // not variable methods + break; + } + + stream << endl; +} + +static void writeSignalDeclarations(const Class& classData, Class::Role role, + TQTextStream& stream) +{ + if (classData.msignals.isEmpty() && classData.asyncReplySignals.isEmpty()) + return; + + TQString prefix; + switch (role) + { + case Class::Interface: + stream << "protected: // implement sending signals" << endl; + stream << " virtual bool handleSignalSend(const TQT_DBusMessage& reply) = 0;" << endl; + stream << " virtual TQString objectPath() const = 0;" << endl; + stream << endl; + stream << "protected: // for sending D-Bus signals" << endl; + prefix = " virtual bool emit"; + break; + + case Class::Proxy: + stream << "signals:" << endl; + stream << " void AsyncErrorResponseDetected(int asyncCallId, const TQT_DBusError error);" << endl << endl; + prefix = " void "; + break; + + case Class::Node: // no signals + break; + } + + TQValueList<Method>::const_iterator it = classData.msignals.begin(); + TQValueList<Method>::const_iterator endIt = classData.msignals.end(); + for (; it != endIt; ++it) + { + stream << prefix; + MethodGenerator::writeMethodDeclaration(*it, false, false, stream); + } + + it = classData.asyncReplySignals.begin(); + endIt = classData.asyncReplySignals.end(); + for (; it != endIt; ++it) + { + stream << prefix; + + Method signal = *it; + signal.name += "AsyncReply"; + + MethodGenerator::writeMethodDeclaration(signal, false, false, stream); + } + + stream << endl; +} + +static void writeSignalEmitters(const Class& classData, TQTextStream& stream) +{ + if (classData.msignals.isEmpty()) return; + + TQValueList<Method>::const_iterator it = classData.msignals.begin(); + TQValueList<Method>::const_iterator endIt = classData.msignals.end(); + for (; it != endIt; ++it) + { + MethodGenerator::writeSignalEmitter(classData, *it, stream); + } + + stream << endl; +} + +static void writeMethodCallDeclarations(const Class& classData, + TQTextStream& stream) +{ + TQValueList<Method>::const_iterator it = classData.methods.begin(); + TQValueList<Method>::const_iterator endIt = classData.methods.end(); + for (; it != endIt; ++it) + { + stream << " "; + MethodGenerator::writeMethodCallDeclaration(*it, stream); + } + + if (!classData.asyncReplyMethods.isEmpty()) + { + stream << "protected:" << endl; + stream << " TQMap<int, TQT_DBusMessage> m_asyncCalls;" << endl; + stream << endl; + } +} + +static void writeInterfaceAsyncReplyHandlers(const Class& classData, + TQTextStream& stream) +{ + if (classData.asyncReplyMethods.isEmpty()) return; + + TQValueList<Method>::const_iterator it = classData.asyncReplyMethods.begin(); + TQValueList<Method>::const_iterator endIt = classData.asyncReplyMethods.end(); + for (; it != endIt; ++it) + { + MethodGenerator::writeInterfaceAsyncReplyHandler(classData, *it, stream); + } +} + +static void writeMethodCalls(const Class& classData, TQTextStream& stream) +{ + TQValueList<Method>::const_iterator it = classData.methods.begin(); + TQValueList<Method>::const_iterator endIt = classData.methods.end(); + for (; it != endIt; ++it) + { + if ((*it).async) continue; + + MethodGenerator::writeMethodCall(classData, *it, stream); + } + + it = classData.asyncMethods.begin(); + endIt = classData.asyncMethods.end(); + for (; it != endIt; ++it) + { + MethodGenerator::writeMethodCall(classData, *it, stream); + } +} + +static void writeProxyMethods(const Class& classData, TQTextStream& stream) +{ + TQValueList<Method>::const_iterator it = classData.methods.begin(); + TQValueList<Method>::const_iterator endIt = classData.methods.end(); + for (; it != endIt; ++it) + { + if ((*it).async) continue; + + MethodGenerator::writeProxyMethod(classData.name, *it, stream); + } + + it = classData.asyncMethods.begin(); + endIt = classData.asyncMethods.end(); + for (; it != endIt; ++it) + { + MethodGenerator::writeProxyMethod(classData.name, *it, stream); + } +} + +static void writeProxyProperties(const Class& classData, TQTextStream& stream) +{ + if (classData.properties.isEmpty()) return; + + MethodGenerator::writeProxyGenericProperty(classData, stream); + + TQValueList<Property>::const_iterator it = classData.properties.begin(); + TQValueList<Property>::const_iterator endIt = classData.properties.end(); + for (; it != endIt; ++it) + { + MethodGenerator::writeProxyProperty(classData, *it, stream); + } +} + +static void splitAsyncProxyMethods(Class& classData) +{ + // create the async identifier + Argument idArgMethod; + idArgMethod.name = "asyncCallId"; + idArgMethod.signature = "int"; + idArgMethod.isPrimitive = true; + idArgMethod.direction = Argument::Out; + + Argument idArgSignal = idArgMethod; + idArgSignal.direction = Argument::In; + + TQValueList<Method>::iterator it = classData.methods.begin(); + TQValueList<Method>::iterator endIt = classData.methods.end(); + for (; it != endIt; ++it) + { + if (!(*it).async) continue; + + Method method = *it; + + TQValueList<Argument> methodArgs; + TQValueList<Argument> signalArgs; + + // add id argument + methodArgs << idArgMethod; + signalArgs << idArgSignal; + + // split in/out arguments: "in" belong to the method, "out" to the new signal + TQValueList<Argument>::const_iterator argIt = method.arguments.begin(); + TQValueList<Argument>::const_iterator argEndIt = method.arguments.end(); + for (; argIt != argEndIt; ++argIt) + { + if ((*argIt).direction == Argument::Out) + { + // signal parameters are "out" but have "in" signature, + // e.g. "const T&" + Argument arg = *argIt; + arg.direction = Argument::In; + + signalArgs << arg; + } + else + methodArgs << *argIt; + } + + // change method + method.arguments = methodArgs; + + classData.asyncMethods << method; + + // create "callback" signal + Method signal = method; + signal.arguments = signalArgs; + + classData.asyncReplySignals << signal; + } +} + +static void splitAsyncInterfaceMethods(Class& classData) +{ + // create the async identifier + Argument idArgMethod; + idArgMethod.name = "asyncCallId"; + idArgMethod.signature = "int"; + idArgMethod.isPrimitive = true; + idArgMethod.direction = Argument::In; + + Argument idArgReply = idArgMethod; + + TQValueList<Method>::iterator it = classData.methods.begin(); + TQValueList<Method>::iterator endIt = classData.methods.end(); + for (; it != endIt; ++it) + { + if (!(*it).async) continue; + + Method method = *it; + + TQValueList<Argument> methodArgs; + TQValueList<Argument> replyArgs; + + // add id argument + methodArgs << idArgMethod; + replyArgs << idArgReply; + + // split in/out arguments: "in" belong to the call, "out" to the reply + TQValueList<Argument>::const_iterator argIt = method.arguments.begin(); + TQValueList<Argument>::const_iterator argEndIt = method.arguments.end(); + for (; argIt != argEndIt; ++argIt) + { + if ((*argIt).direction == Argument::Out) + { + // reply parameters are "out" for the service but "in" for + // the reply handler + Argument arg = *argIt; + arg.direction = Argument::In; + + replyArgs << arg; + } + else + methodArgs << *argIt; + } + + // change method + method.arguments = methodArgs; + + classData.asyncMethods << method; + + // create reply handler + Method reply = method; + reply.arguments = replyArgs; + + classData.asyncReplyMethods << reply; + } +} + +bool ClassGenerator::initStreams(const TQString& baseName, + TQTextStream& headerStream, + TQTextStream& sourceStream) +{ + TQFile* headerFile = new TQFile(baseName + ".h"); + TQFile* sourceFile = new TQFile(baseName + ".cpp"); + + if (!headerFile->open(IO_WriteOnly) || !sourceFile->open(IO_WriteOnly)) + { + delete headerFile; + delete sourceFile; + + return false; + } + + headerStream.setDevice(TQT_TQIODEVICE(headerFile)); + sourceStream.setDevice(TQT_TQIODEVICE(sourceFile)); + + // create header + writeFileHeader(headerStream); + openIncludeGuard(baseName, headerStream); + + // create source + writeFileHeader(sourceStream); + sourceStream << "// declaration include" << endl; + sourceStream << "#include \"" << baseName << ".h\"" << endl; + sourceStream << endl; + + return true; +} + +bool ClassGenerator::finishStreams(const TQString& baseName, + TQTextStream& headerStream, + TQTextStream& sourceStream) +{ + closeIncludeGuard(baseName, headerStream); + writeFileFooter(headerStream); + writeFileFooter(sourceStream); + + TQIODevice* device = headerStream.device(); + headerStream.unsetDevice(); + delete device; + + device = sourceStream.device(); + sourceStream.unsetDevice(); + delete device; + + return true; +} + +bool ClassGenerator::extractClass(const TQDomElement& interfaceElement, + Class& classData) +{ + tqDebug("ClassGenerator: processing interface '%s'", + interfaceElement.attribute("name").latin1()); + + classData.dbusName = interfaceElement.attribute("name"); + + TQStringList nameParts = TQStringList::split('.', classData.dbusName); + + if (nameParts.count() < 2) return false; + + classData.name = nameParts.back(); + nameParts.pop_back(); + classData.namespaces = nameParts; + + return MethodGenerator::extractMethods(interfaceElement, classData); +} + +bool ClassGenerator::generateInterface(const Class& classData, + TQTextStream& headerStream, + TQTextStream& sourceStream) +{ + Class classDataCopy = classData; + splitAsyncInterfaceMethods(classDataCopy); + + // create header + writeHeaderIncludes(classDataCopy, Class::Interface, headerStream); + + openNamespaces(classDataCopy.namespaces, headerStream); + openClassDeclaration(classDataCopy, Class::Interface, headerStream); + + writeSignalDeclarations(classDataCopy, Class::Interface, headerStream); + writeMethodDeclarations(classDataCopy, Class::Interface, headerStream); + writeMethodCallDeclarations(classDataCopy, headerStream); + + closeClassDeclaration(classDataCopy, Class::Interface, headerStream); + closeNamespaces(classDataCopy.namespaces, headerStream); + + // create source + writeSourceIncludes(classDataCopy, Class::Interface, sourceStream); + + openNamespaces(classDataCopy.namespaces, sourceStream); + + MethodGenerator::writeIntrospectionDataMethod(classDataCopy, sourceStream); + + writeSignalEmitters(classDataCopy, sourceStream); + writeInterfaceAsyncReplyHandlers(classDataCopy, sourceStream); + writeMethodCalls(classDataCopy, sourceStream); + + MethodGenerator::writeInterfaceMainMethod(classDataCopy, sourceStream); + + closeNamespaces(classDataCopy.namespaces, sourceStream); + + return true; +} + +bool ClassGenerator::generateProxy(const Class& classData, + TQTextStream& headerStream, + TQTextStream& sourceStream) +{ + Class classDataCopy = classData; + splitAsyncProxyMethods(classDataCopy); + + // create header + writeHeaderIncludes(classDataCopy, Class::Proxy, headerStream); + + openNamespaces(classDataCopy.namespaces, headerStream); + openClassDeclaration(classDataCopy, Class::Proxy, headerStream); + + writeSignalDeclarations(classDataCopy, Class::Proxy, headerStream); + writeMethodDeclarations(classDataCopy, Class::Proxy, headerStream); + + closeClassDeclaration(classDataCopy, Class::Proxy, headerStream); + closeNamespaces(classDataCopy.namespaces, headerStream); + + // create source + writeSourceIncludes(classDataCopy, Class::Proxy, sourceStream); + + openNamespaces(classDataCopy.namespaces, sourceStream); + + MethodGenerator::writeProxyBegin(classDataCopy, sourceStream); + + writeProxyMethods(classDataCopy, sourceStream); + + writeProxyProperties(classDataCopy, sourceStream); + + if (!classDataCopy.msignals.isEmpty()) + MethodGenerator::writeSignalHandler(classDataCopy, sourceStream); + + if (!classDataCopy.asyncReplySignals.isEmpty()) + MethodGenerator::writeProxyAsyncReplyHandler(classDataCopy, sourceStream); + + closeNamespaces(classDataCopy.namespaces, sourceStream); + + return true; +} + +bool ClassGenerator::generateNode(const Class& classData, + const TQValueList<Class>& interfaces, + TQTextStream& headerStream, + TQTextStream& sourceStream) +{ + // create header + writeHeaderIncludes(classData, Class::Node, headerStream); + + openNamespaces(classData.namespaces, headerStream); + openClassDeclaration(classData, Class::Node, headerStream); + + closeClassDeclaration(classData, Class::Node, headerStream); + closeNamespaces(classData.namespaces, headerStream); + + // create source + writeSourceIncludes(classData, Class::Node, sourceStream); + writeInterfaceIncludes(interfaces, sourceStream); + + openNamespaces(classData.namespaces, sourceStream); + + MethodGenerator::writeNodePrivate(classData, sourceStream); + + MethodGenerator::writeNodeBegin(classData, sourceStream); + + MethodGenerator::writeNodeMethods(classData, interfaces, sourceStream); + + closeNamespaces(classData.namespaces, sourceStream); + + return true; +} + +// End of File diff --git a/src/tools/dbusxml2qt3/classgen.h b/src/tools/dbusxml2qt3/classgen.h new file mode 100644 index 0000000..3597890 --- /dev/null +++ b/src/tools/dbusxml2qt3/classgen.h @@ -0,0 +1,54 @@ +/* +* Copyright (C) 2007 Kevin Krammer <kevin.krammer@gmx.at> +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ + +#if !defined(CLASSGEN_H_INCLUDED) +#define CLASSGEN_H_INCLUDED + +// forward declarations +class Class; +class TQDomElement; +class TQTextStream; +template<typename T> class TQValueList; + +class ClassGenerator +{ +public: + static bool initStreams(const TQString& baseName, + TQTextStream& headerStream, TQTextStream& sourceStream); + + static bool finishStreams(const TQString& baseName, + TQTextStream& headerStream, TQTextStream& sourceStream); + + static bool extractClass(const TQDomElement& interfaceElement, Class& classData); + static bool generateInterface(const Class& classData, + TQTextStream& headerStream, + TQTextStream& sourceStream); + static bool generateProxy(const Class& classData, + TQTextStream& headerStream, TQTextStream& sourceStream); + static bool generateNode(const Class& classData, + const TQValueList<Class>& interfaces, + TQTextStream& headerStream, TQTextStream& sourceStream); +}; + +#endif + +// End of File diff --git a/src/tools/dbusxml2qt3/main.cpp b/src/tools/dbusxml2qt3/main.cpp new file mode 100644 index 0000000..0208072 --- /dev/null +++ b/src/tools/dbusxml2qt3/main.cpp @@ -0,0 +1,637 @@ +/* +* Copyright (C) 2007 Kevin Krammer <kevin.krammer@gmx.at> +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ + +// standard includes +#include <iostream> +#include <cstdlib> + +// TQt includes +#include <tqdom.h> +#include <tqfile.h> +#include <tqmap.h> +#include <tqtextstream.h> + +// local includes +#include "classgen.h" +#include "methodgen.h" + +typedef TQMap<TQString, TQString> OptionMap; + +void usage(); + +OptionMap parseOptions(int argc, char** argv); + +bool checkForOption(const OptionMap& options, const TQString& option) +{ + return options.find(option) != options.end(); +} + +int main(int argc, char** argv) +{ + const OptionMap options = parseOptions(argc, argv); + + if (!checkForOption(options, "filename")) + { + std::cerr << "dbusxml2qt3: introspection data file missing" << std::endl; + usage(); + exit(1); + } + + TQString fileName = options["filename"]; + TQFile file(fileName); + if (!file.exists()) + { + std::cerr << "dbusxml2qt3: introspection data file '" + << fileName.local8Bit().data() + << "' does not exist" << std::endl; + exit(2); + } + + if (!file.open(IO_ReadOnly)) + { + std::cerr << "dbusxml2qt3: introspection data file '" + << fileName.local8Bit().data() + << "' cannot be read" << std::endl; + exit(2); + } + + TQDomDocument document; + + if (!document.setContent(&file)) + { + file.close(); + + std::cerr << "dbusxml2qt3: introspection data file '" + << fileName.local8Bit().data() + << "' cannot be parsed" << std::endl; + exit(2); + } + + file.close(); + + TQDomElement rootElement = document.documentElement(); + if (rootElement.isNull() || rootElement.tagName() != "node") + { + std::cerr << "dbusxml2qt3: introspection data file '" + << fileName.local8Bit().data() + << "' does not have a 'node' element as its root node" + << std::endl; + exit(2); + } + + TQValueList<Class> interfaces; + bool hasIntrospectable = false; + + TQDomNode child = rootElement.firstChild(); + for (; !child.isNull(); child = child.nextSibling()) + { + if (!child.isElement()) continue; + + TQDomElement element = child.toElement(); + + if (element.tagName() == "interface") + { + if (!element.attribute("name").isEmpty()) + { + Class classData; + if (ClassGenerator::extractClass(element, classData)) + { + if (classData.dbusName == "org.freedesktop.DBus.Introspectable") + hasIntrospectable = true; + else + interfaces << classData; + } + } + } + } + + if (interfaces.isEmpty()) + { + std::cerr << "dbusxml2qt3: introspection data file '" + << fileName.local8Bit().data() + << "' does not contain any valid interface descriptions" + << std::endl; + exit(3); + } + + bool generateProxies = checkForOption(options, "proxy"); + bool generateInterfaces = checkForOption(options, "interface"); + bool generateNode = checkForOption(options, "node"); + + // if no specific option is selected, we generate everything + bool generateAll = !(generateProxies || generateInterfaces || generateNode); + + if (checkForOption(options, "classname")) + { + // class name only useful for single interfaces or just node + if (interfaces.count() > 1 && (generateAll || generateInterfaces || generateProxies)) + { + std::cerr << "dbusxml2qt3: class name option specified but " + << "introspection data file '" + << fileName.local8Bit().data() + << "' contains more than one interface description" + << std::endl; + exit(3); + } + + // class name for node is handled differently later on + if (!generateNode) + { + TQStringList nameParts = TQStringList::split("::", options["classname"]); + + interfaces[0].name = nameParts.back(); + + nameParts.pop_back(); + interfaces[0].namespaces = nameParts; + } + } + + if (checkForOption(options, "namespace")) + { + TQStringList nameParts = TQStringList::split("::", options["namespace"]); + + TQValueList<Class>::iterator it = interfaces.begin(); + TQValueList<Class>::iterator endIt = interfaces.end(); + for (; it != endIt; ++it) + { + (*it).namespaces = nameParts; + } + } + + if (generateInterfaces || generateAll) + { + TQTextStream headerStream; + TQTextStream sourceStream; + + TQString baseName = options["interface"]; + if (!baseName.isEmpty()) + { + if (!ClassGenerator::initStreams(baseName, headerStream, sourceStream)) + { + std::cerr << "dbusxml2qt3: proxy files, using base name '" + << baseName.local8Bit().data() + << "', could not be opened for writing" + << std::endl; + exit(4); + } + } + + TQValueList<Class>::const_iterator it = interfaces.begin(); + TQValueList<Class>::const_iterator endIt = interfaces.end(); + for (; it != endIt; ++it) + { + if (baseName.isEmpty()) + { + if (!ClassGenerator::initStreams((*it).name.lower() + "interface", + headerStream, sourceStream)) + { + std::cerr << "dbusxml2qt3: interface files, using base name '" + << baseName.local8Bit().data() + << "', could not be opened for writing" + << std::endl; + exit(4); + } + } + + ClassGenerator::generateInterface(*it, headerStream, sourceStream); + + if (baseName.isEmpty()) + { + ClassGenerator::finishStreams((*it).name.lower() + "interface", + headerStream, sourceStream); + } + } + + if (!baseName.isEmpty()) + ClassGenerator::finishStreams(baseName, headerStream, sourceStream); + } + + if (generateProxies || generateAll) + { + TQTextStream headerStream; + TQTextStream sourceStream; + + TQString baseName = options["proxy"]; + if (!baseName.isEmpty()) + { + if (!ClassGenerator::initStreams(baseName, headerStream, sourceStream)) + { + std::cerr << "dbusxml2qt3: proxy files, using base name '" + << baseName.local8Bit().data() + << "', could not be opened for writing" + << std::endl; + exit(4); + } + } + + TQValueList<Class>::const_iterator it = interfaces.begin(); + TQValueList<Class>::const_iterator endIt = interfaces.end(); + for (; it != endIt; ++it) + { + if (baseName.isEmpty()) + { + if (!ClassGenerator::initStreams((*it).name.lower() + "proxy", + headerStream, sourceStream)) + { + std::cerr << "dbusxml2qt3: proxy files, using base name '" + << baseName.local8Bit().data() + << "', could not be opened for writing" + << std::endl; + exit(4); + } + } + + ClassGenerator::generateProxy(*it, headerStream, sourceStream); + + if (baseName.isEmpty()) + { + ClassGenerator::finishStreams((*it).name.lower() + "proxy", + headerStream, sourceStream); + } + } + + if (!baseName.isEmpty()) + ClassGenerator::finishStreams(baseName, headerStream, sourceStream); + } + + if (generateNode || generateAll) + { + if (!hasIntrospectable) + { + tqDebug("Generating org.freedesktop.DBus.Introspectable on demand"); + + Class classData; + classData.name = "Introspectable"; + classData.dbusName = "org.freedesktop.DBus.Introspectable"; + + classData.namespaces << "org" << "freedesktop" << "DBus"; + + Method method; + method.name = "Introspect"; + method.noReply = false; + method.async = false; + + Argument argument; + argument.name = "data"; + argument.direction = Argument::Out; + argument.signature = "TQString"; + argument.accessor = "String"; + argument.isPrimitive = false; + argument.dbusSignature = "s"; + + argument.forwardDeclarations << "class TQString"; + argument.sourceIncludes["TQt"].append("<tqstring.h>"); + + method.arguments << argument; + classData.methods << method; + + TQTextStream headerStream; + TQTextStream sourceStream; + + if (!ClassGenerator::initStreams(classData.name.lower() + "interface", + headerStream, sourceStream)) + { + std::cerr << "dbusxml2qt3: interface files, using base name '" + << classData.name.lower().local8Bit().data() << "interface" + << "', could not be opened for writing" + << std::endl; + exit(4); + } + + ClassGenerator::generateInterface(classData, + headerStream, sourceStream); + + ClassGenerator::finishStreams(classData.name.lower() + "interface", + headerStream, sourceStream); + } + + TQString nodeClassName = options["classname"]; + if (nodeClassName.isEmpty()) + { + nodeClassName = rootElement.attribute("name"); + if (nodeClassName.startsWith("/")) nodeClassName = nodeClassName.mid(1); + if (nodeClassName.isEmpty()) + { + std::cerr << "dbusxml2qt3: cannot generate node without class name." + << std::endl; + exit(3); + } + + nodeClassName.replace('/', "_"); + } + + TQStringList nameParts = TQStringList::split("::", nodeClassName); + + Class classData; + classData.name = nameParts.back(); + + nameParts.pop_back(); + classData.namespaces = nameParts; + + if (checkForOption(options, "namespace")) + { + nameParts = TQStringList::split("::", options["namespace"]); + + classData.namespaces = nameParts; + } + + TQTextStream headerStream; + TQTextStream sourceStream; + + TQString baseName = options["node"]; + if (baseName.isEmpty()) baseName = classData.name.lower() + "node"; + + if (!ClassGenerator::initStreams(baseName, headerStream, sourceStream)) + { + std::cerr << "dbusxml2qt3: interface files, using base name '" + << baseName.local8Bit().data() + << "', could not be opened for writing" + << std::endl; + exit(4); + } + + ClassGenerator::generateNode(classData, interfaces, + headerStream, sourceStream); + + ClassGenerator::finishStreams(baseName, headerStream, sourceStream); + } + + return 0; +} + +void usage() +{ + std::cout << "usage: dbusxml2qt3 [options] <introspectionfile>" << std::endl; + std::cout << std::endl; + + std::cout << "Options:" << std::endl; + std::cout << "-h, --help" << std::endl; + std::cout << "\tDisplay this help" << std::endl; + std::cout << std::endl; + + std::cout << "-c <classname>, --class <classname>" << std::endl; + std::cout << "\tUse 'classname' instead of last string in interface name" + << std::endl; + std::cout << std::endl; + + std::cout << "-N [namespace], --namespace [namespace]" << std::endl; + std::cout << "\tOverride namespaces. If provided, use 'namespace' instead, otherwise ignore namespaces" + << std::endl; + std::cout << std::endl; + + std::cout << "-i [basename], --interface [basename]" << std::endl; + std::cout << "\tGenerate interface files. If provided, use 'basename' for filenames" + << std::endl; + std::cout << std::endl; + + std::cout << "-p [basename], --proxy [basename]" << std::endl; + std::cout << "\tGenerate proxy files. If provided, use 'basename' for filenames" + << std::endl; + std::cout << std::endl; + + std::cout << "-n [basename], --node [basename]" << std::endl; + std::cout << "\tGenerate node files. If provided, use 'basename' for filenames" + << std::endl; + std::cout << std::endl; + + std::cout << "Examples:" << std::endl; + std::cout << "dbusxml2qt3 myinterface.xml" << std::endl; + std::cout << "\tGenerates as much as possible, i.e. interfaces, proxies and, " + << "if a node name is specified in 'myinterface.xml', the node files" + << std::endl; + std::cout << "\tUses lowercased interface names as plus type specific suffix " + << "for the file names" << std::endl; + std::cout << std::endl; + + std::cout << "dbusxml2qt3 myinterface.xml -N" << std::endl; + std::cout << "\tSame as first example but does not use namespaces" + << std::endl; + std::cout << std::endl; + + std::cout << "dbusxml2qt3 myinterface.xml -N org::myorg" << std::endl; + std::cout << "\tSame as first example but overrides namespaces with 'org::myorg'" + << std::endl; + std::cout << std::endl; + + std::cout << "dbusxml2qt3 myinterface.xml -n mynode -c MyNode" << std::endl; + std::cout << "\tGenerate only node files, use 'mynode' as the file basename " + << "and classname 'MyClass'" + << std::endl; + std::cout << std::endl; + + std::cout << "dbusxml2qt3 myinterface.xml -p" << std::endl; + std::cout << "\tGenerate only proxy files, use default file basename" + << std::endl; + std::cout << std::endl; + + std::cout << "dbusxml2qt3 myinterface.xml -p myproxy" << std::endl; + std::cout << "\tGenerate only proxy files, use 'myproxy' as the file basename" + << std::endl; + std::cout << std::endl; +} + +bool testAndSetOption(OptionMap& options, const TQString& option, const TQString& value) +{ + OptionMap::iterator it = options.find(option); + if (it == options.end()) + { + options.insert(option, value); + return true; + } + + return false; +} + +OptionMap parseOptions(int argc, char** argv) +{ + TQStringList args; + for (int i = 1; i < argc; ++i) + { + args << TQString::fromLocal8Bit(argv[i]); + } + + OptionMap options; + + while (!args.isEmpty()) + { + TQString arg = args.front(); + args.pop_front(); + + if (arg.startsWith("-")) + { + if (arg.endsWith("help")) + { + usage(); + exit(0); + } + else if (arg == "-p" || arg == "--proxy") + { + // test for optional argument + TQString value; + if (!args.isEmpty() > 0 && !args[0].startsWith("-")) + { + value = args.front(); + args.pop_front(); + } + + if (!testAndSetOption(options, "proxy", value)) + { + std::cerr << "Error while parsing command line argument '" + << arg.local8Bit().data() << "'"; + + if (!value.isEmpty()) + std::cerr << ", value '" << value.local8Bit().data() << "':"; + else + std::cerr << ":"; + + std::cerr << " already set to '" + << options["proxy"].local8Bit().data() << std::endl; + } + } + else if (arg == "-i" || arg == "--interface") + { + // test for optional argument + TQString value; + if (!args.isEmpty() > 0 && !args[0].startsWith("-")) + { + value = args.front(); + args.pop_front(); + } + + if (!testAndSetOption(options, "interface", value)) + { + std::cerr << "Error while parsing command line argument '" + << arg.local8Bit().data() << "'"; + + if (!value.isEmpty()) + std::cerr << ", value '" << value.local8Bit().data() << "':"; + else + std::cerr << ":"; + + std::cerr << " already set to '" + << options["interface"].local8Bit().data() << std::endl; + } + } + else if (arg == "-n" || arg == "--node") + { + // test for optional argument + TQString value; + if (!args.isEmpty() > 0 && !args[0].startsWith("-")) + { + value = args.front(); + args.pop_front(); + } + + if (!testAndSetOption(options, "node", value)) + { + std::cerr << "Error while parsing command line argument '" + << arg.local8Bit().data() << "'"; + + if (!value.isEmpty()) + std::cerr << ", value '" << value.local8Bit().data() << "':"; + else + std::cerr << ":"; + + std::cerr << " already set to '" + << options["node"].local8Bit().data() << std::endl; + } + } + else if (arg == "-N" || arg == "--namespace") + { + // test for optional argument + TQString value; + if (!args.isEmpty() > 0 && !args[0].startsWith("-")) + { + value = args.front(); + args.pop_front(); + } + + if (!testAndSetOption(options, "namespace", value)) + { + std::cerr << "Error while parsing command line argument '" + << arg.local8Bit().data() << "'"; + + if (!value.isEmpty()) + std::cerr << ", value '" << value.local8Bit().data() << "':"; + else + std::cerr << ":"; + + std::cerr << " already set to '" + << options["namespace"].local8Bit().data() << std::endl; + } + } + else if (arg == "-c" || arg == "--class") + { + // test for mandatory argument + if (args.isEmpty() || args[0].startsWith("-")) + { + std::cerr << "Error while parsing command line argument '" + << arg.local8Bit().data() + << "': mandatory parameter missing" << std::endl; + usage(); + exit(1); + } + + TQString value = args.front(); + args.pop_front(); + + if (!testAndSetOption(options, "classname", value)) + { + std::cerr << "Error while parsing command line argument '" + << arg.local8Bit().data() << "'"; + + if (!value.isEmpty()) + std::cerr << ", value '" << value.local8Bit().data() << "':"; + else + std::cerr << ":"; + + std::cerr << " already set to '" + << options["classname"].local8Bit().data() << std::endl; + } + } + else + { + std::cerr << "Error while parsing command line argument '" + << arg.local8Bit().data() + << "': unknown option" << std::endl; + usage(); + exit(1); + } + } + else + { + if (!testAndSetOption(options, "filename", arg)) + { + std::cerr << "Error while parsing command line argument '" + << arg.local8Bit().data() + << "': introspection file already given as '" + << options["filename"].local8Bit().data() << std::endl; + usage(); + exit(1); + } + } + } + + return options; +} + +// End of File diff --git a/src/tools/dbusxml2qt3/methodgen.cpp b/src/tools/dbusxml2qt3/methodgen.cpp new file mode 100644 index 0000000..4e407d5 --- /dev/null +++ b/src/tools/dbusxml2qt3/methodgen.cpp @@ -0,0 +1,1793 @@ +/* +* Copyright (C) 2007 Kevin Krammer <kevin.krammer@gmx.at> +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ + +// TQt includes +#include <tqdom.h> +#include <tqtextstream.h> + +// local includes +#include "methodgen.h" + +static bool parseDBusSignature(const TQString& signature, Argument& argument) +{ + argument.dbusSignature = signature; + + if (signature.length() == 1) + { + if (signature == "b") + { + argument.signature = "bool"; + argument.accessor = "Bool"; + argument.isPrimitive = true; + } + else if (signature == "y") + { + argument.signature = "TQ_UINT8"; + argument.accessor = "Byte"; + argument.isPrimitive = true; + } + else if (signature == "n") + { + argument.signature = "TQ_INT16"; + argument.accessor = "Int16"; + argument.isPrimitive = true; + } + else if (signature == "q") + { + argument.signature = "TQ_UINT16"; + argument.accessor = "UInt16"; + argument.isPrimitive = true; + } + else if (signature == "i") + { + argument.signature = "TQ_INT32"; + argument.accessor = "Int32"; + argument.isPrimitive = true; + } + else if (signature == "u") + { + argument.signature = "TQ_UINT32"; + argument.accessor = "UInt32"; + argument.isPrimitive = true; + } + else if (signature == "x") + { + argument.signature = "TQ_INT64"; + argument.accessor = "Int64"; + argument.isPrimitive = true; + } + else if (signature == "t") + { + argument.signature = "TQ_UINT64"; + argument.accessor = "UInt64"; + argument.isPrimitive = true; + } + else if (signature == "d") + { + argument.signature = "double"; + argument.accessor = "Double"; + argument.isPrimitive = true; + } + else if (signature == "s") + { + argument.signature = "TQString"; + argument.accessor = "String"; + argument.isPrimitive = false; + + argument.forwardDeclarations.append("class TQString"); + argument.sourceIncludes["TQt"].append("<tqstring.h>"); + } + else if (signature == "o") + { + argument.signature = "TQT_DBusObjectPath"; + argument.accessor = "ObjectPath"; + argument.isPrimitive = false; + + argument.forwardDeclarations.append("class TQT_DBusObjectPath"); + argument.sourceIncludes["tqdbus"].append("<tqdbusobjectpath.h>"); + } + else if (signature == "h") + { + argument.signature = "TQT_DBusUnixFd"; + argument.accessor = "UnixFd"; + argument.isPrimitive = false; + + argument.forwardDeclarations.append("class TQT_DBusUnixFd"); + argument.sourceIncludes["tqdbus"].append("<tqdbusunixfd.h>"); + } + else if (signature == "v") + { + argument.signature = "TQT_DBusVariant"; + argument.accessor = "Variant"; + argument.isPrimitive = false; + + argument.forwardDeclarations.append("class TQT_DBusVariant"); + argument.sourceIncludes["tqdbus"].append("<tqdbusvariant.h>"); + } + else + return false; + } + else if (signature.startsWith("a")) + { + if (signature == "as") + { + argument.signature = "TQStringList"; + argument.accessor = "List"; + argument.subAccessor = "TQStringList"; + argument.isPrimitive = false; + + argument.forwardDeclarations.append("class TQStringList"); + + argument.sourceIncludes["tqdbus"].append("<tqdbusdatalist.h>"); + argument.sourceIncludes["TQt"].append("<tqstringlist.h>"); + } + else if (signature.startsWith("a{")) + { + int from = signature.find("{"); + int to = signature.findRev("}"); + if (from == -1 || to == -1 || (to - from - 1) < 2) return false; + + TQString dictSignature = signature.mid(from + 1, (to - from - 1)); + + Argument key; + if (!parseDBusSignature(dictSignature.left(1), key)) return false; + + Argument value; + if (parseDBusSignature(dictSignature.mid(1), value)) + { + if (!value.subAccessor.isEmpty()) + { + argument.isPrimitive = false; + argument.containerClass = "TQT_DBusDataMap< " + key.signature + " >"; + argument.signature = "TQT_DBusDataMap< " + key.signature + " >"; + argument.accessor = key.accessor + "KeyMap"; + + argument.forwardDeclarations.append("template <typename K> class TQT_DBusDataMap"); + argument.forwardDeclarations += key.forwardDeclarations; + + argument.sourceIncludes = key.sourceIncludes; + argument.sourceIncludes["tqdbus"].append("<tqdbusdata.h>"); + argument.sourceIncludes["tqdbus"].append("<tqdbusdatamap.h>"); + } + else + { + argument.isPrimitive = false; + argument.containerClass = "TQT_DBusDataMap< " + key.signature + " >"; + argument.signature = "TQMap< " + key.signature + + ", " + value.signature + " >"; + argument.accessor = key.accessor + "KeyMap"; + argument.subAccessor = value.accessor + "Map"; + + argument.forwardDeclarations.append("template <typename K, typename V> class TQMap"); + argument.forwardDeclarations += key.forwardDeclarations; + argument.forwardDeclarations += value.forwardDeclarations; + + argument.sourceIncludes = key.sourceIncludes; + argument.sourceIncludes["TQt"].append("<tqmap.h>"); + argument.sourceIncludes["tqdbus"].append("<tqdbusdata.h>"); + argument.sourceIncludes["tqdbus"].append("<tqdbusdatamap.h>"); + + TQMap<TQString, TQStringList>::const_iterator it = + value.sourceIncludes.begin(); + TQMap<TQString, TQStringList>::const_iterator endIt = + value.sourceIncludes.end(); + for (; it != endIt; ++it) + { + argument.sourceIncludes[it.key()] += it.data(); + } + } + } + else + { + argument.isPrimitive = false; + argument.containerClass = "TQT_DBusDataMap< " + key.signature + " >"; + argument.signature = "TQT_DBusDataMap< " + key.signature + " >"; + argument.accessor = key.accessor + "KeyMap"; + + argument.forwardDeclarations.append("template <typename K> class TQT_DBusDataMap"); + argument.forwardDeclarations += key.forwardDeclarations; + + argument.sourceIncludes = key.sourceIncludes; + argument.sourceIncludes["tqdbus"].append("<tqdbusdata.h>"); + argument.sourceIncludes["tqdbus"].append("<tqdbusdatamap.h>"); + } + } + else + { + TQString itemSignature = signature.mid(1); + + Argument item; + if (parseDBusSignature(itemSignature, item) && !itemSignature.startsWith("a")) + { + argument.isPrimitive = false; + argument.signature = "TQValueList< " + item.signature + " >"; + argument.accessor = "List"; + argument.subAccessor = item.accessor + "List"; + argument.containerClass = "TQT_DBusDataList"; + + argument.forwardDeclarations.append("class TQT_DBusDataList"); + argument.forwardDeclarations.append("template <typename T> class TQValueList"); + argument.forwardDeclarations += item.forwardDeclarations; + + argument.sourceIncludes["TQt"].append("<tqvaluelist.h>"); + argument.sourceIncludes["tqdbus"].append("<tqdbusdatalist.h>"); + + TQMap<TQString, TQStringList>::const_iterator it = + item.sourceIncludes.begin(); + TQMap<TQString, TQStringList>::const_iterator endIt = + item.sourceIncludes.end(); + for (; it != endIt; ++it) + { + argument.sourceIncludes[it.key()] += it.data(); + } + } + else + { + argument.signature = "TQT_DBusDataList"; + argument.accessor = "List"; + argument.isPrimitive = false; + + argument.forwardDeclarations.append("class TQT_DBusDataList"); + + argument.sourceIncludes["tqdbus"].append("<tqdbusdatalist.h>"); + } + } + } + else + return false; + + return true; +} + +static TQMap<TQString, TQString> extractTypeAnnotations(const TQDomElement& element) +{ + const TQString annotationPrefix = "org.freedesktop.DBus.TQt3.Type."; + + TQMap<TQString, TQString> annotations; + + TQDomNode node = element.firstChild(); + for (uint count = 1; !node.isNull(); node = node.nextSibling(), ++count) + { + if (!node.isElement()) continue; + + TQDomElement element = node.toElement(); + if (element.tagName() != "annotation") continue; + + TQString name = element.attribute("name"); + if (name.isEmpty()) continue; + + TQString value = element.attribute("value").stripWhiteSpace(); + if (value.isEmpty()) continue; + + if (!name.startsWith(annotationPrefix)) continue; + + TQString arg = name.mid(annotationPrefix.length()); + + annotations.insert(arg, value); + } + + return annotations; +} + +static bool hasAnnotation(const TQDomElement& element, const TQString& annotation, TQString* value = 0) +{ + for (TQDomNode node = element.firstChild(); !node.isNull(); + node = node.nextSibling()) + { + if (!node.isElement()) continue; + + TQDomElement childElement = node.toElement(); + if (childElement.tagName() != "annotation") continue; + if (childElement.attribute("name") != annotation) continue; + + if (value != 0) *value = childElement.attribute("value"); + return true; + } + + return false; +} + +static TQValueList<Argument> extractArguments(const TQDomElement& methodElement, + Class& classData) +{ + TQMap<TQString, TQString> argAnnotations = extractTypeAnnotations(methodElement); + + TQValueList<Argument> arguments; + + bool isSignal = methodElement.tagName() == "signal"; + + uint inCount = 0; + uint outCount = 0; + for (TQDomNode node = methodElement.firstChild(); !node.isNull(); + node = node.nextSibling()) + { + if (!node.isElement()) continue; + + TQDomElement element = node.toElement(); + if (element.tagName() != "arg") continue; + if (element.attribute("type").isEmpty()) continue; + + Argument argument; + argument.name = element.attribute("name"); + if (argument.name.isEmpty()) + argument.name = TQString("arg%1").arg(inCount + outCount); + + argument.direction = Argument::In; + if (!isSignal && element.attribute("direction", "in") == "out") + argument.direction = Argument::Out; + + TQString annotation; + if (!isSignal && argument.direction == Argument::In) + { + annotation = argAnnotations[TQString("In%1").arg(inCount)]; + ++inCount; + } + else + { + annotation = argAnnotations[TQString("Out%1").arg(outCount)]; + ++outCount; + } + + if (!annotation.isEmpty()) + { + // just assume nobody uses annotations for primitives + argument.annotatedType = annotation; + argument.signature = annotation; + argument.isPrimitive = false; + argument.dbusSignature = element.attribute("type"); + + TQString includeBase = + TQString("\"%1type%2.h\"").arg(classData.name.lower()); + + argument.headerIncludes["local"].append(includeBase.arg("declarations")); + argument.sourceIncludes["local"].append(includeBase.arg("includes")); + argument.sourceIncludes["tqdbus"].append("<tqdbusdataconverter.h>"); + } + else if (!parseDBusSignature(element.attribute("type"), argument)) + { + argument.signature = "TQT_DBusData"; + argument.isPrimitive = false; + + argument.forwardDeclarations.append("class TQT_DBusData"); + argument.sourceIncludes["tqdbus"].append("<tqdbusdata.h>"); + } + + arguments.append(argument); + } + + return arguments; +} + +static void writeVariable(const Argument& argument, uint index, + const TQString& prefix, TQTextStream& stream) +{ + stream << prefix << argument.signature << " _" << argument.name; + if (argument.direction == Argument::In) + { + if (!argument.annotatedType.isEmpty()) + { + stream << ";" << endl; + + // TODO: error handling? + stream << prefix << "TQT_DBusDataConverter::convertFromTQT_DBusData<" + << argument.annotatedType + << TQString(">(message[%1], _").arg(index) + << argument.name << ")"; + } + else if (!argument.accessor.isEmpty()) + { + stream << TQString::fromUtf8(" = message[%1].to").arg(index); + stream << argument.accessor; + + if (!argument.subAccessor.isEmpty()) + { + stream << TQString("().to%1").arg(argument.subAccessor); + } + + stream << "()"; + } + else + stream << TQString::fromUtf8(" = message[%1]").arg(index); + } + + stream << ";" << endl; +} + +static void writeVariables(const TQString& prefix, const Method& method, + TQTextStream& stream) +{ + uint count = 0; + TQValueList<Argument>::const_iterator it = method.arguments.begin(); + TQValueList<Argument>::const_iterator endIt = method.arguments.end(); + for (; it != endIt; ++it) + { + writeVariable(*it, count, prefix, stream); + + if ((*it).direction == Argument::In) ++count; + } +} + +static void writeSignalEmit(const Method& signal, TQTextStream& stream) +{ + stream << " emit " << signal.name << "("; + + TQValueList<Argument>::const_iterator it = signal.arguments.begin(); + TQValueList<Argument>::const_iterator endIt = signal.arguments.end(); + for (; it != endIt;) + { + stream << "_" << (*it).name; + + ++it; + if (it != endIt) stream << ", "; + } + + stream << ");" << endl; +} + +static void writeMethodIntrospection(const Method& method, bool& firstArgument, + TQTextStream& stream) +{ + stream << " methodElement.setAttribute(\"name\", \"" + << method.name << "\");" << endl; + + TQValueList<Argument>::const_iterator it = method.arguments.begin(); + TQValueList<Argument>::const_iterator endIt = method.arguments.end(); + for (; it != endIt; ++it) + { + stream << endl; + if (firstArgument) + { + firstArgument = false; + + stream << " TQDomElement argumentElement = document.createElement(" + << "\"arg\");" << endl; + } + else + { + stream << " argumentElement = document.createElement(" + << "\"arg\");" << endl; + } + + stream << " argumentElement.setAttribute(\"name\", \"" + << (*it).name << "\");" << endl; + + stream << " argumentElement.setAttribute(\"type\", \"" + << (*it).dbusSignature << "\");" << endl; + + stream << " argumentElement.setAttribute(\"direction\", \"" + << ((*it).direction == Argument::In ? "in" : "out") << "\");" + << endl; + + stream << " methodElement.appendChild(argumentElement);" << endl; + } + stream << endl; +} + +static void writeNodeInitialization(const Class& classData, + const TQValueList<Class>& interfaces, TQTextStream& stream) +{ + stream << "bool " << classData.name + << "::registerObject(const TQT_DBusConnection& connection, " + << "const TQString& path)" << endl; + stream << "{" << endl; + stream << " if (path.isEmpty()) return false;" << endl; + stream << endl; + + stream << " if (!m_private->objectPath.isEmpty()) unregisterObject();" + << endl; + stream << endl; + + stream << " m_private->connection = connection;" << endl; + stream << " m_private->objectPath = path;" << endl; + stream << endl; + stream << " if (!m_private->connection.registerObject(path, this))" << endl; + stream << " {" << endl; + stream << " m_private->connection = TQT_DBusConnection();" << endl; + stream << " m_private->objectPath = TQString();" << endl; + stream << endl; + stream << " return false;" << endl; + stream << " }" << endl; + stream << endl; + + stream << " if (m_private->interfaces.isEmpty())" << endl; + stream << " {" << endl; + stream << " TQString name = \"org.freedesktop.DBus.Introspectable\";" + << endl; + stream << " TQT_DBusObjectBase* interface = m_private;" << endl; + stream << " m_private->interfaces.insert(name, interface);" << endl; + + TQValueList<Class>::const_iterator it = interfaces.begin(); + TQValueList<Class>::const_iterator endIt = interfaces.end(); + for (; it != endIt; ++it) + { + stream << endl; + stream << " name = \"" << (*it).dbusName << "\";" << endl; + stream << " interface = createInterface(name);" << endl; + stream << " Q_ASSERT(interface != 0);" << endl; + stream << " m_private->interfaces.insert(name, interface);" << endl; + } + + stream << " }" << endl; + stream << endl; + stream << " return true;" << endl; + stream << "}" << endl; + stream << endl; +} +static void writeNodeIntrospection(const Class& classData, + const TQValueList<Class>& interfaces, TQTextStream& stream) +{ + stream << "void " << classData.name << "::Private" + << "::cacheIntrospectionData()" << endl; + stream << "{" << endl; + + stream << " TQDomDocument doc;" << endl; + stream << " TQDomElement nodeElement = doc.createElement(\"node\");" << endl; + stream << " TQDomElement interfaceElement = doc.createElement(\"interface\");" + << endl; + stream << " org::freedesktop::DBus::Introspectable" + << "::buildIntrospectionData(interfaceElement);" << endl; + stream << " nodeElement.appendChild(interfaceElement);" << endl; + + TQValueList<Class>::const_iterator it = interfaces.begin(); + TQValueList<Class>::const_iterator endIt = interfaces.end(); + for (; it != endIt; ++it) + { + if ((*it).dbusName == "org.freedesktop.DBus.Introspectable") continue; + + stream << endl; + stream << " interfaceElement = doc.createElement(\"interface\");" + << endl; + stream << " " << (*it).namespaces.join("::") + "::" + (*it).name + << "::buildIntrospectionData(interfaceElement);" << endl; + stream << " nodeElement.appendChild(interfaceElement);" << endl; + } + + stream << endl; + stream << " doc.appendChild(nodeElement);" << endl; + stream << endl; + + stream << " introspectionData = \"<!DOCTYPE node PUBLIC \\\"" + << "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\\\"\\n" + << "\\\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd" + << "\\\">\\n\";" << endl; + stream << " introspectionData += doc.toString();" << endl; + stream << "}" << endl; + stream << endl; +} + +bool MethodGenerator::extractMethods(const TQDomElement& interfaceElement, + Class& classData) +{ + TQMap<TQString, TQString> propertyAnnotations = + extractTypeAnnotations(interfaceElement); + + uint propertyCount = 0; + for (TQDomNode node = interfaceElement.firstChild(); !node.isNull(); + node = node.nextSibling()) + { + if (!node.isElement()) continue; + + TQDomElement element = node.toElement(); + if (element.attribute("name").isEmpty()) continue; + + if (element.tagName() == "method" || element.tagName() == "signal") + { + Method method; + method.name = element.attribute("name"); + method.arguments = extractArguments(element, classData); + method.noReply = false; + method.async = false; + + if (element.tagName() == "method") + { + method.async = hasAnnotation(element, "org.freedesktop.DBus.GLib.Async"); + classData.methods.append(method); + if (method.async) { + method.async = false; + classData.methods.append(method); + } + } + else + classData.msignals.append(method); + } + else if (element.tagName() == "property") + { + Property property; + property.name = element.attribute("name"); + property.read = element.attribute("access").find("read") != -1; + property.write = element.attribute("access").find("write") != -1; + + TQString annotation = + propertyAnnotations[TQString("Property%1").arg(propertyCount)]; + + if (!annotation.isEmpty()) + { + property.annotatedType = annotation; + property.signature = annotation; + property.dbusSignature = element.attribute("type"); + property.isPrimitive = false; + + TQString includeBase = + TQString("\"%1type%2.h\"").arg(classData.name.lower()); + + property.headerIncludes["local"].append(includeBase.arg("declarations")); + property.sourceIncludes["local"].append(includeBase.arg("includes")); + property.sourceIncludes["tqdbus"].append("<tqdbusdataconverter.h>"); + } + else if (!parseDBusSignature(element.attribute("type"), property)) + { + property.signature = "TQT_DBusData"; + property.isPrimitive = false; + + property.forwardDeclarations.append("class TQT_DBusData"); + property.sourceIncludes["tqdbus"].append("<tqdbusdata.h>"); + } + + classData.properties.append(property); + ++propertyCount; + } + } + + return !classData.methods.isEmpty() || !classData.msignals.isEmpty() || + !classData.properties.isEmpty(); +} + +void MethodGenerator::writeMethodDeclaration(const Method& method, bool pureVirtual, + bool withError, TQTextStream& stream) +{ + stream << method.name << "("; + + TQValueList<Argument>::const_iterator it = method.arguments.begin(); + TQValueList<Argument>::const_iterator endIt = method.arguments.end(); + for (; it != endIt;) + { + if (!(*it).isPrimitive && (*it).direction == Argument::In) + stream << "const "; + + stream << (*it).signature; + + if (!(*it).isPrimitive || (*it).direction == Argument::Out) stream << "&"; + + stream << " " << (*it).name; + + ++it; + if (it != endIt || withError) stream << ", "; + } + + if (withError) + stream << "TQT_DBusError& error)"; + else + stream << ")"; + + if (pureVirtual) + stream << " = 0;" << endl; + else + stream << ";" << endl; + + stream << endl; +} + +void MethodGenerator::writePropertyDeclaration(const Property& property, + bool pureVirtual, TQTextStream& stream) +{ + if (property.write) + { + stream << " virtual void set" << property.name << "("; + + if (!property.isPrimitive) stream << "const "; + + stream << property.signature; + + if (!property.isPrimitive) stream << "&"; + + stream << " value, TQT_DBusError& error)"; + + if (pureVirtual) + stream << " = 0;" << endl; + else + stream << ";" << endl; + } + + if (property.read) + { + stream << " virtual " << property.signature << " get" + << property.name << "(TQT_DBusError& error) const"; + + if (pureVirtual) + stream << " = 0;" << endl; + else + stream << ";" << endl; + } + + if (property.read || property.write) stream << endl; +} + +void MethodGenerator::writeMethodCallDeclaration(const Method& method, + TQTextStream& stream) +{ + if (method.async) + stream << "void call" << method.name << "Async"; + else + stream << "TQT_DBusMessage call" << method.name; + + stream << "(const TQT_DBusMessage& message);" << endl; + stream << endl; +} + +void MethodGenerator::writeMethodCall(const Class& classData, + const Method& method, TQTextStream& stream) +{ + if (method.async) + stream << "void " << classData.name << "::call" << method.name << "Async"; + else + stream << "TQT_DBusMessage " << classData.name << "::call" << method.name; + + stream << "(const TQT_DBusMessage& message)" << endl; + + stream << "{" << endl; + + if (method.async) + { + // FIXME: using writeVariables by removing asyncCallId argument + Method reducedMethod = method; + reducedMethod.arguments.pop_front(); + + writeVariables(" ", reducedMethod, stream); + } + else + { + stream << " TQT_DBusError error;" << endl; + stream << " TQT_DBusMessage reply;" << endl; + stream << endl; + + writeVariables(" ", method, stream); + } + + stream << endl; + + if (method.async) + { + stream << " int _asyncCallId = 0;" << endl; + stream << " while (m_asyncCalls.find(_asyncCallId) != m_asyncCalls.end())" + << endl; + stream << " {" << endl; + stream << " ++_asyncCallId;" << endl; + stream << " }" << endl; + stream << " m_asyncCalls.insert(_asyncCallId, message);" << endl; + stream << endl; + + stream << " " << method.name << "Async("; + } + else + stream << " if (" << method.name << "("; + + TQValueList<Argument>::const_iterator it = method.arguments.begin(); + TQValueList<Argument>::const_iterator endIt = method.arguments.end(); + while (it != endIt) + { + stream << "_" << (*it).name; + + ++it; + if (it != endIt) stream << ", "; + } + + if (method.async) + { + stream << ");" << endl; + stream << endl; + + stream << " return;" << endl; + stream << "}" << endl; + stream << endl; + return; + } + + if (method.arguments.count() > 0) stream << ", "; + stream << "error))" << endl; + + stream << " {" << endl; + stream << " reply = TQT_DBusMessage::methodReply(message);" << endl; + + it = method.arguments.begin(); + for (; it != endIt; ++it) + { + if ((*it).direction == Argument::Out) + { + if (!(*it).annotatedType.isEmpty()) + { + stream << " TQT_DBusData " << (*it).name << "Data;" << endl; + stream << " TQT_DBusDataConverter::convertToTQT_DBusData<" + << (*it).annotatedType << ">(_" + << (*it).name << ", " << (*it).name << "Data);" + << endl; + stream << " reply << " << (*it).name << "Data"; + } + else if (!(*it).accessor.isEmpty()) + { + stream << " reply << TQT_DBusData::from" << (*it).accessor; + if (!(*it).subAccessor.isEmpty()) + { + stream << "(" << (*it).containerClass; + } + + stream << "(_" << (*it).name << ")"; + + if (!(*it).subAccessor.isEmpty()) + { + stream << ")"; + } + } + else + stream << " reply << _" << (*it).name; + + stream << ";" << endl; + } + } + stream << " }" << endl; + stream << " else" << endl; + stream << " {" << endl; + + stream << " if (!error.isValid())" << endl; + stream << " {" << endl; + stream << " tqWarning(\"Call to implementation of "; + + TQStringList::const_iterator nsIt = classData.namespaces.begin(); + TQStringList::const_iterator nsEndIt = classData.namespaces.end(); + for (; nsIt != nsEndIt; ++nsIt) + { + stream << *nsIt << "::"; + } + + stream << classData.name << "::" << method.name; + stream << " returned 'false' but error object is not valid!\");" << endl; + stream << endl; + stream << " error = TQT_DBusError::stdFailed(\""; + + nsIt = classData.namespaces.begin(); + for (; nsIt != nsEndIt; ++nsIt) + { + stream << *nsIt << "."; + } + + stream << classData.name << "." << method.name << " execution failed\");" + << endl; + stream << " }" << endl; + stream << endl; + + stream << " reply = TQT_DBusMessage::methodError(message, error);" << endl; + + stream << " }" << endl; + stream << endl; + stream << " return reply;" << endl; + stream << "}" << endl; + stream << endl; +} + +void MethodGenerator::writeSignalEmitter(const Class& classData, + const Method& method, TQTextStream& stream) +{ + stream << "bool " << classData.name << "::emit" << method.name << "("; + + TQValueList<Argument>::const_iterator it = method.arguments.begin(); + TQValueList<Argument>::const_iterator endIt = method.arguments.end(); + for (; it != endIt;) + { + if (!(*it).isPrimitive && (*it).direction == Argument::In) + stream << "const "; + + stream << (*it).signature; + + if (!(*it).isPrimitive || (*it).direction == Argument::Out) stream << "&"; + + stream << " " << (*it).name; + + ++it; + if (it != endIt) stream << ", "; + } + + stream << ")" << endl; + + stream << "{" << endl; + + // TODO: create error or use enum for return + stream << " TQString path = objectPath();" << endl; + stream << " Q_ASSERT(!path.isEmpty());" << endl; + stream << endl; + + stream << " TQT_DBusMessage message = TQT_DBusMessage::signal(path, \""; + stream << classData.dbusName << "\", \"" << method.name << "\");" << endl; + stream << endl; + + it = method.arguments.begin(); + for (; it != endIt; ++it) + { + if ((*it).direction == Argument::In) + { + if (!(*it).annotatedType.isEmpty()) + { + // TODO: error handling + stream << " TQT_DBusData " << (*it).name << "Data;" << endl; + stream << " if (TQT_DBusDataConverter:convertToTQT_DBusData<" + << (*it).annotatedType << ">(" + << (*it).name << ", " << (*it).name << "Data" + << ") != TQT_DBusDataConverter::Success) return false;" + << endl; + stream << " message << " << (*it).name << "Data"; + } + else if (!(*it).accessor.isEmpty()) + { + stream << " message << TQT_DBusData::from" << (*it).accessor; + if (!(*it).subAccessor.isEmpty()) + { + stream << "(" << (*it).containerClass; + } + + stream << "(" << (*it).name << ")"; + + if (!(*it).subAccessor.isEmpty()) + { + stream << ")"; + } + } + else + stream << " message << " << (*it).name; + + stream << ";" << endl; + } + } + stream << endl; + + stream << " return handleSignalSend(message);" << endl; + + stream << "}" << endl; + stream << endl; +} + + +void MethodGenerator::writeInterfaceAsyncReplyHandler(const Class& classData, + const Method& method, TQTextStream& stream) +{ + stream << "void " << classData.name << "::" << method.name + << "AsyncReply("; + + TQValueList<Argument>::const_iterator it = method.arguments.begin(); + TQValueList<Argument>::const_iterator endIt = method.arguments.end(); + while (it != endIt) + { + if (!(*it).isPrimitive && (*it).direction == Argument::In) + stream << "const "; + + stream << (*it).signature; + + if (!(*it).isPrimitive || (*it).direction == Argument::Out) stream << "&"; + + stream << " " << (*it).name; + + ++it; + if (it != endIt) stream << ", "; + } + stream << ")" << endl; + stream << endl; + stream << "{" << endl; + + stream << " TQMap<int, TQT_DBusMessage>::iterator findIt = m_asyncCalls.find(asyncCallId);" << endl; + stream << " if (findIt == m_asyncCalls.end()) return;" << endl; + stream << endl; + + stream << " TQT_DBusMessage call = findIt.data();" << endl; + stream << " m_asyncCalls.erase(findIt);" << endl; + stream << endl; + + stream << " TQT_DBusMessage reply = TQT_DBusMessage::methodReply(call);" + << endl; + + it = method.arguments.begin(); + for (++it; it != endIt; ++it) // skip asyncCallId at beginning + { + if (!(*it).annotatedType.isEmpty()) + { + stream << " TQT_DBusData " << (*it).name << "Data;" << endl; + + // TODO error handling + stream << " if (TQT_DBusDataConverter::convertToTQT_DBusData<" + << (*it).annotatedType << ">(" << (*it).name << ", " + << (*it).name << "Data" + << ") != TQT_DBusDataConverter::Success) return false;" + << endl; + stream << " reply << " << (*it).name << "Data;" << endl; + } + else if (!(*it).accessor.isEmpty()) + { + stream << " reply << TQT_DBusData::from" << (*it).accessor << "("; + + if ((*it).subAccessor.isEmpty()) + stream << (*it).name; + else + stream << (*it).containerClass << "(" << (*it).name << ")"; + + stream << ");" << endl; + } + else + stream << " reply << " << (*it).name << ";" << endl; + } + stream << endl; + + stream << " handleMethodReply(reply);" << endl; + + stream << "}" << endl; + stream << endl; + + stream << "void " << classData.name << "::" << method.name + << "AsyncError(int asyncCallId, const TQT_DBusError& error)"; + stream << endl; + + stream << "{" << endl; + + stream << " TQMap<int, TQT_DBusMessage>::iterator findIt = m_asyncCalls.find(asyncCallId);" << endl; + stream << " if (findIt == m_asyncCalls.end()) return;" << endl; + stream << endl; + + stream << " TQT_DBusMessage call = findIt.data();" << endl; + stream << " m_asyncCalls.erase(findIt);" << endl; + stream << endl; + + stream << " TQT_DBusMessage reply = TQT_DBusMessage::methodError(call, error);" + << endl; + stream << " handleMethodReply(reply);" << endl; + + stream << "}" << endl; + stream << endl; +} + +void MethodGenerator::writeInterfaceMainMethod(const Class& classData, + TQTextStream& stream) +{ + if (classData.methods.isEmpty()) return; + + stream << "bool " << classData.name + << "::handleMethodCall(const TQT_DBusMessage& message)" << endl; + stream << "{" << endl; + + stream << " if (message.interface() != \"" << classData.dbusName + << "\") return false;" << endl; + stream << endl; + + TQValueList<Method>::const_iterator it = classData.methods.begin(); + TQValueList<Method>::const_iterator endIt = classData.methods.end(); + for (; it != endIt; ++it) + { + stream << " if (message.member() == \"" << (*it).name << "\")" << endl; + stream << " {" << endl; + + if ((*it).async) + { + stream << " call" << (*it).name << "Async(message);" << endl; + stream << endl; + } + else + { + stream << " TQT_DBusMessage reply = call" << (*it).name + << "(message);" << endl; + stream << " handleMethodReply(reply);" << endl; + stream << endl; + } + stream << " return true;" << endl; + stream << " }" << endl; + stream << endl; + } + + stream << " return false; " << endl; + stream << "}" << endl; + stream << endl; +} + +void MethodGenerator::writeSignalHandler(const Class& classData, + TQTextStream& stream) +{ + stream << "void " << classData.name + << "::slotHandleDBusSignal(const TQT_DBusMessage& message)" << endl; + stream << "{" << endl; + + TQValueList<Method>::const_iterator it = classData.msignals.begin(); + TQValueList<Method>::const_iterator endIt = classData.msignals.end(); + bool first = true; + for (; it != endIt; ++it) + { + stream << " "; + + if (!first) + stream << "else "; + else + first = false; + + stream << "if (message.member() == \"" << (*it).name << "\")" << endl; + stream << " {" << endl; + + writeVariables(" ", *it, stream); + stream << endl; + + writeSignalEmit(*it, stream); + + stream << " }" << endl; + } + + stream << "}" << endl; + stream << endl; +} + +void MethodGenerator::writeProxyBegin(const Class& classData, TQTextStream& stream) +{ + stream << classData.name << "::" << classData.name + << "(const TQString& service, const TQString& path, TQObject* parent, const char* name)" << endl; + stream << " : TQObject(parent, name)," << endl; + stream << " m_baseProxy(new TQT_DBusProxy())" << endl; + stream << "{" << endl; + stream << " m_baseProxy->setInterface(\"" + << classData.dbusName << "\");" << endl; + stream << " m_baseProxy->setPath(path);" << endl; + stream << " m_baseProxy->setService(service);" << endl; + stream << endl; + + if (!classData.msignals.isEmpty()) + { + stream << " TQObject::connect(m_baseProxy, " + << "TQT_SIGNAL(dbusSignal(const TQT_DBusMessage&))," << endl; + stream << " this, " + << " TQT_SLOT(slotHandleDBusSignal(const TQT_DBusMessage&)));" + << endl; + } + + if (!classData.asyncReplySignals.isEmpty()) + { + stream << " TQObject::connect(m_baseProxy, " + << "TQT_SIGNAL(asyncReply(int, const TQT_DBusMessage&))," << endl; + stream << " this, " + << " TQT_SLOT(slotHandleAsyncReply(int, const TQT_DBusMessage&)));" + << endl; + } + + stream << "}" << endl; + + stream << endl; + + stream << classData.name << "::~" << classData.name << "()" << endl; + stream << "{" << endl; + stream << " delete m_baseProxy;" << endl; + stream << "}" << endl; + stream << endl; + + stream << "void " << classData.name + << "::setConnection(const TQT_DBusConnection& connection)" << endl; + stream << "{" << endl; + stream << " m_baseProxy->setConnection(connection);" << endl; + stream << "}" << endl; + stream << endl; +} + +void MethodGenerator::writeProxyMethod(const TQString& className, + const Method& method, TQTextStream& stream) +{ + stream << "bool " << className << "::" << method.name + << (method.async ? "Async(" : "("); + + TQValueList<Argument>::const_iterator it = method.arguments.begin(); + TQValueList<Argument>::const_iterator endIt = method.arguments.end(); + for (; it != endIt; ++it) + { + if (!(*it).isPrimitive && (*it).direction == Argument::In) + stream << "const "; + + stream << (*it).signature; + + if (!(*it).isPrimitive || (*it).direction == Argument::Out) stream << "&"; + + stream << " " << (*it).name << ", "; + } + + stream << "TQT_DBusError& error)" << endl; + + stream << "{" << endl; + stream << " TQValueList<TQT_DBusData> parameters;" << endl; + stream << endl; + + uint outCount = 0; + + it = method.arguments.begin(); + for (; it != endIt; ++it) + { + if ((*it).direction == Argument::Out) + { + ++outCount; + continue; + } + + if (!(*it).annotatedType.isEmpty()) + { + stream << " TQT_DBusData " << (*it).name << "Data;" << endl; + + // TODO error handling + stream << " if (TQT_DBusDataConverter::convertToTQT_DBusData<" + << (*it).annotatedType << ">(" << (*it).name << ", " + << (*it).name << "Data" + << ") != TQT_DBusDataConverter::Success) return false;" + << endl; + stream << " parameters << " << (*it).name << "Data;" << endl; + } + else if (!(*it).accessor.isEmpty()) + { + stream << " parameters << TQT_DBusData::from" << (*it).accessor << "("; + + if ((*it).subAccessor.isEmpty()) + stream << (*it).name; + else + stream << (*it).containerClass << "(" << (*it).name << ")"; + + stream << ");" << endl; + } + else + stream << " parameters << " << (*it).name << ";" << endl; + } + + stream << endl; + + if (outCount == 0 && method.noReply) + { + stream << " if (!m_baseProxy->send(\"" << method.name + << "\", parameters))" << endl; + stream << " {" << endl; + stream << " error = m_baseProxy->lastError();" << endl; + stream << " return false;" << endl; + stream << " }" << endl; + stream << " return true;" << endl; + stream << "}" << endl; + stream << endl; + return; + } + + if (method.async) + { + stream << " asyncCallId = m_baseProxy->sendWithAsyncReply(\""; + stream << method.name << "\", parameters);" << endl; + stream << endl; + + stream << " if (asyncCallId != 0) m_asyncCalls[asyncCallId] = \"" + << method.name << "\";" << endl; + stream << endl; + + stream << " error = TQT_DBusError();"; + stream << endl; + + stream << " return (asyncCallId != 0);" << endl; + stream << "}" << endl; + stream << endl; + return; + } + + stream << " TQT_DBusMessage reply = m_baseProxy->sendWithReply(\""; + stream << method.name << "\", parameters, &error);" << endl; + stream << endl; + + stream << " if (reply.type() != TQT_DBusMessage::ReplyMessage) return false;" + << endl; + + if (outCount == 0) + { + stream << " return true;" << endl; + stream << "}" << endl; + stream << endl; + return; + } + + stream << endl; + + // TODO: create error or use enum for return + stream << " if (reply.count() != " << outCount << ") return false;" << endl; + stream << endl; + + bool firstAccessor = true; + bool firstSubAccessor = true; + + it = method.arguments.begin(); + for (; it != endIt; ++it) + { + if ((*it).direction == Argument::In) continue; + + --outCount; + + if (!(*it).annotatedType.isEmpty()) + { + // TODO error handling + stream << " if (TQT_DBusDataConverter::convertFromTQT_DBusData<" + << (*it).annotatedType << ">(reply.front(), " + << (*it).name + << ") != TQT_DBusDataConverter::Success) return false;" + << endl; + } + else if (!(*it).accessor.isEmpty()) + { + if (firstAccessor) + { + stream << " bool ok = false;" << endl; + stream << endl; + firstAccessor = false; + } + + if ((*it).subAccessor.isEmpty()) + { + stream << " " << (*it).name << " = reply.front().to" + << (*it).accessor << "(&ok);" << endl; + } + else + { + if (firstSubAccessor) + { + stream << " bool subOK = false;" << endl; + stream << endl; + firstSubAccessor = false; + } + + stream << " " << (*it).name << " = reply.front().to" + << (*it).accessor << "(&ok).to" << (*it).subAccessor + << "(&subOK);" << endl; + + // TODO: create error or use enum for return + stream << " if (!subOK) return false;" << endl; + } + + // TODO: create error or use enum for return + stream << " if (!ok) return false;" << endl; + } + else + stream << " " << (*it).name << " = reply.front();" << endl; + stream << endl; + + if (outCount > 0) + { + stream << " reply.pop_front();" << endl; + stream << endl; + } + } + + stream << " return true;" << endl; + + stream << "}" << endl; + stream << endl; +} + +void MethodGenerator::writeProxyGenericProperty(const Class& classData, + TQTextStream& stream) +{ + stream << "void " << classData.name + << "::setDBusProperty(const TQString& name, " + << "const TQT_DBusVariant& value, TQT_DBusError& error)" + << endl; + stream << "{" << endl; + + stream << " TQT_DBusConnection connection = m_baseProxy->connection();" << endl; + stream << endl; + stream << " TQT_DBusMessage message = TQT_DBusMessage::methodCall(" + << "m_baseProxy->service(), m_baseProxy->path(), " + << "\"org.freedesktop.DBus.Properties\", \"Set\");" << endl; + stream << endl; + + stream << " message << TQT_DBusData::fromString(m_baseProxy->interface());" + << endl; + stream << " message << TQT_DBusData::fromString(name);" << endl; + stream << " message << TQT_DBusData::fromVariant(value);" << endl; + stream << endl; + + stream << " connection.sendWithReply(message, &error);" << endl; + + stream << "}" << endl; + + stream << endl; + + stream << "TQT_DBusVariant " << classData.name + << "::getDBusProperty(const TQString& name, TQT_DBusError& error) const" + << endl; + stream << "{" << endl; + + stream << " TQT_DBusConnection connection = m_baseProxy->connection();" << endl; + stream << endl; + + stream << " TQT_DBusMessage message = TQT_DBusMessage::methodCall(" + << "m_baseProxy->service(), m_baseProxy->path(), " + << "\"org.freedesktop.DBus.Properties\", \"Get\");" << endl; + stream << endl; + + stream << " message << TQT_DBusData::fromString(m_baseProxy->interface());" + << endl; + stream << " message << TQT_DBusData::fromString(name);" << endl; + stream << endl; + + stream << " TQT_DBusMessage reply = connection.sendWithReply(message, &error);" + << endl; + stream << endl; + + stream << " if (reply.type() != TQT_DBusMessage::ReplyMessage)" + << " return TQT_DBusVariant();" << endl; + stream << " if (reply.count() != 1) return TQT_DBusVariant();" << endl; + + stream << endl; + + stream << " bool ok = false;" << endl; + stream << " TQT_DBusVariant value = reply.front().toVariant(&ok);" << endl; + + // TODO generate error + stream << " if (!ok) return TQT_DBusVariant();" << endl; + stream << endl; + + stream << " return value;" << endl; + + stream << "}" << endl; + + stream << endl; +} + +void MethodGenerator::writeProxyProperty(const Class& classData, + const Property& property, TQTextStream& stream) +{ + if (property.write) + { + stream << "void " << classData.name << "::set" << property.name << "("; + + if (!property.isPrimitive) stream << "const "; + + stream << property.signature; + + if (!property.isPrimitive) stream << "&"; + + stream << " value, TQT_DBusError& error)" << endl; + stream << "{" << endl; + stream << " TQT_DBusVariant variant;" << endl; + + if (!property.annotatedType.isEmpty()) + { + // TODO: error handling + stream << " TQT_DBusDataConverter::convertToTQT_DBusData<" + << property.annotatedType << ">(value, variant.value);" + << endl; + } + else if (!property.accessor.isEmpty()) + { + stream << " variant.value = TQT_DBusData::from" + << property.accessor << "("; + + if (property.subAccessor.isEmpty()) + stream << "value"; + else + stream << property.containerClass << "(value)"; + + stream << ");" << endl; + } + else + stream << " variant.value = TQT_DBusData(value);" << endl; + + stream << " variant.signature = \"" << property.dbusSignature << "\";" + << endl; + + stream << endl; + stream << " setDBusProperty(\"" << property.name + << "\", variant, error);" << endl; + + stream << "}" << endl; + stream << endl; + } + + if (property.read) + { + stream << property.signature << " " << classData.name + << "::get" << property.name << "(TQT_DBusError& error) const" << endl; + stream << "{" << endl; + + stream << " TQT_DBusVariant variant = getDBusProperty(\"" + << property.name << "\", error);" << endl; + stream << endl; + stream << " if (error.isValid()) return " + << property.signature << "();" << endl; + stream << endl; + + if (!property.annotatedType.isEmpty()) + { + stream << " " << property.signature << " result;" << endl; + + // TODO error handling + stream << " TQT_DBusDataConverter::convertFromTQT_DBusData<" + << property.annotatedType << ">(variant.value, result);" + << endl; + } + else if (!property.accessor.isEmpty()) + { + stream << " bool ok = false;" << endl; + stream << endl; + + if (property.subAccessor.isEmpty()) + { + stream << " " << property.signature << " result = "; + stream << " variant.value.to" << property.accessor + << "(&ok);" << endl; + } + else + { + stream << " bool subOK = false;" << endl; + stream << endl; + + stream << " " << property.signature << " result = "; + stream << " variant.value.to" + << property.accessor << "(&ok).to" << property.subAccessor + << "(&subOK);" << endl; + + // TODO: create error + stream << " if (!subOK) {}" << endl; + } + + // TODO: create error + stream << " if (!ok) {}" << endl; + } + else + stream << " " << property.signature << " result = variant.value;"; + stream << endl; + + stream << " return result;" << endl; + stream << "}" << endl; + stream << endl; + } +} + +void MethodGenerator::writeProxyAsyncReplyHandler(const Class& classData, + TQTextStream& stream) +{ + stream << "void " << classData.name + << "::slotHandleAsyncReply(int asyncCallId, const TQT_DBusMessage& message)" << endl; + stream << "{" << endl; + + stream << " TQMap<int, TQString>::iterator findIt = " + << "m_asyncCalls.find(asyncCallId);" << endl; + stream << " if (findIt == m_asyncCalls.end()) return;" << endl; + stream << endl; + stream << " const TQString signalName = findIt.data();" << endl; + stream << " m_asyncCalls.erase(findIt);" << endl; + stream << endl; + + TQValueList<Method>::const_iterator it = classData.asyncReplySignals.begin(); + TQValueList<Method>::const_iterator endIt = classData.asyncReplySignals.end(); + bool first = true; + for (; it != endIt; ++it) + { + stream << " "; + + if (!first) + stream << "else "; + else + first = false; + + stream << "if (signalName == \"" << (*it).name << "\")" << endl; + stream << " {" << endl; + + // FIXME tricking writeVariables and writeSignalEmit into writing + // the reply emit code by manipulating arguments and name + stream << " int _asyncCallId = asyncCallId;" << endl << endl; + + stream << " if (message.type() == TQT_DBusMessage::ErrorMessage) {" << endl; + stream << " emit AsyncErrorResponseDetected(_asyncCallId, message.error());" << endl; + stream << " }" << endl << endl; + + Method signal = *it; + signal.arguments.pop_front(); + + writeVariables(" ", signal, stream); + stream << endl; + + signal = *it; + signal.name += "AsyncReply"; + + writeSignalEmit(signal, stream); + + stream << " }" << endl; + } + + stream << "}" << endl; + stream << endl; +} + +void MethodGenerator::writeIntrospectionDataMethod(const Class& classData, + TQTextStream& stream) +{ + stream << "void " << classData.name + << "::buildIntrospectionData(TQDomElement& interfaceElement)" << endl; + stream << "{" << endl; + + stream << " interfaceElement.setAttribute(\"name\", \"" + << classData.dbusName << "\");" << endl; + stream << endl; + + bool firstMethod = true; + bool firstArgument = true; + + TQValueList<Method>::const_iterator it = classData.methods.begin(); + TQValueList<Method>::const_iterator endIt = classData.methods.end(); + for (; it != endIt; ++it) + { + if (firstMethod) + { + firstMethod = false; + stream << " TQDomDocument document = interfaceElement.ownerDocument();" << endl; + stream << " TQDomElement methodElement = document.createElement(" + << "\"method\");" << endl; + } + else + { + stream << endl; + stream << " methodElement = document.createElement(" + << "\"method\");" << endl; + } + + writeMethodIntrospection(*it, firstArgument, stream); + + stream << " interfaceElement.appendChild(methodElement);" << endl; + } + + it = classData.msignals.begin(); + endIt = classData.msignals.end(); + for (; it != endIt; ++it) + { + if (firstMethod) + { + firstMethod = false; + stream << " TQDomDocument document = interfaceElement.ownerDocument();" << endl; + stream << endl; + stream << " TQDomElement methodElement = document.createElement(" + << "\"signal\");" << endl; + } + else + { + stream << endl; + stream << " methodElement = document.createElement(" + << "\"signal\");" << endl; + } + + writeMethodIntrospection(*it, firstArgument, stream); + + stream << " interfaceElement.appendChild(methodElement);" << endl; + } + + stream << "}" << endl; + stream << endl; +} + +void MethodGenerator::writeNodePrivate(const Class& classData, TQTextStream& stream) +{ + stream << "class " << classData.name + << "::Private : public org::freedesktop::DBus::Introspectable" << endl; + stream << "{" << endl; + stream << "public:" << endl; + stream << " virtual ~Private();" << endl; + stream << endl; + + stream << "public:" << endl; + stream << " TQMap<TQString, TQT_DBusObjectBase*> interfaces;" << endl; + stream << " TQString introspectionData;" << endl; + stream << endl; + stream << " TQT_DBusConnection connection;" << endl; + stream << " TQString objectPath;" << endl; + stream << endl; + + stream << "protected:" << endl; + stream << " virtual bool Introspect(TQString& data, TQT_DBusError& error);" + << endl; + stream << endl; + stream << " virtual void handleMethodReply(const TQT_DBusMessage& reply);" + << endl; + + stream << "private:" << endl; + stream << " void cacheIntrospectionData();" << endl; + + stream << "};" << endl; + stream << endl; +} + +void MethodGenerator::writeNodeBegin(const Class& classData, TQTextStream& stream) +{ + stream << classData.name << "::" << classData.name + << "() : TQT_DBusObjectBase()," << endl; + stream << " m_private(new Private())" << endl; + stream << "{" << endl; + stream << "}" << endl; + stream << endl; + + stream << classData.name << "::~" << classData.name << "()" << endl; + stream << "{" << endl; + stream << " unregisterObject();" << endl; + stream << endl; + stream << " delete m_private;" << endl; + stream << "}" << endl; + stream << endl; +} + +void MethodGenerator::writeNodeMethods(const Class& classData, + const TQValueList<Class>& interfaces, TQTextStream& stream) +{ + writeNodeInitialization(classData, interfaces, stream); + + stream << "void " << classData.name << "::unregisterObject()" << endl; + stream << "{" << endl; + stream << " if (m_private->objectPath.isEmpty()) return;" << endl; + stream << endl; + stream << " m_private->connection.unregisterObject(m_private->objectPath);" << endl; + stream << endl; + stream << " m_private->connection = TQT_DBusConnection();" << endl; + stream << " m_private->objectPath = TQString();" << endl; + stream << "}" << endl; + stream << endl; + + stream << "bool " << classData.name + << "::handleMethodCall(const TQT_DBusMessage& message)" << endl; + stream << "{" << endl; + stream << " TQMap<TQString, TQT_DBusObjectBase*>::iterator findIt = " + << "m_private->interfaces.find(message.interface());" << endl; + stream << " if (findIt == m_private->interfaces.end()) return false;" + << endl; + stream << endl; + stream << " return delegateMethodCall(message, findIt.data());" << endl; + stream << "}" << endl; + stream << endl; + + stream << classData.name << "::Private::~Private()" << endl; + stream << "{" << endl; + stream << " TQMap<TQString, TQT_DBusObjectBase*>::const_iterator it = " + << "interfaces.begin();" << endl; + stream << " TQMap<TQString, TQT_DBusObjectBase*>::const_iterator endIt = " + << "interfaces.end();" << endl; + stream << " for (; it != endIt; ++it)" << endl; + stream << " {" << endl; + stream << " TQT_DBusObjectBase* interface = it.data();" << endl; + stream << " if (interface != this)" << endl; + stream << " delete interface;" << endl; + stream << " }" << endl; + stream << " interfaces.clear();" << endl; + stream << "}" << endl; + stream << endl; + + stream << "bool " << classData.name << "::Private" + << "::Introspect(TQString& data, TQT_DBusError& error)" << endl; + stream << "{" << endl; + stream << " Q_UNUSED(error);" << endl; + stream << " if (introspectionData.isEmpty()) cacheIntrospectionData();" + << endl; + stream << endl; + stream << " data = introspectionData;" << endl; + stream << endl; + stream << " return true;" << endl; + stream << "}" << endl; + stream << endl; + + stream << "void " << classData.name << "::Private" + << "::handleMethodReply(const TQT_DBusMessage& reply)" << endl; + stream << "{" << endl; + stream << " connection.send(reply);" << endl; + stream << "}" << endl; + stream << endl; + + writeNodeIntrospection(classData, interfaces, stream); +} + +// End of File diff --git a/src/tools/dbusxml2qt3/methodgen.h b/src/tools/dbusxml2qt3/methodgen.h new file mode 100644 index 0000000..9954fb2 --- /dev/null +++ b/src/tools/dbusxml2qt3/methodgen.h @@ -0,0 +1,153 @@ +/* +* Copyright (C) 2007 Kevin Krammer <kevin.krammer@gmx.at> +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ + +#if !defined(METHODGEN_H_INCLUDED) +#define METHODGEN_H_INCLUDED + +// TQt includes +#include <tqmap.h> +#include <tqstringlist.h> + +// forward declarations +class TQTextStream; + +class Argument +{ +public: + enum Direction + { + In, + Out + }; + + TQString name; + TQString annotatedType; + TQString signature; + TQString accessor; + TQString subAccessor; + TQString containerClass; + Direction direction; + bool isPrimitive; + + TQStringList forwardDeclarations; + TQMap<TQString, TQStringList> headerIncludes; + TQMap<TQString, TQStringList> sourceIncludes; + + TQString dbusSignature; +}; + +class Method +{ +public: + TQString name; + TQValueList<Argument> arguments; + bool noReply; + bool async; +}; + +class Property : public Argument +{ +public: + bool read; + bool write; +}; + +class Class +{ +public: + enum Role + { + Interface, + Proxy, + Node + }; + + TQString name; + TQString dbusName; + TQStringList namespaces; + TQValueList<Method> methods; + TQValueList<Method> msignals; + TQValueList<Property> properties; + + TQValueList<Method> asyncMethods; + TQValueList<Method> asyncReplySignals; + TQValueList<Method> asyncReplyMethods; +}; + +class MethodGenerator +{ +public: + static bool extractMethods(const TQDomElement& interfaceElement, + Class& classData); + + static void writeMethodDeclaration(const Method& method, bool pureVirtual, + bool withError, TQTextStream& stream); + + static void writePropertyDeclaration(const Property& property, bool pureVirtual, + TQTextStream& stream); + + static void writeMethodCallDeclaration(const Method& method, + TQTextStream& stream); + + static void writeMethodCall(const Class& classData, const Method& method, + TQTextStream& stream); + + static void writeSignalEmitter(const Class& classData, const Method& method, + TQTextStream& stream); + + static void writeInterfaceAsyncReplyHandler(const Class& classData, + const Method& method, + TQTextStream& stream); + + static void writeInterfaceMainMethod(const Class& classData, + TQTextStream& stream); + + static void writeSignalHandler(const Class& classData, TQTextStream& stream); + + static void writeProxyBegin(const Class& classData, TQTextStream& stream); + + static void writeProxyMethod(const TQString& className, const Method& method, + TQTextStream& stream); + + static void writeProxyGenericProperty(const Class& classData, + TQTextStream& stream); + + static void writeProxyProperty(const Class& classData, const Property& property, + TQTextStream& stream); + + static void writeProxyAsyncReplyHandler(const Class& classData, + TQTextStream& stream); + + static void writeIntrospectionDataMethod(const Class& classData, + TQTextStream& stream); + + static void writeNodePrivate(const Class& classData, TQTextStream& stream); + + static void writeNodeBegin(const Class& classData, TQTextStream& stream); + + static void writeNodeMethods(const Class& classData, + const TQValueList<Class>& interfaces, TQTextStream& stream); +}; + +#endif + +// End of File diff --git a/src/tqdbusatomic.h b/src/tqdbusatomic.h new file mode 100644 index 0000000..50ceec3 --- /dev/null +++ b/src/tqdbusatomic.h @@ -0,0 +1,40 @@ +/* qdbusatomic.h Dummy reference counter + * + * Copyright (C) 2005 Kevin Krammer <kevin.krammer@gmx.at> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#ifndef ATOMIC_H +#define ATOMIC_H + +class Atomic +{ +public: + Atomic(int value); + + void ref(); + + bool deref(); + +private: + int m_value; +}; + +#endif diff --git a/src/tqdbusconnection.cpp b/src/tqdbusconnection.cpp new file mode 100644 index 0000000..0360456 --- /dev/null +++ b/src/tqdbusconnection.cpp @@ -0,0 +1,408 @@ +/* qdbusconnection.cpp + * + * Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org> + * Copyright (C) 2005-2007 Kevin Krammer <kevin.krammer@gmx.at> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#include <tqapplication.h> + +#include "tqdbusconnection.h" +#include "tqdbuserror.h" +#include "tqdbusmessage.h" +#include "tqdbusconnection_p.h" + +#include "tqdbusmessage_p.h" + +QT_STATIC_CONST_IMPL char *TQT_DBusConnection::default_connection_name = "qt_dbus_default_connection"; + +class TQT_DBusConnectionManager +{ +public: + TQT_DBusConnectionManager(): default_connection(0) {} + ~TQT_DBusConnectionManager(); + void bindToApplication(); + TQT_DBusConnectionPrivate *connection(const TQString &name) const; + void removeConnection(const TQString &name); + void setConnection(const TQString &name, TQT_DBusConnectionPrivate *c); + + static TQT_DBusConnectionManager* instance() { + if (managerInstance == 0) managerInstance = new TQT_DBusConnectionManager(); + return managerInstance; + } + +private: + TQT_DBusConnectionPrivate *default_connection; + // FIXME-QT4 TQHash<TQString, TQT_DBusConnectionPrivate *> connectionHash; + typedef TQMap<TQString, TQT_DBusConnectionPrivate*> ConnectionHash; + ConnectionHash connectionHash; + + static TQT_DBusConnectionManager* managerInstance; +}; + +// FIXME-QT4 TQ_GLOBAL_STATIC(TQT_DBusConnectionManager, manager); +TQT_DBusConnectionManager* TQT_DBusConnectionManager::managerInstance = 0; +TQT_DBusConnectionManager* manager() { + return TQT_DBusConnectionManager::instance(); +} + +TQT_DBusConnectionPrivate *TQT_DBusConnectionManager::connection(const TQString &name) const +{ + if (name == TQString::fromLatin1(TQT_DBusConnection::default_connection_name)) + return default_connection; + + ConnectionHash::const_iterator it = connectionHash.find(name); + + return (it != connectionHash.end() ? it.data() : 0); +} + +void TQT_DBusConnectionManager::removeConnection(const TQString &name) +{ + TQT_DBusConnectionPrivate *d = 0; + if (name == TQString::fromLatin1(TQT_DBusConnection::default_connection_name)) { + d = default_connection; + default_connection = 0; + } else { + ConnectionHash::iterator it = connectionHash.find(name); + if (it == connectionHash.end()) + return; + + d = it.data(); + connectionHash.erase(it); + } + if (!d->ref.deref()) + delete d; +} + +TQT_DBusConnectionManager::~TQT_DBusConnectionManager() +{ + if (default_connection) { + delete default_connection; + default_connection = 0; + } +/* FIXME-QT4 + for (TQHash<TQString, TQT_DBusConnectionPrivate *>::const_iterator it = connectionHash.constBegin(); + it != connectionHash.constEnd(); ++it) { + delete it.value(); + }*/ + for (ConnectionHash::const_iterator it = connectionHash.constBegin(); + it != connectionHash.constEnd(); ++it) + { + delete it.data(); + } + connectionHash.clear(); +} + +void TQT_DBusConnectionManager::bindToApplication() +{ + if (default_connection) { + default_connection->bindToApplication(); + } +/* FIXME-QT4 + for (TQHash<TQString, TQT_DBusConnectionPrivate *>::const_iterator it = connectionHash.constBegin(); + it != connectionHash.constEnd(); ++it) { + (*it)->bindToApplication(); + }*/ + for (ConnectionHash::const_iterator it = connectionHash.constBegin(); + it != connectionHash.constEnd(); ++it) + { + it.data()->bindToApplication(); + } +} + +void qDBusBindToApplication() +{ + manager()->bindToApplication(); +} + +void TQT_DBusConnectionManager::setConnection(const TQString &name, TQT_DBusConnectionPrivate *c) +{ + if (name == TQString::fromLatin1(TQT_DBusConnection::default_connection_name)) + default_connection = c; + else + connectionHash[name] = c; +} + + +TQT_DBusConnection::TQT_DBusConnection() : d(0) +{ +} + +TQT_DBusConnection::TQT_DBusConnection(const TQString &name) +{ + d = manager()->connection(name); + if (d) + d->ref.ref(); +} + +TQT_DBusConnection::TQT_DBusConnection(const TQT_DBusConnection &other) +{ + d = other.d; + if (d) + d->ref.ref(); +} + +TQT_DBusConnection::~TQT_DBusConnection() +{ + if (d && !d->ref.deref()) + delete d; +} + +TQT_DBusConnection &TQT_DBusConnection::operator=(const TQT_DBusConnection &other) +{ + if (other.d) + other.d->ref.ref(); +/* FIXME-QT4 + TQT_DBusConnectionPrivate *old = static_cast<TQT_DBusConnectionPrivate *>( + q_atomic_set_ptr(&d, other.d));*/ + TQT_DBusConnectionPrivate* old = d; + d = other.d; + if (old && !old->ref.deref()) + delete old; + + return *this; +} + +TQT_DBusConnection TQT_DBusConnection::sessionBus() +{ + return addConnection(TQT_DBusConnection::SessionBus); +} + +TQT_DBusConnection TQT_DBusConnection::systemBus() +{ + return addConnection(TQT_DBusConnection::SystemBus); +} + +TQT_DBusConnection TQT_DBusConnection::addConnection(BusType type, const TQString &name) +{ +// Q_ASSERT_X(TQCoreApplication::instance(), "TQT_DBusConnection::addConnection", +// "Cannot create connection without a Q[Core]Application instance"); + + TQT_DBusConnectionPrivate *d = manager()->connection(name); + if (d) + return TQT_DBusConnection(name); + + d = new TQT_DBusConnectionPrivate; + DBusConnection *c = 0; + switch (type) { + case SystemBus: + c = dbus_bus_get(DBUS_BUS_SYSTEM, &d->error); + break; + case SessionBus: + c = dbus_bus_get(DBUS_BUS_SESSION, &d->error); + break; + case ActivationBus: + c = dbus_bus_get(DBUS_BUS_STARTER, &d->error); + break; + } + d->setConnection(c); //setConnection does the error handling for us + + manager()->setConnection(name, d); + + return TQT_DBusConnection(name); +} + +TQT_DBusConnection TQT_DBusConnection::addConnection(const TQString &address, + const TQString &name) +{ +// Q_ASSERT_X(TQCoreApplication::instance(), "TQT_DBusConnection::addConnection", +// "Cannot create connection without a Q[Core]Application instance"); + + TQT_DBusConnectionPrivate *d = manager()->connection(name); + if (d) + return TQT_DBusConnection(name); + + d = new TQT_DBusConnectionPrivate; + // setConnection does the error handling for us + d->setConnection(dbus_connection_open(address.utf8().data(), &d->error)); + + manager()->setConnection(name, d); + + return TQT_DBusConnection(name); +} + +void TQT_DBusConnection::closeConnection(const TQString &name) +{ + manager()->removeConnection(name); +} + +void TQT_DBusConnectionPrivate::timerEvent(TQTimerEvent *e) +{ + DBusTimeout *timeout = timeouts[e->timerId()]; + dbus_timeout_handle(timeout); +} + +bool TQT_DBusConnection::send(const TQT_DBusMessage &message) const +{ + if (!d || !d->connection) + return false; + + DBusMessage *msg = message.toDBusMessage(); + if (!msg) + return false; + + bool isOk = dbus_connection_send(d->connection, msg, 0); + dbus_message_unref(msg); + return isOk; +} + +int TQT_DBusConnection::sendWithAsyncReply(const TQT_DBusMessage &message, TQObject *receiver, + const char *method) const +{ + if (!d || !d->connection) + return 0; + + return d->sendWithReplyAsync(message, receiver, method); +} + +TQT_DBusMessage TQT_DBusConnection::sendWithReply(const TQT_DBusMessage &message, TQT_DBusError *error) const +{ + if (!d || !d->connection) + return TQT_DBusMessage::fromDBusMessage(0); + + DBusMessage *msg = message.toDBusMessage(); + if (!msg) + return TQT_DBusMessage::fromDBusMessage(0); + + DBusMessage *reply = dbus_connection_send_with_reply_and_block(d->connection, msg, -1, &d->error); + + if (d->handleError() && error) + *error = d->lastError; + + dbus_message_unref(msg); + + TQT_DBusMessage ret = TQT_DBusMessage::fromDBusMessage(reply); + if (reply) { + dbus_message_unref(reply); + } + + bool dbus_error_set = dbus_error_is_set(&d->error); + ret.d->error.setDBUSError(dbus_error_set); + if (error) error->setDBUSError(dbus_error_set); + + return ret; +} + +void TQT_DBusConnection::flush() const +{ + if (!d || !d->connection) return; + + d->flush(); +} + +void TQT_DBusConnection::dispatch() const +{ + if (!d || !d->connection) return; + + d->dispatch(); +} + +void TQT_DBusConnection::scheduleDispatch() const +{ + if (!d || !d->connection) return; + + d->scheduleDispatch(); +} + +bool TQT_DBusConnection::connect(TQObject* object, const char* slot) +{ + if (!d || !d->connection || !object || !slot) + return false; + + bool ok = object->connect(d, TQT_SIGNAL(dbusSignal(const TQT_DBusMessage&)), slot); + + return ok; +} + +bool TQT_DBusConnection::disconnect(TQObject* object, const char* slot) +{ + if (!d || !d->connection || !object || !slot) + return false; + + bool ok = d->disconnect(object, slot); + + return ok; +} + +bool TQT_DBusConnection::registerObject(const TQString& path, TQT_DBusObjectBase* object) +{ + if (!d || !d->connection || !object || path.isEmpty()) + return false; + + TQT_DBusConnectionPrivate::ObjectMap::const_iterator it = d->registeredObjects.find(path); + if (it != d->registeredObjects.end()) + return false; + + d->registeredObjects.insert(path, object); + + return true; +} + +void TQT_DBusConnection::unregisterObject(const TQString &path) +{ + if (!d || !d->connection || path.isEmpty()) + return; + + TQT_DBusConnectionPrivate::ObjectMap::iterator it = d->registeredObjects.find(path); + if (it == d->registeredObjects.end()) + return ; + + d->registeredObjects.erase(it); +} + +bool TQT_DBusConnection::isConnected( ) const +{ + return d && d->connection && dbus_connection_get_is_connected(d->connection); +} + +TQT_DBusError TQT_DBusConnection::lastError() const +{ + return d ? d->lastError : TQT_DBusError(); +} + +TQString TQT_DBusConnection::uniqueName() const +{ + return d && d->connection ? + TQString::fromUtf8(dbus_bus_get_unique_name(d->connection)) + : TQString(); +} + +bool TQT_DBusConnection::requestName(const TQString &name, int modeFlags) +{ + Q_ASSERT(modeFlags >= 0); + + if (!d || !d->connection) + return false; + + if (modeFlags < 0) + return false; + + int dbusFlags = 0; + if (modeFlags & AllowReplace) + dbusFlags |= DBUS_NAME_FLAG_ALLOW_REPLACEMENT; + if (modeFlags & ReplaceExisting) + dbusFlags |= DBUS_NAME_FLAG_REPLACE_EXISTING; + + dbus_bus_request_name(d->connection, name.utf8(), dbusFlags, &d->error); + + return !d->handleError(); +} + +#include "tqdbusconnection.moc" diff --git a/src/tqdbusconnection.h b/src/tqdbusconnection.h new file mode 100644 index 0000000..9fde84b --- /dev/null +++ b/src/tqdbusconnection.h @@ -0,0 +1,663 @@ +/* qdbusconnection.h TQT_DBusConnection object + * + * Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org> + * Copyright (C) 2005-2007 Kevin Krammer <kevin.krammer@gmx.at> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#ifndef TQDBUSCONNECTION_H +#define TQDBUSCONNECTION_H + +/** + * @mainpage TQt3 Bindings for D-Bus + * + * D-Bus is an IPC (inter process communication) technology designed to allow + * applications to interoperate without requiring tight coupling. + * + * For more information about D-Bus itself see its website: + * http://www.freedesktop.org/wiki/Software_2fdbus + * + * The TQt3 D-Bus bindings described here are a TQt3 style API around the base + * implementation to enable TQt3 developers to use D-Bus in their applications + * without requiring them to know about the details of the C based D-Bus API. + * + * The two main use cases are: + * - using the API to access service implemented in other applications. + * See section @ref dbusclient for an introduction on this + * + * - using the API to provide access to services implemented in your application + * See section @ref dbusservice for an introduction on this + * + * Of course an application can do both at the same time. + */ + +/** + * @page dbusconventions Naming and syntax conventions in D-Bus + * + * @section dbusconventions-servicename Service names + * + * The service name is D-Bus application identifier, i.e. either + * the unique name handed out to the peer application by the bus on connect + * (see TQT_DBusConnection::uniqueName()) or, more likely, a well known name the + * peer application has requested, see TQT_DBusConnection::requestName() + * + * Such well known names have the form of word separated by dots, like + * Internet domain names but in reverse order. + * + * For example the name for the bus itself (the D-Bus daemon) would be + * @code + * "org.freedesktop.DBus" + * @endcode + * + * @section dbusconventions-objectpath Object paths + * + * The object path is like an address within the peer host application. + * The path format looks like a Unix file path, i.e. words separated by + * slash @c '/' characters. + * + * For example the path for the bus itself (the D-Bus daemon's main object) + * would be + * @code + * "/org/freedesktop/DBus" + * @endcode + * + * @section dbusconventions-interfacename Interface names + * + * The interface name specifies which group of methods and signals + * implemented by the peer service object is used in proxy operations. + * + * Interface names have the form of word separated by dots, like Internet + * domain names but in reverse order or like a fully qualified Java class name. + * + * For example the interface for the bus itself (the D-Bus daemon's main + * interface) would be + * @code + * "org.freedesktop.DBus" + * @endcode + * + * @section dbusconventions-errorname Error names + * + * A D-Bus error name is a sequence of words separated by dots, similar + * to D-Bus service names or interface names, or like a fully qualified + * Java class name. + * + * For example if a D-Bus service does not handle a method invocation sent + * to it because it doesn't know about the method it will return a D-Bus + * error named + * @code + * "org.freedesktop.DBus.Error.UnknownMethod" + * @endcode + * TQT_DBusError can create some of the more common errors based on a type value + * and decode their names into the type respectively. See TQT_DBusError#ErrorType + * + * @section dbusconventions-membername Method and signal names + * + * There is no mandatory convention for member names, neither for methods nor + * for signals. + * + * However, using the standard interfaces of D-Bus as a hint, it is recommended + * to use "camel case" names starting with an uppercase letter, for example + * @code + * "GetConnectionUnixUser" + * @endcode + */ + +#include "tqdbusmacros.h" +#include <tqstring.h> + +class TQT_DBusConnectionPrivate; +class TQT_DBusError; +class TQT_DBusMessage; +class TQT_DBusObjectBase; +class TQObject; + +/** + * @brief Provides access to a specific D-Bus bus + * + * In order to access a D-Bus message bus an application has to connect to it. + * This is very similar to connecting to an FTP server using TQFtp, where any + * number of commands can be sent in sequence over the same connection. + * + * Additionally to the asynchronous command execution provided by TQFtp a + * TQT_DBusConnection can also execute synchronous (blocking) calls so the + * code around those calls stays closer to in-process method incovations. + * + * However it is recommended to only perform blocking calls on D-Bus service + * methods that are likely to be processed fast. + * + * TQT_DBusConnection implements a shared resource, i.e. if you create a + * connection with a specific name in one part of your code and then + * create one with the same name somewhere else, the second creation will + * actually return the same shared connection object the first caller created. + * + * The application can be connected to more than one message bus simultaniously + * using one or more connections per bus, however the most common case is to + * have one connection per bus. + * + * The two main bus types are: + * - System bus: a bus connecting applications on one system across user + * or session boundaries, for example allowing to communicate + * with system services like printer spoolers, etc + * + * - Session bus: a bus connecting applications within one user session, for + * example started at login or by a session manager. Use cases + * or this kind of bus would be accessing user specific + * resources like addressbooks, retrieving user settings or + * controlling session services (e.g. disabling screensaver + * in a video player application during playback) + * + * While TQT_DBusConnection provides the basic API to access D-Bus services + * it is more convenient to use TQT_DBusProxy on top of the connection. + * + * See sections @ref dbusclient and @ref dbusservice for examples + */ +class TQDBUS_EXPORT TQT_DBusConnection +{ +public: + /** + * DBus bus types + */ + enum BusType + { + /** + * The session bus is a user and user session specific message + * channel. It will usually be started by a login script or a + * session manager. + */ + SessionBus, + + /** + * The system bus is a message channel bridging user level and + * system level process boundaries, e.g. it can allow a user process + * with normal user access restrictions to perform a limited subset + * of operations on a process running with elevated rights. + * + * @warning if an applications exposed services on the system bus, i.e. + * registers objects using registerObject(), it should be + * carefully examined on potential security issues + */ + SystemBus, + + // TODO find out about ActivationBus purpose + ActivationBus + }; + + /** + * @brief Creates an empty/disconnected connection handle + * + * This is mainly used for initializing variables of this type, i.e. like + * the default TQString constructor. + * + * A variable set to such an empty connection can be assigned a working + * connection at any time. + */ + TQT_DBusConnection(); + + /** + * @brief Creates a connection handle to a named connection + * + * This will result in an disconnected connection handle if no + * connection with that name has been created by addConnection before. + * + * Therefore it is recommended to use addConnection() instead to get a + * connection handle. + * + * @param name identifier of the shared connection object + */ + TQT_DBusConnection(const TQString &name); + + /** + * @brief Creates a shallow copy of the given connection + * + * Allows to pass connection handles around by value, similar to TQString + * thus avoiding problems like dangling pointers in application code + * + * @param other the connection to copy from + */ + TQT_DBusConnection(const TQT_DBusConnection &other); + + /** + * @brief Destroys the connection handle + * + * If this handle is the last one referencing the shared connection object + * it will delete it, disconnecting it from any objects it was + * collaborating with + */ + ~TQT_DBusConnection(); + + /** + * @brief Creates a shallow copy of the given connection + * + * Allows to pass connection handles around by value, similar to TQString + * thus avoiding problems like dangling pointers in application code + * + * @param other the connection to copy from + * + * @return a reference to this instance as required by assigment operator + * semantics + */ + TQT_DBusConnection &operator=(const TQT_DBusConnection &other); + + /** + * @brief Returns whether the connection is connected to a bus + * + * @return @c true if the connection can be used, @c false if the handle + * does not have access to a shared connection object or if the + * connection to the bus could not be established or broke + */ + bool isConnected() const; + + /** + * @brief Returns the last error seen by the connection + * + * This can be a connection error, e.g. attempt to connect failed, or a + * transmission error or an error reported by a method call + * + * @return the last error seen by the connection + */ + TQT_DBusError lastError() const; + + /** + * @brief Flags for controlling the behavior name collision handling + * + * @see requestName() + */ + enum NameRequestMode + { + /** + * Do not allow others to take over a name requested by this + * application + */ + NoReplace = 0, + + /** + * Allow other applications that request the same name to get it, + * i.e. allow the bus to transfer the name from this application + * to the one requesting it + */ + AllowReplace = 1, + + /** + * Try to get the name transferred from the current owner to this + * application. This will only work if the other application as + * requested the name using the AllowReplace flag + */ + ReplaceExisting = 2 + }; + + /** + * @brief Requests to be addressable on the bus by a given name + * + * Each connection to a bus gets a unique name once the connection is + * established. This is similar to getting an IP address when connecting + * to the Internet. + * + * If an application's purpose is to provide services to other applications + * the other applications require to know how to address the service + * provider. Similar to a domain name on the Internet D-Bus allows to + * register names on the bus and be addressed through those names instead + * of the connection identifier. + * + * @note this is not required if the application only needs to acccess + * services or only implements generic service APIs + * + * If more than one application request the same name, D-Bus will try + * to resolve this conflict as good as possible. + * The #NameRequestMode flags allow to control how an application prefers + * to be treated in such a conflict. + * + * @param name the name the connection should be addressable with. See + * section @ref dbusconventions-servicename + * @param modeFlags an OR'ed combination of #NameRequestMode flags + * + * @return @c true if the name request was successfull, @c false if + * the connection is not connected to a bus or the name is already + * taken and cannot be tranferred + * + * @see uniqueName() + */ + bool requestName(const TQString &name, int modeFlags = NoReplace); + + /** + * @brief Returns the connection identifier assigned at connect + * + * The unique name is the connection address or identifier the bus assigned + * to this connection when it got established. + * + * @return the connection's unique bus identifier + * + * @see requestName() + */ + TQString uniqueName() const; + + /** + * @brief Sends a message over the bus + * + * Sends a message composed through the TQT_DBusMessage API to the bus. + * This is the main method for service objects (see TQT_DBusObjectBase) to + * send replies and errors for method calls they accepted or for sending + * D-Bus signals. + * + * @note for doing method calls it is more convenient to use TQT_DBusProxy, + * see TQT_DBusProxy::send() + * + * @param message the message to send + * + * @return @c true if sending succeeded, @c false if the connection is not + * connected, if the message lacks information about the recepient + * or if sending fails a at a lower level in the communication + * stack + * + * @see lastError() + */ + bool send(const TQT_DBusMessage &message) const; + + /** + * @brief Sends a message over the bus and waits for the reply + * + * Sends a message composed through the TQT_DBusMessage API to the bus. + * It then blocks and waits until the associated reply is received. + * Any message received in between is stored and can be processed + * by calling dispatch() or scheduleDispatch() + * + * @note for doing method calls it is more convenient to use TQT_DBusProxy, + * see TQT_DBusProxy::sendWithReply() + * + * @param message the message to send + * @param error an optional parameter to directly get any error that might + * occur during processing of the call + * + * @return a message containing either the call's reply or an invalid + * message in case the call failed + * + * @see lastError() + */ + TQT_DBusMessage sendWithReply(const TQT_DBusMessage &message, TQT_DBusError *error = 0) const; + + /** + * @brief Sends a message over the bus, specifying a receiver object for + * replies + * + * Sends a message composed through the TQT_DBusMessage API to the bus and + * returns an identifier number to associate with the reply once it is + * received by the given receiver. + * See TQT_DBusMessage::replySerialNumber() + * + * The required slot signature is + * @code + * void slotname(const TQT_DBusMessage&); + * @endcode + * + * @note for doing method calls it is more convenient to use TQT_DBusProxy, + * see TQT_DBusProxy::sendWithAsyncReply() + * + * @param message the message to send + * @param receiver the TQObject to relay the reply to + * @param slot the slot to invoke for the reply + * + * @return a numeric identifier for association with the reply or @c 0 if + * sending failed + * + * @see lastError() + */ + int sendWithAsyncReply(const TQT_DBusMessage &message, TQObject *receiver, + const char *slot) const; + + /** + * @brief Flushes buffered outgoing message + * + * Attempts to send all enqueued outgoing messages before returning. + */ + void flush() const; + + /** + * @brief Processes buffered inbound messages + * + * Attempts to process all enqueued inbound messages, e.g. replies to + * method calls or received signals. + * + * @warning dispatching message can result in TQt signals being emitted + * before this method returns. In case you just want to make sure + * no inbound message is forgotten, call scheduleDispatch() which + * will execute the dispatch delayed through the event loop. + */ + void dispatch() const; + + /** + * @brief Request a delayed check for inbound buffer processing + * + * Similar to dispatch() but delayed by a single shot timer to ensure + * the method has returned before the processing is started. + * + * If a asynchronous method call is followed by a synchronous call without + * returning to the event loop in between, a call to scheduleDispatch() + * ensures that a pending reply to the asynchronous call is processed + * as soon as possible + */ + void scheduleDispatch() const; + + /** + * @brief Connects an object to receive D-Bus signals + * + * This provides a basic access to all D-Bus signals received on this + * connection. + * For every D-Bus signal processed by the connection object a TQt signal + * is emitted and thus delivered to all receiver objects connected + * through this method. + * + * The required slot signature is + * @code + * void slotname(const TQT_DBusMessage&); + * @endcode + * + * so a suitable receiver could look like this + * @code + * class DBusSignalReceiver : public TQObject + * { + * Q_OBJECT + * + * public slots: + * void dbusSignal(const TQT_DBusMessage&); + * }; + * @endcode + * + * and would be connected like this + * @code + * // assuming the following variables + * TQT_DBusConnection connection; + * DBusSignalReceiver* receiver; + * + * connection.connect(receiver, TQT_SLOT(dbusSignal(const TQT_DBusMessage&))); + * @endcode + * + * See TQT_DBusProxy::dbusSignal() for a more obvious way of connecting slots. + * + * @param object the receiver object + * @param slot the receiver slot (or signal for signal->signal connections) + * + * @return @c true if the connection was successfull, otherwise @c false + * + * @see disconnect() + */ + bool connect(TQObject* object, const char* slot); + + /** + * @brief Disconnects a given receiver from the D-Bus signal handling + * + * @param object the receiver object to disconnect from + * @param slot the receiver slot (or signal for signal->signal connections) + * + * @return @c true if the disconnect was successfull, otherwise @c false + * + * @see connect() + */ + bool disconnect(TQObject* object, const char* slot); + + /** + * @brief Registers a service object for a given path + * + * In order to receive method calls over the D-Bus connection the service + * objects path within its host application has to be registered with the + * connection. See section @ref dbusconventions-objectpath for details. + * + * Only one objects can be registered for a single object path, i.e. + * the path -> object mapping is unambiguous, similar to mapping of + * filesystem paths to files. + * + * If a service object offers more than one interface it is up to the + * service implementation if all are implemented in the object path to this + * method or if the passed object is just another demultiplexer which + * relays the message to the interface implementor. + * + * @param path the object path to register the object for + * @param object the service implementation object for that path + * + * @return @c true if the given object is now registered for the given path + * or @c false if path is empty, object is null or another object + * is already registered for this path + * + * @see unregisterObject() + */ + bool registerObject(const TQString& path, TQT_DBusObjectBase* object); + + /** + * @brief Unregister a service object on a given path + * + * Removes any mapping of object path to service object previously + * registered by registerObject(). + * See section @ref dbusconventions-objectpath for details. + * + * @warning always(!) unregister a service object before deleting it + * + * @param path the object path of the object to unregister + * + * @see registerObject() + */ + void unregisterObject(const TQString &path); + + /** + * @brief Gets a connection to the session bus + * + * Convenience overload for creating the default shared connection to the + * D-Bus session bus. + * + * Equivalent to calling addConnection(SessionBus); + * + * @return a connection handle. Check isConnected() to find out if the + * connection attempt has been successfull + * + * @see addConnection(BusType,const TQString&); + */ + static TQT_DBusConnection sessionBus(); + + /** + * @brief Gets a connection to the system bus + * + * Convenience overload for creating the default shared connection to the + * D-Bus system bus. + * + * Equivalent to calling addConnection(SystemBus); + * + * @return a connection handle. Check isConnected() to find out if the + * connection attempt has been successfull + * + * @see addConnection(BusType,const TQString&); + */ + static TQT_DBusConnection systemBus(); + + /** + * @brief Add a connection to a bus with a specific bus type + * + * This is a factory method as it will create a connection for the given + * name if its not available yet, but return a previously created + * connection for that name if available. + * + * Depending on the #BusType the D-Bus library will connect to the address + * configured for that type, so this is the recommended way to create + * connection to D-Bus. + * + * @code + * // Associate the default connection name with a connection to the user's + * // session bus + * TQT_DBusConnection con = TQT_DBusConnection::addConnection(TQT_DBusConnection::SessionBus); + * + * // check if we are connected and which uniqueName we got + * if (con.isConnected()) + * { + * tqDebug("Connected to session bus. We got uniqueName %s", + * con.uniqueName().local8Bit().data()); + * } + * @endcode + * For the common use cases see also sessionBus() and systemBus() + * + * @param type the #BusType of the bus to connect to + * @param name the name to use for TQT_DBusConnection's connection sharing + * + * @return a connection handle. Check isConnected() to find out if the + * connection attempt has been successfull + * + * @see closeConnection() + */ + static TQT_DBusConnection addConnection(BusType type, + const TQString &name = default_connection_name); + + /** + * @brief Add a connection to a bus at a specific address + * + * This is a factory method as it will create a connection for the given + * name if its not available yet, but return a previously created + * connection for that name if available. + * + * @note this requires to know the address of a D-Bus daemon to connect to + * + * @param address the address of the D-Bus daemon. Usually a Unix domain + * socket address + * @param name the name to use for TQT_DBusConnection's connection sharing + * + * @return a connection handle. Check isConnected() to find out if the + * connection attempt has been successfull + * + * @see closeConnection() + */ + static TQT_DBusConnection addConnection(const TQString &address, + const TQString &name = default_connection_name); + + // TODO check why this doesn't close the D-Bus connection + /** + * @brief Closes a connection with a given name + * + * Removes the name from the pool of shared connections, i.e. a call to + * addConnection() with the same name afterwards will create a new + * connection. + * + * @param name the connection name as used in addConnection() + */ + static void closeConnection(const TQString &name = default_connection_name); + + /** + * String used as the default parameter for connection names + */ + QT_STATIC_CONST char *default_connection_name; + +private: + TQT_DBusConnectionPrivate *d; +}; + +#endif diff --git a/src/tqdbusconnection_p.h b/src/tqdbusconnection_p.h new file mode 100644 index 0000000..6e4efd1 --- /dev/null +++ b/src/tqdbusconnection_p.h @@ -0,0 +1,177 @@ +/* qdbusconnection_p.h TQT_DBusConnection private object + * + * Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org> + * Copyright (C) 2005 Kevin Krammer <kevin.krammer@gmx.at> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the public API. This header file may +// change from version to version without notice, or even be +// removed. +// +// We mean it. +// +// + +#ifndef TQDBUSCONNECTION_P_H +#define TQDBUSCONNECTION_P_H + +#include <tqguardedptr.h> +#include <tqmap.h> +#include <tqobject.h> +#include <tqvaluelist.h> + +#include <dbus/dbus.h> + +#include "tqdbusatomic.h" +#include "tqdbuserror.h" +#include "tqdbusobject.h" +#include "tqdbusmessage.h" + +class TQT_DBusMessage; +class TQSocketNotifier; +class TQTimer; +class TQTimerEvent; + +struct DBusConnection; +struct DBusServer; + +class TQT_DBusResultInfo +{ + public: + TQT_DBusMessage message; + TQObject* receiver; + TQCString method; +}; +typedef TQValueList<TQT_DBusResultInfo> TQT_DBusResultInfoList; + +class TQT_DBusConnectionPrivate: public TQObject +{ + Q_OBJECT + + +public: + TQT_DBusConnectionPrivate(TQObject *parent = 0); + ~TQT_DBusConnectionPrivate(); + + void bindToApplication(); + + void setConnection(DBusConnection *connection); + void setServer(DBusServer *server); + void closeConnection(); + void timerEvent(TQTimerEvent *e); + + bool handleSignal(DBusMessage *msg); + bool handleObjectCall(DBusMessage *message); + bool handleError(); + + void emitPendingCallReply(const TQT_DBusMessage& message); + +signals: + void dbusSignal(const TQT_DBusMessage& message); + + void dbusPendingCallReply(const TQT_DBusMessage& message); + +public slots: + void socketRead(int); + void socketWrite(int); + + void objectDestroyed(TQObject* object); + + void purgeRemovedWatches(); + + void scheduleDispatch(); + void dispatch(); + +public: + DBusError error; + TQT_DBusError lastError; + + enum ConnectionMode { InvalidMode, ServerMode, ClientMode }; + + // FIXME TQAtomic ref; + Atomic ref; + ConnectionMode mode; + DBusConnection *connection; + DBusServer *server; + + TQTimer* dispatcher; + + static int messageMetaType; + static int registerMessageMetaType(); + int sendWithReplyAsync(const TQT_DBusMessage &message, TQObject *receiver, + const char *method); + void flush(); + + struct Watcher + { + Watcher(): watch(0), read(0), write(0) {} + DBusWatch *watch; + TQSocketNotifier *read; + TQSocketNotifier *write; + }; + // FIXME typedef TQMultiHash<int, Watcher> WatcherHash; + typedef TQValueList<Watcher> WatcherList; + WatcherList removedWatches; + typedef TQMap<int, WatcherList> WatcherHash; + WatcherHash watchers; + + // FIXME typedef TQHash<int, DBusTimeout *> TimeoutHash; + typedef TQMap<int, DBusTimeout*> TimeoutHash; + TimeoutHash timeouts; + + typedef TQMap<TQString, TQT_DBusObjectBase*> ObjectMap; + ObjectMap registeredObjects; + + TQValueList<DBusTimeout *> pendingTimeouts; + + struct TQT_DBusPendingCall + { + TQGuardedPtr<TQObject> receiver; + TQCString method; + DBusPendingCall *pending; + }; + typedef TQMap<DBusPendingCall*, TQT_DBusPendingCall*> PendingCallMap; + PendingCallMap pendingCalls; + + typedef TQValueList<TQT_DBusMessage> PendingMessagesForEmit; + PendingMessagesForEmit pendingMessages; + + bool inDispatch; + + TQT_DBusResultInfoList m_resultEmissionQueue; + +public: + void newMethodInResultEmissionQueue(); + +private slots: + void transmitResultEmissionQueue(); + void transmitMessageEmissionQueue(); + +private: + TQTimer* m_resultEmissionQueueTimer; + TQTimer* m_messageEmissionQueueTimer; +}; + +#endif diff --git a/src/tqdbusdata.cpp b/src/tqdbusdata.cpp new file mode 100644 index 0000000..629df57 --- /dev/null +++ b/src/tqdbusdata.cpp @@ -0,0 +1,1121 @@ +/* qdbusdata.cpp DBUS data transport type + * + * Copyright (C) 2007 Kevin Krammer <kevin.krammer@gmx.at> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#include "dbus/dbus.h" + +#include "tqdbusdata.h" +#include "tqdbusdatalist.h" +#include "tqdbusdatamap.h" +#include "tqdbusobjectpath.h" +#include "tqdbusunixfd.h" +#include "tqdbusvariant.h" + +#include <tqshared.h> +#include <tqstring.h> +#include <tqvaluelist.h> + +class TQT_DBusData::Private : public TQShared +{ +public: + Private() : TQShared(), type(TQT_DBusData::Invalid), keyType(TQT_DBusData::Invalid) {} + + ~Private() + { + switch (type) + { + case TQT_DBusData::String: + delete (TQString*)value.pointer; + break; + + case TQT_DBusData::ObjectPath: + delete (TQT_DBusObjectPath*)value.pointer; + break; + + case TQT_DBusData::UnixFd: + delete (TQT_DBusUnixFd*)value.pointer; + break; + + case TQT_DBusData::List: + delete (TQT_DBusDataList*)value.pointer; + break; + + case TQT_DBusData::Struct: + delete (TQValueList<TQT_DBusData>*)value.pointer; + break; + + case TQT_DBusData::Variant: + delete (TQT_DBusVariant*)value.pointer; + break; + + case TQT_DBusData::Map: + switch (keyType) + { + case TQT_DBusData::Byte: + delete (TQT_DBusDataMap<TQ_UINT8>*)value.pointer; + break; + + case TQT_DBusData::Int16: + delete (TQT_DBusDataMap<TQ_INT16>*)value.pointer; + break; + + case TQT_DBusData::UInt16: + delete (TQT_DBusDataMap<TQ_UINT16>*)value.pointer; + break; + + case TQT_DBusData::Int32: + delete (TQT_DBusDataMap<TQ_INT32>*)value.pointer; + break; + + case TQT_DBusData::UInt32: + delete (TQT_DBusDataMap<TQ_UINT32>*)value.pointer; + break; + + case TQT_DBusData::Int64: + delete (TQT_DBusDataMap<TQ_INT64>*)value.pointer; + break; + + case TQT_DBusData::UInt64: + delete (TQT_DBusDataMap<TQ_UINT64>*)value.pointer; + break; + + case TQT_DBusData::String: + delete (TQT_DBusDataMap<TQString>*)value.pointer; + break; + + case TQT_DBusData::ObjectPath: + delete (TQT_DBusDataMap<TQT_DBusObjectPath>*)value.pointer; + break; + + case TQT_DBusData::UnixFd: + delete (TQT_DBusDataMap<TQT_DBusUnixFd>*)value.pointer; + break; + + default: + tqFatal("TQT_DBusData::Private: unhandled map key type %d(%s)", + keyType, TQT_DBusData::typeName(keyType)); + break; + } + break; + + default: + break; + } + } + +public: + Type type; + Type keyType; + + union + { + bool boolValue; + TQ_UINT8 byteValue; + TQ_INT16 int16Value; + TQ_UINT16 uint16Value; + TQ_INT32 int32Value; + TQ_UINT32 uint32Value; + TQ_INT64 int64Value; + TQ_UINT64 uint64Value; + double doubleValue; + void* pointer; + } value; +}; + +// key type definitions for TQT_DBusDataMap +template <> +const TQT_DBusData::Type TQT_DBusDataMap<TQ_UINT8>::m_keyType = TQT_DBusData::Byte; + +template <> +const TQT_DBusData::Type TQT_DBusDataMap<TQ_INT16>::m_keyType = TQT_DBusData::Int16; + +template <> +const TQT_DBusData::Type TQT_DBusDataMap<TQ_UINT16>::m_keyType = TQT_DBusData::UInt16; + +template <> +const TQT_DBusData::Type TQT_DBusDataMap<TQ_INT32>::m_keyType = TQT_DBusData::Int32; + +template <> +const TQT_DBusData::Type TQT_DBusDataMap<TQ_UINT32>::m_keyType = TQT_DBusData::UInt32; + +template <> +const TQT_DBusData::Type TQT_DBusDataMap<TQ_INT64>::m_keyType = TQT_DBusData::Int64; + +template <> +const TQT_DBusData::Type TQT_DBusDataMap<TQ_UINT64>::m_keyType = TQT_DBusData::UInt64; + +template <> +const TQT_DBusData::Type TQT_DBusDataMap<TQString>::m_keyType = TQT_DBusData::String; + +template <> +const TQT_DBusData::Type TQT_DBusDataMap<TQT_DBusObjectPath>::m_keyType = TQT_DBusData::ObjectPath; + +template <> +const TQT_DBusData::Type TQT_DBusDataMap<TQT_DBusUnixFd>::m_keyType = TQT_DBusData::UnixFd; + + +TQT_DBusData::TQT_DBusData() : d(new Private()) +{ +} + +TQT_DBusData::TQT_DBusData(const TQT_DBusData& other) : d(0) +{ + d = other.d; + + d->ref(); +} + +TQT_DBusData::~TQT_DBusData() +{ + if (d->deref()) delete d; +} + +TQT_DBusData& TQT_DBusData::operator=(const TQT_DBusData& other) +{ + if (&other == this) return *this; + + if (d->deref()) delete d; + + d = other.d; + + d->ref(); + + return *this; +} + +bool TQT_DBusData::operator==(const TQT_DBusData& other) const +{ + if (&other == this) return true; + + if (d == other.d) return true; + + if (d->type == other.d->type) + { + switch (d->type) + { + case TQT_DBusData::Invalid: + return true; + + case TQT_DBusData::Bool: + return d->value.boolValue == other.d->value.boolValue; + + case TQT_DBusData::Byte: + return d->value.byteValue == other.d->value.byteValue; + + case TQT_DBusData::Int16: + return d->value.int16Value == other.d->value.int16Value; + + case TQT_DBusData::UInt16: + return d->value.uint16Value == other.d->value.uint16Value; + + case TQT_DBusData::Int32: + return d->value.int32Value == other.d->value.int32Value; + + case TQT_DBusData::UInt32: + return d->value.uint32Value == other.d->value.uint64Value; + + case TQT_DBusData::Int64: + return d->value.int64Value == other.d->value.int64Value; + + case TQT_DBusData::UInt64: + return d->value.uint64Value == other.d->value.uint64Value; + + case TQT_DBusData::Double: + // FIXME: should not compare doubles for equality like this + return d->value.doubleValue == other.d->value.doubleValue; + + case TQT_DBusData::String: + return toString() == other.toString(); + + case TQT_DBusData::ObjectPath: + return toObjectPath() == other.toObjectPath(); + + case TQT_DBusData::UnixFd: + return toUnixFd() == other.toUnixFd(); + + case TQT_DBusData::List: + return toList() == other.toList(); + + case TQT_DBusData::Struct: + return toStruct() == other.toStruct(); + + case TQT_DBusData::Variant: + return toVariant() == other.toVariant(); + + case TQT_DBusData::Map: + if (d->keyType != other.d->keyType) return false; + + switch (d->keyType) + { + case TQT_DBusData::Byte: + return toByteKeyMap() == other.toByteKeyMap(); + + case TQT_DBusData::Int16: + return toInt16KeyMap() == other.toInt16KeyMap(); + + case TQT_DBusData::UInt16: + return toUInt16KeyMap() == other.toUInt16KeyMap(); + + case TQT_DBusData::Int32: + return toInt32KeyMap() == other.toInt32KeyMap(); + + case TQT_DBusData::UInt32: + return toUInt32KeyMap() == other.toUInt32KeyMap(); + + case TQT_DBusData::Int64: + return toInt64KeyMap() == other.toInt64KeyMap(); + + case TQT_DBusData::UInt64: + return toUInt64KeyMap() == other.toUInt64KeyMap(); + + case TQT_DBusData::String: + return toStringKeyMap() == other.toStringKeyMap(); + + case TQT_DBusData::ObjectPath: + return toObjectPathKeyMap() == other.toObjectPathKeyMap(); + + case TQT_DBusData::UnixFd: + return toUnixFdKeyMap() == other.toUnixFdKeyMap(); + + default: + tqFatal("TQT_DBusData operator== unhandled map key type %d(%s)", + d->keyType, TQT_DBusData::typeName(d->keyType)); + break; + } + + break; + } + } + + return false; +} + +bool TQT_DBusData::operator!=(const TQT_DBusData& other) const +{ + return !operator==(other); +} + +TQT_DBusData::Type TQT_DBusData::type() const +{ + return d->type; +} + +TQT_DBusData::Type TQT_DBusData::keyType() const +{ + if (d->type != TQT_DBusData::Map) return TQT_DBusData::Invalid; + + return d->keyType; +} + +const char* TQT_DBusData::typeName(Type type) +{ + switch (type) + { + case TQT_DBusData::Invalid: return "Invalid"; + case TQT_DBusData::Bool: return "Bool"; + case TQT_DBusData::Byte: return "Byte"; + case TQT_DBusData::Int16: return "Int16"; + case TQT_DBusData::UInt16: return "UInt16"; + case TQT_DBusData::Int32: return "Int32"; + case TQT_DBusData::UInt32: return "UInt32"; + case TQT_DBusData::Int64: return "Int64"; + case TQT_DBusData::UInt64: return "UInt64"; + case TQT_DBusData::Double: return "Double"; + case TQT_DBusData::String: return "String"; + case TQT_DBusData::ObjectPath: return "ObjectPath"; + case TQT_DBusData::UnixFd: return "UnixFd"; + case TQT_DBusData::List: return "List"; + case TQT_DBusData::Struct: return "Struct"; + case TQT_DBusData::Variant: return "Variant"; + case TQT_DBusData::Map: return "Map"; + } + + return 0; +} + +TQT_DBusData TQT_DBusData::fromBool(bool value) +{ + TQT_DBusData data; + + data.d->type = TQT_DBusData::Bool; + data.d->value.boolValue = value; + + return data; +} + +bool TQT_DBusData::toBool(bool* ok) const +{ + if (d->type != TQT_DBusData::Bool) + { + if (ok != 0) *ok = false; + return false; + } + + if (ok != 0) *ok = true; + + return d->value.boolValue; +} + +TQT_DBusData TQT_DBusData::fromByte(TQ_UINT8 value) +{ + TQT_DBusData data; + + data.d->type = TQT_DBusData::Byte; + data.d->value.byteValue = value; + + return data; +} + +TQ_UINT8 TQT_DBusData::toByte(bool* ok) const +{ + if (d->type != TQT_DBusData::Byte) + { + if (ok != 0) *ok = false; + return 0; + } + + if (ok != 0) *ok = true; + + return d->value.byteValue; +} + +TQT_DBusData TQT_DBusData::fromInt16(TQ_INT16 value) +{ + TQT_DBusData data; + + data.d->type = TQT_DBusData::Int16; + data.d->value.int16Value = value; + + return data; +} + +TQ_INT16 TQT_DBusData::toInt16(bool* ok) const +{ + if (d->type != TQT_DBusData::Int16) + { + if (ok != 0) *ok = false; + return 0; + } + + if (ok != 0) *ok = true; + + return d->value.int16Value; +} + +TQT_DBusData TQT_DBusData::fromUInt16(TQ_UINT16 value) +{ + TQT_DBusData data; + + data.d->type = TQT_DBusData::UInt16; + data.d->value.uint16Value = value; + + return data; +} + +TQ_UINT16 TQT_DBusData::toUInt16(bool* ok) const +{ + if (d->type != TQT_DBusData::UInt16) + { + if (ok != 0) *ok = false; + return 0; + } + + if (ok != 0) *ok = true; + + return d->value.uint16Value; +} + +TQT_DBusData TQT_DBusData::fromInt32(TQ_INT32 value) +{ + TQT_DBusData data; + + data.d->type = TQT_DBusData::Int32; + data.d->value.int32Value = value; + + return data; +} + +TQ_INT32 TQT_DBusData::toInt32(bool* ok) const +{ + if (d->type != TQT_DBusData::Int32) + { + if (ok != 0) *ok = false; + return 0; + } + + if (ok != 0) *ok = true; + + return d->value.int32Value; +} + +TQT_DBusData TQT_DBusData::fromUInt32(TQ_UINT32 value) +{ + TQT_DBusData data; + + data.d->type = TQT_DBusData::UInt32; + data.d->value.uint32Value = value; + + return data; +} + +TQ_UINT32 TQT_DBusData::toUInt32(bool* ok) const +{ + if (d->type != TQT_DBusData::UInt32) + { + if (ok != 0) *ok = false; + return 0; + } + + if (ok != 0) *ok = true; + + return d->value.uint32Value; +} + +TQT_DBusData TQT_DBusData::fromInt64(TQ_INT64 value) +{ + TQT_DBusData data; + + data.d->type = TQT_DBusData::Int64; + data.d->value.int64Value = value; + + return data; +} + +TQ_INT64 TQT_DBusData::toInt64(bool* ok) const +{ + if (d->type != TQT_DBusData::Int64) + { + if (ok != 0) *ok = false; + return 0; + } + + if (ok != 0) *ok = true; + + return d->value.int64Value; +} + +TQT_DBusData TQT_DBusData::fromUInt64(TQ_UINT64 value) +{ + TQT_DBusData data; + + data.d->type = TQT_DBusData::UInt64; + data.d->value.uint64Value = value; + + return data; +} + +TQ_UINT64 TQT_DBusData::toUInt64(bool* ok) const +{ + if (d->type != TQT_DBusData::UInt64) + { + if (ok != 0) *ok = false; + return 0; + } + + if (ok != 0) *ok = true; + + return d->value.uint64Value; +} + +TQT_DBusData TQT_DBusData::fromDouble(double value) +{ + TQT_DBusData data; + + data.d->type = TQT_DBusData::Double; + data.d->value.doubleValue = value; + + return data; +} + +double TQT_DBusData::toDouble(bool* ok) const +{ + if (d->type != TQT_DBusData::Double) + { + if (ok != 0) *ok = false; + return 0.0; + } + + if (ok != 0) *ok = true; + + return d->value.doubleValue; +} + +TQT_DBusData TQT_DBusData::fromString(const TQString& value) +{ + TQT_DBusData data; + + data.d->type = TQT_DBusData::String; + data.d->value.pointer = new TQString(value); + + return data; +} + +TQString TQT_DBusData::toString(bool* ok) const +{ + if (d->type != TQT_DBusData::String) + { + if (ok != 0) *ok = false; + return TQString(); + } + + if (ok != 0) *ok = true; + + return *((TQString*)d->value.pointer); +} + +TQT_DBusData TQT_DBusData::fromObjectPath(const TQT_DBusObjectPath& value) +{ + TQT_DBusData data; + + if (value.isValid()) + { + data.d->type = TQT_DBusData::ObjectPath; + data.d->value.pointer = new TQT_DBusObjectPath(value); + } + + return data; +} + +TQT_DBusObjectPath TQT_DBusData::toObjectPath(bool* ok) const +{ + if (d->type != TQT_DBusData::ObjectPath) + { + if (ok != 0) *ok = false; + return TQT_DBusObjectPath(); + } + + if (ok != 0) *ok = true; + + return *((TQT_DBusObjectPath*)d->value.pointer); +} + +TQT_DBusData TQT_DBusData::fromUnixFd(const TQT_DBusUnixFd& value) +{ + TQT_DBusData data; + + if (value.isValid()) + { + data.d->type = TQT_DBusData::UnixFd; + data.d->value.pointer = new TQT_DBusUnixFd(value); + } + + return data; +} + +TQT_DBusUnixFd TQT_DBusData::toUnixFd(bool* ok) const +{ + if (d->type != TQT_DBusData::UnixFd) + { + if (ok != 0) *ok = false; + return TQT_DBusUnixFd(); + } + + if (ok != 0) *ok = true; + + return *((TQT_DBusUnixFd*)d->value.pointer); +} + +TQT_DBusData TQT_DBusData::fromList(const TQT_DBusDataList& list) +{ + TQT_DBusData data; + + if (list.type() == TQT_DBusData::Invalid) return data; + + data.d->type = TQT_DBusData::List; + data.d->value.pointer = new TQT_DBusDataList(list); + + return data; +} + +TQT_DBusDataList TQT_DBusData::toList(bool* ok) const +{ + if (d->type != TQT_DBusData::List) + { + if (ok != 0) *ok = false; + return TQT_DBusDataList(); + } + + if (ok != 0) *ok = true; + + return *((TQT_DBusDataList*)d->value.pointer); +} + +TQT_DBusData TQT_DBusData::fromTQValueList(const TQValueList<TQT_DBusData>& list) +{ + return fromList(TQT_DBusDataList(list)); +} + +TQValueList<TQT_DBusData> TQT_DBusData::toTQValueList(bool* ok) const +{ + bool internalOk = false; + TQT_DBusDataList list = toList(&internalOk); + + if (!internalOk) + { + if (ok != 0) *ok = false; + return TQValueList<TQT_DBusData>(); + } + + return list.toTQValueList(); +} + +TQT_DBusData TQT_DBusData::fromStruct(const TQValueList<TQT_DBusData>& memberList) +{ + TQT_DBusData data; + + TQValueList<TQT_DBusData>::const_iterator it = memberList.begin(); + TQValueList<TQT_DBusData>::const_iterator endIt = memberList.end(); + for (; it != endIt; ++it) + { + if ((*it).d->type == Invalid) return data; + } + + data.d->type = TQT_DBusData::Struct; + data.d->value.pointer = new TQValueList<TQT_DBusData>(memberList); + + return data; +} + +TQValueList<TQT_DBusData> TQT_DBusData::toStruct(bool* ok) const +{ + if (d->type != TQT_DBusData::Struct) + { + if (ok != 0) *ok = false; + return TQValueList<TQT_DBusData>(); + } + + if (ok != 0) *ok = true; + + return *((TQValueList<TQT_DBusData>*)d->value.pointer); +} + +TQT_DBusData TQT_DBusData::fromVariant(const TQT_DBusVariant& value) +{ + TQT_DBusData data; + + data.d->type = TQT_DBusData::Variant; + data.d->value.pointer = new TQT_DBusVariant(value); + + return data; +} + +TQT_DBusVariant TQT_DBusData::toVariant(bool* ok) const +{ + if (d->type != TQT_DBusData::Variant) + { + if (ok != 0) *ok = false; + return TQT_DBusVariant(); + } + + if (ok != 0) *ok = true; + + return *((TQT_DBusVariant*)d->value.pointer); +} + +TQT_DBusData TQT_DBusData::fromByteKeyMap(const TQT_DBusDataMap<TQ_UINT8>& map) +{ + TQT_DBusData data; + + data.d->type = TQT_DBusData::Map; + data.d->keyType = map.keyType(); + data.d->value.pointer = new TQT_DBusDataMap<TQ_UINT8>(map); + + return data; +} + +TQT_DBusDataMap<TQ_UINT8> TQT_DBusData::toByteKeyMap(bool* ok) const +{ + if (d->type != TQT_DBusData::Map && d->keyType != TQT_DBusDataMap<TQ_UINT8>::m_keyType) + { + if (ok != 0) *ok = false; + return TQT_DBusDataMap<TQ_UINT8>(); + } + + if (ok != 0) *ok = true; + + return *((TQT_DBusDataMap<TQ_UINT8>*)d->value.pointer); +} + +TQT_DBusData TQT_DBusData::fromInt16KeyMap(const TQT_DBusDataMap<TQ_INT16>& map) +{ + TQT_DBusData data; + + data.d->type = TQT_DBusData::Map; + data.d->keyType = map.keyType(); + data.d->value.pointer = new TQT_DBusDataMap<TQ_INT16>(map); + + return data; +} + +TQT_DBusDataMap<TQ_INT16> TQT_DBusData::toInt16KeyMap(bool* ok) const +{ + if (d->type != TQT_DBusData::Map && d->keyType != TQT_DBusDataMap<TQ_INT16>::m_keyType) + { + if (ok != 0) *ok = false; + return TQT_DBusDataMap<TQ_INT16>(); + } + + if (ok != 0) *ok = true; + + return *((TQT_DBusDataMap<TQ_INT16>*)d->value.pointer); +} + +TQT_DBusData TQT_DBusData::fromUInt16KeyMap(const TQT_DBusDataMap<TQ_UINT16>& map) +{ + TQT_DBusData data; + + data.d->type = TQT_DBusData::Map; + data.d->keyType = map.keyType(); + data.d->value.pointer = new TQT_DBusDataMap<TQ_UINT16>(map); + + return data; +} + +TQT_DBusDataMap<TQ_UINT16> TQT_DBusData::toUInt16KeyMap(bool* ok) const +{ + if (d->type != TQT_DBusData::Map && + d->keyType != TQT_DBusDataMap<TQ_UINT16>::m_keyType) + { + if (ok != 0) *ok = false; + return TQT_DBusDataMap<TQ_UINT16>(); + } + + if (ok != 0) *ok = true; + + return *((TQT_DBusDataMap<TQ_UINT16>*)d->value.pointer); +} + +TQT_DBusData TQT_DBusData::fromInt32KeyMap(const TQT_DBusDataMap<TQ_INT32>& map) +{ + TQT_DBusData data; + + data.d->type = TQT_DBusData::Map; + data.d->keyType = map.keyType(); + data.d->value.pointer = new TQT_DBusDataMap<TQ_INT32>(map); + + return data; +} + +TQT_DBusDataMap<TQ_INT32> TQT_DBusData::toInt32KeyMap(bool* ok) const +{ + if (d->type != TQT_DBusData::Map && d->keyType != TQT_DBusDataMap<TQ_INT32>::m_keyType) + { + if (ok != 0) *ok = false; + return TQT_DBusDataMap<TQ_INT32>(); + } + + if (ok != 0) *ok = true; + + return *((TQT_DBusDataMap<TQ_INT32>*)d->value.pointer); +} + +TQT_DBusData TQT_DBusData::fromUInt32KeyMap(const TQT_DBusDataMap<TQ_UINT32>& map) +{ + TQT_DBusData data; + + data.d->type = TQT_DBusData::Map; + data.d->keyType = map.keyType(); + data.d->value.pointer = new TQT_DBusDataMap<TQ_UINT32>(map); + + return data; +} + +TQT_DBusDataMap<TQ_UINT32> TQT_DBusData::toUInt32KeyMap(bool* ok) const +{ + if (d->type != TQT_DBusData::Map && + d->keyType != TQT_DBusDataMap<TQ_UINT32>::m_keyType) + { + if (ok != 0) *ok = false; + return TQT_DBusDataMap<TQ_UINT32>(); + } + + if (ok != 0) *ok = true; + + return *((TQT_DBusDataMap<TQ_UINT32>*)d->value.pointer); +} + +TQT_DBusData TQT_DBusData::fromInt64KeyMap(const TQT_DBusDataMap<TQ_INT64>& map) +{ + TQT_DBusData data; + + data.d->type = TQT_DBusData::Map; + data.d->keyType = map.keyType(); + data.d->value.pointer = new TQT_DBusDataMap<TQ_INT64>(map); + + return data; +} + +TQT_DBusDataMap<TQ_INT64> TQT_DBusData::toInt64KeyMap(bool* ok) const +{ + if (d->type != TQT_DBusData::Map && d->keyType != TQT_DBusDataMap<TQ_INT64>::m_keyType) + { + if (ok != 0) *ok = false; + return TQT_DBusDataMap<TQ_INT64>(); + } + + if (ok != 0) *ok = true; + + return *((TQT_DBusDataMap<TQ_INT64>*)d->value.pointer); +} + +TQT_DBusData TQT_DBusData::fromUInt64KeyMap(const TQT_DBusDataMap<TQ_UINT64>& map) +{ + TQT_DBusData data; + + data.d->type = TQT_DBusData::Map; + data.d->keyType = map.keyType(); + data.d->value.pointer = new TQT_DBusDataMap<TQ_UINT64>(map); + + return data; +} + +TQT_DBusDataMap<TQ_UINT64> TQT_DBusData::toUInt64KeyMap(bool* ok) const +{ + if (d->type != TQT_DBusData::Map && + d->keyType != TQT_DBusDataMap<TQ_UINT64>::m_keyType) + { + if (ok != 0) *ok = false; + return TQT_DBusDataMap<TQ_UINT64>(); + } + + if (ok != 0) *ok = true; + + return *((TQT_DBusDataMap<TQ_UINT64>*)d->value.pointer); +} + +TQT_DBusData TQT_DBusData::fromStringKeyMap(const TQT_DBusDataMap<TQString>& map) +{ + TQT_DBusData data; + + data.d->type = TQT_DBusData::Map; + data.d->keyType = map.keyType(); + data.d->value.pointer = new TQT_DBusDataMap<TQString>(map); + + return data; +} + +TQT_DBusDataMap<TQString> TQT_DBusData::toStringKeyMap(bool* ok) const +{ + if (d->type != TQT_DBusData::Map && d->keyType != TQT_DBusDataMap<TQString>::m_keyType) + { + if (ok != 0) *ok = false; + return TQT_DBusDataMap<TQString>(); + } + + if (ok != 0) *ok = true; + + return *((TQT_DBusDataMap<TQString>*)d->value.pointer); +} + +TQT_DBusData TQT_DBusData::fromObjectPathKeyMap(const TQT_DBusDataMap<TQT_DBusObjectPath>& map) +{ + TQT_DBusData data; + + data.d->type = TQT_DBusData::Map; + data.d->keyType = map.keyType(); + data.d->value.pointer = new TQT_DBusDataMap<TQT_DBusObjectPath>(map); + + return data; +} + +TQT_DBusDataMap<TQT_DBusObjectPath> TQT_DBusData::toObjectPathKeyMap(bool* ok) const +{ + if (d->type != TQT_DBusData::Map && + d->keyType != TQT_DBusDataMap<TQT_DBusObjectPath>::m_keyType) + { + if (ok != 0) *ok = false; + return TQT_DBusDataMap<TQT_DBusObjectPath>(); + } + + if (ok != 0) *ok = true; + + return *((TQT_DBusDataMap<TQT_DBusObjectPath>*)d->value.pointer); +} + +TQT_DBusData TQT_DBusData::fromUnixFdKeyMap(const TQT_DBusDataMap<TQT_DBusUnixFd>& map) +{ + TQT_DBusData data; + + data.d->type = TQT_DBusData::Map; + data.d->keyType = map.keyType(); + data.d->value.pointer = new TQT_DBusDataMap<TQT_DBusUnixFd>(map); + + return data; +} + +TQT_DBusDataMap<TQT_DBusUnixFd> TQT_DBusData::toUnixFdKeyMap(bool* ok) const +{ + if (d->type != TQT_DBusData::Map && + d->keyType != TQT_DBusDataMap<TQT_DBusUnixFd>::m_keyType) + { + if (ok != 0) *ok = false; + return TQT_DBusDataMap<TQT_DBusUnixFd>(); + } + + if (ok != 0) *ok = true; + + return *((TQT_DBusDataMap<TQT_DBusUnixFd>*)d->value.pointer); +} + +static const char* qDBusTypeForTQT_DBusType(TQT_DBusData::Type type) +{ + switch (type) + { + case TQT_DBusData::Invalid: + return 0; + case TQT_DBusData::Bool: + return DBUS_TYPE_BOOLEAN_AS_STRING; + case TQT_DBusData::Byte: + return DBUS_TYPE_BYTE_AS_STRING; + case TQT_DBusData::Int16: + return DBUS_TYPE_INT16_AS_STRING; + case TQT_DBusData::UInt16: + return DBUS_TYPE_UINT16_AS_STRING; + case TQT_DBusData::Int32: + return DBUS_TYPE_INT32_AS_STRING; + case TQT_DBusData::UInt32: + return DBUS_TYPE_UINT32_AS_STRING; + case TQT_DBusData::Int64: + return DBUS_TYPE_INT64_AS_STRING; + case TQT_DBusData::UInt64: + return DBUS_TYPE_UINT64_AS_STRING; + case TQT_DBusData::Double: + return DBUS_TYPE_DOUBLE_AS_STRING; + case TQT_DBusData::String: + return DBUS_TYPE_STRING_AS_STRING; + case TQT_DBusData::ObjectPath: + return DBUS_TYPE_OBJECT_PATH_AS_STRING; + case TQT_DBusData::UnixFd: + return DBUS_TYPE_UNIX_FD_AS_STRING; + case TQT_DBusData::Variant: + return DBUS_TYPE_VARIANT_AS_STRING; + default: + break; + } + return 0; +} + +template <typename T> +TQCString qDBusSignatureForMapValue(const TQT_DBusDataMap<T>& map) +{ + if (map.hasContainerValueType()) + return map.containerValueType().buildDBusSignature(); + else + return qDBusTypeForTQT_DBusType(map.valueType()); +} + +TQCString TQT_DBusData::buildDBusSignature() const +{ + TQCString signature; + + switch (d->type) + { + case TQT_DBusData::List: + { + TQT_DBusDataList* list = (TQT_DBusDataList*) d->value.pointer; + signature = DBUS_TYPE_ARRAY_AS_STRING; + if (list->hasContainerItemType()) + signature += list->containerItemType().buildDBusSignature(); + else + signature += qDBusTypeForTQT_DBusType(list->type()); + break; + } + + case TQT_DBusData::Struct: + { + signature += DBUS_STRUCT_BEGIN_CHAR; + + TQValueList<TQT_DBusData>* memberList = + (TQValueList<TQT_DBusData>*) d->value.pointer; + + TQValueList<TQT_DBusData>::const_iterator it = (*memberList).begin(); + TQValueList<TQT_DBusData>::const_iterator endIt = (*memberList).end(); + for (; it != endIt; ++it) + { + signature += (*it).buildDBusSignature(); + } + signature += DBUS_STRUCT_END_CHAR; + break; + } + + case TQT_DBusData::Map: + signature += DBUS_TYPE_ARRAY_AS_STRING; + signature += DBUS_DICT_ENTRY_BEGIN_CHAR; + + signature += qDBusTypeForTQT_DBusType(keyType()); + + switch (keyType()) + { + case TQT_DBusData::Byte: + signature += qDBusSignatureForMapValue<TQ_UINT8>( + *((TQT_DBusDataMap<TQ_UINT8>*) d->value.pointer)); + break; + case TQT_DBusData::Int16: + signature += qDBusSignatureForMapValue<TQ_INT16>( + *((TQT_DBusDataMap<TQ_INT16>*) d->value.pointer)); + break; + case TQT_DBusData::UInt16: + signature += qDBusSignatureForMapValue<TQ_UINT16>( + *((TQT_DBusDataMap<TQ_UINT16>*) d->value.pointer)); + break; + case TQT_DBusData::Int32: + signature += qDBusSignatureForMapValue<TQ_INT32>( + *((TQT_DBusDataMap<TQ_INT32>*) d->value.pointer)); + break; + case TQT_DBusData::UInt32: + signature += qDBusSignatureForMapValue<TQ_UINT32>( + *((TQT_DBusDataMap<TQ_UINT32>*) d->value.pointer)); + break; + case TQT_DBusData::Int64: + signature += qDBusSignatureForMapValue<TQ_INT64>( + *((TQT_DBusDataMap<TQ_INT64>*) d->value.pointer)); + break; + case TQT_DBusData::UInt64: + signature += qDBusSignatureForMapValue<TQ_UINT64>( + *((TQT_DBusDataMap<TQ_UINT64>*) d->value.pointer)); + break; + case TQT_DBusData::String: + signature += qDBusSignatureForMapValue<TQString>( + *((TQT_DBusDataMap<TQString>*) d->value.pointer)); + break; + case TQT_DBusData::ObjectPath: + signature += qDBusSignatureForMapValue<TQT_DBusObjectPath>( + *((TQT_DBusDataMap<TQT_DBusObjectPath>*) d->value.pointer)); + break; + case TQT_DBusData::UnixFd: + signature += qDBusSignatureForMapValue<TQT_DBusUnixFd>( + *((TQT_DBusDataMap<TQT_DBusUnixFd>*) d->value.pointer)); + break; + default: + break; + } + + signature += DBUS_DICT_ENTRY_END_CHAR; + break; + + default: + signature = qDBusTypeForTQT_DBusType(d->type); + break; + } + + return signature; +} diff --git a/src/tqdbusdata.h b/src/tqdbusdata.h new file mode 100644 index 0000000..ae64706 --- /dev/null +++ b/src/tqdbusdata.h @@ -0,0 +1,1223 @@ +/* qdbusdata.h DBUS data transport type + * + * Copyright (C) 2007 Kevin Krammer <kevin.krammer@gmx.at> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#ifndef TQDBUSDATA_H +#define TQDBUSDATA_H + +#include "tqdbusmacros.h" +#include <tqglobal.h> + +class TQCString; +class TQT_DBusDataList; +class TQT_DBusVariant; +class TQT_DBusObjectPath; +class TQT_DBusUnixFd; +class TQString; + +template<typename T> class TQValueList; +template<typename T> class TQT_DBusDataMap; + +/** + * @brief Class for accurately representing D-Bus data types + * + * The TQT_DBusData class can be compared to TQt's TQVariant class, but + * specialized to contain data types used in D-Bus messages. + * + * Like TQVariant objects of TQT_DBusData use implicit sharing, i.e. copying + * a TQT_DBusData object is a cheap operation and does not require that the + * content itself is copied. + * + * Depending on the #Type of the object, the content can be a recursive + * construct of TQT_DBusData objects, e.g. a #List can contain elements that are + * containers themselves, e.g. #Map, #Struct, #Variant or even #List again. + * + * @see TQT_DBusDataList + * @see TQT_DBusDataMap + * @see TQT_DBusDataConverter + */ +class TQDBUS_EXPORT TQT_DBusData +{ +public: + /** + * @brief Enum for the data types used in D-Bus messages + * + * In order to provide correct mapping of C++ and TQt types and the data + * types used in D-Bus messages, TQT_DBusData uses explicit naming of types + * where the name is usually the one used in D-Bus, with the exception of + * #List and #Map since this is closer to the TQt container they are + * implemented with (TQValueList and TQMap respectively) + * + * @see type(), keyType() + * @see typeName() + */ + enum Type + { + /** + * Base type for TQT_DBusData objects created by the default constructor. + * + * Also used as the type of returned objects when getter type methods + * fail due to type incompatabilties, i.e. toInt32() called on a #List + * object. + * + * @see isValid() + */ + Invalid = 0, + + /** + * Type when encapsulating a boolean value. + * + * @see fromBool(), toBool() + */ + Bool, + + /** + * Type when encapsulating a byte (unsigned char) value. + * + * @see fromByte(), toByte() + */ + Byte, + + /** + * Type when encapsulating a signed 16-bit integer value. + * + * @see fromInt16(), toInt16() + */ + Int16, + + /** + * Type when encapsulating an unsigned 16-bit integer value. + * + * @see fromUInt16(), toUInt16() + */ + UInt16, + + /** + * Type when encapsulating a signed 32-bit integer value. + * + * @see fromInt32(), toInt32() + */ + Int32, + + /** + * Type when encapsulating an unsigned 32-bit integer value. + * + * @see fromUInt32(), toUInt32() + */ + UInt32, + + /** + * Type when encapsulating a signed 64-bit integer value. + * + * @see fromInt64(), toInt64() + */ + Int64, + + /** + * Type when encapsulating an unsigned 64-bit integer value. + * + * @see fromUInt64(), toUInt64() + */ + UInt64, + + /** + * Type when encapsulating a double value. + * + * @see fromDouble(), toDouble() + */ + Double, + + /** + * Type when encapsulating a string value. + * + * All strings are converted to UTF-8 during transmission + * + * @see fromString(), toString() + */ + String, + + /** + * Type when encapsulating a D-Bus object path. + * + * D-Bus defines a special string variation for transporting the + * paths used to address objects within D-Bus services, see + * @ref dbusconventions-objectpath for formatting details. + * + * @note from the point of view of this bindings an object path is + * pretty much a normal string with externally checked restrictions. + * However, method calls or return values can require a signature + * to include an object path and any remote peer might then reject + * the normal string signature. + * + * @see fromObjectPath(), toObjectPath() + */ + ObjectPath, + + /** + * Type when encapsulating a D-Bus unix file handle. + * + * @see fromUnixFd(), toUnixFd() + */ + UnixFd, + + /** + * Type when encapsulating a list of values. + * + * The D-Bus type this maps to is called @c array but since the TQt + * container class used to implement this type is TQValueList (or rather + * TQT_DBusDataList), the TQT_DBusData type is called @c List instead. + * + * A list can contain any of the supported types as elements, even + * container types. + * However it can only contain elements with the same type per list + * object. + * + * @see fromList(), toList() + */ + List, + + /** + * Type when encapsulating a struct of values. + * + * A struct is basically a list of struct member variables, each + * member can be any of the supported types, even containers types. + * + * The C++/TQt value type used in the converter methods is a TQValueList + * with type TQT_DBusData. + * For example a TQRect could be mapped like this: + * @code + * TQRect rect(0, 0, 640, 480); + * TQValueList<TQT_DBusData> memberList; + * + * memberList << TQT_DBusData::fromInt32(rect.x()); + * memberList << TQT_DBusData::fromInt32(rect.y()); + * memberList << TQT_DBusData::fromInt32(rect.width()); + * memberList << TQT_DBusData::fromInt32(rect.height()); + * + * TQT_DBusData data = TQT_DBusData:fromStruct(memberList); + * @endcode + * + * And reconstructed like this: + * @code + * memberList = data.toStruct(); + * + * int x = memberList[0].toInt32(); + * int y = memberList[1].toInt32(); + * int w = memberList[2].toInt32(); + * int h = memberList[3].toInt32(); + * + * rect = TQRect(x, y, w, h); + * @endcode + * + * @note Empty structs, i.e. an empty member list, are not allowed + * + * @see fromStruct(), toStruct() + * @see TQT_DBusDataConverter + */ + Struct, + + /** + * Type when encapsulating a special variable container value. + * + * See TQT_DBusVariant for details on variant usage. + * + * @see fromVariant(), toVariant() + */ + Variant, + + /** + * Type when encapsulating a map of keys to values. + * + * The D-Bus type this maps to is called @c dict but since the TQt + * container class used to implement this type is TQMap (or rather + * TQT_DBusDataMap), the TQT_DBusData type is called @c Map instead. + * + * A map can contain any of the supported types as values, even + * container types, but only the following basic types as keys: + * - #Byte + * - #Int16 + * - #UInt16 + * - #Int32 + * - #UInt32 + * - #Int64 + * - #UInt64 + * - #String + * - #ObjectPath + * - #UnixFd + * + * All values need to be of the same type. + * + * @see fromByteKeyMap(), toByteKeyMap() + * @see fromInt16KeyMap(), toInt16KeyMap() + * @see fromUInt16KeyMap(), toUInt16KeyMap() + * @see fromInt32KeyMap(), toInt32KeyMap() + * @see fromUInt32KeyMap(), toUInt32KeyMap() + * @see fromInt64KeyMap(), toInt64KeyMap() + * @see fromUInt64KeyMap(), toUInt64KeyMap() + * @see fromStringKeyMap(), toStringKeyMap() + * @see fromObjectPathKeyMap(), toObjectPathKeyMap() + * @see fromUnixFdKeyMap(), toUnixFdKeyMap() + */ + Map + }; + + /** + * @brief Creates an empty, #Invalid data object + */ + TQT_DBusData(); + + /** + * @brief Copies a given @p other data object + * + * Since TQT_DBusData is implicitly shared, both objects will have the + * same content and the last object to reference it will delete it. + * + * @param other the object to copy + */ + TQT_DBusData(const TQT_DBusData& other); + + /** + * @brief Destroys the data object + * + * If this is the last instance to a shared content, it will delete it + * as well. + */ + ~TQT_DBusData(); + + /** + * @brief Copies a given @p other data object + * + * Since TQT_DBusData is implicitly shared, both objects will have the + * same content and the last object to reference it will delete it. + * + * @param other the object to copy + * + * @return a reference to this instance + */ + TQT_DBusData& operator=(const TQT_DBusData& other); + + /** + * @brief Checks if the given @p other data object is equal to this instance + * + * Two TQT_DBusData object are considered equal if they reference the same + * shared content or have the same type and the content's equality operator + * says the contents are equal. + * + * @param other the object to compare with + * + * @return @c true if the two data objects are equal, otherwise @c false + */ + bool operator==(const TQT_DBusData& other) const; + + /** + * @brief Checks if the given @p other data object is different from this instance + * + * @param other the object to compare with + * + * @return @c false if the two data objects are not equal, otherwise @c false + * + * @see operator==() + */ + bool operator!=(const TQT_DBusData& other) const; + + /** + * @brief Checks whether the data object contains a valid content + * + * This is equal to checking type() for not being #Invalid + * + * @return @c true if the data object is valid, otherwise @c false + */ + inline bool isValid() const { return type() != TQT_DBusData::Invalid; } + + /** + * @brief Returns the #Type of the data object + * + * @return one of the values of the #Type enum + * + * @see keyType() + * @see typeName() + */ + Type type() const; + + /** + * @brief Returns the #Type of the key type for maps + * + * If the type of the data object is #Map, this method returns the type + * of the map's key, #String for a TQT_DBusDataMap<TQString> + * + * If the type of the data object is not #Map, it will return #Invalid + * + * @return one of the values of the #Type enum, #Invalid if the object is + * not holding a #Map + * + * @see type() + * @see typeName() + */ + Type keyType() const; + + /** + * @brief Returns the string representation of the object's #Type + * + * @return an ASCII C-string for the object's type + * + * @see type() + * @see typeName(Type) + */ + inline const char* typeName() const { return typeName(type()); } + + /** + * @brief Returns the string representation for the given @p type + * + * @param type the #Type to get the string representation for + * + * @return an ASCII C-string for the given @p type + * + * @see type() + * @see typeName() + */ + static const char* typeName(Type type); + + /** + * @brief Creates a data object for the given boolean @p value + * + * @param value the value to encapsulate + * + * @return a data object of type #Bool containing the @p value + * + * @see toBool() + */ + static TQT_DBusData fromBool(bool value); + + /** + * @brief Tries to get the encapsulated boolean value + * + * If the data object is not of type #Bool this will fail, i.e. + * the parameter @p ok will be set to @c false if present. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #Bool) + * + * @return the encapsulated boolean value or @c false if it fails + * + * @see fromBool() + */ + bool toBool(bool* ok = 0) const; + + /** + * @brief Creates a data object for the given byte (unsigned char) @p value + * + * @param value the value to encapsulate + * + * @return a data object of type #Byte containing the @p value + * + * @see toByte() + */ + static TQT_DBusData fromByte(TQ_UINT8 value); + + /** + * @brief Tries to get the encapsulated byte (unsigned char) value + * + * If the data object is not of type #Byte this will fail, i.e. + * the parameter @p ok will be set to @c false if present. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #Byte) + * + * @return the encapsulated byte (unsigned char) value or @c 0 if it fails + * + * @see fromByte() + */ + TQ_UINT8 toByte(bool* ok = 0) const; + + /** + * @brief Creates a data object for the given signed 16-bit integer @p value + * + * @param value the value to encapsulate + * + * @return a data object of type #Int16 containing the @p value + * + * @see toInt16() + */ + static TQT_DBusData fromInt16(TQ_INT16 value); + + /** + * @brief Tries to get the encapsulated signed 16-bit integer value + * + * If the data object is not of type #Int16 this will fail, i.e. + * the parameter @p ok will be set to @c false if present. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #Int16) + * + * @return the encapsulated signed 16-bit integer value or @c 0 if it fails + * + * @see fromInt16() + */ + TQ_INT16 toInt16(bool* ok = 0) const; + + /** + * @brief Creates a data object for the given unsigned 16-bit integer @p value + * + * @param value the value to encapsulate + * + * @return a data object of type #UInt16 containing the @p value + * + * @see toUInt16() + */ + static TQT_DBusData fromUInt16(TQ_UINT16 value); + + /** + * @brief Tries to get the encapsulated unsigned 16-bit integer value + * + * If the data object is not of type #UInt16 this will fail, i.e. + * the parameter @p ok will be set to @c false if present. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #UInt16) + * + * @return the encapsulated unsigned 16-bit integer value or @c 0 if it fails + * + * @see fromUInt16() + */ + TQ_UINT16 toUInt16(bool* ok = 0) const; + + /** + * @brief Creates a data object for the given signed 32-bit integer @p value + * + * @param value the value to encapsulate + * + * @return a data object of type #Int32 containing the @p value + * + * @see toInt32() + */ + static TQT_DBusData fromInt32(TQ_INT32 value); + + /** + * @brief Tries to get the encapsulated signed 32-bit integer value + * + * If the data object is not of type #Int32 this will fail, i.e. + * the parameter @p ok will be set to @c false if present. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #Int32) + * + * @return the encapsulated signed 32-bit integer value or @c 0 if it fails + * + * @see fromInt32() + */ + TQ_INT32 toInt32(bool* ok = 0) const; + + /** + * @brief Creates a data object for the given unsigned 32-bit integer @p value + * + * @param value the value to encapsulate + * + * @return a data object of type #UInt32 containing the @p value + * + * @see toUInt32() + */ + static TQT_DBusData fromUInt32(TQ_UINT32 value); + + /** + * @brief Tries to get the encapsulated unsigned 32-bit integer value + * + * If the data object is not of type #UInt32 this will fail, i.e. + * the parameter @p ok will be set to @c false if present. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #UInt32) + * + * @return the encapsulated unsigned 32-bit integer value or @c 0 if it fails + * + * @see fromUInt32() + */ + TQ_UINT32 toUInt32(bool* ok = 0) const; + + /** + * @brief Creates a data object for the given signed 64-bit integer @p value + * + * @param value the value to encapsulate + * + * @return a data object of type #Int64 containing the @p value + * + * @see toInt64() + */ + static TQT_DBusData fromInt64(TQ_INT64 value); + + /** + * @brief Tries to get the encapsulated signed 64-bit integer value + * + * If the data object is not of type #Int64 this will fail, i.e. + * the parameter @p ok will be set to @c false if present. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #Int64) + * + * @return the encapsulated signed 64-bit integer value or @c 0 if it fails + * + * @see fromInt64() + */ + TQ_INT64 toInt64(bool* ok = 0) const; + + /** + * @brief Creates a data object for the given unsigned 64-bit integer @p value + * + * @param value the value to encapsulate + * + * @return a data object of type #UInt64 containing the @p value + * + * @see toUInt64() + */ + static TQT_DBusData fromUInt64(TQ_UINT64 value); + + /** + * @brief Tries to get the encapsulated unsigned 64-bit integer value + * + * If the data object is not of type #UInt64 this will fail, i.e. + * the parameter @p ok will be set to @c false if present. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #UInt64) + * + * @return the encapsulated unsigned 64-bit integer value or @c 0 if it fails + * + * @see fromUInt64() + */ + TQ_UINT64 toUInt64(bool* ok = 0) const; + + /** + * @brief Creates a data object for the given double @p value + * + * @param value the value to encapsulate + * + * @return a data object of type #Double containing the @p value + * + * @see toDouble() + */ + static TQT_DBusData fromDouble(double value); + + /** + * @brief Tries to get the encapsulated double value + * + * If the data object is not of type #Double this will fail, i.e. + * the parameter @p ok will be set to @c false if present. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #Double) + * + * @return the encapsulated double value or @c 0.0 if it fails + * + * @see fromDouble() + */ + double toDouble(bool* ok = 0) const; + + /** + * @brief Creates a data object for the given string @p value + * + * @param value the value to encapsulate + * + * @return a data object of type #String containing the @p value + * + * @see toString() + */ + static TQT_DBusData fromString(const TQString& value); + + /** + * @brief Tries to get the encapsulated string value + * + * If the data object is not of type #String this will fail, i.e. + * the parameter @p ok will be set to @c false if present. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #String) + * + * @return the encapsulated string value or @c TQString() if it fails + * + * @see fromString() + */ + TQString toString(bool* ok = 0) const; + + /** + * @brief Creates a data object for the given object path @p value + * + * @param value the value to encapsulate + * + * @return a data object of type #ObjectPath containing the @p value + * + * @see toObjectPath() + */ + static TQT_DBusData fromObjectPath(const TQT_DBusObjectPath& value); + + /** + * @brief Tries to get the encapsulated object path value + * + * If the data object is not of type #ObjectPath this will fail, i.e. + * the parameter @p ok will be set to @c false if present. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #ObjectPath) + * + * @return the encapsulated object path value or an empty and invalid object + * if it fails + * + * @see fromObjectPath() + */ + TQT_DBusObjectPath toObjectPath(bool* ok = 0) const; + + /** + * @brief Creates a data object for the given unix file handle @p value + * + * @param value the value to encapsulate + * + * @return a data object of type #UnixFd containing the @p value + * + * @see toUnixFd() + */ + static TQT_DBusData fromUnixFd(const TQT_DBusUnixFd& value); + + /** + * @brief Tries to get the encapsulated unix file handle value + * + * If the data object is not of type #UnixFd this will fail, i.e. + * the parameter @p ok will be set to @c false if present. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #UnixFd) + * + * @return the encapsulated object path value or an empty and invalid object + * if it fails + * + * @see fromUnixFd() + */ + TQT_DBusUnixFd toUnixFd(bool* ok = 0) const; + + /** + * @brief Creates a data object for the given @p list + * + * \note The list is allowed to be empty but is required to have a valid type + * + * Unless the list the is empty, the convenience method fromTQValueList() will + * usually be easier to use since it does not require to create a + * TQT_DBusDataList first. For empty lists this method has to be used to + * make sure there is sufficient type information on the list's elements + * available for the binding's marshalling code. + * + * @param list the list to encapsulate + * + * @return a data object of type #List containing the @p list or + * an #Invalid object if the list's type is #Invalid + * + * @see toList() + */ + static TQT_DBusData fromList(const TQT_DBusDataList& list); + + /** + * @brief Tries to get the encapsulated list + * + * If the data object is not of type #List this will fail, i.e. + * the parameter @p ok will be set to @c false if present. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #List) + * + * @return the encapsulated list or an empty and #Invalid list if it fails + * + * @see fromList() + */ + TQT_DBusDataList toList(bool* ok = 0) const; + + /** + * @brief Creates a data object for the given @p list + * + * @warning All elements of the list have to be of the same #Type + * + * Convenience overload for fromList(), usually more straight forward to use + * because it doesn't require to create a TQT_DBusDataList object first, + * however it can only handle lists which contain elements, for empty lists + * fromList() is the only option. + * + * @param list the list to encapsulate + * + * @return a data object of type #List containing the @p list or + * an #Invalid object if the list is empty or if elements have + * different types. + * + * @see toTQValueList() + */ + static TQT_DBusData fromTQValueList(const TQValueList<TQT_DBusData>& list); + + /** + * @brief Tries to get the encapsulated list + * + * Convenience overload for toList(). + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #List) + * + * @return the encapsulated list or an empty and #Invalid list if it fails + * + * @see fromTQValueList() + */ + TQValueList<TQT_DBusData> toTQValueList(bool* ok = 0) const; + + /** + * @brief Creates a data object for the given struct's @p memberList + * + * See the documentation of #Struct for an example. + * + * @param memberList the list of already encapsulated struct members + * + * @return a data object of type #Struct containing the @p memberList + * + * @see toStruct() + */ + static TQT_DBusData fromStruct(const TQValueList<TQT_DBusData>& memberList); + + /** + * @brief Tries to get the encapsulated struct memberList + * + * If the data object is not of type #Struct this will fail, i.e. + * the parameter @p ok will be set to @c false if present. + * + * See the documentation of #Struct for an example. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #Struct) + * + * @return the encapsulated memberList or an empty list if it fails + * + * @see fromStruct() + */ + TQValueList<TQT_DBusData> toStruct(bool* ok = 0) const; + + /** + * @brief Creates a data object for the given variant @p value + * + * @param value the value to encapsulate + * + * @return a data object of type #Variant containing the @p value + * + * @see toVariant() + */ + static TQT_DBusData fromVariant(const TQT_DBusVariant& value); + + /** + * @brief Tries to get the encapsulated variant value + * + * If the data object is not of type #Variant this will fail, i.e. + * the parameter @p ok will be set to @c false if present. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #Variant) + * + * @return the encapsulated variant value or an empty variant if it fails + * + * @see fromVariant() + */ + TQT_DBusVariant toVariant(bool* ok = 0) const; + + /** + * @brief Creates a data object for the given @p map + * + * \note The map is allowed to be empty but is required to have a valid + * value type + * + * The resulting data object will have the keyType() set to #Byte. + * + * @param map the map to encapsulate + * + * @return a data object of type #Map containing the @p map or + * an #Invalid object if the map's value type is #Invalid + * + * @see toByteKeyMap() + */ + static TQT_DBusData fromByteKeyMap(const TQT_DBusDataMap<TQ_UINT8>& map); + + /** + * @brief Tries to get the encapsulated map + * + * If the data object is not of type #Map or if its value type is not #Byte + * this will fail, i.e. the parameter @p ok will be set to @c false if + * present. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #Map or + * value type not #Byte) + * + * @return the encapsulated map or an empty and #Invalid map if it fails + * + * @see fromByteKeyMap() + */ + TQT_DBusDataMap<TQ_UINT8> toByteKeyMap(bool* ok = 0) const; + + /** + * @brief Creates a data object for the given @p map + * + * \note The map is allowed to be empty but is required to have a valid + * value type + * + * The resulting data object will have the keyType() set to #Int16. + * + * @param map the map to encapsulate + * + * @return a data object of type #Map containing the @p map or + * an #Invalid object if the map's value type is #Invalid + * + * @see toInt16KeyMap() + */ + static TQT_DBusData fromInt16KeyMap(const TQT_DBusDataMap<TQ_INT16>& map); + + /** + * @brief Tries to get the encapsulated map + * + * If the data object is not of type #Map or if its value type is not #Int16 + * this will fail, i.e. the parameter @p ok will be set to @c false if + * present. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #Map or + * value type not #Int16) + * + * @return the encapsulated map or an empty and #Invalid map if it fails + * + * @see fromInt16KeyMap() + */ + TQT_DBusDataMap<TQ_INT16> toInt16KeyMap(bool* ok = 0) const; + + /** + * @brief Creates a data object for the given @p map + * + * \note The map is allowed to be empty but is required to have a valid + * value type + * + * The resulting data object will have the keyType() set to #UInt16. + * + * @param map the map to encapsulate + * + * @return a data object of type #Map containing the @p map or + * an #Invalid object if the map's value type is #Invalid + * + * @see toUInt16KeyMap() + */ + static TQT_DBusData fromUInt16KeyMap(const TQT_DBusDataMap<TQ_UINT16>& map); + + /** + * @brief Tries to get the encapsulated map + * + * If the data object is not of type #Map or if its value type is not #UInt16 + * this will fail, i.e. the parameter @p ok will be set to @c false if + * present. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #Map or + * value type not #UInt16) + * + * @return the encapsulated map or an empty and #Invalid map if it fails + * + * @see fromUInt16KeyMap() + */ + TQT_DBusDataMap<TQ_UINT16> toUInt16KeyMap(bool* ok = 0) const; + + /** + * @brief Creates a data object for the given @p map + * + * \note The map is allowed to be empty but is required to have a valid + * value type + * + * The resulting data object will have the keyType() set to #Int32. + * + * @param map the map to encapsulate + * + * @return a data object of type #Map containing the @p map or + * an #Invalid object if the map's value type is #Invalid + * + * @see toInt32KeyMap() + */ + static TQT_DBusData fromInt32KeyMap(const TQT_DBusDataMap<TQ_INT32>& map); + + /** + * @brief Tries to get the encapsulated map + * + * If the data object is not of type #Map or if its value type is not #Int32 + * this will fail, i.e. the parameter @p ok will be set to @c false if + * present. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #Map or + * value type not #Int32) + * + * @return the encapsulated map or an empty and #Invalid map if it fails + * + * @see fromInt32KeyMap() + */ + TQT_DBusDataMap<TQ_INT32> toInt32KeyMap(bool* ok = 0) const; + + /** + * @brief Creates a data object for the given @p map + * + * \note The map is allowed to be empty but is required to have a valid + * value type + * + * The resulting data object will have the keyType() set to #UInt32. + * + * @param map the map to encapsulate + * + * @return a data object of type #Map containing the @p map or + * an #Invalid object if the map's value type is #Invalid + * + * @see toUInt32KeyMap() + */ + static TQT_DBusData fromUInt32KeyMap(const TQT_DBusDataMap<TQ_UINT32>& map); + + /** + * @brief Tries to get the encapsulated map + * + * If the data object is not of type #Map or if its value type is not #UInt32 + * this will fail, i.e. the parameter @p ok will be set to @c false if + * present. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #Map or + * value type not #UInt32) + * + * @return the encapsulated map or an empty and #Invalid map if it fails + * + * @see fromUInt32KeyMap() + */ + TQT_DBusDataMap<TQ_UINT32> toUInt32KeyMap(bool* ok = 0) const; + + /** + * @brief Creates a data object for the given @p map + * + * \note The map is allowed to be empty but is required to have a valid + * value type + * + * The resulting data object will have the keyType() set to #Int64. + * + * @param map the map to encapsulate + * + * @return a data object of type #Map containing the @p map or + * an #Invalid object if the map's value type is #Invalid + * + * @see toInt64KeyMap() + */ + static TQT_DBusData fromInt64KeyMap(const TQT_DBusDataMap<TQ_INT64>& map); + + /** + * @brief Tries to get the encapsulated map + * + * If the data object is not of type #Map or if its value type is not #Int64 + * this will fail, i.e. the parameter @p ok will be set to @c false if + * present. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #Map or + * value type not #Int64) + * + * @return the encapsulated map or an empty and #Invalid map if it fails + * + * @see fromInt64KeyMap() + */ + TQT_DBusDataMap<TQ_INT64> toInt64KeyMap(bool* ok = 0) const; + + /** + * @brief Creates a data object for the given @p map + * + * \note The map is allowed to be empty but is required to have a valid + * value type + * + * The resulting data object will have the keyType() set to #UInt64. + * + * @param map the map to encapsulate + * + * @return a data object of type #Map containing the @p map or + * an #Invalid object if the map's value type is #Invalid + * + * @see toUInt64KeyMap() + */ + static TQT_DBusData fromUInt64KeyMap(const TQT_DBusDataMap<TQ_UINT64>& map); + + /** + * @brief Tries to get the encapsulated map + * + * If the data object is not of type #Map or if its value type is not #UInt64 + * this will fail, i.e. the parameter @p ok will be set to @c false if + * present. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #Map or + * value type not #UInt64) + * + * @return the encapsulated map or an empty and #Invalid map if it fails + * + * @see fromUInt64KeyMap() + */ + TQT_DBusDataMap<TQ_UINT64> toUInt64KeyMap(bool* ok = 0) const; + + /** + * @brief Creates a data object for the given @p map + * + * \note The map is allowed to be empty but is required to have a valid + * value type + * + * The resulting data object will have the keyType() set to #String. + * + * @param map the map to encapsulate + * + * @return a data object of type #Map containing the @p map or + * an #Invalid object if the map's value type is #Invalid + * + * @see toStringKeyMap() + */ + static TQT_DBusData fromStringKeyMap(const TQT_DBusDataMap<TQString>& map); + + /** + * @brief Tries to get the encapsulated map + * + * If the data object is not of type #Map or if its value type is not #String + * this will fail, i.e. the parameter @p ok will be set to @c false if + * present. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #Map or + * value type not #String) + * + * @return the encapsulated map or an empty and #Invalid map if it fails + * + * @see fromStringKeyMap() + */ + TQT_DBusDataMap<TQString> toStringKeyMap(bool* ok = 0) const; + + /** + * @brief Creates a data object for the given @p map + * + * \note The map is allowed to be empty but is required to have a valid + * value type + * + * The resulting data object will have the keyType() set to #ObjectPath. + * + * @param map the map to encapsulate + * + * @return a data object of type #Map containing the @p map or + * an #Invalid object if the map's value type is #Invalid + * + * @see toObjectPathKeyMap() + */ + static TQT_DBusData fromObjectPathKeyMap(const TQT_DBusDataMap<TQT_DBusObjectPath>& map); + + /** + * @brief Tries to get the encapsulated map + * + * If the data object is not of type #Map or if its value type is not + * #ObjectPath this will fail, i.e. the parameter @p ok will be set to + * @c false if present. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #Map or + * value type not #ObjectPath) + * + * @return the encapsulated map or an empty and #Invalid map if it fails + * + * @see fromObjectPathKeyMap() + */ + TQT_DBusDataMap<TQT_DBusObjectPath> toObjectPathKeyMap(bool* ok = 0) const; + + /** + * @brief Creates a data object for the given @p map + * + * \note The map is allowed to be empty but is required to have a valid + * value type + * + * The resulting data object will have the keyType() set to #UnixFd. + * + * @param map the map to encapsulate + * + * @return a data object of type #Map containing the @p map or + * an #Invalid object if the map's value type is #Invalid + * + * @see toUnixFdhKeyMap() + */ + static TQT_DBusData fromUnixFdKeyMap(const TQT_DBusDataMap<TQT_DBusUnixFd>& map); + + /** + * @brief Tries to get the encapsulated map + * + * If the data object is not of type #Map or if its value type is not + * #UnixFd this will fail, i.e. the parameter @p ok will be set to + * @c false if present. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type #Map or + * value type not #UnixFd) + * + * @return the encapsulated map or an empty and #Invalid map if it fails + * + * @see fromUnixFdKeyMap() + */ + TQT_DBusDataMap<TQT_DBusUnixFd> toUnixFdKeyMap(bool* ok = 0) const; + + /** + * @brief Creates the data objects D-Bus signature + * + * Recursivly builds the D-Bus signature of the data object if it holds a + * container type, i.e. if the object is of type #List, #Map or #Struct + * + * This can be used to create a signature for TQT_DBusVariant when creating one + * for sending over D-Bus. + * + * @return a string containing the content's signature, or a null string + * if the data object is #Invalid + */ + TQCString buildDBusSignature() const; + +private: + class Private; + Private* d; +}; + +#endif diff --git a/src/tqdbusdataconverter.cpp b/src/tqdbusdataconverter.cpp new file mode 100644 index 0000000..50575b8 --- /dev/null +++ b/src/tqdbusdataconverter.cpp @@ -0,0 +1,143 @@ +/* qdbusdataconverter.cpp TQT_DBusDataConverter template + * + * Copyright (C) 2007 Kevin Krammer <kevin.krammer@gmx.at> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#include "tqdbusdataconverter.h" +#include "tqdbusdata.h" + +#include <tqpoint.h> +#include <tqrect.h> +#include <tqsize.h> +#include <tqvaluelist.h> + +template <> +TQT_DBusDataConverter::Result TQT_DBusDataConverter::convertFromTQT_DBusData<TQRect>(const TQT_DBusData& dbusData, TQRect& typeData) +{ + if (dbusData.type() != TQT_DBusData::Struct) return InvalidSignature; + + TQValueList<TQT_DBusData> members = dbusData.toStruct(); + if (members.count() != 4) return InvalidSignature; + + TQ_INT32 values[4]; + + TQValueList<TQT_DBusData>::const_iterator it = members.begin(); + TQValueList<TQT_DBusData>::const_iterator endIt = members.end(); + for (uint i = 0; it != endIt; ++it, ++i) + { + bool ok = false; + values[i] = (*it).toInt32(&ok); + if (!ok) return InvalidSignature; + } + + typeData = TQRect(values[0], values[1], values[2], values[3]); + + return Success; +} + +template <> +TQT_DBusDataConverter::Result TQT_DBusDataConverter::convertToTQT_DBusData<TQRect>(const TQRect& typeData, TQT_DBusData& dbusData) +{ + TQValueList<TQT_DBusData> members; + + members << TQT_DBusData::fromInt32(typeData.x()); + members << TQT_DBusData::fromInt32(typeData.y()); + members << TQT_DBusData::fromInt32(typeData.width()); + members << TQT_DBusData::fromInt32(typeData.height()); + + dbusData = TQT_DBusData::fromStruct(members); + + return Success; +} + +template <> +TQT_DBusDataConverter::Result TQT_DBusDataConverter::convertFromTQT_DBusData<TQPoint>(const TQT_DBusData& dbusData, TQPoint& typeData) +{ + if (dbusData.type() != TQT_DBusData::Struct) return InvalidSignature; + + TQValueList<TQT_DBusData> members = dbusData.toStruct(); + if (members.count() != 2) return InvalidSignature; + + TQ_INT32 values[2]; + + TQValueList<TQT_DBusData>::const_iterator it = members.begin(); + TQValueList<TQT_DBusData>::const_iterator endIt = members.end(); + for (uint i = 0; it != endIt; ++it, ++i) + { + bool ok = false; + values[i] = (*it).toInt32(&ok); + if (!ok) return InvalidSignature; + } + + typeData = TQPoint(values[0], values[1]); + + return Success; +} + +template <> +TQT_DBusDataConverter::Result TQT_DBusDataConverter::convertToTQT_DBusData<TQPoint>(const TQPoint& typeData, TQT_DBusData& dbusData) +{ + TQValueList<TQT_DBusData> members; + + members << TQT_DBusData::fromInt32(typeData.x()); + members << TQT_DBusData::fromInt32(typeData.y()); + + dbusData = TQT_DBusData::fromStruct(members); + + return Success; +} + +template <> +TQT_DBusDataConverter::Result TQT_DBusDataConverter::convertFromTQT_DBusData<TQSize>(const TQT_DBusData& dbusData, TQSize& typeData) +{ + if (dbusData.type() != TQT_DBusData::Struct) return InvalidSignature; + + TQValueList<TQT_DBusData> members = dbusData.toStruct(); + if (members.count() != 2) return InvalidSignature; + + TQ_INT32 values[2]; + + TQValueList<TQT_DBusData>::const_iterator it = members.begin(); + TQValueList<TQT_DBusData>::const_iterator endIt = members.end(); + for (uint i = 0; it != endIt; ++it, ++i) + { + bool ok = false; + values[i] = (*it).toInt32(&ok); + if (!ok) return InvalidSignature; + } + + typeData = TQSize(values[0], values[1]); + + return Success; +} + +template <> +TQT_DBusDataConverter::Result TQT_DBusDataConverter::convertToTQT_DBusData<TQSize>(const TQSize& typeData, TQT_DBusData& dbusData) +{ + TQValueList<TQT_DBusData> members; + + members << TQT_DBusData::fromInt32(typeData.width()); + members << TQT_DBusData::fromInt32(typeData.height()); + + dbusData = TQT_DBusData::fromStruct(members); + + return Success; +} diff --git a/src/tqdbusdataconverter.h b/src/tqdbusdataconverter.h new file mode 100644 index 0000000..2ca21a0 --- /dev/null +++ b/src/tqdbusdataconverter.h @@ -0,0 +1,207 @@ +/* qdbusdataconverter.h TQT_DBusDataConverter template + * + * Copyright (C) 2007 Kevin Krammer <kevin.krammer@gmx.at> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#ifndef TQDBUSDATACONVERTER_H +#define TQDBUSDATACONVERTER_H + +#include "tqdbusmacros.h" + +class TQT_DBusData; + +/** + * @brief Template based converter for getting complex data into or from TQT_DBusData objects + * + * Any data to transport over D-Bus, i.e. method/signal paramaters or properties, need + * to be converted into a TQT_DBusData instance. + * + * For complex types, e.g. structures or nested containers, this can be quite some code, + * and will likely be needed for more than one call. + * Therefore it is more convenient to implement the conversions once per complex type. + * + * Example: sending and recieving a TQRect over D-Bus. + * In D-Bus terminology a TQRect is a struct of four 32-bit signed integers. The code to do + * this manually looks like this: + * @code + * TQRect rect(0, 0, 100, 100); + * + * TQValueList<TQT_DBusData> structMembers; + * structMembers << TQT_DBusData::fromInt32(rect.x()); + * structMembers << TQT_DBusData::fromInt32(rect.y()); + * structMembers << TQT_DBusData::fromInt32(rect.wdth()); + * structMembers << TQT_DBusData::fromInt32(rect.height()); + * + * TQT_DBusData rectStruct = TQT_DBusData::fromStruct(structMembers); + * @endcode + * and reverse (without the error checking) + * @code + * TQT_DBusData dbusData; // assume we got this from a D-Bus call + * + * TQValueList<TQT_DBusData> structMembers = dbudData.toStruct(); + * + * int x = structMembers[0].toInt32(); + * int y = structMembers[1].toInt32(); + * int w = structMembers[2].toInt32(); + * int h = structMembers[3].toInt32(); + * + * TQRect rect(x, y, w, h); + * @endcode + * + * Rather than implementing it in the method which performs the D-Bus call, basically the same + * code can be used as a spezialisation of the TQT_DBusDataConverter methods and then used like this: + * @code + * TQRect rect(0, 0, 100, 100); + * TQT_DBusData rectStruct; + * + * TQT_DBusDataConverter::convertToTQT_DBusData<TQRect>(rect, rectStruct); + * @endcode + * and + * @code + * TQRect rect; + * TQT_DBusData dbusData; // assume we got this from a D-Bus call + * + * TQT_DBusDataConverter::convertFromTQT_DBusData<TQRect>(dbusData, rect); + * @endcode + * + * @note The bindings library contains the spezialisations for TQRect, TQPoint and TQSize. + */ +class TQDBUS_EXPORT TQT_DBusDataConverter +{ +public: + /** + * @brief Conversion result values + */ + enum Result + { + /** + * Conversion successfull + */ + Success, + + /** + * Conversion failed because the passed TQT_DBusData instance does not contain data + * of the needed signature, e.g. too few to too many members for a struct or wrong types. + * + * @see TQT_DBusError::stdInvalidSignature() + */ + InvalidSignature, + + /** + * Conversion failed because the passed TQT_DBusData contained values which are not allowed, + * e.g. out of range for a numerical type used a an enum or flags. + * + * @see TQT_DBusError::stdInvalidArgs() + */ + InvalidArgument + }; + + /** + * @brief Conversion from a filled TQT_DBusData instance to a native type + * + * For example the implementation for TQPoint looks like this: + * @code + * template <> + * TQT_DBusDataConverter::Result + * TQT_DBusDataConverter::convertFromTQT_DBusData<TQPoint>(const TQT_DBusData& dbusData, TQPoint& typeData) + * { + * if (dbusData.type() != TQT_DBusData::Struct) return InvalidSignature; + * + * TQValueList<TQT_DBusData> members = dbusData.toStruct(); + * if (members.count() != 2) return InvalidSignature; + * + * bool ok = false; + * int x = members[0].toInt32(&ok); + * if (!ok) return InvalidSignature; + * + * int y = members[1].toInt32(&ok); + * if (!ok) return InvalidSignature; + * + * typeData = TQPoint(x, y); + * + * return Success; + * } + * @endcode + * + * And then can be used like this: + * @code + * TQT_DBusMessage reply; // assume we got this as a D-Bus call reply + * TQPoint point; + * + * if (TQT_DBusDataConverter::convertFromTQT_DBusData(reply[0], point) != TQT_DBusDataConverter::Success) + * { + * // error handling + * } + * @endcode + * + * @param dbusData the binding's data instance to get the content from + * @param typeData the native type instance to put the content into + * + * @return the conversion result value + */ + template <class T> + static Result convertFromTQT_DBusData(const TQT_DBusData& dbusData, T& typeData); + + /** + * @brief Conversion from a native type to a TQT_DBusData instance + * + * For example the implementation for TQPoint looks like this: + * @code + * template <> + * TQT_DBusDataConversion::Result + * TQT_DBusDataConversion::convertToTQT_DBusData<TQPoint>(const TQPoint& typeData, TQT_DBusData& dbusData) + * { + * TQValueList<TQT_DBusData> members; + * members << TQT_DBusData::fromInt32(typeData.x()); + * members << TQT_DBusData::fromInt32(typeData.y()); + * + * dbusData = TQT_DBusData::fromStruct(members); + * + * return Success; + * } + * @endcode + * + * And then can be used like this: + * @code + * TQPoint point(-10, 100); + * TQT_DBusMessage methodCall; // assume created by TQBusMessage::methodCall() + * + * TQT_DBusData dbusData; + * if (TQT_DBusDataConverter::convertToTQT_DBusData<TQPoint>(point, dbusData) != TQT_DBusDataConverter::Success) + * { + * // error handling + * } + * else + * { + * methodCall << dbusData; + * } + * @endcode + * + * @param typeData the native type instance to get the content from + * @param dbusData the binding's data instance to put the content into + * + * @return the conversion result value + */ + template <class T> + static Result convertToTQT_DBusData(const T& typeData, TQT_DBusData& dbusData); +}; + +#endif diff --git a/src/tqdbusdatalist.cpp b/src/tqdbusdatalist.cpp new file mode 100644 index 0000000..23f60a5 --- /dev/null +++ b/src/tqdbusdatalist.cpp @@ -0,0 +1,786 @@ +/* qdbusdatalist.cpp list of DBUS data transport type + * + * Copyright (C) 2007 Kevin Krammer <kevin.krammer@gmx.at> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#include "tqdbusdatalist.h" +#include "tqdbusobjectpath.h" +#include "tqdbusunixfd.h" +#include "tqdbusvariant.h" + +#include <tqstringlist.h> + +class TQT_DBusDataList::Private +{ +public: + Private() : type(TQT_DBusData::Invalid) {} + +public: + TQT_DBusData::Type type; + TQT_DBusData containerItem; + TQValueList<TQT_DBusData> list; +}; + +TQT_DBusDataList::TQT_DBusDataList() : d(new Private()) +{ +} + +TQT_DBusDataList::TQT_DBusDataList(TQT_DBusData::Type simpleItemType) : d(new Private()) +{ + d->type = simpleItemType; +} + +TQT_DBusDataList::TQT_DBusDataList(const TQT_DBusData& containerItemType) : d(new Private()) +{ + d->type = containerItemType.type(); + + switch(d->type) + { + case TQT_DBusData::List: // fall through + case TQT_DBusData::Struct: // fall through + case TQT_DBusData::Map: + d->containerItem = containerItemType; + break; + + default: // not a container + break; + } +} + +TQT_DBusDataList::TQT_DBusDataList(const TQT_DBusDataList& other) : d(new Private()) +{ + d->type = other.d->type; + d->list = other.d->list; + d->containerItem = other.d->containerItem; +} + +TQT_DBusDataList::TQT_DBusDataList(const TQValueList<TQT_DBusData>& other) : d(new Private()) +{ + if (other.isEmpty()) return; + + TQValueList<TQT_DBusData>::const_iterator it = other.begin(); + TQValueList<TQT_DBusData>::const_iterator endIt = other.end(); + + d->type = (*it).type(); + + TQCString elementSignature; + if (hasContainerItemType()) + { + d->containerItem = other[0]; // would be nice to get an empty one + elementSignature = d->containerItem.buildDBusSignature(); + } + + for (++it; it != endIt; ++it) + { + if (d->type != (*it).type()) + { + d->type = TQT_DBusData::Invalid; + d->containerItem = TQT_DBusData(); + + return; + } + else if (hasContainerItemType()) + { + if ((*it).buildDBusSignature() != elementSignature) + { + d->type = TQT_DBusData::Invalid; + d->containerItem = TQT_DBusData(); + + return; + } + } + } + + d->list = other; +} + +TQT_DBusDataList::TQT_DBusDataList(const TQValueList<bool>& other) : d(new Private()) +{ + d->type = TQT_DBusData::Bool; + + if (other.isEmpty()) return; + + TQValueList<bool>::const_iterator it = other.begin(); + TQValueList<bool>::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + d->list << TQT_DBusData::fromBool(*it); + } +} + +TQT_DBusDataList::TQT_DBusDataList(const TQValueList<TQ_UINT8>& other) : d(new Private()) +{ + d->type = TQT_DBusData::Byte; + + if (other.isEmpty()) return; + + TQValueList<TQ_UINT8>::const_iterator it = other.begin(); + TQValueList<TQ_UINT8>::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + d->list << TQT_DBusData::fromByte(*it); + } +} + +TQT_DBusDataList::TQT_DBusDataList(const TQValueList<TQ_INT16>& other) : d(new Private()) +{ + d->type = TQT_DBusData::Int16; + + if (other.isEmpty()) return; + + TQValueList<TQ_INT16>::const_iterator it = other.begin(); + TQValueList<TQ_INT16>::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + d->list << TQT_DBusData::fromInt16(*it); + } +} + +TQT_DBusDataList::TQT_DBusDataList(const TQValueList<TQ_UINT16>& other) : d(new Private()) +{ + d->type = TQT_DBusData::UInt16; + + if (other.isEmpty()) return; + + TQValueList<TQ_UINT16>::const_iterator it = other.begin(); + TQValueList<TQ_UINT16>::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + d->list << TQT_DBusData::fromUInt16(*it); + } +} + +TQT_DBusDataList::TQT_DBusDataList(const TQValueList<TQ_INT32>& other) : d(new Private()) +{ + d->type = TQT_DBusData::Int32; + + if (other.isEmpty()) return; + + TQValueList<TQ_INT32>::const_iterator it = other.begin(); + TQValueList<TQ_INT32>::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + d->list << TQT_DBusData::fromInt32(*it); + } +} + +TQT_DBusDataList::TQT_DBusDataList(const TQValueList<TQ_UINT32>& other) : d(new Private()) +{ + d->type = TQT_DBusData::UInt32; + + if (other.isEmpty()) return; + + TQValueList<TQ_UINT32>::const_iterator it = other.begin(); + TQValueList<TQ_UINT32>::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + d->list << TQT_DBusData::fromUInt32(*it); + } +} + +TQT_DBusDataList::TQT_DBusDataList(const TQValueList<TQ_INT64>& other) : d(new Private()) +{ + d->type = TQT_DBusData::Int64; + + if (other.isEmpty()) return; + + TQValueList<TQ_INT64>::const_iterator it = other.begin(); + TQValueList<TQ_INT64>::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + d->list << TQT_DBusData::fromInt64(*it); + } +} + +TQT_DBusDataList::TQT_DBusDataList(const TQValueList<TQ_UINT64>& other) : d(new Private()) +{ + d->type = TQT_DBusData::UInt64; + + if (other.isEmpty()) return; + + TQValueList<TQ_UINT64>::const_iterator it = other.begin(); + TQValueList<TQ_UINT64>::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + d->list << TQT_DBusData::fromUInt64(*it); + } +} + +TQT_DBusDataList::TQT_DBusDataList(const TQValueList<double>& other) : d(new Private()) +{ + d->type = TQT_DBusData::Double; + + if (other.isEmpty()) return; + + TQValueList<double>::const_iterator it = other.begin(); + TQValueList<double>::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + d->list << TQT_DBusData::fromDouble(*it); + } +} + +TQT_DBusDataList::TQT_DBusDataList(const TQValueList<TQT_DBusVariant>& other) + : d(new Private()) +{ + d->type = TQT_DBusData::Variant; + + if (other.isEmpty()) return; + + TQValueList<TQT_DBusVariant>::const_iterator it = other.begin(); + TQValueList<TQT_DBusVariant>::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + d->list << TQT_DBusData::fromVariant(*it); + } +} + +TQT_DBusDataList::TQT_DBusDataList(const TQStringList& other) : d(new Private()) +{ + d->type = TQT_DBusData::String; + + if (other.isEmpty()) return; + + TQStringList::const_iterator it = other.begin(); + TQStringList::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + d->list << TQT_DBusData::fromString(*it); + } +} + +TQT_DBusDataList::TQT_DBusDataList(const TQValueList<TQT_DBusObjectPath>& other) + : d(new Private()) +{ + d->type = TQT_DBusData::ObjectPath; + + if (other.isEmpty()) return; + + TQValueList<TQT_DBusObjectPath>::const_iterator it = other.begin(); + TQValueList<TQT_DBusObjectPath>::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + d->list << TQT_DBusData::fromObjectPath(*it); + } +} + +TQT_DBusDataList::TQT_DBusDataList(const TQValueList<TQT_DBusUnixFd>& other) + : d(new Private()) +{ + d->type = TQT_DBusData::UnixFd; + + if (other.isEmpty()) return; + + TQValueList<TQT_DBusUnixFd>::const_iterator it = other.begin(); + TQValueList<TQT_DBusUnixFd>::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + d->list << TQT_DBusData::fromUnixFd(*it); + } +} + +TQT_DBusDataList::~TQT_DBusDataList() +{ + delete d; +} + +TQT_DBusDataList& TQT_DBusDataList::operator=(const TQT_DBusDataList& other) +{ + if (&other == this) return *this; + + d->type = other.d->type; + d->list = other.d->list; + d->containerItem = other.d->containerItem; + + return *this; +} + +TQT_DBusDataList& TQT_DBusDataList::operator=(const TQValueList<TQT_DBusData>& other) +{ + d->list.clear(); + d->type = TQT_DBusData::Invalid; + d->containerItem = TQT_DBusData(); + + if (other.isEmpty()) return *this; + + TQValueList<TQT_DBusData>::const_iterator it = other.begin(); + TQValueList<TQT_DBusData>::const_iterator endIt = other.end(); + + d->type = (*it).type(); + + TQCString elementSignature; + if (hasContainerItemType()) + { + d->containerItem = other[0]; // would be nice to get an empty one + + elementSignature = d->containerItem.buildDBusSignature(); + } + + for (++it; it != endIt; ++it) + { + if (d->type != (*it).type()) + { + d->type = TQT_DBusData::Invalid; + d->containerItem = TQT_DBusData(); + + return *this; + } + else if (hasContainerItemType()) + { + if ((*it).buildDBusSignature() != elementSignature) + { + d->type = TQT_DBusData::Invalid; + d->containerItem = TQT_DBusData(); + + return *this; + } + } + } + + d->list = other; + + return *this; +} + +TQT_DBusDataList& TQT_DBusDataList::operator=(const TQStringList& other) +{ + d->list.clear(); + d->type = TQT_DBusData::String; + d->containerItem = TQT_DBusData(); + + TQStringList::const_iterator it = other.begin(); + TQStringList::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + d->list << TQT_DBusData::fromString(*it); + } + + return *this; +} + +TQT_DBusData::Type TQT_DBusDataList::type() const +{ + return d->type; +} + +bool TQT_DBusDataList::hasContainerItemType() const +{ + return d->type == TQT_DBusData::List || d->type == TQT_DBusData::Map + || d->type == TQT_DBusData::Struct; +} + +TQT_DBusData TQT_DBusDataList::containerItemType() const +{ + return d->containerItem; +} + +bool TQT_DBusDataList::isEmpty() const +{ + return d->list.isEmpty(); +} + +uint TQT_DBusDataList::count() const +{ + return d->list.count(); +} + +bool TQT_DBusDataList::operator==(const TQT_DBusDataList& other) const +{ + if (&other == this) return true; + if (d == other.d) return true; + + bool containerEqual = true; + if (hasContainerItemType()) + { + if (other.hasContainerItemType()) + { + containerEqual = d->containerItem.buildDBusSignature() == + other.d->containerItem.buildDBusSignature(); + } + else + containerEqual = false; + } + else if (other.hasContainerItemType()) + containerEqual = false; + + return d->type == other.d->type && containerEqual && d->list == other.d->list; +} + +bool TQT_DBusDataList::operator!=(const TQT_DBusDataList& other) const +{ + if (&other == this) return false; + if (d == other.d) return false; + + bool containerEqual = true; + if (hasContainerItemType()) + { + if (other.hasContainerItemType()) + { + containerEqual = d->containerItem.buildDBusSignature() == + other.d->containerItem.buildDBusSignature(); + } + else + containerEqual = false; + } + else if (other.hasContainerItemType()) + containerEqual = false; + + return d->type != other.d->type || !containerEqual || d->list != other.d->list; +} + +void TQT_DBusDataList::clear() +{ + d->list.clear(); +} + +TQT_DBusDataList& TQT_DBusDataList::operator<<(const TQT_DBusData& data) +{ + if (data.type() == TQT_DBusData::Invalid) return *this; + + if (d->type == TQT_DBusData::Invalid) + { + d->type = data.type(); + + // check if we are now have container items + if (hasContainerItemType()) d->containerItem = data; + + d->list << data; + } + else if (d->type != data.type()) + { + tqWarning("TQT_DBusDataList: trying to add data of type %s to list of type %s", + data.typeName(), TQT_DBusData::typeName(d->type)); + } + else if (hasContainerItemType()) + { + TQCString ourSignature = d->containerItem.buildDBusSignature(); + TQCString dataSignature = data.buildDBusSignature(); + + if (ourSignature != dataSignature) + { + tqWarning("TQT_DBusDataList: trying to add data with signature %s " + "to list with item signature %s", + dataSignature.data(), ourSignature.data()); + } + else + d->list << data; + } + else + d->list << data; + + return *this; +} + +TQValueList<TQT_DBusData> TQT_DBusDataList::toTQValueList() const +{ + return d->list; +} + +TQStringList TQT_DBusDataList::toTQStringList(bool* ok) const +{ + if (d->type != TQT_DBusData::String) + { + if (ok != 0) *ok = false; + return TQStringList(); + } + + TQStringList result; + + TQValueList<TQT_DBusData>::const_iterator it = d->list.begin(); + TQValueList<TQT_DBusData>::const_iterator endIt = d->list.end(); + for (; it != endIt; ++it) + { + result << (*it).toString(); + } + + if (ok != 0) *ok = true; + + return result; +} + +TQValueList<bool> TQT_DBusDataList::toBoolList(bool* ok) const +{ + if (d->type != TQT_DBusData::Bool) + { + if (ok != 0) *ok = false; + return TQValueList<bool>(); + } + + TQValueList<bool> result; + + TQValueList<TQT_DBusData>::const_iterator it = d->list.begin(); + TQValueList<TQT_DBusData>::const_iterator endIt = d->list.end(); + for (; it != endIt; ++it) + { + result << (*it).toBool(); + } + + if (ok != 0) *ok = true; + + return result; +} + +TQValueList<TQ_UINT8> TQT_DBusDataList::toByteList(bool* ok) const +{ + if (d->type != TQT_DBusData::Byte) + { + if (ok != 0) *ok = false; + return TQValueList<TQ_UINT8>(); + } + + TQValueList<TQ_UINT8> result; + + TQValueList<TQT_DBusData>::const_iterator it = d->list.begin(); + TQValueList<TQT_DBusData>::const_iterator endIt = d->list.end(); + for (; it != endIt; ++it) + { + result << (*it).toByte(); + } + + if (ok != 0) *ok = true; + + return result; +} + +TQValueList<TQ_INT16> TQT_DBusDataList::toInt16List(bool* ok) const +{ + if (d->type != TQT_DBusData::Int16) + { + if (ok != 0) *ok = false; + return TQValueList<TQ_INT16>(); + } + + TQValueList<TQ_INT16> result; + + TQValueList<TQT_DBusData>::const_iterator it = d->list.begin(); + TQValueList<TQT_DBusData>::const_iterator endIt = d->list.end(); + for (; it != endIt; ++it) + { + result << (*it).toInt16(); + } + + if (ok != 0) *ok = true; + + return result; +} + +TQValueList<TQ_UINT16> TQT_DBusDataList::toUInt16List(bool* ok) const +{ + if (d->type != TQT_DBusData::UInt16) + { + if (ok != 0) *ok = false; + return TQValueList<TQ_UINT16>(); + } + + TQValueList<TQ_UINT16> result; + + TQValueList<TQT_DBusData>::const_iterator it = d->list.begin(); + TQValueList<TQT_DBusData>::const_iterator endIt = d->list.end(); + for (; it != endIt; ++it) + { + result << (*it).toUInt16(); + } + + if (ok != 0) *ok = true; + + return result; +} + +TQValueList<TQ_INT32> TQT_DBusDataList::toInt32List(bool* ok) const +{ + if (d->type != TQT_DBusData::Int32) + { + if (ok != 0) *ok = false; + return TQValueList<TQ_INT32>(); + } + + TQValueList<TQ_INT32> result; + + TQValueList<TQT_DBusData>::const_iterator it = d->list.begin(); + TQValueList<TQT_DBusData>::const_iterator endIt = d->list.end(); + for (; it != endIt; ++it) + { + result << (*it).toInt32(); + } + + if (ok != 0) *ok = true; + + return result; +} + +TQValueList<TQ_UINT32> TQT_DBusDataList::toUInt32List(bool* ok) const +{ + if (d->type != TQT_DBusData::UInt32) + { + if (ok != 0) *ok = false; + return TQValueList<TQ_UINT32>(); + } + + TQValueList<TQ_UINT32> result; + + TQValueList<TQT_DBusData>::const_iterator it = d->list.begin(); + TQValueList<TQT_DBusData>::const_iterator endIt = d->list.end(); + for (; it != endIt; ++it) + { + result << (*it).toUInt32(); + } + + if (ok != 0) *ok = true; + + return result; +} + +TQValueList<TQ_INT64> TQT_DBusDataList::toInt64List(bool* ok) const +{ + if (d->type != TQT_DBusData::Int64) + { + if (ok != 0) *ok = false; + return TQValueList<TQ_INT64>(); + } + + TQValueList<TQ_INT64> result; + + TQValueList<TQT_DBusData>::const_iterator it = d->list.begin(); + TQValueList<TQT_DBusData>::const_iterator endIt = d->list.end(); + for (; it != endIt; ++it) + { + result << (*it).toInt64(); + } + + if (ok != 0) *ok = true; + + return result; +} + +TQValueList<TQ_UINT64> TQT_DBusDataList::toUInt64List(bool* ok) const +{ + if (d->type != TQT_DBusData::UInt64) + { + if (ok != 0) *ok = false; + return TQValueList<TQ_UINT64>(); + } + + TQValueList<TQ_UINT64> result; + + TQValueList<TQT_DBusData>::const_iterator it = d->list.begin(); + TQValueList<TQT_DBusData>::const_iterator endIt = d->list.end(); + for (; it != endIt; ++it) + { + result << (*it).toUInt64(); + } + + if (ok != 0) *ok = true; + + return result; +} + +TQValueList<double> TQT_DBusDataList::toDoubleList(bool* ok) const +{ + if (d->type != TQT_DBusData::Double) + { + if (ok != 0) *ok = false; + return TQValueList<double>(); + } + + TQValueList<double> result; + + TQValueList<TQT_DBusData>::const_iterator it = d->list.begin(); + TQValueList<TQT_DBusData>::const_iterator endIt = d->list.end(); + for (; it != endIt; ++it) + { + result << (*it).toDouble(); + } + + if (ok != 0) *ok = true; + + return result; +} + +TQValueList<TQString> TQT_DBusDataList::toStringList(bool* ok) const +{ + return toTQStringList(ok); +} + +TQValueList<TQT_DBusObjectPath> TQT_DBusDataList::toObjectPathList(bool* ok) const +{ + if (d->type != TQT_DBusData::ObjectPath) + { + if (ok != 0) *ok = false; + return TQValueList<TQT_DBusObjectPath>(); + } + + TQValueList<TQT_DBusObjectPath> result; + + TQValueList<TQT_DBusData>::const_iterator it = d->list.begin(); + TQValueList<TQT_DBusData>::const_iterator endIt = d->list.end(); + for (; it != endIt; ++it) + { + result << (*it).toObjectPath(); + } + + if (ok != 0) *ok = true; + + return result; +} + +TQValueList<TQT_DBusUnixFd> TQT_DBusDataList::toUnixFdList(bool* ok) const +{ + if (d->type != TQT_DBusData::UnixFd) + { + if (ok != 0) *ok = false; + return TQValueList<TQT_DBusUnixFd>(); + } + + TQValueList<TQT_DBusUnixFd> result; + + TQValueList<TQT_DBusData>::const_iterator it = d->list.begin(); + TQValueList<TQT_DBusData>::const_iterator endIt = d->list.end(); + for (; it != endIt; ++it) + { + result << (*it).toUnixFd(); + } + + if (ok != 0) *ok = true; + + return result; +} + +TQValueList<TQT_DBusVariant> TQT_DBusDataList::toVariantList(bool* ok) const +{ + if (d->type != TQT_DBusData::Variant) + { + if (ok != 0) *ok = false; + return TQValueList<TQT_DBusVariant>(); + } + + TQValueList<TQT_DBusVariant> result; + + TQValueList<TQT_DBusData>::const_iterator it = d->list.begin(); + TQValueList<TQT_DBusData>::const_iterator endIt = d->list.end(); + for (; it != endIt; ++it) + { + result << (*it).toVariant(); + } + + if (ok != 0) *ok = true; + + return result; +} diff --git a/src/tqdbusdatalist.h b/src/tqdbusdatalist.h new file mode 100644 index 0000000..bd0b467 --- /dev/null +++ b/src/tqdbusdatalist.h @@ -0,0 +1,758 @@ +/* qdbusdatalist.h list of DBUS data transport type + * + * Copyright (C) 2007 Kevin Krammer <kevin.krammer@gmx.at> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#ifndef TQDBUSDATALIST_H +#define TQDBUSDATALIST_H + +#include "tqdbusdata.h" + +template <typename T> class TQValueList; +class TQT_DBusObjectPath; +class TQT_DBusVariant; +class TQT_DBusUnixFd; +class TQString; +class TQStringList; + +/** + * @brief Class to transport lists of D-Bus data types + * + * \note while the D-Bus data type is actually called @c array this bindings + * use the term @c list since the behavior and characteristics of the + * implementation is more list like. + * + * There are basically two ways to create TQT_DBusDataList objects: + * - non-empty from content + * - empty by specifying the desired element type + * + * Example for creating a filled list from content + * @code + * TQValueList<TQ_INT16> intList; + * list << 2 << 3 << 5 << 7; + * + * TQT_DBusDataList dbusList(intList); + * TQT_DBusData data = TQT_DBusData::fromList(dbusList); + * + * // or even shorter, using implicit conversion + * TQT_DBusData other = TQT_DBusData::fromList(intList); + * @endcode + * + * Example for creating an empty list + * @code + * // empty list for a simple type + * TQT_DBusDataList list(TQT_DBusData::Double); + * + * // empty list for a list of string lists + * TQT_DBusData elementType = TQT_DBusData::fromList(TQT_DBusDataList(TQT_DBusData::String)); + * TQT_DBusDataList outerList(elementType); + * @endcode + * + * @see TQT_DBusDataMap + */ +class TQDBUS_EXPORT TQT_DBusDataList +{ +public: + /** + * @brief Creates an empty and invalid list + * + * @see TQT_DBusData::Invalid + */ + TQT_DBusDataList(); + + /** + * @brief Creates an empty list with the given simple type for elements + * + * The given type has be one of the non-container types, i.e. any other than + * TQT_DBusData::Map, TQT_DBusData::List or TQT_DBusData::Struct + * + * For creating a list with elements which are containers themselves, use + * TQT_DBusDataList(const TQT_DBusData&); + * + * @param simpleItemType the type of the elements in the new list + */ + explicit TQT_DBusDataList(TQT_DBusData::Type simpleItemType); + + /** + * @brief Creates an empty list with the given container type for elements + * + * For creating a list with simple elements you can also use + * TQT_DBusDataList(TQT_DBusData::Type); + * + * @param containerItemType the type of the elements in the new list + * + * @see hasContainerItemType() + */ + explicit TQT_DBusDataList(const TQT_DBusData& containerItemType); + + /** + * @brief Creates a list from the given @p other list + * + * This behaves basically like copying a TQValueList through its copy + * constructor, i.e. no value are actually copied at this time. + * + * @param other the other list object to copy from + */ + TQT_DBusDataList(const TQT_DBusDataList& other); + + /** + * @brief Creates a list from the given TQValueList of TQT_DBusData objects + * + * If the @p other list is empty, this will behave like TQT_DBusDataList(), + * i.e. create an empty and invalid list object. + * + * Type information for the list object, i.e. element type and, if applicable, + * container item type, will be derived from the @p other list's elements. + * + * \warning if the elements of the @p other list do not all have the same + * type, the list object will also be empty and invalid + * + * @param other the TQValueList of TQT_DBusData objects to copy from + * + * @see toTQValueList() + */ + TQT_DBusDataList(const TQValueList<TQT_DBusData>& other); + + /** + * @brief Creates a list from the given TQValueList of boolean values + * + * Type information for the list object will be set to TQT_DBusData::Bool + * also when the @p other list is empty, i.e. this allows to create an + * empty but valid list object, comparable to using + * TQT_DBusDataList(TQT_DBusData::Type) with TQT_DBusData::Bool + * + * @param other the TQValueList of boolean values to copy from + * + * @see toBoolList() + */ + TQT_DBusDataList(const TQValueList<bool>& other); + + /** + * @brief Creates a list from the given TQValueList of byte (unsigned char) values + * + * Type information for the list object will be set to TQT_DBusData::Byte + * also when the @p other list is empty, i.e. this allows to create an + * empty but valid list object, comparable to using + * TQT_DBusDataList(TQT_DBusData::Type) with TQT_DBusData::Byte + * + * @param other the TQValueList of byte (unsigned char) values to copy from + * + * @see toByteList() + */ + TQT_DBusDataList(const TQValueList<TQ_UINT8>& other); + + /** + * @brief Creates a list from the given TQValueList of signed 16-bit integer values + * + * Type information for the list object will be set to TQT_DBusData::Int16 + * also when the @p other list is empty, i.e. this allows to create an + * empty but valid list object, comparable to using + * TQT_DBusDataList(TQT_DBusData::Type) with TQT_DBusData::Int16 + * + * @param other the TQValueList of signed 16-bit integer values to copy from + * + * @see toInt16List() + */ + TQT_DBusDataList(const TQValueList<TQ_INT16>& other); + + /** + * @brief Creates a list from the given TQValueList of unsigned 16-bit integer values + * + * Type information for the list object will be set to TQT_DBusData::UInt16 + * also when the @p other list is empty, i.e. this allows to create an + * empty but valid list object, comparable to using + * TQT_DBusDataList(TQT_DBusData::Type) with TQT_DBusData::UInt16 + * + * @param other the TQValueList of unsigned 16-bit integer values to copy from + * + * @see toUInt16List() + */ + TQT_DBusDataList(const TQValueList<TQ_UINT16>& other); + + /** + * @brief Creates a list from the given TQValueList of signed 32-bit integer values + * + * Type information for the list object will be set to TQT_DBusData::Int32 + * also when the @p other list is empty, i.e. this allows to create an + * empty but valid list object, comparable to using + * TQT_DBusDataList(TQT_DBusData::Type) with TQT_DBusData::Int32 + * + * @param other the TQValueList of signed 32-bit integer values to copy from + * + * @see toInt32List() + */ + TQT_DBusDataList(const TQValueList<TQ_INT32>& other); + + /** + * @brief Creates a list from the given TQValueList of unsigned 32-bit integer values + * + * Type information for the list object will be set to TQT_DBusData::UInt16 + * also when the @p other list is empty, i.e. this allows to create an + * empty but valid list object, comparable to using + * TQT_DBusDataList(TQT_DBusData::Type) with TQT_DBusData::UInt32 + * + * @param other the TQValueList of unsigned 32-bit integer values to copy from + * + * @see toUInt32List() + */ + TQT_DBusDataList(const TQValueList<TQ_UINT32>& other); + + /** + * @brief Creates a list from the given TQValueList of signed 64-bit integer values + * + * Type information for the list object will be set to TQT_DBusData::Int64 + * also when the @p other list is empty, i.e. this allows to create an + * empty but valid list object, comparable to using + * TQT_DBusDataList(TQT_DBusData::Type) with TQT_DBusData::Int64 + * + * @param other the TQValueList of signed 64-bit integer values to copy from + * + * @see toInt64List() + */ + TQT_DBusDataList(const TQValueList<TQ_INT64>& other); + + /** + * @brief Creates a list from the given TQValueList of unsigned 64-bit integer values + * + * Type information for the list object will be set to TQT_DBusData::UInt64 + * also when the @p other list is empty, i.e. this allows to create an + * empty but valid list object, comparable to using + * TQT_DBusDataList(TQT_DBusData::Type) with TQT_DBusData::UInt64 + * + * @param other the TQValueList of unsigned 64-bit integer values to copy from + * + * @see toUInt64List() + */ + TQT_DBusDataList(const TQValueList<TQ_UINT64>& other); + + /** + * @brief Creates a list from the given TQValueList of double values + * + * Type information for the list object will be set to TQT_DBusData::Double + * also when the @p other list is empty, i.e. this allows to create an + * empty but valid list object, comparable to using + * TQT_DBusDataList(TQT_DBusData::Type) with TQT_DBusData::Double + * + * @param other the TQValueList of double values to copy from + * + * @see toDoubleList() + */ + TQT_DBusDataList(const TQValueList<double>& other); + + /** + * @brief Creates a list from the given TQValueList of TQT_DBusVariant values + * + * Type information for the list object will be set to TQT_DBusData::Variant + * also when the @p other list is empty, i.e. this allows to create an + * empty but valid list object, comparable to using + * TQT_DBusDataList(TQT_DBusData::Type) with TQT_DBusData::Variant + * + * @param other the TQValueList of variant values to copy from + * + * @see toVariantList() + */ + TQT_DBusDataList(const TQValueList<TQT_DBusVariant>& other); + + /** + * @brief Creates a list from the given TQStringList's values + * + * Type information for the list object will be set to TQT_DBusData::String + * also when the @p other list is empty, i.e. this allows to create an + * empty but valid list object, comparable to using + * TQT_DBusDataList(TQT_DBusData::Type) with TQT_DBusData::String + * + * @param other the TQStringList to copy from + * + * @see toTQStringList() + */ + TQT_DBusDataList(const TQStringList& other); + + /** + * @brief Creates a list from the given TQValueList of object path values + * + * Type information for the list object will be set to TQT_DBusData::ObjectPath + * also when the @p other list is empty, i.e. this allows to create an + * empty but valid list object, comparable to using + * TQT_DBusDataList(TQT_DBusData::Type) with TQT_DBusData::ObjectPath + * + * @param other the TQValueList of object path values to copy from + * + * @see toObjectPathList() + */ + TQT_DBusDataList(const TQValueList<TQT_DBusObjectPath>& other); + + /** + * @brief Creates a list from the given TQValueList of unix file handle values + * + * Type information for the list object will be set to TQT_DBusData::UnixFd + * also when the @p other list is empty, i.e. this allows to create an + * empty but valid list object, comparable to using + * TQT_DBusDataList(TQT_DBusData::Type) with TQT_DBusData::UnixFd + * + * @param other the TQValueList of unix file handle values to copy from + * + * @see toUnixFdList() + */ + TQT_DBusDataList(const TQValueList<TQT_DBusUnixFd>& other); + + /** + * @brief Destroys the list object + */ + ~TQT_DBusDataList(); + + /** + * @brief Copies from the given @p other list + * + * This behaves basically like copying a TQValueList through its assignment + * operator, i.e. no value are actually copied at this time. + * + * @param other the other list object to copy from + * + * @return a reference to this list object + */ + TQT_DBusDataList& operator=(const TQT_DBusDataList& other); + + /** + * @brief Copies from the given @p other list + * + * This behaves basically like copying a TQValueList through its assignment + * operator, i.e. no value are actually copied at this time. + * + * \warning the elements of the given @p other list have to be of the same + * type. If they aren't this list's content will cleared and the + * type will be set to TQT_DBusData::Invalid + * + * @param other the other list object to copy from + * + * @return a reference to this list object + */ + TQT_DBusDataList& operator=(const TQValueList<TQT_DBusData>& other); + + /** + * @brief Copies from the given @p other list + * + * Convenience overload as TQStringList is a very common data type in + * TQt and D-Bus methods also use "arrays of strings" quite often. + * + * The list object's type will be set to TQT_DBusData::String. If the object + * previously had a container as its element type, this will be reset, i.e. + * hasContainerItemType() will return @c false + * + * @param other the stringlist to copy from + * + * @return a reference to this list object + */ + TQT_DBusDataList& operator=(const TQStringList& other); + + /** + * @brief Returns the element type of the list object + * + * @return one of the values of the TQT_DBusData#Type enum + * + * @see hasContainerItemType() + * @see containerItemType() + */ + TQT_DBusData::Type type() const; + + /** + * @brief Checks whether the element type is a data container itself + * + * If the elements of the list are containers as well, this will return + * @c true + * In this case containerItemType() will return a prototype for such a + * container. + * + * @return @c true if the element type is either TQT_DBusData::Map, + * TQT_DBusData::List or TQT_DBusData::Struct, otherwise @c false + * + * @see TQT_DBusDataList(const TQT_DBusData&) + */ + bool hasContainerItemType() const; + + /** + * @brief Returns a container prototype for the list's element type + * + * Lists which have containers as their elements, i.e. hasContainerItemType() + * returns @c true this will actually specify the details for the use + * container, i.e. the returned data object can be queried for type and + * possible further subtypes. + * + * @return a data object detailing the element type or an invalid data object + * if the list does not have a container as its element type + * + * @see TQT_DBusDataList(const TQT_DBusData&); + * @see type() + * @see TQT_DBusData::Invalid + */ + TQT_DBusData containerItemType() const; + + /** + * @brief Checks whether this list object has a valid element type + * + * This is equal to checking type() for not being TQT_DBusData::Invalid + * + * @return @c true if the list object is valid, otherwise @c false + */ + inline bool isValid() const { return type() != TQT_DBusData::Invalid; } + + /** + * @brief Checks whether this list object has any elements + * + * @return @c true if there are no elements in this list, otherwise @c false + * + * @see count() + */ + bool isEmpty() const; + + /** + * @brief Returns the number of elements of this list object + * + * @return the number of elements + * + * @see isEmpty() + */ + uint count() const; + + /** + * @brief Checks whether the given @p other list is equal to this one + * + * Two lists are considered equal when they have the same type (and same + * container item type if the have one) and the element lists are equal + * as well. + * + * @param other the other list object to compare with + * + * @return @c true if the lists are equal, otherwise @c false + * + * @see TQT_DBusData::operator==() + */ + bool operator==(const TQT_DBusDataList& other) const; + + /** + * @brief Checks whether the given @p other list is different from this one + * + * Two lists are considered different when they have the different type (or + * different container item type if the have one) or the element lists are + * equal are different. + * + * @param other the other list object to compare with + * + * @return @c true if the lists are different, otherwise @c false + * + * @see TQT_DBusData::operator!=() + */ + bool operator!=(const TQT_DBusDataList& other) const; + + /** + * @brief Clears the list + * + * Type and, if applicable, container element type will stay untouched. + */ + void clear(); + + /** + * @brief Appends a given value to the list + * + * Basically works like the respective TQValueList operator, but checks if + * type of the new value matches the type of the list. + * Lists that are invalid will accept any new type and will then be + * typed accordingly. + * + * If @p data is invalid itself, it will not be appended at any time. + * + * \note the more common use case is to work with a TQValueList and then + * use the respective constructor to create the TQT_DBusDataList object + * + * @param data the data item to append to the list + * + * @return a reference to this list object + */ + TQT_DBusDataList& operator<<(const TQT_DBusData& data); + + /** + * @brief Converts the list object into a TQValueList with TQT_DBusData elements + * + * @return the values of the list object as a TQValueList + */ + TQValueList<TQT_DBusData> toTQValueList() const; + + /** + * @brief Tries to get the list object's elements as a TQStringList + * + * This is a convenience overload for the case when the list is of + * type TQT_DBusData::String. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type + * TQT_DBusData::String) + * + * @return a TQStringList containing the list object's string elements or + * an empty list when converting fails + * + * @see toStringList() + * @see TQT_DBusData::toString() + */ + TQStringList toTQStringList(bool* ok = 0) const; + + /** + * @brief Tries to get the list object's elements as a TQValueList of bool + * + * This is a convenience overload for the case when the list is of + * type TQT_DBusData::Bool. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type + * TQT_DBusData::Bool) + * + * @return a TQValueList of bool containing the list object's boolean + * elements or an empty list when converting fails + * + * @see TQT_DBusData::toBool() + */ + TQValueList<bool> toBoolList(bool* ok = 0) const; + + /** + * @brief Tries to get the list object's elements as a TQValueList of TQ_UINT8 + * + * This is a convenience overload for the case when the list is of + * type TQT_DBusData::Byte. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type + * TQT_DBusData::Byte) + * + * @return a TQValueList of TQ_UINT8 containing the list object's byte + * elements or an empty list when converting fails + * + * @see TQT_DBusData::toByte() + */ + TQValueList<TQ_UINT8> toByteList(bool* ok = 0) const; + + /** + * @brief Tries to get the list object's elements as a TQValueList of TQ_INT16 + * + * This is a convenience overload for the case when the list is of + * type TQT_DBusData::Int16. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type + * TQT_DBusData::Int16) + * + * @return a TQValueList of TQ_INT16 containing the list object's + * signed 16-bit integer elements or an empty list when converting + * fails + * + * @see TQT_DBusData::toInt16() + */ + TQValueList<TQ_INT16> toInt16List(bool* ok = 0) const; + + /** + * @brief Tries to get the list object's elements as a TQValueList of TQ_UINT16 + * + * This is a convenience overload for the case when the list is of + * type TQT_DBusData::UInt16. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type + * TQT_DBusData::UInt16) + * + * @return a TQValueList of TQ_UINT16 containing the list object's + * unsigned 16-bit integer elements or an empty list when converting + * fails + * + * @see TQT_DBusData::toUInt16() + */ + TQValueList<TQ_UINT16> toUInt16List(bool* ok = 0) const; + + /** + * @brief Tries to get the list object's elements as a TQValueList of TQ_INT32 + * + * This is a convenience overload for the case when the list is of + * type TQT_DBusData::Int32. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type + * TQT_DBusData::Int32) + * + * @return a TQValueList of TQ_INT32 containing the list object's + * signed 32-bit integer elements or an empty list when converting + * fails + * + * @see TQT_DBusData::toInt32() + */ + TQValueList<TQ_INT32> toInt32List(bool* ok = 0) const; + + /** + * @brief Tries to get the list object's elements as a TQValueList of TQ_UINT32 + * + * This is a convenience overload for the case when the list is of + * type TQT_DBusData::UInt32. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type + * TQT_DBusData::UInt32) + * + * @return a TQValueList of TQ_UINT32 containing the list object's + * unsigned 32-bit integer elements or an empty list when converting + * fails + * + * @see TQT_DBusData::toUInt32() + */ + TQValueList<TQ_UINT32> toUInt32List(bool* ok = 0) const; + + /** + * @brief Tries to get the list object's elements as a TQValueList of TQ_INT64 + * + * This is a convenience overload for the case when the list is of + * type TQT_DBusData::Int64. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type + * TQT_DBusData::Int64) + * + * @return a TQValueList of TQ_INT64 containing the list object's + * signed 64-bit integer elements or an empty list when converting + * fails + * + * @see TQT_DBusData::toInt64() + */ + TQValueList<TQ_INT64> toInt64List(bool* ok = 0) const; + + /** + * @brief Tries to get the list object's elements as a TQValueList of TQ_UINT64 + * + * This is a convenience overload for the case when the list is of + * type TQT_DBusData::UInt64. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type + * TQT_DBusData::UInt64) + * + * @return a TQValueList of TQ_UINT64 containing the list object's + * unsigned 64-bit integer elements or an empty list when converting + * fails + * + * @see TQT_DBusData::toUInt64() + */ + TQValueList<TQ_UINT64> toUInt64List(bool* ok = 0) const; + + /** + * @brief Tries to get the list object's elements as a TQValueList of double + * + * This is a convenience overload for the case when the list is of + * type TQT_DBusData::Double. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type + * TQT_DBusData::Double) + * + * @return a TQValueList of double containing the list object's double + * elements or an empty list when converting fails + * + * @see TQT_DBusData::toDouble() + */ + TQValueList<double> toDoubleList(bool* ok = 0) const; + + /** + * @brief Tries to get the list object's elements as a TQValueList of TQString + * + * This is a convenience overload for the case when the list is of + * type TQT_DBusData::String, see also toTQStringList(). + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type + * TQT_DBusData::String) + * + * @return a TQValueList of TQString containing the list object's string + * elements or an empty list when converting fails + * + * @see TQT_DBusData::toString() + */ + TQValueList<TQString> toStringList(bool* ok = 0) const; + + /** + * @brief Tries to get the list object's elements as a TQValueList of object paths + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type + * TQT_DBusData::ObjectPath) + * + * @return a TQValueList of object paths containing the list object's object path + * elements or an empty list when converting fails + * + * @see TQT_DBusData::toObjectPath() + */ + TQValueList<TQT_DBusObjectPath> toObjectPathList(bool* ok = 0) const; + + /** + * @brief Tries to get the list object's elements as a TQValueList of TQT_DBusVariant + * + * This is a convenience overload for the case when the list is of + * type TQT_DBusData::Variant. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type + * TQT_DBusData::Variant) + * + * @return a TQValueList of TQT_DBusVariant containing the list object's + * TQT_DBusVariant elements or an empty list when converting fails + * + * @see TQT_DBusData::toVariant() + */ + TQValueList<TQT_DBusVariant> toVariantList(bool* ok = 0) const; + + /** + * @brief Tries to get the list object's elements as a TQValueList of TQT_DBusUnixFd + * + * This is a convenience overload for the case when the list is of + * type TQT_DBusData::UnixFd. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of type + * TQT_DBusData::UnixFd) + * + * @return a TQValueList of TQT_DBusUnixFd containing the list object's + * TQT_DBusUnixFd elements or an empty list when converting fails + * + * @see TQT_DBusData::toUnixFd() + */ + TQValueList<TQT_DBusUnixFd> toUnixFdList(bool* ok = 0) const; + +private: + class Private; + Private* d; +}; + +#endif diff --git a/src/tqdbusdatamap.h b/src/tqdbusdatamap.h new file mode 100644 index 0000000..ecb06d2 --- /dev/null +++ b/src/tqdbusdatamap.h @@ -0,0 +1,1281 @@ +/* qdbusdatamap.h DBUS data mapping transport type + * + * Copyright (C) 2007 Kevin Krammer <kevin.krammer@gmx.at> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#ifndef TQDBUSDATAMAP_H +#define TQDBUSDATAMAP_H + +#include "tqdbusmacros.h" +#include <tqmap.h> + +class TQT_DBusData; +class TQT_DBusObjectPath; +class TQT_DBusUnixFd; +class TQT_DBusVariant; + +/** + * @brief Class to transport maps of D-Bus data types + * + * \note while the D-Bus data type is actually called @c dict this bindings + * use the term @c map since TQT_DBusDataMap is essentially a TQMap + * + * There are basically two ways to create TQT_DBusDataMap objects: + * - non-empty from content + * - empty by specifying the desired element type + * + * Example for creating a filled map from content + * @code + * TQMap<TQ_INT16, TQString> intToStringMap; + * map.insert(2, "two"); + * map.insert(3, "three"); + * map.insert(5, "five"); + * map.insert(7, "seven"); + * + * TQT_DBusDataMap<TQ_INT16> dbusMap(intToStringMap); + * TQT_DBusData data = TQT_DBusData::fromInt16KeyMap(dbusMap); + * + * // or even shorter, using implicit conversion + * TQT_DBusData other = TQT_DBusData::fromInt16KeyMap(intList); + * @endcode + * + * Example for creating an empty map + * @code + * // empty map for a simple type, mapping from TQString to double + * TQT_DBusDataMap<TQString> list(TQT_DBusData::Double); + * + * // empty map for value type string lists + * TQT_DBusData valueType = TQT_DBusData::fromList(TQT_DBusDataList(TQT_DBusData::String)); + * TQT_DBusDataMap<TQString> map(valueType); + * @endcode + * + * @see TQT_DBusDataList + */ +template <typename T> +class TQDBUS_EXPORT TQT_DBusDataMap : private TQMap<T, TQT_DBusData> +{ + friend class TQT_DBusData; + +public: + /** + * Constant iterator. A TQMapConstIterator with value type specified + * as TQT_DBusData + */ + typedef TQMapConstIterator<T, TQT_DBusData> const_iterator; + + /** + * @brief Creates an empty and invalid map + * + * @see TQT_DBusData::Invalid + */ + TQT_DBusDataMap<T>() + : TQMap<T, TQT_DBusData>(), m_valueType(TQT_DBusData::Invalid) {} + + /** + * @brief Creates an empty map with the given simple type for values + * + * The given type has be one of the non-container types, i.e. any other than + * TQT_DBusData::Map, TQT_DBusData::List or TQT_DBusData::Struct + * + * For creating a map with elements which are containers themselves, use + * TQT_DBusDataMap<T>(const TQT_DBusData&); + * + * @param simpleValueType the type of the values in the new map + */ + explicit TQT_DBusDataMap<T>(TQT_DBusData::Type simpleValueType) + : TQMap<T, TQT_DBusData>(), m_valueType(simpleValueType) {} + + /** + * @brief Creates an empty map with the given container type for values + * + * For creating a map with simple values you can also use + * TQT_DBusDataMap<T>(TQT_DBusData::Type); + * + * @param containerValueType the type of the values in the new map + * + * @see hasContainerValueType() + */ + explicit TQT_DBusDataMap<T>(const TQT_DBusData& containerValueType) + : TQMap<T, TQT_DBusData>(), m_valueType(containerValueType.type()) + { + if (hasContainerValueType()) m_containerValueType = containerValueType; + } + + /** + * @brief Creates a map from the given @p other map + * + * This behaves basically like copying a TQMap through its copy + * constructor, i.e. no value are actually copied at this time. + * + * @param other the other map object to copy from + */ + TQT_DBusDataMap<T>(const TQT_DBusDataMap<T>& other) + : TQMap<T, TQT_DBusData>(other), m_valueType(other.m_valueType), + m_containerValueType(other.m_containerValueType) {} + + /** + * @brief Creates a map from the given TQMap of TQT_DBusData objects + * + * If the @p other map is empty, this will behave like TQT_DBusDataMap<T>(), + * i.e. create an empty and invalid map object. + * + * Type information for the map object, i.e. value type and, if applicable, + * container value type, will be derived from the @p other map's elements. + * + * \warning if the values of the @p other map do not all have the same + * type, the map object will also be empty and invalid + * + * @param other the TQMap of TQT_DBusData objects to copy from + * + * @see toTQMap() + */ + TQT_DBusDataMap<T>(const TQMap<T, TQT_DBusData>& other) + : TQMap<T, TQT_DBusData>(other), m_valueType(TQT_DBusData::Invalid) + { + const_iterator it = begin(); + if (it == end()) return; + + m_valueType = (*it).type(); + + TQCString containerSignature; + if (hasContainerValueType()) + { + m_containerValueType = it.data(); + containerSignature = m_containerValueType.buildDBusSignature(); + } + + for (++it; it != end(); ++it) + { + if ((*it).type() != m_valueType) + { + m_valueType = TQT_DBusData::Invalid; + m_containerValueType = TQT_DBusData(); + + clear(); + return; + } + else if (hasContainerValueType()) + { + if (it.data().buildDBusSignature() != containerSignature) + { + m_valueType = TQT_DBusData::Invalid; + m_containerValueType = TQT_DBusData(); + + clear(); + return; + } + } + } + } + + /** + * @brief Creates a list from the given TQMap of boolean values + * + * Type information for the map object will be set to TQT_DBusData::Bool + * also when the @p other map is empty, i.e. this allows to create an + * empty but valid map object, comparable to using + * TQT_DBusDataMap<T>(TQT_DBusData::Type) with TQT_DBusData::Bool + * + * @param other the TQMap of boolean values to copy from + * + * @see toBoolMap() + */ + TQT_DBusDataMap<T>(const TQMap<T, bool>& other) + : TQMap<T, TQT_DBusData>(), m_valueType(TQT_DBusData::Bool) + { + typename TQMap<T, bool>::const_iterator it = other.begin(); + typename TQMap<T, bool>::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + insert(it.key(), TQT_DBusData::fromBool(it.data())); + } + } + + /** + * @brief Creates a map from the given TQMap of byte (unsigned char) values + * + * Type information for the map object will be set to TQT_DBusData::Byte + * also when the @p other map is empty, i.e. this allows to create an + * empty but valid map object, comparable to using + * TQT_DBusDataMap<T>(TQT_DBusData::Type) with TQT_DBusData::Byte + * + * @param other the TQMap of byte (unsigned char) values to copy from + * + * @see toByteMap() + */ + TQT_DBusDataMap<T>(const TQMap<T, TQ_UINT8>& other) + : TQMap<T, TQT_DBusData>(), m_valueType(TQT_DBusData::Byte) + { + typename TQMap<T, TQ_UINT8>::const_iterator it = other.begin(); + typename TQMap<T, TQ_UINT8>::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + insert(it.key(), TQT_DBusData::fromByte(it.data())); + } + } + + /** + * @brief Creates a map from the given TQMap of signed 16-bit integer values + * + * Type information for the map object will be set to TQT_DBusData::Int16 + * also when the @p other map is empty, i.e. this allows to create an + * empty but valid map object, comparable to using + * TQT_DBusDataMap<T>(TQT_DBusData::Type) with TQT_DBusData::Int16 + * + * @param other the TQMap of signed 16-bit integer values to copy from + * + * @see toInt16Map() + */ + TQT_DBusDataMap<T>(const TQMap<T, TQ_INT16>& other) + : TQMap<T, TQT_DBusData>(), m_valueType(TQT_DBusData::Int16) + { + typename TQMap<T, TQ_INT16>::const_iterator it = other.begin(); + typename TQMap<T, TQ_INT16>::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + insert(it.key(), TQT_DBusData::fromInt16(it.data())); + } + } + + /** + * @brief Creates a map from the given TQMap of unsigned 16-bit integer values + * + * Type information for the map object will be set to TQT_DBusData::UInt16 + * also when the @p other map is empty, i.e. this allows to create an + * empty but valid map object, comparable to using + * TQT_DBusDataMap<T>(TQT_DBusData::Type) with TQT_DBusData::UInt16 + * + * @param other the TQMap of unsigned 16-bit integer values to copy from + * + * @see toUInt16Map() + */ + TQT_DBusDataMap<T>(const TQMap<T, TQ_UINT16>& other) + : TQMap<T, TQT_DBusData>(), m_valueType(TQT_DBusData::UInt16) + { + typename TQMap<T, TQ_UINT16>::const_iterator it = other.begin(); + typename TQMap<T, TQ_UINT16>::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + insert(it.key(), TQT_DBusData::fromUInt16(it.data())); + } + } + + /** + * @brief Creates a map from the given TQMap of signed 32-bit integer values + * + * Type information for the map object will be set to TQT_DBusData::Int32 + * also when the @p other map is empty, i.e. this allows to create an + * empty but valid map object, comparable to using + * TQT_DBusDataMap<T>(TQT_DBusData::Type) with TQT_DBusData::Int32 + * + * @param other the TQMap of signed 32-bit integer values to copy from + * + * @see toInt32Map() + */ + TQT_DBusDataMap<T>(const TQMap<T, TQ_INT32>& other) + : TQMap<T, TQT_DBusData>(), m_valueType(TQT_DBusData::Int32) + { + typename TQMap<T, TQ_INT32>::const_iterator it = other.begin(); + typename TQMap<T, TQ_INT32>::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + insert(it.key(), TQT_DBusData::fromInt32(it.data())); + } + } + + /** + * @brief Creates a map from the given TQMap of unsigned 32-bit integer values + * + * Type information for the map object will be set to TQT_DBusData::UInt16 + * also when the @p other map is empty, i.e. this allows to create an + * empty but valid map object, comparable to using + * TQT_DBusDataMap<T>(TQT_DBusData::Type) with TQT_DBusData::UInt32 + * + * @param other the TQMap of unsigned 32-bit integer values to copy from + * + * @see toUInt32Map() + */ + TQT_DBusDataMap<T>(const TQMap<T, TQ_UINT32>& other) + : TQMap<T, TQT_DBusData>(), m_valueType(TQT_DBusData::UInt32) + { + typename TQMap<T, TQ_UINT32>::const_iterator it = other.begin(); + typename TQMap<T, TQ_UINT32>::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + insert(it.key(), TQT_DBusData::fromUInt32(it.data())); + } + } + + /** + * @brief Creates a map from the given TQMap of signed 64-bit integer values + * + * Type information for the map object will be set to TQT_DBusData::Int64 + * also when the @p other map is empty, i.e. this allows to create an + * empty but valid map object, comparable to using + * TQT_DBusDataMap<T>(TQT_DBusData::Type) with TQT_DBusData::Int64 + * + * @param other the TQMap of signed 64-bit integer values to copy from + * + * @see toInt64Map() + */ + TQT_DBusDataMap<T>(const TQMap<T, TQ_INT64>& other) + : TQMap<T, TQT_DBusData>(), m_valueType(TQT_DBusData::Int64) + { + typename TQMap<T, TQ_INT64>::const_iterator it = other.begin(); + typename TQMap<T, TQ_INT64>::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + insert(it.key(), TQT_DBusData::fromInt64(it.data())); + } + } + + /** + * @brief Creates a map from the given TQMap of unsigned 64-bit integer values + * + * Type information for the map object will be set to TQT_DBusData::UInt64 + * also when the @p other map is empty, i.e. this allows to create an + * empty but valid map object, comparable to using + * TQT_DBusDataMap<T>(TQT_DBusData::Type) with TQT_DBusData::UInt64 + * + * @param other the TQMap of unsigned 64-bit integer values to copy from + * + * @see toUInt64Map() + */ + TQT_DBusDataMap<T>(const TQMap<T, TQ_UINT64>& other) + : TQMap<T, TQT_DBusData>(), m_valueType(TQT_DBusData::UInt64) + { + typename TQMap<T, TQ_UINT64>::const_iterator it = other.begin(); + typename TQMap<T, TQ_UINT64>::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + insert(it.key(), TQT_DBusData::fromUInt64(it.data())); + } + } + + /** + * @brief Creates a map from the given TQMap of double values + * + * Type information for the map object will be set to TQT_DBusData::Double + * also when the @p other map is empty, i.e. this allows to create an + * empty but valid map object, comparable to using + * TQT_DBusDataMap<T>(TQT_DBusData::Type) with TQT_DBusData::Double + * + * @param other the TQMap of double values to copy from + * + * @see toDoubleMap() + */ + TQT_DBusDataMap<T>(const TQMap<T, double>& other) + : TQMap<T, TQT_DBusData>(), m_valueType(TQT_DBusData::Double) + { + typename TQMap<T, double>::const_iterator it = other.begin(); + typename TQMap<T, double>::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + insert(it.key(), TQT_DBusData::fromDouble(it.data())); + } + } + + /** + * @brief Creates a map from the given TQMap of TQString values + * + * Type information for the map object will be set to TQT_DBusData::String + * also when the @p other map is empty, i.e. this allows to create an + * empty but valid map object, comparable to using + * TQT_DBusDataMap<T>(TQT_DBusData::Type) with TQT_DBusData::String + * + * @param other the TQMap of TQString values to copy from + * + * @see toStringMap() + */ + TQT_DBusDataMap<T>(const TQMap<T, TQString>& other) + : TQMap<T, TQT_DBusData>(), m_valueType(TQT_DBusData::String) + { + typename TQMap<T, TQString>::const_iterator it = other.begin(); + typename TQMap<T, TQString>::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + insert(it.key(), TQT_DBusData::fromString(it.data())); + } + } + + /** + * @brief Creates a map from the given TQMap of object path values + * + * Type information for the map object will be set to TQT_DBusData::ObjectPath + * also when the @p other map is empty, i.e. this allows to create an + * empty but valid map object, comparable to using + * TQT_DBusDataMap<T>(TQT_DBusData::Type) with TQT_DBusData::ObjectPath + * + * @param other the TQMap of object path values to copy from + * + * @see toObjectPathMap() + */ + TQT_DBusDataMap<T>(const TQMap<T, TQT_DBusObjectPath>& other) + : TQMap<T, TQT_DBusData>(), m_valueType(TQT_DBusData::ObjectPath) + { + typename TQMap<T, TQT_DBusObjectPath>::const_iterator it = other.begin(); + typename TQMap<T, TQT_DBusObjectPath>::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + insert(it.key(), TQT_DBusData::fromObjectPath(it.data())); + } + } + + /** + * @brief Creates a map from the given TQMap of TQT_DBusUnixFd values + * + * Type information for the map object will be set to TQT_DBusData::UnixFd + * also when the @p other map is empty, i.e. this allows to create an + * empty but valid map object, comparable to using + * TQT_DBusDataMap<T>(TQT_DBusData::Type) with TQT_DBusData::UnixFd + * + * @param other the TQMap of TQT_DBusUnixFd values to copy from + * + * @see toUnixFdMap() + */ + TQT_DBusDataMap<T>(const TQMap<T, TQT_DBusUnixFd>& other) + : TQMap<T, TQT_DBusData>(), m_valueType(TQT_DBusData::UnixFd) + { + typename TQMap<T, TQT_DBusUnixFd>::const_iterator it = other.begin(); + typename TQMap<T, TQT_DBusUnixFd>::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + insert(it.key(), TQT_DBusData::fromUnixFd(it.data())); + } + } + + /** + * @brief Creates a map from the given TQMap of TQT_DBusVariant values + * + * Type information for the map object will be set to TQT_DBusData::Variant + * also when the @p other map is empty, i.e. this allows to create an + * empty but valid map object, comparable to using + * TQT_DBusDataMap<T>(TQT_DBusData::Type) with TQT_DBusData::Variant + * + * @param other the TQMap of variant values to copy from + * + * @see toVariantMap() + */ + TQT_DBusDataMap<T>(const TQMap<T, TQT_DBusVariant>& other) + : TQMap<T, TQT_DBusData>(), m_valueType(TQT_DBusData::Variant) + { + typename TQMap<T, TQT_DBusVariant>::const_iterator it = other.begin(); + typename TQMap<T, TQT_DBusVariant>::const_iterator endIt = other.end(); + for (; it != endIt; ++it) + { + insert(it.key(), TQT_DBusData::fromVariant(it.data())); + } + } + + /** + * @brief Copies from the given @p other map + * + * This behaves basically like copying a TQMap through its assignment + * operator, i.e. no value are actually copied at this time. + * + * @param other the other map object to copy from + * + * @return a reference to this map object + */ + TQT_DBusDataMap<T>& operator=(const TQT_DBusDataMap<T>& other) + { + TQMap<T, TQT_DBusData>::operator=(other); + + m_valueType = other.m_valueType; + m_containerValueType = other.m_containerValueType; + + return *this; + } + + /** + * @brief Copies from the given @p other map + * + * This behaves basically like copying a TQMap through its assignment + * operator, i.e. no value are actually copied at this time. + * + * \warning the value of the given @p other map have to be of the same + * type. If they aren't this maps's content will cleared and the + * value type will be set to TQT_DBusData::Invalid + * + * @param other the other map object to copy from + * + * @return a reference to this map object + */ + TQT_DBusDataMap<T>& operator=(const TQMap<T, TQT_DBusData>& other) + { + TQMap<T, TQT_DBusData>::operator=(other); + + m_valueType = TQT_DBusData::Invalid; + m_containerValueType = TQT_DBusData(); + + const_iterator it = begin(); + if (it == end()) return *this; + + m_valueType = (*it).type(); + + TQCString containerSignature; + if (hasContainerValueType()) + { + m_containerValueType = it.data(); + containerSignature = m_containerValueType.buildDBusSignature(); + } + + for (++it; it != end(); ++it) + { + if ((*it).type() != m_valueType) + { + m_valueType = TQT_DBusData::Invalid; + m_containerValueType = TQT_DBusData(); + + clear(); + return *this; + } + else if (hasContainerValueType()) + { + if (it.data()->buildSignature() != containerSignature) + { + m_valueType = TQT_DBusData::Invalid; + m_containerValueType = TQT_DBusData(); + + clear(); + return *this; + } + } + } + + return *this; + } + + /** + * @brief Returns the key type of the map object + * + * @return one of the values of the TQT_DBusData#Type enum suitable for + * map keys. See TQT_DBusData::Map for details + * + * @see valueType() + */ + TQT_DBusData::Type keyType() const { return m_keyType; } + + /** + * @brief Returns the value type of the map object + * + * @return one of the values of the TQT_DBusData#Type enum + * + * @see hasContainerValueType() + * @see containerValueType() + * @see keyType() + */ + TQT_DBusData::Type valueType() const { return m_valueType; } + + /** + * @brief Checks whether the value type is a data container itself + * + * If the value of the map are containers as well, this will return + * @c true + * In this case containerValueType() will return a prototype for such a + * container. + * + * @return @c true if the value type is either TQT_DBusData::Map, + * TQT_DBusData::List or TQT_DBusData::Struct, otherwise @c false + * + * @see TQT_DBusDataMap<T>(const TQT_DBusData&) + */ + bool hasContainerValueType() const + { + return m_valueType == TQT_DBusData::List || m_valueType == TQT_DBusData::Struct + || m_valueType == TQT_DBusData::Map; + } + + /** + * @brief Returns a container prototype for the map's value type + * + * Lists which have containers as their elements, i.e. hasContainerValueType() + * returns @c true this will actually specify the details for the use + * container, i.e. the returned data object can be queried for type and + * possible further subtypes. + * + * @return a data object detailing the value type or an invalid data object + * if the map does not have a container as its element type + * + * @see TQT_DBusDataMap<T>(const TQT_DBusData&); + * @see valueType() + * @see TQT_DBusData::Invalid + */ + TQT_DBusData containerValueType() const { return m_containerValueType; } + + /** + * @brief Checks whether this map object has a valid value type + * + * This is equal to checking valueType() for not being TQT_DBusData::Invalid + * + * @return @c true if the map object is valid, otherwise @c false + */ + inline bool isValid() const { return valueType() != TQT_DBusData::Invalid; } + + /** + * @brief Checks whether this map object has any key/value pairs + * + * @return @c true if there are no key/values in this map, otherwise @c false + * + * @see count() + */ + bool isEmpty() const { return TQMap<T, TQT_DBusData>::empty(); } + + /** + * @brief Returns the number of key/value pairs of this map object + * + * @return the number of key/value pairs + * + * @see isEmpty() + */ + uint count() const { return TQMap<T, TQT_DBusData>::count(); } + + /** + * @brief Checks whether the given @p other map is equal to this one + * + * Two maps are considered equal when they have the same value type (and same + * container value type if the have one) and the key/value pairs are equal + * as well. + * + * @param other the other map object to compare with + * + * @return @c true if the maps are equal, otherwise @c false + * + * @see TQT_DBusData::operator==() + */ + bool operator==(const TQT_DBusDataMap<T>& other) const + { + if (m_valueType != other.m_valueType) return false; + + if (count() != other.count()) return false; + + if (hasContainerValueType() != other.hasContainerValueType()) return false; + + if (hasContainerValueType()) + { + if (m_containerValueType.buildDBusSignature() != + other.m_containerValueType.buildDBusSignature()) return false; + } + + const_iterator it = begin(); + const_iterator otherIt = other.begin(); + for (; it != end() && otherIt != other.end(); ++it, ++otherIt) + { + if (it.key() != otherIt.key()) return false; + + if (!(it.data() == otherIt.data())) return false; + } + + return true; + } + + /** + * @brief Clears the map + * + * Value type and, if applicable, container value type will stay untouched. + */ + void clear() { TQMap<T, TQT_DBusData>::clear(); } + + /** + * @brief Returns an iterator to the first item according to the key sort order + * + * @see TQMap::begin() + */ + const_iterator begin() const + { + return TQMap<T, TQT_DBusData>::begin(); + } + + /** + * @brief Returns an iterator to an invalid position + * + * @see TQMap::end() + */ + const_iterator end() const + { + return TQMap<T, TQT_DBusData>::end(); + } + + /** + * @brief Inserts a given value for a given key + * + * Basically works like the respective TQMap method, but checks if + * type of the new value matches the value type of the list. + * Maps that are invalid will accept any new type and will then be + * typed accordingly. + * + * If @p data is invalid itself, it will not be inserted at any time. + * + * \note the more common use case is to work with a TQMap and then + * use the respective constructor to create the TQT_DBusDataMap object + * + * @param key the key were to insert into the map + * @param data the data item to insert into the map + * + * @return @c true on successfull insert, otherwise @c false + */ + bool insert(const T& key, const TQT_DBusData& data) + { + if (data.type() == TQT_DBusData::Invalid) return false; + + if (m_valueType == TQT_DBusData::Invalid) + { + m_valueType = data.type(); + + // TODO: create empty copy of container + if (hasContainerValueType()) m_containerValueType = data; + + TQMap<T, TQT_DBusData>::insert(key, data); + } + else if (data.type() != m_valueType) + { + tqWarning("TQT_DBusDataMap: trying to add data of type %s to map of type %s", + data.typeName(), TQT_DBusData::typeName(m_valueType)); + } + else if (hasContainerValueType()) + { + TQCString ourSignature = m_containerValueType.buildDBusSignature(); + TQCString dataSignature = data.buildDBusSignature(); + + if (ourSignature != dataSignature) + { + tqWarning("TQT_DBusDataMap: trying to add data with signature %s " + "to map with value signature %s", + dataSignature.data(), ourSignature.data()); + } + else + TQMap<T, TQT_DBusData>::insert(key, data); + } + else + TQMap<T, TQT_DBusData>::insert(key, data); + + return true; + } + + /** + * @brief Converts the map object into a TQMap with TQT_DBusData elements + * + * @return the key/value pairs of the map object as a TQMap + */ + TQMap<T, TQT_DBusData> toTQMap() const { return *this; } + + /** + * @brief Tries to get the map object's pairs as a TQMap of bool + * + * This is a convenience overload for the case when the map is of + * value type TQT_DBusData::Bool. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of value type + * TQT_DBusData::Bool) + * + * @return a TQMap of bool containing the list object's boolean + * values or an empty map when converting fails + * + * @see TQT_DBusData::toBool() + */ + TQMap<T, bool> toBoolMap(bool* ok = 0) const + { + if (m_valueType != TQT_DBusData::Bool) + { + if (ok != 0) *ok = false; + return TQMap<T, bool>(); + } + + TQMap<T, bool> result; + + const_iterator it = begin(); + const_iterator endIt = end(); + for (; it != endIt; ++it) + { + result.insert(it.key(), (*it).toBool()); + } + + if (ok != 0) *ok = true; + + return result; + } + + /** + * @brief Tries to get the map object's pairs as a TQMap of TQ_UINT8 + * + * This is a convenience overload for the case when the map is of + * value type TQT_DBusData::Byte. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of value type + * TQT_DBusData::Byte) + * + * @return a TQMap of TQ_UINT8 containing the list object's byte + * values or an empty map when converting fails + * + * @see TQT_DBusData::toBool() + */ + TQMap<T, TQ_UINT8> toByteMap(bool* ok = 0) const + { + if (m_valueType != TQT_DBusData::Byte) + { + if (ok != 0) *ok = false; + return TQMap<T, TQ_UINT8>(); + } + + TQMap<T, TQ_UINT8> result; + + const_iterator it = begin(); + const_iterator endIt = end(); + for (; it != endIt; ++it) + { + result.insert(it.key(), (*it).toByte()); + } + + if (ok != 0) *ok = true; + + return result; + } + + /** + * @brief Tries to get the map object's pairs as a TQMap of TQ_INT16 + * + * This is a convenience overload for the case when the map is of + * value type TQT_DBusData::Int16. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of value type + * TQT_DBusData::Int16) + * + * @return a TQMap of TQ_INT16 containing the map object's + * signed 16-bit integer values or an empty map when converting + * fails + * + * @see TQT_DBusData::toInt16() + */ + TQMap<T, TQ_INT16> toInt16Map(bool* ok = 0) const + { + if (m_valueType != TQT_DBusData::Int16) + { + if (ok != 0) *ok = false; + return TQMap<T, TQ_INT16>(); + } + + TQMap<T, TQ_INT16> result; + + const_iterator it = begin(); + const_iterator endIt = end(); + for (; it != endIt; ++it) + { + result.insert(it.key(), (*it).toInt16()); + } + + if (ok != 0) *ok = true; + + return result; + } + + /** + * @brief Tries to get the map object's pairs as a TQMap of TQ_UINT16 + * + * This is a convenience overload for the case when the map is of + * value type TQT_DBusData::UInt16. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of value type + * TQT_DBusData::UInt16) + * + * @return a TQMap of TQ_UINT16 containing the map object's + * unsigned 16-bit integer values or an empty map when converting + * fails + * + * @see TQT_DBusData::toUInt16() + */ + TQMap<T, TQ_UINT16> toUInt16Map(bool* ok = 0) const + { + if (m_valueType != TQT_DBusData::UInt16) + { + if (ok != 0) *ok = false; + return TQMap<T, TQ_UINT16>(); + } + + TQMap<T, TQ_UINT16> result; + + const_iterator it = begin(); + const_iterator endIt = end(); + for (; it != endIt; ++it) + { + result.insert(it.key(), (*it).toUInt16()); + } + + if (ok != 0) *ok = true; + + return result; + } + + /** + * @brief Tries to get the map object's pairs as a TQMap of TQ_INT32 + * + * This is a convenience overload for the case when the map is of + * value type TQT_DBusData::Int32. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of value type + * TQT_DBusData::Int32) + * + * @return a TQMap of TQ_INT32 containing the map object's + * signed 32-bit integer values or an empty map when converting + * fails + * + * @see TQT_DBusData::toInt32() + */ + TQMap<T, TQ_INT32> toInt32Map(bool* ok = 0) const + { + if (m_valueType != TQT_DBusData::Int32) + { + if (ok != 0) *ok = false; + return TQMap<T, TQ_INT32>(); + } + + TQMap<T, TQ_INT32> result; + + const_iterator it = begin(); + const_iterator endIt = end(); + for (; it != endIt; ++it) + { + result.insert(it.key(), (*it).toInt32()); + } + + if (ok != 0) *ok = true; + + return result; + } + + /** + * @brief Tries to get the map object's pairs as a TQMap of TQ_UINT32 + * + * This is a convenience overload for the case when the map is of + * value type TQT_DBusData::UInt32. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of value type + * TQT_DBusData::UInt32) + * + * @return a TQMap of TQ_UINT32 containing the map object's + * unsigned 32-bit integer values or an empty map when converting + * fails + * + * @see TQT_DBusData::toUInt32() + */ + TQMap<T, TQ_UINT32> toUInt32Map(bool* ok = 0) const + { + if (m_valueType != TQT_DBusData::UInt32) + { + if (ok != 0) *ok = false; + return TQMap<T, TQ_UINT32>(); + } + + TQMap<T, TQ_UINT32> result; + + const_iterator it = begin(); + const_iterator endIt = end(); + for (; it != endIt; ++it) + { + result.insert(it.key(), (*it).toUInt32()); + } + + if (ok != 0) *ok = true; + + return result; + } + + /** + * @brief Tries to get the map object's pairs as a TQMap of TQ_INT64 + * + * This is a convenience overload for the case when the map is of + * value type TQT_DBusData::Int64. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of value type + * TQT_DBusData::Int64) + * + * @return a TQMap of TQ_INT64 containing the map object's + * signed 64-bit integer values or an empty map when converting + * fails + * + * @see TQT_DBusData::toInt64() + */ + TQMap<T, TQ_INT64> toInt64Map(bool* ok = 0) const + { + if (m_valueType != TQT_DBusData::Int64) + { + if (ok != 0) *ok = false; + return TQMap<T, TQ_INT64>(); + } + + TQMap<T, TQ_INT64> result; + + const_iterator it = begin(); + const_iterator endIt = end(); + for (; it != endIt; ++it) + { + result.insert(it.key(), (*it).toInt64()); + } + + if (ok != 0) *ok = true; + + return result; + } + + /** + * @brief Tries to get the map object's pairs as a TQMap of TQ_UINT64 + * + * This is a convenience overload for the case when the map is of + * value type TQT_DBusData::UInt64. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of value type + * TQT_DBusData::UInt64) + * + * @return a TQMap of TQ_UINT64 containing the map object's + * unsigned 64-bit integer values or an empty map when converting + * fails + * + * @see TQT_DBusData::toUInt64() + */ + TQMap<T, TQ_UINT64> toUInt64Map(bool* ok = 0) const + { + if (m_valueType != TQT_DBusData::UInt64) + { + if (ok != 0) *ok = false; + return TQMap<T, TQ_UINT64>(); + } + + TQMap<T, TQ_UINT64> result; + + const_iterator it = begin(); + const_iterator endIt = end(); + for (; it != endIt; ++it) + { + result.insert(it.key(), (*it).toUInt64()); + } + + if (ok != 0) *ok = true; + + return result; + } + + /** + * @brief Tries to get the map object's pairs as a TQMap of double + * + * This is a convenience overload for the case when the map is of + * value type TQT_DBusData::Double. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of value type + * TQT_DBusData::Double) + * + * @return a TQMap of double containing the map object's double + * values or an empty map when converting fails + * + * @see TQT_DBusData::toDouble() + */ + TQMap<T, double> toDoubleMap(bool* ok = 0) const + { + if (m_valueType != TQT_DBusData::Double) + { + if (ok != 0) *ok = false; + return TQMap<T, double>(); + } + + TQMap<T, double> result; + + const_iterator it = begin(); + const_iterator endIt = end(); + for (; it != endIt; ++it) + { + result.insert(it.key(), (*it).toDouble()); + } + + if (ok != 0) *ok = true; + + return result; + } + + /** + * @brief Tries to get the map object's pairs as a TQMap of TQString + * + * This is a convenience overload for the case when the map is of + * value type TQT_DBusData::String, see also toTQStringList(). + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of value type + * TQT_DBusData::String) + * + * @return a TQMap of TQString containing the map object's string + * values or an empty map when converting fails + * + * @see TQT_DBusData::toString() + */ + TQMap<T, TQString> toStringMap(bool* ok = 0) const + { + if (m_valueType != TQT_DBusData::String) + { + if (ok != 0) *ok = false; + return TQMap<T, TQString>(); + } + + TQMap<T, TQString> result; + + const_iterator it = begin(); + const_iterator endIt = end(); + for (; it != endIt; ++it) + { + result.insert(it.key(), (*it).toString()); + } + + if (ok != 0) *ok = true; + + return result; + } + + /** + * @brief Tries to get the map object's pairs as a TQMap of object paths + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of value type + * TQT_DBusData::ObjectPath) + * + * @return a TQMap of object paths containing the map object's object path + * values or an empty map when converting fails + * + * @see TQT_DBusData::toObjectPath() + */ + TQMap<T, TQT_DBusObjectPath> toObjectPathMap(bool* ok = 0) const + { + if (m_valueType != TQT_DBusData::ObjectPath) + { + if (ok != 0) *ok = false; + return TQMap<T, TQT_DBusObjectPath>(); + } + + TQMap<T, TQT_DBusObjectPath> result; + + const_iterator it = begin(); + const_iterator endIt = end(); + for (; it != endIt; ++it) + { + result.insert(it.key(), (*it).toObjectPath()); + } + + if (ok != 0) *ok = true; + + return result; + } + + /** + * @brief Tries to get the map object's pairs as a TQMap of TQT_DBusUnixFd + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of value type + * TQT_DBusData::UnixFd) + * + * @return a TQMap of TQT_DBusUnixFd containing the map object's TQT_DBusUnixFd + * values or an empty map when converting fails + * + * @see TQT_DBusData::toUnixFd() + */ + TQMap<T, TQT_DBusObjectPath> toUnixFdMap(bool* ok = 0) const + { + if (m_valueType != TQT_DBusData::UnixFd) + { + if (ok != 0) *ok = false; + return TQMap<T, TQT_DBusUnixFd>(); + } + + TQMap<T, TQT_DBusUnixFd> result; + + const_iterator it = begin(); + const_iterator endIt = end(); + for (; it != endIt; ++it) + { + result.insert(it.key(), (*it).toUnixFd()); + } + + if (ok != 0) *ok = true; + + return result; + } + + /** + * @brief Tries to get the map object's pairs as a TQMap of TQT_DBusVariant + * + * This is a convenience overload for the case when the map is of + * value type TQT_DBusData::Variant. + * + * @param ok optional pointer to a bool variable to store the + * success information in, i.e. will be set to @c true on success + * and to @c false if the conversion failed (not of value type + * TQT_DBusData::Variant) + * + * @return a TQMap of TQT_DBusVariant containing the map object's + * TQT_DBusVariant values or an empty map when converting fails + * + * @see TQT_DBusData::toVariant() + */ + TQMap<T, TQT_DBusVariant> toVariantMap(bool* ok = 0) const + { + if (m_valueType != TQT_DBusData::Variant) + { + if (ok != 0) *ok = false; + return TQMap<T, TQT_DBusVariant>(); + } + + TQMap<T, TQT_DBusVariant> result; + + const_iterator it = begin(); + const_iterator endIt = end(); + for (; it != endIt; ++it) + { + result.insert(it.key(), (*it).toVariant()); + } + + if (ok != 0) *ok = true; + + return result; + } + +private: + TQT_DBusData::Type m_valueType; + TQT_DBusData m_containerValueType; + + static const TQT_DBusData::Type m_keyType; +}; + +#endif diff --git a/src/tqdbuserror.cpp b/src/tqdbuserror.cpp new file mode 100644 index 0000000..d0b1eb9 --- /dev/null +++ b/src/tqdbuserror.cpp @@ -0,0 +1,216 @@ +/* qdbuserror.cpp TQT_DBusError object + * + * Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org> + * Copyright (C) 2005-2007 Kevin Krammer <kevin.krammer@gmx.at> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#include "tqdbuserror.h" + +#include <dbus/dbus.h> + +#include <tqmap.h> + +typedef TQMap<TQString, TQT_DBusError::ErrorType> ErrorNameMap; +static ErrorNameMap errorTypesByName; + +static TQString qDBusErrorNameForType(TQT_DBusError::ErrorType type) +{ + switch (type) + { + case TQT_DBusError::InvalidError: + Q_ASSERT(false); + return TQString(); + + case TQT_DBusError::Failed: + return TQString::fromUtf8(DBUS_ERROR_FAILED); + case TQT_DBusError:: NoMemory: + return TQString::fromUtf8(DBUS_ERROR_NO_MEMORY); + case TQT_DBusError:: ServiceUnknown: + return TQString::fromUtf8(DBUS_ERROR_SERVICE_UNKNOWN); + case TQT_DBusError:: NameHasNoOwner: + return TQString::fromUtf8(DBUS_ERROR_NAME_HAS_NO_OWNER); + case TQT_DBusError:: NoReply: + return TQString::fromUtf8(DBUS_ERROR_NO_REPLY); + case TQT_DBusError:: IOError: + return TQString::fromUtf8(DBUS_ERROR_IO_ERROR); + case TQT_DBusError:: BadAddress: + return TQString::fromUtf8(DBUS_ERROR_BAD_ADDRESS); + case TQT_DBusError:: NotSupported: + return TQString::fromUtf8(DBUS_ERROR_NOT_SUPPORTED); + case TQT_DBusError:: LimitsExceeded: + return TQString::fromUtf8(DBUS_ERROR_LIMITS_EXCEEDED); + case TQT_DBusError:: AccessDenied: + return TQString::fromUtf8(DBUS_ERROR_ACCESS_DENIED); + case TQT_DBusError:: AuthFailed: + return TQString::fromUtf8(DBUS_ERROR_AUTH_FAILED); + case TQT_DBusError:: NoServer: + return TQString::fromUtf8(DBUS_ERROR_NO_SERVER); + case TQT_DBusError:: Timeout: + return TQString::fromUtf8(DBUS_ERROR_TIMEOUT); + case TQT_DBusError:: NoNetwork: + return TQString::fromUtf8(DBUS_ERROR_NO_NETWORK); + case TQT_DBusError:: Disconnected: + return TQString::fromUtf8(DBUS_ERROR_DISCONNECTED); + case TQT_DBusError:: InvalidArgs: + return TQString::fromUtf8(DBUS_ERROR_INVALID_ARGS); + case TQT_DBusError:: FileNotFound: + return TQString::fromUtf8(DBUS_ERROR_FILE_NOT_FOUND); + case TQT_DBusError:: FileExists: + return TQString::fromUtf8(DBUS_ERROR_FILE_EXISTS); + case TQT_DBusError:: UnknownMethod: + return TQString::fromUtf8(DBUS_ERROR_UNKNOWN_METHOD); + case TQT_DBusError:: TimedOut: + return TQString::fromUtf8(DBUS_ERROR_TIMED_OUT); + case TQT_DBusError:: InvalidSignature: + return TQString::fromUtf8(DBUS_ERROR_INVALID_SIGNATURE); + + case TQT_DBusError::UserDefined: + Q_ASSERT(false); + return TQString(); + } + + Q_ASSERT(false); + return TQString(); +} + +static void qDBusErrorSetupNameMapping() +{ + for (int i = TQT_DBusError::InvalidError + 1; i < TQT_DBusError::UserDefined; ++i) + { + TQT_DBusError::ErrorType type = static_cast<TQT_DBusError::ErrorType>(i); + errorTypesByName[qDBusErrorNameForType(type)] = type; + } +} + +static TQT_DBusError::ErrorType qDBusErrorTypeForName(const TQString& name) +{ + if (name.isEmpty()) return TQT_DBusError::InvalidError; + + if (errorTypesByName.isEmpty()) + qDBusErrorSetupNameMapping(); + + ErrorNameMap::const_iterator it = errorTypesByName.find(name); + if (it != errorTypesByName.end()) return it.data(); + + return TQT_DBusError::UserDefined; +} + +TQT_DBusError::TQT_DBusError() : errorType(InvalidError), m_dbusErrorSet(false) +{ +} + +TQT_DBusError::TQT_DBusError(const DBusError *error) : errorType(InvalidError), m_dbusErrorSet(false) +{ + if (!error || !dbus_error_is_set(error)) + return; + + nm = TQString::fromUtf8(error->name); + msg = TQString::fromUtf8(error->message); + + errorType = qDBusErrorTypeForName(nm); +} + +TQT_DBusError::TQT_DBusError(const TQString& error, const TQString& message) + : errorType(UserDefined), m_dbusErrorSet(false), nm(error), msg(message) +{ + errorType = qDBusErrorTypeForName(nm); +} + +bool TQT_DBusError::isValid() const +{ + return errorType != InvalidError && !nm.isEmpty() && !msg.isEmpty(); +} + +TQT_DBusError::TQT_DBusError(ErrorType type, const TQString& message) + : errorType(type), m_dbusErrorSet(false), msg(message) +{ + nm = qDBusErrorNameForType(type); +} + +TQT_DBusError TQT_DBusError::stdFailed(const TQString& message) +{ + return TQT_DBusError(TQT_DBusError::Failed, message); +} + +TQT_DBusError TQT_DBusError::stdNoMemory(const TQString& message) +{ + return TQT_DBusError(TQT_DBusError::NoMemory, message); +} + +TQT_DBusError TQT_DBusError::stdNoReply(const TQString& message) +{ + return TQT_DBusError(TQT_DBusError::NoReply, message); +} + +TQT_DBusError TQT_DBusError::stdIOError(const TQString& message) +{ + return TQT_DBusError(TQT_DBusError::IOError, message); +} + +TQT_DBusError TQT_DBusError::stdNotSupported(const TQString& message) +{ + return TQT_DBusError(TQT_DBusError::NotSupported, message); +} + +TQT_DBusError TQT_DBusError::stdLimitsExceeded(const TQString& message) +{ + return TQT_DBusError(TQT_DBusError::LimitsExceeded, message); +} + +TQT_DBusError TQT_DBusError::stdAccessDenied(const TQString& message) +{ + return TQT_DBusError(TQT_DBusError::AccessDenied, message); +} + +TQT_DBusError TQT_DBusError::stdAuthFailed(const TQString& message) +{ + return TQT_DBusError(TQT_DBusError::AuthFailed, message); +} + +TQT_DBusError TQT_DBusError::stdTimeout(const TQString& message) +{ + return TQT_DBusError(TQT_DBusError::Timeout, message); +} + +TQT_DBusError TQT_DBusError::stdInvalidArgs(const TQString& message) +{ + return TQT_DBusError(TQT_DBusError::InvalidArgs, message); +} + +TQT_DBusError TQT_DBusError::stdFileNotFound(const TQString& message) +{ + return TQT_DBusError(TQT_DBusError::FileNotFound, message); +} + +TQT_DBusError TQT_DBusError::stdFileExists(const TQString& message) +{ + return TQT_DBusError(TQT_DBusError::FileExists, message); +} + +TQT_DBusError TQT_DBusError::stdUnknownMethod(const TQString& message) +{ + return TQT_DBusError(TQT_DBusError::UnknownMethod, message); +} + +TQT_DBusError TQT_DBusError::stdInvalidSignature(const TQString& message) +{ + return TQT_DBusError(TQT_DBusError::InvalidSignature, message); +} diff --git a/src/tqdbuserror.h b/src/tqdbuserror.h new file mode 100644 index 0000000..ff11ffb --- /dev/null +++ b/src/tqdbuserror.h @@ -0,0 +1,476 @@ +/* qdbuserror.h TQT_DBusError object + * + * Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org> + * Copyright (C) 2005 Kevin Krammer <kevin.krammer@gmx.at> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#ifndef TQDBUSERROR_H +#define TQDBUSERROR_H + +#include "tqdbusmacros.h" +#include <tqstring.h> + +struct DBusError; + +/** + * @brief Class for transporting D-Bus errors + * + * A D-Bus error has two parts: an error name (see section + * @ref dbusconventions-errorname) and a message string detailing the error in + * human presentable form. + */ +class TQDBUS_EXPORT TQT_DBusError +{ +public: + /** + * @brief Enum of standard D-Bus error types + * + * D-Bus defines a list of common error types and their names. + * The values of this enum map to those an application is likely to encounter + * and likely to create itself. + * + * Standard errors can either be created by specifying the D-Bus error name + * or, as a convenience, by using factory methods of this class for the + * most common ones. + * + * All D-Bus standard error names are within the @c "org.freedesktop.DBus.Error" + * namespace. + * + * @see name() + */ + enum ErrorType + { + /** + * @brief TQT_DBusError specific value, to represent invalid error objects. + * + * @see isValid() + */ + InvalidError, + + /** + * @brief Generic failure cause + * + * Can be used whenever the other predefined errors do no match. Basically + * just meaning "something when wrong, see message() for details" + * + * @see stdFailed() + */ + Failed, + + /** + * @brief An operation could not allocate enough memory + * + * @see stdNoMemory() + */ + NoMemory, + + /** + * @brief An addressed service is neither connected nor can it be activated + */ + ServiceUnknown, + + /** + * @brief A non-unique name used in a message is not known + * + * If a message addresses a D-Bus connection through a non-unique + * (requested) name and the D-Bus does not have a mapping to any of the + * unique names. + */ + NameHasNoOwner, + + /** + * @brief An call failed to send a reply but one was expected + * + * @see stdNoReply() + */ + NoReply, + + /** + * @brief An IO error occured during an operation + * + * Generic indicator that some kind of IO operation failed, e.g. + * reading from a socket. + * + * @see stdIOError() + */ + IOError, + + /** + * @brief Caused by trying to connect to a malformed address + * + * Returned by TQT_DBusConnection's addConnection if the specified address + * isn't a valid D-Bus bus address. + * + * @see TQT_DBusConnection::addConnection(const TQString&,const TQString&); + */ + BadAddress, + + /** + * @brief An otherwise valid operation request could not be handled + * + * Primarily useful when a service implements a specific interface but + * does not (yet) handle all possible situations. + * + * @see stdNotSupported() + */ + NotSupported, + + /** + * @brief Use of a limited resource reached its limit + * + * @see stdLimitsExceeded() + */ + LimitsExceeded, + + /** + * @brief Caused by security restrictions denying an operation + * + * Primarily useful when a client tries to manipulate resources a service + * has associated with a different client and which should not be changable + * by anyone else. + * + * @see stdAccessDenied() + */ + AccessDenied, + + /** + * @brief An authentification mechanism failed + * + * @see stdAuthFailed() + */ + AuthFailed, + + /** + * @brief Connection to a D-Bus server failed + */ + NoServer, + + /** + * @brief An timeout occured during an operation + * + * @warning D-Bus defined to quite similar errors but does not detail + * when either one can occur. See #TimedOut + * + * @see stdTimeout() + */ + Timeout, + + /** + * @brief The network intended as a transport channel is not available + */ + NoNetwork, + + /** + * @brief Caused by trying to use an unconnected D-Bus connection + * + * @see TQT_DBusConnection::isConnected() + */ + Disconnected, + + /** + * @brief Caused by invalid arguments passed to a method call + * + * Primarily usefull for service implementations when the incoming + * call does not transport the expected parameters, e.g. wrong types + * or wrong values. + * + * @see stdInvalidArgs() + */ + InvalidArgs, + + /** + * @brief A file necessary for an operation is not avaiable + * + * @see stdFileNotFound() + */ + FileNotFound, + + /** + * @brief Target file exists but operation does not allow overwriting + * + * @see stdFileExists() + */ + FileExists, + + /** + * @brief A method call addresses and unknown method + * + * @see stdUnknownMethod() + */ + UnknownMethod, + + /** + * @brief An operation timed out + * + * @warning D-Bus defined to quite similar errors but does not detail + * when either one can occur. See #Timeout + */ + TimedOut, + + /** + * @brief An type signature is not valid + * + * A possible cause is a TQT_DBusVariant with an invalid signature, i.e. + * the transported signature is empty, contains unknown type characters + * or has mismatched container enclosings. + * + * @note in case a service implementation wants to indicate that a method + * call did not transport the correct parameter types, use + * #InvalidArgs instead + * + * @see stdInvalidSignature() + */ + InvalidSignature, + + /** + * @brief Generic type for all errors not matching on of the other predefined + * + * @see TQT_DBusError(const TQString&,const TQString&); + */ + UserDefined + }; + + /** + * @brief Creates an empty and invalid error object + */ + TQT_DBusError(); + + /** + * @brief Creates an error object from an C API D-Bus error object + * + * @param error a pointer to the C API D-Bus error + */ + TQT_DBusError(const DBusError *error); + + /** + * @brief Creates an error object for its two given components + * + * @param error a D-Bus error name + * @param message the potentially i18n'ed error description message + * + * @see name() + */ + TQT_DBusError(const TQString& error, const TQString& message); + + /** + * @brief Returns the D-Bus error name + * + * See section @ref dbusconventions-errorname for details. + * + * @return the D-Bus error name + * + * @see message() + */ + inline TQString name() const { return nm; } + + /** + * @brief Returns a string describing the error + * + * The message is meant to further detail or describe the error. + * It is usually a translated error message meant for direct + * presentation to the user. + * + * @return the error's message + * + * @see name() + */ + inline TQString message() const { return msg; } + + /** + * @brief Returns a type for checking of standard errors + * + * D-Bus specifies a couple of standard error names, which are mapped to + * TQT_DBusError types in order to make creating and checking for them easier. + * + * @return the error's type + * + * @see name() + */ + inline ErrorType type() const { return errorType; } + + /** + * @brief Returns whether the error was caused by DBUS itself + * + * A TQT_DBusError is considered valid if both name and message are set. + * + * @return @c true if dbus_error_is_set was true after DBUS call completion + */ + inline bool dbusErrorSet() const { return m_dbusErrorSet; } + + /** + * @internal + */ + inline void setDBUSError(bool err) const { m_dbusErrorSet = err; } + + /** + * @brief Returns whether the error object is valid + * + * A TQT_DBusError is considered valid if both name and message are set. + * + * @return @c true if neither name nor message is @c TQString() and the + * error type is a valid type + */ + bool isValid() const; + + /** + * @brief Creates a D-Bus standard error for generic failure + * + * @param message the message detailing the encountered problem + * + * @return an error object of type #Failed with the given @p message + */ + static TQT_DBusError stdFailed(const TQString& message); + + /** + * @brief Creates a D-Bus standard error for out of memory situations + * + * @param message the message detailing the encountered problem + * + * @return an error object of type #NoMemory with the given @p message + */ + static TQT_DBusError stdNoMemory(const TQString& message); + + /** + * @brief Creates a D-Bus standard error for expected reply missing + * + * @param message the message detailing the encountered problem + * + * @return an error object of type #NoReply with the given @p message + */ + static TQT_DBusError stdNoReply(const TQString& message); + + /** + * @brief Creates a D-Bus standard error for generic IO errors + * + * @param message the message detailing the encountered problem + * + * @return an error object of type #IOError with the given @p message + */ + static TQT_DBusError stdIOError(const TQString& message); + + /** + * @brief Creates a D-Bus standard error for unsupported operations + * + * @param message the message detailing the encountered problem + * + * @return an error object of type #NotSupported with the given @p message + */ + static TQT_DBusError stdNotSupported(const TQString& message); + + /** + * @brief Creates a D-Bus standard error for exceeding a limited resource + * + * @param message the message detailing the encountered problem + * + * @return an error object of type #LimitsExceeded with the given @p message + */ + static TQT_DBusError stdLimitsExceeded(const TQString& message); + + /** + * @brief Creates a D-Bus standard error for access to a resource being denied + * + * @param message the message detailing the encountered problem + * + * @return an error object of type #AccessDenied with the given @p message + */ + static TQT_DBusError stdAccessDenied(const TQString& message); + + /** + * @brief Creates a D-Bus standard error for failed authentification + * + * @param message the message detailing the encountered problem + * + * @return an error object of type #AuthFailed with the given @p message + */ + static TQT_DBusError stdAuthFailed(const TQString& message); + + /** + * @brief Creates a D-Bus standard error for timeouts during operations + * + * @param message the message detailing the encountered problem + * + * @return an error object of type #Timeout with the given @p message + */ + static TQT_DBusError stdTimeout(const TQString& message); + + /** + * @brief Creates a D-Bus standard error for call arguments being invalid + * + * @param message the message detailing the encountered problem + * + * @return an error object of type #InvalidArgs with the given @p message + */ + static TQT_DBusError stdInvalidArgs(const TQString& message); + + /** + * @brief Creates a D-Bus standard error for a file not being available + * + * @param message the message detailing the encountered problem + * + * @return an error object of type #FileNotFound with the given @p message + */ + static TQT_DBusError stdFileNotFound(const TQString& message); + + /** + * @brief Creates a D-Bus standard error for a file being in the way + * + * @param message the message detailing the encountered problem + * + * @return an error object of type #FileExists with the given @p message + */ + static TQT_DBusError stdFileExists(const TQString& message); + + /** + * @brief Creates a D-Bus standard error for an unknown methods being called + * + * @param message the message detailing the encountered problem + * + * @return an error object of type #UnknownMethod with the given @p message + */ + static TQT_DBusError stdUnknownMethod(const TQString& message); + + /** + * @brief Creates a D-Bus standard error for D-Bus type signature not valid + * + * @param message the message detailing the encountered problem + * + * @return an error object of type #InvalidSignature with the given @p message + */ + static TQT_DBusError stdInvalidSignature(const TQString& message); + +private: + ErrorType errorType; + mutable bool m_dbusErrorSet; + + TQString nm, msg; + + /** + * @brief Creates an error object for one of the standard D-Bus errors + * + * @param type one of the standard error causes + * @param message the potentially i18n'ed error description message + * + * @see ErrorType + */ + TQT_DBusError(ErrorType type, const TQString& message); +}; + +#endif diff --git a/src/tqdbusintegrator.cpp b/src/tqdbusintegrator.cpp new file mode 100644 index 0000000..c7129bd --- /dev/null +++ b/src/tqdbusintegrator.cpp @@ -0,0 +1,689 @@ +/* qdbusintegrator.cpp TQT_DBusConnection private implementation + * + * Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org> + * Copyright (C) 2005 Kevin Krammer <kevin.krammer@gmx.at> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#include <tqapplication.h> +#include <tqevent.h> +#include <tqmetaobject.h> +#include <tqsocketnotifier.h> +#include <tqtimer.h> + +#include "tqdbusconnection_p.h" +#include "tqdbusmessage.h" + +Atomic::Atomic(int value) : m_value(value) +{ +} + +void Atomic::ref() +{ + m_value++; +} + +bool Atomic::deref() +{ + m_value--; + return m_value > 0; +} + +int TQT_DBusConnectionPrivate::messageMetaType = 0; + +static dbus_bool_t qDBusAddTimeout(DBusTimeout *timeout, void *data) +{ + Q_ASSERT(timeout); + Q_ASSERT(data); + + // tqDebug("addTimeout %d", dbus_timeout_get_interval(timeout)); + + TQT_DBusConnectionPrivate *d = static_cast<TQT_DBusConnectionPrivate *>(data); + + if (!dbus_timeout_get_enabled(timeout)) + return true; + + if (!tqApp) { + d->pendingTimeouts.append(timeout); + return true; + } + int timerId = d->startTimer(dbus_timeout_get_interval(timeout)); + if (!timerId) + return false; + + d->timeouts[timerId] = timeout; + return true; +} + +static void qDBusRemoveTimeout(DBusTimeout *timeout, void *data) +{ + Q_ASSERT(timeout); + Q_ASSERT(data); + + // tqDebug("removeTimeout"); + + TQT_DBusConnectionPrivate *d = static_cast<TQT_DBusConnectionPrivate *>(data); + for (TQValueList<DBusTimeout*>::iterator it = d->pendingTimeouts.begin(); + it != d->pendingTimeouts.end();) { + if ((*it) == timeout) { + it = d->pendingTimeouts.erase(it); + } + else + ++it; + } + + TQT_DBusConnectionPrivate::TimeoutHash::iterator it = d->timeouts.begin(); + while (it != d->timeouts.end()) { + if (it.data() == timeout) { + d->killTimer(it.key()); + TQT_DBusConnectionPrivate::TimeoutHash::iterator copyIt = it; + ++it; + d->timeouts.erase(copyIt); + } else { + ++it; + } + } +} + +static void qDBusToggleTimeout(DBusTimeout *timeout, void *data) +{ + Q_ASSERT(timeout); + Q_ASSERT(data); + + //tqDebug("ToggleTimeout"); + + qDBusRemoveTimeout(timeout, data); + qDBusAddTimeout(timeout, data); +} + +static dbus_bool_t qDBusAddWatch(DBusWatch *watch, void *data) +{ + Q_ASSERT(watch); + Q_ASSERT(data); + + TQT_DBusConnectionPrivate *d = static_cast<TQT_DBusConnectionPrivate *>(data); + + int flags = dbus_watch_get_flags(watch); + int fd = dbus_watch_get_unix_fd(watch); + + TQT_DBusConnectionPrivate::Watcher watcher; + if (flags & DBUS_WATCH_READABLE) { + bool enabled = dbus_watch_get_enabled(watch); + //tqDebug("addReadWatch %d %s", fd, (enabled ? "enabled" : "disabled")); + watcher.watch = watch; + if (tqApp) { + watcher.read = new TQSocketNotifier(fd, TQSocketNotifier::Read, d); + if (!enabled) watcher.read->setEnabled(false); + d->connect(watcher.read, TQT_SIGNAL(activated(int)), TQT_SLOT(socketRead(int))); + } + } + if (flags & DBUS_WATCH_WRITABLE) { + bool enabled = dbus_watch_get_enabled(watch); + //tqDebug("addWriteWatch %d %s", fd, (enabled ? "enabled" : "disabled")); + watcher.watch = watch; + if (tqApp) { + watcher.write = new TQSocketNotifier(fd, TQSocketNotifier::Write, d); + if (!enabled) watcher.write->setEnabled(false); + d->connect(watcher.write, TQT_SIGNAL(activated(int)), TQT_SLOT(socketWrite(int))); + } + } + // FIXME-QT4 d->watchers.insertMulti(fd, watcher); + TQT_DBusConnectionPrivate::WatcherHash::iterator it = d->watchers.find(fd); + if (it == d->watchers.end()) + { + it = d->watchers.insert(fd, TQT_DBusConnectionPrivate::WatcherList()); + } + it.data().append(watcher); + + return true; +} + +static void qDBusRemoveWatch(DBusWatch *watch, void *data) +{ + Q_ASSERT(watch); + Q_ASSERT(data); + + //tqDebug("remove watch"); + + TQT_DBusConnectionPrivate *d = static_cast<TQT_DBusConnectionPrivate *>(data); + int fd = dbus_watch_get_unix_fd(watch); + + TQT_DBusConnectionPrivate::WatcherHash::iterator it = d->watchers.find(fd); + if (it != d->watchers.end()) + { + TQT_DBusConnectionPrivate::WatcherList& list = *it; + for (TQT_DBusConnectionPrivate::WatcherList::iterator wit = list.begin(); + wit != list.end(); ++wit) + { + if ((*wit).watch == watch) + { + // migth be called from a function triggered by a socket listener + // so just disconnect them and schedule their delayed deletion. + + d->removedWatches.append(*wit); + if ((*wit).read) + { + (*wit).read->disconnect(d); + (*wit).read = 0; + } + if ((*wit).write) + { + (*wit).write->disconnect(d); + (*wit).write = 0; + } + (*wit).watch = 0; + } + } + } + + if (d->removedWatches.count() > 0) + TQTimer::singleShot(0, d, TQT_SLOT(purgeRemovedWatches())); +} + +static void qDBusToggleWatch(DBusWatch *watch, void *data) +{ + Q_ASSERT(watch); + Q_ASSERT(data); + + //tqDebug("toggle watch"); + + TQT_DBusConnectionPrivate *d = static_cast<TQT_DBusConnectionPrivate *>(data); + int fd = dbus_watch_get_unix_fd(watch); + + TQT_DBusConnectionPrivate::WatcherHash::iterator it = d->watchers.find(fd); + if (it != d->watchers.end()) { + TQT_DBusConnectionPrivate::WatcherList& list = *it; + for (TQT_DBusConnectionPrivate::WatcherList::iterator wit = list.begin(); wit != list.end(); + ++wit) + { + if ((*wit).watch == watch) { + bool enabled = dbus_watch_get_enabled(watch); + int flags = dbus_watch_get_flags(watch); + +// tqDebug("toggle watch %d to %d (write: %d, read: %d)", +// dbus_watch_get_unix_fd(watch), enabled, +// flags & DBUS_WATCH_WRITABLE, flags & DBUS_WATCH_READABLE); + + if (flags & DBUS_WATCH_READABLE && (*wit).read) + (*wit).read->setEnabled(enabled); + if (flags & DBUS_WATCH_WRITABLE && (*wit).write) + (*wit).write->setEnabled(enabled); + return; + } + } + } +} + +static void qDBusNewConnection(DBusServer *server, DBusConnection *c, void *data) +{ + Q_ASSERT(data); Q_ASSERT(server); Q_ASSERT(c); + + tqDebug("SERVER: GOT A NEW CONNECTION"); // TODO +} + +static DBusHandlerResult qDBusSignalFilter(DBusConnection *connection, + DBusMessage *message, void *data) +{ + Q_ASSERT(data); + Q_UNUSED(connection); + + TQT_DBusConnectionPrivate *d = static_cast<TQT_DBusConnectionPrivate *>(data); + if (d->mode == TQT_DBusConnectionPrivate::InvalidMode) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + int msgType = dbus_message_get_type(message); + bool handled = false; + + //TQT_DBusMessage amsg = TQT_DBusMessage::fromDBusMessage(message); + //tqDebug() << "got message: " << dbus_message_get_type(message) << amsg; + + if (msgType == DBUS_MESSAGE_TYPE_SIGNAL) { + handled = d->handleSignal(message); + } else if (msgType == DBUS_MESSAGE_TYPE_METHOD_CALL) { + handled = d->handleObjectCall(message); + } + + return handled ? DBUS_HANDLER_RESULT_HANDLED : + DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +int TQT_DBusConnectionPrivate::registerMessageMetaType() +{ + // FIXME-QT4 int tp = messageMetaType = qRegisterMetaType<TQT_DBusMessage>("TQT_DBusMessage"); + int tp = 0; + return tp; +} + +TQT_DBusConnectionPrivate::TQT_DBusConnectionPrivate(TQObject *parent) + : TQObject(parent), ref(1), mode(InvalidMode), connection(0), server(0), + dispatcher(0), inDispatch(false) +{ + static const int msgType = registerMessageMetaType(); + Q_UNUSED(msgType); + + dbus_error_init(&error); + + dispatcher = new TQTimer(this); + TQObject::connect(dispatcher, TQT_SIGNAL(timeout()), this, TQT_SLOT(dispatch())); + + m_resultEmissionQueueTimer = new TQTimer(this); + TQObject::connect(m_resultEmissionQueueTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(transmitResultEmissionQueue())); + m_messageEmissionQueueTimer = new TQTimer(this); + TQObject::connect(m_messageEmissionQueueTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(transmitMessageEmissionQueue())); +} + +TQT_DBusConnectionPrivate::~TQT_DBusConnectionPrivate() +{ + for (PendingCallMap::iterator it = pendingCalls.begin(); it != pendingCalls.end();) + { + PendingCallMap::iterator copyIt = it; + ++it; + dbus_pending_call_cancel(copyIt.key()); + dbus_pending_call_unref(copyIt.key()); + delete copyIt.data(); + pendingCalls.erase(copyIt); + } + + if (dbus_error_is_set(&error)) + dbus_error_free(&error); + + closeConnection(); +} + +void TQT_DBusConnectionPrivate::closeConnection() +{ + ConnectionMode oldMode = mode; + mode = InvalidMode; // prevent reentrancy + if (oldMode == ServerMode) { + if (server) { + dbus_server_disconnect(server); + dbus_server_unref(server); + server = 0; + } + } else if (oldMode == ClientMode) { + if (connection) { + // closing shared connections is forbidden +#if 0 + dbus_connection_close(connection); + // send the "close" message + while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS); +#endif + dbus_connection_unref(connection); + connection = 0; + } + } +} + +bool TQT_DBusConnectionPrivate::handleError() +{ + lastError = TQT_DBusError(&error); + if (dbus_error_is_set(&error)) + dbus_error_free(&error); + return lastError.isValid(); +} + +void TQT_DBusConnectionPrivate::emitPendingCallReply(const TQT_DBusMessage& message) +{ + emit dbusPendingCallReply(message); +} + +void TQT_DBusConnectionPrivate::bindToApplication() +{ + // Yay, now that we have an application we are in business + // Re-add all watchers + WatcherHash oldWatchers = watchers; + watchers.clear(); + // FIXME-QT4 TQHashIterator<int, TQT_DBusConnectionPrivate::Watcher> it(oldWatchers); + for (WatcherHash::const_iterator it = oldWatchers.begin(); it != oldWatchers.end(); ++it) + { + const WatcherList& list = *it; + for (WatcherList::const_iterator wit = list.begin(); wit != list.end(); ++wit) + { + if (!(*wit).read && !(*wit).write) { + qDBusAddWatch((*wit).watch, this); + } + } + } + + // Re-add all timeouts + while (!pendingTimeouts.isEmpty()) { + qDBusAddTimeout(pendingTimeouts.first(), this); + pendingTimeouts.pop_front(); + } +} + +void TQT_DBusConnectionPrivate::socketRead(int fd) +{ + // FIXME-QT4 TQHashIterator<int, TQT_DBusConnectionPrivate::Watcher> it(watchers); + WatcherHash::const_iterator it = watchers.find(fd); + if (it != watchers.end()) { + const WatcherList& list = *it; + for (WatcherList::const_iterator wit = list.begin(); wit != list.end(); ++wit) { + if ((*wit).read && (*wit).read->isEnabled()) { + if (!dbus_watch_handle((*wit).watch, DBUS_WATCH_READABLE)) + tqDebug("OUT OF MEM"); + } + } + } + if (mode == ClientMode) + scheduleDispatch(); +} + +void TQT_DBusConnectionPrivate::socketWrite(int fd) +{ + // FIXME-QT4 TQHashIterator<int, TQT_DBusConnectionPrivate::Watcher> it(watchers); + WatcherHash::const_iterator it = watchers.find(fd); + if (it != watchers.end()) { + const WatcherList& list = *it; + for (WatcherList::const_iterator wit = list.begin(); wit != list.end(); ++wit) { + if ((*wit).write && (*wit).write->isEnabled()) { + if (!dbus_watch_handle((*wit).watch, DBUS_WATCH_WRITABLE)) + tqDebug("OUT OF MEM"); + } + } + } +} + +void TQT_DBusConnectionPrivate::objectDestroyed(TQObject* object) +{ + //tqDebug("Object destroyed"); + for (PendingCallMap::iterator it = pendingCalls.begin(); it != pendingCalls.end();) + { + TQObject* receiver = (TQObject*) it.data()->receiver; + if (receiver == object || receiver == 0) + { + PendingCallMap::iterator copyIt = it; + ++it; + + dbus_pending_call_cancel(copyIt.key()); + dbus_pending_call_unref(copyIt.key()); + delete copyIt.data(); + pendingCalls.erase(copyIt); + } + else + ++it; + } +} + +void TQT_DBusConnectionPrivate::purgeRemovedWatches() +{ + if (removedWatches.isEmpty()) return; + + WatcherList::iterator listIt = removedWatches.begin(); + for (; listIt != removedWatches.end(); ++listIt) + { + delete (*listIt).read; + delete (*listIt).write; + } + removedWatches.clear(); + + uint count = 0; + WatcherHash::iterator it = watchers.begin(); + while (it != watchers.end()) + { + WatcherList& list = *it; + listIt = list.begin(); + while (listIt != list.end()) + { + if (!((*listIt).read) && !((*listIt).write)) + { + listIt = list.erase(listIt); + ++count; + } + } + + if (list.isEmpty()) + { + WatcherHash::iterator copyIt = it; + ++it; + watchers.erase(copyIt); + } + else + ++it; + } +} + +void TQT_DBusConnectionPrivate::scheduleDispatch() +{ + dispatcher->start(0); +} + +void TQT_DBusConnectionPrivate::dispatch() +{ + // dbus_connection_dispatch will hang if called recursively + if (inDispatch) { + printf("[dbus-1-tqt] WARNING: Attempt to call dispatch() recursively was silently ignored to prevent lockup!\n\r"); fflush(stdout); + return; + } + inDispatch = true; + + if (mode == ClientMode) + { + if (dbus_connection_dispatch(connection) != DBUS_DISPATCH_DATA_REMAINS) + { + // stop dispatch timer + dispatcher->stop(); + } + } + + inDispatch = false; +} + +void TQT_DBusConnectionPrivate::transmitMessageEmissionQueue() +{ + TQT_DBusConnectionPrivate::PendingMessagesForEmit::iterator pmfe; + pmfe = pendingMessages.begin(); + while (pmfe != pendingMessages.end()) { + TQT_DBusMessage msg = *pmfe; + pmfe = pendingMessages.remove(pmfe); + dbusSignal(msg); + } +} + +bool TQT_DBusConnectionPrivate::handleObjectCall(DBusMessage *message) +{ + TQT_DBusMessage msg = TQT_DBusMessage::fromDBusMessage(message); + + ObjectMap::iterator it = registeredObjects.find(msg.path()); + if (it == registeredObjects.end()) + return false; + + return it.data()->handleMethodCall(msg); +} + +bool TQT_DBusConnectionPrivate::handleSignal(DBusMessage *message) +{ + TQT_DBusMessage msg = TQT_DBusMessage::fromDBusMessage(message); + + // yes, it is a single "|" below... + // FIXME-QT4 + //return handleSignal(TQString(), msg) | handleSignal(msg.path(), msg); + + // If dbusSignal(msg) were called here, it could easily cause a lockup as it would enter the TQt3 event loop, + // which could result in arbitrary methods being called while still inside dbus_connection_dispatch. + // Instead, I enqueue the messages here for TQt3 event loop transmission after dbus_connection_dispatch is finished. + pendingMessages.append(msg); + if (!m_messageEmissionQueueTimer->isActive()) m_messageEmissionQueueTimer->start(0, TRUE); + + return true; +} + +static dbus_int32_t server_slot = -1; + +void TQT_DBusConnectionPrivate::setServer(DBusServer *s) +{ + if (!server) { + handleError(); + return; + } + + server = s; + mode = ServerMode; + + dbus_server_allocate_data_slot(&server_slot); + if (server_slot < 0) + return; + + dbus_server_set_watch_functions(server, qDBusAddWatch, qDBusRemoveWatch, + qDBusToggleWatch, this, 0); // ### check return type? + dbus_server_set_timeout_functions(server, qDBusAddTimeout, qDBusRemoveTimeout, + qDBusToggleTimeout, this, 0); + dbus_server_set_new_connection_function(server, qDBusNewConnection, this, 0); + + dbus_server_set_data(server, server_slot, this, 0); +} + +void TQT_DBusConnectionPrivate::setConnection(DBusConnection *dbc) +{ + if (!dbc) { + handleError(); + return; + } + + connection = dbc; + mode = ClientMode; + + dbus_connection_set_exit_on_disconnect(connection, false); + dbus_connection_set_watch_functions(connection, qDBusAddWatch, qDBusRemoveWatch, + qDBusToggleWatch, this, 0); + dbus_connection_set_timeout_functions(connection, qDBusAddTimeout, qDBusRemoveTimeout, + qDBusToggleTimeout, this, 0); +// dbus_bus_add_match(connection, "type='signal',interface='com.trolltech.dbus.Signal'", &error); +// dbus_bus_add_match(connection, "type='signal'", &error); + + dbus_bus_add_match(connection, "type='signal'", &error); + if (handleError()) { + closeConnection(); + return; + } + + const char *service = dbus_bus_get_unique_name(connection); + if (service) { + TQCString filter; + filter += "destination='"; + filter += service; + filter += "\'"; + + dbus_bus_add_match(connection, filter.data(), &error); + if (handleError()) { + closeConnection(); + return; + } + } else { + tqWarning("TQT_DBusConnectionPrivate::SetConnection: Unable to get unique name"); + } + + dbus_connection_add_filter(connection, qDBusSignalFilter, this, 0); + + //tqDebug("unique name: %s", service); +} + +static void qDBusResultReceived(DBusPendingCall *pending, void *user_data) +{ + //tqDebug("Pending Call Result received"); + TQT_DBusConnectionPrivate* d = reinterpret_cast<TQT_DBusConnectionPrivate*>(user_data); + TQT_DBusConnectionPrivate::PendingCallMap::iterator it = d->pendingCalls.find(pending); + + DBusMessage *dbusReply = dbus_pending_call_steal_reply(pending); + + dbus_set_error_from_message(&d->error, dbusReply); + d->handleError(); + + if (it != d->pendingCalls.end()) + { + TQT_DBusMessage reply = TQT_DBusMessage::fromDBusMessage(dbusReply); + + TQT_DBusResultInfo dbusResult; + dbusResult.message = reply; + dbusResult.receiver = it.data()->receiver; + dbusResult.method = it.data()->method.data(); + d->m_resultEmissionQueue.append(dbusResult); + d->newMethodInResultEmissionQueue(); + } + + dbus_message_unref(dbusReply); + dbus_pending_call_unref(pending); + delete it.data(); + + d->pendingCalls.erase(it); +} + +int TQT_DBusConnectionPrivate::sendWithReplyAsync(const TQT_DBusMessage &message, TQObject *receiver, + const char *method) +{ + if (!receiver || !method) + return 0; + + if (!TQObject::connect(receiver, TQT_SIGNAL(destroyed(TQObject*)), + this, TQT_SLOT(objectDestroyed(TQObject*)))) + return false; + + DBusMessage *msg = message.toDBusMessage(); + if (!msg) + return 0; + + int msg_serial = 0; + DBusPendingCall *pending = 0; + if (dbus_connection_send_with_reply(connection, msg, &pending, message.timeout())) { + TQT_DBusPendingCall *pcall = new TQT_DBusPendingCall; + pcall->receiver = receiver; + pcall->method = method; + pcall->pending = pending; + pendingCalls.insert(pcall->pending, pcall); + + dbus_pending_call_set_notify(pending, qDBusResultReceived, this, 0); + + msg_serial = dbus_message_get_serial(msg); + } + + dbus_message_unref(msg); + return msg_serial; +} + +void TQT_DBusConnectionPrivate::flush() +{ + if (!connection) return; + + dbus_connection_flush(connection); +} + +void TQT_DBusConnectionPrivate::newMethodInResultEmissionQueue() +{ + if (!m_resultEmissionQueueTimer->isActive()) m_resultEmissionQueueTimer->start(0, TRUE); +} + +void TQT_DBusConnectionPrivate::transmitResultEmissionQueue() +{ + if (!m_resultEmissionQueue.isEmpty()) { + TQT_DBusResultInfoList::Iterator it; + it = m_resultEmissionQueue.begin(); + while (it != m_resultEmissionQueue.end()) { + TQT_DBusResultInfo dbusResult = (*it); + m_resultEmissionQueue.remove(it); + it = m_resultEmissionQueue.begin(); + + TQObject::connect(this, TQT_SIGNAL(dbusPendingCallReply(const TQT_DBusMessage&)), dbusResult.receiver, dbusResult.method.data()); + emitPendingCallReply(dbusResult.message); + TQObject::disconnect(this, TQT_SIGNAL(dbusPendingCallReply(const TQT_DBusMessage&)), dbusResult.receiver, dbusResult.method.data()); + } + } +} + +#include "tqdbusconnection_p.moc" diff --git a/src/tqdbusmacros.h b/src/tqdbusmacros.h new file mode 100644 index 0000000..2470094 --- /dev/null +++ b/src/tqdbusmacros.h @@ -0,0 +1,31 @@ +/* qdbusmacros TQDBUS macro definitions + * + * Copyright (C) 2005 Kevin Krammer <kevin.krammer@gmx.at> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#ifndef TQDBUSMACROS_H +#define TQDBUSMACROS_H + +#include <tqglobal.h> + +#define TQDBUS_EXPORT TQ_EXPORT + +#endif diff --git a/src/tqdbusmarshall.cpp b/src/tqdbusmarshall.cpp new file mode 100644 index 0000000..7f0781f --- /dev/null +++ b/src/tqdbusmarshall.cpp @@ -0,0 +1,1254 @@ +/* qdbusmarshall.cpp + * + * Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org> + * Copyright (C) 2007 Kevin Krammer <kevin.krammer@gmx.at> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#include "tqdbusmarshall.h" +#include "tqdbusdata.h" +#include "tqdbusdatalist.h" +#include "tqdbusdatamap.h" +#include "tqdbusobjectpath.h" +#include "tqdbusunixfd.h" +#include "tqdbusvariant.h" + +#include <tqvariant.h> +#include <tqvaluelist.h> +#include <tqmap.h> +#include <tqstringlist.h> +#include <tqvaluevector.h> + +#include <dbus/dbus.h> + +template <typename T> +inline T qIterGet(DBusMessageIter *it) +{ + T t; + dbus_message_iter_get_basic(it, &t); + return t; +} + +static TQT_DBusData::Type qSingleTypeForDBusSignature(char signature) +{ + switch (signature) + { + case 'b': return TQT_DBusData::Bool; + case 'y': return TQT_DBusData::Byte; + case 'n': return TQT_DBusData::Int16; + case 'q': return TQT_DBusData::UInt16; + case 'i': return TQT_DBusData::Int32; + case 'u': return TQT_DBusData::UInt32; + case 'x': return TQT_DBusData::Int64; + case 't': return TQT_DBusData::UInt64; + case 'd': return TQT_DBusData::Double; + case 's': return TQT_DBusData::String; + case 'o': return TQT_DBusData::ObjectPath; + case 'g': return TQT_DBusData::String; + case 'v': return TQT_DBusData::Variant; + case 'h': return TQT_DBusData::UnixFd; + + default: + break; + } + + return TQT_DBusData::Invalid; +} + +static TQValueList<TQT_DBusData> parseSignature(TQCString& signature) +{ +// tqDebug("parseSignature(%s)", signature.data()); + TQValueList<TQT_DBusData> result; + + while (!signature.isEmpty()) + { + switch (signature[0]) + { + case '(': { + signature = signature.mid(1); + TQValueList<TQT_DBusData> memberList = parseSignature(signature); + result << TQT_DBusData::fromStruct(memberList); + Q_ASSERT(!signature.isEmpty() && signature[0] == ')'); + signature = signature.mid(1); + break; + } + case ')': return result; + case '{': { + TQT_DBusData::Type keyType = + qSingleTypeForDBusSignature(signature[1]); + TQT_DBusData::Type valueType = + qSingleTypeForDBusSignature(signature[2]); + if (valueType != TQT_DBusData::Invalid) + { + switch (keyType) + { + case TQT_DBusData::Byte: + result << TQT_DBusData::fromByteKeyMap( + TQT_DBusDataMap<TQ_UINT8>(valueType)); + break; + case TQT_DBusData::Int16: + result << TQT_DBusData::fromInt16KeyMap( + TQT_DBusDataMap<TQ_INT16>(valueType)); + break; + case TQT_DBusData::UInt16: + result << TQT_DBusData::fromUInt16KeyMap( + TQT_DBusDataMap<TQ_UINT16>(valueType)); + break; + case TQT_DBusData::Int32: + result << TQT_DBusData::fromInt32KeyMap( + TQT_DBusDataMap<TQ_INT32>(valueType)); + break; + case TQT_DBusData::UInt32: + result << TQT_DBusData::fromUInt32KeyMap( + TQT_DBusDataMap<TQ_UINT32>(valueType)); + break; + case TQT_DBusData::Int64: + result << TQT_DBusData::fromInt64KeyMap( + TQT_DBusDataMap<TQ_INT64>(valueType)); + break; + case TQT_DBusData::UInt64: + result << TQT_DBusData::fromUInt64KeyMap( + TQT_DBusDataMap<TQ_UINT64>(valueType)); + break; + case TQT_DBusData::String: + result << TQT_DBusData::fromStringKeyMap( + TQT_DBusDataMap<TQString>(valueType)); + break; + case TQT_DBusData::ObjectPath: + result << TQT_DBusData::fromObjectPathKeyMap( + TQT_DBusDataMap<TQT_DBusObjectPath>(valueType)); + break; + case TQT_DBusData::UnixFd: + result << TQT_DBusData::fromUnixFdKeyMap( + TQT_DBusDataMap<TQT_DBusUnixFd>(valueType)); + break; + default: + tqWarning("TQT_DBusMarshall: unsupported map key type %s " + "at de-marshalling", + TQT_DBusData::typeName(keyType)); + break; + } + signature = signature.mid(3); + } + else + { + signature = signature.mid(2); + TQValueList<TQT_DBusData> valueContainer = + parseSignature(signature); + Q_ASSERT(valueContainer.count() == 1); + + switch (keyType) + { + case TQT_DBusData::Byte: + result << TQT_DBusData::fromByteKeyMap( + TQT_DBusDataMap<TQ_UINT8>(valueContainer[0])); + break; + case TQT_DBusData::Int16: + result << TQT_DBusData::fromInt16KeyMap( + TQT_DBusDataMap<TQ_INT16>(valueContainer[0])); + break; + case TQT_DBusData::UInt16: + result << TQT_DBusData::fromUInt16KeyMap( + TQT_DBusDataMap<TQ_UINT16>(valueContainer[0])); + break; + case TQT_DBusData::Int32: + result << TQT_DBusData::fromInt32KeyMap( + TQT_DBusDataMap<TQ_INT32>(valueContainer[0])); + break; + case TQT_DBusData::UInt32: + result << TQT_DBusData::fromUInt32KeyMap( + TQT_DBusDataMap<TQ_UINT32>(valueContainer[0])); + break; + case TQT_DBusData::Int64: + result << TQT_DBusData::fromInt64KeyMap( + TQT_DBusDataMap<TQ_INT64>(valueContainer[0])); + break; + case TQT_DBusData::UInt64: + result << TQT_DBusData::fromUInt64KeyMap( + TQT_DBusDataMap<TQ_UINT64>(valueContainer[0])); + break; + case TQT_DBusData::String: + result << TQT_DBusData::fromStringKeyMap( + TQT_DBusDataMap<TQString>(valueContainer[0])); + break; + case TQT_DBusData::ObjectPath: + result << TQT_DBusData::fromObjectPathKeyMap( + TQT_DBusDataMap<TQT_DBusObjectPath>(valueContainer[0])); + break; + case TQT_DBusData::UnixFd: + result << TQT_DBusData::fromUnixFdKeyMap( + TQT_DBusDataMap<TQT_DBusUnixFd>(valueContainer[0])); + break; + default: + tqWarning("TQT_DBusMarshall: unsupported map key type %s " + "at de-marshalling", + TQT_DBusData::typeName(keyType)); + break; + } + } + Q_ASSERT(!signature.isEmpty() && signature[0] == '}'); + signature = signature.mid(1); + break; + } + case '}': return result; + case 'a': { + TQT_DBusData::Type elementType = + qSingleTypeForDBusSignature(signature[1]); + if (elementType != TQT_DBusData::Invalid) + { + TQT_DBusDataList list(elementType); + result << TQT_DBusData::fromList(list); + signature = signature.mid(2); + } + else + { + signature = signature.mid(1); + bool array = signature[0] != '{'; + + TQValueList<TQT_DBusData> elementContainer = + parseSignature(signature); + Q_ASSERT(elementContainer.count() == 1); + + if (array) + { + TQT_DBusDataList list(elementContainer[0]); + result << TQT_DBusData::fromList(list); + } + else + result << elementContainer[0]; + } + break; + } + default: + TQT_DBusData::Type elementType = + qSingleTypeForDBusSignature(signature[0]); + if (elementType != TQT_DBusData::Invalid) + { + switch (elementType) + { + case TQT_DBusData::Bool: + result << TQT_DBusData::fromBool( + (0)); + break; + case TQT_DBusData::Byte: + result << TQT_DBusData::fromByte( + (0)); + break; + case TQT_DBusData::Int16: + result << TQT_DBusData::fromInt16( + (0)); + break; + case TQT_DBusData::UInt16: + result << TQT_DBusData::fromUInt16( + (0)); + break; + case TQT_DBusData::Int32: + result << TQT_DBusData::fromInt32( + (0)); + break; + case TQT_DBusData::UInt32: + result << TQT_DBusData::fromUInt32( + (0)); + break; + case TQT_DBusData::Int64: + result << TQT_DBusData::fromInt64( + (0)); + break; + case TQT_DBusData::UInt64: + result << TQT_DBusData::fromUInt64( + (0)); + break; + case TQT_DBusData::String: + result << TQT_DBusData::fromString( + (TQString())); + break; + case TQT_DBusData::ObjectPath: + result << TQT_DBusData::fromObjectPath( + (TQT_DBusObjectPath())); + break; + case TQT_DBusData::UnixFd: + result << TQT_DBusData::fromUnixFd( + (TQT_DBusUnixFd())); + break; + default: + result << TQT_DBusData(); + tqWarning("TQT_DBusMarshall: unsupported element type %s " + "at de-marshalling", + TQT_DBusData::typeName(elementType)); + break; + } + signature = signature.mid(1); + } + else { + result << TQT_DBusData(); + signature = signature.mid(1); + } + break; + } + } + + return result; +} + +static TQT_DBusData qFetchParameter(DBusMessageIter *it); + +void qFetchByteKeyMapEntry(TQT_DBusDataMap<TQ_UINT8>& map, DBusMessageIter* it) +{ + DBusMessageIter itemIter; + dbus_message_iter_recurse(it, &itemIter); + Q_ASSERT(dbus_message_iter_has_next(&itemIter)); + + TQ_UINT8 key = qFetchParameter(&itemIter).toByte(); + + dbus_message_iter_next(&itemIter); + + map.insert(key, qFetchParameter(&itemIter)); +} + +void qFetchInt16KeyMapEntry(TQT_DBusDataMap<TQ_INT16>& map, DBusMessageIter* it) +{ + DBusMessageIter itemIter; + dbus_message_iter_recurse(it, &itemIter); + Q_ASSERT(dbus_message_iter_has_next(&itemIter)); + + TQ_INT16 key = qFetchParameter(&itemIter).toInt16(); + + dbus_message_iter_next(&itemIter); + + map.insert(key, qFetchParameter(&itemIter)); +} + +void qFetchUInt16KeyMapEntry(TQT_DBusDataMap<TQ_UINT16>& map, DBusMessageIter* it) +{ + DBusMessageIter itemIter; + dbus_message_iter_recurse(it, &itemIter); + Q_ASSERT(dbus_message_iter_has_next(&itemIter)); + + TQ_UINT16 key = qFetchParameter(&itemIter).toUInt16(); + + dbus_message_iter_next(&itemIter); + + map.insert(key, qFetchParameter(&itemIter)); +} + +void qFetchInt32KeyMapEntry(TQT_DBusDataMap<TQ_INT32>& map, DBusMessageIter* it) +{ + DBusMessageIter itemIter; + dbus_message_iter_recurse(it, &itemIter); + Q_ASSERT(dbus_message_iter_has_next(&itemIter)); + + TQ_INT32 key = qFetchParameter(&itemIter).toInt32(); + + dbus_message_iter_next(&itemIter); + + map.insert(key, qFetchParameter(&itemIter)); +} + +void qFetchUInt32KeyMapEntry(TQT_DBusDataMap<TQ_UINT32>& map, DBusMessageIter* it) +{ + DBusMessageIter itemIter; + dbus_message_iter_recurse(it, &itemIter); + Q_ASSERT(dbus_message_iter_has_next(&itemIter)); + + TQ_UINT32 key = qFetchParameter(&itemIter).toUInt32(); + + dbus_message_iter_next(&itemIter); + + map.insert(key, qFetchParameter(&itemIter)); +} + +void qFetchInt64KeyMapEntry(TQT_DBusDataMap<TQ_INT64>& map, DBusMessageIter* it) +{ + DBusMessageIter itemIter; + dbus_message_iter_recurse(it, &itemIter); + Q_ASSERT(dbus_message_iter_has_next(&itemIter)); + + TQ_INT64 key = qFetchParameter(&itemIter).toInt64(); + + dbus_message_iter_next(&itemIter); + + map.insert(key, qFetchParameter(&itemIter)); +} + +void qFetchUInt64KeyMapEntry(TQT_DBusDataMap<TQ_UINT64>& map, DBusMessageIter* it) +{ + DBusMessageIter itemIter; + dbus_message_iter_recurse(it, &itemIter); + Q_ASSERT(dbus_message_iter_has_next(&itemIter)); + + TQ_UINT64 key = qFetchParameter(&itemIter).toUInt64(); + + dbus_message_iter_next(&itemIter); + + map.insert(key, qFetchParameter(&itemIter)); +} + +void qFetchObjectPathKeyMapEntry(TQT_DBusDataMap<TQT_DBusObjectPath>& map, DBusMessageIter* it) +{ + DBusMessageIter itemIter; + dbus_message_iter_recurse(it, &itemIter); + Q_ASSERT(dbus_message_iter_has_next(&itemIter)); + + TQT_DBusObjectPath key = qFetchParameter(&itemIter).toObjectPath(); + + dbus_message_iter_next(&itemIter); + + map.insert(key, qFetchParameter(&itemIter)); +} + +void qFetchStringKeyMapEntry(TQT_DBusDataMap<TQString>& map, DBusMessageIter* it) +{ + DBusMessageIter itemIter; + dbus_message_iter_recurse(it, &itemIter); + Q_ASSERT(dbus_message_iter_has_next(&itemIter)); + + TQString key = qFetchParameter(&itemIter).toString(); + + dbus_message_iter_next(&itemIter); + + map.insert(key, qFetchParameter(&itemIter)); +} + +static TQT_DBusData qFetchMap(DBusMessageIter *it, const TQT_DBusData& prototype) +{ + if (dbus_message_iter_get_arg_type(it) == DBUS_TYPE_INVALID) + return prototype; + + DBusMessageIter itemIter; + dbus_message_iter_recurse(it, &itemIter); + if (dbus_message_iter_get_arg_type(&itemIter) == DBUS_TYPE_INVALID) + return prototype; + + switch (dbus_message_iter_get_arg_type(&itemIter)) { + case DBUS_TYPE_BYTE: { + TQT_DBusDataMap<TQ_UINT8> map = prototype.toByteKeyMap(); + do { + qFetchByteKeyMapEntry(map, it); + } while (dbus_message_iter_next(it)); + + return TQT_DBusData::fromByteKeyMap(map); + } + + case DBUS_TYPE_INT16: { + TQT_DBusDataMap<TQ_INT16> map = prototype.toInt16KeyMap(); + do { + qFetchInt16KeyMapEntry(map, it); + } while (dbus_message_iter_next(it)); + + return TQT_DBusData::fromInt16KeyMap(map); + } + + case DBUS_TYPE_UINT16: { + TQT_DBusDataMap<TQ_UINT16> map = prototype.toUInt16KeyMap(); + do { + qFetchUInt16KeyMapEntry(map, it); + } while (dbus_message_iter_next(it)); + + return TQT_DBusData::fromUInt16KeyMap(map); + } + + case DBUS_TYPE_INT32: { + TQT_DBusDataMap<TQ_INT32> map = prototype.toInt32KeyMap(); + do { + qFetchInt32KeyMapEntry(map, it); + } while (dbus_message_iter_next(it)); + + return TQT_DBusData::fromInt32KeyMap(map); + } + + case DBUS_TYPE_UINT32: { + TQT_DBusDataMap<TQ_UINT32> map = prototype.toUInt32KeyMap(); + do { + qFetchUInt32KeyMapEntry(map, it); + } while (dbus_message_iter_next(it)); + + return TQT_DBusData::fromUInt32KeyMap(map); + } + + case DBUS_TYPE_INT64: { + TQT_DBusDataMap<TQ_INT64> map = prototype.toInt64KeyMap(); + do { + qFetchInt64KeyMapEntry(map, it); + } while (dbus_message_iter_next(it)); + + return TQT_DBusData::fromInt64KeyMap(map); + } + + case DBUS_TYPE_UINT64: { + TQT_DBusDataMap<TQ_UINT64> map = prototype.toUInt64KeyMap(); + do { + qFetchUInt64KeyMapEntry(map, it); + } while (dbus_message_iter_next(it)); + + return TQT_DBusData::fromUInt64KeyMap(map); + } + + case DBUS_TYPE_OBJECT_PATH: { + TQT_DBusDataMap<TQT_DBusObjectPath> map = prototype.toObjectPathKeyMap(); + do { + qFetchObjectPathKeyMapEntry(map, it); + } while (dbus_message_iter_next(it)); + + return TQT_DBusData::fromObjectPathKeyMap(map); + } + case DBUS_TYPE_STRING: // fall through + case DBUS_TYPE_SIGNATURE: { + TQT_DBusDataMap<TQString> map = prototype.toStringKeyMap(); + do { + qFetchStringKeyMapEntry(map, it); + } while (dbus_message_iter_next(it)); + + return TQT_DBusData::fromStringKeyMap(map); + } + + default: + break; + } + + return prototype; +} + +static TQT_DBusData qFetchParameter(DBusMessageIter *it) +{ + switch (dbus_message_iter_get_arg_type(it)) { + case DBUS_TYPE_BOOLEAN: + return TQT_DBusData::fromBool(qIterGet<dbus_bool_t>(it)); + case DBUS_TYPE_BYTE: + return TQT_DBusData::fromByte(qIterGet<unsigned char>(it)); + case DBUS_TYPE_INT16: + return TQT_DBusData::fromInt16(qIterGet<dbus_int16_t>(it)); + case DBUS_TYPE_UINT16: + return TQT_DBusData::fromUInt16(qIterGet<dbus_uint16_t>(it)); + case DBUS_TYPE_INT32: + return TQT_DBusData::fromInt32(qIterGet<dbus_int32_t>(it)); + case DBUS_TYPE_UINT32: + return TQT_DBusData::fromUInt32(qIterGet<dbus_uint32_t>(it)); + case DBUS_TYPE_INT64: + return TQT_DBusData::fromInt64(qIterGet<dbus_int64_t>(it)); + case DBUS_TYPE_UINT64: + return TQT_DBusData::fromUInt64(qIterGet<dbus_uint64_t>(it)); + case DBUS_TYPE_DOUBLE: + return TQT_DBusData::fromDouble(qIterGet<double>(it)); + case DBUS_TYPE_STRING: + case DBUS_TYPE_SIGNATURE: + return TQT_DBusData::fromString(TQString::fromUtf8(qIterGet<char *>(it))); + case DBUS_TYPE_OBJECT_PATH: + return TQT_DBusData::fromObjectPath(TQT_DBusObjectPath(qIterGet<char *>(it))); + case DBUS_TYPE_ARRAY: { + int arrayType = dbus_message_iter_get_element_type(it); + + char* sig = dbus_message_iter_get_signature(it); + TQCString signature = sig; + dbus_free(sig); + + TQValueList<TQT_DBusData> prototypeList = parseSignature(signature); + + if (arrayType == DBUS_TYPE_DICT_ENTRY) { + DBusMessageIter sub; + dbus_message_iter_recurse(it, &sub); + + return qFetchMap(&sub, prototypeList[0]); + } else { + TQT_DBusDataList list = prototypeList[0].toList(); + + DBusMessageIter arrayIt; + dbus_message_iter_recurse(it, &arrayIt); + + while (dbus_message_iter_get_arg_type(&arrayIt) != DBUS_TYPE_INVALID) { + list << qFetchParameter(&arrayIt); + + dbus_message_iter_next(&arrayIt); + } + + return TQT_DBusData::fromList(list); + } + } + case DBUS_TYPE_VARIANT: { + TQT_DBusVariant dvariant; + DBusMessageIter sub; + dbus_message_iter_recurse(it, &sub); + + char* signature = dbus_message_iter_get_signature(&sub); + dvariant.signature = TQString::fromUtf8(signature); + dbus_free(signature); + + dvariant.value = qFetchParameter(&sub); + + return TQT_DBusData::fromVariant(dvariant); + } + case DBUS_TYPE_STRUCT: { + TQValueList<TQT_DBusData> memberList; + + DBusMessageIter subIt; + dbus_message_iter_recurse(it, &subIt); + + uint index = 0; + while (dbus_message_iter_get_arg_type(&subIt) != DBUS_TYPE_INVALID) { + memberList << qFetchParameter(&subIt); + + dbus_message_iter_next(&subIt); + ++index; + } + + return TQT_DBusData::fromStruct(memberList); + } + case DBUS_TYPE_UNIX_FD: { + TQT_DBusUnixFd unixFd; + unixFd.giveFileDescriptor(qIterGet<dbus_uint32_t>(it)); + return TQT_DBusData::fromUnixFd(unixFd); + } +#if 0 + case DBUS_TYPE_INVALID: + // TODO: check if there is better way to detect empty arrays + return TQT_DBusData(); + break; +#endif + default: + tqWarning("TQT_DBusMarshall: Don't know how to de-marshall type %d '%c'", + dbus_message_iter_get_arg_type(it), + dbus_message_iter_get_arg_type(it)); + return TQT_DBusData(); + break; + } +} + +void TQT_DBusMarshall::messageToList(TQValueList<TQT_DBusData>& list, DBusMessage* message) +{ + Q_ASSERT(message); + + DBusMessageIter it; + if (!dbus_message_iter_init(message, &it)) return; + + do + { + list << qFetchParameter(&it); + } + while (dbus_message_iter_next(&it)); +} + +static void tqAppendToMessage(DBusMessageIter *it, const TQString &str) +{ + TQByteArray ba = str.utf8(); + const char *cdata = ba.data(); + dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &cdata); +} + +static void tqAppendToMessage(DBusMessageIter *it, const TQT_DBusObjectPath &path) +{ + const char *cdata = path.data(); + dbus_message_iter_append_basic(it, DBUS_TYPE_OBJECT_PATH, &cdata); +} + +static void tqAppendToMessage(DBusMessageIter *it, const TQT_DBusUnixFd &unixFd) +{ + const dbus_int32_t cdata = unixFd.fileDescriptor(); + dbus_message_iter_append_basic(it, DBUS_TYPE_UNIX_FD, &cdata); +} + +static const char* qDBusTypeForTQT_DBusType(TQT_DBusData::Type type) +{ + switch (type) + { + case TQT_DBusData::Invalid: + return 0; + + case TQT_DBusData::Bool: + return DBUS_TYPE_BOOLEAN_AS_STRING; + + case TQT_DBusData::Byte: + return DBUS_TYPE_BYTE_AS_STRING; + + case TQT_DBusData::Int16: + return DBUS_TYPE_INT16_AS_STRING; + + case TQT_DBusData::UInt16: + return DBUS_TYPE_UINT16_AS_STRING; + + case TQT_DBusData::Int32: + return DBUS_TYPE_INT32_AS_STRING; + + case TQT_DBusData::UInt32: + return DBUS_TYPE_UINT32_AS_STRING; + + case TQT_DBusData::Int64: + return DBUS_TYPE_INT64_AS_STRING; + + case TQT_DBusData::UInt64: + return DBUS_TYPE_UINT64_AS_STRING; + + case TQT_DBusData::Double: + return DBUS_TYPE_DOUBLE_AS_STRING; + + case TQT_DBusData::String: + return DBUS_TYPE_STRING_AS_STRING; + + case TQT_DBusData::ObjectPath: + return DBUS_TYPE_OBJECT_PATH_AS_STRING; + + case TQT_DBusData::List: + return DBUS_TYPE_ARRAY_AS_STRING; + + case TQT_DBusData::Struct: + return DBUS_TYPE_STRUCT_AS_STRING; + + case TQT_DBusData::Variant: + return DBUS_TYPE_VARIANT_AS_STRING; + + case TQT_DBusData::Map: + return DBUS_TYPE_DICT_ENTRY_AS_STRING; + + case TQT_DBusData::UnixFd: + return DBUS_TYPE_UNIX_FD_AS_STRING; + } + return 0; +} + +static void qDBusDataToIterator(DBusMessageIter* it, const TQT_DBusData& var); + +static void qDBusByteKeyMapToIterator(DBusMessageIter* it, const TQT_DBusData& var) +{ + DBusMessageIter sub; + TQCString sig; + + TQT_DBusDataMap<TQ_UINT8> map = var.toByteKeyMap(); + + sig += DBUS_DICT_ENTRY_BEGIN_CHAR; + sig += qDBusTypeForTQT_DBusType(map.keyType()); + + if (map.hasContainerValueType()) + sig += map.containerValueType().buildDBusSignature(); + else + sig += qDBusTypeForTQT_DBusType(map.valueType()); + sig += DBUS_DICT_ENTRY_END_CHAR; + + dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, sig.data(), &sub); + + TQT_DBusDataMap<TQ_UINT8>::const_iterator mit = map.begin(); + for (; mit != map.end(); ++mit) + { + DBusMessageIter itemIterator; + dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, + 0, &itemIterator); + + dbus_message_iter_append_basic(it, DBUS_TYPE_BYTE, &(mit.key())); + qDBusDataToIterator(&itemIterator, mit.data()); + + dbus_message_iter_close_container(&sub, &itemIterator); + } + + dbus_message_iter_close_container(it, &sub); +} + +static void qDBusInt16KeyMapToIterator(DBusMessageIter* it, const TQT_DBusData& var) +{ + DBusMessageIter sub; + TQCString sig; + + TQT_DBusDataMap<TQ_INT16> map = var.toInt16KeyMap(); + + sig += DBUS_DICT_ENTRY_BEGIN_CHAR; + sig += qDBusTypeForTQT_DBusType(map.keyType()); + + if (map.hasContainerValueType()) + sig += map.containerValueType().buildDBusSignature(); + else + sig += qDBusTypeForTQT_DBusType(map.valueType()); + sig += DBUS_DICT_ENTRY_END_CHAR; + + dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, sig.data(), &sub); + + TQT_DBusDataMap<TQ_INT16>::const_iterator mit = map.begin(); + for (; mit != map.end(); ++mit) + { + DBusMessageIter itemIterator; + dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, + 0, &itemIterator); + + dbus_message_iter_append_basic(it, DBUS_TYPE_INT16, &(mit.key())); + qDBusDataToIterator(&itemIterator, mit.data()); + + dbus_message_iter_close_container(&sub, &itemIterator); + } + + dbus_message_iter_close_container(it, &sub); +} + +static void qDBusUInt16KeyMapToIterator(DBusMessageIter* it, const TQT_DBusData& var) +{ + DBusMessageIter sub; + TQCString sig; + + TQT_DBusDataMap<TQ_UINT16> map = var.toUInt16KeyMap(); + + sig += DBUS_DICT_ENTRY_BEGIN_CHAR; + sig += qDBusTypeForTQT_DBusType(map.keyType()); + + if (map.hasContainerValueType()) + sig += map.containerValueType().buildDBusSignature(); + else + sig += qDBusTypeForTQT_DBusType(map.valueType()); + sig += DBUS_DICT_ENTRY_END_CHAR; + + dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, sig.data(), &sub); + + TQT_DBusDataMap<TQ_UINT16>::const_iterator mit = map.begin(); + for (; mit != map.end(); ++mit) + { + DBusMessageIter itemIterator; + dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, + 0, &itemIterator); + + dbus_message_iter_append_basic(it, DBUS_TYPE_UINT16, &(mit.key())); + qDBusDataToIterator(&itemIterator, mit.data()); + + dbus_message_iter_close_container(&sub, &itemIterator); + } + + dbus_message_iter_close_container(it, &sub); +} + +static void qDBusInt32KeyMapToIterator(DBusMessageIter* it, const TQT_DBusData& var) +{ + DBusMessageIter sub; + TQCString sig; + + TQT_DBusDataMap<TQ_INT32> map = var.toInt32KeyMap(); + + sig += DBUS_DICT_ENTRY_BEGIN_CHAR; + sig += qDBusTypeForTQT_DBusType(map.keyType()); + + if (map.hasContainerValueType()) + sig += map.containerValueType().buildDBusSignature(); + else + sig += qDBusTypeForTQT_DBusType(map.valueType()); + sig += DBUS_DICT_ENTRY_END_CHAR; + + dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, sig.data(), &sub); + + TQT_DBusDataMap<TQ_INT32>::const_iterator mit = map.begin(); + for (; mit != map.end(); ++mit) + { + DBusMessageIter itemIterator; + dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, + 0, &itemIterator); + + dbus_message_iter_append_basic(it, DBUS_TYPE_INT32, &(mit.key())); + qDBusDataToIterator(&itemIterator, mit.data()); + + dbus_message_iter_close_container(&sub, &itemIterator); + } + + dbus_message_iter_close_container(it, &sub); +} + +static void qDBusUInt32KeyMapToIterator(DBusMessageIter* it, const TQT_DBusData& var) +{ + DBusMessageIter sub; + TQCString sig; + + TQT_DBusDataMap<TQ_UINT32> map = var.toUInt32KeyMap(); + + sig += DBUS_DICT_ENTRY_BEGIN_CHAR; + sig += qDBusTypeForTQT_DBusType(map.keyType()); + + if (map.hasContainerValueType()) + sig += map.containerValueType().buildDBusSignature(); + else + sig += qDBusTypeForTQT_DBusType(map.valueType()); + sig += DBUS_DICT_ENTRY_END_CHAR; + + dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, sig.data(), &sub); + + TQT_DBusDataMap<TQ_UINT32>::const_iterator mit = map.begin(); + for (; mit != map.end(); ++mit) + { + DBusMessageIter itemIterator; + dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, + 0, &itemIterator); + + dbus_message_iter_append_basic(it, DBUS_TYPE_UINT32, &(mit.key())); + qDBusDataToIterator(&itemIterator, mit.data()); + + dbus_message_iter_close_container(&sub, &itemIterator); + } + + dbus_message_iter_close_container(it, &sub); +} + +static void qDBusInt64KeyMapToIterator(DBusMessageIter* it, const TQT_DBusData& var) +{ + DBusMessageIter sub; + TQCString sig; + + TQT_DBusDataMap<TQ_INT64> map = var.toInt64KeyMap(); + + sig += DBUS_DICT_ENTRY_BEGIN_CHAR; + sig += qDBusTypeForTQT_DBusType(map.keyType()); + + if (map.hasContainerValueType()) + sig += map.containerValueType().buildDBusSignature(); + else + sig += qDBusTypeForTQT_DBusType(map.valueType()); + sig += DBUS_DICT_ENTRY_END_CHAR; + + dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, sig.data(), &sub); + + TQT_DBusDataMap<TQ_INT64>::const_iterator mit = map.begin(); + for (; mit != map.end(); ++mit) + { + DBusMessageIter itemIterator; + dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, + 0, &itemIterator); + + dbus_message_iter_append_basic(it, DBUS_TYPE_INT64, &(mit.key())); + qDBusDataToIterator(&itemIterator, mit.data()); + + dbus_message_iter_close_container(&sub, &itemIterator); + } + + dbus_message_iter_close_container(it, &sub); +} + +static void qDBusUInt64KeyMapToIterator(DBusMessageIter* it, const TQT_DBusData& var) +{ + DBusMessageIter sub; + TQCString sig; + + TQT_DBusDataMap<TQ_UINT64> map = var.toUInt64KeyMap(); + + sig += DBUS_DICT_ENTRY_BEGIN_CHAR; + sig += qDBusTypeForTQT_DBusType(map.keyType()); + + if (map.hasContainerValueType()) + sig += map.containerValueType().buildDBusSignature(); + else + sig += qDBusTypeForTQT_DBusType(map.valueType()); + sig += DBUS_DICT_ENTRY_END_CHAR; + + dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, sig.data(), &sub); + + TQT_DBusDataMap<TQ_UINT64>::const_iterator mit = map.begin(); + for (; mit != map.end(); ++mit) + { + DBusMessageIter itemIterator; + dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, + 0, &itemIterator); + + dbus_message_iter_append_basic(it, DBUS_TYPE_UINT64, &(mit.key())); + qDBusDataToIterator(&itemIterator, mit.data()); + + dbus_message_iter_close_container(&sub, &itemIterator); + } + + dbus_message_iter_close_container(it, &sub); +} + +static void qDBusStringKeyMapToIterator(DBusMessageIter* it, const TQT_DBusData& var) +{ + DBusMessageIter sub; + TQCString sig; + + TQT_DBusDataMap<TQString> map = var.toStringKeyMap(); + + sig += DBUS_DICT_ENTRY_BEGIN_CHAR; + sig += qDBusTypeForTQT_DBusType(map.keyType()); + + if (map.hasContainerValueType()) + sig += map.containerValueType().buildDBusSignature(); + else + sig += qDBusTypeForTQT_DBusType(map.valueType()); + sig += DBUS_DICT_ENTRY_END_CHAR; + + dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, sig.data(), &sub); + + TQT_DBusDataMap<TQString>::const_iterator mit = map.begin(); + for (; mit != map.end(); ++mit) + { + DBusMessageIter itemIterator; + dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, + 0, &itemIterator); + + tqAppendToMessage(&itemIterator, mit.key()); + qDBusDataToIterator(&itemIterator, mit.data()); + + dbus_message_iter_close_container(&sub, &itemIterator); + } + + dbus_message_iter_close_container(it, &sub); +} + +static void qDBusObjectPathKeyMapToIterator(DBusMessageIter* it, + const TQT_DBusData& var) +{ + DBusMessageIter sub; + TQCString sig; + + TQT_DBusDataMap<TQT_DBusObjectPath> map = var.toObjectPathKeyMap(); + + sig += DBUS_DICT_ENTRY_BEGIN_CHAR; + sig += qDBusTypeForTQT_DBusType(map.keyType()); + + if (map.hasContainerValueType()) + sig += map.containerValueType().buildDBusSignature(); + else + sig += qDBusTypeForTQT_DBusType(map.valueType()); + sig += DBUS_DICT_ENTRY_END_CHAR; + + dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, sig.data(), &sub); + + TQT_DBusDataMap<TQT_DBusObjectPath>::const_iterator mit = map.begin(); + for (; mit != map.end(); ++mit) + { + DBusMessageIter itemIterator; + dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, + 0, &itemIterator); + + tqAppendToMessage(&itemIterator, mit.key()); + qDBusDataToIterator(&itemIterator, mit.data()); + + dbus_message_iter_close_container(&sub, &itemIterator); + } + + dbus_message_iter_close_container(it, &sub); +} + +static void qDBusUnixFdKeyMapToIterator(DBusMessageIter* it, const TQT_DBusData& var) +{ + DBusMessageIter sub; + TQCString sig; + + TQT_DBusDataMap<TQT_DBusUnixFd> map = var.toUnixFdKeyMap(); + + sig += DBUS_DICT_ENTRY_BEGIN_CHAR; + sig += qDBusTypeForTQT_DBusType(map.keyType()); + + if (map.hasContainerValueType()) + sig += map.containerValueType().buildDBusSignature(); + else + sig += qDBusTypeForTQT_DBusType(map.valueType()); + sig += DBUS_DICT_ENTRY_END_CHAR; + + dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, sig.data(), &sub); + + TQT_DBusDataMap<TQT_DBusUnixFd>::const_iterator mit = map.begin(); + for (; mit != map.end(); ++mit) + { + DBusMessageIter itemIterator; + dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, + 0, &itemIterator); + + dbus_message_iter_append_basic(it, DBUS_TYPE_UNIX_FD, &(mit.key())); + qDBusDataToIterator(&itemIterator, mit.data()); + + dbus_message_iter_close_container(&sub, &itemIterator); + } + + dbus_message_iter_close_container(it, &sub); +} + +static void qDBusDataToIterator(DBusMessageIter* it, const TQT_DBusData& var) +{ + switch (var.type()) + { + case TQT_DBusData::Bool: + { + dbus_bool_t value = var.toBool(); + dbus_message_iter_append_basic(it, DBUS_TYPE_BOOLEAN, &value); + break; + } + case TQT_DBusData::Byte: + { + TQ_UINT8 value = var.toByte(); + dbus_message_iter_append_basic(it, DBUS_TYPE_BYTE, &value); + break; + } + case TQT_DBusData::Int16: { + TQ_INT16 value = var.toInt16(); + dbus_message_iter_append_basic(it, DBUS_TYPE_INT16, &value); + break; + } + case TQT_DBusData::UInt16: { + TQ_UINT16 value = var.toUInt16(); + dbus_message_iter_append_basic(it, DBUS_TYPE_UINT16, &value); + break; + } + case TQT_DBusData::Int32: { + TQ_INT32 value = var.toInt32(); + dbus_message_iter_append_basic(it, DBUS_TYPE_INT32, &value); + break; + } + case TQT_DBusData::UInt32: { + TQ_UINT32 value = var.toUInt32(); + dbus_message_iter_append_basic(it, DBUS_TYPE_UINT32, &value); + break; + } + case TQT_DBusData::Int64: { + TQ_INT64 value = var.toInt64(); + dbus_message_iter_append_basic(it, DBUS_TYPE_INT64, &value); + break; + } + case TQT_DBusData::UInt64: { + TQ_UINT64 value = var.toUInt64(); + dbus_message_iter_append_basic(it, DBUS_TYPE_UINT64, &value); + break; + } + case TQT_DBusData::Double: { + double value = var.toDouble(); + dbus_message_iter_append_basic(it, DBUS_TYPE_DOUBLE, &value); + break; + } + case TQT_DBusData::String: + tqAppendToMessage(it, var.toString()); + break; + case TQT_DBusData::ObjectPath: + tqAppendToMessage(it, var.toObjectPath()); + break; + case TQT_DBusData::UnixFd: { + tqAppendToMessage(it, var.toUnixFd()); + break; + } + case TQT_DBusData::List: { + TQT_DBusDataList list = var.toList(); + + TQCString signature = 0; + if (list.hasContainerItemType()) + signature = list.containerItemType().buildDBusSignature(); + else + signature = qDBusTypeForTQT_DBusType(list.type()); + + DBusMessageIter sub; + dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, + signature.data(), &sub); + + const TQValueList<TQT_DBusData> valueList = var.toTQValueList(); + TQValueList<TQT_DBusData>::const_iterator listIt = valueList.begin(); + TQValueList<TQT_DBusData>::const_iterator listEndIt = valueList.end(); + for (; listIt != listEndIt; ++listIt) + { + qDBusDataToIterator(&sub, *listIt); + } + dbus_message_iter_close_container(it, &sub); + break; + } + case TQT_DBusData::Map: { + switch (var.keyType()) { + case TQT_DBusData::Byte: + qDBusByteKeyMapToIterator(it, var); + break; + case TQT_DBusData::Int16: + qDBusInt16KeyMapToIterator(it, var); + break; + case TQT_DBusData::UInt16: + qDBusUInt16KeyMapToIterator(it, var); + break; + case TQT_DBusData::Int32: + qDBusInt32KeyMapToIterator(it, var); + break; + case TQT_DBusData::UInt32: + qDBusUInt32KeyMapToIterator(it, var); + break; + case TQT_DBusData::Int64: + qDBusInt64KeyMapToIterator(it, var); + break; + case TQT_DBusData::UInt64: + qDBusUInt64KeyMapToIterator(it, var); + break; + case TQT_DBusData::String: + qDBusStringKeyMapToIterator(it, var); + break; + case TQT_DBusData::ObjectPath: + qDBusObjectPathKeyMapToIterator(it, var); + break; + case TQT_DBusData::UnixFd: + qDBusUnixFdKeyMapToIterator(it, var); + break; + default: + tqWarning("TQT_DBusMarshall: unhandled map key type %s " + "at marshalling", + TQT_DBusData::typeName(var.keyType())); + break; + } + break; + } + case TQT_DBusData::Variant: { + TQT_DBusVariant variant = var.toVariant(); + if (variant.signature.isEmpty() || !variant.value.isValid()) break; + + DBusMessageIter sub; + dbus_message_iter_open_container(it, DBUS_TYPE_VARIANT, + variant.signature.utf8(), &sub); + + qDBusDataToIterator(&sub, variant.value); + + dbus_message_iter_close_container(it, &sub); + break; + } + case TQT_DBusData::Struct: { + TQValueList<TQT_DBusData> memberList = var.toStruct(); + if (memberList.isEmpty()) break; + + DBusMessageIter sub; + dbus_message_iter_open_container(it, DBUS_TYPE_STRUCT, NULL, &sub); + + TQValueList<TQT_DBusData>::const_iterator memberIt = memberList.begin(); + TQValueList<TQT_DBusData>::const_iterator memberEndIt = memberList.end(); + for (; memberIt != memberEndIt; ++memberIt) + { + qDBusDataToIterator(&sub, *memberIt); + } + + dbus_message_iter_close_container(it, &sub); + } +#if 0 + case TQVariant::ByteArray: { + const TQByteArray array = var.toByteArray(); + const char* cdata = array.data(); + DBusMessageIter sub; + dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &sub); + dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &cdata, array.size()); + dbus_message_iter_close_container(it, &sub); + break; + } +#endif + default: + //tqWarning("Don't know how to handle type %s", var.typeName()); + break; + } +} + +void qListToIterator(DBusMessageIter* it, const TQValueList<TQT_DBusData>& list) +{ + if (list.isEmpty()) return; + + TQValueList<TQT_DBusData>::const_iterator listIt = list.begin(); + TQValueList<TQT_DBusData>::const_iterator listEndIt = list.end(); + for (; listIt != listEndIt; ++listIt) + { + qDBusDataToIterator(it, *listIt); + } +} + +void TQT_DBusMarshall::listToMessage(const TQValueList<TQT_DBusData> &list, DBusMessage *msg) +{ + Q_ASSERT(msg); + DBusMessageIter it; + dbus_message_iter_init_append(msg, &it); + qListToIterator(&it, list); +} diff --git a/src/tqdbusmarshall.h b/src/tqdbusmarshall.h new file mode 100644 index 0000000..6c41587 --- /dev/null +++ b/src/tqdbusmarshall.h @@ -0,0 +1,40 @@ +/* qdbusmarshall.h TQT_DBusMarshall object + * + * Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#ifndef TQDBUSMARSHALL_H +#define TQDBUSMARSHALL_H + +struct DBusMessage; + +class TQT_DBusData; + +template <typename T> class TQValueList; + +class TQT_DBusMarshall +{ +public: + static void listToMessage(const TQValueList<TQT_DBusData> &list, DBusMessage* message); + static void messageToList(TQValueList<TQT_DBusData>& list, DBusMessage* message); +}; + +#endif diff --git a/src/tqdbusmessage.cpp b/src/tqdbusmessage.cpp new file mode 100644 index 0000000..455e549 --- /dev/null +++ b/src/tqdbusmessage.cpp @@ -0,0 +1,263 @@ +/* qdbusmessage.cpp + * + * Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org> + * Copyright (C) 2005 Kevin Krammer <kevin.krammer@gmx.at> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#include "tqdbusmessage.h" + +#include <tqstringlist.h> + +#include <dbus/dbus.h> + +#include "tqdbusmarshall.h" +#include "tqdbusmessage_p.h" + +TQT_DBusMessagePrivate::TQT_DBusMessagePrivate(TQT_DBusMessage *qq) + : msg(0), reply(0), q(qq), type(DBUS_MESSAGE_TYPE_INVALID), timeout(-1), ref(1) +{ +} + +TQT_DBusMessagePrivate::~TQT_DBusMessagePrivate() +{ + if (msg) + dbus_message_unref(msg); + if (reply) + dbus_message_unref(reply); +} + +/////////////// + + +TQT_DBusMessage TQT_DBusMessage::signal(const TQString &path, const TQString &interface, + const TQString &member) +{ + TQT_DBusMessage message; + message.d->type = DBUS_MESSAGE_TYPE_SIGNAL; + message.d->path = path; + message.d->interface = interface; + message.d->member = member; + + return message; +} + +TQT_DBusMessage TQT_DBusMessage::methodCall(const TQString &service, const TQString &path, + const TQString &interface, const TQString &method) +{ + TQT_DBusMessage message; + message.d->type = DBUS_MESSAGE_TYPE_METHOD_CALL; + message.d->service = service; + message.d->path = path; + message.d->interface = interface; + message.d->member = method; + + return message; +} + +TQT_DBusMessage TQT_DBusMessage::methodReply(const TQT_DBusMessage &other) +{ + Q_ASSERT(other.d->msg); + + TQT_DBusMessage message; + message.d->type = DBUS_MESSAGE_TYPE_METHOD_RETURN; + message.d->reply = dbus_message_ref(other.d->msg); + + return message; +} + +TQT_DBusMessage TQT_DBusMessage::methodError(const TQT_DBusMessage &other, const TQT_DBusError& error) +{ + Q_ASSERT(other.d->msg); + + TQT_DBusMessage message; + if (!error.isValid()) + { + tqWarning("TQT_DBusMessage: error passed to methodError() is not valid!"); + return message; + } + + message.d->type = DBUS_MESSAGE_TYPE_ERROR; + message.d->reply = dbus_message_ref(other.d->msg); + message.d->error = error; + + return message; +} + +TQT_DBusMessage::TQT_DBusMessage() +{ + d = new TQT_DBusMessagePrivate(this); +} + +TQT_DBusMessage::TQT_DBusMessage(const TQT_DBusMessage &other) + : TQValueList<TQT_DBusData>(other) +{ + d = other.d; + d->ref.ref(); +} + +TQT_DBusMessage::~TQT_DBusMessage() +{ + if (!d->ref.deref()) + delete d; +} + +TQT_DBusMessage &TQT_DBusMessage::operator=(const TQT_DBusMessage &other) +{ + TQValueList<TQT_DBusData>::operator=(other); + // FIXME-QT4 qAtomicAssign(d, other.d); + if (other.d) other.d->ref.ref(); + TQT_DBusMessagePrivate* old = d; + d = other.d; + if (old && !old->ref.deref()) + delete old; + return *this; +} + +DBusMessage *TQT_DBusMessage::toDBusMessage() const +{ + DBusMessage *msg = 0; + switch (d->type) { + case DBUS_MESSAGE_TYPE_METHOD_CALL: + msg = dbus_message_new_method_call(d->service.utf8().data(), + d->path.utf8().data(), d->interface.utf8().data(), + d->member.utf8().data()); + break; + case DBUS_MESSAGE_TYPE_SIGNAL: + msg = dbus_message_new_signal(d->path.utf8().data(), + d->interface.utf8().data(), d->member.utf8().data()); + break; + case DBUS_MESSAGE_TYPE_METHOD_RETURN: + msg = dbus_message_new_method_return(d->reply); + break; + case DBUS_MESSAGE_TYPE_ERROR: + msg = dbus_message_new_error(d->reply, d->error.name().utf8().data(), + d->error.message().utf8().data()); + break; + } + if (!msg) + return 0; + + TQT_DBusMarshall::listToMessage(*this, msg); + return msg; +} + +TQT_DBusMessage TQT_DBusMessage::fromDBusMessage(DBusMessage *dmsg) +{ + TQT_DBusMessage message; + if (!dmsg) + return message; + + message.d->type = dbus_message_get_type(dmsg); + message.d->path = TQString::fromUtf8(dbus_message_get_path(dmsg)); + message.d->interface = TQString::fromUtf8(dbus_message_get_interface(dmsg)); + message.d->member = TQString::fromUtf8(dbus_message_get_member(dmsg)); + message.d->sender = TQString::fromUtf8(dbus_message_get_sender(dmsg)); + message.d->msg = dbus_message_ref(dmsg); + + DBusError dbusError; + dbus_error_init(&dbusError); + if (dbus_set_error_from_message(&dbusError, dmsg)) + { + message.d->error = TQT_DBusError(&dbusError); + } + + TQT_DBusMarshall::messageToList(message, dmsg); + + return message; +} + +TQString TQT_DBusMessage::path() const +{ + return d->path; +} + +TQString TQT_DBusMessage::interface() const +{ + return d->interface; +} + +TQString TQT_DBusMessage::member() const +{ + return d->member; +} + +TQString TQT_DBusMessage::sender() const +{ + return d->sender; +} + +TQT_DBusError TQT_DBusMessage::error() const +{ + return d->error; +} + +int TQT_DBusMessage::timeout() const +{ + return d->timeout; +} + +void TQT_DBusMessage::setTimeout(int ms) +{ + d->timeout = ms; +} + +/*! + Returns the unique serial number assigned to this message + or 0 if the message was not sent yet. + */ +int TQT_DBusMessage::serialNumber() const +{ + if (!d->msg) + return 0; + return dbus_message_get_serial(d->msg); +} + +/*! + Returns the unique serial number assigned to the message + that triggered this reply message. + + If this message is not a reply to another message, 0 + is returned. + + */ +int TQT_DBusMessage::replySerialNumber() const +{ + if (!d->msg) + return 0; + return dbus_message_get_reply_serial(d->msg); +} + +TQT_DBusMessage::MessageType TQT_DBusMessage::type() const +{ + switch (d->type) { + case DBUS_MESSAGE_TYPE_METHOD_CALL: + return MethodCallMessage; + case DBUS_MESSAGE_TYPE_METHOD_RETURN: + return ReplyMessage; + case DBUS_MESSAGE_TYPE_ERROR: + return ErrorMessage; + case DBUS_MESSAGE_TYPE_SIGNAL: + return SignalMessage; + default: + return InvalidMessage; + } +} + diff --git a/src/tqdbusmessage.h b/src/tqdbusmessage.h new file mode 100644 index 0000000..665a83f --- /dev/null +++ b/src/tqdbusmessage.h @@ -0,0 +1,514 @@ +/* qdbusmessage.h TQT_DBusMessage object + * + * Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org> + * Copyright (C) 2005-2007 Kevin Krammer <kevin.krammer@gmx.at> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#ifndef TQDBUSMESSAGE_H +#define TQDBUSMESSAGE_H + +#include "tqdbusmacros.h" +#include "tqdbusdata.h" + +#include <tqvaluelist.h> + +#include <limits.h> + +class TQT_DBusError; +class TQT_DBusMessagePrivate; +struct DBusMessage; + +/** + * @brief A message converts and transports data over D-Bus + * + * A TQT_DBusMessage is implicitly shared, similar to a TQString, i.e. copying + * a message creates just a shallow copy. + * + * The TQT_DBusMessage is the TQt3 bindings means of encapsulating data for a + * method call, a method reply or an error. + * + * Data specifying the sender and receipient is directly accessible through + * getter methods, while data, e.g. method parameters or return values, are + * managed as a list of TQT_DBusData. + * + * To create a message suitable for sending use one of the static factory + * methods: + * - signal() for creating a D-Bus signal message + * + * - methodCall() for creating a D-Bus method calls to a service object + * + * - methodReply() for creating a method reply on success + * + * - methodError() for creating a method reply on error + * + * @note for applications that just want to perform method calls and/or receive + * signals, it is usually more convenient to use TQT_DBusProxy instead. + * + * Message sending is achieved through TQT_DBusConnection + * + * Example: + * @code + * TQT_DBusConnection con = TQT_DBusConnection::sessionBus(); + * + * // receipient service is the bus' main interface + * + * TQString service = "org.freedesktop.DBus"; + * TQString path = "/org/freedesktop/DBus"; + * TQString interface = "org.freedesktop.DBus"; + * + * TQT_DBusMessage msg = TQBusMessage::methodCall(service, path, interface, "ListNames"); + * + * TQT_DBusMessage reply = con.sendWithReply(msg); + * + * // awaiting for a message list + * + * if (reply.type() != TQT_DBusMessage::ReplyMessage || reply.count() != 2 || + * reply[0].type() != TQT_DBusData::List) + * { + * // error handling here + * } + * else + * { + * TQStringList list = reply[0].toTQStringList(); + * + * // reply handling here + * } + * @endcode + * + * A service returning such a reply would do something like this + * @code + * bool Service::handleMethodCall(const TQT_DBusMessage& call) + * { + * // checks for correctness, i.e. correct interface, member, + * // would usually haven been placed here + * + * TQStringList result; + * result << "Foo" << "Bar"; + * + * TQT_DBusMessage reply = TQT_DBusMessage::methodReply(call); + * reply << TQT_DBusData::fromList(result); + * + * connection.send(reply); + * + * return true; + * } + * @endcode + */ +class TQDBUS_EXPORT TQT_DBusMessage: public TQValueList<TQT_DBusData> +{ + friend class TQT_DBusConnection; +public: + /** + * @brief Anonymous enum for timeout constants + * + * @see timeout() + * @see setTimeout() + */ + enum + { + /** + * Use whatever D-Bus has as default timeout + */ + DefaultTimeout = -1, + + /** + * Use no timeout at all, i.e. wait as long as necessary + */ + NoTimeout = INT_MAX + }; + + /** + * @brief D-Bus message types + * + * A message of a specific type can be created using the respective factory + * method. A message created by the default constructor becomes an + * InvalidMessage + * + * @see type() + * @see signal() + * @see methodCall() + * @see methodReply() + * @see methodError() + */ + enum MessageType + { + /** + * An invalid message cannot be sent over D-Bus. This type serves for + * initializing message variables without requiring a "real" message + */ + InvalidMessage, + + /** + * A message for doing method calls on remote service objects + * + * @see methodCall() + */ + MethodCallMessage, + + /** + * A message for replying to a method call in case of success + * + * @see methodReply() + */ + ReplyMessage, + + /** + * A message for replying to a method call in case of failure + * + * @see methodError() + */ + ErrorMessage, + + /** + * A message for emitting D-Bus signals + * + * @see signal() + */ + SignalMessage + }; + + /** + * @brief Creates an empty and invalid message + * + * To create a message suitable for sending through D-Bus see the factory + * methods signal(), methodCall(), methodReply() and methodError() + * + * @see #InvalidMessage + */ + TQT_DBusMessage(); + + + /** + * @brief Creates a shallow copy of the given message + * + * This instance will become a handle to the same message data the other + * message is using, including #MessageType + * + * @param other the message to copy + */ + TQT_DBusMessage(const TQT_DBusMessage &other); + + /** + * @brief Destroys a message + * + * If this message handle is the last one using this respective message + * content, the message content will be deleted as well + */ + ~TQT_DBusMessage(); + + /** + * @brief Creates a shallow copy of the given message + * + * This instance will become a handle to the same message data the other + * message is usingm including #MessageType + * + * Any content used in this instance will be deleted if this instance was + * the last handle using that content + * + * @param other the message to copy + * + * @return a reference to this instance as required by assignment operator + * semantics + */ + TQT_DBusMessage &operator=(const TQT_DBusMessage &other); + + /** + * @brief Creates a message for sending a D-Bus signal + * + * Sending/emitting a signal over D-Bus requires a message of type + * #SignalMessage as well as the information where it is coming from, i.e. + * which interface of which object is sending it. + * See @ref dbusconventions for recommendations on those parameters. + * + * @param path the object path of the service object + * @param interface the object's interface to which the signal belongs + * @param member the signal's name + * + * @return a message suitable for appending arguments and for sending + * + * @see TQT_DBusConnection::send() + */ + static TQT_DBusMessage signal(const TQString &path, const TQString &interface, + const TQString &member); + + /** + * @brief Creates a message for sending a D-Bus method call + * + * Invoking a method over D-Bus requires a message of type + * #MethodCallMessage as well as the information where it should be sent + * to, e.g which interface of which object in which service. + * See @ref dbusconventions for recommendations on those parameters. + * + * @param service the D-Bus name of the application hosting the service + * object + * @param path the object path of the service object + * @param interface the object's interface to which the method belongs + * @param method the method's name + * + * @return a message suitable for appending arguments and for sending + * + * @see methodReply() + * @see methodError() + * @see TQT_DBusConnection::send() + */ + static TQT_DBusMessage methodCall(const TQString &service, const TQString &path, + const TQString &interface, const TQString &method); + + /** + * @brief Creates a message for replying to a D-Bus method call + * + * Replying to a D-Bus method call in the case of success requires a message + * of type #ReplyMessage as well as the information to which method call it + * is replying to. + * + * @param other the method call message it is replying to + * + * @return a message suitable for appending arguments and for sending + * + * @see methodCall() + * @see methodError() + * @see TQT_DBusConnection::send() + */ + static TQT_DBusMessage methodReply(const TQT_DBusMessage &other); + + /** + * @brief Creates a message for replying to a D-Bus method call + * + * Replying to a D-Bus method call in the case of failure requires a message + * of type #ErrorMessage as well as the information to which method call it + * is replying to and which error occured. + * + * @param other the method call message it is replying to + * @param error the error which occured during during the method call + * + * @return a message suitable for appending arguments and for sending + * + * @see methodCall() + * @see methodReply() + * @see TQT_DBusConnection::send() + */ + static TQT_DBusMessage methodError(const TQT_DBusMessage &other, const TQT_DBusError& error); + + /** + * @brief Returns the message's object path + * + * See section @ref dbusconventions-objectpath for details. + * + * The context of the object path depends on the message type: + * - #SignalMessage: the path of the service object which emits the signal + * - #MethodCallMessage: the path of the service object the call is sent to + * - #ReplyMessage: the path of the object which is replying + * - #ErrorMessage: the path of the object which is replying + * + * @return a non-empty object path or @c TQString() + * + * @see interface() + * @see member() + * @see sender() + */ + TQString path() const; + + /** + * @brief Returns the message's interface name + * + * See section @ref dbusconventions-interfacename for details. + * + * The context of the interface name depends on the message type: + * - #SignalMessage: the name of the interface which emits the signal + * - #MethodCallMessage: the name of the interface the call is sent to + * - #ReplyMessage: the name of the interface to which the method belonged + * - #ErrorMessage: the name of the interface to which the method belonged + * + * @return a non-empty interface name or @c TQString() + * + * @see path() + * @see member() + * @see sender() + */ + TQString interface() const; + + /** + * @brief Returns the message's member name + * + * See section @ref dbusconventions-membername for details. + * + * The context of the member name depends on the message type: + * - #SignalMessage: the name of the emitted signal + * - #MethodCallMessage: the name of the method to call + * - #ReplyMessage: the name of the method which replies + * - #ErrorMessage: the name of the method which replies + * + * @return a non-empty member name or @c TQString() + * + * @see path() + * @see interface() + * @see sender() + */ + TQString member() const; + + /** + * @brief Returns the name of the message sender + * + * The message sender name or address used on the D-Bus message bus + * to refer to the application which sent this message. + * + * See section @ref dbusconventions-servicename for details. + * + * This can either be a unique name as handed out by the bus, see + * TQT_DBusConnection::uniqueName() or a name registered with + * TQT_DBusConnection::requestName() + * + * @return a non-empty D-Bus sender name or @c TQString() + * + * @see path() + * @see interface() + * @see member() + */ + TQString sender() const; + + /** + * @brief Returns the error of an error message + * + * If this message is of type #ErrorMessage, this method can be used + * to retrieve the respective error object + * + * @return the transported error object. Will be empty if this is not an + * error message + * + * @see type() + */ + TQT_DBusError error() const; + + /** + * @brief Returns which kind of message this is + * + * @return the message's type + */ + MessageType type() const; + + /** + * @brief Returns the message's timeout + * + * @return the asynchronous wait timeout in milliseconds + * + * @see setTimeout() + */ + int timeout() const; + + /** + * @brief Sets the message's timeout + * + * The timeout is the number of milliseconds the D-Bus connection will + * wait for the reply of an asynchronous call. + * + * If no reply is received in time, an error message will be delivered to + * the asynchronous reply receiver. + * + * If no timeout is set explicitly, #DefaultTimeout is assumed, which is + * usually the best option + * + * @return the asynchronous wait timeout in milliseconds + * + * @param ms timeout in milliseconds + * + * @see timeout() + * @see #DefaultTimeout + * @see #NoTimeout + */ + void setTimeout(int ms); + + /** + * @brief Returns the message's serial number + * + * The serial number is some kind of short term identifier for messages + * travelling the same connection. + * + * It can be used to associate a reply or error message with a method + * call message. + * + * @return the message's serial number or @c 0 if the message hasn't been + * send yets + * + * @see replySerialNumber() + */ + int serialNumber() const; + + /** + * @brief Returns the message's reply serial number + * + * The reply serial number is the serial number of the method call message + * this message is a reply to. + * + * If this is neither a message of type #ReplyMessage or #ErrorMessage, the + * returned value will be @c 0 + * + * It can be used to associate a reply or error message with a method + * call message. + * + * @return the serial number of the associated method call message or @c 0 + * if this message is not a reply message + * + * @see serialNumber() + * @see methodReply() + * @see methodError() + * @see TQT_DBusConnection::sendWithAsyncReply() + * @see TQT_DBusProxy::sendWithAsyncReply() + */ + int replySerialNumber() const; + +//protected: + /** + * @brief Creates a raw D-Bus message from this TQt3-bindings message + * + * Marshalls data contained in the message's value list into D-Bus data + * format and creates a low level API D-Bus message for it. + * + * @note ownership of the returned message is transferred to the caller, + * i.e. it has to be deleted using dbus_message_unref() + * + * @return a C API D-Bus message or @c 0 if this is an #InvalidMessage + * or marshalling failed + */ + DBusMessage *toDBusMessage() const; + + /** + * @brief Creates a TQt3-bindings message from the given raw D-Bus message + * + * De-marshalls data contained in the message to a list of TQT_DBusData. + * + * @note ownership of the given message is shared between the caller and + * the returned message, i.e. the message as increased the reference + * counter and will still have access to the raw message even if the + * caller "deleted" it using dbus_message_unref() + * + * @param dmsg a C API D-Bus message + * + * @return a TQt3 bindings message. Can be an #InvalidMessage if the given + * message was @c 0 or if de-marshalling failed + */ + static TQT_DBusMessage fromDBusMessage(DBusMessage *dmsg); + +private: + TQT_DBusMessagePrivate *d; +}; + +#endif + diff --git a/src/tqdbusmessage_p.h b/src/tqdbusmessage_p.h new file mode 100644 index 0000000..657460f --- /dev/null +++ b/src/tqdbusmessage_p.h @@ -0,0 +1,52 @@ +/* qdbusmessage.h TQT_DBusMessage private object + * + * Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org> + * Copyright (C) 2005 Kevin Krammer <kevin.krammer@gmx.at> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#ifndef TQDBUSMESSAGE_P_H +#define TQDBUSMESSAGE_P_H + +#include <tqstring.h> + +#include "tqdbusatomic.h" +#include "tqdbuserror.h" + +struct DBusMessage; + +class TQT_DBusMessagePrivate +{ +public: + TQT_DBusMessagePrivate(TQT_DBusMessage *qq); + ~TQT_DBusMessagePrivate(); + + TQString path, interface, member, service, sender; + TQT_DBusError error; + DBusMessage *msg; + DBusMessage *reply; + TQT_DBusMessage *q; + int type; + int timeout; + // FIXME-QT4 TQAtomic ref; + Atomic ref; +}; + +#endif diff --git a/src/tqdbusobject.h b/src/tqdbusobject.h new file mode 100644 index 0000000..aa16750 --- /dev/null +++ b/src/tqdbusobject.h @@ -0,0 +1,372 @@ +/* qdbusobject.h DBUS service object interface + * + * Copyright (C) 2005-2007 Kevin Krammer <kevin.krammer@gmx.at> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#ifndef TQDBUSOBJECT_H +#define TQDBUSOBJECT_H + +/** + * @page dbusservice Providing services over D-Bus + * + * Contents: + * - @ref dbusservice-introduction + * - @ref dbusservice-example + * - @ref dbusservice-requestname + * - @ref dbusservice-registerobjects + * - @ref dbusservice-interfaces + * + * @section dbusservice-introduction Introduction + * + * The TQt3 bindings do not support autogeneration of service objects yet. In + * order to provide interfaces over D-Bus, an application has to implement the + * TQT_DBusObjectBase interface and register an instance of the resulting class + * with the TQT_DBusConnection. + * + * @section dbusservice-example A simple D-Bus client example + * + * @code + * #include <dbus/tqdbusconnection.h>; + * #include <dbus/tqdbusobject.h>; + * + * class TQStringList; + * + * class TestService : public TQT_DBusObjectBase + * { + * public: + * TestService(const TQT_DBusConnection& connection); + * virtual ~TestService(); + * + * protected: + * virtual bool handleMethodCall(const TQT_DBusMessage& message); + * + * private: + * TQT_DBusConnection m_connection; + * + * private: + * TQStringList sortStrings(const TQStringList& list); + * }; + * @endcode + * @code + * + * #include <tqstringlist.h>; + * + * #include <dbus/tqdbuserror.h>; + * #include <dbus/tqdbusmessage.h>; + * + * TestService::TestService(const TQT_DBusConnection& connection) : m_connection(connection) + * { + * m_connection.registerObject("/ListSorter", this); + * } + * + * TestService::~TestService() + * { + * m_connection.unregisterObject("/ListSorter"); + * } + * + * // return false to let D-Bus send a standard error message that the method is unknown + * + * bool TestService::handleMethod(const TQT_DBusMessage& message) + * { + * if (message.interface() != "org.example.Sort") return false; + * + * if (message.member() == "Strings") + * { + * // check parameters + * + * if (message.count() != 1 || message[0].type() != TQT_DBusData::List) + * { + * // method signature not what we expected + * + * TQT_DBusError error = TQT_DBusError::stdInvalidArgs( + * "Expected one argument of type array of string"); + * + * TQT_DBusMessage reply = TQT_DBusMessage::methodError(message, error); + * + * // send error + * + * m_connection.send(reply); + * + * // tell D-Bus we did handle the call + * + * return true; + * } + * + * // call implementation + * + * TQStringList result = sortStrings(message[0].toTQStringList()); + * + * // prepare reply + * + * TQT_DBusMessage reply = TQT_DBusMessage::methodReply(message); + * + * reply << TQT_DBusData::fromList(result); + * + * // send reply + * + * m_connection.send(reply); + * + * // tell D-Bus we did handle the call + * + * return true; + * } + * + * return false; + * } + * + * TQStringList TestService::sortStrings(const TQStringList& list) + * { + * TQStringList result = list; + * + * result.sort(); + * + * return result; + * } + * @endcode + * @code + * int main(int argc, char** argv) + * { + * TQApplication app(argc, argv, false); + * + * TQT_DBusConnection connection = TQT_DBusConnection::sessionBus(); + * if (!connection.isConnected()) + * tqFatal("Cannot connect to session bus"); + * + * // try to get a specific service name + * if (!connection.requestName("org.example.SortService")) + * { + * tqWarning("Requesting name 'org.example.SortService' failed. " + * "Will only be addressable through unique name '%s'", + * connection.uniqueName().local8Bit().data()); + * } + * else + * { + * tqDebug("Requesting name 'org.example.SortService' successfull"); + * } + * + * TestService service(connection); + * + * return app.exec(); + * } + * @endcode + * + * @section dbusservice-requestname Requesting service name + * + * When an application connects to D-Bus it gets a unique name generated by + * the bus daemon. + * + * However, an application providing service will often want to be reachable + * under a fixed name, like a webserver being reachable through a domain name + * independent from its actual IP address. + * See section @ref dbusconventions-servicename for details on service names. + * + * In order to get such a specific name an application has to request it + * using TQT_DBusConnection::requestName() + * + * The example above request @c "org.example.SortService" but continues with + * the default unique name in the case some other application is currently + * owning that name. + * + * @section dbusservice-registerobjects Registering objects + * + * To make service objects available to other applications on the same + * bus the application has to register the objects instances with the + * connection to the bus using TQT_DBusConnection::registerObject() + * + * Registering means to specify an object path where the object will be + * located, i.e. how it can be unambiguously be addressed in method calls. + * See section @ref dbusconventions-objectpath for details on object paths. + * + * If the applications has introspectable objects it is recommended to + * register an introspectable root object, i.e. using @c "/" as the path, so + * other applications have a common place to start asking for introspection + * data. + * + * In the example above a service object providing sorting services on lists is + * registered on the path @c "/ListSorter" + * + * @section dbusservice-interfaces Service interfaces + * + * D-Bus methods and signals of a service object a grouped into interfaces. + * + * See section @ref dbusconventions-interfacename for details on interface + * naming. + * + * An object can implement any number of interfaces, for example the interface + * for the functionality it wants to provide and a D-Bus standard interface like + * @c "org.freedesktop.DBus.Introspectable" for providing an XML description of + * all its interfaces. + * + * + * The service object of the example above implements just one interface + * @c "org.example.Sort" and its handleMethodCall() explicitly checks all + * received messages and rejects any messsage not sent to this particular + * interface by returning @c false and thus telling the D-Bus layer to + * generate a standard error response. + * + * Multiple interfaces can of course be directly implemented in one C++ class, + * however it might sometimes be wise to delegate calls for different + * interfaces to different implementations: + * @code + * class Interface1 : public TQT_DBusObjectBase + * { + * public: + * Interface1(const TQT_DBusConnection&); + * + * protected: + * virtual bool handleMethodCall(const TQT_DBusMessage&); + * }; + * + * class Interface2 : public TQT_DBusObjectBase + * { + * public: + * Interface2(const TQT_DBusConnection&); + * + * protected: + * virtual bool handleMethodCall(const TQT_DBusMessage&); + * }; + * + * class MultiInterfaceService : public TQT_DBusObjectBase + * { + * public: + * MultiInterfaceService(const TQT_DBusConnection&); + * + * protected: + * virtual bool handleMethodCall(const TQT_DBusMessage&); + * + * private: + * TQMap<TQString, TQT_DBusObjectBase*> m_interfaces; + * }; + * + * MultiInterfaceService::MultiInterfaceService(const TQT_DBusConnection& connection) + * { + * m_interfaces.insert("org.example.Interface1", new Interface1(connection)); + * m_interfaces.insert("org.example.Interface2", new Interface2(connection)); + * } + * + * bool MultiInterfaceService::handleMethodCall(const TQT_DBusMessage& message) + * { + * // delegate call to its interface handler + * TQT_DBusObjectBase* handler = m_interfaces[message.interface()]; + * if (handler != 0) + * return delegateMethodCall->(message, handler); + * else + * return false; // no such interface + * } + * @endcode + */ + +/** + * @include example-service.h + * @example example-service.cpp + */ + +#include "tqdbusmacros.h" + +class TQT_DBusMessage; + +/** + * @brief Base interface for D-Bus service objects + * + * In order to register a service object with the TQT_DBusConnection it needs to + * implement the interface specified by this class. + * + * The connection will forward all method calls that have a path equivalent + * to the path the service object was registered with to the object's + * handleMethodCall() method. See TQT_DBusConnection::registerObject() + * + * If for some reason, e.g. the call is not meant for this interface, or the + * method is unknown, the implementation can just return @c false and the + * connection will handle the rest. + * + * See section @ref dbusservice for documentation on how to use TQT_DBusObjectBase + */ +class TQDBUS_EXPORT TQT_DBusObjectBase +{ + friend class TQT_DBusConnectionPrivate; +public: + /** + * @brief Destroys the object + */ + virtual ~TQT_DBusObjectBase() {} + +protected: + /** + * @brief Method call entry point + * + * This method has to be implemented to handle method calls sent to the + * service object. + * An object implementation can handle all its interfaces in one class or + * again forward the method call to interface implementators. + * + * If for some reason, e.g. the call is not meant for this interface, or + * the method is unknown, the implementation can just return @c false and + * the connection will handle the rest. + * + * If an error occurs during the method call, e.g. the number of parameters + * or their types are not what would be expected, the service object + * should reply with a TQT_DBusMessage of type TQT_DBusMessage::ErrorMessage + * which in turn should include the D-Bus error describing the problem. + * See TQT_DBusConnection::send() for sending reply messages. + * + * See TQT_DBusMessage::methodError() and TQT_DBusMessage::methodReply() on + * how to create suitable reply messages for the given method call. + * + * @param message the method call to handle + * + * @return @c true if the message can be handled independent if handling + * resulted in an error. In this case implementations should an + * error reply. Returns @c false only if interface or method are + * unknown + */ + virtual bool handleMethodCall(const TQT_DBusMessage& message) = 0; + + /** + * @brief Delegate a method call to another object + * + * When a service object is built as a collection of separated interface + * class instances, i.e. each interface of the object is implemented in + * its own TQT_DBusObjectBase subclass and the main object just wanst to pass + * on the method calls to the respective interface implementations, it + * can do so by calling this base class method. + * + * Since it is a method of the base class, it can call the otherwise + * protected handleMethodCall() of the interface implementor. + * + * See @ref dbusservice-interfaces for an example. + * + * @param message the method call to delegate + * @param delegate the object which should handle the call instead + * + * @return @c true if the message can be handled independent if handling + * resulted in an error. In this case implementations should an + * error reply. Returns @c false only if interface or method are + * unknown + * + */ + bool delegateMethodCall(const TQT_DBusMessage& message, TQT_DBusObjectBase* delegate) + { + return delegate->handleMethodCall(message); + } +}; + +#endif + diff --git a/src/tqdbusobjectpath.cpp b/src/tqdbusobjectpath.cpp new file mode 100644 index 0000000..0f42860 --- /dev/null +++ b/src/tqdbusobjectpath.cpp @@ -0,0 +1,79 @@ +/* qdbusobjectpath.cpp DBUS object path data type + * + * Copyright (C) 2007 Kevin Krammer <kevin.krammer@gmx.at> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#include "tqdbusobjectpath.h" + +TQT_DBusObjectPath::TQT_DBusObjectPath() : TQCString() +{ +} + +TQT_DBusObjectPath::TQT_DBusObjectPath(const TQT_DBusObjectPath& other) : TQCString(static_cast<const TQCString&>(other)) +{ +} + +TQT_DBusObjectPath::TQT_DBusObjectPath(const TQCString& other) : TQCString(static_cast<const TQCString&>(other)) +{ +} + +TQT_DBusObjectPath::TQT_DBusObjectPath(const TQT_DBusObjectPath& parentNode, + const TQCString& nodeName) + : TQCString(static_cast<const TQCString&>(parentNode)) +{ + if (parentNode.length() != 1) append("/"); + + append(nodeName); +} + +bool TQT_DBusObjectPath::isValid() const +{ + return (validate(*this) == -1); +} + +TQT_DBusObjectPath TQT_DBusObjectPath::parentNode() const +{ + if (length() == 1) return TQT_DBusObjectPath(); + + int index = findRev('/'); + + if (index == -1) return TQT_DBusObjectPath(); + + if (index == 0) return left(1); + + return left(index); +} + +int TQT_DBusObjectPath::validate(const TQCString& path) +{ + if (path.isEmpty()) return 0; + + if (path[0] != '/') return 0; + + // TODO add additional checks + + uint len = path.length(); + + // only root node allowed to end in slash + if (path[len - 1] == '/' && len > 1) return (len - 1); + + return -1; +} diff --git a/src/tqdbusobjectpath.h b/src/tqdbusobjectpath.h new file mode 100644 index 0000000..7a166c6 --- /dev/null +++ b/src/tqdbusobjectpath.h @@ -0,0 +1,119 @@ +/* qdbusobjectpath.h DBUS object path data type + * + * Copyright (C) 2007 Kevin Krammer <kevin.krammer@gmx.at> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#ifndef TQDBUSOBJECTPATH_H +#define TQDBUSOBJECTPATH_H + +#include <tqcstring.h> +#include "tqdbusmacros.h" + +/** + * @brief Class for representing D-Bus object paths + * + * This data type is necessary to correctly represent object paths in the + * context of D-Bus messages, since normal strings have a different D-Bus + * signature than object paths. + * + * @see @ref dbusconventions-objectpath + */ +class TQDBUS_EXPORT TQT_DBusObjectPath : public TQCString +{ +public: + /** + * @brief Creates an empty and invalid object path + */ + TQT_DBusObjectPath(); + + /** + * @brief Creates copy of the given @p other object path + * + * @param other the object path to copy + */ + TQT_DBusObjectPath(const TQT_DBusObjectPath& other); + + /** + * @brief Creates copy of the given @p other object path + * + * @param other the object path to copy + */ + TQT_DBusObjectPath(const TQCString& other); + + /** + * @brief Creates an object path for an object as a child of the parent node + * + * This is basically like specifying a directory and a file name to create + * the file's full path. + * + * Example: + * @code + * TQT_DBusObjectPath rootNode("/"); // => "/" + * + * TQT_DBusObjectPath childNod(rootNode, "child"); // => "/child" + * + * TQT_DBusObjectPath grandChildNode(childNode, "grandchild"); // => "/child/grandchild" + * @endcode + * + * @param parentNode the object path to create the child on + * @param nodeName the name of the child node + */ + TQT_DBusObjectPath(const TQT_DBusObjectPath& parentNode, const TQCString& nodeName); + + /** + * @brief Returns whether the current content is considered a valid object path + * + * @note Calls validate() to perform a check on the current content + * + * @return \c true if the object's content describe a valid object path, + * otherwise @c false + * + * @see @ref dbusconventions-objectpath + */ + bool isValid() const; + + /** + * @brief Returns the object path of this path's parent node + * + * This is basically like getting the directory of an file path + * + * @return the parent node's object path or an empty and invalid object + * if this is already the root node + */ + TQT_DBusObjectPath parentNode() const; + + /** + * @brief Checks the given string for validity as a D-Bus object path + * + * See section @ref dbusconventions-objectpath for information on object + * path formatting. + * + * @param path the string to check + * + * @return @c -1 if the object path is valid, otherwise the index of the + * first violating character + * + * @see isValid() + */ + static int validate(const TQCString& path); +}; + +#endif diff --git a/src/tqdbusproxy.cpp b/src/tqdbusproxy.cpp new file mode 100644 index 0000000..7ca6118 --- /dev/null +++ b/src/tqdbusproxy.cpp @@ -0,0 +1,209 @@ +/* qdbusproxy.cpp DBUS Object proxy + * + * Copyright (C) 2005 Kevin Krammer <kevin.krammer@gmx.at> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#include "tqdbuserror.h" +#include "tqdbusconnection.h" +#include "tqdbusmessage.h" +#include "tqdbusproxy.h" + +class TQT_DBusProxy::Private +{ +public: + Private() : canSend(false) {} + ~Private() {} + + void checkCanSend() + { + canSend = !path.isEmpty() && !service.isEmpty() && !interface.isEmpty(); + } + +public: + TQT_DBusConnection connection; + + TQString service; + TQString path; + TQString interface; + bool canSend; + + TQT_DBusError error; +}; + +TQT_DBusProxy::TQT_DBusProxy(TQObject* parent, const char* name) + : TQObject(parent, (name ? name : "TQT_DBusProxy")), + d(new Private()) +{ +} + +TQT_DBusProxy::TQT_DBusProxy(const TQT_DBusConnection& connection, + TQObject* parent, const char* name) + : TQObject(parent, (name ? name : "TQT_DBusProxy")), + d(new Private()) +{ + setConnection(connection); +} + +TQT_DBusProxy::TQT_DBusProxy(const TQString& service, const TQString& path, + const TQString& interface, const TQT_DBusConnection& connection, + TQObject* parent, const char* name) + : TQObject(parent, (name ? name : "TQT_DBusProxy")), + d(new Private()) +{ + setConnection(connection); + + d->service = service; + d->path = path; + d->interface = interface; + d->checkCanSend(); +} + +TQT_DBusProxy::~TQT_DBusProxy() +{ + delete d; +} + +bool TQT_DBusProxy::setConnection(const TQT_DBusConnection& connection) +{ + d->connection.disconnect(this, TQT_SLOT(handleDBusSignal(const TQT_DBusMessage&))); + + d->connection = connection; + + return d->connection.connect(this, TQT_SLOT(handleDBusSignal(const TQT_DBusMessage&))); +} + +const TQT_DBusConnection& TQT_DBusProxy::connection() const +{ + return d->connection; +} + +void TQT_DBusProxy::setService(const TQString& service) +{ + d->service = service; + d->checkCanSend(); +} + +TQString TQT_DBusProxy::service() const +{ + return d->service; +} + +void TQT_DBusProxy::setPath(const TQString& path) +{ + d->path = path; + d->checkCanSend(); +} + +TQString TQT_DBusProxy::path() const +{ + return d->path; +} + +void TQT_DBusProxy::setInterface(const TQString& interface) +{ + d->interface = interface; + d->checkCanSend(); +} + +TQString TQT_DBusProxy::interface() const +{ + return d->interface; +} + +bool TQT_DBusProxy::canSend() const +{ + return d->canSend && d->connection.isConnected(); +} + +bool TQT_DBusProxy::send(const TQString& method, const TQValueList<TQT_DBusData>& params) const +{ + if (!d->canSend || method.isEmpty() || !d->connection.isConnected()) + return false; + + TQT_DBusMessage message = TQT_DBusMessage::methodCall(d->service, d->path, + d->interface, method); + message += params; + + return d->connection.send(message); +} + +TQT_DBusMessage TQT_DBusProxy::sendWithReply(const TQString& method, + const TQValueList<TQT_DBusData>& params, + TQT_DBusError* error) const +{ + if (!d->canSend || method.isEmpty() || !d->connection.isConnected()) + return TQT_DBusMessage(); + + TQT_DBusMessage message = TQT_DBusMessage::methodCall(d->service, d->path, + d->interface, method); + message += params; + + TQT_DBusMessage reply = d->connection.sendWithReply(message, &d->error); + + if (error) + *error = d->error; + + return reply; +} + +int TQT_DBusProxy::sendWithAsyncReply(const TQString& method, const TQValueList<TQT_DBusData>& params) +{ + if (!d->canSend || method.isEmpty() || !d->connection.isConnected()) + return 0; + + TQT_DBusMessage message = TQT_DBusMessage::methodCall(d->service, d->path, + d->interface, method); + message += params; + + return d->connection.sendWithAsyncReply(message, this, + TQT_SLOT(handleAsyncReply(const TQT_DBusMessage&))); +} + +TQT_DBusError TQT_DBusProxy::lastError() const +{ + return d->error; +} + +void TQT_DBusProxy::handleDBusSignal(const TQT_DBusMessage& message) +{ + if (!d->path.isEmpty() && d->path != message.path()) + return; + + // only filter by service name if the name is a unique name + // because signals are always coming from a connection's unique name + // and filtering by a generic name would reject all signals + if (d->service.startsWith(":") && d->service != message.sender()) + return; + + if (!d->interface.isEmpty() && d->interface != message.interface()) + return; + + emit dbusSignal(message); +} + +void TQT_DBusProxy::handleAsyncReply(const TQT_DBusMessage& message) +{ + d->error = message.error(); + + emit asyncReply(message.replySerialNumber(), message); +} + +#include "tqdbusproxy.moc" diff --git a/src/tqdbusproxy.h b/src/tqdbusproxy.h new file mode 100644 index 0000000..8d594cd --- /dev/null +++ b/src/tqdbusproxy.h @@ -0,0 +1,585 @@ +/* qdbusproxy.h DBUS Object proxy + * + * Copyright (C) 2005-2007 Kevin Krammer <kevin.krammer@gmx.at> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#ifndef TQDBUSPROXY_H +#define TQDBUSPROXY_H + +/** + * @page dbusclient Using D-Bus as a client + * + * Contents: + * - @ref dbusclient-introduction + * + * - @ref dbusclient-example + * + * - @ref dbusclient-initialization + * + * - @ref dbusclient-methodcall + * - @ref dbusclient-synccall + * - @ref dbusclient-asynccall + * + * - @ref dbusclient-signals + * - @ref dbusclient-signals-example + * + * @section dbusclient-introduction Introduction + * + * While it is of course possible to just exchange D-Bus messages with a + * D-Bus service, it is a lot more comfortable to use TQT_DBusProxy. + * + * With TQT_DBusProxy you only need to specify the service object once, i.e. + * its D-Bus name, path and interface, and just provide the method and its + * parameters when initiating an invokation. + * + * Additionally the proxy transforms D-Bus signals from the proxy's peer + * (the D-Bus service object's interface it is associated with) to TQObject + * signal carrying the original signal's content. + * + * @section dbusclient-example A simple D-Bus client example + * + * @code + * #include <dbus/tqdbusconnection.h> + * #include <dbus/tqdbusmessage.h> + * #include <dbus/tqdbusproxy.h> + * + * int main() + * { + * // establish a connection to the session bus + * + * TQT_DBusConnection connection = TQT_DBusConnection::sessionBus(); + * if (!connection.isConnected()) + * tqFatal("Failed to connect to session bus"); + * + * // create a proxy object for method calls + * + * TQT_DBusProxy proxy(connection); + * proxy.setService("org.freedesktop.DBus"); // who we work with + * proxy.setPath("/org/freedesktop/DBus"); // which object inside the peer work with + * proxy.setInterface("org.freedesktop.DBus"); // which of its interfaces we will use + * + * // call the "ListNames" method. It returns an array of string, in TQt3 terms + * // a TQStringList, it expects no parameters + * + * TQValueList<TQT_DBusData> params; + * TQT_DBusMessage reply = proxy.sendWithReply("ListNames", params); + * + * if (reply.type() != TQT_DBusMessage::ReplyMessage) + * tqFatal("Call failed"); + * + * if (reply.count() != 1 || reply[0].type() != TQT_DBusData::List) + * tqFatal("Unexpected reply"); + * + * bool ok = false; + * TQStringList names = reply[0].toTQStringList(&ok); + * + * if (!ok) tqFatal("Unexpected reply"); + * + * for (TQStringList::iterator it = names.begin(); it != names.end(); ++it) + * { + * tqDebug("%s", (*it).local8Bit().data()); + * } + * + * return 0; + * } + * @endcode + * + * @section dbusclient-initialization Program initialization + * + * A connection to the bus is acquired using TQT_DBusConnection::sessionBus() + * + * Next, a proxy is created for the object @c "/org/freedesktop/DBus" with + * interface @c "org.freedesktop.DBus" on the service @c "org.freedesktop.DBus" + * + * This is a proxy for the message bus itself. + * + * @section dbusclient-methodcall Method invocation + * + * There are two choices for method invocation: + * - sychronous (blocking) calls + * - asynchronous (non-blocking) calls + * + * @subsection dbusclient-synccall Synchronous method calls + * + * As seen in the example code above, a synchronous method call can be achieved + * by TQT_DBusProxy::sendWithReply(). It sends a method call to the remote object, + * and blocks until reply is received. The outgoing arguments are specified as + * a list of TQT_DBusData. + * + * @subsection dbusclient-asynccall Asynchronous method calls + * + * To invoke a method asynchronously, connect the proxy's signal + * TQT_DBusProxy::asyncReply(int, const TQT_DBusMessage&) to a suitable slot like + * with any other TQt Signal-Slot connection. + * + * Then call TQT_DBusProxy::sendWithAsyncReply() + * It returns a numerical identifier of the call, so it can be related in the + * slot once the result is available. + * + * The slot's first argument is the reveived reply's call identifier as + * returned by the method call. The second parameter is the reply message + * similar to the one in the synchronous call. + * + * @note For asynchronous calls you'll need a running event loop, i.e. a + * TQApplication object and its exec() having been invoked. + * + * @section dbusclient-signals Connecting to D-Bus signals + * + * To receive D-BUS signals just connect to the TQT_DBusProxy's signal + * TQT_DBusProxy::dbusSignal(const TQT_DBusMessage&) + * + * It will be emitted whenever a D-Bus signal message is received from the peer + * object. + * Filtering of signals is based on the value set for @c service, @c path and + * @c interface + * + * @note Filtering for @c service will only happen if @c service is a unique + * D-Bus name, i.e. if it starts with a colon @c ":" since D-Bus signals + * carry the sender's unique name and filtering by a requested name + * would reject all signals + * + * Usually a proxy will be also be used to send to the peer object, thus having + * them all set. However if a proxy is only needed for signals, any of the + * three properties can be omitted (e.g. set to @c TQString() ), in which + * case only the available properties will be checked against the respective + * message field when deciding about dropping or emitting the message. + * See TQT_DBusProxy::handleDBusSignal() + * + * If you want all signal travelling on the bus, or apply filtering for + * different criteria, e.g. get all signals coming from interfaces starting + * with @c "org.", use @c TQT_DBusConnection::connect() instead. + * The signature of the slot stays the same. + * + * @subsection dbusclient-signals-example Signal example + * + * First declare a receiver class: + * @code + * class MyReceiver : public TQObject + * { + * Q_OBJECT + * + * public slots: + * void handleDBusSignal(const TQT_DBusMessage&); + * }; + * @endcode + * Then somewhere else in a source file: + * @code + * TQT_DBusConnection connection = TQT_DBusConnection::sessionBus(); + * + * MyReceiver* receiver1 = new MyReceiver(); + * + * connection.connect(receiver1, TQT_SLOT(handleDBusSignal(const TQT_DBusMessage&))); + * @endcode + * @c receiver1 will get all signals on this connection + * + * @code + * TQT_DBusProxy* proxy = new TQT_DBusProxy(connection); + * proxy->setService("org.freedesktop.DBus"); // who we work with + * proxy->setPath("/org/freedesktop/DBus"); // which object inside the peer work with + * proxy->setInterface("org.freedesktop.DBus"); // which of its interfaces we will use + * + * MyReceiver* receiver2 = new MyReceiver(); + * + * TQObject::connect(proxy, TQT_SIGNAL(dbusSignal(const TQT_DBusMessage&)), + * receiver2, TQT_SLOT(handleDBusSignal(const TQT_DBusMessage&))); + * @endcode + * @c receiver2 will only get signals coming from the proxy's peer interface + */ + +/** + * @include example-client.h + * @example example-client.cpp + */ + +#include <tqobject.h> + +#include "tqdbusmacros.h" + +class TQT_DBusConnection; +class TQT_DBusData; +class TQT_DBusError; +class TQT_DBusMessage; + +template <class T> class TQValueList; + +/** + * @brief Client interface to a remote service object + * + * TQT_DBusProxy provides a convenience interface for working with D-Bus services, + * or more precisely, interfaces of D-Bus service objects. + * + * A D-Bus service object is identified through the name of its host application + * on the bus and its path (logical location) within the host application. + * Such a service object can implement any number of interfaces, i.e. groups + * methods and signals, and can create a TQT_DBusProxy instance for every one + * your application needs to work with. + * + * See section @ref dbusclient for documentation on how to use TQT_DBusProxy + */ +class TQDBUS_EXPORT TQT_DBusProxy : public TQObject +{ + Q_OBJECT + +public: + /** + * @brief Creates a proxy without binding it to a service or connection + * + * This basic constructor allows to create a proxy and specify the peer + * object and interface later on. + * + * @param parent TQObject parent + * @param name TQObject name + */ + TQT_DBusProxy(TQObject* parent = 0, const char* name = 0); + + /** + * @brief Creates a proxy on a given connection without binding it to a + * service + * + * Similar to the above constructor, it does not yet specify and details + * about the proxy's peer, but already specifies which connection to work + * on. + * + * This can be useful to monitor all signal on a connection without + * filtering for a specific peer. + * + * @param connection the D-Bus connection to work on + * @param parent TQObject parent + * @param name TQObject name + */ + TQT_DBusProxy(const TQT_DBusConnection& connection, TQObject* parent = 0, + const char* name = 0); + + /** + * @brief Creates a proxy for a given peer on a given connection + * + * This creates a proxy for a specific peer object-interface combination + * It is equvalent to creating an "empty" proxy and calling setConnection(), + * setService(), setPath() and setInterface() manually. + * + * @param service the name the peer's host application uses on the bus + * @param path the peer object's path within its host application + * @param interface the interface to work with + * @param connection the D-Bus connection to work on + * @param parent TQObject parent + * @param name TQObject name + */ + TQT_DBusProxy(const TQString& service, const TQString& path, + const TQString& interface, const TQT_DBusConnection& connection, + TQObject* parent = 0, const char* name = 0); + + /** + * @brief Destroys the proxy instance + */ + virtual ~TQT_DBusProxy(); + + /** + * @brief Sets the D-Bus connection to work on + * + * Disconnects from any previously used connection and connects + * to the new connection's signal distribution. + * If no peer information has been provided at creation time or through + * the other set methods, the instance's signal dbusSignal() will emit + * all signals received on the given connection. + * + * @param connection the D-Bus connection to work on + * + * @return @c true if connecting to the new connection's signal succeeded, + * @c false if it failed, e.g. if the connection is a "null" + * connection + * + * @see connection() + * @see setService() + * @see setPath() + * @see setInterface() + */ + bool setConnection(const TQT_DBusConnection& connection); + + /** + * @brief Returns the currently used D-Bus connection + * + * @see setConnection() + */ + const TQT_DBusConnection& connection() const; + + /** + * @brief Sets the peer's service name + * + * A non-empty service name is required if the proxy is to be used for + * method calls. See section @ref dbusconventions-servicename for details. + * + * If a string other than @c TQString() is set, it will be used to + * filter signals, i.e. a signal received by the proxy will only be emitted + * if the service name matches. + * + * @param service the peer's name on the bus + * + * @see service() + * @see setPath() + * @see setInterface() + */ + void setService(const TQString& service); + + /** + * @brief Returns the peer's service name + * + * @return the peer object's service name + * + * @see setService() + */ + TQString service() const; + + /** + * @brief Sets the peer's object path + * + * A non-empty object path is required if the proxy is to be used for + * method calls. See section @ref dbusconventions-objectpath for details. + * + * If a string other than @c TQString() is set, it will be used to + * filter signals, i.e. a signal received by the proxy will only be emitted + * if the object path matches. + * + * @param path the peer's object path inside its host application + * (logical address) + * + * @see path() + * @see setService() + * @see setInterface() + */ + void setPath(const TQString& path); + + /** + * @brief Returns the peer's object path + * + * @return the peer object's path + * + * @see setPath() + */ + TQString path() const; + + /** + * @brief Sets the name of the peer interface + * + * A non-empty interface name is required if the proxy is to be used for + * method calls. See section @ref dbusconventions-interfacename for + * details. + * + * If a string other than @c TQString() is set, it will be used to + * filter signals, i.e. a signal received by the proxy will only be emitted + * if the interface name matches. + * + * @param interface the peer's interface to work with + * + * @see interface() + * @see setService() + * @see setPath() + */ + void setInterface(const TQString& interface); + + /** + * @brief Returns the name of the peer interface + * + * @return the peer object's interface + * + * @see setInterface() + */ + TQString interface() const; + + /** + * @brief Returns whether the proxy can be used to send method calls + * + * The capabilitly to send method calls depends on having all necessary + * base information: + * - Service name, see setService() + * - Object path, see setPath() + * - Interface, see setInterface() + * + * and a working connection, see setConnection() + * + * @return @c true if method calls can be sent, @c false if any of the three + * base information is missing or if the connection is not connected + * + * @see send() + * @see sendWithReply() + * @see sendWithAsyncReply() + */ + bool canSend() const; + + /** + * @brief Sends a method call to the peer object + * + * This is roughly equivalent to calling a C++ method with no return value + * or like ignoring the it. + * + * @param method the name of the method to invoke + * @param params the method parameters. Use an empty list if the method + * does not require parameters + * + * @return @c true if sending succeeded, @c false if sending failed, + * the method name was empty or any of the conditions for + * successfull sending as described for canSend() are not met + * + * @see lastError() + * @see sendWithReply() + * @see sendWithAsyncReply() + * @see @ref dbusconventions-membername + */ + bool send(const TQString& method, const TQValueList<TQT_DBusData>& params) const; + + /** + * @brief Sends a method call to the peer object and waits for the reply + * + * This is roughly equivalent to calling a C++ method on a local object. + * + * @param method the name of the method to invoke + * @param params the method parameters. Use an empty list if the method + * does not require parameters + * @param error optional parameter to get any error directly + * + * @return a TQT_DBusMessage containing any return values of the invoked method. + * Will be an invalid message if an error occurs. The error can be + * accessed through the optional paramater @p error or through + * lastError() + * + * @see canSend() + * @see send() + * @see sendWithAsyncReply() + * @see @ref dbusconventions-membername + */ + TQT_DBusMessage sendWithReply(const TQString& method, + const TQValueList<TQT_DBusData>& params, TQT_DBusError* error = 0) const; + + /** + * @brief Sends a method call to the peer object but does not wait for an + * answer + * + * This is roughly equivalent to calling a C++ method on a local TQt + * event loop driven object, where the result of the method call is + * delivered later through a signal. + * + * @note as with TQt's asychronous classes this needs a running event loop + * + * @param method the name of the method to invoke + * @param params the method parameters. Use an empty list if the method + * does not require parameters + * + * @return a serial number to easily identify the reply once it is received + * or 0 if the call is not possible, i.e. the method name is empty + * or any of the conditions for canSend() are not met + * + * @warning if a asynchronous call is followed by a synchronous call, e.g. + * using sendWithReply(), without returning to the event loop, + * is recommended to call TQT_DBusConnection::scheduleDispatch() + * after the synchronous call to make sure any reply received + * during the blocking call is delivered + * + * @see asyncReply() + * @see send() + * @see sendWithReply() + * @see @ref dbusconventions-membername + */ + int sendWithAsyncReply(const TQString& method, const TQValueList<TQT_DBusData>& params); + + /** + * @brief Returns the last error seen by the proxy + * + * The last error can a connection error, e.g. sending a message failed due + * connection being lost, or the error of the last call to sendWithReply or + * the error of the last received asyncReply() + * + * @return the last dbus error seen by this proxy + */ + TQT_DBusError lastError() const; + +signals: + /** + * @brief Signal emitted for D-Bus signals from the peer + * + * Signals received on the proxy's connection are filtered by + * handleDBusSignal() for all proxy properties that are not empty. + * + * @param message the signal's content + * + * @see TQT_DBusMessage::SignalMessage + */ + void dbusSignal(const TQT_DBusMessage& message); + + /** + * @brief Signal emitted for received replies to asynchronous method calls + * + * If a method invoked by using sendWithAsyncReply() send a response, e.g. + * method return value or errors, this signal is emitted to notify the + * proxy's user. + * + * @param callID the method call's serial number as returned by + * sendWithAsyncReply() + * @param message the reply's content + * + * @see handleAsyncReply() + * @see TQT_DBusMessage::replySerialNumber() + */ + void asyncReply(int callID, const TQT_DBusMessage& message); + +protected slots: + /** + * @brief Handles D-Bus signals received on the proxy's connection + * + * The base implementation checks each non-empty property, i.e. service + * name, object path and interface, with the respective field of the + * signal's D-Bus message. + * + * If all available matches succeed, the message is emitted by + * dbusSignal(), otherwise it is discarded. + * + * @note Filtering for @c service will only happen if @c service is a + * unique D-Bus name, i.e. if it starts with a colon @c ":" since + * D-Bus signals carry the sender's unique name and filtering by a + * requested name would reject all signals. + * + * @param message the D-Bus signal message as received + * + * @see TQT_DBusMessage::SignalMessage + */ + virtual void handleDBusSignal(const TQT_DBusMessage& message); + + /** + * @brief Handles replies to asynchronous method calls + * + * The base implementation simply extracts the reply's error and makes + * it available for lastError(). It then emits asyncReply() + * + * @param message the D-Bus reply message as received + * + * @see TQT_DBusMessage::replySerialNumber() + */ + virtual void handleAsyncReply(const TQT_DBusMessage& message); + +private: + class Private; + Private* d; + +private: + TQT_DBusProxy(const TQT_DBusProxy&); + TQT_DBusProxy& operator=(const TQT_DBusProxy&); +}; + +#endif + diff --git a/src/tqdbusserver.cpp b/src/tqdbusserver.cpp new file mode 100644 index 0000000..6bad746 --- /dev/null +++ b/src/tqdbusserver.cpp @@ -0,0 +1,60 @@ +/* qdbusserver.cpp + * + * Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#include "tqdbusserver.h" +#include "tqdbusconnection_p.h" + +TQT_DBusServer::TQT_DBusServer(const TQString &addr, TQObject *parent) + : TQObject(parent) +{ + d = new TQT_DBusConnectionPrivate(this); + + if (addr.isEmpty()) + return; + + d->setServer(dbus_server_listen(addr.utf8().data(), &d->error)); +} + +bool TQT_DBusServer::isConnected() const +{ + return d->server && dbus_server_get_is_connected(d->server); +} + +TQT_DBusError TQT_DBusServer::lastError() const +{ + return d->lastError; +} + +TQString TQT_DBusServer::address() const +{ + TQString addr; + if (d->server) { + char *c = dbus_server_get_address(d->server); + addr = TQString::fromUtf8(c); + dbus_free(c); + } + + return addr; +} + +#include "tqdbusserver.moc" diff --git a/src/tqdbusserver.h b/src/tqdbusserver.h new file mode 100644 index 0000000..0660a87 --- /dev/null +++ b/src/tqdbusserver.h @@ -0,0 +1,53 @@ +/* qdbusserver.h TQT_DBusServer object + * + * Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#ifndef TQDBUSSERVER_H +#define TQDBUSSERVER_H + +#include "tqdbusmacros.h" +#include <tqobject.h> + +class TQString; + +class TQT_DBusConnectionPrivate; +class TQT_DBusError; + + +class TQDBUS_EXPORT TQT_DBusServer: public TQObject +{ + Q_OBJECT + +public: + TQT_DBusServer(const TQString &address, TQObject *parent = 0); + + bool isConnected() const; + TQT_DBusError lastError() const; + TQString address() const; + +private: + TQT_DBusServer(const TQT_DBusServer&); + TQT_DBusServer& operator=(const TQT_DBusServer&); + TQT_DBusConnectionPrivate *d; +}; + +#endif diff --git a/src/tqdbusunixfd.cpp b/src/tqdbusunixfd.cpp new file mode 100644 index 0000000..3aa4ba2 --- /dev/null +++ b/src/tqdbusunixfd.cpp @@ -0,0 +1,95 @@ +/* tqdbusunixfd.cpp DBUS unix file handle data type + * + * Copyright (C) 2013 Slávek Banko <slavek.banko@axis.cz> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#include <unistd.h> +#include "tqdbusunixfd.h" + +TQT_DBusUnixFd::TQT_DBusUnixFd() : d(new TQT_DBusUnixFdPrivate()) +{ + d->ref(); + d->fd = -1; +}; + +TQT_DBusUnixFd::TQT_DBusUnixFd(const TQT_DBusUnixFd& other) : d(other.d) +{ + d->ref(); +} + +TQT_DBusUnixFd::TQT_DBusUnixFd(int other) : d(0) +{ + setFileDescriptor(other); +} + +TQT_DBusUnixFd::~TQT_DBusUnixFd() +{ + if (d && d->deref() ) { + if ( isValid() ) { + close(d->fd); + } + delete d; + } +} + +bool TQT_DBusUnixFd::isValid() const +{ + return d ? d->fd != -1 : false; +} + +int TQT_DBusUnixFd::fileDescriptor() const +{ + return d ? d->fd : -1; +} + +void TQT_DBusUnixFd::setFileDescriptor(int fileDescriptor) +{ + giveFileDescriptor(fileDescriptor != -1 ? dup(fileDescriptor) : -1); +} + +void TQT_DBusUnixFd::giveFileDescriptor(int fileDescriptor) +{ + if ( d && d->deref() ) { + if ( isValid() ) { + close(d->fd); + } + } + else { + d = new TQT_DBusUnixFdPrivate; + } + d->ref(); + d->fd = fileDescriptor; +} + +TQT_DBusUnixFd &TQT_DBusUnixFd::operator=( const TQT_DBusUnixFd &other ) +{ + if (other.d) { + other.d->ref(); + } + if ( d && d->deref() ) { + if ( isValid() ) { + close(d->fd); + } + delete d; + } + d = other.d; + return *this; +} diff --git a/src/tqdbusunixfd.h b/src/tqdbusunixfd.h new file mode 100644 index 0000000..9f48a37 --- /dev/null +++ b/src/tqdbusunixfd.h @@ -0,0 +1,150 @@ +/* tqdbusunixfd.h DBUS unix file handle data type + * + * Copyright (C) 2013 Slávek Banko <slavek.banko@axis.cz> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#ifndef TQDBUSUNIXFD_H +#define TQDBUSUNIXFD_H + +#include "dbus/dbus.h" +#ifndef QT_H +#include "ntqshared.h" +#endif // QT_H +#include "tqdbusmacros.h" + + +#ifndef DBUS_TYPE_UNIX_FD +#define DBUS_TYPE_UNIX_FD ((int) 'h') +#endif + +#ifndef DBUS_TYPE_UNIX_FD_AS_STRING +#define DBUS_TYPE_UNIX_FD_AS_STRING "h" +#endif + +/** + * @brief Class for representing D-Bus unix file handles + * + * This data type is necessary to correctly represent unix file handles in the + * context of D-Bus messages, since normal strings have a different D-Bus + * signature than unix file handles. + * + * @see @ref dbusconventions-unixfd + */ +class TQDBUS_EXPORT TQT_DBusUnixFd +{ +public: + /** + * @brief Creates an empty and invalid unix file handle + */ + TQT_DBusUnixFd(); + + /** + * @brief Creates copy of the given @p other unix file handle + * + * @param other the unix file handle to copy + */ + TQT_DBusUnixFd(const TQT_DBusUnixFd& other); + + /** + * @brief Creates copy of the given @p other unix file handle + * + * @param other the unix file handle to copy + */ + TQT_DBusUnixFd(int other); + + /** + * @brief Destroys the unix file handle + */ + virtual ~TQT_DBusUnixFd(); + + /** + * @brief Returns whether the current content is considered a valid unix file handle + * + * @return \c true if the object's content describe a valid unix file handle, + * otherwise @c false + * + * @see @ref dbusconventions-unixfd + */ + bool isValid() const; + + /** + * @brief Get unix file handle + * + * @see @ref dbusconventions-unixfd + */ + int fileDescriptor() const; + + /** + * @brief Set new unix file handle + * + * @see @ref dbusconventions-unixfd + */ + void setFileDescriptor(int fileDescriptor); + + /** + * @brief Give unix file handle + * + * @see @ref dbusconventions-unixfd + */ + void giveFileDescriptor(int fileDescriptor); + + /** + * @brief Copy unix file handle from TQT_DBusUnixFd + * + * @see @ref dbusconventions-unixfd + */ + TQT_DBusUnixFd &operator=( const TQT_DBusUnixFd &other ); + + /** + * @brief Checks if the given @p other variant is equal to this one + * + * @param other unix file handle to compare with + * + * @return @c true if both use same file handle, otherwise + * @c false + */ + inline bool operator==(const TQT_DBusUnixFd& other) const + { + return (&other == this) || (other.d == d); + } + + /** + * @brief Checks if the given @p other variant is not equal to this one + * + * @param other unix file handle to compare with + * + * @return @c true if both use different file handle, otherwise + * @c false + */ + inline bool operator!=(const TQT_DBusUnixFd& other) const + { + return (&other != this) && (other.d != d); + } + + +protected: + struct TQT_DBusUnixFdPrivate : public TQShared { + int fd; + } *d; + +}; + +#endif diff --git a/src/tqdbusvariant.h b/src/tqdbusvariant.h new file mode 100644 index 0000000..11c0ec5 --- /dev/null +++ b/src/tqdbusvariant.h @@ -0,0 +1,120 @@ +/* qdbusvariant.h DBUS variant struct + * + * Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org> + * + * Licensed under the Academic Free License version 2.1 + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + */ + +#ifndef TQDBUSVARIANT_H +#define TQDBUSVARIANT_H + +#include "tqdbusmacros.h" +#include "tqdbusdata.h" + +#include <tqstring.h> + +/** + * @brief Data type for representing a D-Bus variant + * + * When D-Bus methods or signal require that a paramater can have any of the + * D-Bus data types, a D-Bus variant can be used. + * + * Basically a D-Bus variant includes the actual data and a D-Bus data signature + * to allow a receiver to determine the contents. + * + * Since the TQT_DBusVariant's #value member will already be fully de-marshalled, + * a receiver using this bindings can savely ignore the signature if it doesn't + * need it for a different purpose (e.g. logging). + * + * However, when creating a TQT_DBusVariant object for sending, make sure the + * #signature member is correctly setup, for example by using the #value + * member's buildDBusSignature() method. + * + * @code + * TQT_DBusVariant variant; + * + * variant.value = TQT_DBusData::fromInt32(131719); + * variant.signature = variant.value.buildDBusSignature(); + * @endcode + */ +class TQDBUS_EXPORT TQT_DBusVariant +{ +public: + /** + * @brief Creates an empty variant object + */ + TQT_DBusVariant() {} + + /** + * @brief Copies the given @p other variant object + * + * @param other the variant object to copy from + */ + TQT_DBusVariant(const TQT_DBusVariant& other) + { + signature = other.signature; + value = other.value; + } + + /** + * @brief Checks if the given @p other variant is equal to this one + * + * @param other the variant object to compare with + * + * @return @c true if both #signature and #value are equal, otherwise + * @c false + */ + inline bool operator==(const TQT_DBusVariant& other) const + { + if (&other == this) return true; + + return signature == other.signature && value == other.value; + } + + /** + * @brief Checks if the given @p other variant is not equal to this one + * + * @param other the variant object to compare with + * + * @return @c true if either #signature or #value is different, otherwise + * @c false + */ + inline bool operator!=(const TQT_DBusVariant& other) const + { + if (&other == this) return false; + + return signature != other.signature || value != other.value; + } + +public: + /** + * @brief The D-Bus data signature of the data contained in #value + * + * @see TQT_DBusData::buildDBusSignature() + */ + TQString signature; + + /** + * @brief The D-Bus data type to transport as a variant + */ + TQT_DBusData value; +}; + +#endif + |