RCP Eclipse RCP: Wo/wann im Plugin ist workbench initialisiert?

  • Themenstarter Themenstarter tuxedo
  • Beginndatum Beginndatum
T

tuxedo

Gast
Hallo zusammen,

hab hier eine Eclipse RCP Anwendung die aus mehreren Plugins besteht. Eines der Plugins soll ein Untermenü in der Menüleiste dynamisch erweitern können. Hab das mal experimentell aufgebaut, und das geht auch recht gut.

Das Problem das ich nun habe ist folgendes:

Der Inhalt des Untermenüs ist abhängig von der Selektion im Editor (der aus einem anderen Plugin stammt) bzw. der Selektion in einem View (welcher ebenfalls aus einem anderen Plugin stammt).

Meine Aktuelle Lösung würde so aussehen:

Java:
			IWorkbench workbench = PlatformUI.getWorkbench();
			IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();

			window.getSelectionService().addSelectionListener(new ISelectionListener() {
				
				@Override
				public void selectionChanged(IWorkbenchPart part, ISelection selection) {
					System.out.println("part="+part+" selection="+selection);				
				}
			});
			System.err.println("SelectionListener registered!");

Ich regsitriere also global einen Selection-Listener. In dessen Implementierung muss ich dann nur noch auswerten was selektiert wurde und dann ggf. das Menü aktualisieren. Dieser Listener soll in dem Plugin laufen, von dem auch das Menü angepasst wird. Nur brauche ich dazu die workbench-Instanz.

Und ich hab aktuell keinen Schimmer, wie ich von einem Plugin aus so früh wie möglich an eine gültige workbench-Instanz komme. Über die Activator-Klasse des Plugins hab ich's schon mit der start() Methode probiert. Doch start() wird aufgerufen bevor es eine Workbench-Instanz gibt.

Hat jemand nen Tiopp für mich an welcher Stelle ich im Plugin den Listener registrieren kann, es also schon eine Workbench-Instanz gibt?

Gruß
Alex
 
hm? läuft das plugin nicht in einer workbench? muss es die workbench nicht vor dem plugin geben?

edith:
Java:
	public Activator() {
		IWorkbench wb = PlatformUI.getWorkbench();
		System.out.println(wb);
	}

ausgabe: org.eclipse.ui.internal.Workbench@15b25a1
habs gerade probiert, also in constructor vom Activator hat der die workbench doch schon

oder versteh ich was falsch?
 
Zuletzt bearbeitet:
Wenn ich das in der Activator-Klasse mache, die im "hauptprojekt" neben der "ApplicationWorkbenchAdvisor" Klasse liegt, dann ja. Aber nicht wenn ich das in der Activator-Klasse des anderen Plugins, welches aber in der gleichen Workbench laufen soll mache...

Hab jetzt mehrfach gelesen, dass man mit

Java:
UIJob job = new UIJob("RegisterListener") {
			
			@Override
			public IStatus runInUIThread(IProgressMonitor monitor) {
				WallColorBrightnessProfilesHandler.registerListener();
				return Status.OK_STATUS;
			}
		};

innerhalt vom
Code:
Activator#start()
das ganze im UI Thread ausführen kann, und das dann logischerweise erst ausgeführt wird, wenn Workbench mit dem UI da ist. Nur dummerweise wird das bei mir gar nie ausgeführt?!

*rätsel*

- Alex
 
Also die ganzen "führ's doch im UI aus" Tipps von Stackoverflow.com helfen kein bisschen. Hab das ganze jetzt mal debugged:

Der UIJob wird gecancelled, eben weil noch kein UI da ist... Man, ich krieg noch nen Vogel :shock: .. Kann doch nicht so schwer sein ein Plugin erst dann zu starten/aktivieren wenn das Workbench da ist???:L Aber ich komm nicht drauf...

- Alex
 
Als ob ich da nicht auch schon drauf gekommen wäre. Aber wenn du mir erklären kannst (link oder stichwort wäre schonmal hilfreich) wie ich deklarativ ein Untermenü anlege, dessen weitere Verzweigung und Kommandos abhängig von der Selektion eines View/Editors sind, dann würde mich das auch zur Lösung bringen.

Gruß
Alex

[update]
Das bringt mich ein kleines Stückchen weiter:
Help - Eclipse SDK

Damit hab ich jetzt schonmal ein initialisiertes Workbench-Objekt. Jetzt muss ich nur noch den Listener registrieren können. Bis dato hab ich das über

