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.awt.Container;
018: import java.awt.Cursor;
019: import java.awt.Dimension;
020: import java.awt.Graphics;
021: import java.awt.Insets;
022: import java.awt.Point;
023: import java.awt.Rectangle;
024: import java.awt.Shape;
025: import java.awt.event.ActionEvent;
026: import java.beans.PropertyChangeEvent;
027: import java.beans.PropertyChangeListener;
028: import java.util.Iterator;
029: import java.util.List;
030:
031: import javax.swing.Action;
032: import javax.swing.JComponent;
033: import javax.swing.JEditorPane;
034: import javax.swing.SwingUtilities;
035: import javax.swing.event.DocumentEvent;
036: import javax.swing.event.DocumentListener;
037: import javax.swing.plaf.ComponentUI;
038: import javax.swing.plaf.TextUI;
039: import javax.swing.text.AttributeSet;
040: import javax.swing.text.BadLocationException;
041: import javax.swing.text.Caret;
042: import javax.swing.text.Document;
043: import javax.swing.text.EditorKit;
044: import javax.swing.text.Element;
045: import javax.swing.text.JTextComponent;
046: import javax.swing.text.Position;
047: import javax.swing.text.TextAction;
048: import javax.swing.text.View;
049: import javax.swing.text.ViewFactory;
050:
051: /**
052: * Text UI implementation
053: *
054: * @author Miloslav Metelka
055: * @version 1.00
056: */
057:
058: public class BaseTextUI extends TextUI implements ViewFactory,
059: PropertyChangeListener, DocumentListener {
060:
061: /** Get rid of mantisa problems */
062: private static final int MAX_SPAN = Integer.MAX_VALUE - 512;
063:
064: /** Minimum component width */
065: private static final int MIN_WIDTH = 300;
066: /** Minimum component height */
067: private static final int MIN_HEIGHT = 200;
068:
069: /** Editor component */
070: private JTextComponent component;
071:
072: /** Extended UI */
073: private EditorUI editorUI;
074:
075: /** ID of the component in registry */
076: int componentID = -1;
077:
078: /** Instance of the <tt>GetFocusedComponentAction</tt> */
079: private static final GetFocusedComponentAction gfcAction = new GetFocusedComponentAction();
080:
081: /** Root view of view hierarchy */
082: private RootView rootView;
083:
084: public BaseTextUI() {
085: rootView = new RootView();
086: }
087:
088: static JTextComponent getFocusedComponent() {
089: return gfcAction.getFocusedComponent2();
090: }
091:
092: /** Called when the model of component is changed */
093: protected void modelChanged(BaseDocument oldDoc, BaseDocument newDoc) {
094: if (oldDoc != null) {
095: oldDoc.removeDocumentListener(this );
096: }
097:
098: if (newDoc != null) {
099: newDoc.addDocumentListener(this );
100: Registry.activate(newDoc); // Activate the new document
101:
102: ViewFactory f = rootView.getViewFactory();
103: BaseKit kit = (BaseKit) getEditorKit(component);
104:
105: component.removeAll();
106:
107: Element elem = newDoc.getDefaultRootElement();
108: View v = f.create(elem);
109: rootView.setView(v);
110: rootView.updateMainHeight(); // compute actual height of views
111:
112: component.revalidate();
113:
114: // Execute actions related to document installaction into the
115: // component
116: Settings.KitAndValue[] kv = Settings.getValueHierarchy(kit
117: .getClass(),
118: SettingsNames.DOC_INSTALL_ACTION_NAME_LIST);
119: for (int i = kv.length - 1; i >= 0; i--) {
120: List actList = (List) kv[i].value;
121: actList = kit.translateActionNameList(actList); // translate
122: // names to
123: // actions
124: if (actList != null) {
125: for (Iterator iter = actList.iterator(); iter
126: .hasNext();) {
127: Action a = (Action) iter.next();
128: a.actionPerformed(new ActionEvent(component,
129: ActionEvent.ACTION_PERFORMED, "")); // NOI18N
130: }
131: }
132: }
133: }
134:
135: }
136:
137: /** Update height of the views */
138: void updateHeight() {
139: rootView.updateMainHeight();
140: }
141:
142: /** Installs the UI for a component. */
143: public void installUI(JComponent c) {
144: if (c instanceof JTextComponent) {
145: component = (JTextComponent) c; // this is associated component
146:
147: getEditorUI().installUI(component);
148:
149: component.setOpaque(true); // opaque by default
150: component.setAutoscrolls(true); // autoscrolling by default
151:
152: // attach to the model and component
153: component.addPropertyChangeListener(this );
154:
155: BaseKit kit = (BaseKit) getEditorKit(component);
156: // Create and attach caret
157: Caret caret = kit.createCaret();
158: component.setCaretColor(Color.black); // will be changed by
159: // settings later
160: component.setCaret(caret);
161:
162: // assign blink rate
163: int br = SettingsUtil.getInteger(Utilities
164: .getKitClass(component),
165: SettingsNames.CARET_BLINK_RATE,
166: SettingsDefaults.defaultCaretBlinkRate.intValue());
167: caret.setBlinkRate(br);
168:
169: // Create document
170: BaseDocument doc = Utilities.getDocument(component);
171: if (doc != null) {
172: modelChanged(null, doc);
173: }
174:
175: /**
176: * Patch for 1.3 - assigns a null UI input map into the component.
177: * The following block stands for the following code:
178: *
179: * SwingUtilities.replaceUIInputMap(c, JComponent.WHEN_FOCUSED,
180: * null);
181: *
182: */
183:
184: try {
185: Class inputMapClass = Class
186: .forName("javax.swing.InputMap"); // NOI18N
187: if (inputMapClass != null) {
188: java.lang.reflect.Method replaceUIInputMapMethod = SwingUtilities.class
189: .getDeclaredMethod(
190: "replaceUIInputMap",
191: new Class[] { JComponent.class,
192: Integer.TYPE, inputMapClass }); // NOI18N
193: replaceUIInputMapMethod.invoke(null, new Object[] {
194: c, new Integer(JComponent.WHEN_FOCUSED),
195: null });
196: }
197: } catch (Throwable t) {
198: }
199:
200: Registry.addComponent(component);
201: Registry.activate(component);
202: component.setCursor(Cursor
203: .getPredefinedCursor(Cursor.TEXT_CURSOR));
204: }
205: }
206:
207: /** Deinstalls the UI for a component */
208: public void uninstallUI(JComponent c) {
209: component.removePropertyChangeListener(this );
210: component.getDocument().removeDocumentListener(this );
211:
212: rootView.setView(null); // sets inner view of root view to null
213: component.removeAll();
214: component.setKeymap(null);
215:
216: component.setCaret(null);
217:
218: getEditorUI().uninstallUI(component);
219: Registry.removeComponent(component);
220:
221: // Clear the editorUI so it will be recreated according to the kit
222: // of the component for which the installUI() is called
223: editorUI = null;
224:
225: component = null;
226: }
227:
228: /**
229: * Paint the UI.
230: *
231: * @param g
232: * the graphics context
233: * @param c
234: * the editor component
235: */
236: public void paint(Graphics g, JComponent c) {
237: if ((rootView.getViewCount() > 0)
238: && (rootView.getView(0) != null)) {
239: BaseDocument doc = Utilities.getDocument(component);
240: if (c == component && doc != null) {
241: doc.readLock();
242: try {
243:
244: // paint the view hierarchy
245: getEditorUI().paint(g);
246:
247: // paint the caret
248: Caret caret = component.getCaret();
249: if (caret != null) {
250: caret.paint(g);
251: }
252:
253: // check virtual size change
254: if (getEditorUI().virtualSizeUpdated) {
255: preferenceChanged(true, true);
256: }
257:
258: } finally {
259: doc.readUnlock();
260: }
261: }
262: }
263: }
264:
265: /** Paint either image region or classic graphics region */
266: void paintRegion(Graphics g) {
267: rootView.paint(g, null);
268: }
269:
270: /**
271: * Gets the preferred size for the editor component. If the component has
272: * been given a size prior to receiving this request, it will set the size
273: * of the view hierarchy to reflect the size of the component before
274: * requesting the preferred size of the view hierarchy. This allows
275: * formatted views to format to the current component size before answering
276: * the request. Other views don't care about currently formatted size and
277: * give the same answer either way.
278: *
279: * @param c
280: * the editor component
281: * @return the size
282: */
283: public Dimension getPreferredSize(JComponent c) {
284: Insets i = c.getInsets();
285: Insets margin = getEditorUI().getTextMargin();
286: Dimension d = c.getSize();
287: BaseDocument doc = (c instanceof JTextComponent) ? Utilities
288: .getDocument((JTextComponent) c) : null;
289: if (doc != null) {
290: doc.readLock();
291: }
292: try {
293: // first try to change the root view size
294: if ((d.width > (i.left + i.right))
295: && (d.height > (i.top + i.bottom))) {
296: rootView.setSize(d.width - i.left - i.right, d.height
297: - i.top - i.bottom);
298: }
299: // now get the real preferred size
300: d.width = (int) Math.min(rootView
301: .getPreferredSpan(View.X_AXIS)
302: + i.left + i.right + margin.left + margin.right,
303: MAX_SPAN);
304: d.height = (int) Math.min(rootView
305: .getPreferredSpan(View.Y_AXIS)
306: + i.top + i.bottom + margin.top + margin.bottom,
307: MAX_SPAN);
308: } finally {
309: if (doc != null) {
310: doc.readUnlock();
311: }
312: }
313: return d;
314: }
315:
316: /**
317: * Gets the minimum size for the editor component.
318: *
319: * @param c
320: * the editor component
321: * @return the size
322: */
323: public Dimension getMinimumSize(JComponent c) {
324: Insets i = c.getInsets();
325: Insets margin = getEditorUI().getTextMargin();
326: Dimension d = new Dimension();
327: BaseDocument doc = (c instanceof JTextComponent) ? Utilities
328: .getDocument((JTextComponent) c) : null;
329: if (doc != null) {
330: doc.readLock();
331: }
332: try {
333: d.width = (int) rootView.getMinimumSpan(View.X_AXIS)
334: + i.left + i.right + margin.left + margin.right;
335: d.height = (int) rootView.getMinimumSpan(View.Y_AXIS)
336: + i.top + i.bottom + margin.top + margin.bottom;
337: } finally {
338: if (doc != null) {
339: doc.readUnlock();
340: }
341: }
342: return d;
343: }
344:
345: /**
346: * Gets the maximum size for the editor component.
347: *
348: * @param c
349: * the editor component
350: * @return the size
351: */
352: public Dimension getMaximumSize(JComponent c) {
353: Insets i = c.getInsets();
354: Insets margin = getEditorUI().getTextMargin();
355: Dimension d = new Dimension();
356: BaseDocument doc = (c instanceof JTextComponent) ? Utilities
357: .getDocument((JTextComponent) c) : null;
358: if (doc != null) {
359: doc.readLock();
360: }
361: try {
362: d.width = (int) Math.min(rootView
363: .getMaximumSpan(View.X_AXIS)
364: + i.left + i.right + margin.left + margin.right,
365: MAX_SPAN);
366: d.height = (int) Math.min(rootView
367: .getMaximumSpan(View.Y_AXIS)
368: + i.top + i.bottom + margin.top + margin.bottom,
369: MAX_SPAN);
370: } finally {
371: if (doc != null) {
372: doc.readUnlock();
373: }
374: }
375: return d;
376: }
377:
378: public void invalidateStartY() {
379: rootView.invalidateStartY();
380: }
381:
382: /** Similair to modelToView() but without acquiring the document read lock. */
383: public Rectangle modelToView(JTextComponent c, int pos)
384: throws BadLocationException {
385: return (Rectangle) rootView.modelToView(pos, null,
386: Position.Bias.Forward);
387: }
388:
389: public Rectangle modelToView(JTextComponent c, int pos,
390: Position.Bias bias) throws BadLocationException {
391: return (Rectangle) rootView.modelToView(pos, null, bias);
392: }
393:
394: void modelToViewDG(int pos, DrawGraphics dg)
395: throws BadLocationException {
396: rootView.modelToViewDG(pos, dg);
397: }
398:
399: public int getYFromPos(int pos) throws BadLocationException {
400: return rootView.getYFromPos(pos);
401: }
402:
403: public int getPosFromY(int y) throws BadLocationException {
404: return rootView.getPosFromY(y);
405: }
406:
407: public int getBaseX(int y) {
408: return rootView.getBaseX(y);
409: }
410:
411: public int viewToModel(JTextComponent c, Point pt) {
412: return viewToModel(c, pt.x, pt.y);
413: }
414:
415: public int viewToModel(JTextComponent c, int x, int y) {
416: return rootView.viewToModel(x, y, null, null);
417: }
418:
419: public int viewToModel(JTextComponent c, Point pt,
420: Position.Bias[] biasReturn) {
421: return rootView.viewToModel(pt.x, pt.y, null, biasReturn);
422: }
423:
424: /**
425: * Next visually represented model location where caret can be placed. This
426: * version works without placing read lock on the document.
427: */
428: public int getNextVisualPositionFrom(JTextComponent t, int pos,
429: Position.Bias b, int direction, Position.Bias[] biasRet)
430: throws BadLocationException {
431: return rootView.getNextVisualPositionFrom(pos, b, null,
432: direction, biasRet);
433: }
434:
435: public void damageRange(JTextComponent c, int p0, int p1) {
436: damageRange(c, p0, p1, Position.Bias.Forward,
437: Position.Bias.Backward);
438: }
439:
440: /**
441: * Causes the portion of the view responsible for the given part of the
442: * model to be repainted.
443: *
444: * @param p0
445: * the beginning of the range >= 0
446: * @param p1
447: * the end of the range >= p0
448: */
449: public void damageRange(JTextComponent t, int p0, int p1,
450: Position.Bias p0Bias, Position.Bias p1Bias) {
451: BaseDocument doc = Utilities.getDocument(component);
452: if (t == component && doc != null) {
453: doc.readLock();
454: try {
455: Rectangle r = (Rectangle) rootView.modelToView(p0,
456: p0Bias, p1, p1Bias, null);
457: component.repaint(r.x, r.y, r.width, r.height);
458: } catch (BadLocationException e) {
459: } finally {
460: doc.readUnlock();
461: }
462: }
463: }
464:
465: /**
466: * Fetches the EditorKit for the UI.
467: *
468: * @return the component capabilities
469: */
470: public EditorKit getEditorKit(JTextComponent c) {
471: JEditorPane pane = (JEditorPane) component;
472: return pane.getEditorKit();
473: }
474:
475: /** Fetches a root view of the view hierarchy. */
476: public View getRootView(JTextComponent c) {
477: return rootView;
478: }
479:
480: /** Get extended UI. This is called from views to get correct extended UI. */
481: public EditorUI getEditorUI() {
482: if (editorUI == null) {
483: BaseKit kit = (BaseKit) getEditorKit(component);
484: editorUI = kit.createEditorUI();
485: }
486: return editorUI;
487: }
488:
489: /**
490: * This method gets called when a bound property is changed. We are looking
491: * for document changes on the component.
492: */
493: public void propertyChange(PropertyChangeEvent evt) {
494: String propName = evt.getPropertyName();
495: if ("document".equals(propName)) {
496: BaseDocument oldDoc = (evt.getOldValue() instanceof BaseDocument) ? (BaseDocument) evt
497: .getOldValue()
498: : null;
499: BaseDocument newDoc = (evt.getNewValue() instanceof BaseDocument) ? (BaseDocument) evt
500: .getNewValue()
501: : null;
502: modelChanged(oldDoc, newDoc);
503: }
504: }
505:
506: /** Insert to document notification. */
507: public void insertUpdate(DocumentEvent evt) {
508: rootView.insertUpdate(evt, null, rootView.getViewFactory());
509: if (((BaseDocumentEvent) evt).getLFCount() > 0
510: || evt.getLength() == 0) {
511: if (getEditorUI().updateVirtualHeight(rootView.getHeight())) {
512: preferenceChanged(true, true);
513: }
514: getEditorUI().checkLineLimit();
515: if (evt.getLength() == 0) { // initial read performed !!! needed?
516: component.repaint(500);
517: }
518: }
519: }
520:
521: /** Remove from document notification. */
522: public void removeUpdate(DocumentEvent evt) {
523: rootView.removeUpdate(evt, null, rootView.getViewFactory());
524: if (((BaseDocumentEvent) evt).getLFCount() > 0) {
525: if (getEditorUI().updateVirtualHeight(rootView.getHeight())) {
526: preferenceChanged(true, true);
527: }
528: }
529: }
530:
531: /**
532: * The change in document notification.
533: *
534: * @param evt
535: * The change notification from the currently associated
536: * document.
537: */
538: public void changedUpdate(DocumentEvent evt) {
539: if (evt instanceof BaseDocumentEvent) {
540: BaseDocumentEvent bdevt = (BaseDocumentEvent) evt;
541: BaseDocument doc = (BaseDocument) bdevt.getDocument();
542: String layerName = bdevt.getDrawLayerName();
543: if (layerName != null) {
544: getEditorUI().addLayer(doc.findLayer(layerName),
545: bdevt.getDrawLayerVisibility());
546: } else { // some other type of change, propagate to root view
547: rootView.changedUpdate(evt, null, rootView
548: .getViewFactory());
549: }
550: }
551: }
552:
553: /**
554: * Creates a view for an element.
555: *
556: * @param elem
557: * the element
558: * @return the newly created view or null
559: */
560: public View create(Element elem) {
561: View v = null;
562: if (elem instanceof BaseElement) {
563: v = new LeafView(elem);
564: }
565: return v;
566: }
567:
568: /**
569: * Creates a view for an element.
570: *
571: * @param elem
572: * the element
573: * @param p0
574: * the starting offset >= 0
575: * @param p1
576: * the ending offset >= p0
577: * @return the view
578: */
579: public View create(Element elem, int p0, int p1) {
580: return new LeafView(elem);
581: }
582:
583: // from JEditorPane ui
584: public static ComponentUI createUI(JComponent c) {
585: return new BaseTextUI();
586: }
587:
588: /** Specifies that some preference has changed. */
589: public void preferenceChanged(boolean width, boolean height) {
590: getEditorUI().virtualSizeUpdated = false;
591:
592: component.revalidate();
593:
594: }
595:
596: /** Root view */
597: class RootView extends BaseView {
598:
599: BaseView view;
600:
601: RootView() {
602: super (null);
603: }
604:
605: /**
606: * Sets the only one inner view of root view to either null or a valid
607: * view.
608: */
609: void setView(View v) {
610: if (v instanceof BaseView) { // only BaseView instances are
611: // supported
612: if (view != null) {
613: // enable grb.col.
614: view.setParent(null);
615: }
616: view = (BaseView) v;
617: if (view != null) {
618: view.setParent(this );
619: }
620: }
621: }
622:
623: /** Fetches attributes associated with view */
624: public AttributeSet getAttributes() {
625: return null;
626: }
627:
628: /**
629: * Determines the preferred span for this view along an axis.
630: *
631: * @param axis
632: * may be either X_AXIS or Y_AXIS
633: * @return the span the view would like to be rendered into.
634: */
635: public float getPreferredSpan(int axis) {
636: EditorUI editorUI = BaseTextUI.this .getEditorUI();
637: switch (axis) {
638: case X_AXIS:
639: return Math
640: .max(
641: BaseTextUI.this .getEditorUI().virtualSize.width,
642: MIN_WIDTH);
643: case Y_AXIS:
644: return Math
645: .max(
646: BaseTextUI.this .getEditorUI().virtualSize.height,
647: MIN_HEIGHT);
648: }
649: return 0f;
650: }
651:
652: /** Determines minimum span along an axis */
653: public float getMinimumSpan(int axis) {
654: return getPreferredSpan(axis);
655: }
656:
657: /** Determines maximum span along an axis */
658: public float getMaximumSpan(int axis) {
659: return Integer.MAX_VALUE;
660: }
661:
662: /** Specifies that a preference has changed. */
663: public void preferenceChanged(View child, boolean width,
664: boolean height) {
665: BaseTextUI.this .preferenceChanged(width, height);
666: }
667:
668: /** Determines the desired alignment for this view along an axis. */
669: public float getAlignment(int axis) {
670: if (view != null) {
671: return view.getAlignment(axis);
672: }
673: return 0;
674: }
675:
676: /** Renders the view. */
677: public void paint(Graphics g, Shape allocation) {
678: if (view != null) {
679: view.paint(g, allocation);
680: }
681: }
682:
683: /** Sets the parent view. */
684: public void setParent(View parent) {
685: // root view has no parent
686: }
687:
688: /** Returns the number of views in this view. */
689: public int getViewCount() {
690: return 1;
691: }
692:
693: /** Gets the n-th view in this container. */
694: public View getView(int n) {
695: return view;
696: }
697:
698: /**
699: * Fetches the allocation for the given child view. Returns the whole
700: * allocated area.
701: */
702: public Shape getChildAllocation(int index, Shape a) {
703: return a;
704: }
705:
706: /**
707: * Provides a mapping from the document model coordinate space to the
708: * coordinate space of the view mapped to it.
709: */
710: public Shape modelToView(int pos, Shape a, Position.Bias b)
711: throws BadLocationException {
712: if (view != null) {
713: return view.modelToView(pos, a, b);
714: }
715: return null;
716: }
717:
718: public Shape modelToView(int p0, Position.Bias b0, int p1,
719: Position.Bias b1, Shape a) throws BadLocationException {
720: if (view != null) {
721: return view.modelToView(p0, b0, p1, b1, a);
722: }
723: return null;
724: }
725:
726: public void modelToViewDG(int pos, DrawGraphics dg)
727: throws BadLocationException {
728: if (view != null) {
729: view.modelToViewDG(pos, dg);
730: }
731: }
732:
733: /**
734: * Determine next visually represented model location where caret can be
735: * placed.
736: */
737: public int getNextVisualPositionFrom(int pos, Position.Bias b,
738: Shape a, int direction, Position.Bias[] biasRet)
739: throws BadLocationException {
740: if (view != null) {
741: int nextPos = view.getNextVisualPositionFrom(pos, b, a,
742: direction, biasRet);
743: if (nextPos != -1) {
744: pos = nextPos;
745: } else {
746: if (biasRet != null) {
747: biasRet[0] = b;
748: }
749: }
750: }
751: return pos;
752: }
753:
754: /**
755: * Provides a mapping from the view coordinate space to the logical
756: * coordinate space of the model.
757: */
758: public int viewToModel(float x, float y, Shape a,
759: Position.Bias[] b) {
760: if (view != null) {
761: return view.viewToModel(x, y, a, b);
762: }
763: return -1;
764: }
765:
766: /** Get y-coord value from position */
767: protected int getYFromPos(int pos) throws BadLocationException {
768: if (view != null) {
769: return view.getYFromPos(pos);
770: }
771: return 0;
772: }
773:
774: /** Get position when knowing y-coord */
775: protected int getPosFromY(int y) {
776: if (view != null) {
777: return view.getPosFromY(y);
778: }
779: return -1;
780: }
781:
782: protected int getBaseX(int y) {
783: if (view != null) {
784: return view.getBaseX(y);
785: }
786: return 0;
787: }
788:
789: /**
790: * Gives notification that something was inserted into the document in a
791: * location that this view is responsible for.
792: *
793: * @param e
794: * the change information from the associated document
795: * @param a
796: * the current allocation of the view
797: * @param f
798: * the factory to use to rebuild if the view has children
799: */
800: public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) {
801: if (view != null) {
802: view.insertUpdate(e, a, f);
803: }
804: }
805:
806: /**
807: * Gives notification that something was removed from the document in a
808: * location that this view is responsible for.
809: *
810: * @param e
811: * the change information from the associated document
812: * @param a
813: * the current allocation of the view
814: * @param f
815: * the factory to use to rebuild if the view has children
816: */
817: public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) {
818: if (view != null) {
819: view.removeUpdate(e, a, f);
820: }
821: }
822:
823: /**
824: * Gives notification from the document that attributes were changed in
825: * a location that this view is responsible for.
826: *
827: * @param e
828: * the change information from the associated document
829: * @param a
830: * the current allocation of the view
831: * @param f
832: * the factory to use to rebuild if the view has children
833: */
834: public void changedUpdate(DocumentEvent e, Shape a,
835: ViewFactory f) {
836: if (view != null) {
837: view.changedUpdate(e, a, f);
838: }
839: }
840:
841: /** Returns the document model underlying the view. */
842: public Document getDocument() {
843: return component.getDocument();
844: }
845:
846: /** Returns the starting offset into the model for this view. */
847: public int getStartOffset() {
848: if (view != null) {
849: return view.getStartOffset();
850: }
851: return getElement().getStartOffset();
852: }
853:
854: /**
855: * Returns the ending offset into the model for this view.
856: *
857: * @return the ending offset
858: */
859: public int getEndOffset() {
860: if (view != null) {
861: return view.getEndOffset();
862: }
863: return getElement().getEndOffset();
864: }
865:
866: /** Gets the element that this view is mapped to. */
867: public Element getElement() {
868: if (view != null) {
869: return view.getElement();
870: }
871: return component.getDocument().getDefaultRootElement();
872: }
873:
874: /** Breaks this view on the given axis at the given length. */
875: public View breakView(int axis, float len, Shape a) {
876: return null; // no breaking of the root view
877: }
878:
879: /**
880: * Determines the resizability of the view along the given axis. A value
881: * of 0 or less is not resizable.
882: */
883: public int getResizeWeight(int axis) {
884: if (view != null) {
885: return view.getResizeWeight(axis);
886: }
887: return 0;
888: }
889:
890: /** Sets the view size. */
891: public void setSize(float width, float height) {
892: if (view != null) {
893: view.setSize(width, height);
894: }
895: }
896:
897: /** Fetches the container hosting the view. */
898: public Container getContainer() {
899: return component;
900: }
901:
902: /**
903: * Fetches the factory to be used for building the various view
904: * fragments that make up the view that represents the model. This is
905: * what determines how the model will be represented. This is
906: * implemented to fetch the factory provided by the associated EditorKit
907: * unless that is null, in which case this simply returns the
908: * BasicTextUI itself which allows subclasses to implement a simple
909: * factory directly without creating extra objects.
910: *
911: * @return the factory
912: */
913: public ViewFactory getViewFactory() {
914: EditorKit kit = getEditorKit(component);
915: ViewFactory f = kit.getViewFactory();
916: if (f != null) {
917: return f;
918: }
919: return BaseTextUI.this ;
920: }
921:
922: protected int getStartY() {
923: return BaseTextUI.this .getEditorUI().textMargin.top;
924: }
925:
926: protected int getPaintAreas(Graphics g, int clipY,
927: int clipHeight) {
928: return 0; // no paint areas
929: }
930:
931: protected void paintAreas(Graphics g, int clipY,
932: int clipHeight, int paintAreas) {
933: // no painting for the root view
934: }
935:
936: protected int getViewStartY(BaseView view, int helperInd) {
937: return getStartY();
938: }
939:
940: protected void invalidateStartY() {
941: if (view != null) {
942: view.invalidateStartY();
943: }
944: }
945:
946: public int getHeight() {
947: if (view != null) {
948: return view.getHeight();
949: }
950: return 0;
951: }
952:
953: public void updateMainHeight() {
954: if (view != null) {
955: view.updateMainHeight();
956: EditorUI editorUI = BaseTextUI.this .getEditorUI();
957: if (editorUI.updateVirtualHeight(getHeight())) {
958: BaseTextUI.this .preferenceChanged(true, true);
959: }
960: }
961: }
962:
963: }
964:
965: private static class GetFocusedComponentAction extends TextAction {
966:
967: private GetFocusedComponentAction() {
968: super ("get-focused-component");
969: }
970:
971: public void actionPerformed(ActionEvent evt) {
972: }
973:
974: JTextComponent getFocusedComponent2() {
975: return super.getFocusedComponent();
976: }
977:
978: }
979:
980: };
|