KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > java > codegen > FieldB


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.java.codegen;
21
22 import java.io.*;
23 import javax.swing.text.*;
24
25 import org.openide.src.*;
26 import org.openide.text.*;
27
28 import org.netbeans.modules.java.bridge.Binding;
29
30 /**
31  *
32  * @author Svatopluk Dedic <mailto:sdedic@netbeans.org>
33  * @version 0.1
34  */

35 class FieldB extends Member implements Binding.Field {
36     private static final boolean DEBUG = false;
37
38     /** Links to the previous and next fields in the field declarator.
39      * If both are null, the field is declared alone and single should be set to
40      * true.
41      */

42     FieldB previous, next;
43     
44     /** Bounds that contain the type declaration.
45      */

46     public PositionBounds typeBounds;
47     
48     boolean single;
49     
50     public FieldB(FieldElement el, SourceText s) {
51         super(el, s);
52         single = true;
53     }
54     
55     
56     /**
57      * Links another Field after this one; those fields will act as a field group.
58      */

59     public void linkAfter(TextBinding t) {
60         FieldB f = (FieldB)t;
61         if (next == f)
62             return;
63         
64         if (next != null) {
65             next.previous = f;
66             next.single = f == null && next.next == null;
67             next.adjustBounds();
68         }
69         if (f != null) {
70             f.previous = this;
71             f.next = next;
72             f.single = false;
73             single = false;
74             if (typeBounds != null)
75                 f.typeBounds = typeBounds;
76         } else {
77             single = previous == null;
78             adjustBounds();
79         }
80         next = f;
81     }
82     
83     
84     public void linkBefore(TextBinding t) {
85         FieldB f = (FieldB)t;
86         if (previous == f)
87             return;
88         
89         if (previous != null) {
90             previous.next = f;
91             previous.single = f == null && previous.previous == null;
92             previous.adjustBounds();
93         }
94         if (f != null) {
95             f.previous = previous;
96             f.next = this;
97             f.single = false;
98             single = false;
99         } else {
100             single = next == null;
101             adjustBounds();
102         }
103         previous = f;
104     }
105     
106     private boolean isSingle() {
107         return single;
108     }
109     
110     private void adjustBounds() {
111         if (!isSingle() || typeBounds == null)
112             return;
113         if (DEBUG)
114             System.err.println("Adjusting bounds for single field..."); // NOI18N
115
headerBounds = new PositionBounds(typeBounds.getBegin(), headerBounds.getEnd());
116         if (docBounds == null)
117             wholeBounds = new PositionBounds(typeBounds.getBegin(), wholeBounds.getEnd());
118         else
119             wholeBounds = new PositionBounds(docBounds.getBegin(), wholeBounds.getEnd());
120         
121         typeBounds = null;
122     }
123
124     private FieldElement cloneField() {
125         return (FieldElement)cloneElement();
126     }
127     
128     protected int classifyProperty(String JavaDoc name) {
129         if (name == PROP_INIT_VALUE)
130             return CLASS_BODY;
131         else
132             return CLASS_HEADER;
133     }
134     
135     public void updateBounds(int kind, PositionBounds b) {
136         if (kind == BOUNDS_FIELD_TYPE) {
137             if (typeBounds == null || b != null)
138                 this.typeBounds = b;
139         } else {
140             super.updateBounds(kind, b);
141         }
142     }
143     
144     protected void regenerateBody(org.openide.src.Element el) throws SourceException {
145         regenerateInitializer((FieldElement) el);
146     }
147     
148     protected void doChangeProperty(String JavaDoc property, Object JavaDoc old, final Object JavaDoc now)
149     throws Exception JavaDoc {
150         if (isSingle() || property == PROP_INIT_VALUE) {
151             super.doChangeProperty(property, old, now);
152             return;
153         }
154         
155         if (property == PROP_NAME) {
156             source.runAtomic(getElement(), new ExceptionRunnable() {
157                 public void run() throws Exception JavaDoc {
158                     CodeGenerator.fillTextBounds(headerBounds,
159                         ((Identifier)now).getSourceName());
160                 }
161             });
162         } else {
163             FieldElement f = cloneField();
164             applyPropertyChange(f, property, now);
165             new SingleMaker(f).run();
166         }
167     }
168     
169     /** Changes the declared type of the field.
170      */

171     public void changeType(Type newType) throws SourceException {
172         if (!source.isGeneratorEnabled())
173             return;
174         
175         if (isSingle()) {
176             FieldElement f = cloneField();
177             f.setType(newType);
178             regenerateHeader(f);
179             return;
180         }
181         FieldElement f = cloneField();
182         f.setType(newType);
183         source.runAtomic(getElement(), new SingleMaker(f));
184     }
185     
186     private void regenerateJavaDoc() throws SourceException {
187         super.regenerateJavaDoc(getElement(), ((FieldElement)getElement()).getJavaDoc());
188     }
189
190     /**
191      * Prepares the field for insertion of a sibling. Since the operation is
192      * symmetric, and we only care for insertion between two siblings, move the burden
193      * to the field that precede the new sibling.
194      */

195     public PositionRef prepareInsert(ElementBinding tbi, boolean after)
196     throws SourceException {
197         if (after && next != null) {
198             breakFieldGroup();
199             if (DEBUG)
200                 source.dumpDocument();
201         } else if (!after && previous != null) {
202             previous.breakFieldGroup();
203             if (DEBUG)
204                 source.dumpDocument();
205         }
206         if (DEBUG) {
207             System.err.println("prepareInsert: after = " + after + "wholeBounds = " + wholeBounds); // NOI18N
208
}
209         return super.prepareInsert(tbi, after);
210     }
211     
212     /** Breaks the field group after _this_ field's declaration.
213      */

214     void breakFieldGroup() throws SourceException {
215         try {
216             final String JavaDoc headerText = typeBounds.getText();
217             final FieldB prev = this.previous;
218             final FieldB next = this.next;
219             final StyledDocument doc = findDocument();
220
221             if (DEBUG) {
222                 System.err.println("breakFieldGroup invoked on " + getField()); // NOI18N
223
System.err.println("[breakFieldGroup] headerText = " + headerText); // NOI18N
224
System.err.println("[breakFieldGroup] myBounds = " + wholeBounds); // NOI18N
225
dumpBoundsForChain();
226             }
227             if (next == null) {
228                 throw new IllegalStateException JavaDoc("breakFieldGroup invoked on field " // NOI18N
229
+ ((FieldElement)getElement()).getName() + " that is at the end of the group"); // NOI18N
230
}
231             PositionBounds insertion;
232
233
234             // this is because we don't want to extend (body)Bounds:
235
// 1. turn the last character to a semicolon.
236
// 2. insert a newline (formatted through the indent engine)
237
// 3. insert type specification (again formatted)
238
PositionBounds replacement = new PositionBounds(
239                 source.createPos(
240                     wholeBounds.getEnd().getOffset() - 1,
241                     Position.Bias.Backward
242                 ),
243                 source.createPos(
244                     wholeBounds.getEnd().getOffset(),
245                     Position.Bias.Forward
246                 )
247             );
248             CodeGenerator.fillTextBounds(replacement,
249                 CodeGenerator.formatText(doc, replacement.getBegin(), ";")); // NOI18N
250

251             String JavaDoc separator = CodeGenerator.formatText(doc, replacement.getEnd(),
252                 "\n" + headerText) + " "; // NOI18N
253
int hdrOffset = separator.indexOf(headerText);
254
255             PositionBounds insertion2 = new PositionBounds(
256                 source.createPos(
257                     replacement.getEnd().getOffset(),
258                     Position.Bias.Forward
259                 ),
260                 source.createPos(
261                     next.headerBounds.getBegin().getOffset(),
262                     Position.Bias.Backward
263                 )
264             );
265             insertion2.setText(separator);
266             
267             PositionBounds tBounds = new PositionBounds(
268                 source.createPos(insertion2.getBegin().getOffset() + hdrOffset, Position.Bias.Backward),
269                 source.createPos(insertion2.getEnd().getOffset() - 1, Position.Bias.Forward)
270             );
271
272             /*
273             insertion = wholeBounds.insertAfter(
274                     CodeGenerator.formatText(doc, replacement.getEnd(), "\n") // NOI18N
275                 );
276
277             PositionBounds insertion2 = new PositionBounds(
278                 source.createPos(
279                     insertion.getEnd().getOffset(),
280                     Position.Bias.Forward
281                 ),
282                 source.createPos(
283                     next.headerBounds.getBegin().getOffset(),
284                     Position.Bias.Backward
285                 )
286             );
287              */

288
289             if (DEBUG) {
290                 System.err.println("[breakFieldGroup] Insertion for type is " + insertion2 + // NOI18N
291
" hdr offset = " + hdrOffset); // NOI18N
292
}
293             /*
294             // insert a copy of type specification for the rest of the fields
295             insertion2.setText(headerText + " ");
296
297             // type bounds have to stick with the type.
298             PositionBounds tBounds = new PositionBounds(
299                 insertion.getBegin(),
300                 source.createPos(
301                     insertion2.getEnd().getOffset(),
302                     Position.Bias.Forward
303                 )
304             );
305              */

306
307             if (DEBUG) {
308                 System.err.println("[breakFieldGroup] next's type bounds = " + tBounds); // NOI18N
309
}
310
311             // adjust the bounds for the immediate next field and clear it's
312
// JavaDoc bounds since it hasn't any JavaDoc yet.
313
next.typeBounds = tBounds;
314             next.wholeBounds = new PositionBounds(
315                 tBounds.getBegin(),
316                 next.wholeBounds.getEnd()
317             );
318             // this should set next.previous -> null, this->next to null, next->single to true,
319
// this->single to <whatever>
320
next.linkBefore(null);
321             // clear the next fields' docBounds.
322
next.docBounds = null;
323
324             // set typeBounds for all fields starting with `next' and duplicate
325
// javadoc/bounds for the rest of next's group.
326
for (FieldB fimpl = next.next; fimpl != null; fimpl = fimpl.next) {
327                 fimpl.typeBounds = tBounds;
328                 fimpl.docBounds = next.docBounds;
329             }
330
331             if (DEBUG) {
332                 if (prev != null) {
333                     System.err.println("Dumping prev chain:"); // NOI18N
334
prev.dumpBoundsForChain();
335                 }
336                 System.err.println("Dumping next chain:"); // NOI18N
337
next.dumpBoundsForChain();
338             }
339             
340             if (docBounds != null) {
341                 // regenerate -- this WILL create a DocBounds for the javadoc,
342
// it is based on an assumption, that bounds are correct -->
343
// javadoc will be OK.
344
next.regenerateJavaDoc();
345             }
346             adjustBounds();
347             if (DEBUG) {
348                 System.err.println("breakFieldGroup report:"); // NOI18N
349
System.err.println("-- first part tail details:"); // NOI18N
350
System.err.println("whole = " + wholeBounds + " header = " + headerBounds // NOI18N
351
+ " body = " + bodyBounds + " type = " + typeBounds + " single = " + isSingle()); // NOI18N
352
System.err.println("-- second part head details:"); // NOI18N
353
System.err.println("whole = " + next.wholeBounds + " header = " + next.headerBounds // NOI18N
354
+ " body = " + next.bodyBounds + " type = " + next.typeBounds + " single = " + next.isSingle()); // NOI18N
355
System.err.println("link deatils:"); // NOI18N
356
System.err.println("tail = " + this + " head = " + next + " tail's next = " + this.next + // NOI18N
357
" head's prev = " + next.previous); // NOI18N
358
source.dumpDocument();
359             }
360         } catch (Exception JavaDoc ex) {
361             SourceText.rethrowException(getElement(), ex);
362         }
363     }
364     
365     /** Changes contents of the initializer of the field.
366      */

367     public void changeInitializer(String JavaDoc newInitializer) throws SourceException {
368         if (!source.isGeneratorEnabled())
369             return;
370         
371         FieldElement f = cloneField();
372         f.setInitValue(newInitializer);
373         regenerateInitializer(f);
374     }
375     
376     protected void regenerateWhole(org.openide.src.Element model, boolean updatePositions)
377     throws SourceException {
378         super.regenerateWhole(model, updatePositions);
379         int headerEndOffset = headerBounds.getEnd().getOffset();
380         
381         if (updatePositions && (((FieldElement)model).getInitValue().length() > 0)) {
382             // adjust start of a body to point right after name, if the model has some
383
// initial value:
384
bodyBounds = new PositionBounds(
385                 source.createPos(headerEndOffset, Position.Bias.Backward),
386                 bodyBounds.getEnd());
387         } else {
388             // defense against null or ill-formed body bounds:
389
bodyBounds = null;
390         }
391     }
392     
393     /**
394      * Requests change of member's modifiers.
395      */

396     public void changeModifiers(int newMods) throws SourceException {
397         if (!source.isGeneratorEnabled())
398             return;
399         
400         if (isSingle()) {
401             super.changeModifiers(newMods);
402             return;
403         }
404         
405         FieldElement f = cloneField();
406         f.setModifiers(newMods);
407         source.runAtomic(getElement(), new SingleMaker(f));
408     }
409     
410     /**
411      * Requests a change of member's name.
412      */

413     public void changeName(final Identifier name) throws SourceException {
414         if (!source.isGeneratorEnabled())
415             return;
416         
417         if (isSingle()) {
418             super.changeName(name);
419             return;
420         }
421         source.runAtomic(getElement(), new ExceptionRunnable() {
422             public void run() throws Exception JavaDoc {
423                 CodeGenerator.fillTextBounds(headerBounds, name.getSourceName());
424             }
425         });
426     }
427     
428     /**
429      * Removes the element from the SourceText.
430      * @return UndoableEdit operation that will result in re-inserting of the element in
431      * the storage
432      */

433     public void remove(boolean collapseBefore, boolean collapseAfter) throws SourceException, IllegalStateException JavaDoc {
434         if (isSingle()) {
435             super.remove(collapseBefore, collapseAfter);
436             return;
437         }
438         removeFromGroup();
439     }
440     
441     /**
442      * Updates the storage binding object from an external SourceText.
443      */

444     public void updateFrom(Binding other) {
445     }
446     
447     public void changeJavaDoc(JavaDoc content) throws SourceException {
448         if (!source.isGeneratorEnabled())
449             return;
450         if (!isSingle()) {
451             FieldElement f=(FieldElement)getElement();
452             source.runAtomic(f, new SingleMaker(f));
453         }
454         super.changeJavaDoc(content);
455     }
456
457     private void regenerateInitializer(final FieldElement fld) throws SourceException {
458         final StyledDocument doc;
459
460         doc = source.getDocument();
461
462         ExceptionRunnable run = new ExceptionRunnable() {
463             public void run() throws Exception JavaDoc {
464                 String JavaDoc txt;
465                 String JavaDoc init = fld.getInitValue();
466         int start;
467         
468         if (bodyBounds == null) {
469             start = wholeBounds.getEnd().getOffset() - 1;
470         } else {
471             start = bodyBounds.getBegin().getOffset();
472         }
473                 
474                 if (init != null &&
475                 !init.equals("")) {
476                     StringWriter writer = new StringWriter();
477                     Writer iWriter = CodeGenerator.findIndentWriter(doc, start, writer);
478                     iWriter.write(" = "); // NOI18N
479
ElementPrinter prn = new ElementPrinterImpl(iWriter, fld, ElementPrinter.BODY_BEGIN,
480                     ElementPrinter.BODY_END);
481                     try {
482                         fld.print(prn);
483                     } catch (ElementPrinterInterruptException e) {
484                     }
485                     txt = writer.toString();
486                 } else {
487                     txt = "";
488                 }
489                 if (bodyBounds == null) {
490                     bodyBounds = new PositionBounds(
491                         headerBounds.getEnd(),
492                         source.createPos(wholeBounds.getEnd().getOffset() - 1, Position.Bias.Backward));
493                 } else if (bodyBounds.getBegin().getOffset() == bodyBounds.getEnd().getOffset()) {
494                     bodyBounds = new PositionBounds(
495                         headerBounds.getEnd(), bodyBounds.getEnd()
496                     );
497                 }
498                 bodyBounds.setText(txt);
499             }
500         };
501         
502         source.runAtomic(getElement(), run);
503     }
504     
505     private void unlinkField() {
506         FieldB p = previous;
507
508         if (previous != null) {
509             previous.next = next;
510             previous.single = previous.previous == null && next == null;
511             previous.adjustBounds();
512         }
513         if (next != null) {
514             next.previous = p;
515             next.single = next.next == null && p == null;
516             next.adjustBounds();
517         }
518         previous = next = null;
519         single = true;
520         adjustBounds();
521     }
522     
523     private FieldElement getField() {
524         return (FieldElement)getElement();
525     }
526
527     void removeFromGroup() throws SourceException {
528         PositionRef endRef;
529         PositionBounds removal;
530         
531         if (DEBUG) {
532             System.err.println("Field " + getField().getName().toString() + ": removing from SourceText file."); // NOI18N
533
System.err.println("previous = " + (previous == null ? (Object JavaDoc)previous : (Object JavaDoc)previous.getField())); // NOI18N
534
System.err.println("next = " + (next == null ? (Object JavaDoc)next : (Object JavaDoc)next.getField())); // NOI18N
535
dumpBoundsForChain();
536         }
537         endRef = source.createPos(wholeBounds.getEnd().getOffset(), Position.Bias.Forward);
538         if (previous != null) {
539             if (DEBUG) {
540                 System.err.println("previous = " + previous + " f = " + previous.getField().getName().toString()); // NOI18N
541
System.err.println("it's wholebounds = " + previous.wholeBounds); // NOI18N
542
}
543             removal = new PositionBounds(
544             source.createPos(previous.wholeBounds.getEnd().getOffset() - 1, Position.Bias.Forward),
545             source.createPos(wholeBounds.getEnd().getOffset() - 1, Position.Bias.Backward));
546         } else {
547             // We're the first field in the field element chain. We have to retain
548
// the type declarator in place and remove only the name.
549
removal = new PositionBounds(headerBounds.getBegin(), endRef);
550         }
551         // rebuild the field group links:
552
if (previous != null) {
553             // previous field ought to contain
554
// the delimiter after the field being removed.
555
// endRef points to the delimiter.
556
// bounds ought to contain entire field including the delimiter.
557
previous.wholeBounds = new PositionBounds(
558                 previous.wholeBounds.getBegin(),
559                 source.createPos(
560                     endRef.getOffset(),
561                     Position.Bias.Forward)
562                 );
563             if (DEBUG) {
564                 System.err.println("[removeFromGroup] previous' bounds: " + // NOI18N
565
previous.wholeBounds);
566             }
567         }
568         if (DEBUG) {
569             System.err.println("removal bounds: " + removal); // NOI18N
570
}
571         try {
572             CodeGenerator.clearBounds(removal, false);
573             if (DEBUG)
574                 source.dumpDocument();
575         } catch (BadLocationException ex) {
576             SourceText.rethrowException(getElement(),ex);
577         }
578         
579         if (DEBUG) {
580             System.err.println("breakFieldGroup report:"); // NOI18N
581
System.err.println("-- first part tail details:"); // NOI18N
582
if (previous != null) {
583                 System.err.println("whole = " + previous.wholeBounds + " header = " + previous.headerBounds // NOI18N
584
+ " body = " + previous.bodyBounds + " type = " + previous.typeBounds + " single = " + previous.isSingle()); // NOI18N
585
System.err.println("-- second part head details:"); // NOI18N
586
}
587             if (next != null) {
588                 System.err.println("whole = " + next.wholeBounds + " header = " + next.headerBounds // NOI18N
589
+ " body = " + next.bodyBounds + " type = " + next.typeBounds + " single = " + next.isSingle()); // NOI18N
590
}
591             System.err.println("link deatils:"); // NOI18N
592
System.err.println("tail = " + previous + " head = " + next); // NOI18N
593
if (previous != null) {
594                 System.err.println(" tail's next = " + previous.next); // NOI18N
595
}
596             if (next != null) {
597                 System.err.println("head's prev = " + next.previous); // NOI18N
598
}
599             System.err.println("myPrevious = " + previous + "myNext = " + next); // NOI18N
600
}
601         FieldB p = previous, n = next;
602         unlinkField();
603         if (DEBUG) {
604             System.err.println("link deatils after unlink:"); // NOI18N
605
System.err.println("tail = " + p + " head = " + n); // NOI18N
606
if (p != null) {
607                 System.err.println(" tail's next = " + p.next); // NOI18N
608
}
609             if (n != null) {
610                 System.err.println("head's prev = " + n.previous); // NOI18N
611
}
612             System.err.println("myPrevious = " + previous + "myNext = " + next); // NOI18N
613

614             if (DEBUG) {
615                 if (p != null) {
616                     System.err.println("Dumping previous chain:"); // NOI18N
617
p.dumpBoundsForChain();
618                 }
619                 if (n != null) {
620                     System.err.println("Dumping next chain:"); // NOI18N
621
n.dumpBoundsForChain();
622                 }
623             }
624         }
625         previous = next = null;
626     }
627     
628     private void dumpBoundsForChain() {
629         if (!DEBUG)
630             return;
631         FieldB begin = this;
632         while (begin.previous != null)
633             begin = begin.previous;
634         
635         while (begin != null) {
636             begin.dumpFieldBounds();
637             begin = begin.next;
638         }
639     }
640     
641     private void dumpFieldBounds() {
642         if (!DEBUG)
643             return;
644         System.err.println("Dumping bounds for: " + getField() + "(" + this + ")"); // NOI18N
645
System.err.println("header = " + headerBounds); // NOI18N
646
System.err.println("body = " + bodyBounds); // NOI18N
647
System.err.println("whole = " + wholeBounds); // NOI18N
648
System.err.println("type = " + typeBounds); // NOI18N
649
System.err.println("------------------------------------");
650     }
651     
652     private class SingleMaker extends PartialGenerator {
653         SingleMaker(FieldElement model) throws SourceException {
654             super(FieldB.this.findDocument(), model, true);
655         }
656         
657         private void makeSingle() throws Exception JavaDoc {
658             ElementBinding p = previous;
659             ElementBinding n = next;
660             PositionBounds newBounds;
661             
662             if (p == null && n == null) {
663                 throw new IllegalStateException JavaDoc("Field does not refer to its siblings"); // NOI18N
664
}
665             if (p == null) {
666                 p = containerRef.findPrevious(FieldB.this);
667             }
668             if (n == null) {
669                 n = containerRef.findNext(FieldB.this);
670             }
671             // removes this field from its group.
672
if (DEBUG) {
673                 System.err.println("[makeSingle] prevField = " + p + // NOI18N
674
", nextField = " + n); // NOI18N
675
}
676             removeFromGroup();
677             if (DEBUG)
678                 source.dumpDocument();
679             containerRef.insertChild(FieldB.this, p, n);
680         }
681         
682         public void run() throws Exception JavaDoc {
683             makeSingle();
684             this.posBounds = wholeBounds;
685             if (DEBUG) {
686                 System.err.println("Field made single:"); // NOI18N
687
dumpBoundsForChain();
688                 source.dumpDocument();
689             }
690             super.run();
691         }
692     }
693 }
694
Popular Tags