View speichern/laden beim schließen

SegFault

Bekanntes Mitglied
Ich habe folgendes Problem. Ich benutze eine View in der ich eine Tabelle habe. Diese benenutzt init(...,Memento memento) und saveState(Memento memento) Um den zustand der Tabelle (Spaltenbreite und Anordnung) zu speichern und beim öffnen wieder zu laden.
Nun das problem, die View soll Schließbar sein. Beim schließen wird aber nicht saveState ausgeführt. Sondern nur beim Workbench close. Wie kann ich also beim Schließen der View das Speichern auslösen (Ideal wäre wirklich das saveState was auch beim Workbench close verwendet wird, aber da müsste ich frisch an das Memento ran).

Dann ist das Problem der anzeige meiner view. es gibt eine .showView(ViewID) funktion. Dummerweise wird beim öffnen einer View damit auch nicht das init ausgelöst. Wie mache ich das also richtig das beim Schließen einer View der status wirklich gesichert wird und beim neu öffnen auf jeden fall wieder geladen.

Ich weiß das es dafür einen weg gibt. Denn der Klassenfenster von Eclipse nutzt das ganze. Das kann ich schließen und beim öffnen sind auch wieder die Pfade Expanded die es vorher schon waren.
 
G

Gast2

Gast
Ja bei der View gibts ein attribut restoreable vielleicht hilft dir das... Keiner Ahnung was das genau macht
 

SegFault

Bekanntes Mitglied
Das restorable Attribut gibt nur an ob die View beim öffnen des Workbenches wieder her gestellt wird. Das hat nichts mit dem schließen und öffnen zu tun. In dem Zusammenhang fällt mir noch eine Frage ein, wie kann ich eine View ausserhalb einer Perspektive Factory an bestimmter Stelle öffnen? Wie macht das Eclipse im allgemeinen. Der Package Explorer wird immer links angedockt, auch wenn ich ihn schließe und neu öffne. Wie mache ich sowas? Unabhängig von der Frage wie ich eine View komplett wiederherstellen kann. Denn das ini wird beim händischen öffnen einer View nicht mehr mit dem memento ausgeführt.
 

Wildcard

Top Contributor
View Positionen können im Layout als Platzhalter angelegt werden. Wenn die View dann in der Perspektive geöffnet wird, erscheint sie dort wo den den Platzhalter für die View positioniert hast.
 
G

Gast2

Gast
View Positionen können im Layout als Platzhalter angelegt werden. Wenn die View dann in der Perspektive geöffnet wird, erscheint sie dort wo den den Platzhalter für die View positioniert hast.

Wie ist es dann wenn man sie woanders hin verschiebt und neu öffnet??? Noch nie ausprobiert Oo... Morgen mal testen, ob die neues Postion gespeichert wird ^^...
 

SegFault

Bekanntes Mitglied
Hmm... die view immer wieder in den gleichen zustand zurück zu setzen ist also schwerer als ich dachte. Die Sachen vom RCP Erfordern das die View noch geöffnet ist. Beim neu öffnen der View wird diese nie mit init initialisiert (nur beim öffnen des Workbenches). Beim schließen der View wird nichts gespeichert, nur beim schließen des Workbenches. Wenn nicht jemand da wirklich net tolle sache kennt wie man sowas umsetzt muss ich mir was eigenes einfallen lassen. Dafür kommen auch noch ein paar fragen auf die kommen aber in einen anderen Thread. Ich lass das noch ein Tag offen ggf kommen noch ein paar gute Ideen wie man eine View dauerhaft Persisiteren kann. Ansonsten mach ichs demnächst als "erledigt"
 

SegFault

Bekanntes Mitglied
Wie schon gesagt, so einfach scheints nicht zu gehen. Meine Idee ist gerade folgende:
Ich bau einen Service bei dem die einzelnen Views einen State anfordern können (Mit einer unique id) aus diesen werden die entsprechenden Werte geladen. Zusätzlich müssen die Views garantieren das sie alle änderungen direkt wieder in dieses State Objekt schreiben. Nach dem schließen des Views ist dieses State Objekt ja noch vorhanden da es vom Service verwaltet wird. Beim schließen des Workbenches kann ich dann alle der State Objekte speichern bzw beim startup wieder initialisieren. Sofern niemanden was besseres einfällt wäre das wohl ne möglichkeit das ganze so um zu setzen.
 

SegFault

Bekanntes Mitglied
Die Version mit dem Service klappt ganz gut. Ich hab auch Vererbung eingesetzt damit ich beliebige Objekt Per Memento Persistieren kann. Ich denke mal das lager ich aus um es ggf bei anderen Projekten weiterverwenden zu können.
 

dzim

Top Contributor
Hm, ich finde das ist tatsächlich eine interessante Frage, die du hier aufwirfst... Ich geb zu, ich hab nur die Hälfte verstanden, da ich bisher weder mit Mementos noch Services gearbeitet habe.
Kannst du mir da ein paar Tipps geben?

Ich habe, damit ich nicht völlig unwissend daher komme gerade mal versucht einen View mit Memento zu versehen und hinterher die Daten erst einmal nur auszulesen, aber mein Test (ich starte immer aus eclipse heraus mein product) hat nirgendwo die workbench.xml angelegt und somit auch hinter nichts wieder auslesen können...

Folgendes habe ich zum speichern genutzt (kA ob ich wirklich alle sachen so bekommen hätte, wie gewollt, aber irgendwas hätte kommen müssen):
Java:
public void saveState(IMemento memento) {
	IMemento pShelfMemento = memento.createChild(PHSELF_MEMENTO);

	PShelfItem selectedPShelfItem = shelf.getSelection();
	pShelfMemento
			.createChild(SELECTED_PLUGIN, selectedPShelfItem.getText());
		Control[] pShelfItemControls = selectedPShelfItem.getBody()
			.getChildren();

	if (pShelfItemControls.length == 1
			&& pShelfItemControls[0] instanceof Tree) {
		Tree pluginTree = (Tree) pShelfItemControls[0];

		TreeItem[] selection = pluginTree.getSelection();

		if (selection != null) {
			for (TreeItem taskItem : selection) {
				pShelfMemento
						.createChild(SELECTED_TASK, taskItem.getText());
			}
		}
	}
}

Mus da noch was beachtet werden?

Danke und Grüße,
Daniel
 

SegFault

Bekanntes Mitglied
ich hab aktuell wenig Zeit... ich schau mir das heut nachmittag an. Das mit den Mementos geht halt gut hat aber einige Tücken. Die da wären:

Sobald eine View komplett geschlossen wird und innerhalb der sitzung wieder geöffnet wird, wird sie nicht aus dem Memento geladen. (In diesen fall ist memento==null beim init).
Ist die View geschlossen wenn der Workbench geschlossen wird kann auch nichts gespeichert werden. D.H. die einstellungen für diese View sind nach dem neustart weg (das xml file wird jedesmal neu angelegt).

Bei deinen Code fällt mir folgendes auf. Du legst ein child im PShelfMemento an ohne dir die Referenz darauf zu geben.
Java:
IMemento mymemento = pShelfMemento
            .createChild(SELECTED_PLUGIN, selectedPShelfItem.getText());
        Control[] pShelfItemControls = selectedPShelfItem.getBody()
            .getChildren();

da dies die Wurzel für alle Tasks ist kannst du dann machen

Java:
mymemento.putString(taskItem.getText())

Du musst dir immer vorstellen dass du einen baum aufbaust. CreateChild erstellt einen weiteren Knoten und gibts dir eine Referenz zurück. mit .putString .putInteger etc kannst du in den Knoten daten speichern. Mit getString... lieferst du die entsprechenden Werte die in den Knoten gespeichert sind wieder zurück.

zum auslesen machst du dann etwas wie:

Java:
//liefert alle subnodes von PSHELF_MEMENTO
IMemento[] items = memento.getChilds(PHSELF_MEMENTO);
for ( IMemento mem : items )
{
   IMemento[] selecteditems = mem.getChilds(SELECTED_PLUGIN);
   for ( IMemento item : selecteditems )
   {
        ... item.getString(SELECTED_TASK);
   }
}

Der Code ist weder getestes noch wirklich vollständig. Ist nur ein ansatz wie man das macht. Kann (und wird) also noch einige fehler enthalten.

P.S.: Sofern dich der andere Weg interessiert (also das man views restoren kann selbst wenn die View zwischendrinn geschlossen wird, kann ich gerne meinen Ansatz über den Dienst mal näher ausführen.
 
Zuletzt bearbeitet:

dzim

Top Contributor
Hi,

ich hab (auch zu dem kurzfristigen Speichern) folgenden link bei, googlen entdeckt:
FAQ How does a view persist its state between sessions? - Eclipsepedia

Aber ich würde auch gern deine Variante hören!

Ich hab das Speichern jetzt so abgeändert:
Java:
@Override
	public void saveState(IMemento memento) {
		super.saveState(memento);

		IMemento pShelfMemento = memento.createChild(PHSELF_MEMENTO);

		PShelfItem selectedPShelfItem = shelf.getSelection();
		pShelfMemento.putString(SELECTED_PLUGIN, selectedPShelfItem.getText());

		Control[] pShelfItemControls = selectedPShelfItem.getBody()
				.getChildren();

		if (pShelfItemControls.length == 1
				&& pShelfItemControls[0] instanceof Tree) {
			Tree pluginTree = (Tree) pShelfItemControls[0];

			TreeItem[] selection = pluginTree.getSelection();

			if (selection != null) {
				for (TreeItem taskItem : selection) {
					pShelfMemento.putString(SELECTED_TASK, taskItem.getText());
				}
			}
		}
	}

Allerdings wird noch immer nichts gespeichert... Ich habe aber noch zwei Ideen, warum evtl. nicht:
1) Ich habe das setSaveAndRestore(true) in der initialize-Methode des ApplikationWorkbenchAdvisor nicht eingeschaltet
2) Der View an dem ich es teste, ist nur ein ShortView, der über die Extension eingestellt und normalerweise nicht standardmäßig sichtbar ist.

Ich werde das mal austesten...
 

SegFault

Bekanntes Mitglied
1.) ist das Problem. Du musst Save and Restore auf on schalten ansonsten wird das init mit den memento nicht aufgerufen.
Das Tutorial was du gefunden hast hatte ich auch gefunden. Wie schon gesagt, das hat seine tücken wenn das View schließbar ist. Sobald du dein Workbench beendest während das View geschlossen ist werden keine Einstellungen zu dem View gespeichert. Mit unter ist so etwas gewollt aber bei mir nicht. Ich würde gerne den Aufbau der View auch dann speichern wenn sie geschlossen wurde.
 

dzim

Top Contributor
Ok, dann danke für den Tipp mit dem ersten Problem.

Wenn du irgendwann noch mir verraten kannst, wie das über die Services gelöst hast, wäre das Klasse - das heißt, wenn du darfst ;-)
 

SegFault

Bekanntes Mitglied
Das ganze wird jetzt etwas ausführlicher. Der Code für den Service:
Java:
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map.Entry;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.XMLMemento;

import de.weiss.werksattclient.tools.persistableitems.PersistableNode;
import de.weiss.werkstattclient.service.IPersistableItemService;

public class PersistableItemService implements IPersistableItemService
{

	private static final String ROOT_ID = "STORABLE_DATA";
	private HashMap<String,PersistableNode> data = new HashMap<String,PersistableNode>();
	
	
	public PersistableItemService() 
	{
		
	}

	public PersistableNode getNode(String id)
	{
		return data.get(id);
	}
	
	public void addNode(String id, PersistableNode node)
	{
		data.put(id, node);
	}
	
	
	public void saveState()
	{
		try
		{
			XMLMemento memento = XMLMemento.createWriteRoot(ROOT_ID);
			for ( Entry<String, PersistableNode> ent : data.entrySet())
			{
				IMemento child = memento.createChild("PERSISTABLE_ITEM",ent.getKey());
				child.putString("classname", ent.getValue().getClass().getName());
				ent.getValue().saveState(child);
			}
			Writer writer = new FileWriter(PersistableItemService.getMementoFile());
			memento.save(writer);
		}
		catch ( Exception ex )
		{
			Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Fehler beim öffnen von Memento", ex));
		}
	}
	
	public void loadState()
	{
		try
		{
			data.clear();
			FileReader reader = new FileReader(PersistableItemService.getMementoFile());
			XMLMemento memento = XMLMemento.createReadRoot(reader);
			IMemento[] childs = memento.getChildren("PERSISTABLE_ITEM");
			if ( childs == null)return;
			for (IMemento child : childs)
			{
				String classname = child.getString("classname");
				PersistableNode node = (PersistableNode)Class.forName(classname).newInstance();
				node.restoreState(child);
				data.put(child.getID(), node);
			}
		}
		catch ( Exception ex )
		{
			Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Fehler beim laden von Memento", ex));
		}
	}
	
	private static File getMementoFile() throws IOException
	{
		File mementofile = Activator.getDefault().getStateLocation().append("persistable_data.xml").toFile();
		if (!mementofile.exists())
		{
			mementofile.createNewFile();
			XMLMemento memento = XMLMemento.createWriteRoot(ROOT_ID);
			Writer writer = new FileWriter(mementofile);
			memento.save(writer);
				
		}
		return mementofile;
	}
}
Zusätzlich gibts es ein interface was Klassen Implementieren müsse welche gespeichert werden sollen:
Java:
public interface PersistableNode 
{
	public abstract void saveState(IMemento memento);
	public abstract void restoreState(IMemento memento);
};
Hier mal eine Implementierung davon (Ist dazu das die Ordnung innerhalb einer Tabelle und die Tabellenspalten dazu zu speichern), saveState und restoreState hat im grunde den selben sinn wie beim View
Java:
public class PersistableTableData implements PersistableNode 
{
	private LinkedList<TableHeading> heading = new LinkedList<TableHeading>();
	private int[] columnpos;
	
	public void setColumnPos(int[] cp)
	{
		this.columnpos = cp;
	}
	
	public int[] getColumnPos()
	{
		return this.columnpos;
	}
	
	public LinkedList<TableHeading> getHeading()
	{
		return heading;
	}
	
	public void addHeading(TableHeading heading)
	{
		this.heading.add(heading);
	}
	
	public void clearHeading()
	{
		this.heading.clear();
	}
	
	@Override
	public void restoreState(IMemento memento) 
	{
		clearHeading();
		IMemento[] pos =  memento.getChildren("pos");
		this.columnpos = new int[pos.length];
		for ( int i = 0; i < pos.length; ++i)this.columnpos[i] = pos[i].getInteger("p");
		IMemento[] columndata = memento.getChildren("columns");
		for ( IMemento mem : columndata)
		{
			String name = mem.getString("name");
			int width = mem.getInteger("width");
			boolean resizable = mem.getBoolean("resizeable");
			boolean moveable = mem.getBoolean("moveable");
			TableHeading th = new TableHeading(name,width,resizable,moveable);
			this.heading.add(th);
		}
		
	}

	@Override
	public void saveState(IMemento memento)
	{
		for ( int i : this.columnpos)
		{
			IMemento pos = memento.createChild("pos");
			pos.putInteger("p", i);
		}
		for ( TableHeading th : this.heading)
		{
			IMemento columns = memento.createChild("columns");
			columns.putString("name",th.heading);
			columns.putInteger("width", th.size);
			columns.putBoolean("resizeable", th.resizeable);
			columns.putBoolean("moveable", th.moveable);
		}
		
	}
	

}
Und hier der Aktivator des Plugins welcher den Service anbietet. (Laden des zustandes beim starten und speichern beim beenden)

Java:
/*
 * (non-Javadoc)
 * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
 */
public void start(BundleContext context) throws Exception {
	super.start(context);
	System.out.println("Activating tools");
	plugin = this;
	pis = new PersistableItemService();
	context.registerService(IDataProviderService.class.getName(), new DataProvider(), null);
	context.registerService(IPersistableItemService.class.getName(), pis, null);
	pis.loadState();
}

/*
 * (non-Javadoc)
 * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
 */
public void stop(BundleContext context) throws Exception {
	System.out.println("Deactivating tools");
	pis.saveState();
	plugin = null;
	super.stop(context);
}
Und hier mal eine Beispielmethode in der ich den Service nutze um die Daten für meine Tabelle an zu fordern
Java:
private void restore()
{
	ServiceReference ref = Activator.getDefault().getBundle().getBundleContext().getServiceReference(IPersistableItemService.class.getName()); 
	IPersistableItemService pis = (IPersistableItemService)Activator.getDefault().getBundle().getBundleContext().getService(ref);
	ptd = (PersistableTableData) pis.getNode(id);
	if ( ptd != null )
	{
		heading = ptd.getHeading();
		createHeaders();
	}
	else
	{
		ptd = new PersistableTableData();
		pis.addNode(this.id, ptd);
	}
}
Im grunde läuft der Service darauf hinaus das man bei ihm über eine id instanz von PersistableData anfordern kann. Die kann dann natürlich alles enthalten. Es muss nur sichergestellt werden das in die instanz von PersistableData alle änderungen wieder reingeschrieben werden, die dann gespeichert werden sollen. Sofern die id über die man die PersistableData anforder noch nicht vergeben ist wird null zurück gegeben. Dann muss man die natürlich anlegen.

Ein paar Tücken hat das ganze.: Es könnten id's enthalten sein die gar nicht mehr benötigt werden. Diese muss man wohl von hand aus der entsprechenden xml Datei löschen oder das ganze Prinzip noch etwas aufbohren. Aktuell hat das ganze noch ein paar Probleme (Siehe meinen Beitrag zum Thema das ich das XMLMemento noch nicht korrekt lesen kann) aber ich denke das krieg ich behoben.
 
Zuletzt bearbeitet:
Ähnliche Java Themen
  Titel Forum Antworten Datum
