EMF und Notification Framework

G

Gast2

Hallo zusammen,

ich hätte ein paar Fragen zum Notification Framework von EMF. Ich nöchte einen ContentProvider für einen TableViewer machen.

1. Gibt es auch einen Adapter der nur auf ein Attribut reagiert oder muss immer überpüft werden, ob das richtige Attribut ankommt?

2. Ich verteh nicht für was die AdapterFactory genau da ist? Und was daran besser sein soll und wie man diese verwendet.

EMF generiert mir ja eine AdapterFactoryImpl aber die einzelenen createMyObjectAdapter sind alle mit null implementiertl.

Mit dem adapt kriert die Factory den richtigen Adapter und fügt diesen meinem eObject zu.
Aber wie bekomme ich den Adapter wieder aus der Liste raus? Bin ich dafür selber verantwortlich oder gehe ich dafür auch über den Adapter?

Wie gesagt seh den Vorteil der Factory noch nicht?!?


Java:
public class FahrtContentProvider implements IStructuredContentProvider{

	private MyEObject eObject;
	private Viewer viewer;
	private Adapter adapter;
	
	public FahrtContentProvider(){
		adapter = new EContentAdapter(){
			@Override
			public void notifyChanged(Notification notification) {
                                   //1. geht das auch leichter?
				   switch (notification.getFeatureID(MyEObject.class))
				    {
				      case KindergeldPackage.MYEOBJECT__PERSONLIST:
				      viewer.refresh();
				       break;
				    }
			}
		};
	eObject.eAdapters().add(adapter);
		
                 //2.
		 AdapterFactory someAdapterFactory = .;
		  Object requiredType = ...;
		  if(someAdapterFactory.isFactoryForType(requiredType))
		  {
		    Adapter theAdapter = someAdapterFactory.adapt(someObject, requiredType);
		    ...
		  }
		

	
	}
	
	@Override
	public void dispose() {
		eObject.eAdapters().remove(adapter);
		
	}

	@Override
	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
		this.viewer = viewer;
		
	}

	@Override
	public Object[] getElements(Object inputElement) {
		return eObject.getPersonList().toArray();
	}

}
 
Die generierte Factory ist primär zum extenden Gedacht um bestimmte Adaptertype zu erstellen.
Adapter sind nicht nur Listener, sie können auch verwendet werden um zusätzliche Funktionalität an ein Objekt anzuklinken.
Wenn es dir nur um einen Content Provider geht der automatisch den Tree aktualisiert, dann kannst du dir die Arbeit sparen:
Java:
treeViewer.setContentProvider(new AdapterFactoryContentProvider(new YourModelItemProviderAdapterFactory));
//beachte das 'Item' Provider Adapter Factory
Gleiches gibt es auch für den Label Provider, AdapterFactoryLabelProvider.
Wenn du dir die YourModelItemProviderAdapterFactory Klasse ansiehst, dann verstehst du vielleicht auch wie die generierte leere AdapterFactory zu verstehen ist.
 
G

Gast2

Okay das schau ich mir mal an...

Aber ich beschreib mein Problem nochmal genauer vielleicht kennst du dazu auch ne coole Variante ;)...

Also ich hab Object1 das hat eine 1:n beziehung zu Object2...

Das heißt Object1 hat eine EList<Object2>...

So nun stell ich von Object1 alle Object 2 in einem TableViewer dar.

Dafür hab ich dem oberen ContentProvider geschrieben. Es gibt einen Add/Remove Dialog für Object2.
Das heißt wenn ich Object1 ein Object2 hinzufüge muss ich ich den tableviewer refresehen. Aber ja nur auf das attribut von wenn sich die Liste änder darum der switch case.

Verständlich?:)
 
Das heißt wenn ich Object1 ein Object2 hinzufüge muss ich ich den tableviewer refresehen.
Nein, musst du nicht, der AdapterFactoryContentProvider und AdapterFactoryLabelProvider macht das automatisch, auch bei strukturellen Änderungen.
 
G

Gast2

okay versuche ich das mal... Extra nen eigenen geschrieben shit^^...
 
G

Gast2

Nein, musst du nicht, der AdapterFactoryContentProvider und AdapterFactoryLabelProvider macht das automatisch, auch bei strukturellen Änderungen.
Mhm also irgendwie kapier ich es nicht... hab mit jetzt den edit code generieren lassen

Hab nur ein Object1ItemProvider und ein Object2ItemProvider

und eine ItemProviderAdapterFactory dann hab ich folgendes gemacht aber es passiert gar nichts...

Java:
		tableViewer.setContentProvider(new AdapterFactoryContentProvider(new ItemProviderAdapterFactory()));
		tableViewer.setLabelProvider(new AdapterFactoryLabelProvider (new ItemProviderAdapterFactory()));

muss ich noch was bestimmtes aufrufen? Oder geht die Variante nur für TreeViewer?
Hier wird immer Null zurück gegegen da, das 2te if nicht gegeben ist. Was muss ich den in das setInput den reinmachen? Ich dachte die Liste die der tableviewer anzeigen soll ...
Java:
	@Override
	public Object adapt(Object object, Object type) {
		if (isFactoryForType(type)) {
			Object adapter = super.adapt(object, type);
			if (!(type instanceof Class<?>) || (((Class<?>)type).isInstance(adapter))) {
				return adapter;
			}
		}

		return null;
	}
