# View updaten Teil 2



## crackstone (15. Jul 2008)

Hallo allerseits,

*EDIT: problem hat sich gelöst, wie immer, dann wenn man mal nachfragt kommt 5 minuten später die lösung daherspaziert. --> hab ein notifyListeners() vergessen. :roll: *

Ich beschäftige mich seit ein paar Tagen mit RCP und stehe im Moment einfach total an.
Die Tutorials im Netz sind alle wunderbar, nur sobald ich anfange darauf aufbauend weiter zu programmiern fehlt es mir an Hintergrundwissen.
Mein Problem ist folgendes. Ich habe eine Liste von Personen und möchte mit einem Wizard Personen hinzufügen. Der Wizard klappt wunderbar, die Person ist auch hinzugefügt jedoch bekomm ich es einfach nicht hin den View in dem die Personen zu sehen ist upzudaten um die neue Person anzuzeigen.

Ich habe mir dazu schon folgenden Thread angesehen: http://java-forum.org/de/viewtopic.php?t=68656&highlight=view+updaten, bin jedoch auch damit nicht weit gekommen.

Vom Prinzip her ist mir klar, dass ich irgendwo einen Listener brauche der wenn die Person hinzugefügt wurde den View updated - Nur wie update ich die View - was muss ich aufrufen um den View mal zu clearen. Ich denke dabei an folgenden Ablauf:

removeEverything <-- wie mach ich das?
und dann einfach noch creatPartControl aufrufen

Ist das die richtige Variante?

Anbei mein Code vom View und dem ContentProvider:

View:

```
public class View1 extends ViewPart {
	public static final String ID = "project1.views.View1";
	private Action doubleClickAction;
	private Action singleClickAction;
	private TableViewer viewer;
	private IViewSite viewSite;
	private Composite parent;
	private MyModel model;

	public void createPartControl(Composite parent) {
		
		this.parent = parent;
		viewSite = getViewSite();
		viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL
				| SWT.V_SCROLL);
		viewer.setContentProvider(new MyContentProvider(viewer, this));
		viewer.setLabelProvider(new MyLabelProvider(this));
		viewer.getTable().setLinesVisible(true);
		viewer.setInput(getViewSite());
		// New
		hookDoubleClickAction();
		hookSingleClickAction();
		contributeActions();
		getSite().setSelectionProvider(viewer);
		// New contextm
		MenuManager menuManager = new MenuManager();
		Menu menu = menuManager.createContextMenu(viewer.getTable());
		// Set the MenuManager
		viewer.getTable().setMenu(menu);
		getSite().registerContextMenu(menuManager, viewer);
		// Make the selection available
		getSite().setSelectionProvider(viewer);
	}

	public void setFocus() {
		viewer.getControl().setFocus();
	}
	
	public void refreshView() {
		System.out.println("refreshView()");
		viewer.refresh();
	}

	// New
	private void hookDoubleClickAction() {
		viewer.addDoubleClickListener(new IDoubleClickListener() {
			public void doubleClick(DoubleClickEvent event) {
				doubleClickAction.run();
			}
		});
	}

       .............. hier gehts dann weiter mit doubleclick und singleclick Listenern
```

ContentProvider:


```
public class MyContentProvider implements IStructuredContentProvider, PropertyChangeListener {

	private MyModel content;
	private final Viewer viewer;
	private View1 view;
	public MyContentProvider(Viewer viewer, View1 view) {
		this.viewer = viewer;
		this.view = view;
		content = new MyModel();
		content.addChangeListener(this);
	}

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

	@Override
	public void dispose() {
	}

	@Override
	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
		// TODO Auto-generated method stub
	}

	@Override
	public void propertyChange(PropertyChangeEvent arg0) {
//		viewer.refresh();
		view.refreshView();
	}

 }
```

Ziel ist es in der refreshView() Methode den View neu aufzubauen. Was ich dabei bis jetzt nicht hinbekommen hab war es den View überhaupt erstmal komplett zu clearen, löschen, removen was auch immer es braucht um den Inhalt neu aufbauen zu können.

clear, remove und refresh haben dabei eben nichts geholfen.

Ich bin dankbar für jeden Denkanstoss oder Code Schnippsel.

Stehe einfach an!

mfg
-stone 

*EDIT: problem hat sich gelöst, wie immer, dann wenn man mal nachfragt kommt 5 minuten später die lösung daherspaziert. --> hab ein notifyListeners() vergessen. :roll: *


----------



## dzim (15. Jul 2008)

Hallo erstmal!

Also du hast da ein sehr seltsam verlinktes Model. Du kannst es dir ausserhalb ja nicht mal holen, wie willst du es da ändern? Das finde ich sehr unflexibel.
Ich gebe zu, das ich bis jetzt auch nicht so genau weiß, wo ich das Modell am besten verlinken sollte, ich hab mich aber (derzeit) für den Activator des Plug-Ins entschieden und lasse es dort als statisches Objekt liegen und hole es mir auch mit einer statischen Methode.
Ich habe es in meinem letzten Projekt so gemacht, dass ich im Modell ein Objekt der Klasse PropertyChangeSupport hatte, dass ich mit add-/removePropertyChangeListener(...) ansprechen konnte und das in den Gettern und Settern der Model-Bean ein .firePropertyChange(...) aufgerufen hat.
Wenn du dann von deinem View PropertyChangeListener implementieren lässt und auch den View am Model anmeldest kannst du in der entsprechenden propertyChange(...) Methode auch deinen Table- oder Whatever-Viewer "refreshen" lassen.

