This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 103467
Collapse All | Expand All

(-)a/openide.text/src/org/openide/text/CloneableEditorSupport.java (-2 / +290 lines)
Lines 93-100 Link Here
93
import javax.swing.event.DocumentListener;
93
import javax.swing.event.DocumentListener;
94
import javax.swing.event.UndoableEditEvent;
94
import javax.swing.event.UndoableEditEvent;
95
import javax.swing.text.*;
95
import javax.swing.text.*;
96
import javax.swing.undo.AbstractUndoableEdit;
96
import javax.swing.undo.CannotRedoException;
97
import javax.swing.undo.CannotRedoException;
97
import javax.swing.undo.CannotUndoException;
98
import javax.swing.undo.CannotUndoException;
99
import javax.swing.undo.CompoundEdit;
100
import javax.swing.undo.UndoManager;
98
import javax.swing.undo.UndoableEdit;
101
import javax.swing.undo.UndoableEdit;
99
import org.netbeans.api.editor.mimelookup.MimeLookup;
102
import org.netbeans.api.editor.mimelookup.MimeLookup;
100
import org.netbeans.api.editor.mimelookup.MimePath;
103
import org.netbeans.api.editor.mimelookup.MimePath;
Lines 120-125 Link Here
120
* but does not implement
123
* but does not implement
121
* those interfaces. It is up to the subclass to decide which interfaces
124
* those interfaces. It is up to the subclass to decide which interfaces
122
* really implement and which not.
125
* really implement and which not.
126
* <P>
127
* This class supports collecting multiple edits into a group which is treated
128
* as a single edit by undo/redo. Send BEGIN_COMIT_GROUP and END_COMIT_GROUP
129
* to UndoableEditListener. These must always be paired.
123
*
130
*
124
* @author Jaroslav Tulach
131
* @author Jaroslav Tulach
125
*/
132
*/
Lines 128-133 Link Here
128
    
135
    
129
    /** Common name for editor mode. */
136
    /** Common name for editor mode. */
130
    public static final String EDITOR_MODE = "editor"; // NOI18N
137
    public static final String EDITOR_MODE = "editor"; // NOI18N
138
    /** Start a group of edits which will be committed as a single edit. */
139
    public static final UndoableEdit BEGIN_COMIT_GROUP = UndoGroupManager.BEGIN_COMIT_GROUP;
140
    /** End a group of edits. */
141
    public static final UndoableEdit END_COMIT_GROUP = UndoGroupManager.END_COMIT_GROUP;
131
    private static final String PROP_PANE = "CloneableEditorSupport.Pane"; //NOI18N
142
    private static final String PROP_PANE = "CloneableEditorSupport.Pane"; //NOI18N
132
    private static final int DOCUMENT_NO = 0;
143
    private static final int DOCUMENT_NO = 0;
133
    private static final int DOCUMENT_LOADING = 1;
144
    private static final int DOCUMENT_LOADING = 1;
Lines 2986-2992 Link Here
2986
    }
2997
    }
2987
2998
2988
    /** Generic undoable edit that delegates to the given undoable edit. */
2999
    /** Generic undoable edit that delegates to the given undoable edit. */