Will eigentlich jetzt sowas machen object1.getObjects2().add(object2) und die Table soll ein refresh erhalten...
 
Zuletzt bearbeitet von einem Moderator:
G

Gast2

Lass deine generierten ItemProvider zusätzlich ITableItemContentProvider implementieren.
Siehe dazu hier im Kapitel Tables:
Using EMF
Der Labelprovider funktioniert einwandfrei =)...


Mhm was muss ich für den ContentProvider noch machen? DDie Tabelle wird nicht gerefreshed...
Was muss ich den als Input mitgeben? Object 1 oder die Liste von Object2?
 
Zuletzt bearbeitet von einem Moderator:
G

Gast2

Änderst du auch die gleiche Instanz die auch in der Tabelle enthalten ist?
Es kommt ersteinmal gar nichts in die Tabelle rein. Also ich hab ein AddCommand
und dann mach ich sowas object1.getObjects2().add(object)


Änderst du auch die gleiche Instanz die auch in der Tabelle enthalten ist?

Normal den Parent der Objekte die du anzeigen möchtest, du kannst aber auch eine Liste verwenden.
Hab beides versucht... Wenn ich den parent übergebe verstehe ich halt nicht woher er wissen soll dass er die Objekte 2 von objekt1 anzeigen lassen soll.
Muss ich den ItemProvider vom parent(Object1) auch händisch überarbeiten?
 
Hab beides versucht... Wenn ich den parent übergebe verstehe ich halt nicht woher er wissen soll dass er die Objekte 2 von objekt1 anzeigen lassen soll.
Muss ich den ItemProvider vom parent(Object1) auch händisch überarbeiten?
Im Genmodel kann man in der Properties View für jedes Feature eintragen ob es ein 'children' Feature ist. Standardmäßig passiert das bei Containment References. Aus dieser Information wird dann pro ItemProvider die getChildrenFeatures Methode generiert die dem ItemProvider sagt was er bei getChildren liefern soll.
 
G

Gast2

Im Genmodel kann man in der Properties View für jedes Feature eintragen ob es ein 'children' Feature ist. Standardmäßig passiert das bei Containment References. Aus dieser Information wird dann pro ItemProvider die getChildrenFeatures Methode generiert die dem ItemProvider sagt was er bei getChildren liefern soll.
Okay in dem part wo feature steht ist containment true

in dem part wo edit steht ist bei children false.


EDIT:

Also wenn ich edit children auf true setze und notify auf true dann klappts.

aber mein labelprovider wird noch nicht benachrichtigt wenn ich ein object aus der tabelle heraus veränder. das heißt bei den sturktur änderungen passt was noch nicht.
denkeder labelprovider bekommt keine struktur änderungen.
 
Zuletzt bearbeitet von einem Moderator:
Okay in dem part wo feature steht ist containment true

in dem part wo edit steht ist bei children false.
Wenn du das Feature erst anlegst nachdem das genmodel erstellt wurde auf, oder du es erst später auf Containment setzt, dann musst du das genmodel selbst anpassen (oder neu erstellen).
aber mein labelprovider wird noch nicht benachrichtigt wenn ich ein object aus der tabelle heraus veränder. das heißt bei den sturktur änderungen passt was noch nicht.
denkeder labelprovider bekommt keine struktur änderungen.
Gab mal ein Beispiel was und wie du es tust und was anschließend in der Tabelle passieren soll.
 
G

Gast2

Hier mal ein Beispiel für ein einfaches Ecore (nur eine Node die wieder Nodes enthalten kann).
[XML]<?xml version="1.0" encoding="UTF-8"?>
<ecore:EPackage xmi:version="2.0"
xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="providermodel"
nsURI="http://example.org/provider" nsPrefix="pr">
<eClassifiers xsi:type="ecore:EClass" name="Node">
<eStructuralFeatures xsi:type="ecore:EReference" name="children" upperBound="-1"
eType="#//Node" containment="true"/>
</eClassifiers>
</ecore:EPackage>[/XML]

Dann eine View um das ganze zu testen:
Java:
public class ViewPart1 extends ViewPart {

	private TreeViewer viewer;


	@Override
	public void createPartControl(final Composite parent) {
		viewer = new TreeViewer(parent);
		AdapterFactory factory = new ProvidermodelItemProviderAdapterFactory();
		viewer.setLabelProvider(new AdapterFactoryLabelProvider(factory));
		viewer.setContentProvider(new AdapterFactoryContentProvider(factory));
		final Node root = ProvidermodelFactory.eINSTANCE.createNode();
		Node child = ProvidermodelFactory.eINSTANCE.createNode();
		root.getChildren().add(child);
		viewer.setInput(root);
		parent.getDisplay().timerExec(1000, new Runnable() {
		
			@Override
			public void run() {
				root.getChildren().add(ProvidermodelFactory.eINSTANCE.createNode());
				parent.getDisplay().timerExec(1000, this);
			}
		});
		
	}

