# MultiPageEditor isDirty



## Kris (8. Feb 2010)

Hallo

Ich habe eine Klasse abgeleitet von FormEditor. In der Methode createPages werden Klassen, die von FormPage abgeleitet werden, hinzugefügt. Wenn aus einer Seite etwas verändert wird, dann reagiert isDirty nicht. Wie kann man es so einrichten, dass bei einer Veränderung der Editor als Dirty dargestellt wird?
So wie im Produkt oder Projekt Editor.


----------



## Gast2 (9. Feb 2010)

Zeig mal ein bischen Code...


----------



## Kris (9. Feb 2010)

Im FormEditor:

Das Problem in der isDirty-Methode ist, dass diese erst beim Focuserhalt des Fensters oder beim öffnen und schliessen aufgerufen wird.


```
@Override
	protected void createPages() {
		try {
			createPage1();
			createPage2();
                } catch (PartInitException e) {
			e.printStackTrace();
		}
	}

        private void createPage1() throws PartInitException {
		perDaten = new PersoenlicheDaten(this, person);
		int index = addPage(perDaten);
		setPageText(index, "Persönliche Daten");
	}

	private void createPage2() throws PartInitException {
		medDaten = new TeilnehmerMedizinischeDaten(this, person);
		int index = addPage(medDaten);
		setPageText(index, "Medizinische Daten");
	}

@Override
	public boolean isDirty() {
		if(perDaten.isDirty()){
			return true;
		}
		if (this.medDaten.isDirty()) {
			return true;
		}
		return false;
	}
```

Im FormPage:


```
public class PersoenlicheDaten extends FormPage {

	private Person person;
	private Text vorname;
	private Text nachname;
	private DateChooserCombo geburtsdatum;
	private Text staatsabgehoerigkeit;

	public PersoenlicheDaten(FormEditor editor, Person person) {
		super(editor, "Personalien", "Persönliche Daten");
		this.person = person;
	}

         // Getter und Setter

	protected void createFormContent(IManagedForm managedForm) {
		ScrolledForm form = managedForm.getForm();
		FormToolkit toolkit = managedForm.getToolkit();
		form.setText("Titel");
		//form.setBackgroundImage(FormArticlePlugin.getDefault().getImage(
		//		FormArticlePlugin.IMG_FORM_BG));
		ColumnLayout layout = new ColumnLayout();
		form.getBody().setLayout(layout);
		createPersonalienSection(form, toolkit, "Personalien");
	}

	@Override
	public boolean isDirty() {
		if(!nachname.getText().equals(person.getNachname())){
			return true;
		}
		return false;
	}

	private void createPersonalienSection(final ScrolledForm form,
			FormToolkit toolkit, String title) {
		Section sectionPersonalien = toolkit.createSection(form.getBody(),
				Section.DESCRIPTION | Section.TITLE_BAR | Section.TWISTIE
						| Section.EXPANDED);
		toolkit.createCompositeSeparator(sectionPersonalien);
		Composite client = toolkit
				.createComposite(sectionPersonalien, SWT.WRAP);
		GridLayout layout = new GridLayout();
		layout.numColumns = 2;
		client.setLayout(layout);
		GridData gdPer = new GridData(GridData.FILL_HORIZONTAL);
		Label labelVorname = toolkit.createLabel(client, "Vorname", SWT.NONE);
		labelVorname.setVisible(true);
		vorname = toolkit.createText(client, person.getVorname(), SWT.BORDER);
		vorname.setLayoutData(gdPer);
		Label labelNachname = toolkit.createLabel(client, "Nachname", SWT.NONE);
		labelNachname.setVisible(true);
		nachname = toolkit.createText(client, person.getNachname(), SWT.BORDER);
		nachname.setLayoutData(gdPer);
		Label labelGeburtsdatum = toolkit.createLabel(client, "Geburtsdatum",
				SWT.NONE);
		labelGeburtsdatum.setVisible(true);
		Composite dateChooser = toolkit.createComposite(client, SWT.BORDER);
		geburtsdatum = new DateChooserCombo(dateChooser, SWT.NONE);
		geburtsdatum.setTheme(DateChooserTheme.CLASSIC);
		geburtsdatum.setWeeksVisible(true);
		geburtsdatum.setFooterVisible(true);
		Label labelStaatsangehörigkeit = toolkit.createLabel(client,
				"Staatsangehörigkeit", SWT.NONE);
		labelStaatsangehörigkeit.setVisible(true);
		staatsabgehoerigkeit = toolkit.createText(client, person
				.getStaatsangehoerigkeit(), SWT.BORDER);
		staatsabgehoerigkeit.setLayoutData(gdPer);
		sectionPersonalien.setText(title);
		sectionPersonalien.setDescription("Hier werden die Personalien");
		sectionPersonalien.setClient(client);
		sectionPersonalien.setExpanded(true);
		sectionPersonalien.addExpansionListener(new ExpansionAdapter() {
			public void expansionStateChanged(ExpansionEvent e) {
				form.reflow(false);
			}
		});
	}

	@Override
	public void dispose() {
		super.dispose();
	}
```


----------



## Gast2 (9. Feb 2010)

Kris hat gesagt.:


> Im FormEditor:
> 
> Das Problem in der isDirty-Methode ist, dass diese erst beim Focuserhalt des Fensters oder beim öffnen und schliessen aufgerufen wird.



Ja klar wann soll sie den sonst augerufen werden? 
Ein bischen Code welches das Beispiel demonstriert würde genügen, mach einfach einen kleinen MultiPageEditor den ich compilieren und einfügen kann, sonst kann ich nichts mitanfangen


----------



## Kris (9. Feb 2010)

Wenn man die Plugin.xml aufmacht, dann hat man einen MultiPageEditor. Wenn man nun in irgendeinem Feld etwas verändert, dann wird der Editor sofort als Dirty angezeigt. (Sternchen vor dem Namen) 

Muss ich dafür einen Listener in jede Komponente einfügen, damit dieser dann reagiert und die Methode ausführt?


----------



## Gast2 (9. Feb 2010)

Kris hat gesagt.:


> Wenn man die Plugin.xml aufmacht, dann hat man einen MultiPageEditor. Wenn man nun in irgendeinem Feld etwas verändert, dann wird der Editor sofort als Dirty angezeigt. (Sternchen vor dem Namen)
> 
> Muss ich dafür einen Listener in jede Komponente einfügen, damit dieser dann reagiert und die Methode ausführt?



hier hab ich mal ein kleines Bsp.
Multi page

```
package multi;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IPersistableElement;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.MultiPageEditorPart;

public class MultiPage extends MultiPageEditorPart {

	@Override
	protected void createPages() {
	try {
			addPage(new Editor1(), new MyInput("Editor 1"));
			setPageText(0, "Editor 1");
			addPage(new Editor2(),new MyInput("Editor 2"));
			setPageText(0, "Editor 2");
		} catch (PartInitException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

	@Override
	public void doSave(IProgressMonitor monitor) {
		System.out.println("save multi part");
		for(int i = 0; i < getPageCount() ; i++){
			if(getEditor(i).isDirty())
				getEditor(i).doSave(monitor);
		}
	}

	@Override
	public void doSaveAs() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public boolean isSaveAsAllowed() {
		// TODO Auto-generated method stub
		return false;
	}

	public static class MyInput implements IEditorInput{

		String name ;
		
		public MyInput(String name){
			this.name = name;
		}
		
		@Override
		public boolean exists() {
			// TODO Auto-generated method stub
			return false;
		}

		@Override
		public ImageDescriptor getImageDescriptor() {
			// TODO Auto-generated method stub
			return null;
		}

		@Override
		public String getName() {
			// TODO Auto-generated method stub
			return name;
		}

		@Override
		public IPersistableElement getPersistable() {
			// TODO Auto-generated method stub
			return null;
		}

		@Override
		public String getToolTipText() {
			// TODO Auto-generated method stub
			return name;
		}

		@Override
		public Object getAdapter(Class adapter) {
			// TODO Auto-generated method stub
			return null;
		}
		
	}
}
```

Editor 1

