001: /*
002: * Jacareto Copyright (c) 2002-2005
003: * Applied Computer Science Research Group, Darmstadt University of
004: * Technology, Institute of Mathematics & Computer Science,
005: * Ludwigsburg University of Education, and Computer Based
006: * Learning Research Group, Aachen University. All rights reserved.
007: *
008: * Jacareto is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU General Public
010: * License as published by the Free Software Foundation; either
011: * version 2 of the License, or (at your option) any later version.
012: *
013: * Jacareto is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016: * General Public License for more details.
017: *
018: * You should have received a copy of the GNU General Public
019: * License along with Jacareto; if not, write to the Free
020: * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
021: *
022: */
023:
024: package jacareto.struct;
025:
026: import jacareto.parse.RecordTokenizer;
027: import jacareto.parse.RecordTokenizerState;
028: import jacareto.record.ActionEventRecordable;
029: import jacareto.record.KeyEventRecordable;
030: import jacareto.system.Environment;
031: import jacareto.toolkit.CharacterToolkit;
032: import jacareto.toolkit.StringToolkit;
033:
034: import java.awt.event.KeyEvent;
035:
036: import java.util.Vector;
037:
038: /**
039: * This structure element stands for a typed key.
040: *
041: * @author <a href="mailto:cspannagel@web.de">Christian Spannagel</a>
042: * @version 1.01
043: */
044: public class ModifiedKeySequence extends StructureElement {
045: /** The index where the sequence of non-modifier keys starts. */
046: private int startIndex;
047:
048: /** The index where the sequence of non-modifier keys ends. */
049: private int endIndex;
050: private boolean isShiftDown;
051: private boolean isControlDown;
052: private boolean isAltDown;
053: private boolean isMetaDown;
054: private boolean isAltGraphDown;
055: private boolean isCharacterSequence;
056:
057: /**
058: * Creates a new "modified key sequence" structure element.
059: *
060: * @param env the environment
061: * @param children the child structure elements
062: */
063: public ModifiedKeySequence(Environment env,
064: StructureElement[] children) {
065: super (env, children);
066: isShiftDown = isControlDown = isAltDown = isAltGraphDown = isMetaDown = false;
067:
068: boolean modFound = false;
069: startIndex = 0;
070:
071: do {
072: modFound = false;
073:
074: if (children[startIndex] instanceof KeyEventRecordable) {
075: int keyCode = ((KeyEventRecordable) children[startIndex])
076: .getKeyCode();
077:
078: if (keyCode == KeyEvent.VK_SHIFT) {
079: modFound = isShiftDown = true;
080: } else if (keyCode == KeyEvent.VK_CONTROL) {
081: modFound = isControlDown = true;
082: } else if (keyCode == KeyEvent.VK_ALT) {
083: modFound = isAltDown = true;
084: } else if (keyCode == KeyEvent.VK_ALT_GRAPH) {
085: modFound = isAltGraphDown = true;
086: } else if (keyCode == KeyEvent.VK_META) {
087: modFound = isMetaDown = true;
088: }
089: }
090:
091: if (modFound) {
092: startIndex++;
093: }
094: } while (modFound && (startIndex < children.length));
095:
096: endIndex = children.length;
097:
098: if (isShiftDown) {
099: endIndex--;
100: }
101:
102: if (isControlDown) {
103: endIndex--;
104: }
105:
106: if (isAltDown) {
107: endIndex--;
108: }
109:
110: if (isAltGraphDown) {
111: endIndex--;
112: }
113:
114: if (isMetaDown) {
115: endIndex--;
116: }
117: }
118:
119: /**
120: * Creates a new "modified key sequence" structure element.
121: *
122: * @param env the environment
123: * @param children the child structure elements
124: * @param startIndex the index where the sequence of of non-modifier keys starts
125: * @param endIndex the index where the sequence of of non-modifier keys endss
126: */
127: public ModifiedKeySequence(Environment env,
128: StructureElement[] children, int startIndex, int endIndex) {
129: super (env, children);
130: this .startIndex = startIndex;
131: this .endIndex = endIndex;
132: isShiftDown = isControlDown = isAltDown = isAltGraphDown = isMetaDown = false;
133:
134: for (int i = 0; i < startIndex; i++) {
135: KeyEventRecordable keyEvent = (KeyEventRecordable) children[i];
136: int keyCode = keyEvent.getKeyCode();
137:
138: if (keyCode == KeyEvent.VK_SHIFT) {
139: isShiftDown = true;
140: } else if (keyCode == KeyEvent.VK_CONTROL) {
141: isControlDown = true;
142: } else if (keyCode == KeyEvent.VK_ALT) {
143: isAltDown = true;
144: } else if (keyCode == KeyEvent.VK_ALT_GRAPH) {
145: isAltGraphDown = true;
146: } else if (keyCode == KeyEvent.VK_META) {
147: isMetaDown = true;
148: }
149: }
150: }
151:
152: /**
153: * Parses a record which is tokenized by the given record tokenizer.
154: *
155: * @param env DOCUMENT ME!
156: * @param recordTokenizer the record tokenizer
157: *
158: * @return a structure element, or <code>null</code> if this class cannot parse the record at
159: * the current position
160: */
161: public static StructureElement parse(Environment env,
162: RecordTokenizer recordTokenizer) {
163: StructureElement result = null;
164: RecordTokenizerState rtState = recordTokenizer.saveState();
165: Vector addedChildren = new Vector(5, 5);
166:
167: try {
168: boolean ctrl = false;
169: boolean shift = false;
170: boolean alt = false;
171: boolean altgr = false;
172: boolean meta = false;
173:
174: // Read the modifiers first
175: boolean modFound = true;
176:
177: while (modFound && recordTokenizer.hasMore()) {
178: modFound = false;
179:
180: KeyEventRecordable keyEvent = (KeyEventRecordable) recordTokenizer
181: .get();
182:
183: if ((keyEvent.getKeyCode() == KeyEvent.VK_SHIFT)
184: && (keyEvent.getID() == KeyEvent.KEY_PRESSED)) {
185: modFound = shift = true;
186: } else if ((keyEvent.getKeyCode() == KeyEvent.VK_CONTROL)
187: && (keyEvent.getID() == KeyEvent.KEY_PRESSED)) {
188: modFound = ctrl = true;
189: } else if ((keyEvent.getKeyCode() == KeyEvent.VK_ALT)
190: && (keyEvent.getID() == KeyEvent.KEY_PRESSED)) {
191: modFound = alt = true;
192: } else if ((keyEvent.getKeyCode() == KeyEvent.VK_ALT_GRAPH)
193: && (keyEvent.getID() == KeyEvent.KEY_PRESSED)) {
194: modFound = altgr = true;
195: } else if ((keyEvent.getKeyCode() == KeyEvent.VK_META)
196: && (keyEvent.getID() == KeyEvent.KEY_PRESSED)) {
197: modFound = meta = true;
198: }
199:
200: if (modFound) {
201: recordTokenizer.forward();
202: addedChildren.add(keyEvent);
203: }
204: }
205:
206: if (addedChildren.size() == 0) {
207: throw new Exception();
208: }
209:
210: int startIndex = addedChildren.size();
211:
212: // Read the other chars which are not modifiers
213: modFound = false;
214:
215: do {
216: KeyTyped keyTyped = (KeyTyped) KeyTyped.parse(env,
217: recordTokenizer);
218:
219: if (keyTyped != null) {
220: addedChildren.add(keyTyped);
221: } else {
222: StructureElement nextElement = recordTokenizer
223: .get();
224:
225: if (nextElement instanceof KeyEventRecordable) {
226: KeyEventRecordable keyEvent = (KeyEventRecordable) nextElement;
227: int keyCode = keyEvent.getKeyCode();
228:
229: if ((keyCode == KeyEvent.VK_ALT)
230: || (keyCode == KeyEvent.VK_SHIFT)
231: || (keyCode == KeyEvent.VK_CONTROL)
232: || (keyCode == KeyEvent.VK_ALT_GRAPH)
233: || (keyCode == KeyEvent.VK_META)) {
234: modFound = true;
235: } else {
236: recordTokenizer.forward();
237: addedChildren.add(keyEvent);
238: }
239: } else if (nextElement instanceof ActionEventRecordable) {
240: recordTokenizer.forward();
241: addedChildren.add(nextElement);
242: } else {
243: throw new Exception();
244: }
245: }
246: } while (!modFound);
247:
248: int endIndex = addedChildren.size();
249:
250: if (startIndex == endIndex) {
251: throw new Exception();
252: }
253:
254: // Read the modifiers again; all modifiers must be resetted
255: modFound = true;
256:
257: while (modFound && recordTokenizer.hasMore()
258: && (alt || ctrl || shift)) {
259: modFound = false;
260:
261: KeyEventRecordable keyEvent = (KeyEventRecordable) recordTokenizer
262: .get();
263:
264: if ((keyEvent.getKeyCode() == KeyEvent.VK_SHIFT)
265: && (keyEvent.getID() == KeyEvent.KEY_RELEASED)) {
266: modFound = true;
267:
268: if (shift) {
269: shift = false;
270: } else {
271: throw new Exception();
272: }
273: } else if ((keyEvent.getKeyCode() == KeyEvent.VK_CONTROL)
274: && (keyEvent.getID() == KeyEvent.KEY_RELEASED)) {
275: modFound = true;
276:
277: if (ctrl) {
278: ctrl = false;
279: } else {
280: throw new Exception();
281: }
282: } else if ((keyEvent.getKeyCode() == KeyEvent.VK_ALT)
283: && (keyEvent.getID() == KeyEvent.KEY_RELEASED)) {
284: modFound = true;
285:
286: if (alt) {
287: alt = false;
288: } else {
289: throw new Exception();
290: }
291: } else if ((keyEvent.getKeyCode() == KeyEvent.VK_ALT_GRAPH)
292: && (keyEvent.getID() == KeyEvent.KEY_RELEASED)) {
293: modFound = true;
294:
295: if (altgr) {
296: altgr = false;
297: } else {
298: throw new Exception();
299: }
300: } else if ((keyEvent.getKeyCode() == KeyEvent.VK_META)
301: && (keyEvent.getID() == KeyEvent.KEY_RELEASED)) {
302: modFound = true;
303:
304: if (meta) {
305: meta = false;
306: } else {
307: throw new Exception();
308: }
309: }
310:
311: if (modFound) {
312: recordTokenizer.forward();
313: addedChildren.add(keyEvent);
314: }
315: }
316:
317: if (alt || ctrl || shift || (addedChildren.size() == 0)) {
318: throw new Exception();
319: } else {
320: //result = new ModifiedKeySequence (env, vectorToArray (addedChildren));
321: result = new ModifiedKeySequence(env,
322: vectorToArray(addedChildren), startIndex,
323: endIndex);
324: }
325: } catch (Throwable t) {
326: recordTokenizer.restoreState(rtState);
327: }
328:
329: return result;
330: }
331:
332: /**
333: * Returns the name of the element.
334: *
335: * @return the name
336: */
337: public String getElementName() {
338: return language
339: .getString("Structures.ModifiedKeySequence.Name");
340: }
341:
342: /**
343: * Returns a description of the element.
344: *
345: * @return the description
346: */
347: public String getElementDescription() {
348: return language
349: .getString("Structures.ModifiedKeySequence.Description");
350: }
351:
352: /**
353: * Returns a string describing the key sequence.
354: *
355: * @return DOCUMENT ME!
356: */
357: public String getKeyString() {
358: String keyString = "";
359: String charKeyString = "";
360:
361: isCharacterSequence = true;
362:
363: if (isControlDown) {
364: keyString += "Ctrl+";
365: }
366:
367: if (isAltDown) {
368: keyString += "Alt+";
369: }
370:
371: if (isShiftDown) {
372: keyString += "Shift+";
373: }
374:
375: if (isAltGraphDown) {
376: keyString += "AltGr+";
377: }
378:
379: if (isMetaDown) {
380: keyString += "Meta+";
381: }
382:
383: for (int i = startIndex; i < endIndex; i++) {
384: StructureElement child = getChild(i);
385: int keyCode = 0;
386: char keyChar = ' ';
387:
388: if (child instanceof KeyEventRecordable) {
389: keyCode = ((KeyEventRecordable) child).getKeyCode();
390: keyChar = ((KeyEventRecordable) child).getKeyChar();
391: } else if (child instanceof KeyTyped) {
392: keyCode = ((KeyTyped) child).getKeyCode();
393: keyChar = ((KeyTyped) child).getKeyChar();
394: } else if (child instanceof ActionEventRecordable) {
395: keyString = ((ActionEventRecordable) child)
396: .getActionCommand();
397:
398: break;
399: }
400:
401: String keyCodeString = CharacterToolkit.getString(keyChar,
402: keyCode);
403: keyString += keyCodeString;
404:
405: if (((isControlDown && isAltDown) || isAltGraphDown)
406: && StringToolkit.areEqual(keyCodeString, "7")) {
407: charKeyString += "{";
408: } else if (((isControlDown && isAltDown) || isAltGraphDown)
409: && StringToolkit.areEqual(keyCodeString, "0")) {
410: charKeyString += "}";
411: } else if (((isControlDown && isAltDown) || isAltGraphDown)
412: && StringToolkit.areEqual(keyCodeString, "8")) {
413: charKeyString += "[";
414: } else if (((isControlDown && isAltDown) || isAltGraphDown)
415: && StringToolkit.areEqual(keyCodeString, "9")) {
416: charKeyString += "]";
417: } else if (isShiftDown
418: && StringToolkit.areEqual(keyCodeString, "8")) {
419: charKeyString += "(";
420: } else if (isShiftDown
421: && StringToolkit.areEqual(keyCodeString, "9")) {
422: charKeyString += ")";
423: } else {
424: isCharacterSequence = false;
425: }
426: }
427:
428: if (isCharacterSequence) {
429: keyString = charKeyString;
430: }
431:
432: return keyString;
433: }
434:
435: /**
436: * Returns a String which describes the content of the element shortly.
437: *
438: * @return a string with a short description of the element
439: */
440: public String toShortString() {
441: String result = "";
442:
443: if (!isCharacterSequence) {
444: result = getElementName() + " (" + getKeyString() + ")";
445: } else {
446: result = "\""
447: + getKeyString()
448: + "\" "
449: + language
450: .getString("Structures.KeySequence.Typed");
451: }
452:
453: result = ((result.length() < 40) ? result : (result.substring(
454: 0, 37) + "..."));
455:
456: return result;
457: }
458:
459: /**
460: * Clones the element.
461: *
462: * @return DOCUMENT ME!
463: */
464: public Object clone() {
465: StructureElement[] clonedChildren = getClonedChildren();
466:
467: return new ModifiedKeySequence(env, clonedChildren, startIndex,
468: endIndex);
469: }
470: }
|