Model-Beispiel:

```
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);

	private List<FileEntry> files;

	public List<FileEntry> getFiles() {
		return files;
	}

	public void setFiles(List<FileEntry> files) {

		final List<FileEntry> old = this.files;

		this.files = files;

		this.pcs.firePropertyChange("files", old, files);
	}

	public void addFile(FileEntry file) {

		List<FileEntry> newFiles = null;

		if (this.files != null) {
			for (FileEntry fe : this.files) {
				if (fe.getName().equals(file.getName())) {
					return;
				}
			}
			newFiles = new LinkedList<FileEntry>(this.files);

		} else {
			newFiles = new LinkedList<FileEntry>();
		}

		FileEntry newFileEntry = new FileEntry(file, this);
		newFiles.add(newFileEntry);

		this.pcs.firePropertyChange("files", this.files, newFiles);

		this.files = newFiles;
	}

	public void addFiles(List<FileEntry> files) {

		List<FileEntry> newFiles = null;

		if (this.files != null) {
			newFiles = new LinkedList<FileEntry>(this.files);
			for (FileEntry fe : files) {
				boolean contains = false;
				for (FileEntry old_fe : this.files) {
					if (fe.getName().equals(old_fe.getName())) {
						contains = true;
						break;
					}
				}
				if (!contains) {
					newFiles.add(fe);
				}
			}
		} else {
			newFiles = new LinkedList<FileEntry>(files);
		}

		this.pcs.firePropertyChange("files", this.files, newFiles);

		this.files = newFiles;
	}

	public void removeFile(FileEntry file) {

		final List<FileEntry> old = this.files;

		if (this.files == null) {
			return;
		}

		if (!this.files.contains(file)) {
			return;
		}

		this.files.remove(file);

		this.pcs.firePropertyChange("files", old, files);
	}

	public void addPropertyChangeListener(PropertyChangeListener listener) {
		this.pcs.addPropertyChangeListener(listener);
	}

	public void removePropertyChangeListener(PropertyChangeListener listener) {
		this.pcs.removePropertyChangeListener(listener);
	}
```

So hab ich mir im View das Model geholt (getModel() ist statisch)

```
torrentViewer.setInput(Activator.getModel().getFiles());
```

Hier die ganze PropertyChange-Geschichte aus dem View

```
private void resgisterPropertyChangeListener() {
		Activator.getModel().addPropertyChangeListener(this);
	}

	@SuppressWarnings("unchecked")
	@Override
	public void propertyChange(PropertyChangeEvent evt) {

		String message = "Property \"" + evt.getPropertyName()
				+ "\" reports a change:" + "\n\t";

		if (evt.getPropertyName().equals("files")) {

			List<FileEntry> old_list = (List<FileEntry>) evt.getOldValue();
			List<FileEntry> new_list = (List<FileEntry>) evt.getNewValue();

			message += "old (List-size): "
					+ ((old_list == null) ? "null" : old_list.size())
					+ ", new (List-size): " + new_list.size();

			this.refreshViewer((List<FileEntry>) evt.getNewValue());

		} else if (evt.getPropertyName().toLowerCase().startsWith("file-")) {

			if (evt.getOldValue() instanceof String) {

				message += "old (file-name): " + (String) evt.getOldValue()
						+ ", new (file-name): " + (String) evt.getNewValue();

			} else if (evt.getOldValue() instanceof File) {

				message += "old (file-file): "
						+ ((File) evt.getOldValue()).getName()
						+ ", new (file-file): "
						+ ((File) evt.getNewValue()).getName();

			} else if (evt.getOldValue() instanceof Boolean) {

				message += "old (file-boolean): "
						+ ((Boolean) evt.getOldValue())
						+ ", new (file-boolean): "
						+ ((Boolean) evt.getNewValue());
			}

			this.refreshViewer(Activator.getModel().getFiles());
		}

		System.err.println(message);
		Logger.logInfo(message);
	}

	public void refreshViewer(List<FileEntry> newEntries) {

		this.viewer.setLabelProvider(labelProvider);
		this.viewer.setInput(newEntries);
		this.viewer.refresh();
	}
```

Die letzte methode wäre den Refresh von ausserhalb zu machen, dazu musst du einen UIJob implementieren (könntest du also auch im Model machen - finde ich mittlerweile zwar gut zu wissen das es geht, aber eher unsauber). Du müsstest dir im UIJob über die PlatformUI deinen View holen und dann refreshen - geht alles, ist aber glaub ich umständlicher als das Ding mit dem Model...

Grüßle


----------



## crackstone (15. Jul 2008)

Wow!

Danke für diese Beschreibung als alternative. Mein Code basiert schwer auf dem Tutorial von Lars Vogel.
Bin jetz mal froh dass es klappt, denn ich kämpf schon wieder mit den nächsten Dingen...

Schönen Nachmittag noch
-cstone


----------

