001: /*
002: * (C) Copyright IBM Corp. 1998-2005. All Rights Reserved.
003: *
004: * The program is provided "as is" without any warranty express or
005: * implied, including the warranty of non-infringement and the implied
006: * warranties of merchantibility and fitness for a particular purpose.
007: * IBM will not be liable for any damages suffered by you as a result
008: * of using the Program. In no event will IBM be liable for any
009: * special, indirect or consequential damages or lost profits even if
010: * IBM has been advised of the possibility of their occurrence. IBM
011: * will not be liable for any third party claims against you.
012: */
013: package com.ibm.richtext.textpanel;
014:
015: import java.awt.Adjustable;
016: import java.awt.BorderLayout;
017: import java.awt.Color;
018: import java.awt.Graphics;
019: import java.lang.reflect.InvocationTargetException;
020:
021: import javax.swing.JPanel;
022: import javax.swing.JComponent;
023: import javax.swing.JScrollBar;
024: import javax.swing.SwingUtilities;
025:
026: import java.awt.datatransfer.Clipboard;
027:
028: import com.ibm.richtext.textlayout.attributes.AttributeMap;
029:
030: import com.ibm.richtext.styledtext.StyleModifier;
031: import com.ibm.richtext.styledtext.MConstText;
032:
033: /**
034: * JTextPanel is an implementation of MTextPanel in a Swing JPanel.
035: * @see MTextPanel
036: */
037: public final class JTextPanel extends JPanel implements MTextPanel {
038:
039: static final String COPYRIGHT = "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
040: private ATextPanelImpl fImpl;
041:
042: /**
043: * Return a TextPanelSettings instance with all settings set
044: * to the default values. Clients can modify this object;
045: * modifications will not affect the default values.
046: * @return a TextPanelSettings instance set to default values
047: * @see TextPanelSettings
048: */
049: public static TextPanelSettings getDefaultSettings() {
050:
051: return ATextPanelImpl.getDefaultSettings();
052: }
053:
054: /**
055: * Create a new JTextPanel with the default settings.
056: * @param initialText the text document. If null document text is empty.
057: * @param clipboard the clipboard to use for cut, copy, and paste
058: * operations. If null this panel will use a private clipboard.
059: */
060: public JTextPanel(MConstText initialText,
061: java.awt.datatransfer.Clipboard clipboard) {
062:
063: this (ATextPanelImpl.fgDefaultSettings, initialText, clipboard);
064: }
065:
066: /**
067: * Create a new JTextPanel.
068: * @param settings the settings for this JTextPanel
069: * @param initialText the text document. If null document text is empty.
070: * @param clipboard the clipboard to use for cut, copy, and paste
071: * operations. If null this panel will use a private clipboard.
072: * @see TextPanelSettings
073: */
074: public JTextPanel(TextPanelSettings settings,
075: MConstText initialText, Clipboard clipboard) {
076:
077: super (false);
078:
079: JScrollBar horzSb = null;
080: JScrollBar vertSb = null;
081:
082: if (settings.getScrollable()) {
083:
084: setLayout(new ScrollBarLayout());
085:
086: boolean scrollBarsVisible = settings.getScrollBarsVisible();
087:
088: if (scrollBarsVisible) {
089: horzSb = new JScrollBar(Adjustable.HORIZONTAL);
090: vertSb = new JScrollBar(Adjustable.VERTICAL);
091: add("South", horzSb);
092: add("East", vertSb);
093: }
094: } else {
095: setLayout(new BorderLayout());
096: }
097:
098: RunStrategy runStrategy = new RunStrategy() {
099: void doIt(Runnable r) {
100: try {
101: SwingUtilities.invokeAndWait(r);
102: } catch (InterruptedException e) {
103: // If operation was interrupted, then client
104: // called wait or sleep (or something similar)
105: // which is inappropriate for a client of this
106: // class. Rethrow error and let client handle it.
107: e.printStackTrace();
108: throw new Error("Interrupted in RunStrategy: " + e);
109: } catch (InvocationTargetException e) {
110: // Who knows how this one happens...
111: e.printStackTrace();
112: throw new Error(
113: "InvocationTargetException in RunStrategy: "
114: + e);
115: }
116: }
117: };
118:
119: fImpl = new ATextPanelImpl(runStrategy, settings, initialText,
120: clipboard, this , horzSb, vertSb);
121:
122: final FakeComponent textComponent = fImpl.getTextComponent();
123:
124: JComponent textHost = new JComponent() {
125: {
126: textComponent.setHost(this );
127: }
128:
129: public void addNotify() {
130: super .addNotify();
131: textComponent.addNotify();
132: }
133:
134: public void paint(Graphics g) {
135: textComponent.paint(g);
136: }
137: };
138:
139: add("Center", textHost);
140:
141: textHost.requestFocus();
142: }
143:
144: /**
145: * Add the given TextPanelListener to the listeners which will
146: * receive update notifications from this JTextPanel.
147: * @param listener the listener to add
148: */
149: public void addListener(TextPanelListener listener) {
150:
151: fImpl.addListener(listener);
152: }
153:
154: /**
155: * Remove the given TextPanelListener from the listeners which will
156: * receive update notifications from this JTextPanel.
157: * @param listener the listener to remove
158: */
159: public void removeListener(TextPanelListener listener) {
160:
161: fImpl.removeListener(listener);
162: }
163:
164: //============
165: // Text Access
166: //============
167:
168: /**
169: * Set the document to <tt>newText</tt>. This operation
170: * modifies the text in the JTextPanel. It does not modify or adopt
171: * <tt>newText</tt>. This method sets the selection an insertion point at
172: * the end of the text.
173: * @param newText the text which will replace the current text.
174: */
175: public void setText(MConstText newText) {
176:
177: fImpl.setText(newText);
178: }
179:
180: /**
181: * Append the given text to the end of the document. Equivalent to
182: * <tt>insert(newText, getTextLength())</tt>.
183: * @param newText the text to append to the document
184: */
185: public void append(MConstText newText) {
186:
187: fImpl.append(newText);
188: }
189:
190: /**
191: * Insert the given text into the document at the given position.
192: * Equivalent to
193: * <tt>replaceRange(newText, position, position)</tt>.
194: * @param newText the text to insert into the document.
195: * @param position the position in the document where the
196: * text will be inserted
197: */
198: public void insert(MConstText newText, int position) {
199:
200: fImpl.insert(newText, position);
201: }
202:
203: /**
204: * Replace the given range with <tt>newText</tt>. After this
205: * operation the selection range is an insertion point at the
206: * end of the new text.
207: * @param newText the text with which to replace the range
208: * @param start the beginning of the range to replace
209: * @param end the end of the range to replace
210: */
211: public void replaceRange(MConstText newText, int start, int end) {
212:
213: fImpl.replaceRange(newText, start, end);
214: }
215:
216: /**
217: * Return the length of the text document in the JTextPanel.
218: * @return the length of the text document in the JTextPanel
219: */
220: public int getTextLength() {
221:
222: return fImpl.getTextLength();
223: }
224:
225: /**
226: * Return the text document in the JTextPanel.
227: * @return the text document in the JTextPanel.
228: */
229: public MConstText getText() {
230:
231: return fImpl.getText();
232: }
233:
234: //============
235: // Selection Access
236: //============
237:
238: /**
239: * Return the offset of the start of the selection.
240: */
241: public int getSelectionStart() {
242:
243: return fImpl.getSelectionStart();
244: }
245:
246: /**
247: * Return the offset of the end of the selection.
248: */
249: public int getSelectionEnd() {
250:
251: return fImpl.getSelectionEnd();
252: }
253:
254: /**
255: * Set the beginning of the selection range. This is
256: * equivalent to <tt>select(selectionStart, getSelectionEnd())</tt>.
257: * @param selectionStart the start of the new selection range
258: */
259: public void setSelectionStart(int selectionStart) {
260:
261: fImpl.setSelectionStart(selectionStart);
262: }
263:
264: /**
265: * Set the end of the selection range. This is
266: * equivalent to <tt>select(getSelectionStart(), selectionEnd)</tt>.
267: * @param selectionEnd the end of the new selection range
268: */
269: public void setSelectionEnd(int selectionEnd) {
270:
271: fImpl.setSelectionEnd(selectionEnd);
272: }
273:
274: /**
275: * Set the selection range to an insertion point at the given
276: * offset. This is equivalent to
277: * <tt>select(position, position)</tt>.
278: * @param position the offset of the new insertion point
279: */
280: public void setCaretPosition(int position) {
281:
282: fImpl.setCaretPosition(position);
283: }
284:
285: /**
286: * Set the selection range to the given range. The range start
287: * is pinned between 0 and the text length; the range end is pinned
288: * between the range start and the end of the text. These semantics
289: * are identical to those of <tt>java.awt.TextComponent</tt>.
290: * This method has no effect if the text is not selectable.
291: * @param selectionStart the beginning of the selection range
292: * @param selectionEnd the end of the selection range
293: */
294: public void select(int selectionStart, int selectionEnd) {
295:
296: fImpl.select(selectionStart, selectionEnd);
297: }
298:
299: /**
300: * Select all of the text in the document. This method has no effect if
301: * the text is not selectable.
302: */
303: public void selectAll() {
304:
305: fImpl.selectAll();
306: }
307:
308: //============
309: // Format Width
310: //============
311:
312: /**
313: * Return the total format width, in pixels. The format width is the
314: * width to which text is wrapped.
315: * @return the format width
316: */
317: public int getFormatWidth() {
318:
319: return fImpl.getFormatWidth();
320: }
321:
322: /**
323: * Return true if the paragraph at the given offset is left-to-right.
324: * @param offset an offset in the text
325: * @return true if the paragraph at the given offset is left-to-right
326: */
327: public boolean paragraphIsLeftToRight(int offset) {
328:
329: return fImpl.paragraphIsLeftToRight(offset);
330: }
331:
332: /**
333: * Return true if there is a change which can be undone.
334: * @return true if there is a change which can be undone.
335: */
336: public boolean canUndo() {
337:
338: return fImpl.canUndo();
339: }
340:
341: /**
342: * Return true if there is a change which can be redone.
343: * @return true if there is a change which can be redone.
344: */
345: public boolean canRedo() {
346:
347: return fImpl.canRedo();
348: }
349:
350: /**
351: * Return true if the clipboard contains contents which could be
352: * transfered into the text.
353: * @return true if the clipboard has text content.
354: */
355: public boolean clipboardNotEmpty() {
356:
357: return fImpl.clipboardNotEmpty();
358: }
359:
360: /**
361: * Return an AttributeMap of keys with default values. The default
362: * values are used when displaying text for values which are not
363: * specified in the text.
364: * @return an AttributeMap of default key-value pairs
365: */
366: public AttributeMap getDefaultValues() {
367:
368: return fImpl.getDefaultValues();
369: }
370:
371: /**
372: * This method inspects the character style runs in the selection
373: * range (or the typing style at the insertion point). It returns:
374: * <ul>
375: * <li>The value of <tt>key</tt>, if the value of <tt>key</tt>
376: * is the same in all of the style runs in the selection, or</li>
377: * <li><tt>MULTIPLE_VALUES</tt>, if two or more style runs have different
378: * values for <tt>key</tt>.</li>
379: * </ul>
380: * If a style run does not contain <tt>key</tt>,
381: * its value is considered to be the default style for <tt>key</tt>,
382: * as defined by the default values AttributeMap. Note that if
383: * <tt>key</tt> does not have a default value this method may return
384: * null.
385: * This method is useful for configuring style menus.
386: * @param key the key used to retrieve values for comparison
387: * @see MTextPanel#MULTIPLE_VALUES
388: */
389: public Object getCharacterStyleOverSelection(Object key) {
390:
391: return fImpl.getCharacterStyleOverSelection(key);
392: }
393:
394: /**
395: * This method inspects the paragraph style runs in the selection
396: * range (or the typing style at the insertion point). It returns:
397: * <ul>
398: * <li>The value of <tt>key</tt>, if the value of <tt>key</tt>
399: * is the same in all of the style runs in the selection, or</li>
400: * <li><tt>MULTIPLE_VALUES</tt>, if two or more style runs have
401: * different values for <tt>key</tt>.</li>
402: * </ul>
403: * If a style run does not contain <tt>key</tt>,
404: * its value is considered to be the default style for <tt>key</tt>,
405: * as defined by the default values AttributeMap. Note that if
406: * <tt>key</tt> does not have a default value this method may return
407: * null.
408: * This method is useful for configuring style menus.
409: * @param key the key used to retrieve values for comparison
410: * @see MTextPanel#MULTIPLE_VALUES
411: */
412: public Object getParagraphStyleOverSelection(Object key) {
413:
414: return fImpl.getParagraphStyleOverSelection(key);
415: }
416:
417: /**
418: * Remove the selected text from the document and place it
419: * on the clipboard. This method has no effect if the text
420: * is not editable, or if no text is selected.
421: */
422: public void cut() {
423: fImpl.cut();
424: }
425:
426: /**
427: * Place the selected text on the clipboard. This method has
428: * no effect if no text is selected.
429: */
430: public void copy() {
431: fImpl.copy();
432: }
433:
434: /**
435: * Replace the currently selected text with the text on the clipboard.
436: * This method has no effect if the text is not editable, or if no
437: * text is on the clipboard.
438: */
439: public void paste() {
440: fImpl.paste();
441: }
442:
443: /**
444: * Remove selected text from the document, without altering the clipboard.
445: * This method has no effect if the
446: * text is not editable.
447: */
448: public void clear() {
449: fImpl.clear();
450: }
451:
452: /**
453: * Undo the most recent text change. This method has no effect if
454: * there is no change to undo.
455: */
456: public void undo() {
457: fImpl.undo();
458: }
459:
460: /**
461: * Redo the most recent text change. This method has no effect if
462: * there is no change to redo.
463: */
464: public void redo() {
465: fImpl.redo();
466: }
467:
468: /**
469: * Return the number of commands the command log can hold.
470: * @return the number of commands the command log can hold
471: */
472: public int getCommandLogSize() {
473:
474: return fImpl.getCommandLogSize();
475: }
476:
477: /**
478: * Set the number of commands the command log can hold. All
479: * redoable commands are removed when this method is called.
480: * @param size the number of commands kept in the command log
481: */
482: public void setCommandLogSize(int size) {
483: fImpl.setCommandLogSize(size);
484: }
485:
486: /**
487: * Remove all commands from the command log.
488: */
489: public void clearCommandLog() {
490: fImpl.clearCommandLog();
491: }
492:
493: /**
494: * Modify the character styles on the selected characters. If no characters
495: * are selected, modify the typing style.
496: * @param modifier the StyleModifier with which to modify the styles
497: */
498: public void modifyCharacterStyleOnSelection(StyleModifier modifier) {
499: fImpl.modifyCharacterStyleOnSelection(modifier);
500: }
501:
502: /**
503: * Modify the paragraph styles in paragraphs containing selected characters, or
504: * the paragraph containing the insertion point.
505: * @param modifier the StyleModifier with which to modify the styles
506: */
507: public void modifyParagraphStyleOnSelection(StyleModifier modifier) {
508: fImpl.modifyParagraphStyleOnSelection(modifier);
509: }
510:
511: /**
512: * Return the KeyRemap used to process key events.
513: * @return the key remap used to process key events
514: * @see #setKeyRemap
515: */
516: public KeyRemap getKeyRemap() {
517:
518: return fImpl.getKeyRemap();
519: }
520:
521: /**
522: * Use the given KeyRemap to map key events to characters.
523: * Only key
524: * events are affected by the remap; other text entering the
525: * control (via the clipboard, for example) is not affected
526: * by the KeyRemap.
527: * <p>
528: * Do not pass <tt>null</tt> to this method to leave key
529: * events unmapped. Instead, use <tt>KeyRemap.getIdentityRemap()</tt>
530: * @param remap the KeyRemap to use for mapping key events to characters
531: * @exception java.lang.NullPointerException if parameter is null
532: * @see KeyRemap
533: */
534: public void setKeyRemap(KeyRemap remap) {
535:
536: fImpl.setKeyRemap(remap);
537: }
538:
539: /**
540: * Return the modification flag of the current text change.
541: * @see #setModified
542: */
543: public boolean isModified() {
544:
545: return fImpl.isModified();
546: }
547:
548: /**
549: * Set the modification flag of the current text change.
550: */
551: public void setModified(boolean modified) {
552:
553: fImpl.setModified(modified);
554: }
555:
556: /**
557: * This method is for KeyEventForwarder's use only!
558: */
559: ATextPanelImpl getImpl() {
560:
561: return fImpl;
562: }
563:
564: public void setBackground(Color color) {
565: super .setBackground(color);
566: java.awt.Component[] compList = getComponents();
567: for (int i = 0; i < compList.length; i++) {
568: if (!(compList[i] instanceof JScrollBar)) {
569: compList[i].setBackground(color);
570: }
571: }
572: }
573: }
|