FR/Documentation/Composants et boite de dialogue

From Apache OpenOffice Wiki
Jump to: navigation, search

Nous allons réaliser une boîte de dialogue pour faire fonctionner notre compteur, ce sera le fil conducteur de ce chapitre. L'idée est d'utiliser l'environnement OOoBasic, car il est aisé d'y créer des boîtes de dialogue. Comme on va le voir tout au long de ce chapitre, il existe plusieurs méthodes pour faciliter l'utilisation d'un composant à l'aide des boîtes de dialogue. La première solution que l'on se propose d'examiner consiste à ne rien changer du code C++ du composant mais à enrober ce code par du OOoBasic et à utiliser ainsi les facilités de la gestion des sous-programmes OOoBasic par des boutons d'une boîte de dialogue.

Ajouter une boîte de dialogue au compteur avec le Basic

Rappelons pour information que notre compteur dispose de quatre méthodes :

  1. increment
  2. decrement
  3. setCount
  4. getCount

On va donc chercher à réaliser une boîte de dialogue qui va proposer un bouton par méthode. Elle proposera d'autre part deux champs texte :

  1. un champ texte pour positionner une valeur dans le compteur (donc associé au bouton setCount)
  2. un champ texte pour afficher la valeur du compteur (donc associé au bouton getCount)

Pour se faire une idée de quoi il s'agit, voici une image de la boîte de dialogue

Notre boîte de dialogue

Pour faire fonctionner l'ensemble on peut tout simplement utiliser le code OOoBasic suivant :

'Listing 1
REM  *****  BASIC  *****
	Dim oSimpleComponent
	Dim oDialog
Sub demonstrateSimpleComponent
	oSimpleComponent = CreateUnoService( "foo.Counter" )
	'oInspector = createUnoService("org.openoffice.InstanceInspector")
	'oInspector.inspect(oSimpleComponent, "MyCounter")
	'XRay oSimpleComponent
	oDialog=CreateUnoDialog(DialogLibraries.Standard.Dialog1)
	oDialog.Execute()
	oDialog.dispose()
End Sub
 
Sub increment
  oSimpleComponent.increment()
End Sub
 
Sub decrement
   oSimpleComponent.decrement()
End Sub
 
Sub getCount
   Dim oTextField
   oTextField = oDialog.getControl("TextField2")
   oTextField.setText( oSimpleComponent.getCount())  
End Sub
 
Sub setCount
	Dim oTextField
	oTextField = oDialog.getControl("TextField1")
	'implicit conversion String to Integer
	oSimpleComponent.setCount(oTextField.getText())
End Sub

en prenant soin d'associer aux boutons les sous-programmes OOoBasic correspondants. Dans ce programme on a laissé en commentaire les différentes façons de réaliser l'introspection sur notre compteur, mais ceci n'a pas grand intérêt pour ce qui nous préoccupe. Template:Documentation/Note

Appel direct des méthodes du compteur à l'aide du service d'Introspection

Comme indiqué dans le Developer's Guide, depuis la version 2.0.4 il est possible d'associer directement des méthodes d'un composant à des événements de boutons (ou autres contrôles). Une autre façon de dire les choses, c'est que l'enrobage que l'on a utilisé dans la section précédente du genre :

'Listing 2
REM  *****  BASIC  *****
Sub increment
  oSimpleComponent.increment()
End Sub

n'est plus nécessaire. Mais ceci a un coût : on ne pourra pas toujours garder le composant sans en modifier le code C++. Pour commencer par le plus simple, nous allons modifier notre programme OOoBasic, notre boîte de dialogue mais pas notre compteur.

Appel direct d'une méthode du compteur sans changer son code

On reprend en le modifiant le programme OOoBasic (Listing 1) précédent pour qu'il utilise le service com.sun.star.awt.DialogProvider2 qui nous fournit la méthode "createDialogWithHandler" convoitée. Voici le programme correspondant :

'Listing 3
REM  *****  BASIC  *****
	Dim oSimpleComponent
	Dim oDialog