```
package multi;


import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.EditorPart;

public class Editor1 extends EditorPart{

	@Override
	public void doSave(IProgressMonitor monitor) {
		System.out.println("save part 1");
		
	}

	@Override
	public void doSaveAs() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void init(IEditorSite site, IEditorInput input)
			throws PartInitException {
		setSite(site);
		setInput(input);
		
	}

	@Override
	public boolean isDirty() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean isSaveAsAllowed() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void createPartControl(Composite parent) {
		Label label = new Label(parent, SWT.NONE);
		label.setText("kop");
		
	}

	@Override
	public void setFocus() {
		// TODO Auto-generated method stub
		
	}

}
```
Editor 2


```
package multi;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.EditorPart;

public class Editor2 extends EditorPart{

	@Override
	public void doSave(IProgressMonitor monitor) {
		System.out.println("save part 2");
		
	}

	@Override
	public void doSaveAs() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void init(IEditorSite site, IEditorInput input)
			throws PartInitException {
		setSite(site);
		setInput(input);
		
	}

	@Override
	public boolean isDirty() {
		return true;
	}

	@Override
	public boolean isSaveAsAllowed() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void createPartControl(Composite parent) {
		Text text = new Text(parent,SWT.BORDER);
		
	}

	@Override
	public void setFocus() {
		// TODO Auto-generated method stub
		
	}

}
```


plugin.xml
[XML]
   <extension
         point="org.eclipse.ui.editors">
      <editor
            class="multi.MultiPage"
            default="false"
            id="test"
            name="Mutli">
      </editor>
   </extension>
[/XML]

sobald ein editorpart dirty ist wird die ganez multipage auch dirty


----------



## Kris (9. Feb 2010)

Hier besteht das selbe Problem wie Vorher. Der Marker, dass der ganze MultiPageEditor dirty ist, wid erst gesetzt, wenn man auf einen anderen Editor geht und dann den Focus auf den urpsünglichen setzt. Zwar merkt das Programm, dass die Seite bearbeitet wurde aber markiert es nicht sofort beim Bearbeiten.


----------



## Kris (9. Feb 2010)

Macht es evtl. einen unterschied, wenn die ganzen Komponenten in einer Section liegen?


----------



## Gast2 (9. Feb 2010)

Kris hat gesagt.:


> Macht es evtl. einen unterschied, wenn die ganzen Komponenten in einer Section liegen?



Kann ich nicht sagen, das obige Beispiel funktioniert bei mir wunderbar und das isDirty wird auch gleich angezeigt...

Wie gesagt poste mir ein KSKB, weil ich mir klappt es...


----------



## Kris (9. Feb 2010)

Ich habe dein Beispiel etwas ummoduliert, indem ich in der Methode des zweiten Editors nicht direkt true zurückliefere sondern eine Bedingung eingebaut habe.


```
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IPersistableElement;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.MultiPageEditorPart;

public class MultiPage extends MultiPageEditorPart {
	 
    @Override
    protected void createPages() {
    try {
            addPage(new Editor1(), new MyInput("Editor 1"));
            setPageText(0, "Editor 1");
            addPage(new Editor2(), new MyInput("Editor 2"));
            setPageText(1, "Editor 2");
        } catch (PartInitException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
 
    @Override
    public void doSave(IProgressMonitor monitor) {
        System.out.println("save multi part");
        for(int i = 0; i < getPageCount() ; i++){
            if(getEditor(i).isDirty())
                getEditor(i).doSave(monitor);
        }
    }
 
    @Override
    public void doSaveAs() {
        // TODO Auto-generated method stub
        
    }
 
    @Override
    public boolean isSaveAsAllowed() {
        // TODO Auto-generated method stub
        return false;
    }
 
    public static class MyInput implements IEditorInput{
 
        String name ;
        
        public MyInput(String name){
            this.name = name;
        }
        
        @Override
        public boolean exists() {
            // TODO Auto-generated method stub
            return false;
        }
 
        @Override
        public ImageDescriptor getImageDescriptor() {
            // TODO Auto-generated method stub
            return null;
        }
 
        @Override
        public String getName() {
            // TODO Auto-generated method stub
            return name;
        }
 
        @Override
        public IPersistableElement getPersistable() {
            // TODO Auto-generated method stub
            return null;
        }
 
        @Override
        public String getToolTipText() {
            // TODO Auto-generated method stub
            return name;
        }
 
        @Override
        public Object getAdapter(Class adapter) {
            // TODO Auto-generated method stub
            return null;
        }
        
    }
}
```


```
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.EditorPart;

public class Editor1 extends EditorPart{
	 
    @Override
    public void doSave(IProgressMonitor monitor) {
        System.out.println("save part 1");
        
    }
 
    @Override
    public void doSaveAs() {
        // TODO Auto-generated method stub
        
    }
 
    @Override
    public void init(IEditorSite site, IEditorInput input)
            throws PartInitException {
        setSite(site);
        setInput(input);
        
    }
 
    @Override
    public boolean isDirty() {
        // TODO Auto-generated method stub
        return false;
    }
 
    @Override
    public boolean isSaveAsAllowed() {
        // TODO Auto-generated method stub
        return false;
    }
 
    @Override
    public void createPartControl(Composite parent) {
        Label label = new Label(parent, SWT.NONE);
        label.setText("kop");
        
    }
 
    @Override
    public void setFocus() {
        // TODO Auto-generated method stub
        
    }
 
}
```


```
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.EditorPart;

public class Editor2 extends EditorPart{
	 
	private Text text;
	 
    @Override
    public void doSave(IProgressMonitor monitor) {
        System.out.println("save part 2");
        
    }
 
    @Override
    public void doSaveAs() {
        // TODO Auto-generated method stub
        
    }
 
    @Override
    public void init(IEditorSite site, IEditorInput input)
            throws PartInitException {
        setSite(site);
        setInput(input);
        
    }
 
    @Override
    public boolean isDirty() {
        if(!text.getText().equals("String")){
        	return true;
        }
    	return false;
    }
 
    @Override
    public boolean isSaveAsAllowed() {
        // TODO Auto-generated method stub
        return false;
    }
 
    @Override
    public void createPartControl(Composite parent) {
        text = new Text(parent,SWT.BORDER);
        text.setText("String");
        
    }
 
    @Override
    public void setFocus() {
        // TODO Auto-generated method stub
        
    }
 
}
```


----------



## Gast2 (9. Feb 2010)

ich glaub ich weiß was dein Problem ist du musst natürlich auch noch ein event schmeißen wenn etwas in das textfeld eingetragen wird oder sonst etwas gemacht wurde.Der Editor muss ja wissen wann er erneut prüfen soll.


```
@Override
	public void createPartControl(Composite parent) {
		Text text = new Text(parent,SWT.BORDER);
		text.addModifyListener(new ModifyListener() {
			
			@Override
			public void modifyText(ModifyEvent e) {
				firePropertyChange(PROP_DIRTY);
				
			}
		});
		
	}
```


----------



## Kris (9. Feb 2010)

Das habe ich mir gedacht. Hatte aber die Hoffnung, dass alles automatisch gehen würde. 

Gibt es ein Event, das man auf alle Komponenten wie Textfelder, Checkboxen, Comboboxen, etc. anwenden kann?


----------



## Gast2 (9. Feb 2010)

Kris hat gesagt.:


> Das habe ich mir gedacht. Hatte aber die Hoffnung, dass alles automatisch gehen würde.
> 
> Gibt es ein Event, das man auf alle Komponenten wie Textfelder, Checkboxen, Comboboxen, etc. anwenden kann?



Nee glaub nicht bei allem wo du was eingeben kannst ModiyfListener ...
Checkboxen(Button) ist SelectionListener
usw. 
Aber keine ahnung du musst den listener ja nur einmal erstellen für die Komponenten und kannst den ja dann immer wieder verwenden.


----------



## Kris (9. Feb 2010)

OK. Danke.

Ist aber doch noch nicht erledigt. Wenn der Modifyerlistener die isDirty-Methode aufruft, passiert nichts.
Welche Methode wird beim wechseln der Editoren aufgerufen? Die wiederrum die isDirtyMethode aufruft um das Fenster zu markieren.


Jetzt habe ich es geschafft, der Modifier muss die  editorDirtyStateChanged() Methode des Editors aufrufen. Erst dann erhält man das gewünschte Ergebnis.

Vielen Dank nochmal.


----------

