Eclipse RCP
20.09.2010 - 24.09.2010, Hamburg
git
07.10.2010 - 08.10.2010, Essen
Eclipse RCP

Rezepte

Plug-in Spy verwenden, um Eclipse-Komponenten aufzuspüren

Der Eclipse Plug-in Spy erlaubt Ihnen, die Klasse und das Plug-in zu UI-Komponenten in Eclipse zu lokalisieren. Betätigen Sie dazu die Tastenkombination “Alt+Shift+F1” und der Plug-in Spy erscheint mit allen Informationen zum aktuell geöffneten Element:

Screenshot

Um den Plugin-Spy für RCP-Anwendungen zu aktivieren, starten Sie die Anwendung mit dem Plug-in org.eclipse.pde.runtime.

Commands programmatisch ausführen

Möchten Sie einen Command programmatisch ausführen, sollten sie den Handler nicht direkt instantiieren, sondern den HandlerService dazu verwenden, um den aktuell gültigen Handler für den Command auszuführen:

IHandlerService handlerService = (IHandlerService) PlatformUI.getWorkbench()
    .getService(IHandlerService.class);
handlerService.executeCommand("com.example.somecommand", null);

Commands: Expressions erweitern mit Property-Testern

Ein Property Tester erlaubt es, die Ausdrücke zur Evaluierung von Expressions zu ergänzen. Diese können beispielsweise bei der Aktivierung von Handlern für die Selektion verwendet werden, um Werte des selektierten Objekts abzufragen. Nehmen wir an, wir möchten einen Handler nur dann aktivieren, wenn es sich bei der ausgewählten Adresse um eine Firma handelt.

Dazu müssen wir unserem Plug-in zunächst eine Abhängigkeit zum Plug-in org.eclipse.core.expressions hinzufügen, da dieses den Extension Point zur Deklaration eigener Property Tester bereitstellt:

Require-Bundle: [...],
 org.eclipse.core.expressions

Nun können wir einen Property Tester deklarieren. Ein Property Tester bekommt eine eindeutige ID, eine implementierende Klasse und ist gültig für den angegebenen Objekttyp type. Der Name des Properties setzt sich aus einem Namespace und dem Namen zusammen, im folgenden Beispiel “com.example.addressbook.isCompany”:

<extension point="org.eclipse.core.expressions.propertyTesters">
   <propertyTester
         id="com.example.addressbook.AddressPropertyTester"
         class="com.example.addressbook.AddressPropertyTester"
         type="com.example.addressbook.entities.Address"
         namespace="com.example.addressbook"
         properties="isCompany"/>
</extension>

Die Implementierung hat zur Evaluierung des Properties das receiver-Objekt (wie im type-Attribut deklariert) und den Namen des Properties zur Verfügung. Zusätzlich kann der Nutzer des Properties eine Liste von Argumenten und einen erwarteten Wert angeben, die dem PropertyTester übergeben werden:

public class AddressPropertyTester extends PropertyTester {

    @Override
    public boolean test(Object receiver, String property, Object[] args, Object expectedValue) {
        return ((Address) receiver).isCompany();
    }

}

Ein solcher Property-Tester kann nun in test-Elementen verwendet werden:

<test property="com.example.addressbook.isCompany" forcePluginActivation="true"/>

Möchten wir beispielsweise einen Menüeintrag nur für Firmen aktivieren, könnten wir dies folgendermaßen erreichen:

<extension point="org.eclipse.ui.handlers">
    <handler class="com.example.SomeHandler" commandId="com.example.SomeCommand">
        <activeWhen>
            <with variable="selection">
                <iterate ifEmpty="false" operator="or">
                    <and>
                        <instanceof value="com.example.addressbook.entities.Address"/>
                        <test property="com.example.addressbook.isCompany"/>
                    </and>
                </iterate>
            </with>
        </activeWhen>
    </handler>
</extension>

Commands: Expressions mit Source Providern um eigene Variablen erweitern

Mit dem Extension Point org.eclipse.ui.services können Sie eigene Variablen zur Verwendung in with-Elementen bei der Aktivierung von Commands und Command-Handlern deklarieren. Dazu deklarieren Sie einen SourceProvider und spezifizieren die bereitgestellten Variablen. Da die Evaluierung von Variablen nach Prioritäten gewichtet wird (eine Prüfung auf das aktive View mittels activePartId ist beispielsweise höher priorisiert als die Prüfung auf die geöffnete Perspektive), müssen Sie mittels priorityLevel angeben, wie Ihre eigene Variable priorisiert wird:

<extension point="org.eclipse.ui.services">
   <sourceProvider provider="com.example.SomeSourceProvider">
      <variable name="com.example.someVariable" priorityLevel="activePartId"/>
   </sourceProvider>
</extension>

