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 |
} |