Sub demonstrateSimpleComponent
	oSimpleComponent = CreateUnoService( "foo.Counter" )
	oCreateDialog2=CreateUnoService("com.sun.star.awt.DialogProvider2")
	'Merci ms777 pour la ligne suivante (voir http://www.oooforum.org/forum/viewtopic.phtml?t=84168)
	oCreateDialog2.initialize(Array(ThisComponent))
	oDialog=oCreateDialog2.createDialogWithHandler("vnd.sun.star.script:Standard.Dialog1?location=document", _
		oSimpleComponent, StarDesktop.getActiveFrame() )
	oDialog.Execute()
	oDialog.dispose()
End Sub
 
'Sub increment
'  oSimpleComponent.increment()
'End Sub
 
Sub decrement
   oSimpleComponent.decrement()
End Sub
 
Sub getCount
   Dim oTextField
   oTextField = oDialog.getControl("TextField2")
   oTextField.setText( oSimpleComponent.getCount())  
End Sub
 
Sub setCount
	Dim oTextField
	oTextField = oDialog.getControl("TextField1")
	'implicit conversion String to Integer
	oSimpleComponent.setCount(oTextField.getText())
End Sub

Comme vous pouvez le voir, j'ai mis en commentaire le sous-programme OOoBasic "increment", il ne peut donc plus fonctionner. En fait j'ai modifié aussi la boîte de dialogue pour que le bouton "increment" n'appelle plus un sous-programme de macro, mais directement une méthode du composant counter. Cette page en anglais du Developer's Guide explique comment on procède pour cela. La partie initialisation s'en trouve légèrement changée. Template:Documentation/Note Il nous est possible de poursuivre comme cela avec la méthode decrement du compteur, mais impossible de continuer avec les deux autres méthodes "setCount" et "getCount". Pour comprendre pourquoi, il faut se poser la question de savoir comment tout cela fonctionne. En fait dans ce cas précis c'est le service d'introspection com.sun.star.beans.Introspection qui va être utilisé automatiquement pour retrouver la méthode. Mais cette introspection automatique n'est capable de retrouver que les méthodes ayant pour signature :

void [nomMethod](void);

ou encore

  void [nomMethod] 
  ( 
      [in] com::sun::star::awt::XDialog xDialog, 
      [in] any aEvent 
  );

et cela tombe bien parce que nos deux premières méthodes "increment" et "decrement" ont cette signature là, mais ce n'est pas le cas des deux suivantes "setCount" et "getCount". Si l'on veut les faire fonctionner avec le même principe que celui déjà invoqué, il nous faudra retirer les paramètres correspondants. C'est ce que l'on a fait en OOoBasic lorsqu'on a enrobé les méthodes C++ : regardez le "Sub getCount" en OOoBasic n'a plus de paramètre dans le listing 3 !

Documentation caution.png Je me suis aperçu après coup que la signature de "increment" est en fait "long increment();" mais cela ne semble pas avoir perturbé le fonctionnement. A vérifier tout cela.

Appel direct de toutes les méthodes du compteur

Dans cette section nous allons chercher à modifier le compteur pour qu'il fonctionne complètement par appel direct de toutes ses méthodes. Comme indiqué en fin de section précédente, cela veut dire que nos deux méthodes "setCount" et "getCount" n'auront plus de paramètres. Elles devront être capables de lire/écrire dans les contrôles de champs de textes de la boîte de dialogue. Ceci va avoir de profondes répercutions sur le code du compteur car il va nous falloir obtenir un Service Manager (com.sun.star.lang.XMultiComponentFactory) pour être capable de lancer la boîte de dialogue à partir du code C++ et surtout d'obtenir l'interface com.sun.star.awt.XControlContainer pour accéder aux contrôles qui nous intéressent. Le Developer's Guide considère que l'obtention d'un Service Manager se fait par l'intermédiaire du contexte. Nous allons donc d'abord résoudre ce problème.

Obtention du contexte

L'obtention du contexte peut se faire à l'aide de quatre modifications de notre fichier source counter.cxx.

Ajout d'un champ

Pour récupérer le contexte on ajoute le champ

Reference< XComponentContext > m_xContext;

dans la classe du compteur. On rappelle qu'un contexte est une paire chaîne de caractères/valeur.

Remplacement du sous-programme d'initialisation

L'ancien sous-programme d'initialisation doit être remplacé. Il s'agissait de

// ancien sous programme a supprimer
Reference< XInterface > SAL_CALL MyCounterImpl_create(
    Reference< XComponentContext > const & xContext )
    SAL_THROW( () )
{
    return static_cast< XTypeProvider * >( new MyCounterImpl() );
}