	@Override
	public void setFocus() {
		viewer.getControl().setFocus();

	}

}
Wie du siehst wird jede Sekunde eine neue Node hinzugefügt und die View aktualisiert sich vollautomatisch. Ob Tree, Table, Liste, oder sonstwas ist dabei egal. Wenn das bei dir nicht funktioniert, dann weil du irgendetwas anders machst als in diesem Beispiel und ohne zu wissen was du anders machst kann ich dir nicht helfen.
 
G

Gast2

Hier mal ein Beispiel für ein einfaches Ecore (nur eine Node die wieder Nodes enthalten kann).
[XML]<?xml version="1.0" encoding="UTF-8"?>
<ecore:EPackage xmi:version="2.0"
xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="providermodel"
nsURI="http://example.org/provider" nsPrefix="pr">
<eClassifiers xsi:type="ecore:EClass" name="Node">
<eStructuralFeatures xsi:type="ecore:EReference" name="children" upperBound="-1"
eType="#//Node" containment="true"/>
</eClassifiers>
</ecore:EPackage>[/XML]

Dann eine View um das ganze zu testen:
Java:
public class ViewPart1 extends ViewPart {

	private TreeViewer viewer;


	@Override
	public void createPartControl(final Composite parent) {
		viewer = new TreeViewer(parent);
		AdapterFactory factory = new ProvidermodelItemProviderAdapterFactory();
		viewer.setLabelProvider(new AdapterFactoryLabelProvider(factory));
		viewer.setContentProvider(new AdapterFactoryContentProvider(factory));
		final Node root = ProvidermodelFactory.eINSTANCE.createNode();
		Node child = ProvidermodelFactory.eINSTANCE.createNode();
		root.getChildren().add(child);
		viewer.setInput(root);
		parent.getDisplay().timerExec(1000, new Runnable() {
		
			@Override
			public void run() {
				root.getChildren().add(ProvidermodelFactory.eINSTANCE.createNode());
				parent.getDisplay().timerExec(1000, this);
			}
		});
		
	}

	@Override
	public void setFocus() {
		viewer.getControl().setFocus();

	}

}
Wie du siehst wird jede Sekunde eine neue Node hinzugefügt und die View aktualisiert sich vollautomatisch. Ob Tree, Table, Liste, oder sonstwas ist dabei egal. Wenn das bei dir nicht funktioniert, dann weil du irgendetwas anders machst als in diesem Beispiel und ohne zu wissen was du anders machst kann ich dir nicht helfen.
Ja das klappt bei mir auch, aber jetzt will von einem Node ein Attribut ändern. z.B. den Namen.
Dann wird die Instanz geändert aber der LabelProvider macht nichts. Weißt wie ich mein?
Ich mach morgen auch mal ein KSKB...
 
Ja das klappt bei mir auch, aber jetzt will von einem Node ein Attribut ändern. z.B. den Namen.
Dann wird die Instanz geändert aber der LabelProvider macht nichts. Weißt wie ich mein?
Ich mach morgen auch mal ein KSKB...
Nein, das stimmt nicht, siehe hier (ich habe im Ecore ein zusätliches Attribut 'name' eingefügt:
Java:
public class ViewPart1 extends ViewPart {

	private TreeViewer viewer;


	@Override
	public void createPartControl(final Composite parent) {
		viewer = new TreeViewer(parent);
		AdapterFactory factory = new ProvidermodelItemProviderAdapterFactory();
		viewer.setLabelProvider(new AdapterFactoryLabelProvider(factory));
		viewer.setContentProvider(new AdapterFactoryContentProvider(factory));
		final Node root = ProvidermodelFactory.eINSTANCE.createNode();
		Node child = ProvidermodelFactory.eINSTANCE.createNode();
		root.getChildren().add(child);
		viewer.setInput(root);
		parent.getDisplay().timerExec(1000, new Runnable() {
		
			@Override
			public void run() {
				root.getChildren().add(ProvidermodelFactory.eINSTANCE.createNode());
				parent.getDisplay().timerExec(1000, this);
				for (Node node : root.getChildren()) {
					node.setName(SimpleDateFormat.getTimeInstance().format(new Date()));
				}
			}
		});
		
	}

	@Override
	public void setFocus() {
		viewer.getControl().setFocus();

	}

}
 
G

Gast2

Mhm versuch ich morgen mal und mach es mit 2 verschiedene Klassen velleicht kannst mir dann mein fehler sagen wenn ich ein KSKB hab ;)...
 
G

Gast2

Danke jetzt klappts.

Ich hab 2 Unterschiede festgestellt:

1. In meinem genModel createChild false. Hab das genModel wegeschmissen und nochmal neu erzeugt.

2. Habe ich meinen beiden Provider (Label und Content) jeweils eine neue Factory mitgegeben anstatt die gleiche jetzt tuts =)...

Erspart echt viel Arbeit Danke für den Tip..
 
Passende Stellenanzeigen aus deiner Region:

Neue Themen

Oben