Den SourceProvider leiten Sie von AbstractSourceProvider ab und spezifieren, welche Variablen bereitgestellt werden und wie diese belegt sind:

public class SomeSourceProvider extends AbstractSourceProvider {
    private static final String SOME_VAR = "com.example.someVariable";

    public Map getCurrentState() {
        HashMap<String, String> values = new HashMap<String, String>();
        values.put(SOME_VAR, "someValue");
        return values;
    }

    public String[] getProvidedSourceNames() {
        return new String[] { SOME_VAR };
    }
}

Dabei ist zu beachten, dass fireSourceChanged immer dann aufgerufen werden muss, wenn sich der Wert einer Variable verändert hat, da die Eclipse Plattform die Variablen nur bei Bedarf evaluiert.

Eine so deklarierte Variable können Sie in Expressions mit einem with-Element abfragen:

<extension point="org.eclipse.ui.handlers">
   <handler class="com.example.SomeHandler" commandId="com.example.someCommand">
      <activeWhen>
         <with variable="com.example.someVariable">
            <equals value="someValue"/>
         </with>
      </activeWhen>
   </handler>
</extension>

Commands: Dynamisches aktualisieren mit IElementUpdater

Es besteht die Möglichkeit, dass ein Handler zugehörige UI-Elemente wie Menüeinträge oder Toolbar-Buttons verändert. Nehmen wir an, Sie möchten den Text eines Menüeintrages entsprechend der aktuellen Selektion ergänzen:

IElementUpdater

Lassen Sie dazu Ihren Handler das Interface IElementUpdater implementieren. In der updateElement-Methode können Sie nun das UI-Element manipulieren:

public class SendEmailHandler extends AbstractHandler implements IElementUpdater {

    @Override
    public Object execute(ExecutionEvent event) throws ExecutionException {
        //...
    }

    @Override
    public void updateElement(UIElement element, Map parameters) {
        String text = "E-Mail senden";
        ISelection selection = PlatformUI.getWorkbench().getActiveWorkbenchWindow()
                .getSelectionService().getSelection();
        if (!selection.isEmpty() && selection instanceof IStructuredSelection) {
            Object selectedObject = ((IStructuredSelection) selection).getFirstElement();
            if (selectedObject instanceof Address) {
                Address address = ((Address) selectedObject);
                text = "E-Mail an " + address.getName() + " senden";
            }
        }
        element.setText(text);
    }

}

Dem UIElement können Sie folgende Eigenschaften setzen:

Der Element-Updater wird automatisch ausgeführt, sobald sich die Umgebung verändert. Im obigen Beispiel wird immer, wenn sich die Selektion ändert, auch SendEmailHandler.updateElement ausgeführt und der Menüeintrag aktualisiert. Möchten Sie auf Ereignisse außerhalb der Kontrolle von Eclipse reagieren, können Sie programmatisch eine Aktualisierung über den CommandService auslösen:

ICommandService commandService = (ICommandService) PlatformUI.getWorkbench().getService(
    ICommandService.class);
commandService.refreshElements("com.example.addressbook.email", null);

Commands: Checkbox/Toggle-Menücontributionen

Mit folgendem Rezept können Sie umschaltbare Menü-/Toolbareinträge realisieren:

Toggling commands

Contributen Sie den Command wie gewohnt über org.eclipse.ui.menus, geben Sie jedoch style="toggle" an:

<extension point="org.eclipse.ui.menus">
    <menuContribution
        locationURI="menu:com.example.somemenu">
            <command commandId="com.example.somecommand" style="toggle"/>
    </menuContribution>
</extension>

Fügen Sie Ihrem Command ein state-Element mit der ID STYLE und der Klasse ToggleState hinzu. Dieses State-Objekt wird den aktuellen Zustand des Commands aufnehmen:

<command id="com.example.somecommand" name="SomeCommand">
    <state class="org.eclipse.jface.commands.ToggleState" id="STYLE"/>
</command>

Fügen Sie ihrem Projekt die ToggleHandler-Klasse hinzu und implementieren Sie Ihren eigenen Handler basierend auf ToggleHandler:

public class SomeCommandHandler extends ToggleHandler {

      @Override
      protected void executeToggle(ExecutionEvent event, boolean checked) {
            System.out.println(checked);
      }

}
Dr. Michael Mock, 21. April, 20:36 Uhr

Hinweis aus zum "automatischen" Ausfuehren der udpateElement() methode:
http://blog.eclipse-tips.com/2009/02/commands-part-5-authentication-in-rcp.html
One last piece, the Command Framework will call the updateElement() method only when the value of the variables in the *when expression is changed.

Über Ihre Kommentare und Hinweise freue ich mich sehr:
Ralf Ebert | Eclipse RCP Buch | Rezepte