RCP EMF View

  • Themenstarter Themenstarter freak_007
  • Beginndatum Beginndatum
Weil ich ein eigenes Resourceplugin für mein Karteikastenprogramm brauch. Da hab ich mir gedacht wenn es bei Editoren geht dann sollte es auch bei Viewparts gehen. Und ein DnD haben will.
 
Also du willst so etwas wie den generierten Editor als View haben.
Du kannst den Editor als Basis nehmen und dann statt extends EditorPart extends ViewPart schreiben.
Danach musst du ein paar Methoden anpassen und insbesondere musst du dir überlegen wo die Resource herkommt. Sollte nicht weiter schwierig werden.
Du kannst auch einfach eine View from-scratch Schreiben. Mit dem AdapterFactoryContentProvider und AdapterFactoryLabelProvider hast du schonmal den Baum. Drag'n'Drop wird ebenfalls über die ItemProvider realisiert, schau es dir einfach im generierten Editor ab.
 
Hallo,

ich häng mich mal mit dran, da ich mir die selbe Frage gestellt habe.

Also kann ich mir über den Extension-Point org.eclipse.ui.views in meinem RCP Plugin zunächst mal eine View erstellen.
Dort benutze ich dann einen TreeViewer (oder was auch immer für einen Viewer).
Welche Content- bzw. LabelProvider muss ich denn konkret dann benutzen? Kann ich einen von den Modelspezifischen benutzen? Also sagen wir, ich habe ein Model "Organ", dann gibt es ja "OrganItemProvider". Kann ich diesen als Content- und LabelProvider benutzen oder muss ich irgendwie Umwege gehen?

Weil es gibt dort ja keine konkrete getElements-Methode oder sowas. Im Editor gibt es so Zeilen wir
Code:
selectionViewer.setContentProvider(new AdapterFactoryContentProvider(adapterFactory));

Da steig ich aber noch nicht so hinter, wie genau die funktionieren.

Also konkrete Frage:
  1. Welchen Content- und LabelProvider muss ich meinem Viewer konkret übergeben?
  2. Wo modifiziere ich die "üblichen" Methoden (z.B. getChildren...)?

Für einen Hinweis wäre ich sehr dankbar.

MfG
M@ndy
 
1. AdapterFactoryContentProvider und AdapterFactoryLabelProvider.
Diese generischen Provider schlagen den richtigen ItemProvider für dein Model in einer Registry nach und delegieren dann anschließend an die generierten ItemProvider. Die Provider aktualisieren auch automatisch den Viewer wenn das Modell verändert wird, ist also ein Rundum sorglos Paket.

2. Im jeweiligen generierten ItemProvider. Du kannst um EMF Genmodel auch einstellen was die 'children feature' einer Klasse sind (per Default alle Containment Referenzen) dann wird die getChildren passend erzeugt. Wenn du flexiblere Logik brauchst kannst du wie gesagt den generierten ItemProvider händisch anpassen.
 
Hallo Wildcard,

1. also ist der Aufruf erstmal identisch mit dem in der Editor-Klasse. Wenn ich das richtig verstanden habe, dürfte es so also nicht möglich sein, mit dem CNF zu arbeiten, da man dem AdaptarFactoryContent- und LabelProvider ja eine AdapterFactory übergeben muss, was ich mir schwierig vorstelle, wenn ich das im navigatorContent-ExstensionPoint in der plugin.xml eintragen soll. Hab auch noch keine Beispiel von EMF und CNF gesehen.
Nur so ein Randgedanke. Werd mich erstmal mit meiner "normalen" View auseinandersetzen.

2. Werd mal mit den genmodel-Einstellungen ein bisschen rumspielen.

Danke für die Hinweise. Sobald es hakt, schrei ich wieder ;-)

Lieben Gruß
M@ndy
 
Doch, CNF und EMF ist kein Problem. Implementiere die nötigen Interfaces einfach selbst und delegiere die entsprechenden Tasks einen AdapterFactoryLabelProvider und AdapterFactoryContentProvider.
GMF integriert EMF übrigens auch in CNF.
 
Ist zwar schon ein bisschen her, aber immernoch bzw. wieder aktuell für mich.

Hab jetzt in einer RCP-Anwendung (eine eigene, nicht den EMF Editor als RCP) eine View erzeugt mit einem TableViewer.

Content- und Labelprovider hab ich wie oben beschrieben eingebunden, die AdapterFactory entsprechend angelegt:

Code:
adapterFactory = new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE);

31:  adapterFactory.addAdapterFactory(new ResourceItemProviderAdapterFactory());
32:  adapterFactory.addAdapterFactory(new SongmanagerItemProviderAdapterFactory());
33:  adapterFactory.addAdapterFactory(new ReflectiveItemProviderAdapterFactory());
		
viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL| SWT.V_SCROLL);
		
viewer.setContentProvider(new AdapterFactoryContentProvider(adapterFactory));
viewer.setLabelProvider(new AdapterFactoryLabelProvider(adapterFactory));

Problem:
Wenn ich das so aber starte, kann er das edit-Plugin (aus dem die ContentProvider ja kommen) nicht dynamisch laden.

