diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /unodevtools | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'unodevtools')
-rw-r--r-- | unodevtools/Executable_uno-skeletonmaker.mk | 41 | ||||
-rw-r--r-- | unodevtools/IwyuFilter_unodevtools.yaml | 2 | ||||
-rw-r--r-- | unodevtools/Makefile | 14 | ||||
-rw-r--r-- | unodevtools/Module_unodevtools.mk | 20 | ||||
-rw-r--r-- | unodevtools/README.md | 6 | ||||
-rw-r--r-- | unodevtools/inc/options.hxx | 41 | ||||
-rw-r--r-- | unodevtools/source/skeletonmaker/cppcompskeleton.cxx | 1221 | ||||
-rw-r--r-- | unodevtools/source/skeletonmaker/cpptypemaker.cxx | 976 | ||||
-rw-r--r-- | unodevtools/source/skeletonmaker/javacompskeleton.cxx | 920 | ||||
-rw-r--r-- | unodevtools/source/skeletonmaker/javatypemaker.cxx | 861 | ||||
-rw-r--r-- | unodevtools/source/skeletonmaker/skeletoncommon.cxx | 589 | ||||
-rw-r--r-- | unodevtools/source/skeletonmaker/skeletoncommon.hxx | 138 | ||||
-rw-r--r-- | unodevtools/source/skeletonmaker/skeletoncpp.hxx | 94 | ||||
-rw-r--r-- | unodevtools/source/skeletonmaker/skeletonjava.hxx | 57 | ||||
-rw-r--r-- | unodevtools/source/skeletonmaker/skeletonmaker.cxx | 315 | ||||
-rw-r--r-- | unodevtools/source/unodevtools/options.cxx | 85 |
16 files changed, 5380 insertions, 0 deletions
diff --git a/unodevtools/Executable_uno-skeletonmaker.mk b/unodevtools/Executable_uno-skeletonmaker.mk new file mode 100644 index 0000000000..87f8d3ca9b --- /dev/null +++ b/unodevtools/Executable_uno-skeletonmaker.mk @@ -0,0 +1,41 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Executable_Executable,uno-skeletonmaker)) + +$(eval $(call gb_Executable_use_external,uno-skeletonmaker,boost_headers)) + +$(eval $(call gb_Executable_set_include,uno-skeletonmaker,\ + -I$(SRCDIR)/unodevtools/inc \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_Executable_use_libraries,uno-skeletonmaker,\ + sal \ + salhelper \ + unoidl \ +)) + +$(eval $(call gb_Executable_use_static_libraries,uno-skeletonmaker,\ + codemaker \ + codemaker_cpp \ + codemaker_java \ +)) + +$(eval $(call gb_Executable_add_exception_objects,uno-skeletonmaker,\ + unodevtools/source/unodevtools/options \ + unodevtools/source/skeletonmaker/skeletonmaker \ + unodevtools/source/skeletonmaker/skeletoncommon \ + unodevtools/source/skeletonmaker/javatypemaker \ + unodevtools/source/skeletonmaker/cpptypemaker \ + unodevtools/source/skeletonmaker/javacompskeleton \ + unodevtools/source/skeletonmaker/cppcompskeleton \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/unodevtools/IwyuFilter_unodevtools.yaml b/unodevtools/IwyuFilter_unodevtools.yaml new file mode 100644 index 0000000000..5e1f0b518a --- /dev/null +++ b/unodevtools/IwyuFilter_unodevtools.yaml @@ -0,0 +1,2 @@ +--- +assumeFilename: unodevtools/source/skeletonmaker/skeletonmaker.cxx diff --git a/unodevtools/Makefile b/unodevtools/Makefile new file mode 100644 index 0000000000..0997e62848 --- /dev/null +++ b/unodevtools/Makefile @@ -0,0 +1,14 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +module_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST)))) + +include $(module_directory)/../solenv/gbuild/partial_build.mk + +# vim: set noet sw=4 ts=4: diff --git a/unodevtools/Module_unodevtools.mk b/unodevtools/Module_unodevtools.mk new file mode 100644 index 0000000000..95aa46065a --- /dev/null +++ b/unodevtools/Module_unodevtools.mk @@ -0,0 +1,20 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Module_Module,unodevtools)) + +ifneq (,$(filter ODK,$(BUILD_TYPE))) + +$(eval $(call gb_Module_add_targets,unodevtools,\ + Executable_uno-skeletonmaker \ +)) + +endif + +# vim:set noet sw=4 ts=4: diff --git a/unodevtools/README.md b/unodevtools/README.md new file mode 100644 index 0000000000..16692e371e --- /dev/null +++ b/unodevtools/README.md @@ -0,0 +1,6 @@ +# Helper Tools for External UNO Component Developers + +This module contains some tools for people writing UNO components. In +particular it will auto-generate skeletons for implementing UNO +interfaces - that declare all the relevant methods leaving the code to +be filled in. This can be done for C++ or Java. diff --git a/unodevtools/inc/options.hxx b/unodevtools/inc/options.hxx new file mode 100644 index 0000000000..2ec56abeff --- /dev/null +++ b/unodevtools/inc/options.hxx @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <sal/config.h> + +#include <string_view> + +#include <rtl/ustring.hxx> + +namespace unodevtools { + + +bool readOption( OUString * pValue, const char * pOpt, + sal_uInt32 * pnIndex, std::u16string_view aArg); + // throws CannotDumpException + + +bool readOption( const char * pOpt, + sal_uInt32 * pnIndex, std::u16string_view aArg); + +} // end of namespace unodevtools + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unodevtools/source/skeletonmaker/cppcompskeleton.cxx b/unodevtools/source/skeletonmaker/cppcompskeleton.cxx new file mode 100644 index 0000000000..8fbb96c194 --- /dev/null +++ b/unodevtools/source/skeletonmaker/cppcompskeleton.cxx @@ -0,0 +1,1221 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <codemaker/commoncpp.hxx> +#include <codemaker/global.hxx> + +#include "skeletoncommon.hxx" +#include "skeletoncpp.hxx" + +#include <iostream> +#include <string_view> + +using namespace ::codemaker::cpp; + +namespace skeletonmaker::cpp { + +static void generateIncludes(std::ostream & o, + const std::set< OUString >& interfaces, + std::u16string_view propertyhelper, const bool serviceobject, + const bool supportxcomponent) +{ + o << "#include \"sal/config.h\"\n"; + if (serviceobject) { + o << "#include \"cppuhelper/factory.hxx\"\n" + "#include \"cppuhelper/implementationentry.hxx\"\n"; + } else { + o << "#include \"com/sun/star/uno/XComponentContext.hpp\"\n"; + } + if (supportxcomponent) { + o << "#include \"cppuhelper/compbase" << interfaces.size() << ".hxx\"\n"; + o << "#include \"cppuhelper/basemutex.hxx\"\n"; + } else { + o << "#include \"cppuhelper/implbase" << interfaces.size() << ".hxx\"\n"; + } + + if (propertyhelper.size() > 1) { + if (propertyhelper == u"_") + o << "#include \"cppuhelper/rpopshlp.hxx\"\n"; + else + o << "#include \"cppuhelper/propertysetmixin.hxx\"\n"; + } + + for (const auto& rIface : interfaces) + { + o << "#include \"" + << rIface.replace('.', '/') + << ".hpp\"\n"; + } +} + +static short generateNamespace(std::ostream & o, + const OString & implname, + bool serviceobject, + OString & nm) +{ + short count=0; + sal_Int32 index = implname.lastIndexOf('.'); + if (serviceobject) { + o << "\n\n// component helper namespace\n"; + } else { + o << "\n"; + } + OStringBuffer buf; + if (index == -1) { + if (serviceobject) { + buf.append("comp_" + implname); + nm = buf.makeStringAndClear(); + o << "namespace comp_" << implname << " {\n\n"; + count=1; + } else { + nm.clear(); + } + } else { + sal_Int32 nPos=0; + do { + OString token(implname.getToken(0, '.', nPos)); + if (nPos < 0 && serviceobject) { + buf.append("::comp_" + token); + o << "namespace comp_" << token << " { "; + count++; + } else { + buf.append("::" + token); + o << "namespace " << token << " { "; + count++; + } + } while( nPos <= index ); + nm = buf.makeStringAndClear(); + o << "\n\n"; + } + return count; +} + +static OString generateCompHelperDeclaration(std::ostream & o, + const OString & implname) +{ + OString nm; + short nbrackets = generateNamespace(o, implname, true, nm); + + o << "namespace css = ::com::sun::star;\n\n"; + + // generate component/service helper functions + o << "// component and service helper functions:\n" + "OUString SAL_CALL _getImplementationName();\n" + "css::uno::Sequence< OUString > SAL_CALL " + "_getSupportedServiceNames();\n" + "css::uno::Reference< css::uno::XInterface > SAL_CALL _create(" + " css::uno::Reference< css::uno::XComponentContext > const & " + "context );\n\n"; + + // close namespace + for (short i=0; i < nbrackets; i++) + o << "} "; + o << "// closing component helper namespace\n\n"; + + return nm; +} + +static void generateCompHelperDefinition(std::ostream & o, + const OString & implname, + const OString & classname, + const std::set< OUString >& services) +{ + OString nm; + short nbrackets = generateNamespace(o, implname, true, nm); + + o << "OUString SAL_CALL _getImplementationName() {\n" + " return OUString(\n" + " \"" << implname << "\");\n}\n\n"; + + o << "css::uno::Sequence< OUString > SAL_CALL " + "_getSupportedServiceNames()\n{\n css::uno::Sequence< " + "OUString > s(" << services.size() << ");\n"; + + short i=0; + for (const auto& rService : services) + { + o << " s[" << i++ << "] = OUString(\"" + << rService << "\");\n"; + } + o << " return s;\n}\n\n"; + + o << "css::uno::Reference< css::uno::XInterface > SAL_CALL _create(" + "\n const css::uno::Reference< css::uno::XComponentContext > & " + "context)\n{\n" + " return static_cast< ::cppu::OWeakObject * >(new " + << classname << "(context));\n}\n\n"; + + // close namespace + for (short j=0; j < nbrackets; j++) + o << "} "; + o << "// closing component helper namespace\n\n"; + +} + +static void generateCompFunctions(std::ostream & o, const OString & nmspace) +{ + o << "static ::cppu::ImplementationEntry const entries[] = {\n" + " { &" << nmspace << "::_create,\n &" + << nmspace << "::_getImplementationName,\n &" + << nmspace << "::_getSupportedServiceNames,\n" + " &::cppu::createSingleComponentFactory, 0, 0 },\n" + " { 0, 0, 0, 0, 0, 0 }\n};\n\n"; + + o << "extern \"C\" SAL_DLLPUBLIC_EXPORT void * SAL_CALL component_getFactory(\n" + " const char * implName, void * serviceManager, void * registryKey)\n{\n" + " return ::cppu::component_getFactoryHelper(\n" + " implName, serviceManager, registryKey, entries);\n}\n\n"; + + o << "extern \"C\" sal_Bool SAL_CALL component_writeInfo(\n" + " void * serviceManager, void * registryKey)\n{\n" + " return ::cppu::component_writeInfoHelper(" + "serviceManager, registryKey, entries);\n}\n"; +} + +void generateXPropertySetBodies(std::ostream& o, + const OString & classname, + const OString & propertyhelper) +{ + o << "// com.sun.star.beans.XPropertySet:\n"; + + o << "css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL " + << classname << "getPropertySetInfo() throw (" + "css::uno::RuntimeException)\n{\n return ::cppu::PropertySetMixin< " + << propertyhelper + << " >::getPropertySetInfo();\n}\n\n"; + + o << "void SAL_CALL " << classname << "setPropertyValue(const OUString" + " & aPropertyName, const css::uno::Any & aValue) throw (" + "css::uno::RuntimeException, css::beans::UnknownPropertyException, " + "css::beans::PropertyVetoException, css::lang::IllegalArgumentException, " + "css::lang::WrappedTargetException)\n{\n ::cppu::PropertySetMixin< " + << propertyhelper << " >::setPropertyValue(aPropertyName, aValue);\n}\n\n"; + + + o << "css::uno::Any SAL_CALL " << classname << "getPropertyValue(const " + "OUString & aPropertyName) throw (css::uno::RuntimeException, " + "css::beans::UnknownPropertyException, css::lang::WrappedTargetException)" + "\n{\n return ::cppu::PropertySetMixin< " + << propertyhelper << " >::getPropertyValue(aPropertyName);\n}\n\n"; + + o << "void SAL_CALL " << classname << "addPropertyChangeListener(const " + "OUString & aPropertyName, const css::uno::Reference< " + "css::beans::XPropertyChangeListener > & xListener) throw (" + "css::uno::RuntimeException, css::beans::UnknownPropertyException, " + "css::lang::WrappedTargetException)\n{\n ::cppu::PropertySetMixin< " + << propertyhelper + << " >::addPropertyChangeListener(aPropertyName, xListener);\n}\n\n"; + + o << "void SAL_CALL " << classname << "removePropertyChangeListener(const " + "OUString & aPropertyName, const css::uno::Reference< " + "css::beans::XPropertyChangeListener > & xListener) throw (" + "css::uno::RuntimeException, css::beans::UnknownPropertyException, " + "css::lang::WrappedTargetException)\n{\n ::cppu::PropertySetMixin< " + << propertyhelper + << " >::removePropertyChangeListener(aPropertyName, xListener);\n}\n\n"; + + o << "void SAL_CALL " << classname << "addVetoableChangeListener(const " + "OUString & aPropertyName, const css::uno::Reference< " + "css::beans::XVetoableChangeListener > & xListener) throw (" + "css::uno::RuntimeException, css::beans::UnknownPropertyException, " + "css::lang::WrappedTargetException)\n{\n ::cppu::PropertySetMixin< " + << propertyhelper + << " >::addVetoableChangeListener(aPropertyName, xListener);\n}\n\n"; + + o << "void SAL_CALL " << classname << "removeVetoableChangeListener(const " + "OUString & aPropertyName, const css::uno::Reference< " + "css::beans::XVetoableChangeListener > & xListener) throw (" + "css::uno::RuntimeException, css::beans::UnknownPropertyException, " + "css::lang::WrappedTargetException)\n{\n ::cppu::PropertySetMixin< " + << propertyhelper + << " >::removeVetoableChangeListener(aPropertyName, xListener);\n}\n\n"; +} + +void generateXFastPropertySetBodies(std::ostream& o, + const OString & classname, + const OString & propertyhelper) +{ + o << "// com.sun.star.beans.XFastPropertySet:\n"; + + o << "void SAL_CALL " << classname << "setFastPropertyValue( ::sal_Int32 " + "nHandle, const css::uno::Any& aValue ) throw (" + "css::beans::UnknownPropertyException, css::beans::PropertyVetoException, " + "css::lang::IllegalArgumentException, css::lang::WrappedTargetException, " + "css::uno::RuntimeException)\n{\n ::cppu::PropertySetMixin< " + << propertyhelper << " >::setFastPropertyValue(nHandle, aValue);\n}\n\n"; + + + o << "css::uno::Any SAL_CALL " << classname << "getFastPropertyValue( " + "::sal_Int32 nHandle ) throw (css::beans::UnknownPropertyException, " + "css::lang::WrappedTargetException, css::uno::RuntimeException)\n{\n" + " return ::cppu::PropertySetMixin< " + << propertyhelper << " >::getFastPropertyValue(nHandle);\n}\n\n"; +} + +void generateXPropertyAccessBodies(std::ostream& o, + const OString & classname, + const OString & propertyhelper) +{ + o << " // com.sun.star.beans.XPropertyAccess:\n"; + + o << "css::uno::Sequence< css::beans::PropertyValue > SAL_CALL " + << classname << "getPropertyValues( ) throw (" + "css::uno::RuntimeException)\n{\n" + " return ::cppu::PropertySetMixin< " + << propertyhelper << " >::getPropertyValues();\n}\n\n"; + + o << "void SAL_CALL " << classname << "setPropertyValues( const " + "css::uno::Sequence< css::beans::PropertyValue >& aProps ) throw (" + "css::beans::UnknownPropertyException, css::beans::PropertyVetoException, " + "css::lang::IllegalArgumentException, css::lang::WrappedTargetException, " + "css::uno::RuntimeException)\n{\n" + " ::cppu::PropertySetMixin< " + << propertyhelper << " >::setPropertyValues(aProps);\n}\n\n"; +} + +void generateXLocalizable(std::ostream& o, const OString & classname) +{ + o << "// css::lang::XLocalizable:\n" + "void SAL_CALL " << classname << "setLocale(const css::lang::" + "Locale & eLocale) throw (css::uno::RuntimeException)\n{\n" + " m_locale = eLocale;\n}\n\n" + "css::lang::Locale SAL_CALL " << classname << "getLocale() " + "throw (css::uno::RuntimeException)\n{\n return m_locale;\n}\n\n"; +} + +void generateXAddInBodies(std::ostream& o, const OString & classname) +{ + o << "// css::sheet::XAddIn:\n"; + + o << "OUString SAL_CALL " << classname << "getProgrammaticFuntionName(" + "const OUString & aDisplayName) throw (css::uno::RuntimeException)" + "\n{\n OUString ret;\n try {\n css::uno::Reference< " + "css::container::XNameAccess > xNAccess(m_xHAccess, css::uno::UNO_QUERY);\n" + " css::uno::Sequence< OUString > functions = " + "xNAccess->getElementNames();\n sal_Int32 len = functions." + "getLength();\n OUString sDisplayName;\n" + " for (sal_Int32 i=0; i < len; ++i) {\n" + " sDisplayName = getAddinProperty(functions[i], " + "OUString(),\n " + "sDISPLAYNAME);\n if (sDisplayName.equals(aDisplayName))\n" + " return functions[i];\n }\n }\n" + " catch ( const css::uno::RuntimeException & e ) {\n throw e;\n }\n" + " catch ( css::uno::Exception & ) {\n }\n return ret;\n}\n\n"; + + o << "OUString SAL_CALL " << classname << "getDisplayFunctionName(const " + "OUString & aProgrammaticName) throw (css::uno::RuntimeException)\n" + "{\n return getAddinProperty(aProgrammaticName, OUString(), " + "sDISPLAYNAME);\n}\n\n"; + + o << "OUString SAL_CALL " << classname << "getFunctionDescription(const " + "OUString & aProgrammaticName) throw (css::uno::RuntimeException)\n" + "{\n return getAddinProperty(aProgrammaticName, OUString(), " + "sDESCRIPTION);\n}\n\n"; + + o << "OUString SAL_CALL " << classname << "getDisplayArgumentName(const " + "OUString & aProgrammaticFunctionName, ::sal_Int32 nArgument) throw " + "(css::uno::RuntimeException)\n{\n return getAddinProperty(" + "aProgrammaticFunctionName,\n m_functionMap[" + "aProgrammaticFunctionName][nArgument],\n" + " sDISPLAYNAME);\n}\n\n"; + + o << "OUString SAL_CALL " << classname << "getArgumentDescription(const " + "OUString & aProgrammaticFunctionName, ::sal_Int32 nArgument) throw " + "(css::uno::RuntimeException)\n{\n return getAddinProperty(" + "aProgrammaticFunctionName,\n " + "m_functionMap[aProgrammaticFunctionName][nArgument],\n" + " sDESCRIPTION);\n}\n\n"; + + o << "OUString SAL_CALL " << classname << "getProgrammaticCategoryName(" + "const OUString & aProgrammaticFunctionName) throw (" + "css::uno::RuntimeException)\n{\n return getAddinProperty(" + "aProgrammaticFunctionName, OUString(), sCATEGORY);\n}\n\n"; + + o << "OUString SAL_CALL " << classname << "getDisplayCategoryName(const " + "OUString & aProgrammaticFunctionName) throw (" + "css::uno::RuntimeException)\n{\n return getAddinProperty(" + "aProgrammaticFunctionName, OUString(), " + "sCATEGORYDISPLAYNAME);\n}\n\n"; +} + +void generateXCompatibilityNamesBodies(std::ostream& o, const OString & classname) +{ + o << "// css::sheet::XCompatibilityNames:\n" + "css::uno::Sequence< css::sheet::LocalizedName > SAL_CALL " << classname + << "getCompatibilityNames(const OUString & aProgrammaticName) throw " + "(css::uno::RuntimeException)\n{\n css::uno::Sequence< " + "css::sheet::LocalizedName > seqLocalizedNames;\n try {\n " + "OUStringBuffer buf(" + "aProgrammaticName);\n buf.appendAscii(\"/CompatibilityName\");\n" + " OUString hname(buf.makeStringAndClear());\n\n " + "if ( m_xCompAccess->hasByHierarchicalName(hname) ) {\n" + " css::uno::Reference< css::container::XNameAccess > " + "xNameAccess(\n" + " m_xCompAccess->getByHierarchicalName(hname), " + "css::uno::UNO_QUERY);\n\n css::uno::Sequence< OUString" + " > elems = \n xNameAccess->getElementNames();" + "\n ::sal_Int32 len = elems.getLength();\n\n " + "seqLocalizedNames.realloc(len);\n\n OUString " + "sCompatibilityName;\n for (::sal_Int32 i=0; i < len; ++i) {\n" + " OUString sLocale(elems[i]);\n " + "xNameAccess->getByName(sLocale) >>= sCompatibilityName;\n\n" + " css::lang::Locale aLocale;\n " + "::sal_Int32 nIndex = 0, nToken = 0;\n " + /* FIXME-BCP47: this will break. */ + "do {\n OUString aToken = sLocale.getToken(0, '-', " + "nIndex);\n switch (nToken++) {\n " + "case 0:\n aLocale.Language = aToken;\n" + " break;\n case 1:\n" + " aLocale.Country = aToken;\n " + " break;\n default:\n " + "aLocale.Variant = sLocale.copy(nIndex-aToken.getLength()-1);\n" + " nIndex = -1;\n }\n" + " } while ( nIndex >= 0 );\n\n " + "seqLocalizedNames[i].Locale = aLocale;\n " + "seqLocalizedNames[i].Name = sCompatibilityName;\n }" + "\n }\n }\n catch ( const css::uno::RuntimeException & e ) {\n " + "throw e;\n }\n catch ( css::uno::Exception & ) {\n }\n\n" + " return seqLocalizedNames;\n}\n\n"; +} + +void generateXInitialization(std::ostream& o, const OString & classname) +{ + o << "// css::lang::XInitialization:\n" + "void SAL_CALL " << classname << "initialize( const css::uno::Sequence< " + "css::uno::Any >& aArguments ) " + "throw (css::uno::Exception, css::uno::RuntimeException)\n{\n" + " css::uno::Reference < css::frame::XFrame > xFrame;\n" + " if ( aArguments.getLength() ) {\n aArguments[0] >>= xFrame;\n" + " m_xFrame = xFrame;\n }\n}\n\n"; +} + +void generateXDispatch(std::ostream& o, + const OString & classname, + const ProtocolCmdMap & protocolCmdMap) +{ + // com.sun.star.frame.XDispatch + // dispatch + o << "// css::frame::XDispatch:\n" + "void SAL_CALL " << classname << "dispatch( const css::util::URL& aURL, const " + "css::uno::Sequence< css::beans::PropertyValue >& aArguments ) throw" + "(css::uno::RuntimeException)\n{\n"; + + for (const auto& rEntry : protocolCmdMap) { + o << " if ( aURL.Protocol.equalsAscii(\"" << rEntry.first + << "\") == 0 )\n {\n"; + + for (const auto& rCmd : rEntry.second) { + o << " if ( aURL.Path.equalsAscii(\"" << rCmd << "\") )\n" + " {\n // add your own code here\n" + " return;\n }\n"; + } + + o << " }\n"; + } + o << "}\n\n"; + + // addStatusListener + o << "void SAL_CALL " << classname << "addStatusListener( const css::uno::Reference< " + "css::frame::XStatusListener >& xControl, const css::util::URL& aURL ) " + "throw (css::uno::RuntimeException)\n{\n" + " // add your own code here\n}\n\n"; + + // removeStatusListener + o << "void SAL_CALL " << classname << "removeStatusListener( const css::uno::Reference" + "< css::frame::XStatusListener >& xControl, const css::util::URL& aURL ) " + "throw (css::uno::RuntimeException)\n{\n" + " // add your own code here\n}\n\n"; +} + +void generateXDispatchProvider(std::ostream& o, + const OString & classname, + const ProtocolCmdMap & protocolCmdMap) +{ + + // com.sun.star.frame.XDispatchProvider + // queryDispatch + o << "// css::frame::XDispatchProvider:\n" + "css::uno::Reference< css::frame::XDispatch > SAL_CALL " << classname + << "queryDispatch( const css::util::URL& aURL," + " const OUString& sTargetFrameName, sal_Int32 nSearchFlags ) " + "throw(css::uno::RuntimeException)\n{\n css::uno::Reference< " + "css::frame::XDispatch > xRet;\n" + " if ( !m_xFrame.is() )\n return 0;\n\n"; + + for (const auto& rEntry : protocolCmdMap) { + o << " if ( aURL.Protocol.equalsAscii(\"" << rEntry.first + << "\") == 0 )\n {\n"; + + for (const auto& rCmd : rEntry.second) { + o << " if ( aURL.Path.equalsAscii(\"" << rCmd << "\") == 0 )\n" + " xRet = this;\n"; + } + + o << " }\n"; + } + o << " return xRet;\n}\n\n"; + + // queryDispatches + o << "css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL " + << classname << "queryDispatches( const css::uno::Sequence< " + "css::frame::DispatchDescriptor >& seqDescripts ) throw(" + "css::uno::RuntimeException)\n{\n" + " sal_Int32 nCount = seqDescripts.getLength();\n" + " css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > " + "lDispatcher(nCount);\n\n" + " for( sal_Int32 i=0; i<nCount; ++i ) {\n" + " lDispatcher[i] = queryDispatch( seqDescripts[i].FeatureURL,\n" + " seqDescripts[i].FrameName,\n" + " seqDescripts[i].SearchFlags );\n" + " }\n\n return lDispatcher;\n}\n\n"; +} + +static void generateAddinConstructorAndHelper(std::ostream& o, + ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, const OString & classname, + const std::set< OUString >& interfaces) +{ + o << classname << "::" << classname + << "(css::uno::Reference< css::uno::XComponentContext > const & context) :\n" + " m_xContext(context), m_locale()\n{\n"; + + if (options.backwardcompatible) { + o << " try {\n"; + + generateFunctionParameterMap(o, options, manager, interfaces); + + o << " css::uno::Reference< css::lang::XMultiServiceFactory > xProvider" + "(\n m_xContext->getServiceManager()->createInstanceWithContext" + "(\n OUString(\n " + " \"com.sun.star.configuration.ConfigurationProvider\")," + "\n m_xContext ), css::uno::UNO_QUERY );\n\n"; + + o << " OUString sReadOnlyView(\n" + " \"com.sun.star.configuration.ConfigurationAccess\");\n\n"; + + o << " OUStringBuffer sPath(OUString(\n" + " \"/org.openoffice.Office.CalcAddIns/AddInInfo/\"));\n" + " sPath.appendAscii(sADDIN_SERVICENAME);\n" + " sPath.appendAscii(\"/AddInFunctions\");\n\n" + " // create arguments: nodepath\n" + " css::beans::PropertyValue aArgument;\n" + " aArgument.Name = OUString(\"nodepath\");\n" + " aArgument.Value <<= sPath.makeStringAndClear();\n\n" + " css::uno::Sequence< css::uno::Any > aArguments(1);\n" + " aArguments[0] <<= aArgument;\n\n"; + + o << " // create the default view using default UI locale\n" + " css::uno::Reference< css::uno::XInterface > xIface =\n" + " xProvider->createInstanceWithArguments(sReadOnlyView, " + "aArguments);\n\n" + " m_xHAccess.set(xIface, css::uno::UNO_QUERY);" + "\n\n"; + + o << " // extend arguments to create a view for all locales to get " + "simple\n // access to the compatibilityname property\n" + " aArgument.Name = OUString(\"locale\");\n" + " aArgument.Value <<= OUString(\"*\");\n" + " aArguments.realloc(2);\n" + " aArguments[1] <<= aArgument;\n\n" + " // create view for all locales\n" + " xIface = xProvider->createInstanceWithArguments(sReadOnlyView, " + "aArguments);\n\n" + " m_xCompAccess.set(xIface, css::uno::UNO_QUERY);\n"; + + o << " }\n catch ( css::uno::Exception & ) {\n }\n}\n\n"; + + o << "// addin configuration property helper function:\nOUString " + "SAL_CALL " << classname << "::getAddinProperty(const OUString &" + " funcName, const OUString & paramName, const char * propName) " + "throw (css::uno::RuntimeException)\n{\n" + " OUString ret;\n try {\n " + "OUStringBuffer buf(funcName);\n" + " if (!paramName.isEmpty()) {\n" + " buf.appendAscii(\"/Parameters/\");\n" + " buf.append(paramName);\n }\n\n" + " css::uno::Reference< css::beans::XPropertySet > xPropSet(\n" + " m_xHAccess->getByHierarchicalName(\n" + " buf.makeStringAndClear()), css::uno::UNO_QUERY);\n" + " xPropSet->getPropertyValue(\n " + "OUString(propName)) >>= ret;\n }\n" + " catch ( const css::uno::RuntimeException & e ) {\n throw e;\n }\n" + " catch ( css::uno::Exception & ) {\n }\n return ret;\n"; + } + o <<"}\n\n"; +} + +static void generateMemberInitialization(std::ostream& o, + ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + AttributeInfo const & members) +{ + for (const auto& rMember : members) + { + sal_Int32 rank; + if ((manager->decompose(rMember.type, true, nullptr, &rank, nullptr, nullptr) + <= codemaker::UnoType::Sort::Char) + && rank == 0) + { + o << ",\n m_" << rMember.name << "("; + printType(o, options, manager, rMember.type, 16, true); + o << ")"; + } + } +} + +static void generateMemberDeclaration(std::ostream& o, + ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + AttributeInfo const & members) +{ + for (const auto& rMember : members) + { + o << " "; + printType(o, options, manager, rMember.type, 1); + o << " m_" << rMember.name << ";\n"; + } +} + +static OString generateClassDefinition(std::ostream& o, + ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + OString const & classname, + std::set< OUString > const & interfaces, + AttributeInfo const & properties, + AttributeInfo const & attributes, + std::set< OUString > const & propinterfaces, + OUString const & propertyhelper, bool supportxcomponent) +{ + OStringBuffer parentname(64); + o << "class " << classname << ":\n"; + + if (!interfaces.empty()) { + if (supportxcomponent) { + parentname.append("::cppu::WeakComponentImplHelper" + + OString::number(static_cast<sal_Int32>(interfaces.size()))); + o << " private ::cppu::BaseMutex,\n" + " public ::cppu::WeakComponentImplHelper" + << interfaces.size() << "<"; + } else { + parentname.append("::cppu::WeakImplHelper" + + OString::number(static_cast<sal_Int32>(interfaces.size()))); + o << " public ::cppu::WeakImplHelper" << interfaces.size() << "<"; + } + + std::set< OUString >::const_iterator iter = interfaces.begin(); + while (iter != interfaces.end()) + { + o << "\n " << scopedCppName(u2b(*iter)); + ++iter; + if (iter != interfaces.end()) + o << ","; + else + o << ">"; + } + } + + if (propertyhelper.getLength() > 1) { + o << ",\n public ::cppu::PropertySetMixin< " + << scopedCppName(u2b(propertyhelper)) << " >"; + } + + o << "\n{\npublic:\n" + " explicit " << classname << "(" + "css::uno::Reference< css::uno::XComponentContext > const & context);\n\n"; + + // generate component/service helper functions +// o << " // component and service helper functions:\n" +// << " static OUString SAL_CALL _getImplementationName();\n" +// << " static css::uno::Sequence< OUString > SAL_CALL " +// << "_getSupportedServiceNames();\n" +// << " static css::uno::Reference< css::uno::XInterface > SAL_CALL _create(" +// << "\n css::uno::Reference< css::uno::XComponentContext > const & " +// << "context);\n\n"; + + // override queryInterface + if (propertyhelper.getLength() > 1) { + o << " // css::uno::XInterface:\n" + " virtual css::uno::Any SAL_CALL queryInterface(" + "css::uno::Type const & type) throw (" + "css::uno::RuntimeException);\n"; + + OStringBuffer buffer(256); + buffer.append(parentname + "< "); + std::set< OUString >::const_iterator iter = interfaces.begin(); + while (iter != interfaces.end()) + { + buffer.append(scopedCppName(u2b(*iter))); + ++iter; + if (iter != interfaces.end()) + buffer.append(", "); + else + buffer.append(" >"); + } + OString parent(buffer.makeStringAndClear()); + o << " virtual void SAL_CALL acquire() throw ()\n { " + << parent << "::acquire(); }\n"; + o << " virtual void SAL_CALL release() throw ()\n { " + << parent << "::release(); }\n\n"; + } + + codemaker::GeneratedTypeSet generated; + for (const auto& rIface : interfaces) + { + printMethods(o, options, manager, rIface, generated, ""_ostr, ""_ostr, " "_ostr, + true, propertyhelper); + } + + o << "private:\n " << classname << "(const " << classname << " &); // not defined\n" + " " << classname << "& operator=(const " << classname << " &); // not defined\n\n" + " // destructor is private and will be called indirectly by the release call" + " virtual ~" << classname << "() {}\n\n"; + + if (options.componenttype == 2) { + o << " typedef boost::unordered_map< ::sal_Int32, OUString, " + "boost::hash<::sal_Int32> > ParamMap;\n" + " typedef boost::unordered_map< OUString, ParamMap, " + "OUStringHash > FunctionMap;\n\n" + " OUString SAL_CALL getAddinProperty(const OUString & " + "funcName, const OUString & paramName, const char * propName) " + "throw (css::uno::RuntimeException);\n\n"; + } + + if (supportxcomponent) { + o << " // override WeakComponentImplHelperBase::disposing()\n" + " // This function is called upon disposing the component,\n" + " // if your component needs special work when it becomes\n" + " // disposed, do it here.\n" + " virtual void SAL_CALL disposing();\n\n"; + } + + // members + o << " css::uno::Reference< css::uno::XComponentContext > m_xContext;\n"; + if (!supportxcomponent && !attributes.empty()) + o << " mutable ::osl::Mutex m_aMutex;\n"; + + // additional member for add-ons + if (options.componenttype == 3) { + o << " css::uno::Reference< css::frame::XFrame > m_xFrame;\n"; + } + + if (options.componenttype == 2) { + if (options.backwardcompatible) { + o <<" css::uno::Reference< css::container::XHierarchicalNameAccess > " + "m_xHAccess;\n" + " css::uno::Reference< css::container::XHierarchicalNameAccess > " + "m_xCompAccess;\n" + " FunctionMap m_functionMap;\n"; + } + o << " css::lang::Locale m_locale;\n"; + } + + generateMemberDeclaration(o, options, manager, properties); + generateMemberDeclaration(o, options, manager, attributes); + +// if (!properties.empty()) +// { +// AttributeInfo::const_iterator iter = properties.begin(); +// while (iter != properties.end()) +// { +// o << " "; +// printType(o, options, manager, iter->second.first.replace('.','/'), +// 1, false); +// o << " m_" << iter->first << ";\n"; +// ++iter; +// } +// } +// if (!attributes.empty()) +// { +// AttributeInfo::const_iterator iter = attributes.begin(); +// while (iter != attributes.end()) +// { +// o << " "; +// printType(o, options, manager, iter->second.first.replace('.','/'), +// 1, false); +// o << " m_" << iter->first << ";\n"; +// ++iter; +// } +// } + + o << "};\n\n"; + + // generate constructor + if (options.componenttype == 2) { + generateAddinConstructorAndHelper(o, options, manager, + classname, interfaces); + } else { + o << classname << "::" << classname + << "(css::uno::Reference< css::uno::XComponentContext > const & context) :\n"; + if (supportxcomponent) { + o << " ::cppu::WeakComponentImplHelper" << interfaces.size() << "<"; + std::set< OUString >::const_iterator iter = interfaces.begin(); + while (iter != interfaces.end()) { + o << "\n " << scopedCppName(u2b(*iter)); + ++iter; + if (iter != interfaces.end()) + o << ","; + else + o << ">(m_aMutex),\n"; + } + } + if (propertyhelper.getLength() > 1) { + o << " ::cppu::PropertySetMixin< " + << scopedCppName(u2b(propertyhelper)) << " >(\n" + " context, static_cast< Implements >(\n "; + OStringBuffer buffer(128); + if (propinterfaces.find("com/sun/star/beans/XPropertySet") + != propinterfaces.end()) { + buffer.append("IMPLEMENTS_PROPERTY_SET"); + } + if (propinterfaces.find("com/sun/star/beans/XFastPropertySet") + != propinterfaces.end()) { + if (!buffer.isEmpty()) + buffer.append(" | IMPLEMENTS_FAST_PROPERTY_SET"); + else + buffer.append("IMPLEMENTS_FAST_PROPERTY_SET"); + } + if (propinterfaces.find("com/sun/star/beans/XPropertyAccess") + != propinterfaces.end()) { + if (!buffer.isEmpty()) + buffer.append(" | IMPLEMENTS_PROPERTY_ACCESS"); + else + buffer.append("IMPLEMENTS_PROPERTY_ACCESS"); + } + o << buffer.makeStringAndClear() + << "), css::uno::Sequence< OUString >()),\n"; + } + o << " m_xContext(context)"; + + generateMemberInitialization(o, options, manager, properties); + generateMemberInitialization(o, options, manager, attributes); + + o << "\n{}\n\n"; + } + + // generate service/component helper function implementations +// generateServiceHelper(o, options.implname, classname, services); + + if (supportxcomponent) { + o << "// override WeakComponentImplHelperBase::disposing()\n" + "// This function is called upon disposing the component,\n" + "// if your component needs special work when it becomes\n" + "// disposed, do it here.\n" + "void SAL_CALL " << classname << "::disposing()\n{\n\n}\n\n"; + } + + return parentname.makeStringAndClear(); +} + +static void generateXServiceInfoBodies(std::ostream& o, + OString const & classname, + OString const & comphelpernamespace) +{ + o << "// com.sun.star.uno.XServiceInfo:\n" + "OUString SAL_CALL " << classname << "getImplementationName() " + "throw (css::uno::RuntimeException)\n{\n " + "return " << comphelpernamespace << "::_getImplementationName();\n}\n\n"; + + o << "sal_Bool SAL_CALL " << classname + << "supportsService(OUString const & " + "serviceName) throw (css::uno::RuntimeException)\n{\n " + "css::uno::Sequence< OUString > serviceNames = " + << comphelpernamespace << "::_getSupportedServiceNames();\n " + "for (::sal_Int32 i = 0; i < serviceNames.getLength(); ++i) {\n " + " if (serviceNames[i] == serviceName)\n return sal_True;\n" + " }\n return sal_False;\n}\n\n"; + + o << "css::uno::Sequence< OUString > SAL_CALL " << classname + << "getSupportedServiceNames() throw (css::uno::RuntimeException)\n{\n " + "return " << comphelpernamespace + << "::_getSupportedServiceNames();\n}\n\n"; +} + + +static void generateMethodBodies(std::ostream& o, + ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + std::set< OUString > const & interfaces, + std::string_view classname, + OString const & comphelpernamespace, + OUString const & propertyhelper) +{ + OString name = OString::Concat(classname) + "::"; + codemaker::GeneratedTypeSet generated; + for (const auto& rIface : interfaces) { + if ( rIface == "com.sun.star.lang.XServiceInfo" ) { + generateXServiceInfoBodies(o, name, comphelpernamespace); + generated.add(u2b(rIface)); + } else { + printMethods(o, options, manager, rIface, generated, "_"_ostr, + name, ""_ostr, true, propertyhelper); + } + } +} + +static void generateQueryInterface(std::ostream& o, + ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + const std::set< OUString >& interfaces, + OString const & parentname, + OString const & classname, + std::u16string_view propertyhelper) +{ + if (propertyhelper.empty()) + return; + + o << "css::uno::Any " << classname + << "::queryInterface(css::uno::Type const & type) throw (" + "css::uno::RuntimeException)\n{\n "; + + if (!propertyhelper.empty()) + o << "return "; + else + o << "css::uno::Any a("; + + o << parentname << "<"; + std::set< OUString >::const_iterator iter = interfaces.begin(); + while (iter != interfaces.end()) + { + o << "\n " << scopedCppName(u2b(*iter)); + ++iter; + if (iter != interfaces.end()) + o << ","; + else + o << ">"; + } + + if (!propertyhelper.empty()) { + o << "::queryInterface(type);\n"; + } else { + o << "::queryInterface(type));\n"; + o << " return a.hasValue() ? a\n : ("; + if (propertyhelper == u"_") { + o << "::cppu::OPropertySetHelper::queryInterface(type));\n"; + } else { + o << "::cppu::PropertySetMixin<\n "; + printType(o, options, manager, propertyhelper, 0); + o << " >::queryInterface(\n type));\n"; + } + } + o << "}\n\n"; +} + +void generateSkeleton(ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + std::vector< OString > const & types) +{ + // special handling of calc add-ins + if (options.componenttype == 2) { + generateCalcAddin(options, manager, types); + return; + } + + std::set< OUString > interfaces; + std::set< OUString > services; + AttributeInfo properties; + AttributeInfo attributes; + std::set< OUString > propinterfaces; + bool serviceobject = false; + bool supportxcomponent = false; + + for (const auto& rType : types) { + checkType(manager, b2u(rType), interfaces, services, properties); + } + + if (options.componenttype == 3) { + // the Protocolhandler service is mandatory for a protocol handler add-on, + // so it is defaulted. The XDispatchProvider provides Dispatch objects for + // certain functions and the generated impl object implements XDispatch + // directly for simplicity reasons. + checkType(manager, "com.sun.star.frame.ProtocolHandler", + interfaces, services, properties); + checkType(manager, "com.sun.star.frame.XDispatch", + interfaces, services, properties); + } + + // check if service object or simple UNO object + if (!services.empty()) + serviceobject = true; + + OUString propertyhelper = checkPropertyHelper( + options, manager, services, interfaces, attributes, propinterfaces); + + checkDefaultInterfaces(interfaces, services, propertyhelper); + + if (interfaces.size() > 12) + throw CannotDumpException( + "the skeletonmaker supports components with 12 interfaces " + "only (limitation of the UNO implementation helpers)!"); + + + supportxcomponent = checkXComponentSupport(manager, interfaces); + + OString compFileName; + OString tmpFileName; + std::ostream* pofs = nullptr; + bool standardout = getOutputStream(options, ".cxx"_ostr, + &pofs, compFileName, tmpFileName); + + try { + if (!standardout && options.license) { + printLicenseHeader(*pofs); + } + + generateIncludes(*pofs, interfaces, propertyhelper, serviceobject, + supportxcomponent); + + if (options.componenttype == 3) { + *pofs << "#include \"com/sun/star/frame/XFrame.hpp\"\n"; + } + + // namespace + OString nmspace; + short nm = 0; + + if (serviceobject) { + nmspace = generateCompHelperDeclaration(*pofs, options.implname); + + *pofs << + "\n\n/// anonymous implementation namespace\nnamespace {\n\n" + "namespace css = ::com::sun::star;\n\n"; + } else { + nm = generateNamespace(*pofs, options.implname, false, nmspace); + *pofs << "namespace css = ::com::sun::star;\n\n"; + } + + sal_Int32 index = 0; + OString classname(options.implname); + if ((index = classname.lastIndexOf('.')) > 0) + classname = classname.copy(index+1); + + OString parentname( + generateClassDefinition(*pofs, + options, manager, classname, interfaces, properties, + attributes, propinterfaces, propertyhelper, supportxcomponent)); + + generateQueryInterface(*pofs, options, manager, interfaces, parentname, + classname, propertyhelper); + + generateMethodBodies(*pofs, options, manager, interfaces, classname, + nmspace, propertyhelper); + + if (serviceobject) { + // close namespace + *pofs << "} // closing anonymous implementation namespace\n\n"; + + generateCompHelperDefinition(*pofs, options.implname, + classname, services); + generateCompFunctions(*pofs, nmspace); + } else { + // close namespace + for (short i=0; i < nm; i++) + *pofs << "} "; + *pofs << (nm > 0 ? "// closing namespace\n\n" : "\n"); + } + + if (!standardout) + { + if (static_cast<std::ofstream*>(pofs)->is_open()) + static_cast<std::ofstream*>(pofs)->close(); + delete pofs; + OSL_VERIFY(makeValidTypeFile(compFileName, tmpFileName, false)); + } + } catch (CannotDumpException & e) { + std::cerr << "ERROR: " << e.getMessage() << "\n"; + if ( !standardout ) { + if (static_cast<std::ofstream*>(pofs)->is_open()) + static_cast<std::ofstream*>(pofs)->close(); + delete pofs; + // remove existing type file if something goes wrong to ensure + // consistency + if (fileExists(compFileName)) + removeTypeFile(compFileName); + + // remove tmp file if something goes wrong + removeTypeFile(tmpFileName); + } + } +} + +void generateCalcAddin(ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + std::vector< OString > const & types) +{ + std::set< OUString > interfaces; + std::set< OUString > services; + AttributeInfo properties; + AttributeInfo attributes; + std::set< OUString > propinterfaces; + bool serviceobject = false; + bool supportxcomponent = false; + + + for (const auto& rType : types) { + checkType(manager, b2u(rType), interfaces, services, properties); + } + + OUString sAddinService; + if (services.size() != 1) { + throw CannotDumpException( + "for calc add-in components one and only one service type is necessary!" + " Please reference a valid type with the '-t' option."); + } + + + // get the one and only add-in service for later use + std::set< OUString >::const_iterator iter2 = services.begin(); + sAddinService = *iter2; + if (sAddinService == "com.sun.star.sheet.AddIn") { + sAddinService = *(++iter2); + } + + // if backwardcompatible==true the AddIn service needs to be added to the + // supported service list, the necessary interfaces are mapped to the add-in + // configuration. Since OO.org 2.0.4 this is obsolete and the add-in is + // taken from the configuration from Calc directly, this simplifies the + // add-in code + if (options.backwardcompatible) { + checkType(manager, "com.sun.star.sheet.AddIn", + interfaces, services, properties); + } else { + // special case for the optional XLocalization interface. It should be + // implemented always. But it is parent of the XAddIn and we need it only + // if backwardcompatible is false. + interfaces.insert("com.sun.star.lang.XLocalizable"); + } + + OUString propertyhelper = checkPropertyHelper( + options, manager, services, interfaces, attributes, propinterfaces); + + if (!propertyhelper.isEmpty()) + std::cerr << "WARNING: interfaces specifying calc add-in functions " + "shouldn't support attributes!\n"; + + checkDefaultInterfaces(interfaces, services, propertyhelper); + + if (interfaces.size() > 12) { + throw CannotDumpException( + "the skeletonmaker supports components with 12 interfaces " + "only (limitation of the UNO implementation helpers)!"); + } + + // check if service object or simple UNO object + if (!services.empty()) + serviceobject = true; + + supportxcomponent = checkXComponentSupport(manager, interfaces); + if (supportxcomponent) + std::cerr << "WARNING: add-ins shouldn't support " + "com.sun.star.uno.XComponent!\n"; + + OString compFileName; + OString tmpFileName; + std::ostream* pofs = nullptr; + bool standardout = getOutputStream(options, ".cxx"_ostr, + &pofs, compFileName, tmpFileName); + + try { + if (!standardout && options.license) { + printLicenseHeader(*pofs); + } + + generateIncludes(*pofs, interfaces, propertyhelper, serviceobject, + supportxcomponent); + + *pofs << + "#include \"com/sun/star/beans/PropertyValue.hpp\"\n" + "#include \"com/sun/star/beans/XPropertySet.hpp\"\n" + "#include \"com/sun/star/container/XNameAccess.hpp\"\n" + "#include \"com/sun/star/container/XHierarchicalNameAccess.hpp\"\n\n" + "#include \"rtl/ustrbuf.hxx\"\n\n" + "#include <boost/unordered_map.hpp>\n" + "#include <set>\n"; + + // namespace + OString nmspace(generateCompHelperDeclaration(*pofs, options.implname)); + + *pofs << + "\n\n// anonymous implementation namespace\nnamespace {\n\n" + "namespace css = ::com::sun::star;\n\n"; + + sal_Int32 index = 0; + OString classname(options.implname); + if ((index = classname.lastIndexOf('.')) > 0) { + classname = classname.copy(index+1); + } + + if (options.backwardcompatible) { + *pofs << "static const char * sADDIN_SERVICENAME = \"" + << sAddinService << "\";\n\n"; + *pofs << "static const char * sDISPLAYNAME = \"DisplayName\";\n" + "static const char * sDESCRIPTION = \"Description\";\n" + "static const char * sCATEGORY = \"Category\";\n" + "static const char * sCATEGORYDISPLAYNAME = \"CategoryDisplayName\";" + "\n\n"; + } + + OString parentname( + generateClassDefinition(*pofs, + options, manager, classname, interfaces, properties, + attributes, propinterfaces, propertyhelper, supportxcomponent)); + + generateQueryInterface(*pofs, options, manager, interfaces, parentname, + classname, propertyhelper); + + generateMethodBodies(*pofs, options, manager, interfaces, classname, + nmspace, propertyhelper); + + // close namespace + *pofs << "} // closing anonymous implementation namespace\n\n"; + + generateCompHelperDefinition(*pofs, options.implname, classname, + services); + + generateCompFunctions(*pofs, nmspace); + + if (!standardout) + { + if (static_cast<std::ofstream*>(pofs)->is_open()) + static_cast<std::ofstream*>(pofs)->close(); + delete pofs; + OSL_VERIFY(makeValidTypeFile(compFileName, tmpFileName, false)); + } + } catch (CannotDumpException & e) { + std::cerr << "ERROR: " << e.getMessage() << "\n"; + if ( !standardout ) { + if (static_cast<std::ofstream*>(pofs)->is_open()) + static_cast<std::ofstream*>(pofs)->close(); + delete pofs; + // remove existing type file if something goes wrong to ensure + // consistency + if (fileExists(compFileName)) + removeTypeFile(compFileName); + + // remove tmp file if something goes wrong + removeTypeFile(tmpFileName); + } + } +} + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unodevtools/source/skeletonmaker/cpptypemaker.cxx b/unodevtools/source/skeletonmaker/cpptypemaker.cxx new file mode 100644 index 0000000000..5e5e165b2f --- /dev/null +++ b/unodevtools/source/skeletonmaker/cpptypemaker.cxx @@ -0,0 +1,976 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <codemaker/codemaker.hxx> +#include <codemaker/commoncpp.hxx> +#include <codemaker/global.hxx> + +#include "skeletoncommon.hxx" +#include "skeletoncpp.hxx" + +#include <algorithm> +#include <string_view> + +using namespace ::codemaker::cpp; + +namespace skeletonmaker::cpp { + +static void printType( + std::ostream & o, ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + codemaker::UnoType::Sort sort, std::u16string_view nucleus, sal_Int32 rank, + std::vector< OUString > const & arguments, + rtl::Reference< unoidl::Entity > const & entity, short referenceType, + bool defaultvalue) +{ + if (defaultvalue && rank == 0 && sort <= codemaker::UnoType::Sort::Char) { + switch (sort) { + case codemaker::UnoType::Sort::Boolean: + o << "sal_False"; + return; + case codemaker::UnoType::Sort::Char: + case codemaker::UnoType::Sort::Byte: + case codemaker::UnoType::Sort::Short: + case codemaker::UnoType::Sort::UnsignedShort: + case codemaker::UnoType::Sort::Long: + case codemaker::UnoType::Sort::UnsignedLong: + case codemaker::UnoType::Sort::Hyper: + case codemaker::UnoType::Sort::UnsignedHyper: + case codemaker::UnoType::Sort::Float: + case codemaker::UnoType::Sort::Double: + o << "0"; + return; + default: + break; + } + } + + if (defaultvalue && referenceType == 16) { + if (sort == codemaker::UnoType::Sort::Enum) { + auto pEnumTypeEntity(dynamic_cast<unoidl::EnumTypeEntity *>(entity.get())); + assert(pEnumTypeEntity); + o << OUString(nucleus.substr(nucleus.rfind('.') + 1)) << "_" + << pEnumTypeEntity->getMembers()[0].name; + } + return; + } + bool bReference = false; + if (((sort > codemaker::UnoType::Sort::Char || + rank > 0) && referenceType != 8 && + !(sort == codemaker::UnoType::Sort::Enum && referenceType == 4 && rank == 0)) || + (sort <= codemaker::UnoType::Sort::Char && referenceType == 2)) + { + bReference = true; + } + + if (bReference && referenceType == 4) + o << "const "; + + for (sal_Int32 i = 0; i < rank; ++i) { + o << ((options.shortnames) ? "css::uno::Sequence< " : + "::com::sun::star::uno::Sequence< "); + } + if (sort == codemaker::UnoType::Sort::Interface && referenceType > 0) { + o << ((options.shortnames) ? "css::uno::Reference< " : + "::com::sun::star::uno::Reference< "); + } + + o << scopedCppName(codemaker::cpp::translateUnoToCppType(sort, nucleus), + options.shortnames && referenceType > 0); + + if (sort == codemaker::UnoType::Sort::Interface && referenceType > 0) + o << " >"; + + if (!arguments.empty()) { + o << "< "; + for (std::vector< OUString >::const_iterator i(arguments.begin()); + i != arguments.end(); ++i) + { + if (i != arguments.begin()) + o << ", "; + + printType(o, options, manager, *i, 1); + } + o << " >"; + } + + for (sal_Int32 i = 0; i < rank; ++i) + o << " >"; + + if (bReference && referenceType > 1) + o << " &"; + + if (referenceType == 8 && (sort > codemaker::UnoType::Sort::Char || rank > 0)) + o << "()"; +} + +void printType( + std::ostream & o, ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, std::u16string_view name, + short referenceType, bool defaultvalue) +{ + OUString nucleus; + sal_Int32 rank; + std::vector< OUString > arguments; + rtl::Reference< unoidl::Entity > entity; + codemaker::UnoType::Sort sort = manager->decompose( + name, true, &nucleus, &rank, &arguments, &entity); + printType( + o, options, manager, sort, nucleus, rank, arguments, entity, + referenceType, defaultvalue); +} + +static bool printConstructorParameters( + std::ostream & o, ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + codemaker::UnoType::Sort sort, + rtl::Reference< unoidl::Entity > const & entity, std::u16string_view name, + std::vector< OUString > const & arguments) +{ + bool previous = false; + switch (sort) { + case codemaker::UnoType::Sort::PlainStruct: + { + rtl::Reference< unoidl::PlainStructTypeEntity > ent2( + dynamic_cast< unoidl::PlainStructTypeEntity * >(entity.get())); + assert(ent2.is()); + if (!ent2->getDirectBase().isEmpty()) { + rtl::Reference< unoidl::Entity > baseEnt; + codemaker::UnoType::Sort baseSort = manager->getSort( + ent2->getDirectBase(), &baseEnt); + previous = printConstructorParameters( + o, options, manager, baseSort, baseEnt, + ent2->getDirectBase(), std::vector< OUString >()); + } + for (const auto& rMember : ent2->getDirectMembers()) + { + if (previous) { + o << ", "; + } + previous = true; + printType(o, options, manager, rMember.type, 4); + o << ' ' + << codemaker::cpp::translateUnoToCppIdentifier( + u2b(rMember.name), "param"); + } + break; + } + case codemaker::UnoType::Sort::PolymorphicStructTemplate: + { + rtl::Reference< unoidl::PolymorphicStructTypeTemplateEntity > ent2( + dynamic_cast< unoidl::PolymorphicStructTypeTemplateEntity * >( + entity.get())); + assert(ent2.is()); + for (const auto& rMember : ent2->getMembers()) + { + if (previous) { + o << ", "; + } + previous = true; + if (rMember.parameterized) { + o << rMember.type; + } else { + printType(o, options, manager, rMember.type, 4); + } + o << ' ' + << codemaker::cpp::translateUnoToCppIdentifier( + u2b(rMember.name), "param"); + } + break; + } + case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct: + { + rtl::Reference< unoidl::PolymorphicStructTypeTemplateEntity > ent2( + dynamic_cast< unoidl::PolymorphicStructTypeTemplateEntity * >( + entity.get())); + assert(ent2.is()); + for (const auto& rMember : ent2->getMembers()) + { + if (previous) { + o << ", "; + } + previous = true; + if (rMember.parameterized) { + auto j = std::find(ent2->getTypeParameters().begin(), + ent2->getTypeParameters().end(), rMember.type); + if (j != ent2->getTypeParameters().end()) { + o << arguments[j - ent2->getTypeParameters().begin()]; + } + } else { + printType(o, options, manager, rMember.type, 4); + } + o << ' ' + << codemaker::cpp::translateUnoToCppIdentifier( + u2b(rMember.name), "param"); + } + break; + } + case codemaker::UnoType::Sort::Exception: + { + rtl::Reference< unoidl::ExceptionTypeEntity > ent2( + dynamic_cast< unoidl::ExceptionTypeEntity * >(entity.get())); + assert(ent2.is()); + if (!ent2->getDirectBase().isEmpty()) { + rtl::Reference< unoidl::Entity > baseEnt; + codemaker::UnoType::Sort baseSort = manager->getSort( + ent2->getDirectBase(), &baseEnt); + previous = printConstructorParameters( + o, options, manager, baseSort, baseEnt, + ent2->getDirectBase(), std::vector< OUString >()); + } + for (const auto& rMember : ent2->getDirectMembers()) + { + if (previous) { + o << ", "; + } + previous = true; + printType(o, options, manager, rMember.type, 4); + o << ' ' + << codemaker::cpp::translateUnoToCppIdentifier( + u2b(rMember.name), "param"); + } + break; + } + default: + throw CannotDumpException( + OUString::Concat("unexpected entity \"") + name + + "\" in call to skeletonmaker::cpp::printConstructorParameters"); + } + return previous; +} + +static void printConstructor( + std::ostream & o, ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + codemaker::UnoType::Sort sort, + rtl::Reference< unoidl::Entity > const & entity, std::u16string_view name, + std::vector< OUString > const & arguments) +{ + o << "public " << OUString(name.substr(name.rfind('.') + 1)) << '('; + printConstructorParameters( + o, options, manager, sort, entity, name, arguments); + o << ");\n"; +} + +static void printMethodParameters( + std::ostream & o, ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + std::vector< unoidl::InterfaceTypeEntity::Method::Parameter > const & + parameters, + bool withType) +{ + for (std::vector< unoidl::InterfaceTypeEntity::Method::Parameter >:: + const_iterator i(parameters.begin()); + i != parameters.end(); ++i) + { + if (i != parameters.begin()) { + o << ", "; + } + if (withType) { + short referenceType; + if (i->direction + == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN) + { + referenceType = 4; + } else { + referenceType = 2; + } + printType(o, options, manager, i->type, referenceType); + o << ' '; + } + o << codemaker::cpp::translateUnoToCppIdentifier(u2b(i->name), "param"); + } +} + +static void printExceptionSpecification( + std::ostream & o, + ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + std::vector< OUString > const & exceptions) +{ + o << ((options.shortnames) ? " throw (css::uno::RuntimeException" : + " throw (::com::sun::star::uno::RuntimeException"); + for (const auto& rException : exceptions) + { + o << ", "; + printType(o, options, manager, rException, 1); + } + o << ")"; +} + +static void printSetPropertyMixinBody( + std::ostream & o, unoidl::InterfaceTypeEntity::Attribute const & attribute) +{ + unoidl::AccumulationBasedServiceEntity::Property::Attributes propFlags + = checkAdditionalPropertyFlags(attribute); + + o << "\n{\n"; + + if (attribute.bound) + o << " BoundListeners l;\n"; + + if (propFlags & unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_CONSTRAINED) { + OString fieldtype = codemaker::convertString(attribute.type); + + sal_Int32 index = fieldtype.lastIndexOf('<'); + sal_Int32 nPos=0; + bool single = true; + bool optional = false; + OStringBuffer buffer1(64); + OStringBuffer buffer2(64); + do + { + OString s(fieldtype.getToken(0, '<', nPos)); + OString t = s.copy(s.lastIndexOf('/')+1); + + if (t == "Optional") { + optional=true; + if (single) { + single=false; + buffer1.append("the_value.IsPresent"); + buffer2.append("the_value.Value"); + } else { + buffer1.insert(0, t); + buffer1.append(".IsPresent"); + buffer2.insert(0, t); + buffer2.append(".Value"); + } + } else { + if (single) { + single=false; + if (!optional) + buffer1.append("the_value.Value"); + + buffer2.append("the_value.Value"); + } else { + if (!optional) { + buffer1.insert(0, t); + buffer1.append(".Value"); + } + buffer2.insert(0, t); + buffer2.append(".Value"); + } + } + } while( nPos <= index ); + + o << " css::uno::Any v;\n"; + if (optional) { + o << " if(" << buffer1.makeStringAndClear() << ")\n {\n v <<= " << buffer2.makeStringAndClear() << ";\n }\n"; + } else { + o << " v <<= " << buffer2.makeStringAndClear() << ";\n\n"; + } + + o << " prepareSet(\n OUString(\"" + << attribute.name << "\"),\n css::uno::Any(), v, "; + } else { + o << " prepareSet(\n OUString(\"" + << attribute.name << "\"),\n css::uno::Any(), css::uno::Any(), "; + } + + if (attribute.bound) + o << "&l);\n"; + else + o << "0);\n"; + + o << " {\n osl::MutexGuard g(m_aMutex);\n m_" + << attribute.name << " = the_value;\n }\n"; + + if (attribute.bound) + o << " l.notify();\n"; + + o << "}\n\n"; +} + +void printMethods(std::ostream & o, + ProgramOptions const & options, rtl::Reference< TypeManager > const & manager, + OUString const & name, codemaker::GeneratedTypeSet & generated, + OString const & delegate, OString const & classname, + OString const & indentation, bool defaultvalue, + OUString const & propertyhelper) +{ + if (generated.contains(u2b(name)) || name == "com.sun.star.uno.XInterface" || + (defaultvalue && + ( name == "com.sun.star.lang.XComponent" || + name == "com.sun.star.lang.XTypeProvider" || + name == "com.sun.star.uno.XWeak" ) ) ) + { + return; + } + + static OString sd("_"_ostr); + bool body = !delegate.isEmpty(); + bool defaultbody = delegate == sd; + + if (body && propertyhelper.getLength() > 1) { + if (name == "com.sun.star.beans.XPropertySet") { + generated.add(u2b(name)); + generateXPropertySetBodies( + o, classname, scopedCppName(u2b(propertyhelper))); + return; + } else if (name == "com.sun.star.beans.XFastPropertySet") { + generated.add(u2b(name)); + generateXFastPropertySetBodies( + o, classname, scopedCppName(u2b(propertyhelper))); + return; + } else if (name == "com.sun.star.beans.XPropertyAccess") { + generated.add(u2b(name)); + generateXPropertyAccessBodies( + o, classname, scopedCppName(u2b(propertyhelper))); + return; + } + } + + if (body && options.componenttype == 2) { + if (name == "com.sun.star.lang.XServiceName") { + o << "// ::com::sun::star::lang::XServiceName:\n" + "OUString SAL_CALL " << classname << "getServiceName() " + "throw (css::uno::RuntimeException)\n{\n " + "return OUString(" + "sADDIN_SERVICENAME);\n}\n"; + generated.add(u2b(name)); + return; + } else if (name == "com.sun.star.sheet.XAddIn") { + generateXAddInBodies(o, classname); + generated.add(u2b(name)); + + // special handling of XLocalizable -> parent of XAddIn + if (!generated.contains("com.sun.star.lang.XLocalizable"_ostr)) { + generateXLocalizable(o, classname); + generated.add("com.sun.star.lang.XLocalizable"_ostr); + } + return; + } else if (name == "com.sun.star.lang.XLocalizable") { + generateXLocalizable(o, classname); + generated.add(u2b(name)); + return; + } else if (name == "com.sun.star.sheet.XCompatibilityNames") { + generateXCompatibilityNamesBodies(o, classname); + generated.add(u2b(name)); + return; + } + } + + if (body && options.componenttype == 3) { + if (name == "com.sun.star.lang.XInitialization") { + generateXInitialization(o, classname); + generated.add(u2b(name)); + return; + } else if (name == "com.sun.star.frame.XDispatch") { + generateXDispatch(o, classname, options.protocolCmdMap); + generated.add(u2b(name)); + return; + } else if (name == "com.sun.star.frame.XDispatchProvider") { + generateXDispatchProvider(o, classname, options.protocolCmdMap); + generated.add(u2b(name)); + return; + } + } + + generated.add(u2b(name)); + rtl::Reference< unoidl::Entity > ent; + if (manager->getSort(name, &ent) != codemaker::UnoType::Sort::Interface) + { + throw CannotDumpException( + "unexpected entity \"" + name + + "\" in call to skeletonmaker::cpp::printMethods"); + } + rtl::Reference< unoidl::InterfaceTypeEntity > ent2( + dynamic_cast< unoidl::InterfaceTypeEntity * >(ent.get())); + assert(ent2.is()); + if (options.all || defaultvalue) { + for (const auto& rBase : ent2->getDirectMandatoryBases()) + { + printMethods( + o, options, manager, rBase.name, generated, delegate, classname, + indentation, defaultvalue, propertyhelper); + } + if (!(ent2->getDirectAttributes().empty() + && ent2->getDirectMethods().empty())) + { + o << indentation << "// "; + printType(o, options, manager, name, 0); + o << ":\n"; + } + } + for (const auto& rAttr : ent2->getDirectAttributes()) + { + o << indentation; + if (!body) + o << "virtual "; + + printType(o, options, manager, rAttr.type, 1); + o << " SAL_CALL "; + if (!classname.isEmpty()) + o << classname; + + o << "get" << rAttr.name << "()"; + printExceptionSpecification(o, options, manager, rAttr.getExceptions); + if (body) { + if (defaultbody) { + if (!propertyhelper.isEmpty()) { + o << "\n{\n osl::MutexGuard g(m_aMutex);\n return m_" + << rAttr.name << ";\n}\n\n"; + } else { + o << "\n{\n return "; + if (options.componenttype == 1) { + o << "m_" << rAttr.name; + } else { + printType(o, options, manager, rAttr.type, 8, true); + } + o << ";\n}\n\n"; + } + } else { + o << "\n" << indentation << "{\n" << indentation << " return " + << delegate << "get" << rAttr.name << "();\n" + << indentation << "}\n\n"; + } + } else { + o << ";\n"; + } + + if (!rAttr.readOnly) { + o << indentation; + if (!body) + o << "virtual "; + + o << "void SAL_CALL "; + if (!classname.isEmpty()) + o << classname; + + o << "set" << rAttr.name << '('; + printType(o, options, manager, rAttr.type, 4); + o << " the_value)"; + printExceptionSpecification(o, options, manager, rAttr.setExceptions); + if (body) { + if (defaultbody) { + if (!propertyhelper.isEmpty()) { + printSetPropertyMixinBody(o, rAttr); + } else { + if (options.componenttype == 1) { + o << "\n{\n m_" << rAttr.name + << " = the_value;\n}\n\n"; + } else { + o << "\n{\n\n}\n\n"; + } + } + } else { + o << "\n" << indentation << "{\n" << indentation << " " + << delegate << "set" << rAttr.name + << "(the_value);\n" << indentation << "}\n\n"; + } + } else { + o << ";\n"; + } + } + } + for (const auto& rMethod : ent2->getDirectMethods()) + { + o << indentation; + if (!body) + o << "virtual "; + + printType(o, options, manager, rMethod.returnType, 1); + o << " SAL_CALL "; + if (!classname.isEmpty()) + o << classname; + + o << rMethod.name << '('; + printMethodParameters(o, options, manager, rMethod.parameters, true); + o << ')'; + printExceptionSpecification(o, options, manager, rMethod.exceptions); + if (body) { + if (defaultbody) { + o << "\n{\n"; + if (rMethod.returnType != "void") { + o << " // TODO: Exchange the default return implementation for \"" + << rMethod.name << "\" !!!\n"; + o << " // Exchange the default return implementation.\n" + " // NOTE: Default initialized polymorphic structs " + "can cause problems because of\n // missing default " + "initialization of primitive types of some C++ compilers or" + "\n // different Any initialization in Java and C++ " + "polymorphic structs.\n return "; + printType(o, options, manager, rMethod.returnType, 8, true); + o << ";"; + } else { + o << " // TODO: Insert your implementation for \"" + << rMethod.name << "\" here."; + } + o << "\n}\n\n"; + } else { + o << "\n" << indentation << "{\n" << indentation << " "; + if (rMethod.returnType != "void") + o << "return "; + + o << delegate << rMethod.name << '('; + printMethodParameters( + o, options, manager, rMethod.parameters, false); + o << ");\n" << indentation << "}\n\n"; + } + } else { + o << ";\n"; + } + } + + if (!body) + o << "\n"; +} + +static void printConstructors( + std::ostream & o, ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, OUString const & name) +{ + rtl::Reference< unoidl::Entity > ent; + if (manager->getSort(name, &ent) + != codemaker::UnoType::Sort::SingleInterfaceBasedService) + { + throw CannotDumpException( + "unexpected entity \"" + name + + "\" in call to skeletonmaker::java::printConstructors"); + } + rtl::Reference< unoidl::SingleInterfaceBasedServiceEntity > ent2( + dynamic_cast< unoidl::SingleInterfaceBasedServiceEntity * >(ent.get())); + assert(ent2.is()); + for (const auto& rConstructor : ent2->getConstructors()) + { + o << "static "; + printType(o, options, manager, ent2->getBase(), 1); + o << ' '; + if (rConstructor.defaultConstructor) { + o << "create"; + } else { + o << codemaker::cpp::translateUnoToCppIdentifier( + u2b(rConstructor.name), "method"); + } + o << ((options.shortnames) ? "(css::uno::Reference< css" : + "(::com::sun::star::uno::Reference< ::com::sun::star") + << "::uno::XComponentContext > const & the_context"; + for (const auto& rParam : rConstructor.parameters) + { + o << ", "; + printType(o, options, manager, rParam.type, 4); + o << ' ' + << codemaker::cpp::translateUnoToCppIdentifier( + u2b(rParam.name), "param"); + } + o << ')'; + printExceptionSpecification(o, options, manager, rConstructor.exceptions); + o << ";\n"; + } +} + +static void printServiceMembers( + std::ostream & o, ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + OUString const & name, + rtl::Reference< unoidl::AccumulationBasedServiceEntity > const & entity, + OString const & delegate) +{ + assert(entity.is()); + for (const auto& rService : entity->getDirectMandatoryBaseServices()) + { + o << "\n// exported service " << rService.name << "\n"; + generateDocumentation(o, options, manager, u2b(rService.name), delegate); + o << "\n// end of exported service " << rService.name << "\n"; + } + for (const auto& rIface : entity->getDirectMandatoryBaseInterfaces()) + { + o << "\n// supported interface " << rIface.name << "\n"; + generateDocumentation(o, options, manager, u2b(rIface.name), delegate); + } + if (delegate.isEmpty()) { + o << "\n// properties of service \""<< name << "\"\n"; + for (const auto& rProp : entity->getDirectProperties()) + { + o << "// private "; + printType(o, options, manager, rProp.type, 1); + o << " " + << codemaker::cpp::translateUnoToCppIdentifier( + u2b(rProp.name), "property") + << ";\n"; + } + } +} + +static void printMapsToCppType( + std::ostream & o, ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + codemaker::UnoType::Sort sort, std::u16string_view nucleus, sal_Int32 rank, + std::vector< OUString > const & arguments, + rtl::Reference< unoidl::Entity > const & entity, const char * cppTypeSort) +{ + o << "maps to C++ "; + if (cppTypeSort != nullptr) + o << cppTypeSort << ' '; + + o << "type \""; + if (rank == 0 && nucleus == u"com.sun.star.uno.XInterface") { + o << "Reference< com::sun::star::uno::XInterface >"; + } else { + printType( + o, options, manager, sort, nucleus, rank, arguments, entity, 0, + false); + } + o << '"'; +} + +void generateDocumentation(std::ostream & o, + ProgramOptions const & options, rtl::Reference< TypeManager > const & manager, + OString const & type, OString const & delegate) +{ + OUString nucleus; + sal_Int32 rank; + codemaker::UnoType::Sort sort = manager->decompose( + b2u(type), false, &nucleus, &rank, nullptr, nullptr); + + bool comment = true; + if (!delegate.isEmpty()) { + if (sort != codemaker::UnoType::Sort::Interface && + sort != codemaker::UnoType::Sort::SingleInterfaceBasedService && + sort != codemaker::UnoType::Sort::AccumulationBasedService ) + { + return; + } + comment = false; + } + + if (comment) { + o << "\n// UNO"; + if (rank != 0) { + o << " sequence type"; + } else if (sort <= codemaker::UnoType::Sort::Any) { + o << " simple type"; + } else { + switch (sort) { + case codemaker::UnoType::Sort::Interface: + o << " interface type"; + break; + + case codemaker::UnoType::Sort::Module: + o << "IDL module"; + break; + + case codemaker::UnoType::Sort::PlainStruct: + o << " simple struct type"; + break; + + case codemaker::UnoType::Sort::PolymorphicStructTemplate: + o << " polymorphic struct type template"; + break; + + case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct: + o << " instantiated polymorphic struct type"; + break; + + case codemaker::UnoType::Sort::Enum: + o << " enum type"; + break; + + case codemaker::UnoType::Sort::Exception: + o << " exception type"; + break; + + case codemaker::UnoType::Sort::Typedef: + o << "IDL typedef"; + break; + + case codemaker::UnoType::Sort::SingleInterfaceBasedService: + o << " single-inheritance--based service"; + break; + + case codemaker::UnoType::Sort::AccumulationBasedService: + o << "IDL accumulation-based service"; + break; + + case codemaker::UnoType::Sort::InterfaceBasedSingleton: + o << " inheritance-based singleton"; + break; + + case codemaker::UnoType::Sort::ServiceBasedSingleton: + o << "IDL service-based singleton"; + break; + + case codemaker::UnoType::Sort::ConstantGroup: + o << "IDL constant group"; + break; + + default: + OSL_ASSERT(false); + break; + } + } + o << " \"" << type << "\" "; + } + std::vector< OUString > arguments; + rtl::Reference< unoidl::Entity > entity; + sort = manager->decompose( + b2u(type), true, &nucleus, &rank, &arguments, &entity); + if (rank != 0) { + if (comment) { + printMapsToCppType( + o, options, manager, sort, nucleus, rank, arguments, entity, + "array"); + o << '\n'; + } + } else if (sort <= codemaker::UnoType::Sort::Any) { + if (comment) { + printMapsToCppType( + o, options, manager, sort, nucleus, rank, arguments, entity, nullptr); + o << '\n'; + } + } else { + switch (sort) { + case codemaker::UnoType::Sort::Interface: + if (comment) + printMapsToCppType( + o, options, manager, sort, nucleus, rank, arguments, entity, + "interface"); + if (nucleus == "com.sun.star.uno.XInterface") { + if (comment) + o << '\n'; + } else { + if (comment) + o << "; " << (options.all ? "all" : "direct") << " methods:\n"; + + codemaker::GeneratedTypeSet generated; + printMethods( + o, options, manager, nucleus, generated, delegate, + options.implname, ""_ostr); + } + break; + + case codemaker::UnoType::Sort::Module: + printMapsToCppType( + o, options, manager, sort, nucleus, rank, arguments, entity, + "namespace"); + o << '\n'; + break; + + case codemaker::UnoType::Sort::PlainStruct: + printMapsToCppType( + o, options, manager, sort, nucleus, rank, arguments, entity, + "class"); + o << "; full constructor:\n"; + printConstructor( + o, options, manager, codemaker::UnoType::Sort::PlainStruct, + entity, nucleus, arguments); + break; + + case codemaker::UnoType::Sort::PolymorphicStructTemplate: + printMapsToCppType( + o, options, manager, sort, nucleus, rank, arguments, entity, + "class template"); + o << "; full constructor:\n"; + printConstructor( + o, options, manager, + codemaker::UnoType::Sort::PolymorphicStructTemplate, + entity, nucleus, arguments); + break; + + case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct: + printMapsToCppType( + o, options, manager, sort, nucleus, rank, arguments, entity, + "class template instantiation"); + o << "; full constructor:\n"; + printConstructor( + o, options, manager, + codemaker::UnoType::Sort::InstantiatedPolymorphicStruct, + entity, nucleus, arguments); + break; + + case codemaker::UnoType::Sort::Enum: + printMapsToCppType( + o, options, manager, sort, nucleus, rank, arguments, entity, + "enum"); + o << '\n'; + break; + + case codemaker::UnoType::Sort::ConstantGroup: + printMapsToCppType( + o, options, manager, sort, nucleus, rank, arguments, entity, + "namespace"); + o << '\n'; + break; + + case codemaker::UnoType::Sort::Exception: + printMapsToCppType( + o, options, manager, sort, nucleus, rank, arguments, entity, + "exception class"); + o << "; full constructor:\n"; + printConstructor( + o, options, manager, codemaker::UnoType::Sort::Exception, + entity, nucleus, arguments); + break; + + case codemaker::UnoType::Sort::SingleInterfaceBasedService: + if (comment) { + printMapsToCppType( + o, options, manager, sort, nucleus, rank, arguments, entity, + "class"); + o << "; construction methods:\n"; + printConstructors(o, options, manager, nucleus); + } + generateDocumentation( + o, options, manager, + u2b(dynamic_cast<unoidl::SingleInterfaceBasedServiceEntity&>(*entity) + .getBase()), + delegate); + break; + + case codemaker::UnoType::Sort::AccumulationBasedService: + if (comment) + o << ("does not map to C++\n" + "// the service members are generated instead\n"); + printServiceMembers( + o, options, manager, nucleus, + dynamic_cast< unoidl::AccumulationBasedServiceEntity * >( + entity.get()), + delegate); + break; + + case codemaker::UnoType::Sort::InterfaceBasedSingleton: + printMapsToCppType( + o, options, manager, sort, nucleus, rank, arguments, entity, + "class"); + o << "; get method:\nstatic "; + printType( + o, options, manager, + dynamic_cast< unoidl::InterfaceBasedSingletonEntity & >( + *entity).getBase(), + 1); + o << " get(::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > const & context);\n"; + break; + + case codemaker::UnoType::Sort::ServiceBasedSingleton: + o << "does not map to C++\n"; + break; + + default: + OSL_ASSERT(false); + break; + } + } +} + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unodevtools/source/skeletonmaker/javacompskeleton.cxx b/unodevtools/source/skeletonmaker/javacompskeleton.cxx new file mode 100644 index 0000000000..1de92fac0b --- /dev/null +++ b/unodevtools/source/skeletonmaker/javacompskeleton.cxx @@ -0,0 +1,920 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <codemaker/commonjava.hxx> +#include <codemaker/global.hxx> +#include <rtl/strbuf.hxx> + +#include "skeletoncommon.hxx" +#include "skeletonjava.hxx" + +#include <iostream> + +using namespace ::codemaker::java; + +namespace skeletonmaker::java { + +static void generatePackage(std::ostream & o, std::string_view implname) +{ + size_t index = implname.rfind('.'); + if (index != std::string_view::npos) + o << "package " << implname.substr(0, index) << ";\n\n"; +} + +static void generateImports(std::ostream & o, ProgramOptions const & options, + std::u16string_view propertyhelper, + bool serviceobject, bool supportxcomponent) +{ + if (options.componenttype == 3) + o << "import com.sun.star.uno.UnoRuntime;\n"; + o << "import com.sun.star.uno.XComponentContext;\n"; + if (serviceobject) { + o << "import com.sun.star.lib.uno.helper.Factory;\n"; + o << "import com.sun.star.lang.XSingleComponentFactory;\n"; + o << "import com.sun.star.registry.XRegistryKey;\n"; + } + + if (propertyhelper != u"_") { + if (supportxcomponent) + o << "import com.sun.star.lib.uno.helper.ComponentBase;\n"; + else + o << "import com.sun.star.lib.uno.helper.WeakBase;\n"; + } + if (!propertyhelper.empty()) { + if (propertyhelper == u"_") { + o << "import com.sun.star.lib.uno.helper.PropertySet;\n"; + o << "import com.sun.star.beans.PropertyAttribute;\n"; + } else { + o << "import com.sun.star.uno.Type;\n"; + o << "import com.sun.star.uno.Any;\n"; + o << "import com.sun.star.beans.Ambiguous;\n"; + o << "import com.sun.star.beans.Defaulted;\n"; + o << "import com.sun.star.beans.Optional;\n"; + o << "import com.sun.star.lib.uno.helper.PropertySetMixin;\n"; + } + } +} + +static void generateCompFunctions(std::ostream & o, const OString & classname) +{ + o << " public static XSingleComponentFactory __getComponentFactory(" + " String sImplementationName ) {\n" + " XSingleComponentFactory xFactory = null;\n\n" + " if ( sImplementationName.equals( m_implementationName ) )\n" + " xFactory = Factory.createComponentFactory(" + << classname << ".class, m_serviceNames);\n" + " return xFactory;\n }\n\n"; + + o << " public static boolean __writeRegistryServiceInfo(" + " XRegistryKey xRegistryKey ) {\n" + " return Factory.writeRegistryServiceInfo(m_implementationName,\n" + " m_serviceNames,\n" + " xRegistryKey);\n" + " }\n\n"; +} + +static void generateXServiceInfoBodies(std::ostream& o) +{ + o << " // com.sun.star.lang.XServiceInfo:\n"; + o << " public String getImplementationName() {\n" + " return m_implementationName;\n }\n\n"; + + o << " public boolean supportsService( String sService ) {\n" + " int len = m_serviceNames.length;\n\n" + " for( int i=0; i < len; i++) {\n" + " if (sService.equals(m_serviceNames[i]))\n" + " return true;\n" + " }\n return false;\n }\n\n"; + + o << " public String[] getSupportedServiceNames() {\n" + " return m_serviceNames;\n }\n\n"; +} + +void generateXPropertySetBodies(std::ostream& o) +{ + o << " // com.sun.star.beans.XPropertySet:\n"; + o << " public com.sun.star.beans.XPropertySetInfo getPropertySetInfo()\n" + " {\n return m_prophlp.getPropertySetInfo();\n }\n\n"; + + o << " public void setPropertyValue(String aPropertyName, " + "Object aValue) throws " + "com.sun.star.beans.UnknownPropertyException, " + "com.sun.star.beans.PropertyVetoException, " + "com.sun.star.lang.IllegalArgumentException," + "com.sun.star.lang.WrappedTargetException\n {\n " + "m_prophlp.setPropertyValue(aPropertyName, aValue);\n }\n\n"; + + o << " public Object getPropertyValue(String " + "aPropertyName) throws com.sun.star.beans.UnknownPropertyException, " + "com.sun.star.lang.WrappedTargetException\n {\n return " + "m_prophlp.getPropertyValue(aPropertyName);\n }\n\n"; + + o << " public void addPropertyChangeListener(String aPropertyName" + ", com.sun.star.beans.XPropertyChangeListener xListener) throws " + "com.sun.star.beans.UnknownPropertyException, " + "com.sun.star.lang.WrappedTargetException\n {\n " + "m_prophlp.addPropertyChangeListener(aPropertyName, xListener);\n }\n\n"; + + o << " public void removePropertyChangeListener(String " + "aPropertyName, com.sun.star.beans.XPropertyChangeListener xListener) " + "throws com.sun.star.beans.UnknownPropertyException, " + "com.sun.star.lang.WrappedTargetException\n {\n " + "m_prophlp.removePropertyChangeListener(aPropertyName, xListener);\n" + " }\n\n"; + + o << " public void addVetoableChangeListener(String aPropertyName" + ", com.sun.star.beans.XVetoableChangeListener xListener) throws " + "com.sun.star.beans.UnknownPropertyException, " + "com.sun.star.lang.WrappedTargetException\n {\n " + "m_prophlp.addVetoableChangeListener(aPropertyName, xListener);\n }\n\n"; + + o << " public void removeVetoableChangeListener(String " + "aPropertyName, com.sun.star.beans.XVetoableChangeListener xListener) " + "throws com.sun.star.beans.UnknownPropertyException, " + "com.sun.star.lang.WrappedTargetException\n {\n " + "m_prophlp.removeVetoableChangeListener(aPropertyName, xListener);\n }\n\n"; +} + +void generateXFastPropertySetBodies(std::ostream& o) +{ + o << " // com.sun.star.beans.XFastPropertySet:\n"; + + o << " public void setFastPropertyValue(int nHandle, Object " + "aValue) throws com.sun.star.beans.UnknownPropertyException, " + "com.sun.star.beans.PropertyVetoException, " + "com.sun.star.lang.IllegalArgumentException, " + "com.sun.star.lang.WrappedTargetException\n {\n " + "m_prophlp.setFastPropertyValue(nHandle, aValue);\n }\n\n"; + + o << " public Object getFastPropertyValue(int nHandle) throws " + "com.sun.star.beans.UnknownPropertyException, " + "com.sun.star.lang.WrappedTargetException\n {\n return " + "m_prophlp.getFastPropertyValue(nHandle);\n }\n\n"; +} + +void generateXPropertyAccessBodies(std::ostream& o) +{ + o << " // com.sun.star.beans.XPropertyAccess:\n"; + + o << " public com.sun.star.beans.PropertyValue[] getPropertyValues()\n" + " {\n return m_prophlp.getPropertyValues();\n }\n\n"; + + o << " public void setPropertyValues(com.sun.star.beans.PropertyValue[] " + "aProps) throws com.sun.star.beans.UnknownPropertyException, " + "com.sun.star.beans.PropertyVetoException, " + "com.sun.star.lang.IllegalArgumentException, " + "com.sun.star.lang.WrappedTargetException\n {\n " + "m_prophlp.setPropertyValues(aProps);\n }\n\n"; +} + + +static bool checkAttribute( + OStringBuffer& attributeValue, + unoidl::AccumulationBasedServiceEntity::Property::Attributes attribute) +{ + bool cast = false; + sal_uInt16 attributes[9] = { + /* com::sun::star::beans::PropertyValue::MAYBEVOID */ 1, + /* com::sun::star::beans::PropertyValue::BOUND */ 2, + /* com::sun::star::beans::PropertyValue::CONSTRAINED */ 4, + /* com::sun::star::beans::PropertyValue::TRANSIENT */ 8, + /* com::sun::star::beans::PropertyValue::READONLY */ 16, + /* com::sun::star::beans::PropertyValue::MAYBEAMBIGUOUS */ 32, + /* com::sun::star::beans::PropertyValue::MAYBEDEFAULT */ 64, + /* com::sun::star::beans::PropertyValue::REMOVABLE */ 128, + /* com::sun::star::beans::PropertyValue::OPTIONAL */ 256 }; + + for (sal_uInt16 i = 0; i < 9; i++) + { + if (attribute & attributes[i]) { + if (!attributeValue.isEmpty()) { + cast = true; + attributeValue.append("|"); + } + switch (attributes[i]) + { + case 1: + attributeValue.append("PropertyAttribute.MAYBEVOID"); + break; + case 2: + attributeValue.append("PropertyAttribute.BOUND"); + break; + case 4: + attributeValue.append("PropertyAttribute.CONSTRAINED"); + break; + case 8: + attributeValue.append("PropertyAttribute.TRANSIENT"); + break; + case 16: + attributeValue.append("PropertyAttribute.READONLY"); + break; + case 32: + attributeValue.append("PropertyAttribute.MAYBEAMBIGUOUS"); + break; + case 64: + attributeValue.append("PropertyAttribute.MAYBEDEFAULT"); + break; + case 128: + attributeValue.append("PropertyAttribute.REMOVABLE"); + break; + case 256: + attributeValue.append("PropertyAttribute.OPTIONAL"); + break; + } + } + } + if (cast) { + attributeValue.insert(0, '('); + attributeValue.append(')'); + } + + return cast; +} + +static void registerProperties(std::ostream& o, + const AttributeInfo& properties, + const OString& indentation) +{ + if (!properties.empty()) { + bool cast = false; + OStringBuffer attributeValue; + for (const auto& rProp : properties) + { + if (rProp.attributes != 0) { + cast = checkAttribute(attributeValue, rProp.attributes); + } else { + cast = true; + attributeValue.append('0'); + } + + o << indentation << "registerProperty(\"" << rProp.name + << "\", \"m_" << rProp.name << "\",\n" + << indentation << " "; + if (cast) + o << "(short)"; + + o << attributeValue.makeStringAndClear() << ");\n"; + } + } +} + +static void generateXLocalizableBodies(std::ostream& o) { + // com.sun.star.lang.XLocalizable: + // setLocale + o << " // com.sun.star.lang.XLocalizable:\n" + " public void setLocale(com.sun.star.lang.Locale eLocale)\n {\n" + " m_locale = eLocale;\n }\n\n"; + + // getLocale + o << " public com.sun.star.lang.Locale getLocale()\n {\n" + " return m_locale;\n }\n\n"; +} + +static void generateXAddInBodies(std::ostream& o) +{ + // com.sun.star.sheet.XAddIn: + // getProgrammaticFuntionName + o << " // com.sun.star.sheet.XAddIn:\n" + " public String getProgrammaticFuntionName(String " + "aDisplayName)\n {\n" + " try {\n" + " com.sun.star.container.XNameAccess xNAccess =\n" + " (com.sun.star.container.XNameAccess)UnoRuntime." + "queryInterface(\n" + " com.sun.star.container.XNameAccess.class, m_xHAccess);" + "\n String functions[] = xNAccess.getElementNames();\n" + " String sDisplayName = \"\";\n" + " int len = functions.length;\n" + " for (int i=0; i < len; ++i) {\n" + " sDisplayName = com.sun.star.uno.AnyConverter.toString(\n" + " getAddinProperty(functions[i], \"\", sDISPLAYNAME));\n" + " if (sDisplayName.equals(aDisplayName))\n" + " return functions[i];\n }\n" + " }\n catch ( com.sun.star.uno.RuntimeException e ) {\n" + " throw e;\n }\n" + " catch ( com.sun.star.uno.Exception e ) {\n }\n\n" + " return \"\";\n }\n\n"; + + // getDisplayFunctionName + o << " public String getDisplayFunctionName(String " + "aProgrammaticName)\n {\n" + " return getAddinProperty(aProgrammaticName, \"\", sDISPLAYNAME);\n" + " }\n\n"; + + // getFunctionDescription + o << " public String getFunctionDescription(String " + "aProgrammaticName)\n {\n" + " return getAddinProperty(aProgrammaticName, \"\", sDESCRIPTION);\n" + " }\n\n"; + + // getDisplayArgumentName + o << " public String getDisplayArgumentName(String " + "aProgrammaticFunctionName, int nArgument)\n {\n"; + o << " return getAddinProperty(aProgrammaticFunctionName,\n" + " m_functionMap.get(\n" + " aProgrammaticFunctionName).get(" + "nArgument),\n" + " sDISPLAYNAME);\n }\n\n"; + + // getArgumentDescription + o << " public String getArgumentDescription(String " + "aProgrammaticFunctionName, int nArgument)\n {\n"; + o << " return getAddinProperty(aProgrammaticFunctionName,\n" + " m_functionMap.get(\n" + " aProgrammaticFunctionName).get(" + "nArgument),\n" + " sDESCRIPTION);\n }\n\n"; + + // getProgrammaticCategoryName + o << " public String getProgrammaticCategoryName(String " + "aProgrammaticFunctionName)\n {\n" + " return getAddinProperty(aProgrammaticFunctionName, \"\", " + "sCATEGORY);\n }\n\n"; + + // getDisplayCategoryName + o << " public String getDisplayCategoryName(String " + "aProgrammaticFunctionName)\n {\n" + " return getAddinProperty(aProgrammaticFunctionName, \"\", " + "sCATEGORYDISPLAYNAME);\n }\n\n"; +} + +static void generateXCompatibilityNamesBodies(std::ostream& o) +{ + o << " // com.sun.star.sheet.XCompatibilityNames:\n" + " public com.sun.star.sheet.LocalizedName[] getCompatibilityNames(" + "String aProgrammaticName)\n {\n" + " com.sun.star.sheet.LocalizedName[] seqLocalizedNames =\n" + " new com.sun.star.sheet.LocalizedName[0];\n\n try {\n"; + + o << " StringBuffer path = new StringBuffer(aProgrammaticName);\n" + " path.append(\"/CompatibilityName\");\n" + " String hname = path.toString();\n\n"; + + o << " if ( m_xCompAccess.hasByHierarchicalName(hname) ) {\n" + " com.sun.star.container.XNameAccess xNameAccess =\n" + " (com.sun.star.container.XNameAccess)UnoRuntime." + "queryInterface(\n" + " com.sun.star.container.XNameAccess.class,\n" + " m_xCompAccess.getByHierarchicalName(hname));\n\n" + " String elems[] = xNameAccess.getElementNames();\n" + " int len = elems.length;\n" + " seqLocalizedNames = new com.sun.star.sheet.LocalizedName" + "[len];\n String sCompatibilityName = \"\";\n\n"; + + o << " for (int i=0; i < len; ++i) {\n" + " String sLocale = elems[i];\n" + " sCompatibilityName = com.sun.star.uno.AnyConverter." + "toString(\n xNameAccess.getByName(sLocale));\n\n" + " com.sun.star.lang.Locale aLocale = \n" + " new com.sun.star.lang.Locale();\n\n" + /* FIXME-BCP47: this will break. */ + " String tokens[] = sLocale.split(\"-\");\n" + " int nToken = tokens.length;\n" + " if (nToken >= 1) aLocale.Language = tokens[0];\n" + " if (nToken >= 2) aLocale.Country = tokens[1];\n" + " if (nToken >= 3) {\n" + " StringBuffer buf = \n" + " new StringBuffer(tokens[2]);\n" + " for (int t=3; t < nToken; ++t)\n" + " buf.append(tokens[t]);\n\n" + " aLocale.Variant = buf.toString();\n" + " }\n\n" + " seqLocalizedNames[i].Locale = aLocale;\n" + " seqLocalizedNames[i].Name = sCompatibilityName;\n" + " }\n }\n }\n" + " catch ( com.sun.star.uno.RuntimeException e ) {\n" + " throw e;\n }\n" + " catch ( com.sun.star.uno.Exception e ) {\n }\n\n" + " return seqLocalizedNames;\n }\n\n"; +} + +static void generateXInitializationBodies(std::ostream& o) +{ + o << " // com.sun.star.lang.XInitialization:\n" + " public void initialize( Object[] object )\n" + " throws com.sun.star.uno.Exception\n {\n" + " if ( object.length > 0 )\n {\n" + " m_xFrame = (com.sun.star.frame.XFrame)UnoRuntime.queryInterface(\n" + " com.sun.star.frame.XFrame.class, object[0]);\n }\n }\n\n"; +} + +static void generateXDispatchBodies(std::ostream& o, ProgramOptions const & options) +{ + // com.sun.star.frame.XDispatch + // dispatch + o << " // com.sun.star.frame.XDispatch:\n" + " public void dispatch( com.sun.star.util.URL aURL,\n" + " com.sun.star.beans.PropertyValue[] aArguments )\n {\n"; + + for (const auto& rEntry : options.protocolCmdMap) { + o << " if ( aURL.Protocol.equals(\"" << rEntry.first + << "\") )\n {\n"; + + for (const auto& rCmd : rEntry.second) { + o << " if ( aURL.Path.equals(\"" << rCmd << "\") )\n" + " {\n // add your own code here\n" + " return;\n }\n"; + } + + o << " }\n"; + } + o << " }\n\n"; + + // addStatusListener + o << " public void addStatusListener( com.sun.star.frame.XStatusListener xControl,\n" + " com.sun.star.util.URL aURL )\n {\n" + " // add your own code here\n }\n\n"; + + // com.sun.star.frame.XDispatch + o << " public void removeStatusListener( com.sun.star.frame.XStatusListener xControl,\n" + " com.sun.star.util.URL aURL )\n {\n" + " // add your own code here\n }\n\n"; +} + +static void generateXDispatchProviderBodies(std::ostream& o, ProgramOptions const & options) +{ + // com.sun.star.frame.XDispatchProvider + // queryDispatch + o << " // com.sun.star.frame.XDispatchProvider:\n" + " public com.sun.star.frame.XDispatch queryDispatch( com.sun.star.util.URL aURL,\n" + " String sTargetFrameName,\n" + " int iSearchFlags )\n {\n"; + + for (const auto& rEntry : options.protocolCmdMap) { + o << " if ( aURL.Protocol.equals(\"" << rEntry.first + << "\") )\n {\n"; + + for (const auto& rCmd : rEntry.second) { + o << " if ( aURL.Path.equals(\"" << rCmd << "\") )\n" + " return this;\n"; + } + + o << " }\n"; + } + o << " return null;\n }\n\n"; + + // queryDispatches + o << " // com.sun.star.frame.XDispatchProvider:\n" + " public com.sun.star.frame.XDispatch[] queryDispatches(\n" + " com.sun.star.frame.DispatchDescriptor[] seqDescriptors )\n {\n" + " int nCount = seqDescriptors.length;\n" + " com.sun.star.frame.XDispatch[] seqDispatcher =\n" + " new com.sun.star.frame.XDispatch[seqDescriptors.length];\n\n" + " for( int i=0; i < nCount; ++i )\n {\n" + " seqDispatcher[i] = queryDispatch(seqDescriptors[i].FeatureURL,\n" + " seqDescriptors[i].FrameName,\n" + " seqDescriptors[i].SearchFlags );\n" + " }\n return seqDispatcher;\n }\n\n"; +} + +static void generateMethodBodies(std::ostream& o, + ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + const std::set< OUString >& interfaces, + const OString& indentation, bool usepropertymixin) +{ + codemaker::GeneratedTypeSet generated; + for (const OUString& type : interfaces) { + if (type == "com.sun.star.lang.XServiceInfo") { + generateXServiceInfoBodies(o); + generated.add(u2b(type)); + } else { + if (options.componenttype == 2) { + if (type == "com.sun.star.lang.XServiceName") { + o << " // com.sun.star.lang.XServiceName:\n" + " public String getServiceName() {\n" + " return sADDIN_SERVICENAME;\n }\n"; + generated.add(u2b(type)); + continue; + } else if (type == "com.sun.star.sheet.XAddIn") { + generateXAddInBodies(o); + generated.add(u2b(type)); + + // special handling of XLocalizable -> parent of XAddIn + if (!generated.contains("com.sun.star.lang.XLocalizable"_ostr)) { + generateXLocalizableBodies(o); + generated.add("com.sun.star.lang.XLocalizable"_ostr); + } + continue; + } else if (type == "com.sun.star.lang.XLocalizable") { + generateXLocalizableBodies(o); + generated.add(u2b(type)); + continue; + } else if (type == "com.sun.star.sheet.XCompatibilityNames") { + generateXCompatibilityNamesBodies(o); + generated.add(u2b(type)); + continue; + } + } + if (options.componenttype == 3) { + if (type == "com.sun.star.lang.XInitialization") { + generateXInitializationBodies(o); + generated.add(u2b(type)); + continue; + } else if (type == "com.sun.star.frame.XDispatch") { + generateXDispatchBodies(o, options); + generated.add(u2b(type)); + continue; + } else if (type == "com.sun.star.frame.XDispatchProvider") { + generateXDispatchProviderBodies(o, options); + generated.add(u2b(type)); + continue; + } + } + printMethods(o, options, manager, type, generated, "_"_ostr, + indentation, true, usepropertymixin); + } + } +} + +const char* const propcomment= +" // use the last parameter of the PropertySetMixin constructor\n" +" // for your optional attributes if necessary. See the documentation\n" +" // of the PropertySetMixin helper for further information.\n" +" // Ensure that your attributes are initialized correctly!\n"; + + +static void generateAddinConstructorAndHelper(std::ostream& o, + ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, const OString & classname, + const std::set< OUString >& services, + const std::set< OUString >& interfaces) +{ + o << " private com.sun.star.lang.Locale m_locale = " + "new com.sun.star.lang.Locale();\n"; + + if (!options.backwardcompatible) { + // Constructor + o << "\n public " << classname << "( XComponentContext context )\n" + " {\n m_xContext = context;\n }\n\n"; + return; + } + + + // get the one and only add-in service for later use + std::set< OUString >::const_iterator iter = services.begin(); + OUString sAddinService = *iter; + if (sAddinService == "com.sun.star.sheet.AddIn") { + sAddinService = *(++iter); + } + + + // add-in specific fields + o << "\n private static final String sADDIN_SERVICENAME = \"" + << sAddinService << "\";\n\n"; + o << " private static final String sDISPLAYNAME = " + "\"DisplayName\";\n" + " private static final String sDESCRIPTION = " + "\"Description\";\n" + " private static final String sCATEGORY = \"Category\";\n" + " private static final String sCATEGORYDISPLAYNAME = " + "\"CategoryDisplayName\";\n\n"; + + o << " private com.sun.star.container.XHierarchicalNameAccess " + "m_xHAccess = null;\n" + " private com.sun.star.container.XHierarchicalNameAccess " + "m_xCompAccess = null;\n"; + o << " private java.util.Hashtable<\n String, " + "java.util.Hashtable< Integer, String> > m_functionMap = null;\n\n"; + + // Constructor + o << "\n public " << classname << "( XComponentContext context )\n {\n" + " m_xContext = context;\n\n" + " try {\n"; + + o << " m_functionMap = new java.util.Hashtable<\n" + " String, java.util.Hashtable< Integer, String > >();\n\n"; + + generateFunctionParameterMap(o, options, manager, interfaces); + + o << " com.sun.star.lang.XMultiServiceFactory xProvider = \n" + " (com.sun.star.lang.XMultiServiceFactory)UnoRuntime." + "queryInterface(\n" + " com.sun.star.lang.XMultiServiceFactory.class,\n" + " m_xContext.getServiceManager().createInstanceWithContext(" + "\n \"com.sun.star.configuration.ConfigurationProvider\"" + ",\n m_xContext));\n\n"; + + o << " String sReadOnlyView = " + "\"com.sun.star.configuration.ConfigurationAccess\";\n\n"; + + o << " StringBuffer sPath = new StringBuffer(\n" + " \"/org.openoffice.Office.CalcAddIns/AddInInfo/\");\n" + " sPath.append(sADDIN_SERVICENAME);\n" + " sPath.append(\"/AddInFunctions\");\n\n"; + + o << " // create arguments: nodepath\n" + " com.sun.star.beans.PropertyValue aArgument = \n" + " new com.sun.star.beans.PropertyValue();\n" + " aArgument.Name = \"nodepath\";\n" + " aArgument.Value = new com.sun.star.uno.Any(\n" + " com.sun.star.uno.Type.STRING, sPath.toString());\n\n"; + + o << " Object aArguments[] = new Object[1];\n" + " aArguments[0] = new com.sun.star.uno.Any(" + " new com.sun.star.uno.Type(\n" + " com.sun.star.beans.PropertyValue.class), aArgument);\n\n"; + + o << " // create the default view using default UI locale\n" + " Object xIface = \n" + " xProvider.createInstanceWithArguments(sReadOnlyView, " + "aArguments);\n\n"; + + o << " m_xHAccess = (com.sun.star.container.XHierarchicalNameAccess)\n" + " UnoRuntime.queryInterface(\n" + " com.sun.star.container.XHierarchicalNameAccess.class, " + "xIface);\n\n"; + + o << " // extends arguments to create a view for all locales to get " + "simple\n // access to the compatibilityname property\n" + " aArguments = new Object[2];\n" + " aArguments[0] = new com.sun.star.uno.Any( " + "new com.sun.star.uno.Type(\n" + " com.sun.star.beans.PropertyValue.class), aArgument);\n" + " aArgument.Name = \"locale\";\n" + " aArgument.Value = new com.sun.star.uno.Any(\n" + " com.sun.star.uno.Type.STRING, \"*\");\n" + " aArguments[1] = new com.sun.star.uno.Any( " + " new com.sun.star.uno.Type(\n" + " com.sun.star.beans.PropertyValue.class), aArgument);\n\n"; + + o << " // create view for all locales\n" + " xIface = xProvider.createInstanceWithArguments(sReadOnlyView, " + "aArguments);\n\n" + " m_xCompAccess = (com.sun.star.container.XHierarchicalNameAccess)\n" + " UnoRuntime.queryInterface(\n" + " com.sun.star.container.XHierarchicalNameAccess.class, " + "xIface);\n }\n" + " catch ( com.sun.star.uno.Exception e ) {\n }\n }\n\n"; + + // add-in helper function + o << " // addin configuration property helper function:\n" + " String getAddinProperty(String funcName, " + "String paramName, String propName)\n {\n" + " try {\n StringBuffer buf = " + "new StringBuffer(funcName);\n\n" + " if (paramName.length() > 0) {\n" + " buf.append(\"/Parameters/\");\n" + " buf.append(paramName);\n }\n\n"; + + o << " com.sun.star.beans.XPropertySet xPropSet =\n" + " (com.sun.star.beans.XPropertySet)UnoRuntime." + "queryInterface(\n" + " com.sun.star.beans.XPropertySet.class,\n" + " m_xHAccess.getByHierarchicalName(buf.toString()));\n\n" + " return com.sun.star.uno.AnyConverter.toString(\n" + " xPropSet.getPropertyValue(propName));\n }\n" + " catch ( com.sun.star.uno.RuntimeException e ) {\n" + " throw e;\n }\n" + " catch ( com.sun.star.uno.Exception e ) {\n }\n" + " return \"\";\n }\n\n"; +} + + +static void generateClassDefinition(std::ostream& o, + ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + const OString & classname, + const std::set< OUString >& services, + const std::set< OUString >& interfaces, + const AttributeInfo& properties, + const AttributeInfo& attributes, + const OUString& propertyhelper, bool supportxcomponent) +{ + o << "\n\npublic final class " << classname << " extends "; + + if (!interfaces.empty()) { + if (propertyhelper == "_") { + o << "PropertySet\n"; + } else { + if (supportxcomponent) + o << "ComponentBase\n"; + else + o << "WeakBase\n"; + } + o << " implements "; + std::set< OUString >::const_iterator iter = interfaces.begin(); + while (iter != interfaces.end()) { + o << (*iter); + ++iter; + if (iter != interfaces.end()) + o << ",\n "; + } + } + o << "\n{\n"; + + o << " private final XComponentContext m_xContext;\n"; + + // additional member for add-ons + if (options.componenttype == 3) { + o << " private com.sun.star.frame.XFrame m_xFrame;\n"; + } + + // check property helper + if (propertyhelper.getLength() > 1) + o << " private final PropertySetMixin m_prophlp;\n"; + + o << " private static final String m_implementationName = " + << classname << ".class.getName();\n"; + + if (!services.empty()) { + o << " private static final String[] m_serviceNames = {\n"; + std::set< OUString >::const_iterator iter = services.begin(); + while (iter != services.end()) { + o << " \"" << (*iter).replace('/','.') << "\""; + ++iter; + if (iter != services.end()) + o << ",\n"; + else + o << " };\n\n"; + } + } + + // attribute/property members + if (!properties.empty()) { + o << " // properties\n"; + for (const auto& rProp : properties) { + o << " protected "; + printType(o, options, manager, rProp.type, false); + o << " m_" << rProp.name << ";\n"; + } + } else if (!attributes.empty()) { + o << " // attributes\n"; + for (const auto& rAttr : attributes) { + o << " private "; + printType(o, options, manager, rAttr.type, false); + o << " m_" << rAttr.name << " = "; + printType(o, options, manager, rAttr.type, false, true); + o <<";\n"; + } + } + + // special handling of calc add-ins + if (options.componenttype == 2) + { + generateAddinConstructorAndHelper(o, options, manager, classname, + services, interfaces); + } else { + o << "\n public " << classname << "( XComponentContext context )\n" + " {\n m_xContext = context;\n"; + if (propertyhelper == "_") { + registerProperties(o, properties, " "_ostr); + } else { + if (propertyhelper.getLength() > 1) { + o << propcomment + << " m_prophlp = new PropertySetMixin(m_xContext, this,\n" + " new Type(" << propertyhelper + << ".class), null);\n"; + } + } + o << " };\n\n"; + + } + + if (!services.empty()) + generateCompFunctions(o, classname); + + generateMethodBodies(o, options, manager, interfaces, + " "_ostr, propertyhelper.getLength() > 1); + + // end of class definition + o << "}\n"; +} + +void generateSkeleton(ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + std::vector< OString > const & types) +{ + std::set< OUString > interfaces; + std::set< OUString > services; + AttributeInfo properties; + AttributeInfo attributes; + std::set< OUString > propinterfaces; + bool serviceobject = false; + bool supportxcomponent = false; + + for (const auto& rType : types) { + checkType(manager, b2u(rType), interfaces, services, properties); + } + + if (options.componenttype == 3) { + // the Protocolhandler service is mandatory for a protocol handler add-on, + // so it is defaulted. The XDispatchProvider provides Dispatch objects for + // certain functions and the generated impl object implements XDispatch + // directly for simplicity reasons. + checkType(manager, "com.sun.star.frame.ProtocolHandler", + interfaces, services, properties); + checkType(manager, "com.sun.star.frame.XDispatch", + interfaces, services, properties); + } + + if (options.componenttype == 2) { + if (services.size() != 1) { + throw CannotDumpException( + "for calc add-in components one and only one service type is " + "necessary! Please reference a valid type with the '-t' option."); + } + + // if backwardcompatible==true the AddIn service needs to be added to the + // supported service list, the necessary interfaces are mapped to the add-in + // configuration. Since OO.org 2.0.4 this is obsolete and the add-in is + // taken from the configuration from Calc directly, this simplifies the + // add-in code + if (options.backwardcompatible) { + checkType(manager, "com.sun.star.sheet.AddIn", + interfaces, services, properties); + } else { + // special case for the optional XLocalization interface. It should be + // implemented always. But it is parent of the XAddIn and we need it only + // if backwardcompatible is false. + interfaces.insert("com.sun.star.lang.XLocalizable"); + } + } + + + // check if service object or simple UNO object + if (!services.empty()) + serviceobject = true; + + OUString propertyhelper = checkPropertyHelper( + options, manager, services, interfaces, attributes, propinterfaces); + checkDefaultInterfaces(interfaces, services, propertyhelper); + + if (options.componenttype == 2) { + if (!propertyhelper.isEmpty()) + std::cerr << "WARNING: interfaces specifying calc add-in functions " + "shouldn't support attributes!\n"; + } + + supportxcomponent = checkXComponentSupport(manager, interfaces); + + OString compFileName; + OString tmpFileName; + std::ostream* pofs = nullptr; + bool standardout = getOutputStream(options, ".java"_ostr, + &pofs, compFileName, tmpFileName); + + try { + if (!standardout && options.license) { + printLicenseHeader(*pofs); + } + + generatePackage(*pofs, options.implname); + + generateImports(*pofs, options, propertyhelper, + serviceobject, supportxcomponent); + + OString classname(options.implname); + sal_Int32 index = 0; + if ((index = classname.lastIndexOf('.')) > 0) + classname = classname.copy(index+1); + + generateClassDefinition(*pofs, options, manager, classname, services, + interfaces, properties, attributes, propertyhelper, + supportxcomponent); + + if ( !standardout && pofs && static_cast<std::ofstream*>(pofs)->is_open()) { + static_cast<std::ofstream*>(pofs)->close(); + delete pofs; + OSL_VERIFY(makeValidTypeFile(compFileName, tmpFileName, false)); + } + } catch (CannotDumpException & e) { + std::cerr << "ERROR: " << e.getMessage() << "\n"; + if ( !standardout ) { + if (pofs && static_cast<std::ofstream*>(pofs)->is_open()) { + static_cast<std::ofstream*>(pofs)->close(); + delete pofs; + } + // remove existing type file if something goes wrong to ensure + // consistency + if (fileExists(compFileName)) + removeTypeFile(compFileName); + + // remove tmp file if something goes wrong + removeTypeFile(tmpFileName); + } + } +} + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unodevtools/source/skeletonmaker/javatypemaker.cxx b/unodevtools/source/skeletonmaker/javatypemaker.cxx new file mode 100644 index 0000000000..803090ab22 --- /dev/null +++ b/unodevtools/source/skeletonmaker/javatypemaker.cxx @@ -0,0 +1,861 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <algorithm> +#include <cstring> +#include <string_view> + +#include <codemaker/codemaker.hxx> +#include <codemaker/commonjava.hxx> +#include <codemaker/global.hxx> + +#include "skeletoncommon.hxx" +#include "skeletonjava.hxx" + +namespace skeletonmaker::java { + +static void printType( + std::ostream & o, ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + codemaker::UnoType::Sort sort, std::u16string_view nucleus, sal_Int32 rank, + std::vector< OUString > const & arguments, bool referenceType, + bool defaultvalue) +{ + if (defaultvalue && rank == 0 && sort <= codemaker::UnoType::Sort::Char) { + switch (sort) { + case codemaker::UnoType::Sort::Boolean: + o << "false"; + return; + case codemaker::UnoType::Sort::Char: + case codemaker::UnoType::Sort::Byte: + case codemaker::UnoType::Sort::Short: + case codemaker::UnoType::Sort::UnsignedShort: + case codemaker::UnoType::Sort::Long: + case codemaker::UnoType::Sort::UnsignedLong: + case codemaker::UnoType::Sort::Hyper: + case codemaker::UnoType::Sort::UnsignedHyper: + case codemaker::UnoType::Sort::Float: + case codemaker::UnoType::Sort::Double: + o << "0"; + return; + default: + break; + } + } + + if (defaultvalue) { + if (sort == codemaker::UnoType::Sort::Interface) { + o << "null"; + return; + } else if (sort == codemaker::UnoType::Sort::Any && rank == 0) { + o << "com.sun.star.uno.Any.VOID"; + return; + } else if (sort == codemaker::UnoType::Sort::Type && rank == 0) { + o << "com.sun.star.uno.Type.VOID"; + return; + } else if (sort != codemaker::UnoType::Sort::Enum || rank != 0) { + o << "new "; + } + } + + OString sType( + codemaker::java::translateUnoToJavaType( + sort, u2b(nucleus), referenceType && rank == 0)); + if (sType.startsWith("java.lang.")) { + sType = sType.copy(std::strlen("java.lang.")); + } + o << sType; + if (!arguments.empty()) { + o << '<'; + for (std::vector< OUString >::const_iterator i(arguments.begin()); + i != arguments.end(); ++i) + { + if (i != arguments.begin()) { + o << ", "; + } + printType(o, options, manager, *i, true); + } + o << '>'; + } + for (sal_Int32 i = 0; i != rank; ++i) { + if (defaultvalue) + o << "[0]"; + else + o << "[]"; + } + + if (defaultvalue && sort > codemaker::UnoType::Sort::Char && rank == 0) { + if (sort == codemaker::UnoType::Sort::Enum) + o << ".getDefault()"; + else + o << "()"; + } +} + +void printType( + std::ostream & o, ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, std::u16string_view name, + bool referenceType, bool defaultvalue) +{ + OUString nucleus; + sal_Int32 rank; + std::vector< OUString > arguments; + codemaker::UnoType::Sort sort = manager->decompose( + name, true, &nucleus, &rank, &arguments, nullptr); + printType( + o, options, manager, sort, nucleus, rank, arguments, referenceType, + defaultvalue); +} + +static bool printConstructorParameters( + std::ostream & o, ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + codemaker::UnoType::Sort sort, + rtl::Reference< unoidl::Entity > const & entity, std::u16string_view name, + std::vector< OUString > const & arguments) +{ + bool previous = false; + switch (sort) { + case codemaker::UnoType::Sort::PlainStruct: + { + rtl::Reference< unoidl::PlainStructTypeEntity > ent2( + dynamic_cast< unoidl::PlainStructTypeEntity * >(entity.get())); + assert(ent2.is()); + if (!ent2->getDirectBase().isEmpty()) { + rtl::Reference< unoidl::Entity > baseEnt; + codemaker::UnoType::Sort baseSort = manager->getSort( + ent2->getDirectBase(), &baseEnt); + previous = printConstructorParameters( + o, options, manager, baseSort, baseEnt, + ent2->getDirectBase(), std::vector< OUString >()); + } + for (const auto& rMember : ent2->getDirectMembers()) + { + if (previous) { + o << ", "; + } + previous = true; + printType(o, options, manager, rMember.type, false); + o << ' ' + << codemaker::java::translateUnoToJavaIdentifier( + u2b(rMember.name), "param"); + } + break; + } + case codemaker::UnoType::Sort::PolymorphicStructTemplate: + { + rtl::Reference< unoidl::PolymorphicStructTypeTemplateEntity > ent2( + dynamic_cast< unoidl::PolymorphicStructTypeTemplateEntity * >( + entity.get())); + assert(ent2.is()); + for (const auto& rMember : ent2->getMembers()) + { + if (previous) { + o << ", "; + } + previous = true; + if (rMember.parameterized) { + o << rMember.type; + } else { + printType(o, options, manager, rMember.type, false); + } + o << ' ' + << codemaker::java::translateUnoToJavaIdentifier( + u2b(rMember.name), "param"); + } + break; + } + case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct: + { + rtl::Reference< unoidl::PolymorphicStructTypeTemplateEntity > ent2( + dynamic_cast< unoidl::PolymorphicStructTypeTemplateEntity * >( + entity.get())); + assert(ent2.is()); + for (const auto& rMember : ent2->getMembers()) + { + if (previous) { + o << ", "; + } + previous = true; + if (rMember.parameterized) { + auto j = std::find(ent2->getTypeParameters().begin(), + ent2->getTypeParameters().end(), rMember.type); + if (j != ent2->getTypeParameters().end()) { + o << arguments[j - ent2->getTypeParameters().begin()]; + } + } else { + printType(o, options, manager, rMember.type, false); + } + o << ' ' + << codemaker::java::translateUnoToJavaIdentifier( + u2b(rMember.name), "param"); + } + break; + } + case codemaker::UnoType::Sort::Exception: + { + rtl::Reference< unoidl::ExceptionTypeEntity > ent2( + dynamic_cast< unoidl::ExceptionTypeEntity * >(entity.get())); + assert(ent2.is()); + if (!ent2->getDirectBase().isEmpty()) { + rtl::Reference< unoidl::Entity > baseEnt; + codemaker::UnoType::Sort baseSort = manager->getSort( + ent2->getDirectBase(), &baseEnt); + previous = printConstructorParameters( + o, options, manager, baseSort, baseEnt, + ent2->getDirectBase(), std::vector< OUString >()); + } + for (const auto& rMember : ent2->getDirectMembers()) + { + if (previous) { + o << ", "; + } + previous = true; + printType(o, options, manager, rMember.type, false); + o << ' ' + << codemaker::java::translateUnoToJavaIdentifier( + u2b(rMember.name), "param"); + } + break; + } + default: + throw CannotDumpException( + OUString::Concat("unexpected entity \"") + name + + "\" in call to skeletonmaker::cpp::printConstructorParameters"); + } + return previous; +} + +static void printConstructor( + std::ostream & o, ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + codemaker::UnoType::Sort sort, + rtl::Reference< unoidl::Entity > const & entity, std::u16string_view name, + std::vector< OUString > const & arguments) +{ + o << "public " << OUString(name.substr(name.rfind('.') + 1)) << '('; + printConstructorParameters( + o, options, manager, sort, entity, name, arguments); + o << ");\n"; +} + +static void printMethodParameters( + std::ostream & o, ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + std::vector< unoidl::InterfaceTypeEntity::Method::Parameter > const & + parameters, + bool withType) +{ + for (std::vector< unoidl::InterfaceTypeEntity::Method::Parameter >:: + const_iterator i(parameters.begin()); + i != parameters.end(); ++i) + { + if (i != parameters.begin()) { + o << ", "; + } + if (withType) { + printType(o, options, manager, i->type, false); + if (i->direction + != unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN) + { + o << "[]"; + } + o << ' '; + } + o << codemaker::java::translateUnoToJavaIdentifier( + u2b(i->name), "param"); + } +} + +static void printExceptionSpecification( + std::ostream & o, ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + std::vector< OUString > const & exceptions) +{ + if (!exceptions.empty()) { + o << " throws "; + for (std::vector< OUString >::const_iterator i(exceptions.begin()); + i != exceptions.end(); ++i) + { + if (i !=exceptions.begin() ) { + o << ", "; + } + printType(o, options, manager, *i, false); + } + } +} + + +static void printSetPropertyMixinBody( + std::ostream & o, unoidl::InterfaceTypeEntity::Attribute const & attribute, + OString const & indentation) +{ + unoidl::AccumulationBasedServiceEntity::Property::Attributes propFlags + = checkAdditionalPropertyFlags(attribute); + + o << "\n" << indentation << "{\n"; + + if ( attribute.bound ) { + o << indentation << " PropertySetMixin.BoundListeners l = " + "new PropertySetMixin.BoundListeners();\n\n"; + } + + o << indentation << " m_prophlp.prepareSet(\"" + << attribute.name << "\", "; + if ( propFlags & unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_CONSTRAINED ) { + OString fieldtype = codemaker::convertString(attribute.type); + + sal_Int32 index = fieldtype.lastIndexOf('<'); + sal_Int32 nPos=0; + bool single = true; + bool optional = false; + OStringBuffer buffer1(64); + OStringBuffer buffer2(64); + do + { + OString s(fieldtype.getToken(0, '<', nPos)); + OString t{ OString::Concat("((") + s.subView(s.lastIndexOf('/')+1) + ")" }; + + if ( t == "((Optional)" ) { + optional=true; + if (single) { + single=false; + buffer1.append("the_value.IsPresent"); + buffer2.append("the_value.Value"); + } else { + buffer1.insert(0, t); + buffer1.append(").IsPresent"); + buffer2.insert(0, t); + buffer2.append(").Value"); + } + } else { + if ( single ) { + single=false; + if ( !optional ) { + buffer1.append("the_value.Value"); + } + buffer2.append("the_value.Value"); + } else { + if ( !optional ) { + buffer1.insert(0, t); + buffer1.append(").Value"); + } + buffer2.insert(0, t); + buffer2.append(").Value"); + } + } + } while( nPos <= index ); + + o << "Any.VOID,\n" << indentation << " "; + if ( optional ) + o << "("; + o << buffer1.makeStringAndClear(); + if ( optional ) + o << ") ? " << buffer2.makeStringAndClear() << " : Any.VOID,\n" + << indentation << " "; + else + o << ", "; + } + + if ( attribute.bound ) + o << "l"; + else + o << "null"; + o << ");\n"; + + o << indentation << " synchronized (this) {\n" + << indentation << " m_" << attribute.name + << " = the_value;\n" << indentation << " }\n"; + + if ( attribute.bound ) { + o << indentation << " l.notifyListeners();\n"; + } + o << indentation << "}\n\n"; +} + +void printMethods(std::ostream & o, + ProgramOptions const & options, rtl::Reference< TypeManager > const & manager, + OUString const & name, + codemaker::GeneratedTypeSet & generated, + OString const & delegate, OString const & indentation, + bool defaultvalue, bool usepropertymixin) +{ + if ( generated.contains(u2b(name)) || name == "com.sun.star.uno.XInterface" || + ( defaultvalue && + ( name == "com.sun.star.lang.XComponent" || + name == "com.sun.star.lang.XTypeProvider" || + name == "com.sun.star.uno.XWeak" ) ) ) { + return; + } + + if ( usepropertymixin ) { + if (name == "com.sun.star.beans.XPropertySet") { + generated.add(u2b(name)); + generateXPropertySetBodies(o); + return; + } else if (name == "com.sun.star.beans.XFastPropertySet") { + generated.add(u2b(name)); + generateXFastPropertySetBodies(o); + return; + } else if (name == "com.sun.star.beans.XPropertyAccess") { + generated.add(u2b(name)); + generateXPropertyAccessBodies(o); + return; + } + } + + static OString sd("_"_ostr); + bool body = !delegate.isEmpty(); + bool defaultbody = delegate == sd; + + generated.add(u2b(name)); + rtl::Reference< unoidl::Entity > ent; + if (manager->getSort(name, &ent) != codemaker::UnoType::Sort::Interface) + { + throw CannotDumpException( + "unexpected entity \"" + name + + "\" in call to skeletonmaker::java::printMethods"); + } + rtl::Reference< unoidl::InterfaceTypeEntity > ent2( + dynamic_cast< unoidl::InterfaceTypeEntity * >(ent.get())); + assert(ent2.is()); + if ( options.all || defaultvalue ) { + for (const auto& rBase : ent2->getDirectMandatoryBases()) + { + printMethods( + o, options, manager, rBase.name, generated, delegate, indentation, + defaultvalue, usepropertymixin); + } + if (!(ent2->getDirectAttributes().empty() + && ent2->getDirectMethods().empty())) + { + o << indentation << "// "; + printType(o, options, manager, name, false); + o << ":\n"; + } + } + for (const auto& rAttr : ent2->getDirectAttributes()) + { + o << indentation << "public "; + printType(o, options, manager, rAttr.type, false); + o << " get" << rAttr.name << "()"; + printExceptionSpecification(o, options, manager, rAttr.getExceptions); + if ( body ) { + if ( defaultbody ) { + if ( usepropertymixin ) { + o << "\n" << indentation << "{\n" << indentation + << " return m_" << rAttr.name << ";\n" << indentation + << "}\n\n"; + } else { + o << "\n" << indentation << "{\n" << indentation + << " return "; + printType(o, options, manager, rAttr.type, false, true); + o << ";\n" << indentation << "}\n\n"; + } + } else { + o << "\n" << indentation << "{\n" << indentation + << " return " << delegate << "get" << rAttr.name + << "();\n" << indentation << "}\n\n"; + } + } else { + o << ";\n"; + } + + // REMOVE next line + if (!rAttr.readOnly) { + o << indentation << "public void set" << rAttr.name << '('; + printType(o, options, manager, rAttr.type, false); + o << " the_value)"; + printExceptionSpecification(o, options, manager, rAttr.setExceptions); + if ( body ) { + if ( defaultbody ) { + if ( usepropertymixin ) { + printSetPropertyMixinBody(o, rAttr, indentation); + } else { + o << "\n" << indentation << "{\n\n" << indentation + << "}\n\n"; + } + } else { + o << "\n" << indentation << "{\n" << indentation + << " " << delegate << "set" << rAttr.name + << "(the_value);\n" << indentation << "}\n\n"; + } + } else { + o << ";\n"; + } + } + } + for (const auto& rMethod : ent2->getDirectMethods()) + { + o << indentation << "public "; + printType(o, options, manager, rMethod.returnType, false); + o << ' ' << rMethod.name << '('; + printMethodParameters(o, options, manager, rMethod.parameters, true); + o << ')'; + printExceptionSpecification(o, options, manager, rMethod.exceptions); + if ( body ) { + if ( defaultbody ) { + o << "\n" << indentation << "{\n"; + if (rMethod.returnType != "void") { + o << indentation << " // TODO: Exchange the default return implementation for \"" << rMethod.name << "\" !!!\n"; + o << indentation << " // NOTE: " + "Default initialized polymorphic structs can cause problems" + "\n" << indentation << " // because of missing default " + "initialization of primitive types of\n" << indentation + << " // some C++ compilers or different Any initialization" + " in Java and C++\n" << indentation + << " // polymorphic structs.\n" << indentation + << " return "; + printType(o, options, manager, rMethod.returnType, false, true); + o << ";"; + } else { + o << indentation << " // TODO: Insert your implementation for \"" + << rMethod.name << "\" here."; + } + o << "\n" << indentation << "}\n\n"; + } else { + o << "\n" << indentation << "{\n" << indentation << " "; + if (rMethod.returnType != "void") { + o << "return "; + } + o << delegate << rMethod.name << '('; + printMethodParameters( + o, options, manager, rMethod.parameters, false); + o << ");\n" << indentation << "}\n\n"; + } + } else { + o << ";\n"; + } + } +} + +static void printConstructors( + std::ostream & o, ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, OUString const & name) +{ + rtl::Reference< unoidl::Entity > ent; + if (manager->getSort(name, &ent) + != codemaker::UnoType::Sort::SingleInterfaceBasedService) + { + throw CannotDumpException( + "unexpected entity \"" + name + + "\" in call to skeletonmaker::java::printConstructors"); + } + rtl::Reference< unoidl::SingleInterfaceBasedServiceEntity > ent2( + dynamic_cast< unoidl::SingleInterfaceBasedServiceEntity * >(ent.get())); + assert(ent2.is()); + for (const auto& rConstructor : ent2->getConstructors()) + { + o << "public static "; + printType(o, options, manager, ent2->getBase(), false); + o << ' '; + if (rConstructor.defaultConstructor) { + o << "create"; + } else { + o << codemaker::java::translateUnoToJavaIdentifier( + u2b(rConstructor.name), "method"); + } + o << "(com.sun.star.uno.XComponentContext the_context"; + for (const auto& rParam : rConstructor.parameters) + { + o << ", "; + printType(o, options, manager, rParam.type, false); + if (rParam.rest) { + o << "..."; + } + o << ' ' + << codemaker::java::translateUnoToJavaIdentifier( + u2b(rParam.name), "param"); + } + o << ')'; + printExceptionSpecification(o, options, manager, rConstructor.exceptions); + o << ";\n"; + } +} + +static void printServiceMembers( + std::ostream & o, ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + OUString const & name, + rtl::Reference< unoidl::AccumulationBasedServiceEntity > const & entity, + OString const & delegate) +{ + assert(entity.is()); + for (const auto& rService : entity->getDirectMandatoryBaseServices()) + { + o << "\n// exported service " << rService.name << "\n"; + generateDocumentation(o, options, manager, u2b(rService.name), delegate); + } + for (const auto& rIface : entity->getDirectMandatoryBaseInterfaces()) + { + o << "\n// supported interface " << rIface.name << "\n"; + generateDocumentation(o, options, manager, u2b(rIface.name), delegate); + } + o << "\n// properties of service \""<< name << "\"\n"; + for (const auto& rProp : entity->getDirectProperties()) + { + o << "// private "; + printType(o, options, manager, rProp.type, false); + o << " " + << codemaker::java::translateUnoToJavaIdentifier( + u2b(rProp.name), "property") + << ";\n"; + } +} + +static void printMapsToJavaType( + std::ostream & o, ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + codemaker::UnoType::Sort sort, std::u16string_view nucleus, sal_Int32 rank, + std::vector< OUString > const & arguments, const char * javaTypeSort) +{ + o << "maps to Java 1.5 "; + if (javaTypeSort != nullptr) { + o << javaTypeSort << ' '; + } + o << "type \""; + if (rank == 0 && nucleus == u"com.sun.star.uno.XInterface") { + o << "com.sun.star.uno.XInterface"; + } else { + printType( + o, options, manager, sort, nucleus, rank, arguments, false, false); + } + o << '"'; +} + +void generateDocumentation(std::ostream & o, + ProgramOptions const & options, rtl::Reference< TypeManager > const & manager, + OString const & type, OString const & delegate) +{ + OUString nucleus; + sal_Int32 rank; + codemaker::UnoType::Sort sort = manager->decompose( + b2u(type), false, &nucleus, &rank, nullptr, nullptr); + + bool comment = true; + if (!delegate.isEmpty()) { + if (sort != codemaker::UnoType::Sort::Interface && + sort != codemaker::UnoType::Sort::SingleInterfaceBasedService && + sort != codemaker::UnoType::Sort::AccumulationBasedService ) + { + return; + } + comment = false; + } + + if (comment) { + o << "\n// UNO"; + if (rank != 0) { + o << " sequence type"; + } else if (sort <= codemaker::UnoType::Sort::Any) { + o << " simple type"; + } else { + switch (sort) { + case codemaker::UnoType::Sort::Interface: + o << " interface type"; + break; + + case codemaker::UnoType::Sort::Module: + o << "IDL module"; + break; + + case codemaker::UnoType::Sort::PlainStruct: + o << " simple struct type"; + break; + + case codemaker::UnoType::Sort::PolymorphicStructTemplate: + o << " polymorphic struct type template"; + break; + + case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct: + o << " instantiated polymorphic struct type"; + break; + + case codemaker::UnoType::Sort::Enum: + o << " enum type"; + break; + + case codemaker::UnoType::Sort::Exception: + o << " exception type"; + break; + + case codemaker::UnoType::Sort::Typedef: + o << "IDL typedef"; + break; + + case codemaker::UnoType::Sort::SingleInterfaceBasedService: + o << " single-inheritance--based service"; + break; + + case codemaker::UnoType::Sort::AccumulationBasedService: + o << "IDL accumulation-based service"; + break; + + case codemaker::UnoType::Sort::InterfaceBasedSingleton: + o << " inheritance-based singleton"; + break; + + case codemaker::UnoType::Sort::ServiceBasedSingleton: + o << "IDL service-based singleton"; + break; + + case codemaker::UnoType::Sort::ConstantGroup: + o << "IDL constant group"; + break; + + default: + OSL_ASSERT(false); + break; + } + } + o << " \"" << type << "\" "; + } + std::vector< OUString > arguments; + rtl::Reference< unoidl::Entity > entity; + sort = manager->decompose( + b2u(type), true, &nucleus, &rank, &arguments, &entity); + if (rank != 0) { + printMapsToJavaType( + o, options, manager, sort, nucleus, rank, arguments, "array"); + o << '\n'; + } else if (sort <= codemaker::UnoType::Sort::Any) { + printMapsToJavaType( + o, options, manager, sort, nucleus, rank, arguments, nullptr); + o << '\n'; + } else { + switch (sort) { + case codemaker::UnoType::Sort::Interface: + printMapsToJavaType( + o, options, manager, sort, nucleus, rank, arguments, + "interface"); + if (nucleus == "com.sun.star.uno.XInterface") { + o << '\n'; + } else { + o << "; " << (options.all ? "all" : "direct") << " methods:\n"; + codemaker::GeneratedTypeSet generated; + printMethods( + o, options, manager, nucleus, generated, delegate, ""_ostr); + } + break; + + case codemaker::UnoType::Sort::Module: + printMapsToJavaType( + o, options, manager, sort, nucleus, rank, arguments, "package"); + o << '\n'; + break; + + case codemaker::UnoType::Sort::PlainStruct: + printMapsToJavaType( + o, options, manager, sort, nucleus, rank, arguments, "class"); + o << "; full constructor:\n"; + printConstructor( + o, options, manager, codemaker::UnoType::Sort::PlainStruct, + entity, nucleus, arguments); + break; + + case codemaker::UnoType::Sort::PolymorphicStructTemplate: + printMapsToJavaType( + o, options, manager, sort, nucleus, rank, arguments, + "generic class"); + o << "; full constructor:\n"; + printConstructor( + o, options, manager, + codemaker::UnoType::Sort::PolymorphicStructTemplate, + entity, nucleus, arguments); + break; + + case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct: + printMapsToJavaType( + o, options, manager, sort, nucleus, rank, arguments, + "generic class instantiation"); + o << "; full constructor:\n"; + printConstructor( + o, options, manager, + codemaker::UnoType::Sort::InstantiatedPolymorphicStruct, + entity, nucleus, arguments); + break; + + case codemaker::UnoType::Sort::Enum: + case codemaker::UnoType::Sort::ConstantGroup: + printMapsToJavaType( + o, options, manager, sort, nucleus, rank, arguments, "class"); + o << '\n'; + break; + + case codemaker::UnoType::Sort::Exception: + printMapsToJavaType( + o, options, manager, sort, nucleus, rank, arguments, + "exception class"); + o << "; full constructor:\n"; + printConstructor( + o, options, manager, codemaker::UnoType::Sort::Exception, + entity, nucleus, arguments); + break; + + case codemaker::UnoType::Sort::SingleInterfaceBasedService: + printMapsToJavaType( + o, options, manager, sort, nucleus, rank, arguments, "class"); + o << "; construction methods:\n"; + printConstructors(o, options, manager, nucleus); + generateDocumentation( + o, options, manager, + u2b(dynamic_cast< unoidl::SingleInterfaceBasedServiceEntity & >( + *entity).getBase()), + delegate); + break; + + case codemaker::UnoType::Sort::AccumulationBasedService: + o << ("does not map to Java\n" + "// the service members are generated instead\n"); + printServiceMembers( + o, options, manager, nucleus, + dynamic_cast< unoidl::AccumulationBasedServiceEntity * >( + entity.get()), + delegate); + break; + + case codemaker::UnoType::Sort::InterfaceBasedSingleton: + printMapsToJavaType( + o, options, manager, sort, nucleus, rank, arguments, "class"); + o << "; get method:\npublic static "; + printType( + o, options, manager, + dynamic_cast< unoidl::InterfaceBasedSingletonEntity & >( + *entity).getBase(), + false); + o << " get(com.sun.star.uno.XComponentContext context);\n"; + break; + + case codemaker::UnoType::Sort::ServiceBasedSingleton: + o << "does not map to Java\n"; + break; + + default: + OSL_ASSERT(false); + break; + } + } +} + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unodevtools/source/skeletonmaker/skeletoncommon.cxx b/unodevtools/source/skeletonmaker/skeletoncommon.cxx new file mode 100644 index 0000000000..664bc90888 --- /dev/null +++ b/unodevtools/source/skeletonmaker/skeletoncommon.cxx @@ -0,0 +1,589 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <codemaker/commoncpp.hxx> +#include <codemaker/generatedtypeset.hxx> +#include <codemaker/global.hxx> +#include <unoidl/unoidl.hxx> + +#include "skeletoncommon.hxx" + +#include <algorithm> +#include <cassert> +#include <iostream> +#include <string_view> + +using namespace ::codemaker::cpp; + +namespace skeletonmaker { + +void printLicenseHeader(std::ostream& o) +{ + o << "/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */\n" + "/*\n" + " * This file is part of the LibreOffice project.\n" + " *\n" + " * This Source Code Form is subject to the terms of the Mozilla Public\n" + " * License, v. 2.0. If a copy of the MPL was not distributed with this\n" + " * file, You can obtain one at http://mozilla.org/MPL/2.0/.\n" + " */\n\n"; +} + +bool getOutputStream(ProgramOptions const & options, + OString const & extension, + std::ostream** ppOutputStream, + OString & targetSourceFileName, + OString & tmpSourceFileName) +{ + bool bStandardout = false; + if ( options.outputpath == "stdout" ) + { + bStandardout = true; + *ppOutputStream = &std::cout; + return bStandardout; + } + + targetSourceFileName = createFileNameFromType( + options.outputpath, options.implname.replace('.','/'), extension); + + OString tmpDir = getTempDir(targetSourceFileName); + FileStream file; + file.createTempFile(tmpDir); + + if( !file.isValid() ) + { + throw CannotDumpException( + "cannot open " + b2u(targetSourceFileName) + " for writing"); + } + tmpSourceFileName = file.getName(); + file.close(); + *ppOutputStream = new std::ofstream(tmpSourceFileName.getStr(), + std::ios_base::binary); + + return bStandardout; +} + +static bool containsAttribute(AttributeInfo& attributes, OUString const & attrname) +{ + return std::any_of(attributes.begin(), attributes.end(), + [&attrname](const unoidl::AccumulationBasedServiceEntity::Property& rAttr) { + return rAttr.name == attrname; }); +} + +// collect attributes including inherited attributes +static void checkAttributes(rtl::Reference< TypeManager > const & manager, + OUString const & name, + AttributeInfo& attributes, + std::set< OUString >& propinterfaces) +{ + if ( name == "com.sun.star.beans.XPropertySet" || + name == "com.sun.star.beans.XFastPropertySet" || + name == "com.sun.star.beans.XPropertyAccess" ) + { + propinterfaces.insert(name); + } + rtl::Reference< unoidl::Entity > ent; + switch (manager->getSort(name, &ent)) { + case codemaker::UnoType::Sort::Interface: + { + rtl::Reference< unoidl::InterfaceTypeEntity > ent2( + dynamic_cast< unoidl::InterfaceTypeEntity * >(ent.get())); + assert(ent2.is()); + for (const auto& rBase : ent2->getDirectMandatoryBases()) + { + checkAttributes(manager, rBase.name, attributes, propinterfaces); + } + for (const auto& rAttr : ent2->getDirectAttributes()) + { + if (!containsAttribute(attributes, rAttr.name)) { + attributes.emplace_back( + rAttr.name, rAttr.type, + (unoidl::AccumulationBasedServiceEntity::Property:: + Attributes( + ((rAttr.bound + ? unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_BOUND + : 0) + | (rAttr.readOnly + ? unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_READ_ONLY + : 0)))), + std::vector< OUString >()); + } + } + break; + } + case codemaker::UnoType::Sort::AccumulationBasedService: + { + rtl::Reference< unoidl::AccumulationBasedServiceEntity > ent2( + dynamic_cast< unoidl::AccumulationBasedServiceEntity * >( + ent.get())); + assert(ent2.is()); + for (const auto& rService : ent2->getDirectMandatoryBaseServices()) + { + checkAttributes(manager, rService.name, attributes, propinterfaces); + } + for (const auto& rIface : ent2->getDirectMandatoryBaseInterfaces()) + { + checkAttributes(manager, rIface.name, attributes, propinterfaces); + } + for (const auto& rProp : ent2->getDirectProperties()) + { + if (!containsAttribute(attributes, rProp.name)) { + attributes.push_back(rProp); + } + } + break; + } + default: + throw CannotDumpException( + "unexpected entity \"" + name + + "\" in call to skeletonmaker::checkAttributes"); + } +} + +void checkType(rtl::Reference< TypeManager > const & manager, + OUString const & name, + std::set< OUString >& interfaceTypes, + std::set< OUString >& serviceTypes, + AttributeInfo& properties) +{ + rtl::Reference< unoidl::Entity > ent; + switch (manager->getSort(name, &ent)) { + case codemaker::UnoType::Sort::Interface: + // com.sun.star.lang.XComponent should be also not in the list + // but it will be used for checking the impl helper and will be + // removed later if necessary. + if ( name == "com.sun.star.lang.XTypeProvider" || + name == "com.sun.star.uno.XWeak" ) + return; + interfaceTypes.insert(name); + break; + case codemaker::UnoType::Sort::SingleInterfaceBasedService: + if (serviceTypes.insert(name).second) { + rtl::Reference< unoidl::SingleInterfaceBasedServiceEntity > ent2( + dynamic_cast< unoidl::SingleInterfaceBasedServiceEntity * >( + ent.get())); + assert(ent2.is()); + if (interfaceTypes.insert(ent2->getBase()).second) { + // check if constructors are specified, if yes automatically + // support of XInitialization. We will take care of the default + // constructor because in this case XInitialization is not + // called. + if (ent2->getConstructors().size() > 1 || + (ent2->getConstructors().size() == 1 && + !ent2->getConstructors()[0].defaultConstructor)) + { + interfaceTypes.insert(OUString("com.sun.star.lang.XInitialization")); + } + } + } + break; + case codemaker::UnoType::Sort::AccumulationBasedService: + if ( serviceTypes.insert(name).second ) { + rtl::Reference< unoidl::AccumulationBasedServiceEntity > ent2( + dynamic_cast< unoidl::AccumulationBasedServiceEntity * >( + ent.get())); + assert(ent2.is()); + for (const auto& rService : ent2->getDirectMandatoryBaseServices()) + { + checkType( + manager, rService.name, interfaceTypes, serviceTypes, properties); + } + for (const auto& rIface : ent2->getDirectMandatoryBaseInterfaces()) + { + checkType( + manager, rIface.name, interfaceTypes, serviceTypes, properties); + } + for (const auto& rProp : ent2->getDirectProperties()) + { + properties.push_back(rProp); + } + } + break; + default: + throw CannotDumpException( + "unexpected entity \"" + name + + "\" in call to skeletonmaker::checkType"); + } +} + +void checkDefaultInterfaces( + std::set< OUString >& interfaces, + const std::set< OUString >& services, + std::u16string_view propertyhelper) +{ + if ( services.empty() ) { + interfaces.erase("com.sun.star.lang.XServiceInfo"); + } else { + interfaces.insert("com.sun.star.lang.XServiceInfo"); + } + + if ( propertyhelper == u"_" ) { + interfaces.erase("com.sun.star.beans.XPropertySet"); + interfaces.erase("com.sun.star.beans.XFastPropertySet"); + interfaces.erase("com.sun.star.beans.XPropertyAccess"); + } +} + +static bool checkServiceProperties(rtl::Reference< TypeManager > const & manager, + OUString const & name) +{ + rtl::Reference< unoidl::Entity > ent; + if (manager->getSort(name, &ent) + == codemaker::UnoType::Sort::AccumulationBasedService) + { + rtl::Reference< unoidl::AccumulationBasedServiceEntity > ent2( + dynamic_cast< unoidl::AccumulationBasedServiceEntity * >( + ent.get())); + assert(ent2.is()); + if (!ent2->getDirectProperties().empty()) { + return true; + } + return std::any_of(ent2->getDirectMandatoryBaseServices().begin(), + ent2->getDirectMandatoryBaseServices().end(), + [&manager](const unoidl::AnnotatedReference& rService) { + return checkServiceProperties(manager, rService.name); }); + } + return false; +} + + +OUString checkPropertyHelper( + ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + const std::set< OUString >& services, + const std::set< OUString >& interfaces, + AttributeInfo& attributes, + std::set< OUString >& propinterfaces) +{ + std::set< OUString >::const_iterator iter; + std::set< OUString >::const_iterator end; + + if ( !services.empty() ) { + iter = services.begin(); + end = services.end(); + } else { + iter = interfaces.begin(); + end = interfaces.end(); + } + + bool oldStyleWithProperties = false; + while ( iter != end ) { + rtl::Reference< unoidl::Entity > ent; + codemaker::UnoType::Sort sort = manager->getSort(*iter, &ent); + if ( !services.empty() ) { + if (options.supportpropertysetmixin + && (sort + == codemaker::UnoType::Sort::SingleInterfaceBasedService)) + { + rtl::Reference< unoidl::SingleInterfaceBasedServiceEntity > + ent2( + dynamic_cast< + unoidl::SingleInterfaceBasedServiceEntity * >( + ent.get())); + assert(ent2.is()); + checkAttributes( + manager, ent2->getBase(), attributes, propinterfaces); + if (!(attributes.empty() || propinterfaces.empty())) { + return ent2->getBase(); + } + } else { + oldStyleWithProperties = checkServiceProperties(manager, *iter); + } + } else { + checkAttributes(manager, *iter, attributes, propinterfaces); + if (!(attributes.empty() || propinterfaces.empty())) { + return *iter; + } + } + ++iter; + } + + return oldStyleWithProperties ? OUString("_") : OUString(); +} + +static bool checkXComponentSupport( + rtl::Reference< TypeManager > const & manager, OUString const & name) +{ + assert(manager.is()); + if (name == "com.sun.star.lang.XComponent") { + return true; + } + rtl::Reference< unoidl::Entity > ent; + codemaker::UnoType::Sort sort = manager->getSort(name, &ent); + if (sort != codemaker::UnoType::Sort::Interface) { + throw CannotDumpException( + "unexpected entity \"" + name + + "\" in call to skeletonmaker::checkXComponentSupport"); + } + rtl::Reference< unoidl::InterfaceTypeEntity > ent2( + dynamic_cast< unoidl::InterfaceTypeEntity * >(ent.get())); + assert(ent2.is()); + return std::any_of(ent2->getDirectMandatoryBases().begin(), ent2->getDirectMandatoryBases().end(), + [&manager](const unoidl::AnnotatedReference& rBase) { return checkXComponentSupport(manager, rBase.name); }); +} + + +// if XComponent is directly specified, return true and remove it from the +// supported interfaces list +bool checkXComponentSupport(rtl::Reference< TypeManager > const & manager, + std::set< OUString >& interfaces) +{ + if ( interfaces.empty() ) + return false; + + for ( const auto& rIface : interfaces ) { + if ( rIface == "com.sun.star.lang.XComponent" ) { + interfaces.erase("com.sun.star.lang.XComponent"); + return true; + } + if ( checkXComponentSupport(manager, rIface) ) + return true; + } + + return false; +} + +unoidl::AccumulationBasedServiceEntity::Property::Attributes +checkAdditionalPropertyFlags( + unoidl::InterfaceTypeEntity::Attribute const & attribute) +{ + int flags = 0; + bool getterSupportsUnknown = false; + for (const auto& rException : attribute.getExceptions) + { + if (rException == "com.sun.star.beans.UnknownPropertyException") { + getterSupportsUnknown = true; + } + } + for (const auto& rException : attribute.setExceptions) + { + if (rException == "com.sun.star.beans.PropertyVetoException") { + flags |= unoidl::AccumulationBasedServiceEntity::Property:: + ATTRIBUTE_CONSTRAINED; + } else if (getterSupportsUnknown + && rException == "com.sun.star.beans.UnknownPropertyException") + { + flags |= unoidl::AccumulationBasedServiceEntity::Property:: + ATTRIBUTE_OPTIONAL; + } + } + return unoidl::AccumulationBasedServiceEntity::Property::Attributes(flags); +} + +// This function checks if the specified types for parameters and return +// types are allowed add-in types, for more info see the com.sun.star.sheet.AddIn +// service description +static bool checkAddinType(rtl::Reference< TypeManager > const & manager, + std::u16string_view type, bool & bLastAny, + bool & bHasXPropertySet, bool bIsReturn) +{ + assert(manager.is()); + sal_Int32 rank; + codemaker::UnoType::Sort sort = manager->decompose( + type, true, nullptr, &rank, nullptr, nullptr); + + if ( sort == codemaker::UnoType::Sort::Long || + sort == codemaker::UnoType::Sort::Double || + sort == codemaker::UnoType::Sort::String ) + { + if ( rank == 0 || rank ==2 ) + return true; + } + if ( sort == codemaker::UnoType::Sort::Any ) + { + if ( rank <= 2 ) { + if ( rank ==1 ) { + if ( bIsReturn ) + return false; + bLastAny = true; + } + + return true; + } + } + if ( sort == codemaker::UnoType::Sort::Interface ) + { + if ( bIsReturn && type == u"com.sun.star.sheet.XVolatileResult" ) + return true; + if ( !bIsReturn && type == u"com.sun.star.table.XCellRange" ) + return true; + if ( !bIsReturn && type == u"com.sun.star.beans.XPropertySet" ) + { + if ( bHasXPropertySet ) { + return false; + } else { + bHasXPropertySet = true; + return true; + } + } + } + return false; +} + +static void checkAddInTypes( + rtl::Reference< TypeManager > const & manager, std::u16string_view name, + rtl::Reference< unoidl::InterfaceTypeEntity > const & entity) +{ + assert(entity.is()); + bool bLastAny = false; + bool bHasXPropertySet = false; + for (const auto& rMethod : entity->getDirectMethods()) + { + if ( !checkAddinType( + manager, rMethod.returnType, bLastAny, bHasXPropertySet, true) ) + { + throw CannotDumpException( + OUString::Concat("the return type of the calc add-in function '") + name + + ":" + rMethod.name + + "' is invalid. Please check your IDL definition."); + } + + bHasXPropertySet = false; + for (const auto& rParam : rMethod.parameters) + { + bLastAny = false; + if ( !checkAddinType(manager, rParam.type, + bLastAny, bHasXPropertySet, false) || + bLastAny ) + { + throw CannotDumpException( + "the type of the " + rParam.name + + " parameter of the calc add-in function '" + name + + ":" + rMethod.name + "' is invalid." + + (bLastAny + ? OUString( + " The type 'sequence<any>' is allowed as last" + " parameter only.") + : OUString()) + + (bHasXPropertySet + ? OUString( + " The type 'XPropertySet' is allowed only once.") + : OUString()) + + " Please check your IDL definition."); + } + } + } +} + +static void generateFunctionParameterMap(std::ostream& o, + ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + OUString const & name, + ::codemaker::GeneratedTypeSet & generated, + bool& bFirst) +{ + if ( name == "com.sun.star.uno.XInterface" || + name == "com.sun.star.lang.XLocalizable" || + name == "com.sun.star.lang.XServiceInfo" || + // the next three checks becomes obsolete when configuration is used + name == "com.sun.star.sheet.XAddIn" || + name == "com.sun.star.sheet.XCompatibilityNames" || + name == "com.sun.star.lang.XServiceName" ) + { + return; + } + + rtl::Reference< unoidl::Entity > ent; + codemaker::UnoType::Sort sort = manager->getSort(name, &ent); + if (sort != codemaker::UnoType::Sort::Interface) { + throw CannotDumpException( + "unexpected entity \"" + name + + "\" in call to skeletonmaker::generateFunctionParameterMap"); + } + rtl::Reference< unoidl::InterfaceTypeEntity > ent2( + dynamic_cast< unoidl::InterfaceTypeEntity * >(ent.get())); + assert(ent2.is()); + + // check if the specified add-in functions supports valid types + checkAddInTypes(manager, name, ent2); + + for (const auto& rBase : ent2->getDirectMandatoryBases()) + { + generateFunctionParameterMap( + o, options, manager, rBase.name, generated, bFirst); + } + + if ( generated.contains(u2b(name)) ) + return; + else + generated.add(u2b(name)); + + for (const auto& rMethod : ent2->getDirectMethods()) + { + if ( bFirst ) { + if (options.language == 2) { + o << " ParamMap fpm;\n"; + } + else { + o << " java.util.Hashtable< Integer, String > fpm = " + "new java.util.Hashtable< Integer, String >();\n"; + } + bFirst = false; + } else + if ( options.language == 2 ) { + o << " fpm = ParamMap();\n"; + } + else { + o << " fpm = new java.util.Hashtable< " + "Integer, String >();\n"; + } + + std::vector< unoidl::InterfaceTypeEntity::Method::Parameter >::size_type + n = 0; + for (const auto& rParam : rMethod.parameters) + { + if ( options.language == 2 ) { + o << " fpm[" << n + << "] = OUString(\"" + << rParam.name + << "\");\n"; + } + else { + o << " fpm.put(" << n << ", \"" + << rParam.name + << "\");\n"; + } + ++n; + } + + if ( options.language == 2 ) { + o << " m_functionMap[OUString(\"" + << rMethod.name << "\")] = fpm;\n\n"; + } + else { + o << " m_functionMap.put(\"" << rMethod.name << "\", fpm);\n\n"; + } + } +} + +void generateFunctionParameterMap(std::ostream& o, + ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + const std::set< OUString >& interfaces) +{ + ::codemaker::GeneratedTypeSet generated; + bool bFirst = true; + for ( const auto& rIface : interfaces ) { + generateFunctionParameterMap(o, options, manager, rIface, generated, bFirst); + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unodevtools/source/skeletonmaker/skeletoncommon.hxx b/unodevtools/source/skeletonmaker/skeletoncommon.hxx new file mode 100644 index 0000000000..a6ff050696 --- /dev/null +++ b/unodevtools/source/skeletonmaker/skeletoncommon.hxx @@ -0,0 +1,138 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include <sal/config.h> + +#include <rtl/ref.hxx> +#include <rtl/string.hxx> +#include <codemaker/typemanager.hxx> +#include <unoidl/unoidl.hxx> + +#include <fstream> +#include <map> +#include <set> + +namespace skeletonmaker { + +typedef ::std::map< OString, ::std::vector< OString > > ProtocolCmdMap; + +typedef ::std::vector< unoidl::AccumulationBasedServiceEntity::Property > +AttributeInfo; + +struct ProgramOptions { + ProgramOptions(): all(false), dump(false), license(false), + shortnames(false), supportpropertysetmixin(false), + backwardcompatible(false), language(1), componenttype(1) {} + + bool all; + bool dump; + bool license; + bool shortnames; + bool supportpropertysetmixin; + bool backwardcompatible; + // language specifier - is extendable + // 1 = Java + // 2 = C++ + short language; + // component type + // 1 = default UNO component - is extendable + // 2 = calc add-in + // 3 = add-on + short componenttype; + OString outputpath; + OString implname; + ProtocolCmdMap protocolCmdMap; +}; + + +/** + print the standard OpenOffice.org license header + + @param o specifies the output stream + @param filename specifies the source file name +*/ +void printLicenseHeader(std::ostream& o); + +/** + create dependent on the output path, the implementation name and the + extension a new output file. If output path is equal "stdout" the tool + generates the output to standard out. + + @param options the program options including the output path and the + implementation name + @param extension specifies the file extensions (e.g. .cxx or .java) + @param ppOutputStream out parameter returning the output stream + @param targetSourceFileName out parameter returning the generated file name + constructed on base of the output path, the + implementation name and the extension + @param tmpSourceFileName out parameter returning the temporary file name based + on the output path and a generated temporary file name. + @return true if output is generated to standard out or else false +*/ +bool getOutputStream(ProgramOptions const & options, + OString const & extension, + std::ostream** ppOutputStream, + OString & targetSourceFileName, + OString & tmpSourceFileName); + +void checkType(rtl::Reference< TypeManager > const & manager, + OUString const & type, + std::set< OUString >& interfaceTypes, + std::set< OUString >& serviceTypes, + AttributeInfo& properties); + +void checkDefaultInterfaces( + std::set< OUString >& interfaces, + const std::set< OUString >& services, + std::u16string_view propertyhelper); + +OUString checkPropertyHelper( + ProgramOptions const & options, rtl::Reference< TypeManager > const & manager, + const std::set< OUString >& services, + const std::set< OUString >& interfaces, + AttributeInfo& attributes, + std::set< OUString >& propinterfaces); + +/** + checks if XComponent have to be supported, if yes it removes it from the + supported interfaces list because it becomes implemented by the appropriate + helper + + @param manager a type manager + @param interfaces a list of interfaces which should be implemented + + @return true if XComponent have to be supported +*/ +bool checkXComponentSupport(rtl::Reference< TypeManager > const & manager, + std::set< OUString >& interfaces); + + +unoidl::AccumulationBasedServiceEntity::Property::Attributes +checkAdditionalPropertyFlags( + unoidl::InterfaceTypeEntity::Attribute const & attribute); + +void generateFunctionParameterMap(std::ostream& o, + ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + const std::set< OUString >& interfaces); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unodevtools/source/skeletonmaker/skeletoncpp.hxx b/unodevtools/source/skeletonmaker/skeletoncpp.hxx new file mode 100644 index 0000000000..822c92bb34 --- /dev/null +++ b/unodevtools/source/skeletonmaker/skeletoncpp.hxx @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include <fstream> +#include <string_view> + +#include <codemaker/generatedtypeset.hxx> +#include "skeletoncommon.hxx" + +namespace skeletonmaker::cpp { + +// referenceType +// 0 = no reference +// 1 = use of css::uno::Reference for interfaces +// 2 = reference (includes css::uno::Reference for interfaces) +// 4 = const reference (includes css::uno::Reference for interfaces) +// 8 = default construction for example for return types, means "return <type>();" +// 16 = default member initialization in a constructor +void printType( + std::ostream & o, ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, std::u16string_view name, + short referenceType, bool defaultvalue = false); + +void printMethods(std::ostream & o, + ProgramOptions const & options, rtl::Reference< TypeManager > const & manager, + OUString const & name, + codemaker::GeneratedTypeSet & generated, + OString const & delegate, + OString const & classname, + OString const & indentation, + bool defaultvalue=false, + OUString const & propertyhelper=OUString()); + +void generateDocumentation(std::ostream & o, + ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + OString const & type, + OString const & delegate); + + +void generateSkeleton(ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + std::vector< OString > const & types); + +void generateCalcAddin(ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + std::vector< OString > const & types); + +void generateXPropertySetBodies(std::ostream& o, + const OString & classname, + const OString & interfaceName); +void generateXFastPropertySetBodies(std::ostream& o, + const OString & classname, + const OString & interfaceName); +void generateXPropertyAccessBodies(std::ostream& o, + const OString & classname, + const OString & interfaceName); + +void generateXAddInBodies(std::ostream& o, const OString & classname); + +void generateXLocalizable(std::ostream& o, const OString & classname); + +void generateXCompatibilityNamesBodies(std::ostream& o, const OString & classname); + +void generateXInitialization(std::ostream& o, const OString & classname); + +void generateXDispatch(std::ostream& o, + const OString & classname, + const ProtocolCmdMap & protocolCmdMap); + +void generateXDispatchProvider(std::ostream& o, + const OString & classname, + const ProtocolCmdMap & protocolCmdMap); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unodevtools/source/skeletonmaker/skeletonjava.hxx b/unodevtools/source/skeletonmaker/skeletonjava.hxx new file mode 100644 index 0000000000..7ba2b8e2e0 --- /dev/null +++ b/unodevtools/source/skeletonmaker/skeletonjava.hxx @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include <fstream> +#include <string_view> + +#include <codemaker/generatedtypeset.hxx> +#include "skeletoncommon.hxx" + +namespace skeletonmaker::java { + +void printType( + std::ostream & o, ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, std::u16string_view name, + bool referenceType, bool defaultvalue = false); + +void printMethods(std::ostream & o, + ProgramOptions const & options, rtl::Reference< TypeManager > const & manager, + OUString const & name, + codemaker::GeneratedTypeSet & generated, + OString const & delegate, + OString const & indentation, + bool defaultvalue=false, + bool usepropertymixin=false); + +void generateDocumentation(std::ostream & o, + ProgramOptions const & options, + rtl::Reference< TypeManager > const & manager, + OString const & type, + OString const & delegate); + +void generateSkeleton(ProgramOptions const & options, rtl::Reference< TypeManager > const & manager, std::vector< OString > const & types); + +void generateXPropertySetBodies(std::ostream& o); +void generateXFastPropertySetBodies(std::ostream& o); +void generateXPropertyAccessBodies(std::ostream& o); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unodevtools/source/skeletonmaker/skeletonmaker.cxx b/unodevtools/source/skeletonmaker/skeletonmaker.cxx new file mode 100644 index 0000000000..02ff21a5ec --- /dev/null +++ b/unodevtools/source/skeletonmaker/skeletonmaker.cxx @@ -0,0 +1,315 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include <iostream> + +#include <codemaker/global.hxx> +#include <codemaker/typemanager.hxx> +#include <sal/main.h> +#include <rtl/process.h> +#include <options.hxx> +#include <unoidl/unoidl.hxx> + +#include "skeletonjava.hxx" +#include "skeletoncpp.hxx" + +using namespace ::skeletonmaker; +using namespace ::unodevtools; + +namespace { + +const char usageText[] = +"\n sub-commands:\n" +" dump dump declarations on stdout (e.g. constructors, methods, type\n" +" mapping for properties) or complete method bodies with\n" +" method forwarding.\n" +" component generates language specific code skeleton files using the\n" +" implementation name as the file and class name\n" +" calc-add-in generates a language specific code skeleton for a calc add-in\n" +" using the implementation name as the file and class name. A \n" +" service type is necessary, referencing an interface which defines\n" +" the new add-in functions.\n" +" add-on generates a language specific code skeleton for an add-on component\n" +" using the implementation name as the file and class name. The protocol\n" +" name(s) and the corresponding command(s) have to be specified with the\n" +" '-p' option.\n" +"\n options:\n" +" -a, --all list all interface methods, not only the direct\n" +" ones\n" +" --(java5|cpp) select the target language\n" +" --java5 generate output for Java 1.5 or later (is \n" +" currently the default)\n" +" --cpp generate output for C++\n" +" -sn, --shortnames using namespace abbreviation 'css:': for\n" +" '::com::sun::star::', only valid for sub-command\n" +" 'dump' and target language 'cpp'. It is default for the\n" +" sub-command 'component'.\n" +" --propertysetmixin the generated skeleton implements the cppu::PropertySetMixin\n" +" helper if a referenced new style service specifies an\n" +" interface which provides attributes (directly or inherited).\n" +" -lh --licenseheader generates a default LibreOffice MPL license\n" +" header at the beginning of a component source file.\n" +" This option is taken into account in 'component' mode\n" +" only and if -o is unequal 'stdout'.\n" +" -bc specifies that the generated calc add-in is backward\n" +" --backward-compatible compatible to older office versions and implement the\n" +" former required add-in interfaces where the implementation\n" +" is mapped on the new add-in configuration. In this case\n" +" the config schema needs to be bundled with the extension\n" +" add-in as well. Default is a minimal add-in component\n" +" skeleton based on the configuration coming with the\n" +" office since OO.org 2.0.4.\n" +" -o <path> path specifies an existing directory where the\n" +" output files are generated to, only valid for\n" +" sub-command 'component'. If path=stdout the generated\n" +" code is generated on standard out instead of a file.\n" +" -l <file> specifies a binary type library (can be used more\n" +" than once).\n" +" -n <name> specifies an implementation name for the component\n" +" (used as classname, filename and package|namespace\n" +" name). In 'dump' mode it is used as classname (e.g.\n" +" \"MyBase::\", C++ only) to generate method bodies not\n" +" inline.\n" +" -d <name> specifies a base classname or a delegator.\n" +" In 'dump' mode it is used as a delegator to forward\n" +" methods. It can be used as '<name>::' for base\n" +" forwarding, or '<name>->|.' for composition.\n" +" Using \"_\" means that a default bodies with default\n" +" return values are dumped.\n" +" -t <name> specifies a UNOIDL type name, e.g.\n" +" com.sun.star.text.XText (can be used more than once)\n" +" -p <protocol:cmd(s)> specifies an add-on protocol name and the corresponding\n" +" command names, where the commands are a ',' separated list\n" +" of unique commands. This option is only valid for add-ons.\n" +" -V, --version print version number and exit\n" +" -h, --help print this help and exit\n\n"; + +void printUsageAndExit(const char* programname, const char* version) +{ + std::cerr + << "\n using: " << programname << "\n" + " dump [<options>] -t <type> ...\n" + " " << programname << "\n" + " component [<options>] -n <name> -t <type> ...\n" + " " << programname << "\n" + " calc-add-in [<options>] -n <name> -t <add-in_service>\n" + " " << programname << "\n" + " add-on [<options>] -n <name> -p <protocol_name:command,...>\n" + " " << programname << " -V, --version\n" + " " << programname << " -h, --help\n" + << usageText + << programname << " Version " << version << "\n\n"; +} + +} + +SAL_IMPLEMENT_MAIN() +{ + const char* const version = "0.4"; + const char* const programname = "uno-skeletonmaker"; + + sal_uInt32 nCount = rtl_getAppCommandArgCount(); + if ( nCount == 0 ) { + printUsageAndExit(programname, version); + exit(EXIT_FAILURE); + } + + ProgramOptions options; + std::vector< OString > registries; + std::vector< OString > types; + OString delegate; + + try { + + sal_uInt32 nPos = 0; + OUString arg, sOption; + + // check command + rtl_getAppCommandArg(nPos++, &arg.pData); + if ( arg == "dump" ) { + options.dump = true; + } else if ( arg == "component" ) { + options.dump = false; + options.shortnames = true; + } else if ( arg == "calc-add-in" ) { + options.dump = false; + options.shortnames = true; + options.componenttype = 2; + } else if ( arg == "add-on" ) { + options.dump = false; + options.shortnames = true; + options.componenttype = 3; + } else if ( readOption( "h", &nPos, arg) || + readOption( "help", &nPos, arg) ) { + printUsageAndExit(programname, version); + exit(EXIT_SUCCESS); + } else if ( readOption( "V", &nPos, arg) || + readOption( "version", &nPos, arg) ) { + std::cerr << "\n Sun Microsystems (R) " << programname + << " Version " << version << "\n\n"; + exit(EXIT_SUCCESS); + } else { + std::cerr << "ERROR: unexpected command \"" << arg << "\"!\n"; + printUsageAndExit(programname, version); + exit(EXIT_FAILURE); + } + + // read up to arguments + while ( nPos < nCount ) + { + rtl_getAppCommandArg(nPos, &arg.pData); + + if ( readOption( "a", &nPos, arg) || + readOption( "all", &nPos, arg) ) { + options.all = true; + continue; + } + if ( readOption( "java4", &nPos, arg) ) { + std::cerr << + "\nError: Java 1.4 is no longer supported, use --java5 instead\n"; + } + if ( readOption( "java5", &nPos, arg) ) { + options.language = 1; + continue; + } + if ( readOption( "cpp", &nPos, arg) ) { + options.language = 2; + continue; + } + if ( readOption( "sn", &nPos, arg) || + readOption( "shortnames", &nPos, arg) ) { + options.shortnames = true; + continue; + } + if ( readOption( "lh", &nPos, arg) || + readOption( "licenseheader", &nPos, arg) ) { + options.license = true; + continue; + } + if ( readOption( "bc", &nPos, arg) || + readOption( "backward-compatible", &nPos, arg) ) { + options.backwardcompatible = true; + continue; + } + if ( readOption( "propertysetmixin", &nPos, arg) ) { + options.supportpropertysetmixin = true; + continue; + } + if ( readOption( &sOption, "d", &nPos, arg) ) { + delegate = OUStringToOString(sOption, RTL_TEXTENCODING_UTF8); + continue; + } + if ( readOption( &sOption, "n", &nPos, arg) ) { + options.implname = OUStringToOString(sOption, RTL_TEXTENCODING_UTF8); + continue; + } + if ( readOption( &sOption, "o", &nPos, arg) ) { + options.outputpath = OUStringToOString(sOption, RTL_TEXTENCODING_UTF8); + continue; + } + if ( readOption( &sOption, "l", &nPos, arg) ) { + registries.push_back(OUStringToOString(sOption, RTL_TEXTENCODING_UTF8)); + continue; + } + if ( readOption( &sOption, "t", &nPos, arg) ) { + types.push_back(OUStringToOString(sOption, RTL_TEXTENCODING_UTF8)); + continue; + } + if ( readOption( &sOption, "p", &nPos, arg) ) { + OString sTmp(OUStringToOString(sOption, RTL_TEXTENCODING_UTF8)); + sal_Int32 nIndex{ sTmp.indexOf(':')+1 }; + const OString sPrt = sTmp.copy(0, nIndex); + std::vector< OString > vCmds; + while (nIndex>=0) + vCmds.push_back(sTmp.getToken( 0, ',', nIndex )); + options.protocolCmdMap.emplace(sPrt, vCmds); + continue; + } + + + // else illegal argument + throw CannotDumpException("unexpected parameter \"" + arg + "\"!"); + } + + if ( types.empty() && options.componenttype != 3) { + std::cerr + << "\nError: no type is specified, use the -t option at least once\n"; + printUsageAndExit(programname, version); + exit(EXIT_FAILURE); + } + + rtl::Reference< TypeManager > manager(new TypeManager); + for (const auto& rRegistry : registries) + { + manager->loadProvider(convertToFileUrl(rRegistry), true); + } + + if ( options.dump ) { + for (const auto& rType : types) { + std::cout << "\n/***************************************************" + "*****************************/\n"; + switch (options.language ) + { + case 1: //Java + java::generateDocumentation(std::cout, options, manager, + rType, delegate); + break; + case 2: //C++ + cpp::generateDocumentation(std::cout, options, manager, + rType, delegate); + break; + default: + OSL_ASSERT(false); + break; + } + } + } else { + switch ( options.language ) + { + case 1: //Java + java::generateSkeleton(options, manager, types); + break; + case 2: //C++ + cpp::generateSkeleton(options, manager, types); + break; + default: + OSL_ASSERT(false); + break; + } + } + + } catch (CannotDumpException & e) { + std::cerr << "ERROR: " << e.getMessage() << '\n'; + return EXIT_FAILURE; + } catch (unoidl::NoSuchFileException & e) { + std::cerr << "ERROR: No such file <" << e.getUri() << ">\n"; + return EXIT_FAILURE; + } catch (unoidl::FileFormatException & e) { + std::cerr + << "ERROR: Bad format of <" << e.getUri() << ">, \"" + << e.getDetail() << "\"\n"; + return EXIT_FAILURE; + } catch (std::exception & e) { + std::cerr << "ERROR: " << e.what() << "\n"; + return EXIT_FAILURE; + } + + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unodevtools/source/unodevtools/options.cxx b/unodevtools/source/unodevtools/options.cxx new file mode 100644 index 0000000000..523eaac780 --- /dev/null +++ b/unodevtools/source/unodevtools/options.cxx @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <codemaker/global.hxx> +#include <o3tl/safeint.hxx> +#include <o3tl/string_view.hxx> +#include <rtl/ustring.hxx> +#include <rtl/process.h> +#include <sal/log.hxx> +#include <options.hxx> + +namespace unodevtools { + + +bool readOption( OUString * pValue, const char * pOpt, + sal_uInt32 * pnIndex, std::u16string_view aArg) +{ + static constexpr OUString dash = u"-"_ustr; + if(aArg.find(dash) != 0) + return false; + + OUString aOpt = OUString::createFromAscii( pOpt ); + + if (aArg.size() < o3tl::make_unsigned(aOpt.getLength())) + return false; + + if (aOpt.equalsIgnoreAsciiCase( aArg.substr(1) )) { + // take next argument + ++(*pnIndex); + + rtl_getAppCommandArg(*pnIndex, &pValue->pData); + if (*pnIndex >= rtl_getAppCommandArgCount() || + pValue->subView(1) == dash) + { + throw CannotDumpException( + "incomplete option \"-" + aOpt + "\" given!"); + } + SAL_INFO("unodevtools", "identified option -" << pOpt << " = " << *pValue); + ++(*pnIndex); + return true; + } else if (aArg.find(aOpt) == 1) { + *pValue = aArg.substr(1 + aOpt.getLength()); + SAL_INFO("unodevtools", "identified option -" << pOpt << " = " << *pValue); + ++(*pnIndex); + + return true; + } + return false; +} + + +bool readOption( const char * pOpt, + sal_uInt32 * pnIndex, std::u16string_view aArg) +{ + OUString aOpt = OUString::createFromAscii(pOpt); + + if((o3tl::starts_with(aArg, u"-") && aOpt.equalsIgnoreAsciiCase(aArg.substr(1))) || + (o3tl::starts_with(aArg, u"--") && aOpt.equalsIgnoreAsciiCase(aArg.substr(2))) ) + { + ++(*pnIndex); + SAL_INFO("unodevtools", "identified option --" << pOpt); + return true; + } + return false; +} + +} // end of namespace unodevtools + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |