Using Dialogs in Components

From Apache OpenOffice Wiki
Jump to: navigation, search



In general components using dialogs are like any other component. But they need some additional code to instantiate and display the dialog(s) to be used and to accept the events created by the dialog controls.

Instantiate and display a dialog

To do this an extended version of the com.sun.star.awt.DialogProvider service - described in chapter Scripting Framework - has to be used. The extended service version com.sun.star.awt.DialogProvider2 supports com.sun.star.awt.XDialogProvider2 providing an additional method com.sun.star.awt.XDialog createDialogWithHandler(...) that allows to pass an interface when creating the dialog. This interface will be used as event handler and called if events are bound to the component.

The following code is taken from the DialogComponent SDK example that can be found in SDK/examples/DevelopersGuide/Components and shows how a dialog is created and displayed using the DialogProvider2 service:

  // XTestDialogHandler
  public String createDialog( String DialogURL, XModel xModel, XFrame xFrame ) {
      m_xFrame = xFrame;  
 
      try { 
          XMultiComponentFactory xMCF = m_xCmpCtx.getServiceManager();
          Object obj;
 
          // If valid we must pass the XModel when creating a DialogProvider object
          if( xModel != null ) {
              Object[] args = new Object[1];
              args[0] = xModel;
 
              obj = xMCF.createInstanceWithArgumentsAndContext(
                  "com.sun.star.awt.DialogProvider2", args, m_xCmpCtx );
          }
          else {
              obj = xMCF.createInstanceWithContext(
                  "com.sun.star.awt.DialogProvider2", m_xCmpCtx );
          }
 
          XDialogProvider2 xDialogProvider = (XDialogProvider2)
              UnoRuntime.queryInterface( XDialogProvider2.class, obj );
 
          XDialog xDialog = xDialogProvider.createDialogWithHandler( DialogURL, this );
          if( xDialog != null )
              xDialog.execute();
      }
      catch (Exception e) { 
          e.printStackTrace(); 
      }
      return "Created dialog \"" + DialogURL + "\"";
  }

The variable m_xCmpCtx is the com.sun.star.uno.XComponentContext interface passed to the component while initialisation. If the dialog that should be created is placed inside a document a com.sun.star.frame.XModel interface xModel representing this document has to be passed. It's used as argument to initialise the DialogProvider service enabling the access to the document's Dialog Libraries. If xModel is null the dialog has to be placed in the application library container. This also has to be reflected in the DialogURL passed to the method.

Example code for a Basic/Dialog library Library1 placed in a document:

  Sub TestDialogComponent()
      oComp = CreateUnoService( "com.sun.star.test.TestDialogHandler" )
      oComp.createDialog( "vnd.sun.star.script:Library1.Dialog1?location=document", _
          ThisComponent, StarDesktop.getActiveFrame() )
  End Sub

Example code for a Basic/Dialog library Library1 placed in "My Macros":

  Sub TestDialogComponent()
      oComp = CreateUnoService( "com.sun.star.test.TestDialogHandler" )
      oComp.createDialog( "vnd.sun.star.script:Library1.Dialog1?location=application", _
          null, StarDesktop.getActiveFrame() )
  End Sub

The dialog contained in the DialogComponent.odt sample document in SDK/examples/DevelopersGuide/Components/DialogComponent looks like this.

Sample dialog with controls

The button labels show which component method is called in each case. The next chapter explains how these methods can be implemented inside the component. Method "doit3" isn't implemented at all. It's called in the sample dialog to show the resulting error message:

Error message for Component method not found

Accept events created by dialog controls

The event handling functionality can be implemented in two different ways. The test component described here uses both ways.

The first way is to implement the generic handler interface com.sun.star.awt.XDialogEventHandler containing two methods:

  interface XDialogEventHandler: com::sun::star::uno::XInterface
  {
      bool callHandlerMethod
      (
          [in] com::sun::star::awt::XDialog xDialog, 
          [in] any Event,  
          [in] string MethodName 
      )
 
      sequence<string> getSupportedMethodNames();
  }

If an event occurs that is bound to a component method and the component implements this interface, the method callHandlerMethod will be called first, with the method name used in the event binding passed as MethodName parameter. In this example this would be:

  xHandler.callHandlerMethod( xDialog, aEvent, "handleEvent" );

xDialog points to the same dialog instance that has been returned by the createDialogWithHandler() method. Event represents the event object originally passed to the awt listener method. E.g. in case of the "When initiating" event used in this example the corresponding awt listener interface is com.sun.star.awt.XActionListener and an com.sun.star.awt.ActionEvent is passed to its actionPerformed method when the event occurs. This ActionEvent object will also be passed to callHandlerMethod. The Event object has to be passed as any, because other events use different listener interfaces with other event object types. callHandlerMethod returns a bool value. Returning true means that the event has been handled.

