Refactoring of name editor.
[taxeditor.git] / taxeditor-editor / src / main / java / eu / etaxonomy / taxeditor / editor / MultiPageTaxonEditor.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9
10 package eu.etaxonomy.taxeditor.editor;
11
12 import java.util.ArrayList;
13 import java.util.List;
14 import java.util.UUID;
15
16 import org.eclipse.core.commands.operations.IUndoContext;
17 import org.eclipse.core.commands.operations.UndoContext;
18 import org.eclipse.core.runtime.IProgressMonitor;
19 import org.eclipse.ui.IEditorInput;
20 import org.eclipse.ui.IEditorPart;
21 import org.eclipse.ui.IEditorSite;
22 import org.eclipse.ui.PartInitException;
23 import org.eclipse.ui.forms.editor.FormEditor;
24
25 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
26 import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
27 import eu.etaxonomy.cdm.model.common.CdmBase;
28 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
29 import eu.etaxonomy.cdm.model.taxon.Taxon;
30 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
31 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
32 import eu.etaxonomy.taxeditor.editor.name.TaxonNameEditor;
33 import eu.etaxonomy.taxeditor.editor.name.container.AbstractGroupedContainer;
34 import eu.etaxonomy.taxeditor.model.DataChangeBridge;
35 import eu.etaxonomy.taxeditor.model.IDataChangeBehavior;
36 import eu.etaxonomy.taxeditor.model.IDirtyMarkableSelectionProvider;
37 import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
38 import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
39
40 /**
41 *
42 * Generates the tabbed editor with <code>TaxonNameEditor</code> on top and tabs for
43 * "Descriptions", "Concepts", "Geography", etc.
44 *
45 * @author p.ciardelli
46 * @author n.hoffmann
47 * @created 15.05.2008
48 * @version 1.0
49 */
50 public class MultiPageTaxonEditor extends FormEditor implements IConversationEnabled, IPostOperationEnabled, IDirtyMarkableSelectionProvider, IPartContentHasDetails {
51
52 /** Constant <code>ID="eu.etaxonomy.taxeditor.editor.multipage"{trunked}</code> */
53 public static final String ID = "eu.etaxonomy.taxeditor.editor.multipagetaxonview";
54
55 private boolean dirty;
56
57 private ConversationHolder conversation;
58 private IDataChangeBehavior dataChangeBehavior;
59 private IUndoContext undoContext;
60
61 private TaxonEditorInput input;
62
63 /**
64 * <p>Constructor for MultiPageTaxonEditor.</p>
65 */
66 public MultiPageTaxonEditor() {
67 super();
68 undoContext = new UndoContext();
69 }
70
71 /** {@inheritDoc} */
72 @Override
73 public void dispose() {
74 conversation.unregisterForDataStoreChanges(this);
75 conversation.close();
76 super.dispose();
77 }
78
79 /* (non-Javadoc)
80 * @see org.eclipse.ui.forms.editor.FormEditor#addPages()
81 */
82 /** {@inheritDoc} */
83 @Override
84 protected void addPages() {
85 input = (TaxonEditorInput) getEditorInput();
86 conversation = input.getConversationHolder();
87 conversation.registerForDataStoreChanges(this);
88
89 try {
90 addPage(Page.NAME.getIndex(), new TaxonNameEditor(this), getEditorInput());
91 // setPageText(Page.NAME.getIndex(), Page.NAME.getTitle());
92
93 // TODO lazy create
94 // addPage(Page.DESCRIPTIVE.getIndex(), new TaxonDescriptionTreeEditor(this), getEditorInput());
95 // setPageText(Page.DESCRIPTIVE.getIndex(), Page.DESCRIPTIVE.getTitle());
96
97 // EditorUtil.showPropertySheet();
98
99 } catch (PartInitException e) {
100 EditorUtil.error(getClass(), e);
101 }
102 }
103
104
105 /** {@inheritDoc} */
106 @Override
107 public void doSave(IProgressMonitor monitor) {
108 monitor.beginTask("Saving Editor", 4);
109 try{
110 if( ! conversation.isBound()){
111 conversation.bind();
112 }
113 monitor.worked(1);
114
115 for(IEditorPart editorPage : getPages()){
116 if(editorPage instanceof TaxonNameEditor){
117 if(((TaxonNameEditor) editorPage).checkForEmptyNames()){
118 // abort
119 return;
120 }
121 }
122
123 editorPage.doSave(monitor);
124 monitor.worked(1);
125 }
126
127 // commit the conversation and start a new transaction immediately
128 conversation.commit(true);
129 monitor.worked(1);
130
131 this.setDirty(false);
132 monitor.worked(1);
133 }finally{
134 monitor.done();
135 }
136 }
137
138
139 private void setDirty(boolean dirty) {
140 this.dirty = dirty;
141 firePropertyChange(PROP_DIRTY);
142 }
143
144 /* (non-Javadoc)
145 * @see org.eclipse.ui.part.MultiPageEditorPart#isDirty()
146 */
147 /**
148 * <p>isDirty</p>
149 *
150 * @return a boolean.
151 */
152 public boolean isDirty() {
153 return dirty;
154 }
155
156 /* (non-Javadoc)
157 * @see org.eclipse.ui.forms.editor.FormEditor#editorDirtyStateChanged()
158 */
159 /** {@inheritDoc} */
160 @Override
161 public void editorDirtyStateChanged() {
162 dirty = true;
163 super.editorDirtyStateChanged();
164 }
165
166
167 /**
168 * {@inheritDoc}
169 *
170 * Checks whether nested editors are calling <code>firePropertyChange(PROP_DIRTY)</code>
171 * to signal an edit has taken place before passing property change along to
172 * <code>super.handlePropertyChange(int propertyId)</code>.
173 */
174 /* (non-Javadoc)
175 * @see org.eclipse.ui.part.MultiPageEditorPart#handlePropertyChange(int)
176 */
177 protected void handlePropertyChange(int propertyId) {
178 if (propertyId == PROP_DIRTY) {
179 setDirty(true);
180 }
181 super.handlePropertyChange(propertyId);
182 }
183
184 /** {@inheritDoc} */
185 @Override
186 public void doSaveAs() {}
187
188 /** {@inheritDoc} */
189 @Override
190 public boolean isSaveAsAllowed() {
191 return false;
192 }
193
194 /** {@inheritDoc} */
195 @Override
196 public void init(IEditorSite site, IEditorInput input) throws PartInitException {
197
198 if (!(input instanceof TaxonEditorInput))
199 throw new PartInitException(
200 "Invalid Input: Must be TaxonEditorInput");
201
202 this.input = (TaxonEditorInput) input;
203
204 // try {
205 // // Listen for name changes,
206 // // change tab for this taxon editor accordingly
207 // getTaxon().addPropertyChangeListener("name",
208 // new PropertyChangeListener() {
209 // public void propertyChange(PropertyChangeEvent e) {
210 // setPartName();
211 // }
212 // });
213 // } catch (NullPointerException e) {
214 // EditorUtil.warn(getClass(), "Caught an NPE while initing an editor. This is most " +
215 // "likely due to the unsuccesful attempt to restore the former " +
216 // "state of the application. We ignore this because the workbench " +
217 // "will simply be reset.");
218 // }
219 setPartName();
220
221 super.init(site, input);
222 }
223
224 /**
225 * Calls <code>MultiPageEditorPart.setPartName(String partName)</code>
226 * with text appropriate to the state of the taxon: any taxon that has
227 * been saved will by necessity have a name to display; a new taxon
228 * should display "New taxon" in the editor tab.
229 */
230 protected void setPartName() {
231
232 String partName = null;
233 TaxonNameBase<?, ?> name = getTaxon().getName();
234
235 if (name != null) {
236 partName = name.getTitleCache();
237 }
238
239 if (partName == null || partName.equals("")) {
240 partName = ("New taxon");
241 }
242
243 setPartName(partName);
244 }
245
246 /**
247 * {@inheritDoc}
248 *
249 * Editor pages call this in their postOperation to notify the MultiPageTaxonEditor
250 * of unsaved changes
251 */
252 public void changed(Object element) {
253 // setDirty(true);
254 dirty = true;
255 super.editorDirtyStateChanged();
256 if(element instanceof TaxonBase){
257 TaxonNameEditor page = (TaxonNameEditor) getPage(Page.NAME);
258 AbstractGroupedContainer container = page.getContainer((TaxonBase) element);
259 if(container != null){
260 container.refresh();
261 }
262 }
263 }
264
265 /**
266 * The accepted taxon that is the input for this editor
267 *
268 * @return the accepted taxon
269 */
270 public Taxon getTaxon(){
271 return input.getTaxon();
272 }
273
274 /*
275 * (non-Javadoc)
276 * @see eu.etaxonomy.cdm.api.conversation.IConversationEnabled#getConversationHolder()
277 */
278 /**
279 * <p>getConversationHolder</p>
280 *
281 * @return a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder} object.
282 */
283 public ConversationHolder getConversationHolder() {
284 return conversation;
285 }
286
287 /**
288 * <p>setConversationHolder</p>
289 *
290 * @param conversation a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder} object.
291 */
292 public void setConversationHolder(ConversationHolder conversation){
293 this.conversation = conversation;
294 }
295
296
297 /**
298 * <p>Getter for the field <code>undoContext</code>.</p>
299 *
300 * @return a {@link org.eclipse.core.commands.operations.IUndoContext} object.
301 */
302 public IUndoContext getUndoContext() {
303 return undoContext;
304 }
305
306 /**
307 * <p>Setter for the field <code>undoContext</code>.</p>
308 *
309 * @param undoContext a {@link org.eclipse.core.commands.operations.IUndoContext} object.
310 */
311 public void setUndoContext(IUndoContext undoContext) {
312 this.undoContext = undoContext;
313 }
314
315 /** {@inheritDoc} */
316 @Override
317 public void setFocus(){
318 //logger.warn("Setting focus to editor");
319 // bind the conversation
320 getConversationHolder().bind();
321 // pass focus to the active editor page
322 getActiveEditor().setFocus();
323 }
324
325 /*
326 * (non-Javadoc)
327 * @see eu.etaxonomy.cdm.persistence.hibernate.ICdmPostCrudObserver#update(eu.etaxonomy.cdm.persistence.hibernate.CdmCrudEvent)
328 */
329 /** {@inheritDoc} */
330 public void update(CdmDataChangeMap events) {
331 if(dataChangeBehavior == null){
332 dataChangeBehavior = new MultiPageTaxonEditorDataChangeBehaviour(this);
333 }
334
335 DataChangeBridge.handleDataChange(events, dataChangeBehavior);
336 }
337
338
339 /*
340 * (non-Javadoc)
341 * @see eu.etaxonomy.taxeditor.store.operations.IPostOperationEnabled#postOperation()
342 */
343 /** {@inheritDoc} */
344 public boolean postOperation(CdmBase objectAffectedByOperation) {
345 setDirty(true);
346
347 for(IEditorPart editor : this.getPages()){
348 if (editor instanceof IPostOperationEnabled) {
349 ((IPostOperationEnabled) editor).postOperation(objectAffectedByOperation);
350 } else {
351 EditorUtil.warn(getClass(), "postOperation not enabled for editor " + editor);
352 }
353 }
354 EditorUtil.warn(getClass(), "postOperation called on MultiPageTaxonEditor. Can you make it more specific?");
355
356 return false;
357 }
358
359 /**
360 * Returns an <code>IEditorPart</code> implementation by type
361 *
362 * @param page the page type
363 * @return a {@link eu.etaxonomy.taxeditor.editor.IMultiPageTaxonEditorPage} object.
364 */
365 public IMultiPageTaxonEditorPage getPage(Page page){
366 for(IEditorPart editor : this.getPages()){
367 if(editor.getClass().equals(page.getClazz())){
368 return (IMultiPageTaxonEditorPage) editor;
369 }
370 }
371 return null;
372 }
373
374 /**
375 * Return a list of <code>AbstractTaxonEditor</code>s registered with this
376 * <code>MultiPageTaxonEditor</code>.
377 *
378 * @return a {@link java.util.List} object.
379 */
380 public List<IMultiPageTaxonEditorPage> getPages(){
381 ArrayList<IMultiPageTaxonEditorPage> editors = new ArrayList<IMultiPageTaxonEditorPage>();
382 for(int i = 0; i < this.getPageCount(); i++){
383
384 editors.add((IMultiPageTaxonEditorPage) this.getEditor(i));
385 }
386 return editors;
387 }
388
389 /**
390 * Refreshes a certain page of the MultipageTaxonEditor
391 *
392 * @param page a {@link eu.etaxonomy.taxeditor.editor.Page} object.
393 * @return a boolean.
394 */
395 public boolean redraw(Page page){
396 return redraw(page, true);
397 }
398
399 /**
400 * Refreshes a certain page of the MultipageTaxonEditor and
401 * sets focus to that page
402 *
403 * @param page a {@link eu.etaxonomy.taxeditor.editor.Page} object.
404 * @param focus a boolean.
405 * @return a boolean.
406 */
407 public boolean redraw(Page page, boolean focus){
408 IMultiPageTaxonEditorPage editorPage = getPage(page);
409 return editorPage != null && editorPage.redraw(focus);
410 }
411
412 /**
413 * <p>onComplete</p>
414 *
415 * @return a boolean.
416 */
417 public boolean onComplete() {
418 return false;
419 }
420
421 /**
422 * Reloads the data for this
423 */
424 public void reload() {
425 if(isDirty()){
426 EditorUtil.warningDialog("Editor has unsaved data", getClass(), "This editor can not be " +
427 "refreshed because it contains unsaved data. Refreshing " +
428 "this editor would discard the changes. Please save this editor, " +
429 "close and reopen it manually in order to get the latest content");
430 }else{
431 TaxonEditorInput input = (TaxonEditorInput) getEditorInput();
432
433 UUID uuid = input.getTaxonNode().getUuid();
434
435 conversation.clear();
436
437 try {
438 TaxonEditorInput newInput = TaxonEditorInput.NewInstance(uuid);
439 setInput(newInput);
440 for(IMultiPageTaxonEditorPage editorPart : getPages()){
441 editorPart.redraw();
442 }
443 } catch (Exception e) {
444 EditorUtil.errorDialog("Error refreshing editor", getClass(), "Could not refresh this editor", e);
445 }
446 }
447 }
448 }