001: /*
002: * Sun Public License Notice
003: *
004: * The contents of this file are subject to the Sun Public License
005: * Version 1.0 (the "License"). You may not use this file except in
006: * compliance with the License. A copy of the License is available at
007: * http://www.sun.com/
008: *
009: * The Original Code is NetBeans. The Initial Developer of the Original
010: * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
011: * Microsystems, Inc. All Rights Reserved.
012: */
013:
014: package org.netbeans.editor;
015:
016: import java.awt.Color;
017: import java.util.List;
018:
019: import javax.swing.text.BadLocationException;
020: import javax.swing.text.JTextComponent;
021: import javax.swing.text.Style;
022: import javax.swing.text.StyleConstants;
023:
024: /**
025: * Various draw layers are located here
026: *
027: * @author Miloslav Metelka
028: * @version 1.00
029: */
030:
031: public class DrawLayerFactory {
032:
033: /** Syntax draw layer name */
034: public static final String SYNTAX_LAYER_NAME = "syntax-layer"; // NOI18N
035:
036: /** Syntax draw layer visibility */
037: public static final int SYNTAX_LAYER_VISIBILITY = 1000;
038:
039: /** Bookmark draw layer name */
040: public static final String BOOKMARK_LAYER_NAME = "bookmark-layer"; // NOI18N
041:
042: /** Bookmark draw layer visibility */
043: public static final int BOOKMARK_LAYER_VISIBILITY = 2000;
044:
045: /** Annotation draw layer name */
046: public static final String ANNOTATION_LAYER_NAME = "annotation-layer"; // NOI18N
047:
048: /** Annotation draw layer visibility */
049: public static final int ANNOTATION_LAYER_VISIBILITY = 2100;
050:
051: /** Highlight search layer name */
052: public static final String HIGHLIGHT_SEARCH_LAYER_NAME = "highlight-search-layer"; // NOI18N
053:
054: /** Highlight search layer visibility */
055: public static final int HIGHLIGHT_SEARCH_LAYER_VISIBILITY = 9000;
056:
057: /** Incremental search layer name */
058: public static final String INC_SEARCH_LAYER_NAME = "inc-search-layer"; // NOI18N
059:
060: /** Incremental search layer visibility */
061: public static final int INC_SEARCH_LAYER_VISIBILITY = 9500;
062:
063: /** Selection draw layer name */
064: public static final String CARET_LAYER_NAME = "caret-layer"; // NOI18N
065:
066: /** Selection draw layer visibility */
067: public static final int CARET_LAYER_VISIBILITY = 10000;
068:
069: /** Guarded layer name */
070: public static final String GUARDED_LAYER_NAME = "guarded-layer"; // NOI18N
071:
072: /** Guarded layer visibility */
073: public static final int GUARDED_LAYER_VISIBILITY = 1400;
074:
075: /**
076: * Layer that colors the text according to the tokens that were parsed. It's
077: * active all the time.
078: */
079: public static class SyntaxLayer extends DrawLayer.AbstractLayer {
080:
081: public SyntaxLayer() {
082: super (SYNTAX_LAYER_NAME);
083: }
084:
085: public void init(DrawContext ctx) {
086: }
087:
088: public boolean isActive(DrawContext ctx,
089: MarkFactory.DrawMark mark) {
090: return true;
091: }
092:
093: public void updateContext(DrawContext ctx) {
094: // Get the token type and docColorings
095: TokenID tokenID = ctx.getTokenID();
096: TokenContextPath tcp = ctx.getTokenContextPath();
097: if (tokenID != null && tcp != null) {
098: // Get the coloring according the name of the token
099: String fullName = tcp.getFullTokenName(tokenID);
100: Coloring c = ctx.getEditorUI().getColoring(fullName);
101: if (c != null) {
102: c.apply(ctx);
103:
104: } else { // Token coloring null, try category
105: TokenCategory cat = tokenID.getCategory();
106: if (cat != null) {
107: fullName = tcp.getFullTokenName(cat);
108: c = ctx.getEditorUI().getColoring(fullName);
109: if (c != null) {
110: c.apply(ctx);
111: }
112: }
113: }
114: }
115: }
116:
117: }
118:
119: /**
120: * This layer colors the line by a color specified in constructor It
121: * requires only activation mark since it deactivates automatically at the
122: * end of line.
123: */
124: public static abstract class ColorLineLayer extends
125: DrawLayer.AbstractLayer {
126:
127: /** Coloring to use for highlighting */
128: Coloring coloring;
129:
130: public ColorLineLayer(String name) {
131: super (name);
132: }
133:
134: public boolean extendsEOL() {
135: return true;
136: }
137:
138: public void init(DrawContext ctx) {
139: coloring = null;
140: }
141:
142: public boolean isActive(DrawContext ctx,
143: MarkFactory.DrawMark mark) {
144: boolean active;
145: if (mark != null) {
146: active = (ctx.getEditorUI().getComponent() != null)
147: && mark.activateLayer;
148: if (active) {
149: try {
150: BaseDocument doc = ctx.getEditorUI()
151: .getDocument();
152: int nextRowStartPos = Utilities.getRowStart(
153: doc, ctx.getFragmentOffset(), 1);
154: if (nextRowStartPos < 0) { // end of doc
155: nextRowStartPos = Integer.MAX_VALUE;
156: }
157: setNextActivityChangeOffset(nextRowStartPos);
158:
159: } catch (BadLocationException e) {
160: active = false;
161: }
162: }
163:
164: } else {
165: active = false;
166: }
167:
168: return active;
169: }
170:
171: public void updateContext(DrawContext ctx) {
172: if (coloring == null) {
173: coloring = getColoring(ctx);
174: }
175: if (coloring != null) {
176: coloring.apply(ctx);
177: }
178: }
179:
180: protected abstract Coloring getColoring(DrawContext ctx);
181:
182: }
183:
184: /**
185: * Layer that covers selection services provided by caret. This layer
186: * assumes that both caretMark and selectionMark in BaseCaret are properly
187: * served so that their active flags are properly set.
188: */
189: public static class CaretLayer extends DrawLayer.AbstractLayer {
190:
191: Coloring coloring;
192:
193: public CaretLayer() {
194: super (CARET_LAYER_NAME);
195: }
196:
197: public boolean extendsEmptyLine() {
198: return true;
199: }
200:
201: public void init(DrawContext ctx) {
202: coloring = null;
203: }
204:
205: public boolean isActive(DrawContext ctx,
206: MarkFactory.DrawMark mark) {
207: boolean active;
208: if (mark != null) {
209: active = mark.activateLayer;
210: } else {
211: JTextComponent c = ctx.getEditorUI().getComponent();
212: active = (c != null)
213: && c.getCaret().isSelectionVisible()
214: && ctx.getFragmentOffset() >= c
215: .getSelectionStart()
216: && ctx.getFragmentOffset() < c
217: .getSelectionEnd();
218: }
219:
220: return active;
221: }
222:
223: public void updateContext(DrawContext ctx) {
224: if (coloring == null) {
225: coloring = ctx.getEditorUI().getColoring(
226: SettingsNames.SELECTION_COLORING);
227: }
228: if (coloring != null) {
229: coloring.apply(ctx);
230: }
231: }
232:
233: }
234:
235: /**
236: * Highlight search layer highlights all occurences of the searched string
237: * in text.
238: */
239: public static class HighlightSearchLayer extends
240: DrawLayer.AbstractLayer {
241:
242: /** Pairs of start and end position of the found string */
243: int blocks[] = new int[] { -1, -1 };
244:
245: /** Coloring to use for highlighting */
246: Coloring coloring;
247:
248: /** Current index for painting */
249: int curInd;
250:
251: /** Enabled flag */
252: boolean enabled;
253:
254: public HighlightSearchLayer() {
255: super (HIGHLIGHT_SEARCH_LAYER_NAME);
256: }
257:
258: public boolean isEnabled() {
259: return enabled;
260: }
261:
262: public void setEnabled(boolean enabled) {
263: this .enabled = enabled;
264: }
265:
266: public void init(DrawContext ctx) {
267: if (enabled) {
268: try {
269: BaseDocument doc = ctx.getEditorUI().getDocument();
270: blocks = FindSupport.getFindSupport().getBlocks(
271: blocks, doc, ctx.getStartOffset(),
272: ctx.getEndOffset());
273: } catch (BadLocationException e) {
274: blocks = new int[] { -1, -1 };
275: }
276: coloring = null; // reset so it will be re-read
277: curInd = 0;
278: }
279: }
280:
281: public boolean isActive(DrawContext ctx,
282: MarkFactory.DrawMark mark) {
283: boolean active;
284: if (enabled) {
285: int pos = ctx.getFragmentOffset();
286: if (pos == blocks[curInd]) {
287: active = true;
288: setNextActivityChangeOffset(blocks[curInd + 1]);
289:
290: } else if (pos == blocks[curInd + 1]) {
291: active = false;
292: curInd += 2;
293: setNextActivityChangeOffset(blocks[curInd]);
294: if (pos == blocks[curInd]) { // just follows
295: setNextActivityChangeOffset(blocks[curInd + 1]);
296: active = true;
297: }
298:
299: } else {
300: setNextActivityChangeOffset(blocks[curInd]);
301: active = false;
302: }
303: } else {
304: active = false;
305: }
306:
307: return active;
308: }
309:
310: public void updateContext(DrawContext ctx) {
311: int pos = ctx.getFragmentOffset();
312: if (pos >= blocks[curInd] && pos < blocks[curInd + 1]) {
313: if (coloring == null) {
314: coloring = ctx.getEditorUI().getColoring(
315: SettingsNames.HIGHLIGHT_SEARCH_COLORING);
316: }
317: if (coloring != null) {
318: coloring.apply(ctx);
319: }
320: }
321: }
322:
323: }
324:
325: /**
326: * Layer covering incremental search. There are just two positions begining
327: * and end of the searched string
328: */
329: public static class IncSearchLayer extends DrawLayer.AbstractLayer {
330:
331: /** Coloring to use for highlighting */
332: Coloring coloring;
333:
334: /** Position where the searched string begins */
335: int pos;
336:
337: /** Length of area to highlight */
338: int len;
339:
340: /** Whether this layer is enabled */
341: boolean enabled;
342:
343: public IncSearchLayer() {
344: super (INC_SEARCH_LAYER_NAME);
345: }
346:
347: public boolean isEnabled() {
348: return enabled;
349: }
350:
351: public void setEnabled(boolean enabled) {
352: this .enabled = enabled;
353: }
354:
355: void setArea(int pos, int len) {
356: this .pos = pos;
357: this .len = len;
358: }
359:
360: int getOffset() {
361: return pos;
362: }
363:
364: int getLength() {
365: return len;
366: }
367:
368: public void init(DrawContext ctx) {
369: setNextActivityChangeOffset(enabled ? pos
370: : Integer.MAX_VALUE);
371: }
372:
373: public boolean isActive(DrawContext ctx,
374: MarkFactory.DrawMark mark) {
375: boolean active = false;
376: if (enabled) {
377: if (ctx.getFragmentOffset() == pos) {
378: active = true;
379: setNextActivityChangeOffset(pos + len);
380: }
381: }
382:
383: return active;
384: }
385:
386: public void updateContext(DrawContext ctx) {
387: if (coloring == null) {
388: coloring = ctx.getEditorUI().getColoring(
389: SettingsNames.INC_SEARCH_COLORING);
390: }
391: if (coloring != null) {
392: coloring.apply(ctx);
393: }
394: }
395:
396: }
397:
398: /** Bookmark layer */
399: public static class BookmarkLayer extends ColorLineLayer {
400:
401: public BookmarkLayer() {
402: super (BOOKMARK_LAYER_NAME);
403: }
404:
405: protected Coloring getColoring(DrawContext ctx) {
406: return ctx.getEditorUI().getColoring(
407: SettingsNames.BOOKMARK_COLORING);
408: }
409:
410: }
411:
412: /** Layer for guarded blocks */
413: static class GuardedLayer extends ColorLineLayer {
414:
415: GuardedDocument doc;
416:
417: GuardedLayer() {
418: super (GUARDED_LAYER_NAME);
419: }
420:
421: public void init(DrawContext ctx) {
422: super .init(ctx);
423: doc = (GuardedDocument) ctx.getEditorUI().getDocument();
424: }
425:
426: public boolean isActive(DrawContext ctx,
427: MarkFactory.DrawMark mark) {
428: boolean active;
429: if (mark != null) {
430: active = mark.activateLayer;
431: } else {
432: active = doc.isPosGuarded(ctx.getFragmentOffset());
433: }
434:
435: return active;
436: }
437:
438: protected Coloring getColoring(DrawContext ctx) {
439: return ctx.getEditorUI().getColoring(
440: SettingsNames.GUARDED_COLORING);
441: }
442:
443: }
444:
445: /** Style layer getting color settings from particular style */
446: public static class StyleLayer extends DrawLayer.AbstractLayer {
447:
448: protected Style style;
449:
450: protected MarkChain markChain;
451:
452: protected Color backColor;
453:
454: protected Color foreColor;
455:
456: public StyleLayer(String layerName, BaseDocument doc,
457: Style style) {
458: super (layerName);
459: this .style = style;
460: markChain = new MarkChain(doc, layerName);
461: }
462:
463: public boolean extendsEOL() {
464: return true;
465: }
466:
467: public final MarkChain getMarkChain() {
468: return markChain;
469: }
470:
471: public void init(DrawContext ctx) {
472: foreColor = StyleConstants.getForeground(style);
473: backColor = StyleConstants.getBackground(style);
474: }
475:
476: public boolean isActive(DrawContext ctx,
477: MarkFactory.DrawMark mark) {
478: boolean active = false;
479: if (mark != null) {
480: active = (ctx.getEditorUI().getComponent() != null)
481: && mark.activateLayer;
482: if (active) {
483: try {
484: BaseDocument doc = ctx.getEditorUI()
485: .getDocument();
486: int nextRowStartPos = Utilities.getRowStart(
487: doc, ctx.getFragmentOffset(), 1);
488: if (nextRowStartPos < 0) { // end of doc
489: nextRowStartPos = Integer.MAX_VALUE;
490: }
491:
492: setNextActivityChangeOffset(nextRowStartPos);
493:
494: } catch (BadLocationException e) {
495: active = false;
496: }
497: }
498:
499: }
500:
501: return active;
502: }
503:
504: public void updateContext(DrawContext ctx) {
505: if (foreColor != null) {
506: ctx.setForeColor(foreColor);
507: }
508: if (backColor != null) {
509: ctx.setBackColor(backColor);
510: }
511: }
512:
513: public String toString() {
514: return super .toString()
515: + ((markChain != null) ? (", " + markChain) : ""); // NOI18N
516: }
517:
518: }
519:
520: /** Test layer for coloring the specific words */
521: public static class WordColoringLayer extends
522: DrawLayer.AbstractLayer {
523:
524: protected StringMap stringMap = new StringMap();
525:
526: public WordColoringLayer(String name) {
527: super (name);
528: }
529:
530: public void put(String s, Coloring c) {
531: stringMap.put(s, c);
532: }
533:
534: public void put(String[] strings, Coloring c) {
535: for (int i = 0; i < strings.length; i++) {
536: put(strings[i], c);
537: }
538: }
539:
540: public void put(List stringList, Coloring c) {
541: String strings[] = new String[stringList.size()];
542: stringList.toArray(strings);
543: put(strings, c);
544: }
545:
546: public void init(DrawContext ctx) {
547: }
548:
549: public boolean isActive(DrawContext ctx,
550: MarkFactory.DrawMark mark) {
551: return true;
552: }
553:
554: public void updateContext(DrawContext ctx) {
555: Coloring c = (Coloring) stringMap.get(ctx.getBuffer(), ctx
556: .getTokenOffset(), ctx.getTokenLength());
557: if (c != null) {
558: c.apply(ctx);
559: }
560: }
561:
562: }
563:
564: /**
565: * Annotation layer for drawing of annotations. Each mark which is stored in
566: * markChain has corresponding Annotation. More than one Annotation can
567: * share one mark. In this case the only one annotation is active and this
568: * must be drawn.
569: */
570: public static class AnnotationLayer extends DrawLayer.AbstractLayer {
571:
572: /** Current coloring */
573: private Coloring coloring;
574:
575: /** Chain of marks attached to this layer */
576: private MarkChain markChain;
577:
578: public AnnotationLayer(BaseDocument doc) {
579: super (ANNOTATION_LAYER_NAME);
580: coloring = null;
581: markChain = new MarkChain(doc, ANNOTATION_LAYER_NAME);
582: }
583:
584: /**
585: * Get chain of marks attached to this draw layer
586: *
587: * @return mark chain
588: */
589: public final MarkChain getMarkChain() {
590: return markChain;
591: }
592:
593: public boolean extendsEOL() {
594: return true;
595: }
596:
597: public boolean isActive(DrawContext ctx,
598: MarkFactory.DrawMark mark) {
599: int nextActivityOffset;
600: coloring = null;
601:
602: if (mark == null)
603: return false;
604:
605: if (ctx.getEditorUI().getComponent() == null
606: || !mark.activateLayer)
607: return false;
608:
609: BaseDocument doc = ctx.getEditorUI().getDocument();
610:
611: // Gets the active annotation attached to this mark. It is possible
612: // that
613: // no active annotation might exist for the mark
614: AnnotationDesc anno = doc.getAnnotations()
615: .getActiveAnnotation(mark);
616: if (anno == null)
617: return false;
618:
619: int nextLineStart = -1;
620: try {
621: nextLineStart = Utilities.getRowStart(doc, ctx
622: .getFragmentOffset(), 1);
623: } catch (BadLocationException e) {
624: return false;
625: }
626: if (nextLineStart < 0) { // end of doc
627: nextLineStart = Integer.MAX_VALUE;
628: }
629: if (anno.isWholeLine()) {
630: nextActivityOffset = nextLineStart;
631: } else {
632: nextActivityOffset = ctx.getFragmentOffset()
633: + anno.getLength();
634: if (nextActivityOffset > nextLineStart)
635: nextActivityOffset = nextLineStart;
636: }
637:
638: setNextActivityChangeOffset(nextActivityOffset);
639: coloring = anno.getColoring();
640:
641: // The following code ensures that if active annotation does not
642: // have highlight the color of next one will be used.
643: // It was decided that it will not be used
644: //
645: // if (coloring.getBackColor() == null) {
646: // AnnotationDesc[] annos =
647: // doc.getAnnotations().getPasiveAnnotations(anno.getLine());
648: // if (annos != null) {
649: // for (int i=0; i<annos.length; i++) {
650: // if (annos[i].getColoring().getBackColor() != null) {
651: // coloring = annos[i].getColoring();
652: // break;
653: // }
654: // }
655: // }
656: // }
657:
658: return true;
659: }
660:
661: public void updateContext(DrawContext ctx) {
662: if (coloring != null) {
663: coloring.apply(ctx);
664: }
665: }
666:
667: }
668:
669: }
|