The method getSupportedMethodNames() should return the names of all methods handled by callHandlerMethod(). It's intended for later use, especially to expand the user interface to allow browsing a component's methods.

If the event has not been handled, because callHandlerMethod returns false or com.sun.star.awt.XDialogEventHandler isn't supported at all by the component, the DialogProvider uses the com.sun.star.beans.Introspection service to detect if one of the following methods is provided by one of the interfaces supported by the component:

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

or

  void [MethodName]( void );

The second method is only used if the first one is not available. In this example the component would have to support an interface containing a method handleEvent with one of these signatures. It also has to support com.sun.star.lang.XTypeProvider because otherwise the introspection mechanism does not work.

As already mentioned the sample component supports both ways to implement handler methods. com.sun.star.awt.XDialogEventHandler is implemented like this:

  private String aHandlerMethod1 = "doit1";
  private String aHandlerMethod2 = "doit2";
 
  //XDialogEventHandler
  public boolean callHandlerMethod( /*IN*/XDialog xDialog, /*IN*/Object EventObject, 
                                    /*IN*/String MethodName ) {
      if ( MethodName.equals( aHandlerMethod1 ) ) {
          showMessageBox( "DialogComponent", "callHandlerMethod() handled \"" + aHandlerMethod1 + "\"" );
          return true;
      }
      else if ( MethodName.equals( aHandlerMethod2 ) ) {
          showMessageBox( "DialogComponent", "callHandlerMethod() handled \"" + aHandlerMethod2 + "\"" );
          return true;
      }
      return false;
  }
 
  public String[] getSupportedMethodNames() {
      String[] retValue= new String[1];
      retValue[0]= aHandlerMethod1;
      retValue[1]= aHandlerMethod2;
      return retValue;
  }

The implementation is very simple to show only the logic. For the two handled method names the method displays a MessageBox and returns true. Otherwise false is returned.

The other methods bound to the sample dialog control events are implemented using the other way. The interface com.sun.star.test.XTestDialogHandler looks like this:

  module com { module sun { module star { module test { 
      interface XTestDialogHandler {  
          string createDialog( [in] string DialogURL, [in] ::com::sun::star::frame::XModel xModel, 
                                                      [in] ::com::sun::star::frame::XFrame xFrame ); 
      void copyText( [in] ::com::sun::star::awt::XDialog xDialog, [in] any aEventObject ); 
      void handleEvent();  
      void handleEventWithArguments( [in] ::com::sun::star::awt::XDialog xDialog, 
                                     [in] any aEventObject );  
      };
  }; }; }; };

Besides the already described createDialog method three methods are defined to handle events. handleEvent and handleEventWithArguments are implemented very simple and only display a message box:

  public void handleEvent() { 
      showMessageBox( "DialogComponent", "handleEvent() called" );
  } 
 
  public void handleEventWithArguments( XDialog xDialog, Object aEventObject ) { 
      showMessageBox( "DialogComponent", "handleEventWithArguments() called\n\n" +
          "Event Object = " + aEventObject );
  }

The method copy text shows, how the passed XDialog interface can be used to access controls on the dialog itself. The details are not described here. For more information see Creating Dialogs at Runtime.

  public void copyText( XDialog xDialog, Object aEventObject ) {
      XControlContainer xControlContainer = (XControlContainer)UnoRuntime.queryInterface(
          XControlContainer.class, xDialog );
 
      String aTextPropertyStr = "Text";
      String aText = "";
      XControl xTextField1Control = xControlContainer.getControl( "TextField1" ); 
      XControlModel xControlModel1 = xTextField1Control.getModel();
      XPropertySet xPropertySet1 = (XPropertySet)UnoRuntime.queryInterface(
      XPropertySet.class, xControlModel1 );
      try {
          aText = (String)xPropertySet1.getPropertyValue( aTextPropertyStr );
      }
      catch (Exception e) {
          e.printStackTrace();
      }
 
      XControl xTextField2Control = xControlContainer.getControl( "TextField2" ); 
      XControlModel xControlModel2 = xTextField2Control.getModel();
      XPropertySet xPropertySet2 = (XPropertySet)UnoRuntime.queryInterface(
          XPropertySet.class, xControlModel2 );
      try {
          xPropertySet2.setPropertyValue( aTextPropertyStr, aText );
      }
      catch (Exception e) {
          e.printStackTrace();
      }
 
      showMessageBox( "DialogComponent", "copyText() called" );
  }

Simple components using dialogs can be realized very easily by supporting XDialogEventHandler as then no own interfaces have to be created. For complex components it could make more sense to define handler interfaces to avoid a huge switch/case blocks in XDialogEventHandler:: callHandlerMethod.

Content on this page is licensed under the Public Documentation License (PDL).
Personal tools
In other languages