Die erste Meldung vom Stack:
Code:
!ENTRY org.eclipse.osgi 4 0 2011-09-09 10:05:34.693
!MESSAGE An error occurred while automatically activating bundle com.vknie.songmanager.edit (6).
!STACK 0
org.osgi.framework.BundleException: The activator songmanager.provider.SongmanagerEditPlugin$Implementation for bundle com.vknie.songmanager.edit is invalid

Hier ist noch ne Zeile, die sich auf den Code oben bezieht:

Code:
at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:107)
at java.lang.ClassLoader.loadClass(Unknown Source)
at com.vknie.songmanager.rcp.views.KopfdatenView.createPartControl(KopfdatenView.java:32)

Die erste Idee, das edit-Plugin unter die Dependencies zu packen, ging nicht, weil ich das Plugin gar nicht hinzufügen KANN (es wird nicht angeboten, vermutlich weil das edit-Plugin über das editor-Plugin mit eingebunden wird).

Jetzt hab ich im Netz schon gelesen, dass der Fehler daher kommt, dass ich schon ein Objekt aus dem Plugin erzeuge (nämlich die Provider), was noch nicht geladen wurde und dass man dieses Plugin vorher in der start-Methode der Application laden soll.

Aber wie macht man das? Hab mich mit OSGI noch nicht so auseinandergesetzt. Bis dato "ging immer alles so".

Über Hinweise oder einen kleinen Code-Schnipsel würde ich mich sehr freuen.

Lieben Gruß
M@ndy
 
Zuletzt bearbeitet:
Jetzt hab ich im Netz schon gelesen, dass der Fehler daher kommt, dass ich schon ein Objekt aus dem Plugin erzeuge (nämlich die Provider), was noch nicht geladen wurde und dass man dieses Plugin vorher in der start-Methode der Application laden soll.
Hmm, nein, das Framework startet das Bundle automatisch sobald die erste Klasse geladen wird, das sollte kein Problem sein.
Hast du noch mehr der Logausgabe?
Falls nein, ist der Edit Code manuell geändert, oder noch komplett generiert?
Wenn alles noch komplett generiert ist, würde ich empfehlen das ganze '.edit' Projekt nochmal zu löschen und neu generieren zu lassen. Möglich das da irgendetwas kaputt gegangen ist.
 
Löschen und neu anlegen hat erstmal geholfen. Keine ahnung, was da schief gelaufen ist. Wollte schon wahnsinnig werden.

Das nächste wird jetzt sein, die Resource aus dem Wizard in die View zu bekommen. Im Original ModelWizard-Code wird in der performFinish-Methode ja ein Editor geöffnet. Könnte ich genauso jetzt den Input eines TableViewers meiner View setzen? Wenn ja, wie komm ich an meine konkrete View?
 
Wenn du sonst keine Referenz hast, kannst du über PlatforumUI auf die aktuelle Page zugreifen. Irgendwo dort sollte es dann Methoden geben um eine View anzuzeigen, hab's gerade nicht im Kopf.
 
Ja, dort gibt es eine showView und eine findView-Methode.

Jetzt hab ich aber ein ganz anderes Problem und frage mich gerade, ob ich es mir unnötig kompliziert mache.

Zwecks anständiger Code-Trennung habe ich 4 Plugins:
songmanager.model,
songmanager.edit,
songmanager.editor und
songmanager.rcp

Mein Wizard befindet sich (wie von EMF vorgesehen) in dem editor-Plugin.
Meine View hab ich in dem rcp-Plugin.
Selbstverständlich hat das rcp-Plugin eine Dependency auf das Editor-Plugin (das ist ja quasi mein Kern).

Wenn ich aber nun aus der performFinish-Methode meines Wizards im editor-Plugin auf die spezielle View aus dem rcp-Plugin zugreifen möchte (casten, damit ich eine selbstgeschriebene getViewer()-Methode aufrufen kann um den input zu setzen), muss ich eine Dependency (bzw. imported packages) zurück auf das rcp-Plugin machen, was natürlich zu einem Cycle führt.

Hab ich es jetzt mit meiner Code-Trennung übertrieben und sollte ich die View besser in das Editor-Plugin packen oder gibt es einen anderen Weg aus diese Dilemma?

Über eine baldige Antwort freut sich
M@ndy

P.S. Dieses Projekt macht mich noch wahnsinnig 😀
 
Dein Problem ist, das Views erstmal primär als Hilfsfenster für den Hauptbereich, den Editor, gedacht sind. Daher haben Views keinen expliziten Input sondern reagieren meistens auf die aktuelle Selektion.
Da hast drei offensichtliche Möglichkeiten:
1. Die View wandert ins Editor Bundle
2. Der Wizard wandert ins RCP Bundle
3. Der Wizard definiert einen Extension Point damit das RCP Bundle die Möglichkeit hat eigenen Code auszuführen wenn der Wizard sich beendet.

Letztere Alternative bietet sich vor allem an wenn da eventuell noch weitere Views dazukommen die ebenfalls etwas anzeigen sollen wenn sich der Wizard beendet.
 

Zurück
Oben