Java:
IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
window.getSelectionService().addSelectionListener(new ISelectionListener() {
...

gemacht. Aber das Window scheint noch nicht dazu sein sein :autsch:

[update2]

So, hab das erste Teilproblem tatsächlich lösen können:

1) Startup Expenstion Point einrichten und auf Klasse zeigen lassen, die IStartup implementiert
2)
Java:
@Override
	public void earlyStartup() {
		mLogger.info("Early Startup");

		final IWorkbench workbench = PlatformUI.getWorkbench();
		mLogger.info("Workbench=" + workbench);
		
		
		UIJob job = new UIJob("RegisterSelectionListenerForDynamicCBPMenu") {
			
			@Override
			public IStatus runInUIThread(IProgressMonitor monitor) {
				IWorkbenchWindow activeWindow = workbench.getActiveWorkbenchWindow();
				mLogger.info("UI activeWindow=" + activeWindow);
				
				activeWindow.getSelectionService().addSelectionListener(new ISelectionListener() {
					@Override
					public void selectionChanged(IWorkbenchPart part, ISelection selection) {
						System.err.println("part=" + part + " selection=" + selection+" class="+selection.getClass());
					}
				});
				mLogger.info("SelectionListener registered!");
				
				return Status.OK_STATUS;
			}
		};
		job.schedule();
	}
 
Zuletzt bearbeitet von einem Moderator:
Ich würde es mit den Command Core Expressions versuchen. Hier ist der Link Command Core Expressions - Eclipsepedia

Hier ein auszug aus der plugin.xml:

[XML]
<extension
id=""
name=""
point="org.eclipse.ui.handlers">
<handler
class="com.commands.OpenInEditor"
commandId="com.commands.OpenInEditor">
<activeWhen>
<with
variable="selection">
<iterate
ifEmpty="false">
<instanceof
value="org.eclipse.jdt.ui.CompilationUnitEditor">
</instanceof>
</iterate>
</with>
</activeWhen>
</handler>
</extension>
[/XML]
 
Und wie krieg ich damit dynamisch, in abhängigkeit von der Selektion in diversen Views/Editoren Sub-Menü's (deren Anzahl ist abhängig von der Selektion) erzeugt/entfernt und nicht nur aktiviert/deaktiviert/sichtbar/unsichtbar gemacht?

Um es etwas präziser zu umschreiben:

Es ist ein Konfig-Menü in dem es ein Sub-menü "Presets" gibt. Darin gibt es dann bis zu 5 Presets und eine "Save current as" Aktion die ein neues Preset anlegt. Jeder Preset-Menü-Eintrag lässt sich nochmal aufklappen, und darin befinden sich verschiedene Commandos.

Die im Menü anzuzeigenden Presets hängen von der Selektion in einem View, bzw. der Selektion in einem Editor ab. Klickt man auf das eine, kann es z.b. 3 Presets geben, klickt man auf das andere gibt vielleicht keinen, und beim nächsten gibts 5.

Mit meiner Lösung geht das nun. Ich hab im Plugin einen SelectionListener registriert, der global alle Selektionen mitbekommt und basierend auf der Selektion das Menü umbaut.

- Alex
 
Zuletzt bearbeitet von einem Moderator:
Das aktiveWhen reagiert auf eine Variable in dem gezeigten Beispiel ist es selektion. Es kann aber auch die Variable activeEditor verwendet werden. Dann musst du noch angeben bei welchen Editor der Menüpunkt aktiv sein soll. Ist der entsprechende Editor aktiv wird Menüpunkt aktiviert oder deaktiviert.
Anstelle von aktiveWhen kannst du auch enabledWhen verwenden, dann wird der Menüpunkt nur angezeigt wenn der entsprechende Editor aktiv ist.

Du musst für jedes Command einen Handler definieren und dann entsprechend die Bedingungen definieren.

Das ganze ist etwas kompliziert, aber wenn man es verstanden hat ist es sehr mächtig und auch leicht zu verwenden.
 
