Difference between revisions of "Writing Professional Components"
SergeMoutou (Talk | contribs) m (→My own Inspector) |
SergeMoutou (Talk | contribs) m (→My own Inspector) |
||
Line 5: | Line 5: | ||
I have already presented in this document [[Constructing_Helpers#Reflection_Helper|my own inspector]] but it wasn't a component. Then it was only valuable when writing binary executable, not component. In this section I will show how to transform it as a component. Because [[Object Inspector|Java Inspector]] is more advanced my component is only interesting when using old an inefficient computers. But for me it represents the only experience with writing a great component. | I have already presented in this document [[Constructing_Helpers#Reflection_Helper|my own inspector]] but it wasn't a component. Then it was only valuable when writing binary executable, not component. In this section I will show how to transform it as a component. Because [[Object Inspector|Java Inspector]] is more advanced my component is only interesting when using old an inefficient computers. But for me it represents the only experience with writing a great component. | ||
− | {{Documentation | + | {{Documentation/Caution|The code presented here is not safe. You can see many "FIXME" in the code. At the moment the version is labelled 0.4}} |
This component is composed with two separate class (at the moment) | This component is composed with two separate class (at the moment) | ||
==The ReflectionHelper class== | ==The ReflectionHelper class== | ||
+ | This class is composed with two source files. Be begin with the header : | ||
+ | <source lang="cpp"> | ||
+ | #ifndef REFLECTIONHELPER_H | ||
+ | #define REFLECTIONHELPER_H | ||
+ | #include <rtl/ustring.hxx> | ||
+ | #include <com/sun/star/uno/Sequence.hxx> | ||
+ | #include <com/sun/star/uno/Any.hxx> | ||
+ | #include <com/sun/star/lang/XMultiComponentFactory.hpp> | ||
+ | #include <com/sun/star/beans/XIntrospection.hpp> | ||
+ | #include <com/sun/star/beans/XIntrospectionAccess.hpp> | ||
+ | #include <com/sun/star/lang/XTypeProvider.hpp> | ||
+ | #include <com/sun/star/beans/MethodConcept.hpp> | ||
+ | #include <com/sun/star/reflection/XIdlMethod.hpp> | ||
+ | #include <com/sun/star/uno/Type.hxx> | ||
+ | #include <com/sun/star/beans/Property.hpp> | ||
+ | #include <com/sun/star/lang/XServiceInfo.hpp> | ||
+ | #include <com/sun/star/reflection/ParamMode.hpp> | ||
+ | |||
+ | using rtl::OUString; | ||
+ | using namespace com::sun::star::reflection; | ||
+ | using namespace com::sun::star::beans; | ||
+ | using namespace com::sun::star::lang; | ||
+ | using namespace com::sun::star::uno; | ||
+ | |||
+ | class ReflectionHelper { | ||
+ | public: | ||
+ | ReflectionHelper(Any toInspect,Reference< XMultiComponentFactory > const & oSVM, Reference< XComponentContext > const & xContext); | ||
+ | |||
+ | Sequence < OUString > getMethods(), | ||
+ | getTypes(), | ||
+ | getServices(), | ||
+ | getPropertiesWithoutValues(), | ||
+ | getPropertiesWithValues(); | ||
+ | Sequence< Reference< XIdlMethod > > getIdlMethods(); | ||
+ | Reference< XIdlMethod > getXIdlMethodByName(OUString aName); | ||
+ | void getTypeAndValue(Any toInspect); | ||
+ | sal_Bool m_simpleObject; | ||
+ | OUString m_OUStrAnyTypeAndValue; // for simple object data | ||
+ | // Print out | ||
+ | // void printOut(); //perhaps const ? | ||
+ | |||
+ | private: | ||
+ | Any m_toInspect; | ||
+ | Reference< XMultiComponentFactory > m_xServiceManager; | ||
+ | Reference< XIntrospection >m_xIntrospection; | ||
+ | Reference< XIntrospectionAccess > m_xIntrospec; | ||
+ | Reference< XTypeProvider > m_xTypeProvider; | ||
+ | Reference< XComponentContext > m_xContext; | ||
+ | OUString getValueName(Any object); | ||
+ | OUString getParamMode(ParamMode paramMode); | ||
+ | // methods | ||
+ | Sequence< Reference< XIdlMethod > > mMethods; | ||
+ | // Interfaces | ||
+ | Sequence< Type > types; | ||
+ | // Services | ||
+ | Reference< XServiceInfo > m_xServiceInfo; | ||
+ | // Sequence< OUString > services; | ||
+ | // Properties | ||
+ | Sequence< Property > Properties; | ||
+ | // protected methods | ||
+ | protected: | ||
+ | Sequence< OUString > convert2SeqOUStrInDEBUGMODE(Sequence < sal_Int8 > seqBytes); | ||
+ | // same as "convert2SeqOUStrInDEBUGMODE" but in one OUString | ||
+ | OUString convert2OUStrInDEBUGMODE(Sequence < sal_Int8 > seqBytes); | ||
+ | }; | ||
+ | #endif //REFLECTIONHELPER_H | ||
+ | </source> | ||
+ | And now the corresponding implementation : | ||
+ | <source lang="cpp"> | ||
+ | // C++ | ||
+ | // Serge Moutou | ||
+ | // with help of <OpenOffice1.1_SDK>/examples/java/Inspector | ||
+ | // and Bernard Marcelly XRay tool | ||
+ | // version 0.1 (22 Dec 2004) | ||
+ | // version 0.2 (4 Jun 2005) added printout in a dialog | ||
+ | // version 0.2.1 (4 Apr 2009) added name of parameters in methods | ||
+ | // version 0.3 (23 Apr 2009) added DEBUG MODE for []bytes properties | ||
+ | // version 0.4 (28 Jul 2009) changed to be used with a component: | ||
+ | // ****** constructor uses XMultiComponentFactoty instead of XMultiServiceFactory | ||
+ | // To do : Exception Handling, to go further with properties values | ||
+ | //#include <org/openoffice/cpp/XInstanceIspector.hpp> | ||
+ | #include "./ReflectionHelper.hpp" | ||
+ | #include <com/sun/star/reflection/XIdlClass.hpp> | ||
+ | #include <com/sun/star/beans/PropertyConcept.hpp> | ||
+ | #include <com/sun/star/beans/XPropertySet.hpp> | ||
+ | //#include <com/sun/star/reflection/ParamMode.hpp> done in ReflectionHelper.hpp | ||
+ | #include <com/sun/star/container/XNameContainer.hpp> | ||
+ | //#include <cppuhelper/implbase1.hxx> | ||
+ | #include <com/sun/star/awt/XTextComponent.hpp> | ||
+ | //#include <com/sun/star/awt/XActionListener.hpp> | ||
+ | #include <com/sun/star/awt/XToolkit.hpp> | ||
+ | #include <com/sun/star/awt/XControlContainer.hpp> | ||
+ | //#include <com/sun/star/awt/PushButtonType.hpp> | ||
+ | //#include <com/sun/star/awt/XButton.hpp> | ||
+ | //#include <com/sun/star/awt/XWindow.hpp> | ||
+ | //#include <com/sun/star/awt/XDialog.hpp> | ||
+ | |||
+ | //#include <com/sun/star/lang/XMultiServiceFactory.hpp> | ||
+ | #include <rtl/ustring.hxx> | ||
+ | #include <rtl/string.hxx> | ||
+ | //#define DEBUG | ||
+ | |||
+ | using namespace com::sun::star::awt; | ||
+ | //using namespace com::sun::star::frame; | ||
+ | using namespace com::sun::star::lang; | ||
+ | using namespace com::sun::star::container; | ||
+ | |||
+ | |||
+ | // Inspector constructor | ||
+ | ReflectionHelper::ReflectionHelper(Any toInspect, Reference< XMultiComponentFactory > const & oSVM, | ||
+ | Reference< XComponentContext > const & xContext) | ||
+ | : m_toInspect(toInspect), m_xServiceManager(oSVM), m_xContext(xContext) { | ||
+ | m_xIntrospection = Reference< XIntrospection >( m_xServiceManager->createInstanceWithContext( | ||
+ | OUString::createFromAscii("com.sun.star.beans.Introspection" ),m_xContext), UNO_QUERY_THROW); | ||
+ | getTypeAndValue(m_toInspect); | ||
+ | |||
+ | } | ||
+ | //FIXME:Bad idea to take a method of ReflectionHelper for that ? | ||
+ | //**** modify data member and then doesn't keep coherence in data ? | ||
+ | void ReflectionHelper::getTypeAndValue(Any toInspect){ | ||
+ | // what kind of object object ? | ||
+ | OUString OUStrAnyTypeAndValue, OUStrTypeValue; | ||
+ | switch (toInspect.pType->eTypeClass) | ||
+ | { | ||
+ | // const defined in <OOo_SDK>/include/typelib/typeclass.h | ||
+ | case typelib_TypeClass_VOID: | ||
+ | OUStrAnyTypeAndValue = OUString::createFromAscii("(")+ OUStrAnyTypeAndValue+ | ||
+ | OUString::createFromAscii(")"); | ||
+ | m_simpleObject = sal_True; | ||
+ | m_OUStrAnyTypeAndValue = OUStrAnyTypeAndValue; | ||
+ | break; | ||
+ | case typelib_TypeClass_BOOLEAN: | ||
+ | sal_Bool MyBool; | ||
+ | toInspect >>= MyBool; | ||
+ | OUStrAnyTypeAndValue = OUString::createFromAscii("(")+ OUStrAnyTypeAndValue+ | ||
+ | OUString::createFromAscii(")=") + OUStrTypeValue.valueOf((sal_Bool) MyBool); | ||
+ | m_simpleObject=sal_True; | ||
+ | m_OUStrAnyTypeAndValue = OUStrAnyTypeAndValue; | ||
+ | break; | ||
+ | // all in a 32 bit data at the moment | ||
+ | case typelib_TypeClass_BYTE: | ||
+ | case typelib_TypeClass_CHAR: | ||
+ | case typelib_TypeClass_SHORT: | ||
+ | case typelib_TypeClass_UNSIGNED_SHORT: | ||
+ | case typelib_TypeClass_UNSIGNED_LONG: | ||
+ | case typelib_TypeClass_LONG: | ||
+ | sal_Int32 *MyLong; | ||
+ | MyLong = (sal_Int32*) toInspect.getValue(); | ||
+ | OUStrAnyTypeAndValue = OUString::createFromAscii("(")+ OUStrAnyTypeAndValue+ | ||
+ | OUString::createFromAscii(")=") + OUStrTypeValue.valueOf((sal_Int32) *MyLong); | ||
+ | m_simpleObject = sal_True; | ||
+ | m_OUStrAnyTypeAndValue = OUStrAnyTypeAndValue; | ||
+ | break; | ||
+ | // all in the double data at the moment | ||
+ | case typelib_TypeClass_FLOAT: | ||
+ | case typelib_TypeClass_DOUBLE: | ||
+ | double *myDouble; | ||
+ | myDouble = (double*) toInspect.getValue(); | ||
+ | OUStrAnyTypeAndValue = OUString::createFromAscii("(")+ OUStrAnyTypeAndValue+ | ||
+ | OUString::createFromAscii(")=") + OUStrTypeValue.valueOf((double) *myDouble); | ||
+ | m_simpleObject = sal_True; | ||
+ | m_OUStrAnyTypeAndValue = OUStrAnyTypeAndValue; | ||
+ | break; | ||
+ | /* case typelib_TypeClass_HYPER: | ||
+ | break; | ||
+ | case typelib_TypeClass_ANY: | ||
+ | break; */ | ||
+ | case typelib_TypeClass_STRING: | ||
+ | toInspect >>= OUStrTypeValue; | ||
+ | OUStrAnyTypeAndValue = OUString::createFromAscii("(")+ OUStrAnyTypeAndValue+ | ||
+ | OUString::createFromAscii(")=")+OUStrTypeValue; | ||
+ | m_simpleObject = sal_True; | ||
+ | m_OUStrAnyTypeAndValue = OUStrAnyTypeAndValue; | ||
+ | break; | ||
+ | case typelib_TypeClass_SEQUENCE: | ||
+ | if (toInspect.getValueTypeName() == OUString::createFromAscii("[]byte")) { | ||
+ | Sequence< sal_Int8 > SeqByte; | ||
+ | toInspect >>= SeqByte; | ||
+ | OUString OUStr=OUString::createFromAscii("([]byte)"); | ||
+ | /* OUStr = OUString::createFromAscii("Length:"); | ||
+ | OUStr=OUStr.concat(OUStr.valueOf((sal_Int32) SeqByte.getLength())+ | ||
+ | OUString::createFromAscii(" : "));*/ | ||
+ | OUStrAnyTypeAndValue=OUStr + convert2OUStrInDEBUGMODE(SeqByte); //0.3 version | ||
+ | m_simpleObject = sal_True; | ||
+ | m_OUStrAnyTypeAndValue = OUStrAnyTypeAndValue; | ||
+ | } else | ||
+ | if (toInspect.getValueTypeName() == OUString::createFromAscii("[]string")) { | ||
+ | Sequence< OUString > SeqOUStr; | ||
+ | OUString OUStr; | ||
+ | toInspect >>= SeqOUStr; | ||
+ | OUStr = OUString::createFromAscii("Length:"); | ||
+ | OUStr=OUStr.concat(OUStr.valueOf((sal_Int32) SeqOUStr.getLength())+ | ||
+ | OUString::createFromAscii(" : ")); | ||
+ | for (sal_Int32 i=0; i<SeqOUStr.getLength(); i++){ | ||
+ | OUStr=OUStr.concat(OUString::createFromAscii("\"") | ||
+ | +SeqOUStr[i] | ||
+ | + OUString::createFromAscii("\"")); | ||
+ | } | ||
+ | OUStrAnyTypeAndValue = OUString::createFromAscii("([]string) ") + OUStr; | ||
+ | m_simpleObject = sal_True; | ||
+ | m_OUStrAnyTypeAndValue = OUStrAnyTypeAndValue; | ||
+ | } | ||
+ | break; | ||
+ | case typelib_TypeClass_INTERFACE: | ||
+ | m_xIntrospec = m_xIntrospection->inspect(toInspect); | ||
+ | mMethods = m_xIntrospec -> getMethods(MethodConcept::ALL); | ||
+ | m_xTypeProvider = Reference< XTypeProvider> (toInspect,UNO_QUERY); | ||
+ | types = m_xTypeProvider->getTypes(); | ||
+ | m_xServiceInfo = Reference< XServiceInfo>(toInspect,UNO_QUERY); | ||
+ | Properties = m_xIntrospec -> getProperties(PropertyConcept::ALL); | ||
+ | m_simpleObject = sal_False; | ||
+ | break; | ||
+ | /* case typelib_TypeClass_TYPE: break; | ||
+ | case typelib_TypeClass_ARRAY: break; | ||
+ | case typelib_TypeClass_SERVICE: break; | ||
+ | case typelib_TypeClass_INTERFACE_METHOD: break; | ||
+ | case typelib_TypeClass_INTERFACE_ATTRIBUTE:break; | ||
+ | case typelib_TypeClass_ENUM: break; | ||
+ | case typelib_TypeClass_STRUCT:break; */ | ||
+ | //default: | ||
+ | } // switch | ||
+ | } | ||
+ | |||
+ | |||
+ | //OK | ||
+ | Sequence < OUString > ReflectionHelper::getServices() { | ||
+ | return m_xServiceInfo->getSupportedServiceNames(); | ||
+ | } | ||
+ | |||
+ | //OK | ||
+ | Sequence < OUString > ReflectionHelper::getMethods(){ | ||
+ | Sequence< OUString > methods(mMethods.getLength()); | ||
+ | for (int i=0;i<mMethods.getLength();i++){ | ||
+ | OUString params; | ||
+ | params=OUString::createFromAscii("("); | ||
+ | Sequence< ParamInfo > ParamInfos = mMethods[i]->getParameterInfos(); | ||
+ | if (ParamInfos.getLength() > 0) { | ||
+ | for (int j=0;j<ParamInfos.getLength();j++){ | ||
+ | Reference< XIdlClass > xIdlClass = ParamInfos[j].aType; | ||
+ | if (j == 0) | ||
+ | // first parameter has no leading comma | ||
+ | params += OUString::createFromAscii("[") + getParamMode(ParamInfos[j].aMode)+ | ||
+ | OUString::createFromAscii("]") + | ||
+ | xIdlClass->getName() + OUString::createFromAscii(" ") + ParamInfos[j].aName; | ||
+ | else | ||
+ | params += OUString::createFromAscii(",[") + getParamMode(ParamInfos[j].aMode)+ | ||
+ | OUString::createFromAscii("]")+ | ||
+ | xIdlClass->getName() + OUString::createFromAscii(" ") + ParamInfos[j].aName; | ||
+ | } | ||
+ | } | ||
+ | params += OUString::createFromAscii(")"); | ||
+ | methods[i] = mMethods[i]->getReturnType()->getName()+OUString::createFromAscii(" ")+ | ||
+ | mMethods[i]->getName()+params; | ||
+ | } | ||
+ | return methods; | ||
+ | } | ||
+ | |||
+ | Sequence< Reference< XIdlMethod > > ReflectionHelper::getIdlMethods(){ | ||
+ | return mMethods; | ||
+ | } | ||
+ | // added for 0.4 version | ||
+ | Reference< XIdlMethod > ReflectionHelper::getXIdlMethodByName(OUString aName){ | ||
+ | Reference< XIdlMethod > xIdlMethod = m_xIntrospec->getMethod(aName,MethodConcept::ALL); | ||
+ | return xIdlMethod; | ||
+ | } | ||
+ | // OK | ||
+ | Sequence < OUString > ReflectionHelper::getTypes(){ | ||
+ | Sequence< OUString > interfaces(types.getLength()); | ||
+ | for (int i=0;i<types.getLength();i++){ | ||
+ | interfaces[i] = types[i].getTypeName(); | ||
+ | } | ||
+ | return interfaces; | ||
+ | } | ||
+ | |||
+ | // to improve : change all the tests with getCppuType : probably quicker than a string test | ||
+ | OUString ReflectionHelper::getValueName(Any object){ | ||
+ | OUString OUStr; | ||
+ | OUStr = OUString::createFromAscii("!! Unable to compute values !!"); | ||
+ | if (object.hasValue()) { | ||
+ | if (object.isExtractableTo(getCppuBooleanType())){ | ||
+ | sal_Bool MyBool; | ||
+ | object >>= MyBool; | ||
+ | return OUStr.valueOf((sal_Bool) MyBool); | ||
+ | } else | ||
+ | if (object.getValueTypeName() == OUString::createFromAscii("string")) { | ||
+ | OUString *MyOUStr; | ||
+ | MyOUStr = (OUString *) object.getValue(); | ||
+ | OUStr = OUString::createFromAscii("\""); | ||
+ | return OUStr + *MyOUStr + OUString::createFromAscii("\""); | ||
+ | } else | ||
+ | if (object.getValueTypeName() == OUString::createFromAscii("long")) { | ||
+ | sal_Int32 *MyLong; | ||
+ | MyLong = (sal_Int32*) object.getValue(); | ||
+ | return OUStr.valueOf((sal_Int32) *MyLong); | ||
+ | } else | ||
+ | if (object.getValueTypeName() == OUString::createFromAscii("short")) { | ||
+ | sal_Int16 *MyShort; | ||
+ | MyShort = (sal_Int16*) object.getValue(); | ||
+ | return OUStr.valueOf((sal_Int32) *MyShort); | ||
+ | } else | ||
+ | if (object.getValueTypeName() == OUString::createFromAscii("[]byte")) { | ||
+ | Sequence< sal_Int8 > SeqByte; | ||
+ | object >>= SeqByte; | ||
+ | OUString OUStr=convert2OUStrInDEBUGMODE(SeqByte); //0.3 version | ||
+ | return OUStr; | ||
+ | } else | ||
+ | if (object.getValueTypeName() == OUString::createFromAscii("[]string")) { | ||
+ | Sequence< OUString > SeqOUStr; | ||
+ | object >>= SeqOUStr; | ||
+ | OUStr = OUString::createFromAscii("Length:"); | ||
+ | OUStr=OUStr.concat(OUStr.valueOf((sal_Int32) SeqOUStr.getLength())+ | ||
+ | OUString::createFromAscii(" : ")); | ||
+ | for (sal_Int32 i=0; i<SeqOUStr.getLength(); i++){ | ||
+ | OUStr=OUStr.concat(OUString::createFromAscii("\"") | ||
+ | +SeqOUStr[i] | ||
+ | + OUString::createFromAscii("\"")); | ||
+ | } | ||
+ | return OUStr; | ||
+ | } else return OUStr; | ||
+ | } else return OUStr; | ||
+ | } | ||
+ | |||
+ | // OK | ||
+ | // Get properties with values : only those computed in getValueName | ||
+ | // améliorer avec : | ||
+ | // voir SDK2.3.1 portable IUT <SDK>/examples/cpp/extensions/source/objectbrowser/uno_lang.cxx | ||
+ | Sequence < OUString > ReflectionHelper::getPropertiesWithValues(){ | ||
+ | Sequence< OUString > propWithVal(Properties.getLength()); | ||
+ | for (int i=0;i<Properties.getLength();i++){ | ||
+ | Type typ = getCppuType( (const Reference< XPropertySet > *)0); | ||
+ | Reference< XPropertySet > rPropertySet(m_xIntrospec->queryAdapter(typ),UNO_QUERY); | ||
+ | Reference< XPropertySetInfo > rPropertySetInfo=rPropertySet->getPropertySetInfo(); | ||
+ | Any object; | ||
+ | if (rPropertySetInfo->hasPropertyByName(Properties[i].Name)){ | ||
+ | object <<= rPropertySet->getPropertyValue(Properties[i].Name); | ||
+ | //if (object.hasValue()) printf("Valeur trouvee : \n"); | ||
+ | propWithVal[i] = Properties[i].Name + OUString::createFromAscii(" = (")+ | ||
+ | Properties[i].Type.getTypeName() + OUString::createFromAscii(") ") | ||
+ | + getValueName(object); | ||
+ | //+ object.getValueTypeName(); | ||
+ | } | ||
+ | } | ||
+ | return propWithVal; | ||
+ | } | ||
+ | |||
+ | // OK | ||
+ | // Get properties without values but types | ||
+ | Sequence < OUString > ReflectionHelper::getPropertiesWithoutValues(){ | ||
+ | Sequence< OUString > propWithVal(Properties.getLength()); | ||
+ | for (int i=0;i<Properties.getLength();i++){ | ||
+ | Type typ = getCppuType( (const Reference< XPropertySet > *)0); | ||
+ | Reference< XPropertySet > xPropertySet(m_xIntrospec->queryAdapter(typ),UNO_QUERY); | ||
+ | Reference< XPropertySetInfo > xPropertySetInfo=xPropertySet->getPropertySetInfo(); | ||
+ | if (xPropertySetInfo->hasPropertyByName(Properties[i].Name)){ | ||
+ | propWithVal[i] = Properties[i].Name + OUString::createFromAscii(" = (")+ | ||
+ | Properties[i].Type.getTypeName() + OUString::createFromAscii(")"); | ||
+ | } | ||
+ | } | ||
+ | return propWithVal; | ||
+ | } | ||
+ | |||
+ | // Don't forget to add : #include <com/sun/star/reflection/ParamMode.hpp> | ||
+ | // Don't forget to add "com.sun.star.reflection.ParamMode \" in the makefile | ||
+ | OUString ReflectionHelper::getParamMode(ParamMode paramMode) { | ||
+ | OUString toReturn; | ||
+ | toReturn = OUString::createFromAscii(""); | ||
+ | if (paramMode == ParamMode_IN) toReturn = OUString::createFromAscii("IN"); else | ||
+ | if (paramMode == ParamMode_OUT) toReturn = OUString::createFromAscii("OUT"); else | ||
+ | if (paramMode == ParamMode_INOUT) toReturn = OUString::createFromAscii("INOUT"); | ||
+ | return toReturn; | ||
+ | } | ||
+ | // added for 0.3 version | ||
+ | Sequence< OUString > ReflectionHelper::convert2SeqOUStrInDEBUGMODE(Sequence < sal_Int8 > seqBytes){ | ||
+ | sal_Int8 Hexa[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; | ||
+ | sal_Int32 lin,col; | ||
+ | sal_Char line[80]; | ||
+ | sal_Int32 len,sequenceSize,index; | ||
+ | len=seqBytes.getLength(); | ||
+ | sequenceSize=(len>>4)+2; | ||
+ | if ((len&0XFFF0)==len) sequenceSize--; //if len%16==0 | ||
+ | Sequence< OUString > SeqOUStr(sequenceSize); | ||
+ | // First line with length | ||
+ | SeqOUStr[0] = OUString::createFromAscii("Length:")+ | ||
+ | OUString::valueOf((sal_Int32) seqBytes.getLength())+ | ||
+ | OUString::createFromAscii(" "); | ||
+ | len = len&0XFFF0; // remove the modulo 16 | ||
+ | for(lin=0;lin<len;lin=lin+16){ | ||
+ | for(col=0;col<16;col++){ | ||
+ | line[3*col]=Hexa[((unsigned char)seqBytes[lin+col])>>4]; | ||
+ | line[3*col+1]=Hexa[seqBytes[lin+col]&0x0F]; | ||
+ | line[3*col+2]=' '; | ||
+ | if ((seqBytes[lin+col]<128)&&(seqBytes[lin+col]>20)) line[50+col]=seqBytes[lin+col]; | ||
+ | else line[50+col]='.'; | ||
+ | } /* end of for */ | ||
+ | line[66]=0; /* end of cstring...*/ | ||
+ | line[48]=' ';line[49]=' '; | ||
+ | // ready to add the OUString in Sequence | ||
+ | if ((lin%16)==0) index = lin/16+1; else index=lin/16+2; | ||
+ | SeqOUStr[index]=OUString::createFromAscii(line); | ||
+ | } /* end of for */ | ||
+ | // the last line is more complicated because not complete | ||
+ | // we only keep modulo | ||
+ | len=seqBytes.getLength()&0x000F; | ||
+ | if (len>0) { // only a line here if non-empty | ||
+ | for (lin=0;lin<len;lin++){ | ||
+ | col=lin; | ||
+ | line[3*col]=Hexa[((unsigned char)seqBytes[lin])>>4]; | ||
+ | line[3*col+1]=Hexa[seqBytes[lin]&0x0F]; | ||
+ | line[3*col+2]=' '; | ||
+ | if ((seqBytes[lin]<128)&&(seqBytes[lin]>20)) line[50+col]=seqBytes[lin]; | ||
+ | else line[50+col]='.'; | ||
+ | } | ||
+ | // we complete the line | ||
+ | for (++col;col<16;col++){ | ||
+ | line[3*col]=' ';line[3*col+1]=' ';line[3*col+2]=' ';line[50+col]=' '; | ||
+ | } | ||
+ | line[66]=0; /* end of string...*/ | ||
+ | line[48]=' ';line[49]=' '; | ||
+ | // ready to add the OUString in Sequence | ||
+ | SeqOUStr[lin/16+2]=OUString::createFromAscii(line); | ||
+ | } //end if | ||
+ | return SeqOUStr; | ||
+ | } | ||
+ | |||
+ | // added for 0.3 version | ||
+ | OUString ReflectionHelper::convert2OUStrInDEBUGMODE(Sequence < sal_Int8 > seqBytes){ | ||
+ | Sequence <OUString> SeqOUStr = convert2SeqOUStrInDEBUGMODE(seqBytes); | ||
+ | OUString OUStr; | ||
+ | for(sal_Int32 i=0;i<SeqOUStr.getLength();i++) | ||
+ | OUStr = OUStr+SeqOUStr[i]+OUString::createFromAscii("\n"); | ||
+ | return OUStr; | ||
+ | } | ||
+ | </source> | ||
==The Component== | ==The Component== | ||
=Transforming a component= | =Transforming a component= |
Revision as of 12:40, 3 August 2009
This chapter is under construction for a while because I don't master all the topics evocated here at the moment. SergeMoutou 12:20, 3 August 2009 (UTC) |
Writing components is not as easy as developping binary executable. When an exception occurs in your component a recovery process of your document begins. This process is too long to try some code and correct the errors. When designing a component, it would be a good idea to conceive it as a binary executable before to change it into a component. In this chapter we will discuss this idea and also the exceptions. But before starting we examine at first the inspection tools.
Contents
Java Inspector
My own Inspector
I have already presented in this document my own inspector but it wasn't a component. Then it was only valuable when writing binary executable, not component. In this section I will show how to transform it as a component. Because Java Inspector is more advanced my component is only interesting when using old an inefficient computers. But for me it represents the only experience with writing a great component.
The code presented here is not safe. You can see many "FIXME" in the code. At the moment the version is labelled 0.4 |
This component is composed with two separate class (at the moment)
The ReflectionHelper class
This class is composed with two source files. Be begin with the header :
#ifndef REFLECTIONHELPER_H #define REFLECTIONHELPER_H #include <rtl/ustring.hxx> #include <com/sun/star/uno/Sequence.hxx> #include <com/sun/star/uno/Any.hxx> #include <com/sun/star/lang/XMultiComponentFactory.hpp> #include <com/sun/star/beans/XIntrospection.hpp> #include <com/sun/star/beans/XIntrospectionAccess.hpp> #include <com/sun/star/lang/XTypeProvider.hpp> #include <com/sun/star/beans/MethodConcept.hpp> #include <com/sun/star/reflection/XIdlMethod.hpp> #include <com/sun/star/uno/Type.hxx> #include <com/sun/star/beans/Property.hpp> #include <com/sun/star/lang/XServiceInfo.hpp> #include <com/sun/star/reflection/ParamMode.hpp> using rtl::OUString; using namespace com::sun::star::reflection; using namespace com::sun::star::beans; using namespace com::sun::star::lang; using namespace com::sun::star::uno; class ReflectionHelper { public: ReflectionHelper(Any toInspect,Reference< XMultiComponentFactory > const & oSVM, Reference< XComponentContext > const & xContext); Sequence < OUString > getMethods(), getTypes(), getServices(), getPropertiesWithoutValues(), getPropertiesWithValues(); Sequence< Reference< XIdlMethod > > getIdlMethods(); Reference< XIdlMethod > getXIdlMethodByName(OUString aName); void getTypeAndValue(Any toInspect); sal_Bool m_simpleObject; OUString m_OUStrAnyTypeAndValue; // for simple object data // Print out // void printOut(); //perhaps const ? private: Any m_toInspect; Reference< XMultiComponentFactory > m_xServiceManager; Reference< XIntrospection >m_xIntrospection; Reference< XIntrospectionAccess > m_xIntrospec; Reference< XTypeProvider > m_xTypeProvider; Reference< XComponentContext > m_xContext; OUString getValueName(Any object); OUString getParamMode(ParamMode paramMode); // methods Sequence< Reference< XIdlMethod > > mMethods; // Interfaces Sequence< Type > types; // Services Reference< XServiceInfo > m_xServiceInfo; // Sequence< OUString > services; // Properties Sequence< Property > Properties; // protected methods protected: Sequence< OUString > convert2SeqOUStrInDEBUGMODE(Sequence < sal_Int8 > seqBytes); // same as "convert2SeqOUStrInDEBUGMODE" but in one OUString OUString convert2OUStrInDEBUGMODE(Sequence < sal_Int8 > seqBytes); }; #endif //REFLECTIONHELPER_H
And now the corresponding implementation :
// C++ // Serge Moutou // with help of <OpenOffice1.1_SDK>/examples/java/Inspector // and Bernard Marcelly XRay tool // version 0.1 (22 Dec 2004) // version 0.2 (4 Jun 2005) added printout in a dialog // version 0.2.1 (4 Apr 2009) added name of parameters in methods // version 0.3 (23 Apr 2009) added DEBUG MODE for []bytes properties // version 0.4 (28 Jul 2009) changed to be used with a component: // ****** constructor uses XMultiComponentFactoty instead of XMultiServiceFactory // To do : Exception Handling, to go further with properties values //#include <org/openoffice/cpp/XInstanceIspector.hpp> #include "./ReflectionHelper.hpp" #include <com/sun/star/reflection/XIdlClass.hpp> #include <com/sun/star/beans/PropertyConcept.hpp> #include <com/sun/star/beans/XPropertySet.hpp> //#include <com/sun/star/reflection/ParamMode.hpp> done in ReflectionHelper.hpp #include <com/sun/star/container/XNameContainer.hpp> //#include <cppuhelper/implbase1.hxx> #include <com/sun/star/awt/XTextComponent.hpp> //#include <com/sun/star/awt/XActionListener.hpp> #include <com/sun/star/awt/XToolkit.hpp> #include <com/sun/star/awt/XControlContainer.hpp> //#include <com/sun/star/awt/PushButtonType.hpp> //#include <com/sun/star/awt/XButton.hpp> //#include <com/sun/star/awt/XWindow.hpp> //#include <com/sun/star/awt/XDialog.hpp> //#include <com/sun/star/lang/XMultiServiceFactory.hpp> #include <rtl/ustring.hxx> #include <rtl/string.hxx> //#define DEBUG using namespace com::sun::star::awt; //using namespace com::sun::star::frame; using namespace com::sun::star::lang; using namespace com::sun::star::container; // Inspector constructor ReflectionHelper::ReflectionHelper(Any toInspect, Reference< XMultiComponentFactory > const & oSVM, Reference< XComponentContext > const & xContext) : m_toInspect(toInspect), m_xServiceManager(oSVM), m_xContext(xContext) { m_xIntrospection = Reference< XIntrospection >( m_xServiceManager->createInstanceWithContext( OUString::createFromAscii("com.sun.star.beans.Introspection" ),m_xContext), UNO_QUERY_THROW); getTypeAndValue(m_toInspect); } //FIXME:Bad idea to take a method of ReflectionHelper for that ? //**** modify data member and then doesn't keep coherence in data ? void ReflectionHelper::getTypeAndValue(Any toInspect){ // what kind of object object ? OUString OUStrAnyTypeAndValue, OUStrTypeValue; switch (toInspect.pType->eTypeClass) { // const defined in <OOo_SDK>/include/typelib/typeclass.h case typelib_TypeClass_VOID: OUStrAnyTypeAndValue = OUString::createFromAscii("(")+ OUStrAnyTypeAndValue+ OUString::createFromAscii(")"); m_simpleObject = sal_True; m_OUStrAnyTypeAndValue = OUStrAnyTypeAndValue; break; case typelib_TypeClass_BOOLEAN: sal_Bool MyBool; toInspect >>= MyBool; OUStrAnyTypeAndValue = OUString::createFromAscii("(")+ OUStrAnyTypeAndValue+ OUString::createFromAscii(")=") + OUStrTypeValue.valueOf((sal_Bool) MyBool); m_simpleObject=sal_True; m_OUStrAnyTypeAndValue = OUStrAnyTypeAndValue; break; // all in a 32 bit data at the moment case typelib_TypeClass_BYTE: case typelib_TypeClass_CHAR: case typelib_TypeClass_SHORT: case typelib_TypeClass_UNSIGNED_SHORT: case typelib_TypeClass_UNSIGNED_LONG: case typelib_TypeClass_LONG: sal_Int32 *MyLong; MyLong = (sal_Int32*) toInspect.getValue(); OUStrAnyTypeAndValue = OUString::createFromAscii("(")+ OUStrAnyTypeAndValue+ OUString::createFromAscii(")=") + OUStrTypeValue.valueOf((sal_Int32) *MyLong); m_simpleObject = sal_True; m_OUStrAnyTypeAndValue = OUStrAnyTypeAndValue; break; // all in the double data at the moment case typelib_TypeClass_FLOAT: case typelib_TypeClass_DOUBLE: double *myDouble; myDouble = (double*) toInspect.getValue(); OUStrAnyTypeAndValue = OUString::createFromAscii("(")+ OUStrAnyTypeAndValue+ OUString::createFromAscii(")=") + OUStrTypeValue.valueOf((double) *myDouble); m_simpleObject = sal_True; m_OUStrAnyTypeAndValue = OUStrAnyTypeAndValue; break; /* case typelib_TypeClass_HYPER: break; case typelib_TypeClass_ANY: break; */ case typelib_TypeClass_STRING: toInspect >>= OUStrTypeValue; OUStrAnyTypeAndValue = OUString::createFromAscii("(")+ OUStrAnyTypeAndValue+ OUString::createFromAscii(")=")+OUStrTypeValue; m_simpleObject = sal_True; m_OUStrAnyTypeAndValue = OUStrAnyTypeAndValue; break; case typelib_TypeClass_SEQUENCE: if (toInspect.getValueTypeName() == OUString::createFromAscii("[]byte")) { Sequence< sal_Int8 > SeqByte; toInspect >>= SeqByte; OUString OUStr=OUString::createFromAscii("([]byte)"); /* OUStr = OUString::createFromAscii("Length:"); OUStr=OUStr.concat(OUStr.valueOf((sal_Int32) SeqByte.getLength())+ OUString::createFromAscii(" : "));*/ OUStrAnyTypeAndValue=OUStr + convert2OUStrInDEBUGMODE(SeqByte); //0.3 version m_simpleObject = sal_True; m_OUStrAnyTypeAndValue = OUStrAnyTypeAndValue; } else if (toInspect.getValueTypeName() == OUString::createFromAscii("[]string")) { Sequence< OUString > SeqOUStr; OUString OUStr; toInspect >>= SeqOUStr; OUStr = OUString::createFromAscii("Length:"); OUStr=OUStr.concat(OUStr.valueOf((sal_Int32) SeqOUStr.getLength())+ OUString::createFromAscii(" : ")); for (sal_Int32 i=0; i<SeqOUStr.getLength(); i++){ OUStr=OUStr.concat(OUString::createFromAscii("\"") +SeqOUStr[i] + OUString::createFromAscii("\"")); } OUStrAnyTypeAndValue = OUString::createFromAscii("([]string) ") + OUStr; m_simpleObject = sal_True; m_OUStrAnyTypeAndValue = OUStrAnyTypeAndValue; } break; case typelib_TypeClass_INTERFACE: m_xIntrospec = m_xIntrospection->inspect(toInspect); mMethods = m_xIntrospec -> getMethods(MethodConcept::ALL); m_xTypeProvider = Reference< XTypeProvider> (toInspect,UNO_QUERY); types = m_xTypeProvider->getTypes(); m_xServiceInfo = Reference< XServiceInfo>(toInspect,UNO_QUERY); Properties = m_xIntrospec -> getProperties(PropertyConcept::ALL); m_simpleObject = sal_False; break; /* case typelib_TypeClass_TYPE: break; case typelib_TypeClass_ARRAY: break; case typelib_TypeClass_SERVICE: break; case typelib_TypeClass_INTERFACE_METHOD: break; case typelib_TypeClass_INTERFACE_ATTRIBUTE:break; case typelib_TypeClass_ENUM: break; case typelib_TypeClass_STRUCT:break; */ //default: } // switch } //OK Sequence < OUString > ReflectionHelper::getServices() { return m_xServiceInfo->getSupportedServiceNames(); } //OK Sequence < OUString > ReflectionHelper::getMethods(){ Sequence< OUString > methods(mMethods.getLength()); for (int i=0;i<mMethods.getLength();i++){ OUString params; params=OUString::createFromAscii("("); Sequence< ParamInfo > ParamInfos = mMethods[i]->getParameterInfos(); if (ParamInfos.getLength() > 0) { for (int j=0;j<ParamInfos.getLength();j++){ Reference< XIdlClass > xIdlClass = ParamInfos[j].aType; if (j == 0) // first parameter has no leading comma params += OUString::createFromAscii("[") + getParamMode(ParamInfos[j].aMode)+ OUString::createFromAscii("]") + xIdlClass->getName() + OUString::createFromAscii(" ") + ParamInfos[j].aName; else params += OUString::createFromAscii(",[") + getParamMode(ParamInfos[j].aMode)+ OUString::createFromAscii("]")+ xIdlClass->getName() + OUString::createFromAscii(" ") + ParamInfos[j].aName; } } params += OUString::createFromAscii(")"); methods[i] = mMethods[i]->getReturnType()->getName()+OUString::createFromAscii(" ")+ mMethods[i]->getName()+params; } return methods; } Sequence< Reference< XIdlMethod > > ReflectionHelper::getIdlMethods(){ return mMethods; } // added for 0.4 version Reference< XIdlMethod > ReflectionHelper::getXIdlMethodByName(OUString aName){ Reference< XIdlMethod > xIdlMethod = m_xIntrospec->getMethod(aName,MethodConcept::ALL); return xIdlMethod; } // OK Sequence < OUString > ReflectionHelper::getTypes(){ Sequence< OUString > interfaces(types.getLength()); for (int i=0;i<types.getLength();i++){ interfaces[i] = types[i].getTypeName(); } return interfaces; } // to improve : change all the tests with getCppuType : probably quicker than a string test OUString ReflectionHelper::getValueName(Any object){ OUString OUStr; OUStr = OUString::createFromAscii("!! Unable to compute values !!"); if (object.hasValue()) { if (object.isExtractableTo(getCppuBooleanType())){ sal_Bool MyBool; object >>= MyBool; return OUStr.valueOf((sal_Bool) MyBool); } else if (object.getValueTypeName() == OUString::createFromAscii("string")) { OUString *MyOUStr; MyOUStr = (OUString *) object.getValue(); OUStr = OUString::createFromAscii("\""); return OUStr + *MyOUStr + OUString::createFromAscii("\""); } else if (object.getValueTypeName() == OUString::createFromAscii("long")) { sal_Int32 *MyLong; MyLong = (sal_Int32*) object.getValue(); return OUStr.valueOf((sal_Int32) *MyLong); } else if (object.getValueTypeName() == OUString::createFromAscii("short")) { sal_Int16 *MyShort; MyShort = (sal_Int16*) object.getValue(); return OUStr.valueOf((sal_Int32) *MyShort); } else if (object.getValueTypeName() == OUString::createFromAscii("[]byte")) { Sequence< sal_Int8 > SeqByte; object >>= SeqByte; OUString OUStr=convert2OUStrInDEBUGMODE(SeqByte); //0.3 version return OUStr; } else if (object.getValueTypeName() == OUString::createFromAscii("[]string")) { Sequence< OUString > SeqOUStr; object >>= SeqOUStr; OUStr = OUString::createFromAscii("Length:"); OUStr=OUStr.concat(OUStr.valueOf((sal_Int32) SeqOUStr.getLength())+ OUString::createFromAscii(" : ")); for (sal_Int32 i=0; i<SeqOUStr.getLength(); i++){ OUStr=OUStr.concat(OUString::createFromAscii("\"") +SeqOUStr[i] + OUString::createFromAscii("\"")); } return OUStr; } else return OUStr; } else return OUStr; } // OK // Get properties with values : only those computed in getValueName // améliorer avec : // voir SDK2.3.1 portable IUT <SDK>/examples/cpp/extensions/source/objectbrowser/uno_lang.cxx Sequence < OUString > ReflectionHelper::getPropertiesWithValues(){ Sequence< OUString > propWithVal(Properties.getLength()); for (int i=0;i<Properties.getLength();i++){ Type typ = getCppuType( (const Reference< XPropertySet > *)0); Reference< XPropertySet > rPropertySet(m_xIntrospec->queryAdapter(typ),UNO_QUERY); Reference< XPropertySetInfo > rPropertySetInfo=rPropertySet->getPropertySetInfo(); Any object; if (rPropertySetInfo->hasPropertyByName(Properties[i].Name)){ object <<= rPropertySet->getPropertyValue(Properties[i].Name); //if (object.hasValue()) printf("Valeur trouvee : \n"); propWithVal[i] = Properties[i].Name + OUString::createFromAscii(" = (")+ Properties[i].Type.getTypeName() + OUString::createFromAscii(") ") + getValueName(object); //+ object.getValueTypeName(); } } return propWithVal; } // OK // Get properties without values but types Sequence < OUString > ReflectionHelper::getPropertiesWithoutValues(){ Sequence< OUString > propWithVal(Properties.getLength()); for (int i=0;i<Properties.getLength();i++){ Type typ = getCppuType( (const Reference< XPropertySet > *)0); Reference< XPropertySet > xPropertySet(m_xIntrospec->queryAdapter(typ),UNO_QUERY); Reference< XPropertySetInfo > xPropertySetInfo=xPropertySet->getPropertySetInfo(); if (xPropertySetInfo->hasPropertyByName(Properties[i].Name)){ propWithVal[i] = Properties[i].Name + OUString::createFromAscii(" = (")+ Properties[i].Type.getTypeName() + OUString::createFromAscii(")"); } } return propWithVal; } // Don't forget to add : #include <com/sun/star/reflection/ParamMode.hpp> // Don't forget to add "com.sun.star.reflection.ParamMode \" in the makefile OUString ReflectionHelper::getParamMode(ParamMode paramMode) { OUString toReturn; toReturn = OUString::createFromAscii(""); if (paramMode == ParamMode_IN) toReturn = OUString::createFromAscii("IN"); else if (paramMode == ParamMode_OUT) toReturn = OUString::createFromAscii("OUT"); else if (paramMode == ParamMode_INOUT) toReturn = OUString::createFromAscii("INOUT"); return toReturn; } // added for 0.3 version Sequence< OUString > ReflectionHelper::convert2SeqOUStrInDEBUGMODE(Sequence < sal_Int8 > seqBytes){ sal_Int8 Hexa[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; sal_Int32 lin,col; sal_Char line[80]; sal_Int32 len,sequenceSize,index; len=seqBytes.getLength(); sequenceSize=(len>>4)+2; if ((len&0XFFF0)==len) sequenceSize--; //if len%16==0 Sequence< OUString > SeqOUStr(sequenceSize); // First line with length SeqOUStr[0] = OUString::createFromAscii("Length:")+ OUString::valueOf((sal_Int32) seqBytes.getLength())+ OUString::createFromAscii(" "); len = len&0XFFF0; // remove the modulo 16 for(lin=0;lin<len;lin=lin+16){ for(col=0;col<16;col++){ line[3*col]=Hexa[((unsigned char)seqBytes[lin+col])>>4]; line[3*col+1]=Hexa[seqBytes[lin+col]&0x0F]; line[3*col+2]=' '; if ((seqBytes[lin+col]<128)&&(seqBytes[lin+col]>20)) line[50+col]=seqBytes[lin+col]; else line[50+col]='.'; } /* end of for */ line[66]=0; /* end of cstring...*/ line[48]=' ';line[49]=' '; // ready to add the OUString in Sequence if ((lin%16)==0) index = lin/16+1; else index=lin/16+2; SeqOUStr[index]=OUString::createFromAscii(line); } /* end of for */ // the last line is more complicated because not complete // we only keep modulo len=seqBytes.getLength()&0x000F; if (len>0) { // only a line here if non-empty for (lin=0;lin<len;lin++){ col=lin; line[3*col]=Hexa[((unsigned char)seqBytes[lin])>>4]; line[3*col+1]=Hexa[seqBytes[lin]&0x0F]; line[3*col+2]=' '; if ((seqBytes[lin]<128)&&(seqBytes[lin]>20)) line[50+col]=seqBytes[lin]; else line[50+col]='.'; } // we complete the line for (++col;col<16;col++){ line[3*col]=' ';line[3*col+1]=' ';line[3*col+2]=' ';line[50+col]=' '; } line[66]=0; /* end of string...*/ line[48]=' ';line[49]=' '; // ready to add the OUString in Sequence SeqOUStr[lin/16+2]=OUString::createFromAscii(line); } //end if return SeqOUStr; } // added for 0.3 version OUString ReflectionHelper::convert2OUStrInDEBUGMODE(Sequence < sal_Int8 > seqBytes){ Sequence <OUString> SeqOUStr = convert2SeqOUStrInDEBUGMODE(seqBytes); OUString OUStr; for(sal_Int32 i=0;i<SeqOUStr.getLength();i++) OUStr = OUStr+SeqOUStr[i]+OUString::createFromAscii("\n"); return OUStr; }