Project

General

Profile

Download (14.3 KB) Statistics
| Branch: | Tag: | Revision:
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.name.TaxonNameEditor;
34
import eu.etaxonomy.taxeditor.editor.name.container.AbstractGroupedContainer;
35
import eu.etaxonomy.taxeditor.model.AbstractUtility;
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
45
 * for "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
53
		IConversationEnabled, IPostOperationEnabled,
54
		IDirtyMarkableSelectionProvider, IPartContentHasDetails, ISecuredEditor {
55

    
56
	/** Constant <code>ID="eu.etaxonomy.taxeditor.editor.taxon"{trunked}</code> */
57
	public static final String ID = "eu.etaxonomy.taxeditor.editor.taxon";
58

    
59
	private boolean dirty;
60

    
61
	private ConversationHolder conversation;
62
	private IDataChangeBehavior dataChangeBehavior;
63
	private IUndoContext undoContext;
64

    
65
	private TaxonEditorInput input;
66

    
67
	/**
68
	 * <p>
69
	 * Constructor for MultiPageTaxonEditor.
70
	 * </p>
71
	 */
72
	public MultiPageTaxonEditor() {
73
		super();
74
		undoContext = new UndoContext();
75
	}
76

    
77
	/** {@inheritDoc} */
78
	@Override
79
	public void dispose() {
80
		conversation.unregisterForDataStoreChanges(this);
81
		conversation.close();
82
		super.dispose();
83
	}
84

    
85
	/*
86
	 * (non-Javadoc)
87
	 *
88
	 * @see org.eclipse.ui.forms.editor.FormEditor#addPages()
89
	 */
90
	/** {@inheritDoc} */
91
	@Override
92
	protected void addPages() {
93
		input = (TaxonEditorInput) getEditorInput();
94
		conversation = input.getConversationHolder();
95
		conversation.registerForDataStoreChanges(this);
96

    
97
		try {
98
			addPage(Page.NAME.getIndex(), new TaxonNameEditor(this),
99
					getEditorInput());
100
			// setPageText(Page.NAME.getIndex(), Page.NAME.getTitle());
101

    
102
			// TODO lazy create
103
			// addPage(Page.DESCRIPTIVE.getIndex(), new
104
			// TaxonDescriptionTreeEditor(this), getEditorInput());
105
			// setPageText(Page.DESCRIPTIVE.getIndex(),
106
			// Page.DESCRIPTIVE.getTitle());
107

    
108
			// EditorUtil.showPropertySheet();
109

    
110
		} catch (PartInitException e) {
111
			AbstractUtility.error(getClass(), e);
112
		}
113
	}
114

    
115
	/** {@inheritDoc} */
116
	@Override
117
	public void doSave(IProgressMonitor monitor) {
118
		monitor.beginTask("Saving Editor", 4);
119
		try {
120
			if (!conversation.isBound()) {
121
				conversation.bind();
122
			}
123
			monitor.worked(1);
124

    
125
            for (IEditorPart editorPage : getPages()) {
126
                if (editorPage instanceof TaxonNameEditor) {
127
                    if (((TaxonNameEditor) editorPage).checkForEmptyNames()) {
128
                        MessageDialog.openWarning(AbstractUtility.getShell(), "No Name Specified",
129
                                "An attempt was made to save a taxon or synonym with "
130
                                        + "an empty name. Operation was cancelled.");
131
                        return;
132
                    }
133
                }
134

    
135
                editorPage.doSave(monitor);
136
                monitor.worked(1);
137
            }
138

    
139
			// commit the conversation and start a new transaction immediately
140
			conversation.commit(true);
141
			monitor.worked(1);
142

    
143
            this.setDirty(false);
144
            monitor.worked(1);
145
        } catch (Exception e) {
146
            setFocus();
147
            AbstractUtility.errorDialog("An error occurred while saving", getClass(),
148
                    "An error occurred while saving the editor. Please close and reopen the taxon again.", e);
149
            disableEditor(true);
150
        } finally {
151
            monitor.done();
152
        }
153
	}
154

    
155
	private void disableEditor(boolean isOnError) {
156
		for (IMultiPageTaxonEditorPage editorPage : getPages()) {
157
			if(isOnError){
158
				editorPage.setOnError();
159
			}else {
160
				editorPage.setDisabled();
161
			}
162
		}
163
		conversation.unregisterForDataStoreChanges(this);
164
		conversation.close();
165
		setDirty(false);
166
	}
167

    
168
	private void setDirty(boolean dirty) {
169
		this.dirty = dirty;
170
		firePropertyChange(PROP_DIRTY);
171
	}
172

    
173
	/*
174
	 * (non-Javadoc)
175
	 *
176
	 * @see org.eclipse.ui.part.MultiPageEditorPart#isDirty()
177
	 */
178
	/**
179
	 * <p>
180
	 * isDirty
181
	 * </p>
182
	 *
183
	 * @return a boolean.
184
	 */
185
	@Override
186
    public boolean isDirty() {
187
		return dirty;
188
	}
189

    
190
	/*
191
	 * (non-Javadoc)
192
	 *
193
	 * @see org.eclipse.ui.forms.editor.FormEditor#editorDirtyStateChanged()
194
	 */
195
	/** {@inheritDoc} */
196
	@Override
197
	public void editorDirtyStateChanged() {
198
		dirty = true;
199
		super.editorDirtyStateChanged();
200
	}
201

    
202
	/**
203
	 * {@inheritDoc}
204
	 *
205
	 * Checks whether nested editors are calling
206
	 * <code>firePropertyChange(PROP_DIRTY)</code> to signal an edit has taken
207
	 * place before passing property change along to
208
	 * <code>super.handlePropertyChange(int propertyId)</code>.
209
	 */
210
	/*
211
	 * (non-Javadoc)
212
	 *
213
	 * @see org.eclipse.ui.part.MultiPageEditorPart#handlePropertyChange(int)
214
	 */
215
	@Override
216
    protected void handlePropertyChange(int propertyId) {
217
		if (propertyId == PROP_DIRTY) {
218
			setDirty(true);
219
		}
220
		super.handlePropertyChange(propertyId);
221
	}
222

    
223
	/** {@inheritDoc} */
224
	@Override
225
	public void doSaveAs() {
226
	}
227

    
228
	/** {@inheritDoc} */
229
	@Override
230
	public boolean isSaveAsAllowed() {
231
		return false;
232
	}
233

    
234
	/** {@inheritDoc} */
235
	@Override
236
	public void init(IEditorSite site, IEditorInput input)
237
			throws PartInitException {
238

    
239
		if (!(input instanceof TaxonEditorInput)) {
240
            throw new PartInitException(
241
					"Invalid Input: Must be TaxonEditorInput");
242
        }
243

    
244
		this.input = (TaxonEditorInput) input;
245

    
246
		// try {
247
		// // Listen for name changes,
248
		// // change tab for this taxon editor accordingly
249
		// getTaxon().addPropertyChangeListener("name",
250
		// new PropertyChangeListener() {
251
		// public void propertyChange(PropertyChangeEvent e) {
252
		// setPartName();
253
		// }
254
		// });
255
		// } catch (NullPointerException e) {
256
		// EditorUtil.warn(getClass(),
257
		// "Caught an NPE while initing an editor. This is most " +
258
		// "likely due to the unsuccesful attempt to restore the former " +
259
		// "state of the application. We ignore this because the workbench " +
260
		// "will simply be reset.");
261
		// }
262
		setPartName();
263

    
264
		super.init(site, input);
265
	}
266

    
267
	/**
268
	 * Calls <code>MultiPageEditorPart.setPartName(String partName)</code> with
269
	 * text appropriate to the state of the taxon: any taxon that has been saved
270
	 * will by necessity have a name to display; a new taxon should display
271
	 * "New taxon" in the editor tab.
272
	 */
273
	protected void setPartName() {
274

    
275
		String partName = null;
276
		TaxonNameBase<?, ?> name = getTaxon().getName();
277

    
278
		if (name != null) {
279
			partName = name.getTitleCache();
280
		}
281

    
282
		if (partName == null || partName.equals("")) {
283
			partName = ("New taxon");
284
		}
285

    
286
		setPartName(partName);
287
	}
288

    
289
    /**
290
     * {@inheritDoc}
291
     *
292
     * Editor pages call this in their postOperation to notify the
293
     * MultiPageTaxonEditor of unsaved changes
294
     */
295
    @Override
296
    public void changed(Object element) {
297
        // setDirty(true);
298
        dirty = true;
299
        super.editorDirtyStateChanged();
300
        if (element instanceof TaxonBase) {
301
            TaxonNameEditor page = (TaxonNameEditor) getPage(Page.NAME);
302
            AbstractGroupedContainer container = page.getContainer((TaxonBase) element);
303
            if (container != null) {
304
                container.refresh();
305
            }
306
        }
307
    }
308

    
309
	/**
310
	 * The accepted taxon that is the input for this editor
311
	 *
312
	 * @return the accepted taxon
313
	 */
314
	public Taxon getTaxon() {
315
		return input.getTaxon();
316
	}
317

    
318
	/*
319
	 * (non-Javadoc)
320
	 *
321
	 * @see
322
	 * eu.etaxonomy.cdm.api.conversation.IConversationEnabled#getConversationHolder
323
	 * ()
324
	 */
325
	/**
326
	 * <p>
327
	 * getConversationHolder
328
	 * </p>
329
	 *
330
	 * @return a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder}
331
	 *         object.
332
	 */
333
	@Override
334
    public ConversationHolder getConversationHolder() {
335
		return conversation;
336
	}
337

    
338
	/**
339
	 * <p>
340
	 * setConversationHolder
341
	 * </p>
342
	 *
343
	 * @param conversation
344
	 *            a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder}
345
	 *            object.
346
	 */
347
	public void setConversationHolder(ConversationHolder conversation) {
348
		this.conversation = conversation;
349
	}
350

    
351
	/**
352
	 * <p>
353
	 * Getter for the field <code>undoContext</code>.
354
	 * </p>
355
	 *
356
	 * @return a {@link org.eclipse.core.commands.operations.IUndoContext}
357
	 *         object.
358
	 */
359
	public IUndoContext getUndoContext() {
360
		return undoContext;
361
	}
362

    
363
	/**
364
	 * <p>
365
	 * Setter for the field <code>undoContext</code>.
366
	 * </p>
367
	 *
368
	 * @param undoContext
369
	 *            a {@link org.eclipse.core.commands.operations.IUndoContext}
370
	 *            object.
371
	 */
372
	public void setUndoContext(IUndoContext undoContext) {
373
		this.undoContext = undoContext;
374
	}
375

    
376
	/** {@inheritDoc} */
377
	@Override
378
	public void setFocus() {
379
		// logger.warn("Setting focus to editor");
380
		// bind the conversation
381
		getConversationHolder().bind();
382
		// pass focus to the active editor page
383
		getActiveEditor().setFocus();
384
	}
385

    
386
    /*
387
     * (non-Javadoc)
388
     *
389
     * @see
390
     * eu.etaxonomy.cdm.persistence.hibernate.ICdmPostCrudObserver#update(eu
391
     * .etaxonomy.cdm.persistence.hibernate.CdmCrudEvent)
392
     */
393
    /** {@inheritDoc} */
394
    @Override
395
    public void update(CdmDataChangeMap events) {
396
        if (dataChangeBehavior == null) {
397
            dataChangeBehavior = new MultiPageTaxonEditorDataChangeBehaviour(this);
398
        }
399

    
400
        DataChangeBridge.handleDataChange(events, dataChangeBehavior);
401
    }
402

    
403
    /*
404
     * (non-Javadoc)
405
     *
406
     * @see
407
     * eu.etaxonomy.taxeditor.store.operations.IPostOperationEnabled#postOperation
408
     * ()
409
     */
410
    /** {@inheritDoc} */
411
    @Override
412
    public boolean postOperation(CdmBase objectAffectedByOperation) {
413
        setDirty(true);
414

    
415
        for (IEditorPart editor : this.getPages()) {
416
            if (editor instanceof IPostOperationEnabled) {
417
                ((IPostOperationEnabled) editor).postOperation(objectAffectedByOperation);
418
            } else {
419
                AbstractUtility.warn(getClass(), "postOperation not enabled for editor " + editor);
420
            }
421
        }
422
        AbstractUtility.warn(getClass(), "postOperation called on MultiPageTaxonEditor. Can you make it more specific?");
423

    
424
        return false;
425
    }
426

    
427
	/**
428
	 * Returns an <code>IEditorPart</code> implementation by type
429
	 *
430
	 * @param page
431
	 *            the page type
432
	 * @return a {@link eu.etaxonomy.taxeditor.editor.IMultiPageTaxonEditorPage}
433
	 *         object.
434
	 */
435
	public IMultiPageTaxonEditorPage getPage(Page page) {
436
		for (IEditorPart editor : this.getPages()) {
437
			if (editor.getClass().equals(page.getClazz())) {
438
				return (IMultiPageTaxonEditorPage) editor;
439
			}
440
		}
441
		return null;
442
	}
443

    
444
	/**
445
	 * Return a list of <code>AbstractTaxonEditor</code>s registered with this
446
	 * <code>MultiPageTaxonEditor</code>.
447
	 *
448
	 * @return a {@link java.util.List} object.
449
	 */
450
	public List<IMultiPageTaxonEditorPage> getPages() {
451
		ArrayList<IMultiPageTaxonEditorPage> editors = new ArrayList<IMultiPageTaxonEditorPage>();
452
		for (int i = 0; i < this.getPageCount(); i++) {
453

    
454
			editors.add((IMultiPageTaxonEditorPage) this.getEditor(i));
455
		}
456
		return editors;
457
	}
458

    
459
	/**
460
	 * Refreshes a certain page of the MultipageTaxonEditor
461
	 *
462
	 * @param page
463
	 *            a {@link eu.etaxonomy.taxeditor.editor.Page} object.
464
	 * @return a boolean.
465
	 */
466
	public boolean redraw(Page page) {
467
		return redraw(page, true);
468
	}
469

    
470
	/**
471
	 * Refreshes a certain page of the MultipageTaxonEditor and sets focus to
472
	 * that page
473
	 *
474
	 * @param page
475
	 *            a {@link eu.etaxonomy.taxeditor.editor.Page} object.
476
	 * @param focus
477
	 *            a boolean.
478
	 * @return a boolean.
479
	 */
480
	public boolean redraw(Page page, boolean focus) {
481
		IMultiPageTaxonEditorPage editorPage = getPage(page);
482
		return editorPage != null && editorPage.redraw(focus);
483
	}
484

    
485
	/**
486
	 * <p>
487
	 * onComplete
488
	 * </p>
489
	 *
490
	 * @return a boolean.
491
	 */
492
	@Override
493
    public boolean onComplete() {
494
		return false;
495
	}
496

    
497
    /**
498
     * Reloads the data for this
499
     */
500
    public void reload() {
501
        if (isDirty()) {
502
            AbstractUtility.warningDialog("Editor has unsaved data", getClass(), "This editor can not be "
503
                    + "refreshed because it contains unsaved data. Refreshing "
504
                    + "this editor would discard the changes. Please save this editor, "
505
                    + "close and reopen it manually in order to get the latest content");
506
        } else {
507
            TaxonEditorInput input = (TaxonEditorInput) getEditorInput();
508

    
509
            UUID uuid = input.getTaxonNode().getUuid();
510

    
511
            conversation.clear();
512

    
513
            try {
514
                TaxonEditorInput newInput = TaxonEditorInput.NewInstance(uuid);
515
                setInput(newInput);
516
                for (IMultiPageTaxonEditorPage editorPart : getPages()) {
517
                    editorPart.redraw();
518
                }
519
            } catch (Exception e) {
520
                AbstractUtility.errorDialog("Error refreshing editor", getClass(), "Could not refresh this editor", e);
521
            }
522
        }
523
    }
524

    
525
	@Override
526
	public String toString() {
527
		return String.format("%s[%s]", this.getClass().getSimpleName(), getEditorInput());
528
	}
529

    
530
	@Override
531
	public boolean permissionsSatisfied() {
532
		IEditorPart activeEditor = getActiveEditor();
533
		if(activeEditor != null && ISecuredEditor.class.isAssignableFrom(activeEditor.getClass())){
534
			return ((ISecuredEditor)activeEditor).permissionsSatisfied();
535
		}
536
		return true;
537
	}
538
}
(7-7/17)