001: /*
002: * <p>Copyright: Copyright Xoetrope Ltd. (c) 2001-2003</p>
003: * <p>License: see license.txt</p>
004: * <p>$Revision: 1.10 $</p>
005: */
006: package com.xoetrope.swing;
007:
008: import java.io.IOException;
009: import java.net.URL;
010:
011: import java.awt.BorderLayout;
012: import java.awt.Color;
013: import java.awt.Container;
014: import java.awt.Cursor;
015: import java.awt.Font;
016: import javax.swing.JComponent;
017: import javax.swing.JEditorPane;
018: import javax.swing.JScrollPane;
019: import javax.swing.JViewport;
020: import javax.swing.SwingUtilities;
021: import javax.swing.border.EmptyBorder;
022: import javax.swing.event.HyperlinkEvent;
023: import javax.swing.event.HyperlinkListener;
024: import javax.swing.text.Document;
025: import javax.swing.text.html.HTMLEditorKit;
026: import javax.swing.text.html.StyleSheet;
027: import net.xoetrope.xui.XAttributedComponent;
028: import net.xoetrope.xui.XProject;
029: import net.xoetrope.xui.XProjectManager;
030: import net.xoetrope.xui.XTextHolder;
031:
032: /**
033: * HTML Text Control
034: *
035: * <p> Copyright (c) Xoetrope Ltd., 2001-2006, This software is licensed under
036: * the GNU Public License (GPL), please see license.txt for more details. If
037: * you make commercial use of this software you must purchase a commercial
038: * license from Xoetrope.</p>
039: * <p> $Revision: 1.10 $</p>
040: */
041: public class XHtmlText extends JComponent implements
042: XAttributedComponent, HyperlinkListener, XTextHolder {
043: /**
044: * The owner project and the context in which this object operates.
045: */
046: protected XProject currentProject = XProjectManager
047: .getCurrentProject();
048:
049: public XHtmlText() {
050: initialize();
051: }
052:
053: private void initialize() {
054: html = new JEditorPane();
055: html.setEditable(false);
056: html.addHyperlinkListener(this );
057:
058: JScrollPane scroller = new JScrollPane();
059: scroller.setOpaque(false);
060: scroller.setBorder(new EmptyBorder(0, 0, 0, 0));
061: JViewport vp = scroller.getViewport();
062: vp.setOpaque(false);
063: vp.add(html);
064: vp.setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE);
065:
066: setLayout(new BorderLayout());
067: add(scroller, BorderLayout.CENTER);
068:
069: html.setBackground(getBackground());
070: validText = new String("");
071:
072: editor = new HTMLEditorKit();
073: html.setEditorKit(editor);
074: }
075:
076: public void setBackground(Color c) {
077: super .setBackground(c);
078: html.setBackground(c);
079: }
080:
081: public void setForeground(Color c) {
082: super .setForeground(c);
083: //setFontAndColor( getFont(), c );
084: }
085:
086: /**
087: * Sets the controls text.
088: * The recommended way of setting the control's text is with the
089: * setLangString function.
090: * @param value to be shown as text.
091: */
092: public void setText(String value) {
093: validText = new String(value);
094: html.setText(value);
095: }
096:
097: /**
098: * Gets the controls text.
099: * @return the value shown as text.
100: */
101: public String getText() {
102: return validText;
103: }
104:
105: /**
106: * Opens a new file.
107: */
108: public void open(String name) {
109: try {
110: html.setPage(currentProject.getUrl(name));
111: } catch (IOException ex) {
112: ex.printStackTrace();
113: }
114: }
115:
116: /**
117: * Notification of a change relative to a
118: * hyperlink.
119: */
120: public void hyperlinkUpdate(HyperlinkEvent e) {
121: if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
122: linkActivated(e.getURL());
123: }
124: }
125:
126: /**
127: * Follows the reference in an
128: * link. The given url is the requested reference.
129: * By default this calls <a href="#setPage">setPage</a>,
130: * and if an exception is thrown the original previous
131: * document is restored and a beep sounded. If an
132: * attempt was made to follow a link, but it represented
133: * a malformed url, this method will be called with a
134: * null argument.
135: *
136: * @param u the URL to follow
137: */
138: protected void linkActivated(URL u) {
139: Cursor c = html.getCursor();
140: Cursor waitCursor = Cursor
141: .getPredefinedCursor(Cursor.WAIT_CURSOR);
142: html.setCursor(waitCursor);
143: SwingUtilities.invokeLater(new PageLoader(u, c));
144: }
145:
146: /**
147: * Set one or more attributes of the component. Currently this handles the
148: * attributes
149: * <OL>
150: * <LI>headingStyle, value=the table header style</LI>
151: * <LI>selectionStyle, value=the selected row style</LI>
152: * <LI>interactive, value=true|false</LI>
153: * <LI>updateModel, value=true|false update the underlying model selection (the selected row)</LI>
154: * </OL>
155: * @param attribName the attribute name
156: * @param attribValue the attribute value
157: * @return 0 for success, non zero for failure or to require some further action
158: */
159: public int setAttribute(String attribName, Object attribValue) {
160: String attribValueStr = (String) attribValue;
161: if ("html".equals(attribName)) {
162: open(attribValueStr);
163: return 0;
164: } else if ("content".equals(attribName)) {
165: validText = new String(attribValueStr);
166: html.setText(attribValueStr);
167: return 0;
168: }
169:
170: return -1;
171: }
172:
173: /**
174: * Sets the default font and default color. These are set by
175: * adding a rule for the body that specifies the font and color.
176: * This allows the html to override these should it wish to have
177: * a custom font or color.
178: */
179: private void setFontAndColor(Font font, Color fg) {
180: StyleSheet ss = new StyleSheet();
181: StringBuffer rule = null;
182:
183: if (font != null) {
184: rule = new StringBuffer("body { font-family: ");
185: rule.append(font.getFamily());
186: rule.append(";");
187: rule.append(" font-size: ");
188: rule.append(font.getSize());
189: rule.append("pt");
190: if (font.isBold())
191: rule.append("; font-weight: 700");
192:
193: if (font.isItalic())
194: rule.append("; font-style: italic");
195: }
196:
197: if (fg != null) {
198: if (rule == null)
199: rule = new StringBuffer("body { color: #");
200: else
201: rule.append("; color: #");
202:
203: if (fg.getRed() < 16)
204: rule.append('0');
205:
206: rule.append(Integer.toHexString(fg.getRed()));
207: if (fg.getGreen() < 16)
208: rule.append('0');
209:
210: rule.append(Integer.toHexString(fg.getGreen()));
211: if (fg.getBlue() < 16)
212: rule.append('0');
213:
214: rule.append(Integer.toHexString(fg.getBlue()));
215: }
216:
217: if (rule != null) {
218: rule.append(" }");
219: try {
220: ss.addRule(rule.toString());
221: editor.setStyleSheet(ss);
222: html.repaint();
223: } catch (RuntimeException re) {
224: re.printStackTrace();
225: }
226: }
227: }
228:
229: /**
230: * Repaint the component once it has been created
231: */
232: public void addNotify() {
233: super .addNotify();
234: validate();
235: }
236:
237: /**
238: * temporary class that loads synchronously (although
239: * later than the request so that a cursor change
240: * can be done).
241: */
242: class PageLoader implements Runnable {
243: PageLoader(URL u, Cursor c) {
244: url = u;
245: cursor = c;
246: }
247:
248: public void run() {
249: if (url == null) {
250: // restore the original cursor
251: html.setCursor(cursor);
252:
253: // PENDING(prinz) remove this hack when
254: // automatic validation is activated.
255: Container parent = html.getParent();
256: parent.repaint();
257: } else {
258: Document doc = html.getDocument();
259: try {
260: html.setPage(url);
261: } catch (IOException ioe) {
262: html.setDocument(doc);
263: getToolkit().beep();
264: } finally {
265: // schedule the cursor to revert after
266: // the paint has happended.
267: url = null;
268: SwingUtilities.invokeLater(this );
269: }
270: }
271: }
272:
273: URL url;
274: Cursor cursor;
275: }
276:
277: private int formatType = -1;
278: private String formatString = null;
279: private String validText = null;
280:
281: protected HTMLEditorKit editor;
282: protected JEditorPane html;
283: }
|