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