Project

General

Profile

Download (16.5 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.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

    
82
    /** {@inheritDoc} */
83
    @Override
84
    public void dispose() {
85
        input.dispose();
86
        conversation.unregisterForDataStoreChanges(this);
87
        conversation.close();
88
        super.dispose();
89
    }
90

    
91
    /*
92
     * (non-Javadoc)
93
     *
94
     * @see org.eclipse.ui.forms.editor.FormEditor#addPages()
95
     */
96
    /** {@inheritDoc} */
97
    @Override
98
    protected void addPages() {
99
        input = (TaxonEditorInput) getEditorInput();
100
        conversation = input.getConversationHolder();
101
        conversation.registerForDataStoreChanges(this);
102

    
103
        try {
104
            addPage(Page.NAME.getIndex(), new TaxonNameEditor(this),
105
                    getEditorInput());
106
            // setPageText(Page.NAME.getIndex(), Page.NAME.getTitle());
107

    
108
            // TODO lazy create
109
            // addPage(Page.DESCRIPTIVE.getIndex(), new
110
            // TaxonDescriptionTreeEditor(this), getEditorInput());
111
            // setPageText(Page.DESCRIPTIVE.getIndex(),
112
            // Page.DESCRIPTIVE.getTitle());
113

    
114
            // EditorUtil.showPropertySheet();
115

    
116
        } catch (PartInitException e) {
117
            MessagingUtils.error(getClass(), e);
118
        }
119
    }
120

    
121
    /** {@inheritDoc} */
122
    @Override
123
    public void doSave(IProgressMonitor monitor) {
124
        monitor.beginTask("Saving Editor", 4);
125
        try {
126
            if (!conversation.isBound()) {
127
                conversation.bind();
128
            }
129
            monitor.worked(1);
130

    
131
            for (IEditorPart editorPage : getPages()) {
132
                if (editorPage instanceof TaxonNameEditor) {
133
                    if (((TaxonNameEditor) editorPage).checkForEmptyNames()) {
134
                        MessageDialog.openWarning(AbstractUtility.getShell(), "No Name Specified",
135
                                "An attempt was made to save a taxon or synonym with "
136
                                        + "an empty name. Operation was cancelled.");
137
                        return;
138
                    }
139
                }
140

    
141
                editorPage.doSave(monitor);
142
                monitor.worked(1);
143
            }
144

    
145
            // commit the conversation and start a new transaction immediately
146

    
147
            input.merge();
148
            conversation.commit(true);
149
            monitor.worked(1);
150

    
151
            this.setDirty(false);
152
            monitor.worked(1);
153
        } catch (Exception e) {
154
            setFocus();
155
            MessagingUtils.operationDialog(this, e, TaxeditorEditorPlugin.PLUGIN_ID,"saving a taxon", " Please close and reopen the taxon again.");
156
            disableEditor(true);
157
        } finally {
158
            monitor.done();
159
        }
160
    }
161

    
162
    private void disableEditor(boolean isOnError) {
163
        for (IMultiPageTaxonEditorPage editorPage : getPages()) {
164
            if(isOnError){
165
                editorPage.setOnError();
166
            }else {
167
                editorPage.setDisabled();
168
            }
169
        }
170

    
171
        conversation.unregisterForDataStoreChanges(this);
172
        conversation.close();
173
        setDirty(false);
174
    }
175

    
176
    private void setDirty(boolean dirty) {
177
        this.dirty = dirty;
178
        firePropertyChange(PROP_DIRTY);
179
    }
180

    
181
    /*
182
     * (non-Javadoc)
183
     *
184
     * @see org.eclipse.ui.part.MultiPageEditorPart#isDirty()
185
     */
186
    /**
187
     * <p>
188
     * isDirty
189
     * </p>
190
     *
191
     * @return a boolean.
192
     */
193
    @Override
194
    public boolean isDirty() {
195
        return dirty;
196
    }
197

    
198
    /*
199
     * (non-Javadoc)
200
     *
201
     * @see org.eclipse.ui.forms.editor.FormEditor#editorDirtyStateChanged()
202
     */
203
    /** {@inheritDoc} */
204
    @Override
205
    public void editorDirtyStateChanged() {
206
        dirty = true;
207
        super.editorDirtyStateChanged();
208
    }
209

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

    
231
    /** {@inheritDoc} */
232
    @Override
233
    public void doSaveAs() {
234
    }
235

    
236
    /** {@inheritDoc} */
237
    @Override
238
    public boolean isSaveAsAllowed() {
239
        return false;
240
    }
241

    
242
    /** {@inheritDoc} */
243
    @Override
244
    public void init(IEditorSite site, IEditorInput input)
245
            throws PartInitException {
246

    
247
        if (!(input instanceof TaxonEditorInput)) {
248
            throw new PartInitException(
249
                    "Invalid Input: Must be TaxonEditorInput");
250
        }
251

    
252
        this.input = (TaxonEditorInput) input;
253

    
254

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

    
273
        super.init(site, input);
274
    }
275

    
276
    /**
277
     * Calls <code>MultiPageEditorPart.setPartName(String partName)</code> with
278
     * text appropriate to the state of the taxon: any taxon that has been saved
279
     * will by necessity have a name to display; a new taxon should display
280
     * "New taxon" in the editor tab.
281
     */
282
    protected void setPartName() {
283

    
284
        String partName = null;
285
        TaxonNameBase<?, ?> name = getTaxon().getName();
286

    
287
        if (name != null) {
288
            partName = name.getTitleCache();
289
        }
290

    
291
        if (partName == null || partName.equals("")) {
292
            partName = ("New taxon");
293
        }
294

    
295
        setPartName(partName);
296
    }
297

    
298
    /**
299
     * {@inheritDoc}
300
     *
301
     * Editor pages call this in their postOperation to notify the
302
     * MultiPageTaxonEditor of unsaved changes
303
     */
304
    @Override
305
    public void changed(Object element) {
306
        // setDirty(true);
307
        dirty = true;
308
        super.editorDirtyStateChanged();
309
        if (element instanceof TaxonBase) {
310
            TaxonNameEditor page = (TaxonNameEditor) getPage(Page.NAME);
311
            AbstractGroupedContainer container = page.getContainer((TaxonBase) element);
312
            if (container != null) {
313
                container.refresh();
314
            }
315
        }
316
        //refresh part title
317
        //TODO: refresh taxon node in taxon navigator
318
        setPartName();
319
    }
320

    
321
    /* (non-Javadoc)
322
     * @see eu.etaxonomy.taxeditor.model.IDirtyMarkableSelectionProvider#forceDirty()
323
     */
324
    @Override
325
    public void forceDirty() {
326
        changed(null);
327
    }
328

    
329
    /**
330
     * The accepted taxon that is the input for this editor
331
     *
332
     * @return the accepted taxon
333
     */
334
    public Taxon getTaxon() {
335
        return input.getTaxon();
336
    }
337

    
338
    /*
339
     * (non-Javadoc)
340
     *
341
     * @see
342
     * eu.etaxonomy.cdm.api.conversation.IConversationEnabled#getConversationHolder
343
     * ()
344
     */
345
    /**
346
     * <p>
347
     * getConversationHolder
348
     * </p>
349
     *
350
     * @return a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder}
351
     *         object.
352
     */
353
    @Override
354
    public ConversationHolder getConversationHolder() {
355
        return conversation;
356
    }
357

    
358
    /**
359
     * <p>
360
     * setConversationHolder
361
     * </p>
362
     *
363
     * @param conversation
364
     *            a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder}
365
     *            object.
366
     */
367
    public void setConversationHolder(ConversationHolder conversation) {
368
        this.conversation = conversation;
369
    }
370

    
371
    /**
372
     * <p>
373
     * Getter for the field <code>undoContext</code>.
374
     * </p>
375
     *
376
     * @return a {@link org.eclipse.core.commands.operations.IUndoContext}
377
     *         object.
378
     */
379
    public IUndoContext getUndoContext() {
380
        return undoContext;
381
    }
382

    
383
    /**
384
     * <p>
385
     * Setter for the field <code>undoContext</code>.
386
     * </p>
387
     *
388
     * @param undoContext
389
     *            a {@link org.eclipse.core.commands.operations.IUndoContext}
390
     *            object.
391
     */
392
    public void setUndoContext(IUndoContext undoContext) {
393
        this.undoContext = undoContext;
394
    }
395

    
396
    /** {@inheritDoc} */
397
    @Override
398
    public void setFocus() {
399
        // logger.warn("Setting focus to editor");
400
        // bind the conversation
401
        getConversationHolder().bind();
402
        input.bind();
403
        // pass focus to the active editor page
404
        getActiveEditor().setFocus();
405
    }
406

    
407
    /*
408
     * (non-Javadoc)
409
     *
410
     * @see
411
     * eu.etaxonomy.cdm.persistence.hibernate.ICdmPostCrudObserver#update(eu
412
     * .etaxonomy.cdm.persistence.hibernate.CdmCrudEvent)
413
     */
414
    /** {@inheritDoc} */
415
    @Override
416
    public void update(CdmDataChangeMap events) {
417
        if (dataChangeBehavior == null) {
418
            dataChangeBehavior = new MultiPageTaxonEditorDataChangeBehaviour(this);
419
        }
420

    
421
        DataChangeBridge.handleDataChange(events, dataChangeBehavior);
422
    }
423

    
424
    /*
425
     * (non-Javadoc)
426
     *
427
     * @see
428
     * eu.etaxonomy.taxeditor.store.operations.IPostOperationEnabled#postOperation
429
     * ()
430
     */
431
    /** {@inheritDoc} */
432
    @Override
433
    public boolean postOperation(CdmBase objectAffectedByOperation) {
434
    		setDirty(true);
435

    
436
        for (IEditorPart editor : this.getPages()) {
437
            if (editor instanceof IPostOperationEnabled) {
438
                ((IPostOperationEnabled) editor).postOperation(objectAffectedByOperation);
439
            } else {
440
                MessagingUtils.warn(getClass(), "postOperation not enabled for editor " + editor);
441
            }
442
        }
443
        MessagingUtils.warn(getClass(), "postOperation called on MultiPageTaxonEditor. Can you make it more specific?");
444

    
445
        return false;
446
    }
447

    
448
    /**
449
     * Returns an <code>IEditorPart</code> implementation by type
450
     *
451
     * @param page
452
     *            the page type
453
     * @return a {@link eu.etaxonomy.taxeditor.editor.IMultiPageTaxonEditorPage}
454
     *         object.
455
     */
456
    public IMultiPageTaxonEditorPage getPage(Page page) {
457
        for (IEditorPart editor : this.getPages()) {
458
            if (editor.getClass().equals(page.getClazz())) {
459
                return (IMultiPageTaxonEditorPage) editor;
460
            }
461
        }
462
        return null;
463
    }
464

    
465
    /**
466
     * Return a list of <code>AbstractTaxonEditor</code>s registered with this
467
     * <code>MultiPageTaxonEditor</code>.
468
     *
469
     * @return a {@link java.util.List} object.
470
     */
471
    public List<IMultiPageTaxonEditorPage> getPages() {
472
        ArrayList<IMultiPageTaxonEditorPage> editors = new ArrayList<IMultiPageTaxonEditorPage>();
473
        for (int i = 0; i < this.getPageCount(); i++) {
474

    
475
            editors.add((IMultiPageTaxonEditorPage) this.getEditor(i));
476
        }
477
        return editors;
478
    }
479

    
480
    /**
481
     * Refreshes a certain page of the MultipageTaxonEditor
482
     *
483
     * @param page
484
     *            a {@link eu.etaxonomy.taxeditor.editor.Page} object.
485
     * @return a boolean.
486
     */
487
    public boolean redraw(Page page) {
488
        return redraw(page, true);
489
    }
490

    
491
    /**
492
     * Refreshes a certain page of the MultipageTaxonEditor and sets focus to
493
     * that page
494
     *
495
     * @param page
496
     *            a {@link eu.etaxonomy.taxeditor.editor.Page} object.
497
     * @param focus
498
     *            a boolean.
499
     * @return a boolean.
500
     */
501
    public boolean redraw(Page page, boolean focus) {
502
        IMultiPageTaxonEditorPage editorPage = getPage(page);
503
        return editorPage != null && editorPage.redraw(focus);
504
    }
505

    
506
    /**
507
     * <p>
508
     * onComplete
509
     * </p>
510
     *
511
     * @return a boolean.
512
     */
513
    @Override
514
    public boolean onComplete() {
515
        return false;
516
    }
517

    
518
    /**
519
     * Reloads the data for this
520
     */
521
    public void reload() {
522
        if (isDirty()) {
523
            MessagingUtils.warningDialog("Editor has unsaved data", getClass(), "This editor can not be "
524
                    + "refreshed because it contains unsaved data. Refreshing "
525
                    + "this editor would discard the changes. Please save this editor, "
526
                    + "close and reopen it manually in order to get the latest content");
527
        } else {
528
            TaxonEditorInput input = (TaxonEditorInput) getEditorInput();
529

    
530
            UUID uuid = input.getTaxonNode().getUuid();
531

    
532
            conversation.clear();
533

    
534
            try {
535
                TaxonEditorInput newInput = TaxonEditorInput.NewInstance(uuid);
536
                setInput(newInput);
537
                for (IMultiPageTaxonEditorPage editorPart : getPages()) {
538
                    editorPart.redraw();
539
                }
540
            } catch (Exception e) {
541
                MessagingUtils.messageDialog("Error refreshing editor", getClass(), "Could not refresh this editor", e);
542
            }
543
        }
544
    }
545

    
546
    @Override
547
    public String toString() {
548
        return String.format("%s[%s]", this.getClass().getSimpleName(), getEditorInput());
549
    }
550

    
551
    @Override
552
    public boolean permissionsSatisfied() {
553
        IEditorPart activeEditor = getActiveEditor();
554
        if(activeEditor != null && ISecuredEditor.class.isAssignableFrom(activeEditor.getClass())){
555
            return ((ISecuredEditor)activeEditor).permissionsSatisfied();
556
        }
557
        return true;
558
    }
559

    
560
    /* (non-Javadoc)
561
     * @see eu.etaxonomy.taxeditor.model.IPartContentHasMedia#canAttachMedia()
562
     */
563
    @Override
564
    public boolean canAttachMedia() {
565
        return true;
566
    }
567

    
568
}
(8-8/18)