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:
parent
e95e41aef0
commit
7a495bc720
2 changed files with 104 additions and 174 deletions
|
@ -43,7 +43,7 @@ import org.thdl.util.StatusBar;
|
|||
* @author Edward Garrett, Tibetan and Himalayan Digital Library
|
||||
* @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.
|
||||
* 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 Clipboard rtfBoard;
|
||||
|
||||
private Hashtable actions;
|
||||
|
||||
|
||||
/** Initializes this object. All constructors should call
|
||||
this. */
|
||||
|
@ -293,8 +296,71 @@ public class DuffPane extends TibetanPane implements KeyListener, FocusListener
|
|||
|
||||
addKeyListener(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
|
||||
* 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
|
||||
cut-and-paste operations are disabled. */
|
||||
public void copyCurrentSelection() {
|
||||
public void copy() {
|
||||
copy(getSelectionStart(), getSelectionEnd(), false);
|
||||
}
|
||||
|
||||
/** If this.isEditable(), then this copies the current selection
|
||||
to the system clipboard and then deletes it. */
|
||||
public void cutCurrentSelection() {
|
||||
public void cut() {
|
||||
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
|
||||
* document, at the specified position. The only kind of
|
||||
|
@ -1063,197 +1133,63 @@ public void paste(int offset) {
|
|||
public void disableCutAndPaste() {
|
||||
isCutAndPasteEnabled = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is required as part of the
|
||||
* implementation of the KeyListener
|
||||
* interface.
|
||||
*
|
||||
* Basically this method only handles action keys -
|
||||
* Escape, Ctrl-c, Ctrl-x, etc, and TAB and ENTER.
|
||||
* Other keystrokes are handled by keyTyped.
|
||||
* Required by contract with the KeyListener interface,
|
||||
* this method initializes the keyboard
|
||||
* when an action key is pressed. It leaves the
|
||||
* behavior up to the Keymap of this DuffPane.
|
||||
*/
|
||||
public void keyPressed(KeyEvent e) {
|
||||
// FIXME: exceptions thrown here do not cause the program to fail, even in development mode.
|
||||
|
||||
if (e.isActionKey())
|
||||
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,
|
||||
* this method does (almost) nothing.
|
||||
* Required by contract with the KeyListener interface,
|
||||
* 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
|
||||
*/
|
||||
public void keyReleased(KeyEvent e) {
|
||||
// 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)
|
||||
initKeyboard();
|
||||
}
|
||||
|
||||
/**
|
||||
* Required of implementations of the KeyListener interface,
|
||||
* this method handles the pressing of non-control and non-action keys. If the user
|
||||
* is in Tibetan typing mode, then the KeyEvent
|
||||
* e is consumed, and passed on to {@link #processTibetan(KeyEvent e)}, which
|
||||
* contains the meat of the keyboard logic. If the user is in English mode, then
|
||||
* {@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);
|
||||
}
|
||||
private void processRomanChar(String key, MutableAttributeSet attSet) {
|
||||
switch (key.charAt(0)) {
|
||||
case KeyEvent.VK_BACK_SPACE:
|
||||
break;
|
||||
default:
|
||||
append(key, attSet);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interprets a key typed during Tibetan input 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).
|
||||
/** Utility method called by DuffPane's Keymap as the
|
||||
default behavior when the user is in Tibetan typing mode.
|
||||
@param c the character the user entered in whatever keyboard
|
||||
is in use
|
||||
@param shouldIBackSpace false iff a press of the backspace key
|
||||
should not backspace, such as when you've selected some text
|
||||
and then pressed backspace
|
||||
@see #processTibetan(KeyEvent) */
|
||||
and then pressed backspace ACTUALLY I DONT KNOW IF THIS IS
|
||||
NECESSARY ANYMORE SINCE BACKSPACE IS NOW HANDLED BY THE
|
||||
DEFAULT KEYMAP FOR JTEXTCOMPONENT */
|
||||
private void processTibetanChar(char c, boolean shouldIBackSpace) {
|
||||
|
||||
// Have we modified the status bar?
|
||||
|
@ -1364,12 +1300,6 @@ public void paste(int offset) {
|
|||
appendStatus(" (because you typed enter, tab, or escape)");
|
||||
break;
|
||||
|
||||
case KeyEvent.VK_BACK_SPACE:
|
||||
if (shouldIBackSpace) {
|
||||
backSpace(1);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
String val = String.valueOf(c);
|
||||
|
||||
|
|
|
@ -809,11 +809,11 @@ public class Jskad extends JPanel implements DocumentListener {
|
|||
}
|
||||
|
||||
private void cutSelection() {
|
||||
dp.cutCurrentSelection();
|
||||
dp.cut();
|
||||
}
|
||||
|
||||
private void copySelection() {
|
||||
dp.copyCurrentSelection();
|
||||
dp.copy();
|
||||
}
|
||||
|
||||
private void pasteSelection() {
|
||||
|
|
Loading…
Reference in a new issue