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 51872
Collapse All | Expand All

(-)openide-spec-vers.properties (-1 / +1 lines)
Lines 4-7 Link Here
4
# Must always be numeric (numbers separated by '.', e.g. 4.11).
4
# Must always be numeric (numbers separated by '.', e.g. 4.11).
5
# See http://openide.netbeans.org/versioning-policy.html for more.
5
# See http://openide.netbeans.org/versioning-policy.html for more.
6
6
7
openide.specification.version=5.2
7
openide.specification.version=5.3
(-)arch/arch-openide-editor.xml (+15 lines)
Lines 375-380 Link Here
375
This property can be used by the modules and is part of the Editor API.
375
This property can be used by the modules and is part of the Editor API.
376
</api>
376
</api>
377
377
378
<api type="export" group="property" name="javax.swing.text.Document.beforeModificationListener" category="friend" >
379
In order to fix <a href="http://openide.netbeans.org/issues/show_bug.cgi?id=51872">issue 51872</a> the 
380
openide needs a way how to be notified about change of a document outside of its Document lock. 
381
<code>DocumentListener</code>s are always notified under the lock, so a special contract has
382
been established (since version 5.3) by registering an instance of <code>VetoableListener</code>
383
by calling <code>putProperty ("beforeModificationListener", listener)</code>. The
384
NetBeans aware document are adviced to honor this property and call the listener
385
outside of the document lock when a modification is made. The actual contract
386
of the call can be seen in 
387
<a href="http://www.netbeans.org/source/browse/openide/test/unit/src/org/openide/text/NbLikeEditorKit.java">NbLikeEditorKit.java</a> 
388
in methods 
389
<code>insertString</code> and <code>remove</code>.
390
391
</api>
392
378
</answer>
393
</answer>
379
394
380
395
(-)src/org/openide/text/CloneableEditorSupport.java (-36 / +28 lines)
Lines 556-563 Link Here
556
             public void run() {
556
             public void run() {
557
                 try {
557
                 try {
558
                     doc.removeDocumentListener(getListener());
558
                     doc.removeDocumentListener(getListener());
559
                     doc.putProperty ("beforeModificationListener", null); // NOI18N
559
                     doc.remove(0, doc.getLength()); // remove all text
560
                     doc.remove(0, doc.getLength()); // remove all text
560
                     doc.addDocumentListener(getListener());
561
                     doc.addDocumentListener(getListener());
562
                     doc.putProperty ("beforeModificationListener", getListener ()); // NOI18N
561
                 } catch(BadLocationException ble) {
563
                 } catch(BadLocationException ble) {
562
                     ErrorManager.getDefault().notify(
564
                     ErrorManager.getDefault().notify(
563
                         ErrorManager.INFORMATIONAL, ble);
565
                         ErrorManager.INFORMATIONAL, ble);
Lines 1323-1337 Link Here
1323
    }
1325
    }
1324
    
1326
    
1325
    /** Conditionally calls notifyModified 
1327
    /** Conditionally calls notifyModified 
1328
     * @return true if the modification was allowed, false if it should be prohibited
1326
     */
1329
     */
1327
    private final void callNotifyModified () {
1330
    private final boolean callNotifyModified () {
1328
        if (!alreadyModified) {
1331
        if (!alreadyModified) {
1329
            alreadyModified = true;
1332
            alreadyModified = true;
1330
            if (!notifyModified ()) {
1333
            if (!notifyModified ()) {
1331
                revertUpcomingUndo ();
1334
                revertUpcomingUndo ();
1332
                alreadyModified = false;
1335
                alreadyModified = false;
1336
                return false;
1333
            }
1337
            }
1334
        }
1338
        }
1339
        return true;
1335
    }
1340
    }
1336
    
1341
    
1337
    /** Called when the document is being modified.
1342
    /** Called when the document is being modified.
Lines 1425-1430 Link Here
1425
                }
1430
                }
1426
                UndoRedo ur = getUndoRedo();
1431
                UndoRedo ur = getUndoRedo();
1427
                sd.removeDocumentListener(getListener());
1432
                sd.removeDocumentListener(getListener());
1433
                sd.putProperty ("beforeModificationListener", null); // NOI18N
1428
                try {
1434
                try {
1429
                    if(ur.canUndo()) {
1435
                    if(ur.canUndo()) {
1430
                        Toolkit.getDefaultToolkit().beep();
1436
                        Toolkit.getDefaultToolkit().beep();
Lines 1435-1440 Link Here
1435
                        ErrorManager.INFORMATIONAL, cne);
1441
                        ErrorManager.INFORMATIONAL, cne);
1436
                } finally {
1442
                } finally {
1437
                    sd.addDocumentListener(getListener());
1443
                    sd.addDocumentListener(getListener());
1444
                    sd.putProperty ("beforeModificationListener", getListener ()); // NOI18N
1438
                }
1445
                }
1439
            }
1446
            }
1440
        };
1447
        };
Lines 1494-1531 Link Here
1494
    }
1501
    }
1495
1502
1496
1503
1497
    // other public methods ................................................................
1498
1499
1500
    /* JST: Commented out
1501
    * Set actions for toolbar.
1502
    * @param actions list of actions
1503
    *
1504
    public void setActions (SystemAction[] actions) {
1505
        this.actions = actions;
1506
    }
1507
1508
    /** Utility method which enables or disables listening to modifications
1509
    * on asociated document.
1510
    * <P>
1511
    * Could be useful if we have to modify document, but do not want the
1512
    * Save and Save All actions to be enabled/disabled automatically.
1513
    * Initially modifications are listened to.
1514
    * @param listenToModifs whether to listen to modifications
1515
    *
1516
    public void setModificationListening (final boolean listenToModifs) {
1517
        if (this.listenToModifs == listenToModifs) return;
1518
        this.listenToModifs = listenToModifs;
1519
        if (doc == null) return;
1520
        if (listenToModifs)
1521
            doc.addi(getModifL());
1522
        else
1523
            doc.removeDocumentListener(getModifL());
1524
    }
1525
    */
1526
1527
1528
1529
    /** Loads the document for this object.
1504
    /** Loads the document for this object.
1530
    * @param kit kit to use
1505
    * @param kit kit to use
1531
    * @param d original document to load data into
1506
    * @param d original document to load data into
Lines 1617-1622 Link Here
1617
        if (doc != null) {
1592
        if (doc != null) {
1618
            doc.removeUndoableEditListener (getUndoRedo ());
1593
            doc.removeUndoableEditListener (getUndoRedo ());
1619
            doc.removeDocumentListener(getListener());
1594
            doc.removeDocumentListener(getListener());
1595
            doc.putProperty ("beforeModificationListener", null);
1620
        }
1596
        }
1621
1597
1622
        if (positionManager != null) {
1598
        if (positionManager != null) {
Lines 1949-1957 Link Here
1949
     * document, environment and also temporarilly on undoredo.
1925
     * document, environment and also temporarilly on undoredo.
1950
     */
1926
     */
1951
    private final class Listener extends Object
1927
    private final class Listener extends Object
1952
    implements ChangeListener, DocumentListener, PropertyChangeListener, Runnable {
1928
    implements ChangeListener, DocumentListener, PropertyChangeListener, 
1929
    Runnable, java.beans.VetoableChangeListener {
1953
1930
1954
	Listener() {}
1931
        Listener() {}
1955
1932
1956
        /** Stores exception from loadDocument, can be set in run method */
1933
        /** Stores exception from loadDocument, can be set in run method */
1957
        private IOException loadExc;
1934
        private IOException loadExc;
Lines 1993-1998 Link Here
1993
            //modified(); (bugfix #1492)
1970
            //modified(); (bugfix #1492)
1994
        }
1971
        }
1995
1972
1973
        public void vetoableChange (PropertyChangeEvent evt) throws java.beans.PropertyVetoException {
1974
            if ("modified".equals (evt.getPropertyName ())) { // NOI18N
1975
                if (Boolean.TRUE.equals (evt.getNewValue ())) {
1976
                    if (!callNotifyModified ()) {
1977
                        throw new java.beans.PropertyVetoException ("Not allowed", evt); // NOI18N
1978
                    }
1979
                } else {
1980
                    notifyUnmodified ();
1981
                }
1982
            }
1983
        }
1984
1996
        /** Gives notification that there was an insert into the document.
1985
        /** Gives notification that there was an insert into the document.
1997
        * @param ev event describing the action
1986
        * @param ev event describing the action
1998
        */
1987
        */
Lines 2054-2059 Link Here
2054
                 * which can prevent dedloks that sometimes occured during file reload.
2043
                 * which can prevent dedloks that sometimes occured during file reload.
2055
                 */
2044
                 */
2056
                 doc.removeDocumentListener(getListener());
2045
                 doc.removeDocumentListener(getListener());
2046
                 doc.putProperty ("beforeModificationListener", null); // NOI18N
2057
                 try {
2047
                 try {
2058
                    loadExc = null; 
2048
                    loadExc = null; 
2059
                    LOCAL_LOAD_TASK.set(Boolean.TRUE);
2049
                    LOCAL_LOAD_TASK.set(Boolean.TRUE);
Lines 2079-2085 Link Here
2079
                 
2069
                 
2080
                 // Start listening on changes in document
2070
                 // Start listening on changes in document
2081
                 doc.addDocumentListener(getListener());
2071
                 doc.addDocumentListener(getListener());
2072
                 doc.putProperty ("beforeModificationListener", getListener ()); // NOI18N // NOI18N
2082
            }   
2073
            }   
2074
2083
//        }
2075
//        }
2084
    }
2076
    }
