Lines 215-221
Link Here
|
215 |
private Listener listener; |
215 |
private Listener listener; |
216 |
|
216 |
|
217 |
/** the undo/redo manager to use for this document */ |
217 |
/** the undo/redo manager to use for this document */ |
218 |
private UndoRedo.Manager undoRedo; |
218 |
private UndoRedoManager undoRedo; |
219 |
|
219 |
|
220 |
/** lines set for this object */ |
220 |
/** lines set for this object */ |
221 |
private Line.Set lineSet; |
221 |
private Line.Set lineSet; |
Lines 261-268
Link Here
|
261 |
* <br> |
261 |
* <br> |
262 |
* Also set when document is being reloaded. |
262 |
* Also set when document is being reloaded. |
263 |
*/ |
263 |
*/ |
264 |
private boolean revertingUndoOrReloading; |
264 |
private boolean documentReloading; |
265 |
private boolean justRevertedToNotModified; |
|
|
266 |
private volatile int documentStatus = DOCUMENT_NO; |
265 |
private volatile int documentStatus = DOCUMENT_NO; |
267 |
private Throwable prepareDocumentRuntimeException; |
266 |
private Throwable prepareDocumentRuntimeException; |
268 |
|
267 |
|
Lines 271-280
Link Here
|
271 |
*/ |
270 |
*/ |
272 |
private Map<Line,Reference<Line>> lineSetWHM; |
271 |
private Map<Line,Reference<Line>> lineSetWHM; |
273 |
private boolean annotationsLoaded; |
272 |
private boolean annotationsLoaded; |
|
|
273 |
|
274 |
private DocFilter docFilter; |
274 |
|
275 |
|
275 |
/** Classes that have been warned about overriding asynchronousOpen() */ |
276 |
/** Classes that have been warned about overriding asynchronousOpen() */ |
276 |
private static final Set<Class> warnedClasses = new WeakSet<Class>(); |
277 |
private static final Set<Class> warnedClasses = new WeakSet<Class>(); |
277 |
|
278 |
|
278 |
/** Creates new CloneableEditorSupport attached to given environment. |
279 |
/** Creates new CloneableEditorSupport attached to given environment. |
279 |
* |
280 |
* |
280 |
* @param env environment that is source of all actions around the |
281 |
* @param env environment that is source of all actions around the |
Lines 385-395
Link Here
|
385 |
} |
386 |
} |
386 |
|
387 |
|
387 |
if (undoRedo == null) { |
388 |
if (undoRedo == null) { |
388 |
undoRedo = createUndoRedoManager(); |
389 |
UndoRedo.Manager mgr = createUndoRedoManager(); |
|
|
390 |
if (!(mgr instanceof UndoRedoManager)) { |
391 |
ERR.info("createUndoRedoManager(): ignoring created instance of class " + // NOI18N |
392 |
mgr.getClass() + " since CloneableEditorSupport requires instance of " + // NOI18N" |
393 |
UndoRedoManager.class.getName() + "\n"); // NOI18N |
394 |
mgr = new UndoRedoManager(this); |
395 |
} |
396 |
undoRedo = (UndoRedoManager) mgr; |
389 |
} |
397 |
} |
390 |
|
398 |
|
391 |
return undoRedo; |
399 |
return undoRedo; |
392 |
} |
400 |
} |
|
|
401 |
|
402 |
UndoRedoManager getUndoRedoManager() { |
403 |
return (UndoRedoManager) getUndoRedo(); |
404 |
} |
393 |
|
405 |
|
394 |
/** Provides access to position manager for the document. |
406 |
/** Provides access to position manager for the document. |
395 |
* It maintains a set of positions even the document is in memory |
407 |
* It maintains a set of positions even the document is in memory |
Lines 728-733
Link Here
|
728 |
// atomic action has finished |
740 |
// atomic action has finished |
729 |
// definitively sooner than leaving lock section |
741 |
// definitively sooner than leaving lock section |
730 |
// and notifying al waiters, see #47022 |
742 |
// and notifying al waiters, see #47022 |
|
|
743 |
getUndoRedoManager().markSavepoint(); |
731 |
getDoc().addUndoableEditListener(getUndoRedo()); |
744 |
getDoc().addUndoableEditListener(getUndoRedo()); |
732 |
d = getDoc(); |
745 |
d = getDoc(); |
733 |
} catch (DelegateIOExc t) { |
746 |
} catch (DelegateIOExc t) { |
Lines 782-793
Link Here
|
782 |
} else { |
795 |
} else { |
783 |
d.putProperty("modificationListener", null); // NOI18N |
796 |
d.putProperty("modificationListener", null); // NOI18N |
784 |
} |
797 |
} |
785 |
} else { |
798 |
} |
786 |
if (add) { |
799 |
|
787 |
d.addDocumentListener(getListener()); |
800 |
if (add) { |
788 |
} else { |
801 |
if (d instanceof AbstractDocument) { |
789 |
d.removeDocumentListener(getListener()); |
802 |
AbstractDocument aDoc = (AbstractDocument) d; |
|
|
803 |
DocumentFilter origFilter = aDoc.getDocumentFilter(); |
804 |
docFilter = new DocFilter(origFilter); |
805 |
aDoc.setDocumentFilter(docFilter); |
806 |
} else { // Put property for non-AD |
807 |
DocumentFilter origFilter = (DocumentFilter) d.getProperty(DocumentFilter.class); |
808 |
docFilter = new DocFilter(origFilter); |
809 |
d.putProperty(DocumentFilter.class, docFilter); |
790 |
} |
810 |
} |
|
|
811 |
d.addDocumentListener(getListener()); |
812 |
|
813 |
|
814 |
} else { // remove filter |
815 |
if (docFilter != null) { |
816 |
if (d instanceof AbstractDocument) { |
817 |
AbstractDocument aDoc = (AbstractDocument) d; |
818 |
aDoc.setDocumentFilter(docFilter.origFilter); |
819 |
} else { // Put property for non-AD |
820 |
d.putProperty(DocumentFilter.class, docFilter.origFilter); |
821 |
} |
822 |
docFilter = null; |
823 |
} |
824 |
d.removeDocumentListener(getListener()); |
791 |
} |
825 |
} |
792 |
} |
826 |
} |
793 |
|
827 |
|
Lines 1076-1083
Link Here
|
1076 |
} |
1110 |
} |
1077 |
} |
1111 |
} |
1078 |
|
1112 |
|
1079 |
// Insert before-save undo event to enable unmodifying undo |
1113 |
getUndoRedoManager().markSavepoint(); |
1080 |
getUndoRedo().undoableEditHappened(new UndoableEditEvent(this, new BeforeSaveEdit(lastSaveTime))); |
|
|
1081 |
|
1114 |
|
1082 |
// update cached info about lines |
1115 |
// update cached info about lines |
1083 |
updateLineSet(true); |
1116 |
updateLineSet(true); |
Lines 1101-1107
Link Here
|
1101 |
// Run before-save actions |
1134 |
// Run before-save actions |
1102 |
Runnable beforeSaveRunnable = (Runnable) myDoc.getProperty("beforeSaveRunnable"); |
1135 |
Runnable beforeSaveRunnable = (Runnable) myDoc.getProperty("beforeSaveRunnable"); |
1103 |
if (beforeSaveRunnable != null) { |
1136 |
if (beforeSaveRunnable != null) { |
1104 |
beforeSaveRunnable.run(); |
1137 |
undoRedo.setPerformingSaveActions(true); |
|
|
1138 |
try { |
1139 |
beforeSaveRunnable.run(); |
1140 |
} finally { |
1141 |
undoRedo.setPerformingSaveActions(false); |
1142 |
} |
1105 |
} |
1143 |
} |
1106 |
|
1144 |
|
1107 |
SaveAsReader saveAsReader = new SaveAsReader(); |
1145 |
SaveAsReader saveAsReader = new SaveAsReader(); |
Lines 1505-1518
Link Here
|
1505 |
/** Test whether the document is ready. |
1543 |
/** Test whether the document is ready. |
1506 |
* @return <code>true</code> if document is ready |
1544 |
* @return <code>true</code> if document is ready |
1507 |
*/ |
1545 |
*/ |
1508 |
private boolean isDocumentReady() { |
1546 |
boolean isDocumentReady() { |
1509 |
CloneableEditorSupport redirect = CloneableEditorSupportRedirector.findRedirect(this); |
1547 |
CloneableEditorSupport redirect = CloneableEditorSupportRedirector.findRedirect(this); |
1510 |
if (redirect != null) { |
1548 |
if (redirect != null) { |
1511 |
return redirect.isDocumentReady(); |
1549 |
return redirect.isDocumentReady(); |
1512 |
} |
1550 |
} |
1513 |
return documentStatus == DOCUMENT_READY; |
1551 |
return documentStatus == DOCUMENT_READY; |
1514 |
} |
1552 |
} |
1515 |
|
1553 |
|
1516 |
/** |
1554 |
/** |
1517 |
* Set the MIME type for the document. |
1555 |
* Set the MIME type for the document. |
1518 |
* @param s the new MIME type |
1556 |
* @param s the new MIME type |
Lines 1600-1606
Link Here
|
1600 |
* @return the undo/redo manager |
1638 |
* @return the undo/redo manager |
1601 |
*/ |
1639 |
*/ |
1602 |
protected UndoRedo.Manager createUndoRedoManager() { |
1640 |
protected UndoRedo.Manager createUndoRedoManager() { |
1603 |
return new CESUndoRedoManager(this); |
1641 |
return new UndoRedoManager(this); |
1604 |
} |
1642 |
} |
1605 |
|
1643 |
|
1606 |
/** Returns an InputStream which reads the current data from this editor, taking into |
1644 |
/** Returns an InputStream which reads the current data from this editor, taking into |
Lines 1808-1813
Link Here
|
1808 |
// XXX do this from AWT??? |
1846 |
// XXX do this from AWT??? |
1809 |
ERR.fine("task-discardAllEdits"); |
1847 |
ERR.fine("task-discardAllEdits"); |
1810 |
getUndoRedo().discardAllEdits(); |
1848 |
getUndoRedo().discardAllEdits(); |
|
|
1849 |
getUndoRedoManager().markSavepoint(); |
1811 |
ERR.fine("task-check already modified"); |
1850 |
ERR.fine("task-check already modified"); |
1812 |
// #57104 - if modified previously now it should become unmodified |
1851 |
// #57104 - if modified previously now it should become unmodified |
1813 |
if (isAlreadyModified()) { |
1852 |
if (isAlreadyModified()) { |
Lines 1925-1954
Link Here
|
1925 |
* @return true if the modification was allowed, false if it should be prohibited |
1964 |
* @return true if the modification was allowed, false if it should be prohibited |
1926 |
*/ |
1965 |
*/ |
1927 |
final boolean callNotifyModified() { |
1966 |
final boolean callNotifyModified() { |
1928 |
// #57104 - when reverting undo the revertingUndoOrReloading flag is set |
1967 |
if (!isAlreadyModified() && !documentReloading) { |
1929 |
// to prevent infinite undoing which could happen now due to fix #56963 |
|
|
1930 |
// (undoable edit being undone in the document notifies |
1931 |
// document's modification listener to mark the file as modified). |
1932 |
// Maybe clearing alreadyModified flag |
1933 |
// AFTER revertPreviousOrUpcomingUndo() could suffice as well |
1934 |
// instead of the revertingUndoOrReloading flag. |
1935 |
// Also notifyModified() is not called during reloadDocument() |
1936 |
// to prevent situation when output stream is taken from the file |
1937 |
// (for which CloneableEditorSupport exists) under file's lock |
1938 |
// and once closed (still under file's lock) the CES is trying to reload |
1939 |
// the file calling notifyModified() that tries to grab the lock |
1940 |
// and fails leading to undoing of the file's content to the one |
1941 |
// before the reload. |
1942 |
if (!isAlreadyModified() && !revertingUndoOrReloading) { |
1943 |
setAlreadyModified(true); |
1968 |
setAlreadyModified(true); |
1944 |
|
1969 |
|
1945 |
if (!notifyModified()) { |
1970 |
if (!notifyModified()) { |
1946 |
ERR.log(Level.INFO,"callNotifyModified notifyModified returns false this:" + getClass().getName()); |
|
|
1947 |
setAlreadyModified(false); |
1971 |
setAlreadyModified(false); |
1948 |
revertingUndoOrReloading = true; |
|
|
1949 |
revertPreviousOrUpcomingUndo(); |
1950 |
revertingUndoOrReloading = false; |
1951 |
|
1952 |
return false; |
1972 |
return false; |
1953 |
} |
1973 |
} |
1954 |
} |
1974 |
} |
Lines 2036-2116
Link Here
|
2036 |
return true; |
2056 |
return true; |
2037 |
} |
2057 |
} |
2038 |
|
2058 |
|
2039 |
/** Resets listening on <code>UndoRedo</code>, |
|
|
2040 |
* and in case next undo edit comes, schedules processesing of it. |
2041 |
* Used to revert modification e.g. of document of [read-only] env. */ |
2042 |
private void revertPreviousOrUpcomingUndo() { |
2043 |
UndoRedo.Manager ur = getUndoRedo(); |
2044 |
Listener l = getListener(); |
2045 |
|
2046 |
if (Boolean.TRUE.equals(getDocument().getProperty("supportsModificationListener"))) { // NOI18N |
2047 |
|
2048 |
// revert undos now |
2049 |
SearchBeforeModificationEdit edit = new SearchBeforeModificationEdit(); |
2050 |
|
2051 |
try { |
2052 |
for (;;) { |
2053 |
edit.delegate = null; |
2054 |
ur.undoableEditHappened(new UndoableEditEvent(getDocument(), edit)); |
2055 |
|
2056 |
if (edit.delegate == null) break; // no previous edit |
2057 |
|
2058 |
if (edit.delegate instanceof BeforeModificationEdit) { |
2059 |
if (edit.delegate != null) { |
2060 |
// undo anyway |
2061 |
ur.undo(); |
2062 |
} |
2063 |
|
2064 |
// and exit |
2065 |
break; |
2066 |
} |
2067 |
|
2068 |
if (edit.delegate instanceof BeforeSaveEdit) { |
2069 |
break; |
2070 |
} |
2071 |
|
2072 |
// otherwise remove the edit |
2073 |
ur.undo(); |
2074 |
} |
2075 |
} catch (CannotUndoException ex) { |
2076 |
// ok, cannot undo, just ignore this |
2077 |
} |
2078 |
} else { |
2079 |
// revert upcomming undo |
2080 |
l.setUndoTask(new Runnable() { |
2081 |
public void run() { |
2082 |
undoAll(); |
2083 |
} |
2084 |
} |
2085 |
); |
2086 |
ur.addChangeListener(l); |
2087 |
} |
2088 |
} |
2089 |
|
2090 |
/** Creates <code>Runnable</code> which tries to make one undo. Helper method. |
2091 |
* @see #revertUpcomingUndo */ |
2092 |
final void undoAll() { |
2093 |
StyledDocument sd = getDoc(); |
2094 |
|
2095 |
if (sd == null) { |
2096 |
// #20883, doc can be null(!), doCloseDocument was faster. |
2097 |
return; |
2098 |
} |
2099 |
|
2100 |
UndoRedo ur = getUndoRedo(); |
2101 |
addRemoveDocListener(sd, false); |
2102 |
|
2103 |
try { |
2104 |
if (ur.canUndo()) { |
2105 |
ur.undo(); |
2106 |
} |
2107 |
} catch (CannotUndoException cne) { |
2108 |
ERR.log(Level.INFO, null, cne); |
2109 |
} finally { |
2110 |
addRemoveDocListener(sd, true); |
2111 |
} |
2112 |
} |
2113 |
|
2114 |
/** Method that is called when all components of the support are |
2059 |
/** Method that is called when all components of the support are |
2115 |
* closed. The default implementation closes the document. |
2060 |
* closed. The default implementation closes the document. |
2116 |
* |
2061 |
* |
Lines 2844-2861
Link Here
|
2844 |
/** The listener that this support uses to communicate with |
2789 |
/** The listener that this support uses to communicate with |
2845 |
* document, environment and also temporarilly on undoredo. |
2790 |
* document, environment and also temporarilly on undoredo. |
2846 |
*/ |
2791 |
*/ |
2847 |
private final class Listener extends Object implements ChangeListener, DocumentListener, PropertyChangeListener, |
2792 |
private final class Listener extends Object implements PropertyChangeListener, DocumentListener, |
2848 |
Runnable, java.beans.VetoableChangeListener { |
2793 |
Runnable, java.beans.VetoableChangeListener { |
|
|
2794 |
|
2795 |
/** Stores exception from loadDocument, can be set in run method */ |
2796 |
private IOException loadExc; |
2797 |
|
2849 |
/** revert modification if asked */ |
2798 |
/** revert modification if asked */ |
2850 |
private boolean revertModifiedFlag; |
2799 |
private boolean revertModifiedFlag; |
2851 |
|
2800 |
|
2852 |
/** Stores exception from loadDocument, can be set in run method */ |
|
|
2853 |
private IOException loadExc; |
2854 |
|
2855 |
/** Stores temporarilly undo task for reverting prohibited changes. |
2856 |
* @see CloneableEditorSupport#createUndoTask */ |
2857 |
private Runnable undoTask; |
2858 |
|
2859 |
Listener() { |
2801 |
Listener() { |
2860 |
} |
2802 |
} |
2861 |
|
2803 |
|
Lines 2868-2895
Link Here
|
2868 |
// loadExc = null; |
2810 |
// loadExc = null; |
2869 |
return ret; |
2811 |
return ret; |
2870 |
} |
2812 |
} |
2871 |
|
2813 |
|
2872 |
/** Sets undo task used to revert prohibited change. */ |
2814 |
public void insertUpdate(DocumentEvent evt) { |
2873 |
public void setUndoTask(Runnable undoTask) { |
2815 |
callNotifyModified(); |
2874 |
this.undoTask = undoTask; |
2816 |
revertModifiedFlag = false; |
2875 |
} |
2817 |
} |
2876 |
|
2818 |
|
2877 |
/** Schedules reverting(undoing) of prohibited change. |
2819 |
public void removeUpdate(DocumentEvent evt) { |
2878 |
* Implements <code>ChangeListener</code>. |
2820 |
callNotifyModified(); |
2879 |
* @see #revertUpcomingUndo */ |
2821 |
revertModifiedFlag = false; |
2880 |
public void stateChanged(ChangeEvent evt) { |
|
|
2881 |
getUndoRedo().removeChangeListener(this); |
2882 |
undoTask.run(); |
2883 |
|
2884 |
//SwingUtilities.invokeLater(undoTask); |
2885 |
undoTask = null; |
2886 |
} |
2822 |
} |
2887 |
|
2823 |
|
2888 |
/** Gives notification that an attribute or set of attributes changed. |
2824 |
public void changedUpdate(DocumentEvent evt) { |
2889 |
* @param ev event describing the action |
|
|
2890 |
*/ |
2891 |
public void changedUpdate(DocumentEvent ev) { |
2892 |
//modified(); (bugfix #1492) |
2893 |
} |
2825 |
} |
2894 |
|
2826 |
|
2895 |
public void vetoableChange(PropertyChangeEvent evt) |
2827 |
public void vetoableChange(PropertyChangeEvent evt) |
Lines 2912-2933
Link Here
|
2912 |
} |
2844 |
} |
2913 |
} |
2845 |
} |
2914 |
|
2846 |
|
2915 |
/** Gives notification that there was an insert into the document. |
|
|
2916 |
* @param ev event describing the action |
2917 |
*/ |
2918 |
public void insertUpdate(DocumentEvent ev) { |
2919 |
callNotifyModified(); |
2920 |
revertModifiedFlag = false; |
2921 |
} |
2922 |
|
2923 |
/** Gives notification that a portion of the document has been removed. |
2924 |
* @param ev event describing the action |
2925 |
*/ |
2926 |
public void removeUpdate(DocumentEvent ev) { |
2927 |
callNotifyModified(); |
2928 |
revertModifiedFlag = false; |
2929 |
} |
2930 |
|
2931 |
/** Listener to changes in the Env. |
2847 |
/** Listener to changes in the Env. |
2932 |
*/ |
2848 |
*/ |
2933 |
public void propertyChange(PropertyChangeEvent ev) { |
2849 |
public void propertyChange(PropertyChangeEvent ev) { |
Lines 2963-2971
Link Here
|
2963 |
} |
2879 |
} |
2964 |
|
2880 |
|
2965 |
// #57104 - avoid notifyModified() which takes file lock |
2881 |
// #57104 - avoid notifyModified() which takes file lock |
2966 |
revertingUndoOrReloading = true; |
2882 |
documentReloading = true; |
2967 |
NbDocument.runAtomic(sd, this); |
2883 |
NbDocument.runAtomic(sd, this); |
2968 |
revertingUndoOrReloading = false; // #57104 |
2884 |
documentReloading = false; // #57104 |
2969 |
|
2885 |
|
2970 |
return; |
2886 |
return; |
2971 |
} |
2887 |
} |
Lines 3022-3030
Link Here
|
3022 |
|
2938 |
|
3023 |
setLastSaveTime(cesEnv().getTime().getTime()); |
2939 |
setLastSaveTime(cesEnv().getTime().getTime()); |
3024 |
|
2940 |
|
3025 |
// Insert before-save undo event to enable unmodifying undo |
|
|
3026 |
getUndoRedo().undoableEditHappened(new UndoableEditEvent(this, new BeforeSaveEdit(lastSaveTime))); |
3027 |
|
3028 |
// Start listening on changes in document |
2941 |
// Start listening on changes in document |
3029 |
addRemoveDocListener(getDoc(), true); |
2942 |
addRemoveDocListener(getDoc(), true); |
3030 |
} |
2943 |
} |
Lines 3032-3787
Link Here
|
3032 |
// } |
2945 |
// } |
3033 |
} |
2946 |
} |
3034 |
|
2947 |
|
3035 |
/** Generic undoable edit that delegates to the given undoable edit. */ |
|
|
3036 |
private class FilterUndoableEdit |
3037 |
implements UndoableEdit, UndoGroupManager.SeparateEdit |
3038 |
{ |
3039 |
protected UndoableEdit delegate; |
3040 |
|
3041 |
FilterUndoableEdit() { |
3042 |
} |
3043 |
|
3044 |
public void undo() throws CannotUndoException { |
3045 |
if (delegate != null) { |
3046 |
delegate.undo(); |
3047 |
} |
3048 |
} |
3049 |
|
3050 |
public boolean canUndo() { |
3051 |
if (delegate != null) { |
3052 |
return delegate.canUndo(); |
3053 |
} else { |
3054 |
return false; |
3055 |
} |
3056 |
} |
3057 |
|
3058 |
public void redo() throws CannotRedoException { |
3059 |
if (delegate != null) { |
3060 |
delegate.redo(); |
3061 |
} |
3062 |
} |
3063 |
|
3064 |
public boolean canRedo() { |
3065 |
if (delegate != null) { |
3066 |
return delegate.canRedo(); |
3067 |
} else { |
3068 |
return false; |
3069 |
} |
3070 |
} |
3071 |
|
3072 |
public void die() { |
3073 |
if (delegate != null) { |
3074 |
delegate.die(); |
3075 |
} |
3076 |
} |
3077 |
|
3078 |
public boolean addEdit(UndoableEdit anEdit) { |
3079 |
if (delegate != null) { |
3080 |
return delegate.addEdit(anEdit); |
3081 |
} else { |
3082 |
return false; |
3083 |
} |
3084 |
} |
3085 |
|
3086 |
public boolean replaceEdit(UndoableEdit anEdit) { |
3087 |
if (delegate != null) { |
3088 |
return delegate.replaceEdit(anEdit); |
3089 |
} else { |
3090 |
return false; |
3091 |
} |
3092 |
} |
3093 |
|
3094 |
public boolean isSignificant() { |
3095 |
if (delegate != null) { |
3096 |
return delegate.isSignificant(); |
3097 |
} else { |
3098 |
return true; |
3099 |
} |
3100 |
} |
3101 |
|
3102 |
public String getPresentationName() { |
3103 |
if (delegate != null) { |
3104 |
return delegate.getPresentationName(); |
3105 |
} else { |
3106 |
return ""; // NOI18N |
3107 |
} |
3108 |
} |
3109 |
|
3110 |
public String getUndoPresentationName() { |
3111 |
if (delegate != null) { |
3112 |
return delegate.getUndoPresentationName(); |
3113 |
} else { |
3114 |
return ""; // NOI18N |
3115 |
} |
3116 |
} |
3117 |
|
3118 |
public String getRedoPresentationName() { |
3119 |
if (delegate != null) { |
3120 |
return delegate.getRedoPresentationName(); |
3121 |
} else { |
3122 |
return ""; // NOI18N |
3123 |
} |
3124 |
} |
3125 |
} |
3126 |
|
3127 |
/** Undoable edit that is put before the savepoint. Its replaceEdit() |
3128 |
* method will consume and wrap the edit that precedes the save. |
3129 |
* If the edit is added to the begining of the queue then |
3130 |
* the isSignificant() implementation guarantees that the edit |
3131 |
* will not be removed from the queue. |
3132 |
* When redone it marks the document as not modified. |
3133 |
*/ |
3134 |
private class BeforeSaveEdit extends FilterUndoableEdit { |
3135 |
private long saveTime; |
3136 |
|
3137 |
BeforeSaveEdit(long saveTime) { |
3138 |
this.saveTime = saveTime; |
3139 |
} |
3140 |
|
3141 |
@Override |
3142 |
public boolean replaceEdit(UndoableEdit anEdit) { |
3143 |
if (delegate == null) { |
3144 |
delegate = anEdit; |
3145 |
|
3146 |
return true; // signal consumed |
3147 |
} |
3148 |
|
3149 |
return false; |
3150 |
} |
3151 |
|
3152 |
@Override |
3153 |
public boolean addEdit(UndoableEdit anEdit) { |
3154 |
if (!(anEdit instanceof BeforeModificationEdit) && !(anEdit instanceof SearchBeforeModificationEdit)) { |
3155 |
/* UndoRedo.addEdit() must not be done lazily |
3156 |
* because the edit must be "inserted" before the current one. |
3157 |
*/ |
3158 |
getUndoRedo().addEdit(new BeforeModificationEdit(saveTime, anEdit)); |
3159 |
|
3160 |
return true; |
3161 |
} |
3162 |
|
3163 |
return false; |
3164 |
} |
3165 |
|
3166 |
@Override |
3167 |
public void redo() { |
3168 |
super.redo(); |
3169 |
|
3170 |
if (saveTime == lastSaveTime) { |
3171 |
justRevertedToNotModified = true; |
3172 |
} |
3173 |
} |
3174 |
|
3175 |
@Override |
3176 |
public boolean isSignificant() { |
3177 |
return (delegate != null); |
3178 |
} |
3179 |
} |
3180 |
|
3181 |
/** Edit that is created by wrapping the given edit. |
3182 |
* When undone it marks the document as not modified. |
3183 |
*/ |
3184 |
private class BeforeModificationEdit extends FilterUndoableEdit { |
3185 |
private long saveTime; |
3186 |
|
3187 |
BeforeModificationEdit(long saveTime, UndoableEdit delegate) { |
3188 |
this.saveTime = saveTime; |
3189 |
this.delegate = delegate; |
3190 |
ERR.log(Level.FINEST, null, new Exception("new BeforeModificationEdit(" + saveTime +")")); // NOI18N |
3191 |
} |
3192 |
|
3193 |
@Override |
3194 |
public boolean addEdit(UndoableEdit anEdit) { |
3195 |
if ((delegate == null) && !(anEdit instanceof SearchBeforeModificationEdit)) { |
3196 |
delegate = anEdit; |
3197 |
|
3198 |
return true; |
3199 |
} |
3200 |
|
3201 |
return delegate.addEdit(anEdit); |
3202 |
} |
3203 |
|
3204 |
@Override |
3205 |
public void undo() { |
3206 |
super.undo(); |
3207 |
|
3208 |
boolean res = saveTime == lastSaveTime; |
3209 |
ERR.fine("Comparing saveTime and lastSaveTime: " + saveTime + "==" + lastSaveTime + " is " + res); // NOI18N |
3210 |
if (res) { |
3211 |
justRevertedToNotModified = true; |
3212 |
} |
3213 |
} |
3214 |
} |
3215 |
|
3216 |
/** This edit is used to search for BeforeModificationEdit in UndoRedo |
3217 |
* manager. This is not much nice solution, but well, there is not |
3218 |
* much other chances to get inside UndoRedo. |
3219 |
*/ |
3220 |
private class SearchBeforeModificationEdit extends FilterUndoableEdit { |
3221 |
SearchBeforeModificationEdit() { |
3222 |
} |
3223 |
|
3224 |
@Override |
3225 |
public boolean replaceEdit(UndoableEdit anEdit) { |
3226 |
if (delegate == null) { |
3227 |
delegate = anEdit; |
3228 |
|
3229 |
return true; // signal consumed |
3230 |
} |
3231 |
|
3232 |
return false; |
3233 |
} |
3234 |
} |
3235 |
|
3236 |
/** An improved version of UndoRedo manager that locks document before |
3237 |
* doing any other operations. |
3238 |
*/ |
3239 |
private final static class CESUndoRedoManager extends UndoGroupManager { |
3240 |
private CloneableEditorSupport support; |
3241 |
|
3242 |
public CESUndoRedoManager(CloneableEditorSupport c) { |
3243 |
this.support = c; |
3244 |
super.setLimit(1000); |
3245 |
} |
3246 |
|
3247 |
@Override |
3248 |
public void redo() throws javax.swing.undo.CannotRedoException { |
3249 |
final StyledDocument myDoc = support.getDocument(); |
3250 |
|
3251 |
if (myDoc == null) { |
3252 |
throw new javax.swing.undo.CannotRedoException(); // NOI18N |
3253 |
} |
3254 |
|
3255 |
support.justRevertedToNotModified = false; |
3256 |
new RenderUndo(0, myDoc); |
3257 |
|
3258 |
if (support.justRevertedToNotModified && support.isAlreadyModified()) { |
3259 |
support.callNotifyUnmodified(); |
3260 |
} |
3261 |
} |
3262 |
|
3263 |
@Override |
3264 |
public void undo() throws javax.swing.undo.CannotUndoException { |
3265 |
final StyledDocument myDoc = support.getDocument(); |
3266 |
|
3267 |
if (myDoc == null) { |
3268 |
throw new javax.swing.undo.CannotUndoException(); // NOI18N |
3269 |
} |
3270 |
|
3271 |
support.justRevertedToNotModified = false; |
3272 |
new RenderUndo(1, myDoc); |
3273 |
|
3274 |
if (support.justRevertedToNotModified && support.isAlreadyModified()) { |
3275 |
support.callNotifyUnmodified(); |
3276 |
} |
3277 |
} |
3278 |
|
3279 |
@Override |
3280 |
public boolean canRedo() { |
3281 |
final StyledDocument myDoc = support.getDocument(); |
3282 |
|
3283 |
return new RenderUndo(2, myDoc, 0, true).booleanResult; |
3284 |
} |
3285 |
|
3286 |
@Override |
3287 |
public boolean canUndo() { |
3288 |
final StyledDocument myDoc = support.getDocument(); |
3289 |
|
3290 |
return new RenderUndo(3, myDoc, 0, true).booleanResult; |
3291 |
} |
3292 |
|
3293 |
@Override |
3294 |
public int getLimit() { |
3295 |
final StyledDocument myDoc = support.getDocument(); |
3296 |
|
3297 |
return new RenderUndo(4, myDoc).intResult; |
3298 |
} |
3299 |
|
3300 |
@Override |
3301 |
public void discardAllEdits() { |
3302 |
final StyledDocument myDoc = support.getDocument(); |
3303 |
new RenderUndo(5, myDoc); |
3304 |
// Insert before-save undo event to enable unmodifying undo |
3305 |
undoableEditHappened(new UndoableEditEvent(support, support.new BeforeSaveEdit(support.lastSaveTime))); |
3306 |
} |
3307 |
|
3308 |
@Override |
3309 |
public void setLimit(int l) { |
3310 |
final StyledDocument myDoc = support.getDocument(); |
3311 |
new RenderUndo(6, myDoc, l); |
3312 |
} |
3313 |
|
3314 |
@Override |
3315 |
public boolean canUndoOrRedo() { |
3316 |
final StyledDocument myDoc = support.getDocument(); |
3317 |
|
3318 |
return new RenderUndo(7, myDoc, 0, true).booleanResult; |
3319 |
} |
3320 |
|
3321 |
@Override |
3322 |
public java.lang.String getUndoOrRedoPresentationName() { |
3323 |
if (support.isDocumentReady()) { |
3324 |
final StyledDocument myDoc = support.getDocument(); |
3325 |
return new RenderUndo(8, myDoc, 0, true).stringResult; |
3326 |
} else { |
3327 |
return ""; |
3328 |
} |
3329 |
} |
3330 |
|
3331 |
@Override |
3332 |
public java.lang.String getRedoPresentationName() { |
3333 |
if (support.isDocumentReady()) { |
3334 |
final StyledDocument myDoc = support.getDocument(); |
3335 |
return new RenderUndo(9, myDoc, 0, true).stringResult; |
3336 |
} else { |
3337 |
return ""; |
3338 |
} |
3339 |
} |
3340 |
|
3341 |
@Override |
3342 |
public java.lang.String getUndoPresentationName() { |
3343 |
if (support.isDocumentReady()) { |
3344 |
final StyledDocument myDoc = support.getDocument(); |
3345 |
return new RenderUndo(10, myDoc, 0, true).stringResult; |
3346 |
} else { |
3347 |
return ""; |
3348 |
} |
3349 |
} |
3350 |
|
3351 |
@Override |
3352 |
public void undoOrRedo() throws javax.swing.undo.CannotUndoException, javax.swing.undo.CannotRedoException { |
3353 |
final StyledDocument myDoc = support.getDocument(); |
3354 |
|
3355 |
if (myDoc == null) { |
3356 |
throw new javax.swing.undo.CannotUndoException(); // NOI18N |
3357 |
} |
3358 |
|
3359 |
support.justRevertedToNotModified = false; |
3360 |
new RenderUndo(11, myDoc); |
3361 |
|
3362 |
if (support.justRevertedToNotModified && support.isAlreadyModified()) { |
3363 |
support.callNotifyUnmodified(); |
3364 |
} |
3365 |
} |
3366 |
|
3367 |
private final class RenderUndo implements Runnable { |
3368 |
private final int type; |
3369 |
public boolean booleanResult; |
3370 |
public int intResult; |
3371 |
public String stringResult; |
3372 |
private final boolean readonly; |
3373 |
|
3374 |
public RenderUndo(int type, StyledDocument doc) { |
3375 |
this(type, doc, 0); |
3376 |
} |
3377 |
|
3378 |
public RenderUndo(int type, StyledDocument doc, int intValue) { |
3379 |
this(type, doc, intValue, false); |
3380 |
} |
3381 |
|
3382 |
public RenderUndo(int type, StyledDocument doc, int intValue, boolean readonly) { |
3383 |
this.type = type; |
3384 |
this.intResult = intValue; |
3385 |
this.readonly = readonly; |
3386 |
|
3387 |
if (!readonly && (doc instanceof NbDocument.WriteLockable)) { |
3388 |
((NbDocument.WriteLockable) doc).runAtomic(this); |
3389 |
} else { |
3390 |
if (readonly && doc != null) { |
3391 |
doc.render(this); |
3392 |
} else { |
3393 |
// if the document is not one of "NetBeans ready" |
3394 |
// that supports locking we do not have many |
3395 |
// chances to do something. Maybe check for AbstractDocument |
3396 |
// and call writeLock using reflection, but better than |
3397 |
// that, let's leave this simple for now and wait for |
3398 |
// bug reports (if any appear) |
3399 |
run(); |
3400 |
} |
3401 |
} |
3402 |
} |
3403 |
|
3404 |
public void run() { |
3405 |
switch (type) { |
3406 |
case 0: |
3407 |
CESUndoRedoManager.super.redo(); |
3408 |
|
3409 |
break; |
3410 |
|
3411 |
case 1: |
3412 |
CESUndoRedoManager.super.undo(); |
3413 |
|
3414 |
break; |
3415 |
|
3416 |
case 2: |
3417 |
booleanResult = CESUndoRedoManager.super.canRedo(); |
3418 |
|
3419 |
break; |
3420 |
|
3421 |
case 3: |
3422 |
booleanResult = CESUndoRedoManager.super.canUndo(); |
3423 |
|
3424 |
break; |
3425 |
|
3426 |
case 4: |
3427 |
intResult = CESUndoRedoManager.super.getLimit(); |
3428 |
|
3429 |
break; |
3430 |
|
3431 |
case 5: |
3432 |
CESUndoRedoManager.super.discardAllEdits(); |
3433 |
|
3434 |
break; |
3435 |
|
3436 |
case 6: |
3437 |
CESUndoRedoManager.super.setLimit(intResult); |
3438 |
|
3439 |
break; |
3440 |
|
3441 |
case 7: |
3442 |
CESUndoRedoManager.super.canUndoOrRedo(); |
3443 |
|
3444 |
break; |
3445 |
|
3446 |
case 8: |
3447 |
stringResult = CESUndoRedoManager.super.getUndoOrRedoPresentationName(); |
3448 |
|
3449 |
break; |
3450 |
|
3451 |
case 9: |
3452 |
stringResult = CESUndoRedoManager.super.getRedoPresentationName(); |
3453 |
|
3454 |
break; |
3455 |
|
3456 |
case 10: |
3457 |
stringResult = CESUndoRedoManager.super.getUndoPresentationName(); |
3458 |
|
3459 |
break; |
3460 |
|
3461 |
case 11: |
3462 |
CESUndoRedoManager.super.undoOrRedo(); |
3463 |
|
3464 |
break; |
3465 |
|
3466 |
default: |
3467 |
throw new IllegalArgumentException("Unknown type: " + type); |
3468 |
} |
3469 |
} |
3470 |
} |
3471 |
} |
3472 |
|
3473 |
/** |
3474 |
* <tt>UndoGroupManager</tt> extends {@link UndoManager} |
3475 |
* and allows explicit control of what |
3476 |
* <tt>UndoableEdit</tt>s are coalesced into compound edits, |
3477 |
* rather than using the rules defined by the edits themselves. |
3478 |
* Groups are defined using BEGIN_COMMIT_GROUP and END_COMMIT_GROUP. |
3479 |
* Send these to UndoableEditListener. These must always be paired. |
3480 |
* <p> |
3481 |
* These use cases are supported. |
3482 |
* </p> |
3483 |
* <ol> |
3484 |
* <li> Default behavior is defined by {@link UndoManager}.</li> |
3485 |
* <li> <tt>UnddoableEdit</tt>s issued between {@link #BEGIN_COMMIT_GROUP} |
3486 |
* and {@link #END_COMMIT_GROUP} are placed into a single |
3487 |
* {@link CompoundEdit}. |
3488 |
* Thus <tt>undo()</tt> and <tt>redo()</tt> treat them |
3489 |
* as a single undo/redo.</li> |
3490 |
* <li>BEGIN/END nest.</li> |
3491 |
* <li> Issue MARK_COMMIT_GROUP to commit accumulated |
3492 |
* <tt>UndoableEdit</tt>s into a single <tt>CompoundEdit</tt> |
3493 |
* and to continue accumulating; |
3494 |
* an application could do this at strategic points, such as EndOfLine |
3495 |
* input or cursor movement.</li> |
3496 |
* </ol> |
3497 |
* @see UndoManager |
3498 |
*/ |
3499 |
private static class UndoGroupManager extends UndoRedo.Manager { |
3500 |
/** signals that edits are being accumulated */ |
3501 |
private int buildUndoGroup; |
3502 |
/** accumulate edits here in undoGroup */ |
3503 |
private CompoundEdit undoGroup; |
3504 |
/** |
3505 |
* Signal that nested group started and that current undo group |
3506 |
* must be committed if edit is added. Then can avoid doing the commit |
3507 |
* if the nested group turns out to be empty. |
3508 |
*/ |
3509 |
private int needsNestingCommit; |
3510 |
|
3511 |
/** |
3512 |
* Start a group of edits which will be committed as a single edit |
3513 |
* for purpose of undo/redo. |
3514 |
* Nesting semantics are that any BEGIN_COMMIT_GROUP and |
3515 |
* END_COMMIT_GROUP delimits a commit-group, unless the group is |
3516 |
* empty in which case the begin/end is ignored. |
3517 |
* While coalescing edits, any undo/redo/save implicitly delimits |
3518 |
* a commit-group. |
3519 |
*/ |
3520 |
static final UndoableEdit BEGIN_COMMIT_GROUP = new CommitGroupEdit(); |
3521 |
/** End a group of edits. */ |
3522 |
static final UndoableEdit END_COMMIT_GROUP = new CommitGroupEdit(); |
3523 |
/** |
3524 |
* Any coalesced edits become a commit-group and a new commit-group |
3525 |
* is started. |
3526 |
*/ |
3527 |
static final UndoableEdit MARK_COMMIT_GROUP = new CommitGroupEdit(); |
3528 |
|
3529 |
/** SeparateEdit tags an UndoableEdit so the |
3530 |
* UndoGroupManager does not coalesce it. |
3531 |
*/ |
3532 |
interface SeparateEdit { |
3533 |
} |
3534 |
|
3535 |
private static class CommitGroupEdit extends AbstractUndoableEdit { |
3536 |
@Override |
3537 |
public boolean isSignificant() { |
3538 |
return false; |
3539 |
} |
3540 |
|
3541 |
@Override |
3542 |
public boolean canRedo() |
3543 |
{ |
3544 |
return true; |
3545 |
} |
3546 |
|
3547 |
@Override |
3548 |
public boolean canUndo() |
3549 |
{ |
3550 |
return true; |
3551 |
} |
3552 |
} |
3553 |
|
3554 |
@Override |
3555 |
public void undoableEditHappened(UndoableEditEvent ue) |
3556 |
{ |
3557 |
if(ue.getEdit() == BEGIN_COMMIT_GROUP) { |
3558 |
beginUndoGroup(); |
3559 |
} else if(ue.getEdit() == END_COMMIT_GROUP) { |
3560 |
endUndoGroup(); |
3561 |
} else if(ue.getEdit() == MARK_COMMIT_GROUP) { |
3562 |
commitUndoGroup(); |
3563 |
} else { |
3564 |
super.undoableEditHappened(ue); |
3565 |
} |
3566 |
} |
3567 |
|
3568 |
/** |
3569 |
* Direct this <tt>UndoGroupManager</tt> to begin coalescing any |
3570 |
* <tt>UndoableEdit</tt>s that are added into a <tt>CompoundEdit</tt>. |
3571 |
* <p>If edits are already being coalesced and some have been |
3572 |
* accumulated, they are flagged for commitment as an atomic group and |
3573 |
* a new group will be started. |
3574 |
* @see #addEdit |
3575 |
* @see #endUndoGroup |
3576 |
*/ |
3577 |
private synchronized void beginUndoGroup() { |
3578 |
if(undoGroup != null) |
3579 |
needsNestingCommit++; |
3580 |
ERR.log(Level.FINE, "beginUndoGroup: nesting {0}", buildUndoGroup); |
3581 |
buildUndoGroup++; |
3582 |
} |
3583 |
|
3584 |
/** |
3585 |
* Direct this <tt>UndoGroupManager</tt> to stop coalescing edits. |
3586 |
* Until <tt>beginUndoGroupManager</tt> is invoked, |
3587 |
* any received <tt>UndoableEdit</tt>s are added singly. |
3588 |
* <p> |
3589 |
* This has no effect if edits are not being coalesced, for example |
3590 |
* if <tt>beginUndoGroup</tt> has not been called. |
3591 |
*/ |
3592 |
private synchronized void endUndoGroup() { |
3593 |
buildUndoGroup--; |
3594 |
ERR.log(Level.FINE, "endUndoGroup: nesting {0}", buildUndoGroup); |
3595 |
if(buildUndoGroup < 0) { |
3596 |
ERR.log(Level.INFO, null, new Exception("endUndoGroup without beginUndoGroup")); |
3597 |
// slam buildUndoGroup to 0 to disable nesting |
3598 |
buildUndoGroup = 0; |
3599 |
} |
3600 |
if(needsNestingCommit <= 0) |
3601 |
commitUndoGroup(); |
3602 |
if(--needsNestingCommit < 0) |
3603 |
needsNestingCommit = 0; |
3604 |
} |
3605 |
|
3606 |
/** |
3607 |
* Commit any accumulated <tt>UndoableEdit</tt>s as an atomic |
3608 |
* <tt>undo</tt>/<tt>redo</tt> group. {@link CompoundEdit#end} |
3609 |
* is invoked on the <tt>CompoundEdit</tt> and it is added as a single |
3610 |
* <tt>UndoableEdit</tt> to this <tt>UndoManager</tt>. |
3611 |
* <p> |
3612 |
* If edits are currently being coalesced, a new undo group is started. |
3613 |
* This has no effect if edits are not being coalesced, for example |
3614 |
* <tt>beginUndoGroup</tt> has not been called. |
3615 |
*/ |
3616 |
private synchronized void commitUndoGroup() { |
3617 |
if(undoGroup == null) { |
3618 |
return; |
3619 |
} |
3620 |
|
3621 |
// undoGroup is being set to null, |
3622 |
// needsNestingCommit has no meaning now |
3623 |
needsNestingCommit = 0; |
3624 |
|
3625 |
// super.addEdit may end up in this.addEdit, |
3626 |
// so buildUndoGroup must be false |
3627 |
int saveBuildUndoGroup = buildUndoGroup; |
3628 |
buildUndoGroup = 0; |
3629 |
|
3630 |
undoGroup.end(); |
3631 |
super.addEdit(undoGroup); |
3632 |
undoGroup = null; |
3633 |
|
3634 |
buildUndoGroup = saveBuildUndoGroup; |
3635 |
} |
3636 |
|
3637 |
/** Add this edit separately, not part of a group. |
3638 |
* @return super.addEdit |
3639 |
*/ |
3640 |
private boolean commitAddEdit(UndoableEdit anEdit) { |
3641 |
commitUndoGroup(); |
3642 |
|
3643 |
int saveBuildUndoGroup = buildUndoGroup; |
3644 |
buildUndoGroup = 0; |
3645 |
boolean f = super.addEdit(anEdit); |
3646 |
//boolean f = addEdit(undoGroup); |
3647 |
buildUndoGroup = saveBuildUndoGroup; |
3648 |
return f; |
3649 |
} |
3650 |
|
3651 |
/** |
3652 |
* If there's a pending undo group that needs to be committed |
3653 |
* then commit it. |
3654 |
* If this <tt>UndoManager</tt> is coalescing edits then add |
3655 |
* <tt>anEdit</tt> to the accumulating <tt>CompoundEdit</tt>. |
3656 |
* Otherwise, add it to this UndoManager. In either case the |
3657 |
* edit is saved for later <tt>undo</tt> or <tt>redo</tt>. |
3658 |
* @return {@inheritDoc} |
3659 |
* @see #beginUndoGroup |
3660 |
* @see #endUndoGroup |
3661 |
*/ |
3662 |
@Override |
3663 |
public synchronized boolean addEdit(UndoableEdit anEdit) { |
3664 |
if(!isInProgress()) |
3665 |
return false; |
3666 |
|
3667 |
if(needsNestingCommit > 0) { |
3668 |
commitUndoGroup(); |
3669 |
} |
3670 |
|
3671 |
if(buildUndoGroup > 0) { |
3672 |
if(anEdit instanceof SeparateEdit) |
3673 |
return commitAddEdit(anEdit); |
3674 |
if(undoGroup == null) |
3675 |
undoGroup = new CompoundEdit(); |
3676 |
return undoGroup.addEdit(anEdit); |
3677 |
} else { |
3678 |
return super.addEdit(anEdit); |
3679 |
} |
3680 |
} |
3681 |
|
3682 |
@Override |
3683 |
public synchronized void discardAllEdits() { |
3684 |
commitUndoGroup(); |
3685 |
super.discardAllEdits(); |
3686 |
} |
3687 |
|
3688 |
// |
3689 |
// TODO: limits |
3690 |
// |
3691 |
|
3692 |
@Override |
3693 |
public synchronized void undoOrRedo() { |
3694 |
commitUndoGroup(); |
3695 |
super.undoOrRedo(); |
3696 |
} |
3697 |
|
3698 |
@Override |
3699 |
public synchronized boolean canUndoOrRedo() { |
3700 |
if(undoGroup != null) |
3701 |
return true; |
3702 |
return super.canUndoOrRedo(); |
3703 |
} |
3704 |
|
3705 |
@Override |
3706 |
public synchronized void undo() { |
3707 |
commitUndoGroup(); |
3708 |
super.undo(); |
3709 |
} |
3710 |
|
3711 |
@Override |
3712 |
public synchronized boolean canUndo() { |
3713 |
if(undoGroup != null) |
3714 |
return true; |
3715 |
return super.canUndo(); |
3716 |
} |
3717 |
|
3718 |
@Override |
3719 |
public synchronized void redo() { |
3720 |
if(undoGroup != null) |
3721 |
throw new CannotRedoException(); |
3722 |
super.redo(); |
3723 |
} |
3724 |
|
3725 |
@Override |
3726 |
public synchronized boolean canRedo() { |
3727 |
if(undoGroup != null) |
3728 |
return false; |
3729 |
return super.canRedo(); |
3730 |
} |
3731 |
|
3732 |
@Override |
3733 |
public synchronized void end() { |
3734 |
commitUndoGroup(); |
3735 |
super.end(); |
3736 |
} |
3737 |
|
3738 |
@Override |
3739 |
public synchronized String getUndoOrRedoPresentationName() { |
3740 |
if(undoGroup != null) |
3741 |
return undoGroup.getUndoPresentationName(); |
3742 |
return super.getUndoOrRedoPresentationName(); |
3743 |
} |
3744 |
|
3745 |
@Override |
3746 |
public synchronized String getUndoPresentationName() { |
3747 |
if(undoGroup != null) |
3748 |
return undoGroup.getUndoPresentationName(); |
3749 |
return super.getUndoPresentationName(); |
3750 |
} |
3751 |
|
3752 |
@Override |
3753 |
public synchronized String getRedoPresentationName() { |
3754 |
if(undoGroup != null) |
3755 |
return undoGroup.getRedoPresentationName(); |
3756 |
return super.getRedoPresentationName(); |
3757 |
} |
3758 |
|
3759 |
@Override |
3760 |
public boolean isSignificant() { |
3761 |
if(undoGroup != null && undoGroup.isSignificant()) { |
3762 |
return true; |
3763 |
} |
3764 |
return super.isSignificant(); |
3765 |
} |
3766 |
|
3767 |
@Override |
3768 |
public synchronized void die() { |
3769 |
commitUndoGroup(); |
3770 |
super.die(); |
3771 |
} |
3772 |
|
3773 |
@Override |
3774 |
public String getPresentationName() { |
3775 |
if(undoGroup != null) |
3776 |
return undoGroup.getPresentationName(); |
3777 |
return super.getPresentationName(); |
3778 |
} |
3779 |
|
3780 |
// The protected methods are only accessed from |
3781 |
// synchronized methods that do commitUndoGroup |
3782 |
// so they do not need to be overridden in this class |
3783 |
} |
3784 |
|
3785 |
/** Special runtime exception that holds the original I/O failure. |
2948 |
/** Special runtime exception that holds the original I/O failure. |
3786 |
*/ |
2949 |
*/ |
3787 |
static final class DelegateIOExc extends IllegalStateException { |
2950 |
static final class DelegateIOExc extends IllegalStateException { |
Lines 3791-3794
Link Here
|
3791 |
} |
2954 |
} |
3792 |
} |
2955 |
} |
3793 |
|
2956 |
|
|
|
2957 |
private final class DocFilter extends DocumentFilter { |
2958 |
|
2959 |
final DocumentFilter origFilter; |
2960 |
|
2961 |
DocFilter(DocumentFilter origFilter) { |
2962 |
this.origFilter = origFilter; |
2963 |
} |
2964 |
|
2965 |
@Override |
2966 |
public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException { |
2967 |
boolean origModified = checkModificationAllowed(offset); |
2968 |
boolean success = false; |
2969 |
try { |
2970 |
if (origFilter != null) { |
2971 |
origFilter.insertString(fb, offset, string, attr); |
2972 |
} else { |
2973 |
super.insertString(fb, offset, string, attr); |
2974 |
} |
2975 |
success = true; |
2976 |
} finally { |
2977 |
if (!success) { |
2978 |
if (!origModified) { |
2979 |
callNotifyUnmodified(); |
2980 |
} |
2981 |
} |
2982 |
} |
2983 |
} |
2984 |
|
2985 |
@Override |
2986 |
public void remove(FilterBypass fb, int offset, int length) throws BadLocationException { |
2987 |
boolean origModified = checkModificationAllowed(offset); |
2988 |
boolean success = false; |
2989 |
try { |
2990 |
if (origFilter != null) { |
2991 |
origFilter.remove(fb, offset, length); |
2992 |
} else { |
2993 |
super.remove(fb, offset, length); |
2994 |
} |
2995 |
success = true; |
2996 |
} finally { |
2997 |
if (!success) { |
2998 |
if (!origModified) { |
2999 |
callNotifyUnmodified(); |
3000 |
} |
3001 |
} |
3002 |
} |
3003 |
} |
3004 |
|
3005 |
@Override |
3006 |
public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException { |
3007 |
boolean origModified = checkModificationAllowed(offset); |
3008 |
boolean success = false; |
3009 |
try { |
3010 |
if (origFilter != null) { |
3011 |
origFilter.replace(fb, offset, length, text, attrs); |
3012 |
} else { |
3013 |
super.replace(fb, offset, length, text, attrs); |
3014 |
} |
3015 |
success = true; |
3016 |
} finally { |
3017 |
if (!success) { |
3018 |
if (!origModified) { |
3019 |
callNotifyUnmodified(); |
3020 |
} |
3021 |
} |
3022 |
} |
3023 |
} |
3024 |
|
3025 |
private boolean checkModificationAllowed(int offset) throws BadLocationException { |
3026 |
boolean alreadyModified = isAlreadyModified(); |
3027 |
if (!callNotifyModified()) { |
3028 |
throw new BadLocationException("Modification not allowed", offset); // NOI18N |
3029 |
} |
3030 |
return alreadyModified; |
3031 |
} |
3032 |
|
3033 |
} |
3034 |
|
3794 |
} |
3035 |
} |