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

(-)indent/.cvsignore (+1 lines)
Added Link Here
1
build
(-)indent/apichanges.xml (+123 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!--
3
The contents of this file are subject to the terms of the Common Development
4
and Distribution License (the License). You may not use this file except in
5
compliance with the License.
6
7
You can obtain a copy of the License at http://www.netbeans.org/cddl.html
8
or http://www.netbeans.org/cddl.txt.
9
10
When distributing Covered Code, include this CDDL Header Notice in each file
11
and include the License file at http://www.netbeans.org/cddl.txt.
12
If applicable, add the following below the CDDL Header, with the fields
13
enclosed by brackets [] replaced by your own identifying information:
14
"Portions Copyrighted [year] [name of copyright owner]"
15
16
The Original Software is NetBeans. The Initial Developer of the Original
17
Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
18
Microsystems, Inc. All Rights Reserved.
19
-->
20
<?xml-stylesheet type="text/xml" href="../../nbbuild/javadoctools/apichanges.xsl"?>
21
<!DOCTYPE apichanges PUBLIC "-//NetBeans//DTD API changes list 1.0//EN" "../../nbbuild/javadoctools/apichanges.dtd">
22
23
<!--
24
25
INFO FOR PEOPLE ADDING CHANGES:
26
27
Check the DTD (apichanges.dtd) for details on the syntax. You do not
28
need to regenerate the HTML, as this is part of Javadoc generation; just
29
change the XML. Rough syntax of a change (several parts optional):
30
31
<change>
32
    <api name="compiler"/>
33
    <summary>Some brief description here, can use <b>XHTML</b></summary>
34
    <version major="1" minor="99"/>
35
    <date day="13" month="6" year="2001"/>
36
    <author login="jrhacker"/>
37
    <compatibility addition="yes"/>
38
    <description>
39
        The main description of the change here.
40
        Again can use full <b>XHTML</b> as needed.
41
    </description>
42
    <class package="org.openide.compiler" name="DoWhatIWantCompiler"/>
43
    <issue number="14309"/>
44
</change>
45
46
Also permitted elements: <package>, <branch>. <version> is API spec
47
version, recommended for all new changes. <compatibility> should say
48
if things were added/modified/deprecated/etc. and give all information
49
related to upgrading old code. List affected top-level classes and
50
link to issue numbers if applicable. See the DTD for more details.
51
52
Changes need not be in any particular order, they are sorted in various
53
ways by the stylesheet anyway.
54
55
Dates are assumed to mean "on the trunk". If you *also* make the same
56
change on a stabilization branch, use the <branch> tag to indicate this
57
and explain why the change was made on a branch in the <description>.
58
59
Please only change this file on the trunk! Rather: you can change it
60
on branches if you want, but these changes will be ignored; only the
61
trunk version of this file is important.
62
63
Deprecations do not count as incompatible, assuming that code using the
64
deprecated calls continues to see their documented behavior. But do
65
specify deprecation="yes" in <compatibility>.
66
67
This file is not a replacement for Javadoc: it is intended to list changes,
68
not describe the complete current behavior, for which ordinary documentation
69
is the proper place.
70
71
-->
72
73
<apichanges>
74
75
    <!-- First, a list of API names you may use: -->
76
    <apidefs>
77
        <apidef name="general">General</apidef>
78
        <!-- etc. -->
79
    </apidefs>
80
81
    <!-- ACTUAL CHANGES BEGIN HERE: -->
82
83
    <changes>
84
85
        <change id="created">
86
            <summary>editor/indent module was created.</summary>
87
            <version major="1" minor="0"/>
88
            <date day="14" month="6" year="2007"/>
89
            <author login="mmetelka"/>
90
            <compatibility binary="compatible" source="compatible" semantic="compatible"/>
91
            <description>
92
                The module was created.
93
            </description>
94
        </change>
95
96
    </changes>
97
98
    <!-- Now the surrounding HTML text and document structure: -->
99
100
    <htmlcontents>
101
<!-- Generated from apichanges.xml -->
102
    <head>
103
      <title>Change History of Editor Indentation API</title>
104
      <link rel="stylesheet" href="prose.css" type="text/css"/>
105
    </head>
106
    <body>
107
108
<p class="overviewlink"><a href="overview-summary.html">Overview</a></p>
109
110
<h1>Introduction</h1>
111
112
<p>This document lists changes made to the <a href="overview-summary.html">Editor Indent API</a>.</p>
113
114
<!-- The actual lists of changes, as summaries and details: -->
115
      <hr/>
116
      <standard-changelists module-code-name="org.netbeans.modules.editor.indent/1"/>
117
118
      <hr/><p>@FOOTER@</p>
119
120
    </body>
121
  </htmlcontents>
122
123
</apichanges>
(-)indent/arch.xml (+1167 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?><!-- -*- sgml-indent-step: 1 -*- -->
2
<!--
3
The contents of this file are subject to the terms of the Common Development
4
and Distribution License (the License). You may not use this file except in
5
compliance with the License.
6
7
You can obtain a copy of the License at http://www.netbeans.org/cddl.html
8
or http://www.netbeans.org/cddl.txt.
9
10
When distributing Covered Code, include this CDDL Header Notice in each file
11
and include the License file at http://www.netbeans.org/cddl.txt.
12
If applicable, add the following below the CDDL Header, with the fields
13
enclosed by brackets [] replaced by your own identifying information:
14
"Portions Copyrighted [year] [name of copyright owner]"
15
16
The Original Software is NetBeans. The Initial Developer of the Original
17
Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
18
Microsystems, Inc. All Rights Reserved.
19
-->
20
<!DOCTYPE api-answers PUBLIC "-//NetBeans//DTD Arch Answers//EN" "../../nbbuild/antsrc/org/netbeans/nbbuild/Arch.dtd" [
21
  <!ENTITY api-questions SYSTEM "../../nbbuild/antsrc/org/netbeans/nbbuild/Arch-api-questions.xml">
22
]>
23
24
<api-answers
25
  question-version="1.29"
26
  author="yourname@netbeans.org"
27
>
28
29
  &api-questions;
30
31
32
<!--
33
        <question id="arch-overall" when="init">
34
            Describe the overall architecture. 
35
            <hint>
36
            What will be API for 
37
            <a href="http://openide.netbeans.org/tutorial/api-design.html#design.apiandspi">
38
                clients and what support API</a>? 
39
            What parts will be pluggable?
40
            How will plug-ins be registered? Please use <code>&lt;api type="export"/&gt;</code>
41
            to describe your general APIs and specify their
42
            <a href="http://openide.netbeans.org/tutorial/api-design.html#category-private">
43
            stability categories</a>.
44
            If possible please provide simple diagrams.
45
            </hint>
46
        </question>
47
-->
48
 <answer id="arch-overall">
49
  <p>
50
   Editor Indentation module defines 
51
   <api name="EditorIndentationAPI" group="java" type="export" category="official"/>
52
   providing indentation and reformatting services to the clients.
53
   <br/>
54
   It also contains SPI allowing the modules to register language-specific
55
   indenters and formatters into
56
   <a href="@org-netbeans-modules-editor-mimelookup@/org/netbeans/api/editor/mimelookup/MimeLookup.html">MimeLookup</a>
57
   through XML layers.
58
  </p>
59
 </answer>
60
61
62
63
<!--
64
        <question id="arch-quality" when="init">
65
            How will the <a href="http://www.netbeans.org/community/guidelines/q-evangelism.html">quality</a>
66
            of your code be tested and 
67
            how are future regressions going to be prevented?
68
            <hint>
69
            What kind of testing do
70
            you want to use? How much functionality, in which areas,
71
            should be covered by the tests? How you find out that your
72
            project was successful?
73
            </hint>
74
        </question>
75
-->
76
 <answer id="arch-quality">
77
  <p>
78
   Unit tests are provided for checking correctness of infrastructure and delegation
79
   from the legacy editor actions to the new API.
80
  </p>
81
 </answer>
82
83
84
85
<!--
86
        <question id="arch-time" when="init">
87
            What are the time estimates of the work?
88
            <hint>
89
            Please express your estimates of how long the design, implementation,
90
            stabilization are likely to last. How many people will be needed to
91
            implement this and what is the expected milestone by which the work should be 
92
            ready?
93
            </hint>
94
        </question>
95
-->
96
 <answer id="arch-time">
97
  <p>
98
   Available for NetBeans 6.0.
99
  </p>
100
 </answer>
101
102
103
104
<!--
105
        <question id="arch-usecases" when="init">
106
            <hint>
107
                Content of this answer will be displayed as part of page at
108
                http://www.netbeans.org/download/dev/javadoc/usecases.html 
109
                You can use tags &lt;usecase name="name&gt; regular html description &lt;/usecase&gt;
110
                and if you want to use an URL you can prefix if with @TOP@ to begin
111
                at the root of your javadoc
112
            </hint>
113
        
114
            Describe the main <a href="http://openide.netbeans.org/tutorial/api-design.html#usecase">
115
            use cases</a> of the new API. Who will use it under
116
            what circumstances? What kind of code would typically need to be written
117
            to use the module?
118
        </question>
119
-->
120
 <answer id="arch-usecases">
121
<h1>
122
API Usecases
123
</h1>
124
125
<h3>
126
Fix indentation of a single or multiple lines of a document.
127
</h3>
128
<p>
129
Altghough there are formatting actions already there may be clients
130
wishing to explicitly fix indentation of e.g. a newly inserted code into a Swing document.
131
</p>
132
<p>
133
The same code is used after inserting a newline into a document.
134
</p>
135
The 
136
<a href="@org-netbeans-modules-editor-indent@/org/netbeans/api/editor/indent/Indent.html">Indent</a>
137
is an entry point for performing reindentation. The following code should be used by clients:
138
<pre>
139
Indent indent = Indent.get(doc);
140
indent.lock();
141
try {
142
    doc.atomicLock();
143
    try {
144
        indent.reindent(startOffset, endOffset);
145
    } finally {
146
        doc.atomicUnlock();
147
    }
148
} finally {
149
    indent.unlock();
150
}
151
</pre>
152
153
<h3>
154
Code beautification of a selected area of a document.
155
</h3>
156
<p>
157
Code beautification should not only fix line indentation but it may also perform
158
extra changes to code according to formatting rules. For example add newlines
159
 or additional whitespace or add/remove extra braces etc.
160
</p>
161
The 
162
<a href="@org-netbeans-modules-editor-indent@/org/netbeans/api/editor/indent/Reformat.html">Reformat</a>
163
class should be used:
164
<pre>
165
Reformat reformat = Reformat.get(doc);
166
reformat.lock();
167
try {
168
    doc.atomicLock();
169
    try {
170
        reformat.reformat(startOffset, endOffset);
171
    } finally {
172
        doc.atomicUnlock();
173
    }
174
} finally {
175
    reformat.unlock();
176
}
177
</pre>
178
 </answer>
179
180
181
182
<!--
183
        <question id="arch-what" when="init">
184
            What is this project good for?
185
            <hint>
186
            Please provide here a few lines describing the project, 
187
            what problem it should solve, provide links to documentation, 
188
            specifications, etc.
189
            </hint>
190
        </question>
191
-->
192
 <answer id="arch-what">
193
  <p>
194
   Editor indentation performs reindentation and code beautification of Swing document.
195
  </p>
196
 </answer>
197
198
199
200
<!--
201
        <question id="arch-where" when="impl">
202
            Where one can find sources for your module?
203
            <hint>
204
                Please provide link to the CVS web client at
205
                http://www.netbeans.org/download/source_browse.html
206
                or just use tag defaultanswer generate='here'
207
            </hint>
208
        </question>
209
-->
210
 <answer id="arch-where">
211
  <defaultanswer generate='here' />
212
 </answer>
213
214
215
216
<!--
217
        <question id="compat-deprecation" when="init">
218
            How the introduction of your project influences functionality
219
            provided by previous version of the product?
220
            <hint>
221
            If you are planning to deprecate/remove/change any existing APIs,
222
            list them here accompanied with the reason explaining why you
223
            are doing so.
224
            </hint>
225
        </question>
226
-->
227
 <answer id="compat-deprecation">
228
  <p>
229
   The new API should coexist with existing APIs mainly
230
   <a href="@org-openide-text@/org/openide/text/IndentEngine.html">IndentEngine</a>
231
   <a href="@org-netbeans-modules-editor-lib@/org/netbeans/editor/Formatter.html">Formatter</a>
232
   but in the future we would like to deprecate the mentioned APIs.
233
  </p>
234
 </answer>
235
236
237
238
<!--
239
        <question id="compat-i18n" when="impl">
240
            Is your module correctly internationalized?
241
            <hint>
242
            Correct internationalization means that it obeys instructions 
243
            at <a href="http://www.netbeans.org/download/dev/javadoc/org-openide-modules/org/openide/modules/doc-files/i18n-branding.html">
244
            NetBeans I18N pages</a>.
245
            </hint>
246
        </question>
247
-->
248
 <answer id="compat-i18n">
249
  <p>
250
   Yes.
251
  </p>
252
 </answer>
253
254
255
256
<!--
257
        <question id="compat-standards" when="init">
258
            Does the module implement or define any standards? Is the 
259
            implementation exact or does it deviate somehow?
260
        </question>
261
-->
262
 <answer id="compat-standards">
263
  <p>
264
   No.
265
  </p>
266
 </answer>
267
268
269
270
<!--
271
        <question id="compat-version" when="impl">
272
            Can your module coexist with earlier and future
273
            versions of itself? Can you correctly read all old settings? Will future
274
            versions be able to read your current settings? Can you read
275
            or politely ignore settings stored by a future version?
276
            
277
            <hint>
278
            Very helpful for reading settings is to store version number
279
            there, so future versions can decide whether how to read/convert
280
            the settings and older versions can ignore the new ones.
281
            </hint>
282
        </question>
283
-->
284
 <answer id="compat-version">
285
  <p>
286
   Yes.
287
  </p>
288
 </answer>
289
290
291
292
<!--
293
        <question id="dep-jre" when="final">
294
            Which version of JRE do you need (1.2, 1.3, 1.4, etc.)?
295
            <hint>
296
            It is expected that if your module runs on 1.x that it will run 
297
            on 1.x+1 if no, state that please. Also describe here cases where
298
            you run different code on different versions of JRE and why.
299
            </hint>
300
        </question>
301
-->
302
 <answer id="dep-jre">
303
  <p>
304
   JRE 1.5.
305
  </p>
306
 </answer>
307
308
309
310
<!--
311
        <question id="dep-jrejdk" when="final">
312
            Do you require the JDK or is the JRE enough?
313
        </question>
314
-->
315
 <answer id="dep-jrejdk">
316
  <p>
317
   JRE is enough.
318
  </p>
319
 </answer>
320
321
322
323
<!--
324
        <question id="dep-nb" when="init">
325
            What other NetBeans projects and modules does this one depend on?
326
            <hint>
327
            Depending on other NetBeans projects influnces the ability of
328
            users of your work to customize their own branded version of
329
            NetBeans by enabling and disabling some modules. Too
330
            much dependencies restrict this kind of customization. If that
331
            is your case, then you may want to split your functionality into
332
            pieces of autoload, eager and regular modules which can be
333
            enabled independently. Usually the answer to this question
334
            is generated from your <code>project.xml</code> file, but
335
            if it is not guessed correctly, you can suppress it by
336
            specifying &lt;defaultanswer generate="none"/&gt; and
337
            write here your own. Please describe such projects as imported APIs using
338
            the <code>&lt;api name="identification" type="import or export" category="stable" url="where is the description" /&gt;</code>.
339
            By doing this information gets listed in the summary page of your
340
            javadoc.
341
            </hint>
342
        </question>
343
-->
344
 <answer id="dep-nb">
345
  <defaultanswer generate='here' />
346
 </answer>
347
348
349
350
<!--
351
        <question id="dep-non-nb" when="init">
352
            What other projects outside NetBeans does this one depend on?
353
            
354
            <hint>
355
            Depending on 3rd party libraries is always problematic,
356
            especially if they are not open source, as that complicates
357
            the licensing scheme of NetBeans. Please enumerate your
358
            external dependencies here, so it is correctly understood since
359
            the begining what are the legal implications of your project.
360
            Also please note that
361
            some non-NetBeans projects are packaged as NetBeans modules
362
            (see <a href="http://libs.netbeans.org/">libraries</a>) and
363
            it is preferred to use this approach when more modules may
364
            depend and share such third-party libraries.
365
            </hint>
366
        </question>
367
-->
368
 <answer id="dep-non-nb">
369
  <p>
370
   None.
371
  </p>
372
 </answer>
373
374
375
376
<!--
377
        <question id="dep-platform" when="init">
378
            On which platforms does your module run? Does it run in the same
379
            way on each?
380
            <hint>
381
            If you plan any dependency on OS or any usage of native code,
382
            please describe why you are doing so and describe how you envision
383
            to enforce the portability of your code.
384
            Please note that there is a support for <a href="http://www.netbeans.org/download/dev/javadoc/org-openide-modules/org/openide/modules/doc-files/api.html#how-os-specific">OS conditionally
385
            enabled modules</a> which together with autoload/eager modules
386
            can allow you to enable to provide the best OS aware support
387
            on certain OSes while providing compatibility bridge on the not
388
            supported ones.
389
            Also please list the supported
390
            OSes/HW platforms and mentioned the lovest version of JDK required
391
            for your project to run on. Also state whether JRE is enough or
392
            you really need JDK.
393
            </hint>
394
        </question>
395
-->
396
 <answer id="dep-platform">
397
  <p>
398
   All platforms.
399
  </p>
400
 </answer>
401
402
403
404
<!--
405
        <question id="deploy-dependencies" when="final">
406
            What do other modules need to do to declare a dependency on this one,
407
            in addition to or instead of the normal module dependency declaration
408
            (e.g. tokens to require)?
409
            <hint>
410
                Provide a sample of the actual lines you would add to a module manifest
411
                to declare a dependency, for example OpenIDE-Module-Requires: some.token.
412
                If other modules should not depend on this module, or should just use a
413
                simple regular module dependency, you can just answer "nothing". If you
414
                intentionally expose a semistable API to clients using implementation
415
                dependencies, you should mention that here (but there is no need to give
416
                an example of usage).
417
            </hint>
418
        </question>
419
-->
420
 <answer id="deploy-dependencies">
421
  <p>
422
   Nothing.
423
  </p>
424
 </answer>
425
426
427
428
<!--
429
        <question id="deploy-jar" when="impl">
430
            Do you deploy just module JAR file(s) or other files as well?
431
            <hint>
432
            Usually a module consist of one JAR file (perhaps with Class-Path
433
            extensions) and also a configuration file that enables it. If you
434
            have any other files, use
435
            &lt;api group="java.io.File" name="yourname" type="export" category="friend"&gt;...&lt;/api&gt;
436
            to define the location, name and stability of your files (of course
437
            changing "yourname" and "friend" to suit your needs).
438
            
439
            If it uses more than one JAR, describe where they are located, how
440
            they refer to each other. 
441
            If it consist of module JAR(s) and other files, please describe
442
            what is their purpose, why other files are necessary. Please 
443
            make sure that installation/uninstallation leaves the system 
444
            in state as it was before installation.
445
            </hint>
446
        </question>
447
-->
448
 <answer id="deploy-jar">
449
  <p>
450
   Jar only.
451
  </p>
452
 </answer>
453
454
455
456
<!--
457
        <question id="deploy-nbm" when="impl">
458
            Can you deploy an NBM via the Update Center?
459
            <hint>
460
            If not why?
461
            </hint>
462
        </question>
463
-->
464
 <answer id="deploy-nbm">
465
  <p>
466
   Yes.
467
  </p>
468
 </answer>
469
470
471
472
<!--
473
        <question id="deploy-packages" when="init">
474
            Are packages of your module made inaccessible by not declaring them
475
            public?
476
            
477
            <hint>
478
            By default NetBeans build harness treats all packages are private.
479
            If you export some of them - either as public or friend packages,
480
            you should have a reason. If the reason is described elsewhere
481
            in this document, you can ignore this question.
482
            </hint>
483
        </question>
484
-->
485
 <answer id="deploy-packages">
486
  <p>
487
   Only API and SPI packages are public.
488
  </p>
489
 </answer>
490
491
492
493
<!--
494
        <question id="deploy-shared" when="final">
495
            Do you need to be installed in the shared location only, or in the user directory only,
496
            or can your module be installed anywhere?
497
            <hint>
498
            Installation location shall not matter, if it does explain why.
499
            Consider also whether <code>InstalledFileLocator</code> can help.
500
            </hint>
501
        </question>
502
-->
503
 <answer id="deploy-shared">
504
  <p>
505
   Anywhere.
506
  </p>
507
 </answer>
508
509
510
511
<!--
512
        <question id="exec-ant-tasks" when="impl">
513
            Do you define or register any ant tasks that other can use?
514
            
515
            <hint>
516
            If you provide an ant task that users can use, you need to be very
517
            careful about its syntax and behaviour, as it most likely forms an
518
	          API for end users and as there is a lot of end users, their reaction
519
            when such API gets broken can be pretty strong.
520
            </hint>
521
        </question>
522
-->
523
 <answer id="exec-ant-tasks">
524
  <p>
525
   No.
526
  </p>
527
 </answer>
528
529
530
531
<!--
532
        <question id="exec-classloader" when="impl">
533
            Does your code create its own class loader(s)?
534
            <hint>
535
            A bit unusual. Please explain why and what for.
536
            </hint>
537
        </question>
538
-->
539
 <answer id="exec-classloader">
540
  <p>
541
   No.
542
  </p>
543
 </answer>
544
545
546
547
<!--
548
        <question id="exec-component" when="impl">
549
            Is execution of your code influenced by any (string) property
550
            of any of your components?
551
            
552
            <hint>
553
            Often <code>JComponent.getClientProperty</code>, <code>Action.getValue</code>
554
            or <code>PropertyDescriptor.getValue</code>, etc. are used to influence
555
            a behavior of some code. This of course forms an interface that should
556
            be documented. Also if one depends on some interface that an object
557
            implements (<code>component instanceof Runnable</code>) that forms an
558
            API as well.
559
            </hint>
560
        </question>
561
-->
562
 <answer id="exec-component">
563
  <p>
564
   No.
565
  </p>
566
 </answer>
567
568
569
570
<!--
571
        <question id="exec-introspection" when="impl">
572
            Does your module use any kind of runtime type information (<code>instanceof</code>,
573
            work with <code>java.lang.Class</code>, etc.)?
574
            <hint>
575
            Check for cases when you have an object of type A and you also
576
            expect it to (possibly) be of type B and do some special action. That
577
            should be documented. The same applies on operations in meta-level
578
            (Class.isInstance(...), Class.isAssignableFrom(...), etc.).
579
            </hint>
580
        </question>
581
-->
582
 <answer id="exec-introspection">
583
  <p>
584
   No.
585
  </p>
586
 </answer>
587
588
589
590
<!--
591
        <question id="exec-privateaccess" when="final">
592
            Are you aware of any other parts of the system calling some of 
593
            your methods by reflection?
594
            <hint>
595
            If so, describe the "contract" as an API. Likely private or friend one, but
596
            still API and consider rewrite of it.
597
            </hint>
598
        </question>
599
-->
600
 <answer id="exec-privateaccess">
601
  <p>
602
   No.
603
  </p>
604
 </answer>
605
606
607
608
<!--
609
        <question id="exec-process" when="impl">
610
            Do you execute an external process from your module? How do you ensure
611
            that the result is the same on different platforms? Do you parse output?
612
            Do you depend on result code?
613
            <hint>
614
            If you feed an input, parse the output please declare that as an API.
615
            </hint>
616
        </question>
617
-->
618
 <answer id="exec-process">
619
  <p>
620
   No.
621
  </p>
622
 </answer>
623
624
625
626
<!--
627
        <question id="exec-property" when="impl">
628
            Is execution of your code influenced by any environment or
629
            Java system (<code>System.getProperty</code>) property?
630
            On a similar note, is there something interesting that you
631
            pass to <code>java.util.logging.Logger</code>? Or do you observe
632
            what others log?
633
            <hint>
634
            If there is a property that can change the behavior of your 
635
            code, somebody will likely use it. You should describe what it does 
636
            and the <a href="http://openide.netbeans.org/tutorial/api-design.html#life">stability category</a>
637
            of this API. You may use
638
            <pre>
639
                &lt;api type="export" group="property" name="id" category="private" url="http://..."&gt;
640
                    description of the property, where it is used, what it influence, etc.
641
                &lt;/api&gt;            
642
            </pre>
643
            </hint>
644
        </question>
645
-->
646
 <answer id="exec-property">
647
  <p>
648
   No.
649
  </p>
650
 </answer>
651
652
653
654
<!--
655
        <question id="exec-reflection" when="impl">
656
            Does your code use Java Reflection to execute other code?
657
            <hint>
658
            This usually indicates a missing or insufficient API in the other
659
            part of the system. If the other side is not aware of your dependency
660
            this contract can be easily broken.
661
            </hint>
662
        </question>
663
-->
664
 <answer id="exec-reflection">
665
  <p>
666
   No.
667
  </p>
668
 </answer>
669
670
671
672
<!--
673
        <question id="exec-threading" when="init">
674
            What threading models, if any, does your module adhere to? How the
675
            project behaves with respect to threading?
676
            <hint>
677
                Is your API threadsafe? Can it be accessed from any threads or
678
                just from some dedicated ones? Any special relation to AWT and
679
                its Event Dispatch thread? Also
680
                if your module calls foreign APIs which have a specific threading model,
681
                indicate how you comply with the requirements for multithreaded access
682
                (synchronization, mutexes, etc.) applicable to those APIs.
683
                If your module defines any APIs, or has complex internal structures
684
                that might be used from multiple threads, declare how you protect
685
                data against concurrent access, race conditions, deadlocks, etc.,
686
                and whether such rules are enforced by runtime warnings, errors, assertions, etc.
687
                Examples: a class might be non-thread-safe (like Java Collections); might
688
                be fully thread-safe (internal locking); might require access through a mutex
689
                (and may or may not automatically acquire that mutex on behalf of a client method);
690
                might be able to run only in the event queue; etc.
691
                Also describe when any events are fired: synchronously, asynchronously, etc.
692
                Ideas: <a href="http://core.netbeans.org/proposals/threading/index.html#recommendations">Threading Recommendations</a> (in progress)
693
            </hint>
694
        </question>
695
-->
696
 <answer id="exec-threading">
697
  <p>
698
   Both reindentation and reformatting are executed synchronously in a thread that calls
699
   the API classes (typically AWT thread).
700
  </p>
701
 </answer>
702
703
704
705
<!--
706
        <question id="format-clipboard" when="impl">
707
            Which data flavors (if any) does your code read from or insert to
708
            the clipboard (by access to clipboard on means calling methods on <code>java.awt.datatransfer.Transferable</code>?
709
            
710
            <hint>
711
            Often Node's deal with clipboard by usage of <code>Node.clipboardCopy, Node.clipboardCut and Node.pasteTypes</code>.
712
            Check your code for overriding these methods.
713
            </hint>
714
        </question>
715
-->
716
 <answer id="format-clipboard">
717
  <p>
718
   None.
719
  </p>
720
 </answer>
721
722
723
724
<!--
725
        <question id="format-dnd" when="impl">
726
            Which protocols (if any) does your code understand during Drag &amp; Drop?
727
            <hint>
728
            Often Node's deal with clipboard by usage of <code>Node.drag, Node.getDropType</code>. 
729
            Check your code for overriding these methods. Btw. if they are not overridden, they
730
            by default delegate to <code>Node.clipboardCopy, Node.clipboardCut and Node.pasteTypes</code>.
731
            </hint>
732
        </question>
733
-->
734
 <answer id="format-dnd">
735
  <p>
736
   None.
737
  </p>
738
 </answer>
739
740
741
742
<!--
743
        <question id="format-types" when="impl">
744
            Which protocols and file formats (if any) does your module read or write on disk,
745
            or transmit or receive over the network? Do you generate an ant build script?
746
            Can it be edited and modified? 
747
            
748
            <hint>
749
            <p>
750
            Files can be read and written by other programs, modules and users. If they influence
751
            your behaviour, make sure you either document the format or claim that it is a private
752
            api (using the &lt;api&gt; tag). 
753
            </p>
754
            
755
            <p>
756
            If you generate an ant build file, this is very likely going to be seen by end users and
757
            they will be attempted to edit it. You should be ready for that and provide here a link
758
            to documentation that you have for such purposes and also describe how you are going to
759
            understand such files during next release, when you (very likely) slightly change the 
760
            format.
761
            </p>
762
            </hint>
763
        </question>
764
-->
765
 <answer id="format-types">
766
  <p>
767
   None.
768
  </p>
769
 </answer>
770
771
772
773
<!--
774
        <question id="lookup-lookup" when="init">
775
            Does your module use <code>org.openide.util.Lookup</code>
776
            or any similar technology to find any components to communicate with? Which ones?
777
            
778
            <hint>
779
            NetBeans is build around a generic registry of services called
780
            lookup. It is preferable to use it for registration and discovery
781
            if possible. See
782
            <a href="http://www.netbeans.org/download/dev/javadoc/org-openide-util/org/openide/util/lookup/doc-files/index.html">
783
            The Solution to Comunication Between Components
784
            </a>. If you do not plan to use lookup and insist usage
785
            of other solution, then please describe why it is not working for
786
            you.
787
            <br/>
788
            When filling the final version of your arch document, please
789
            describe the interfaces you are searching for, where 
790
            are defined, whether you are searching for just one or more of them,
791
            if the order is important, etc. Also classify the stability of such
792
            API contract. Use &lt;api group=&amp;lookup&amp; /&gt; tag, so
793
            your information gets listed in the summary page of your javadoc.
794
            </hint>
795
        </question>
796
-->
797
 <answer id="lookup-lookup">
798
  <p>
799
   It uses MimeLookup to search for registered indentation and reformatting task factories.
800
  </p>
801
 </answer>
802
803
804
805
<!--
806
        <question id="lookup-register" when="final">
807
            Do you register anything into lookup for other code to find?
808
            <hint>
809
            Do you register using layer file or using <code>META-INF/services</code>?
810
            Who is supposed to find your component?
811
            </hint>
812
        </question>
813
-->
814
 <answer id="lookup-register">
815
  <p>
816
   The module registers <code>org.netbeans.modules.editor.lib.FormatterOverride</code>
817
   implementation so that it gets callback-ed from Editor Library formatter's infrastructure.
818
  </p>
819
 </answer>
820
821
822
823
<!--
824
        <question id="lookup-remove" when="final">
825
            Do you remove entries of other modules from lookup?
826
            <hint>
827
            Why? Of course, that is possible, but it can be dangerous. Is the module
828
            your are masking resource from aware of what you are doing?
829
            </hint>
830
        </question>
831
-->
832
 <answer id="lookup-remove">
833
  <p>
834
   No.
835
  </p>
836
 </answer>
837
838
839
840
<!--
841
        <question id="perf-exit" when="final">
842
            Does your module run any code on exit?
843
        </question>
844
-->
845
 <answer id="perf-exit">
846
  <p>
847
   No.
848
  </p>
849
 </answer>
850
851
852
853
<!--
854
        <question id="perf-huge_dialogs" when="final">
855
            Does your module contain any dialogs or wizards with a large number of
856
            GUI controls such as combo boxes, lists, trees, or text areas?
857
        </question>
858
-->
859
 <answer id="perf-huge_dialogs">
860
  <p>
861
   No.
862
  </p>
863
 </answer>
864
865
866
867
<!--
868
        <question id="perf-limit" when="init">
869
            Are there any hard-coded or practical limits in the number or size of
870
            elements your code can handle?
871
            <hint>
872
                Most of algorithms have increasing memory and speed complexity
873
                with respect to size of data they operate on. What is the critical
874
                part of your project that can be seen as a bottleneck with
875
                respect to speed or required memory? What are the practical
876
                sizes of data you tested your project with? What is your estimate
877
                of potential size of data that would cause visible performance
878
                problems? Is there some kind of check to detect such situation
879
                and prevent "hard" crashes - for example the CloneableEditorSupport
880
                checks for size of a file to be opened in editor
881
                and if it is larger than 1Mb it shows a dialog giving the
882
                user the right to decide - e.g. to cancel or commit suicide.
883
            </hint>
884
        </question>
885
-->
886
 <answer id="perf-limit">
887
  <p>
888
   No.
889
  </p>
890
 </answer>
891
892
893
894
<!--
895
        <question id="perf-mem" when="final">
896
            How much memory does your component consume? Estimate
897
            with a relation to the number of windows, etc.
898
        </question>
899
-->
900
 <answer id="perf-mem">
901
  <p>
902
   No significant memory consumption. Only line indent strings are reasonably cached.
903
  </p>
904
 </answer>
905
906
907
908
<!--
909
        <question id="perf-menus" when="final">
910
            Does your module use dynamically updated context menus, or
911
            context-sensitive actions with complicated and slow enablement logic?
912
            <hint>
913
                If you do a lot of tricks when adding actions to regular or context menus, you can significantly
914
                slow down display of the menu, even when the user is not using your action. Pay attention to
915
                actions you add to the main menu bar, and to context menus of foreign nodes or components. If
916
                the action is conditionally enabled, or changes its display dynamically, you need to check the
917
                impact on performance. In some cases it may be more appropriate to make a simple action that is
918
                always enabled but does more detailed checks in a dialog if it is actually run.
919
            </hint>
920
        </question>
921
-->
922
 <answer id="perf-menus">
923
  <p>
924
   No.
925
  </p>
926
 </answer>
927
928
929
930
<!--
931
        <question id="perf-progress" when="final">
932
            Does your module execute any long-running tasks?
933
            
934
            <hint>Long running tasks should never block 
935
            AWT thread as it badly hurts the UI
936
            <a href="http://performance.netbeans.org/responsiveness/issues.html">
937
            responsiveness</a>.
938
            Tasks like connecting over
939
            network, computing huge amount of data, compilation
940
            be done asynchronously (for example
941
            using <code>RequestProcessor</code>), definitively it should 
942
            not block AWT thread.
943
            </hint>
944
        </question>
945
-->
946
 <answer id="perf-progress">
947
  <p>
948
   Reformatting or reindentation of a large block of text can be time-consuming.
949
   <br/>
950
   The API is however not tied to be called in AWT thread only so the caller may reschedule
951
   the processing into another thread. It should ensure that the user won't be typing
952
   (or otherwise modifying) the document being reformatted.
953
  </p>
954
 </answer>
955
956
957
958
<!--
959
        <question id="perf-scale" when="init">
960
            Which external criteria influence the performance of your
961
            program (size of file in editor, number of files in menu, 
962
            in source directory, etc.) and how well your code scales?
963
            <hint>
964
            Please include some estimates, there are other more detailed 
965
            questions to answer in later phases of implementation. 
966
            </hint>
967
        </question>
968
-->
969
 <answer id="perf-scale">
970
  <p>
971
   Size of the code block being reformatted and complexity of the reformatters.
972
  </p>
973
 </answer>
974
975
976
977
<!--
978
        <question id="perf-spi" when="init">
979
            How the performance of the plugged in code will be enforced?
980
            <hint>
981
            If you allow foreign code to be plugged into your own module, how
982
            do you enforce that it will behave correctly and quickly and will not
983
            negatively influence the performance of your own module?
984
            </hint>
985
        </question>
986
-->
987
 <answer id="perf-spi">
988
  <p>
989
   The plugged in code should control its complexity. The indentation infrastructure
990
   may provide a logger for displaying of the time spent in the reformatting
991
   and reindenting tasks.
992
  </p>
993
 </answer>
994
995
996
997
<!--
998
        <question id="perf-startup" when="final">
999
            Does your module run any code on startup?
1000
        </question>
1001
-->
1002
 <answer id="perf-startup">
1003
  <p>
1004
   No.
1005
  </p>
1006
 </answer>
1007
1008
1009
1010
<!--
1011
        <question id="perf-wakeup" when="final">
1012
            Does any piece of your code wake up periodically and do something
1013
            even when the system is otherwise idle (no user interaction)?
1014
        </question>
1015
-->
1016
 <answer id="perf-wakeup">
1017
  <p>
1018
   No.
1019
  </p>
1020
 </answer>
1021
1022
1023
1024
<!--
1025
        <question id="resources-file" when="final">
1026
            Does your module use <code>java.io.File</code> directly?
1027
            
1028
            <hint>
1029
            NetBeans provide a logical wrapper over plain files called 
1030
            <code>org.openide.filesystems.FileObject</code> that
1031
            provides uniform access to such resources and is the preferred
1032
            way that should be used. But of course there can be situations when
1033
            this is not suitable.
1034
            </hint>
1035
        </question>
1036
-->
1037
 <answer id="resources-file">
1038
  <p>
1039
   No.
1040
  </p>
1041
 </answer>
1042
1043
1044
1045
<!--
1046
        <question id="resources-layer" when="final">
1047
            Does your module provide own layer? Does it create any files or
1048
            folders in it? What it is trying to communicate by that and with which 
1049
            components?
1050
            
1051
            <hint>
1052
            NetBeans allows automatic and declarative installation of resources 
1053
            by module layers. Module register files into appropriate places
1054
            and other components use that information to perform their task
1055
            (build menu, toolbar, window layout, list of templates, set of
1056
            options, etc.). 
1057
            </hint>
1058
        </question>
1059
-->
1060
 <answer id="resources-layer">
1061
  <p>
1062
   No.
1063
  </p>
1064
 </answer>
1065
1066
1067
1068
<!--
1069
        <question id="resources-mask" when="final">
1070
            Does your module mask/hide/override any resources provided by other modules in
1071
            their layers?
1072
            
1073
            <hint>
1074
            If you mask a file provided by another module, you probably depend
1075
            on that and do not want the other module to (for example) change
1076
            the file's name. That module shall thus make that file available as an API
1077
            of some stability category.
1078
            </hint>
1079
        </question>
1080
-->
1081
 <answer id="resources-mask">
1082
  <p>
1083
   No.
1084
  </p>
1085
 </answer>
1086
1087
1088
1089
<!--
1090
        <question id="resources-preferences" when="final">
1091
            Does your module uses preferences via Preferences API? Does your module use NbPreferences or
1092
            or regular JDK Preferences ? Does it read, write or both ? 
1093
            Does it share preferences with other modules ? If so, then why ?
1094
            <hint>
1095
                You may use
1096
                    &lt;api type="export" group="preferences"
1097
                    name="preference node name" category="private"&gt;
1098
                    description of individual keys, where it is used, what it
1099
                    influences, whether the module reads/write it, etc.
1100
                    &lt;/api&gt;
1101
                Due to XML ID restrictions, rather than /org/netbeans/modules/foo give the "name" as org.netbeans.modules.foo.
1102
                Note that if you use NbPreferences this name will then be the same as the code name base of the module.
1103
            </hint>
1104
        </question>
1105
-->
1106
 <answer id="resources-preferences">
1107
  <p>
1108
   No.
1109
  </p>
1110
 </answer>
1111
1112
1113
1114
<!--
1115
        <question id="resources-read" when="final">
1116
            Does your module read any resources from layers? For what purpose?
1117
            
1118
            <hint>
1119
            As this is some kind of intermodule dependency, it is a kind of API.
1120
            Please describe it and classify according to 
1121
            <a href="http://openide.netbeans.org/tutorial/api-design.html#categories">
1122
            common stability categories</a>.
1123
            </hint>
1124
        </question>
1125
-->
1126
 <answer id="resources-read">
1127
  <p>
1128
   Not directly. Only through MimeLookup.
1129
  </p>
1130
 </answer>
1131
1132
1133
1134
<!--
1135
        <question id="security-grant" when="final">
1136
            Does your code grant additional rights to some other code?
1137
            <hint>Avoid using a class loader that adds extra
1138
            permissions to loaded code unless really necessary.
1139
            Also note that your API implementation
1140
            can also expose unneeded permissions to enemy code by
1141
            calling AccessController.doPrivileged().</hint>
1142
        </question>
1143
-->
1144
 <answer id="security-grant">
1145
  <p>
1146
   No.
1147
  </p>
1148
 </answer>
1149
1150
1151
1152
<!--
1153
        <question id="security-policy" when="final">
1154
            Does your functionality require modifications to the standard policy file?
1155
            <hint>Your code might pass control to third-party code not
1156
            coming from trusted domains. This could be code downloaded over the
1157
            network or code coming from libraries that are not bundled
1158
            with NetBeans. Which permissions need to be granted to which domains?</hint>
1159
        </question>
1160
-->
1161
 <answer id="security-policy">
1162
  <p>
1163
   No.
1164
  </p>
1165
 </answer>
1166
1167
</api-answers>
(-)indent/build.xml (+23 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!--
3
The contents of this file are subject to the terms of the Common Development
4
and Distribution License (the License). You may not use this file except in
5
compliance with the License.
6
7
You can obtain a copy of the License at http://www.netbeans.org/cddl.html
8
or http://www.netbeans.org/cddl.txt.
9
10
When distributing Covered Code, include this CDDL Header Notice in each file
11
and include the License file at http://www.netbeans.org/cddl.txt.
12
If applicable, add the following below the CDDL Header, with the fields
13
enclosed by brackets [] replaced by your own identifying information:
14
"Portions Copyrighted [year] [name of copyright owner]"
15
16
The Original Software is NetBeans. The Initial Developer of the Original
17
Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
18
Microsystems, Inc. All Rights Reserved.
19
-->
20
21
<project name="editor/indent" default="netbeans" basedir=".">
22
    <import file="../../nbbuild/templates/projectized.xml"/>
23
</project>
(-)indent/manifest.mf (+4 lines)
Added Link Here
1
Manifest-Version: 1.0
2
OpenIDE-Module: org.netbeans.modules.editor.indent/1
3
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/editor/indent/Bundle.properties
4
OpenIDE-Module-Layer: org/netbeans/modules/editor/indent/resources/layer.xml
(-)indent/nbproject/.cvsignore (+1 lines)
Added Link Here
1
private
(-)indent/nbproject/project.properties (+24 lines)
Added Link Here
1
# The contents of this file are subject to the terms of the Common Development
2
# and Distribution License (the License). You may not use this file except in
3
# compliance with the License.
4
#
5
# You can obtain a copy of the License at http://www.netbeans.org/cddl.html
6
# or http://www.netbeans.org/cddl.txt.
7
#
8
# When distributing Covered Code, include this CDDL Header Notice in each file
9
# and include the License file at http://www.netbeans.org/cddl.txt.
10
# If applicable, add the following below the CDDL Header, with the fields
11
# enclosed by brackets [] replaced by your own identifying information:
12
# "Portions Copyrighted [year] [name of copyright owner]"
13
#
14
# The Original Software is NetBeans. The Initial Developer of the Original
15
# Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
16
# Microsystems, Inc. All Rights Reserved.
17
18
javac.source=1.5
19
javac.compilerargs=-Xlint:unchecked
20
spec.version.base=1.0
21
22
javadoc.arch=${basedir}/arch.xml
23
javadoc.apichanges=${basedir}/apichanges.xml
24
javadoc.title=Editor Indentation
(-)indent/nbproject/project.xml (+98 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!--
3
The contents of this file are subject to the terms of the Common Development
4
and Distribution License (the License). You may not use this file except in
5
compliance with the License.
6
7
You can obtain a copy of the License at http://www.netbeans.org/cddl.html
8
or http://www.netbeans.org/cddl.txt.
9
10
When distributing Covered Code, include this CDDL Header Notice in each file
11
and include the License file at http://www.netbeans.org/cddl.txt.
12
If applicable, add the following below the CDDL Header, with the fields
13
enclosed by brackets [] replaced by your own identifying information:
14
"Portions Copyrighted [year] [name of copyright owner]"
15
16
The Original Software is NetBeans. The Initial Developer of the Original
17
Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
18
Microsystems, Inc. All Rights Reserved.
19
-->
20
<project xmlns="http://www.netbeans.org/ns/project/1">
21
    <type>org.netbeans.modules.apisupport.project</type>
22
    <configuration>
23
        <data xmlns="http://www.netbeans.org/ns/nb-module-project/2">
24
            <code-name-base>org.netbeans.modules.editor.indent</code-name-base>
25
            <module-dependencies>
26
                <dependency>
27
                    <code-name-base>org.netbeans.modules.editor.lib</code-name-base>
28
                    <build-prerequisite/>
29
                    <compile-dependency/>
30
                    <run-dependency>
31
                        <release-version>1</release-version>
32
                        <implementation-version/>
33
                    </run-dependency>
34
                </dependency>
35
                <dependency>
36
                    <code-name-base>org.netbeans.modules.editor.mimelookup</code-name-base>
37
                    <build-prerequisite/>
38
                    <compile-dependency/>
39
                    <run-dependency>
40
                        <release-version>1</release-version>
41
                        <specification-version>1.5</specification-version>
42
                    </run-dependency>
43
                </dependency>
44
                <dependency>
45
                    <code-name-base>org.netbeans.modules.editor.util</code-name-base>
46
                    <build-prerequisite/>
47
                    <compile-dependency/>
48
                    <run-dependency>
49
                        <release-version>1</release-version>
50
                        <specification-version>1.17</specification-version>
51
                    </run-dependency>
52
                </dependency>
53
                <dependency>
54
                    <code-name-base>org.netbeans.modules.lexer</code-name-base>
55
                    <build-prerequisite/>
56
                    <compile-dependency/>
57
                    <run-dependency>
58
                        <release-version>2</release-version>
59
                        <specification-version>1.19</specification-version>
60
                    </run-dependency>
61
                </dependency>
62
                <dependency>
63
                    <code-name-base>org.openide.util</code-name-base>
64
                    <build-prerequisite/>
65
                    <compile-dependency/>
66
                    <run-dependency>
67
                        <specification-version>7.9</specification-version>
68
                    </run-dependency>
69
                </dependency>
70
            </module-dependencies>
71
            <test-dependencies>
72
                <test-type>
73
                    <name>unit</name>
74
                    <test-dependency>
75
                        <code-name-base>org.netbeans.modules.editor.indent</code-name-base>
76
                        <recursive/>
77
                        <compile-dependency/>
78
                    </test-dependency>
79
                    <test-dependency>
80
                        <code-name-base>org.netbeans.modules.editor</code-name-base>
81
                        <compile-dependency/>
82
                    </test-dependency>
83
                    <test-dependency>
84
                        <code-name-base>org.netbeans.modules.editor.lib</code-name-base>
85
                        <compile-dependency/>
86
                    </test-dependency>
87
                </test-type>
88
                <test-type>
89
                    <name>qa-functional</name>
90
                </test-type>
91
            </test-dependencies>
92
            <public-packages>
93
                <package>org.netbeans.api.editor.indent</package>
94
                <package>org.netbeans.spi.editor.indent</package>
95
            </public-packages>
96
        </data>
97
    </configuration>
98
</project>
(-)indent/src/META-INF/services/org.netbeans.modules.editor.lib.FormatterOverride (+1 lines)
Added Link Here
1
org.netbeans.modules.editor.indent.FormatterOverrideImpl
(-)indent/src/org/netbeans/api/editor/indent/Indent.java (+149 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.api.editor.indent;
21
22
import javax.swing.text.BadLocationException;
23
import javax.swing.text.Document;
24
import org.netbeans.modules.editor.indent.IndentImpl;
25
26
/**
27
 * Reindentation of a single or multiple lines in the document
28
 * means fixing of the line's indent only but does not do any other
29
 * code beautification.
30
 * <br/>
31
 * The following pattern should be used:
32
 * <pre>
33
 * indent.lock();
34
 * try {
35
 *     doc.atomicLock();
36
 *     try {
37
 *         indent.reindent(...);
38
 *     } finally {
39
 *         doc.atomicUnlock();
40
 *     }
41
 * } finally {
42
 *     indent.unlock();
43
 * }
44
 * </pre>
45
 *
46
 * @author Miloslav Metelka
47
 */
48
public final class Indent {
49
    
50
    /**
51
     *  Get the indentation for the given document.
52
     * 
53
     * @param doc non-null document.
54
     * @return non-null indentation.
55
     */
56
    public static Indent get(Document doc) {
57
        IndentImpl indentImpl = IndentImpl.get(doc);
58
        Indent indent = indentImpl.getIndent();
59
        if (indent == null) {
60
            indent = new Indent(indentImpl);
61
            indentImpl.setIndent(indent);
62
        }
63
        return indent;
64
    }
65
    
66
    private final IndentImpl impl;
67
    
68
    private Indent(IndentImpl impl) {
69
        this.impl = impl;
70
    }
71
    
72
    /**
73
     * Clients should call this method before acquiring of document's write lock.
74
     * <br/>
75
     * The following pattern should be used:
76
     * <pre>
77
     * indent.lock();
78
     * try {
79
     *     doc.atomicLock();
80
     *     try {
81
     *         indent.reindent(...);
82
     *     } finally {
83
     *         doc.atomicUnlock();
84
     *     }
85
     * } finally {
86
     *     indent.unlock();
87
     * }
88
     * </pre>
89
     */
90
    public void lock() {
91
        impl.indentLock();
92
    }
93
    
94
    /**
95
     * Clients should call this method after releasing of document's write lock.
96
     * <br/>
97
     * The following pattern should be used:
98
     * <pre>
99
     * indent.lock();
100
     * try {
101
     *     doc.atomicLock();
102
     *     try {
103
     *         indent.reindent(...);
104
     *     } finally {
105
     *         doc.atomicUnlock();
106
     *     }
107
     * } finally {
108
     *     indent.unlock();
109
     * }
110
     * </pre>
111
     */
112
    public void unlock() {
113
        impl.indentUnlock();
114
    }
115
    
116
    /**
117
     * Correct indentation on a single line determined by the given offset.
118
     * <br/>
119
     * Typically it is called after newline gets inserted
120
     * or when a line is reindented explicitly (e.g. by pressing TAB key in emacs mode).
121
     * <br/>
122
     * This method will fallback to the editor formatting infrastructure
123
     * in case there are no registered indent or reformat factories.
124
     * 
125
     * @param offset &gt;=0 any offset on the line to be reformatted.
126
     * @throws BadLocationException in case the indenter attempted to insert/remove
127
     *  at an invalid offset or e.g. into a guarded section.
128
     */
129
    public void reindent(int offset) throws BadLocationException {
130
        reindent(offset, offset);
131
    }
132
133
    /**
134
     * Correct indentation of all lines in the given offset range.
135
     * <br/>
136
     * This method will fallback to the editor formatting infrastructure
137
     * in case there are no registered indent or reformat factories.
138
     * 
139
     * @param startOffset &gt;=0 any offset on a first line to be reformatted.
140
     * @param endOffset &gt;=startOffset any offset (including end offset) 
141
     *   on a last line to be reformatted.
142
     * @throws BadLocationException in case the indenter attempted to insert/remove
143
     *  at an invalid offset or e.g. into a guarded section.
144
     */
145
    public void reindent(int startOffset, int endOffset) throws BadLocationException {
146
        impl.reindent(startOffset, endOffset);
147
    }
148
149
}
(-)indent/src/org/netbeans/api/editor/indent/IndentUtils.java (+240 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.api.editor.indent;
21
22
import javax.swing.text.BadLocationException;
23
import javax.swing.text.Document;
24
import javax.swing.text.Element;
25
import javax.swing.text.PlainDocument;
26
import org.netbeans.editor.BaseDocument;
27
import org.netbeans.editor.BaseKit;
28
import org.netbeans.editor.Formatter;
29
import org.netbeans.editor.Settings;
30
import org.netbeans.editor.SettingsNames;
31
import org.netbeans.lib.editor.util.ArrayUtilities;
32
import org.netbeans.lib.editor.util.swing.DocumentUtilities;
33
import org.netbeans.modules.editor.indent.IndentImpl;
34
35
/**
36
 * Utility methods related to indentation and reformatting.
37
 *
38
 * @author Miloslav Metelka
39
 */
40
public final class IndentUtils {
41
    
42
    private static final int MAX_CACHED_INDENT = 80;
43
    
44
    private static final String[] cachedSpacesStrings = new String[MAX_CACHED_INDENT + 1];
45
    static {
46
        cachedSpacesStrings[0] = "";
47
    }
48
    
49
    private static final int MAX_CACHED_TAB_SIZE = 8; // Should mostly be <= 8
50
    
51
    /**
52
     * Cached indentation string containing tabs.
53
     * <br/>
54
     * The cache does not contain indents smaller than the particular tabSize
55
     * since they are only spaces contained in cachedSpacesStrings.
56
     */
57
    private static final String[][] cachedTabIndents = new String[MAX_CACHED_TAB_SIZE][];
58
    
59
    private IndentUtils() {
60
        // no instances
61
    }
62
    
63
    /**
64
     * Get number of spaces that form a single indentation level.
65
     * 
66
     * @return &gt;=0 size of indentation level in spaces.
67
     */
68
    public static int indentLevelSize(Document doc) {
69
        int indentLevel;
70
        if (doc instanceof BaseDocument) {
71
            indentLevel = ((BaseDocument)doc).getShiftWidth();
72
        } else {
73
            Object val = Settings.getValue(BaseKit.class, SettingsNames.INDENT_SHIFT_WIDTH);
74
            indentLevel = (val instanceof Integer) ? ((Integer)val).intValue() : tabSize(doc);
75
        }
76
        return indentLevel;
77
    }
78
79
    /**
80
     * Get number of spaces that visually substitute '\t' character.
81
     * 
82
     * @return &gt;=0 size corresponding to '\t' character in spaces.
83
     */
84
    public static int tabSize(Document doc) {
85
        int tabSize;
86
        if (doc instanceof BaseDocument) {
87
            tabSize = ((BaseDocument)doc).getTabSize();
88
        } else {
89
            Object val = doc.getProperty(PlainDocument.tabSizeAttribute);
90
            tabSize = (val instanceof Integer) ? ((Integer)val).intValue() : 8;
91
        }
92
        assert (tabSize >= 0) : "Retrieved tabSize=" + tabSize + " < 0"; // NOI18N
93
        return tabSize;
94
    }
95
96
    /**
97
     * Get whether the indentation strings should contain hard tabs '\t'
98
     * or whether they should only contain spaces.
99
     * 
100
     * @return true if the tabs should be expanded or false if not.
101
     */
102
    public static boolean isExpandTabs(Document doc) {
103
        if (doc instanceof BaseDocument) {
104
            Formatter formatter = ((BaseDocument)doc).getFormatter();
105
            return (formatter != null) ? formatter.expandTabs() : true;
106
        } else
107
            return true;
108
    }
109
    
110
    /**
111
     * Get start offset of a line in a document.
112
     * 
113
     * @param doc non-null document.
114
     * @param offset &gt;= 0 offset anywhere on the line.
115
     * @throws BadLocationException for invalid offset
116
     */
117
    public static int lineStartOffset(Document doc, int offset) throws BadLocationException {
118
        checkOffsetInDocument(doc, offset);
119
        Element lineRootElement = IndentImpl.lineRootElement(doc);
120
        return lineRootElement.getElement(lineRootElement.getElementIndex(offset)).getStartOffset();
121
    }
122
123
    /**
124
     * Get indentation of a line in a document as a number of spaces.
125
     * 
126
     * @param doc non-null document.
127
     * @param lineStartOffset &gt;= 0 start offset of a line in the document.
128
     * @throws BadLocationException for invalid offset
129
     */
130
    public static int lineIndent(Document doc, int lineStartOffset) throws BadLocationException {
131
        checkOffsetInDocument(doc, lineStartOffset);
132
        CharSequence docText = DocumentUtilities.getText(doc);
133
        int indent = 0;
134
        int tabSize = -1;
135
        while (lineStartOffset < docText.length()) {
136
            char ch;
137
            switch (ch = docText.charAt(lineStartOffset)) {
138
                case '\n':
139
                    return indent;
140
141
                case '\t':
142
                    if (tabSize == -1)
143
                        tabSize = tabSize(doc);
144
                    // Round to next tab stop
145
                    indent = (indent + tabSize) / tabSize * tabSize;
146
147
                default:
148
                    if (Character.isWhitespace(ch))
149
                        indent++;
150
                    else
151
                        return indent;
152
            }
153
        }
154
        return indent;
155
    }
156
    
157
    /**
158
     * Create (or get from cache) indentation string for the given indent.
159
     * <br/>
160
     * The indentation settings (tab-size etc. are determined based on the given
161
     * document).
162
     * 
163
     * @param doc document from which the indentation settings will be retrieved.
164
     * @param indent &gt;=0 indentation in number of spaces.
165
     * @return indentation string containing tabs and spaces according to the document's
166
     *  settings (tab-size etc.).
167
     */
168
    public static String createIndentString(Document doc, int indent) {
169
        if (indent < 0)
170
            throw new IllegalArgumentException("indent=" + indent + " < 0"); // NOI18N
171
        return cachedOrCreatedIndentString(indent, isExpandTabs(doc), tabSize(doc));
172
    }
173
    
174
    static String cachedOrCreatedIndentString(int indent, boolean expandTabs, int tabSize) {
175
        String indentString;
176
        if (expandTabs || (indent < tabSize)) {
177
            if (indent <= MAX_CACHED_INDENT) {
178
                synchronized (cachedSpacesStrings) {
179
                    indentString = cachedSpacesStrings[indent];
180
                    if (indentString == null) {
181
                        // Create string with MAX_CACHED_SPACES spaces first if not cached yet
182
                        indentString = cachedSpacesStrings[MAX_CACHED_INDENT];
183
                        if (indentString == null) {
184
                            indentString = createSpacesString(MAX_CACHED_INDENT);
185
                            cachedSpacesStrings[MAX_CACHED_INDENT] = indentString;
186
                        }
187
                        indentString = indentString.substring(0, indent);
188
                        cachedSpacesStrings[indent] = indentString;
189
                    }
190
                }
191
            } else {
192
                indentString = createSpacesString(indent);
193
            }
194
195
        } else { // Do not expand tabs
196
            if (indent <= MAX_CACHED_INDENT && tabSize <= MAX_CACHED_TAB_SIZE) {
197
                synchronized (cachedTabIndents) {
198
                    String[] tabIndents = cachedTabIndents[tabSize];
199
                    if (tabIndents == null) {
200
                        // Do not cache spaces-only strings
201
                        tabIndents = new String[MAX_CACHED_INDENT - tabSize];
202
                        cachedTabIndents[tabSize] = tabIndents;
203
                    }
204
                    indentString = tabIndents[indent - tabSize];
205
                    if (indentString == null) {
206
                        indentString = createTabIndentString(indent, tabSize);
207
                        tabIndents[indent - tabSize] = indentString;
208
                    }
209
                }
210
            } else {
211
                indentString = createTabIndentString(indent, tabSize);
212
            }
213
        }
214
        return indentString;
215
    }
216
    
217
    private static String createSpacesString(int spaceCount) {
218
        StringBuilder sb = new StringBuilder(spaceCount);
219
        ArrayUtilities.appendSpaces(sb, spaceCount);
220
        return sb.toString();
221
    }
222
    
223
    private static String createTabIndentString(int indent, int tabSize) {
224
        StringBuilder sb = new StringBuilder();
225
        while (indent >= tabSize) {
226
            sb.append('\t');
227
            indent -= tabSize;
228
        }
229
        ArrayUtilities.appendSpaces(sb, indent);
230
        return sb.toString();
231
    }
232
    
233
    private static void checkOffsetInDocument(Document doc, int offset) throws BadLocationException {
234
        if (offset < 0)
235
            throw new BadLocationException("offset=" + offset + " < 0", offset); // NOI18N
236
        if (offset > doc.getLength())
237
            throw new BadLocationException("offset=" + offset + " > doc.getLength()=" + doc.getLength(), offset);
238
    }
239
240
}
(-)indent/src/org/netbeans/api/editor/indent/Reformat.java (+132 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.api.editor.indent;
21
22
import javax.swing.text.BadLocationException;
23
import javax.swing.text.Document;
24
import org.netbeans.modules.editor.indent.IndentImpl;
25
26
/**
27
 * Reformatting of a block of code in a document.
28
 * <br/>
29
 * The following pattern should be used:
30
 * <pre>
31
 * reformat.lock();
32
 * try {
33
 *     doc.atomicLock();
34
 *     try {
35
 *         reformat.reformat(...);
36
 *     } finally {
37
 *         doc.atomicUnlock();
38
 *     }
39
 * } finally {
40
 *     reformat.unlock();
41
 * }
42
 * </pre>
43
 *
44
 * @author Miloslav Metelka
45
 */
46
public final class Reformat {
47
    
48
    /**
49
     *  Get the reformatting for the given document.
50
     * 
51
     * @param doc non-null document.
52
     * @return non-null reformat object.
53
     */
54
    public static Reformat get(Document doc) {
55
        IndentImpl indentImpl = IndentImpl.get(doc);
56
        Reformat reformat = indentImpl.getReformat();
57
        if (reformat == null) {
58
            reformat = new Reformat(indentImpl);
59
            indentImpl.setReformat(reformat);
60
        }
61
        return reformat;
62
    }
63
    
64
    private final IndentImpl impl;
65
    
66
    private Reformat(IndentImpl impl) {
67
        this.impl = impl;
68
    }
69
    
70
    /**
71
     * Clients should call this method before acquiring of document's write lock.
72
     * <br/>
73
     * The following pattern should be used:
74
     * <pre>
75
     * reformat.lock();
76
     * try {
77
     *     doc.atomicLock();
78
     *     try {
79
     *         reformat.reformat(...);
80
     *     } finally {
81
     *         doc.atomicUnlock();
82
     *     }
83
     * } finally {
84
     *     reformat.unlock();
85
     * }
86
     * </pre>
87
     */
88
    public void lock() {
89
        impl.reformatLock();
90
    }
91
    
92
    /**
93
     * Clients should call this method after releasing of document's write lock.
94
     * <br/>
95
     * The following pattern should be used:
96
     * <pre>
97
     * reformat.lock();
98
     * try {
99
     *     doc.atomicLock();
100
     *     try {
101
     *         reformat.reformat(...);
102
     *     } finally {
103
     *         doc.atomicUnlock();
104
     *     }
105
     * } finally {
106
     *     reformat.unlock();
107
     * }
108
     * </pre>
109
     */
110
    public void unlock() {
111
        impl.reformatUnlock();
112
    }
113
    
114
    /**
115
     * Reformat a given range of code in the given document.
116
     * <br/>
117
     * It includes possible fixing of indentation and possible code beautification
118
     * dependent on the implementation of the reformatter.
119
     * 
120
     * <p>
121
     * If the reformatter implementation is not available the reindentation
122
     * will be performed (i.e. just the line indentation will be fixed)
123
     * as a closest match.
124
     * 
125
     * @param startOffset start offset of the area to be reformatted.
126
     * @param endOffset end offset of the area to be reformatted.
127
     */
128
    public void reformat(int startOffset, int endOffset) throws BadLocationException {
129
        impl.reformat(startOffset, endOffset);
130
    }
131
132
}
(-)indent/src/org/netbeans/modules/editor/indent/Bundle.properties (+22 lines)
Added Link Here
1
# The contents of this file are subject to the terms of the Common Development
2
# and Distribution License (the License). You may not use this file except in
3
# compliance with the License.
4
#
5
# You can obtain a copy of the License at http://www.netbeans.org/cddl.html
6
# or http://www.netbeans.org/cddl.txt.
7
#
8
# When distributing Covered Code, include this CDDL Header Notice in each file
9
# and include the License file at http://www.netbeans.org/cddl.txt.
10
# If applicable, add the following below the CDDL Header, with the fields
11
# enclosed by brackets [] replaced by your own identifying information:
12
# "Portions Copyrighted [year] [name of copyright owner]"
13
#
14
# The Original Software is NetBeans. The Initial Developer of the Original
15
# Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
16
# Microsystems, Inc. All Rights Reserved.
17
18
OpenIDE-Module-Name=Editor Indentation
19
OpenIDE-Module-Display-Category=Editing
20
OpenIDE-Module-Short-Description=Contains indentation APIs and SPIs.
21
OpenIDE-Module-Long-Description=The module includes indenation and code formatting APIs and infrastructure.
22
(-)indent/src/org/netbeans/modules/editor/indent/FormatterImpl.java (+122 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.modules.editor.indent;
21
22
import java.io.IOException;
23
import java.io.Writer;
24
import javax.swing.text.BadLocationException;
25
import javax.swing.text.Document;
26
import javax.swing.text.JTextComponent;
27
import org.netbeans.editor.BaseDocument;
28
import org.netbeans.editor.Formatter;
29
import org.netbeans.editor.GuardedException;
30
import org.netbeans.editor.ext.ExtFormatter;
31
import org.netbeans.spi.editor.indent.Context;
32
33
/**
34
 * Indentation and code reformatting services for a swing text document.
35
 *
36
 * @author Miloslav Metelka
37
 */
38
public final class FormatterImpl extends ExtFormatter {
39
    
40
    private Formatter defaultFormatter;
41
    
42
    private IndentImpl indentImpl;
43
    
44
    FormatterImpl(Formatter defaultFormatter, Document doc) {
45
        super(defaultFormatter.getKitClass());
46
        this.indentImpl = IndentImpl.get(doc);
47
    }
48
    
49
    public int[] getReformatBlock(JTextComponent target, String typedText) {
50
        return (defaultFormatter instanceof ExtFormatter)
51
                ? ((ExtFormatter)defaultFormatter).getReformatBlock(target, typedText)
52
                : null;
53
    }
54
    
55
    public void indentLock() {
56
        indentImpl.indentLock();
57
    }
58
    
59
    public void indentUnlock() {
60
        indentImpl.indentUnlock();
61
    }
62
    
63
    public void reformatLock() {
64
        indentImpl.reformatLock();
65
    }
66
    
67
    public void reformatUnlock() {
68
        indentImpl.reformatUnlock();
69
    }
70
71
    public int indentLine(Document doc, int offset) {
72
        try {
73
            indentImpl.reindent(offset, offset);
74
            return offset;
75
        } catch (GuardedException e) {
76
            java.awt.Toolkit.getDefaultToolkit().beep();
77
        } catch (BadLocationException e) {
78
            throw new IllegalStateException(e);
79
        }
80
        return offset;
81
    }
82
83
    /** Inserts new line at given position and indents the new line with
84
    * spaces.
85
    *
86
    * @param doc the document to work on
87
    * @param offset the offset of a character on the line
88
    * @return new offset to place cursor to
89
    */
90
    public int indentNewLine(Document doc, int offset) {
91
        try {
92
            doc.insertString(offset, "\n", null); // NOI18N
93
            offset++;
94
            return indentLine(doc, offset);
95
        } catch (GuardedException e) {
96
            java.awt.Toolkit.getDefaultToolkit().beep();
97
        } catch (BadLocationException e) {
98
            throw new IllegalStateException(e);
99
        }
100
        return offset;
101
    }
102
103
    public Writer reformat(BaseDocument doc, int startOffset, int endOffset,
104
    boolean indentOnly) throws BadLocationException, IOException {
105
        // TBD delegate somehow
106
        return (defaultFormatter instanceof ExtFormatter)
107
                ? ((ExtFormatter)defaultFormatter).reformat(doc, startOffset, endOffset, indentOnly)
108
                : null;
109
    }
110
    
111
    public int reformat(BaseDocument doc, int startOffset, int endOffset)
112
    throws BadLocationException {
113
        if (doc != indentImpl.document())
114
            return endOffset - startOffset; // should not happen in reality
115
        indentImpl.reformat(startOffset, endOffset);
116
        Context ctx = indentImpl.reformatContext();
117
        return (ctx != null)
118
                ? ctx.endOffset() - ctx.startOffset()
119
                : endOffset - startOffset;
120
    }
121
122
}
(-)indent/src/org/netbeans/modules/editor/indent/FormatterOverrideImpl.java (+41 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.modules.editor.indent;
21
22
import javax.swing.text.Document;
23
import org.netbeans.editor.Formatter;
24
import org.netbeans.modules.editor.lib.FormatterOverride;
25
26
/**
27
 * Indentation and code reformatting services for a swing text document.
28
 *
29
 * @author Miloslav Metelka
30
 */
31
public final class FormatterOverrideImpl implements FormatterOverride {
32
33
    public Formatter getFormatter(Document doc, Formatter defaultFormatter) {
34
        IndentImpl indentImpl = IndentImpl.get(doc);
35
        if (indentImpl.hasIndentOrReformatFactories()) {
36
            defaultFormatter = new FormatterImpl(defaultFormatter, doc);
37
        }
38
        return defaultFormatter;
39
    }
40
41
}
(-)indent/src/org/netbeans/modules/editor/indent/IndentImpl.java (+406 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.modules.editor.indent;
21
22
import java.util.ArrayList;
23
import java.util.HashMap;
24
import java.util.List;
25
import java.util.Map;
26
import java.util.Set;
27
import java.util.logging.Logger;
28
import javax.swing.text.BadLocationException;
29
import javax.swing.text.Document;
30
import javax.swing.text.Element;
31
import javax.swing.text.StyledDocument;
32
import org.netbeans.api.editor.indent.Indent;
33
import org.netbeans.api.editor.indent.Reformat;
34
import org.netbeans.api.editor.mimelookup.MimeLookup;
35
import org.netbeans.api.editor.mimelookup.MimePath;
36
import org.netbeans.api.lexer.LanguagePath;
37
import org.netbeans.api.lexer.TokenHierarchy;
38
import org.netbeans.editor.BaseDocument;
39
import org.netbeans.spi.editor.indent.Context;
40
import org.netbeans.spi.editor.indent.ExtraLock;
41
import org.netbeans.spi.editor.indent.IndentTask;
42
import org.netbeans.spi.editor.indent.ReformatTask;
43
import org.openide.util.Lookup;
44
45
/**
46
 * Indentation and code reformatting services for a swing text document.
47
 *
48
 * @author Miloslav Metelka
49
 */
50
public final class IndentImpl {
51
    
52
    // -J-Dorg.netbeans.modules.editor.indent.IndentImpl=FINE
53
    private static final Logger LOG = Logger.getLogger(IndentImpl.class.getName());
54
    
55
    public static IndentImpl get(Document doc) {
56
        IndentImpl indentImpl = (IndentImpl)doc.getProperty(IndentImpl.class);
57
        if (indentImpl == null) {
58
            indentImpl = new IndentImpl(doc);
59
            doc.putProperty(IndentImpl.class, indentImpl);
60
        }
61
        return indentImpl;
62
    }
63
    
64
    private final Document doc;
65
    
66
    private Indent indent;
67
    
68
    private Reformat reformat;
69
    
70
    private TaskHandler indentHandler;
71
    
72
    private TaskHandler reformatHandler;
73
    
74
    public IndentImpl(Document doc) {
75
        this.doc = doc;
76
    }
77
    
78
    public Document document() {
79
        return doc;
80
    }
81
    
82
    public Indent getIndent() {
83
        return indent;
84
    }
85
    
86
    public void setIndent(Indent indent) {
87
        this.indent = indent;
88
    }
89
90
    public Reformat getReformat() {
91
        return reformat;
92
    }
93
    
94
    public void setReformat(Reformat reformat) {
95
        this.reformat = reformat;
96
    }
97
    
98
    public boolean hasIndentOrReformatFactories() {
99
        return new TaskHandler(true, doc).hasFactories();
100
    }
101
    
102
    public synchronized void indentLock() {
103
        if (indentHandler != null)
104
            throw new IllegalStateException("Already locked");
105
        indentHandler = new TaskHandler(true, doc);
106
        if (indentHandler.collectTasks()) {
107
            indentHandler.lock();
108
        }
109
    }
110
    
111
    public synchronized void indentUnlock() {
112
        if (indentHandler == null)
113
            throw new IllegalStateException("Already unlocked");
114
        indentHandler.unlock();
115
        indentHandler = null;
116
    }
117
    
118
    public Context indentContext() {
119
        return indentHandler.context();
120
    }
121
    
122
    public synchronized void reformatLock() {
123
        if (reformatHandler != null)
124
            throw new IllegalStateException("Already locked");
125
        reformatHandler = new TaskHandler(false, doc);
126
        if (reformatHandler.collectTasks()) {
127
            reformatHandler.lock();
128
        }
129
    }
130
    
131
    public synchronized void reformatUnlock() {
132
        if (reformatHandler == null)
133
            throw new IllegalStateException("Already unlocked");
134
        reformatHandler.unlock();
135
        reformatHandler = null;
136
    }
137
    
138
    public Context reformatContext() {
139
        return reformatHandler.context();
140
    }
141
142
    public void reindent(int startOffset, int endOffset) throws BadLocationException {
143
        assert (indentHandler != null) : "Not locked. Use Indent.lock()"; // NOI18N
144
        assert (startOffset <= endOffset) : "startOffset=" + startOffset + " > endOffset=" + endOffset; // NOI18N
145
        // Find begining of line
146
        Element lineRootElem = lineRootElement(doc);
147
        // Correct the start offset to point to the begining of the start line
148
        int startLineIndex = lineRootElem.getElementIndex(startOffset);
149
        if (startLineIndex < 0)
150
            return; // Invalid line index => do nothing
151
        Element lineElem = lineRootElem.getElement(startLineIndex);
152
        int startLineOffset = lineElem.getStartOffset();
153
        boolean done = false;
154
        if (indentHandler.hasItems()) {
155
            // Find ending line element - by default use the same as for start offset
156
            if (endOffset > lineElem.getEndOffset()) { // need to get a different line element
157
                int endLineIndex = lineRootElem.getElementIndex(endOffset);
158
                lineElem = lineRootElem.getElement(endLineIndex);
159
                // Check if the given endOffset ends right after line's newline (in fact at the begining of the next line)
160
                if (endLineIndex > 0 && lineElem.getStartOffset() == endOffset) {
161
                    endLineIndex--;
162
                    lineElem = lineRootElem.getElement(endLineIndex);
163
                }
164
            }
165
166
            // Create context from begining of the start line till the end of the end line.
167
            IndentSpiPackageAccessor.get().resetBounds(
168
                    indentHandler.context(),
169
                    doc.createPosition(startLineOffset),
170
                    doc.createPosition(lineElem.getEndOffset()));
171
            
172
            // Perform whole reindent on top and possibly embedded levels
173
            indentHandler.runTasks();
174
            done = true;
175
        }
176
177
        // Fallback to Formatter
178
        if (!done && doc instanceof BaseDocument) {
179
            // Original formatter does not have reindentation of multiple lines
180
            // so reformat start line and continue for each line.
181
            do {
182
                ((BaseDocument)doc).getFormatter().indentLine(doc, startOffset);
183
                startOffset = lineElem.getEndOffset(); // Move to next line
184
            } while (startOffset < endOffset);
185
186
        }
187
    }
188
189
    public void reformat(int startOffset, int endOffset) throws BadLocationException {
190
        assert (reformatHandler != null) : "Not locked. Use Reformat.lock()"; // NOI18N
191
        assert (startOffset <= endOffset) : "startOffset=" + startOffset + " > endOffset=" + endOffset; // NOI18N
192
        boolean done = false;
193
        if (reformatHandler.hasItems()) {
194
            IndentSpiPackageAccessor.get().resetBounds(
195
                    reformatHandler.context(),
196
                    doc.createPosition(startOffset),
197
                    doc.createPosition(endOffset));
198
            
199
            // Run top and embedded reformatting
200
            reformatHandler.runTasks();
201
            
202
            // Perform reformatting of the top section and possible embedded sections
203
            done = true;
204
        }
205
        
206
        // Fallback to Formatter
207
        if (!done && doc instanceof BaseDocument) {
208
            BaseDocument bdoc = (BaseDocument)doc;
209
            bdoc.getFormatter().reformat(bdoc, startOffset, endOffset);
210
        }
211
    }
212
    
213
    public static Element lineRootElement(Document doc) {
214
        return (doc instanceof StyledDocument)
215
            ? ((StyledDocument)doc).getParagraphElement(0).getParentElement()
216
            : doc.getDefaultRootElement();
217
    }
218
219
    private static final class TaskHandler {
220
        
221
        private boolean indent;
222
        
223
        private Context context;
224
        
225
        private List<MimeItem> items;
226
        
227
        private Map<MimePath,MimeItem> mime2Item;
228
        
229
        private int maxMimePathSize;
230
        
231
        TaskHandler(boolean indent, Document doc) {
232
            this.indent = indent;
233
            context = IndentSpiPackageAccessor.get().createContext(indent, doc);
234
        }
235
        
236
        boolean isIndent() {
237
            return indent;
238
        }
239
        
240
        Context context() {
241
            return context;
242
        }
243
        
244
        Document document() {
245
            return context.document();
246
        }
247
        
248
        int maxMimePathSize() {
249
            return maxMimePathSize;
250
        }
251
        
252
        boolean collectTasks() {
253
            String mimeType = docMimeType();
254
            if (mimeType != null) {
255
                // Get base indent task for the document.
256
                // Only if it exists also get the ones for possible embedded sections.
257
                MimePath mimePath = MimePath.get(mimeType);
258
                if (addItem(mimePath)) {
259
                    // Also add the embedded ones
260
                    TokenHierarchy<?> hi = TokenHierarchy.get(document());
261
                    if (hi != null) {
262
                        Set<LanguagePath> languagePaths = hi.languagePaths();
263
                        for (LanguagePath lp : languagePaths) {
264
                            mimePath = MimePath.parse(lp.mimePath());
265
                            addItem(mimePath);
266
                        }
267
                    }
268
                }
269
            }
270
            return (items != null);
271
        }
272
273
        void lock() {
274
            for (MimeItem item : items) {
275
                item.lock();
276
            }
277
        }
278
279
        void unlock() {
280
            for (MimeItem item : items) {
281
                item.unlock();
282
            }
283
        }
284
        
285
        boolean hasFactories() {
286
            String mimeType = docMimeType();
287
            return (mimeType != null && new MimeItem(this, MimePath.get(mimeType)).hasFactories());
288
        }
289
        
290
        boolean hasItems() {
291
            return (items != null);
292
        }
293
        
294
        void runTasks() throws BadLocationException {
295
            // Run top-level task and possibly embedded tasks according to the context
296
            if (items == null) // Do nothing for no items
297
                return;
298
            
299
            // Start with the doc's mime type's task
300
            item(0).runTask();
301
302
            // Continue by reformatting the embedded sections from top-level to embedded
303
            int mimePathSize = 2;
304
            while (mimePathSize < maxMimePathSize) {
305
                // TBD walk the top-level token sequence and go into it
306
                mimePathSize++;
307
            }
308
309
        }
310
        
311
        private boolean addItem(MimePath mimePath) {
312
            maxMimePathSize = Math.max(maxMimePathSize, mimePath.size());
313
            MimeItem item = new MimeItem(this, mimePath);
314
            if (item.createTask()) {
315
                if (items == null) {
316
                    items = new ArrayList<MimeItem>();
317
                    mime2Item = new HashMap<MimePath,MimeItem>();
318
                }
319
                if (!mime2Item.containsKey(item.mimePath())) {
320
                    items.add(item);
321
                    mime2Item.put(item.mimePath(), item);
322
                }
323
                return true;
324
            }
325
            return false;
326
        }
327
        
328
        private MimeItem item(int index) {
329
            return items.get(index);
330
        }
331
        
332
        private String docMimeType() {
333
            return (String)document().getProperty("mimeType");
334
        }
335
        
336
    }
337
    
338
    /**
339
     * Item that services indentation/reformatting for a single mime-path.
340
     */
341
    private static final class MimeItem {
342
        
343
        private final TaskHandler handler;
344
        
345
        private final MimePath mimePath;
346
        
347
        private IndentTask indentTask;
348
        
349
        private ReformatTask reformatTask;
350
        
351
        private ExtraLock extraLock;
352
        
353
        MimeItem(TaskHandler handler, MimePath mimePath) {
354
            this.handler = handler;
355
            this.mimePath = mimePath;
356
        }
357
        
358
        MimePath mimePath() {
359
            return mimePath;
360
        }
361
        
362
        boolean hasFactories() {
363
            Lookup lookup = MimeLookup.getLookup(mimePath);
364
            return (lookup.lookup(IndentTask.Factory.class) != null)
365
                || (lookup.lookup(ReformatTask.Factory.class) != null);
366
        }
367
        
368
        boolean createTask() {
369
            Lookup lookup = MimeLookup.getLookup(mimePath);
370
            if (!handler.isIndent()) { // Attempt reformat task first
371
                ReformatTask.Factory factory = lookup.lookup(ReformatTask.Factory.class);
372
                if (factory != null && (reformatTask = factory.createTask(handler.context())) != null) {
373
                    extraLock = reformatTask.reformatLock();
374
                    return true;
375
                }
376
            }
377
            
378
            if (handler.isIndent() || reformatTask == null) { // Possibly fallback to reindent for reformatting
379
                IndentTask.Factory factory = lookup.lookup(IndentTask.Factory.class);
380
                if (factory != null && (indentTask = factory.createTask(handler.context())) != null) {
381
                    extraLock = indentTask.indentLock();
382
                    return true;
383
                }
384
            }
385
            return false;
386
        }
387
        
388
        void lock() {
389
            extraLock.lock();
390
        }
391
        
392
        void runTask() throws BadLocationException {
393
            if (indentTask != null) {
394
                indentTask.reindent();
395
            } else {
396
                reformatTask.reformat();
397
            }
398
        }
399
        
400
        void unlock() {
401
            extraLock.unlock();
402
        }
403
404
    }
405
406
}
(-)indent/src/org/netbeans/modules/editor/indent/IndentSpiPackageAccessor.java (+64 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.modules.editor.indent;
21
22
import javax.swing.text.Document;
23
import javax.swing.text.Position;
24
import org.netbeans.spi.editor.indent.Context;
25
26
/**
27
 * Accessor for the package-private functionality of bookmarks API.
28
 *
29
 * @author Miloslav Metelka
30
 * @version 1.00
31
 */
32
33
public abstract class IndentSpiPackageAccessor {
34
    
35
    private static IndentSpiPackageAccessor INSTANCE;
36
    
37
    public static IndentSpiPackageAccessor get() {
38
        if (INSTANCE == null) {
39
            // Enforce the static initializer in Context class to be run
40
            try {
41
                Class.forName(Context.class.getName(), true, Context.class.getClassLoader());
42
            } catch (ClassNotFoundException e) { }
43
        }
44
        return INSTANCE;
45
    }
46
47
    /**
48
     * Register the accessor. The method can only be called once
49
     * - othewise it throws IllegalStateException.
50
     * 
51
     * @param accessor instance.
52
     */
53
    public static void register(IndentSpiPackageAccessor accessor) {
54
        if (INSTANCE != null) {
55
            throw new IllegalStateException("Already registered"); // NOI18N
56
        }
57
        INSTANCE = accessor;
58
    }
59
    
60
    public abstract Context createContext(boolean indent, Document doc);
61
    
62
    public abstract void resetBounds(Context ctx, Position startPos, Position endPos);
63
    
64
}
(-)indent/src/org/netbeans/modules/editor/indent/resources/layer.xml (+26 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!--
3
The contents of this file are subject to the terms of the Common Development
4
and Distribution License (the License). You may not use this file except in
5
compliance with the License.
6
7
You can obtain a copy of the License at http://www.netbeans.org/cddl.html
8
or http://www.netbeans.org/cddl.txt.
9
10
When distributing Covered Code, include this CDDL Header Notice in each file
11
and include the License file at http://www.netbeans.org/cddl.txt.
12
If applicable, add the following below the CDDL Header, with the fields
13
enclosed by brackets [] replaced by your own identifying information:
14
"Portions Copyrighted [year] [name of copyright owner]"
15
16
The Original Software is NetBeans. The Initial Developer of the Original
17
Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
18
Microsystems, Inc. All Rights Reserved.
19
-->
20
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem-1_1.dtd">
21
22
23
<filesystem>
24
    <folder name="Editors">
25
    </folder>
26
</filesystem>
(-)indent/src/org/netbeans/spi/editor/indent/Context.java (+123 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.spi.editor.indent;
21
22
import javax.swing.text.Document;
23
import javax.swing.text.Position;
24
import org.netbeans.modules.editor.indent.IndentSpiPackageAccessor;
25
26
27
/**
28
 * Context information for both indentation and reformatting.
29
 * <br/>
30
 * A common class allows to conveniently share code between indentation and reformatting.
31
 * {@link #isIndent()} allows to check whether the actual processing
32
 * is indentation or reformatting.
33
 *
34
 * @author Miloslav Metelka
35
 */
36
37
public final class Context {
38
    
39
    static {
40
        IndentSpiPackageAccessor.register(new PackageAccessor());
41
    }
42
    
43
    private final boolean indent;
44
    
45
    private final Document doc;
46
    
47
    private Position startPos;
48
    
49
    private Position endPos;
50
    
51
    Context(boolean indent, Document doc) {
52
        this.indent = indent;
53
        this.doc = doc;
54
        this.startPos = startPos;
55
        this.endPos = endPos;
56
    }
57
    
58
    /**
59
     * Document for which the reformatting or indenting is being done.
60
     */
61
    public Document document() {
62
        return doc;
63
    }
64
    
65
    /**
66
     * Starting offset of the area to be reformatted or reindented.
67
     * <br/>
68
     * The value gets updated accordingly when the reformatter performs modifications
69
     * in the affected area.
70
     */
71
    public int startOffset() {
72
        return (startPos != null) ? startPos.getOffset() : -1;
73
    }
74
    
75
    /**
76
     * Starting offset of the area to be reformatted or reindented.
77
     * <br/>
78
     * The value gets updated accordingly when the reformatter performs modifications
79
     * in the affected area.
80
     */
81
    public int endOffset() {
82
        return (endPos != null) ? endPos.getOffset() : -1;
83
    }
84
    
85
    /**
86
     * Modify indent of the line at the offset passed as the parameter.
87
     */
88
    public void modifyIndent(int offset) {
89
        // TBD
90
    }
91
    
92
    /*
93
     * Check whether the actual processing
94
     * is indentation or reformatting.
95
     * 
96
     * <br/>
97
     * Indent tasks may be used for reformatting in case a reformat task
98
     * is not available (for the given mimepath) but the indent task is available.
99
     * 
100
     * @return true if indentation is being done or false for reformatting.
101
     */
102
    public boolean isIndent() {
103
        return indent;
104
    }
105
    
106
    void resetBounds(Position startPos, Position endPos) {
107
        this.startPos = startPos;
108
        this.endPos = endPos;
109
    }
110
111
    private static final class PackageAccessor extends IndentSpiPackageAccessor {
112
113
        public Context createContext(boolean indent, Document doc) {
114
            return new Context(indent, doc);
115
        }
116
        
117
        public void resetBounds(Context ctx, Position startPos, Position endPos) {
118
            ctx.resetBounds(startPos, endPos);
119
        }
120
        
121
    }
122
123
}
(-)indent/src/org/netbeans/spi/editor/indent/ExtraLock.java (+53 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.spi.editor.indent;
21
22
/**
23
 * Extra locking may be necessary for indentation/reformatting
24
 * before the document gets write-locked and the actual
25
 * indentation/reformatting gets started.
26
 * <br/>
27
 * For example java infrastructure requires this.
28
 * <br/>
29
 * The infrastructure guarantees this processing:
30
 * <pre>
31
 *   extraLock.lock();
32
 *   try {
33
 *       doc.atomicLock(); // either BaseDocument or e.g. NbDocument.runAtomic()
34
 *       try {
35
 *           // indent or reformat ...
36
 *       } finally {
37
 *           doc.atomicUnlock();
38
 *       }
39
 *   } finally {
40
 *       extraLock.unlock();
41
 *   }
42
 * </pre>
43
 *
44
 * @author Miloslav Metelka
45
 */
46
47
public interface ExtraLock {
48
49
    void lock();
50
        
51
    void unlock();
52
    
53
}
(-)indent/src/org/netbeans/spi/editor/indent/IndentTask.java (+74 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.spi.editor.indent;
21
22
import javax.swing.text.BadLocationException;
23
24
/**
25
 * Indent task performs indentation on a single or multiple lines.
26
 * <br/>
27
 * Typically it is used to fix indentation after newline was inserted
28
 * or to fix indentation for a selected block of code.
29
 *
30
 * @author Miloslav Metelka
31
 */
32
33
public interface IndentTask {
34
35
    /**
36
     * Perform reindentation of the line(s) of {@link Context#getDocument()}
37
     * between {@link Context#startOffset()} and {@link Context#endOffset()}.
38
     * <br/>
39
     * It is called from AWT thread and it should process synchronously. It is used
40
     * after a newline is inserted after the user presses Enter
41
     * or when a current line must be reindented e.g. when Tab is pressed in emacs mode.
42
     * <br/>
43
     * The method should use information from the context and modify
44
     * indentation at the given offset in the document.
45
     * 
46
     * @throws BadLocationException in case the indent task attempted to insert/remove
47
     *  at an invalid offset or e.g. into a guarded section.
48
     */
49
    void reindent() throws BadLocationException;
50
    
51
    /**
52
     * Get an extra locking or null if no extra locking is necessary.
53
     */
54
    ExtraLock indentLock();
55
56
    /**
57
     * Indent task factory produces indent tasks for the given context.
58
     * <br/>
59
     * It should be registered in MimeLookup via xml layer in "/Editors/&lt;mime-type&gt;"
60
     * folder.
61
     */
62
    public interface Factory {
63
64
        /**
65
         * Create indenting task.
66
         *
67
         * @param context non-null indentation context.
68
         * @return indenting task or null if the factory cannot handle the given context.
69
         */
70
        IndentTask createTask(Context context);
71
72
    }
73
74
}
(-)indent/src/org/netbeans/spi/editor/indent/ReformatTask.java (+74 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.spi.editor.indent;
21
22
import javax.swing.text.BadLocationException;
23
24
/**
25
 * Reformat task performs actual reformatting within offset bounds of the given context.
26
 *
27
 * @author Miloslav Metelka
28
 */
29
30
public interface ReformatTask {
31
32
    /**
33
     * Perform reformatting of the {@link Context#getDocument()}
34
     * between {@link Context#startOffset()} and {@link Context#endOffset()}.
35
     * <br/>
36
     * This method may be called several times repetitively for different areas
37
     * of a reformatted area.
38
     * <br/>
39
     * It is called from AWT thread and it should process synchronously. It is used
40
     * after a newline is inserted after the user presses Enter
41
     * or when a current line must be reindented e.g. when Tab is pressed in emacs mode.
42
     * <br/>
43
     * The method should use information from the context and modify
44
     * indentation at the given offset in the document.
45
     * 
46
     * @throws BadLocationException in case the formatter attempted to insert/remove
47
     *  at an invalid offset or e.g. into a guarded section.
48
     */
49
    void reformat() throws BadLocationException;
50
51
    /**
52
     * Get an extra locking or null if no extra locking is necessary.
53
     */
54
    ExtraLock reformatLock();
55
    
56
    /**
57
     * Reformat task factory produces reformat tasks for the given context.
58
     * <br/>
59
     * It should be registered in MimeLookup via xml layer in "/Editors/&lt;mime-type&gt;"
60
     * folder.
61
     */
62
    public interface Factory {
63
64
        /**
65
         * Create reformatting task.
66
         *
67
         * @param context non-null indentation context.
68
         * @return reformatting task or null if the factory cannot handle the given context.
69
         */
70
        ReformatTask createTask(Context context);
71
72
    }
73
74
}
(-)indent/test/.cvsignore (+3 lines)
Added Link Here
1
lib
2
results
3
work
(-)indent/test/build.xml (+54 lines)
Added Link Here
1
<?xml version="1.0"?>
2
<!--
3
The contents of this file are subject to the terms of the Common Development
4
and Distribution License (the License). You may not use this file except in
5
compliance with the License.
6
7
You can obtain a copy of the License at http://www.netbeans.org/cddl.html
8
or http://www.netbeans.org/cddl.txt.
9
10
When distributing Covered Code, include this CDDL Header Notice in each file
11
and include the License file at http://www.netbeans.org/cddl.txt.
12
If applicable, add the following below the CDDL Header, with the fields
13
enclosed by brackets [] replaced by your own identifying information:
14
"Portions Copyrighted [year] [name of copyright owner]"
15
16
The Original Software is NetBeans. The Initial Developer of the Original
17
Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
18
Microsystems, Inc. All Rights Reserved.
19
-->
20
<project name="editor/indent test build script" basedir="." default="all">
21
22
    <!-- Name of tested module -->
23
    <property name="xtest.module" value="editor/indent"/>
24
    
25
    <!-- Imports buildtests, cleantests, runtest, cleanresults, realclean, printconfig targets. -->
26
    <import file="../../../nbbuild/templates/xtest.xml"/>
27
    <import file="../../../nbbuild/templates/xtest-unit.xml"/>
28
    
29
    <!-- default testtypes, attributes used when no value is supplied from command line -->
30
    <property name="xtest.testtype" value="unit"/>
31
    <property name="xtest.attribs" value="stable"/>
32
33
    <!-- Build lexer tests -->
34
    <target name="build-lexer-tests">
35
        <!--  Cannot use
36
              <ant dir="../../openide/text/test" target="buildtests" inheritall="false"/>
37
              because inheritAll="false" doesn't work for all properties. -->
38
        <java classname="org.apache.tools.ant.Main" classpath="${java.class.path}" fork="true">
39
            <arg value="-f"/>
40
            <arg value="../../../lexer/test/build.xml"/>
41
            <arg value="-Dxtest.testtype=unit"/>
42
            <arg value="-Dxtest.attribs=stable"/>
43
            <arg value="buildtests"/>
44
        </java>
45
    </target>
46
    
47
    <target name="default-compiler" depends="build-lexer-tests,xtest-unit.default-compiler"/>
48
49
    <target name="run-unit-test-noJIT">
50
        <antcall target="run-unit-test">
51
            <param name="xtest.jvm.args" value="-Xint" />
52
        </antcall>
53
    </target>
54
</project>
(-)indent/test/cfg-unit.xml (+62 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!DOCTYPE mconfig PUBLIC "-//NetBeans//DTD XTest cfg 1.0//EN" "http://www.netbeans.org/dtds/xtest-cfg-1_0.dtd">
3
<!--
4
The contents of this file are subject to the terms of the Common Development
5
and Distribution License (the License). You may not use this file except in
6
compliance with the License.
7
8
You can obtain a copy of the License at http://www.netbeans.org/cddl.html
9
or http://www.netbeans.org/cddl.txt.
10
11
When distributing Covered Code, include this CDDL Header Notice in each file
12
and include the License file at http://www.netbeans.org/cddl.txt.
13
If applicable, add the following below the CDDL Header, with the fields
14
enclosed by brackets [] replaced by your own identifying information:
15
"Portions Copyrighted [year] [name of copyright owner]"
16
17
The Original Software is NetBeans. The Initial Developer of the Original
18
Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
19
Microsystems, Inc. All Rights Reserved.
20
-->
21
22
<!-- 
23
  These classes are excluded by default (defined in build.xml):
24
    "**/*Suite.class"
25
    "**/*$$*.class"
26
    "**/data/**"
27
    "**/hidden/**"
28
    "**/*Hidden.*"
29
    "**/*Hid.*"
30
-->
31
32
<mconfig name="editor/indent unit test config">
33
    
34
    <testbag testattribs="stable" executor="code" name="testbag_1">
35
        <testset dir="unit/src">
36
            <patternset>
37
                <include name="**/**Test.class"/>
38
                <exclude name="org/netbeans/spi/editor/highlighting/performance/**"/>
39
            </patternset>
40
        </testset>
41
    </testbag>
42
    
43
    <testbag testattribs="failing" executor="code" name="testbag_2">
44
        <testset dir="unit/src">
45
            <patternset>
46
            </patternset>
47
        </testset>
48
    </testbag>
49
    
50
    <!-- If you want to use this testbag you *must* provide xtest.includes property, -->
51
    <!-- (either on cmd line or in the script) to explicitly define which test       -->
52
    <!-- you want to run. This will run *only* tests from unit/src folder !!!        -->
53
    <testbag testattribs="empty" executor="code" name="testbag_empty">
54
        <testset dir="unit/src"/>
55
    </testbag>
56
57
    <executor name="code" antfile="build.xml" target="run-unit-test" default="true"/>
58
    <executor name="code-noJIT" antfile="build.xml" target="run-unit-test-noJIT" />
59
    
60
    <compiler name="unit-compiler" antfile="build.xml" target="default-compiler" default="true"/>
61
    
62
</mconfig>
(-)indent/test/unit/src/META-INF/services/org.netbeans.spi.editor.mimelookup.MimeDataProvider (+1 lines)
Added Link Here
1
org.netbeans.modules.editor.indent.IndentTestMimeDataProvider
(-)indent/test/unit/src/org/netbeans/api/editor/indent/IndentTest.java (+118 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.api.editor.indent;
21
22
import javax.swing.text.BadLocationException;
23
import javax.swing.text.Document;
24
import javax.swing.text.PlainDocument;
25
import org.netbeans.junit.NbTestCase;
26
import org.netbeans.modules.editor.indent.IndentTestMimeDataProvider;
27
import org.netbeans.spi.editor.indent.Context;
28
import org.netbeans.spi.editor.indent.ExtraLock;
29
import org.netbeans.spi.editor.indent.IndentTask;
30
31
/**
32
 *
33
 * @author Miloslav Metelka
34
 */
35
public class IndentTest extends NbTestCase {
36
    
37
    private static final String MIME_TYPE = "text/x-test";
38
39
    public IndentTest(String name) {
40
        super(name);
41
    }
42
43
    public void testFindIndentTaskFactory() throws BadLocationException {
44
        TestIndentTask.TestFactory factory = new TestIndentTask.TestFactory();
45
        IndentTestMimeDataProvider.addInstances(MIME_TYPE, factory);
46
        Document doc = new PlainDocument();
47
        doc.putProperty("mimeType", MIME_TYPE);
48
        Indent indent = Indent.get(doc);
49
        indent.lock();
50
        try {
51
            //doc.atomicLock();
52
            try {
53
                indent.reindent(0);
54
            } finally {
55
                //doc.atomicUnlock();
56
            }
57
        } finally {
58
            indent.unlock();
59
        }
60
        // Check that the factory was used
61
        assertTrue(factory.lastCreatedTask.indentPerformed);
62
    }
63
64
    private static final class TestIndentTask implements IndentTask {
65
        
66
        private Context context;
67
        
68
        TestExtraLocking lastCreatedLocking;
69
        
70
        boolean indentPerformed;
71
72
        TestIndentTask(Context context) {
73
            this.context = context;
74
        }
75
76
        public void reindent() throws BadLocationException {
77
            assertTrue(lastCreatedLocking.locked);
78
            context.document().insertString(0, " ", null);
79
            indentPerformed = true;
80
        }
81
        
82
        public ExtraLock indentLock() {
83
            return (lastCreatedLocking = new TestExtraLocking());
84
        }
85
        
86
        static final class TestFactory implements IndentTask.Factory {
87
            
88
            static TestIndentTask lastCreatedTask;
89
90
            public IndentTask createTask(Context context) {
91
                return (lastCreatedTask = new TestIndentTask(context));
92
            }
93
            
94
        }
95
96
    }
97
    
98
    private static final class TestExtraLocking implements ExtraLock {
99
        
100
        Boolean locked;
101
        
102
        public Boolean locked() {
103
            return locked;
104
        }
105
106
        public void lock() {
107
            if (locked != null)
108
                assertFalse(locked);
109
            locked = true;
110
        }
111
112
        public void unlock() {
113
            assertTrue(locked);
114
            locked = false;
115
        }
116
        
117
    }
118
}
(-)indent/test/unit/src/org/netbeans/api/editor/indent/IndentUtilsTest.java (+80 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.api.editor.indent;
21
22
import org.netbeans.junit.NbTestCase;
23
import org.netbeans.lib.editor.util.ArrayUtilities;
24
25
/**
26
 *
27
 * @author Miloslav Metelka
28
 */
29
public class IndentUtilsTest extends NbTestCase {
30
    
31
    private static final String MIME_TYPE = "text/x-test";
32
33
    public IndentUtilsTest(String name) {
34
        super(name);
35
    }
36
37
    public void testIndentUtils() throws Exception {
38
        // Test empty indent
39
        assertSame("", IndentUtils.cachedOrCreatedIndentString(0, true, 8));
40
        assertSame("", IndentUtils.cachedOrCreatedIndentString(0, false, 4));
41
        
42
        // Test <tabSize
43
        String s;
44
        assertEquals("   ", s = IndentUtils.cachedOrCreatedIndentString(3, false, 4));
45
        // Test caching of indent strings
46
        assertSame(s, IndentUtils.cachedOrCreatedIndentString(3, false, 4));
47
        
48
        // Test ==tabSize
49
        assertEquals("\t", s = IndentUtils.cachedOrCreatedIndentString(4, false, 4));
50
        assertSame(s, IndentUtils.cachedOrCreatedIndentString(4, false, 4));
51
52
        // Test >tabSize
53
        assertEquals("\t  ", s = IndentUtils.cachedOrCreatedIndentString(6, false, 4));
54
        assertSame(s, IndentUtils.cachedOrCreatedIndentString(6, false, 4));
55
        assertEquals("\t\t\t   ", s = IndentUtils.cachedOrCreatedIndentString(15, false, 4));
56
        assertSame(s, IndentUtils.cachedOrCreatedIndentString(15, false, 4));
57
        
58
        // Test spaces-only
59
        assertEquals("          ", s = IndentUtils.cachedOrCreatedIndentString(10, true, 4));
60
        assertEquals(s, IndentUtils.cachedOrCreatedIndentString(10, true, 4));
61
        
62
        // Test many (non-cached) spaces
63
        int testUncachedIndent = 90;
64
        StringBuilder sb = new StringBuilder(testUncachedIndent);
65
        ArrayUtilities.appendSpaces(sb, testUncachedIndent);
66
        assertEquals(sb.toString(), IndentUtils.cachedOrCreatedIndentString(testUncachedIndent, true, 4));
67
        
68
        // Test long (non-cached) tab indent
69
        int i = testUncachedIndent;
70
        sb.setLength(0);
71
        while (i >= 8) {
72
            sb.append('\t');
73
            i -= 8;
74
        }
75
        ArrayUtilities.appendSpaces(sb, i);
76
        assertEquals(sb.toString(), IndentUtils.cachedOrCreatedIndentString(testUncachedIndent, false, 8));
77
        
78
    }
79
80
}
(-)indent/test/unit/src/org/netbeans/modules/editor/indent/IndentActionsTest.java (+146 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.modules.editor.indent;
21
22
import java.awt.event.ActionEvent;
23
import javax.swing.Action;
24
import javax.swing.JEditorPane;
25
import javax.swing.SwingUtilities;
26
import org.netbeans.api.editor.indent.*;
27
import javax.swing.text.BadLocationException;
28
import org.netbeans.editor.BaseKit;
29
import org.netbeans.junit.NbTestCase;
30
import org.netbeans.modules.editor.NbEditorKit;
31
import org.netbeans.modules.editor.indent.IndentTestMimeDataProvider;
32
import org.netbeans.spi.editor.indent.Context;
33
import org.netbeans.spi.editor.indent.ExtraLock;
34
import org.netbeans.spi.editor.indent.IndentTask;
35
36
/**
37
 *
38
 * @author Miloslav Metelka
39
 */
40
public class IndentActionsTest extends NbTestCase {
41
    
42
    private static final String MIME_TYPE = "text/x-test-actions";
43
44
    public IndentActionsTest(String name) {
45
        super(name);
46
    }
47
48
    public void testIndentActions() {
49
        // Must run in AWT thread (BaseKit.install() checks for that)
50
        if (!SwingUtilities.isEventDispatchThread()) {
51
            SwingUtilities.invokeLater(
52
                new Runnable() {
53
                    public void run() {
54
                        testIndentActions();
55
                    }
56
                }
57
            );
58
            return;
59
        }
60
61
        assertTrue(SwingUtilities.isEventDispatchThread());
62
        TestIndentTask.TestFactory factory = new TestIndentTask.TestFactory();
63
        IndentTestMimeDataProvider.addInstances(MIME_TYPE, factory);
64
        TestKit kit = new TestKit();
65
        JEditorPane pane = new JEditorPane();
66
        pane.setEditorKit(kit);
67
        assertEquals(MIME_TYPE, pane.getDocument().getProperty("mimeType"));
68
        //doc.putProperty("mimeType", MIME_TYPE);
69
        
70
        // Test insert new line action
71
        Action a = kit.getActionByName(BaseKit.insertBreakAction);
72
        assertNotNull(a);
73
        a.actionPerformed(new ActionEvent(pane, 0, ""));
74
        // Check that the factory was used
75
        assertTrue(factory.lastCreatedTask.indentPerformed);
76
77
        // Test reformat action
78
         a = kit.getActionByName(BaseKit.formatAction);
79
        assertNotNull(a);
80
        a.actionPerformed(new ActionEvent(pane, 0, ""));
81
82
    }
83
84
    private static final class TestIndentTask implements IndentTask {
85
        
86
        private Context context;
87
        
88
        TestExtraLocking lastCreatedLocking;
89
        
90
        boolean indentPerformed;
91
92
        TestIndentTask(Context context) {
93
            this.context = context;
94
        }
95
96
        public void reindent() throws BadLocationException {
97
            assertTrue(lastCreatedLocking.locked);
98
            context.document().insertString(0, " ", null);
99
            indentPerformed = true;
100
        }
101
        
102
        public ExtraLock indentLock() {
103
            return (lastCreatedLocking = new TestExtraLocking());
104
        }
105
        
106
        static final class TestFactory implements IndentTask.Factory {
107
            
108
            static TestIndentTask lastCreatedTask;
109
110
            public IndentTask createTask(Context context) {
111
                return (lastCreatedTask = new TestIndentTask(context));
112
            }
113
            
114
        }
115
116
    }
117
    
118
    private static final class TestExtraLocking implements ExtraLock {
119
        
120
        Boolean locked;
121
        
122
        public Boolean locked() {
123
            return locked;
124
        }
125
126
        public void lock() {
127
            if (locked != null)
128
                assertFalse(locked);
129
            locked = true;
130
        }
131
132
        public void unlock() {
133
            assertTrue(locked);
134
            locked = false;
135
        }
136
        
137
    }
138
    
139
    private static final class TestKit extends NbEditorKit {
140
        
141
        public String getContentType() {
142
            return MIME_TYPE;
143
        }
144
        
145
    }
146
}
(-)indent/test/unit/src/org/netbeans/modules/editor/indent/IndentTestMimeDataProvider.java (+126 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.modules.editor.indent;
21
22
import java.util.ArrayList;
23
import java.util.Arrays;
24
import java.util.HashMap;
25
import org.netbeans.api.editor.mimelookup.MimePath;
26
import org.netbeans.spi.editor.mimelookup.MimeDataProvider;
27
import org.openide.util.Lookup;
28
import org.openide.util.lookup.AbstractLookup;
29
import org.openide.util.lookup.InstanceContent;
30
31
/**
32
 * Testing mime data provider.
33
 *
34
 * @author vita
35
 */
36
public final class IndentTestMimeDataProvider implements MimeDataProvider {
37
    
38
    private static final HashMap<String, Lkp> CACHE = new HashMap<String, Lkp>();
39
    
40
    /** Creates a new instance of MemoryMimeDataProvider */
41
    public IndentTestMimeDataProvider() {
42
    }
43
44
    public Lookup getLookup(MimePath mimePath) {
45
        return getLookup(mimePath.getPath(), true);
46
    }
47
    
48
    public static void addInstances(String mimePath, Object... instances) {
49
        assert mimePath != null : "Mime path can't be null";
50
        getLookup(mimePath, true).addInstances(instances);
51
    }
52
    
53
    public static void removeInstances(String mimePath, Object... instances) {
54
        assert mimePath != null : "Mime path can't be null";
55
        getLookup(mimePath, true).removeInstances(instances);
56
    }
57
    
58
    public static void reset(String mimePath) {
59
        if (mimePath == null) {
60
            synchronized (CACHE) {
61
                for(Lkp lookup : CACHE.values()) {
62
                    lookup.reset();
63
                }
64
            }
65
        } else {
66
            Lkp lookup = getLookup(mimePath, false);
67
            if (lookup != null) {
68
                lookup.reset();
69
            }
70
        }
71
    }
72
    
73
    private static Lkp getLookup(String mimePath, boolean create) {
74
        synchronized (CACHE) {
75
            Lkp lookup = CACHE.get(mimePath);
76
            if (lookup == null && create) {
77
                lookup = new Lkp();
78
                CACHE.put(mimePath, lookup);
79
            }
80
            return lookup;
81
        }
82
    }
83
    
84
    private static final class Lkp extends AbstractLookup {
85
        
86
        private ArrayList<Object> all = new ArrayList<Object>();
87
        private InstanceContent contents;
88
            
89
        public Lkp() {
90
            this(new InstanceContent());
91
        }
92
        
93
        private Lkp(InstanceContent ic) {
94
            super(ic);
95
            this.contents = ic;
96
        }
97
        
98
        public void addInstances(Object... instances) {
99
            all.addAll(Arrays.asList(instances));
100
            contents.set(all, null);
101
        }
102
103
        public void removeInstances(Object... instances) {
104
            ArrayList<Object> newAll = new ArrayList<Object>();
105
            
106
            loop:
107
            for(Object oo : all) {
108
                for(Object o : instances) {
109
                    if (o == oo) {
110
                        continue loop;
111
                    }
112
                }
113
                
114
                newAll.add(oo);
115
            }
116
            
117
            all = newAll;
118
            contents.set(all, null);
119
        }
120
        
121
        public void reset() {
122
            all.clear();
123
            contents.set(all, null);
124
        }
125
    } // End of Lkp class
126
}
(-)libsrc/org/netbeans/editor/ActionFactory.java (-32 / +38 lines)
Lines 1483-1530 Link Here
1483
                Cursor origCursor = target.getCursor();
1483
                Cursor origCursor = target.getCursor();
1484
                target.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
1484
                target.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
1485
1485
1486
                doc.atomicLock();
1486
                Formatter formatter = doc.getFormatter();
1487
                formatter.reformatLock();
1487
                try {
1488
                try {
1489
                    doc.atomicLock();
1490
                    try {
1488
1491
1489
                    int startPos;
1492
                        int startPos;
1490
                    Position endPosition;
1493
                        Position endPosition;
1491
                    if (caret.isSelectionVisible()) {
1494
                        if (caret.isSelectionVisible()) {
1492
                        startPos = target.getSelectionStart();
1495
                            startPos = target.getSelectionStart();
1493
                        endPosition = doc.createPosition(target.getSelectionEnd());
1496
                            endPosition = doc.createPosition(target.getSelectionEnd());
1494
                    } else {
1497
                        } else {
1495
                        startPos = 0;
1498
                            startPos = 0;
1496
                        endPosition = doc.createPosition(doc.getLength());
1499
                            endPosition = doc.createPosition(doc.getLength());
1497
                    }
1500
                        }
1498
1501
1499
                    int pos = startPos;
1502
                        int pos = startPos;
1500
                    if (gdoc != null) {
1503
                        if (gdoc != null) {
1501
                        pos = gdoc.getGuardedBlockChain().adjustToBlockEnd(pos);
1504
                            pos = gdoc.getGuardedBlockChain().adjustToBlockEnd(pos);
1502
                    }
1505
                        }
1503
1506
1504
                    while (pos < endPosition.getOffset()) {
1507
                        while (pos < endPosition.getOffset()) {
1505
                        int stopPos = endPosition.getOffset();
1508
                            int stopPos = endPosition.getOffset();
1506
                        if (gdoc != null) { // adjust to start of the next guarded block
1509
                            if (gdoc != null) { // adjust to start of the next guarded block
1507
                            stopPos = gdoc.getGuardedBlockChain().adjustToNextBlockStart(pos);
1510
                                stopPos = gdoc.getGuardedBlockChain().adjustToNextBlockStart(pos);
1508
                            if (stopPos == -1 || stopPos > endPosition.getOffset()) {
1511
                                if (stopPos == -1 || stopPos > endPosition.getOffset()) {
1509
                                stopPos = endPosition.getOffset();
1512
                                    stopPos = endPosition.getOffset();
1513
                                }
1510
                            }
1514
                            }
1511
                        }
1512
1515
1513
                        int reformattedLen = doc.getFormatter().reformat(doc, pos, stopPos);
1516
                            int reformattedLen = formatter.reformat(doc, pos, stopPos);
1514
                        pos = pos + reformattedLen;
1517
                            pos = pos + reformattedLen;
1515
1518
1516
                        if (gdoc != null) { // adjust to end of current block
1519
                            if (gdoc != null) { // adjust to end of current block
1517
                            pos = gdoc.getGuardedBlockChain().adjustToBlockEnd(pos);
1520
                                pos = gdoc.getGuardedBlockChain().adjustToBlockEnd(pos);
1521
                            }
1518
                        }
1522
                        }
1519
                    }
1520
1523
1521
                } catch (GuardedException e) {
1524
                    } catch (GuardedException e) {
1522
                    target.getToolkit().beep();
1525
                        target.getToolkit().beep();
1523
                } catch (BadLocationException e) {
1526
                    } catch (BadLocationException e) {
1524
                    Utilities.annotateLoggable(e);
1527
                        Utilities.annotateLoggable(e);
1528
                    } finally {
1529
                        doc.atomicUnlock();
1530
                        target.setCursor(origCursor);
1531
                    }
1525
                } finally {
1532
                } finally {
1526
                    doc.atomicUnlock();
1533
                    formatter.reformatUnlock();
1527
                    target.setCursor(origCursor);
1528
                }
1534
                }
1529
            }
1535
            }
1530
        }
1536
        }
(-)libsrc/org/netbeans/editor/BaseDocument.java (-1 / +7 lines)
Lines 52-57 Link Here
52
import javax.swing.undo.CannotUndoException;
52
import javax.swing.undo.CannotUndoException;
53
import javax.swing.undo.CannotRedoException;
53
import javax.swing.undo.CannotRedoException;
54
import org.netbeans.lib.editor.util.swing.DocumentListenerPriority;
54
import org.netbeans.lib.editor.util.swing.DocumentListenerPriority;
55
import org.netbeans.modules.editor.lib.FormatterOverride;
56
import org.openide.util.Lookup;
55
57
56
/**
58
/**
57
* Document implementation
59
* Document implementation
Lines 439-445 Link Here
439
441
440
    /** Get the formatter for this document. */
442
    /** Get the formatter for this document. */
441
    public Formatter getFormatter() {
443
    public Formatter getFormatter() {
442
        return Formatter.getFormatter(kitClass);
444
        Formatter f = (Formatter)getProperty("defaultFormatter");
445
        if (f == null)
446
            f = Formatter.getFormatter(kitClass);
447
        FormatterOverride fp = Lookup.getDefault().lookup(FormatterOverride.class);
448
        return (fp != null) ? fp.getFormatter(this, f) : f;
443
    }
449
    }
444
450
445
    public SyntaxSupport getSyntaxSupport() {
451
    public SyntaxSupport getSyntaxSupport() {
(-)libsrc/org/netbeans/editor/BaseKit.java (-12 / +18 lines)
Lines 1112-1132 Link Here
1112
                }
1112
                }
1113
1113
1114
                BaseDocument doc = (BaseDocument)target.getDocument();
1114
                BaseDocument doc = (BaseDocument)target.getDocument();
1115
                doc.atomicLock();
1115
                Formatter formatter = doc.getFormatter();
1116
                DocumentUtilities.setTypingModification(doc, true);
1116
                formatter.indentLock();
1117
                try{
1117
                try {
1118
                    target.replaceSelection("");
1118
                    doc.atomicLock();
1119
                    Caret caret = target.getCaret();
1119
                    DocumentUtilities.setTypingModification(doc, true);
1120
                    Object cookie = beforeBreak(target, doc, caret);
1120
                    try {
1121
                        target.replaceSelection("");
1122
                        Caret caret = target.getCaret();
1123
                        Object cookie = beforeBreak(target, doc, caret);
1121
1124
1122
                    int dotPos = caret.getDot();
1125
                        int dotPos = caret.getDot();
1123
                    int newDotPos = doc.getFormatter().indentNewLine(doc, dotPos);
1126
                        int newDotPos = doc.getFormatter().indentNewLine(doc, dotPos);
1124
                    caret.setDot(newDotPos);
1127
                        caret.setDot(newDotPos);
1125
1128
1126
                    afterBreak(target, doc, caret, cookie);
1129
                        afterBreak(target, doc, caret, cookie);
1130
                    } finally {
1131
                        DocumentUtilities.setTypingModification(doc, false);
1132
                        doc.atomicUnlock();
1133
                    }
1127
                } finally {
1134
                } finally {
1128
                    DocumentUtilities.setTypingModification(doc, false);
1135
                    formatter.indentUnlock();
1129
                    doc.atomicUnlock();
1130
                }
1136
                }
1131
            }
1137
            }
1132
        }
1138
        }
(-)libsrc/org/netbeans/editor/Formatter.java (+109 lines)
Lines 497-500 Link Here
497
        return writer;
497
        return writer;
498
    }
498
    }
499
499
500
    /**
501
     * Formatter clients should call this method
502
     * before acquiring of the document's write lock
503
     * and using of the {@link #indentLine(Document,int)}
504
     * and {@link #indentNewLine(Document,int)} methods.
505
     * <br/>
506
     * Subclasses may override this method
507
     * and perform necessary pre-locking (e.g. of java infrastructure).
508
     * <br/>
509
     * The following pattern should be used:
510
     * <pre>
511
     * formatter.indentLock();
512
     * try {
513
     *     doc.atomicLock();
514
     *     try {
515
     *         formatter.indentLine(...);
516
     *     } finally {
517
     *         doc.atomicUnlock();
518
     *     }
519
     * } finally {
520
     *     formatter.indentUnlock();
521
     * }
522
     * </pre>
523
     */
524
    public void indentLock() {
525
        // No extra locking by default
526
    }
527
    
528
    /**
529
     * Formatter clients should call this method 
530
     * after releasing of the document's write lock
531
     * as a counterpart of {@link #indentLock()}.
532
     * <br/>
533
     * Subclasses may override this method
534
     * and perform necessary post-unlocking (e.g. of java infrastructure).
535
     * <br/>
536
     * The following pattern should be used:
537
     * <pre>
538
     * formatter.indentLock();
539
     * try {
540
     *     doc.atomicLock();
541
     *     try {
542
     *         formatter.indentLine(...);
543
     *     } finally {
544
     *         doc.atomicUnlock();
545
     *     }
546
     * } finally {
547
     *     formatter.indentUnlock();
548
     * }
549
     * </pre>
550
     */
551
    public void indentUnlock() {
552
        // No extra locking by default
553
    }
554
555
    /**
556
     * Formatter clients should call this method 
557
     * before acquiring of the document's write lock
558
     * before using of {@link #reformat(BaseDocument,int,int)} method.
559
     * <br/>
560
     * Subclasses may override this method
561
     * and perform necessary pre-locking (e.g. of java infrastructure).
562
     * <br/>
563
     * The following pattern should be used:
564
     * <pre>
565
     * formatter.reformatLock();
566
     * try {
567
     *     doc.atomicLock();
568
     *     try {
569
     *         formatter.reformat(...);
570
     *     } finally {
571
     *         doc.atomicUnlock();
572
     *     }
573
     * } finally {
574
     *     formatter.reformatUnlock();
575
     * }
576
     * </pre>
577
     */
578
    public void reformatLock() {
579
        // No extra locking by default
580
    }
581
    
582
    /**
583
     * Formatter clients should call this method 
584
     * after releasing of the document's write lock
585
     * as a counterpart of {@link #reformatLock()}.
586
     * <br/>
587
     * Subclasses may override this method
588
     * and perform necessary post-unlocking (e.g. of java infrastructure).
589
     * <br/>
590
     * The following pattern should be used:
591
     * <pre>
592
     * formatter.reformatLock();
593
     * try {
594
     *     doc.atomicLock();
595
     *     try {
596
     *         formatter.reformat(...);
597
     *     } finally {
598
     *         doc.atomicUnlock();
599
     *     }
600
     * } finally {
601
     *     formatter.reformatUnlock();
602
     * }
603
     * </pre>
604
     */
605
    public void reformatUnlock() {
606
        // No extra locking by default
607
    }
608
500
}
609
}
(-)libsrc/org/netbeans/modules/editor/lib/FormatterOverride.java (+44 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.modules.editor.lib;
21
22
import javax.swing.text.Document;
23
import org.netbeans.editor.Formatter;
24
25
/**
26
 * Class to be searched in lookup that can override a formatter for the given document.
27
 * <br/>
28
 * It is a private contract between editor/lib and editor/indent.
29
 *
30
 * @author Miloslav Metelka
31
 */
32
public interface FormatterOverride {
33
34
    /**
35
     * Possibly override the default formatter used for the given document.
36
     * 
37
     * @param doc non-null document for which the formatter is being searched.
38
     * @param defaultFormatter default formatter found by the infrastructure
39
     *   or null if there is none.
40
     * @return overriden formatter or the default formatter passed as the argument.
41
     */
42
    Formatter getFormatter(Document doc, Formatter defaultFormatter);
43
44
}
(-)src/org/netbeans/modules/editor/NbEditorDocument.java (+394 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.modules.editor;
21
22
import java.awt.Font;
23
import java.awt.Color;
24
import java.awt.Component;
25
import java.util.ArrayList;
26
import java.util.HashMap;
27
import java.text.AttributedCharacterIterator;
28
import javax.swing.text.AttributeSet;
29
import javax.swing.JEditorPane;
30
import org.netbeans.editor.BaseKit;
31
import org.netbeans.editor.GuardedDocument;
32
import org.netbeans.editor.PrintContainer;
33
import org.netbeans.editor.Formatter;
34
import org.netbeans.editor.Settings;
35
import org.netbeans.editor.SettingsChangeEvent;
36
import org.netbeans.editor.Utilities;
37
import org.openide.text.NbDocument;
38
import org.openide.text.AttributedCharacters;
39
import javax.swing.text.Position;
40
import org.openide.text.Annotation;
41
import java.beans.PropertyChangeListener;
42
import java.beans.PropertyChangeEvent;
43
import java.util.Dictionary;
44
import java.util.Map;
45
import java.util.WeakHashMap;
46
import javax.swing.JToolBar;
47
import javax.swing.event.ChangeEvent;
48
import javax.swing.event.ChangeListener;
49
import org.netbeans.editor.BaseDocument;
50
import javax.swing.text.BadLocationException;
51
import javax.swing.text.Document;
52
import org.netbeans.editor.AnnotationDesc;
53
54
/**
55
* BaseDocument extension managing the readonly blocks of text
56
*
57
* @author Miloslav Metelka
58
* @version 1.00
59
*/
60
61
public class NbEditorDocument extends GuardedDocument
62
implements NbDocument.PositionBiasable, NbDocument.WriteLockable,
63
NbDocument.Printable, NbDocument.CustomEditor, NbDocument.CustomToolbar, NbDocument.Annotatable {
64
65
    /** Name of the formatter setting. */
66
    public static final String FORMATTER = "formatter"; // NOI18N
67
68
    /** Mime type of the document. The name of this property corresponds
69
     * to the property that is filled in the document by CloneableEditorSupport.
70
     */
71
    public static final String MIME_TYPE_PROP = "mimeType"; // NOI18N
72
73
    /** Indent engine for the given kitClass. */
74
    public static final String INDENT_ENGINE = "indentEngine"; // NOI18N
75
76
    /** Formatter being used. */
77
    private Formatter formatter;
78
79
    /** Map of [Annotation, AnnotationDesc] */
80
    private HashMap annoMap;
81
82
    // #39718 hotfix
83
    private WeakHashMap annoBlackList;
84
85
    public NbEditorDocument(Class kitClass) {
86
        super(kitClass);
87
        addStyleToLayerMapping(NbDocument.BREAKPOINT_STYLE_NAME,
88
                               NbDocument.BREAKPOINT_STYLE_NAME + "Layer:10"); // NOI18N
89
        addStyleToLayerMapping(NbDocument.ERROR_STYLE_NAME,
90
                               NbDocument.ERROR_STYLE_NAME + "Layer:20"); // NOI18N
91
        addStyleToLayerMapping(NbDocument.CURRENT_STYLE_NAME,
92
                               NbDocument.CURRENT_STYLE_NAME + "Layer:30"); // NOI18N
93
        setNormalStyleName(NbDocument.NORMAL_STYLE_NAME);
94
        
95
        annoMap = new HashMap(20);
96
        annoBlackList = new WeakHashMap();
97
    }
98
99
    public void settingsChange(SettingsChangeEvent evt) {
100
        super.settingsChange(evt);
101
102
        // Check whether the mimeType is set
103
        Object o = getProperty(MIME_TYPE_PROP);
104
        if (!(o instanceof String)) {
105
            BaseKit kit = BaseKit.getKit(getKitClass());
106
            putProperty(MIME_TYPE_PROP, kit.getContentType());
107
        }
108
109
        // Fill in the indentEngine property
110
        putProperty(INDENT_ENGINE,
111
            new BaseDocument.PropertyEvaluator() {
112
113
                private Object cached;
114
115
                public Object getValue() {
116
                    if (cached == null) {
117
                        cached = Settings.getValue(getKitClass(), INDENT_ENGINE);
118
                    }
119
                    
120
                    return cached;
121
                }
122
            }
123
        );
124
125
        // Refresh formatter
126
        formatter = null;
127
128
    }
129
130
    public void setCharacterAttributes(int offset, int length, AttributeSet s,
131
                                       boolean replace) {
132
        if (s != null) {
133
            Object val = s.getAttribute(NbDocument.GUARDED);
134
            if (val != null && val instanceof Boolean) {
135
                if (((Boolean)val).booleanValue() == true) { // want make guarded
136
                    super.setCharacterAttributes(offset, length, guardedSet, replace);
137
                } else { // want make unguarded
138
                    super.setCharacterAttributes(offset, length, unguardedSet, replace);
139
                }
140
            } else { // not special values, just pass
141
                super.setCharacterAttributes(offset, length, s, replace);
142
            }
143
        }
144
    }
145
146
    public java.text.AttributedCharacterIterator[] createPrintIterators() {
147
        NbPrintContainer npc = new NbPrintContainer();
148
        print(npc);
149
        return npc.getIterators();
150
    }
151
152
    public Component createEditor(JEditorPane j) {
153
        return Utilities.getEditorUI(j).getExtComponent();
154
    }
155
156
    public JToolBar createToolbar(JEditorPane j) {
157
        return Utilities.getEditorUI(j).getToolBarComponent();
158
    }
159
    
160
    public Formatter getFormatter() {
161
        Formatter f = formatter;
162
        if (f == null) {
163
            formatter = (Formatter)Settings.getValue(getKitClass(), FORMATTER);
164
            f = formatter;
165
        }
166
        putProperty("defaultFormatter", f);
167
        // The super implementation will inspect "defaultFormatter" property
168
        return super.getFormatter();
169
    }
170
171
    /** Add annotation to the document. For annotation of whole line
172
     * the length parameter can be ignored (specify value -1).
173
     * @param startPos position which represent begining 
174
     * of the annotated text
175
     * @param length length of the annotated text. If -1 is specified 
176
     * the whole line will be annotated
177
     * @param annotation annotation which is attached to this text */
178
    public void addAnnotation(Position startPos, int length, Annotation annotation) {
179
        Integer count = (Integer)annoBlackList.get(annotation);
180
        if (count != null) {
181
            // #39718 hotfix - test whether the annotation was already removed; if so, just remove it from the black list and return
182
            if (count.intValue() == -1) {
183
                annoBlackList.remove(annotation);
184
                return;
185
            } else if (count.intValue() < -1) {
186
                annoBlackList.put(annotation, new Integer(count.intValue() + 1));
187
                return;
188
            }
189
        }
190
        // partial fix of #33165 - read-locking of the document added
191
        // BTW should only be invoked in EQ - see NbDocument.addAnnotation()
192
        readLock();
193
        try {
194
            // Recreate annotation's position to make sure it's in this doc at a valid offset
195
            int docLen = getLength();
196
            int offset = startPos.getOffset();
197
            offset = Math.min(offset, docLen);
198
            try {
199
                startPos = createPosition(offset);
200
            } catch (BadLocationException e) {
201
                startPos = null; // should never happen
202
            }
203
            
204
            AnnotationDescDelegate a = (AnnotationDescDelegate)annoMap.get(annotation);
205
            if (a != null) { // already added before
206
                // #39718 hotfix - remove the original annotation descriptor and put the annotation on the black list
207
                a.detachListeners();
208
                getAnnotations().removeAnnotation(a);
209
                annoMap.remove(annotation);
210
                annoBlackList.put(annotation, new Integer(count != null ? count.intValue() + 1 : 1));
211
            }
212
            if (annotation.getAnnotationType() != null) {
213
                a = new AnnotationDescDelegate(this, startPos, length, annotation);
214
                annoMap.put(annotation, a);
215
                getAnnotations().addAnnotation(a);
216
            }
217
        } finally {
218
            readUnlock();
219
        }
220
    }
221
222
    /** Removal of added annotation.
223
     * @param annotation annotation which is going to be removed */
224
    public void removeAnnotation(Annotation annotation) {
225
        if (annotation == null) { // issue 14803
226
            return; // can't do more as the rest of stacktrace is in openide and ant
227
        }
228
229
        Integer count = (Integer)annoBlackList.get(annotation);
230
        if (count != null) {
231
            // #39718 hotfix - test whether the annotation was already removed; if so, just remove it from the black list and return
232
            if (count.intValue() == 1) {
233
                annoBlackList.remove(annotation);
234
                return;
235
            } else if (count.intValue() > 1) {
236
                annoBlackList.put(annotation, new Integer(count.intValue() - 1));
237
                return;
238
            }
239
        }
240
        // partial fix of #33165 - read-locking of the document added
241
        // BTW should only be invoked in EQ - see NbDocument.removeAnnotation()
242
        readLock();
243
        try {
244
            if (annotation.getAnnotationType() != null) {
245
                AnnotationDescDelegate a = (AnnotationDescDelegate)annoMap.get(annotation);
246
                if (a == null) { // not added yet
247
                    // #39718 hotfix - put the annotation on the black list and return
248
                    annoBlackList.put(annotation, new Integer(count != null ? count.intValue() - 1 : -1));
249
                    return;
250
                }
251
                a.detachListeners();
252
                getAnnotations().removeAnnotation(a);
253
                annoMap.remove(annotation);
254
            }
255
        } finally {
256
            readUnlock();
257
        }
258
    }
259
    
260
    Map getAnnoMap(){
261
        return annoMap;
262
    }
263
264
    void addStreamDescriptionChangeListener(ChangeListener l) {
265
        listenerList.add(ChangeListener.class, l);
266
    }
267
    
268
    void removeStreamDescriptionChangeListener(ChangeListener l) {
269
        listenerList.remove(ChangeListener.class, l);
270
    }
271
    
272
    private void fireStreamDescriptionChange() {
273
        ChangeEvent evt = new ChangeEvent(this);
274
        Object[] listeners = listenerList.getListenerList();
275
        for (int i = listeners.length - 2; i >= 0; i -= 2) {
276
            if (listeners[i] == ChangeListener.class) {
277
                ((ChangeListener)listeners[i + 1]).stateChanged(evt);
278
            }
279
        }
280
    }
281
282
    protected Dictionary createDocumentProperties(Dictionary origDocumentProperties) {
283
        return new LazyPropertyMap(origDocumentProperties) {
284
            public Object put(Object key, Object value) {
285
                Object origValue = super.put(key, value);
286
                if (Document.StreamDescriptionProperty.equals(key)) {
287
                    if (origValue == null || !origValue.equals(value)) {
288
                        fireStreamDescriptionChange();
289
                    }
290
                }
291
                
292
                return origValue;
293
            }
294
        };
295
    }
296
297
    /** Implementation of AnnotationDesc, which delegate to Annotation instance
298
     * defined in org.openide.text package.
299
     */
300
    static class AnnotationDescDelegate extends AnnotationDesc {
301
        
302
        private Annotation delegate;
303
        private PropertyChangeListener l;
304
        private Position pos;
305
        private BaseDocument doc;
306
        
307
        AnnotationDescDelegate(BaseDocument doc, Position pos, int length, Annotation anno) {
308
            super(pos.getOffset(),length);
309
            this.pos = pos;
310
            this.delegate = anno;
311
            this.doc = doc;
312
            
313
            // update AnnotationDesc.type member
314
            updateAnnotationType();
315
            
316
            // forward property changes to AnnotationDesc property changes
317
            l = new PropertyChangeListener() {
318
                public void propertyChange (PropertyChangeEvent evt) {
319
                    if (evt.getPropertyName() == Annotation.PROP_SHORT_DESCRIPTION)
320
                        firePropertyChange(AnnotationDesc.PROP_SHORT_DESCRIPTION, null, null);
321
                    if (evt.getPropertyName() == Annotation.PROP_MOVE_TO_FRONT)
322
                        firePropertyChange(AnnotationDesc.PROP_MOVE_TO_FRONT, null, null);
323
                    if (evt.getPropertyName() == Annotation.PROP_ANNOTATION_TYPE) {
324
                        updateAnnotationType();
325
                        firePropertyChange(AnnotationDesc.PROP_ANNOTATION_TYPE, null, null);
326
                    }
327
                }
328
            };
329
            delegate.addPropertyChangeListener(l);
330
        }
331
        
332
        public String getAnnotationType() {
333
            return delegate.getAnnotationType();
334
        }
335
        
336
        public String getShortDescription() {
337
            return delegate.getShortDescription();
338
        }
339
        
340
        void detachListeners() {
341
            delegate.removePropertyChangeListener(l);
342
        }
343
344
        public int getOffset() {
345
            return pos.getOffset();
346
        }
347
        
348
        public int getLine() {
349
            try {
350
                return Utilities.getLineOffset(doc, pos.getOffset());
351
            } catch (BadLocationException e) {
352
                return 0;
353
            }
354
        }
355
        
356
    }
357
    
358
    
359
    class NbPrintContainer extends AttributedCharacters implements PrintContainer {
360
361
        ArrayList acl = new ArrayList();
362
363
        AttributedCharacters a;
364
365
        NbPrintContainer() {
366
            a = new AttributedCharacters();
367
        }
368
369
        public void add(char[] chars, Font font, Color foreColor, Color backColor) {
370
            a.append(chars, font, foreColor);
371
        }
372
373
        public void eol() {
374
            acl.add(a);
375
            a = new AttributedCharacters();
376
        }
377
378
        public boolean initEmptyLines() {
379
            return true;
380
        }
381
382
        public AttributedCharacterIterator[] getIterators() {
383
            int cnt = acl.size();
384
            AttributedCharacterIterator[] acis = new AttributedCharacterIterator[cnt];
385
            for (int i = 0; i < cnt; i++) {
386
                AttributedCharacters ac = (AttributedCharacters)acl.get(i);
387
                acis[i] = ac.iterator();
388
            }
389
            return acis;
390
        }
391
392
    }
393
394
}

Return to bug 91718