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