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

(-)UndoRedo.java (-1 / +273 lines)
Lines 93-99 Link Here
93
93
94
    /** An undo manager which fires a change event each time it consumes a new undoable edit.
94
    /** An undo manager which fires a change event each time it consumes a new undoable edit.
95
    */
95
    */
96
    public static class Manager extends UndoManager implements UndoRedo {
96
    public static class Manager extends UndoGroupManager implements UndoRedo {
97
        static final long serialVersionUID = 6721367974521509720L;
97
        static final long serialVersionUID = 6721367974521509720L;
98
98
99
        private final ChangeSupport cs = new ChangeSupport(this);
99
        private final ChangeSupport cs = new ChangeSupport(this);
Lines 251-255 Link Here
251
        public String getRedoPresentationName() {
251
        public String getRedoPresentationName() {
252
            return ""; // NOI18N
252
            return ""; // NOI18N
253
        }
253
        }
254
    }
255
256
    /** <tt>UndoGroupManager</tt> extends {@link UndoManager}
257
     * and allows explicit control of what
258
     * <tt>UndoableEdit</tt>s are coalesced into compound edits,
259
     * rather than using the rules defined by the edits themselves.
260
     * Other than the default usage, special handling is initiated by invoking
261
     * <tt>beginUndoGroup()</tt>.
262
     * <p>
263
     * Three use cases are supported.
264
     * </p>
265
     * <ol>
266
     * <li> Default behavior is defined by {@link UndoManager}.</li>
267
     * <li> <tt>UnddoableEdit</tt>s issued between {@link #beginUndoGroup}
268
     * and {@link endUndoGroup} are placed into a single {@link CompoundEdit}.
269
     * Thus <tt>undo()</tt> and <tt>redo()</tt> treat them atomically.</li>
270
     * <li> Use {@link commitUndoGroup} to place any accumulated
271
     * <tt>UndoableEdit</tt>s into a <tt>CompoundEdit</tt>;
272
     * an application could do this at strategic points, such as EndOfLine
273
     * input or cursor movement. In this way, the application can accumulate
274
     * large chunks, but this behavior would not be enabled unless
275
     * <tt>beginUndoGroup</tt> is first invoked.</li>
276
     * </ol>
277
     * Note that the semantics of {@link UndoManager} are preserved at all
278
     * times, so certain methods, such as <tt>undo()</tt>, automatically issue
279
     * <tt>commitUndoGroup()</tt>.
280
     * @see UndoManager
281
     */
282
    public static class UndoGroupManager extends UndoManager {
283
        /** signals that edits should be accumulated */
284
        private boolean buildUndoGroup;
285
        /** accumulate edits here in undoGroup */
286
        private CompoundEdit undoGroup;
287
288
        /**
289
         * Direct this <tt>UndoGroupManager</tt> to begin coalescing any
290
         * <tt>UndoableEdit</tt>s that are added into a <tt>CompoundEdit</tt>.
291
         * <p>If edits are already being coalesced and some have been 
292
         * accumulated, they are commited as an atomic group and a new
293
         * group is started.
294
         * @see #addEdit
295
         * @see #endUndoGroup
296
         * @see #commitUndoGroup
297
         */
298
        public synchronized void beginUndoGroup() {
299
            commitUndoGroup();
300
            buildUndoGroup = true;
301
        }
302
303
        /**
304
         * Direct this <tt>UndoGroupManager</tt> to stop coalescing edits.
305
         * {@link #commitUndoGroup} is invoked to save accumulated edits as
306
         * an atomic group.
307
         * Until <tt>beginUndoGroupManager</tt> is invoked,
308
         * received <tt>UndoableEdit</tt>s are added singly.
309
         * <p>
310
         * This has no effect if edits are not being coalesced, for example
311
         * if <tt>beginUndoGroup</tt> has not been called.
312
         * @see #commitUndoGroup
313
         */
314
        public synchronized void endUndoGroup() {
315
            buildUndoGroup = false;
316
            commitUndoGroup();
317
        }
318
319
        /**
320
         * Commit any accumulated <tt>UndoableEdit</tt>s as an atomic
321
         * <tt>undo</tt>/<tt>redo</tt> group. {@link CompoundEdit#end}
322
         * is invoked on the <tt>CompoundEdit</tt> and it is added as a single
323
         * <tt>UndoableEdit</tt> to this <tt>UndoManager</tt>.
324
         * <p>
325
         * If edits are currently being coalesced, a new undo group is started.
326
         * This has no effect if edits are not being coalesced, for example
327
         * <tt>beginUndoGroup</tt> has not been called.
328
         */
329
        public synchronized void commitUndoGroup() {
330
            if(undoGroup == null) {
331
                return;
332
            }
333
            // super.addEdit may end up in this.addEdit,
334
            // so buildUndoGroup must be false
335
            boolean saveBuildUndoGroup = buildUndoGroup;
336
            buildUndoGroup = false;
337
338
            undoGroup.end();
339
            super.addEdit(undoGroup);
340
            undoGroup = null;
341
342
            buildUndoGroup = saveBuildUndoGroup;
343
        }
344
345
        // HACK ALERT! There are a variety of "marker" edits added to track
346
        // the modified state of the file. These can not be coalesced into
347
        // an undo group. So for proof of concept, detect them questionably.
348
349
        private static final String magicClassPrefix
350
                = "org.openide.text.CloneableEditorSupport$";
351
352
        /* return true if the edit is a magic marker, else false. */
353
        private boolean isMagic(UndoableEdit anEdit) {
354
            return anEdit.getClass().getName().startsWith(magicClassPrefix);
355
        }
356
357
        /** Add this edit atomically, not part of a group.
358
         * @return super.addEdit
359
         */
360
        private boolean commitAddEdit(UndoableEdit anEdit) {
361
            commitUndoGroup();
362
363
            boolean saveBuildUndoGroup = buildUndoGroup;
364
            buildUndoGroup = false;
365
            boolean f = super.addEdit(anEdit);
366
            //boolean f = addEdit(undoGroup);
367
            buildUndoGroup = saveBuildUndoGroup;
368
            return f;
369
        }
370
371
        /** AtomicEdit tags an UndoableEdit so the
372
         * UndoGroupManager does not coalesce it.
373
         */
374
        public interface AtomicEdit {
375
        }
376
377
        /**
378
         * If this <tt>UndoManager</tt> is coalescing edits then add
379
         * <tt>anEdit</tt> to the accumulating <tt>CompoundEdit</tt>.
380
         * Otherwise, add it to this UndoManager. In either case the
381
         * edit is saved for later <tt>undo</tt> or <tt>redo</tt>.
382
         * @return {@inheritDoc}
383
         * @see #beginUndoGroup
384
         * @see #endUndoGroup
385
         * @see #commitUndoGroup
386
         */
387
        public synchronized boolean addEdit(UndoableEdit anEdit) {
388
            if(!isInProgress())
389
                return false;
390
391
            if(buildUndoGroup) {
392
                if(anEdit instanceof AtomicEdit || isMagic(anEdit))
393
                    return commitAddEdit(anEdit);
394
                if(undoGroup == null)
395
                    undoGroup = new CompoundEdit();
396
                return undoGroup.addEdit(anEdit);
397
            } else {
398
                return super.addEdit(anEdit);
399
            }
400
        }
401
402
        /** {@inheritDoc} */
403
        public synchronized void discardAllEdits() {
404
            commitUndoGroup();
405
            super.discardAllEdits();
406
        }
407
408
        //
409
        // TODO: limits
410
        //
411
412
        /** {@inheritDoc} */
413
        public synchronized void undoOrRedo() {
414
            commitUndoGroup();
415
            super.undoOrRedo();
416
        }
417
418
        /** {@inheritDoc} */
419
        public synchronized boolean canUndoOrRedo() {
420
            if(undoGroup != null)
421
                return true;
422
            return super.canUndoOrRedo();
423
        }
424
425
        /** {@inheritDoc} */
426
        public synchronized void undo() {
427
            commitUndoGroup();
428
            super.undo();
429
        }
430
431
        /** {@inheritDoc} */
432
        public synchronized boolean canUndo() {
433
            if(undoGroup != null)
434
                return true;
435
            return super.canUndo();
436
        }
437
438
        /** {@inheritDoc} */
439
        public synchronized void redo() {
440
            if(undoGroup != null)
441
                throw new CannotRedoException();
442
            super.redo();
443
        }
444
445
        /** {@inheritDoc} */
446
        public synchronized boolean canRedo() {
447
            if(undoGroup != null)
448
                return false;
449
            return super.canRedo();
450
        }
451
452
        /** {@inheritDoc} */
453
        public synchronized void end() {
454
            commitUndoGroup();
455
            super.end();
456
        }
457
458
        /** {@inheritDoc} */
459
        public synchronized String getUndoOrRedoPresentationName() {
460
            if(undoGroup != null)
461
                return undoGroup.getUndoPresentationName();
462
            return super.getUndoOrRedoPresentationName();
463
        }
464
465
        /** {@inheritDoc} */
466
        public synchronized String getUndoPresentationName() {
467
            if(undoGroup != null)
468
                return undoGroup.getUndoPresentationName();
469
            return super.getUndoPresentationName();
470
        }
471
472
        /** {@inheritDoc} */
473
        public synchronized String getRedoPresentationName() {
474
            if(undoGroup != null)
475
                return undoGroup.getRedoPresentationName();
476
            return super.getRedoPresentationName();
477
        }
478
479
        /** {@inheritDoc} */
480
        public boolean isSignificant() {
481
            if(undoGroup != null && undoGroup.isSignificant()) {
482
                return true;
483
            }
484
            return super.isSignificant();
485
        }
486
487
        /** {@inheritDoc} */
488
        public synchronized void die() {
489
            commitUndoGroup();
490
            super.die();
491
        }
492
493
        /** {@inheritDoc} */
494
        public String getPresentationName() {
495
            if(undoGroup != null)
496
                return undoGroup.getPresentationName();
497
            return super.getPresentationName();
498
        }
499
500
        // The protected methods are only accessed from
501
        // synchronized methods that commitUndoGroup,
502
        // they do not need to be in this class
503
        /*protected UndoableEdit editToBeUndone() {
504
            if(undoGroup != null)
505
                return null;
506
            return super.editToBeUndone();
507
        }
508
509
        protected UndoableEdit editToBeRedone() {
510
            if(undoGroup != null)
511
                return null;
512
            return super.editToBeRedone();
513
        }
514
515
        protected void undoTo(UndoableEdit edit) {
516
            if(undoGroup != null)
517
                throw new CannotUndoException();
518
            super.undoTo(edit);
519
        }
520
521
        protected void redoTo(UndoableEdit edit) {
522
            if(undoGroup != null)
523
                throw new CannotRedoException();
524
            super.redoTo(edit);
525
        }*/
254
    }
526
    }
255
}
527
}

Return to bug 103467