Project

General

Profile

Download (16.7 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
        // 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
308
        if (element != null){
309
            dirty = true;
310
            super.editorDirtyStateChanged();
311
        }
312

    
313
        if (element instanceof TaxonBase) {
314
            TaxonNameEditor page = (TaxonNameEditor) getPage(Page.NAME);
315
            AbstractGroupedContainer container = page.getContainer((TaxonBase) element);
316
            if (container != null) {
317
                container.refresh();
318
            }
319
        }
320
        //refresh part title
321
        //TODO: refresh taxon node in taxon navigator
322
        setPartName();
323
    }
324

    
325
    /* (non-Javadoc)
326
     * @see eu.etaxonomy.taxeditor.model.IDirtyMarkableSelectionProvider#forceDirty()
327
     */
328
    @Override
329
    public void forceDirty() {
330
        changed(null);
331
    }
332

    
333
    /**
334
     * The accepted taxon that is the input for this editor
335
     *
336
     * @return the accepted taxon
337
     */
338
    public Taxon getTaxon() {
339
        return input.getTaxon();
340
    }
341

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

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

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

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

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

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

    
425
        DataChangeBridge.handleDataChange(events, dataChangeBehavior);
426
    }
427

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

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

    
449
        return false;
450
    }
451

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

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

    
479
            editors.add((IMultiPageTaxonEditorPage) this.getEditor(i));
480
        }
481
        return editors;
482
    }
483

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

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

    
510
    /**
511
     * <p>
512
     * onComplete
513
     * </p>
514
     *
515
     * @return a boolean.
516
     */
517
    @Override
518
    public boolean onComplete() {
519
        return false;
520
    }
521

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

    
534
            UUID uuid = input.getTaxonNode().getUuid();
535

    
536
            conversation.clear();
537

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

    
550
    @Override
551
    public String toString() {
552
        return String.format("%s[%s]", this.getClass().getSimpleName(), getEditorInput());
553
    }
554

    
555
    @Override
556
    public boolean permissionsSatisfied() {
557
        IEditorPart activeEditor = getActiveEditor();
558
        if(activeEditor != null && ISecuredEditor.class.isAssignableFrom(activeEditor.getClass())){
559
            return ((ISecuredEditor)activeEditor).permissionsSatisfied();
560
        }
561
        return true;
562
    }
563

    
564
    /* (non-Javadoc)
565
     * @see eu.etaxonomy.taxeditor.model.IPartContentHasMedia#canAttachMedia()
566
     */
567
    @Override
568
    public boolean canAttachMedia() {
569
        return true;
570
    }
571

    
572
}
(8-8/18)