2085
2077
Lines 2286-2292 Link Here
2286
        public void undo() {
2278
        public void undo() {
2287
            super.undo();
2279
            super.undo();
2288
2280
2289
            if (saveTime == lastSaveTime) {
2281
            if (saveTime == lastSaveTime && alreadyModified) {
2290
                notifyUnmodified();
2282
                notifyUnmodified();
2291
            }
2283
            }
2292
        }
2284
        }
(-)test/unit/src/org/openide/text/NbLikeEditorKit.java (+42 lines)
Lines 14-19 Link Here
14
14
15
package org.openide.text;
15
package org.openide.text;
16
16
17
import java.beans.VetoableChangeListener;
17
import javax.swing.text.*;
18
import javax.swing.text.*;
18
19
19
/**
20
/**
Lines 88-92 Link Here
88
        public java.awt.Color getForeground(javax.swing.text.AttributeSet attr) {
89
        public java.awt.Color getForeground(javax.swing.text.AttributeSet attr) {
89
            return null;
90
            return null;
90
        }
91
        }
92
93
        public void insertString (int offs, String str, AttributeSet a) throws BadLocationException {
94
            insOrRemove (offs, str, a, 0, true);
95
        }
96
97
        public void remove (int offs, int len) throws BadLocationException {
98
            insOrRemove (offs, null, null, len, false);
99
        }
100
        
101
        
102
        private void insOrRemove (int offset, String str, AttributeSet set, int len, boolean insert) 
103
        throws BadLocationException {
104
            Object o = getProperty ("beforeModificationListener");
105
            if (o instanceof VetoableChangeListener) {
106
                VetoableChangeListener l = (VetoableChangeListener)o;
107
                try {
108
                    l.vetoableChange (new java.beans.PropertyChangeEvent (this, "modified", null, Boolean.TRUE));
109
                } catch (java.beans.PropertyVetoException ex) {
110
                    return;
111
                }
112
            }
113
            
114
            try {
115
                if (insert) {
116
                    super.insertString (offset, str, set);
117
                } else {
118
                    super.remove(offset, len);
119
                }
120
            } catch (BadLocationException ex) {
121
                if (o instanceof VetoableChangeListener) {
122
                    VetoableChangeListener l = (VetoableChangeListener)o;
123
                    try {
124
                        l.vetoableChange (new java.beans.PropertyChangeEvent (this, "modified", null, Boolean.FALSE));
125
                    } catch (java.beans.PropertyVetoException ignore) {
126
                        // ignore this
127
                    }
128
                }
129
                throw ex;
130
            }
131
        }
132
91
    } // end of Doc
133
    } // end of Doc
92
}
134
}
(-)test/unit/src/org/openide/text/NotifyModifiedTest.java (-19 / +77 lines)
Lines 45-50 Link Here
45
    private java.util.List/*<java.beans.PropertyChangeListener>*/ propL = new java.util.ArrayList ();
