Added
Link Here
|
1 |
/* |
2 |
* Sun Public License Notice |
3 |
* |
4 |
* The contents of this file are subject to the Sun Public License |
5 |
* Version 1.0 (the "License"). You may not use this file except in |
6 |
* compliance with the License. A copy of the License is available at |
7 |
* http://www.sun.com/ |
8 |
* |
9 |
* The Original Code is NetBeans. The Initial Developer of the Original |
10 |
* Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun |
11 |
* Microsystems, Inc. All Rights Reserved. |
12 |
*/ |
13 |
|
14 |
|
15 |
package org.openide.text; |
16 |
|
17 |
|
18 |
import java.io.File; |
19 |
import java.io.IOException; |
20 |
import java.lang.reflect.Method; |
21 |
import java.util.Collections; |
22 |
import javax.swing.SwingUtilities; |
23 |
import javax.swing.text.BadLocationException; |
24 |
import javax.swing.text.Position; |
25 |
import javax.swing.text.StyledDocument; |
26 |
|
27 |
import junit.textui.TestRunner; |
28 |
|
29 |
import org.netbeans.junit.NbTestCase; |
30 |
import org.netbeans.junit.NbTestSuite; |
31 |
import org.openide.actions.*; |
32 |
import org.openide.cookies.CloseCookie; |
33 |
import org.openide.cookies.EditCookie; |
34 |
|
35 |
import org.openide.cookies.EditorCookie; |
36 |
import org.openide.cookies.OpenCookie; |
37 |
import org.openide.cookies.PrintCookie; |
38 |
import org.openide.cookies.SaveCookie; |
39 |
import org.openide.filesystems.FileLock; |
40 |
import org.openide.filesystems.FileObject; |
41 |
import org.openide.filesystems.FileStateInvalidException; |
42 |
import org.openide.filesystems.FileSystem; |
43 |
import org.openide.filesystems.Repository; |
44 |
import org.openide.filesystems.TestUtilHid; |
45 |
import org.openide.loaders.DataNode; |
46 |
import org.openide.loaders.DataObject; |
47 |
import org.openide.loaders.DataObjectExistsException; |
48 |
import org.openide.loaders.ExtensionList; |
49 |
import org.openide.loaders.MultiDataObject; |
50 |
import org.openide.loaders.MultiFileLoader; |
51 |
import org.openide.loaders.UniFileLoader; |
52 |
import org.openide.nodes.Children; |
53 |
import org.openide.nodes.CookieSet; |
54 |
import org.openide.nodes.Node; |
55 |
import org.openide.text.CloneableEditorSupport; |
56 |
import org.openide.util.HelpCtx; |
57 |
import org.openide.util.Lookup; |
58 |
import org.openide.util.NbBundle; |
59 |
import org.openide.util.actions.SystemAction; |
60 |
import org.openide.windows.CloneableOpenSupport; |
61 |
import org.openide.windows.WindowManager; |
62 |
|
63 |
|
64 |
/** |
65 |
*/ |
66 |
public class AnnotationProviderTest extends NbTestCase { |
67 |
|
68 |
public AnnotationProviderTest(String s) { |
69 |
super(s); |
70 |
} |
71 |
|
72 |
public static void main(String[] args) { |
73 |
TestRunner.run(new NbTestSuite(AnnotationProviderTest.class)); |
74 |
} |
75 |
|
76 |
private FileSystem fs; |
77 |
|
78 |
protected void setUp() throws Exception { |
79 |
System.setProperty("org.openide.util.Lookup", "org.openide.text.AnnotationProviderTest$Lkp"); |
80 |
|
81 |
TestUtilHid.destroyLocalFileSystem (getName()); |
82 |
fs = TestUtilHid.createLocalFileSystem (getName(), new String[] {}); |
83 |
} |
84 |
|
85 |
protected void tearDown() throws Exception { |
86 |
} |
87 |
|
88 |
public void testLookupIsConsistent() throws Exception { |
89 |
Object o = Lookup.getDefault().lookup(AnnotationProvider.class); |
90 |
if(o == null) { |
91 |
fail("No annotation provider found"); |
92 |
} |
93 |
|
94 |
FileObject fo = fs.getRoot().createData("test", "txt"); |
95 |
|
96 |
DataObject data = DataObject.find(fo); |
97 |
|
98 |
EditorCookie ec = (EditorCookie)data.getCookie(EditorCookie.class); |
99 |
|
100 |
if(!(ec instanceof CloneableEditorSupport)) { |
101 |
fail("Bad editor cookie type"); |
102 |
} |
103 |
|
104 |
CloneableEditorSupport ces = (CloneableEditorSupport)ec; |
105 |
|
106 |
ConsistencyCheckProvider.called = 0; |
107 |
ces.open(); |
108 |
|
109 |
assertEquals("Provider called exactly once", 1, ConsistencyCheckProvider.called); |
110 |
assertEquals("Consistent lookup content", data.getPrimaryFile(), ConsistencyCheckProvider.inLkp); |
111 |
|
112 |
assertEquals("Exactly one annotation attached", 1, ces.getLineSet().getCurrent(0).getAnnotationCount()); |
113 |
|
114 |
ces.close(); |
115 |
assertEquals("Exactly one annotation attached after close", 1, ces.getLineSet().getCurrent(0).getAnnotationCount()); |
116 |
|
117 |
ConsistencyCheckProvider.called = 0; |
118 |
ces.open(); |
119 |
assertEquals("Provider called exactly once during reopen", 1, ConsistencyCheckProvider.called); |
120 |
assertEquals("Exactly one annotation attached after reopen", 1, ces.getLineSet().getCurrent(0).getAnnotationCount()); |
121 |
|
122 |
} |
123 |
public static class ConsistencyCheckProvider implements AnnotationProvider { |
124 |
|
125 |
private static int called; |
126 |
private static FileObject inLkp; |
127 |
|
128 |
public void annotate(org.openide.text.Line.Set set, org.openide.util.Lookup context) { |
129 |
inLkp= (FileObject)context.lookup(FileObject.class); |
130 |
called++; |
131 |
|
132 |
set.getCurrent(0).addAnnotation(new MyAnnotation()); |
133 |
} |
134 |
|
135 |
} |
136 |
|
137 |
|
138 |
// below is only irrelevant support stuff |
139 |
|
140 |
private static class MyAnnotation extends Annotation { |
141 |
|
142 |
public String getAnnotationType() { |
143 |
return "nowhere"; |
144 |
} |
145 |
|
146 |
public String getShortDescription() { |
147 |
return "Test annotation"; |
148 |
} |
149 |
|
150 |
} |
151 |
|
152 |
protected boolean runInEQ() { |
153 |
return true; |
154 |
} |
155 |
|
156 |
// |
157 |
// Code from text module |
158 |
// |
159 |
|
160 |
|
161 |
public static final class TXTDataLoader extends UniFileLoader { |
162 |
|
163 |
/** Generated serial version UID. */ |
164 |
static final long serialVersionUID =-3658061894653334886L; |
165 |
|
166 |
/** file attribute which forces a file to be considered a text file */ |
167 |
static final String ATTR_IS_TEXT_FILE = "org.netbeans.modules.text.IsTextFile"; // NOI18N |
168 |
|
169 |
|
170 |
/** Creates new <code>TXTDataLoader</code>. */ |
171 |
public TXTDataLoader() { |
172 |
super("org.netbeans.modules.text.TXTDataObject"); // NOI18N |
173 |
} |
174 |
|
175 |
/** Does initialization. Initializes extension list. */ |
176 |
protected void initialize () { |
177 |
super.initialize(); |
178 |
|
179 |
ExtensionList ext = new ExtensionList(); |
180 |
ext.addExtension("txt"); // NOI18N |
181 |
ext.addExtension("doc"); // NOI18N |
182 |
ext.addExtension("me"); // for read.me files // NOI18N |
183 |
ext.addExtension("policy"); // NOI18N |
184 |
ext.addExtension("mf"); // for manifest.mf files // NOI18N |
185 |
ext.addExtension("MF"); // -""- // NOI18N |
186 |
ext.addExtension("log"); // log files are nice to be readable // NOI18N |
187 |
setExtensions(ext); |
188 |
} |
189 |
|
190 |
/** Gets default display name. Overrides superclass method. */ |
191 |
protected String defaultDisplayName() { |
192 |
return NbBundle.getBundle(TXTDataLoader.class).getString("PROP_TXTLoader_Name"); |
193 |
} |
194 |
|
195 |
/** Gets default system actions. Overrides superclass method. */ |
196 |
protected SystemAction[] defaultActions() { |
197 |
return new SystemAction[] { |
198 |
SystemAction.get(OpenAction.class), |
199 |
SystemAction.get (FileSystemAction.class), |
200 |
null, |
201 |
SystemAction.get(CutAction.class), |
202 |
SystemAction.get(CopyAction.class), |
203 |
SystemAction.get(PasteAction.class), |
204 |
null, |
205 |
SystemAction.get(DeleteAction.class), |
206 |
SystemAction.get(RenameAction.class), |
207 |
null, |
208 |
SystemAction.get(SaveAsTemplateAction.class), |
209 |
null, |
210 |
SystemAction.get(ToolsAction.class), |
211 |
SystemAction.get(PropertiesAction.class), |
212 |
}; |
213 |
} |
214 |
|
215 |
/** Check whether a file is recognized. |
216 |
* It will be if the extension matches, or if it is marked to be a text file. */ |
217 |
protected FileObject findPrimaryFile (FileObject fo) { |
218 |
boolean isSysFile; |
219 |
try { |
220 |
isSysFile = fo.getFileSystem () == Repository.getDefault ().getDefaultFileSystem (); |
221 |
} catch (FileStateInvalidException fsie) { |
222 |
// Never mind. |
223 |
isSysFile = false; |
224 |
} |
225 |
if (! isSysFile && Boolean.TRUE.equals (fo.getAttribute (ATTR_IS_TEXT_FILE))) |
226 |
return fo; |
227 |
return super.findPrimaryFile (fo); |
228 |
} |
229 |
|
230 |
/** Creates new <code>TXTDataObject</code> for specified <code>FileObject</code>. |
231 |
* @param fo FileObject |
232 |
* @return new TXTDataObject |
233 |
*/ |
234 |
protected MultiDataObject createMultiObject(final FileObject fo) |
235 |
throws IOException { |
236 |
return new TXTDataObject(fo, this); |
237 |
} |
238 |
|
239 |
} // end of TXTDataLoader |
240 |
|
241 |
|
242 |
public static final class TXTDataObject extends MultiDataObject implements CookieSet.Factory { |
243 |
|
244 |
/** Generated Serialized Version UID */ |
245 |
static final long serialVersionUID = 4795737295255253334L; |
246 |
|
247 |
/** Editor support for text data object. */ |
248 |
private transient TXTEditorSupport editorSupport; |
249 |
|
250 |
|
251 |
/** Constructor. */ |
252 |
public TXTDataObject(final FileObject obj, final MultiFileLoader loader) throws DataObjectExistsException { |
253 |
super(obj, loader); |
254 |
|
255 |
getCookieSet().add(TXTEditorSupport.class, this); |
256 |
} |
257 |
|
258 |
|
259 |
/** Implements <code>CookieSet.Factory</code> interface. */ |
260 |
public Node.Cookie createCookie(Class clazz) { |
261 |
if(clazz.isAssignableFrom(TXTEditorSupport.class)) |
262 |
return getEditorSupport(); |
263 |
else |
264 |
return null; |
265 |
} |
266 |
|
267 |
// Accessibility from TXTEditorSupport: |
268 |
CookieSet getCookieSet0() { |
269 |
return getCookieSet(); |
270 |
} |
271 |
|
272 |
/** Gets editor support for this data object. */ |
273 |
private TXTEditorSupport getEditorSupport() { |
274 |
if(editorSupport == null) { |
275 |
synchronized(this) { |
276 |
if(editorSupport == null) |
277 |
editorSupport = new TXTEditorSupport(this); |
278 |
} |
279 |
} |
280 |
|
281 |
return editorSupport; |
282 |
} |
283 |
|
284 |
/** Provides node that should represent this data object. When a node for representation |
285 |
* in a parent is requested by a call to getNode (parent) it is the exact copy of this node |
286 |
* with only parent changed. This implementation creates instance <code>DataNode</code>. |
287 |
* <p> |
288 |
* This method is called only once. |
289 |
* |
290 |
* @return the node representation for this data object |
291 |
* @see DataNode |
292 |
*/ |
293 |
protected Node createNodeDelegate () { |
294 |
return new TXTNode(this); |
295 |
} |
296 |
|
297 |
/** Help context for this object. |
298 |
* @return help context |
299 |
*/ |
300 |
public HelpCtx getHelpCtx () { |
301 |
return new HelpCtx (TXTDataObject.class); |
302 |
} |
303 |
|
304 |
|
305 |
/** Text node implementation. |
306 |
* Leaf node, default action opens editor or instantiates template. |
307 |
* Icons redefined. |
308 |
*/ |
309 |
public static final class TXTNode extends DataNode { |
310 |
/** Icon base for the TXTNode node */ |
311 |
private static final String TXT_ICON_BASE = "org/netbeans/modules/text/txtObject"; // NOI18N |
312 |
|
313 |
/** Constructs node. */ |
314 |
public TXTNode (final DataObject dataObject) { |
315 |
super(dataObject, Children.LEAF); |
316 |
setIconBase(TXT_ICON_BASE); |
317 |
} |
318 |
|
319 |
/** Overrides default action from DataNode. */ |
320 |
public SystemAction getDefaultAction () { |
321 |
SystemAction result = super.getDefaultAction(); |
322 |
return result == null ? SystemAction.get(OpenAction.class) : result; |
323 |
} |
324 |
} // End of nested class TXTNode. |
325 |
|
326 |
} // TXTDataObject |
327 |
|
328 |
|
329 |
public static final class TXTEditorSupport extends DataEditorSupport |
330 |
implements OpenCookie, EditCookie, EditorCookie.Observable, PrintCookie, CloseCookie { |
331 |
|
332 |
/** SaveCookie for this support instance. The cookie is adding/removing |
333 |
* data object's cookie set depending on if modification flag was set/unset. */ |
334 |
private final SaveCookie saveCookie = new SaveCookie() { |
335 |
/** Implements <code>SaveCookie</code> interface. */ |
336 |
public void save() throws IOException { |
337 |
TXTEditorSupport.this.saveDocument(); |
338 |
TXTEditorSupport.this.getDataObject().setModified(false); |
339 |
} |
340 |
}; |
341 |
|
342 |
|
343 |
/** Constructor. */ |
344 |
TXTEditorSupport(TXTDataObject obj) { |
345 |
super(obj, new Environment(obj)); |
346 |
|
347 |
setMIMEType("text/plain"); // NOI18N |
348 |
} |
349 |
|
350 |
/** |
351 |
* Overrides superclass method. Adds adding of save cookie if the document has been marked modified. |
352 |
* @return true if the environment accepted being marked as modified |
353 |
* or false if it has refused and the document should remain unmodified |
354 |
*/ |
355 |
protected boolean notifyModified () { |
356 |
if (!super.notifyModified()) |
357 |
return false; |
358 |
|
359 |
addSaveCookie(); |
360 |
|
361 |
return true; |
362 |
} |
363 |
|
364 |
/** Overrides superclass method. Adds removing of save cookie. */ |
365 |
protected void notifyUnmodified () { |
366 |
super.notifyUnmodified(); |
367 |
|
368 |
removeSaveCookie(); |
369 |
} |
370 |
|
371 |
/** Helper method. Adds save cookie to the data object. */ |
372 |
private void addSaveCookie() { |
373 |
TXTDataObject obj = (TXTDataObject)getDataObject(); |
374 |
|
375 |
// Adds save cookie to the data object. |
376 |
if(obj.getCookie(SaveCookie.class) == null) { |
377 |
obj.getCookieSet0().add(saveCookie); |
378 |
obj.setModified(true); |
379 |
} |
380 |
} |
381 |
|
382 |
/** Helper method. Removes save cookie from the data object. */ |
383 |
private void removeSaveCookie() { |
384 |
TXTDataObject obj = (TXTDataObject)getDataObject(); |
385 |
|
386 |
// Remove save cookie from the data object. |
387 |
Node.Cookie cookie = obj.getCookie(SaveCookie.class); |
388 |
|
389 |
if(cookie != null && cookie.equals(saveCookie)) { |
390 |
obj.getCookieSet0().remove(saveCookie); |
391 |
obj.setModified(false); |
392 |
} |
393 |
} |
394 |
|
395 |
|
396 |
/** Nested class. Environment for this support. Extends |
397 |
* <code>DataEditorSupport.Env</code> abstract class. |
398 |
*/ |
399 |
|
400 |
private static class Environment extends DataEditorSupport.Env |
401 |
{ |
402 |
private static final long serialVersionUID = 3499855082262173256L; |
403 |
|
404 |
/** Constructor. */ |
405 |
public Environment(TXTDataObject obj) { |
406 |
super(obj); |
407 |
} |
408 |
|
409 |
|
410 |
/** Implements abstract superclass method. */ |
411 |
protected FileObject getFile() { |
412 |
return getDataObject().getPrimaryFile(); |
413 |
} |
414 |
|
415 |
/** Implements abstract superclass method.*/ |
416 |
protected FileLock takeLock() throws IOException { |
417 |
return ((TXTDataObject)getDataObject()).getPrimaryEntry().takeLock(); |
418 |
} |
419 |
|
420 |
/** |
421 |
* Overrides superclass method. |
422 |
* @return text editor support (instance of enclosing class) |
423 |
*/ |
424 |
public CloneableOpenSupport findCloneableOpenSupport() { |
425 |
return (TXTEditorSupport)getDataObject().getCookie(TXTEditorSupport.class); |
426 |
} |
427 |
} // End of nested Environment class. |
428 |
|
429 |
} // TXTEditorSupport |
430 |
|
431 |
|
432 |
private static class MyPool extends org.openide.loaders.DataLoaderPool { |
433 |
protected java.util.Enumeration loaders() { |
434 |
return Collections.enumeration(Collections.singleton( |
435 |
TXTDataLoader.getLoader(TXTDataLoader.class) |
436 |
)); |
437 |
} |
438 |
|
439 |
} |
440 |
|
441 |
public static class Lkp extends org.openide.util.lookup.AbstractLookup { |
442 |
public Lkp () { |
443 |
this (new org.openide.util.lookup.InstanceContent ()); |
444 |
} |
445 |
|
446 |
private Lkp (org.openide.util.lookup.InstanceContent ic) { |
447 |
super (ic); |
448 |
|
449 |
ic.add (new MyPool ()); |
450 |
ic.add (new ConsistencyCheckProvider ()); |
451 |
} |
452 |
} |
453 |
} |