que l'on change maintenant par

// nouveau sous-programme
Reference< XInterface > SAL_CALL MyCounterImpl_createInstance(
    Reference< XComponentContext > const & xContext )
    SAL_THROW( () )
{
    return static_cast< ::cppu::OWeakObject * >( new MyCounterImpl( xContext ) );
}

Changement du tableau des entrées

On doit procéder au changement dans le tableau des entrées indiqué dans le commentaire ci-dessous

static struct ::cppu::ImplementationEntry s_component_entries [] =
{
    { // MyCounterImpl_create replaced by MyCounterImpl_createInstance 19/05/09
        MyCounterImpl_createInstance, getImplementationName_MyCounterImpl,
        getSupportedServiceNames_MyCounterImpl, ::cppu::createSingleComponentFactory,
        0, 0
    },
    { 0, 0, 0, 0, 0, 0 }
};

Changement du constructeur de la classe

Le constructeur de la classe doit être modifié car il possède un paramètre com.sun.star.uno.XComponentContext maintenant.

inline MyCounterImpl( Reference< XComponentContext > const & xContext)
        : m_xContext( xContext ) {
	//m_xMCF=m_xContext->getServiceManager();
	}

Ces quatres opérations fonctionnent, on peut mémoriser le contexte dans notre classe mais on n'a toujours pas le service manager !

Documentation caution.png J'ai essayé de réaliser un constructeur de classe du type
// doesn't work
Reference< XInterface > SAL_CALL MyCounterImpl_createInstance( const Reference< XMultiServiceFactory > & rSMgr)
	throw( Exception )
{
	return (cppu::OWeakObject*) new MyCounterImpl( rSMgr );
}

qui obtient directement un service Manager (comme dans les AddOn) mais sans succès. A explorer plus tard.

Obtention du Service Manager

Il existe en fait plusieurs Service Manager mais celui qu'il nous est possible de récupérer à partir du contexte d'un composant est une interface com.sun.star.lang.XMultiComponentFactory. L'interface XMultiComponentFactory peut être mémorisée en ajoutant un champ :

Reference< XMultiComponentFactory > m_xMCF;

à notre classe compteur. Il nous faut alors changer notre constructeur de la classe pour qu'il mémorise vraiment le Service Manager :

inline MyCounterImpl( Reference< XComponentContext > const & xContext)
        : m_xContext( xContext ) {
	m_xMCF=m_xContext->getServiceManager();
	}

Vous devez ajouter dans le code source une directive d'inclusion

#ifndef _COM_SUN_STAR_LANG_XMULTICOMPONENTFACTORY_HPP_
#include <com/sun/star/lang/XMultiComponentFactory.hpp>
#endif

mais rien dans le Makefile car si vous prenez soin de regarder le fichier CppComponent.uno.xml vous verrez bien apparaître l'interface com.sun.star.lang.XMultiComponentFactory et donc le fichier com/sun/star/lang/XMultiComponentFactory.hpp a été généré pour vous.

Prêt pour le grand saut

Nous sommes prêt à réaliser notre compteur autonome avec sa boîte de dialogue. Pour éviter un agacement du lecteur, nous allons cesser de détailler les modifications une par une et donner dans cette section les codes complets associés.

Fichier Counter.idl

Notre nouveau fichier IDL respecte vraiment la signature des méthodes maintenant. Il devient donc :

#include <com/sun/star/uno/XInterface.idl>
//#include <com/sun/star/beans/XPropertySet.idl>
 
module foo
{
       interface XCountable : com::sun::star::uno::XInterface
	{
		void getCount();
		void setCount();
		void increment();
		void decrement();
	};
 
	service Counter
	{
		// exported interfaces:
		interface XCountable;
	};
};

Examinons maintenant le code du compteur.

Fichier counter.cxx

Le code source est un peu long.

Il existe une autre méthode pour appeler les méthodes d'un composant. Il s'agit d'implanter une interface com.sun.star.awt.XDialogEventHandler dans notre composant. Je ne sais pas si cette méthode est plus efficace que l'utilisation de l'introspection.

Utilisation de l'interface XDialogEventHandler

Retour à la page d'accueil

Page d'accueil du développement C++ à l'aide du SDK

Voir aussi

Personal tools