45
    private java.util.List/*<java.beans.PropertyChangeListener>*/ propL = new java.util.ArrayList ();
46
    private java.beans.VetoableChangeListener vetoL;
46
    private java.beans.VetoableChangeListener vetoL;
47
    private boolean shouldVetoNotifyModified;
47
    private boolean shouldVetoNotifyModified;
48
    /** kit to create */
49
    private javax.swing.text.EditorKit editorKit;
48
50
49
    
51
    
50
    public NotifyModifiedTest(java.lang.String testName) {
52
    public NotifyModifiedTest(java.lang.String testName) {
Lines 57-62 Link Here
57
    }
59
    }
58
    
60
    
59
    public void testJustOneCallToModified () throws Exception {
61
    public void testJustOneCallToModified () throws Exception {
62
        doJustOneCallToModified ();
63
    }
64
65
    public void testJustOneCallToModifiedWithNbLikeKit () throws Exception {
66
        editorKit = new NbLikeEditorKit ();
67
        doJustOneCallToModified ();
68
    }
69
    
70
    private void doJustOneCallToModified () throws Exception {
60
        content = "Line1\nLine2\n";
71
        content = "Line1\nLine2\n";
61
        
72
        
62
        // in order to set.getLines() work correctly, the document has to be loaded
73
        // in order to set.getLines() work correctly, the document has to be loaded
Lines 80-85 Link Here
80
    }
91
    }
81
    
92
    
