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