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