82
    public void testTheDocumentReturnsBackIfModifyIsNotAllowed () throws Exception {
93
    public void testTheDocumentReturnsBackIfModifyIsNotAllowed () throws Exception {
94
        doTheDocumentReturnsBackIfModifyIsNotAllowed ();
95
    }
96
    public void testTheDocumentReturnsBackIfModifyIsNotAllowedWithNbLikeKit () throws Exception {
97
        editorKit = new NbLikeEditorKit ();
98
        doTheDocumentReturnsBackIfModifyIsNotAllowed ();
99
    }
100
    
101
    private void doTheDocumentReturnsBackIfModifyIsNotAllowed () throws Exception {
83
        content = "Nic\n";
102
        content = "Nic\n";
84
        
103
        
85
        // in order to set.getLines() work correctly, the document has to be loaded
104
        // in order to set.getLines() work correctly, the document has to be loaded
Lines 91-96 Link Here
91
        // should be reverted in SwingUtilities.invokeLater
110
        // should be reverted in SwingUtilities.invokeLater
92
        doc.insertString (0, "Ahoj", null);
111
        doc.insertString (0, "Ahoj", null);
93
        waitEQ ();
112
        waitEQ ();
113
        
114
        assertEquals ("One modification called (but it was vetoed)", 1, support.notifyModified);
115
        assertEquals ("No unmodification called", 0, support.notifyUnmodified);
116
117
        String first = doc.getText (0, 1);
118
        assertEquals ("First letter is N", "N", first);
119
    }
120
    public void testBadLocationException () throws Exception {
121
        doBadLocationException (0);
122
    }
123
    public void testBadLocationExceptionNbLikeKit () throws Exception {
124
        editorKit = new NbLikeEditorKit ();
125
        doBadLocationException (1);
126
    }
127
    
128
    private void doBadLocationException (int expected) throws Exception {
129
        content = "Nic\n";
130
        
131
        // in order to set.getLines() work correctly, the document has to be loaded
132
        javax.swing.text.Document doc = support.openDocument();
133
        assertEquals ("No modification", 0, support.notifyModified);
134
        
135
        try {
136
            doc.insertString (10, "Ahoj", null);
137
            fail ("This should generate bad location exception");
138
        } catch (javax.swing.text.BadLocationException ex) {
139
            // ok
140
        }
141
        
142
        assertEquals (expected + " modification called (but it was vetoed)", expected, support.notifyModified);
143
        assertEquals (expected + " unmodification called", expected, support.notifyUnmodified);
94
144
95
        String first = doc.getText (0, 1);
145
        String first = doc.getText (0, 1);
96
        assertEquals ("First letter is N", "N", first);
146
        assertEquals ("First letter is N", "N", first);
Lines 166-193 Link Here
166
    }
216
    }
167
    
217
    
168
    private void checkThatDocumentLockIsNotHeld () {
218
    private void checkThatDocumentLockIsNotHeld () {
169
        /*
219
        if (editorKit instanceof NbLikeEditorKit) {
170
        class X implements Runnable {
220
            class X implements Runnable {
171
            private boolean second;
221
                private boolean second;
172
            private boolean ok;
222
                private boolean ok;
173
            
223
174
            public void run () {
224
                public void run () {
175
                if (second) {
225
                    if (second) {
176
                    ok = true;
226
                        ok = true;
177
                    return;
227
                        return;
178
                } else {
228
                    } else {
179
                    second = true;
229
                        second = true;
180
                    javax.swing.text.Document doc = support.getDocument ();
230
                        javax.swing.text.Document doc = support.getDocument ();
181
                    assertNotNull (doc);
231
                        assertNotNull (doc);
182
                    doc.render (this);
232
                        doc.render (this);
183
                    return;
233
                        return;
234
                    }
184
                }
235
                }
185
            }
236
            }
237
238
            X x = new X ();
239
            org.openide.util.RequestProcessor.getDefault ().post (x).waitFinished ();
240
            assertTrue ("No lock is held on document when running notifyModified", x.ok);
186
        }
241
        }
187
        
188
        X x = new X ();
189
        org.openide.util.RequestProcessor.getDefault ().post (x).waitFinished ();
190
         */
191
    }
242
    }
192
243
193
    /** Implementation of the CES */
244
    /** Implementation of the CES */
Lines 235-240 Link Here
235
            boolean retValue;            
286
            boolean retValue;            
236
            retValue = super.notifyModified();
287
            retValue = super.notifyModified();
237
            return retValue;
288
            return retValue;
289
        }
290
        
291
        protected javax.swing.text.EditorKit createEditorKit() {
292
            if (editorKit != null) {
293
                return editorKit;
294
            } 
295
            return super.createEditorKit ();
238
        }
296
        }
239
        
297
        
240
    }
298
    }

Return to bug 51872