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