Ja, das leuchtet mir schon ein. Ich kann menupunkte/Unterpunkte haben die basierend auf Variablen und folglich auch Selektionen aktiviert/deaktiviert oder sichtbar/unsichtbar sind. Aber bei mir änder sich ja die Anzahl der Menüpunkte und die dahinterliegende Referenz je nach Selektion. Heute sinds bis zu 5 Presets die ich so über's Menu abfahren muss. Das würde ggf. noch statisch gehen. Würde man dann einfach 5 Einträge anlegen und nur die Aktivierung/Sichtbarkeit steuern und über andere Variablen im Handler die dahinterliegende Referenz abbilden. Aber morgen brauch ich evtl schon 10 solcher dynamischer Untermenüs's oder sogar im Worstcase unbegrenzt viele. In dem Fall ist es wohl flexibler und (jetzt auch) einfacher das programmatisch zu fahren, als mit aller Gewalt das pseudo-dynamisch deklarativ zu lösen.
 
Die Argumentation verstehe ich nicht. Wenn sich die Anzahl der Menüs ändert, musst du derzeit doch auch Code ändern. Inwiefern ist das also dynamischer?
Ich denke der deklarative Ansatz ist dynamischer, denn du kannst neue Menüs dann auch durch neue Bundles oder Fragmente bereitstellen.
Ausserdem hat der deklarative Ansatz den großen Vorteil das dein Bundle nicht gestartet werden muss, bis es wirklich benötigt wird, also Code zur Ausführung kommt.
 
Die Argumentation verstehe ich nicht. Wenn sich die Anzahl der Menüs ändert, musst du derzeit doch auch Code ändern.

Nö, muss ich nicht. Die Menüeintrage und die Anzahl sind Laufzeitabhängig. Kommt drauf an was ich selektiere.

Inwiefern ist das also dynamischer?
Ich denke der deklarative Ansatz ist dynamischer, denn du kannst neue Menüs dann auch durch neue Bundles oder Fragmente bereitstellen.

Dynamischer deshalb, weil es davon abhängt was ich wann anklicke. Wenn ich das deklarativ mache, dann ist das solange statisch, bis ich das deklarierte anfasse. Okay, es auch auch ein klein wenig dynamisch, da ich in Abhängigkeit von Variablen im System Menüpunkte ein/ausblenden aktivieren/deaktivieren kann. Aber ich bin damit immernoch auf das, was ich mal deklariert habe eingegrenzt. Ich kann nicht dynamisch beliebiug viele Menüpunkte hinzufügen wenn ich das statisch deklariert habe.

Ausserdem hat der deklarative Ansatz den großen Vorteil das dein Bundle nicht gestartet werden muss, bis es wirklich benötigt wird, also Code zur Ausführung kommt.

Das ist für mich irrelevant.

Ich versuchs meine Requirements nochmal genauer zu formulieren:

Die Anwendung soll Displaywände, die aus mehreren Displays besteht steuern. Steuern im Sinne von Helligkeit, Farbabgleich, welcher Eingang an jeweiligen Display, ...

Die Anwendung kann viele Displaywände ansteuern. Und jede Displaywand hat 0..n Profile für Helligkeit+Kontrast+Farbe.

Je nachdem welche Displaywand ich in der Anwendung in einem View oder im Editor selektiere, soll in der Menüleiste "Konfiguration" im Untermenu "Profile" die einzelnen Profile der jeweils selektierten Displaywand als weiteres Untermenü von "Profile" auftauchen. Und dieses Untermenü hat dann Kommandos wie "löschen", "anwenden", "umbenennen", ...

Code:
Menüleiste
         +-----------[Konfigurieren]
                                   +-----------[Profile]
                                                       +--------[Profil 1]
                                                       |                 +------löschen
                                                       |                 +------anwenden
                                                       |                 +------umbenennen
                                                       |                 +------....
                                                       +--------[Profil ...]
                                                       |                   +------löschen
                                                       |                   +------anwenden
                                                       |                   +------umbenennen
                                                       |                   +------....
                                                       +--------[Profil n]
                                                                         +------löschen
                                                                         +------anwenden
                                                                         +------umbenennen
                                                                         +------....

Je nachdem ob ich jetzt die eine, oder andere Wand selektiere, hab ich eine unterschiedliche Anzahl an Profilen im Menü sichtbar. ich wüsste nicht wie ich das deklarativ festlegen, und wie das dann noch dynamisch sein soll.

Deklarativ hab ich festgelegt dass es ein Menu "Profile" gibt. Aber dynamisch, per Code generiert, sind die Untermenüs "Profil x" (die natürlich beliebig heissen können).
 
Ach, jetzt hab ich dich verstanden. Die Anzahl der Menüs bestimmt sich nicht alleine aus Code, sondern wird aus Nutzdaten berechnet. Ja, da hast du tatsächlich keine andere Wahl als programmatisch vorzugehen.
 

Zurück
Oben