mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-13 08:53:20 +00:00
RichEdit AWT and Swing panels. This is the central package for the control.
X-SVN-Rev: 1191
This commit is contained in:
parent
bf82494a6f
commit
e9f426a35d
37 changed files with 8110 additions and 0 deletions
761
icu4j/src/com/ibm/richtext/textpanel/ATextPanelImpl.java
Executable file
761
icu4j/src/com/ibm/richtext/textpanel/ATextPanelImpl.java
Executable file
|
@ -0,0 +1,761 @@
|
|||
/*
|
||||
* @(#)$RCSfile: ATextPanelImpl.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
import java.awt.Adjustable;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.datatransfer.Clipboard;
|
||||
|
||||
import com.ibm.textlayout.attributes.AttributeMap;
|
||||
import com.ibm.textlayout.attributes.AttributeSet;
|
||||
|
||||
import com.ibm.richtext.styledtext.StyleModifier;
|
||||
import com.ibm.richtext.styledtext.MConstText;
|
||||
import com.ibm.richtext.styledtext.MText;
|
||||
import com.ibm.richtext.styledtext.StyledText;
|
||||
import com.ibm.richtext.textformat.TextOffset;
|
||||
|
||||
/**
|
||||
* Implementation class for TextPanel and JTextPanel.
|
||||
*/
|
||||
final class ATextPanelImpl {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
|
||||
private RunStrategy fRunStrategy = null;
|
||||
private TextComponent fTextComponent = null;
|
||||
private TextSelection fSelection = null;
|
||||
private TextEditBehavior fEditBehavior = null;
|
||||
private MText fText = null;
|
||||
|
||||
private PanelEventBroadcaster fBroadcaster;
|
||||
private KeyRemap fRemap = KeyRemap.getIdentityRemap();
|
||||
|
||||
// This is a little ugly. TextPanel supports its modified
|
||||
// flag whether or not it is editable, or even selectable.
|
||||
// So if there's no command log to keep track of the flag
|
||||
// state then its done right here in TextPanel. If the
|
||||
// panel is editable this flag is ignored.
|
||||
private boolean fModified = false;
|
||||
|
||||
static final TextPanelSettings fgDefaultSettings = new TextPanelSettings();
|
||||
|
||||
static TextPanelSettings getDefaultSettings() {
|
||||
|
||||
return (TextPanelSettings) fgDefaultSettings.clone();
|
||||
}
|
||||
|
||||
ATextPanelImpl(RunStrategy runStrategy,
|
||||
TextPanelSettings settings,
|
||||
MConstText initialText,
|
||||
Clipboard clipboard,
|
||||
MTextPanel client,
|
||||
Adjustable horzSb,
|
||||
Adjustable vertSb) {
|
||||
|
||||
fRunStrategy = runStrategy;
|
||||
fBroadcaster = new PanelEventBroadcaster(client);
|
||||
|
||||
Scroller scroller = null;
|
||||
if (settings.getScrollable()) {
|
||||
scroller = new Scroller(horzSb, vertSb);
|
||||
}
|
||||
|
||||
StyledTextClipboard textClipboard =
|
||||
StyledTextClipboard.getClipboardFor(clipboard);
|
||||
|
||||
fText = new StyledText();
|
||||
if (initialText != null) {
|
||||
fText.append(initialText);
|
||||
}
|
||||
|
||||
fTextComponent = new TextComponent(fText,
|
||||
settings.getDefaultValues(),
|
||||
settings.getWraps(),
|
||||
TextComponent.WINDOW_WIDTH,
|
||||
TextComponent.DEFAULT_INSET,
|
||||
textClipboard,
|
||||
settings.getScrollable(),
|
||||
scroller,
|
||||
fBroadcaster);
|
||||
|
||||
if (scroller != null) {
|
||||
scroller.setClient(fTextComponent);
|
||||
}
|
||||
|
||||
// May have to wait until component has host to do this:
|
||||
if (settings.getSelectable()) {
|
||||
fSelection = new TextSelection(fTextComponent,
|
||||
fBroadcaster,
|
||||
fRunStrategy);
|
||||
fSelection.addToOwner(fTextComponent);
|
||||
if (settings.getEditable()) {
|
||||
fEditBehavior = new TextEditBehavior(
|
||||
fTextComponent, fSelection, fBroadcaster, fRemap);
|
||||
fEditBehavior.addToOwner(fTextComponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FakeComponent getTextComponent() {
|
||||
|
||||
return fTextComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given TextPanelListener to the listeners which will
|
||||
* receive update notifications from this TextPanel.
|
||||
* @param listener the listener to add
|
||||
*/
|
||||
public void addListener(TextPanelListener listener) {
|
||||
|
||||
fBroadcaster.addListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given TextPanelListener from the listeners which will
|
||||
* receive update notifications from this TextPanel.
|
||||
* @param listener the listener to remove
|
||||
*/
|
||||
public void removeListener(TextPanelListener listener) {
|
||||
|
||||
fBroadcaster.removeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* You know what this does...
|
||||
*/
|
||||
private static int pin(int value, int min, int max) {
|
||||
|
||||
if (min > max) {
|
||||
throw new IllegalArgumentException("Invalid range");
|
||||
}
|
||||
|
||||
if (value < min) {
|
||||
value = min;
|
||||
}
|
||||
else if (value > max) {
|
||||
value = max;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
//============
|
||||
// Text Access
|
||||
//============
|
||||
|
||||
/**
|
||||
* Set the document to <tt>newText</tt>. This operation
|
||||
* modifies the text in the TextPanel. It does not modify or adopt
|
||||
* <tt>newText</tt>. This method sets the selection an insertion point at
|
||||
* the end of the text.
|
||||
* @param newText the text which will replace the current text.
|
||||
*/
|
||||
public void setText(MConstText newText) {
|
||||
|
||||
replaceRange(newText, 0, getTextLength());
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the given text to the end of the document. Equivalent to
|
||||
* <tt>insert(newText, getTextLength())</tt>.
|
||||
* @param newText the text to append to the document
|
||||
*/
|
||||
public void append(MConstText newText) {
|
||||
|
||||
int length = getTextLength();
|
||||
replaceRange(newText, length, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the given text into the document at the given position.
|
||||
* Equivalent to
|
||||
* <tt>replaceRange(newText, position, position)</tt>.
|
||||
* @param newText the text to insert into the document.
|
||||
* @param position the position in the document where the
|
||||
* text will be inserted
|
||||
*/
|
||||
public void insert(MConstText newText, int position) {
|
||||
|
||||
replaceRange(newText, position, position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the given range with <tt>newText</tt>. After this
|
||||
* operation the selection range is an insertion point at the
|
||||
* end of the new text.
|
||||
* @param newText the text with which to replace the range
|
||||
* @param start the beginning of the range to replace
|
||||
* @param end the end of the range to replace
|
||||
*/
|
||||
public void replaceRange(MConstText newText, int start, int end) {
|
||||
|
||||
int length = getTextLength();
|
||||
|
||||
start = pin(start, 0, length);
|
||||
end = pin(end, start, length);
|
||||
|
||||
if (fSelection != null) {
|
||||
|
||||
// If we're selectable, but not editable, we'll temporarily
|
||||
// make ourselves editable to change the text. A little funny
|
||||
// but there's a lot of code for getting caret stuff right,
|
||||
// and this is not a common operation anyway.
|
||||
|
||||
TextEditBehavior behavior;
|
||||
|
||||
if (fEditBehavior == null) {
|
||||
behavior = new TextEditBehavior(fTextComponent, fSelection, fBroadcaster, fRemap);
|
||||
behavior.addToOwner(fTextComponent);
|
||||
}
|
||||
else {
|
||||
behavior = fEditBehavior;
|
||||
}
|
||||
|
||||
TextOffset newSelection = new TextOffset(start + newText.length(),
|
||||
TextOffset.AFTER_OFFSET);
|
||||
|
||||
TextReplacement replacement = new TextReplacement(start, end,
|
||||
newText,
|
||||
newSelection,
|
||||
newSelection);
|
||||
|
||||
fTextComponent.textControlEventOccurred(Behavior.REPLACE,
|
||||
replacement);
|
||||
if (fEditBehavior == null) {
|
||||
behavior.removeFromOwner();
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
MText oldText = fTextComponent.getModifiableText();
|
||||
fTextComponent.stopBackgroundFormatting();
|
||||
oldText.replaceAll(newText);
|
||||
fTextComponent.reformatAndDrawText(0, newText.length(), null, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the length of the text document in the TextPanel.
|
||||
* @return the length of the text document in the TextPanel
|
||||
*/
|
||||
public int getTextLength() {
|
||||
|
||||
return fTextComponent.getText().length();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the text document in the TextPanel.
|
||||
* @return the text document in the TextPanel.
|
||||
*/
|
||||
public MConstText getText() {
|
||||
|
||||
return fTextComponent.getText();
|
||||
}
|
||||
|
||||
//============
|
||||
// Selection Access
|
||||
//============
|
||||
|
||||
/**
|
||||
* Return the offset of the start of the selection.
|
||||
*/
|
||||
public int getSelectionStart() {
|
||||
|
||||
if (fSelection != null) {
|
||||
return fSelection.getStart().fOffset;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the offset of the end of the selection.
|
||||
*/
|
||||
public int getSelectionEnd() {
|
||||
|
||||
if (fSelection != null) {
|
||||
return fSelection.getEnd().fOffset;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the beginning of the selection range. This is
|
||||
* equivalent to <tt>select(selectionStart, getSelectionEnd())</tt>.
|
||||
* @param selectionStart the start of the new selection range
|
||||
*/
|
||||
public void setSelectionStart(int selectionStart) {
|
||||
|
||||
select(selectionStart, getSelectionEnd());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the end of the selection range. This is
|
||||
* equivalent to <tt>select(getSelectionStart(), selectionEnd)</tt>.
|
||||
* @param selectionStart the start of the new selection range
|
||||
*/
|
||||
public void setSelectionEnd(int selectionEnd) {
|
||||
|
||||
select(getSelectionStart(), selectionEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selection range to an insertion point at the given
|
||||
* offset. This is equivalent to
|
||||
* <tt>select(position, position)</tt>.
|
||||
* @param position the offset of the new insertion point
|
||||
*/
|
||||
public void setCaretPosition(int position) {
|
||||
|
||||
select(position, position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selection range to the given range. The range start
|
||||
* is pinned between 0 and the text length; the range end is pinned
|
||||
* between the range start and the end of the text. These semantics
|
||||
* are identical to those of <tt>java.awt.TextComponent</tt>.
|
||||
* This method has no effect if the text is not selectable.
|
||||
* @param selectionStart the beginning of the selection range
|
||||
* @param selectionEnd the end of the selection range
|
||||
*/
|
||||
public void select(int selectionStart, int selectionEnd) {
|
||||
|
||||
int length = getTextLength();
|
||||
|
||||
selectionStart = pin(selectionStart, 0, length);
|
||||
selectionEnd = pin(selectionEnd, selectionStart, length);
|
||||
|
||||
TextRange range = new TextRange(selectionStart, selectionEnd);
|
||||
fTextComponent.textControlEventOccurred(Behavior.SELECT, range);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select all of the text in the document. This method has no effect if
|
||||
* the text is not selectable.
|
||||
*/
|
||||
public void selectAll() {
|
||||
|
||||
select(0, getTextLength());
|
||||
}
|
||||
|
||||
|
||||
//============
|
||||
// Format Width
|
||||
//============
|
||||
|
||||
/**
|
||||
* Return the total format width, in pixels. The format width is the
|
||||
* width to which text is wrapped.
|
||||
* @return the format width
|
||||
*/
|
||||
public int getFormatWidth() {
|
||||
|
||||
return fTextComponent.getFormatWidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the paragraph at the given offset is left-to-right.
|
||||
* @param offset an offset in the text
|
||||
* @return true if the paragraph at the given offset is left-to-right
|
||||
*/
|
||||
public boolean paragraphIsLeftToRight(int offset) {
|
||||
|
||||
return fTextComponent.paragraphIsLeftToRight(offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is a change which can be undone.
|
||||
* @return true if there is a change which can be undone.
|
||||
*/
|
||||
public boolean canUndo() {
|
||||
|
||||
if (fEditBehavior != null) {
|
||||
return fEditBehavior.canUndo();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is a change which can be redone.
|
||||
* @return true if there is a change which can be redone.
|
||||
*/
|
||||
public boolean canRedo() {
|
||||
|
||||
if (fEditBehavior != null) {
|
||||
return fEditBehavior.canRedo();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the clipboard contains contents which could be
|
||||
* transfered into the text.
|
||||
* @return true if the clipboard has text content.
|
||||
*/
|
||||
public boolean clipboardNotEmpty() {
|
||||
|
||||
return fTextComponent.getClipboard().hasContents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an AttributeMap of keys with default values. The default
|
||||
* values are used when displaying text for values which are not
|
||||
* specified in the text.
|
||||
* @return an AttributeMap of default key-value pairs
|
||||
*/
|
||||
public AttributeMap getDefaultValues() {
|
||||
|
||||
return fTextComponent.getDefaultValues();
|
||||
}
|
||||
|
||||
private static boolean objectsAreEqual(Object lhs, Object rhs) {
|
||||
|
||||
if (lhs == null) {
|
||||
return rhs == null;
|
||||
}
|
||||
else {
|
||||
return lhs.equals(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
private static Object consistentCharStyle(MConstText text,
|
||||
int start,
|
||||
int limit,
|
||||
Object key,
|
||||
Object defaultValue) {
|
||||
|
||||
if (start >= limit) {
|
||||
throw new IllegalArgumentException("Invalid range.");
|
||||
}
|
||||
|
||||
int runStart = start;
|
||||
Object initialValue = text.characterStyleAt(runStart).get(key);
|
||||
|
||||
if (initialValue == null) {
|
||||
initialValue = defaultValue;
|
||||
}
|
||||
|
||||
for (runStart = text.characterStyleLimit(runStart);
|
||||
runStart < limit;
|
||||
runStart = text.characterStyleLimit(runStart)) {
|
||||
|
||||
Object nextValue = text.characterStyleAt(runStart).get(key);
|
||||
|
||||
if (nextValue == null) {
|
||||
nextValue = defaultValue;
|
||||
}
|
||||
|
||||
if (!objectsAreEqual(initialValue, nextValue)) {
|
||||
return MTextPanel.MULTIPLE_VALUES;
|
||||
}
|
||||
}
|
||||
|
||||
return initialValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method inspects the character style runs in the selection
|
||||
* range (or the typing style at the insertion point) and returns:
|
||||
* <ul>
|
||||
* <li>The value of <tt>key</tt>, if the value of <tt>key</tt>
|
||||
* is the same in all of the style runs in the selection, or</li>
|
||||
* <li>null, if two or more style runs have different values for <tt>key</tt>.</li>
|
||||
* </ul>
|
||||
* If a style run does not contain <tt>key</tt>,
|
||||
* its value is considered to be <tt>defaultStyle</tt>.
|
||||
* This method is useful for configuring style menus.
|
||||
* @param key the key used to retrieve values for comparison
|
||||
* @param defaultValue the implicit value of <tt>key</tt> in
|
||||
* style runs where <tt>key</tt> is not defined
|
||||
*/
|
||||
public Object getCharacterStyleOverSelection(Object key) {
|
||||
|
||||
TextRange selRange;
|
||||
if (fSelection != null)
|
||||
selRange = fSelection.getSelectionRange();
|
||||
else
|
||||
selRange = new TextRange(0, 0);
|
||||
|
||||
if (selRange.start == selRange.limit) {
|
||||
|
||||
AttributeMap compStyle;
|
||||
|
||||
if (fEditBehavior != null) {
|
||||
compStyle = fEditBehavior.getInsertionPointStyle();
|
||||
}
|
||||
else {
|
||||
compStyle = TextEditBehavior.typingStyleAt(fText, selRange.start, selRange.limit);
|
||||
}
|
||||
|
||||
Object value = compStyle.get(key);
|
||||
return value==null? getDefaultValues().get(key) : value;
|
||||
}
|
||||
else {
|
||||
return consistentCharStyle(fText,
|
||||
selRange.start,
|
||||
selRange.limit,
|
||||
key,
|
||||
getDefaultValues().get(key));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method inspects the paragraph style runs in the selection
|
||||
* range (or the typing style at the insertion point) and returns:
|
||||
* <ul>
|
||||
* <li>The value of <tt>key</tt>, if the value of <tt>key</tt>
|
||||
* is the same in all of the style runs in the selection, or</li>
|
||||
* <li>null, if two or more style runs have different values for <tt>key</tt>.</li>
|
||||
* </ul>
|
||||
* If a style run does not contain <tt>key</tt>,
|
||||
* its value is considered to be <tt>defaultStyle</tt>.
|
||||
* This method is useful for configuring style menus.
|
||||
* @param key the key used to retrieve values for comparison
|
||||
* @param defaultValue the implicit value of <tt>key</tt> in
|
||||
* style runs where <tt>key</tt> is not defined
|
||||
*/
|
||||
public Object getParagraphStyleOverSelection(Object key) {
|
||||
|
||||
TextRange selRange;
|
||||
if (fSelection != null) {
|
||||
selRange = fSelection.getSelectionRange();
|
||||
}
|
||||
else {
|
||||
selRange = new TextRange(0, 0);
|
||||
}
|
||||
|
||||
if (selRange.start == selRange.limit) {
|
||||
AttributeMap pStyle = fText.paragraphStyleAt(selRange.start);
|
||||
Object value = pStyle.get(key);
|
||||
return value==null? getDefaultValues().get(key) : value;
|
||||
}
|
||||
else {
|
||||
int paragraphStart = selRange.start;
|
||||
Object defaultValue = getDefaultValues().get(key);
|
||||
Object initialValue = fText.paragraphStyleAt(paragraphStart).get(key);
|
||||
if (initialValue == null) {
|
||||
initialValue = defaultValue;
|
||||
}
|
||||
|
||||
for (paragraphStart = fText.paragraphLimit(paragraphStart);
|
||||
paragraphStart < selRange.limit;
|
||||
paragraphStart = fText.paragraphLimit(paragraphStart)) {
|
||||
|
||||
Object nextValue = fText.paragraphStyleAt(paragraphStart).get(key);
|
||||
if (nextValue == null) {
|
||||
nextValue = defaultValue;
|
||||
}
|
||||
|
||||
if (!objectsAreEqual(initialValue, nextValue)) {
|
||||
return MTextPanel.MULTIPLE_VALUES;
|
||||
}
|
||||
}
|
||||
|
||||
return initialValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the selected text from the document and place it
|
||||
* on the clipboard. This method has no effect if the text
|
||||
* is not editable, or if no text is selected.
|
||||
*/
|
||||
public void cut() {
|
||||
fTextComponent.textControlEventOccurred(Behavior.CUT, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Place the selected text on the clipboard. This method has
|
||||
* no effect if no text is selected.
|
||||
*/
|
||||
public void copy() {
|
||||
fTextComponent.textControlEventOccurred(Behavior.COPY, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the currently selected text with the text on the clipboard.
|
||||
* This method has no effect if the text is not editable, or if no
|
||||
* text is on the clipboard.
|
||||
*/
|
||||
public void paste() {
|
||||
fTextComponent.textControlEventOccurred(Behavior.PASTE, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove selected text from the document, without altering the clipboard.
|
||||
* This method has no effect if the
|
||||
* text is not editable.
|
||||
*/
|
||||
public void clear() {
|
||||
fTextComponent.textControlEventOccurred(Behavior.CLEAR, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undo the most recent text change. This method has no effect if
|
||||
* there is no change to undo.
|
||||
*/
|
||||
public void undo() {
|
||||
fTextComponent.textControlEventOccurred(Behavior.UNDO, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Redo the most recent text change. This method has no effect if
|
||||
* there is no change to redo.
|
||||
*/
|
||||
public void redo() {
|
||||
fTextComponent.textControlEventOccurred(Behavior.REDO, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of commands the command log can hold.
|
||||
* @return the number of commands the command log can hold
|
||||
*/
|
||||
public int getCommandLogSize() {
|
||||
|
||||
if (fEditBehavior != null) {
|
||||
return fEditBehavior.getCommandLogSize();
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of commands the command log can hold. All
|
||||
* redoable commands are removed when this method is called.
|
||||
* @param size the number of commands kept in the command log
|
||||
*/
|
||||
public void setCommandLogSize(int size) {
|
||||
fTextComponent.textControlEventOccurred(Behavior.SET_COMMAND_LOG_SIZE,
|
||||
new Integer(size));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all commands from the command log.
|
||||
*/
|
||||
public void clearCommandLog() {
|
||||
fTextComponent.textControlEventOccurred(Behavior.CLEAR_COMMAND_LOG, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the character styles on the selected characters. If no characters
|
||||
* are selected, modify the typing style.
|
||||
* @param modifier the StyleModifier with which to modify the styles
|
||||
*/
|
||||
public void modifyCharacterStyleOnSelection(StyleModifier modifier) {
|
||||
fTextComponent.textControlEventOccurred(Behavior.CHARACTER_STYLE_MOD, modifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the paragraph styles in paragraphs containing selected characters, or
|
||||
* the paragraph containing the insertion point.
|
||||
* @param modifier the StyleModifier with which to modify the styles
|
||||
*/
|
||||
public void modifyParagraphStyleOnSelection(StyleModifier modifier) {
|
||||
fTextComponent.textControlEventOccurred(Behavior.PARAGRAPH_STYLE_MOD, modifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the KeyRemap used to process key events.
|
||||
* @return the key remap used to process key events
|
||||
* @see #setKeyRemap
|
||||
*/
|
||||
public KeyRemap getKeyRemap() {
|
||||
|
||||
return fRemap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the given KeyRemap to map key events to characters.
|
||||
* Only key
|
||||
* events are affected by the remap; other text entering the
|
||||
* control (via the clipboard, for example) is not affected
|
||||
* by the KeyRemap.
|
||||
* <p>
|
||||
* Do not pass <tt>null</tt> to this method to leave key
|
||||
* events unmapped. Instead, use <tt>KeyRemap.getIdentityRemap()</tt>
|
||||
* @param remap the KeyRemap to use for mapping key events to characters
|
||||
* @exception java.lang.NullPointerException if parameter is null
|
||||
* @see KeyRemap
|
||||
*/
|
||||
public void setKeyRemap(KeyRemap remap) {
|
||||
|
||||
if (remap == null) {
|
||||
throw new NullPointerException("remap can't be null");
|
||||
}
|
||||
|
||||
fRemap = remap;
|
||||
if (fEditBehavior != null) {
|
||||
fEditBehavior.setKeyRemap(remap);
|
||||
}
|
||||
|
||||
fBroadcaster.textStateChanged(TextPanelEvent.KEYREMAP_CHANGED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the modification flag of the current text change.
|
||||
* @see #setModified
|
||||
*/
|
||||
public boolean isModified() {
|
||||
|
||||
if (fEditBehavior != null) {
|
||||
return fEditBehavior.isModified();
|
||||
}
|
||||
else {
|
||||
return fModified;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the modification flag of the current text change.
|
||||
*/
|
||||
public void setModified(boolean modified) {
|
||||
|
||||
boolean handled = fTextComponent.textControlEventOccurred(
|
||||
Behavior.SET_MODIFIED,
|
||||
modified? Boolean.TRUE : Boolean.FALSE);
|
||||
if (!handled) {
|
||||
fModified = modified;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is for perf-testing only!
|
||||
*/
|
||||
void handleKeyEvent(java.awt.event.KeyEvent keyEvent) {
|
||||
switch (keyEvent.getID()) {
|
||||
case java.awt.event.KeyEvent.KEY_PRESSED:
|
||||
fTextComponent.keyPressed(keyEvent);
|
||||
break;
|
||||
case java.awt.event.KeyEvent.KEY_TYPED:
|
||||
fTextComponent.keyTyped(keyEvent);
|
||||
break;
|
||||
case java.awt.event.KeyEvent.KEY_RELEASED:
|
||||
fTextComponent.keyReleased(keyEvent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
180
icu4j/src/com/ibm/richtext/textpanel/ArabicTransliteration.java
Executable file
180
icu4j/src/com/ibm/richtext/textpanel/ArabicTransliteration.java
Executable file
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* @(#)$RCSfile: ArabicTransliteration.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
/*
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998, All Rights Reserved
|
||||
*/
|
||||
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
/*
|
||||
For any incoming character C
|
||||
if you can map C using the following FakeArabicTable, return
|
||||
FakeArabicTable(C)
|
||||
else if C is from A through Z, return FakeArabicTable(lowercase(C))
|
||||
else just return C
|
||||
|
||||
|
||||
FakeArabicTable is defined by the following mapping
|
||||
|
||||
0 0660;ARABIC-INDIC DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;;
|
||||
1 0661;ARABIC-INDIC DIGIT ONE;Nd;0;AN;;1;1;1;N;;;;;
|
||||
2 0662;ARABIC-INDIC DIGIT TWO;Nd;0;AN;;2;2;2;N;;;;;
|
||||
3 0663;ARABIC-INDIC DIGIT THREE;Nd;0;AN;;3;3;3;N;;;;;
|
||||
4 0664;ARABIC-INDIC DIGIT FOUR;Nd;0;AN;;4;4;4;N;;;;;
|
||||
5 0665;ARABIC-INDIC DIGIT FIVE;Nd;0;AN;;5;5;5;N;;;;;
|
||||
6 0666;ARABIC-INDIC DIGIT SIX;Nd;0;AN;;6;6;6;N;;;;;
|
||||
7 0667;ARABIC-INDIC DIGIT SEVEN;Nd;0;AN;;7;7;7;N;;;;;
|
||||
8 0668;ARABIC-INDIC DIGIT EIGHT;Nd;0;AN;;8;8;8;N;;;;;
|
||||
9 0669;ARABIC-INDIC DIGIT NINE;Nd;0;AN;;9;9;9;N;;;;;
|
||||
|
||||
% 066A;ARABIC PERCENT SIGN;Po;0;ET;;;;;N;;;;;
|
||||
. 066B;ARABIC DECIMAL SEPARATOR;Po;0;AN;;;;;N;;;;;
|
||||
, 060C;ARABIC COMMA;Po;0;R;;;;;N;;;;;
|
||||
- 0640;ARABIC TATWEEL;Lm;0;R;;;;;N;;;;;
|
||||
' 0652;ARABIC SUKUN;Mn;34;R;;;;;N;;;;;
|
||||
" 0651;ARABIC SHADDA;Mn;33;R;;;;;N;ARABIC SHADDAH;;;;
|
||||
; 061B;ARABIC SEMICOLON;Po;0;R;;;;;N;;;;;
|
||||
? 061F;ARABIC QUESTION MARK;Po;0;R;;;;;N;;;;;
|
||||
|
||||
a 0627;ARABIC LETTER ALEF;Lo;0;R;;;;;N;;;;;
|
||||
A 0639;ARABIC LETTER AIN;Lo;0;R;;;;;N;;;;;
|
||||
b 0628;ARABIC LETTER BEH;Lo;0;R;;;;;N;ARABIC LETTER BAA;;;;
|
||||
c 0635;ARABIC LETTER SAD;Lo;0;R;;;;;N;;;;;
|
||||
d 062F;ARABIC LETTER DAL;Lo;0;R;;;;;N;;;;;
|
||||
D 0630;ARABIC LETTER THAL;Lo;0;R;;;;;N;;;;;
|
||||
E 064B;ARABIC FATHATAN;Mn;27;R;;;;;N;;;;;
|
||||
e 064E;ARABIC FATHA;Mn;30;R;;;;;N;ARABIC FATHAH;;;;
|
||||
f 0641;ARABIC LETTER FEH;Lo;0;R;;;;;N;ARABIC LETTER FA;;;;
|
||||
g 063A;ARABIC LETTER GHAIN;Lo;0;R;;;;;N;;;;;
|
||||
h 062D;ARABIC LETTER HAH;Lo;0;R;;;;;N;ARABIC LETTER HAA;;;;
|
||||
H 0647;ARABIC LETTER HEH;Lo;0;R;;;;;N;ARABIC LETTER HA;;;;
|
||||
I 064D;ARABIC KASRATAN;Mn;29;R;;;;;N;;;;;
|
||||
i 0650;ARABIC KASRA;Mn;32;R;;;;;N;ARABIC KASRAH;;;;
|
||||
j 062C;ARABIC LETTER JEEM;Lo;0;R;;;;;N;;;;;
|
||||
K 062E;ARABIC LETTER KHAH;Lo;0;R;;;;;N;ARABIC LETTER KHAA;;;;
|
||||
k 0643;ARABIC LETTER KAF;Lo;0;R;;;;;N;ARABIC LETTER CAF;;;;
|
||||
l 0644;ARABIC LETTER LAM;Lo;0;R;;;;;N;;;;;
|
||||
m 0645;ARABIC LETTER MEEM;Lo;0;R;;;;;N;;;;;
|
||||
n 0646;ARABIC LETTER NOON;Lo;0;R;;;;;N;;;;;
|
||||
o 064F;ARABIC DAMMA;Mn;31;R;;;;;N;ARABIC DAMMAH;;;;
|
||||
p 0628;ARABIC LETTER BEH;Lo;0;R;;;;;N;ARABIC LETTER BAA;;;;
|
||||
q 0642;ARABIC LETTER QAF;Lo;0;R;;;;;N;;;;;
|
||||
r 0631;ARABIC LETTER REH;Lo;0;R;;;;;N;ARABIC LETTER RA;;;;
|
||||
s 0633;ARABIC LETTER SEEN;Lo;0;R;;;;;N;;;;;
|
||||
S 0634;ARABIC LETTER SHEEN;Lo;0;R;;;;;N;;;;;
|
||||
t 062A;ARABIC LETTER TEH;Lo;0;R;;;;;N;ARABIC LETTER TAA;;;;
|
||||
T 062B;ARABIC LETTER THEH;Lo;0;R;;;;;N;ARABIC LETTER THAA;;;;
|
||||
U 064C;ARABIC DAMMATAN;Mn;28;R;;;;;N;;;;;
|
||||
u 064F;ARABIC DAMMA;Mn;31;R;;;;;N;ARABIC DAMMAH;;;;
|
||||
v 0641;ARABIC LETTER FEH;Lo;0;R;;;;;N;ARABIC LETTER FA;;;;
|
||||
w 0648;ARABIC LETTER WAW;Lo;0;R;;;;;N;;;;;
|
||||
x 0633;ARABIC LETTER SEEN;Lo;0;R;;;;;N;;;;;
|
||||
y 064A;ARABIC LETTER YEH;Lo;0;R;;;;;N;ARABIC LETTER YA;;;;
|
||||
z 0632;ARABIC LETTER ZAIN;Lo;0;R;;;;;N;;;;;
|
||||
Z 0638;ARABIC LETTER ZAH;Lo;0;R;;;;;N;ARABIC LETTER DHAH;;;;
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class implements KeyRemap to produce transliterated Arabic
|
||||
* characters from Latin-1 characters.
|
||||
*/
|
||||
|
||||
final class ArabicTransliteration extends KeyRemap {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
public char remap(char c) {
|
||||
|
||||
switch (c) {
|
||||
case '0': return '\u0660'; // ARABIC-INDIC DIGIT ZERO
|
||||
case '1': return '\u0661'; // ARABIC-INDIC DIGIT ONE
|
||||
case '2': return '\u0662'; // ARABIC-INDIC DIGIT TWO
|
||||
case '3': return '\u0663'; // ARABIC-INDIC DIGIT THREE
|
||||
case '4': return '\u0664'; // ARABIC-INDIC DIGIT FOUR
|
||||
case '5': return '\u0665'; // ARABIC-INDIC DIGIT FIVE
|
||||
case '6': return '\u0666'; // ARABIC-INDIC DIGIT SIX
|
||||
case '7': return '\u0667'; // ARABIC-INDIC DIGIT SEVEN
|
||||
case '8': return '\u0668'; // ARABIC-INDIC DIGIT EIGHT
|
||||
case '9': return '\u0669'; // ARABIC-INDIC DIGIT NINE
|
||||
|
||||
case '%': return '\u066A'; // ARABIC PERCENT SIGN
|
||||
// the Traditional Arabic font does not contain this character
|
||||
// case '.': return '\u066B'; // ARABIC DECIMAL SEPARATOR
|
||||
case ',': return '\u060C'; // ARABIC COMMA
|
||||
case '-': return '\u0640'; // ARABIC TATWEEL
|
||||
case '\'': return '\u0652'; // ARABIC SUKUN
|
||||
case '"': return '\u0651'; // ARABIC SHADDA
|
||||
case ';': return '\u061B'; // ARABIC SEMICOLON
|
||||
case '?': return '\u061F'; // ARABIC QUESTION MARK
|
||||
|
||||
case 'a': return '\u0627'; // ARABIC LETTER ALEF
|
||||
case 'A': return '\u0639'; // ARABIC LETTER AIN
|
||||
case 'b': return '\u0628'; // ARABIC LETTER BEH
|
||||
case 'B': return '\u0628'; // ARABIC LETTER BEH
|
||||
case 'c': return '\u0635'; // ARABIC LETTER SAD
|
||||
case 'C': return '\u0635'; // ARABIC LETTER SAD
|
||||
case 'd': return '\u062F'; // ARABIC LETTER DAL
|
||||
case 'D': return '\u0630'; // ARABIC LETTER THAL
|
||||
case 'e': return '\u064E'; // ARABIC FATHA
|
||||
case 'E': return '\u064B'; // ARABIC FATHATAN
|
||||
case 'f': return '\u0641'; // ARABIC LETTER FEH
|
||||
case 'F': return '\u0641'; // ARABIC LETTER FEH
|
||||
case 'g': return '\u063A'; // ARABIC LETTER GHAIN
|
||||
case 'G': return '\u063A'; // ARABIC LETTER GHAIN
|
||||
case 'h': return '\u062D'; // ARABIC LETTER HAH
|
||||
case 'H': return '\u0647'; // ARABIC LETTER HEH
|
||||
case 'i': return '\u0650'; // ARABIC KASRA
|
||||
case 'I': return '\u064D'; // ARABIC KASRATAN
|
||||
case 'j': return '\u062C'; // ARABIC LETTER JEEM
|
||||
case 'J': return '\u062C'; // ARABIC LETTER JEEM
|
||||
case 'k': return '\u0643'; // ARABIC LETTER KAF
|
||||
case 'K': return '\u062E'; // ARABIC LETTER KHAH
|
||||
case 'l': return '\u0644'; // ARABIC LETTER LAM
|
||||
case 'L': return '\u0644'; // ARABIC LETTER LAM
|
||||
case 'm': return '\u0645'; // ARABIC LETTER MEEM
|
||||
case 'M': return '\u0645'; // ARABIC LETTER MEEM
|
||||
case 'n': return '\u0646'; // ARABIC LETTER NOON
|
||||
case 'N': return '\u0646'; // ARABIC LETTER NOON
|
||||
case 'o': return '\u064F'; // ARABIC DAMMA
|
||||
case 'O': return '\u064F'; // ARABIC DAMMA
|
||||
case 'p': return '\u0628'; // ARABIC LETTER BEH
|
||||
case 'P': return '\u0628'; // ARABIC LETTER BEH
|
||||
case 'q': return '\u0642'; // ARABIC LETTER QAF
|
||||
case 'Q': return '\u0642'; // ARABIC LETTER QAF
|
||||
case 'r': return '\u0631'; // ARABIC LETTER REH
|
||||
case 'R': return '\u0631'; // ARABIC LETTER REH
|
||||
case 's': return '\u0633'; // ARABIC LETTER SEEN
|
||||
case 'S': return '\u0634'; // ARABIC LETTER SHEEN
|
||||
case 't': return '\u062A'; // ARABIC LETTER TEH
|
||||
case 'T': return '\u062B'; // ARABIC LETTER THEH
|
||||
case 'U': return '\u064C'; // ARABIC DAMMATAN
|
||||
case 'u': return '\u064F'; // ARABIC DAMMA
|
||||
case 'v': return '\u0641'; // ARABIC LETTER FEH
|
||||
case 'V': return '\u0641'; // ARABIC LETTER FEH
|
||||
case 'w': return '\u0648'; // ARABIC LETTER WAW
|
||||
case 'W': return '\u0648'; // ARABIC LETTER WAW
|
||||
case 'x': return '\u0633'; // ARABIC LETTER SEEN
|
||||
case 'X': return '\u0633'; // ARABIC LETTER SEEN
|
||||
case 'y': return '\u064A'; // ARABIC LETTER YEH
|
||||
case 'Y': return '\u064A'; // ARABIC LETTER YEH
|
||||
case 'z': return '\u0632'; // ARABIC LETTER ZAIN
|
||||
case 'Z': return '\u0638'; // ARABIC LETTER ZAH
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
}
|
203
icu4j/src/com/ibm/richtext/textpanel/Behavior.java
Executable file
203
icu4j/src/com/ibm/richtext/textpanel/Behavior.java
Executable file
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* @(#)$RCSfile: Behavior.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
/** A class that handles events for a BehaviorOwner.
|
||||
* A behavior enacpsulates some piece of the event-handling logic for a component.
|
||||
* This allows the client to separate event-handling logic out into separate classes
|
||||
* according to function, or to dynamically change the way a component handles
|
||||
* events without adding a lot of special-case code to the panel itself.
|
||||
* Behaviors are stored in a linked list, and all behaviors get a crack at an event before
|
||||
* the owner gets a crack at them (right now, we rely on objects that implement
|
||||
* BehaviorOwner to support these semantics).
|
||||
* Behavior provides all the same event-handling functions that Component provides, and
|
||||
* they all have exactly the same syntax and semantics. */
|
||||
abstract class Behavior {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
private Behavior fNextBehavior = null;
|
||||
private BehaviorOwner fOwner = null;
|
||||
|
||||
static class EventType {
|
||||
|
||||
EventType() {
|
||||
}
|
||||
}
|
||||
|
||||
// events - should these be in TextPanel (or elsewhere)?
|
||||
|
||||
// This event's WHAT parameter is a TextRange instance
|
||||
static final EventType SELECT = new EventType();
|
||||
|
||||
// No WHAT param for these:
|
||||
static final EventType CUT = new EventType();
|
||||
static final EventType COPY = new EventType();
|
||||
static final EventType PASTE = new EventType();
|
||||
static final EventType CLEAR = new EventType();
|
||||
static final EventType UNDO = new EventType();
|
||||
static final EventType REDO = new EventType();
|
||||
static final EventType CLEAR_COMMAND_LOG = new EventType();
|
||||
|
||||
// WHAT param is a StyleModifier
|
||||
static final EventType CHARACTER_STYLE_MOD = new EventType();
|
||||
static final EventType PARAGRAPH_STYLE_MOD = new EventType();
|
||||
|
||||
// With this event, values of the WHAT parameter are
|
||||
// either Boolean.TRUE or Boolean.FALSE
|
||||
static final EventType SET_MODIFIED = new EventType();
|
||||
|
||||
// WHAT param is a TextReplacement
|
||||
static final EventType REPLACE = new EventType();
|
||||
|
||||
// WHAT param is an Integer
|
||||
static final EventType SET_COMMAND_LOG_SIZE = new EventType();
|
||||
|
||||
public Behavior() {
|
||||
}
|
||||
|
||||
public void addToOwner(BehaviorOwner owner) {
|
||||
removeFromOwner();
|
||||
fOwner = owner;
|
||||
setNextBehavior(owner.getBehavior());
|
||||
owner.setBehavior(this);
|
||||
}
|
||||
|
||||
public boolean focusGained(FocusEvent e) {
|
||||
if (fNextBehavior != null)
|
||||
return fNextBehavior.focusGained(e);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean focusLost(FocusEvent e) {
|
||||
if (fNextBehavior != null)
|
||||
return fNextBehavior.focusLost(e);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean keyPressed(KeyEvent e) {
|
||||
if (fNextBehavior != null)
|
||||
return fNextBehavior.keyPressed(e);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean keyTyped(KeyEvent e) {
|
||||
|
||||
if (fNextBehavior != null) {
|
||||
return fNextBehavior.keyTyped(e);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean keyReleased(KeyEvent e) {
|
||||
if (fNextBehavior != null)
|
||||
return fNextBehavior.keyReleased(e);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean mouseDragged(MouseEvent e) {
|
||||
if (fNextBehavior != null)
|
||||
return fNextBehavior.mouseDragged(e);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean mouseEntered(MouseEvent e) {
|
||||
if (fNextBehavior != null)
|
||||
return fNextBehavior.mouseEntered(e);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean mouseExited(MouseEvent e) {
|
||||
if (fNextBehavior != null)
|
||||
return fNextBehavior.mouseExited(e);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean mouseMoved(MouseEvent e) {
|
||||
if (fNextBehavior != null)
|
||||
return fNextBehavior.mouseMoved(e);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean mousePressed(MouseEvent e) {
|
||||
if (fNextBehavior != null)
|
||||
return fNextBehavior.mousePressed(e);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean mouseReleased(MouseEvent e) {
|
||||
if (fNextBehavior != null)
|
||||
return fNextBehavior.mouseReleased(e);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public final Behavior nextBehavior() {
|
||||
return fNextBehavior;
|
||||
}
|
||||
|
||||
public boolean paint(Graphics g, Rectangle drawRect) {
|
||||
if (fNextBehavior != null)
|
||||
return fNextBehavior.paint(g, drawRect);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public void removeFromOwner() {
|
||||
if (fOwner != null) {
|
||||
if (fOwner.getBehavior() == this)
|
||||
fOwner.setBehavior(nextBehavior());
|
||||
else {
|
||||
Behavior current = fOwner.getBehavior();
|
||||
|
||||
while (current != null && current.nextBehavior() != this)
|
||||
current = current.nextBehavior();
|
||||
if (current != null)
|
||||
current.setNextBehavior(nextBehavior());
|
||||
}
|
||||
setNextBehavior(null);
|
||||
fOwner = null;
|
||||
}
|
||||
}
|
||||
|
||||
public final void setNextBehavior(Behavior next) {
|
||||
fNextBehavior = next;
|
||||
}
|
||||
|
||||
public boolean textControlEventOccurred(EventType event, Object data) {
|
||||
if (fNextBehavior != null)
|
||||
return fNextBehavior.textControlEventOccurred(event, data);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
22
icu4j/src/com/ibm/richtext/textpanel/BehaviorOwner.java
Executable file
22
icu4j/src/com/ibm/richtext/textpanel/BehaviorOwner.java
Executable file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* @(#)$RCSfile: BehaviorOwner.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
interface BehaviorOwner {
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
public Behavior getBehavior();
|
||||
public void setBehavior(Behavior b);
|
||||
}
|
55
icu4j/src/com/ibm/richtext/textpanel/Command.java
Executable file
55
icu4j/src/com/ibm/richtext/textpanel/Command.java
Executable file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* @(#)$RCSfile: Command.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
abstract class Command {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
private Command fPreviousCommand = null;
|
||||
|
||||
// fModified is used to keep a textModified flag for
|
||||
// clients
|
||||
private boolean fModified;
|
||||
|
||||
public Command() {
|
||||
fModified = true;
|
||||
}
|
||||
|
||||
public Command previousCommand() {
|
||||
return fPreviousCommand;
|
||||
}
|
||||
|
||||
public void setPreviousCommand(Command previousCommand) {
|
||||
fPreviousCommand = previousCommand;
|
||||
}
|
||||
|
||||
public abstract void execute();
|
||||
public abstract void undo();
|
||||
|
||||
public void redo() {
|
||||
execute();
|
||||
}
|
||||
|
||||
public final boolean isModified() {
|
||||
|
||||
return fModified;
|
||||
}
|
||||
|
||||
public final void setModified(boolean modified) {
|
||||
|
||||
fModified = modified;
|
||||
}
|
||||
}
|
32
icu4j/src/com/ibm/richtext/textpanel/FakeComponent.java
Executable file
32
icu4j/src/com/ibm/richtext/textpanel/FakeComponent.java
Executable file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* @(#)$RCSfile: FakeComponent.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
|
||||
abstract class FakeComponent {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
protected Component fHost;
|
||||
|
||||
abstract void addNotify();
|
||||
abstract void paint(Graphics g);
|
||||
void setHost(Component host) {
|
||||
fHost = host;
|
||||
}
|
||||
abstract void requestFocus();
|
||||
}
|
183
icu4j/src/com/ibm/richtext/textpanel/HackArabicTransliteration.java
Executable file
183
icu4j/src/com/ibm/richtext/textpanel/HackArabicTransliteration.java
Executable file
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* @(#)$RCSfile: HackArabicTransliteration.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
/*
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998, All Rights Reserved
|
||||
*/
|
||||
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
/*
|
||||
For any incoming character C
|
||||
if you can map C using the following FakeArabicTable, return
|
||||
FakeArabicTable(C)
|
||||
else if C is from A through Z, return FakeArabicTable(lowercase(C))
|
||||
else just return C
|
||||
|
||||
|
||||
FakeArabicTable is defined by the following mapping
|
||||
|
||||
0 0660;ARABIC-INDIC DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;;
|
||||
1 0661;ARABIC-INDIC DIGIT ONE;Nd;0;AN;;1;1;1;N;;;;;
|
||||
2 0662;ARABIC-INDIC DIGIT TWO;Nd;0;AN;;2;2;2;N;;;;;
|
||||
3 0663;ARABIC-INDIC DIGIT THREE;Nd;0;AN;;3;3;3;N;;;;;
|
||||
4 0664;ARABIC-INDIC DIGIT FOUR;Nd;0;AN;;4;4;4;N;;;;;
|
||||
5 0665;ARABIC-INDIC DIGIT FIVE;Nd;0;AN;;5;5;5;N;;;;;
|
||||
6 0666;ARABIC-INDIC DIGIT SIX;Nd;0;AN;;6;6;6;N;;;;;
|
||||
7 0667;ARABIC-INDIC DIGIT SEVEN;Nd;0;AN;;7;7;7;N;;;;;
|
||||
8 0668;ARABIC-INDIC DIGIT EIGHT;Nd;0;AN;;8;8;8;N;;;;;
|
||||
9 0669;ARABIC-INDIC DIGIT NINE;Nd;0;AN;;9;9;9;N;;;;;
|
||||
|
||||
% 066A;ARABIC PERCENT SIGN;Po;0;ET;;;;;N;;;;;
|
||||
. 066B;ARABIC DECIMAL SEPARATOR;Po;0;AN;;;;;N;;;;;
|
||||
, 060C;ARABIC COMMA;Po;0;R;;;;;N;;;;;
|
||||
- 0640;ARABIC TATWEEL;Lm;0;R;;;;;N;;;;;
|
||||
' 0652;ARABIC SUKUN;Mn;34;R;;;;;N;;;;;
|
||||
" 0651;ARABIC SHADDA;Mn;33;R;;;;;N;ARABIC SHADDAH;;;;
|
||||
; 061B;ARABIC SEMICOLON;Po;0;R;;;;;N;;;;;
|
||||
? 061F;ARABIC QUESTION MARK;Po;0;R;;;;;N;;;;;
|
||||
|
||||
a 0627;ARABIC LETTER ALEF;Lo;0;R;;;;;N;;;;;
|
||||
A 0639;ARABIC LETTER AIN;Lo;0;R;;;;;N;;;;;
|
||||
b 0628;ARABIC LETTER BEH;Lo;0;R;;;;;N;ARABIC LETTER BAA;;;;
|
||||
c 0635;ARABIC LETTER SAD;Lo;0;R;;;;;N;;;;;
|
||||
d 062F;ARABIC LETTER DAL;Lo;0;R;;;;;N;;;;;
|
||||
D 0630;ARABIC LETTER THAL;Lo;0;R;;;;;N;;;;;
|
||||
E 064B;ARABIC FATHATAN;Mn;27;R;;;;;N;;;;;
|
||||
e 064E;ARABIC FATHA;Mn;30;R;;;;;N;ARABIC FATHAH;;;;
|
||||
f 0641;ARABIC LETTER FEH;Lo;0;R;;;;;N;ARABIC LETTER FA;;;;
|
||||
g 063A;ARABIC LETTER GHAIN;Lo;0;R;;;;;N;;;;;
|
||||
h 062D;ARABIC LETTER HAH;Lo;0;R;;;;;N;ARABIC LETTER HAA;;;;
|
||||
H 0647;ARABIC LETTER HEH;Lo;0;R;;;;;N;ARABIC LETTER HA;;;;
|
||||
I 064D;ARABIC KASRATAN;Mn;29;R;;;;;N;;;;;
|
||||
i 0650;ARABIC KASRA;Mn;32;R;;;;;N;ARABIC KASRAH;;;;
|
||||
j 062C;ARABIC LETTER JEEM;Lo;0;R;;;;;N;;;;;
|
||||
K 062E;ARABIC LETTER KHAH;Lo;0;R;;;;;N;ARABIC LETTER KHAA;;;;
|
||||
k 0643;ARABIC LETTER KAF;Lo;0;R;;;;;N;ARABIC LETTER CAF;;;;
|
||||
l 0644;ARABIC LETTER LAM;Lo;0;R;;;;;N;;;;;
|
||||
m 0645;ARABIC LETTER MEEM;Lo;0;R;;;;;N;;;;;
|
||||
n 0646;ARABIC LETTER NOON;Lo;0;R;;;;;N;;;;;
|
||||
o 064F;ARABIC DAMMA;Mn;31;R;;;;;N;ARABIC DAMMAH;;;;
|
||||
p 0628;ARABIC LETTER BEH;Lo;0;R;;;;;N;ARABIC LETTER BAA;;;;
|
||||
q 0642;ARABIC LETTER QAF;Lo;0;R;;;;;N;;;;;
|
||||
r 0631;ARABIC LETTER REH;Lo;0;R;;;;;N;ARABIC LETTER RA;;;;
|
||||
s 0633;ARABIC LETTER SEEN;Lo;0;R;;;;;N;;;;;
|
||||
S 0634;ARABIC LETTER SHEEN;Lo;0;R;;;;;N;;;;;
|
||||
t 062A;ARABIC LETTER TEH;Lo;0;R;;;;;N;ARABIC LETTER TAA;;;;
|
||||
T 062B;ARABIC LETTER THEH;Lo;0;R;;;;;N;ARABIC LETTER THAA;;;;
|
||||
U 064C;ARABIC DAMMATAN;Mn;28;R;;;;;N;;;;;
|
||||
u 064F;ARABIC DAMMA;Mn;31;R;;;;;N;ARABIC DAMMAH;;;;
|
||||
v 0641;ARABIC LETTER FEH;Lo;0;R;;;;;N;ARABIC LETTER FA;;;;
|
||||
w 0648;ARABIC LETTER WAW;Lo;0;R;;;;;N;;;;;
|
||||
x 0633;ARABIC LETTER SEEN;Lo;0;R;;;;;N;;;;;
|
||||
y 064A;ARABIC LETTER YEH;Lo;0;R;;;;;N;ARABIC LETTER YA;;;;
|
||||
z 0632;ARABIC LETTER ZAIN;Lo;0;R;;;;;N;;;;;
|
||||
Z 0638;ARABIC LETTER ZAH;Lo;0;R;;;;;N;ARABIC LETTER DHAH;;;;
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class implements KeyRemap to produce transliterated Arabic
|
||||
* characters from Latin-1 characters.
|
||||
*/
|
||||
|
||||
// NOTE: this class eliminates Arabic vowels which look ugly
|
||||
// in the font in which we happen to be demo'ing. It's totally
|
||||
// bogus otherwise.
|
||||
final class HackArabicTransliteration extends KeyRemap {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
public char remap(char c) {
|
||||
|
||||
switch (c) {
|
||||
case '0': return '\u0660'; // ARABIC-INDIC DIGIT ZERO
|
||||
case '1': return '\u0661'; // ARABIC-INDIC DIGIT ONE
|
||||
case '2': return '\u0662'; // ARABIC-INDIC DIGIT TWO
|
||||
case '3': return '\u0663'; // ARABIC-INDIC DIGIT THREE
|
||||
case '4': return '\u0664'; // ARABIC-INDIC DIGIT FOUR
|
||||
case '5': return '\u0665'; // ARABIC-INDIC DIGIT FIVE
|
||||
case '6': return '\u0666'; // ARABIC-INDIC DIGIT SIX
|
||||
case '7': return '\u0667'; // ARABIC-INDIC DIGIT SEVEN
|
||||
case '8': return '\u0668'; // ARABIC-INDIC DIGIT EIGHT
|
||||
case '9': return '\u0669'; // ARABIC-INDIC DIGIT NINE
|
||||
|
||||
case '%': return '\u066A'; // ARABIC PERCENT SIGN
|
||||
// the Traditional Arabic font does not contain this character
|
||||
// case '.': return '\u066B'; // ARABIC DECIMAL SEPARATOR
|
||||
case ',': return '\u060C'; // ARABIC COMMA
|
||||
case '-': return '\u0640'; // ARABIC TATWEEL
|
||||
case '\'': return '\u0652'; // ARABIC SUKUN
|
||||
case '"': return '\u0651'; // ARABIC SHADDA
|
||||
case ';': return '\u061B'; // ARABIC SEMICOLON
|
||||
case '?': return '\u061F'; // ARABIC QUESTION MARK
|
||||
|
||||
case 'a': return '\u0627'; // ARABIC LETTER ALEF
|
||||
case 'A': return '\u0639'; // ARABIC LETTER AIN
|
||||
case 'b': return '\u0628'; // ARABIC LETTER BEH
|
||||
case 'B': return '\u0628'; // ARABIC LETTER BEH
|
||||
case 'c': return '\u0635'; // ARABIC LETTER SAD
|
||||
case 'C': return '\u0635'; // ARABIC LETTER SAD
|
||||
case 'd': return '\u062F'; // ARABIC LETTER DAL
|
||||
case 'D': return '\u0630'; // ARABIC LETTER THAL
|
||||
case 'e': //return '\u064E'; // ARABIC FATHA
|
||||
case 'E': //return '\u064B'; // ARABIC FATHATAN
|
||||
case 'f': return '\u0641'; // ARABIC LETTER FEH
|
||||
case 'F': return '\u0641'; // ARABIC LETTER FEH
|
||||
case 'g': return '\u063A'; // ARABIC LETTER GHAIN
|
||||
case 'G': return '\u063A'; // ARABIC LETTER GHAIN
|
||||
case 'h': return '\u062D'; // ARABIC LETTER HAH
|
||||
case 'H': return '\u0647'; // ARABIC LETTER HEH
|
||||
case 'i': //return '\u0650'; // ARABIC KASRA
|
||||
case 'I': //return '\u064D'; // ARABIC KASRATAN
|
||||
case 'j': return '\u062C'; // ARABIC LETTER JEEM
|
||||
case 'J': return '\u062C'; // ARABIC LETTER JEEM
|
||||
case 'k': return '\u0643'; // ARABIC LETTER KAF
|
||||
case 'K': return '\u062E'; // ARABIC LETTER KHAH
|
||||
case 'l': return '\u0644'; // ARABIC LETTER LAM
|
||||
case 'L': return '\u0644'; // ARABIC LETTER LAM
|
||||
case 'm': return '\u0645'; // ARABIC LETTER MEEM
|
||||
case 'M': return '\u0645'; // ARABIC LETTER MEEM
|
||||
case 'n': return '\u0646'; // ARABIC LETTER NOON
|
||||
case 'N': return '\u0646'; // ARABIC LETTER NOON
|
||||
case 'o': //return '\u064F'; // ARABIC DAMMA
|
||||
case 'O': //return '\u064F'; // ARABIC DAMMA
|
||||
case 'p': return '\u0628'; // ARABIC LETTER BEH
|
||||
case 'P': return '\u0628'; // ARABIC LETTER BEH
|
||||
case 'q': return '\u0642'; // ARABIC LETTER QAF
|
||||
case 'Q': return '\u0642'; // ARABIC LETTER QAF
|
||||
case 'r': return '\u0631'; // ARABIC LETTER REH
|
||||
case 'R': return '\u0631'; // ARABIC LETTER REH
|
||||
case 's': return '\u0633'; // ARABIC LETTER SEEN
|
||||
case 'S': return '\u0634'; // ARABIC LETTER SHEEN
|
||||
case 't': return '\u062A'; // ARABIC LETTER TEH
|
||||
case 'T': return '\u062B'; // ARABIC LETTER THEH
|
||||
case 'U': //return '\u064C'; // ARABIC DAMMATAN
|
||||
case 'u': //return '\u064F'; // ARABIC DAMMA
|
||||
case 'v': return '\u0641'; // ARABIC LETTER FEH
|
||||
case 'V': return '\u0641'; // ARABIC LETTER FEH
|
||||
case 'w': return '\u0648'; // ARABIC LETTER WAW
|
||||
case 'W': return '\u0648'; // ARABIC LETTER WAW
|
||||
case 'x': return '\u0633'; // ARABIC LETTER SEEN
|
||||
case 'X': return '\u0633'; // ARABIC LETTER SEEN
|
||||
case 'y': return '\u064A'; // ARABIC LETTER YEH
|
||||
case 'Y': return '\u064A'; // ARABIC LETTER YEH
|
||||
case 'z': return '\u0632'; // ARABIC LETTER ZAIN
|
||||
case 'Z': return '\u0638'; // ARABIC LETTER ZAH
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
}
|
90
icu4j/src/com/ibm/richtext/textpanel/HebrewTransliteration.java
Executable file
90
icu4j/src/com/ibm/richtext/textpanel/HebrewTransliteration.java
Executable file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* @(#)$RCSfile: HebrewTransliteration.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
/*
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998, All Rights Reserved
|
||||
*/
|
||||
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
/**
|
||||
* This class implements KeyRemap to produce transliterated Hebrew
|
||||
* characters from Latin-1 characters.
|
||||
*/
|
||||
|
||||
final class HebrewTransliteration extends KeyRemap {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
public char remap(char c) {
|
||||
|
||||
switch (c) {
|
||||
case 'a': return '\u05D0'; // HEBREW LETTER ALEF
|
||||
case 'A': return '\u05E2'; // HEBREW LETTER AYIN
|
||||
case 'b': return '\u05D1'; // HEBREW LETTER BET
|
||||
case 'B': return '\u05D1'; // HEBREW LETTER BET
|
||||
case 'c': return '\u05E6'; // HEBREW LETTER TSADI
|
||||
case 'C': return '\u05E5'; // HEBREW LETTER FINAL TSADI
|
||||
case 'd': return '\u05D3'; // HEBREW LETTER DALET
|
||||
case 'D': return '\u05BC'; // HEBREW POINT DAGESH
|
||||
case 'e': return '\u05B5'; // HEBREW POINT TSERE
|
||||
case 'E': return '\u05B6'; // HEBREW POINT SEGOL
|
||||
case 'f': return '\u05E4'; // HEBREW LETTER PE
|
||||
case 'F': return '\u05E4'; // HEBREW LETTER PE
|
||||
case 'g': return '\u05D2'; // HEBREW LETTER GIMEL
|
||||
case 'G': return '\u05D2'; // HEBREW LETTER GIMEL
|
||||
case 'h': return '\u05D4'; // HEBREW LETTER HE
|
||||
case 'H': return '\u05D7'; // HEBREW LETTER HET
|
||||
case 'i': return '\u05D9'; // HEBREW LETTER YOD
|
||||
case 'I': return '\u05B4'; // HEBREW POINT HIRIQ
|
||||
case 'j': return '\u05D9'; // HEBREW LETTER YOD
|
||||
case 'J': return '\u05C1'; // HEBREW POINT SHIN DOT
|
||||
case 'k': return '\u05DB'; // HEBREW LETTER KAF
|
||||
case 'K': return '\u05DA'; // HEBREW LETTER FINAL KAF
|
||||
case 'l': return '\u05DC'; // HEBREW LETTER LAMED
|
||||
case 'L': return '\u05DC'; // HEBREW LETTER LAMED
|
||||
case 'm': return '\u05DE'; // HEBREW LETTER MEM
|
||||
case 'M': return '\u05DD'; // HEBREW LETTER FINAL MEM
|
||||
case 'n': return '\u05E0'; // HEBREW LETTER NUN
|
||||
case 'N': return '\u05DF'; // HEBREW LETTER FINAL NUN
|
||||
case 'o': return '\u05D5'; // HEBREW LETTER VAV
|
||||
case 'O': return '\u05B9'; // HEBREW POINT HOLAM
|
||||
case 'p': return '\u05E4'; // HEBREW LETTER PE
|
||||
case 'P': return '\u05E3'; // HEBREW LETTER FINAL PE
|
||||
case 'q': return '\u05E7'; // HEBREW LETTER QOF
|
||||
case 'Q': return '\u05E7'; // HEBREW LETTER QOF
|
||||
case 'r': return '\u05E8'; // HEBREW LETTER RESH
|
||||
case 'R': return '\u05BF'; // HEBREW POINT RAFE
|
||||
case 's': return '\u05E9'; // HEBREW LETTER SHIN
|
||||
case 'S': return '\u05E1'; // HEBREW LETTER SAMEKH
|
||||
case 't': return '\u05EA'; // HEBREW LETTER TAV
|
||||
case 'T': return '\u05D8'; // HEBREW LETTER TET
|
||||
case 'u': return '\u05D5'; // HEBREW LETTER VAV
|
||||
case 'U': return '\u05BB'; // HEBREW POINT QUBUTS
|
||||
case 'v': return '\u05D5'; // HEBREW LETTER VAV
|
||||
case 'V': return '\u05B7'; // HEBREW POINT PATAH
|
||||
case 'w': return '\u05D5'; // HEBREW LETTER VAV
|
||||
case 'W': return '\u05B8'; // HEBREW POINT QAMATS
|
||||
case 'x': return '\u05E6'; // HEBREW LETTER TSADI
|
||||
case 'X': return '\u05E5'; // HEBREW LETTER FINAL TSADI
|
||||
case 'y': return '\u05D9'; // HEBREW LETTER YOD
|
||||
case 'Y': return '\u05D9'; // HEBREW LETTER YOD
|
||||
case 'z': return '\u05D6'; // HEBREW LETTER ZAYIN
|
||||
case 'Z': return '\u05C2'; // HEBREW POINT SIN DOT
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
}
|
84
icu4j/src/com/ibm/richtext/textpanel/IsraelNikudKeyboard.java
Executable file
84
icu4j/src/com/ibm/richtext/textpanel/IsraelNikudKeyboard.java
Executable file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* @(#)$RCSfile: IsraelNikudKeyboard.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
/*
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998, All Rights Reserved
|
||||
*/
|
||||
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
/**
|
||||
* This class simulates a Nikud keyboard on a US-English
|
||||
* keyboard. It is very much a work in progress.
|
||||
*/
|
||||
|
||||
final class IsraelNikudKeyboard extends KeyRemap {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
public char remap(char c) {
|
||||
|
||||
switch(c) {
|
||||
case 't': return '\u05D0'; // alef
|
||||
case 'c': return '\u05D1'; // bet
|
||||
case 'd': return '\u05D2'; // gimel
|
||||
case 's': return '\u05D3'; // dalet
|
||||
case 'v': return '\u05D4'; // he
|
||||
case 'u': return '\u05D5'; // vav
|
||||
case 'z': return '\u05D6'; // zayin
|
||||
case 'j': return '\u05D7'; // het
|
||||
case 'y': return '\u05D8'; // tet
|
||||
case 'h': return '\u05D9'; // yod
|
||||
case 'l': return '\u05DA'; // final kaf
|
||||
case 'f': return '\u05DB'; // kaf
|
||||
case 'k': return '\u05DC'; // lamed
|
||||
case 'o': return '\u05DD'; // final mem
|
||||
case 'n': return '\u05DE'; // mem
|
||||
case 'i': return '\u05DF'; // final nun
|
||||
case 'b': return '\u05E0'; // nun
|
||||
case 'x': return '\u05E1'; // samech
|
||||
case 'g': return '\u05E2'; // ayin
|
||||
case ';': return '\u05E3'; // final pe
|
||||
case 'p': return '\u05E4'; // pe
|
||||
case '.': return '\u05E5'; // final tsadi
|
||||
case 'm': return '\u05E6'; // tsadi
|
||||
case 'e': return '\u05E7'; // qof
|
||||
case 'r': return '\u05E8'; // resh
|
||||
case 'a': return '\u05E9'; // shin
|
||||
case ',': return '\u05EA'; // tav
|
||||
case 'w': return ',';
|
||||
case 'q': return '/';
|
||||
case '/': return '.';
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
public char remap(KeyEvent keyEvent) {
|
||||
|
||||
// Note: only one ctrl case now (ctrl-/ -> dagesh).
|
||||
// Better implementation will be needed for more cases.
|
||||
|
||||
if (keyEvent.isControlDown()) {
|
||||
if (keyEvent.getKeyCode() == KeyEvent.VK_SLASH) {
|
||||
return '\u05BC'; // dagesh
|
||||
}
|
||||
}
|
||||
|
||||
return remap(keyEvent.getKeyChar());
|
||||
}
|
||||
}
|
571
icu4j/src/com/ibm/richtext/textpanel/JTextPanel.java
Executable file
571
icu4j/src/com/ibm/richtext/textpanel/JTextPanel.java
Executable file
|
@ -0,0 +1,571 @@
|
|||
/*
|
||||
* @(#)$RCSfile: JTextPanel.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Graphics;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JScrollBar;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import java.awt.datatransfer.Clipboard;
|
||||
|
||||
import com.ibm.textlayout.attributes.AttributeMap;
|
||||
|
||||
import com.ibm.richtext.styledtext.StyleModifier;
|
||||
import com.ibm.richtext.styledtext.MConstText;
|
||||
import com.ibm.richtext.styledtext.StyledText;
|
||||
|
||||
/**
|
||||
* JTextPanel is an implementation of MTextPanel in a Swing JPanel.
|
||||
* @see MTextPanel
|
||||
*/
|
||||
public final class JTextPanel extends JPanel implements MTextPanel {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
private ATextPanelImpl fImpl;
|
||||
|
||||
/**
|
||||
* Return a TextPanelSettings instance with all settings set
|
||||
* to the default values. Clients can modify this object;
|
||||
* modifications will not affect the default values.
|
||||
* @return a TextPanelSettings instance set to default values
|
||||
* @see TextPanelSettings
|
||||
*/
|
||||
public static TextPanelSettings getDefaultSettings() {
|
||||
|
||||
return ATextPanelImpl.getDefaultSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new JTextPanel with the default settings.
|
||||
* @param initialText the text document. If null document text is empty.
|
||||
* @param clipboard the clipboard to use for cut, copy, and paste
|
||||
* operations. If null this panel will use a private clipboard.
|
||||
*/
|
||||
public JTextPanel(MConstText initialText,
|
||||
java.awt.datatransfer.Clipboard clipboard) {
|
||||
|
||||
this(ATextPanelImpl.fgDefaultSettings, initialText, clipboard);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new JTextPanel.
|
||||
* @param settings the settings for this JTextPanel
|
||||
* @param initialText the text document. If null document text is empty.
|
||||
* @param clipboard the clipboard to use for cut, copy, and paste
|
||||
* operations. If null this panel will use a private clipboard.
|
||||
* @see TextPanelSettings
|
||||
*/
|
||||
public JTextPanel(TextPanelSettings settings,
|
||||
MConstText initialText,
|
||||
Clipboard clipboard) {
|
||||
|
||||
super(false);
|
||||
|
||||
JScrollBar horzSb = null;
|
||||
JScrollBar vertSb = null;
|
||||
|
||||
if (settings.getScrollable()) {
|
||||
|
||||
setLayout(new ScrollBarLayout());
|
||||
|
||||
boolean scrollBarsVisible = settings.getScrollBarsVisible();
|
||||
|
||||
if (scrollBarsVisible) {
|
||||
horzSb = new JScrollBar(JScrollBar.HORIZONTAL);
|
||||
vertSb = new JScrollBar(JScrollBar.VERTICAL);
|
||||
add("South", horzSb);
|
||||
add("East", vertSb);
|
||||
}
|
||||
}
|
||||
else {
|
||||
setLayout(new BorderLayout());
|
||||
}
|
||||
|
||||
RunStrategy runStrategy = new RunStrategy() {
|
||||
void doIt(Runnable r) {
|
||||
try {
|
||||
SwingUtilities.invokeAndWait(r);
|
||||
}
|
||||
catch(InterruptedException e) {
|
||||
// If operation was interrupted, then client
|
||||
// called wait or sleep (or something similar)
|
||||
// which is inappropriate for a client of this
|
||||
// class. Rethrow error and let client handle it.
|
||||
e.printStackTrace();
|
||||
throw new Error("Interrupted in RunStrategy: " + e);
|
||||
}
|
||||
catch(InvocationTargetException e) {
|
||||
// Who knows how this one happens...
|
||||
e.printStackTrace();
|
||||
throw new Error("InvocationTargetException in RunStrategy: " + e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fImpl = new ATextPanelImpl(runStrategy,
|
||||
settings,
|
||||
initialText,
|
||||
clipboard,
|
||||
this,
|
||||
horzSb,
|
||||
vertSb);
|
||||
|
||||
final FakeComponent textComponent = fImpl.getTextComponent();
|
||||
|
||||
JComponent textHost = new JComponent() {
|
||||
{
|
||||
textComponent.setHost(this);
|
||||
}
|
||||
public void addNotify() {
|
||||
super.addNotify();
|
||||
textComponent.addNotify();
|
||||
}
|
||||
public void paint(Graphics g) {
|
||||
textComponent.paint(g);
|
||||
}
|
||||
};
|
||||
|
||||
add("Center", textHost);
|
||||
|
||||
textHost.requestFocus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given TextPanelListener to the listeners which will
|
||||
* receive update notifications from this JTextPanel.
|
||||
* @param listener the listener to add
|
||||
*/
|
||||
public void addListener(TextPanelListener listener) {
|
||||
|
||||
fImpl.addListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given TextPanelListener from the listeners which will
|
||||
* receive update notifications from this JTextPanel.
|
||||
* @param listener the listener to remove
|
||||
*/
|
||||
public void removeListener(TextPanelListener listener) {
|
||||
|
||||
fImpl.removeListener(listener);
|
||||
}
|
||||
|
||||
//============
|
||||
// Text Access
|
||||
//============
|
||||
|
||||
/**
|
||||
* Set the document to <tt>newText</tt>. This operation
|
||||
* modifies the text in the JTextPanel. It does not modify or adopt
|
||||
* <tt>newText</tt>. This method sets the selection an insertion point at
|
||||
* the end of the text.
|
||||
* @param newText the text which will replace the current text.
|
||||
*/
|
||||
public void setText(MConstText newText) {
|
||||
|
||||
fImpl.setText(newText);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the given text to the end of the document. Equivalent to
|
||||
* <tt>insert(newText, getTextLength())</tt>.
|
||||
* @param newText the text to append to the document
|
||||
*/
|
||||
public void append(MConstText newText) {
|
||||
|
||||
fImpl.append(newText);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the given text into the document at the given position.
|
||||
* Equivalent to
|
||||
* <tt>replaceRange(newText, position, position)</tt>.
|
||||
* @param newText the text to insert into the document.
|
||||
* @param position the position in the document where the
|
||||
* text will be inserted
|
||||
*/
|
||||
public void insert(MConstText newText, int position) {
|
||||
|
||||
fImpl.insert(newText, position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the given range with <tt>newText</tt>. After this
|
||||
* operation the selection range is an insertion point at the
|
||||
* end of the new text.
|
||||
* @param newText the text with which to replace the range
|
||||
* @param start the beginning of the range to replace
|
||||
* @param end the end of the range to replace
|
||||
*/
|
||||
public void replaceRange(MConstText newText, int start, int end) {
|
||||
|
||||
fImpl.replaceRange(newText, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the length of the text document in the JTextPanel.
|
||||
* @return the length of the text document in the JTextPanel
|
||||
*/
|
||||
public int getTextLength() {
|
||||
|
||||
return fImpl.getTextLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the text document in the JTextPanel.
|
||||
* @return the text document in the JTextPanel.
|
||||
*/
|
||||
public MConstText getText() {
|
||||
|
||||
return fImpl.getText();
|
||||
}
|
||||
|
||||
//============
|
||||
// Selection Access
|
||||
//============
|
||||
|
||||
/**
|
||||
* Return the offset of the start of the selection.
|
||||
*/
|
||||
public int getSelectionStart() {
|
||||
|
||||
return fImpl.getSelectionStart();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the offset of the end of the selection.
|
||||
*/
|
||||
public int getSelectionEnd() {
|
||||
|
||||
return fImpl.getSelectionEnd();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the beginning of the selection range. This is
|
||||
* equivalent to <tt>select(selectionStart, getSelectionEnd())</tt>.
|
||||
* @param selectionStart the start of the new selection range
|
||||
*/
|
||||
public void setSelectionStart(int selectionStart) {
|
||||
|
||||
fImpl.setSelectionStart(selectionStart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the end of the selection range. This is
|
||||
* equivalent to <tt>select(getSelectionStart(), selectionEnd)</tt>.
|
||||
* @param selectionStart the start of the new selection range
|
||||
*/
|
||||
public void setSelectionEnd(int selectionEnd) {
|
||||
|
||||
fImpl.setSelectionEnd(selectionEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selection range to an insertion point at the given
|
||||
* offset. This is equivalent to
|
||||
* <tt>select(position, position)</tt>.
|
||||
* @param position the offset of the new insertion point
|
||||
*/
|
||||
public void setCaretPosition(int position) {
|
||||
|
||||
fImpl.setCaretPosition(position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selection range to the given range. The range start
|
||||
* is pinned between 0 and the text length; the range end is pinned
|
||||
* between the range start and the end of the text. These semantics
|
||||
* are identical to those of <tt>java.awt.TextComponent</tt>.
|
||||
* This method has no effect if the text is not selectable.
|
||||
* @param selectionStart the beginning of the selection range
|
||||
* @param selectionEnd the end of the selection range
|
||||
*/
|
||||
public void select(int selectionStart, int selectionEnd) {
|
||||
|
||||
fImpl.select(selectionStart, selectionEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select all of the text in the document. This method has no effect if
|
||||
* the text is not selectable.
|
||||
*/
|
||||
public void selectAll() {
|
||||
|
||||
fImpl.selectAll();
|
||||
}
|
||||
|
||||
|
||||
//============
|
||||
// Format Width
|
||||
//============
|
||||
|
||||
/**
|
||||
* Return the total format width, in pixels. The format width is the
|
||||
* width to which text is wrapped.
|
||||
* @return the format width
|
||||
*/
|
||||
public int getFormatWidth() {
|
||||
|
||||
return fImpl.getFormatWidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the paragraph at the given offset is left-to-right.
|
||||
* @param offset an offset in the text
|
||||
* @return true if the paragraph at the given offset is left-to-right
|
||||
*/
|
||||
public boolean paragraphIsLeftToRight(int offset) {
|
||||
|
||||
return fImpl.paragraphIsLeftToRight(offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is a change which can be undone.
|
||||
* @return true if there is a change which can be undone.
|
||||
*/
|
||||
public boolean canUndo() {
|
||||
|
||||
return fImpl.canUndo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is a change which can be redone.
|
||||
* @return true if there is a change which can be redone.
|
||||
*/
|
||||
public boolean canRedo() {
|
||||
|
||||
return fImpl.canRedo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the clipboard contains contents which could be
|
||||
* transfered into the text.
|
||||
* @return true if the clipboard has text content.
|
||||
*/
|
||||
public boolean clipboardNotEmpty() {
|
||||
|
||||
return fImpl.clipboardNotEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an AttributeMap of keys with default values. The default
|
||||
* values are used when displaying text for values which are not
|
||||
* specified in the text.
|
||||
* @return an AttributeMap of default key-value pairs
|
||||
*/
|
||||
public AttributeMap getDefaultValues() {
|
||||
|
||||
return fImpl.getDefaultValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method inspects the character style runs in the selection
|
||||
* range (or the typing style at the insertion point). It returns:
|
||||
* <ul>
|
||||
* <li>The value of <tt>key</tt>, if the value of <tt>key</tt>
|
||||
* is the same in all of the style runs in the selection, or</li>
|
||||
* <li><tt>MULTIPLE_VALUES</tt>, if two or more style runs have different
|
||||
* values for <tt>key</tt>.</li>
|
||||
* </ul>
|
||||
* If a style run does not contain <tt>key</tt>,
|
||||
* its value is considered to be the default style for <tt>key</tt>,
|
||||
* as defined by the default values AttributeMap. Note that if
|
||||
* <tt>key</tt> does not have a default value this method may return
|
||||
* null.
|
||||
* This method is useful for configuring style menus.
|
||||
* @param key the key used to retrieve values for comparison
|
||||
* @see MTextPanel#MULTIPLE_VALUES
|
||||
*/
|
||||
public Object getCharacterStyleOverSelection(Object key) {
|
||||
|
||||
return fImpl.getCharacterStyleOverSelection(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method inspects the paragraph style runs in the selection
|
||||
* range (or the typing style at the insertion point). It returns:
|
||||
* <ul>
|
||||
* <li>The value of <tt>key</tt>, if the value of <tt>key</tt>
|
||||
* is the same in all of the style runs in the selection, or</li>
|
||||
* <li><tt>MULTIPLE_VALUES</tt>, if two or more style runs have
|
||||
* different values for <tt>key</tt>.</li>
|
||||
* </ul>
|
||||
* If a style run does not contain <tt>key</tt>,
|
||||
* its value is considered to be the default style for <tt>key</tt>,
|
||||
* as defined by the default values AttributeMap. Note that if
|
||||
* <tt>key</tt> does not have a default value this method may return
|
||||
* null.
|
||||
* This method is useful for configuring style menus.
|
||||
* @param key the key used to retrieve values for comparison
|
||||
* @see MTextPanel#MULTIPLE_VALUES
|
||||
*/
|
||||
public Object getParagraphStyleOverSelection(Object key) {
|
||||
|
||||
return fImpl.getParagraphStyleOverSelection(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the selected text from the document and place it
|
||||
* on the clipboard. This method has no effect if the text
|
||||
* is not editable, or if no text is selected.
|
||||
*/
|
||||
public void cut() {
|
||||
fImpl.cut();
|
||||
}
|
||||
|
||||
/**
|
||||
* Place the selected text on the clipboard. This method has
|
||||
* no effect if no text is selected.
|
||||
*/
|
||||
public void copy() {
|
||||
fImpl.copy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the currently selected text with the text on the clipboard.
|
||||
* This method has no effect if the text is not editable, or if no
|
||||
* text is on the clipboard.
|
||||
*/
|
||||
public void paste() {
|
||||
fImpl.paste();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove selected text from the document, without altering the clipboard.
|
||||
* This method has no effect if the
|
||||
* text is not editable.
|
||||
*/
|
||||
public void clear() {
|
||||
fImpl.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Undo the most recent text change. This method has no effect if
|
||||
* there is no change to undo.
|
||||
*/
|
||||
public void undo() {
|
||||
fImpl.undo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Redo the most recent text change. This method has no effect if
|
||||
* there is no change to redo.
|
||||
*/
|
||||
public void redo() {
|
||||
fImpl.redo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of commands the command log can hold.
|
||||
* @return the number of commands the command log can hold
|
||||
*/
|
||||
public int getCommandLogSize() {
|
||||
|
||||
return fImpl.getCommandLogSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of commands the command log can hold. All
|
||||
* redoable commands are removed when this method is called.
|
||||
* @param size the number of commands kept in the command log
|
||||
*/
|
||||
public void setCommandLogSize(int size) {
|
||||
fImpl.setCommandLogSize(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all commands from the command log.
|
||||
*/
|
||||
public void clearCommandLog() {
|
||||
fImpl.clearCommandLog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the character styles on the selected characters. If no characters
|
||||
* are selected, modify the typing style.
|
||||
* @param modifier the StyleModifier with which to modify the styles
|
||||
*/
|
||||
public void modifyCharacterStyleOnSelection(StyleModifier modifier) {
|
||||
fImpl.modifyCharacterStyleOnSelection(modifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the paragraph styles in paragraphs containing selected characters, or
|
||||
* the paragraph containing the insertion point.
|
||||
* @param modifier the StyleModifier with which to modify the styles
|
||||
*/
|
||||
public void modifyParagraphStyleOnSelection(StyleModifier modifier) {
|
||||
fImpl.modifyParagraphStyleOnSelection(modifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the KeyRemap used to process key events.
|
||||
* @return the key remap used to process key events
|
||||
* @see #setKeyRemap
|
||||
*/
|
||||
public KeyRemap getKeyRemap() {
|
||||
|
||||
return fImpl.getKeyRemap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the given KeyRemap to map key events to characters.
|
||||
* Only key
|
||||
* events are affected by the remap; other text entering the
|
||||
* control (via the clipboard, for example) is not affected
|
||||
* by the KeyRemap.
|
||||
* <p>
|
||||
* Do not pass <tt>null</tt> to this method to leave key
|
||||
* events unmapped. Instead, use <tt>KeyRemap.getIdentityRemap()</tt>
|
||||
* @param remap the KeyRemap to use for mapping key events to characters
|
||||
* @exception java.lang.NullPointerException if parameter is null
|
||||
* @see KeyRemap
|
||||
*/
|
||||
public void setKeyRemap(KeyRemap remap) {
|
||||
|
||||
fImpl.setKeyRemap(remap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the modification flag of the current text change.
|
||||
* @see #setModified
|
||||
*/
|
||||
public boolean isModified() {
|
||||
|
||||
return fImpl.isModified();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the modification flag of the current text change.
|
||||
*/
|
||||
public void setModified(boolean modified) {
|
||||
|
||||
fImpl.setModified(modified);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is for perf-testing only!
|
||||
*/
|
||||
void handleKeyEvent(java.awt.event.KeyEvent keyEvent) {
|
||||
|
||||
fImpl.handleKeyEvent(keyEvent);
|
||||
}
|
||||
}
|
39
icu4j/src/com/ibm/richtext/textpanel/KeyEventForwarder.java
Executable file
39
icu4j/src/com/ibm/richtext/textpanel/KeyEventForwarder.java
Executable file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* @(#)$RCSfile: KeyEventForwarder.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
/**
|
||||
* This class forwards key events to a TextPanel component for
|
||||
* testing purposes.
|
||||
* It's sole reason for existence is to prevent the key-event
|
||||
* API from being public on TextPanel, and being mistaken for
|
||||
* standard API. This class is only for testing!
|
||||
*/
|
||||
public final class KeyEventForwarder {
|
||||
|
||||
private TextPanel fRichText;
|
||||
|
||||
public KeyEventForwarder(TextPanel richText) {
|
||||
|
||||
fRichText = richText;
|
||||
}
|
||||
|
||||
public void handleKeyEvent(KeyEvent keyEvent) {
|
||||
|
||||
fRichText.handleKeyEvent(keyEvent);
|
||||
}
|
||||
}
|
118
icu4j/src/com/ibm/richtext/textpanel/KeyRemap.java
Executable file
118
icu4j/src/com/ibm/richtext/textpanel/KeyRemap.java
Executable file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* @(#)$RCSfile: KeyRemap.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
/*
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998, All Rights Reserved
|
||||
*/
|
||||
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
/**
|
||||
* KeyRemap maps keys on a standard US keyboard to characters
|
||||
* in other alphabets. Currently, mappings to Arabic, Hebrew
|
||||
* and Thai are supported. In the future, clients may be
|
||||
* to define their own mappings by subclassing this class.
|
||||
* <P>
|
||||
* @see TextPanel#setKeyRemap
|
||||
*/
|
||||
|
||||
public class KeyRemap {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
/**
|
||||
* Create a new KeyRemap.
|
||||
*/
|
||||
protected KeyRemap() {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the character on the simulated keyboard
|
||||
* which is (most likely) generated by typing the character c
|
||||
* on the actual keyboard. For greater accuracy, use the remap
|
||||
* method which takes a KeyEvent, since it can take modifier
|
||||
* keys into account.
|
||||
* @arg c a character on the actual keyboard
|
||||
* @return the character on the simulated keyboard which would
|
||||
* result from the key combination which produced the
|
||||
* given character on the actual keyboard
|
||||
*/
|
||||
/*public*/ char remap(char c) {
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the character on the simulated keyboard
|
||||
* which keyEvent generates.
|
||||
* @arg keyEvent a key event from the actual keyboard
|
||||
* @return the character on the simulated keyboard generated by
|
||||
* keyEvent
|
||||
*/
|
||||
/*public*/ char remap(KeyEvent keyEvent) {
|
||||
|
||||
return remap(keyEvent.getKeyChar());
|
||||
}
|
||||
|
||||
private static final KeyRemap IDENTITY = new KeyRemap();
|
||||
private static final KeyRemap ARABIC_TRANSLITERATION = new ArabicTransliteration();
|
||||
private static final KeyRemap HEBREW_TRANSLITERATION = new HebrewTransliteration();
|
||||
private static final KeyRemap ISRAEL_NIKUD = new IsraelNikudKeyboard();
|
||||
private static final KeyRemap THAI = new ThaiKeyRemap();
|
||||
|
||||
/**
|
||||
* Return a KeyRemap which maps every character to itself.
|
||||
*/
|
||||
public static KeyRemap getIdentityRemap() {
|
||||
|
||||
return IDENTITY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a KeyRemap which maps keys to
|
||||
* characters in the Arabic alphabet, using a simple transliteration.
|
||||
*/
|
||||
public static KeyRemap getArabicTransliteration() {
|
||||
|
||||
return ARABIC_TRANSLITERATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a KeyRemap which maps keys to
|
||||
* characters in the Hebrew alphabet, using a simple transliteration.
|
||||
*/
|
||||
public static KeyRemap getHebrewTransliteration() {
|
||||
|
||||
return HEBREW_TRANSLITERATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a KeyRemap which emulates a standard Hebrew keyboard.
|
||||
*/
|
||||
public static KeyRemap getIsraelNikud() {
|
||||
|
||||
return ISRAEL_NIKUD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a KeyRemap which emulates a Thai Ketmanee keyboard.
|
||||
*/
|
||||
public static KeyRemap getThaiKetmanee() {
|
||||
|
||||
return THAI;
|
||||
}
|
||||
}
|
375
icu4j/src/com/ibm/richtext/textpanel/MTextPanel.java
Executable file
375
icu4j/src/com/ibm/richtext/textpanel/MTextPanel.java
Executable file
|
@ -0,0 +1,375 @@
|
|||
/*
|
||||
* @(#)$RCSfile: MTextPanel.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
import com.ibm.textlayout.attributes.AttributeMap;
|
||||
|
||||
import com.ibm.richtext.styledtext.StyleModifier;
|
||||
import com.ibm.richtext.styledtext.MConstText;
|
||||
|
||||
/**
|
||||
* MTextPanel is implemented by Components which provide selectable
|
||||
* editable styled text.
|
||||
* <p>
|
||||
* Implementations of MTextPanel provide a simple, standard user interface
|
||||
* for text editing. MTextPanel supplies scrollable display, typing,
|
||||
* arrow-key support, character selection, word-
|
||||
* and sentence-selection (by double-clicking and triple-clicking,
|
||||
* respectively), text styles, clipboard operations (cut, copy and paste)
|
||||
* and a log of changes for undo-redo.
|
||||
* <p>
|
||||
* MTextPanel implementations do not provide user interface elements
|
||||
* such as an edit menu or style menu. This support is provided in
|
||||
* different packages, and is implemented with MTextPanel's API.
|
||||
* MTextPanel includes methods for setting selections and styles on text,
|
||||
* and using the clipboard and command-log functionality.
|
||||
* MTextPanel's API for selection and text handling is similar to that
|
||||
* of <tt>java.awt.TextArea</tt> and
|
||||
* <tt>java.awt.TextComponent</tt>.
|
||||
* <p>
|
||||
* MTextPanel supports bidirectional and complex text. In bidirectional
|
||||
* text, offsets at direction boundaries have dual carets. Logical selection
|
||||
* is used, so selections across run directions may not be contiguous in
|
||||
* display.
|
||||
*/
|
||||
public interface MTextPanel {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
|
||||
/**
|
||||
* This value is returned from <tt>getCharacterStyleOverSelection</tt>
|
||||
* and <tt>getParagraphStyleOverSelection</tt> to indicate that the
|
||||
* selection range contains multiple values for a key.
|
||||
* <p>
|
||||
* There is no reason for this Object ever to appear in an AttributeMap
|
||||
* as a value. Obviously, if it does there will be no way to distinguish
|
||||
* between multiple values across the selection and a consistent value of
|
||||
* <tt>MULTIPLE_VALUES</tt> for the key.
|
||||
* @see #getCharacterStyleOverSelection
|
||||
* @see #getParagraphStyleOverSelection
|
||||
*/
|
||||
public static final Object MULTIPLE_VALUES = new Object();
|
||||
|
||||
/**
|
||||
* Add the given TextPanelListener to the listeners which will
|
||||
* receive update notifications from this MTextPanel.
|
||||
* @param listener the listener to add
|
||||
*/
|
||||
public void addListener(TextPanelListener listener);
|
||||
|
||||
/**
|
||||
* Remove the given TextPanelListener from the listeners which will
|
||||
* receive update notifications from this MTextPanel.
|
||||
* @param listener the listener to remove
|
||||
*/
|
||||
public void removeListener(TextPanelListener listener);
|
||||
|
||||
/**
|
||||
* Set the document to <tt>newText</tt>. This operation
|
||||
* modifies the text in the MTextPanel. It does not modify or adopt
|
||||
* <tt>newText</tt>. This method sets the selection an insertion point at
|
||||
* the end of the text.
|
||||
* @param newText the text which will replace the current text.
|
||||
*/
|
||||
public void setText(MConstText newText);
|
||||
|
||||
/**
|
||||
* Append the given text to the end of the document. Equivalent to
|
||||
* <tt>insert(newText, getTextLength())</tt>.
|
||||
* @param newText the text to append to the document
|
||||
*/
|
||||
public void append(MConstText newText);
|
||||
|
||||
/**
|
||||
* Insert the given text into the document at the given position.
|
||||
* Equivalent to
|
||||
* <tt>replaceRange(newText, position, position)</tt>.
|
||||
* @param newText the text to insert into the document.
|
||||
* @param position the position in the document where the
|
||||
* text will be inserted
|
||||
*/
|
||||
public void insert(MConstText newText, int position);
|
||||
|
||||
/**
|
||||
* Replace the given range with <tt>newText</tt>. After this
|
||||
* operation the selection range is an insertion point at the
|
||||
* end of the new text.
|
||||
* @param newText the text with which to replace the range
|
||||
* @param start the beginning of the range to replace
|
||||
* @param end the end of the range to replace
|
||||
*/
|
||||
public void replaceRange(MConstText newText, int start, int end);
|
||||
|
||||
/**
|
||||
* Return the length of the text document in the MTextPanel.
|
||||
* @return the length of the text document in the MTextPanel
|
||||
*/
|
||||
public int getTextLength();
|
||||
|
||||
/**
|
||||
* Return the text document in the MTextPanel.
|
||||
* @return the text document in the MTextPanel.
|
||||
*/
|
||||
public MConstText getText();
|
||||
|
||||
//============
|
||||
// Selection Access
|
||||
//============
|
||||
|
||||
/**
|
||||
* Return the offset of the start of the selection.
|
||||
*/
|
||||
public int getSelectionStart();
|
||||
|
||||
/**
|
||||
* Return the offset of the end of the selection.
|
||||
*/
|
||||
public int getSelectionEnd();
|
||||
|
||||
/**
|
||||
* Set the beginning of the selection range. This is
|
||||
* equivalent to <tt>select(selectionStart, getSelectionEnd())</tt>.
|
||||
* @param selectionStart the start of the new selection range
|
||||
*/
|
||||
public void setSelectionStart(int selectionStart);
|
||||
|
||||
/**
|
||||
* Set the end of the selection range. This is
|
||||
* equivalent to <tt>select(getSelectionStart(), selectionEnd)</tt>.
|
||||
* @param selectionStart the start of the new selection range
|
||||
*/
|
||||
public void setSelectionEnd(int selectionEnd);
|
||||
|
||||
/**
|
||||
* Set the selection range to an insertion point at the given
|
||||
* offset. This is equivalent to
|
||||
* <tt>select(position, position)</tt>.
|
||||
* @param position the offset of the new insertion point
|
||||
*/
|
||||
public void setCaretPosition(int position);
|
||||
|
||||
/**
|
||||
* Set the selection range to the given range. The range start
|
||||
* is pinned between 0 and the text length; the range end is pinned
|
||||
* between the range start and the end of the text. These semantics
|
||||
* are identical to those of <tt>java.awt.TextComponent</tt>.
|
||||
* This method has no effect if the text is not selectable.
|
||||
* @param selectionStart the beginning of the selection range
|
||||
* @param selectionEnd the end of the selection range
|
||||
*/
|
||||
public void select(int selectionStart, int selectionEnd);
|
||||
|
||||
/**
|
||||
* Select all of the text in the document. This method has no effect if
|
||||
* the text is not selectable.
|
||||
*/
|
||||
public void selectAll();
|
||||
|
||||
|
||||
//============
|
||||
// Format Width
|
||||
//============
|
||||
|
||||
/**
|
||||
* Return the total format width, in pixels. The format width is the
|
||||
* width to which text is wrapped.
|
||||
* @return the format width
|
||||
*/
|
||||
public int getFormatWidth();
|
||||
|
||||
/**
|
||||
* Return true if the paragraph at the given offset is left-to-right.
|
||||
* @param offset an offset in the text
|
||||
* @return true if the paragraph at the given offset is left-to-right
|
||||
*/
|
||||
public boolean paragraphIsLeftToRight(int offset);
|
||||
|
||||
/**
|
||||
* Return true if there is a change which can be undone.
|
||||
* @return true if there is a change which can be undone.
|
||||
*/
|
||||
public boolean canUndo();
|
||||
|
||||
/**
|
||||
* Return true if there is a change which can be redone.
|
||||
* @return true if there is a change which can be redone.
|
||||
*/
|
||||
public boolean canRedo();
|
||||
|
||||
/**
|
||||
* Return true if the clipboard contains contents which could be
|
||||
* transfered into the text.
|
||||
* @return true if the clipboard has text content.
|
||||
*/
|
||||
public boolean clipboardNotEmpty();
|
||||
|
||||
|
||||
//============
|
||||
// Styles
|
||||
//============
|
||||
|
||||
/**
|
||||
* Return an AttributeMap of keys with default values. The default
|
||||
* values are used when displaying text for values which are not
|
||||
* specified in the text.
|
||||
* @return an AttributeMap of default key-value pairs
|
||||
*/
|
||||
public AttributeMap getDefaultValues();
|
||||
|
||||
/**
|
||||
* This method inspects the character style runs in the selection
|
||||
* range (or the typing style at the insertion point). It returns:
|
||||
* <ul>
|
||||
* <li>The value of <tt>key</tt>, if the value of <tt>key</tt>
|
||||
* is the same in all of the style runs in the selection, or</li>
|
||||
* <li><tt>MULTIPLE_VALUES</tt>, if two or more style runs have different
|
||||
* values for <tt>key</tt>.</li>
|
||||
* </ul>
|
||||
* If a style run does not contain <tt>key</tt>,
|
||||
* its value is considered to be the default style for <tt>key</tt>,
|
||||
* as defined by the default values AttributeMap. Note that if
|
||||
* <tt>key</tt> does not have a default value this method may return
|
||||
* null.
|
||||
* This method is useful for configuring style menus.
|
||||
* @param key the key used to retrieve values for comparison
|
||||
* @see #MULTIPLE_VALUES
|
||||
*/
|
||||
public Object getCharacterStyleOverSelection(Object key);
|
||||
|
||||
/**
|
||||
* This method inspects the paragraph style runs in the selection
|
||||
* range (or the typing style at the insertion point). It returns:
|
||||
* <ul>
|
||||
* <li>The value of <tt>key</tt>, if the value of <tt>key</tt>
|
||||
* is the same in all of the style runs in the selection, or</li>
|
||||
* <li><tt>MULTIPLE_VALUES</tt>, if two or more style runs have
|
||||
* different values for <tt>key</tt>.</li>
|
||||
* </ul>
|
||||
* If a style run does not contain <tt>key</tt>,
|
||||
* its value is considered to be the default style for <tt>key</tt>,
|
||||
* as defined by the default values AttributeMap. Note that if
|
||||
* <tt>key</tt> does not have a default value this method may return
|
||||
* null.
|
||||
* This method is useful for configuring style menus.
|
||||
* @param key the key used to retrieve values for comparison
|
||||
* @see #MULTIPLE_VALUES
|
||||
*/
|
||||
public Object getParagraphStyleOverSelection(Object key);
|
||||
|
||||
/**
|
||||
* Remove the selected text from the document and place it
|
||||
* on the clipboard. This method has no effect if the text
|
||||
* is not editable, or if no text is selected.
|
||||
*/
|
||||
public void cut();
|
||||
|
||||
/**
|
||||
* Place the selected text on the clipboard. This method has
|
||||
* no effect if no text is selected.
|
||||
*/
|
||||
public void copy();
|
||||
|
||||
/**
|
||||
* Replace the currently selected text with the text on the clipboard.
|
||||
* This method has no effect if the text is not editable, or if no
|
||||
* text is on the clipboard.
|
||||
*/
|
||||
public void paste();
|
||||
|
||||
/**
|
||||
* Remove selected text from the document, without altering the clipboard.
|
||||
* This method has no effect if the
|
||||
* text is not editable.
|
||||
*/
|
||||
public void clear();
|
||||
|
||||
/**
|
||||
* Undo the most recent text change. This method has no effect if
|
||||
* there is no change to undo.
|
||||
*/
|
||||
public void undo();
|
||||
|
||||
/**
|
||||
* Redo the most recent text change. This method has no effect if
|
||||
* there is no change to redo.
|
||||
*/
|
||||
public void redo();
|
||||
|
||||
/**
|
||||
* Return the number of commands the command log can hold.
|
||||
* @return the number of commands the command log can hold
|
||||
*/
|
||||
public int getCommandLogSize();
|
||||
|
||||
/**
|
||||
* Set the number of commands the command log can hold. All
|
||||
* redoable commands are removed when this method is called.
|
||||
* @param size the number of commands kept in the command log
|
||||
*/
|
||||
public void setCommandLogSize(int size);
|
||||
|
||||
/**
|
||||
* Remove all commands from the command log.
|
||||
*/
|
||||
public void clearCommandLog();
|
||||
|
||||
/**
|
||||
* Modify the character styles on the selected characters. If no characters
|
||||
* are selected, modify the typing style.
|
||||
* @param modifier the StyleModifier with which to modify the styles
|
||||
*/
|
||||
public void modifyCharacterStyleOnSelection(StyleModifier modifier);
|
||||
|
||||
/**
|
||||
* Modify the paragraph styles in paragraphs containing selected characters, or
|
||||
* the paragraph containing the insertion point.
|
||||
* @param modifier the StyleModifier with which to modify the styles
|
||||
*/
|
||||
public void modifyParagraphStyleOnSelection(StyleModifier modifier);
|
||||
|
||||
/**
|
||||
* Return the KeyRemap used to process key events.
|
||||
* @return the key remap used to process key events
|
||||
* @see #setKeyRemap
|
||||
*/
|
||||
public KeyRemap getKeyRemap();
|
||||
|
||||
/**
|
||||
* Use the given KeyRemap to map key events to characters.
|
||||
* Only key
|
||||
* events are affected by the remap; other text entering the
|
||||
* control (via the clipboard, for example) is not affected
|
||||
* by the KeyRemap.
|
||||
* <p>
|
||||
* Do not pass <tt>null</tt> to this method to leave key
|
||||
* events unmapped. Instead, use <tt>KeyRemap.getIdentityRemap()</tt>
|
||||
* @param remap the KeyRemap to use for mapping key events to characters
|
||||
* @exception java.lang.NullPointerException if parameter is null
|
||||
* @see KeyRemap
|
||||
*/
|
||||
public void setKeyRemap(KeyRemap remap);
|
||||
|
||||
/**
|
||||
* Return the modification flag of the current text change.
|
||||
* @see #setModified
|
||||
*/
|
||||
public boolean isModified();
|
||||
|
||||
/**
|
||||
* Set the modification flag of the current text change.
|
||||
*/
|
||||
public void setModified(boolean modified);
|
||||
}
|
52
icu4j/src/com/ibm/richtext/textpanel/OffscreenBufferCache.java
Executable file
52
icu4j/src/com/ibm/richtext/textpanel/OffscreenBufferCache.java
Executable file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* @(#)$RCSfile: OffscreenBufferCache.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.awt.Component;
|
||||
|
||||
class OffscreenBufferCache {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
private Image fOffscreenBuffer = null;
|
||||
private Component fHost;
|
||||
|
||||
OffscreenBufferCache(Component host) {
|
||||
|
||||
fHost = host;
|
||||
}
|
||||
|
||||
private Image makeBuffer(int width, int height) {
|
||||
|
||||
return fHost.createImage(Math.max(width, 1), Math.max(height, 1));
|
||||
}
|
||||
|
||||
Image getBuffer(int width, int height) {
|
||||
|
||||
Image buffer = fOffscreenBuffer;
|
||||
|
||||
if (buffer != null) {
|
||||
if (buffer.getWidth(fHost) >= width &&
|
||||
buffer.getHeight(fHost) >= height) {
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
buffer = makeBuffer(width, height);
|
||||
fOffscreenBuffer = buffer;
|
||||
return buffer;
|
||||
}
|
||||
}
|
100
icu4j/src/com/ibm/richtext/textpanel/PanelEventBroadcaster.java
Executable file
100
icu4j/src/com/ibm/richtext/textpanel/PanelEventBroadcaster.java
Executable file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* @(#)$RCSfile: PanelEventBroadcaster.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* This class listens for text state change notifications
|
||||
* and broadcasts them to all of its listeners.
|
||||
*/
|
||||
final class PanelEventBroadcaster {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
private static final int FIRST = TextPanelEvent.TEXT_PANEL_FIRST;
|
||||
|
||||
private final Vector[] fListeners;
|
||||
private final TextPanelEvent[] fEvents;
|
||||
|
||||
/**
|
||||
* Construct a new PanelEventBroadcaster.
|
||||
* @param panel the TextPanel for which events are broadcasted
|
||||
*/
|
||||
public PanelEventBroadcaster(MTextPanel panel) {
|
||||
|
||||
int count = TextPanelEvent.TEXT_PANEL_LAST - FIRST + 1;
|
||||
|
||||
fEvents = new TextPanelEvent[count];
|
||||
fListeners = new Vector[count];
|
||||
|
||||
for (int i=0; i < fListeners.length; i++) {
|
||||
fEvents[i] = new TextPanelEvent(panel, i+FIRST);
|
||||
fListeners[i] = new Vector();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given TextPanelListener to the TextPanelListeners to
|
||||
* which notifications are forwarded.
|
||||
* @param listener the listener to add
|
||||
*/
|
||||
public synchronized void addListener(TextPanelListener listener) {
|
||||
|
||||
for (int i=FIRST; i <= TextPanelEvent.TEXT_PANEL_LAST; i++) {
|
||||
Vector listeners = fListeners[i-FIRST];
|
||||
if (listener.respondsToEventType(i)) {
|
||||
if (!listeners.contains(listener)) {
|
||||
listeners.addElement(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given TextPanelListener from the TextPanelListeners to
|
||||
* which notifications are forwarded.
|
||||
* @param listener the listener to remove
|
||||
*/
|
||||
public synchronized void removeListener(TextPanelListener listener) {
|
||||
|
||||
for (int i=FIRST; i <= TextPanelEvent.TEXT_PANEL_LAST; i++) {
|
||||
Vector listeners = fListeners[i-FIRST];
|
||||
if (listener.respondsToEventType(i)) {
|
||||
listeners.removeElement(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive a notification and forward it to all listeners.
|
||||
* @changeCode one of the constants in the TextPanelListener class
|
||||
*/
|
||||
public synchronized void textStateChanged(int id) {
|
||||
|
||||
int index = id-FIRST;
|
||||
TextPanelEvent event = fEvents[index];
|
||||
Vector listeners = fListeners[index];
|
||||
|
||||
int size = listeners.size();
|
||||
|
||||
for (int i=0; i < size; i++) {
|
||||
|
||||
TextPanelListener listener =
|
||||
(TextPanelListener) listeners.elementAt(i);
|
||||
listener.textEventOccurred(event);
|
||||
}
|
||||
}
|
||||
}
|
22
icu4j/src/com/ibm/richtext/textpanel/RunStrategy.java
Executable file
22
icu4j/src/com/ibm/richtext/textpanel/RunStrategy.java
Executable file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* @(#)$RCSfile: RunStrategy.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
class RunStrategy {
|
||||
|
||||
void doIt(Runnable r) {
|
||||
r.run();
|
||||
}
|
||||
}
|
153
icu4j/src/com/ibm/richtext/textpanel/ScrollBarLayout.java
Executable file
153
icu4j/src/com/ibm/richtext/textpanel/ScrollBarLayout.java
Executable file
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* @(#)$RCSfile: ScrollBarLayout.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Insets;
|
||||
import java.awt.LayoutManager;
|
||||
|
||||
class ScrollBarLayout implements LayoutManager {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
Component fHorizScrollBar = null;
|
||||
Component fVertScrollBar = null;
|
||||
Component fChild = null;
|
||||
|
||||
public ScrollBarLayout() {
|
||||
}
|
||||
|
||||
public void addLayoutComponent(String name, Component comp) {
|
||||
|
||||
if ("Center".equals(name))
|
||||
fChild = comp;
|
||||
else if ("South".equals(name))
|
||||
fHorizScrollBar = comp;
|
||||
else if ("East".equals(name))
|
||||
fVertScrollBar = comp;
|
||||
}
|
||||
|
||||
public void layoutContainer(Container target) {
|
||||
|
||||
Insets insets = target.getInsets();
|
||||
Dimension targetSize = target.getSize();
|
||||
int hsbHeight = (fHorizScrollBar != null) ? fHorizScrollBar.getPreferredSize().
|
||||
height : 0;
|
||||
int vsbWidth = (fVertScrollBar != null) ? fVertScrollBar.getPreferredSize().
|
||||
width : 0;
|
||||
|
||||
if (fHorizScrollBar != null)
|
||||
fHorizScrollBar.setBounds(insets.left, targetSize.height - insets.bottom -
|
||||
hsbHeight, targetSize.width - vsbWidth, hsbHeight);
|
||||
|
||||
if (fVertScrollBar != null)
|
||||
fVertScrollBar.setBounds(targetSize.width - insets.right - vsbWidth,
|
||||
insets.top, vsbWidth, targetSize.height - hsbHeight);
|
||||
|
||||
if (fChild != null)
|
||||
fChild.setBounds(insets.left, insets.top, targetSize.width - insets.right - vsbWidth,
|
||||
targetSize.height - insets.bottom - hsbHeight);
|
||||
}
|
||||
|
||||
public Dimension minimumLayoutSize(Container target) {
|
||||
|
||||
Dimension returnVal = new Dimension(0, 0);
|
||||
Dimension hsbSize;
|
||||
Dimension vsbSize;
|
||||
Dimension childSize;
|
||||
|
||||
if (fHorizScrollBar != null && fHorizScrollBar.isVisible()) {
|
||||
hsbSize = fHorizScrollBar.getMinimumSize();
|
||||
}
|
||||
else {
|
||||
hsbSize = new Dimension(0, 0);
|
||||
}
|
||||
|
||||
if (fVertScrollBar != null && fVertScrollBar.isVisible()) {
|
||||
vsbSize = fVertScrollBar.getMinimumSize();
|
||||
}
|
||||
else {
|
||||
vsbSize = new Dimension(0, 0);
|
||||
}
|
||||
|
||||
if (fChild != null && fChild.isVisible()) {
|
||||
childSize = fChild.getMinimumSize();
|
||||
}
|
||||
else {
|
||||
childSize = new Dimension(0, 0);
|
||||
}
|
||||
|
||||
returnVal.width = Math.max(childSize.width, hsbSize.width) + vsbSize.width;
|
||||
returnVal.height = Math.max(childSize.height, vsbSize.height) + hsbSize.height;
|
||||
|
||||
Insets insets = target.getInsets();
|
||||
|
||||
returnVal.width += insets.left + insets.right;
|
||||
returnVal.height += insets.top + insets.bottom;
|
||||
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
public Dimension preferredLayoutSize(Container target) {
|
||||
|
||||
Dimension returnVal = new Dimension(0, 0);
|
||||
Dimension hsbSize;
|
||||
Dimension vsbSize;
|
||||
Dimension childSize;
|
||||
|
||||
if (fHorizScrollBar != null && fHorizScrollBar.isVisible()) {
|
||||
hsbSize = fHorizScrollBar.getPreferredSize();
|
||||
}
|
||||
else {
|
||||
hsbSize = new Dimension(0, 0);
|
||||
}
|
||||
|
||||
if (fVertScrollBar != null && fVertScrollBar.isVisible()) {
|
||||
vsbSize = fVertScrollBar.getPreferredSize();
|
||||
}
|
||||
else {
|
||||
vsbSize = new Dimension(0, 0);
|
||||
}
|
||||
|
||||
if (fChild != null && fChild.isVisible()) {
|
||||
childSize = fChild.getPreferredSize();
|
||||
}
|
||||
else {
|
||||
childSize = new Dimension(0, 0);
|
||||
}
|
||||
|
||||
returnVal.width = Math.max(childSize.width, hsbSize.width) + vsbSize.width;
|
||||
returnVal.height = Math.max(childSize.height, vsbSize.height) + hsbSize.height;
|
||||
|
||||
Insets insets = target.getInsets();
|
||||
|
||||
returnVal.width += insets.left + insets.right;
|
||||
returnVal.height += insets.top + insets.bottom;
|
||||
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
public void removeLayoutComponent(Component comp) {
|
||||
|
||||
if (comp == fChild)
|
||||
fChild = null;
|
||||
else if (comp == fHorizScrollBar)
|
||||
fHorizScrollBar = null;
|
||||
else if (comp == fVertScrollBar)
|
||||
fVertScrollBar = null;
|
||||
}
|
||||
}
|
207
icu4j/src/com/ibm/richtext/textpanel/Scroller.java
Executable file
207
icu4j/src/com/ibm/richtext/textpanel/Scroller.java
Executable file
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* @(#)$RCSfile: Scroller.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
/*
|
||||
7/9/97 - changed some deprecated methods in Scrollbar
|
||||
Also setting Unit and Block increment values. Maybe
|
||||
it matters...
|
||||
6/29/98 - reimplemented this class. Now this class talks to
|
||||
any component which implements Scroller.Client.
|
||||
ScrollHolder is gone, too.
|
||||
2/4/99 - No longer a Panel. Also, doesn't create Scrollbars,
|
||||
and in fact doesn't even use the Scrollbar class
|
||||
directly.
|
||||
*/
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Dimension;
|
||||
|
||||
import java.awt.event.AdjustmentListener;
|
||||
import java.awt.event.AdjustmentEvent;
|
||||
import java.awt.Adjustable;
|
||||
|
||||
/**
|
||||
* This class manages the interaction between a scrollable client
|
||||
* and vertical and horizontal scrollbars. It calls the client's
|
||||
* scrollTo method in response to manipulation of the scroll bars.
|
||||
*
|
||||
* This class used to be a Panel containing the scrollbars and
|
||||
* the client panel. As part of the migration away from direct
|
||||
* AWT dependencies, this class is no longer part of the view
|
||||
* hierarchy. Instead it simply keeps a reference to its
|
||||
* client and scroll bars. It is the responsibility of higher-
|
||||
* level classes to set up the view hierarchy.
|
||||
*/
|
||||
final class Scroller implements AdjustmentListener
|
||||
{
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
|
||||
static interface Client {
|
||||
void scrollTo(int x, int y);
|
||||
Rectangle getScrollSize();
|
||||
Rectangle getBounds();
|
||||
}
|
||||
|
||||
private Adjustable fHorizScrollBar = null;
|
||||
private Adjustable fVertScrollBar = null;
|
||||
private Client fClient = null;
|
||||
|
||||
/**
|
||||
* These are used if the respective Scrollbar is not present.
|
||||
*/
|
||||
private int fHorizValue, fVertValue;
|
||||
|
||||
private static final int DEFAULT_UNIT_INC = 10;
|
||||
|
||||
/**
|
||||
* Construct a new Scroller with the given Adjustables,
|
||||
* which really should be scrollbars of some ilk.
|
||||
* Also, the Adjustables are required to be AWT Components,
|
||||
* so the Scroller can enable and disable them.
|
||||
* However, a Scroller can work with either AWT Scrollbars
|
||||
* or JFC JScrollbars.
|
||||
* @param horizScrollbar the horizontal scrollbar. null if
|
||||
* there is no horizontal scrollbar.
|
||||
* @param vertScrollbar the vertical scrollbar. null if
|
||||
* there is no vertical scrollbar.
|
||||
*/
|
||||
public Scroller(Adjustable horizScrollBar,
|
||||
Adjustable vertScrollBar) {
|
||||
|
||||
//setLayout(new ScrollBarLayout());
|
||||
|
||||
fHorizScrollBar = horizScrollBar;
|
||||
fVertScrollBar = vertScrollBar;
|
||||
|
||||
if (fVertScrollBar != null) {
|
||||
fVertScrollBar.setUnitIncrement(DEFAULT_UNIT_INC);
|
||||
fVertScrollBar.addAdjustmentListener(this);
|
||||
}
|
||||
if (fHorizScrollBar != null) {
|
||||
fHorizScrollBar.setUnitIncrement(DEFAULT_UNIT_INC);
|
||||
fHorizScrollBar.addAdjustmentListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void setClient(Client client) {
|
||||
|
||||
fClient = client;
|
||||
clientScrollSizeChanged();
|
||||
}
|
||||
|
||||
public void adjustmentValueChanged(AdjustmentEvent event) {
|
||||
|
||||
boolean horizontal;
|
||||
if (event.getAdjustable() == fHorizScrollBar) {
|
||||
int vertVal = fVertScrollBar == null? fVertValue :
|
||||
fVertScrollBar.getValue();
|
||||
scrollTo(event.getValue(), vertVal);
|
||||
}
|
||||
else {
|
||||
int horizVal = fHorizScrollBar == null? fHorizValue :
|
||||
fHorizScrollBar.getValue();
|
||||
scrollTo(horizVal, event.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void setValues(Adjustable scrollbar,
|
||||
int visible,
|
||||
int minimum,
|
||||
int height) {
|
||||
|
||||
int maximum = minimum+height;
|
||||
|
||||
if (scrollbar != null) {
|
||||
|
||||
Component scrollbarToo = (Component) scrollbar;
|
||||
|
||||
if (maximum <= visible) {
|
||||
scrollbarToo.setEnabled(false);
|
||||
}
|
||||
else {
|
||||
scrollbarToo.setEnabled(true);
|
||||
}
|
||||
|
||||
scrollbar.setMinimum(minimum);
|
||||
scrollbar.setMaximum(maximum);
|
||||
scrollbar.setVisibleAmount(visible);
|
||||
scrollbar.setBlockIncrement(visible-DEFAULT_UNIT_INC);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void clientScrollSizeChanged()
|
||||
{
|
||||
Rectangle bounds = fClient.getBounds();
|
||||
Rectangle preferredSize = fClient.getScrollSize();
|
||||
|
||||
setValues(fHorizScrollBar, bounds.width, preferredSize.x, preferredSize.width);
|
||||
setValues(fVertScrollBar, bounds.height, preferredSize.y, preferredSize.height);
|
||||
}
|
||||
|
||||
public void setPosition(int x, int y) {
|
||||
|
||||
if (fHorizScrollBar != null) {
|
||||
fHorizScrollBar.setValue(x);
|
||||
}
|
||||
else {
|
||||
fHorizValue = x;
|
||||
}
|
||||
if (fVertScrollBar != null) {
|
||||
fVertScrollBar.setValue(y);
|
||||
}
|
||||
else {
|
||||
fVertValue = y;
|
||||
}
|
||||
}
|
||||
|
||||
private void scrollTo(int x, int y)
|
||||
{
|
||||
fClient.scrollTo(x, y);
|
||||
}
|
||||
|
||||
public void setHorizLineDistance(int newDistance)
|
||||
{
|
||||
if (fHorizScrollBar != null) {
|
||||
fHorizScrollBar.setUnitIncrement(newDistance);
|
||||
}
|
||||
}
|
||||
|
||||
public void setHorizPageOverlap(int newOverlap)
|
||||
{
|
||||
if (fHorizScrollBar != null) {
|
||||
fHorizScrollBar.setBlockIncrement(
|
||||
fHorizScrollBar.getVisibleAmount()-newOverlap);
|
||||
}
|
||||
}
|
||||
|
||||
public void setVertLineDistance(int newDistance)
|
||||
{
|
||||
if (fVertScrollBar != null) {
|
||||
fVertScrollBar.setUnitIncrement(newDistance);
|
||||
}
|
||||
}
|
||||
|
||||
public void setVertPageOverlap(int newOverlap)
|
||||
{
|
||||
if (fVertScrollBar != null) {
|
||||
fVertScrollBar.setBlockIncrement(
|
||||
fVertScrollBar.getVisibleAmount()-newOverlap);
|
||||
}
|
||||
}
|
||||
}
|
206
icu4j/src/com/ibm/richtext/textpanel/SelectionDragInteractor.java
Executable file
206
icu4j/src/com/ibm/richtext/textpanel/SelectionDragInteractor.java
Executable file
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* @(#)$RCSfile: SelectionDragInteractor.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
import java.text.BreakIterator;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
import com.ibm.richtext.textformat.TextOffset;
|
||||
|
||||
final class SelectionDragInteractor extends Behavior implements Runnable {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
private TextComponent fTextComponent;
|
||||
private TextSelection fSelection;
|
||||
private RunStrategy fRunStrategy;
|
||||
|
||||
private TextOffset fAnchorStart; // aliases text offsets - client beware
|
||||
private TextOffset fAnchorEnd;
|
||||
private TextOffset fCurrent;
|
||||
|
||||
private final boolean fWasZeroLength;
|
||||
|
||||
private int fCurrentX;
|
||||
private int fCurrentY;
|
||||
private boolean fMouseOutside;
|
||||
|
||||
private Thread fAutoscrollThread = null;
|
||||
private boolean fThreadRun = true;
|
||||
|
||||
private static final int kScrollSleep = 300;
|
||||
|
||||
public SelectionDragInteractor(TextSelection selection,
|
||||
TextComponent textComponent,
|
||||
RunStrategy runStrategy,
|
||||
TextOffset anchorStart,
|
||||
TextOffset anchorEnd,
|
||||
TextOffset current,
|
||||
int initialX,
|
||||
int initialY,
|
||||
boolean wasZeroLength) {
|
||||
|
||||
fTextComponent = textComponent;
|
||||
fSelection = selection;
|
||||
fRunStrategy = runStrategy;
|
||||
fAnchorStart = anchorStart;
|
||||
fAnchorEnd = anchorEnd;
|
||||
fCurrent = current;
|
||||
|
||||
fCurrentX = initialX;
|
||||
fCurrentY = initialY;
|
||||
fMouseOutside = false;
|
||||
|
||||
fWasZeroLength = wasZeroLength;
|
||||
|
||||
setSelection();
|
||||
}
|
||||
|
||||
public boolean textControlEventOccurred(Behavior.EventType event, Object what) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean focusGained(FocusEvent event) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean focusLost(FocusEvent event) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean keyPressed(KeyEvent event) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean keyTyped(KeyEvent event) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean keyReleased(KeyEvent event) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized boolean mouseDragged(MouseEvent e) {
|
||||
|
||||
int x = e.getX(), y = e.getY();
|
||||
if (fCurrentX != x || fCurrentY != y) {
|
||||
fCurrentX = x;
|
||||
fCurrentY = y;
|
||||
processMouseLocation();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized boolean mouseEnter(MouseEvent e) {
|
||||
|
||||
fMouseOutside = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized boolean mouseExited(MouseEvent e) {
|
||||
|
||||
if (fAutoscrollThread == null) {
|
||||
fAutoscrollThread = new Thread(this);
|
||||
fAutoscrollThread.start();
|
||||
}
|
||||
fMouseOutside = true;
|
||||
notify();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized boolean mouseReleased(MouseEvent e) {
|
||||
|
||||
fMouseOutside = false;
|
||||
fThreadRun = false;
|
||||
if (fAutoscrollThread != null) {
|
||||
fAutoscrollThread.interrupt();
|
||||
}
|
||||
|
||||
removeFromOwner();
|
||||
boolean isZeroLength = TextSelection.rangeIsZeroLength(fAnchorStart,
|
||||
fAnchorEnd,
|
||||
fCurrent);
|
||||
fSelection.mouseReleased(isZeroLength != fWasZeroLength);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void processMouseLocation() {
|
||||
|
||||
fTextComponent.scrollToShow(fCurrentX, fCurrentY);
|
||||
fTextComponent.pointToTextOffset(fCurrent, fCurrentX, fCurrentY, null, true);
|
||||
setSelection();
|
||||
}
|
||||
|
||||
private void setSelection() {
|
||||
|
||||
if (fCurrent.greaterThan(fAnchorEnd)) {
|
||||
fSelection.advanceToNextBoundary(fCurrent);
|
||||
fSelection.setSelRangeAndDraw(fAnchorStart, fCurrent, fAnchorStart);
|
||||
}
|
||||
else if (fCurrent.lessThan(fAnchorStart)) {
|
||||
fSelection.advanceToPreviousBoundary(fCurrent);
|
||||
fSelection.setSelRangeAndDraw(fCurrent, fAnchorEnd, fAnchorStart);
|
||||
}
|
||||
else {
|
||||
fCurrent.assign(fAnchorEnd);
|
||||
fSelection.setSelRangeAndDraw(fAnchorStart, fAnchorEnd, fAnchorStart);
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
|
||||
Runnable doMouseLoc = new Runnable() {
|
||||
public void run() {
|
||||
processMouseLocation();
|
||||
}
|
||||
};
|
||||
|
||||
while (fThreadRun) {
|
||||
|
||||
try {
|
||||
Thread.sleep(kScrollSleep);
|
||||
}
|
||||
catch(InterruptedException e) {
|
||||
return; // just quit scrolling
|
||||
}
|
||||
|
||||
synchronized(this) {
|
||||
|
||||
while (!fMouseOutside) {
|
||||
try {
|
||||
wait();
|
||||
}
|
||||
catch(InterruptedException e) {
|
||||
return; // just quit scrolling
|
||||
}
|
||||
}
|
||||
|
||||
fRunStrategy.doIt(doMouseLoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
177
icu4j/src/com/ibm/richtext/textpanel/SimpleCommandLog.java
Executable file
177
icu4j/src/com/ibm/richtext/textpanel/SimpleCommandLog.java
Executable file
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* @(#)$RCSfile: SimpleCommandLog.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
final class SimpleCommandLog {
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
private Command fLastCommand = null;
|
||||
private Command fCurrentCommand = null;
|
||||
private PanelEventBroadcaster fListener;
|
||||
|
||||
private boolean fBaseIsModified;
|
||||
|
||||
private int fLogSize = 14;
|
||||
|
||||
public SimpleCommandLog(PanelEventBroadcaster listener) {
|
||||
fListener = listener;
|
||||
fBaseIsModified = false;
|
||||
}
|
||||
|
||||
/** adds the specfied command to the top of the command stack
|
||||
* (any undone commands on the stack are removed)
|
||||
* This function assumes the command has already been executed (i.e., its execute() method
|
||||
* has been called, or an equivalent action has been taken) */
|
||||
void add(Command newCommand) {
|
||||
// if there are commands on the stack that have been undone, they are
|
||||
// dropped on the floor here
|
||||
newCommand.setPreviousCommand(fCurrentCommand);
|
||||
|
||||
final Command oldLastCommand = fLastCommand;
|
||||
fLastCommand = null;
|
||||
|
||||
fCurrentCommand = newCommand;
|
||||
limitCommands(fLogSize);
|
||||
|
||||
if (oldLastCommand != null) {
|
||||
fListener.textStateChanged(TextPanelEvent.UNDO_STATE_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the command list is longer than logSize, truncate it.
|
||||
* This method traverses the list each time, and is not a model
|
||||
* of efficiency. It's a temporary way to plug this memory leak
|
||||
* until I can implement a bounded command log.
|
||||
*/
|
||||
private void limitCommands(int logSize) {
|
||||
|
||||
if (logSize == 0) {
|
||||
fCurrentCommand = null;
|
||||
}
|
||||
else {
|
||||
Command currentCommand = fCurrentCommand;
|
||||
int remaining = logSize-1;
|
||||
while (currentCommand != null && remaining > 0) {
|
||||
currentCommand = currentCommand.previousCommand();
|
||||
remaining -= 1;
|
||||
}
|
||||
if (currentCommand != null) {
|
||||
currentCommand.setPreviousCommand(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** adds the specfied command to the top of the command stack and executes it */
|
||||
void addAndDo(Command newCommand) {
|
||||
add(newCommand);
|
||||
newCommand.execute();
|
||||
|
||||
fListener.textStateChanged(TextPanelEvent.UNDO_STATE_CHANGED);
|
||||
}
|
||||
|
||||
/** undoes the command on the top of the command stack, if there is one */
|
||||
void undo() {
|
||||
if (fCurrentCommand != null) {
|
||||
Command current = fCurrentCommand;
|
||||
current.undo();
|
||||
|
||||
fCurrentCommand = current.previousCommand();
|
||||
|
||||
current.setPreviousCommand(fLastCommand);
|
||||
fLastCommand = current;
|
||||
|
||||
fListener.textStateChanged(TextPanelEvent.UNDO_STATE_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
/** redoes the last undone command on the command stack, if there are any */
|
||||
void redo() {
|
||||
if (fLastCommand != null) {
|
||||
Command last = fLastCommand;
|
||||
last.redo();
|
||||
|
||||
fLastCommand = last.previousCommand();
|
||||
|
||||
last.setPreviousCommand(fCurrentCommand);
|
||||
fCurrentCommand = last;
|
||||
|
||||
fListener.textStateChanged(TextPanelEvent.UNDO_STATE_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canUndo() {
|
||||
return fCurrentCommand != null;
|
||||
}
|
||||
|
||||
public boolean canRedo() {
|
||||
return fLastCommand != null;
|
||||
}
|
||||
|
||||
public boolean isModified() {
|
||||
|
||||
if (fCurrentCommand == null) {
|
||||
return fBaseIsModified;
|
||||
}
|
||||
else {
|
||||
return fCurrentCommand.isModified();
|
||||
}
|
||||
}
|
||||
|
||||
public void setModified(boolean modified) {
|
||||
|
||||
if (fCurrentCommand == null) {
|
||||
fBaseIsModified = modified;
|
||||
}
|
||||
else {
|
||||
fCurrentCommand.setModified(modified);
|
||||
}
|
||||
}
|
||||
|
||||
public void clearLog() {
|
||||
|
||||
if (fCurrentCommand != null) {
|
||||
fBaseIsModified = fCurrentCommand.isModified();
|
||||
}
|
||||
boolean changed = fCurrentCommand != null || fLastCommand != null;
|
||||
fCurrentCommand = null;
|
||||
fLastCommand = null;
|
||||
|
||||
fListener.textStateChanged(TextPanelEvent.UNDO_STATE_CHANGED);
|
||||
}
|
||||
|
||||
public void setLogSize(int size) {
|
||||
|
||||
if (size < 0) {
|
||||
throw new IllegalArgumentException("log size cannot be negative");
|
||||
}
|
||||
|
||||
if (size < fLogSize) {
|
||||
limitCommands(size);
|
||||
}
|
||||
|
||||
fLogSize = size;
|
||||
|
||||
if (fLastCommand != null || size == 0) {
|
||||
fLastCommand = null;
|
||||
fListener.textStateChanged(TextPanelEvent.UNDO_STATE_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
public int getLogSize() {
|
||||
|
||||
return fLogSize;
|
||||
}
|
||||
}
|
49
icu4j/src/com/ibm/richtext/textpanel/StyleChangeCommand.java
Executable file
49
icu4j/src/com/ibm/richtext/textpanel/StyleChangeCommand.java
Executable file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* @(#)$RCSfile: StyleChangeCommand.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
import com.ibm.richtext.styledtext.StyleModifier;
|
||||
import com.ibm.richtext.styledtext.MConstText;
|
||||
import com.ibm.richtext.styledtext.MText;
|
||||
import com.ibm.richtext.textformat.TextOffset;
|
||||
|
||||
class StyleChangeCommand extends TextCommand {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
private boolean fCharacter;
|
||||
private StyleModifier fModifier;
|
||||
|
||||
public StyleChangeCommand(TextEditBehavior behavior,
|
||||
MText originalText,
|
||||
TextOffset selStartBefore,
|
||||
TextOffset selEndBefore,
|
||||
StyleModifier modifier,
|
||||
boolean character) {
|
||||
|
||||
super(behavior, originalText, selStartBefore.fOffset, selStartBefore, selEndBefore);
|
||||
fModifier = modifier;
|
||||
fCharacter = character;
|
||||
}
|
||||
|
||||
public int affectedRangeEnd() {
|
||||
return fSelEndBefore.fOffset;
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
fBehavior.doModifyStyles(fAffectedRangeStart, fSelEndBefore.fOffset,
|
||||
fModifier, fCharacter, fSelStartBefore, fSelEndBefore);
|
||||
}
|
||||
}
|
219
icu4j/src/com/ibm/richtext/textpanel/StyledTextClipboard.java
Executable file
219
icu4j/src/com/ibm/richtext/textpanel/StyledTextClipboard.java
Executable file
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* @(#)$RCSfile: StyledTextClipboard.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
import java.awt.datatransfer.Clipboard;
|
||||
import java.awt.datatransfer.ClipboardOwner;
|
||||
import java.awt.datatransfer.Transferable;
|
||||
import java.awt.datatransfer.DataFlavor;
|
||||
import java.awt.datatransfer.UnsupportedFlavorException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import java.awt.Toolkit;
|
||||
|
||||
import com.ibm.textlayout.attributes.AttributeMap;
|
||||
|
||||
import com.ibm.richtext.styledtext.MConstText;
|
||||
import com.ibm.richtext.styledtext.StyledText;
|
||||
|
||||
/**
|
||||
* Wrapper for java.awt.datatransfer.Clipboard
|
||||
* Packages an MConstText in a transferable, and puts it on the clipboard.
|
||||
*/
|
||||
|
||||
class StyledTextClipboard implements ClipboardOwner {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
// This class has a workaround for a bug in the Windows system clipboard.
|
||||
// The system clipboard will only return String content, even
|
||||
// though it has a reference to the contents. So if our
|
||||
// clipboard is the system clipboard, we'll keep a reference
|
||||
// to the content and use that instead of what the Clipboard returns.
|
||||
|
||||
private static Clipboard SYSTEM = null;
|
||||
static {
|
||||
try {
|
||||
SYSTEM = Toolkit.getDefaultToolkit().getSystemClipboard();
|
||||
}
|
||||
catch(Throwable th) {
|
||||
}
|
||||
}
|
||||
|
||||
private static StyledTextClipboard fgSystemClipboard = null;
|
||||
|
||||
public static StyledTextClipboard getClipboardFor(Clipboard clipboard) {
|
||||
|
||||
if (clipboard == SYSTEM && SYSTEM != null) {
|
||||
synchronized(SYSTEM) {
|
||||
if (fgSystemClipboard == null) {
|
||||
fgSystemClipboard = new StyledTextClipboard(SYSTEM, true);
|
||||
}
|
||||
}
|
||||
return fgSystemClipboard;
|
||||
}
|
||||
else {
|
||||
return new StyledTextClipboard(clipboard, false);
|
||||
}
|
||||
}
|
||||
|
||||
private Clipboard fClipboard;
|
||||
private boolean fUseLocalContents;
|
||||
private Transferable fContents = null;
|
||||
|
||||
private StyledTextClipboard(Clipboard clipboard, boolean useLocalContents) {
|
||||
|
||||
if (clipboard == null) {
|
||||
fClipboard = new Clipboard("TextPanel clipboard");
|
||||
}
|
||||
else {
|
||||
fClipboard = clipboard;
|
||||
}
|
||||
|
||||
fUseLocalContents = useLocalContents;
|
||||
}
|
||||
|
||||
public void lostOwnership(Clipboard clipboard,
|
||||
Transferable contents) {
|
||||
if (contents == fContents) {
|
||||
this.fContents = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setContents(MConstText newContents) {
|
||||
|
||||
TransferableText contents = new TransferableText(newContents);
|
||||
if (fClipboard == SYSTEM) {
|
||||
fContents = contents;
|
||||
}
|
||||
fClipboard.setContents(contents, this);
|
||||
}
|
||||
|
||||
private Transferable getClipboardContents() {
|
||||
|
||||
if (fUseLocalContents && fContents != null) {
|
||||
return fContents;
|
||||
}
|
||||
|
||||
return fClipboard.getContents(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Has contents - faster than getContents for finding out whether the
|
||||
* clipboard has text.
|
||||
*/
|
||||
public boolean hasContents() {
|
||||
|
||||
Transferable contents = getClipboardContents();
|
||||
|
||||
if (contents == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return contents.isDataFlavorSupported(MConstText.styledTextFlavor) ||
|
||||
contents.isDataFlavorSupported(DataFlavor.stringFlavor) ||
|
||||
contents.isDataFlavorSupported(DataFlavor.plainTextFlavor);
|
||||
}
|
||||
|
||||
private String getString(InputStream inStream) throws IOException {
|
||||
|
||||
String value = new String();
|
||||
int bytesRead;
|
||||
|
||||
do {
|
||||
byte inBytes[] = new byte[inStream.available()];
|
||||
bytesRead = inStream.read(inBytes);
|
||||
|
||||
if (bytesRead != -1)
|
||||
value = value + new String(inBytes);
|
||||
|
||||
} while (bytesRead != -1);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the Clipboard has text content, return it as an
|
||||
* MConstText. Otherwise return null.
|
||||
* @param defaultStyle the style to apply to unstyled
|
||||
* text (such as a String). If the clipboard
|
||||
* has styled text this parameter is not used.
|
||||
*/
|
||||
public MConstText getContents(AttributeMap defaultStyle) {
|
||||
|
||||
Transferable contents = getClipboardContents();
|
||||
|
||||
if (contents == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
DataFlavor flavors[] = contents.getTransferDataFlavors();
|
||||
|
||||
// search flavors for our flavor, String flavor and raw text flavor
|
||||
|
||||
Exception ex = null;
|
||||
|
||||
try {
|
||||
int i;
|
||||
|
||||
for (i=0; i < flavors.length; i++) {
|
||||
if (flavors[i].equals(MConstText.styledTextFlavor))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < flavors.length) {
|
||||
|
||||
Object data = contents.getTransferData(MConstText.styledTextFlavor);
|
||||
if (data == null)
|
||||
System.out.println("Data is null.");
|
||||
return (MConstText) data;
|
||||
}
|
||||
|
||||
for (i=0; i < flavors.length; i++) {
|
||||
if (flavors[i].equals(DataFlavor.stringFlavor))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < flavors.length) {
|
||||
|
||||
Object data = contents.getTransferData(DataFlavor.stringFlavor);
|
||||
return new StyledText((String) data, defaultStyle);
|
||||
}
|
||||
|
||||
for (i=0; i < flavors.length; i++) {
|
||||
if (flavors[i].equals(DataFlavor.plainTextFlavor))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < flavors.length) {
|
||||
|
||||
Object data = contents.getTransferData(DataFlavor.plainTextFlavor);
|
||||
|
||||
String textString = getString((InputStream) data);
|
||||
return new StyledText(textString, defaultStyle);
|
||||
}
|
||||
}
|
||||
catch(UnsupportedFlavorException e) {
|
||||
ex = e;
|
||||
}
|
||||
catch(IOException e) {
|
||||
ex = e;
|
||||
}
|
||||
|
||||
System.out.println("Exception when retrieving data. Exception:" + ex);
|
||||
return null;
|
||||
}
|
||||
}
|
81
icu4j/src/com/ibm/richtext/textpanel/TextChangeCommand.java
Executable file
81
icu4j/src/com/ibm/richtext/textpanel/TextChangeCommand.java
Executable file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* @(#)$RCSfile: TextChangeCommand.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
import com.ibm.richtext.styledtext.MConstText;
|
||||
import com.ibm.richtext.styledtext.MText;
|
||||
import com.ibm.richtext.textformat.TextOffset;
|
||||
|
||||
class TextChangeCommand extends TextCommand {
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
private MConstText fNewText;
|
||||
private TextOffset fSelStartAfter;
|
||||
private TextOffset fSelEndAfter;
|
||||
|
||||
public TextChangeCommand(TextEditBehavior behavior,
|
||||
MText originalText,
|
||||
MConstText newText,
|
||||
int affectedRangeStart,
|
||||
TextOffset selStartBefore,
|
||||
TextOffset selEndBefore,
|
||||
TextOffset selStartAfter,
|
||||
TextOffset selEndAfter) {
|
||||
super(behavior, originalText, affectedRangeStart, selStartBefore, selEndBefore);
|
||||
fNewText = newText;
|
||||
fSelStartAfter = new TextOffset();
|
||||
fSelStartAfter.assign(selStartAfter);
|
||||
fSelEndAfter = new TextOffset();
|
||||
fSelEndAfter.assign(selEndAfter);
|
||||
}
|
||||
|
||||
public int affectedRangeEnd() {
|
||||
if (fNewText == null)
|
||||
return fAffectedRangeStart;
|
||||
else
|
||||
return fAffectedRangeStart + fNewText.length();
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
fBehavior.doReplaceText(fAffectedRangeStart, fAffectedRangeStart + fOriginalText.length(),
|
||||
fNewText, fSelStartAfter, fSelEndAfter);
|
||||
}
|
||||
|
||||
public int affectedRangeStart() {
|
||||
return fAffectedRangeStart;
|
||||
}
|
||||
|
||||
public void setNewText(MConstText newText) {
|
||||
fNewText = newText;
|
||||
}
|
||||
|
||||
public void setSelRangeAfter(TextOffset start, TextOffset end) {
|
||||
if (fSelStartAfter == null)
|
||||
fSelStartAfter = new TextOffset();
|
||||
if (fSelEndAfter == null)
|
||||
fSelEndAfter = new TextOffset();
|
||||
fSelStartAfter.assign(start);
|
||||
fSelEndAfter.assign(end);
|
||||
}
|
||||
|
||||
public void prependToOldText(MConstText newText) {
|
||||
fOriginalText.insert(0, newText);
|
||||
fAffectedRangeStart -= newText.length();
|
||||
}
|
||||
|
||||
public void appendToOldText(MConstText newText) {
|
||||
fOriginalText.append(newText);
|
||||
}
|
||||
}
|
51
icu4j/src/com/ibm/richtext/textpanel/TextCommand.java
Executable file
51
icu4j/src/com/ibm/richtext/textpanel/TextCommand.java
Executable file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* @(#)$RCSfile: TextCommand.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
import com.ibm.richtext.styledtext.MConstText;
|
||||
import com.ibm.richtext.styledtext.MText;
|
||||
import com.ibm.richtext.textformat.TextOffset;
|
||||
|
||||
abstract class TextCommand extends Command {
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
protected TextEditBehavior fBehavior;
|
||||
protected MText fOriginalText;
|
||||
protected int fAffectedRangeStart;
|
||||
protected TextOffset fSelStartBefore;
|
||||
protected TextOffset fSelEndBefore;
|
||||
|
||||
public TextCommand(TextEditBehavior behavior,
|
||||
MText originalText,
|
||||
int affectedRangeStart,
|
||||
TextOffset selStartBefore,
|
||||
TextOffset selEndBefore) {
|
||||
|
||||
fBehavior = behavior;
|
||||
fOriginalText = originalText;
|
||||
fAffectedRangeStart = affectedRangeStart;
|
||||
fSelStartBefore = new TextOffset();
|
||||
fSelStartBefore.assign(selStartBefore);
|
||||
fSelEndBefore = new TextOffset();
|
||||
fSelEndBefore.assign(selEndBefore);
|
||||
}
|
||||
|
||||
public abstract int affectedRangeEnd();
|
||||
|
||||
public void undo() {
|
||||
fBehavior.doReplaceText(fAffectedRangeStart, affectedRangeEnd(), fOriginalText,
|
||||
fSelStartBefore, fSelEndBefore);
|
||||
}
|
||||
}
|
969
icu4j/src/com/ibm/richtext/textpanel/TextComponent.java
Executable file
969
icu4j/src/com/ibm/richtext/textpanel/TextComponent.java
Executable file
|
@ -0,0 +1,969 @@
|
|||
/*
|
||||
* @(#)$RCSfile: TextComponent.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Image;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import java.awt.event.ComponentAdapter;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.WindowEvent;
|
||||
|
||||
import com.ibm.richtext.styledtext.MConstText;
|
||||
import com.ibm.richtext.styledtext.MText;
|
||||
import com.ibm.richtext.textformat.TextOffset;
|
||||
|
||||
import com.ibm.richtext.textformat.MFormatter;
|
||||
|
||||
import com.ibm.textlayout.attributes.AttributeMap;
|
||||
|
||||
class TextComponent extends FakeComponent
|
||||
implements BehaviorOwner,
|
||||
FocusListener,
|
||||
KeyListener,
|
||||
MouseListener,
|
||||
MouseMotionListener,
|
||||
Scroller.Client {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
|
||||
public static final int WINDOW_WIDTH = -10;
|
||||
public static final int DEFAULT_INSET = 10;
|
||||
|
||||
private static final Color STRONG_CARET_COLOR = Color.black;
|
||||
private static final Color WEAK_CARET_COLOR = Color.darkGray;
|
||||
|
||||
private Behavior fBehavior;
|
||||
private MText fText;
|
||||
private StyledTextClipboard fClipboard;
|
||||
private boolean fScrolls;
|
||||
private Scroller fScroller;
|
||||
|
||||
private DocumentView fDocumentView = null;
|
||||
|
||||
// sigh - can't create DocumentView until addNotify() is called.
|
||||
// These values hold DocumentView ctor args
|
||||
private AttributeMap fDefaultValues;
|
||||
private boolean fViewWraps;
|
||||
private int fViewWrapWidth;
|
||||
private int fViewInsetAmount;
|
||||
|
||||
private PanelEventBroadcaster fListener;
|
||||
|
||||
/**
|
||||
* Create a new TextComponent.
|
||||
* @param text the text model. This model will be used for
|
||||
* the life of the component, even if setText is called
|
||||
* @param wraps if true, the text is wrapped to the specified
|
||||
* wrapping width. If false, the text wraps only at paragraph breaks.
|
||||
* @param wrapWidth ignored if wraps is false. Text wraps to this width
|
||||
* unless the width is WINDOW_WIDTH, in which case text wraps to width
|
||||
* of this component. Should not be negative (unless it is WINDOW_WIDTH).
|
||||
* @param insetAmount the size of the margins around the text
|
||||
* @param clipboard the clipboard to use for cut/copy/paste operations.
|
||||
* If null, the component will use its own clipboard.
|
||||
*/
|
||||
public TextComponent(MText text,
|
||||
AttributeMap defaultValues,
|
||||
boolean wraps,
|
||||
int wrapWidth,
|
||||
int insetAmount,
|
||||
StyledTextClipboard clipboard,
|
||||
boolean scrolls,
|
||||
Scroller scroller,
|
||||
PanelEventBroadcaster listener) {
|
||||
|
||||
fBehavior = null;
|
||||
|
||||
if (text == null) {
|
||||
throw new IllegalArgumentException("Text is null.");
|
||||
}
|
||||
|
||||
fText = text;
|
||||
fDefaultValues = defaultValues;
|
||||
|
||||
if (clipboard == null) {
|
||||
throw new IllegalArgumentException("Clipboard is null.");
|
||||
}
|
||||
fClipboard = clipboard;
|
||||
|
||||
fScrolls = scrolls;
|
||||
|
||||
fScroller = scroller;
|
||||
|
||||
fDocumentView = null;
|
||||
|
||||
fViewWrapWidth = wrapWidth;
|
||||
fViewWraps = wraps;
|
||||
fViewInsetAmount = insetAmount;
|
||||
fListener = listener;
|
||||
}
|
||||
|
||||
AttributeMap getDefaultValues() {
|
||||
|
||||
return fDefaultValues;
|
||||
}
|
||||
|
||||
void setHost(Component component) {
|
||||
|
||||
super.setHost(component);
|
||||
|
||||
component.addFocusListener(this);
|
||||
component.addKeyListener(this);
|
||||
component.addMouseListener(this);
|
||||
component.addMouseMotionListener(this);
|
||||
|
||||
component.addComponentListener(new ComponentAdapter() {
|
||||
public void componentResized(ComponentEvent e) {
|
||||
if (fDocumentView != null) {
|
||||
fDocumentView.hostSizeChanged();
|
||||
scrollToShow(fDocumentView.getDocumentBounds());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Create document view here. TextComponent isn't fully constructed
|
||||
// until this is called.
|
||||
// This must be called by host component!
|
||||
void addNotify() {
|
||||
|
||||
Graphics g = getGraphics();
|
||||
if (g == null) {
|
||||
throw new Error("Graphics should be valid here but isn't.");
|
||||
}
|
||||
|
||||
fDocumentView = new DocumentView(this,
|
||||
fText,
|
||||
fDefaultValues,
|
||||
fViewWraps,
|
||||
fViewWrapWidth,
|
||||
fViewInsetAmount,
|
||||
fListener);
|
||||
documentSizeChanged();
|
||||
fListener.textStateChanged(TextPanelEvent.FORMAT_WIDTH_CHANGED);
|
||||
}
|
||||
|
||||
public Rectangle getBounds() {
|
||||
|
||||
if (fHost != null) {
|
||||
return fHost.getBounds();
|
||||
}
|
||||
else {
|
||||
return new Rectangle(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Graphics getGraphics() {
|
||||
|
||||
return (fHost==null)? null : fHost.getGraphics();
|
||||
}
|
||||
|
||||
void requestFocus() {
|
||||
|
||||
if (fHost != null) {
|
||||
fHost.requestFocus();
|
||||
}
|
||||
}
|
||||
|
||||
// *** Behavior management ***
|
||||
public Behavior getBehavior() {
|
||||
return fBehavior;
|
||||
}
|
||||
|
||||
public void setBehavior(Behavior b) {
|
||||
fBehavior = b;
|
||||
}
|
||||
|
||||
|
||||
// *** Events - just forward to behavior ***
|
||||
public void focusGained(FocusEvent event) {
|
||||
if (fBehavior != null)
|
||||
fBehavior.focusGained(event);
|
||||
}
|
||||
|
||||
public void focusLost(FocusEvent event) {
|
||||
if (fBehavior != null)
|
||||
fBehavior.focusLost(event);
|
||||
}
|
||||
|
||||
public void keyPressed(KeyEvent event) {
|
||||
if (fBehavior != null)
|
||||
fBehavior.keyPressed(event);
|
||||
}
|
||||
|
||||
public void keyTyped(KeyEvent event) {
|
||||
|
||||
if (fBehavior != null) {
|
||||
fBehavior.keyTyped(event);
|
||||
}
|
||||
}
|
||||
|
||||
public void keyReleased(KeyEvent event) {
|
||||
if (fBehavior != null)
|
||||
fBehavior.keyReleased(event);
|
||||
}
|
||||
|
||||
public void mouseClicked(MouseEvent event) {
|
||||
return; // no behavior method for this
|
||||
}
|
||||
|
||||
public void mouseDragged(MouseEvent event) {
|
||||
if (fBehavior != null)
|
||||
fBehavior.mouseDragged(event);
|
||||
}
|
||||
|
||||
public void mouseEntered(MouseEvent event) {
|
||||
if (fBehavior != null)
|
||||
fBehavior.mouseEntered(event);
|
||||
}
|
||||
|
||||
public void mouseExited(MouseEvent event) {
|
||||
if (fBehavior != null)
|
||||
fBehavior.mouseExited(event);
|
||||
}
|
||||
|
||||
public void mouseMoved(MouseEvent event) {
|
||||
if (fBehavior != null)
|
||||
fBehavior.mouseMoved(event);
|
||||
}
|
||||
|
||||
public void mousePressed(MouseEvent event) {
|
||||
if (fBehavior != null)
|
||||
fBehavior.mousePressed(event);
|
||||
}
|
||||
|
||||
public void mouseReleased(MouseEvent event) {
|
||||
if (fBehavior != null)
|
||||
fBehavior.mouseReleased(event);
|
||||
}
|
||||
|
||||
public boolean textControlEventOccurred(Behavior.EventType event, Object what) {
|
||||
|
||||
boolean handled = false;
|
||||
|
||||
if (fBehavior != null) {
|
||||
handled = fBehavior.textControlEventOccurred(event, what);
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
|
||||
// *** Scroll methods - called by Behaviors
|
||||
|
||||
// viewStart, viewLimit is visible bounds of window
|
||||
// targetStart, targetLimit is the region to scroll into view
|
||||
private static int getScrollDifference(int viewStart,
|
||||
int viewLimit,
|
||||
int targetStart,
|
||||
int targetLimit) {
|
||||
|
||||
if (viewStart <= targetStart) {
|
||||
if (viewLimit >= targetLimit) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return Math.max(viewStart-targetStart, viewLimit-targetLimit);
|
||||
}
|
||||
}
|
||||
else if (viewLimit > targetLimit) {
|
||||
|
||||
return viewLimit - targetLimit;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void scrollToShow(Rectangle showRect) {
|
||||
|
||||
if (fDocumentView != null) {
|
||||
Rectangle bounds = getBounds();
|
||||
|
||||
int dx = getScrollDifference(showRect.x, showRect.x + showRect.width,
|
||||
bounds.x, bounds.x + bounds.width);
|
||||
int dy = getScrollDifference(showRect.y, showRect.y + showRect.height,
|
||||
bounds.y, bounds.y + bounds.height);
|
||||
|
||||
scrollSelf(dx, dy);
|
||||
}
|
||||
}
|
||||
|
||||
void scrollToShow(int showX, int showY) {
|
||||
|
||||
if (fDocumentView != null) {
|
||||
int dx = 0, dy = 0;
|
||||
|
||||
Rectangle bounds = getBounds();
|
||||
if (showX < bounds.x) {
|
||||
dx = showX - bounds.x;
|
||||
}
|
||||
else if (showX > bounds.x + bounds.width) {
|
||||
dx = showX - (bounds.x + bounds.width);
|
||||
}
|
||||
|
||||
if (showY < bounds.y) {
|
||||
dy = showY - bounds.y;
|
||||
}
|
||||
else if (showY > bounds.y + bounds.height) {
|
||||
dy = showY - (bounds.y + bounds.height);
|
||||
}
|
||||
|
||||
scrollSelf(dx, dy);
|
||||
}
|
||||
}
|
||||
|
||||
private int pinScrollOffset(int delta,
|
||||
int contentStart,
|
||||
int contentLength,
|
||||
int viewStart,
|
||||
int viewLength) {
|
||||
|
||||
if (delta > 0) {
|
||||
int viewLimit = viewStart + viewLength;
|
||||
int contentLimit = contentStart + contentLength;
|
||||
|
||||
if (viewLimit + delta > contentLimit) {
|
||||
delta = Math.max(0, contentLimit-viewLimit);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (viewStart + delta < contentStart) {
|
||||
delta = Math.min(0, contentStart-viewStart);
|
||||
}
|
||||
}
|
||||
|
||||
return delta;
|
||||
}
|
||||
|
||||
private void scrollSelf(int dx, int dy) {
|
||||
|
||||
boolean scrolled = scrollBy(dx, dy);
|
||||
|
||||
if (scrolled && fScroller != null) {
|
||||
Rectangle documentBounds = fDocumentView.getDocumentBounds();
|
||||
fScroller.setPosition(-documentBounds.x,
|
||||
-documentBounds.y);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized boolean scrollBy(int dx, int dy) {
|
||||
|
||||
boolean scrolled = false;
|
||||
|
||||
if (fScrolls) {
|
||||
Rectangle documentBounds = fDocumentView.getDocumentBounds();
|
||||
Rectangle viewBounds = getBounds();
|
||||
|
||||
int oldDx = dx;
|
||||
dx = pinScrollOffset(dx,
|
||||
documentBounds.x,
|
||||
documentBounds.width,
|
||||
viewBounds.x,
|
||||
viewBounds.width);
|
||||
dy = pinScrollOffset(dy,
|
||||
documentBounds.y,
|
||||
documentBounds.height,
|
||||
viewBounds.y,
|
||||
viewBounds.height);
|
||||
|
||||
if (dx != 0 || dy != 0) {
|
||||
scrolled = true;
|
||||
fDocumentView.moveBy(-dx, -dy);
|
||||
}
|
||||
}
|
||||
|
||||
return scrolled;
|
||||
}
|
||||
|
||||
// implementation of Scroller.Client - called by Scroller
|
||||
// they have to be public since they're in an interface
|
||||
// no one else should call these methods
|
||||
public Rectangle getScrollSize() {
|
||||
|
||||
if (fDocumentView != null) {
|
||||
return fDocumentView.getScrollableArea();
|
||||
}
|
||||
else {
|
||||
return new Rectangle(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void scrollTo(int x, int y) {
|
||||
|
||||
if (fDocumentView != null) {
|
||||
scrollBy(x + fDocumentView.getDocX(), y + fDocumentView.getDocY());
|
||||
}
|
||||
}
|
||||
|
||||
// *** Text access ***
|
||||
MConstText getText() {
|
||||
return fText;
|
||||
}
|
||||
|
||||
MText getModifiableText() {
|
||||
return fText;
|
||||
}
|
||||
|
||||
StyledTextClipboard getClipboard() {
|
||||
return fClipboard;
|
||||
}
|
||||
|
||||
public synchronized void paint(Graphics g) {
|
||||
|
||||
if (fDocumentView != null) {
|
||||
fDocumentView.paint(g);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// *** Metric info - used by Behaviors
|
||||
Rectangle getCaretRect(TextOffset offset) {
|
||||
|
||||
if (fDocumentView != null) {
|
||||
return fDocumentView.getCaretRect(offset);
|
||||
}
|
||||
else {
|
||||
return new Rectangle(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
TextOffset pointToTextOffset(TextOffset result,
|
||||
int x,
|
||||
int y,
|
||||
TextOffset anchor,
|
||||
boolean infiniteMode) {
|
||||
|
||||
if (fDocumentView != null) {
|
||||
return fDocumentView.pointToTextOffset(result, x, y, anchor, infiniteMode);
|
||||
}
|
||||
else {
|
||||
return new TextOffset();
|
||||
}
|
||||
}
|
||||
|
||||
// *** Other stuff used by Behaviors - mostly formatter exports
|
||||
int lineContaining(TextOffset offset) {
|
||||
|
||||
if (fDocumentView != null) {
|
||||
return fDocumentView.lineContaining(offset);
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int lineRangeLow(int lineNumber) {
|
||||
|
||||
if (fDocumentView != null) {
|
||||
return fDocumentView.lineRangeLow(lineNumber);
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int lineRangeLimit(int lineNumber) {
|
||||
|
||||
if (fDocumentView != null) {
|
||||
return fDocumentView.lineRangeLimit(lineNumber);
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void stopBackgroundFormatting() {
|
||||
|
||||
if (fDocumentView != null) {
|
||||
fDocumentView.stopBackgroundFormatting();
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle getBoundingRect(TextOffset offset1, TextOffset offset2) {
|
||||
|
||||
if (fDocumentView != null) {
|
||||
return fDocumentView.getBoundingRect(offset1, offset2);
|
||||
}
|
||||
else {
|
||||
return new Rectangle(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized void reformatAndDrawText(int reformatStart,
|
||||
int reformatLength,
|
||||
TextOffset selStart,
|
||||
TextOffset selEnd,
|
||||
Rectangle additionalUpdateRect,
|
||||
Color hiliteColor) {
|
||||
|
||||
if (fDocumentView != null) {
|
||||
fDocumentView.reformatAndDrawText(reformatStart,
|
||||
reformatLength,
|
||||
selStart,
|
||||
selEnd,
|
||||
additionalUpdateRect,
|
||||
hiliteColor);
|
||||
}
|
||||
}
|
||||
|
||||
TextOffset findNewInsertionOffset(TextOffset result,
|
||||
TextOffset initialOffset,
|
||||
TextOffset previousOffset,
|
||||
short direction) {
|
||||
|
||||
if (fDocumentView != null) {
|
||||
return fDocumentView.findNewInsertionOffset(result, initialOffset, previousOffset, direction);
|
||||
}
|
||||
else {
|
||||
return new TextOffset(initialOffset);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized void drawText(Graphics g,
|
||||
Rectangle damagedRect,
|
||||
boolean selectionVisible,
|
||||
TextOffset selStart,
|
||||
TextOffset selEnd,
|
||||
Color hiliteColor) {
|
||||
|
||||
if (fDocumentView != null) {
|
||||
fDocumentView.drawText(g, damagedRect, selectionVisible, selStart, selEnd, hiliteColor);
|
||||
}
|
||||
}
|
||||
|
||||
private void documentSizeChanged() {
|
||||
|
||||
if (fScroller != null) {
|
||||
fScroller.clientScrollSizeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
int getFormatWidth() {
|
||||
|
||||
if (fDocumentView != null) {
|
||||
return fDocumentView.getFormatWidth();
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the paragraph at the given offset is left-to-right.
|
||||
* @param offset an offset in the text
|
||||
* @return true if the paragraph at the given offset is left-to-right
|
||||
*/
|
||||
boolean paragraphIsLeftToRight(int offset) {
|
||||
|
||||
if (fDocumentView != null) {
|
||||
return fDocumentView.paragraphIsLeftToRight(offset);
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class DocumentView {
|
||||
|
||||
private TextComponent fHost;
|
||||
private boolean fWraps;
|
||||
private boolean fWrapToWindowWidth;
|
||||
private int fInsetAmount;
|
||||
private PanelEventBroadcaster fListener;
|
||||
|
||||
// fBounds is the total scrollable area of the document (including insets)
|
||||
private Rectangle fBounds = new Rectangle();
|
||||
|
||||
private Point fOrigin;
|
||||
|
||||
private MFormatter fFormatter;
|
||||
|
||||
private OffscreenBufferCache fBufferCache;
|
||||
|
||||
// Note, when this is true the caret won't blink in 1.1. Looks like an AWT bug.
|
||||
private static boolean fNoOffscreenBuffer =
|
||||
Boolean.getBoolean("TextComponent.NoOffscreenBuffer");
|
||||
|
||||
// Amount by which to reduce the format width to allow for right-aligned carets.
|
||||
private final int CARET_SLOP = 1;
|
||||
|
||||
DocumentView(TextComponent host,
|
||||
MConstText text,
|
||||
AttributeMap defaultValues,
|
||||
boolean wraps,
|
||||
int wrapWidth,
|
||||
int insetAmount,
|
||||
PanelEventBroadcaster listener) {
|
||||
|
||||
fHost = host;
|
||||
fWrapToWindowWidth = wrapWidth == WINDOW_WIDTH;
|
||||
fInsetAmount = insetAmount;
|
||||
fListener = listener;
|
||||
|
||||
initFormatterAndSize(text, defaultValues, wraps, wrapWidth);
|
||||
|
||||
fBufferCache = new OffscreenBufferCache(host.fHost);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: this computes the bounds rectangle relative to fOrigin
|
||||
*/
|
||||
private void calcBoundsRect() {
|
||||
|
||||
final int insetDim = 2 * fInsetAmount;
|
||||
|
||||
final int minX = fFormatter.minX();
|
||||
final int minY = fFormatter.minY();
|
||||
|
||||
fBounds.setBounds(fOrigin.x + minX - fInsetAmount,
|
||||
fOrigin.y + minY - fInsetAmount,
|
||||
fFormatter.maxX() - minX + insetDim,
|
||||
fFormatter.maxY() - minY + insetDim);
|
||||
//if (minX <= 0) {
|
||||
// System.out.println("calcBoundsRect: minX="+minX+
|
||||
// "; bounds.x="+fBounds.x+"; width="+fBounds.width);
|
||||
//}
|
||||
}
|
||||
|
||||
private void initFormatterAndSize(MConstText text,
|
||||
AttributeMap defaultValues,
|
||||
boolean wraps,
|
||||
int wrapWidth) {
|
||||
|
||||
Rectangle hostBounds = fHost.getBounds();
|
||||
int formatWidth;
|
||||
|
||||
if (!wraps || fWrapToWindowWidth) {
|
||||
formatWidth = hostBounds.width - 2 * fInsetAmount;
|
||||
if (formatWidth <= CARET_SLOP) {
|
||||
formatWidth = CARET_SLOP+1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
formatWidth = wrapWidth;
|
||||
}
|
||||
|
||||
fFormatter = MFormatter.createFormatter(text,
|
||||
defaultValues,
|
||||
formatWidth-CARET_SLOP,
|
||||
wraps,
|
||||
fHost.getGraphics());
|
||||
|
||||
fFormatter.formatToHeight(hostBounds.height * 2);
|
||||
fOrigin = new Point(fInsetAmount, fInsetAmount);
|
||||
calcBoundsRect();
|
||||
}
|
||||
|
||||
// notification method called by TextComponent
|
||||
void hostSizeChanged() {
|
||||
|
||||
final boolean wrap = fFormatter.wrap();
|
||||
if (fWrapToWindowWidth || !wrap) {
|
||||
|
||||
Rectangle hostBounds = fHost.getBounds();
|
||||
final int insetDim = 2 * fInsetAmount;
|
||||
|
||||
int formatWidth = hostBounds.width - 2*fInsetAmount;
|
||||
if (formatWidth <= CARET_SLOP) {
|
||||
formatWidth = CARET_SLOP+1;
|
||||
}
|
||||
fFormatter.setLineBound(formatWidth-CARET_SLOP);
|
||||
|
||||
fFormatter.formatToHeight(hostBounds.y + (hostBounds.height*2) - fOrigin.y);
|
||||
|
||||
calcBoundsRect();
|
||||
|
||||
//System.out.println("Window bounds="+hostBounds+"; document bounds="+fBounds);
|
||||
|
||||
fHost.documentSizeChanged();
|
||||
fListener.textStateChanged(TextPanelEvent.FORMAT_WIDTH_CHANGED);
|
||||
//System.out.println("formatWidth="+formatWidth);
|
||||
//System.out.println("document bounds="+fBounds);
|
||||
//System.out.println();
|
||||
}
|
||||
//dumpWidthInfo();
|
||||
}
|
||||
|
||||
int getFormatWidth() {
|
||||
|
||||
return fFormatter.lineBound();
|
||||
}
|
||||
|
||||
boolean paragraphIsLeftToRight(int offset) {
|
||||
|
||||
int lineNumber = fFormatter.lineContaining(offset);
|
||||
return fFormatter.lineIsLeftToRight(lineNumber);
|
||||
}
|
||||
|
||||
private void textSizeMightHaveChanged() {
|
||||
|
||||
boolean changed = false;
|
||||
final int insetDim = 2 * fInsetAmount;
|
||||
|
||||
int textHeight = fFormatter.maxY() - fFormatter.minY() + insetDim;
|
||||
if (textHeight != fBounds.height) {
|
||||
fBounds.height = textHeight;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (!fFormatter.wrap()) {
|
||||
int textWidth = fFormatter.maxX() - fFormatter.minX() + insetDim;
|
||||
if (textWidth != fBounds.width) {
|
||||
fBounds.width = textWidth;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
//System.out.println("Text size changed. fBounds: " + fBounds);
|
||||
calcBoundsRect();
|
||||
fHost.documentSizeChanged();
|
||||
fHost.scrollToShow(getDocumentBounds());
|
||||
}
|
||||
}
|
||||
|
||||
private void doDrawText(Graphics g,
|
||||
Rectangle drawRect,
|
||||
boolean selectionVisible,
|
||||
TextOffset selStart,
|
||||
TextOffset selEnd,
|
||||
Color hiliteColor) {
|
||||
|
||||
g.clearRect(drawRect.x, drawRect.y, drawRect.width, drawRect.height);
|
||||
|
||||
if (selectionVisible) {
|
||||
fFormatter.draw(g, drawRect, fOrigin, selStart, selEnd, hiliteColor);
|
||||
}
|
||||
else {
|
||||
fFormatter.draw(g, drawRect, fOrigin, null, null, null);
|
||||
}
|
||||
|
||||
if (selStart != null && selStart.equals(selEnd) && selectionVisible) {
|
||||
|
||||
fFormatter.drawCaret(g, selStart, fOrigin,
|
||||
STRONG_CARET_COLOR, WEAK_CARET_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
void drawText(Graphics g,
|
||||
Rectangle drawRect,
|
||||
boolean selectionVisible,
|
||||
TextOffset selStart,
|
||||
TextOffset selEnd,
|
||||
Color hiliteColor) {
|
||||
|
||||
if (g != null) {
|
||||
drawRect = drawRect.intersection(fHost.getBounds());
|
||||
//System.out.println("drawText:drawRect: " + drawRect);
|
||||
g.clipRect(drawRect.x, drawRect.y, drawRect.width, drawRect.height);
|
||||
if (fNoOffscreenBuffer) {
|
||||
doDrawText(g, drawRect, selectionVisible, selStart, selEnd, hiliteColor);
|
||||
}
|
||||
else {
|
||||
Image offscreenBuffer = fBufferCache.getBuffer(drawRect.width, drawRect.height);
|
||||
Graphics offscreenGraphics = offscreenBuffer.getGraphics();
|
||||
offscreenGraphics.translate(-drawRect.x, -drawRect.y);
|
||||
|
||||
doDrawText(offscreenGraphics, drawRect, selectionVisible, selStart, selEnd, hiliteColor);
|
||||
|
||||
g.drawImage(offscreenBuffer, drawRect.x, drawRect.y, fHost.fHost);
|
||||
}
|
||||
}
|
||||
textSizeMightHaveChanged();
|
||||
}
|
||||
|
||||
void reformatAndDrawText(int reformatStart,
|
||||
int reformatLength,
|
||||
TextOffset selStart,
|
||||
TextOffset selEnd,
|
||||
Rectangle additionalUpdateRect,
|
||||
Color hiliteColor) {
|
||||
|
||||
Rectangle visibleBounds = fHost.getBounds();
|
||||
Rectangle redrawRect = fFormatter.updateFormat(reformatStart,
|
||||
reformatLength,
|
||||
visibleBounds,
|
||||
fOrigin);
|
||||
//System.out.println("[1] redrawRect: " + redrawRect);
|
||||
|
||||
if (additionalUpdateRect != null) {
|
||||
redrawRect.add(additionalUpdateRect);
|
||||
//System.out.println("[2] redrawRect: " + redrawRect);
|
||||
}
|
||||
|
||||
boolean haveSelection;
|
||||
|
||||
if (selStart != null && selEnd != null) {
|
||||
haveSelection = true;
|
||||
redrawRect.add(fFormatter.getBoundingRect(selStart, selEnd, fOrigin, fFormatter.LOOSE));
|
||||
//System.out.println("[3] redrawRect: " + redrawRect);
|
||||
}
|
||||
else {
|
||||
haveSelection = false;
|
||||
}
|
||||
|
||||
drawText(fHost.getGraphics(), redrawRect, haveSelection, selStart, selEnd, hiliteColor);
|
||||
}
|
||||
|
||||
private void letBehaviorDraw(Graphics g, Rectangle drawRect) {
|
||||
|
||||
boolean result = false;
|
||||
|
||||
if (fHost.fBehavior != null) {
|
||||
result = fHost.fBehavior.paint(g, drawRect);
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
drawText(g, drawRect, false, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
void moveBy(int dx, int dy) {
|
||||
|
||||
Rectangle visibleBounds = fHost.getBounds();
|
||||
Graphics g = fHost.getGraphics();
|
||||
|
||||
fBounds.x += dx;
|
||||
fBounds.y += dy;
|
||||
fOrigin.x += dx;
|
||||
fOrigin.y += dy;
|
||||
|
||||
Rectangle refreshRect = new Rectangle(visibleBounds);
|
||||
|
||||
if (dx == 0) {
|
||||
if (g != null) {
|
||||
g.copyArea(visibleBounds.x, visibleBounds.y, visibleBounds.width, visibleBounds.height, dx, dy);
|
||||
}
|
||||
if (dy < 0) {
|
||||
refreshRect.y = visibleBounds.y + visibleBounds.height + dy;
|
||||
}
|
||||
refreshRect.height = Math.abs(dy);
|
||||
//System.out.println("refreshRect=" + refreshRect);
|
||||
}
|
||||
|
||||
letBehaviorDraw(g, refreshRect);
|
||||
}
|
||||
|
||||
private Rectangle getInsetBounds() {
|
||||
|
||||
int insetDim = 2 * fInsetAmount;
|
||||
return new Rectangle(fBounds.x-fInsetAmount,
|
||||
fBounds.y-fInsetAmount,
|
||||
fBounds.width+insetDim,
|
||||
fBounds.height+insetDim);
|
||||
}
|
||||
|
||||
void paint(Graphics g) {
|
||||
|
||||
Rectangle hostBounds = fHost.getBounds();
|
||||
Rectangle textRefreshRect = hostBounds.intersection(getInsetBounds());
|
||||
letBehaviorDraw(g, textRefreshRect);
|
||||
}
|
||||
|
||||
Rectangle getCaretRect(TextOffset offset) {
|
||||
|
||||
return fFormatter.getCaretRect(offset, fOrigin);
|
||||
}
|
||||
|
||||
TextOffset pointToTextOffset(TextOffset result,
|
||||
int x,
|
||||
int y,
|
||||
TextOffset anchor,
|
||||
boolean infiniteMode) {
|
||||
|
||||
return fFormatter.pointToTextOffset(result, x, y, fOrigin, anchor, infiniteMode);
|
||||
}
|
||||
|
||||
Rectangle getScrollableArea() {
|
||||
|
||||
Rectangle area = new Rectangle(fBounds);
|
||||
area.x += fInsetAmount - fOrigin.x;
|
||||
area.y += fInsetAmount - fOrigin.y;
|
||||
return area;
|
||||
}
|
||||
|
||||
/**
|
||||
* Doesn't clone so TextComponent needs to be nice. TextComponent
|
||||
* is the only class which can access this anyway.
|
||||
*/
|
||||
Rectangle getDocumentBounds() {
|
||||
|
||||
return fBounds;
|
||||
}
|
||||
|
||||
int getDocX() {
|
||||
|
||||
return fOrigin.x - fInsetAmount;
|
||||
}
|
||||
|
||||
int getDocY() {
|
||||
|
||||
return fOrigin.y - fInsetAmount;
|
||||
}
|
||||
|
||||
int lineContaining(TextOffset offset) {
|
||||
|
||||
return fFormatter.lineContaining(offset);
|
||||
}
|
||||
|
||||
int lineRangeLow(int lineNumber) {
|
||||
|
||||
return fFormatter.lineRangeLow(lineNumber);
|
||||
}
|
||||
|
||||
int lineRangeLimit(int lineNumber) {
|
||||
|
||||
return fFormatter.lineRangeLimit(lineNumber);
|
||||
}
|
||||
|
||||
void stopBackgroundFormatting() {
|
||||
|
||||
fFormatter.stopBackgroundFormatting();
|
||||
}
|
||||
|
||||
Rectangle getBoundingRect(TextOffset offset1, TextOffset offset2) {
|
||||
|
||||
Rectangle r = fFormatter.getBoundingRect(offset1, offset2, fOrigin, fFormatter.TIGHT);
|
||||
//r.width += CARET_SLOP;
|
||||
//System.out.println("offset1="+offset1+"; offset2="+offset2);
|
||||
//System.out.println("bounds width="+r.width+"; host width="+(fHost.getBounds().width));
|
||||
return r;
|
||||
}
|
||||
|
||||
TextOffset findNewInsertionOffset(TextOffset result,
|
||||
TextOffset initialOffset,
|
||||
TextOffset previousOffset,
|
||||
short direction) {
|
||||
|
||||
return fFormatter.findNewInsertionOffset(
|
||||
result, initialOffset, previousOffset, direction);
|
||||
}
|
||||
}
|
||||
}
|
484
icu4j/src/com/ibm/richtext/textpanel/TextEditBehavior.java
Executable file
484
icu4j/src/com/ibm/richtext/textpanel/TextEditBehavior.java
Executable file
|
@ -0,0 +1,484 @@
|
|||
/*
|
||||
* @(#)$RCSfile: TextEditBehavior.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import com.ibm.textlayout.attributes.AttributeMap;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
import com.ibm.richtext.styledtext.MConstText;
|
||||
import com.ibm.richtext.styledtext.MText;
|
||||
import com.ibm.richtext.textformat.TextOffset;
|
||||
import com.ibm.richtext.styledtext.StyleModifier;
|
||||
|
||||
// All changes to the text should happen in this class, or in
|
||||
// its TypingInteractor.
|
||||
|
||||
class TextEditBehavior extends Behavior {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
private TextComponent fTextComponent;
|
||||
private TextSelection fSelection;
|
||||
private MText fText;
|
||||
private SimpleCommandLog fCommandLog;
|
||||
private PanelEventBroadcaster fListener;
|
||||
private TypingInteractor fTypingInteractor = null;
|
||||
private KeyRemap fRemap;
|
||||
|
||||
private AttributeMap fSavedTypingStyle = null;
|
||||
private int fSavedInsPt = 0;
|
||||
|
||||
public TextEditBehavior(TextComponent textComponent,
|
||||
TextSelection selection,
|
||||
PanelEventBroadcaster listener,
|
||||
KeyRemap remap) {
|
||||
|
||||
fTextComponent = textComponent;
|
||||
fSelection = selection;
|
||||
fText = textComponent.getModifiableText();
|
||||
fCommandLog = new SimpleCommandLog(listener);
|
||||
fListener = listener;
|
||||
fRemap = remap;
|
||||
}
|
||||
|
||||
public KeyRemap getKeyRemap() {
|
||||
|
||||
return fRemap;
|
||||
}
|
||||
|
||||
public void setKeyRemap(KeyRemap remap) {
|
||||
|
||||
fRemap = remap;
|
||||
}
|
||||
|
||||
public boolean textControlEventOccurred(Behavior.EventType event, Object what) {
|
||||
|
||||
boolean handled = true;
|
||||
|
||||
if (event == Behavior.CHARACTER_STYLE_MOD ||
|
||||
event == Behavior.PARAGRAPH_STYLE_MOD) {
|
||||
doStyleChange(event, what);
|
||||
}
|
||||
else if (event == Behavior.CUT) {
|
||||
doCut();
|
||||
}
|
||||
else if (event == Behavior.PASTE) {
|
||||
doPaste();
|
||||
}
|
||||
else if (event == Behavior.CLEAR) {
|
||||
doClear();
|
||||
}
|
||||
else if (event == Behavior.REPLACE) {
|
||||
doUndoableReplace((TextReplacement) what);
|
||||
}
|
||||
else if (event == Behavior.UNDO) {
|
||||
fCommandLog.undo();
|
||||
}
|
||||
else if (event == Behavior.REDO) {
|
||||
fCommandLog.redo();
|
||||
}
|
||||
else if (event == Behavior.SET_MODIFIED) {
|
||||
fCommandLog.setModified(what == Boolean.TRUE);
|
||||
}
|
||||
else if (event == Behavior.CLEAR_COMMAND_LOG) {
|
||||
fCommandLog.clearLog();
|
||||
}
|
||||
else if (event == Behavior.SET_COMMAND_LOG_SIZE) {
|
||||
fCommandLog.setLogSize(((Integer)what).intValue());
|
||||
}
|
||||
else {
|
||||
handled = super.textControlEventOccurred(event, what);
|
||||
}
|
||||
|
||||
checkSavedTypingStyle();
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
/**
|
||||
* It's unfortunate that the text is modified and reformatted in
|
||||
* three different methods. This method is the "common prologue"
|
||||
* for all text modifications.
|
||||
*
|
||||
* This method should be called before modifying and reformatting
|
||||
* the text. It does three things: stops caret blinking, stops
|
||||
* background formatting, and returns the Rectangle containing the
|
||||
* current (soon-to-be obsolete) selection.
|
||||
*/
|
||||
private Rectangle prepareForTextEdit() {
|
||||
|
||||
fSelection.stopCaretBlinking();
|
||||
fTextComponent.stopBackgroundFormatting();
|
||||
return fTextComponent.getBoundingRect(fSelection.getStart(), fSelection.getEnd());
|
||||
}
|
||||
|
||||
private void doClear() {
|
||||
TextRange selRange = fSelection.getSelectionRange();
|
||||
|
||||
if (selRange.start == selRange.limit)
|
||||
return;
|
||||
|
||||
doUndoableTextChange(selRange.start, selRange.limit, null, new TextOffset(selRange.
|
||||
start), new TextOffset(selRange.start));
|
||||
}
|
||||
|
||||
private void doCut() {
|
||||
TextRange selRange = fSelection.getSelectionRange();
|
||||
|
||||
if (selRange.start == selRange.limit)
|
||||
return;
|
||||
|
||||
fTextComponent.getClipboard().setContents(fText.extract(selRange.start, selRange.limit));
|
||||
doUndoableTextChange(selRange.start, selRange.limit, null, new TextOffset(selRange.start), new TextOffset(selRange.start));
|
||||
|
||||
fListener.textStateChanged(TextPanelEvent.CLIPBOARD_CHANGED);
|
||||
}
|
||||
|
||||
private void doPaste() {
|
||||
TextRange selRange = fSelection.getSelectionRange();
|
||||
MConstText clipText = fTextComponent.getClipboard().getContents(AttributeMap.EMPTY_ATTRIBUTE_MAP);
|
||||
|
||||
if (clipText != null) {
|
||||
doUndoableTextChange(selRange.start, selRange.limit, clipText,
|
||||
new TextOffset(selRange.start + clipText.length()),
|
||||
new TextOffset(selRange.start + clipText.length()));
|
||||
}
|
||||
else {
|
||||
fListener.textStateChanged(TextPanelEvent.CLIPBOARD_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
private void doUndoableReplace(TextReplacement replacement) {
|
||||
|
||||
doUndoableTextChange(replacement.getStart(),
|
||||
replacement.getLimit(),
|
||||
replacement.getText(),
|
||||
replacement.getSelectionStart(),
|
||||
replacement.getSelectionLimit());
|
||||
}
|
||||
|
||||
/**
|
||||
* Only TypingInteractor and TextCommand should call this!
|
||||
*/
|
||||
void doReplaceText(int start,
|
||||
int limit,
|
||||
MConstText newText,
|
||||
TextOffset newSelStart,
|
||||
TextOffset newSelEnd) {
|
||||
|
||||
int textLength;
|
||||
|
||||
fText.resetDamagedRange();
|
||||
|
||||
Rectangle oldSelRect = prepareForTextEdit();
|
||||
|
||||
if (newText == null) {
|
||||
textLength = 0;
|
||||
fText.remove(start, limit);
|
||||
}
|
||||
else {
|
||||
textLength = newText.length();
|
||||
fText.replace(start, limit, newText, 0, textLength);
|
||||
}
|
||||
fSelection.setSelectionRange(newSelStart, newSelEnd, newSelStart);
|
||||
reformatAndDrawText(fSelection.getStart(),
|
||||
fSelection.getEnd(),
|
||||
oldSelRect);
|
||||
}
|
||||
|
||||
/**
|
||||
* Only the typing interactor should call this!
|
||||
*/
|
||||
void doReplaceSelectedText(char ch, AttributeMap charStyle) {
|
||||
|
||||
int start = fSelection.getStart().fOffset;
|
||||
int limit = fSelection.getEnd().fOffset;
|
||||
TextOffset newOffset = new TextOffset(start + 1);
|
||||
doReplaceText(start, limit, ch, charStyle, newOffset, newOffset);
|
||||
}
|
||||
|
||||
private void doReplaceText(int start,
|
||||
int limit,
|
||||
char ch,
|
||||
AttributeMap charStyle,
|
||||
TextOffset newSelStart,
|
||||
TextOffset newSelEnd) {
|
||||
|
||||
fText.resetDamagedRange();
|
||||
|
||||
Rectangle oldSelRect = prepareForTextEdit();
|
||||
|
||||
fText.replace(start, limit, ch, charStyle);
|
||||
|
||||
fSelection.setSelectionRange(newSelStart, newSelEnd, newSelStart);
|
||||
reformatAndDrawText(fSelection.getStart(),
|
||||
fSelection.getEnd(),
|
||||
oldSelRect);
|
||||
}
|
||||
|
||||
private void doStyleChange(Behavior.EventType event, Object what) {
|
||||
|
||||
TextRange selRange = fSelection.getSelectionRange();
|
||||
boolean character = (event == Behavior.CHARACTER_STYLE_MOD);
|
||||
|
||||
if (selRange.start != selRange.limit || !character) {
|
||||
doUndoableStyleChange(what, character);
|
||||
}
|
||||
else {
|
||||
TypingInteractor interactor =
|
||||
new TypingInteractor(fTextComponent,
|
||||
fSelection,
|
||||
fSavedTypingStyle,
|
||||
this,
|
||||
fCommandLog,
|
||||
fListener);
|
||||
|
||||
interactor.addToOwner(fTextComponent);
|
||||
interactor.textControlEventOccurred(event, what);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Only text commands should call this method!
|
||||
*/
|
||||
void doModifyStyles(int start,
|
||||
int limit,
|
||||
StyleModifier modifier,
|
||||
boolean character,
|
||||
TextOffset newSelStart,
|
||||
TextOffset newSelEnd) {
|
||||
|
||||
fText.resetDamagedRange();
|
||||
|
||||
Rectangle oldSelRect = prepareForTextEdit();
|
||||
|
||||
if (character) {
|
||||
fText.modifyCharacterStyles(start, limit, modifier);
|
||||
}
|
||||
else {
|
||||
fText.modifyParagraphStyles(start, limit, modifier);
|
||||
}
|
||||
|
||||
fSelection.setSelectionRange(newSelStart, newSelEnd, newSelStart);
|
||||
reformatAndDrawText(newSelStart,
|
||||
newSelEnd,
|
||||
oldSelRect);
|
||||
}
|
||||
|
||||
private void doUndoableStyleChange(Object what,
|
||||
boolean character) {
|
||||
|
||||
TextOffset selStart = fSelection.getStart();
|
||||
TextOffset selEnd = fSelection.getEnd();
|
||||
|
||||
MText oldText = fText.extractWritable(selStart.fOffset, selEnd.fOffset);
|
||||
StyleChangeCommand command = new StyleChangeCommand(
|
||||
this, oldText, selStart, selEnd, (StyleModifier) what, character);
|
||||
|
||||
fCommandLog.addAndDo(command);
|
||||
|
||||
fListener.textStateChanged(TextPanelEvent.SELECTION_STYLES_CHANGED);
|
||||
}
|
||||
|
||||
private void doUndoableTextChange(int start,
|
||||
int limit,
|
||||
MConstText newText,
|
||||
TextOffset newSelStart,
|
||||
TextOffset newSelEnd) {
|
||||
|
||||
TextChangeCommand command = new TextChangeCommand(this, fText.extractWritable(start, limit),
|
||||
newText, start, fSelection.getStart(), fSelection.getEnd(),
|
||||
newSelStart, newSelEnd);
|
||||
|
||||
fCommandLog.addAndDo(command);
|
||||
}
|
||||
|
||||
public boolean canUndo() {
|
||||
|
||||
boolean canUndo = false;
|
||||
|
||||
if (fTypingInteractor != null) {
|
||||
canUndo = fTypingInteractor.hasPendingCommand();
|
||||
}
|
||||
|
||||
if (!canUndo) {
|
||||
canUndo = fCommandLog.canUndo();
|
||||
}
|
||||
|
||||
return canUndo;
|
||||
}
|
||||
|
||||
public boolean canRedo() {
|
||||
|
||||
return fCommandLog.canRedo();
|
||||
}
|
||||
|
||||
public boolean isModified() {
|
||||
|
||||
if (fTypingInteractor != null) {
|
||||
if (fTypingInteractor.hasPendingCommand()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return fCommandLog.isModified();
|
||||
}
|
||||
|
||||
public int getCommandLogSize() {
|
||||
|
||||
return fCommandLog.getLogSize();
|
||||
}
|
||||
|
||||
public AttributeMap getInsertionPointStyle() {
|
||||
|
||||
if (fTypingInteractor != null) {
|
||||
return fTypingInteractor.getTypingStyle();
|
||||
}
|
||||
|
||||
if (fSavedTypingStyle != null) {
|
||||
return fSavedTypingStyle;
|
||||
}
|
||||
|
||||
TextRange range = fSelection.getSelectionRange();
|
||||
return typingStyleAt(fText, range.start, range.limit);
|
||||
}
|
||||
|
||||
public boolean keyPressed(KeyEvent e) {
|
||||
|
||||
boolean handled = true;
|
||||
if (TypingInteractor.handledByTypingInteractor(e)) {
|
||||
TypingInteractor interactor = new TypingInteractor(fTextComponent,
|
||||
fSelection,
|
||||
fSavedTypingStyle,
|
||||
this,
|
||||
fCommandLog,
|
||||
fListener);
|
||||
|
||||
interactor.addToOwner(fTextComponent);
|
||||
interactor.keyPressed(e);
|
||||
}
|
||||
else {
|
||||
handled = super.keyPressed(e);
|
||||
checkSavedTypingStyle();
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
public boolean keyTyped(KeyEvent e) {
|
||||
|
||||
boolean handled = true;
|
||||
if (TypingInteractor.handledByTypingInteractor(e)) {
|
||||
TypingInteractor interactor = new TypingInteractor(fTextComponent,
|
||||
fSelection,
|
||||
fSavedTypingStyle,
|
||||
this,
|
||||
fCommandLog,
|
||||
fListener);
|
||||
|
||||
interactor.addToOwner(fTextComponent);
|
||||
interactor.keyTyped(e);
|
||||
}
|
||||
else {
|
||||
handled = super.keyTyped(e);
|
||||
checkSavedTypingStyle();
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
public boolean mouseReleased(MouseEvent e) {
|
||||
|
||||
boolean result = super.mouseReleased(e);
|
||||
checkSavedTypingStyle();
|
||||
return result;
|
||||
}
|
||||
|
||||
private void reformatAndDrawText(TextOffset selStart,
|
||||
TextOffset selLimit,
|
||||
Rectangle oldSelRect)
|
||||
{
|
||||
if (!fSelection.enabled()) {
|
||||
selStart = selLimit = null;
|
||||
}
|
||||
|
||||
int reformatStart = fText.damagedRangeStart();
|
||||
int reformatLength = fText.damagedRangeLimit() - reformatStart;
|
||||
|
||||
if (reformatStart != Integer.MAX_VALUE) {
|
||||
fTextComponent.reformatAndDrawText(reformatStart,
|
||||
reformatLength,
|
||||
selStart,
|
||||
selLimit,
|
||||
oldSelRect,
|
||||
fSelection.getHighlightColor());
|
||||
}
|
||||
|
||||
fSelection.scrollToShowSelection();
|
||||
|
||||
// sometimes this should send SELECTION_STYLES_CHANGED
|
||||
fListener.textStateChanged(TextPanelEvent.TEXT_CHANGED);
|
||||
|
||||
fSelection.restartCaretBlinking(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Only TypingInteractor should call this.
|
||||
*/
|
||||
void setTypingInteractor(TypingInteractor interactor) {
|
||||
fTypingInteractor = interactor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only TypingInteractor should call this.
|
||||
*/
|
||||
void setSavedTypingStyle(AttributeMap style, int insPt) {
|
||||
|
||||
fSavedTypingStyle = style;
|
||||
fSavedInsPt = insPt;
|
||||
}
|
||||
|
||||
private void checkSavedTypingStyle() {
|
||||
|
||||
if (fSavedTypingStyle != null) {
|
||||
int selStart = fSelection.getStart().fOffset;
|
||||
int selLimit = fSelection.getEnd().fOffset;
|
||||
if (selStart != fSavedInsPt || selStart != selLimit) {
|
||||
fSavedTypingStyle = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the style appropriate for typing on the given selection
|
||||
* range.
|
||||
*/
|
||||
public static AttributeMap typingStyleAt(MConstText text, int start, int limit) {
|
||||
|
||||
if (start < limit) {
|
||||
return text.characterStyleAt(start);
|
||||
}
|
||||
else if (start > 0) {
|
||||
return text.characterStyleAt(start - 1);
|
||||
}
|
||||
else {
|
||||
return text.characterStyleAt(0);
|
||||
}
|
||||
}
|
||||
}
|
543
icu4j/src/com/ibm/richtext/textpanel/TextPanel.java
Executable file
543
icu4j/src/com/ibm/richtext/textpanel/TextPanel.java
Executable file
|
@ -0,0 +1,543 @@
|
|||
/*
|
||||
* @(#)$RCSfile: TextPanel.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Panel;
|
||||
import java.awt.Scrollbar;
|
||||
|
||||
import java.awt.datatransfer.Clipboard;
|
||||
|
||||
import com.ibm.textlayout.attributes.AttributeMap;
|
||||
|
||||
import com.ibm.richtext.styledtext.StyleModifier;
|
||||
import com.ibm.richtext.styledtext.MConstText;
|
||||
import com.ibm.richtext.styledtext.StyledText;
|
||||
|
||||
/**
|
||||
* TextPanel is an implementation of MTextPanel in an AWT Panel.
|
||||
* @see MTextPanel
|
||||
*/
|
||||
public final class TextPanel extends Panel implements MTextPanel {
|
||||
|
||||
private ATextPanelImpl fImpl;
|
||||
|
||||
/**
|
||||
* Return a TextPanelSettings instance with all settings set
|
||||
* to the default values. Clients can modify this object;
|
||||
* modifications will not affect the default values.
|
||||
* @return a TextPanelSettings instance set to default values
|
||||
* @see TextPanelSettings
|
||||
*/
|
||||
public static TextPanelSettings getDefaultSettings() {
|
||||
|
||||
return ATextPanelImpl.getDefaultSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new TextPanel with the default settings.
|
||||
* @param initialText the text document. If null document text is empty.
|
||||
* @param clipboard the clipboard to use for cut, copy, and paste
|
||||
* operations. If null this panel will use a private clipboard.
|
||||
*/
|
||||
public TextPanel(MConstText initialText,
|
||||
Clipboard clipboard) {
|
||||
|
||||
this(ATextPanelImpl.fgDefaultSettings, initialText, clipboard);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new TextPanel.
|
||||
* @param settings the settings for this TextPanel
|
||||
* @param initialText the text document. If null document text is empty.
|
||||
* @param clipboard the clipboard to use for cut, copy, and paste
|
||||
* operations. If null this panel will use a private clipboard.
|
||||
* @see TextPanelSettings
|
||||
*/
|
||||
public TextPanel(TextPanelSettings settings,
|
||||
MConstText initialText,
|
||||
Clipboard clipboard) {
|
||||
|
||||
Scrollbar horzSb = null;
|
||||
Scrollbar vertSb = null;
|
||||
|
||||
if (settings.getScrollable()) {
|
||||
|
||||
setLayout(new ScrollBarLayout());
|
||||
|
||||
boolean scrollBarsVisible = settings.getScrollBarsVisible();
|
||||
|
||||
if (scrollBarsVisible) {
|
||||
horzSb = new Scrollbar(Scrollbar.HORIZONTAL);
|
||||
vertSb = new Scrollbar(Scrollbar.VERTICAL);
|
||||
add("South", horzSb);
|
||||
add("East", vertSb);
|
||||
}
|
||||
}
|
||||
else {
|
||||
setLayout(new BorderLayout());
|
||||
}
|
||||
|
||||
fImpl = new ATextPanelImpl(new RunStrategy(),
|
||||
settings,
|
||||
initialText,
|
||||
clipboard,
|
||||
this,
|
||||
horzSb,
|
||||
vertSb);
|
||||
|
||||
final FakeComponent textComponent = fImpl.getTextComponent();
|
||||
|
||||
Component textHost = new Component() {
|
||||
{
|
||||
textComponent.setHost(this);
|
||||
}
|
||||
public void addNotify() {
|
||||
super.addNotify();
|
||||
textComponent.addNotify();
|
||||
}
|
||||
public void paint(Graphics g) {
|
||||
textComponent.paint(g);
|
||||
}
|
||||
};
|
||||
|
||||
add("Center", textHost);
|
||||
|
||||
textHost.requestFocus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given TextPanelListener to the listeners which will
|
||||
* receive update notifications from this TextPanel.
|
||||
* @param listener the listener to add
|
||||
*/
|
||||
public void addListener(TextPanelListener listener) {
|
||||
|
||||
fImpl.addListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given TextPanelListener from the listeners which will
|
||||
* receive update notifications from this TextPanel.
|
||||
* @param listener the listener to remove
|
||||
*/
|
||||
public void removeListener(TextPanelListener listener) {
|
||||
|
||||
fImpl.removeListener(listener);
|
||||
}
|
||||
|
||||
//============
|
||||
// Text Access
|
||||
//============
|
||||
|
||||
/**
|
||||
* Set the document to <tt>newText</tt>. This operation
|
||||
* modifies the text in the TextPanel. It does not modify or adopt
|
||||
* <tt>newText</tt>. This method sets the selection an insertion point at
|
||||
* the end of the text.
|
||||
* @param newText the text which will replace the current text.
|
||||
*/
|
||||
public void setText(MConstText newText) {
|
||||
|
||||
fImpl.setText(newText);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the given text to the end of the document. Equivalent to
|
||||
* <tt>insert(newText, getTextLength())</tt>.
|
||||
* @param newText the text to append to the document
|
||||
*/
|
||||
public void append(MConstText newText) {
|
||||
|
||||
fImpl.append(newText);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the given text into the document at the given position.
|
||||
* Equivalent to
|
||||
* <tt>replaceRange(newText, position, position)</tt>.
|
||||
* @param newText the text to insert into the document.
|
||||
* @param position the position in the document where the
|
||||
* text will be inserted
|
||||
*/
|
||||
public void insert(MConstText newText, int position) {
|
||||
|
||||
fImpl.insert(newText, position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the given range with <tt>newText</tt>. After this
|
||||
* operation the selection range is an insertion point at the
|
||||
* end of the new text.
|
||||
* @param newText the text with which to replace the range
|
||||
* @param start the beginning of the range to replace
|
||||
* @param end the end of the range to replace
|
||||
*/
|
||||
public void replaceRange(MConstText newText, int start, int end) {
|
||||
|
||||
fImpl.replaceRange(newText, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the length of the text document in the TextPanel.
|
||||
* @return the length of the text document in the TextPanel
|
||||
*/
|
||||
public int getTextLength() {
|
||||
|
||||
return fImpl.getTextLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the text document in the TextPanel.
|
||||
* @return the text document in the TextPanel.
|
||||
*/
|
||||
public MConstText getText() {
|
||||
|
||||
return fImpl.getText();
|
||||
}
|
||||
|
||||
//============
|
||||
// Selection Access
|
||||
//============
|
||||
|
||||
/**
|
||||
* Return the offset of the start of the selection.
|
||||
*/
|
||||
public int getSelectionStart() {
|
||||
|
||||
return fImpl.getSelectionStart();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the offset of the end of the selection.
|
||||
*/
|
||||
public int getSelectionEnd() {
|
||||
|
||||
return fImpl.getSelectionEnd();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the beginning of the selection range. This is
|
||||
* equivalent to <tt>select(selectionStart, getSelectionEnd())</tt>.
|
||||
* @param selectionStart the start of the new selection range
|
||||
*/
|
||||
public void setSelectionStart(int selectionStart) {
|
||||
|
||||
fImpl.setSelectionStart(selectionStart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the end of the selection range. This is
|
||||
* equivalent to <tt>select(getSelectionStart(), selectionEnd)</tt>.
|
||||
* @param selectionStart the start of the new selection range
|
||||
*/
|
||||
public void setSelectionEnd(int selectionEnd) {
|
||||
|
||||
fImpl.setSelectionEnd(selectionEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selection range to an insertion point at the given
|
||||
* offset. This is equivalent to
|
||||
* <tt>select(position, position)</tt>.
|
||||
* @param position the offset of the new insertion point
|
||||
*/
|
||||
public void setCaretPosition(int position) {
|
||||
|
||||
fImpl.setCaretPosition(position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selection range to the given range. The range start
|
||||
* is pinned between 0 and the text length; the range end is pinned
|
||||
* between the range start and the end of the text. These semantics
|
||||
* are identical to those of <tt>java.awt.TextComponent</tt>.
|
||||
* This method has no effect if the text is not selectable.
|
||||
* @param selectionStart the beginning of the selection range
|
||||
* @param selectionEnd the end of the selection range
|
||||
*/
|
||||
public void select(int selectionStart, int selectionEnd) {
|
||||
|
||||
fImpl.select(selectionStart, selectionEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select all of the text in the document. This method has no effect if
|
||||
* the text is not selectable.
|
||||
*/
|
||||
public void selectAll() {
|
||||
|
||||
fImpl.selectAll();
|
||||
}
|
||||
|
||||
|
||||
//============
|
||||
// Format Width
|
||||
//============
|
||||
|
||||
/**
|
||||
* Return the total format width, in pixels. The format width is the
|
||||
* width to which text is wrapped.
|
||||
* @return the format width
|
||||
*/
|
||||
public int getFormatWidth() {
|
||||
|
||||
return fImpl.getFormatWidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the paragraph at the given offset is left-to-right.
|
||||
* @param offset an offset in the text
|
||||
* @return true if the paragraph at the given offset is left-to-right
|
||||
*/
|
||||
public boolean paragraphIsLeftToRight(int offset) {
|
||||
|
||||
return fImpl.paragraphIsLeftToRight(offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is a change which can be undone.
|
||||
* @return true if there is a change which can be undone.
|
||||
*/
|
||||
public boolean canUndo() {
|
||||
|
||||
return fImpl.canUndo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is a change which can be redone.
|
||||
* @return true if there is a change which can be redone.
|
||||
*/
|
||||
public boolean canRedo() {
|
||||
|
||||
return fImpl.canRedo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the clipboard contains contents which could be
|
||||
* transfered into the text.
|
||||
* @return true if the clipboard has text content.
|
||||
*/
|
||||
public boolean clipboardNotEmpty() {
|
||||
|
||||
return fImpl.clipboardNotEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an AttributeMap of keys with default values. The default
|
||||
* values are used when displaying text for values which are not
|
||||
* specified in the text.
|
||||
* @return an AttributeMap of default key-value pairs
|
||||
*/
|
||||
public AttributeMap getDefaultValues() {
|
||||
|
||||
return fImpl.getDefaultValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method inspects the character style runs in the selection
|
||||
* range (or the typing style at the insertion point). It returns:
|
||||
* <ul>
|
||||
* <li>The value of <tt>key</tt>, if the value of <tt>key</tt>
|
||||
* is the same in all of the style runs in the selection, or</li>
|
||||
* <li><tt>MULTIPLE_VALUES</tt>, if two or more style runs have different
|
||||
* values for <tt>key</tt>.</li>
|
||||
* </ul>
|
||||
* If a style run does not contain <tt>key</tt>,
|
||||
* its value is considered to be the default style for <tt>key</tt>,
|
||||
* as defined by the default values AttributeMap. Note that if
|
||||
* <tt>key</tt> does not have a default value this method may return
|
||||
* null.
|
||||
* This method is useful for configuring style menus.
|
||||
* @param key the key used to retrieve values for comparison
|
||||
* @see MTextPanel#MULTIPLE_VALUES
|
||||
*/
|
||||
public Object getCharacterStyleOverSelection(Object key) {
|
||||
|
||||
return fImpl.getCharacterStyleOverSelection(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method inspects the paragraph style runs in the selection
|
||||
* range (or the typing style at the insertion point). It returns:
|
||||
* <ul>
|
||||
* <li>The value of <tt>key</tt>, if the value of <tt>key</tt>
|
||||
* is the same in all of the style runs in the selection, or</li>
|
||||
* <li><tt>MULTIPLE_VALUES</tt>, if two or more style runs have
|
||||
* different values for <tt>key</tt>.</li>
|
||||
* </ul>
|
||||
* If a style run does not contain <tt>key</tt>,
|
||||
* its value is considered to be the default style for <tt>key</tt>,
|
||||
* as defined by the default values AttributeMap. Note that if
|
||||
* <tt>key</tt> does not have a default value this method may return
|
||||
* null.
|
||||
* This method is useful for configuring style menus.
|
||||
* @param key the key used to retrieve values for comparison
|
||||
* @see MTextPanel#MULTIPLE_VALUES
|
||||
*/
|
||||
public Object getParagraphStyleOverSelection(Object key) {
|
||||
|
||||
return fImpl.getParagraphStyleOverSelection(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the selected text from the document and place it
|
||||
* on the clipboard. This method has no effect if the text
|
||||
* is not editable, or if no text is selected.
|
||||
*/
|
||||
public void cut() {
|
||||
fImpl.cut();
|
||||
}
|
||||
|
||||
/**
|
||||
* Place the selected text on the clipboard. This method has
|
||||
* no effect if no text is selected.
|
||||
*/
|
||||
public void copy() {
|
||||
fImpl.copy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the currently selected text with the text on the clipboard.
|
||||
* This method has no effect if the text is not editable, or if no
|
||||
* text is on the clipboard.
|
||||
*/
|
||||
public void paste() {
|
||||
fImpl.paste();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove selected text from the document, without altering the clipboard.
|
||||
* This method has no effect if the
|
||||
* text is not editable.
|
||||
*/
|
||||
public void clear() {
|
||||
fImpl.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Undo the most recent text change. This method has no effect if
|
||||
* there is no change to undo.
|
||||
*/
|
||||
public void undo() {
|
||||
fImpl.undo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Redo the most recent text change. This method has no effect if
|
||||
* there is no change to redo.
|
||||
*/
|
||||
public void redo() {
|
||||
fImpl.redo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of commands the command log can hold.
|
||||
* @return the number of commands the command log can hold
|
||||
*/
|
||||
public int getCommandLogSize() {
|
||||
|
||||
return fImpl.getCommandLogSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of commands the command log can hold. All
|
||||
* redoable commands are removed when this method is called.
|
||||
* @param size the number of commands kept in the command log
|
||||
*/
|
||||
public void setCommandLogSize(int size) {
|
||||
fImpl.setCommandLogSize(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all commands from the command log.
|
||||
*/
|
||||
public void clearCommandLog() {
|
||||
fImpl.clearCommandLog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the character styles on the selected characters. If no characters
|
||||
* are selected, modify the typing style.
|
||||
* @param modifier the StyleModifier with which to modify the styles
|
||||
*/
|
||||
public void modifyCharacterStyleOnSelection(StyleModifier modifier) {
|
||||
fImpl.modifyCharacterStyleOnSelection(modifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the paragraph styles in paragraphs containing selected characters, or
|
||||
* the paragraph containing the insertion point.
|
||||
* @param modifier the StyleModifier with which to modify the styles
|
||||
*/
|
||||
public void modifyParagraphStyleOnSelection(StyleModifier modifier) {
|
||||
fImpl.modifyParagraphStyleOnSelection(modifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the KeyRemap used to process key events.
|
||||
* @return the key remap used to process key events
|
||||
* @see #setKeyRemap
|
||||
*/
|
||||
public KeyRemap getKeyRemap() {
|
||||
|
||||
return fImpl.getKeyRemap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the given KeyRemap to map key events to characters.
|
||||
* Only key
|
||||
* events are affected by the remap; other text entering the
|
||||
* control (via the clipboard, for example) is not affected
|
||||
* by the KeyRemap.
|
||||
* <p>
|
||||
* Do not pass <tt>null</tt> to this method to leave key
|
||||
* events unmapped. Instead, use <tt>KeyRemap.getIdentityRemap()</tt>
|
||||
* @param remap the KeyRemap to use for mapping key events to characters
|
||||
* @exception java.lang.NullPointerException if parameter is null
|
||||
* @see KeyRemap
|
||||
*/
|
||||
public void setKeyRemap(KeyRemap remap) {
|
||||
|
||||
fImpl.setKeyRemap(remap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the modification flag of the current text change.
|
||||
* @see #setModified
|
||||
*/
|
||||
public boolean isModified() {
|
||||
|
||||
return fImpl.isModified();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the modification flag of the current text change.
|
||||
*/
|
||||
public void setModified(boolean modified) {
|
||||
|
||||
fImpl.setModified(modified);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is for perf-testing only!
|
||||
*/
|
||||
void handleKeyEvent(java.awt.event.KeyEvent keyEvent) {
|
||||
|
||||
fImpl.handleKeyEvent(keyEvent);
|
||||
}
|
||||
}
|
157
icu4j/src/com/ibm/richtext/textpanel/TextPanelEvent.java
Executable file
157
icu4j/src/com/ibm/richtext/textpanel/TextPanelEvent.java
Executable file
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* @(#)$RCSfile: TextPanelEvent.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
import java.util.EventObject;
|
||||
|
||||
/**
|
||||
* TextPanelEvent is generated by an MTextPanel to notify listeners
|
||||
* of changes. To receive TextPanelEvents from an MTextPanel, clients
|
||||
* must implement TextPanelListener and add themselves to the MTextPanel's
|
||||
* list of listeners.
|
||||
* <p>
|
||||
* Some event types are special cases of others. This is intentional - it
|
||||
* allows notifications to be sent less often in certain common cases. For
|
||||
* example, a change in the selection range generates a SELECTION_RANGE_CHANGED
|
||||
* event. This is a very common occurrance, and if many clients listen for this
|
||||
* event, there may be a significant performance penalty. By
|
||||
* listening for a more specialized event (such as SELECTION_EMPTY_CHANGED), clients
|
||||
* can reduce the number of notifications sent.
|
||||
*
|
||||
* @see MTextPanel
|
||||
* @see TextPanelListener
|
||||
*/
|
||||
public final class TextPanelEvent extends EventObject {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
|
||||
/**
|
||||
* The lower bound of TextPanelEvent ID's.
|
||||
*/
|
||||
public static final int TEXT_PANEL_FIRST = 11;
|
||||
|
||||
/**
|
||||
* Events of this type indicate a change in the selection range.
|
||||
* This occurs quite often. Most clients do not need to be
|
||||
* notified every time the selection range changes.
|
||||
*/
|
||||
public static final int SELECTION_RANGE_CHANGED = 11;
|
||||
|
||||
/**
|
||||
* Events of this type are sent when the selection range becomes
|
||||
* 0-length after not being 0-length, or vice versa. This event
|
||||
* is a special case of SELECTION_RANGE_CHANGED.
|
||||
*/
|
||||
public static final int SELECTION_EMPTY_CHANGED = 12;
|
||||
|
||||
/**
|
||||
* Events of this type indicate that the text in the TextPanel changed.
|
||||
* This type of event occurs often.
|
||||
*/
|
||||
public static final int TEXT_CHANGED = 13;
|
||||
|
||||
/**
|
||||
* Events of this type are sent when the styles in the current
|
||||
* selection change.
|
||||
*/
|
||||
public static final int SELECTION_STYLES_CHANGED = 14;
|
||||
|
||||
/**
|
||||
* Events of this type are sent when the undo/redo state changes.
|
||||
*/
|
||||
public static final int UNDO_STATE_CHANGED = 15;
|
||||
|
||||
/**
|
||||
* Events of this type are sent when the clipboard state changes.
|
||||
*/
|
||||
public static final int CLIPBOARD_CHANGED = 16;
|
||||
|
||||
/**
|
||||
* Events of this type are sent when
|
||||
* the wrap width of the text changes.
|
||||
*/
|
||||
public static final int FORMAT_WIDTH_CHANGED = 17;
|
||||
|
||||
/**
|
||||
* Events of this type are sent when the key remap changes.
|
||||
*/
|
||||
public static final int KEYREMAP_CHANGED = 18;
|
||||
|
||||
/**
|
||||
* The upper bound of TextPanelEvent ID's.
|
||||
*/
|
||||
public static final int TEXT_PANEL_LAST = 18;
|
||||
|
||||
private int fId;
|
||||
|
||||
/**
|
||||
* Create a new TextPanelEvent.
|
||||
* @param source the MTextPanel which generated the event
|
||||
* @param id the ID for this event. Must be within
|
||||
* [TEXT_PANEL_FIRST, TEXT_PANEL_LAST].
|
||||
*/
|
||||
TextPanelEvent(MTextPanel source, int id) {
|
||||
|
||||
super(source);
|
||||
if (id < TEXT_PANEL_FIRST || id > TEXT_PANEL_LAST) {
|
||||
throw new IllegalArgumentException("id out of range");
|
||||
}
|
||||
fId = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the event ID for this event. Event ID's are
|
||||
* one of the class constants.
|
||||
* @return the event ID for this event
|
||||
*/
|
||||
public int getID() {
|
||||
|
||||
return fId;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
|
||||
String desc = null;
|
||||
|
||||
switch(fId) {
|
||||
case SELECTION_RANGE_CHANGED:
|
||||
desc = "SELECTION_RANGE_CHANGED";
|
||||
break;
|
||||
case SELECTION_EMPTY_CHANGED:
|
||||
desc = "SELECTION_EMPTY_CHANGED";
|
||||
break;
|
||||
case TEXT_CHANGED:
|
||||
desc = "TEXT_CHANGED";
|
||||
break;
|
||||
case SELECTION_STYLES_CHANGED:
|
||||
desc = "SELECTION_STYLES_CHANGED";
|
||||
break;
|
||||
case UNDO_STATE_CHANGED:
|
||||
desc = "UNDO_STATE_CHANGED";
|
||||
break;
|
||||
case CLIPBOARD_CHANGED:
|
||||
desc = "CLIPBOARD_CHANGED";
|
||||
break;
|
||||
case FORMAT_WIDTH_CHANGED:
|
||||
desc = "FORMAT_WIDTH_CHANGED";
|
||||
break;
|
||||
case KEYREMAP_CHANGED:
|
||||
desc = "KEYREMAP_CHANGED";
|
||||
break;
|
||||
}
|
||||
return "[TextPanelEvent:"+desc+"]";
|
||||
}
|
||||
}
|
42
icu4j/src/com/ibm/richtext/textpanel/TextPanelListener.java
Executable file
42
icu4j/src/com/ibm/richtext/textpanel/TextPanelListener.java
Executable file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* @(#)$RCSfile: TextPanelListener.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
/**
|
||||
* This interface is implemented by classes which
|
||||
* receive change notifications from an MTextPanel.
|
||||
* @see MTextPanel
|
||||
* @see TextPanelEvent
|
||||
*/
|
||||
public interface TextPanelListener {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
/**
|
||||
* Notify listener of an MTextPanel change.
|
||||
* @param event a TextPanelEvent indicating what happened
|
||||
*/
|
||||
public void textEventOccurred(TextPanelEvent event);
|
||||
|
||||
/**
|
||||
* Return true if listener needs to be notified of
|
||||
* the given event type. This allows a text panel to avoid
|
||||
* sending events to uninterested parties.
|
||||
* @param type an event ID from TextPanelEvent
|
||||
* @return true if this listener needs to be notified of
|
||||
* events of the given type
|
||||
*/
|
||||
public boolean respondsToEventType(int type);
|
||||
}
|
283
icu4j/src/com/ibm/richtext/textpanel/TextPanelSettings.java
Executable file
283
icu4j/src/com/ibm/richtext/textpanel/TextPanelSettings.java
Executable file
|
@ -0,0 +1,283 @@
|
|||
/*
|
||||
* @(#)$RCSfile: TextPanelSettings.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.io.Serializable;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import com.ibm.textlayout.attributes.AttributeMap;
|
||||
import com.ibm.textlayout.attributes.TextAttribute;
|
||||
import com.ibm.richtext.styledtext.StandardTabRuler;
|
||||
|
||||
/**
|
||||
* This class contains settings used when constructing an MTextPanel.
|
||||
* The settings controled by this class include:
|
||||
* <ul>
|
||||
* <li>whether the text in the MTextPanel can be scrolled</li>
|
||||
* <li>whether scroll bars in the MTextPanel are visible</li>
|
||||
* <li>whether the text in the MTextPanel can be selected</li>
|
||||
* <li>whether the text in the MTextPanel can be edited</li>
|
||||
* <li>whether lines of text wrap to the MTextPanel's width, or
|
||||
* only end at paragraph separators</li>
|
||||
* <li>the default values for unspecified styles</li>
|
||||
* </ul>
|
||||
* Some settings are dependent on others. Scroll bars are visible
|
||||
* only if the text is scrollable. Also, text which is not editable
|
||||
* if it is not selectable.
|
||||
* <p>
|
||||
*
|
||||
* @see MTextPanel
|
||||
*/
|
||||
public final class TextPanelSettings implements Cloneable, Serializable {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
|
||||
private static final AttributeMap DEFAULTS;
|
||||
static {
|
||||
final Float floatZero = new Float(0.0f);
|
||||
|
||||
Hashtable defaults = new Hashtable();
|
||||
defaults.put(TextAttribute.FAMILY, "Serif");
|
||||
defaults.put(TextAttribute.WEIGHT, new Float(1.0f));
|
||||
defaults.put(TextAttribute.POSTURE, floatZero);
|
||||
defaults.put(TextAttribute.SIZE, new Float(18.0f));
|
||||
defaults.put(TextAttribute.SUPERSCRIPT, new Integer(0));
|
||||
defaults.put(TextAttribute.FOREGROUND, Color.black);
|
||||
defaults.put(TextAttribute.UNDERLINE, new Integer(-1));
|
||||
defaults.put(TextAttribute.STRIKETHROUGH, Boolean.FALSE);
|
||||
|
||||
defaults.put(TextAttribute.EXTRA_LINE_SPACING, floatZero);
|
||||
defaults.put(TextAttribute.FIRST_LINE_INDENT, floatZero);
|
||||
defaults.put(TextAttribute.MIN_LINE_SPACING, floatZero);
|
||||
defaults.put(TextAttribute.LINE_FLUSH, TextAttribute.FLUSH_LEADING);
|
||||
defaults.put(TextAttribute.LEADING_MARGIN, floatZero);
|
||||
defaults.put(TextAttribute.TRAILING_MARGIN, floatZero);
|
||||
defaults.put(TextAttribute.TAB_RULER, new StandardTabRuler());
|
||||
|
||||
DEFAULTS = new AttributeMap(defaults);
|
||||
}
|
||||
|
||||
private boolean fScrollable = true;
|
||||
private boolean fScrollBarsVisible = true;
|
||||
private boolean fSelectable = true;
|
||||
private boolean fEditable = true;
|
||||
private boolean fWraps = true;
|
||||
private AttributeMap fDefaultValues = DEFAULTS;
|
||||
|
||||
/**
|
||||
* Create a TextPanelSettings instance with all settings
|
||||
* set to true.
|
||||
*/
|
||||
public TextPanelSettings() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new TextPanelSettings instance with the
|
||||
* same settings as this.
|
||||
* @return a new TextPanelSettings instance
|
||||
*/
|
||||
public Object clone() {
|
||||
|
||||
TextPanelSettings rhs = new TextPanelSettings();
|
||||
|
||||
rhs.fScrollable = fScrollable;
|
||||
rhs.fScrollBarsVisible = fScrollBarsVisible;
|
||||
rhs.fSelectable = fSelectable;
|
||||
rhs.fEditable = fEditable;
|
||||
rhs.fWraps = fWraps;
|
||||
rhs.fDefaultValues = fDefaultValues;
|
||||
|
||||
return rhs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the scrollable setting, which determines whether text
|
||||
* in an MTextPanel can be scrolled.
|
||||
* @return the scrollable setting
|
||||
*/
|
||||
public boolean getScrollable() {
|
||||
|
||||
return fScrollable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the scrollable setting.
|
||||
* @param scrollable the scrollable setting. If false,
|
||||
* the scrollBarsVisible setting is also set to false.
|
||||
*/
|
||||
public void setScrollable(boolean scrollable) {
|
||||
|
||||
fScrollable = scrollable;
|
||||
fScrollBarsVisible &= scrollable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the scrollBarsVisible setting, which determines whether
|
||||
* scroll bars in an MTextPanel are visible.
|
||||
* @return the scrollBarsVisible setting
|
||||
*/
|
||||
public boolean getScrollBarsVisible() {
|
||||
|
||||
return fScrollBarsVisible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the scrollBarsVisible setting.
|
||||
* @param vis the scrollBarsVisible setting. If true,
|
||||
* the scrollable setting is also set to true.
|
||||
*/
|
||||
public void setScrollBarsVisible(boolean vis) {
|
||||
|
||||
fScrollBarsVisible = vis;
|
||||
fScrollable |= vis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the selectable setting, which determines whether
|
||||
* text in an MTextPanel can be selected.
|
||||
* @return the selectable setting
|
||||
*/
|
||||
public boolean getSelectable() {
|
||||
|
||||
return fSelectable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selectable setting.
|
||||
* @param selectable the selectable setting. If false,
|
||||
* the editable setting is also set to false.
|
||||
*/
|
||||
public void setSelectable(boolean selectable) {
|
||||
|
||||
fSelectable = selectable;
|
||||
fEditable &= selectable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the editable setting, which determines whether
|
||||
* text in an MTextPanel can be edited.
|
||||
* @return the editable setting
|
||||
*/
|
||||
public boolean getEditable() {
|
||||
|
||||
return fEditable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the editable setting.
|
||||
* @param selectable the selectable setting. If true,
|
||||
* the selectable setting is also set to true.
|
||||
*/
|
||||
public void setEditable(boolean editable) {
|
||||
|
||||
fEditable = editable;
|
||||
fSelectable |= editable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the wraps setting, which determines whether
|
||||
* lines of text wrap to the length of the MTextPanel,
|
||||
* or only at paragraph separators.
|
||||
* @return the wraps setting
|
||||
*/
|
||||
public boolean getWraps() {
|
||||
|
||||
return fWraps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the wraps setting.
|
||||
* @param wraps the wraps setting
|
||||
*/
|
||||
public void setWraps(boolean wraps) {
|
||||
|
||||
fWraps = wraps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the AttributeMap of default values for certain keys.
|
||||
* When a key in this AttributeMap is not specified, its value
|
||||
* is taken from this AttributeMap.
|
||||
* @return the AttributeMap of default values
|
||||
* @see MTextPanel#getDefaultValues
|
||||
*/
|
||||
public AttributeMap getDefaultValues() {
|
||||
|
||||
return fDefaultValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the key-value pairs in the given AttributeMap to the
|
||||
* default values. If a key does not appear in the given
|
||||
* AttributeMap, its value in the default value map is
|
||||
* unchanged.
|
||||
* @param map an AttributeMap containing new default values
|
||||
*/
|
||||
public void addDefaultValues(AttributeMap map) {
|
||||
|
||||
fDefaultValues = fDefaultValues.addAttributes(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare this to another Object. This is equal
|
||||
* to another Object if the other Object is a
|
||||
* TextPanelSettings instance with the same
|
||||
* settings as this one.
|
||||
* @param rhs the Object to compare to
|
||||
*/
|
||||
public boolean equals(Object rhs) {
|
||||
|
||||
if (rhs == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rhs == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TextPanelSettings other;
|
||||
try {
|
||||
other = (TextPanelSettings) rhs;
|
||||
}
|
||||
catch(ClassCastException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return other.fScrollable == this.fScrollable &&
|
||||
other.fScrollBarsVisible == this.fScrollBarsVisible &&
|
||||
other.fSelectable == this.fSelectable &&
|
||||
other.fEditable == this.fEditable &&
|
||||
other.fWraps == this.fWraps &&
|
||||
other.fDefaultValues.equals(this.fDefaultValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hash code for this Object.
|
||||
* @return the hash code for this Object
|
||||
*/
|
||||
public int hashCode() {
|
||||
|
||||
int code = fDefaultValues.hashCode();
|
||||
code = code*2 + (fScrollable? 1:0);
|
||||
code = code*2 + (fScrollBarsVisible? 1:0);
|
||||
code = code*2 + (fSelectable? 1:0);
|
||||
code = code*2 + (fEditable? 1:0);
|
||||
code = code*2 + (fWraps? 1:0);
|
||||
|
||||
return code;
|
||||
}
|
||||
}
|
47
icu4j/src/com/ibm/richtext/textpanel/TextRange.java
Executable file
47
icu4j/src/com/ibm/richtext/textpanel/TextRange.java
Executable file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* @(#)$RCSfile: TextRange.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
/**
|
||||
* A <TT>TextRange</TT> represents a range of text bounded by a
|
||||
* start (inclusive), and a limit (exclusive). [start,limit)
|
||||
*/
|
||||
final class TextRange
|
||||
{
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
/** the start of the range */
|
||||
public int start = 0;
|
||||
/** the end of the range */
|
||||
public int limit = 0;
|
||||
|
||||
/**
|
||||
* Create a text range from two ints.
|
||||
* @param start the start of the run
|
||||
* @param limit the end of the run
|
||||
*/
|
||||
public TextRange(int start, int limit)
|
||||
{
|
||||
this.start = start;
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a text range of 0, 0.
|
||||
*/
|
||||
public TextRange() {
|
||||
this.start = this.limit = 0;
|
||||
}
|
||||
}
|
70
icu4j/src/com/ibm/richtext/textpanel/TextReplacement.java
Executable file
70
icu4j/src/com/ibm/richtext/textpanel/TextReplacement.java
Executable file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* @(#)$RCSfile: TextReplacement.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
import com.ibm.richtext.styledtext.MConstText;
|
||||
import com.ibm.richtext.textformat.TextOffset;
|
||||
|
||||
/**
|
||||
* This class is used to pass a REPLACE command to Behaviors.
|
||||
*/
|
||||
final class TextReplacement {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
private int fStart;
|
||||
private int fLimit;
|
||||
private MConstText fText;
|
||||
private TextOffset fSelStart;
|
||||
private TextOffset fSelLimit;
|
||||
|
||||
TextReplacement(int start,
|
||||
int limit,
|
||||
MConstText text,
|
||||
TextOffset selStart,
|
||||
TextOffset selLimit) {
|
||||
|
||||
fStart = start;
|
||||
fLimit = limit;
|
||||
fText = text;
|
||||
fSelStart = selStart;
|
||||
fSelLimit = selLimit;
|
||||
}
|
||||
|
||||
int getStart() {
|
||||
|
||||
return fStart;
|
||||
}
|
||||
|
||||
int getLimit() {
|
||||
|
||||
return fLimit;
|
||||
}
|
||||
|
||||
MConstText getText() {
|
||||
|
||||
return fText;
|
||||
}
|
||||
|
||||
TextOffset getSelectionStart() {
|
||||
|
||||
return fSelStart;
|
||||
}
|
||||
|
||||
TextOffset getSelectionLimit() {
|
||||
|
||||
return fSelLimit;
|
||||
}
|
||||
}
|
926
icu4j/src/com/ibm/richtext/textpanel/TextSelection.java
Executable file
926
icu4j/src/com/ibm/richtext/textpanel/TextSelection.java
Executable file
|
@ -0,0 +1,926 @@
|
|||
/*
|
||||
* @(#)$RCSfile: TextSelection.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
/*
|
||||
7/1/97 - caret blinks
|
||||
|
||||
7/3/97 - fAnchor is no longer restricted to the start or end of the selection. {jbr}
|
||||
Also, removed fVisible - it was identical to enabled().
|
||||
*/
|
||||
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Color;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Point;
|
||||
|
||||
import java.text.BreakIterator;
|
||||
import java.text.CharacterIterator;
|
||||
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.FocusEvent;
|
||||
|
||||
import com.ibm.richtext.styledtext.MConstText;
|
||||
import com.ibm.richtext.textformat.TextOffset;
|
||||
|
||||
import com.ibm.richtext.textformat.MFormatter;
|
||||
|
||||
class TextSelection extends Behavior implements Runnable {
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
static final Color HIGHLIGHTCOLOR = Color.pink;
|
||||
|
||||
private TextComponent fTextComponent;
|
||||
private MConstText fText;
|
||||
private TextOffset fStart;
|
||||
private TextOffset fLimit;
|
||||
private TextOffset fAnchor;
|
||||
private TextOffset fUpDownAnchor = null;
|
||||
private BreakIterator fBoundaries = null;
|
||||
private Color fHighlightColor = HIGHLIGHTCOLOR;
|
||||
private PanelEventBroadcaster fListener;
|
||||
private RunStrategy fRunStrategy;
|
||||
private boolean fMouseDown = false;
|
||||
private boolean fHandlingKeyOrCommand = false;
|
||||
|
||||
private boolean fCaretShouldBlink;
|
||||
private boolean fCaretIsVisible;
|
||||
private int fCaretCount;
|
||||
|
||||
// formerly in base class
|
||||
private boolean fEnabled;
|
||||
|
||||
private MouseEvent fPendingMouseEvent = null;
|
||||
|
||||
private static final int kCaretInterval = 500;
|
||||
|
||||
public void run() {
|
||||
|
||||
final Runnable blinkCaret = new Runnable() {
|
||||
public void run() {
|
||||
fCaretIsVisible = !fCaretIsVisible;
|
||||
Graphics g = fTextComponent.getGraphics();
|
||||
if (g != null) {
|
||||
//System.out.println("caretIsVisible: " + fCaretIsVisible);
|
||||
drawSelection(g, fCaretIsVisible);
|
||||
}
|
||||
else {
|
||||
// Not sure what else to do:
|
||||
fCaretShouldBlink = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// blink caret
|
||||
while (true) {
|
||||
|
||||
synchronized(this) {
|
||||
|
||||
while (!fCaretShouldBlink) {
|
||||
try {
|
||||
wait();
|
||||
}
|
||||
catch(InterruptedException e) {
|
||||
System.out.println("Caught InterruptedException in caret thread.");
|
||||
}
|
||||
}
|
||||
|
||||
++fCaretCount;
|
||||
|
||||
if (fCaretCount % 2 == 0) {
|
||||
fRunStrategy.doIt(blinkCaret);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(kCaretInterval);
|
||||
}
|
||||
catch(InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public TextSelection(TextComponent textComponent,
|
||||
PanelEventBroadcaster listener,
|
||||
RunStrategy runStrategy) {
|
||||
|
||||
fTextComponent = textComponent;
|
||||
fText = textComponent.getText();
|
||||
fListener = listener;
|
||||
fRunStrategy = runStrategy;
|
||||
|
||||
fStart = new TextOffset();
|
||||
fLimit = new TextOffset();
|
||||
fAnchor = new TextOffset();
|
||||
fMouseDown = false;
|
||||
|
||||
fCaretCount = 0;
|
||||
fCaretIsVisible = true;
|
||||
fCaretShouldBlink = false;
|
||||
setEnabled(false);
|
||||
|
||||
Thread caretThread = new Thread(this);
|
||||
caretThread.setDaemon(true);
|
||||
caretThread.start();
|
||||
}
|
||||
|
||||
boolean enabled() {
|
||||
|
||||
return fEnabled;
|
||||
}
|
||||
|
||||
private void setEnabled(boolean enabled) {
|
||||
|
||||
fEnabled = enabled;
|
||||
}
|
||||
|
||||
public boolean textControlEventOccurred(Behavior.EventType event, Object what) {
|
||||
|
||||
boolean result;
|
||||
fHandlingKeyOrCommand = true;
|
||||
|
||||
if (event == Behavior.SELECT) {
|
||||
select((TextRange) what);
|
||||
result = true;
|
||||
}
|
||||
else if (event == Behavior.COPY) {
|
||||
fTextComponent.getClipboard().setContents(fText.extract(fStart.fOffset, fLimit.fOffset));
|
||||
fListener.textStateChanged(TextPanelEvent.CLIPBOARD_CHANGED);
|
||||
result = true;
|
||||
}
|
||||
else {
|
||||
result = false;
|
||||
}
|
||||
|
||||
fHandlingKeyOrCommand = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void advanceToNextBoundary(TextOffset offset) {
|
||||
|
||||
// If there's no boundaries object, or if position at the end of the
|
||||
// document, return the offset unchanged
|
||||
if (fBoundaries == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int position = offset.fOffset;
|
||||
|
||||
if (position >= fText.length()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If position is at a boundary and offset is before position,
|
||||
// leave it unchanged. Otherwise move to next boundary.
|
||||
int nextPos = fBoundaries.following(position);
|
||||
if (fBoundaries.previous() == position &&
|
||||
offset.fPlacement==offset.BEFORE_OFFSET) {
|
||||
return;
|
||||
}
|
||||
|
||||
offset.setOffset(nextPos, TextOffset.AFTER_OFFSET);
|
||||
}
|
||||
|
||||
protected void advanceToPreviousBoundary(TextOffset offset) {
|
||||
|
||||
advanceToPreviousBoundary(offset, false);
|
||||
}
|
||||
|
||||
private void advanceToPreviousBoundary(TextOffset offset, boolean alwaysMove) {
|
||||
// if there's no boundaries object, or if we're sitting at the beginning
|
||||
// of the document, return the offset unchanged
|
||||
if (fBoundaries == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int position = offset.fOffset;
|
||||
|
||||
if (position == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If position is at a boundary, leave it unchanged. Otherwise
|
||||
// move to previous boundary.
|
||||
if (position == fText.length()) {
|
||||
fBoundaries.last();
|
||||
}
|
||||
else {
|
||||
fBoundaries.following(position);
|
||||
}
|
||||
|
||||
int prevPos = fBoundaries.previous();
|
||||
|
||||
if (prevPos == position) {
|
||||
if (!alwaysMove && offset.fPlacement==offset.AFTER_OFFSET) {
|
||||
return;
|
||||
}
|
||||
|
||||
prevPos = fBoundaries.previous();
|
||||
}
|
||||
|
||||
// and finally update the real offset with this new position we've found
|
||||
offset.setOffset(prevPos, TextOffset.AFTER_OFFSET);
|
||||
}
|
||||
|
||||
private void doArrowKey(KeyEvent e, int key) {
|
||||
|
||||
// when there's a selection range, the left and up arrow keys place an
|
||||
// insertion point at the beginning of the range, and the right and down
|
||||
// keys place an insertion point at the end of the range (unless the shift
|
||||
// key is down, of course)
|
||||
|
||||
if (!fStart.equals(fLimit) && !e.isShiftDown()) {
|
||||
if (key == KeyEvent.VK_LEFT || key == KeyEvent.VK_UP)
|
||||
setSelRangeAndDraw(fStart, fStart, fStart);
|
||||
else
|
||||
setSelRangeAndDraw(fLimit, fLimit, fLimit);
|
||||
}
|
||||
else {
|
||||
if (!fAnchor.equals(fStart))
|
||||
fAnchor.assign(fLimit);
|
||||
|
||||
TextOffset liveEnd = (fStart.equals(fAnchor)) ? fLimit : fStart;
|
||||
TextOffset newPos = new TextOffset();
|
||||
|
||||
// if the control key is down, the left and right arrow keys move by whole
|
||||
// word in the appropriate direction (we use a line break object so that we're
|
||||
// not treating spaces and punctuation as words)
|
||||
if (e.isControlDown() && (key == KeyEvent.VK_LEFT || key == KeyEvent.VK_RIGHT)) {
|
||||
fUpDownAnchor = null;
|
||||
fBoundaries = BreakIterator.getLineInstance();
|
||||
fBoundaries.setText(fText.createCharacterIterator());
|
||||
|
||||
newPos.assign(liveEnd);
|
||||
if (key == KeyEvent.VK_RIGHT)
|
||||
advanceToNextBoundary(newPos);
|
||||
else
|
||||
advanceToPreviousBoundary(newPos, true);
|
||||
}
|
||||
|
||||
// if we get down to here, this is a plain-vanilla insertion-point move,
|
||||
// or the shift key is down and we're extending or shortening the selection
|
||||
else {
|
||||
|
||||
// fUpDownAnchor is used to keep track of the horizontal position
|
||||
// across a run of up or down arrow keys (this prevents accumulated
|
||||
// error from destroying our horizontal position)
|
||||
if (key == KeyEvent.VK_LEFT || key == KeyEvent.VK_RIGHT)
|
||||
fUpDownAnchor = null;
|
||||
else {
|
||||
if (fUpDownAnchor == null) {
|
||||
fUpDownAnchor = new TextOffset(liveEnd);
|
||||
}
|
||||
}
|
||||
|
||||
short direction = MFormatter.eRight; // just to have a default...
|
||||
|
||||
switch (key) {
|
||||
case KeyEvent.VK_UP: direction = MFormatter.eUp; break;
|
||||
case KeyEvent.VK_DOWN: direction = MFormatter.eDown; break;
|
||||
case KeyEvent.VK_LEFT: direction = MFormatter.eLeft; break;
|
||||
case KeyEvent.VK_RIGHT: direction = MFormatter.eRight; break;
|
||||
}
|
||||
|
||||
// use the formatter to determine the actual effect of the arrow key
|
||||
fTextComponent.findNewInsertionOffset(newPos, fUpDownAnchor, liveEnd, direction);
|
||||
}
|
||||
|
||||
// if the shift key is down, the selection range is from the anchor point
|
||||
// the site of the last insertion point or the beginning point of the last
|
||||
// selection drag operation) to the newly-calculated position; if the
|
||||
// shift key is down, the newly-calculated position is the insertion point position
|
||||
if (!e.isShiftDown())
|
||||
setSelRangeAndDraw(newPos, newPos, newPos);
|
||||
else {
|
||||
if (newPos.lessThan(fAnchor))
|
||||
setSelRangeAndDraw(newPos, fAnchor, fAnchor);
|
||||
else
|
||||
setSelRangeAndDraw(fAnchor, newPos, fAnchor);
|
||||
}
|
||||
}
|
||||
|
||||
scrollToShowSelectionEnd();
|
||||
fBoundaries = null;
|
||||
}
|
||||
|
||||
private void doEndKey(KeyEvent e) {
|
||||
// ctrl-end moves the insertsion point to the end of the document,
|
||||
// ctrl-shift-end extends the selection so that it ends at the end
|
||||
// of the document
|
||||
|
||||
TextOffset activeEnd, anchor;
|
||||
|
||||
if (fAnchor.equals(fStart)) {
|
||||
activeEnd = new TextOffset(fStart);
|
||||
anchor = new TextOffset(fLimit);
|
||||
}
|
||||
else {
|
||||
activeEnd = new TextOffset(fLimit);
|
||||
anchor = new TextOffset(fStart);
|
||||
}
|
||||
|
||||
if (e.isControlDown()) {
|
||||
TextOffset end = new TextOffset(fText.length(), TextOffset.BEFORE_OFFSET);
|
||||
|
||||
if (e.isShiftDown())
|
||||
setSelRangeAndDraw(anchor, end, anchor);
|
||||
else
|
||||
setSelRangeAndDraw(end, end, end);
|
||||
}
|
||||
|
||||
// end moves the insertion point to the end of the line containing
|
||||
// the end of the current selection
|
||||
// shift-end extends the selection to the end of the line containing
|
||||
// the end of the current selection
|
||||
|
||||
else {
|
||||
|
||||
int oldOffset = activeEnd.fOffset;
|
||||
|
||||
activeEnd.fOffset = fTextComponent.lineRangeLimit(fTextComponent.lineContaining(activeEnd));
|
||||
activeEnd.fPlacement = TextOffset.BEFORE_OFFSET;
|
||||
|
||||
if (fText.paragraphLimit(oldOffset) == activeEnd.fOffset &&
|
||||
activeEnd.fOffset != fText.length() && activeEnd.fOffset > oldOffset) {
|
||||
activeEnd.fOffset--;
|
||||
activeEnd.fPlacement = TextOffset.AFTER_OFFSET;
|
||||
}
|
||||
|
||||
if (!e.isShiftDown())
|
||||
setSelRangeAndDraw(activeEnd, activeEnd, activeEnd);
|
||||
else {
|
||||
if (activeEnd.lessThan(anchor))
|
||||
setSelRangeAndDraw(activeEnd, anchor, anchor);
|
||||
else
|
||||
setSelRangeAndDraw(anchor, activeEnd, anchor);
|
||||
}
|
||||
}
|
||||
|
||||
scrollToShowSelectionEnd();
|
||||
fBoundaries = null;
|
||||
fUpDownAnchor = null;
|
||||
}
|
||||
|
||||
private void doHomeKey(KeyEvent e) {
|
||||
// ctrl-home moves the insertion point to the beginning of the document,
|
||||
// ctrl-shift-home extends the selection so that it begins at the beginning
|
||||
// of the document
|
||||
|
||||
TextOffset activeEnd, anchor;
|
||||
|
||||
if (fAnchor.equals(fStart)) {
|
||||
activeEnd = new TextOffset(fStart);
|
||||
anchor = new TextOffset(fLimit);
|
||||
}
|
||||
else {
|
||||
activeEnd = new TextOffset(fLimit);
|
||||
anchor = new TextOffset(fStart);
|
||||
}
|
||||
|
||||
if (e.isControlDown()) {
|
||||
|
||||
TextOffset start = new TextOffset(0, TextOffset.AFTER_OFFSET);
|
||||
if (e.isShiftDown())
|
||||
setSelRangeAndDraw(start, anchor, anchor);
|
||||
else
|
||||
setSelRangeAndDraw(start, start, start);
|
||||
}
|
||||
|
||||
// home moves the insertion point to the beginning of the line containing
|
||||
// the beginning of the current selection
|
||||
// shift-home extends the selection to the beginning of the line containing
|
||||
// the beginning of the current selection
|
||||
|
||||
else {
|
||||
|
||||
activeEnd.fOffset = fTextComponent.lineRangeLow(fTextComponent.lineContaining(activeEnd));
|
||||
activeEnd.fPlacement = TextOffset.AFTER_OFFSET;
|
||||
|
||||
if (!e.isShiftDown())
|
||||
setSelRangeAndDraw(activeEnd, activeEnd, activeEnd);
|
||||
else {
|
||||
if (activeEnd.lessThan(anchor))
|
||||
setSelRangeAndDraw(activeEnd, anchor, anchor);
|
||||
else
|
||||
setSelRangeAndDraw(anchor, activeEnd, anchor);
|
||||
}
|
||||
}
|
||||
|
||||
scrollToShowSelectionEnd();
|
||||
fBoundaries = null;
|
||||
fUpDownAnchor = null;
|
||||
}
|
||||
|
||||
/** draws or erases the current selection
|
||||
* Draws or erases the highlight region or insertion caret for the current selection
|
||||
* range.
|
||||
* @param g The graphics environment to draw into
|
||||
* @param visible If true, draw the selection; if false, erase it
|
||||
*/
|
||||
protected void drawSelection(Graphics g, boolean visible) {
|
||||
drawSelectionRange(g, fStart, fLimit, visible);
|
||||
}
|
||||
|
||||
/** draws or erases a selection highlight at the specfied positions
|
||||
* Draws or erases a selection highlight or insertion caret corresponding to
|
||||
* the specified selecion range
|
||||
* @param g The graphics environment to draw into. If null, this method does nothing.
|
||||
* @param start The beginning of the range to highlight
|
||||
* @param limit The end of the range to highlight
|
||||
* @param vsible If true, draw; if false, erase
|
||||
*/
|
||||
protected void drawSelectionRange( Graphics g,
|
||||
TextOffset start,
|
||||
TextOffset limit,
|
||||
boolean visible) {
|
||||
if (g == null) {
|
||||
return;
|
||||
}
|
||||
Rectangle selBounds = fTextComponent.getBoundingRect(start, limit);
|
||||
|
||||
selBounds.width = Math.max(1, selBounds.width);
|
||||
selBounds.height = Math.max(1, selBounds.height);
|
||||
|
||||
fTextComponent.drawText(g, selBounds, visible, start, limit, fHighlightColor);
|
||||
}
|
||||
|
||||
protected TextOffset getAnchor() {
|
||||
return fAnchor;
|
||||
}
|
||||
|
||||
public TextOffset getEnd() {
|
||||
return fLimit;
|
||||
}
|
||||
|
||||
public Color getHighlightColor() {
|
||||
return fHighlightColor;
|
||||
}
|
||||
|
||||
public TextOffset getStart() {
|
||||
return fStart;
|
||||
}
|
||||
|
||||
public TextRange getSelectionRange() {
|
||||
|
||||
return new TextRange(fStart.fOffset, fLimit.fOffset);
|
||||
}
|
||||
|
||||
public boolean focusGained(FocusEvent e) {
|
||||
|
||||
setEnabled(true);
|
||||
drawSelection(fTextComponent.getGraphics(), true);
|
||||
|
||||
restartCaretBlinking(true);
|
||||
if (fPendingMouseEvent != null) {
|
||||
mousePressed(fPendingMouseEvent);
|
||||
fPendingMouseEvent = null;
|
||||
}
|
||||
fListener.textStateChanged(TextPanelEvent.CLIPBOARD_CHANGED);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean focusLost(FocusEvent e) {
|
||||
stopCaretBlinking();
|
||||
setEnabled(false);
|
||||
drawSelection(fTextComponent.getGraphics(), false);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given key event can affect the selection
|
||||
* range.
|
||||
*/
|
||||
public static boolean keyAffectsSelection(KeyEvent e) {
|
||||
|
||||
if (e.getID() != e.KEY_PRESSED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int key = e.getKeyCode();
|
||||
|
||||
switch (key) {
|
||||
case KeyEvent.VK_HOME:
|
||||
case KeyEvent.VK_END:
|
||||
case KeyEvent.VK_LEFT:
|
||||
case KeyEvent.VK_RIGHT:
|
||||
case KeyEvent.VK_UP:
|
||||
case KeyEvent.VK_DOWN:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean keyPressed(KeyEvent e) {
|
||||
|
||||
fHandlingKeyOrCommand = true;
|
||||
int key = e.getKeyCode();
|
||||
boolean result = true;
|
||||
|
||||
switch (key) {
|
||||
case KeyEvent.VK_HOME:
|
||||
doHomeKey(e);
|
||||
break;
|
||||
|
||||
case KeyEvent.VK_END:
|
||||
doEndKey(e);
|
||||
break;
|
||||
|
||||
case KeyEvent.VK_LEFT:
|
||||
case KeyEvent.VK_RIGHT:
|
||||
case KeyEvent.VK_UP:
|
||||
case KeyEvent.VK_DOWN:
|
||||
doArrowKey(e, key);
|
||||
break;
|
||||
|
||||
default:
|
||||
fUpDownAnchor = null;
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
fHandlingKeyOrCommand = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean mousePressed(MouseEvent e) {
|
||||
|
||||
if (!enabled()) {
|
||||
fPendingMouseEvent = e;
|
||||
fTextComponent.requestFocus();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fMouseDown)
|
||||
throw new Error("fMouseDown is out of sync with mouse in TextSelection.");
|
||||
|
||||
fMouseDown = true;
|
||||
stopCaretBlinking();
|
||||
|
||||
int x = e.getX(), y = e.getY();
|
||||
boolean wasZeroLength = rangeIsZeroLength(fStart, fLimit, fAnchor);
|
||||
|
||||
TextOffset current = fTextComponent.pointToTextOffset(null, x, y, null, true);
|
||||
TextOffset anchorStart = new TextOffset();
|
||||
TextOffset anchorEnd = new TextOffset();
|
||||
|
||||
fUpDownAnchor = null;
|
||||
|
||||
// if we're not extending the selection...
|
||||
if (!e.isShiftDown()) {
|
||||
|
||||
// if there are multiple clicks, create the appopriate type of BreakIterator
|
||||
// object for finding text boundaries (single clicks don't use a BreakIterator
|
||||
// object)
|
||||
if (e.getClickCount() == 2)
|
||||
fBoundaries = BreakIterator.getWordInstance();
|
||||
else if (e.getClickCount() == 3)
|
||||
fBoundaries = BreakIterator.getSentenceInstance();
|
||||
else
|
||||
fBoundaries = null;
|
||||
|
||||
// if we're using a BreakIterator object, use it to find the nearest boundaries
|
||||
// on either side of the mouse-click position and make them our anchor range
|
||||
if (fBoundaries != null)
|
||||
fBoundaries.setText(fText.createCharacterIterator());
|
||||
|
||||
anchorStart.assign(current);
|
||||
advanceToPreviousBoundary(anchorStart);
|
||||
anchorEnd.assign(current);
|
||||
advanceToNextBoundary(anchorEnd);
|
||||
}
|
||||
|
||||
// if we _are_ extending the selection, determine our anchor range as follows:
|
||||
// fAnchor is the start of the anchor range;
|
||||
// the next boundary (after fAnchor) is the limit of the anchor range.
|
||||
|
||||
else {
|
||||
|
||||
if (fBoundaries != null)
|
||||
fBoundaries.setText(fText.createCharacterIterator());
|
||||
|
||||
anchorStart.assign(fAnchor);
|
||||
anchorEnd.assign(anchorStart);
|
||||
|
||||
advanceToNextBoundary(anchorEnd);
|
||||
}
|
||||
|
||||
SelectionDragInteractor interactor = new SelectionDragInteractor(this,
|
||||
fTextComponent,
|
||||
fRunStrategy,
|
||||
anchorStart,
|
||||
anchorEnd,
|
||||
current,
|
||||
x,
|
||||
y,
|
||||
wasZeroLength);
|
||||
|
||||
interactor.addToOwner(fTextComponent);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean mouseReleased(MouseEvent e) {
|
||||
|
||||
fPendingMouseEvent = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
// drag interactor calls this
|
||||
void mouseReleased(boolean zeroLengthChange) {
|
||||
|
||||
fMouseDown = false;
|
||||
|
||||
if (zeroLengthChange) {
|
||||
fListener.textStateChanged(TextPanelEvent.SELECTION_EMPTY_CHANGED);
|
||||
}
|
||||
fListener.textStateChanged(TextPanelEvent.SELECTION_RANGE_CHANGED);
|
||||
fListener.textStateChanged(TextPanelEvent.SELECTION_STYLES_CHANGED);
|
||||
|
||||
// if caret drawing during mouse drags is supressed, draw caret now.
|
||||
|
||||
restartCaretBlinking(true);
|
||||
}
|
||||
|
||||
|
||||
/** draws the selection
|
||||
* Provided, of course, that the selection is visible, the adorner is enabled,
|
||||
* and we're calling it to adorn the view it actually belongs to
|
||||
* @param g The graphics environment to draw into
|
||||
* @return true if we actually drew
|
||||
*/
|
||||
public boolean paint(Graphics g, Rectangle drawRect) {
|
||||
// don't draw anything unless we're enabled and the selection is visible
|
||||
if (!enabled())
|
||||
return false;
|
||||
|
||||
fTextComponent.drawText(g, drawRect, true, fStart, fLimit, fHighlightColor);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** scrolls the view to reveal the live end of the selection
|
||||
* (i.e., the end that moves if you use the arrow keys with the shift key down)
|
||||
*/
|
||||
public void scrollToShowSelection() {
|
||||
Rectangle selRect = fTextComponent.getBoundingRect(fStart, fLimit);
|
||||
|
||||
fTextComponent.scrollToShow(selRect);
|
||||
}
|
||||
|
||||
/** scrolls the view to reveal the live end of the selection
|
||||
* (i.e., the end that moves if you use the arrow keys with the shift key down)
|
||||
*/
|
||||
public void scrollToShowSelectionEnd() {
|
||||
TextOffset liveEnd;
|
||||
Point[] points;
|
||||
Rectangle caret;
|
||||
|
||||
if (fAnchor.equals(fStart))
|
||||
liveEnd = fLimit;
|
||||
else
|
||||
liveEnd = fStart;
|
||||
|
||||
//points = fTextComponent.textOffsetToPoint(liveEnd);
|
||||
//caret = new Rectangle(points[0]);
|
||||
//caret = caret.union(new Rectangle(points[1]));
|
||||
caret = fTextComponent.getCaretRect(liveEnd);
|
||||
fTextComponent.scrollToShow(caret);
|
||||
}
|
||||
|
||||
private void select(TextRange range) {
|
||||
int textLength = fTextComponent.getText().length();
|
||||
|
||||
TextOffset start = new TextOffset(range.start);
|
||||
|
||||
stopCaretBlinking();
|
||||
setSelRangeAndDraw(start, new TextOffset(range.limit), start);
|
||||
restartCaretBlinking(true);
|
||||
}
|
||||
|
||||
public void setHighlightColor(Color newColor) {
|
||||
fHighlightColor = newColor;
|
||||
if (enabled())
|
||||
drawSelection(fTextComponent.getGraphics(), true);
|
||||
}
|
||||
|
||||
static boolean rangeIsZeroLength(TextOffset start, TextOffset limit, TextOffset anchor) {
|
||||
|
||||
return start.fOffset == limit.fOffset && anchor.fOffset == limit.fOffset;
|
||||
}
|
||||
|
||||
// sigh... look out for aliasing
|
||||
public void setSelectionRange(TextOffset newStart, TextOffset newLimit, TextOffset newAnchor) {
|
||||
|
||||
boolean zeroLengthChange = rangeIsZeroLength(newStart, newLimit, newAnchor) !=
|
||||
rangeIsZeroLength(fStart, fLimit, fAnchor);
|
||||
TextOffset tempNewAnchor;
|
||||
if (newAnchor == fStart || newAnchor == fLimit) {
|
||||
tempNewAnchor = new TextOffset(newAnchor); // clone in case of aliasing
|
||||
}
|
||||
else {
|
||||
tempNewAnchor = newAnchor;
|
||||
}
|
||||
|
||||
// DEBUG {jbr}
|
||||
|
||||
if (newStart.greaterThan(newLimit))
|
||||
throw new IllegalArgumentException("Selection limit is before selection start.");
|
||||
|
||||
if (newLimit != fStart) {
|
||||
fStart.assign(newStart);
|
||||
fLimit.assign(newLimit);
|
||||
}
|
||||
else {
|
||||
fLimit.assign(newLimit);
|
||||
fStart.assign(newStart);
|
||||
}
|
||||
|
||||
fAnchor.assign(tempNewAnchor);
|
||||
|
||||
if (fStart.fOffset == fLimit.fOffset) {
|
||||
fStart.fPlacement = fAnchor.fPlacement;
|
||||
fLimit.fPlacement = fAnchor.fPlacement;
|
||||
}
|
||||
|
||||
if (!fMouseDown) {
|
||||
if (zeroLengthChange) {
|
||||
fListener.textStateChanged(TextPanelEvent.SELECTION_EMPTY_CHANGED);
|
||||
}
|
||||
fListener.textStateChanged(TextPanelEvent.SELECTION_RANGE_CHANGED);
|
||||
if (fHandlingKeyOrCommand) {
|
||||
fListener.textStateChanged(TextPanelEvent.SELECTION_STYLES_CHANGED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sortOffsets(TextOffset offsets[]) {
|
||||
|
||||
int i, j;
|
||||
|
||||
for (i=0; i < offsets.length-1; i++) {
|
||||
for (j=i+1; j < offsets.length; j++) {
|
||||
if (offsets[j].lessThan(offsets[i])) {
|
||||
TextOffset temp = offsets[j];
|
||||
offsets[j] = offsets[i];
|
||||
offsets[i] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG {jbr}
|
||||
for (i=0; i < offsets.length-1; i++)
|
||||
if (offsets[i].greaterThan(offsets[i+1]))
|
||||
throw new Error("sortOffsets failed!");
|
||||
}
|
||||
|
||||
private Rectangle getSelectionChangeRect(
|
||||
TextOffset rangeStart, TextOffset rangeLimit,
|
||||
TextOffset oldStart, TextOffset oldLimit,
|
||||
TextOffset newStart, TextOffset newLimit,
|
||||
boolean drawIfInsPoint) {
|
||||
|
||||
if (!rangeStart.equals(rangeLimit))
|
||||
return fTextComponent.getBoundingRect(rangeStart, rangeLimit);
|
||||
|
||||
// here, rangeStart and rangeLimit are equal
|
||||
|
||||
if (rangeStart.equals(oldLimit)) {
|
||||
|
||||
// range start is OLD insertion point. Redraw if caret is currently visible.
|
||||
|
||||
if (fCaretIsVisible)
|
||||
return fTextComponent.getBoundingRect(rangeStart, rangeStart);
|
||||
}
|
||||
else if (rangeStart.equals(newLimit)) {
|
||||
|
||||
// range start is NEW insertion point.
|
||||
|
||||
if (drawIfInsPoint)
|
||||
return fTextComponent.getBoundingRect(rangeStart, rangeStart);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean rectanglesOverlapVertically(Rectangle r1, Rectangle r2) {
|
||||
|
||||
if (r1 == null || r2 == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return r1.y <= r2.y + r2.height || r2.y <= r1.y + r1.height;
|
||||
}
|
||||
|
||||
// Update to show new selection, redrawing as little as possible
|
||||
|
||||
private void updateSelectionDisplay(
|
||||
TextOffset oldStart, TextOffset oldLimit,
|
||||
TextOffset newStart, TextOffset newLimit, boolean drawIfInsPoint) {
|
||||
|
||||
//System.out.println("newStart:" + newStart + "; newLimit:" + newLimit);
|
||||
|
||||
TextOffset off[] = new TextOffset[4];
|
||||
|
||||
off[0] = oldStart;
|
||||
off[1] = oldLimit;
|
||||
off[2] = newStart;
|
||||
off[3] = newLimit;
|
||||
|
||||
sortOffsets(off);
|
||||
|
||||
Rectangle r1 = getSelectionChangeRect(off[0], off[1], oldStart, oldLimit, newStart, newLimit, drawIfInsPoint);
|
||||
Rectangle r2 = getSelectionChangeRect(off[2], off[3], oldStart, oldLimit, newStart, newLimit, drawIfInsPoint);
|
||||
|
||||
boolean drawSelection = drawIfInsPoint || !newStart.equals(newLimit);
|
||||
|
||||
if (rectanglesOverlapVertically(r1, r2)) {
|
||||
|
||||
fTextComponent.drawText(fTextComponent.getGraphics(), r1.union(r2), drawSelection, newStart, newLimit, fHighlightColor);
|
||||
}
|
||||
else {
|
||||
if (r1 != null)
|
||||
fTextComponent.drawText(fTextComponent.getGraphics(), r1, drawSelection, newStart, newLimit, fHighlightColor);
|
||||
if (r2 != null)
|
||||
fTextComponent.drawText(fTextComponent.getGraphics(), r2, drawSelection, newStart, newLimit, fHighlightColor);
|
||||
}
|
||||
}
|
||||
|
||||
public void setSelRangeAndDraw(TextOffset newStart, TextOffset newLimit, TextOffset newAnchor) {
|
||||
|
||||
// if the old and new selection ranges are the same, don't do anything
|
||||
if (fStart.equals(newStart) && fLimit.equals(newLimit) && fAnchor.equals(newAnchor))
|
||||
return;
|
||||
|
||||
if (enabled())
|
||||
stopCaretBlinking();
|
||||
|
||||
// update the selection on screen if we're enabled and visible
|
||||
|
||||
TextOffset oldStart = new TextOffset(fStart), oldLimit = new TextOffset(fLimit);
|
||||
|
||||
setSelectionRange(newStart, newLimit, newAnchor);
|
||||
|
||||
if (enabled()) {
|
||||
|
||||
// To supress drawing a caret during a mouse drag, pass !fMouseDown instead of true:
|
||||
updateSelectionDisplay(oldStart, oldLimit, fStart, fLimit, true);
|
||||
}
|
||||
|
||||
if (!fMouseDown && enabled())
|
||||
restartCaretBlinking(true);
|
||||
}
|
||||
|
||||
public void stopCaretBlinking() {
|
||||
|
||||
synchronized(this) {
|
||||
fCaretShouldBlink = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume blinking the caret, if the selection is an insertion point.
|
||||
* @param caretIsVisible true if the caret is displayed when this is called.
|
||||
* This method relies on the client to display (or not display) the caret.
|
||||
*/
|
||||
public void restartCaretBlinking(boolean caretIsVisible) {
|
||||
|
||||
synchronized(this) {
|
||||
fCaretShouldBlink = fStart.equals(fLimit);
|
||||
fCaretCount = 0;
|
||||
fCaretIsVisible = caretIsVisible;
|
||||
|
||||
if (fCaretShouldBlink) {
|
||||
try {
|
||||
notify();
|
||||
}
|
||||
catch (IllegalMonitorStateException e) {
|
||||
System.out.println("Caught IllegalMonitorStateException: "+e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeFromOwner() {
|
||||
|
||||
stopCaretBlinking();
|
||||
super.removeFromOwner();
|
||||
}
|
||||
|
||||
}
|
106
icu4j/src/com/ibm/richtext/textpanel/ThaiKeyRemap.java
Executable file
106
icu4j/src/com/ibm/richtext/textpanel/ThaiKeyRemap.java
Executable file
|
@ -0,0 +1,106 @@
|
|||
package com.ibm.richtext.textpanel;
|
||||
|
||||
final class ThaiKeyRemap extends KeyRemap {
|
||||
|
||||
public char remap(char c) {
|
||||
|
||||
switch (c) {
|
||||
case '`': return '\u005f';
|
||||
case '~': return '\u0025';
|
||||
case '1': return '\u0e45';
|
||||
case '!': return '\u002b';
|
||||
case '2': return '\u002f';
|
||||
case '@': return '\u0e51';
|
||||
case '3': return '\u002d';
|
||||
case '#': return '\u0e52';
|
||||
case '4': return '\u0e20';
|
||||
case '$': return '\u0e53';
|
||||
case '5': return '\u0e16';
|
||||
case '%': return '\u0e54';
|
||||
case '6': return '\u0e38';
|
||||
case '^': return '\u0e39';
|
||||
case '7': return '\u0e36';
|
||||
case '&': return '\u0e3f';
|
||||
case '8': return '\u0e04';
|
||||
case '*': return '\u0e55';
|
||||
case '9': return '\u0e15';
|
||||
case '(': return '\u0e56';
|
||||
case '0': return '\u0e08';
|
||||
case ')': return '\u0e57';
|
||||
case '-': return '\u0e02';
|
||||
case '_': return '\u0e58';
|
||||
case '=': return '\u0e08';
|
||||
case '+': return '\u0e59';
|
||||
case 'q': return '\u0e46';
|
||||
case 'Q': return '\u0e50';
|
||||
case 'w': return '\u0e44';
|
||||
case 'W': return '\u0022';
|
||||
case 'e': return '\u0e33';
|
||||
case 'E': return '\u0e0e';
|
||||
case 'r': return '\u0e1e';
|
||||
case 'R': return '\u0e11';
|
||||
case 't': return '\u0e30';
|
||||
case 'T': return '\u0e18';
|
||||
case 'y': return '\u0e31';
|
||||
case 'Y': return '\u0e4d';
|
||||
case 'u': return '\u0e35';
|
||||
case 'U': return '\u0e4a';
|
||||
case 'i': return '\u0e23';
|
||||
case 'I': return '\u0e13';
|
||||
case 'o': return '\u0e19';
|
||||
case 'O': return '\u0e2f';
|
||||
case 'p': return '\u0e22';
|
||||
case 'P': return '\u0e0d';
|
||||
case '[': return '\u0e1a';
|
||||
case '{': return '\u0e10';
|
||||
case ']': return '\u0e25';
|
||||
case '}': return '\u002c';
|
||||
case '\\': return '\u0e03';
|
||||
case '|': return '\u0e05';
|
||||
case 'a': return '\u0e1f';
|
||||
case 'A': return '\u0e24';
|
||||
case 's': return '\u0e2b';
|
||||
case 'S': return '\u0e06';
|
||||
case 'd': return '\u0e01';
|
||||
case 'D': return '\u0e0f';
|
||||
case 'f': return '\u0e14';
|
||||
case 'F': return '\u0e42';
|
||||
case 'g': return '\u0e40';
|
||||
case 'G': return '\u0e0c';
|
||||
case 'h': return '\u0e49';
|
||||
case 'H': return '\u0e47';
|
||||
case 'j': return '\u0e48';
|
||||
case 'J': return '\u0e4b';
|
||||
case 'k': return '\u0e32';
|
||||
case 'K': return '\u0e29';
|
||||
case 'l': return '\u0e2a';
|
||||
case 'L': return '\u0e28';
|
||||
case ';': return '\u0e27';
|
||||
case ':': return '\u0e0b';
|
||||
case '\'': return '\u0e07';
|
||||
case '\"': return '\u002e';
|
||||
case 'z': return '\u0e1c';
|
||||
case 'Z': return '\u0028';
|
||||
case 'x': return '\u0e1b';
|
||||
case 'X': return '\u0029';
|
||||
case 'c': return '\u0e41';
|
||||
case 'C': return '\u0e09';
|
||||
case 'v': return '\u0e2d';
|
||||
case 'V': return '\u0e2e';
|
||||
case 'b': return '\u0e34';
|
||||
case 'B': return '\u0e3a';
|
||||
case 'n': return '\u0e37';
|
||||
case 'N': return '\u0e4c';
|
||||
case 'm': return '\u0e17';
|
||||
case 'M': return '\u003f';
|
||||
case ',': return '\u0e21';
|
||||
case '<': return '\u0e12';
|
||||
case '.': return '\u0e43';
|
||||
case '>': return '\u0e2c';
|
||||
case '/': return '\u0e1d';
|
||||
case '?': return '\u0e26';
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
}
|
90
icu4j/src/com/ibm/richtext/textpanel/TransferableText.java
Executable file
90
icu4j/src/com/ibm/richtext/textpanel/TransferableText.java
Executable file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* @(#)$RCSfile: TransferableText.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
import java.awt.datatransfer.StringSelection;
|
||||
import java.awt.datatransfer.DataFlavor;
|
||||
import java.awt.datatransfer.UnsupportedFlavorException;
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
import com.ibm.richtext.styledtext.MConstText;
|
||||
|
||||
/**
|
||||
* This class allows MConstText instances to be the contents
|
||||
* of a Clipboard. To store an MConstText on the clipboard,
|
||||
* construct a TransferableText from the MConstText, and make
|
||||
* the TransferableText the clipboard contents.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Note: this class inherits from StringSelection because of
|
||||
* a bug in the 1.1.7 system clipboard implementation. The
|
||||
* system clipboard won't put text on the OS clipboard unless
|
||||
* the content is a StringSelection.
|
||||
*/
|
||||
final class TransferableText extends StringSelection
|
||||
{
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
private MConstText fText;
|
||||
|
||||
private static String textToString(MConstText text) {
|
||||
char[] chars = new char[text.length()];
|
||||
text.extractChars(0, chars.length, chars, 0);
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a TransferableText for the given text.
|
||||
* @param text the text to go on the Clipboard. The text is
|
||||
* adopted by this object.
|
||||
*/
|
||||
public TransferableText(MConstText text) {
|
||||
|
||||
super(textToString(text));
|
||||
|
||||
fText = text;
|
||||
}
|
||||
|
||||
public DataFlavor[] getTransferDataFlavors() {
|
||||
|
||||
DataFlavor[] flavors = super.getTransferDataFlavors();
|
||||
DataFlavor[] result = new DataFlavor[flavors.length+1];
|
||||
result[0] = MConstText.styledTextFlavor;
|
||||
System.arraycopy(flavors, 0, result, 1, flavors.length);
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean isDataFlavorSupported(DataFlavor flavor) {
|
||||
|
||||
if (flavor.equals(MConstText.styledTextFlavor)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return super.isDataFlavorSupported(flavor);
|
||||
}
|
||||
}
|
||||
|
||||
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
|
||||
|
||||
if (flavor.equals(MConstText.styledTextFlavor)) {
|
||||
return fText;
|
||||
}
|
||||
else {
|
||||
return super.getTransferData(flavor);
|
||||
}
|
||||
}
|
||||
}
|
356
icu4j/src/com/ibm/richtext/textpanel/TypingInteractor.java
Executable file
356
icu4j/src/com/ibm/richtext/textpanel/TypingInteractor.java
Executable file
|
@ -0,0 +1,356 @@
|
|||
/*
|
||||
* @(#)$RCSfile: TypingInteractor.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:51:23 $
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1998-1999. All Rights Reserved.
|
||||
*
|
||||
* The program is provided "as is" without any warranty express or
|
||||
* implied, including the warranty of non-infringement and the implied
|
||||
* warranties of merchantibility and fitness for a particular purpose.
|
||||
* IBM will not be liable for any damages suffered by you as a result
|
||||
* of using the Program. In no event will IBM be liable for any
|
||||
* special, indirect or consequential damages or lost profits even if
|
||||
* IBM has been advised of the possibility of their occurrence. IBM
|
||||
* will not be liable for any third party claims against you.
|
||||
*/
|
||||
/*
|
||||
2/25/99 - Now processing characters from keyTyped method (not keyPressed).
|
||||
This new way is input-method friendly on 1.2, and is generally
|
||||
more correct.
|
||||
|
||||
7/7/97 - the mouseDidSomething methods used to remove the typing interactor.
|
||||
This is definitely wrong, but maybe that made sense at one time. Anyway,
|
||||
now the mousePressed / mouseReleased methods remove the interactor; the
|
||||
others do nothing.
|
||||
*/
|
||||
|
||||
package com.ibm.richtext.textpanel;
|
||||
|
||||
import com.ibm.textlayout.attributes.AttributeMap;
|
||||
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.FocusEvent;
|
||||
|
||||
import java.text.BreakIterator;
|
||||
|
||||
import com.ibm.richtext.styledtext.StyleModifier;
|
||||
import com.ibm.richtext.styledtext.MConstText;
|
||||
import com.ibm.richtext.styledtext.MText;
|
||||
import com.ibm.richtext.styledtext.StyledText;
|
||||
import com.ibm.richtext.textformat.TextOffset;
|
||||
|
||||
final class TypingInteractor extends Behavior {
|
||||
|
||||
static final String COPYRIGHT =
|
||||
"(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
|
||||
|
||||
private static final char BACKSPACE = 8;
|
||||
private static final char TAB = '\t';
|
||||
private static final char RETURN = '\r';
|
||||
private static final char LINE_FEED = '\n';
|
||||
private static final char PARAGRAPH_SEP = '\u2029';
|
||||
|
||||
private TextComponent fTextComponent;
|
||||
private TextSelection fSelection;
|
||||
private AttributeMap fTypingStyle;
|
||||
private MConstText fText;
|
||||
private TextEditBehavior fParent;
|
||||
private TextChangeCommand fCommand = null;
|
||||
private SimpleCommandLog fCommandLog;
|
||||
private PanelEventBroadcaster fListener;
|
||||
private BreakIterator fCharBreak = null;
|
||||
|
||||
/**
|
||||
* Not all characters that come from the keyboard are handled
|
||||
* as input. For example, ctrl-c is not a typable character.
|
||||
* This method determines whether a particular character from
|
||||
* the keyboard will affect the text.
|
||||
*/
|
||||
private static boolean isTypingInteractorChar(char ch) {
|
||||
|
||||
return ch >= ' ' ||
|
||||
ch == LINE_FEED ||
|
||||
ch == RETURN ||
|
||||
ch == TAB ||
|
||||
ch == BACKSPACE;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method determines whether a TypingInteractor should
|
||||
* handle the given KeyEvent.
|
||||
*/
|
||||
static boolean handledByTypingInteractor(KeyEvent event) {
|
||||
|
||||
final int id = event.getID();
|
||||
|
||||
if (id == event.KEY_TYPED) {
|
||||
return isTypingInteractorChar(event.getKeyChar());
|
||||
}
|
||||
else {
|
||||
return (id == KeyEvent.KEY_PRESSED &&
|
||||
event.getKeyCode() == KeyEvent.VK_DELETE);
|
||||
}
|
||||
}
|
||||
|
||||
public TypingInteractor(TextComponent textComponent,
|
||||
TextSelection selection,
|
||||
AttributeMap typingStyle,
|
||||
TextEditBehavior parent,
|
||||
SimpleCommandLog commandLog,
|
||||
PanelEventBroadcaster listener) {
|
||||
|
||||
fTextComponent = textComponent;
|
||||
fText = textComponent.getText();
|
||||
fSelection = selection;
|
||||
fTypingStyle = typingStyle;
|
||||
fParent = parent;
|
||||
fCommandLog = commandLog;
|
||||
fListener = listener;
|
||||
|
||||
fParent.setTypingInteractor(this);
|
||||
}
|
||||
|
||||
private void endInteraction() {
|
||||
|
||||
removeFromOwner();
|
||||
postTextChangeCommand();
|
||||
|
||||
int selStart = fSelection.getStart().fOffset;
|
||||
int selLimit = fSelection.getEnd().fOffset;
|
||||
fParent.setSavedTypingStyle(selStart==selLimit? fTypingStyle : null, selStart);
|
||||
|
||||
fParent.setTypingInteractor(null);
|
||||
}
|
||||
|
||||
public boolean textControlEventOccurred(Behavior.EventType event, Object what) {
|
||||
|
||||
if (fCommand == null && event == Behavior.CHARACTER_STYLE_MOD) {
|
||||
|
||||
pickUpTypingStyle();
|
||||
fTypingStyle = ((StyleModifier)what).modifyStyle(fTypingStyle);
|
||||
|
||||
fListener.textStateChanged(TextPanelEvent.SELECTION_STYLES_CHANGED);
|
||||
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
Behavior next = nextBehavior(); // save because removeFromOwner() will trash this
|
||||
|
||||
endInteraction();
|
||||
|
||||
if (next != null)
|
||||
return next.textControlEventOccurred(event, what);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void doBackspace() {
|
||||
|
||||
int selStart = fSelection.getStart().fOffset;
|
||||
int selLimit = fSelection.getEnd().fOffset;
|
||||
|
||||
if (selStart == selLimit) {
|
||||
if (selStart != 0) {
|
||||
fTypingStyle = null;
|
||||
pickUpTypingStyle();
|
||||
makeTextChangeCommand();
|
||||
if (selStart <= fCommand.affectedRangeStart()) {
|
||||
fCommand.prependToOldText(fText.extract(selStart - 1, selStart));
|
||||
}
|
||||
TextOffset insPt = new TextOffset(selStart - 1);
|
||||
fParent.doReplaceText(selStart - 1, selStart, null, insPt, insPt);
|
||||
}
|
||||
}
|
||||
else {
|
||||
fTypingStyle = null;
|
||||
makeTextChangeCommand();
|
||||
TextOffset insPt = new TextOffset(selStart);
|
||||
fParent.doReplaceText(selStart, selLimit, null, insPt, insPt);
|
||||
}
|
||||
}
|
||||
|
||||
private void doFwdDelete(boolean ignoreCharBreak) {
|
||||
|
||||
int selStart = fSelection.getStart().fOffset;
|
||||
int selLimit = fSelection.getEnd().fOffset;
|
||||
|
||||
TextOffset insPt = new TextOffset(selStart);
|
||||
|
||||
if (selStart == selLimit) {
|
||||
if (selStart != fText.length()) {
|
||||
fTypingStyle = null;
|
||||
makeTextChangeCommand();
|
||||
int numChars;
|
||||
if (ignoreCharBreak) {
|
||||
numChars = 1;
|
||||
}
|
||||
else {
|
||||
if (fCharBreak == null) {
|
||||
fCharBreak = BreakIterator.getCharacterInstance();
|
||||
}
|
||||
fCharBreak.setText(fText.createCharacterIterator());
|
||||
numChars = fCharBreak.following(selStart) - selStart;
|
||||
}
|
||||
fCommand.appendToOldText(fText.extract(selStart, selStart + numChars));
|
||||
fParent.doReplaceText(selStart, selStart + numChars, null, insPt, insPt);
|
||||
}
|
||||
}
|
||||
else {
|
||||
fTypingStyle = null;
|
||||
makeTextChangeCommand();
|
||||
fParent.doReplaceText(selStart, selLimit, null, insPt, insPt);
|
||||
}
|
||||
}
|
||||
|
||||
private void doNormalKey(char ch) {
|
||||
|
||||
// Sigh - 1.1 reports enter key events as return chars, but
|
||||
// 1.2 reports them as linefeeds.
|
||||
if (ch == RETURN) {
|
||||
ch = LINE_FEED;
|
||||
}
|
||||
pickUpTypingStyle();
|
||||
makeTextChangeCommand();
|
||||
fParent.doReplaceSelectedText(ch, fTypingStyle);
|
||||
}
|
||||
|
||||
public boolean focusGained(FocusEvent e) {
|
||||
|
||||
// pass through, but stick around...
|
||||
return super.focusGained(e);
|
||||
}
|
||||
|
||||
public boolean focusLost(FocusEvent e) {
|
||||
|
||||
// pass through, but stick around...
|
||||
return super.focusLost(e);
|
||||
}
|
||||
|
||||
public boolean keyTyped(KeyEvent e) {
|
||||
|
||||
if (e.getKeyChar() == BACKSPACE) {
|
||||
doBackspace();
|
||||
}
|
||||
else {
|
||||
if (isTypingInteractorChar(e.getKeyChar())) {
|
||||
KeyRemap remap = fParent.getKeyRemap();
|
||||
doNormalKey(remap.remap(e));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean keyPressed(KeyEvent e) {
|
||||
|
||||
int key = e.getKeyCode();
|
||||
if (key == KeyEvent.VK_DELETE) {
|
||||
doFwdDelete(e.isShiftDown());
|
||||
return true;
|
||||
}
|
||||
|
||||
Behavior next = nextBehavior();
|
||||
|
||||
if (TextSelection.keyAffectsSelection(e)) {
|
||||
|
||||
endInteraction();
|
||||
}
|
||||
|
||||
return next.keyPressed(e);
|
||||
}
|
||||
|
||||
public boolean keyReleased(KeyEvent e) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void makeTextChangeCommand() {
|
||||
if (fCommand == null) {
|
||||
TextOffset selStart = fSelection.getStart();
|
||||
TextOffset selEnd = fSelection.getEnd();
|
||||
|
||||
MText writableText = new StyledText();
|
||||
writableText.replace(0, 0, fText, selStart.fOffset, selEnd.fOffset);
|
||||
fCommand = new TextChangeCommand(fParent,
|
||||
writableText,
|
||||
null, selStart.fOffset, selStart, selEnd,
|
||||
new TextOffset(), new TextOffset());
|
||||
|
||||
fListener.textStateChanged(TextPanelEvent.UNDO_STATE_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean mouseDragged(MouseEvent e) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean mouseEntered(MouseEvent e) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean mouseExited(MouseEvent e) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean mouseMoved(MouseEvent e) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean mousePressed(MouseEvent e) {
|
||||
|
||||
Behavior next = nextBehavior(); // save because removeFromOwner() will trash this
|
||||
|
||||
endInteraction();
|
||||
|
||||
if (next != null)
|
||||
return next.mousePressed(e);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean mouseReleased(MouseEvent e) {
|
||||
|
||||
Behavior next = nextBehavior(); // save because removeFromOwner() will trash this
|
||||
|
||||
endInteraction();
|
||||
|
||||
if (next != null)
|
||||
return next.mouseReleased(e);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
private void pickUpTypingStyle() {
|
||||
if (fTypingStyle == null) {
|
||||
int selStart = fSelection.getStart().fOffset;
|
||||
int selLimit = fSelection.getEnd().fOffset;
|
||||
fTypingStyle = TextEditBehavior.typingStyleAt(fText, selStart, selLimit);
|
||||
}
|
||||
}
|
||||
|
||||
private void postTextChangeCommand() {
|
||||
if (fCommand != null) {
|
||||
TextOffset selStart = fSelection.getStart();
|
||||
TextOffset selEnd = fSelection.getEnd();
|
||||
|
||||
fCommand.setNewText(fText.extract(fCommand.affectedRangeStart(), selStart.fOffset));
|
||||
fCommand.setSelRangeAfter(selStart, selEnd);
|
||||
fCommandLog.add(fCommand);
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasPendingCommand() {
|
||||
|
||||
return fCommand != null;
|
||||
}
|
||||
|
||||
AttributeMap getTypingStyle() {
|
||||
|
||||
pickUpTypingStyle();
|
||||
return fTypingStyle;
|
||||
}
|
||||
}
|
7
icu4j/src/com/ibm/richtext/textpanel/package.html
Executable file
7
icu4j/src/com/ibm/richtext/textpanel/package.html
Executable file
|
@ -0,0 +1,7 @@
|
|||
<html>
|
||||
<body bgcolor="white">
|
||||
Provides components (for both AWT and Swing)
|
||||
in which styled text is displayed and edited, and
|
||||
related classes.
|
||||
</body>
|
||||
</html>
|
Loading…
Add table
Reference in a new issue