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