K Position einer Multiple View speichern Plattformprogrammierung 6
S RCP Nach erfolgreicher Erstellung der View, wie weitermachen? Plattformprogrammierung 1
G RCP Show View Command bestimmte View nicht erlauben Plattformprogrammierung 2
S RCP ActionBar Icon nur aktiv, wenn Selection in bestimmter View Plattformprogrammierung 6
M Plugin - Property Page - Get IResource in View Plattformprogrammierung 4
R Eclipse RCP Tabellen-View (Anfängerfrage) Plattformprogrammierung 3
L RCP Eigene View für EditorPart? Plattformprogrammierung 3
M RCP TableViewer schrumpft in View nach manueller Resize auf 1 Zeile Plattformprogrammierung 5
M EMF und Tabbed Properties View Plattformprogrammierung 4
Madlip RCP View austauschen/ändern Plattformprogrammierung 9
B RCP View aktualisieren bei Änderung 2. View Plattformprogrammierung 8
F RCP EMF View Plattformprogrammierung 13
K RCP View wird nicht angezeigt Plattformprogrammierung 2
L RCP Detached View beim Starten des RCPs? Plattformprogrammierung 3
F Tollbar Items disabled wenn View den Focus verliert Plattformprogrammierung 3
S RCP name einer view ändern Plattformprogrammierung 2
L RCP Help in eine View einbinden? Plattformprogrammierung 3
G RCP Menüpunkt Show View Plattformprogrammierung 7
G EMF -> Leere Elemente sollen in Property View nicht angezeigt werden Plattformprogrammierung 9
E eclipse RCP Properties View: ein Element aus Liste pro Zeile anzeigen Plattformprogrammierung 1
Z Eclipse RCP - UDP Strom in View anzeigen Plattformprogrammierung 4
L RCP Canvas in einer View? Plattformprogrammierung 4
lumo Eclipse + 'Could not create view' Plattformprogrammierung 5
L RCP View in einem Editor öffnen? Plattformprogrammierung 3
D Canvas auf View in Eclipse PlugIn Plattformprogrammierung 3
T RCP Menubar wird durch OLE-VIEW überschrieben Plattformprogrammierung 4
S Plugin: View beim Button-Klick austauschen Plattformprogrammierung 7
Saxony View als Image Plattformprogrammierung 2
S View Refreshen Plattformprogrammierung 2
T geladene Views / Event wenn View closed Plattformprogrammierung 4
S Steuerung View (Schließen erkennen/Hide anstatt Close) Plattformprogrammierung 2
L View schließen Plattformprogrammierung 7
L View nicht bekannt machen Plattformprogrammierung 4
lumo View aktivieren jedesmal wen.... Plattformprogrammierung 7
A Overlay in View eines anderen Plug-Ins zeichnen Plattformprogrammierung 2
A View ansprechen Plattformprogrammierung 5
T GMF Property View Plattformprogrammierung 4
M Command in Toolbar aktiv wenn View nicht aktiv Plattformprogrammierung 2
C RCP: Veraenderungen innerhalb einer View per Extension?! Plattformprogrammierung 7
T JSVGCanvas in RCP View anzeigen Plattformprogrammierung 5
ARadauer Mehrere Gui Elemente in View Plattformprogrammierung 4
B RCP - Zugriff von View auf andere View Plattformprogrammierung 4
Saxony [Eclipse RCP] Von woanders View updaten Plattformprogrammierung 11
S View aus anderen Thread aktualisieren Plattformprogrammierung 15
S RCP Anfängerfrage - Zusammenspiel View, Editor, Model Plattformprogrammierung 4
G View Daten übergabe. Plattformprogrammierung 4
N Nicht schließbare View? Plattformprogrammierung 7
C View updaten Teil 2 Plattformprogrammierung 2
B Eclipse RCP: View updaten Plattformprogrammierung 10
dzim Editor aus View öffnen - fehler: unbekannte Editor ID Plattformprogrammierung 11
J Editorfenster von View navigieren lassen? Plattformprogrammierung 5
T Aus einem View in das andere wecheln. Plattformprogrammierung 13
R SWT: nur eine Instanz einer View erlauben Plattformprogrammierung 5
J Variablen speichern? Plattformprogrammierung 2
B RCP Projekt settings speichern Plattformprogrammierung 2
P RCP An Datei speichern (Protokolldatei) Plattformprogrammierung 2
TheWhiteShadow RCP Editor Inhalt speichern Plattformprogrammierung 3
G RCP Resource in User home speichern Plattformprogrammierung 3
D Plugin - Properties ohne PropertyPage speichern Plattformprogrammierung 11
H GEF Modell/Diagramm im XML-Format speichern Plattformprogrammierung 6
musiKk RCP Eclipse: Speichern von Spaltenbreiten Plattformprogrammierung 9
L RCP JFace Treeviewer speichern? Plattformprogrammierung 6
T Speichern eines Objectes in einem Editor (mit isDirty) Plattformprogrammierung 6
S TableView einstellungen speichern Plattformprogrammierung 5
B Simple Action beim Speichern in Eclipse... Plattformprogrammierung 2
T GEF: Speichern Plattformprogrammierung 6
N Speichern von Einstellung Plattformprogrammierung 6
Spot84 speichern funktion aktivieren Plattformprogrammierung 3
N Eclipse RCP: Perspektiven speichern Plattformprogrammierung 6
G OSGi Ressourcen aus anderem Bundle laden Plattformprogrammierung 15
M OSGi Probleme / Unklarheiten beim laden von DLL's Plattformprogrammierung 4
N OSGi: Ressourcen gezielt aus bestimmten Modulen laden? Plattformprogrammierung 4
L RCP Views nacheinander laden? Plattformprogrammierung 2
T Java Rcp Plugin laden Plattformprogrammierung 4
M Klasse aus PLugin /Fragment anhand von String laden Plattformprogrammierung 3
G Activator Bilder laden Plattformprogrammierung 3
dzim java.lang.ClassNotFoundException beim laden eines Plugins Plattformprogrammierung 10
T [RCP] Was passiert genau beim laden eines Plugins? Plattformprogrammierung 4

Ähnliche Java Themen

Neue Themen


Oben