Made the following changes: (1) renamed DuffPane's copySelection, pasteSelection, etc. to copy, paste and so forth, which override JTextComponent's methods by those names: Andres, please change the translation tool accordingly to use these new methods if that it necessary; (2) in order to allow for easier integration of Jskad with other tools such as QuillDriver, I changed DuffPane to rely on a Keymap instead of a KeyListener for its default key intercepts; this addresses the comments to bug 617156. Note that I have been working on Mac OS X and have not extensively tested my changes on a PC yet.

This commit is contained in:
eg3p 2003-04-02 20:37:14 +00:00
parent e95e41aef0
commit 7a495bc720
2 changed files with 104 additions and 174 deletions

View file

@ -43,7 +43,7 @@ import org.thdl.util.StatusBar;
* @author Edward Garrett, Tibetan and Himalayan Digital Library * @author Edward Garrett, Tibetan and Himalayan Digital Library
* @version 1.0 * @version 1.0
*/ */
public class DuffPane extends TibetanPane implements KeyListener, FocusListener { public class DuffPane extends TibetanPane implements FocusListener, KeyListener {
/** /**
* The status bar to update with messages about the current input mode. * The status bar to update with messages about the current input mode.
* Are we expecting a vowel? a subscript? et cetera. * Are we expecting a vowel? a subscript? et cetera.
@ -192,6 +192,9 @@ public class DuffPane extends TibetanPane implements KeyListener, FocusListener
private MutableAttributeSet romanAttributeSet; private MutableAttributeSet romanAttributeSet;
private Clipboard rtfBoard; private Clipboard rtfBoard;
private Hashtable actions;
/** Initializes this object. All constructors should call /** Initializes this object. All constructors should call
this. */ this. */
@ -293,8 +296,71 @@ public class DuffPane extends TibetanPane implements KeyListener, FocusListener
addKeyListener(this); addKeyListener(this);
addFocusListener(this); addFocusListener(this);
setupKeymap();
} }
/**
* This method sets up the keymap used by DuffPane editors.
* The keymap defines a default behavior for key presses
* in both Tibetan and Roman mode.
*/
private void setupKeymap() {
Action defaultAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
if (!DuffPane.this.isEditable()) return;
if ( ((e.getModifiers() & ActionEvent.CTRL_MASK) == ActionEvent.CTRL_MASK) ||
((e.getModifiers() & ActionEvent.ALT_MASK) == ActionEvent.ALT_MASK) ||
((e.getModifiers() & ActionEvent.META_MASK) == ActionEvent.META_MASK)) {
DuffPane.this.initKeyboard();
return;
}
if (e.getActionCommand() != null) {
String key = e.getActionCommand();
if (DuffPane.this.getSelectionStart() < DuffPane.this.getSelectionEnd())
DuffPane.this.replaceSelection("");
if (key != null) {
if (isTibetan) processTibetanChar(key.charAt(0), true);
else {
MutableAttributeSet inputAtts = DuffPane.this.getInputAttributes();
inputAtts.addAttributes(romanAttributeSet);
processRomanChar(key, inputAtts);
}
}
}
}
};
createActionTable(this);
Keymap keymap = addKeymap("DuffBindings", getKeymap());
keymap.setDefaultAction(defaultAction);
setKeymap(keymap);
}
private void createActionTable(JTextComponent textComponent) {
actions = new Hashtable();
Action[] actionsArray = textComponent.getActions();
for (int i = 0; i < actionsArray.length; i++) {
Action a = actionsArray[i];
actions.put(a.getValue(Action.NAME), a);
//System.out.println(a.getValue(Action.NAME));
}
}
private Action getActionByName(String name) {
return (Action)(actions.get(name));
}
/** /**
* This method sets up the Tibetan keyboard. Initially it is called * This method sets up the Tibetan keyboard. Initially it is called
* by the constructor, but it is also called internally whenever * by the constructor, but it is also called internally whenever
@ -885,13 +951,13 @@ class RTFSelection implements ClipboardOwner, Transferable {
/** Copies the current selection to the system clipboard, unless /** Copies the current selection to the system clipboard, unless
cut-and-paste operations are disabled. */ cut-and-paste operations are disabled. */
public void copyCurrentSelection() { public void copy() {
copy(getSelectionStart(), getSelectionEnd(), false); copy(getSelectionStart(), getSelectionEnd(), false);
} }
/** If this.isEditable(), then this copies the current selection /** If this.isEditable(), then this copies the current selection
to the system clipboard and then deletes it. */ to the system clipboard and then deletes it. */
public void cutCurrentSelection() { public void cut() {
copy(getSelectionStart(), getSelectionEnd(), true); copy(getSelectionStart(), getSelectionEnd(), true);
} }
@ -951,6 +1017,10 @@ class RTFSelection implements ClipboardOwner, Transferable {
} }
} }
public void paste() {
paste(getSelectionStart());
}
/** /**
* Pastes the contents of the system clipboard into this object's * Pastes the contents of the system clipboard into this object's
* document, at the specified position. The only kind of * document, at the specified position. The only kind of
@ -1063,197 +1133,63 @@ public void paste(int offset) {
public void disableCutAndPaste() { public void disableCutAndPaste() {
isCutAndPasteEnabled = false; isCutAndPasteEnabled = false;
} }
/** /**
* This method is required as part of the * Required by contract with the KeyListener interface,
* implementation of the KeyListener * this method initializes the keyboard
* interface. * when an action key is pressed. It leaves the
* * behavior up to the Keymap of this DuffPane.
* Basically this method only handles action keys -
* Escape, Ctrl-c, Ctrl-x, etc, and TAB and ENTER.
* Other keystrokes are handled by keyTyped.
*/ */
public void keyPressed(KeyEvent e) { public void keyPressed(KeyEvent e) {
// FIXME: exceptions thrown here do not cause the program to fail, even in development mode. // FIXME: exceptions thrown here do not cause the program to fail, even in development mode.
if (e.isActionKey()) if (e.isActionKey())
initKeyboard(); initKeyboard();
switch (e.getKeyCode()) {
case KeyEvent.VK_ESCAPE:
e.consume();
initKeyboard();
break;
case KeyEvent.VK_A:
if (e.isControlDown() && isCutAndPasteEnabled) {
e.consume();
setSelectionStart(0);
setSelectionEnd(getTibDoc().getLength());
}
break;
case KeyEvent.VK_C:
if (e.isControlDown() && isCutAndPasteEnabled) {
e.consume();
copy(getSelectionStart(), getSelectionEnd(), false);
}
break;
case KeyEvent.VK_X:
if (e.isControlDown() && isCutAndPasteEnabled) {
e.consume();
copy(getSelectionStart(), getSelectionEnd(), true);
}
break;
case KeyEvent.VK_V:
if (e.isControlDown() && isCutAndPasteEnabled) {
e.consume();
// since paste is substituting selected text, first delete
deleteCurrentSelection();
paste(caret.getDot());
}
break;
case KeyEvent.VK_TAB:
e.consume();
if (this.isEditable()) {
initKeyboard();
if (isTibetan)
getTibDoc().appendDuff(caret.getDot(),"\t",TibetanMachineWeb.getAttributeSet(1));
else
append("\t", romanAttributeSet);
}
break;
case KeyEvent.VK_ENTER:
e.consume();
if (this.isEditable()) {
initKeyboard();
if (isTibetan)
getTibDoc().appendDuff(caret.getDot(),"\n",TibetanMachineWeb.getAttributeSet(1)); // FIXME does this work on all platforms?
else
append("\n", romanAttributeSet); // FIXME does this work on all platforms?
}
break;
}
} }
/** /**
* Required of implementations of the Key Listener interface, * Required by contract with the KeyListener interface,
* this method does (almost) nothing. * this method does nothing.
*
* @param e a KeyEvent
*/
public void keyTyped(KeyEvent e) { }
/**
* Required by contract with the Key Listener interface,
* this method initializes the keyboard if the user presses
* backspace.
* *
* @param e the KeyEvent * @param e the KeyEvent
*/ */
public void keyReleased(KeyEvent e) { public void keyReleased(KeyEvent e) {
// FIXME: exceptions thrown here do not cause the program to fail, even in development mode. // FIXME: exceptions thrown here do not cause the program to fail, even in development mode.
/*
* Apparently it works best to check for backspace
* and init the keyboard here in key released
* though i don't really know why...
*/
if (e.getKeyCode() == KeyEvent.VK_BACK_SPACE) if (e.getKeyCode() == KeyEvent.VK_BACK_SPACE)
initKeyboard(); initKeyboard();
} }
/** private void processRomanChar(String key, MutableAttributeSet attSet) {
* Required of implementations of the KeyListener interface, switch (key.charAt(0)) {
* this method handles the pressing of non-control and non-action keys. If the user case KeyEvent.VK_BACK_SPACE:
* is in Tibetan typing mode, then the KeyEvent break;
* e is consumed, and passed on to {@link #processTibetan(KeyEvent e)}, which default:
* contains the meat of the keyboard logic. If the user is in English mode, then append(key, attSet);
* {@link #append(String s, MutableAttributeSet attr) append} is called.
*
* @param e a KeyEvent
*/
public void keyTyped(KeyEvent e) {
// FIXME: exceptions thrown here do not cause the program to fail, even in development mode.
e.consume();
// Respect setEditable(boolean):
if (!this.isEditable())
return;
if (isTibetan)
processTibetan(e);
else {
if (e.isControlDown() || e.isAltDown())
return;
char c = e.getKeyChar();
switch (c) {
case KeyEvent.VK_TAB:
case KeyEvent.VK_ENTER:
case KeyEvent.VK_ESCAPE:
break;
case KeyEvent.VK_BACK_SPACE:
backSpace(1);
break;
default:
append(String.valueOf(c), romanAttributeSet);
}
} }
} }
/** /** Utility method called by DuffPane's Keymap as the
* Interprets a key typed during Tibetan input mode. default behavior when the user is in Tibetan typing mode.
* This method keeps track of which characters the user has and is typing,
* and also of whether or not the user is in stacking
* mode. Most of the keyboard logic can be found here.
*
* If there is a nonnull status bar to be updated (passed to the
* constructor), let's explain to the user which mode we're in, why
* their keypress has changed nothing, etc. At present, this is really
* for developers to understand what's going on. For example, if you
* type s-g-r, you see a single glyph, a three-letter stack, but if you
* type s-d-r, you see two glyphs. If you examine the status bar,
* you'll see that the thing determining that is
* TibTextUtils.getGlyphs, which in turn relies on 'tibwn.ini'.
*
* @param e a KeyEvent */
public void processTibetan(KeyEvent kev) {
/* DLC FIXME: in the extended wylie keyboard, there's a
* potential problem: typing ai gets you what aai gets you,
* not what i gets you. Typing ae gets you what e gets
* you. */
boolean shouldIBackSpace = true;
// We don't handle just any old keypress. We handle only the
// ones that enter text.
if (kev.isControlDown() || kev.isAltDown())
return;
{
int start = getSelectionStart();
int end = getSelectionEnd();
if (start != end) {
if (kev.getKeyCode() != KeyEvent.VK_ESCAPE) {
try {
initKeyboard();
getTibDoc().remove(start, end-start);
shouldIBackSpace = false;
}
catch (BadLocationException ble) {
}
}
}
}
processTibetanChar(kev.getKeyChar(), shouldIBackSpace);
}
/** Utility method used by processTibetan(keyEvent).
@param c the character the user entered in whatever keyboard @param c the character the user entered in whatever keyboard
is in use is in use
@param shouldIBackSpace false iff a press of the backspace key @param shouldIBackSpace false iff a press of the backspace key
should not backspace, such as when you've selected some text should not backspace, such as when you've selected some text
and then pressed backspace and then pressed backspace ACTUALLY I DONT KNOW IF THIS IS
@see #processTibetan(KeyEvent) */ NECESSARY ANYMORE SINCE BACKSPACE IS NOW HANDLED BY THE
DEFAULT KEYMAP FOR JTEXTCOMPONENT */
private void processTibetanChar(char c, boolean shouldIBackSpace) { private void processTibetanChar(char c, boolean shouldIBackSpace) {
// Have we modified the status bar? // Have we modified the status bar?
@ -1364,12 +1300,6 @@ public void paste(int offset) {
appendStatus(" (because you typed enter, tab, or escape)"); appendStatus(" (because you typed enter, tab, or escape)");
break; break;
case KeyEvent.VK_BACK_SPACE:
if (shouldIBackSpace) {
backSpace(1);
break;
}
default: default:
String val = String.valueOf(c); String val = String.valueOf(c);

View file

@ -809,11 +809,11 @@ public class Jskad extends JPanel implements DocumentListener {
} }
private void cutSelection() { private void cutSelection() {
dp.cutCurrentSelection(); dp.cut();
} }
private void copySelection() { private void copySelection() {
dp.copyCurrentSelection(); dp.copy();
} }
private void pasteSelection() { private void pasteSelection() {