2989
    private class FilterUndoableEdit implements UndoableEdit {
3000
    private class FilterUndoableEdit
3001
            implements UndoableEdit, UndoGroupManager.SeparateEdit
3002
    {
2990
        protected UndoableEdit delegate;
3003
        protected UndoableEdit delegate;
2991
3004
2992
        FilterUndoableEdit() {
3005
        FilterUndoableEdit() {
Lines 3187-3193 Link Here
3187
    /** An improved version of UndoRedo manager that locks document before
3200
    /** An improved version of UndoRedo manager that locks document before
3188
     * doing any other operations.
3201
     * doing any other operations.
3189
     */
3202
     */
3190
    private final static class CESUndoRedoManager extends UndoRedo.Manager {
3203
    private final static class CESUndoRedoManager extends UndoGroupManager {
3191
        private CloneableEditorSupport support;
3204
        private CloneableEditorSupport support;
3192
3205
3193
        public CESUndoRedoManager(CloneableEditorSupport c) {
3206
        public CESUndoRedoManager(CloneableEditorSupport c) {
Lines 3421-3426 Link Here
3421
        }
3434
        }
3422
    }
3435
    }
3423
3436
3437
    /**
3438
     * <tt>UndoGroupManager</tt> extends {@link UndoManager}
3439
     * and allows explicit control of what
3440
     * <tt>UndoableEdit</tt>s are coalesced into compound edits,
3441
     * rather than using the rules defined by the edits themselves.
3442
     * Groups are defined using BEGIN_COMIT_GROUP and END_COMIT_GROUP.
3443
     * Send these to UndoableEditListener. These must always be paired.
3444
     * <p>
3445
     * These use cases are supported.
3446
     * </p>
3447
     * <ol>
3448
     * <li> Default behavior is defined by {@link UndoManager}.</li>
3449
     * <li> <tt>UnddoableEdit</tt>s issued between {@link #BEGIN_COMIT_GROUP}
3450
     * and {@link END_COMIT_GROUP} are placed into a single
3451
     * {@link CompoundEdit}.
3452
     * Thus <tt>undo()</tt> and <tt>redo()</tt> treat them 
3453
     * as a single undo/redo.</li>
3454
     * <li> Use {@link comitUndoGroup} to commit accumulated
3455
     * <tt>UndoableEdit</tt>s into a single <tt>CompoundEdit</tt>
3456
     * (and to continue accumulating);
3457
     * an application could do this at strategic points, such as EndOfLine
3458
     * input or cursor movement. In this way, the application can accumulate
3459
     * large chunks.</li>
3460
     * <li>BEGIN/END nest.</li>
3461
     * </ol>
3462
     * @see UndoManager
3463
     */
3464
    private static class UndoGroupManager extends UndoRedo.Manager {
3465
        /** signals that edits are being accumulated */
3466
        private int buildUndoGroup;
3467
        /** accumulate edits here in undoGroup */
3468
        private CompoundEdit undoGroup;
3469
3470
        /** Start a group of edits which will be committed as a single edit. */
3471
        public static final UndoableEdit BEGIN_COMIT_GROUP = new ComitGroupEdit();
3472
        /** End a group of edits. */
3473
        public static final UndoableEdit END_COMIT_GROUP = new ComitGroupEdit();
3474
3475
        /** SeparateEdit tags an UndoableEdit so the
3476
         * UndoGroupManager does not coalesce it.
3477
         */
3478
        public interface SeparateEdit {
3479
        }
3480
3481
        private static class ComitGroupEdit extends AbstractUndoableEdit {
3482
            @Override
3483
            public boolean isSignificant() {
3484
                return false;
3485
            }
3486
        }
3487
3488
        @Override
3489
        public void undoableEditHappened(UndoableEditEvent ue)
3490
        {
3491
            if(ue.getEdit() == BEGIN_COMIT_GROUP) {
3492
                beginUndoGroup();
3493
            } else if(ue.getEdit() == END_COMIT_GROUP) {
3494
                endUndoGroup();
3495
            } else {
3496
                super.undoableEditHappened(ue);
3497
            }
3498
        }
3499
3500
        /**
3501
         * Direct this <tt>UndoGroupManager</tt> to begin coalescing any
3502
         * <tt>UndoableEdit</tt>s that are added into a <tt>CompoundEdit</tt>.
3503
         * <p>If edits are already being coalesced and some have been 
3504
         * accumulated, they are commited as an atomic group and a new
3505
         * group is started.
3506
         * @see #addEdit
3507
         * @see #endUndoGroup
3508
         */
3509
        private synchronized void beginUndoGroup() {
3510
            commitUndoGroup();
3511
            buildUndoGroup++;
3512
        }
3513
3514
        /**
3515
         * Direct this <tt>UndoGroupManager</tt> to stop coalescing edits.
3516
         * Until <tt>beginUndoGroupManager</tt> is invoked,
3517
         * any received <tt>UndoableEdit</tt>s are added singly.
3518
         * <p>
3519
         * This has no effect if edits are not being coalesced, for example
3520
         * if <tt>beginUndoGroup</tt> has not been called.
3521
         */
3522
        private synchronized void endUndoGroup() {
3523
            buildUndoGroup--;
3524
            if(buildUndoGroup < 0)
3525
                buildUndoGroup = 0;
3526
            // slam buildUndoGroup to 0 to disable nesting
3527
            commitUndoGroup();
3528
        }
3529
3530
        /**
3531
         * Commit any accumulated <tt>UndoableEdit</tt>s as an atomic
3532
         * <tt>undo</tt>/<tt>redo</tt> group. {@link CompoundEdit#end}
3533
         * is invoked on the <tt>CompoundEdit</tt> and it is added as a single
3534
         * <tt>UndoableEdit</tt> to this <tt>UndoManager</tt>.
3535
         * <p>
3536
         * If edits are currently being coalesced, a new undo group is started.
3537
         * This has no effect if edits are not being coalesced, for example
3538
         * <tt>beginUndoGroup</tt> has not been called.
3539
         */
3540
        private synchronized void commitUndoGroup() {
3541
            if(undoGroup == null) {
3542
                return;
3543
            }
3544
            // super.addEdit may end up in this.addEdit,
3545
            // so buildUndoGroup must be false
3546
            int saveBuildUndoGroup = buildUndoGroup;
3547
            buildUndoGroup = 0;
3548
3549
            undoGroup.end();
3550
            super.addEdit(undoGroup);
3551
            undoGroup = null;
3552
3553
            buildUndoGroup = saveBuildUndoGroup;
3554
        }
3555
3556
        /** Add this edit separately, not part of a group.
3557
         * @return super.addEdit
3558
         */
3559
        private boolean commitAddEdit(UndoableEdit anEdit) {
3560
            commitUndoGroup();
3561
3562
            int saveBuildUndoGroup = buildUndoGroup;
3563
            buildUndoGroup = 0;
3564
            boolean f = super.addEdit(anEdit);
3565
            //boolean f = addEdit(undoGroup);
3566
            buildUndoGroup = saveBuildUndoGroup;
3567
            return f;
3568
        }
3569
3570
        /**
3571
         * If this <tt>UndoManager</tt> is coalescing edits then add
3572
         * <tt>anEdit</tt> to the accumulating <tt>CompoundEdit</tt>.
3573
         * Otherwise, add it to this UndoManager. In either case the
3574
         * edit is saved for later <tt>undo</tt> or <tt>redo</tt>.
3575
         * @return {@inheritDoc}
3576
         * @see #beginUndoGroup
3577
         * @see #endUndoGroup
3578
         */
3579
        @Override
3580
        public synchronized boolean addEdit(UndoableEdit anEdit) {
3581
            if(!isInProgress())
3582
                return false;
3583
3584
            if(buildUndoGroup > 0) {
3585
                if(anEdit instanceof SeparateEdit)
3586
                    return commitAddEdit(anEdit);
3587
                if(undoGroup == null)
3588
                    undoGroup = new CompoundEdit();
3589
                return undoGroup.addEdit(anEdit);
3590
            } else {
3591
                return super.addEdit(anEdit);
3592
            }
3593
        }
3594
3595
        /** {@inheritDoc} */
3596
        @Override
3597
        public synchronized void discardAllEdits() {
3598
            commitUndoGroup();
3599
            super.discardAllEdits();
3600
        }
3601
3602
        //
3603
        // TODO: limits
3604
        //
3605
3606
        /** {@inheritDoc} */
3607
        @Override
3608
        public synchronized void undoOrRedo() {
3609
            commitUndoGroup();
3610
            super.undoOrRedo();
3611
        }
3612
3613
        /** {@inheritDoc} */
3614
        @Override
3615
        public synchronized boolean canUndoOrRedo() {
3616
            if(undoGroup != null)
3617
                return true;
3618
            return super.canUndoOrRedo();
3619
        }
3620
3621
        /** {@inheritDoc} */
3622
        @Override
3623
        public synchronized void undo() {
3624
            commitUndoGroup();
3625
            super.undo();
3626
        }
3627
3628
        /** {@inheritDoc} */
3629
        @Override
3630
        public synchronized boolean canUndo() {
3631
            if(undoGroup != null)
3632
                return true;
3633
            return super.canUndo();
3634
        }
3635
3636
        /** {@inheritDoc} */
3637
        @Override
3638
        public synchronized void redo() {
3639
            if(undoGroup != null)
3640
                throw new CannotRedoException();
3641
            super.redo();
3642
        }
3643
3644
        /** {@inheritDoc} */
3645
        @Override
3646
        public synchronized boolean canRedo() {
3647
            if(undoGroup != null)
3648
                return false;
3649
            return super.canRedo();
3650
        }
3651
3652
        /** {@inheritDoc} */
3653
        @Override
3654
        public synchronized void end() {
3655
            commitUndoGroup();
3656
            super.end();
3657
        }
3658
3659
        /** {@inheritDoc} */
3660
        @Override
3661
        public synchronized String getUndoOrRedoPresentationName() {
3662
            if(undoGroup != null)
3663
                return undoGroup.getUndoPresentationName();
3664
            return super.getUndoOrRedoPresentationName();
3665
        }
3666
3667
        /** {@inheritDoc} */
3668
        @Override
3669
        public synchronized String getUndoPresentationName() {
3670
            if(undoGroup != null)
3671
                return undoGroup.getUndoPresentationName();
3672
            return super.getUndoPresentationName();
3673
        }
3674
3675
        /** {@inheritDoc} */
3676
        @Override
3677
        public synchronized String getRedoPresentationName() {
3678
            if(undoGroup != null)
3679
                return undoGroup.getRedoPresentationName();
3680
            return super.getRedoPresentationName();
3681
        }
3682
3683
        /** {@inheritDoc} */
3684
        @Override
3685
        public boolean isSignificant() {
3686
            if(undoGroup != null && undoGroup.isSignificant()) {
3687
                return true;
3688
            }
3689
            return super.isSignificant();
3690
        }
3691
3692
        /** {@inheritDoc} */
3693
        @Override
3694
        public synchronized void die() {
3695
            commitUndoGroup();
3696
            super.die();
3697
        }
3698
3699
        /** {@inheritDoc} */
3700
        @Override
3701
        public String getPresentationName() {
3702
            if(undoGroup != null)
3703
                return undoGroup.getPresentationName();
3704
            return super.getPresentationName();
3705
        }
3706
3707
        // The protected methods are only accessed from
3708
        // synchronized methods that do commitUndoGroup
3709
        // so they do not need to be overridden in this class
3710
    }
3711
3424
    /** Special runtime exception that holds the original I/O failure.
3712
    /** Special runtime exception that holds the original I/O failure.
3425
     */
3713
     */
3426
    static final class DelegateIOExc extends IllegalStateException {
3714
    static final class DelegateIOExc extends IllegalStateException {

Return to bug 103467