1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54:
55: import ;
56: import ;
57: import ;
58: import ;
59: import ;
60: import ;
61: import ;
62: import ;
63: import ;
64: import ;
65: import ;
66: import ;
67: import ;
68: import ;
69: import ;
70: import ;
71: import ;
72: import ;
73: import ;
74: import ;
75: import ;
76:
77:
101: public class JEditorPane extends JTextComponent
102: {
103:
108: protected class AccessibleJEditorPane extends AccessibleJTextComponent
109: {
110:
111:
114: protected AccessibleJEditorPane()
115: {
116: super();
117: }
118:
119:
126: public String getAccessibleDescription()
127: {
128: String descr = super.getAccessibleDescription();
129: if (descr == null)
130: return getContentType();
131: else
132: return descr;
133: }
134:
135:
140: public AccessibleStateSet getAccessibleStateSet()
141: {
142: AccessibleStateSet state = super.getAccessibleStateSet();
143:
144: return state;
145: }
146: }
147:
148:
154: protected class AccessibleJEditorPaneHTML extends AccessibleJEditorPane
155: {
156:
163: public AccessibleText getAccessibleText()
164: {
165: return new JEditorPaneAccessibleHypertextSupport();
166: }
167: }
168:
169:
175: protected class JEditorPaneAccessibleHypertextSupport
176: extends AccessibleJEditorPane implements AccessibleHypertext
177: {
178:
179:
182: public JEditorPaneAccessibleHypertextSupport()
183: {
184: super();
185: }
186:
187:
192: public class HTMLLink extends AccessibleHyperlink
193: {
194:
195:
198: Element element;
199:
200:
205: public HTMLLink(Element el)
206: {
207: this.element = el;
208: }
209:
210:
218: public boolean isValid()
219: {
220:
221:
222:
223:
224: HTMLDocument doc = (HTMLDocument) getDocument();
225: return doc.getCharacterElement(element.getStartOffset()) == element;
226: }
227:
228:
236: public int getAccessibleActionCount()
237: {
238:
239: return 1;
240: }
241:
242:
249: public boolean doAccessibleAction(int i)
250: {
251: String href = (String) element.getAttributes().getAttribute("href");
252: HTMLDocument doc = (HTMLDocument) getDocument();
253: try
254: {
255: URL url = new URL(doc.getBase(), href);
256: setPage(url);
257: String desc = doc.getText(element.getStartOffset(),
258: element.getEndOffset() - element.getStartOffset());
259: HyperlinkEvent ev =
260: new HyperlinkEvent(JEditorPane.this,
261: HyperlinkEvent.EventType.ACTIVATED, url, desc,
262: element);
263: fireHyperlinkUpdate(ev);
264: return true;
265: }
266: catch (Exception ex)
267: {
268: return false;
269: }
270: }
271:
272:
281: public String getAccessibleActionDescription(int i)
282: {
283: HTMLDocument doc = (HTMLDocument) getDocument();
284: try
285: {
286: return doc.getText(element.getStartOffset(),
287: element.getEndOffset() - element.getStartOffset());
288: }
289: catch (BadLocationException ex)
290: {
291: throw (AssertionError)
292: new AssertionError("BadLocationException must not be thrown "
293: + "here.")
294: .initCause(ex);
295: }
296: }
297:
298:
307: public Object getAccessibleActionObject(int i)
308: {
309: String href = (String) element.getAttributes().getAttribute("href");
310: HTMLDocument doc = (HTMLDocument) getDocument();
311: try
312: {
313: URL url = new URL(doc.getBase(), href);
314: return url;
315: }
316: catch (MalformedURLException ex)
317: {
318: return null;
319: }
320: }
321:
322:
330: public Object getAccessibleActionAnchor(int i)
331: {
332:
333: return getAccessibleActionDescription(i);
334: }
335:
336:
341: public int getStartIndex()
342: {
343: return element.getStartOffset();
344: }
345:
346:
351: public int getEndIndex()
352: {
353: return element.getEndOffset();
354: }
355:
356: }
357:
358:
363: public int getLinkCount()
364: {
365: HTMLDocument doc = (HTMLDocument) getDocument();
366: HTMLDocument.Iterator linkIter = doc.getIterator(HTML.Tag.A);
367: int count = 0;
368: while (linkIter.isValid())
369: {
370: count++;
371: linkIter.next();
372: }
373: return count;
374: }
375:
376:
386: public AccessibleHyperlink getLink(int i)
387: {
388: HTMLDocument doc = (HTMLDocument) getDocument();
389: HTMLDocument.Iterator linkIter = doc.getIterator(HTML.Tag.A);
390: int count = 0;
391: while (linkIter.isValid())
392: {
393: count++;
394: if (count == i)
395: break;
396: linkIter.next();
397: }
398: if (linkIter.isValid())
399: {
400: int offset = linkIter.getStartOffset();
401:
402:
403:
404: Element el = doc.getCharacterElement(offset);
405: HTMLLink link = new HTMLLink(el);
406: return link;
407: }
408: else
409: return null;
410: }
411:
412:
423: public int getLinkIndex(int c)
424: {
425: HTMLDocument doc = (HTMLDocument) getDocument();
426: HTMLDocument.Iterator linkIter = doc.getIterator(HTML.Tag.A);
427: int count = 0;
428: while (linkIter.isValid())
429: {
430: if (linkIter.getStartOffset() <= c && linkIter.getEndOffset() > c)
431: break;
432: count++;
433: linkIter.next();
434: }
435: if (linkIter.isValid())
436: return count;
437: else
438: return -1;
439: }
440:
441:
451: public String getLinkText(int i)
452: {
453: HTMLDocument doc = (HTMLDocument) getDocument();
454: HTMLDocument.Iterator linkIter = doc.getIterator(HTML.Tag.A);
455: int count = 0;
456: while (linkIter.isValid())
457: {
458: count++;
459: if (count == i)
460: break;
461: linkIter.next();
462: }
463: if (linkIter.isValid())
464: {
465: int offset = linkIter.getStartOffset();
466:
467:
468:
469: Element el = doc.getCharacterElement(offset);
470: try
471: {
472: String text = doc.getText(el.getStartOffset(),
473: el.getEndOffset() - el.getStartOffset());
474: return text;
475: }
476: catch (BadLocationException ex)
477: {
478: throw (AssertionError)
479: new AssertionError("BadLocationException must not be thrown "
480: + "here.")
481: .initCause(ex);
482: }
483: }
484: else
485: return null;
486: }
487: }
488:
489:
492: private static class EditorKitMapping
493: {
494:
497: String className;
498:
499:
502: ClassLoader classLoader;
503:
504:
510: EditorKitMapping(String cn, ClassLoader cl)
511: {
512: className = cn;
513: classLoader = cl;
514: }
515: }
516:
517:
523: private static class PlainEditorKit extends DefaultEditorKit
524: {
525:
526:
529: public ViewFactory getViewFactory()
530: {
531: return new ViewFactory()
532: {
533: public View create(Element el)
534: {
535: return new WrappedPlainView(el);
536: }
537: };
538: }
539: }
540:
541:
544: private class PageStream
545: extends FilterInputStream
546: {
547:
550: private boolean cancelled;
551:
552: protected PageStream(InputStream in)
553: {
554: super(in);
555: cancelled = false;
556: }
557:
558: private void checkCancelled()
559: throws IOException
560: {
561: if (cancelled)
562: throw new IOException("Stream has been cancelled");
563: }
564:
565: void cancel()
566: {
567: cancelled = true;
568: }
569:
570: public int read()
571: throws IOException
572: {
573: checkCancelled();
574: return super.read();
575: }
576:
577: public int read(byte[] b, int off, int len)
578: throws IOException
579: {
580: checkCancelled();
581: return super.read(b, off, len);
582: }
583:
584: public long skip(long n)
585: throws IOException
586: {
587: checkCancelled();
588: return super.skip(n);
589: }
590:
591: public int available()
592: throws IOException
593: {
594: checkCancelled();
595: return super.available();
596: }
597:
598: public void reset()
599: throws IOException
600: {
601: checkCancelled();
602: super.reset();
603: }
604: }
605:
606:
609: private class PageLoader
610: implements Runnable
611: {
612: private Document doc;
613: private PageStream in;
614: private URL old;
615: URL page;
616: PageLoader(Document doc, InputStream in, URL old, URL page)
617: {
618: this.doc = doc;
619: this.in = new PageStream(in);
620: this.old = old;
621: this.page = page;
622: }
623:
624: public void run()
625: {
626: try
627: {
628: read(in, doc);
629: }
630: catch (IOException ex)
631: {
632: UIManager.getLookAndFeel().provideErrorFeedback(JEditorPane.this);
633: }
634: finally
635: {
636: if (SwingUtilities.isEventDispatchThread())
637: firePropertyChange("page", old, page);
638: else
639: {
640: SwingUtilities.invokeLater(new Runnable()
641: {
642: public void run()
643: {
644: firePropertyChange("page", old, page);
645: }
646: });
647: }
648: }
649: }
650:
651: void cancel()
652: {
653: in.cancel();
654: }
655: }
656:
657: private static final long serialVersionUID = 3140472492599046285L;
658:
659: private EditorKit editorKit;
660:
661: boolean focus_root;
662:
663:
666: static HashMap editorKits;
667:
668:
669: static HashMap registerMap;
670:
671: static
672: {
673: registerMap = new HashMap();
674: editorKits = new HashMap();
675: registerEditorKitForContentType("application/rtf",
676: "javax.swing.text.rtf.RTFEditorKit");
677: registerEditorKitForContentType("text/plain",
678: "javax.swing.JEditorPane$PlainEditorKit");
679: registerEditorKitForContentType("text/html",
680: "javax.swing.text.html.HTMLEditorKit");
681: registerEditorKitForContentType("text/rtf",
682: "javax.swing.text.rtf.RTFEditorKit");
683:
684: }
685:
686:
687: HashMap editorMap;
688:
689:
692: private PageLoader loader;
693:
694: public JEditorPane()
695: {
696: init();
697: setEditorKit(createDefaultEditorKit());
698: }
699:
700: public JEditorPane(String url) throws IOException
701: {
702: this(new URL(url));
703: }
704:
705: public JEditorPane(String type, String text)
706: {
707: init();
708: setEditorKit(createEditorKitForContentType(type));
709: setText(text);
710: }
711:
712: public JEditorPane(URL url) throws IOException
713: {
714: init();
715: setEditorKit(createEditorKitForContentType("text/html"));
716: setPage(url);
717: }
718:
719:
723: void init()
724: {
725: editorMap = new HashMap();
726: }
727:
728: protected EditorKit createDefaultEditorKit()
729: {
730: return new PlainEditorKit();
731: }
732:
733:
743: public static EditorKit createEditorKitForContentType(String type)
744: {
745:
746: EditorKit e = (EditorKit) editorKits.get(type);
747: if (e == null)
748: {
749: EditorKitMapping m = (EditorKitMapping) registerMap.get(type);
750: if (m != null)
751: {
752: String className = m.className;
753: ClassLoader loader = m.classLoader;
754: try
755: {
756: e = (EditorKit) loader.loadClass(className).newInstance();
757: }
758: catch (Exception e2)
759: {
760:
761:
762: }
763: }
764:
765: if (e != null)
766: editorKits.put(type, e);
767: }
768: return e;
769: }
770:
771:
776: public void fireHyperlinkUpdate(HyperlinkEvent event)
777: {
778: HyperlinkListener[] listeners = getHyperlinkListeners();
779:
780: for (int index = 0; index < listeners.length; ++index)
781: listeners[index].hyperlinkUpdate(event);
782: }
783:
784:
789: public AccessibleContext getAccessibleContext()
790: {
791: if (accessibleContext == null)
792: {
793: if (getEditorKit() instanceof HTMLEditorKit)
794: accessibleContext = new AccessibleJEditorPaneHTML();
795: else
796: accessibleContext = new AccessibleJEditorPane();
797: }
798: return accessibleContext;
799: }
800:
801: public final String getContentType()
802: {
803: return getEditorKit().getContentType();
804: }
805:
806:
810: public EditorKit getEditorKit()
811: {
812: if (editorKit == null)
813: setEditorKit(createDefaultEditorKit());
814: return editorKit;
815: }
816:
817:
825: public static String getEditorKitClassNameForContentType(String type)
826: {
827: EditorKitMapping m = (EditorKitMapping) registerMap.get(type);
828: String kitName = m != null ? m.className : null;
829: return kitName;
830: }
831:
832:
846: public EditorKit getEditorKitForContentType(String type)
847: {
848:
849: EditorKit e = (EditorKit) editorMap.get(type);
850:
851: if (e == null)
852: {
853: e = createEditorKitForContentType(type);
854: if (e != null)
855: setEditorKitForContentType(type, e);
856: }
857:
858: if (e == null)
859: e = createDefaultEditorKit();
860: return e;
861: }
862:
863:
873: public Dimension getPreferredSize()
874: {
875: Dimension pref = super.getPreferredSize();
876: Container parent = getParent();
877: if (parent instanceof JViewport)
878: {
879: JViewport vp = (JViewport) getParent();
880: TextUI ui = getUI();
881: Dimension min = null;
882: if (! getScrollableTracksViewportWidth())
883: {
884: min = ui.getMinimumSize(this);
885: int vpWidth = vp.getWidth();
886: if (vpWidth != 0 && vpWidth < min.width)
887: pref.width = min.width;
888: }
889: if (! getScrollableTracksViewportHeight())
890: {
891: if (min == null)
892: min = ui.getMinimumSize(this);
893: int vpHeight = vp.getHeight();
894: if (vpHeight != 0 && vpHeight < min.height)
895: pref.height = min.height;
896: }
897: }
898: return pref;
899: }
900:
901:
910: public boolean getScrollableTracksViewportHeight()
911: {
912:
913:
914: Container parent = getParent();
915: int height = parent.getHeight();
916: TextUI ui = getUI();
917: return parent instanceof JViewport
918: && height >= ui.getMinimumSize(this).height
919: && height <= ui.getMaximumSize(this).height;
920: }
921:
922:
931: public boolean getScrollableTracksViewportWidth()
932: {
933:
934:
935: Container parent = getParent();
936: return parent != null && parent instanceof JViewport
937: && parent.getWidth() > getUI().getMinimumSize(this).width;
938: }
939:
940: public URL getPage()
941: {
942: return loader != null ? loader.page : null;
943: }
944:
945: protected InputStream getStream(URL page)
946: throws IOException
947: {
948: URLConnection conn = page.openConnection();
949:
950: String type = conn.getContentType();
951: if (type != null)
952: setContentType(type);
953: InputStream stream = conn.getInputStream();
954: return new BufferedInputStream(stream);
955: }
956:
957: public String getText()
958: {
959: return super.getText();
960: }
961:
962: public String getUIClassID()
963: {
964: return "EditorPaneUI";
965: }
966:
967: public boolean isFocusCycleRoot()
968: {
969: return focus_root;
970: }
971:
972: protected String paramString()
973: {
974: return "JEditorPane";
975: }
976:
977:
980: public void read(InputStream in, Object desc) throws IOException
981: {
982: EditorKit kit = getEditorKit();
983: if (kit instanceof HTMLEditorKit && desc instanceof HTMLDocument)
984: {
985: HTMLDocument doc = (HTMLDocument) desc;
986: setDocument(doc);
987: try
988: {
989: InputStreamReader reader = new InputStreamReader(in);
990: kit.read(reader, doc, 0);
991: }
992: catch (BadLocationException ex)
993: {
994: assert false : "BadLocationException must not be thrown here.";
995: }
996: }
997: else
998: {
999: Reader inRead = new InputStreamReader(in);
1000: super.read(inRead, desc);
1001: }
1002: }
1003:
1004:
1012: public static void registerEditorKitForContentType(String type,
1013: String classname)
1014: {
1015: registerEditorKitForContentType(type, classname,
1016: Thread.currentThread().getContextClassLoader());
1017: }
1018:
1019:
1022: public static void registerEditorKitForContentType(String type,
1023: String classname,
1024: ClassLoader loader)
1025: {
1026: registerMap.put(type, new EditorKitMapping(classname, loader));
1027: }
1028:
1029:
1033: public void replaceSelection(String content)
1034: {
1035:
1036: super.replaceSelection(content);
1037: }
1038:
1039:
1043: public void scrollToReference(String reference)
1044: {
1045:
1046: }
1047:
1048: public final void setContentType(String type)
1049: {
1050:
1051: int paramIndex = type.indexOf(';');
1052: if (paramIndex > -1)
1053: {
1054:
1055: type = type.substring(0, paramIndex).trim();
1056: }
1057: if (editorKit != null
1058: && editorKit.getContentType().equals(type))
1059: return;
1060:
1061: EditorKit kit = getEditorKitForContentType(type);
1062:
1063: if (kit != null)
1064: setEditorKit(kit);
1065: }
1066:
1067: public void setEditorKit(EditorKit newValue)
1068: {
1069: if (editorKit == newValue)
1070: return;
1071:
1072: if (editorKit != null)
1073: editorKit.deinstall(this);
1074:
1075: EditorKit oldValue = editorKit;
1076: editorKit = newValue;
1077:
1078: if (editorKit != null)
1079: {
1080: editorKit.install(this);
1081: setDocument(editorKit.createDefaultDocument());
1082: }
1083:
1084: firePropertyChange("editorKit", oldValue, newValue);
1085: invalidate();
1086: repaint();
1087:
1088: accessibleContext = null;
1089: }
1090:
1091:
1096: public void setEditorKitForContentType(String type, EditorKit k)
1097: {
1098: editorMap.put(type, k);
1099: }
1100:
1101:
1104: public void setPage(String url) throws IOException
1105: {
1106: setPage(new URL(url));
1107: }
1108:
1109:
1112: public void setPage(URL page) throws IOException
1113: {
1114: if (page == null)
1115: throw new IOException("invalid url");
1116:
1117: URL old = getPage();
1118:
1119:
1120:
1121: if (old == null || ! old.sameFile(page))
1122: {
1123: InputStream in = getStream(page);
1124: if (editorKit != null)
1125: {
1126: Document doc = editorKit.createDefaultDocument();
1127: doc.putProperty(Document.StreamDescriptionProperty, page);
1128:
1129: if (loader != null)
1130: loader.cancel();
1131: loader = new PageLoader(doc, in, old, page);
1132:
1133: int prio = -1;
1134: if (doc instanceof AbstractDocument)
1135: {
1136: AbstractDocument aDoc = (AbstractDocument) doc;
1137: prio = aDoc.getAsynchronousLoadPriority();
1138: }
1139: if (prio >= 0)
1140: {
1141:
1142: setDocument(doc);
1143: Thread loadThread = new Thread(loader,
1144: "JEditorPane.PageLoader");
1145: loadThread.setDaemon(true);
1146: loadThread.setPriority(prio);
1147: loadThread.start();
1148: }
1149: else
1150: {
1151:
1152: loader.run();
1153: setDocument(doc);
1154: }
1155: }
1156: }
1157: }
1158:
1159:
1168: public void setText(String t)
1169: {
1170: try
1171: {
1172:
1173: Document doc = getDocument();
1174: doc.remove(0, doc.getLength());
1175: if (t == null || t.equals(""))
1176: return;
1177:
1178:
1179: getEditorKit().read(new StringReader(t), doc, 0);
1180: }
1181: catch (BadLocationException ble)
1182: {
1183:
1184: }
1185: catch (IOException ioe)
1186: {
1187:
1188: }
1189: }
1190:
1191:
1196: public void addHyperlinkListener(HyperlinkListener listener)
1197: {
1198: listenerList.add(HyperlinkListener.class, listener);
1199: }
1200:
1201:
1206: public void removeHyperlinkListener(HyperlinkListener listener)
1207: {
1208: listenerList.remove(HyperlinkListener.class, listener);
1209: }
1210:
1211:
1218: public HyperlinkListener[] getHyperlinkListeners()
1219: {
1220: return (HyperlinkListener[]) getListeners(HyperlinkListener.class);
1221: }
1222: }