comparison src/org/tn5250j/framework/tn5250/Screen5250.java @ 3:e8d2a24e85c6 tn5250

adding tn5250 files
author Carl Byington <carl@five-ten-sg.com>
date Thu, 22 May 2014 12:11:10 -0700
parents
children 3248b46f3973
comparison
equal deleted inserted replaced
2:a01665cb683d 3:e8d2a24e85c6
1 /**
2 * Title: Screen5250.java
3 * Copyright: Copyright (c) 2001 - 2004
4 * Company:
5 * @author Kenneth J. Pouncey
6 * @version 0.5
7 *
8 * Description:
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
13 * any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this software; see the file COPYING. If not, write to
22 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
23 * Boston, MA 02111-1307 USA
24 *
25 */
26 package org.tn5250j.framework.tn5250;
27
28 import static org.tn5250j.TN5250jConstants.*;
29
30 import java.text.DecimalFormat;
31 import java.text.DecimalFormatSymbols;
32 import java.text.NumberFormat;
33 import java.text.ParseException;
34 import java.util.Vector;
35
36 import org.tn5250j.TN5250jConstants;
37 import org.tn5250j.event.ScreenListener;
38 import org.tn5250j.tools.logging.TN5250jLogFactory;
39 import org.tn5250j.tools.logging.TN5250jLogger;
40
41 public class Screen5250 {
42
43 private ScreenFields screenFields;
44 private int lastAttr;
45 private int lastPos;
46 private int lenScreen;
47 private KeyStrokenizer strokenizer;
48 private tnvt sessionVT;
49 private int numRows = 0;
50 private int numCols = 0;
51 protected static final int initAttr = 32;
52 protected static final char initChar = 0;
53 public boolean cursorActive = false;
54 public boolean cursorShown = false;
55 protected boolean insertMode = false;
56 private boolean keyProcessed = false;
57 private Rect dirtyScreen = new Rect();
58
59 public int homePos = 0;
60 public int saveHomePos = 0;
61 private String bufferedKeys;
62 public boolean pendingInsert = false;
63
64 public final static byte STATUS_SYSTEM = 1;
65 public final static byte STATUS_ERROR_CODE = 2;
66 public final static byte STATUS_VALUE_ON = 1;
67 public final static byte STATUS_VALUE_OFF = 2;
68
69 private StringBuffer hsMore = new StringBuffer("More...");
70 private StringBuffer hsBottom = new StringBuffer("Bottom");
71
72 // error codes to be sent to the host on an error
73 private final static int ERR_CURSOR_PROTECTED = 0x05;
74 private final static int ERR_INVALID_SIGN = 0x11;
75 private final static int ERR_NO_ROOM_INSERT = 0x12;
76 private final static int ERR_NUMERIC_ONLY = 0x09;
77 private final static int ERR_DUP_KEY_NOT_ALLOWED = 0x19;
78 private final static int ERR_NUMERIC_09 = 0x10;
79 private final static int ERR_FIELD_MINUS = 0x16;
80 private final static int ERR_FIELD_EXIT_INVALID = 0x18;
81 private final static int ERR_ENTER_NO_ALLOWED = 0x20;
82 private final static int ERR_MANDITORY_ENTER = 0x21;
83
84 private boolean guiInterface = false;
85 private boolean resetRequired = true;
86 private boolean backspaceError = true;
87 private boolean feError;
88
89 // vector of listeners for changes to the screen.
90 Vector<ScreenListener> listeners = null;
91
92 // Operator Information Area
93 private ScreenOIA oia;
94
95 // screen planes
96 protected ScreenPlanes planes;
97
98 //Added by Barry
99 private StringBuffer keybuf;
100
101 private TN5250jLogger log = TN5250jLogFactory.getLogger(this.getClass());
102
103 public Screen5250() {
104
105 //Added by Barry
106 this.keybuf = new StringBuffer();
107
108 try {
109 jbInit();
110 } catch (Exception ex) {
111 log.warn("In constructor: ", ex);
112 }
113 }
114
115 void jbInit() throws Exception {
116
117 lastAttr = 32;
118
119 // default number of rows and columns
120 numRows = 24;
121 numCols = 80;
122
123 setCursor(1, 1); // set initial cursor position
124
125 oia = new ScreenOIA(this);
126 oia.setKeyBoardLocked(true);
127
128 lenScreen = numRows * numCols;
129
130 planes = new ScreenPlanes(this,numRows);
131
132 screenFields = new ScreenFields(this);
133 strokenizer = new KeyStrokenizer();
134 }
135
136 protected ScreenPlanes getPlanes() {
137 return planes;
138 }
139
140 public final ScreenOIA getOIA() {
141 return oia;
142 }
143
144 protected final void setRowsCols(int rows, int cols) {
145
146 int oldRows = numRows;
147 int oldCols = numCols;
148
149 // default number of rows and columns
150 numRows = rows;
151 numCols = cols;
152
153 lenScreen = numRows * numCols;
154
155 planes.setSize(rows);
156
157 // If they are not the same then we need to inform the listeners that
158 // the size changed.
159 if (oldRows != numRows || oldCols != numCols)
160 fireScreenSizeChanged();
161
162 }
163
164
165 public boolean isCursorActive() {
166 return cursorActive;
167
168 }
169
170 public boolean isCursorShown() {
171 return cursorShown;
172 }
173
174 public void setUseGUIInterface(boolean gui) {
175 guiInterface = gui;
176 }
177
178 public void toggleGUIInterface() {
179 guiInterface = !guiInterface;
180 }
181
182 public void setResetRequired(boolean reset) {
183 resetRequired = reset;
184 }
185
186 public void setBackspaceError(boolean onError) {
187 backspaceError = onError;
188 }
189
190 /**
191 * Copy & Paste support
192 *
193 * @see {@link #pasteText(String, boolean)}
194 * @see {@link #copyTextField(int)}
195 */
196 public final String copyText(Rect area) {
197 StringBuilder sb = new StringBuilder();
198 Rect workR = new Rect();
199 workR.setBounds(area);
200 log.debug("Copying " + workR);
201
202 // loop through all the screen characters to send them to the clip board
203 int m = workR.x;
204 int i = 0;
205 int t = 0;
206
207 while (workR.height-- > 0) {
208 t = workR.width;
209 i = workR.y;
210 while (t-- > 0) {
211 // only copy printable characters (in this case >= ' ')
212 char c = planes.getChar(getPos(m - 1, i - 1));
213 if (c >= ' ' && (planes.screenExtended[getPos(m - 1, i - 1)] & EXTENDED_5250_NON_DSP)
214 == 0)
215 sb.append(c);
216 else
217 sb.append(' ');
218
219 i++;
220 }
221 sb.append('\n');
222 m++;
223 }
224 return sb.toString();
225 }
226
227 /**
228 * Copy & Paste support
229 *
230 * @param content
231 * @see {@link #copyText(Rectangle)}
232 */
233 public final void pasteText(String content, boolean special) {
234 if (log.isDebugEnabled()) {
235 log.debug("Pasting, special:"+special);
236 }
237 setCursorActive(false);
238
239 StringBuilder sb = new StringBuilder(content);
240 StringBuilder pd = new StringBuilder();
241
242 // character counters within the string to be pasted.
243 int nextChar = 0;
244 int nChars = sb.length();
245
246 int lr = getRow(lastPos);
247 int lc = getCol(lastPos);
248 resetDirty(lastPos);
249
250 int cpos = lastPos;
251 int length = getScreenLength();
252
253 char c = 0;
254 boolean setIt;
255
256 // save our current place within the FFT.
257 screenFields.saveCurrentField();
258
259 for (int x = nextChar; x < nChars; x++) {
260
261 c = sb.charAt(x);
262
263 if ((c == '\n') || (c == '\r')) {
264
265 log.info("pasted cr-lf>" + pd + "<");
266 pd.setLength(0);
267 // if we read in a cr lf in the data stream we need to go
268 // to the starting column of the next row and start from there
269 cpos = getPos(getRow(cpos)+1,lc);
270
271 // If we go paste the end of the screen then let's start over from
272 // the beginning of the screen space.
273 if (cpos > length)
274 cpos = 0;
275 }
276 else {
277
278 // we will default to set the character always.
279 setIt = true;
280
281 // If we are in a special paste scenario then we check for valid
282 // characters to paste.
283 if (special && (!Character.isLetter(c) && !Character.isDigit(c)))
284 setIt = false;
285
286 // we will only push a character to the screen space if we are in
287 // a field
288 if (isInField(cpos) && setIt) {
289 planes.setChar(cpos, c);
290 setDirty(cpos);
291 screenFields.setCurrentFieldMDT();
292 }
293 // If we placed a character then we go to the next position.
294 if (setIt)
295 cpos++;
296 // we will append the information to our debug buffer.
297 pd.append(c);
298 }
299 }
300
301 // if we have anything else not logged then log it out.
302 if (pd.length() > 0)
303 log.info("pasted >" + pd + "<");
304
305 // restore out position within the FFT.
306 screenFields.restoreCurrentField();
307 updateDirty();
308
309 // restore our cursor position.
310 setCursor(lr + 1, lc + 1);
311
312 setCursorActive(true);
313
314 }
315
316 /**
317 * Copy & Paste support
318 *
319 * @param position
320 * @return
321 * @see {@link #copyText(int)}
322 */
323 public final String copyTextField(int position) {
324 screenFields.saveCurrentField();
325 isInField(position);
326 String result = screenFields.getCurrentFieldText();
327 screenFields.restoreCurrentField();
328 return result;
329 }
330
331 /**
332 *
333 * Copy & Paste end code
334 *
335 */
336
337 /**
338 * Sum them
339 *
340 * @param which
341 * formatting option to use
342 * @return vector string of numberic values
343 */
344 public final Vector<Double> sumThem(boolean which, Rect area) {
345
346 StringBuilder sb = new StringBuilder();
347 Rect workR = new Rect();
348 workR.setBounds(area);
349
350 // gui.rubberband.reset();
351 // gui.repaint();
352
353 log.debug("Summing");
354
355 // obtain the decimal format for parsing
356 DecimalFormat df = (DecimalFormat) NumberFormat.getInstance();
357
358 DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();
359
360 if (which) {
361 dfs.setDecimalSeparator('.');
362 dfs.setGroupingSeparator(',');
363 } else {
364 dfs.setDecimalSeparator(',');
365 dfs.setGroupingSeparator('.');
366 }
367
368 df.setDecimalFormatSymbols(dfs);
369
370 Vector<Double> sumVector = new Vector<Double>();
371
372 // loop through all the screen characters to send them to the clip board
373 int m = workR.x;
374 int i = 0;
375 int t = 0;
376
377 double sum = 0.0;
378
379 while (workR.height-- > 0) {
380 t = workR.width;
381 i = workR.y;
382 while (t-- > 0) {
383
384 // only copy printable numeric characters (in this case >= ' ')
385 // char c = screen[getPos(m - 1, i - 1)].getChar();
386 char c = planes.getChar(getPos(m - 1, i - 1));
387 // if (((c >= '0' && c <= '9') || c == '.' || c == ',' || c == '-')
388 // && !screen[getPos(m - 1, i - 1)].nonDisplay) {
389
390 // TODO: update me here to implement the nonDisplay check as well
391 if (((c >= '0' && c <= '9') || c == '.' || c == ',' || c == '-')) {
392 sb.append(c);
393 }
394 i++;
395 }
396
397 if (sb.length() > 0) {
398 if (sb.charAt(sb.length() - 1) == '-') {
399 sb.insert(0, '-');
400 sb.deleteCharAt(sb.length() - 1);
401 }
402 try {
403 Number n = df.parse(sb.toString());
404 // System.out.println(s + " " + n.doubleValue());
405
406 sumVector.add(new Double(n.doubleValue()));
407 sum += n.doubleValue();
408 } catch (ParseException pe) {
409 log.warn(pe.getMessage() + " at "
410 + pe.getErrorOffset());
411 }
412 }
413 sb.setLength(0);
414 m++;
415 }
416 log.debug("" + sum);
417 return sumVector;
418 }
419
420 /**
421 * This will move the screen cursor based on the mouse event.
422 *
423 * I do not think the checks here for the gui characters should be here but
424 * will leave them here for now until we work out the interaction. This
425 * should be up to the gui frontend in my opinion.
426 *
427 * @param pos
428 */
429 public boolean moveCursor(int pos) {
430
431 if (!oia.isKeyBoardLocked()) {
432
433 if (pos < 0)
434 return false;
435 // because getRowColFromPoint returns offset of 1,1 we need to
436 // translate to offset 0,0
437 // pos -= (numCols + 1);
438
439 int g = planes.getWhichGUI(pos);
440
441 // lets check for hot spots
442 if (g >= BUTTON_LEFT && g <= BUTTON_LAST) {
443 StringBuffer aid = new StringBuffer();
444 boolean aidFlag = true;
445 switch (g) {
446 case BUTTON_RIGHT:
447 case BUTTON_MIDDLE:
448 while (planes.getWhichGUI(--pos) != BUTTON_LEFT) {
449 }
450 case BUTTON_LEFT:
451 if (planes.getChar(pos) == 'F') {
452 pos++;
453 } else
454 aidFlag = false;
455
456 if (planes.getChar(pos + 1) != '='
457 && planes.getChar(pos + 1) != '.'
458 && planes.getChar(pos + 1) != '/') {
459 // System.out.println(" Hotspot clicked!!! we will send
460 // characters " +
461 // screen[pos].getChar() +
462 // screen[pos+1].getChar());
463 aid.append(planes.getChar(pos));
464 aid.append(planes.getChar(pos + 1));
465 } else {
466 log.debug(" Hotspot clicked!!! we will send character "
467 + planes.getChar(pos));
468 aid.append(planes.getChar(pos));
469 }
470 break;
471
472 }
473 if (aidFlag) {
474 switch (g) {
475
476 case BUTTON_LEFT_UP:
477 case BUTTON_MIDDLE_UP:
478 case BUTTON_RIGHT_UP:
479 case BUTTON_ONE_UP:
480 case BUTTON_SB_UP:
481 case BUTTON_SB_GUIDE:
482 sessionVT.sendAidKey(AID_ROLL_UP);
483 break;
484
485 case BUTTON_LEFT_DN:
486 case BUTTON_MIDDLE_DN:
487 case BUTTON_RIGHT_DN:
488 case BUTTON_ONE_DN:
489 case BUTTON_SB_DN:
490 case BUTTON_SB_THUMB:
491
492 sessionVT.sendAidKey(AID_ROLL_DOWN);
493 break;
494 case BUTTON_LEFT_EB:
495 case BUTTON_MIDDLE_EB:
496 case BUTTON_RIGHT_EB:
497 StringBuffer eb = new StringBuffer();
498 while (planes.getWhichGUI(pos--) != BUTTON_LEFT_EB)
499 ;
500 while (planes.getWhichGUI(pos++) != BUTTON_RIGHT_EB) {
501 eb.append(planes.getChar(pos));
502 }
503 org.tn5250j.tools.system.OperatingSystem.displayURL(eb
504 .toString());
505 // take out the log statement when we are sure it is
506 // working
507 log.info("Send to external Browser: " + eb.toString());
508 break;
509
510 default:
511 int aidKey = Integer.parseInt(aid.toString());
512 if (aidKey >= 1 && aidKey <= 12)
513 sessionVT.sendAidKey(0x30 + aidKey);
514 if (aidKey >= 13 && aidKey <= 24)
515 sessionVT.sendAidKey(0xB0 + (aidKey - 12));
516 }
517 } else {
518 if (screenFields.getCurrentField() != null) {
519 int xPos = screenFields.getCurrentField().startPos();
520 for (int x = 0; x < aid.length(); x++) {
521 // System.out.println(sr + "," + (sc + x) + " " +
522 // aid.charAt(x));
523 planes.setChar(xPos + x , aid.charAt(x));
524 }
525 // System.out.println(aid);
526 screenFields.setCurrentFieldMDT();
527 sessionVT.sendAidKey(AID_ENTER);
528 }
529
530 }
531 // return back to the calling routine that the cursor was not moved
532 // but something else here was done like aid keys or the such
533 return false;
534 }
535 // this is a note to not execute this code here when we
536 // implement
537 // the remain after edit function option.
538 // if (gui.rubberband.isAreaSelected()) {
539 // gui.rubberband.reset();
540 // gui.repaint();
541 // } else {
542 goto_XY(pos);
543 isInField(lastPos);
544
545 // return back to the calling object that the cursor was indeed
546 // moved with in the screen object
547 return true;
548 // }
549 }
550 return false;
551 }
552
553 public void setVT(tnvt v) {
554
555 sessionVT = v;
556 }
557
558 /**
559 * Searches the mnemonicData array looking for the specified string. If it
560 * is found it will return the value associated from the mnemonicValue
561 *
562 * @see #sendKeys
563 * @param mnem
564 * string mnemonic value
565 * @return key value of Mnemonic
566 */
567 private int getMnemonicValue(String mnem) {
568
569 for (int x = 0; x < mnemonicData.length; x++) {
570
571 if (mnemonicData[x].equals(mnem))
572 return mnemonicValue[x];
573 }
574 return 0;
575
576 }
577
578 protected void setPrehelpState(boolean setErrorCode, boolean lockKeyboard,
579 boolean unlockIfLocked) {
580 if (oia.isKeyBoardLocked() && unlockIfLocked)
581 oia.setKeyBoardLocked(false);
582 else
583 oia.setKeyBoardLocked(lockKeyboard);
584 bufferedKeys = null;
585 oia.setKeysBuffered(false);
586
587
588 }
589
590 /**
591 * Activate the cursor on screen
592 *
593 * @param activate
594 */
595 public void setCursorActive(boolean activate) {
596
597 // System.out.println("cursor active " + updateCursorLoc + " " +
598 // cursorActive + " " + activate);
599 if (cursorActive && !activate) {
600 setCursorOff();
601 cursorActive = activate;
602 } else {
603 if (!cursorActive && activate) {
604 cursorActive = activate;
605 setCursorOn();
606 }
607 }
608 }
609
610 /**
611 * Set the cursor on
612 */
613 public void setCursorOn() {
614 cursorShown = true;
615 updateCursorLoc();
616 }
617
618 /**
619 * Set the cursor off
620 */
621 public void setCursorOff() {
622
623 cursorShown = false;
624 updateCursorLoc();
625 // System.out.println("cursor off " + updateCursorLoc + " " +
626 // cursorActive);
627
628 }
629
630 /**
631 *
632 */
633 private void updateCursorLoc() {
634
635 if (cursorActive) {
636
637 fireCursorChanged(3);
638
639 }
640 }
641
642 //Added by Barry
643 public String getKeys() {
644 String result = this.keybuf.toString();
645 this.keybuf = new StringBuffer();
646 return result;
647 }
648
649 /**
650 * The sendKeys method sends a string of keys to the virtual screen. This
651 * method acts as if keystrokes were being typed from the keyboard. The
652 * keystrokes will be sent to the location given. The string being passed
653 * can also contain mnemonic values such as [enter] enter key,[tab] tab key,
654 * [pf1] pf1 etc...
655 *
656 * These will be processed as if you had pressed these keys from the
657 * keyboard. All the valid special key values are contained in the MNEMONIC
658 * enumeration:
659 *
660 * <table BORDER COLS=2 WIDTH="50%" >
661 *
662 * <tr>
663 * <td>MNEMONIC_CLEAR</td>
664 * <td>[clear]</td>
665 * </tr>
666 * <tr>
667 * <td>MNEMONIC_ENTER</td>
668 * <td>[enter]</td>
669 * </tr>
670 * <tr>
671 * <td>MNEMONIC_HELP</td>
672 * <td>[help]</td>
673 * </tr>
674 * <tr>
675 * <td>MNEMONIC_PAGE_DOWN</td>
676 * <td>[pgdown]</td>
677 * </tr>
678 * <tr>
679 * <td>MNEMONIC_PAGE_UP</td>
680 * <td>[pgup]</td>
681 * </tr>
682 * <tr>
683 * <td>MNEMONIC_PRINT</td>
684 * <td>[print]</td>
685 * </tr>
686 * <tr>
687 * <td>MNEMONIC_PF1</td>
688 * <td>[pf1]</td>
689 * </tr>
690 * <tr>
691 * <td>MNEMONIC_PF2</td>
692 * <td>[pf2]</td>
693 * </tr>
694 * <tr>
695 * <td>MNEMONIC_PF3</td>
696 * <td>[pf3]</td>
697 * </tr>
698 * <tr>
699 * <td>MNEMONIC_PF4</td>
700 * <td>[pf4]</td>
701 * </tr>
702 * <tr>
703 * <td>MNEMONIC_PF5</td>
704 * <td>[pf5]</td>
705 * </tr>
706 * <tr>
707 * <td>MNEMONIC_PF6</td>
708 * <td>[pf6]</td>
709 * </tr>
710 * <tr>
711 * <td>MNEMONIC_PF7</td>
712 * <td>[pf7]</td>
713 * </tr>
714 * <tr>
715 * <td>MNEMONIC_PF8</td>
716 * <td>[pf8]</td>
717 * </tr>
718 * <tr>
719 * <td>MNEMONIC_PF9</td>
720 * <td>[pf9]</td>
721 * </tr>
722 * <tr>
723 * <td>MNEMONIC_PF10</td>
724 * <td>[pf10]</td>
725 * </tr>
726 * <tr>
727 * <td>MNEMONIC_PF11</td>
728 * <td>[pf11]</td>
729 * </tr>
730 * <tr>
731 * <td>MNEMONIC_PF12</td>
732 * <td>[pf12]</td>
733 * </tr>
734 * <tr>
735 * <td>MNEMONIC_PF13</td>
736 * <td>[pf13]</td>
737 * </tr>
738 * <tr>
739 * <td>MNEMONIC_PF14</td>
740 * <td>[pf14]</td>
741 * </tr>
742 * <tr>
743 * <td>MNEMONIC_PF15</td>
744 * <td>[pf15]</td>
745 * </tr>
746 * <tr>
747 * <td>MNEMONIC_PF16</td>
748 * <td>[pf16]</td>
749 * </tr>
750 * <tr>
751 * <td>MNEMONIC_PF17</td>
752 * <td>[pf17]</td>
753 * </tr>
754 * <tr>
755 * <td>MNEMONIC_PF18</td>
756 * <td>[pf18]</td>
757 * </tr>
758 * <tr>
759 * <td>MNEMONIC_PF19</td>
760 * <td>[pf19]</td>
761 * </tr>
762 * <tr>
763 * <td>MNEMONIC_PF20</td>
764 * <td>[pf20]</td>
765 * </tr>
766 * <tr>
767 * <td>MNEMONIC_PF21</td>
768 * <td>[pf21]</td>
769 * </tr>
770 * <tr>
771 * <td>MNEMONIC_PF22</td>
772 * <td>[pf22]</td>
773 * </tr>
774 * <tr>
775 * <td>MNEMONIC_PF23</td>
776 * <td>[pf23]</td>
777 * </tr>
778 * <tr>
779 * <td>MNEMONIC_PF24</td>
780 * <td>[pf24]</td>
781 * </tr>
782 * <tr>
783 * <td>MNEMONIC_BACK_SPACE</td>
784 * <td>[backspace]</td>
785 * </tr>
786 * <tr>
787 * <td>MNEMONIC_BACK_TAB</td>
788 * <td>[backtab]</td>
789 * </tr>
790 * <tr>
791 * <td>MNEMONIC_UP</td>
792 * <td>[up]</td>
793 * </tr>
794 * <tr>
795 * <td>MNEMONIC_DOWN</td>
796 * <td>[down]</td>
797 * </tr>
798 * <tr>
799 * <td>MNEMONIC_LEFT</td>
800 * <td>[left]</td>
801 * </tr>
802 * <tr>
803 * <td>MNEMONIC_RIGHT</td>
804 * <td>[right]</td>
805 * </tr>
806 * <tr>
807 * <td>MNEMONIC_DELETE</td>
808 * <td>[delete]</td>
809 * </tr>
810 * <tr>
811 * <td>MNEMONIC_TAB</td>
812 * <td>"[tab]</td>
813 * </tr>
814 * <tr>
815 * <td>MNEMONIC_END_OF_FIELD</td>
816 * <td>[eof]</td>
817 * </tr>
818 * <tr>
819 * <td>MNEMONIC_ERASE_EOF</td>
820 * <td>[eraseeof]</td>
821 * </tr>
822 * <tr>
823 * <td>MNEMONIC_ERASE_FIELD</td>
824 * <td>[erasefld]</td>
825 * </tr>
826 * <tr>
827 * <td>MNEMONIC_INSERT</td>
828 * <td>[insert]</td>
829 * </tr>
830 * <tr>
831 * <td>MNEMONIC_HOME</td>
832 * <td>[home]</td>
833 * </tr>
834 * <tr>
835 * <td>MNEMONIC_KEYPAD0</td>
836 * <td>[keypad0]</td>
837 * </tr>
838 * <tr>
839 * <td>MNEMONIC_KEYPAD1</td>
840 * <td>[keypad1]</td>
841 * </tr>
842 * <tr>
843 * <td>MNEMONIC_KEYPAD2</td>
844 * <td>[keypad2]</td>
845 * </tr>
846 * <tr>
847 * <td>MNEMONIC_KEYPAD3</td>
848 * <td>[keypad3]</td>
849 * </tr>
850 * <tr>
851 * <td>MNEMONIC_KEYPAD4</td>
852 * <td>[keypad4]</td>
853 * </tr>
854 * <tr>
855 * <td>MNEMONIC_KEYPAD5</td>
856 * <td>[keypad5]</td>
857 * </tr>
858 * <tr>
859 * <td>MNEMONIC_KEYPAD6</td>
860 * <td>[keypad6]</td>
861 * </tr>
862 * <tr>
863 * <td>MNEMONIC_KEYPAD7</td>
864 * <td>[keypad7]</td>
865 * </tr>
866 * <tr>
867 * <td>MNEMONIC_KEYPAD8</td>
868 * <td>[keypad8]</td>
869 * </tr>
870 * <tr>
871 * <td>MNEMONIC_KEYPAD9</td>
872 * <td>[keypad9]</td>
873 * </tr>
874 * <tr>
875 * <td>MNEMONIC_KEYPAD_PERIOD</td>
876 * <td>[keypad.]</td>
877 * </tr>
878 * <tr>
879 * <td>MNEMONIC_KEYPAD_COMMA</td>
880 * <td>[keypad,]</td>
881 * </tr>
882 * <tr>
883 * <td>MNEMONIC_KEYPAD_MINUS</td>
884 * <td>[keypad-]</td>
885 * </tr>
886 * <tr>
887 * <td>MNEMONIC_FIELD_EXIT</td>
888 * <td>[fldext]</td>
889 * </tr>
890 * <tr>
891 * <td>MNEMONIC_FIELD_PLUS</td>
892 * <td>[field+]</td>
893 * </tr>
894 * <tr>
895 * <td>MNEMONIC_FIELD_MINUS</td>
896 * <td>[field-]</td>
897 * </tr>
898 * <tr>
899 * <td>MNEMONIC_BEGIN_OF_FIELD</td>
900 * <td>[bof]</td>
901 * </tr>
902 * <tr>
903 * <td>MNEMONIC_PA1</td>
904 * <td>[pa1]</td>
905 * </tr>
906 * <tr>
907 * <td>MNEMONIC_PA2</td>
908 * <td>[pa2]</td>
909 * </tr>
910 * <tr>
911 * <td>MNEMONIC_PA3</td>
912 * <td>[pa3]</td>
913 * </tr>
914 * <tr>
915 * <td>MNEMONIC_SYSREQ</td>
916 * <td>[sysreq]</td>
917 * </tr>
918 * <tr>
919 * <td>MNEMONIC_RESET</td>
920 * <td>[reset]</td>
921 * </tr>
922 * <tr>
923 * <td>MNEMONIC_ATTN</td>
924 * <td>[attn]</td>
925 * </tr>
926 * <tr>
927 * <td>MNEMONIC_MARK_LEFT</td>
928 * <td>[markleft]</td>
929 * </tr>
930 * <tr>
931 * <td>MNEMONIC_MARK_RIGHT</td>
932 * <td>[markright]</td>
933 * </tr>
934 * <tr>
935 * <td>MNEMONIC_MARK_UP</td>
936 * <td>[markup]</td>
937 * </tr>
938 * <tr>
939 * <td>MNEMONIC_MARK_DOWN</td>
940 * <td>[markdown]</td>
941 * </tr>
942 *
943 * </table>
944 *
945 * @param text
946 * The string of characters to be sent
947 *
948 * @see #sendAid
949 *
950 * Added synchronized to fix a StringOutOfBounds error - Luc Gorren LDC
951 */
952 public synchronized void sendKeys(String text) {
953
954 // if (text == null) {
955 // return;
956 // }
957 this.keybuf.append(text);
958
959 if (isStatusErrorCode() && !resetRequired) {
960 setCursorActive(false);
961 simulateMnemonic(getMnemonicValue("[reset]"));
962 setCursorActive(true);
963 }
964
965 if (oia.isKeyBoardLocked()) {
966 if (text.equals("[reset]") || text.equals("[sysreq]")
967 || text.equals("[attn]")) {
968 setCursorActive(false);
969 simulateMnemonic(getMnemonicValue(text));
970 setCursorActive(true);
971
972 } else {
973 if (isStatusErrorCode()) {
974 sessionVT.signalBell();
975 return;
976 }
977
978 oia.setKeysBuffered(true);
979
980 if (bufferedKeys == null) {
981 bufferedKeys = text;
982 return;
983 }
984 bufferedKeys += text;
985 return;
986 }
987
988 } else {
989
990 if (oia.isKeysBuffered()) {
991 if (bufferedKeys != null) {
992 text = bufferedKeys + text;
993 }
994 // if (text.length() == 0) {
995 oia.setKeysBuffered(false);
996 // }
997 bufferedKeys = null;
998
999 }
1000 // check to see if position is in a field and if it is then change
1001 // current field to that field
1002 isInField(lastPos, true);
1003 if (text.length() == 1 && !text.equals("[") && !text.equals("]")) {
1004 // setCursorOff2();
1005 setCursorActive(false);
1006 simulateKeyStroke(text.charAt(0));
1007 setCursorActive(true);
1008 // setCursorOn2();
1009 // System.out.println(" text one");
1010
1011 } else {
1012
1013 strokenizer.setKeyStrokes(text);
1014 String s;
1015 boolean done = false;
1016
1017 // setCursorOff2();
1018 setCursorActive(false);
1019 while (!done) {
1020 // while (strokenizer.hasMoreKeyStrokes() && !keyboardLocked
1021 // &&
1022 // !isStatusErrorCode() && !done) {
1023 if (strokenizer.hasMoreKeyStrokes()) {
1024
1025 // check to see if position is in a field and if it is
1026 // then change
1027 // current field to that field
1028 isInField(lastPos, true);
1029 s = strokenizer.nextKeyStroke();
1030 if (s.length() == 1) {
1031 // setCursorOn();
1032 // if (!keysBuffered) {
1033 // System.out.println(" s two" + s);
1034 // setCursorOn();
1035 // }
1036
1037 // try { new Thread().sleep(400);} catch
1038 // (InterruptedException ie) {}
1039 simulateKeyStroke(s.charAt(0));
1040 // System.out.println(" s two " + s + " " +
1041 // cursorActive);
1042 // if (cursorActive && !keysBuffered) {
1043 // System.out.println(" s two" + s);
1044 // setCursorOn();
1045 // }
1046 } else {
1047 simulateMnemonic(getMnemonicValue(s));
1048 // if (!cursorActive && !keysBuffered) {
1049 // System.out.println(" m one");
1050 // setCursorOn();
1051 // }
1052 }
1053
1054 if (oia.isKeyBoardLocked()) {
1055
1056 bufferedKeys = strokenizer
1057 .getUnprocessedKeyStroked();
1058 if (bufferedKeys != null) {
1059 oia.setKeysBuffered(true);
1060
1061 }
1062 done = true;
1063 }
1064
1065 }
1066
1067 else {
1068 // setCursorActive(true);
1069 // setCursorOn();
1070 done = true;
1071 }
1072 }
1073 setCursorActive(true);
1074 }
1075 }
1076 }
1077
1078 /**
1079 * The sendAid method sends an "aid" keystroke to the virtual screen. These
1080 * aid keys can be thought of as special keystrokes, like the Enter key,
1081 * PF1-24 keys or the Page Up key. All the valid special key values are
1082 * contained in the AID_ enumeration:
1083 *
1084 * @param aidKey
1085 * The aid key to be sent to the host
1086 *
1087 * @see #sendKeys
1088 * @see TN5250jConstants#AID_CLEAR
1089 * @see #AID_ENTER
1090 * @see #AID_HELP
1091 * @see #AID_ROLL_UP
1092 * @see #AID_ROLL_DOWN
1093 * @see #AID_ROLL_LEFT
1094 * @see #AID_ROLL_RIGHT
1095 * @see #AID_PRINT
1096 * @see #AID_PF1
1097 * @see #AID_PF2
1098 * @see #AID_PF3
1099 * @see #AID_PF4
1100 * @see #AID_PF5
1101 * @see #AID_PF6
1102 * @see #AID_PF7
1103 * @see #AID_PF8
1104 * @see #AID_PF9
1105 * @see #AID_PF10
1106 * @see #AID_PF11
1107 * @see #AID_PF12
1108 * @see #AID_PF13
1109 * @see #AID_PF14
1110 * @see #AID_PF15
1111 * @see #AID_PF16
1112 * @see #AID_PF17
1113 * @see #AID_PF18
1114 * @see #AID_PF19
1115 * @see #AID_PF20
1116 * @see #AID_PF21
1117 * @see #AID_PF22
1118 * @see #AID_PF23
1119 * @see #AID_PF24
1120 */
1121 public void sendAid(int aidKey) {
1122
1123 sessionVT.sendAidKey(aidKey);
1124 }
1125
1126 /**
1127 * Restores the error line and sets the error mode off.
1128 *
1129 */
1130 protected void resetError() {
1131
1132 restoreErrorLine();
1133 setStatus(STATUS_ERROR_CODE, STATUS_VALUE_OFF, "");
1134
1135 }
1136
1137 protected boolean simulateMnemonic(int mnem) {
1138
1139 boolean simulated = false;
1140
1141 switch (mnem) {
1142
1143 case AID_CLEAR:
1144 case AID_ENTER:
1145 case AID_PF1:
1146 case AID_PF2:
1147 case AID_PF3:
1148 case AID_PF4:
1149 case AID_PF5:
1150 case AID_PF6:
1151 case AID_PF7:
1152 case AID_PF8:
1153 case AID_PF9:
1154 case AID_PF10:
1155 case AID_PF11:
1156 case AID_PF12:
1157 case AID_PF13:
1158 case AID_PF14:
1159 case AID_PF15:
1160 case AID_PF16:
1161 case AID_PF17:
1162 case AID_PF18:
1163 case AID_PF19:
1164 case AID_PF20:
1165 case AID_PF21:
1166 case AID_PF22:
1167 case AID_PF23:
1168 case AID_PF24:
1169 case AID_ROLL_DOWN:
1170 case AID_ROLL_UP:
1171 case AID_ROLL_LEFT:
1172 case AID_ROLL_RIGHT:
1173
1174 if (!screenFields.isCanSendAid()) {
1175 displayError(ERR_ENTER_NO_ALLOWED);
1176 } else
1177 sendAid(mnem);
1178 simulated = true;
1179
1180 break;
1181 case AID_HELP:
1182 sessionVT.sendHelpRequest();
1183 simulated = true;
1184 break;
1185
1186 case AID_PRINT:
1187 sessionVT.hostPrint(1);
1188 simulated = true;
1189 break;
1190
1191 case BACK_SPACE:
1192 if (screenFields.getCurrentField() != null
1193 && screenFields.withinCurrentField(lastPos)
1194 && !screenFields.isCurrentFieldBypassField()) {
1195
1196 if (screenFields.getCurrentField().startPos() == lastPos) {
1197 if (backspaceError)
1198 displayError(ERR_CURSOR_PROTECTED);
1199 else {
1200 gotoFieldPrev();
1201 goto_XY(screenFields.getCurrentField().endPos());
1202 updateDirty();
1203 }
1204 }
1205 else {
1206 screenFields.getCurrentField().getKeyPos(lastPos);
1207 screenFields.getCurrentField().changePos(-1);
1208 resetDirty(screenFields.getCurrentField().getCurrentPos());
1209 shiftLeft(screenFields.getCurrentField().getCurrentPos());
1210 updateDirty();
1211 screenFields.setCurrentFieldMDT();
1212
1213 simulated = true;
1214 }
1215 } else {
1216 displayError(ERR_CURSOR_PROTECTED);
1217
1218 }
1219 break;
1220 case BACK_TAB:
1221
1222 if (screenFields.getCurrentField() != null
1223 && screenFields.isCurrentFieldHighlightedEntry()) {
1224 resetDirty(screenFields.getCurrentField().startPos);
1225 gotoFieldPrev();
1226 updateDirty();
1227 } else
1228 gotoFieldPrev();
1229
1230 if (screenFields.isCurrentFieldContinued()) {
1231 do {
1232 gotoFieldPrev();
1233 } while (screenFields.isCurrentFieldContinuedMiddle()
1234 || screenFields.isCurrentFieldContinuedLast());
1235 }
1236 isInField(lastPos);
1237 simulated = true;
1238 break;
1239 case UP:
1240 case MARK_UP:
1241 process_XY(lastPos - numCols);
1242 simulated = true;
1243 break;
1244 case DOWN:
1245 case MARK_DOWN:
1246 process_XY(lastPos + numCols);
1247 simulated = true;
1248 break;
1249 case LEFT:
1250 case MARK_LEFT:
1251 process_XY(lastPos - 1);
1252 simulated = true;
1253 break;
1254 case RIGHT:
1255 case MARK_RIGHT:
1256 process_XY(lastPos + 1);
1257 simulated = true;
1258 break;
1259 case NEXTWORD:
1260 gotoNextWord();
1261 simulated = true;
1262 break;
1263 case PREVWORD:
1264 gotoPrevWord();
1265 simulated = true;
1266 break;
1267 case DELETE:
1268 if (screenFields.getCurrentField() != null
1269 && screenFields.withinCurrentField(lastPos)
1270 && !screenFields.isCurrentFieldBypassField()) {
1271
1272 resetDirty(lastPos);
1273 screenFields.getCurrentField().getKeyPos(lastPos);
1274 shiftLeft(screenFields.getCurrentFieldPos());
1275 screenFields.setCurrentFieldMDT();
1276 updateDirty();
1277 simulated = true;
1278 } else {
1279 displayError(ERR_CURSOR_PROTECTED);
1280 }
1281
1282 break;
1283 case TAB:
1284
1285 if (screenFields.getCurrentField() != null
1286 && !screenFields.isCurrentFieldContinued()) {
1287 if (screenFields.isCurrentFieldHighlightedEntry()) {
1288 resetDirty(screenFields.getCurrentField().startPos);
1289 gotoFieldNext();
1290 updateDirty();
1291 } else
1292 gotoFieldNext();
1293 } else {
1294 do {
1295 gotoFieldNext();
1296 } while (screenFields.getCurrentField() != null
1297 && (screenFields.isCurrentFieldContinuedMiddle() || screenFields
1298 .isCurrentFieldContinuedLast()));
1299 }
1300
1301 isInField(lastPos);
1302 simulated = true;
1303
1304 break;
1305 case EOF:
1306 if (screenFields.getCurrentField() != null
1307 && screenFields.withinCurrentField(lastPos)
1308 && !screenFields.isCurrentFieldBypassField()) {
1309 int where = endOfField(screenFields.getCurrentField()
1310 .startPos(), true);
1311 if (where > 0) {
1312 setCursor((where / numCols) + 1, (where % numCols) + 1);
1313 }
1314 simulated = true;
1315 } else {
1316 displayError(ERR_CURSOR_PROTECTED);
1317 }
1318 resetDirty(lastPos);
1319
1320 break;
1321 case ERASE_EOF:
1322 if (screenFields.getCurrentField() != null
1323 && screenFields.withinCurrentField(lastPos)
1324 && !screenFields.isCurrentFieldBypassField()) {
1325
1326 int where = lastPos;
1327 resetDirty(lastPos);
1328 if (fieldExit()) {
1329 screenFields.setCurrentFieldMDT();
1330 if (!screenFields.isCurrentFieldContinued()) {
1331 gotoFieldNext();
1332 } else {
1333 do {
1334 gotoFieldNext();
1335 if (screenFields.isCurrentFieldContinued())
1336 fieldExit();
1337 } while (screenFields.isCurrentFieldContinuedMiddle()
1338 || screenFields.isCurrentFieldContinuedLast());
1339 }
1340 }
1341 updateDirty();
1342 goto_XY(where);
1343 simulated = true;
1344
1345 } else {
1346 displayError(ERR_CURSOR_PROTECTED);
1347 }
1348
1349 break;
1350 case ERASE_FIELD:
1351 if (screenFields.getCurrentField() != null
1352 && screenFields.withinCurrentField(lastPos)
1353 && !screenFields.isCurrentFieldBypassField()) {
1354
1355 int where = lastPos;
1356 lastPos = screenFields.getCurrentField().startPos();
1357 resetDirty(lastPos);
1358 if (fieldExit()) {
1359 screenFields.setCurrentFieldMDT();
1360 if (!screenFields.isCurrentFieldContinued()) {
1361 gotoFieldNext();
1362 } else {
1363 do {
1364 gotoFieldNext();
1365 if (screenFields.isCurrentFieldContinued())
1366 fieldExit();
1367 } while (screenFields.isCurrentFieldContinuedMiddle()
1368 || screenFields.isCurrentFieldContinuedLast());
1369 }
1370 }
1371 updateDirty();
1372 goto_XY(where);
1373 simulated = true;
1374
1375 } else {
1376 displayError(ERR_CURSOR_PROTECTED);
1377 }
1378
1379 break;
1380 case INSERT:
1381 // we toggle it
1382 oia.setInsertMode(oia.isInsertMode() ? false : true);
1383 break;
1384 case HOME:
1385 // position to the home position set
1386 if (lastPos + numCols + 1 != homePos) {
1387 goto_XY(homePos - numCols - 1);
1388 // now check if we are in a field
1389 isInField(lastPos);
1390 } else
1391 gotoField(1);
1392 break;
1393 case KEYPAD_0:
1394 simulated = simulateKeyStroke('0');
1395 break;
1396 case KEYPAD_1:
1397 simulated = simulateKeyStroke('1');
1398 break;
1399 case KEYPAD_2:
1400 simulated = simulateKeyStroke('2');
1401 break;
1402 case KEYPAD_3:
1403 simulated = simulateKeyStroke('3');
1404 break;
1405 case KEYPAD_4:
1406 simulated = simulateKeyStroke('4');
1407 break;
1408 case KEYPAD_5:
1409 simulated = simulateKeyStroke('5');
1410 break;
1411 case KEYPAD_6:
1412 simulated = simulateKeyStroke('6');
1413 break;
1414 case KEYPAD_7:
1415 simulated = simulateKeyStroke('7');
1416 break;
1417 case KEYPAD_8:
1418 simulated = simulateKeyStroke('8');
1419 break;
1420 case KEYPAD_9:
1421 simulated = simulateKeyStroke('9');
1422 break;
1423 case KEYPAD_PERIOD:
1424 simulated = simulateKeyStroke('.');
1425 break;
1426 case KEYPAD_COMMA:
1427 simulated = simulateKeyStroke(',');
1428 break;
1429 case KEYPAD_MINUS:
1430 if (screenFields.getCurrentField() != null
1431 && screenFields.withinCurrentField(lastPos)
1432 && !screenFields.isCurrentFieldBypassField()) {
1433
1434 int s = screenFields.getCurrentField().getFieldShift();
1435 if (s == 3 || s == 5 || s == 7) {
1436 planes.setChar(lastPos,'-');
1437
1438 resetDirty(lastPos);
1439 advancePos();
1440 if (fieldExit()) {
1441 screenFields.setCurrentFieldMDT();
1442 if (!screenFields.isCurrentFieldContinued()) {
1443 gotoFieldNext();
1444 } else {
1445 do {
1446 gotoFieldNext();
1447 } while (screenFields
1448 .isCurrentFieldContinuedMiddle()
1449 || screenFields
1450 .isCurrentFieldContinuedLast());
1451 }
1452 simulated = true;
1453 updateDirty();
1454 if (screenFields.isCurrentFieldAutoEnter())
1455 sendAid(AID_ENTER);
1456
1457 }
1458 } else {
1459 displayError(ERR_FIELD_MINUS);
1460
1461 }
1462 } else {
1463 displayError(ERR_CURSOR_PROTECTED);
1464 }
1465
1466 break;
1467 case FIELD_EXIT:
1468 if (screenFields.getCurrentField() != null
1469 && screenFields.withinCurrentField(lastPos)
1470 && !screenFields.isCurrentFieldBypassField()) {
1471
1472 resetDirty(lastPos);
1473
1474 boolean autoFE = screenFields.isCurrentFieldAutoEnter();
1475
1476 if (fieldExit()) {
1477 screenFields.setCurrentFieldMDT();
1478 if (!screenFields.isCurrentFieldContinued() &&
1479 !screenFields.isCurrentFieldAutoEnter()) {
1480 gotoFieldNext();
1481 } else {
1482 do {
1483 gotoFieldNext();
1484 if (screenFields.isCurrentFieldContinued())
1485 fieldExit();
1486 } while (screenFields.isCurrentFieldContinuedMiddle()
1487 || screenFields.isCurrentFieldContinuedLast());
1488 }
1489 }
1490
1491 updateDirty();
1492 simulated = true;
1493 if (autoFE)
1494 sendAid(AID_ENTER);
1495
1496 } else {
1497 displayError(ERR_CURSOR_PROTECTED);
1498 }
1499
1500 break;
1501 case FIELD_PLUS:
1502 if (screenFields.getCurrentField() != null
1503 && screenFields.withinCurrentField(lastPos)
1504 && !screenFields.isCurrentFieldBypassField()) {
1505
1506 resetDirty(lastPos);
1507
1508 boolean autoFE = screenFields.isCurrentFieldAutoEnter();
1509 if (fieldExit()) {
1510 screenFields.setCurrentFieldMDT();
1511 if (!screenFields.isCurrentFieldContinued() &&
1512 !screenFields.isCurrentFieldAutoEnter()) {
1513 gotoFieldNext();
1514 } else {
1515 do {
1516 gotoFieldNext();
1517 } while (screenFields.isCurrentFieldContinuedMiddle()
1518 || screenFields.isCurrentFieldContinuedLast());
1519 }
1520 }
1521 updateDirty();
1522 simulated = true;
1523
1524 if (autoFE)
1525 sendAid(AID_ENTER);
1526
1527 } else {
1528 displayError(ERR_CURSOR_PROTECTED);
1529 }
1530
1531 break;
1532 case FIELD_MINUS:
1533 if (screenFields.getCurrentField() != null
1534 && screenFields.withinCurrentField(lastPos)
1535 && !screenFields.isCurrentFieldBypassField()) {
1536
1537 int s = screenFields.getCurrentField().getFieldShift();
1538 if (s == 3 || s == 5 || s == 7) {
1539 planes.setChar(lastPos, '-');
1540
1541 resetDirty(lastPos);
1542 advancePos();
1543
1544 boolean autoFE = screenFields.isCurrentFieldAutoEnter();
1545
1546 if (fieldExit()) {
1547 screenFields.setCurrentFieldMDT();
1548 if (!screenFields.isCurrentFieldContinued()
1549 && !screenFields.isCurrentFieldAutoEnter()) {
1550 gotoFieldNext();
1551 }
1552 else {
1553 do {
1554 gotoFieldNext();
1555 }
1556 while (screenFields.isCurrentFieldContinuedMiddle()
1557 || screenFields.isCurrentFieldContinuedLast());
1558 }
1559 }
1560 updateDirty();
1561 simulated = true;
1562 if (autoFE)
1563 sendAid(AID_ENTER);
1564
1565 }
1566 else {
1567 displayError(ERR_FIELD_MINUS);
1568
1569 }
1570 }
1571 else {
1572 displayError(ERR_CURSOR_PROTECTED);
1573 }
1574
1575 break;
1576 case BOF:
1577 if (screenFields.getCurrentField() != null
1578 && screenFields.withinCurrentField(lastPos)
1579 && !screenFields.isCurrentFieldBypassField()) {
1580 int where = screenFields.getCurrentField().startPos();
1581 if (where > 0) {
1582 goto_XY(where);
1583 }
1584 simulated = true;
1585 } else {
1586 displayError(ERR_CURSOR_PROTECTED);
1587 }
1588 resetDirty(lastPos);
1589
1590 break;
1591 case SYSREQ:
1592 sessionVT.systemRequest();
1593 simulated = true;
1594 break;
1595 case RESET:
1596 if (isStatusErrorCode()) {
1597 resetError();
1598 isInField(lastPos);
1599 updateDirty();
1600 } else {
1601 setPrehelpState(false, oia.isKeyBoardLocked(), false);
1602 }
1603 simulated = true;
1604 break;
1605 case ATTN:
1606 sessionVT.sendAttentionKey();
1607 simulated = true;
1608 break;
1609 case DUP_FIELD:
1610 if (screenFields.getCurrentField() != null
1611 && screenFields.withinCurrentField(lastPos)
1612 && !screenFields.isCurrentFieldBypassField()) {
1613
1614 if (screenFields.isCurrentFieldDupEnabled()) {
1615 resetDirty(lastPos);
1616 screenFields.getCurrentField().setFieldChar(lastPos,
1617 (char) 0x1C);
1618 screenFields.setCurrentFieldMDT();
1619 gotoFieldNext();
1620 updateDirty();
1621 simulated = true;
1622 } else {
1623 displayError(ERR_DUP_KEY_NOT_ALLOWED);
1624 }
1625 } else {
1626 displayError(ERR_CURSOR_PROTECTED);
1627 }
1628
1629 break;
1630 case NEW_LINE:
1631 if (screenFields.getSize() > 0) {
1632 int startRow = getRow(lastPos) + 1;
1633 int startPos = lastPos;
1634
1635 if (startRow == getRows())
1636 startRow = 0;
1637
1638 setCursor(++startRow, 1);
1639
1640 if (!isInField() && screenFields.getCurrentField() != null
1641 && !screenFields.isCurrentFieldBypassField()) {
1642 while (!isInField()
1643 && screenFields.getCurrentField() != null
1644 && !screenFields.isCurrentFieldBypassField()) {
1645
1646 // lets keep going
1647 advancePos();
1648
1649 // Have we looped the screen?
1650 if (lastPos == startPos) {
1651 // if so then go back to starting point
1652 goto_XY(startPos);
1653 break;
1654 }
1655 }
1656 }
1657 }
1658 simulated = true;
1659 break;
1660 case FAST_CURSOR_DOWN:
1661 int rowNow = (getCurrentRow()-1) + 3;
1662 if (rowNow > getRows()-1)
1663 rowNow = rowNow - getRows();
1664 this.goto_XY(getPos(rowNow,getCurrentCol()-1));
1665 simulated = true;
1666 break;
1667 case FAST_CURSOR_UP:
1668 rowNow = (getCurrentRow()-1) - 3;
1669 if (rowNow < 0)
1670 rowNow = (getRows()) + rowNow;
1671 this.goto_XY(getPos(rowNow,getCurrentCol()-1));
1672 simulated = true;
1673 break;
1674 case FAST_CURSOR_LEFT:
1675 int colNow = (getCurrentCol()-1) - 3;
1676 rowNow = getCurrentRow()-1;
1677 if (colNow <= 0) {
1678 colNow = getColumns() + colNow;
1679 rowNow--;
1680 }
1681 if (rowNow < 0)
1682 rowNow = getRows() - 1;
1683
1684 process_XY(getPos(rowNow,colNow));
1685 simulated = true;
1686 break;
1687 case FAST_CURSOR_RIGHT:
1688 colNow = (getCurrentCol()-1) + 3;
1689 rowNow = getCurrentRow()-1;
1690 if (colNow >= getColumns()) {
1691 colNow = colNow - getColumns();
1692 rowNow++;
1693 }
1694 if (rowNow > getRows() - 1)
1695 rowNow = getRows() - rowNow;
1696
1697 process_XY(getPos(rowNow,colNow));
1698 simulated = true;
1699 break;
1700 default:
1701 log.info(" Mnemonic not supported " + mnem);
1702 break;
1703
1704 }
1705
1706 return simulated;
1707 }
1708
1709 protected boolean simulateKeyStroke(char c) {
1710
1711 if (isStatusErrorCode() && !Character.isISOControl(c) && !keyProcessed) {
1712 if (resetRequired) return false;
1713 resetError();
1714 }
1715
1716 boolean updateField = false;
1717 boolean numericError = false;
1718 boolean updatePos = false;
1719 boolean autoEnter = false;
1720
1721 if (!Character.isISOControl(c)) {
1722
1723 if (screenFields.getCurrentField() != null
1724 && screenFields.withinCurrentField(lastPos)
1725 && !screenFields.isCurrentFieldBypassField()) {
1726
1727 if (screenFields.isCurrentFieldFER()
1728 && !screenFields.withinCurrentField(screenFields
1729 .getCurrentFieldPos())
1730 && lastPos == screenFields.getCurrentField().endPos()
1731 && screenFields.getCurrentFieldPos() > screenFields
1732 .getCurrentField().endPos()) {
1733
1734 displayError(ERR_FIELD_EXIT_INVALID);
1735 feError = true;
1736 return false;
1737 }
1738
1739 switch (screenFields.getCurrentFieldShift()) {
1740 case 0: // Alpha shift
1741 case 2: // Numeric Shift
1742 case 4: // Kakana Shift
1743 updateField = true;
1744 break;
1745 case 1: // Alpha Only
1746 if (Character.isLetter(c) || c == ',' || c == '-'
1747 || c == '.' || c == ' ')
1748 updateField = true;
1749 break;
1750 case 3: // Numeric only
1751 if (Character.isDigit(c) || c == '+' || c == ','
1752 || c == '-' || c == '.' || c == ' ')
1753 updateField = true;
1754 else
1755 numericError = true;
1756 break;
1757 case 5: // Digits only
1758 if (Character.isDigit(c))
1759 updateField = true;
1760 else
1761 displayError(ERR_NUMERIC_09);
1762 break;
1763 case 7: // Signed numeric
1764 if (Character.isDigit(c) || c == '+' || c == '-')
1765 if (lastPos == screenFields.getCurrentField().endPos()
1766 && (c != '+' && c != '-'))
1767 displayError(ERR_INVALID_SIGN);
1768 else
1769 updateField = true;
1770 else
1771 displayError(ERR_NUMERIC_09);
1772 break;
1773 }
1774
1775 if (updateField) {
1776 if (screenFields.isCurrentFieldToUpper())
1777 c = Character.toUpperCase(c);
1778
1779 updatePos = true;
1780 resetDirty(lastPos);
1781
1782 if (oia.isInsertMode()) {
1783 if (endOfField(false) != screenFields.getCurrentField()
1784 .endPos())
1785 shiftRight(lastPos);
1786 else {
1787
1788 displayError(ERR_NO_ROOM_INSERT);
1789 updatePos = false;
1790 }
1791
1792 }
1793
1794 if (updatePos) {
1795 screenFields.getCurrentField().getKeyPos(
1796 getRow(lastPos), getCol(lastPos));
1797 screenFields.getCurrentField().changePos(1);
1798
1799 planes.setChar(lastPos,c);
1800
1801 screenFields.setCurrentFieldMDT();
1802
1803 // if we have gone passed the end of the field then goto
1804 // the next field
1805 if (!screenFields.withinCurrentField(screenFields
1806 .getCurrentFieldPos())) {
1807 if (screenFields.isCurrentFieldAutoEnter()) {
1808 autoEnter = true;
1809 } else if (!screenFields.isCurrentFieldFER())
1810 gotoFieldNext();
1811 else {
1812 // screenFields.getCurrentField().changePos(1);
1813 //
1814 // if (screenFields.
1815 // cursorPos == endPos)
1816 // System.out.println("end of field");
1817 //
1818 // feError != feError;
1819 // if (feError)
1820 // displayError(ERR_FIELD_EXIT_INVALID);
1821 }
1822
1823 } else
1824 setCursor(screenFields.getCurrentField()
1825 .getCursorRow() + 1, screenFields
1826 .getCurrentField().getCursorCol() + 1);
1827
1828 }
1829
1830 fireScreenChanged(1);
1831
1832 if (autoEnter)
1833 sendAid(AID_ENTER);
1834 } else {
1835 if (numericError) {
1836 displayError(ERR_NUMERIC_ONLY);
1837 }
1838 }
1839 } else {
1840 displayError(ERR_CURSOR_PROTECTED);
1841 }
1842
1843 }
1844 return updatePos;
1845 }
1846
1847 /**
1848 * Method: endOfField
1849 * <p>
1850 *
1851 * convenience method that call endOfField with lastRow lastCol and passes
1852 * the posSpace to that method
1853 *
1854 * @param posSpace
1855 * value of type boolean - specifying to return the position of
1856 * the the last space or not
1857 * @return a value of type int - the screen postion (row * columns) + col
1858 *
1859 */
1860 private int endOfField(boolean posSpace) {
1861 return endOfField(lastPos, posSpace);
1862 }
1863
1864 /**
1865 * Method: endOfField
1866 * <p>
1867 *
1868 * gets the position of the last character of the current field posSpace
1869 * parameter tells the routine whether to return the position of the last
1870 * space ( <= ' ') or the last non space posSpace == true last occurrence of
1871 * char <= ' ' posSpace == false last occurrence of char > ' '
1872 *
1873 * @param pos
1874 * value of type int - position to start from
1875 * @param posSpace
1876 * value of type boolean - specifying to return the position of
1877 * the the last space or not
1878 * @return a value of type int - the screen postion (row * columns) + col
1879 *
1880 */
1881 private int endOfField(int pos, boolean posSpace) {
1882
1883 int endPos = screenFields.getCurrentField().endPos();
1884 int fePos = endPos;
1885 // get the number of characters to the right
1886 int count = endPos - pos;
1887
1888 // first lets get the real ending point without spaces and the such
1889 while (planes.getChar(endPos) <= ' ' && count-- > 0) {
1890
1891 endPos--;
1892 }
1893
1894 if (endPos == fePos) {
1895
1896 return endPos;
1897
1898 }
1899 screenFields.getCurrentField().getKeyPos(endPos);
1900 if (posSpace) screenFields.getCurrentField().changePos(+1);
1901 return screenFields.getCurrentFieldPos();
1902
1903 }
1904
1905 private boolean fieldExit() {
1906
1907 int pos = lastPos;
1908 boolean mdt = false;
1909 int end = endOfField(false); // get the ending position of the first
1910 // non blank character in field
1911
1912 ScreenField sf = screenFields.getCurrentField();
1913
1914 if (sf.isMandatoryEnter() && end == sf.startPos()) {
1915 displayError(ERR_MANDITORY_ENTER);
1916 return false;
1917 }
1918
1919 // save off the current pos of the field for checking field exit required
1920 // positioning. the getKeyPos resets this information so it is useless
1921 // for comparing if we are positioned passed the end of field.
1922 // Maybe this should be changed to not update the current cursor position
1923 // of the field.
1924 int currentPos = sf.getCurrentPos();
1925
1926 // get the number of characters to the right
1927 int count = (end - sf.startPos()) - sf.getKeyPos(pos);
1928
1929 if (count == 0 && sf.isFER()) {
1930 if (currentPos > sf.endPos()) {
1931 mdt = true;
1932 return mdt;
1933 }
1934 }
1935
1936 for (; count >= 0; count--) {
1937 planes.setChar(pos, initChar);
1938 setDirty(pos);
1939 pos++;
1940 mdt = true;
1941 }
1942
1943 // This checks for a field minus because a field minus places
1944 // a negative sign and then advances a position. If it is the
1945 // end of the field where the minus is placed then this offset will
1946 // place the count as -1.
1947 if (count == -1) {
1948 int s = sf.getFieldShift();
1949 if (s == 3 || s == 5 || s == 7) {
1950 mdt = true;
1951 }
1952 }
1953
1954 int adj = sf.getAdjustment();
1955
1956 if (adj != 0) {
1957
1958 switch (adj) {
1959
1960 case 5:
1961 rightAdjustField('0');
1962 sf.setRightAdjusted();
1963 break;
1964 case 6:
1965 rightAdjustField(' ');
1966 sf.setRightAdjusted();
1967
1968 break;
1969 case 7:
1970 sf.setManditoryEntered();
1971 break;
1972
1973 }
1974 }
1975 else {
1976
1977 // we need to right adjust signed numeric fields as well.
1978 if (sf.isSignedNumeric()) {
1979 rightAdjustField(' ');
1980 }
1981 }
1982
1983 return mdt;
1984 }
1985
1986 private void rightAdjustField(char fill) {
1987
1988 int end = endOfField(false); // get the ending position of the first
1989 // non blank character in field
1990
1991 // get the number of characters to the right
1992 int count = screenFields.getCurrentField().endPos() - end;
1993
1994 // subtract 1 from count for signed numeric - note for later
1995 if (screenFields.getCurrentField().isSignedNumeric()) {
1996 if (planes.getChar(end -1) != '-')
1997 count--;
1998 }
1999
2000 int pos = screenFields.getCurrentField().startPos();
2001
2002 while (count-- >= 0) {
2003
2004 shiftRight(pos);
2005 planes.setChar(pos,fill);
2006
2007 setDirty(pos);
2008
2009 }
2010
2011 }
2012
2013 private void shiftLeft(int sPos) {
2014
2015 int endPos = 0;
2016
2017 int pos = sPos;
2018 int pPos = sPos;
2019
2020 ScreenField sf = screenFields.getCurrentField();
2021 int end;
2022 int count;
2023 do {
2024 end = endOfField(pPos, false); // get the ending position of the
2025 // first
2026 // non blank character in field
2027
2028 count = (end - screenFields.getCurrentField().startPos())
2029 - screenFields.getCurrentField().getKeyPos(pPos);
2030
2031 // now we loop through and shift the remaining characters to the
2032 // left
2033 while (count-- > 0) {
2034 pos++;
2035 planes.setChar(pPos,planes.getChar(pos));
2036 setDirty(pPos);
2037 pPos = pos;
2038
2039 }
2040
2041 if (screenFields.isCurrentFieldContinued()) {
2042 gotoFieldNext();
2043 if (screenFields.getCurrentField().isContinuedFirst())
2044 break;
2045
2046 pos = screenFields.getCurrentField().startPos();
2047 planes.setChar(pPos,planes.getChar(pos));
2048 setDirty(pPos);
2049
2050 pPos = pos;
2051
2052 }
2053 } while (screenFields.isCurrentFieldContinued()
2054 && !screenFields.getCurrentField().isContinuedFirst());
2055
2056 if (end >= 0 && count >= -1) {
2057
2058 endPos = end;
2059 } else {
2060 endPos = sPos;
2061
2062 }
2063
2064 screenFields.setCurrentField(sf);
2065 planes.setChar(endPos,initChar);
2066 setDirty(endPos);
2067 goto_XY(screenFields.getCurrentFieldPos());
2068 sf = null;
2069
2070 }
2071
2072 private void shiftRight(int sPos) {
2073
2074 int end = endOfField(true); // get the ending position of the first
2075 // non blank character in field
2076 int pos = end;
2077 int pPos = end;
2078
2079 int count = end - sPos;
2080
2081 // now we loop through and shift the remaining characters to the right
2082 while (count-- > 0) {
2083
2084 pos--;
2085 planes.setChar(pPos, planes.getChar(pos));
2086 setDirty(pPos);
2087
2088 pPos = pos;
2089 }
2090 }
2091
2092 public int getRow(int pos) {
2093
2094 // if (pos == 0)
2095 // return 1;
2096
2097 int row = pos / numCols;
2098
2099 if (row < 0) {
2100
2101 row = lastPos / numCols;
2102 }
2103 if (row > (lenScreen / numCols) - 1)
2104 row = (lenScreen / numCols) - 1;
2105
2106 return row;
2107
2108 }
2109
2110 public int getCol(int pos) {
2111 int col = pos % (getColumns());
2112 if (col > 0) return col;
2113 return 0;
2114 }
2115
2116 /**
2117 * This routine is 0 based offset. So to get row 20,1 then pass row 19,0
2118 *
2119 * @param row
2120 * @param col
2121 * @return
2122 */
2123 public int getPos(int row, int col) {
2124
2125 return (row * numCols) + col;
2126 }
2127
2128 /**
2129 * Current position is based on offsets of 1,1 not 0,0 of the current
2130 * position of the screen
2131 *
2132 * @return int
2133 */
2134 public int getCurrentPos() {
2135
2136 // return lastPos + numCols + 1;
2137 return lastPos + 1;
2138
2139 }
2140
2141 /**
2142 * I got this information from a tcp trace of each error. I could not find
2143 * any documenation for this. Maybe there is but I could not find it. If
2144 * anybody finds this documention could you please send me a copy. Please
2145 * note that I did not look that hard either.
2146 * <p>
2147 * 0000: 00 50 73 1D 89 81 00 50 DA 44 C8 45 08 00 45 00 .Ps....P.D.E..E.
2148 * </p>
2149 * <p>
2150 * 0010: 00 36 E9 1C 40 00 80 06 9B F9 C1 A8 33 58 C0 A8 .6..@...k....3X..
2151 * </p>
2152 * <p>
2153 * 0020: C0 02 06 0E 00 17 00 52 6E 88 73 40 DE CB 50 18 .......Rn.s@..P.
2154 * </p>
2155 * <p>
2156 * 0030: 20 12 3C 53 00 00 00 0C 12 A0 00 00 04 01 00 00 . <S............
2157 * </p>
2158 * <p>
2159 * 0040: 00 05 FF EF .... ----------|| The 00 XX is the code to be sent. I
2160 * found the following <table BORDER COLS=2 WIDTH="50%" >
2161 * <tr>
2162 * <td>ERR_CURSOR_PROTECTED</td>
2163 * <td>0x05</td>
2164 * </tr>
2165 * <tr>
2166 * <td>ERR_INVALID_SIGN</td>
2167 * <td>0x11</td>
2168 * </tr>
2169 * <tr>
2170 * <td>ERR_NO_ROOM_INSERT</td>
2171 * <td>0x12</td>
2172 * </tr>
2173 * <tr>
2174 * <td>ERR_NUMERIC_ONLY</td>
2175 * <td>0x09</td>
2176 * </tr>
2177 * <tr>
2178 * <td>ERR_NUMERIC_09</td>
2179 * <td>0x10</td>
2180 * </tr>
2181 * <tr>
2182 * <td>ERR_FIELD_MINUS</td>
2183 * <td>0x16</td>
2184 * </tr>
2185 * <tr>
2186 * <td>ERR_ENTER_NOT_ALLOWED</td>
2187 * <td>0x20</td>
2188 * </tr>
2189 * <tr>
2190 * <td>ERR_MANDITORY_ENTER</td>
2191 * <td>0x21</td>
2192 * </tr>
2193 * <tr>
2194 * <td>ERR_ENTER_NOT_ALLOWED</td>
2195 * <td>0x20</td>
2196 * </tr>
2197 * </table> I am tired of typing and they should be self explanitory. Finding
2198 * them in the first place was the pain.
2199 * </p>
2200 *
2201 * @param ec error code
2202 */
2203 private void displayError(int ec) {
2204 saveHomePos = homePos;
2205 homePos = lastPos + numCols + 1;
2206 pendingInsert = true;
2207 sessionVT.sendNegResponse2(ec);
2208
2209 }
2210
2211 private void process_XY(int pos) {
2212
2213 if (pos < 0)
2214 pos = lenScreen + pos;
2215 if (pos > lenScreen - 1)
2216 pos = pos - lenScreen;
2217
2218 // if there was a field exit error then we need to treat the movement
2219 // of the cursor in a special way that equals that of Client Access.
2220 // If the cursor is moved from the field then we need to reset the
2221 // position within the field so that the last character can be typed
2222 // over again instead of sending the field exit error again.
2223 // We also need to reset the field exit error flag.
2224 //
2225 // How we know we have a field exit error is when the field position is
2226 // set beyond the end of the field and a character is then typed we can
2227 // not position that character. To reset this we need to set the next
2228 // position of the field to not be beyond the end of field but to the
2229 // last character.
2230 //
2231 // Now to make it work like Client Access if the cursor is a back space
2232 // then do not move the cursor but place it on the last field. All
2233 // other keys will reset the field position so that entering over the
2234 // last character will not cause an error but replace that character or
2235 // just plain move the cursor if the key was to do that.
2236
2237 ScreenField sf = screenFields.getCurrentField();
2238 if (feError) {
2239 feError = false;
2240 sf.changePos(-1);
2241 } else {
2242 if (sf != null&& sf.isFER()){
2243 if ((sf.getCurrentPos()
2244 > sf.endPos())) {
2245 if (sf.withinField(pos)) {
2246 sf.getKeyPos(pos);
2247 return;
2248 }
2249 sf.getKeyPos(sf.endPos());
2250 }
2251 }
2252
2253 goto_XY(pos);
2254 }
2255 }
2256
2257 public boolean isUsingGuiInterface() {
2258
2259 return guiInterface;
2260 }
2261
2262 /**
2263 * Convinience class to return if the cursor is in a field or not.
2264 *
2265 * @return true or false
2266 */
2267
2268 protected boolean isInField() {
2269
2270 return isInField(lastPos, true);
2271 }
2272
2273 /**
2274 *
2275 * Convinience class to return if the position that is passed is in a field
2276 * or not. If it is then the chgToField parameter will change the current
2277 * field to this field where the position indicates
2278 *
2279 * @param pos
2280 * @param chgToField
2281 * @return true or false
2282 */
2283 public boolean isInField(int pos, boolean chgToField) {
2284
2285 return screenFields.isInField(pos, chgToField);
2286 }
2287
2288 /**
2289 *
2290 * Convinience class to return if the position that is passed is in a field
2291 * or not. If it is then the field at this position becomes the current
2292 * working field
2293 *
2294 * @param pos
2295 * @return true or false
2296 */
2297 public boolean isInField(int pos) {
2298
2299 return screenFields.isInField(pos, true);
2300 }
2301
2302 /**
2303 * Convinience class to return if the position at row and column that is
2304 * passed is in a field or not. If it is then the field at this position
2305 * becomes the current working field.
2306 *
2307 * @param row
2308 * @param col
2309 * @return true or false
2310 */
2311 public boolean isInField(int row, int col) {
2312
2313 return isInField(row, col, true);
2314 }
2315
2316 /**
2317 *
2318 * Convinience class to return if the position at row and column that is
2319 * passed is in a field or not. If it is then the chgToField parameter will
2320 * change the current field to this field where the row and column
2321 * indicates.
2322 *
2323 * @param row
2324 * @param col
2325 * @param chgToField
2326 * @return true or false
2327 */
2328 public boolean isInField(int row, int col, boolean chgToField) {
2329 return screenFields.isInField((row * numCols) + col, chgToField);
2330 }
2331
2332 /**
2333 * Gets the length of the screen - number of rows times number of columns
2334 *
2335 * @return int value of screen length
2336 */
2337 public int getScreenLength() {
2338
2339 return lenScreen;
2340 }
2341
2342 /**
2343 * Get the number or rows available.
2344 *
2345 * @return number of rows
2346 */
2347 public int getRows() {
2348
2349 return numRows;
2350
2351 }
2352
2353 /**
2354 * Get the number of columns available.
2355 *
2356 * @return number of columns
2357 */
2358 public int getColumns() {
2359
2360 return numCols;
2361
2362 }
2363
2364 /**
2365 * Get the current row where the cursor is
2366 *
2367 * @return the cursor current row position 1,1 based
2368 */
2369 public int getCurrentRow() {
2370
2371 return (lastPos / numCols) + 1;
2372
2373 }
2374
2375 /**
2376 * Get the current column where the cursor is
2377 *
2378 * @return the cursor current column position 1,1 based
2379 */
2380 public int getCurrentCol() {
2381
2382 return (lastPos % numCols) + 1;
2383
2384 }
2385
2386 /**
2387 * The last position of the cursor on the screen - Note - position is based
2388 * 0,0
2389 *
2390 * @return last position
2391 */
2392 protected int getLastPos() {
2393
2394 return lastPos;
2395
2396 }
2397
2398 /**
2399 * Hotspot More... string
2400 *
2401 * @return string literal of More...
2402 */
2403 public StringBuffer getHSMore() {
2404 return hsMore;
2405 }
2406
2407 /**
2408 * Hotspot Bottom string
2409 *
2410 * @return string literal of Bottom
2411 */
2412 public StringBuffer getHSBottom() {
2413 return hsBottom;
2414 }
2415
2416 /**
2417 * Return the whole screen represented as a character array
2418 *
2419 * @return character array containing the text
2420 *
2421 * Added by Luc - LDC
2422 *
2423 * Note to KJP - Have to ask what the difference is between this method and
2424 * the other
2425 */
2426 public char[] getScreenAsAllChars() {
2427 char[] sac = new char[lenScreen];
2428 char c;
2429
2430 for (int x = 0; x < lenScreen; x++) {
2431 c = planes.getChar(x);
2432 // only draw printable characters (in this case >= ' ')
2433 if ((c >= ' ') && (!planes.isAttributePlace(x))) {
2434 sac[x] = c;
2435 // TODO: implement the underline check here
2436 // if (screen[x].underLine && c <= ' ')
2437 // sac[x] = '_';
2438 } else
2439 sac[x] = ' ';
2440 }
2441
2442 return sac;
2443 }
2444
2445 /**
2446 *
2447 * Return the screen represented as a character array
2448 *
2449 * @return character array containing the text
2450 */
2451 public char[] getScreenAsChars() {
2452 char[] sac = new char[lenScreen];
2453 char c;
2454
2455 for (int x = 0; x < lenScreen; x++) {
2456 c = planes.getChar(x);
2457 // only draw printable characters (in this case >= ' ')
2458 if ((c >= ' ') && (!planes.isAttributePlace(x))) {
2459 sac[x] = c;
2460 // TODO: implement the underline check here
2461 // if (screen[x].underLine && c <= ' ')
2462 // sac[x] = '_';
2463 } else
2464 sac[x] = ' ';
2465 }
2466
2467 return sac;
2468 }
2469
2470 public char[] getData(int startRow, int startCol, int endRow, int endCol, int plane) {
2471 try {
2472 int from = getPos(startRow,startCol);
2473 int to = getPos(endRow,endCol);
2474 if (from > to) {
2475
2476 int f = from;
2477 to = f;
2478 from = f;
2479 }
2480 return planes.getPlaneData(from,to,plane);
2481 }
2482 catch (Exception oe) {
2483 return null;
2484 }
2485
2486 }
2487
2488 /**
2489 * <p>
2490 * GetScreen retrieves the various planes associated with the presentation
2491 * space. The data is returned as a linear array of character values in the
2492 * array provided. The array is not terminated by a null character except
2493 * when data is retrieved from the text plane, in which case a single null
2494 * character is appended.
2495 * </p>
2496 * <p>
2497 * The application must supply a buffer for the returned data and the length
2498 * of the buffer. Data is returned starting from the beginning of the
2499 * presentation space and continuing until the buffer is full or the entire
2500 * plane has been copied. For text plane data, the buffer must include one
2501 * extra position for the terminating null character.
2502 * <p>
2503 *
2504 * @param buffer
2505 * @param bufferLength
2506 * @param plane
2507 * @return The number of characters copied to the buffer
2508 * @throws OhioException
2509 */
2510 public synchronized int GetScreen(char buffer[], int bufferLength, int plane)
2511 // throws OhioException {
2512 {
2513 return GetScreen(buffer,bufferLength,0,lenScreen,plane);
2514
2515 }
2516
2517 /**
2518 * <p>
2519 * GetScreen retrieves the various planes associated with the presentation
2520 * space. The data is returned as a linear array of character values in the
2521 * array provided. The array is not terminated by a null character except
2522 * when data is retrieved from the text plane, in which case a single null
2523 * character is appended.
2524 * </p>
2525 * <p>
2526 * The application must supply a buffer for the returned data and the length
2527 * of the buffer. Data is returned starting from the given position and
2528 * continuing until the specified number of characters have been copied, the
2529 * buffer is full or the entire plane has been copied. For text plane data,
2530 * the buffer must include one extra position for the terminating null character.
2531 * </p>
2532 *
2533 * @param buffer
2534 * @param bufferLength
2535 * @param from
2536 * @param length
2537 * @param plane
2538 * @return The number of characters copied to the buffer
2539 * @throws OhioException
2540 */
2541 public synchronized int GetScreen(char buffer[], int bufferLength, int from,
2542 int length, int plane)
2543 // throws OhioException {
2544 {
2545
2546 return planes.GetScreen(buffer,bufferLength, from, length, plane);
2547 }
2548
2549 /**
2550 * <p>
2551 * GetScreen retrieves the various planes associated with the presentation
2552 * space. The data is returned as a linear array of character values in the
2553 * array provided. The array is not terminated by a null character except
2554 * when data is retrieved from the text plane, in which case a single null
2555 * character is appended.
2556 * </p>
2557 * <p>
2558 * The application must supply a buffer for the returned data and the length
2559 * of the buffer. Data is returned starting from the given coordinates and
2560 * continuing until the specified number of characters have been copied,
2561 * the buffer is full, or the entire plane has been copied. For text plane
2562 * data, the buffer must include one extra position for the terminating null
2563 * character.
2564 * </p>
2565 *
2566 * @param buffer
2567 * @param bufferLength
2568 * @param row
2569 * @param col
2570 * @param length
2571 * @param plane
2572 * @return The number of characters copied to the buffer.
2573 * @throws OhioException
2574 */
2575 public synchronized int GetScreen(char buffer[], int bufferLength, int row,
2576 int col, int length, int plane)
2577 // throws OhioException {
2578 {
2579 // Call GetScreen function after converting row and column to
2580 // a position.
2581 return planes.GetScreen(buffer,bufferLength, row, col, length, plane);
2582 }
2583
2584 /**
2585 * <p>
2586 * GetScreenRect retrieves data from the various planes associated with the
2587 * presentation space. The data is returned as a linear array of character
2588 * values in the buffer provided.
2589 * </p>
2590 *
2591 * <p>
2592 * The application supplies two positions that represent opposing corners of
2593 * a rectangle within the presentation space. The starting and ending
2594 * positions can have any spatial relationship to each other. The data
2595 * returned starts from the row containing the upper-most point to the row
2596 * containing the lower-most point, and from the left-most column to the
2597 * right-most column.
2598 * </p>
2599 * <p>
2600 * The specified buffer must be at least large enough to contain the number
2601 * of characters in the rectangle. If the buffer is too small, no data is
2602 * copied and zero is returned by the method. Otherwise, the method returns
2603 * the number of characters copied.
2604 * </p>
2605 *
2606 * @param buffer
2607 * @param bufferLength
2608 * @param startPos
2609 * @param endPos
2610 * @param plane
2611 * @return The number of characters copied to the buffer
2612 * @throws OhioException
2613 */
2614 public synchronized int GetScreenRect(char buffer[], int bufferLength,
2615 int startPos, int endPos, int plane)
2616 // throws OhioException {
2617 {
2618 return planes.GetScreenRect(buffer, bufferLength, startPos, endPos, plane);
2619
2620 }
2621
2622 /**
2623 * <p>
2624 * GetScreenRect retrieves data from the various planes associated with the
2625 * presentation space. The data is returned as a linear array of character
2626 * values in the buffer provided. The buffer is not terminated by a null
2627 * character.
2628 * </p>
2629 * <p>
2630 * The application supplies two coordinates that represent opposing corners
2631 * of a rectangle within the presentation space. The starting and ending
2632 * coordinates can have any spatial relationship to each other. The data
2633 * returned starts from the row containing the upper-most point to the row
2634 * containing the lower-most point, and from the left-most column to the
2635 * right-most column.
2636 * </p>
2637 * <p>
2638 * The specified buffer must be at least large enough to contain the number
2639 * of characters in the rectangle. If the buffer is too small, no data is
2640 * copied and zero is returned by the method. Otherwise, the method returns
2641 * the number of characters copied.
2642 * </p>
2643 *
2644 * @param buffer
2645 * @param bufferLength
2646 * @param startRow
2647 * @param startCol
2648 * @param endRow
2649 * @param endCol
2650 * @param plane
2651 * @return The number characters copied to the buffer
2652 * @throws OhioException
2653 */
2654 public synchronized int GetScreenRect(char buffer[], int bufferLength,
2655 int startRow, int startCol,
2656 int endRow, int endCol, int plane)
2657 // throws OhioException {
2658 {
2659
2660 return planes.GetScreenRect(buffer, bufferLength, startRow, startCol, endRow,
2661 endCol, plane);
2662 }
2663
2664 public synchronized boolean[] getActiveAidKeys() {
2665 return sessionVT.getActiveAidKeys();
2666 }
2667
2668 protected synchronized void setScreenData(String text, int location) {
2669 // throws OhioException {
2670
2671 if (location < 0 || location > lenScreen) {
2672 return;
2673 // throw new OhioException(sessionVT.getSessionConfiguration(),
2674 // OhioScreen5250.class.getName(), "osohio.screen.ohio00300", 1);
2675 }
2676
2677 int pos = location;
2678
2679 int l = text.length();
2680 boolean updated = false;
2681 boolean flag = false;
2682 int x =0;
2683 for (; x < l; x++) {
2684 if (isInField(pos + x,true)) {
2685 if (!screenFields.getCurrentField().isBypassField()) {
2686 if (!flag) {
2687 screenFields.getCurrentField().setMDT();
2688 updated = true;
2689 resetDirty(pos + x);
2690 screenFields.setMasterMDT();
2691 flag = true;
2692 }
2693
2694 planes.screen[pos + x] = text.charAt(x);
2695 setDirty(pos + x);
2696 }
2697 }
2698
2699 }
2700 lastPos = pos + x;
2701 if (updated) {
2702 fireScreenChanged(1);
2703 }
2704
2705 }
2706
2707 /**
2708 * This routine is based on offset 1,1 not 0,0 it will translate to offset
2709 * 0,0 and call the goto_XY(int pos) it is mostly used from external classes
2710 * that use the 1,1 offset
2711 *
2712 * @param row
2713 * @param col
2714 */
2715 public void setCursor(int row, int col) {
2716 goto_XY(((row - 1) * numCols) + (col - 1));
2717 }
2718
2719 // this routine is based on offset 0,0 not 1,1
2720 protected void goto_XY(int pos) {
2721 // setCursorOff();
2722 updateCursorLoc();
2723 lastPos = pos;
2724 // setCursorOn();
2725 updateCursorLoc();
2726 }
2727
2728 /**
2729 * Set the current working field to the field number specified.
2730 *
2731 * @param f -
2732 * numeric field number on the screen
2733 * @return true or false whether it was sucessful
2734 */
2735 public boolean gotoField(int f) {
2736
2737 int sizeFields = screenFields.getSize();
2738
2739 if (f > sizeFields || f <= 0)
2740 return false;
2741
2742 screenFields.setCurrentField(screenFields.getField(f - 1));
2743
2744 while (screenFields.isCurrentFieldBypassField() && f < sizeFields) {
2745
2746 screenFields.setCurrentField(screenFields.getField(f++));
2747
2748 }
2749 return gotoField(screenFields.getCurrentField());
2750 }
2751
2752 /**
2753 * Convenience method to set the field object passed as the currect working
2754 * screen field
2755 *
2756 * @param f
2757 * @return true or false whether it was sucessful
2758 * @see org.tn5250j.ScreenField
2759 */
2760 protected boolean gotoField(ScreenField f) {
2761 if (f != null) {
2762 goto_XY(f.startPos());
2763 return true;
2764 }
2765 return false;
2766 }
2767
2768 /**
2769 * Convenience class to position the cursor to the next word on the screen
2770 *
2771 */
2772 private void gotoNextWord() {
2773
2774 int pos = lastPos;
2775
2776 if (planes.getChar(lastPos) > ' ') {
2777 advancePos();
2778 // get the next space character
2779 while (planes.getChar(lastPos) > ' ' && pos != lastPos) {
2780 advancePos();
2781 }
2782 } else
2783 advancePos();
2784
2785 // now that we are positioned on the next space character get the
2786 // next none space character
2787 while (planes.getChar(lastPos) <= ' ' && pos != lastPos) {
2788 advancePos();
2789 }
2790
2791 }
2792
2793 /**
2794 * Convenience class to position the cursor to the previous word on the
2795 * screen
2796 *
2797 */
2798 private void gotoPrevWord() {
2799
2800 int pos = lastPos;
2801
2802 changePos(-1);
2803
2804 // position previous white space character
2805 while (planes.getChar(lastPos) <= ' ') {
2806 changePos(-1);
2807 if (pos == lastPos)
2808 break;
2809 }
2810
2811 changePos(-1);
2812 // get the previous space character
2813 while (planes.getChar(lastPos) > ' ' && pos != lastPos) {
2814 changePos(-1);
2815 }
2816
2817 // and position one position more should give us the beginning of word
2818 advancePos();
2819
2820 }
2821
2822 /**
2823 * Convinience class to position to the next field on the screen.
2824 *
2825 * @see org.tn5250j.ScreenFields
2826 */
2827 private void gotoFieldNext() {
2828
2829 if (screenFields.isCurrentFieldHighlightedEntry())
2830 unsetFieldHighlighted(screenFields.getCurrentField());
2831
2832 screenFields.gotoFieldNext();
2833
2834 if (screenFields.isCurrentFieldHighlightedEntry())
2835 setFieldHighlighted(screenFields.getCurrentField());
2836 }
2837
2838 /**
2839 * Convinience class to position to the previous field on the screen.
2840 *
2841 * @see org.tn5250j.ScreenFields
2842 */
2843 private void gotoFieldPrev() {
2844
2845 if (screenFields.isCurrentFieldHighlightedEntry())
2846 unsetFieldHighlighted(screenFields.getCurrentField());
2847
2848 screenFields.gotoFieldPrev();
2849
2850 if (screenFields.isCurrentFieldHighlightedEntry())
2851 setFieldHighlighted(screenFields.getCurrentField());
2852
2853 }
2854
2855 /* *** NEVER USED LOCALLY ************************************************** */
2856 // /**
2857 // * Used to restrict the cursor to a particular position on the screen. Used
2858 // * in combination with windows to restrict the cursor to the active window
2859 // * show on the screen.
2860 // *
2861 // * Not supported yet. Please implement me :-(
2862 // *
2863 // * @param depth
2864 // * @param width
2865 // */
2866 // protected void setRestrictCursor(int depth, int width) {
2867 //
2868 // restrictCursor = true;
2869 // // restriction
2870 //
2871 // }
2872
2873 /**
2874 * Creates a window on the screen
2875 *
2876 * @param depth
2877 * @param width
2878 * @param type
2879 * @param gui
2880 * @param monoAttr
2881 * @param colorAttr
2882 * @param ul
2883 * @param upper
2884 * @param ur
2885 * @param left
2886 * @param right
2887 * @param ll
2888 * @param bottom
2889 * @param lr
2890 */
2891 protected void createWindow(int depth, int width, int type, boolean gui,
2892 int monoAttr, int colorAttr, int ul, int upper, int ur, int left,
2893 int right, int ll, int bottom, int lr) {
2894
2895 int c = getCol(lastPos);
2896 int w = 0;
2897 width++;
2898
2899 w = width;
2900 // set leading attribute byte
2901 // screen[lastPos].setCharAndAttr(initChar, initAttr, true);
2902 planes.setScreenCharAndAttr(lastPos, initChar, initAttr, true);
2903 setDirty(lastPos);
2904
2905 advancePos();
2906 // set upper left
2907 // screen[lastPos].setCharAndAttr((char) ul, colorAttr, false);
2908 planes.setScreenCharAndAttr(lastPos, (char) ul, colorAttr, false);
2909 if (gui) {
2910 // screen[lastPos].setUseGUI(UPPER_LEFT);
2911 planes.setUseGUI(lastPos, UPPER_LEFT);
2912 }
2913 setDirty(lastPos);
2914
2915 advancePos();
2916
2917 // draw top row
2918
2919 while (w-- >= 0) {
2920 // screen[lastPos].setCharAndAttr((char) upper, colorAttr, false);
2921 planes.setScreenCharAndAttr(lastPos, (char) upper, colorAttr, false);
2922 if (gui) {
2923 // screen[lastPos].setUseGUI(UPPER);
2924 planes.setUseGUI(lastPos,UPPER);
2925 }
2926 setDirty(lastPos);
2927 advancePos();
2928 }
2929
2930 // set upper right
2931 // screen[lastPos].setCharAndAttr((char) ur, colorAttr, false);
2932 planes.setScreenCharAndAttr(lastPos,(char) ur, colorAttr, false);
2933
2934 if (gui) {
2935 // screen[lastPos].setUseGUI(UPPER_RIGHT);
2936 planes.setUseGUI(lastPos, UPPER_RIGHT);
2937 }
2938 setDirty(lastPos);
2939 advancePos();
2940
2941 // set ending attribute byte
2942 planes.setScreenCharAndAttr(lastPos,initChar, initAttr, true);
2943
2944 setDirty(lastPos);
2945
2946 lastPos = ((getRow(lastPos) + 1) * numCols) + c;
2947
2948 // now handle body of window
2949 while (depth-- > 0) {
2950
2951 // set leading attribute byte
2952 planes.setScreenCharAndAttr(lastPos,initChar, initAttr, true);
2953 setDirty(lastPos);
2954 advancePos();
2955
2956 // set left
2957 planes.setScreenCharAndAttr(lastPos, (char) left, colorAttr, false);
2958
2959 if (gui) {
2960 planes.setUseGUI(lastPos,GUI_LEFT);
2961 }
2962 setDirty(lastPos);
2963 advancePos();
2964
2965 w = width;
2966 // fill it in
2967 while (w-- >= 0) {
2968 // screen[lastPos].setCharAndAttr(initChar, initAttr, true);
2969 planes.setScreenCharAndAttr(lastPos,initChar, initAttr, true);
2970 // screen[lastPos].setUseGUI(NO_GUI);
2971 planes.setUseGUI(lastPos,NO_GUI);
2972 setDirty(lastPos);
2973 advancePos();
2974 }
2975
2976 // set right
2977 // screen[lastPos].setCharAndAttr((char) right, colorAttr, false);
2978 planes.setScreenCharAndAttr(lastPos,(char) right, colorAttr, false);
2979 if (gui) {
2980 // screen[lastPos].setUseGUI(RIGHT);
2981 planes.setUseGUI(lastPos,GUI_RIGHT);
2982 }
2983
2984 setDirty(lastPos);
2985 advancePos();
2986
2987 // set ending attribute byte
2988 // screen[lastPos].setCharAndAttr(initChar, initAttr, true);
2989 planes.setScreenCharAndAttr(lastPos,initChar, initAttr, true);
2990 setDirty(lastPos);
2991
2992 lastPos = ((getRow(lastPos) + 1) * numCols) + c;
2993 }
2994
2995 // set leading attribute byte
2996 // screen[lastPos].setCharAndAttr(initChar, initAttr, true);
2997 planes.setScreenCharAndAttr(lastPos,initChar, initAttr, true);
2998 setDirty(lastPos);
2999 advancePos();
3000
3001 // set lower left
3002 // screen[lastPos].setCharAndAttr((char) ll, colorAttr, false);
3003 planes.setScreenCharAndAttr(lastPos,(char) ll, colorAttr, false);
3004 if (gui) {
3005 // screen[lastPos].setUseGUI(LOWER_LEFT);
3006 planes.setUseGUI(lastPos,LOWER_LEFT);
3007 }
3008 setDirty(lastPos);
3009 advancePos();
3010
3011 w = width;
3012
3013 // draw bottom row
3014 while (w-- >= 0) {
3015 planes.setScreenCharAndAttr(lastPos,(char) bottom, colorAttr, false);
3016 if (gui) {
3017 planes.setUseGUI(lastPos,BOTTOM);
3018 }
3019 setDirty(lastPos);
3020 advancePos();
3021 }
3022
3023 // set lower right
3024 planes.setScreenCharAndAttr(lastPos, (char) lr, colorAttr, false);
3025 if (gui) {
3026 planes.setUseGUI(lastPos,LOWER_RIGHT);
3027 }
3028
3029 setDirty(lastPos);
3030 advancePos();
3031
3032 // set ending attribute byte
3033 planes.setScreenCharAndAttr(lastPos,initChar, initAttr, true);
3034 setDirty(lastPos);
3035
3036 }
3037
3038 /**
3039 * Creates a scroll bar on the screen using the parameters provided.
3040 * ** we only support vertical scroll bars at the time.
3041 *
3042 * @param flag -
3043 * type to draw - vertical or horizontal
3044 * @param totalRowScrollable
3045 * @param totalColScrollable
3046 * @param sliderRowPos
3047 * @param sliderColPos
3048 * @param sbSize
3049 */
3050 protected void createScrollBar(int flag, int totalRowScrollable,
3051 int totalColScrollable, int sliderRowPos, int sliderColPos,
3052 int sbSize) {
3053
3054 // System.out.println("Scrollbar flag: " + flag +
3055 // " scrollable Rows: " + totalRowScrollable +
3056 // " scrollable Cols: " + totalColScrollable +
3057 // " thumb Row: " + sliderRowPos +
3058 // " thumb Col: " + sliderColPos +
3059 // " size: " + sbSize +
3060 // " row: " + getRow(lastPos) +
3061 // " col: " + getCol(lastPos));
3062
3063 int sp = lastPos;
3064 int size = sbSize - 2;
3065
3066 int thumbPos = (int) (size * ((float) sliderColPos / (float) totalColScrollable));
3067 // System.out.println(thumbPos);
3068 planes.setScreenCharAndAttr(sp,' ', 32, false);
3069 planes.setUseGUI(sp,BUTTON_SB_UP);
3070
3071 int ctr = 0;
3072 while (ctr < size) {
3073 sp += numCols;
3074 planes.setScreenCharAndAttr(sp,' ', 32, false);
3075 if (ctr == thumbPos)
3076 planes.setUseGUI(sp,BUTTON_SB_THUMB);
3077 else
3078 planes.setUseGUI(sp, BUTTON_SB_GUIDE);
3079 ctr++;
3080 }
3081 sp += numCols;
3082
3083
3084 planes.setScreenCharAndAttr(sp, ' ', 32, false);
3085 planes.setUseGUI(sp, BUTTON_SB_DN);
3086 }
3087
3088 /**
3089 * Write the title of the window that is on the screen
3090 *
3091 * @param pos
3092 * @param depth
3093 * @param width
3094 * @param orientation
3095 * @param monoAttr
3096 * @param colorAttr
3097 * @param title
3098 */
3099 protected void writeWindowTitle(int pos, int depth, int width,
3100 byte orientation, int monoAttr, int colorAttr, StringBuffer title) {
3101
3102 int len = title.length();
3103
3104 // get bit 0 and 1 for interrogation
3105 switch (orientation & 0xc0) {
3106 case 0x40: // right
3107 pos += (4 + width - len);
3108 break;
3109 case 0x80: // left
3110 pos += 2;
3111 break;
3112 default: // center
3113 // this is to place the position to the first text position of the
3114 // window
3115 // the position passed in is the first attribute position, the next
3116 // is the border character and then there is another attribute after
3117 // that.
3118 pos += (3 + ((width / 2) - (len / 2)));
3119 break;
3120
3121 }
3122
3123 // if bit 2 is on then this is a footer
3124 if ((orientation & 0x20) == 0x20)
3125 pos += ((depth + 1) * numCols);
3126
3127 // System.out.println(pos + "," + width + "," + len+ "," + getRow(pos)
3128 // + "," + getCol(pos) + "," + ((orientation >> 6) & 0xf0));
3129
3130 for (int x = 0; x < len; x++) {
3131 planes.setChar(pos, title.charAt(x));
3132 planes.setUseGUI(pos++, NO_GUI);
3133
3134 }
3135 }
3136
3137 /**
3138 * Roll the screen up or down.
3139 *
3140 * Byte 1: Bit 0 0 = Roll up 1 = Roll down Bits 1-2 Reserved Bits 3-7 Number
3141 * of lines that the designated area is to be rolled Byte 2: Bits 0-7 Line
3142 * number defining the top line of the area that will participate in the
3143 * roll. Byte 3: Bits 0-7 Line number defining the bottom line of the area
3144 * that will participate in the roll.
3145 *
3146 * @param direction
3147 * @param topLine
3148 * @param bottomLine
3149 */
3150 protected void rollScreen(int direction, int topLine, int bottomLine) {
3151
3152 // get the number of lines which are the last 5 bits
3153 /* int lines = direction & 0x7F; */
3154 // get the direction of the roll which is the first bit
3155 // 0 - up
3156 // 1 - down
3157 int updown = direction & 0x80;
3158 final int lines = direction & 0x7F;
3159
3160 // calculate the reference points for the move.
3161 int start = this.getPos(topLine - 1, 0);
3162 int end = this.getPos(bottomLine - 1, numCols - 1);
3163 int len = end - start;
3164
3165 // System.out.println(" starting roll");
3166 // dumpScreen();
3167 switch (updown) {
3168 case 0:
3169 // Now round em up and head em UP.
3170 for (int x = start; x < end + numCols; x++) {
3171 if (x + lines * numCols >= lenScreen) {
3172 //Clear at the end
3173 planes.setChar(x, ' ');
3174 } else {
3175 planes.setChar(x, planes.getChar(x + lines * numCols ));
3176 }
3177 }
3178 break;
3179 case 1:
3180 // Now round em up and head em DOWN.
3181 for (int x = end + numCols; x > 0; x--) {
3182 if ((x - lines * numCols ) < 0 ) {
3183 //Do nothing ... tooo small!!!
3184 } else {
3185 planes.setChar(x - lines * numCols, planes.getChar(x));
3186 //and clear
3187 planes.setChar(x, ' ');
3188 }
3189 }
3190 break;
3191 default:
3192 log.warn(" Invalid roll parameter - please report this");
3193 }
3194 // System.out.println(" end roll");
3195 // dumpScreen();
3196
3197 }
3198
3199 public void dumpScreen() {
3200
3201 StringBuffer sb = new StringBuffer();
3202 char[] s = getScreenAsChars();
3203 int c = getColumns();
3204 int l = getRows() * c;
3205 int col = 0;
3206 for (int x = 0; x < l; x++, col++) {
3207 sb.append(s[x]);
3208 if (col == c) {
3209 sb.append('\n');
3210 col = 0;
3211 }
3212 }
3213 log.info(sb.toString());
3214
3215 }
3216
3217 /**
3218 * Add a field to the field format table.
3219 *
3220 * @param attr - Field attribute
3221 * @param len - length of field
3222 * @param ffw1 - Field format word 1
3223 * @param ffw2 - Field format word 2
3224 * @param fcw1 - Field control word 1
3225 * @param fcw2 - Field control word 2
3226 */
3227 protected void addField(int attr, int len, int ffw1, int ffw2, int fcw1,
3228 int fcw2) {
3229
3230 lastAttr = attr;
3231
3232 planes.setScreenCharAndAttr(lastPos, initChar, lastAttr, true);
3233
3234 setDirty(lastPos);
3235
3236 advancePos();
3237
3238 ScreenField sf = null;
3239
3240 // from 14.6.12 for Start of Field Order 5940 function manual
3241 // examine the format table for an entry that begins at the current
3242 // starting address plus 1.
3243 if (screenFields.existsAtPos(lastPos)) {
3244 screenFields.setCurrentFieldFFWs(ffw1, ffw2);
3245 } else {
3246 sf = screenFields.setField(attr, getRow(lastPos), getCol(lastPos),
3247 len, ffw1, ffw2, fcw1, fcw2);
3248 lastPos = sf.startPos();
3249 int x = len;
3250
3251 boolean gui = guiInterface;
3252 if (sf.isBypassField())
3253 gui = false;
3254
3255 while (x-- > 0) {
3256
3257 if (planes.getChar(lastPos) == 0)
3258 planes.setScreenCharAndAttr(lastPos, ' ', lastAttr, false);
3259 else
3260 planes.setScreenAttr(lastPos,lastAttr);
3261
3262 if (gui) {
3263 planes.setUseGUI(lastPos,FIELD_MIDDLE);
3264 }
3265
3266 // now we set the field plane attributes
3267 planes.setScreenFieldAttr(lastPos,ffw1);
3268
3269 advancePos();
3270
3271 }
3272
3273 if (gui)
3274 if (len > 1) {
3275 planes.setUseGUI(sf.startPos(), FIELD_LEFT);
3276
3277 if (lastPos > 0)
3278 planes.setUseGUI(lastPos - 1, FIELD_RIGHT);
3279 else
3280 planes.setUseGUI(lastPos,FIELD_RIGHT);
3281
3282 }
3283 else {
3284 planes.setUseGUI(lastPos - 1,FIELD_ONE);
3285 }
3286
3287 // screen[lastPos].setCharAndAttr(initChar,initAttr,true);
3288 setEndingAttr(initAttr);
3289
3290 lastPos = sf.startPos();
3291 }
3292
3293 // if (fcw1 != 0 || fcw2 != 0) {
3294
3295 // System.out.println("lr = " + lastRow + " lc = " + lastCol + " " +
3296 // sf.toString());
3297 // }
3298 sf = null;
3299
3300 }
3301
3302
3303 // public void addChoiceField(int attr, int len, int ffw1, int ffw2, int
3304 // fcw1, int fcw2) {
3305 //
3306 // lastAttr = attr;
3307 //
3308 // screen[lastPos].setCharAndAttr(initChar,lastAttr,true);
3309 // setDirty(lastPos);
3310 //
3311 // advancePos();
3312 //
3313 // boolean found = false;
3314 // ScreenField sf = null;
3315 //
3316 // // from 14.6.12 for Start of Field Order 5940 function manual
3317 // // examine the format table for an entry that begins at the current
3318 // // starting address plus 1.
3319 // for (int x = 0;x < sizeFields; x++) {
3320 // sf = screenFields[x];
3321 //
3322 // if (lastPos == sf.startPos()) {
3323 // screenFields.getCurrentField() = sf;
3324 // screenFields.getCurrentField().setFFWs(ffw1,ffw2);
3325 // found = true;
3326 // }
3327 //
3328 // }
3329 //
3330 // if (!found) {
3331 // sf =
3332 // setField(attr,getRow(lastPos),getCol(lastPos),len,ffw1,ffw2,fcw1,fcw2);
3333 //
3334 // lastPos = sf.startPos();
3335 // int x = len;
3336 //
3337 // boolean gui = guiInterface;
3338 // if (sf.isBypassField())
3339 // gui = false;
3340 //
3341 // while (x-- > 0) {
3342 //
3343 // if (screen[lastPos].getChar() == 0)
3344 // screen[lastPos].setCharAndAttr(' ',lastAttr,false);
3345 // else
3346 // screen[lastPos].setAttribute(lastAttr);
3347 //
3348 // if (gui)
3349 // screen[lastPos].setUseGUI(FIELD_MIDDLE);
3350 //
3351 // advancePos();
3352 //
3353 // }
3354 //
3355 // if (gui)
3356 // if (len > 1) {
3357 // screen[sf.startPos()].setUseGUI(FIELD_LEFT);
3358 // if (lastPos > 0)
3359 // screen[lastPos-1].setUseGUI(FIELD_RIGHT);
3360 // else
3361 // screen[lastPos].setUseGUI(FIELD_RIGHT);
3362 //
3363 // }
3364 // else
3365 // screen[lastPos-1].setUseGUI(FIELD_ONE);
3366 //
3367 // setEndingAttr(initAttr);
3368 //
3369 // lastPos = sf.startPos();
3370 // }
3371 //
3372 // // if (fcw1 != 0 || fcw2 != 0) {
3373 // //
3374 // // System.out.println("lr = " + lastRow + " lc = " + lastCol + " " +
3375 // sf.toString());
3376 // // }
3377 // sf = null;
3378 //
3379 // }
3380
3381 /**
3382 * Return the fields that are contained in the Field Format Table
3383 *
3384 * @return ScreenFields object
3385 * @see org.tn5250j.ScreenFields
3386 */
3387 public ScreenFields getScreenFields() {
3388 return screenFields;
3389 }
3390
3391 /**
3392 * Redraw the fields on the screen. Used for gui enhancement to redraw the
3393 * fields when toggling
3394 *
3395 */
3396 protected void drawFields() {
3397
3398 ScreenField sf;
3399
3400 int sizeFields = screenFields.getSize();
3401 for (int x = 0; x < sizeFields; x++) {
3402
3403 sf = screenFields.getField(x);
3404
3405 if (!sf.isBypassField()) {
3406 int pos = sf.startPos();
3407
3408 int l = sf.length;
3409
3410 boolean f = true;
3411
3412 if (l >= lenScreen)
3413 l = lenScreen - 1;
3414
3415 if (l > 1) {
3416 while (l-- > 0) {
3417
3418 if (guiInterface && f) {
3419 planes.setUseGUI(pos,FIELD_LEFT);
3420 f = false;
3421 } else {
3422
3423 planes.setUseGUI(pos,FIELD_MIDDLE);
3424
3425 }
3426
3427 if (guiInterface && l == 0) {
3428 planes.setUseGUI(pos,FIELD_RIGHT);
3429 }
3430
3431 setDirty(pos++);
3432 }
3433 } else {
3434 planes.setUseGUI(pos,FIELD_ONE);
3435 }
3436 }
3437 }
3438
3439 //updateDirty();
3440 }
3441
3442 /**
3443 * Draws the field on the screen. Used to redraw or change the attributes of
3444 * the field.
3445 *
3446 * @param sf -
3447 * Field to be redrawn
3448 * @see org.tn5250j.ScreenField.java
3449 */
3450 protected void drawField(ScreenField sf) {
3451
3452 int pos = sf.startPos();
3453
3454 int x = sf.length;
3455
3456 while (x-- > 0) {
3457 setDirty(pos++);
3458 }
3459
3460 updateDirty();
3461
3462 }
3463
3464 /**
3465 * Set the field to be displayed as highlighted.
3466 *
3467 * @param sf -
3468 * Field to be highlighted
3469 */
3470 protected void setFieldHighlighted(ScreenField sf) {
3471
3472 int pos = sf.startPos();
3473
3474 int x = sf.length;
3475 int na = sf.getHighlightedAttr();
3476
3477 while (x-- > 0) {
3478 planes.setScreenAttr(pos,na);
3479 setDirty(pos++);
3480 }
3481 fireScreenChanged(1);
3482
3483 }
3484
3485 /**
3486 * Draw the field as un higlighted. This is used to reset the field
3487 * presentation on the screen after the field is exited.
3488 *
3489 * @param sf -
3490 * Field to be unhighlighted
3491 */
3492 protected void unsetFieldHighlighted(ScreenField sf) {
3493
3494 int pos = sf.startPos();
3495
3496 int x = sf.length;
3497 int na = sf.getAttr();
3498
3499 while (x-- > 0) {
3500 planes.setScreenAttr(pos,na);
3501 setDirty(pos++);
3502 }
3503 fireScreenChanged(1);
3504
3505 }
3506
3507 public boolean checkHotSpots() {
3508
3509 return planes.checkHotSpots();
3510 }
3511
3512 protected void setChar(int cByte) {
3513 if (lastPos > 0) {
3514 lastAttr = planes.getCharAttr(lastPos - 1);
3515 }
3516 if (cByte > 0 && (char)cByte < ' ') {
3517 planes.setScreenCharAndAttr(lastPos, (char) 0x00, 33, false);
3518 setDirty(lastPos);
3519 advancePos();
3520 } else {
3521 planes.setScreenCharAndAttr(lastPos, (char) cByte, lastAttr, false);
3522 setDirty(lastPos);
3523 if (guiInterface && !isInField(lastPos, false)) {
3524 planes.setUseGUI(lastPos, NO_GUI);
3525 }
3526 advancePos();
3527 }
3528 }
3529
3530 protected void setEndingAttr(int cByte) {
3531 int attr = lastAttr;
3532 setAttr(cByte);
3533 lastAttr = attr;
3534 }
3535
3536 protected void setAttr(int cByte) {
3537 lastAttr = cByte;
3538
3539 // int sattr = screen[lastPos].getCharAttr();
3540 // System.out.println("changing from " + sattr + " to attr " + lastAttr
3541 // +
3542 // " at " + (this.getRow(lastPos) + 1) + "," + (this.getCol(lastPos) +
3543 // 1));
3544 planes.setScreenCharAndAttr(lastPos, initChar, lastAttr, true);
3545 setDirty(lastPos);
3546
3547 advancePos();
3548 int pos = lastPos;
3549
3550 int times = 0;
3551 // sattr = screen[lastPos].getCharAttr();
3552 // System.out.println(" next position after change " + sattr + " last
3553 // attr " + lastAttr +
3554 // " at " + (this.getRow(lastPos) + 1) + "," + (this.getCol(lastPos) +
3555 // 1) +
3556 // " attr place " + screen[lastPos].isAttributePlace());
3557
3558 while (planes.getCharAttr(lastPos) != lastAttr
3559 && !planes.isAttributePlace(lastPos)) {
3560
3561 planes.setScreenAttr(lastPos, lastAttr);
3562 if (guiInterface && !isInField(lastPos, false)) {
3563 int g = planes.getWhichGUI(lastPos);
3564 if (g >= FIELD_LEFT && g <= FIELD_ONE)
3565 planes.setUseGUI(lastPos,NO_GUI);
3566 }
3567 setDirty(lastPos);
3568
3569 times++;
3570 advancePos();
3571 }
3572
3573 // sanity check for right now
3574 // if (times > 200)
3575 // System.out.println(" setAttr = " + times + " start = " + (sr + 1) +
3576 // "," + (sc + 1));
3577
3578 lastPos = pos;
3579 }
3580
3581 protected void setScreenCharAndAttr(char right, int colorAttr, boolean isAttr) {
3582
3583 planes.setScreenCharAndAttr(lastPos,right, colorAttr, isAttr);
3584 setDirty(lastPos);
3585 advancePos();
3586
3587 }
3588
3589 protected void setScreenCharAndAttr(char right, int colorAttr,
3590 int whichGui, boolean isAttr) {
3591
3592 planes.setScreenCharAndAttr(lastPos,right, colorAttr, isAttr);
3593 planes.setUseGUI(lastPos,whichGui);
3594
3595 setDirty(lastPos);
3596 advancePos();
3597
3598 }
3599
3600 /**
3601 * Draw or redraw the dirty parts of the screen and display them.
3602 *
3603 * Rectangle dirty holds the dirty area of the screen to be updated.
3604 *
3605 * If you want to change the screen in anyway you need to set the screen
3606 * attributes before calling this routine.
3607 */
3608 protected void updateDirty() {
3609
3610 fireScreenChanged(1);
3611
3612 }
3613
3614 protected void setDirty(int pos) {
3615
3616 int minr = Math.min(getRow(pos),getRow(dirtyScreen.x));
3617 int minc = Math.min(getCol(pos),getCol(dirtyScreen.x));
3618
3619 int maxr = Math.max(getRow(pos),getRow(dirtyScreen.y));
3620 int maxc = Math.max(getCol(pos),getCol(dirtyScreen.y));
3621
3622 int x1 = getPos(minr,minc);
3623 int x2 = getPos(maxr,maxc);
3624
3625 dirtyScreen.setBounds(x1,x2,0,0);
3626
3627 }
3628
3629 /* *** NEVER USED LOCALLY ************************************************** */
3630 // private void setDirty(int row, int col) {
3631 //
3632 // setDirty(getPos(row, col));
3633 //
3634 // }
3635
3636 private void resetDirty(int pos) {
3637
3638 dirtyScreen.setBounds(pos,pos,0,0);
3639
3640 }
3641
3642 /**
3643 * Change the screen position by one column
3644 */
3645 protected void advancePos() {
3646 changePos(1);
3647 }
3648
3649 /**
3650 * Change position of the screen by the increment of parameter passed.
3651 *
3652 * If the position change is under the minimum of the first screen position
3653 * then the position is moved to the last row and column of the screen.
3654 *
3655 * If the position change is over the last row and column of the screen then
3656 * cursor is moved to first position of the screen.
3657 *
3658 * @param i
3659 */
3660 protected void changePos(int i) {
3661
3662 lastPos += i;
3663 if (lastPos < 0)
3664 lastPos = lenScreen + lastPos;
3665 if (lastPos > lenScreen - 1)
3666 lastPos = lastPos - lenScreen;
3667
3668 // System.out.println(lastRow + "," + ((lastPos) / numCols) + "," +
3669 // lastCol + "," + ((lastPos) % numCols) + "," +
3670 // ((lastRow * numCols) + lastCol) + "," +
3671 // (lastPos));
3672
3673 }
3674
3675 protected void goHome() {
3676
3677 // now we try to move to first input field according to
3678 // 14.6 WRITE TO DISPLAY Command
3679 // ? If the WTD command is valid, after the command is processed,
3680 // the cursor moves to one of three locations:
3681 // - The location set by an insert cursor order (unless control
3682 // character byte 1, bit 1 is equal to B'1'.)
3683 // - The start of the first non-bypass input field defined in the
3684 // format table
3685 // - A default starting address of row 1 column 1.
3686
3687 if (pendingInsert && homePos > 0) {
3688 setCursor(getRow(homePos), getCol(homePos));
3689 isInField(); // we now check if we are in a field
3690 } else {
3691 if (!gotoField(1)) {
3692 homePos = getPos(1, 1);
3693 setCursor(1, 1);
3694 isInField(0, 0); // we now check if we are in a field
3695 } else {
3696 homePos = getPos(getCurrentRow(), getCurrentCol());
3697 }
3698 }
3699 }
3700
3701 protected void setPendingInsert(boolean flag, int icX, int icY) {
3702 pendingInsert = flag;
3703 if (pendingInsert) {
3704 homePos = getPos(icX, icY);
3705 }
3706
3707 if (!isStatusErrorCode()) {
3708 setCursor(icX, icY);
3709 }
3710 }
3711
3712 protected void setPendingInsert(boolean flag) {
3713 if (homePos != -1)
3714 pendingInsert = flag;
3715 }
3716
3717 /**
3718 * Set the error line number to that of number passed.
3719 *
3720 * @param line
3721 */
3722 protected void setErrorLine(int line) {
3723
3724 planes.setErrorLine(line);
3725 }
3726
3727 /**
3728 * Returns the current error line number
3729 *
3730 * @return current error line number
3731 */
3732 protected int getErrorLine() {
3733 return planes.getErrorLine();
3734 }
3735
3736 /**
3737 * Saves off the current error line characters to be used later.
3738 *
3739 */
3740 protected void saveErrorLine() {
3741 planes.saveErrorLine();
3742 }
3743
3744 /**
3745 * Restores the error line characters from the save buffer.
3746 *
3747 * @see #saveErrorLine()
3748 */
3749 protected void restoreErrorLine() {
3750
3751 if (planes.isErrorLineSaved()) {
3752 planes.restoreErrorLine();
3753 fireScreenChanged(1,planes.getErrorLine()-1,0,planes.getErrorLine()-1,numCols - 1);
3754 }
3755 }
3756
3757 protected void setStatus(byte attr, byte value, String s) {
3758
3759 // set the status area
3760 switch (attr) {
3761
3762 case STATUS_SYSTEM:
3763 if (value == STATUS_VALUE_ON) {
3764 oia.setInputInhibited(ScreenOIA.INPUTINHIBITED_SYSTEM_WAIT,ScreenOIA.OIA_LEVEL_INPUT_INHIBITED, s);
3765 }
3766 else {
3767 oia.setInputInhibited(ScreenOIA.INPUTINHIBITED_NOTINHIBITED,ScreenOIA.OIA_LEVEL_NOT_INHIBITED,s);
3768 }
3769 break;
3770
3771 case STATUS_ERROR_CODE:
3772 if (value == STATUS_VALUE_ON) {
3773 setPrehelpState(true, true, false);
3774 oia.setInputInhibited(ScreenOIA.INPUTINHIBITED_SYSTEM_WAIT,
3775 ScreenOIA.OIA_LEVEL_INPUT_ERROR,s);
3776
3777 sessionVT.signalBell();
3778 } else {
3779 oia.setInputInhibited(ScreenOIA.INPUTINHIBITED_NOTINHIBITED,
3780 ScreenOIA.OIA_LEVEL_NOT_INHIBITED);
3781 setPrehelpState(false, true, true);
3782 homePos = saveHomePos;
3783 saveHomePos = 0;
3784 pendingInsert = false;
3785 }
3786 break;
3787
3788 }
3789 }
3790
3791 protected boolean isStatusErrorCode() {
3792
3793 return oia.getLevel() == ScreenOIA.OIA_LEVEL_INPUT_ERROR;
3794
3795 }
3796
3797 /**
3798 * This routine clears the screen, resets row and column to 0, resets the
3799 * last attribute to 32, clears the fields, turns insert mode off,
3800 * clears/initializes the screen character array.
3801 */
3802 protected void clearAll() {
3803
3804 lastAttr = 32;
3805 lastPos = 0;
3806
3807 clearTable();
3808 clearScreen();
3809 planes.setScreenAttr(0, initAttr);
3810 oia.setInsertMode(false);
3811 }
3812
3813 /**
3814 * Clear the fields table
3815 */
3816 protected void clearTable() {
3817
3818 oia.setKeyBoardLocked(true);
3819 screenFields.clearFFT();
3820 planes.initalizeFieldPlanes();
3821 pendingInsert = false;
3822 homePos = -1;
3823 }
3824
3825 /**
3826 * Clear the gui constructs
3827 *
3828 */
3829 protected void clearGuiStuff() {
3830
3831 for (int x = 0; x < lenScreen; x++) {
3832 planes.setUseGUI(x,NO_GUI);
3833 }
3834 dirtyScreen.setBounds(0,lenScreen - 1,0,0);
3835 }
3836
3837 /**
3838 * Clear the screen by setting the initial character and initial attribute
3839 * to all the positions on the screen
3840 */
3841 protected void clearScreen() {
3842
3843 planes.initalizePlanes();
3844
3845 dirtyScreen.setBounds(0,lenScreen - 1,0,0);
3846
3847 oia.clearScreen();
3848
3849 }
3850
3851 protected void restoreScreen() {
3852
3853 lastAttr = 32;
3854 dirtyScreen.setBounds(0,lenScreen - 1,0,0);
3855 updateDirty();
3856 }
3857
3858 /**
3859 * Notify all registered listeners of the onScreenChanged event.
3860 *
3861 */
3862 private void fireScreenChanged(int which, int startRow, int startCol,
3863 int endRow, int endCol) {
3864 if (listeners != null) {
3865 // Patch below contributed by Mitch Blevins
3866 //int size = listeners.size();
3867 Vector<ScreenListener> lc = new Vector<ScreenListener>(listeners);
3868 int size = lc.size();
3869 for (int i = 0; i < size; i++) {
3870 //ScreenListener target =
3871 // (ScreenListener)listeners.elementAt(i);
3872 ScreenListener target = lc.elementAt(i);
3873 target.onScreenChanged(1,startRow,startCol,endRow,endCol);
3874 }
3875 }
3876 dirtyScreen.setBounds(lenScreen,0,0,0);
3877 }
3878
3879 /**
3880 * Notify all registered listeners of the onScreenChanged event.
3881 *
3882 */
3883 private synchronized void fireScreenChanged(int update) {
3884 if (dirtyScreen.x > dirtyScreen.y) {
3885 // log.info(" x < y " + dirtyScreen);
3886 return;
3887 }
3888
3889 fireScreenChanged(update, getRow(dirtyScreen.x), getCol(dirtyScreen.x),
3890 getRow(dirtyScreen.y), getCol(dirtyScreen.y));
3891
3892 }
3893
3894 /**
3895 * Notify all registered listeners of the onScreenChanged event.
3896 *
3897 */
3898 private synchronized void fireCursorChanged(int update) {
3899 int startRow = getRow(lastPos);
3900 int startCol = getCol(lastPos);
3901
3902 if (listeners != null) {
3903 Vector<ScreenListener> lc = new Vector<ScreenListener>(listeners);
3904 //int size = listeners.size();
3905 int size = lc.size();
3906 for (int i = 0; i < size; i++) {
3907 ScreenListener target =
3908 lc.elementAt(i);
3909 target.onScreenChanged(update,startRow,startCol,startRow,startCol);
3910 }
3911 }
3912 }
3913
3914 /**
3915 * Notify all registered listeners of the onScreenSizeChanged event.
3916 *
3917 */
3918 private void fireScreenSizeChanged() {
3919
3920 if (listeners != null) {
3921 Vector<ScreenListener> lc = new Vector<ScreenListener>(listeners);
3922 //int size = listeners.size();
3923 int size = lc.size();
3924 for (int i = 0; i < size; i++) {
3925 ScreenListener target =
3926 lc.elementAt(i);
3927 target.onScreenSizeChanged(numRows,numCols);
3928 }
3929 }
3930 }
3931
3932 /**
3933 * This method does a complete refresh of the screen.
3934 */
3935 public final void updateScreen() {
3936 repaintScreen();
3937 setCursorActive(false);
3938 setCursorActive(true);
3939 }
3940
3941 /**
3942 * Add a ScreenListener to the listener list.
3943 *
3944 * @param listener The ScreenListener to be added
3945 */
3946 public void addScreenListener(ScreenListener listener) {
3947
3948 if (listeners == null) {
3949 listeners = new java.util.Vector<ScreenListener>(3);
3950 }
3951 listeners.addElement(listener);
3952
3953 }
3954
3955 /**
3956 * Remove a ScreenListener from the listener list.
3957 *
3958 * @param listener The ScreenListener to be removed
3959 */
3960 public void removeScreenListener(ScreenListener listener) {
3961
3962 if (listeners == null) {
3963 return;
3964 }
3965 listeners.removeElement(listener);
3966 }
3967
3968 /**
3969 * Utility method to share the repaint behaviour between setBounds() and
3970 * updateScreen.
3971 */
3972 public void repaintScreen() {
3973
3974 setCursorOff();
3975 dirtyScreen.setBounds(0,lenScreen - 1,0,0);
3976 updateDirty();
3977 // restore statuses that were on the screen before resize
3978 if (oia.getLevel() == ScreenOIA.OIA_LEVEL_INPUT_ERROR) {
3979 oia.setInputInhibited(ScreenOIA.INPUTINHIBITED_SYSTEM_WAIT,
3980 ScreenOIA.OIA_LEVEL_INPUT_ERROR);
3981 }
3982
3983 if (oia.getLevel() == ScreenOIA.OIA_LEVEL_INPUT_INHIBITED) {
3984 oia.setInputInhibited(ScreenOIA.INPUTINHIBITED_SYSTEM_WAIT,
3985 ScreenOIA.OIA_LEVEL_INPUT_INHIBITED);
3986 }
3987
3988 if (oia.isMessageWait())
3989 oia.setMessageLightOn();
3990 setCursorOn();
3991 }
3992
3993 // ADDED BY BARRY - changed by Kenneth to use the character plane
3994 // This should be replaced with the getPlane methods when they are implemented
3995 public char[] getCharacters() {
3996 return planes.screen;
3997 }
3998
3999 }