Writing Professional Components
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
I have already tackled Java Inspector in this document (see here). But in this section we will discuss how we can use Java Inspector in a component.
Creating the Header Files
Creating header files could be done with exporting the rdb with extension manager and then using cppumaker
tool. Because the service name is "org.openoffice.InstanceInspector" put the created header files in "<OOo_SDK>/includes/org/openoffice/" folder. You can then use :
// C++ // Listing 1 // Java Inspector #include <org/openoffice/XInstanceInspector.hpp>
in your component.
Creating the corresponding Service
This is done with :
// C++ // Listing 2 // If you want to use java Inspector m_xInspector = Reference< XInstanceInspector > (m_xMCF->createInstanceWithContext( OUString( RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.InstanceInspector" ) ), m_xContext), UNO_QUERY_THROW );
where you see a member data "m_xInspector" has to be added in your component class. The good place for this code is naturally in the constructor of your component class.
Calling the corresponding Interface
If you want to call and see the Java Inspector Dialog, you have to put a code as follows
// C++ // Listing 3 // Java Introspection any <<= somethingToInspect; m_xInspector->inspect(any,OUString::createFromAscii("Inspector")); xParentNode->appendChild(xChildMutTreeNode);
where you have to adapt the "somethingToInspect".
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; }