From 73981aca6f4c8aa10483c0dedb2a00a2aa9c0146 Mon Sep 17 00:00:00 2001 From: dotmg Date: Tue, 13 May 2025 14:41:26 +0200 Subject: [PATCH] Initial commit --- META-INF/MANIFEST.MF | 3 + README | 19 + build.sh | 21 + logging.properties | 61 + net/infordata/em/Main.java | 347 +++ net/infordata/em/crt/XICrt.java | 1249 ++++++++++ net/infordata/em/crt/XICrtBeanInfo.java | 84 + net/infordata/em/crt/XICrtBuffer.java | 599 +++++ net/infordata/em/crt5250/XI5250BaseField.java | 45 + net/infordata/em/crt5250/XI5250Crt.java | 1780 ++++++++++++++ .../em/crt5250/XI5250CrtAdapter.java | 75 + .../em/crt5250/XI5250CrtBeanInfo.java | 97 + net/infordata/em/crt5250/XI5250CrtBuffer.java | 676 ++++++ net/infordata/em/crt5250/XI5250CrtCtrl.java | 275 +++ net/infordata/em/crt5250/XI5250CrtEvent.java | 128 + net/infordata/em/crt5250/XI5250CrtFrame.java | 371 +++ .../em/crt5250/XI5250CrtListener.java | 72 + net/infordata/em/crt5250/XI5250Field.java | 1419 +++++++++++ .../em/crt5250/XI5250FieldAdapter.java | 67 + .../em/crt5250/XI5250FieldEvent.java | 118 + .../em/crt5250/XI5250FieldListener.java | 68 + .../em/crt5250/XI5250FieldPaintAdapter.java | 45 + .../em/crt5250/XI5250FieldPaintEvent.java | 95 + .../em/crt5250/XI5250FieldPaintListener.java | 55 + .../em/crt5250/XI5250FieldSaver.java | 44 + .../em/crt5250/XI5250FieldsList.java | 310 +++ .../em/crt5250/XIEbcdicNTranslator.java | 1070 +++++++++ .../em/crt5250/XIEbcdicTranslator.java | 273 +++ net/infordata/em/crt5250/XIImagesBdl.java | 124 + net/infordata/em/crt5250/resources/3dFx.gif | Bin 0 -> 1029 bytes .../em/crt5250/resources/CapsLock.gif | Bin 0 -> 903 bytes net/infordata/em/crt5250/resources/Copy.gif | Bin 0 -> 153 bytes net/infordata/em/crt5250/resources/Logo.gif | Bin 0 -> 1969 bytes net/infordata/em/crt5250/resources/Paste.gif | Bin 0 -> 173 bytes net/infordata/em/crt5250/resources/Print.gif | Bin 0 -> 155 bytes .../em/crt5250/resources/RefCursor.gif | Bin 0 -> 941 bytes .../em/crt5250/resources/Res.properties | 13 + .../em/crt5250/resources/Res_it.properties | 12 + .../em/crt5250/resources/ShiftDown.gif | Bin 0 -> 220 bytes net/infordata/em/tn5250/Test.java | 126 + net/infordata/em/tn5250/XI5250Applet.java | 544 +++++ net/infordata/em/tn5250/XI5250Cmd.java | 60 + net/infordata/em/tn5250/XI5250CmdList.java | 181 ++ net/infordata/em/tn5250/XI5250Emulator.java | 2099 +++++++++++++++++ .../em/tn5250/XI5250EmulatorAdapter.java | 74 + .../em/tn5250/XI5250EmulatorBeanInfo.java | 102 + .../em/tn5250/XI5250EmulatorCtrl.java | 204 ++ .../em/tn5250/XI5250EmulatorEvent.java | 124 + .../em/tn5250/XI5250EmulatorListener.java | 77 + .../em/tn5250/XI5250EmulatorMemento.java | 83 + net/infordata/em/tn5250/XI5250Exception.java | 47 + net/infordata/em/tn5250/XI5250Frame.java | 331 +++ net/infordata/em/tn5250/XI5250Ord.java | 55 + net/infordata/em/tn5250/XI5250OrdList.java | 206 ++ net/infordata/em/tn5250/XI5250StatusBar.java | 358 +++ net/infordata/em/tn5250/XICCCmd.java | 152 ++ .../em/tn5250/XIClearFmtTableCmd.java | 53 + .../em/tn5250/XIClearUnitAltCmd.java | 70 + net/infordata/em/tn5250/XIClearUnitCmd.java | 63 + net/infordata/em/tn5250/XIDataOrd.java | 130 + net/infordata/em/tn5250/XIEAOrd.java | 87 + .../em/tn5250/XIFieldTo5250Stream.java | 157 ++ net/infordata/em/tn5250/XIICOrd.java | 66 + net/infordata/em/tn5250/XIImagesBdl.java | 134 ++ net/infordata/em/tn5250/XIMCOrd.java | 71 + net/infordata/em/tn5250/XIQueryCmd.java | 90 + net/infordata/em/tn5250/XIRAOrd.java | 75 + net/infordata/em/tn5250/XIReadFieldsCmd.java | 63 + .../em/tn5250/XIReadImmediateCmd.java | 49 + .../em/tn5250/XIReadMdtFieldsCmd.java | 65 + net/infordata/em/tn5250/XIReadScreenCmd.java | 49 + .../em/tn5250/XIRestoreScreenCmd.java | 71 + net/infordata/em/tn5250/XIRollCmd.java | 79 + net/infordata/em/tn5250/XISBAOrd.java | 65 + net/infordata/em/tn5250/XISFOrd.java | 106 + net/infordata/em/tn5250/XISOHOrd.java | 102 + net/infordata/em/tn5250/XISaveScreenCmd.java | 57 + net/infordata/em/tn5250/XITDOrd.java | 90 + net/infordata/em/tn5250/XIWEAOrd.java | 82 + net/infordata/em/tn5250/XIWdsfOrd.java | 65 + .../em/tn5250/XIWriteErrorCodeCmd.java | 64 + .../em/tn5250/XIWriteToDisplayCmd.java | 97 + net/infordata/em/tn5250/resources/Connect.gif | Bin 0 -> 166 bytes .../em/tn5250/resources/Disconnect.gif | Bin 0 -> 160 bytes net/infordata/em/tn5250/resources/Flash.gif | Bin 0 -> 186 bytes .../em/tn5250/resources/HelpState.gif | Bin 0 -> 221 bytes net/infordata/em/tn5250/resources/InFrame.gif | Bin 0 -> 165 bytes net/infordata/em/tn5250/resources/Message.gif | Bin 0 -> 225 bytes .../em/tn5250/resources/NormalLockState.gif | Bin 0 -> 140 bytes .../em/tn5250/resources/Res.properties | 28 + .../em/tn5250/resources/Res_fr.properties | 27 + .../em/tn5250/resources/Res_it.properties | 26 + .../em/tn5250/resources/SnapShot.gif | Bin 0 -> 926 bytes .../tn5250/resources/TemporaryLockState.gif | Bin 0 -> 227 bytes .../em/tn5250/resources/XI5250Emulator_16.gif | Bin 0 -> 151 bytes .../em/tn5250/resources/XI5250Emulator_32.gif | Bin 0 -> 254 bytes .../em/tn5250ext/PSHBTNCHCHandler.java | 115 + net/infordata/em/tn5250ext/Test.java | 184 ++ .../em/tn5250ext/XI5250AppletExt.java | 74 + .../em/tn5250ext/XI5250EmulatorExt.java | 147 ++ .../tn5250ext/XI5250EmulatorExtBeanInfo.java | 97 + .../em/tn5250ext/XI5250FieldConnection.java | 96 + .../em/tn5250ext/XI5250PanelConnection.java | 81 + .../em/tn5250ext/XI5250PanelHandler.java | 885 +++++++ .../em/tn5250ext/XI5250PanelsDispatcher.java | 223 ++ .../XI5250SimplePanelsDispatcher.java | 196 ++ net/infordata/em/tn5250ext/XIHint.java | 365 +++ net/infordata/em/tn5250ext/XIHintWindow.java | 136 ++ net/infordata/em/tn5250ext/XIImage.java | 78 + net/infordata/em/tnprot/XITelnet.java | 933 ++++++++ net/infordata/em/tnprot/XITelnetEmulator.java | 86 + net/infordata/em/util/XICommand.java | 34 + net/infordata/em/util/XICommandMgr.java | 407 ++++ net/infordata/em/util/XIRatioLayout.java | 344 +++ net/infordata/em/util/XIUtil.java | 196 ++ res/res/Monospaced | Bin 0 -> 58464 bytes 116 files changed, 21296 insertions(+) create mode 100644 META-INF/MANIFEST.MF create mode 100644 README create mode 100644 build.sh create mode 100644 logging.properties create mode 100644 net/infordata/em/Main.java create mode 100644 net/infordata/em/crt/XICrt.java create mode 100644 net/infordata/em/crt/XICrtBeanInfo.java create mode 100644 net/infordata/em/crt/XICrtBuffer.java create mode 100644 net/infordata/em/crt5250/XI5250BaseField.java create mode 100644 net/infordata/em/crt5250/XI5250Crt.java create mode 100644 net/infordata/em/crt5250/XI5250CrtAdapter.java create mode 100644 net/infordata/em/crt5250/XI5250CrtBeanInfo.java create mode 100644 net/infordata/em/crt5250/XI5250CrtBuffer.java create mode 100644 net/infordata/em/crt5250/XI5250CrtCtrl.java create mode 100644 net/infordata/em/crt5250/XI5250CrtEvent.java create mode 100644 net/infordata/em/crt5250/XI5250CrtFrame.java create mode 100644 net/infordata/em/crt5250/XI5250CrtListener.java create mode 100644 net/infordata/em/crt5250/XI5250Field.java create mode 100644 net/infordata/em/crt5250/XI5250FieldAdapter.java create mode 100644 net/infordata/em/crt5250/XI5250FieldEvent.java create mode 100644 net/infordata/em/crt5250/XI5250FieldListener.java create mode 100644 net/infordata/em/crt5250/XI5250FieldPaintAdapter.java create mode 100644 net/infordata/em/crt5250/XI5250FieldPaintEvent.java create mode 100644 net/infordata/em/crt5250/XI5250FieldPaintListener.java create mode 100644 net/infordata/em/crt5250/XI5250FieldSaver.java create mode 100644 net/infordata/em/crt5250/XI5250FieldsList.java create mode 100644 net/infordata/em/crt5250/XIEbcdicNTranslator.java create mode 100644 net/infordata/em/crt5250/XIEbcdicTranslator.java create mode 100644 net/infordata/em/crt5250/XIImagesBdl.java create mode 100644 net/infordata/em/crt5250/resources/3dFx.gif create mode 100644 net/infordata/em/crt5250/resources/CapsLock.gif create mode 100644 net/infordata/em/crt5250/resources/Copy.gif create mode 100644 net/infordata/em/crt5250/resources/Logo.gif create mode 100644 net/infordata/em/crt5250/resources/Paste.gif create mode 100644 net/infordata/em/crt5250/resources/Print.gif create mode 100644 net/infordata/em/crt5250/resources/RefCursor.gif create mode 100644 net/infordata/em/crt5250/resources/Res.properties create mode 100644 net/infordata/em/crt5250/resources/Res_it.properties create mode 100644 net/infordata/em/crt5250/resources/ShiftDown.gif create mode 100644 net/infordata/em/tn5250/Test.java create mode 100644 net/infordata/em/tn5250/XI5250Applet.java create mode 100644 net/infordata/em/tn5250/XI5250Cmd.java create mode 100644 net/infordata/em/tn5250/XI5250CmdList.java create mode 100644 net/infordata/em/tn5250/XI5250Emulator.java create mode 100644 net/infordata/em/tn5250/XI5250EmulatorAdapter.java create mode 100644 net/infordata/em/tn5250/XI5250EmulatorBeanInfo.java create mode 100644 net/infordata/em/tn5250/XI5250EmulatorCtrl.java create mode 100644 net/infordata/em/tn5250/XI5250EmulatorEvent.java create mode 100644 net/infordata/em/tn5250/XI5250EmulatorListener.java create mode 100644 net/infordata/em/tn5250/XI5250EmulatorMemento.java create mode 100644 net/infordata/em/tn5250/XI5250Exception.java create mode 100644 net/infordata/em/tn5250/XI5250Frame.java create mode 100644 net/infordata/em/tn5250/XI5250Ord.java create mode 100644 net/infordata/em/tn5250/XI5250OrdList.java create mode 100644 net/infordata/em/tn5250/XI5250StatusBar.java create mode 100644 net/infordata/em/tn5250/XICCCmd.java create mode 100644 net/infordata/em/tn5250/XIClearFmtTableCmd.java create mode 100644 net/infordata/em/tn5250/XIClearUnitAltCmd.java create mode 100644 net/infordata/em/tn5250/XIClearUnitCmd.java create mode 100644 net/infordata/em/tn5250/XIDataOrd.java create mode 100644 net/infordata/em/tn5250/XIEAOrd.java create mode 100644 net/infordata/em/tn5250/XIFieldTo5250Stream.java create mode 100644 net/infordata/em/tn5250/XIICOrd.java create mode 100644 net/infordata/em/tn5250/XIImagesBdl.java create mode 100644 net/infordata/em/tn5250/XIMCOrd.java create mode 100644 net/infordata/em/tn5250/XIQueryCmd.java create mode 100644 net/infordata/em/tn5250/XIRAOrd.java create mode 100644 net/infordata/em/tn5250/XIReadFieldsCmd.java create mode 100644 net/infordata/em/tn5250/XIReadImmediateCmd.java create mode 100644 net/infordata/em/tn5250/XIReadMdtFieldsCmd.java create mode 100644 net/infordata/em/tn5250/XIReadScreenCmd.java create mode 100644 net/infordata/em/tn5250/XIRestoreScreenCmd.java create mode 100644 net/infordata/em/tn5250/XIRollCmd.java create mode 100644 net/infordata/em/tn5250/XISBAOrd.java create mode 100644 net/infordata/em/tn5250/XISFOrd.java create mode 100644 net/infordata/em/tn5250/XISOHOrd.java create mode 100644 net/infordata/em/tn5250/XISaveScreenCmd.java create mode 100644 net/infordata/em/tn5250/XITDOrd.java create mode 100644 net/infordata/em/tn5250/XIWEAOrd.java create mode 100644 net/infordata/em/tn5250/XIWdsfOrd.java create mode 100644 net/infordata/em/tn5250/XIWriteErrorCodeCmd.java create mode 100644 net/infordata/em/tn5250/XIWriteToDisplayCmd.java create mode 100644 net/infordata/em/tn5250/resources/Connect.gif create mode 100644 net/infordata/em/tn5250/resources/Disconnect.gif create mode 100644 net/infordata/em/tn5250/resources/Flash.gif create mode 100644 net/infordata/em/tn5250/resources/HelpState.gif create mode 100644 net/infordata/em/tn5250/resources/InFrame.gif create mode 100644 net/infordata/em/tn5250/resources/Message.gif create mode 100644 net/infordata/em/tn5250/resources/NormalLockState.gif create mode 100644 net/infordata/em/tn5250/resources/Res.properties create mode 100644 net/infordata/em/tn5250/resources/Res_fr.properties create mode 100644 net/infordata/em/tn5250/resources/Res_it.properties create mode 100644 net/infordata/em/tn5250/resources/SnapShot.gif create mode 100644 net/infordata/em/tn5250/resources/TemporaryLockState.gif create mode 100644 net/infordata/em/tn5250/resources/XI5250Emulator_16.gif create mode 100644 net/infordata/em/tn5250/resources/XI5250Emulator_32.gif create mode 100644 net/infordata/em/tn5250ext/PSHBTNCHCHandler.java create mode 100644 net/infordata/em/tn5250ext/Test.java create mode 100644 net/infordata/em/tn5250ext/XI5250AppletExt.java create mode 100644 net/infordata/em/tn5250ext/XI5250EmulatorExt.java create mode 100644 net/infordata/em/tn5250ext/XI5250EmulatorExtBeanInfo.java create mode 100644 net/infordata/em/tn5250ext/XI5250FieldConnection.java create mode 100644 net/infordata/em/tn5250ext/XI5250PanelConnection.java create mode 100644 net/infordata/em/tn5250ext/XI5250PanelHandler.java create mode 100644 net/infordata/em/tn5250ext/XI5250PanelsDispatcher.java create mode 100644 net/infordata/em/tn5250ext/XI5250SimplePanelsDispatcher.java create mode 100644 net/infordata/em/tn5250ext/XIHint.java create mode 100644 net/infordata/em/tn5250ext/XIHintWindow.java create mode 100644 net/infordata/em/tn5250ext/XIImage.java create mode 100644 net/infordata/em/tnprot/XITelnet.java create mode 100644 net/infordata/em/tnprot/XITelnetEmulator.java create mode 100644 net/infordata/em/util/XICommand.java create mode 100644 net/infordata/em/util/XICommandMgr.java create mode 100644 net/infordata/em/util/XIRatioLayout.java create mode 100644 net/infordata/em/util/XIUtil.java create mode 100644 res/res/Monospaced diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF new file mode 100644 index 0000000..8964f22 --- /dev/null +++ b/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: net.infordata.em.Main + diff --git a/README b/README new file mode 100644 index 0000000..0905338 --- /dev/null +++ b/README @@ -0,0 +1,19 @@ +xtn5250mg is a fork of vproietti's xtn5250 (https://sourceforge.net/projects/xtn5250/) + +It implements an emulator for 5250 streams to connect to AS400/iSeries. + +Difference between xtn5250mg and original xtn5250 will follow : + + *** version 0.2 *** + Re-ordering window title. Host comes before software name. + Visual representation of connection status at window title : + - prefix * or ~ if connected + - prefix ! if disconnected + Adds french localization + + *** version 0.1 *** + 1) xtn5250mg can connect to an AS400 which port is different than the default 23. + For such servers, simply append ":" and the port number to the server's address. + 2) KEEPALIVE. If you experience a recurrent session drop with xtn5250 after a + rather small period of inactivity, this fork xtn5250 addresses that issue. However, + the value of /proc/sys/net/ipv4/tcp_keepalive_time may also need to be adjusted. diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..70af366 --- /dev/null +++ b/build.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# Let's go to the folder containing the build.sh file +# We don't want to remove all .class files on the system should +# the script run on / +VERSION="0.1-1.19i" +BASEDIR=$(dirname $0) +echo $BASEDIR +cd $BASEDIR + +# xtn5250mg is a very tiny project. This build is very simple: +# it deletes all .class object to rebuild them all. +find . -name "*.class" | xargs rm -rf + +find . -name "*.java" > .javasources.txt +javac -target 7 -source 7 -encoding "ISO8859-1" @.javasources.txt +#rm -f .javasources.txt + +JARFILE="xtn5250mg-${VERSION}.jar" +rm -f $JARFILE +jar cvmf META-INF/MANIFEST.MF $JARFILE build.sh net README logging.properties -C res res diff --git a/logging.properties b/logging.properties new file mode 100644 index 0000000..a7e9f57 --- /dev/null +++ b/logging.properties @@ -0,0 +1,61 @@ +############################################################ +# Default Logging Configuration File +# +# You can use a different file by specifying a filename +# with the java.util.logging.config.file system property. +# For example java -Djava.util.logging.config.file=myfile +############################################################ + +############################################################ +# Global properties +############################################################ + +# "handlers" specifies a comma separated list of log Handler +# classes. These handlers will be installed during VM startup. +# Note that these classes must be on the system classpath. +# By default we only configure a ConsoleHandler, which will only +# show messages at the INFO and above levels. +handlers= java.util.logging.ConsoleHandler + +# To also add the FileHandler, use the following line instead. +#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler + +# Default global logging level. +# This specifies which kinds of events are logged across +# all loggers. For any given facility this global level +# can be overriden by a facility specific level +# Note that the ConsoleHandler also has a separate level +# setting to limit messages printed to the console. +.level= INFO + +############################################################ +# Handler specific properties. +# Describes specific configuration info for Handlers. +############################################################ + +# default file output is in user's home directory. +#java.util.logging.FileHandler.pattern = %h/java%u.log +java.util.logging.FileHandler.pattern = xtn5250.log +java.util.logging.FileHandler.limit = 50000 +java.util.logging.FileHandler.count = 1 +#java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter +java.util.logging.FileHandler.level = ALL +java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter + +# Limit the message that are printed on the console to INFO and above. +java.util.logging.ConsoleHandler.level = ALL +java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter + + +############################################################ +# Facility specific properties. +# Provides extra control for each logger. +############################################################ + +# For example, set the com.xyz.foo logger to only log SEVERE +# messages: +#net.infordata.em.tnprot.level = FINEST +#net.infordata.em.tn5250.XI5250OrdList.level = FINER +#net.infordata.em.tn5250.XI5250Emulator.level = FINER +#net.infordata.em.tn5250.XI5250CmdList.level = FINEST + diff --git a/net/infordata/em/Main.java b/net/infordata/em/Main.java new file mode 100644 index 0000000..212d193 --- /dev/null +++ b/net/infordata/em/Main.java @@ -0,0 +1,347 @@ +package net.infordata.em; + +import java.awt.Font; +import java.awt.FontFormatException; +import java.awt.Frame; +import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.lang.reflect.InvocationTargetException; +import java.io.IOException; +import java.io.FileNotFoundException; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.File; + +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +import net.infordata.em.crt5250.XI5250Field; +import net.infordata.em.crt5250.XIEbcdicTranslator; +import net.infordata.em.tn5250.XI5250Emulator; +import net.infordata.em.tn5250.XI5250Frame; +import net.infordata.em.tn5250ext.PSHBTNCHCHandler; +import net.infordata.em.tn5250ext.XI5250EmulatorExt; +import net.infordata.em.tn5250ext.XI5250PanelHandler; +import net.infordata.em.tn5250ext.XI5250PanelsDispatcher; +import net.infordata.em.tn5250.XIImagesBdl; + + +/** + * Command line startup utility. + * @author valentino.proietti + */ +public class Main { + + // images + private static XIImagesBdl cvImagesBdl = + net.infordata.em.tn5250.XIImagesBdl.getImagesBdl(); + + private Main() {} + + private static void usageError(String msg) { + System.err.println(msg); + System.err.println("Usage: [-3dFX] [-PSHBTNCHC] [-STRPCCMD] [-altFKeyRemap]" + + " [-maximized] [-cp codepage] [-devName name]" + + " [-autoLogon ;;;;]" + + " host-name"); + System.err.println("Supported code pages:"); + for (String cp : XIEbcdicTranslator.getRegisteredTranslators().keySet()) { + System.err.println(" " + cp + + (XI5250Emulator.DEFAULT_CODE_PAGE.equalsIgnoreCase(cp)? " default" : "")); + } + System.exit(1); + } + + public static Font loadFontFromResource(Class theClass, String fontFileName, float fontSize) { + float fntSize = 12f; + if (fontSize >= 1f) { + fntSize = fontSize; + } + InputStream is = null; + try { + is = new FileInputStream("/tmp/Inconsolata.otf"); + } catch (FileNotFoundException ex) { + System.err.println("file not found font : " + ex); + } + Font font = null; + try { + System.err.println(" createFont Testing res/" + fontFileName + " ... "); + font = Font.createFont(Font.TRUETYPE_FONT, is); + System.err.println(" createFont OK "); + font = font.deriveFont(fntSize); + } catch (FontFormatException | IOException ex) { + System.err.println(" Font err : " + ex.getMessage()); + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException ex) { + System.err.println("Close error : " + ex.getMessage()); + } + } + } + return font; + } + + /** + */ + public static void main(String[] args) { + + boolean pUse3dFX = false; + boolean pAltFKeyRemap = false; + boolean pPSHBTNCHC = false; + boolean pSTRPCCMD = false; + boolean pMaximized = false; + + String arg; + String pHost = null; + boolean expectCP = false; + boolean expectDevName = false; + boolean expectLogonInfo = false; + String cp = null; + String devName = null; + LogonInfo logonInfo = null; + for (int i = 0; i < args.length; i++) { + arg = args[i]; + if (arg.startsWith("-")) { + if ("-3dfx".equalsIgnoreCase(arg)) + pUse3dFX = true; + else if ("-PSHBTNCHC".equalsIgnoreCase(arg)) + pPSHBTNCHC = true; + else if ("-STRPCCMD".equalsIgnoreCase(arg)) + pSTRPCCMD = true; + else if ("-maximized".equalsIgnoreCase(arg)) + pMaximized = true; + else if ("-altFKeyRemap".equalsIgnoreCase(arg)) + pAltFKeyRemap = true; + else if ("-cp".equalsIgnoreCase(arg)) + expectCP = true; + else if ("-devName".equalsIgnoreCase(arg)) + expectDevName = true; + else if ("-autoLogon".equalsIgnoreCase(arg)) + expectLogonInfo = true; + else + usageError("Wrong option: " + arg); + } + else if (expectCP) { + expectCP = false; + if (XIEbcdicTranslator.getTranslator(arg) == null) + usageError("Unknown codepage: " + arg); + cp = arg; + } + else if (expectDevName) { + expectDevName = false; + devName = arg; + } + else if (expectLogonInfo) { + expectLogonInfo = false; + try { + logonInfo = new LogonInfo(arg); + } + catch (IllegalArgumentException ex) { + usageError(ex.getMessage()); + } + } + else { + if (pHost == null) + pHost = arg; + else + usageError("Too many host names."); + } + } + if (expectCP) + usageError("A code page is expected"); + + final boolean altFKeyRemap = pAltFKeyRemap; + final boolean use3dFX = pUse3dFX; + final boolean enablePSHBTNCHC = pPSHBTNCHC; + final boolean enableSTRPCCMD = pSTRPCCMD; + final boolean maximized = pMaximized; + final String host = pHost; + final String codePage = cp; + final String deviceName = devName; + final LogonInfo autoLogonInfo = logonInfo; + try { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + XI5250Emulator em; + if (enablePSHBTNCHC) { + XI5250EmulatorExt emext = new XI5250EmulatorExt(); + PanelsDispatcher disp = new PanelsDispatcher(); + disp.setEmulator(emext); + new PSHBTNCHCHandler(disp); + if (autoLogonInfo != null) + new AutoLogonHandler(disp, autoLogonInfo); + em = emext; + } + else if (autoLogonInfo != null) { + XI5250EmulatorExt emext = new XI5250EmulatorExt(); + PanelsDispatcher disp = new PanelsDispatcher(); + disp.setEmulator(emext); + new AutoLogonHandler(disp, autoLogonInfo); + em = emext; + } + else { + em = new XI5250Emulator(); + } + em.setTerminalType("IBM-3477-FC"); + em.setKeyboardQueue(true); + + em.setStrPcCmdEnabled(enableSTRPCCMD); + em.setAltFKeyRemap(altFKeyRemap); + em.setCodePage(codePage); + + if (deviceName != null) + em.setTelnetEnv("\u0003DEVNAME\u0001" + deviceName); + + if (host != null) { + em.setHost(host); + em.setActive(true); + } + + Font mahefaFont = loadFontFromResource(Main.class, "MonoSpaced", 1); + em.setFont(mahefaFont); + XI5250Frame frm = new XI5250Frame("xtn5250mg" + " " + + XI5250Emulator.VERSION, em); + frm.setFont(mahefaFont); + frm.setIconImage(cvImagesBdl.getImage("Logo")); + + frm.addWindowListener(new WindowAdapter() { + @Override + public void windowClosed(WindowEvent e) { + System.exit(0); + } + }); + + //3D FX + if (use3dFX) { + em.setDefFieldsBorderStyle(XI5250Field.LOWERED_BORDER); + em.setDefBackground(UIManager.getColor("control")); + } + + //frm.setBounds(0, 0, 570, 510); + frm.centerOnScreen(70); + if (maximized) { + frm.doNotPackOnStartup(); + frm.setExtendedState(Frame.MAXIMIZED_BOTH); + } + frm.setVisible(true); + } + }); + } + catch (InterruptedException ex) { + ex.printStackTrace(); + } + catch (InvocationTargetException ex) { + ex.printStackTrace(); + } + } + + ////// + + private static class PanelsDispatcher extends XI5250PanelsDispatcher { + + private AutoLogonHandler ivAutoLogonHandler; + private XI5250PanelHandler ivHandler; + + @Override + public synchronized void addPanelHandler(XI5250PanelHandler panel) { + if (panel instanceof AutoLogonHandler) { + if (ivAutoLogonHandler != null) + throw new IllegalArgumentException("Handler already setted"); + ivAutoLogonHandler = (AutoLogonHandler)panel; + return; + } + if (ivHandler != null) + throw new IllegalArgumentException("Handler already setted"); + ivHandler = panel; + } + + @Override + protected synchronized XI5250PanelHandler getCurrentPanelHandler() { + return (ivAutoLogonHandler != null && ivAutoLogonHandler.detailedTest()) ? ivAutoLogonHandler : ivHandler; + } + + @Override + public synchronized void removePanelHandler(XI5250PanelHandler panel) { + if (ivHandler != panel) + throw new IllegalArgumentException("Not the registered handler " + panel); + ivHandler = null; + } + } + + ////// + + private static class LogonInfo { + + final int fieldsCount; + final String userLabel; + final String passwdLabel; + final String user; + final String passwd; + + LogonInfo(String info) { + String[] ss = info.split(";", 5); + if (ss.length < 5) + throw new IllegalArgumentException("Invalid autoLogon argument"); + try { + fieldsCount = Integer.parseInt(ss[0]); + } + catch (NumberFormatException ex) { + throw new IllegalArgumentException("Invalid autoLogon argument: " + ex.getMessage()); + } + userLabel = ss[1]; + passwdLabel = ss[2]; + user = ss[3]; + passwd = ss[4]; + } + } + + ////// + + private static class AutoLogonHandler extends XI5250PanelHandler { + + private final LogonInfo ivLogonInfo; + private boolean ivLoggedOn; + + public AutoLogonHandler(XI5250PanelsDispatcher aPanelDisp, LogonInfo info) { + super(aPanelDisp); + ivLogonInfo = info; + } + + @Override + protected boolean detailedTest() { + if (ivLoggedOn) + return false; + // I'm expecting xx fields in the logon panel + if (getFields().size() != ivLogonInfo.fieldsCount) + return false; + // Is there the user id field ? + if (!checkField(getFieldNextTo(ivLogonInfo.userLabel), 10)) + return false; + // Is there the password field ? + if (!checkField(getFieldNextTo(ivLogonInfo.passwdLabel), 10)) + return false; + return true; + } + + @Override + protected void start() { + ivLoggedOn = true; + // Start logon panel processing + XI5250Field userField = getFieldNextTo(ivLogonInfo.userLabel); + XI5250Field passwdField = getFieldNextTo(ivLogonInfo.passwdLabel); + userField.setString(ivLogonInfo.user); // Your user id + passwdField.setString(ivLogonInfo.passwd); // Your password + // Simulate the user ENTER key pressed + getEmulator().processRawKeyEvent( + new KeyEvent(getEmulator(), KeyEvent.KEY_PRESSED, + 0, 0, KeyEvent.VK_ENTER, KeyEvent.CHAR_UNDEFINED)); + } + + @Override + protected void stop() { + } + } +} diff --git a/net/infordata/em/crt/XICrt.java b/net/infordata/em/crt/XICrt.java new file mode 100644 index 0000000..34b68c3 --- /dev/null +++ b/net/infordata/em/crt/XICrt.java @@ -0,0 +1,1249 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 08/04/97 rel. 0.92a- new update method that avoid screen flashing. + 18/04/97 rel. 0.92b- setFreeze() method changed. + 14/05/97 rel. 1.00 - first release. + 23/05/97 rel. 1.00a- improved recalcFontSize() method. + 05/06/97 rel. 1.00c- reference cursor. + 08/07/97 rel. 1.01c- if the crt is freezed then the cursor is never drawed. + 14/07/97 rel. 1.02 - setCrtSize() method added. + 15/07/97 rel. 1.02c- finalize() method added. + 17/07/97 rel. 1.02e- revisited setFont(). + 25/07/97 rel. 1.03a- revisited setFont(). + 30/07/97 rel. 1.03b- bugs. + 06/07/97 rel. 1.03c- double-buffering. + 28/08/97 rel. 1.04 - bug in setFreeze(). + 24/09/97 rel. 1.05 - DNCX project. + 14/01/98 rel. 1.06 - asynchronous paint on off-screen image. + 03/03/98 rel. _.___- SWING and reorganization. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + 04/02/99 rel. 1.11 - Swing 1.1, bug in recalcFontSize() and jdk 1.2 support. + 11/06/99 rel. 1.12a- CursorShape interface has been introduced, some rework + on cursor handling. + 29/07/99 rel. 1.14 - Rework on 3d look&feel. + 27/02/01 rel. _.__ - Rework on cursor handling. + */ + + +package net.infordata.em.crt; + + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.image.VolatileImage; +import java.awt.FontFormatException; +import java.io.IOException; +import java.io.FileNotFoundException; +import java.io.ObjectInputStream; +import java.io.InputStream; +import java.io.ObjectOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +import net.infordata.em.util.XIUtil; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Implements a generic monospaced-character panel. + * It uses an out off screen image buffer to speed-up painting operations. + * Character coordinate are zero based. + * + * @see XICrtBuffer + * + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XICrt extends JComponent implements Serializable { + + private static final long serialVersionUID = 1L; + + // Debug level 0 = none, 1 = , 2 = detailed + static final int DEBUG = 0; + + /** + * Minimum accepted font size. + * @see #setFont + */ + public static final int MIN_FONT_SIZE = 1; + public static final int MAX_FONT_SIZE = 30; //!!V 03/03/98 + + // + transient private VolatileImage ivImage; + + // The offscreen buffer. + private XICrtBuffer ivCrtBuffer; + + // repaint is freezed + transient private boolean ivFreeze = false; + transient private int ivRepaintCount; + //!!0.92b + transient private Rectangle ivSumRect; + + // cursor blinking thread + transient private CursorBlinkingThread ivBlinkThread; + + // used to calculate minimum-size + transient private int ivMinCharW; + transient private int ivMinCharH; + + transient private boolean ivInitialized; + + // + private Font ivFont; + + //!!V 03/03/98 + transient private FontsCache ivFontsCache; + + //!!1.11 properties + public static final String CRT_SIZE = "crtSize"; + + //!!1.12a + transient public Cursor ivCursor = new Cursor(); + + private static final CursorShape cvDefaultCursorShape = + new DefaultCursorShape(); + private static final CursorShape cvVoidCursorShape = + new VoidCursorShape(); + + public static Font loadFontFromResource(Class theClass, String fontFileName, float fontSize) { + float fntSize = 12f; + if (fontSize >= 1f) { + fntSize = fontSize; + } + InputStream is = null; + try { + is = new FileInputStream("/tmp/x.ttf"); + } catch (FileNotFoundException ex) { + System.err.println("file not found font : " + ex); + } + Font font = null; + try { + System.err.println(" createFont Testing res/" + fontFileName + " ... "); + font = Font.createFont(Font.TRUETYPE_FONT, is); + System.err.println(" createFont OK "); + font = font.deriveFont(fntSize); + } catch (FontFormatException | IOException ex) { + System.err.println(" Font err : " + ex.getMessage()); + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException ex) { + System.err.println("Close error : " + ex.getMessage()); + } + } + } + return font; + } + /** + * Default constructor. + */ + public XICrt() { + setFreeze(true); + setOpaque(true); + + /* + if (XIUtil.is1dot2) + setFont(new Font("Monospaced", Font.PLAIN, MIN_FONT_SIZE)); + else + */ + Font inconsolata = loadFontFromResource(XICrt.class, "MonoSpaced", MIN_FONT_SIZE); + setFont(inconsolata); + //setFont(new Font("Monospaced", Font.PLAIN, MIN_FONT_SIZE)); + setLayout(null); + setCrtBuffer(createCrtBuffer(80, 24)); + setBackground(Color.red); + } + + + /** + * Factory method for XICrtBuffer creation. + * @see XICrtBuffer + */ + protected XICrtBuffer createCrtBuffer(int nCols, int nRows) { + return new XICrtBuffer(nCols, nRows); + } + + + /** + * Changes the panel font. + * Only monospaced fonts are accepted. + */ + @Override + public void setFont(Font aFont) { + FontMetrics fontMetrics = getFontMetrics(aFont); + if (fontMetrics.charWidth('W') != fontMetrics.charWidth('i')) + { + System.out.println(fontMetrics.charWidth('W')); + System.out.println(fontMetrics.charWidth('i')); + //throw new IllegalArgumentException("We Accept only monospaced font"); + } + + if (aFont.getSize() < MIN_FONT_SIZE) + throw new IllegalArgumentException("Font too small"); + if (aFont.getSize() > MAX_FONT_SIZE) + throw new IllegalArgumentException("Font too great"); + + if (aFont.equals(ivFont)) + return; + + if (ivFont == null || + !aFont.getName().equals(ivFont.getName()) || + aFont.getStyle() != ivFont.getStyle()) + ivFontsCache = new FontsCache(aFont); + + ivFont = aFont; + super.setFont(ivFont); + + if (ivInitialized) + initializeCrtBuffer(); + } + + + /** + */ + @Override + public Font getFont() { + return ivFont; + } + + + private Graphics initializeVolatileImage() { + Font font = getFont(); + FontMetrics fontMetrics = getFontMetrics(font); + + int ww = fontMetrics.charWidth('W'); + int hh = fontMetrics.getHeight(); + ivImage = createVolatileImage(ivCrtBuffer.getCrtSize().width * ww, + ivCrtBuffer.getCrtSize().height * hh); + Graphics gr = ivImage.getGraphics(); + gr.setFont(font); + + fontMetrics = getFontMetrics(new Font(font.getName(), font.getStyle(), MIN_FONT_SIZE)); + ivMinCharW = fontMetrics.charWidth('W'); + ivMinCharH = fontMetrics.getHeight(); + return gr; + } + + /** + */ + private void initializeCrtBuffer() { + synchronized (this) { + ivCrtBuffer.setGraphics(initializeVolatileImage()); + repaint(); + } + // request parent layout recalc. + super.invalidate(); + //!!0.96 it' s up to the parent decide when validate itself + //!!0.96 getParent().validate(); + } + + + /** + * If initialized calls recalcFontSize(). + * @see #recalcFontSize + */ + @Override + public void invalidate() { + if (ivInitialized) + recalcFontSize(); + + super.invalidate(); + } + + + /** + * Redefines Panel.addNotify() to do some initializations when called for + * the first time. + */ + @Override + public void addNotify() { + super.addNotify(); + + if (!ivInitialized) { + ivInitialized = true; + + initializeCrtBuffer(); + //setFont(ivStartFont); + + setFreeze(false); + + //setBlinkingCursor(false); + } + } + + + /** + */ + @Override + public void removeNotify() { + ivInitialized = false; + setFreeze(true); + super.removeNotify(); + ivCrtBuffer.setGraphics(null); + Font inconsolata = loadFontFromResource(XICrt.class, "MonoSpaced", MIN_FONT_SIZE); + setFont(inconsolata); + //setFont(new Font("Monospaced", Font.PLAIN, MIN_FONT_SIZE)); + } + + + /** + * Returns the preferred size based on the current font dimension. + */ + @Override + public Dimension getPreferredSize() { + return ivCrtBuffer.getSize(); + } + + + /** + * Returns the minimum size based on minimum size of the current font. + */ + @Override + public Dimension getMinimumSize() { + return new Dimension(ivMinCharW * ivCrtBuffer.getCrtSize().width, + ivMinCharH * ivCrtBuffer.getCrtSize().height); + } + + + /** + * Redefined to handle the freeze attribute. + * @see #setFreeze + */ + @Override + public void repaint(long tm, int x, int y, int width, int height) { + if (!ivFreeze) + super.repaint(tm, x, y, width, height); + else { + ++ivRepaintCount; + ivSumRect = ivSumRect.union(new Rectangle(x, y, width, height)); + } + } + + + /** + * Freezes the screen, can be used to group more than one repaint. + * Do not forget to restore freeze to false when done. + *
+   * setFreeze(true);
+   * try {
+   *   ...      // repaints to be grouped
+   * }
+   * finally {
+   *   setFreeze(false);
+   * }
+   * 
+ */ + public synchronized void setFreeze(boolean bb) { + if (bb == ivFreeze) + return; + + ivFreeze = bb; //!!1.04 + + if (!ivFreeze) { + if (ivRepaintCount > 0) + repaint(ivSumRect.x, ivSumRect.y, ivSumRect.width, ivSumRect.height); + ivSumRect = null; + ivRepaintCount = 0; + + ivCursor.resync(); + } + else { + ivSumRect = new Rectangle(); + + //!!1.04 avoids cursor refresh + //!!1.04 drawCursor(null, false); + } + } + + + /** + */ + public final boolean isFreeze() { + return ivFreeze; + } + + + /** + */ + @Override + public final void paint(Graphics g) { + // remove cursor from screen + //!!V cannot check if the cursor intersects the clipping area, because the + // cursor shape can exceed the cursor bounding rectangle (5250 reference + // cursor + ivCursor.beforePaint(g); + try { + super.paint(g); + } + finally { + ivCursor.afterPaint(g); + } + } + + + /** + * do nothing. + */ + @Override + protected void paintBorder(Graphics g) { + } + + + /** + * Subclasses must redefine foregroundPaint to add painting. + * @see #foregroundPaint + */ + @Override + public synchronized void paintComponent(Graphics g) { + if (ivImage != null) { + GraphicsConfiguration gconf = getGraphicsConfiguration(); // acquires a tree-lock + synchronized (ivCrtBuffer) { + do { + int returnCode = ivImage.validate(gconf); + if (returnCode == VolatileImage.IMAGE_RESTORED) { + // Contents need to be restored + ivCrtBuffer.invalidateAll(); + } + else if (returnCode == VolatileImage.IMAGE_INCOMPATIBLE) { + // old vImg doesn't work with new GraphicsConfig; re-create it + ivCrtBuffer.setGraphics(initializeVolatileImage()); + ivCrtBuffer.invalidateAll(); + } + ivCrtBuffer.sync(); //!!1.06 + g.drawImage(ivImage, 0, 0, null); + if (true) break; + } while (ivImage.contentsLost()); + } + } + + if (isOpaque()) { + Dimension crtBuf = getCrtBufferSize(); + Dimension crt = getSize(); + g.setColor(getBackground()); + g.fillRect(crtBuf.width, 0, crt.width - crtBuf.width, crt.height); + g.fillRect(0, crtBuf.height, crt.width, crt.height - crtBuf.height); + } + + foregroundPaint(g); + + if (DEBUG >= 2) { + Rectangle rt = g.getClipBounds(); + g.setColor(Color.red); + g.drawRect(rt.x, rt.y, rt.width - 1, rt.height - 1); + } + } + + + /** + * Subclasses must redefine this method to add paintings instead of paint() + */ + protected void foregroundPaint(Graphics g) { + super.paintComponent(g); + } + + + /** + * Clears the panel. + */ + public void clear() { + ivCrtBuffer.clear(); + repaint(); + } + + + /** + * Scrolls a portion of the panel. + */ + public void scroll(boolean down, int row1, int row2, int nLines) { + if (down) + ivCrtBuffer.scrollDown(row1, row2, nLines); + else + ivCrtBuffer.scrollUp(row1, row2, nLines); + + repaint(0, row1 * ivCrtBuffer.getCharSize().height, + ivCrtBuffer.getSize().width, + (row2 - row1) * ivCrtBuffer.getCharSize().height); + } + + + /** + * Draws a string using the default attribute. + */ + public void drawString(String str, int col, int row) { + drawString(str, col, row, ivCrtBuffer.getDefAttr()); + } + + + /** + * Draws a string with the given attribute. + */ + public void drawString(String str, int col, int row, int aAttr) { + ivCrtBuffer.drawString(str, col, row, aAttr); + repaint(col * ivCrtBuffer.getCharSize().width, row * ivCrtBuffer.getCharSize().height, + str.length() * ivCrtBuffer.getCharSize().width, ivCrtBuffer.getCharSize().height); + } + + + /** + * Can be used to verify the presence of a string in the buffer. + * @see String#indexOf + */ + public String getString(int col, int row, int nChars) { + return ivCrtBuffer.getString(col, row, nChars); + } + + + /** + * Can be used to verify the presence of a string in the buffer. + * @see String#indexOf + */ + public String getString() { + return ivCrtBuffer.getString(); + } + + + /** + * Returns the attribute at the given position. + */ + public int getAttr(int col, int row) { + return ivCrtBuffer.getAttr(col, row); + } + + + /** + * Returns the character present at the given position. + */ + public char getChar(int col, int row) { + return ivCrtBuffer.getChar(col, row); + } + + + /** + * Sets the default attribute. + */ + public void setDefAttr(int aAttr) { + ivCrtBuffer.setDefAttr(aAttr); + } + + + /** + * Forces the column coord in crt bounds + */ + protected final int assureColIn(int aCol) { + return Math.max(0, Math.min(ivCrtBuffer.getCrtSize().width - 1, aCol)); + } + + + /** + * Forces the row coord in crt bounds + */ + protected final int assureRowIn(int aRow) { + return Math.max(0, Math.min(ivCrtBuffer.getCrtSize().height - 1, aRow)); + } + + + /** + * Moves the cursor at the give position. + */ + public void setCursorPos(int aCol, int aRow) { + ivCursor.setPosition(assureColIn(aCol), assureRowIn(aRow)); + } + + + /** + * Returns the cursor column position. + */ + public int getCursorCol() { + return ivCursor.getCol(); + } + + + /** + * Returns the cursor row position. + */ + public int getCursorRow() { + return ivCursor.getRow(); + } + + + /** + * Sets the dimensions in chars. + * The screen is cleared and the cursor is moved to (0, 0). + */ + public void setCrtSize(int nCols, int nRows) { + synchronized (this) { + Dimension dim = ivCrtBuffer.getCrtSize(); + + if (dim.width == nCols && dim.height == nRows) + return; + + XICrtBuffer newCrtBuffer = createCrtBuffer(nCols, nRows); + setCrtBuffer(newCrtBuffer); + + if (ivInitialized) //!!1.04 + ivCrtBuffer.setGraphics(ivImage.getGraphics()); + } + + setCursorPos(0, 0); + repaint(); + invalidate(); + + firePropertyChange(CRT_SIZE, null, null); + } + + + /** + * Returns the dimensions in chars. + */ + public Dimension getCrtSize() { + return ivCrtBuffer.getCrtSize(); + } + + + /** + * Sets the offscreen buffer. + */ + protected final void setCrtBuffer(XICrtBuffer aCrt) { + if (aCrt == ivCrtBuffer) + return; + + //!!1.14 if (ivInitialized) + //!!1.14 throw new IllegalArgumentException("Crt already initialized"); + if (aCrt.getCrt() != null) + throw new IllegalArgumentException("Buffer already associated with a crt"); + + if (ivCrtBuffer != null) + ivCrtBuffer.setCrt(null); + ivCrtBuffer = aCrt; + if (ivCrtBuffer != null) + ivCrtBuffer.setCrt(this); + } + + + /** + */ + protected final XICrtBuffer getCrtBuffer() { + return ivCrtBuffer; + } + + + /** + * Returns the dimension in pixels of the off-screen buffer. + */ + public Dimension getCrtBufferSize() { + return ivCrtBuffer.getSize(); + } + + + /** + * Returns the current char size in pixels. + */ + public Dimension getCharSize() { + return ivCrtBuffer.getCharSize(); + } + + + /** + * Returns the minimum char size in pixels. + */ + public Dimension getMinCharSize() { + return new Dimension(ivMinCharW, ivMinCharH); + } + + + /** + * Returns the cursor bounding rectangle. + */ + protected Rectangle getCursorRect() { + return ivCursor.getBoundingRect(); + } + + + /** + */ + public void setCursorVisible(boolean aFlag) { + ivCursor.setVisible(aFlag); + } + + + /** + */ + public final boolean isCursorVisible() { + return ivCursor.isVisible(); + } + + + /** + */ + public synchronized void setBlinkingCursor(boolean flag) { + if (flag == (ivBlinkThread != null)) + return; + + if (flag) { + ivBlinkThread = new CursorBlinkingThread(); + ivBlinkThread.setPriority(Thread.NORM_PRIORITY - 1); + ivBlinkThread.start(); + } + else { + ivBlinkThread.terminate(); + ivBlinkThread = null; + } + + ivCursor.resync(); + } + + + /** + */ + public boolean isBlinkingCursor() { + return ivBlinkThread != null; + } + + + /** + * Used by recalcFontSize. + * Can be changed by subclasses to take care, for example, of the status-bar presence. + * @see recalcFontSize + */ + protected Dimension getTestSize(Font aFont) { + FontMetrics fm = getFontMetrics(aFont); + Dimension res = new Dimension(fm.charWidth('W') * getCrtSize().width, + fm.getHeight() * getCrtSize().height); + return res; + } + + + /** + * Found a font able to cover as much as possible of the off-screen + * buffer surface. + */ + private void recalcFontSize() { + Font font = getFont(); + Dimension size = getSize(); + + int i = 0; + Font xFont = font; + Font yFont = font; + Font ft; + + int startIdx = 1; + if (size.width < ivCrtBuffer.getSize().width) { + for (i = xFont.getSize(); i >= MIN_FONT_SIZE; i -= 4) { + ft = ivFontsCache.getFont(i); + if (getTestSize(ft).width <= size.width) { + xFont = ft; + break; + } + else + xFont = ft; + } + startIdx = 0; + } + // found max font (x dimension) + // to speed up the search uses a two step algorythm + for (int j = startIdx; j >= 0; j--) { + for (i = xFont.getSize(); i <= 30; i += (1 + j * 3)) { + ft = ivFontsCache.getFont(i); + if (getTestSize(ft).width <= size.width) + xFont = ft; + else + break; + } + } + + // found max font (y dimension) + startIdx = 1; + if (size.height < ivCrtBuffer.getSize().height) { + for (i = yFont.getSize(); i >= MIN_FONT_SIZE; i -= 4) { + ft = ivFontsCache.getFont(i); + if (getTestSize(ft).height <= size.height) { + yFont = ft; + break; + } + else + yFont = ft; + } + startIdx = 0; + } + for (int j = startIdx; j >= 0; j--) { + for (i = yFont.getSize(); i <= 30; i += (1 + j * 3)) { + ft = ivFontsCache.getFont(i); + if (getTestSize(ft).height <= size.height) + yFont = ft; + else + break; + } + } + + // try to use the smaller one + setFont(ivFontsCache.getFont(Math.min(xFont.getSize(), yFont.getSize()))); + } + + + /** + * From char coords to point coords. + */ + public final Point toPoints(int aCol, int aRow) { + return ivCrtBuffer.toPoints(aCol, aRow); + } + + + /** + * From char coords to point coords. + */ + public final Rectangle toPoints(int aCol, int aRow, int aNCols, int aNRows) { + return ivCrtBuffer.toPoints(aCol, aRow, aNCols, aNRows); + } + + + /** + */ + @Override + protected void finalize() throws Throwable { + setBlinkingCursor(false); + super.finalize(); + } + + + /** + */ + void writeObject(ObjectOutputStream oos) throws IOException { + oos.defaultWriteObject(); + } + + void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { + ois.defaultReadObject(); + } + + + /** + */ + protected CursorShape getCursorShape() { + return cvDefaultCursorShape; + } + + /** + */ + protected CursorShape getFixedCursorShape() { + return null; + } + + + /** + * Used only for test purposes. + */ + public static void main(String[] argv) { + JFrame frm = new JFrame(); + XICrt crt = new XICrt(); + + crt.drawString("eccome" + '!', 0, 1); + + crt.setBackground(Color.green); + + + frm.getContentPane().add(crt); + frm.setBounds(0, 0, 600, 500); + + frm.setVisible(true); + + crt.setCursorVisible(true); + crt.drawString("CIAO", 0, 0); + crt.drawString("X", 79, 23); + + System.out.println(crt.ivCrtBuffer.getChar(79, 23)); + + try { + Thread.sleep(5000); + } + catch (Exception ex) { + } + crt.drawString("ARICIAO", 20, 0); + + System.out.println("end."); + } + + + ////////////////////////////////////////////////////////////////////////////// + + private class FontsCache { + + private Font[] ivFonts = new Font[MAX_FONT_SIZE - MIN_FONT_SIZE + 1]; + private Font ivFont; + + + public FontsCache(Font font) { + ivFont = font; + } + + + public Font getFont(int size) { + if (ivFonts[size - MIN_FONT_SIZE] == null) { + ivFonts[size - MIN_FONT_SIZE] = new Font(ivFont.getName(), + ivFont.getStyle(), + size); + } + return ivFonts[size - MIN_FONT_SIZE]; + } + } + + + ////////////////////////////////////////////////////////////////////////////// + + private class CursorBlinkingThread extends Thread { + + private volatile boolean ivTerminate = false; + + + public CursorBlinkingThread() { + super("XICrt cursor blinking thread"); + } + + + public void terminate() { + ivTerminate = true; + interrupt(); + } + + + @Override + public void run() { + while (!ivTerminate) { + if (isCursorVisible()) + ivCursor.blink(); + + try { + Thread.sleep(700); + } + catch (Exception ex) { + } + } + } + } + + + ////////////////////////////////////////////////////////////////////////////// + + /** + * A cursor shape cannot change its shape, but you can switch to a different + * cursor shape. + */ + public static interface CursorShape { + + /** + */ + public void drawCursorShape(Graphics gc, Rectangle rt); + } + + + ////////////////////////////////////////////////////////////////////////////// + + /** + */ + public static class VoidCursorShape implements CursorShape { + + /** + */ + public void drawCursorShape(Graphics gc, Rectangle rt) { + } + } + + + ////////////////////////////////////////////////////////////////////////////// + + /** + */ + public static class DefaultCursorShape implements CursorShape { + + /** + */ + public void drawCursorShape(Graphics gc, Rectangle rt) { + gc.setColor(Color.white); + gc.setXORMode(Color.black); + gc.fillRect(rt.x, rt.y, rt.width, rt.height); + gc.setPaintMode(); + } + } + + + ////////////////////////////////////////////////////////////////////////////// + + /** + */ + private class Cursor implements Serializable { + + private static final long serialVersionUID = 1L; + + transient private List ivCursorsPH = new ArrayList(10); + + private CursorPlaceHolder ivCurrentCursorPH = new CursorPlaceHolder(0, 0); + + private boolean ivVisible = true; + + transient private int ivPending = 0; + transient private int ivPendingBlink = 0; + + transient private Runnable ivPendingEvent = new Runnable() { + public void run() { + ivPending = 0; + sync(false, null, true); + } + }; + + transient private Runnable ivPendingBlinkEvent = new Runnable() { + private boolean flag; + public void run() { + ivPendingBlink = 0; + flag = !flag; + sync(true, null, flag); + } + }; + + /** + */ + public void resync() { + if (SwingUtilities.isEventDispatchThread()) + ivPendingEvent.run(); + else + if ((ivPending++) == 0) + SwingUtilities.invokeLater(ivPendingEvent); + } + + /** + */ + public void blink() { + if (SwingUtilities.isEventDispatchThread()) + ivPendingBlinkEvent.run(); + else + if ((ivPendingBlink++) == 0) + SwingUtilities.invokeLater(ivPendingBlinkEvent); + } + + /** + */ + public void setPosition(int col, int row) { + synchronized (ivCursorsPH) { + if (col == getCol() && row == getRow()) + return; + ivCursorsPH.add(ivCurrentCursorPH); + ivCurrentCursorPH = new CursorPlaceHolder(col, row); + } + resync(); + } + + /** + */ + public void setVisible(boolean flag) { + synchronized (ivCursorsPH) { + if (flag == ivVisible) + return; + ivVisible = flag; + ivCursorsPH.add(ivCurrentCursorPH); + ivCurrentCursorPH = new CursorPlaceHolder(getCol(), getRow()); + } + resync(); + } + + /** + */ + public final int getCol() { return ivCurrentCursorPH.getCol(); } + public final int getRow() { return ivCurrentCursorPH.getRow(); } + + /** + */ + public final boolean isVisible() { return ivVisible; } + + /** + */ + public Rectangle getBoundingRect() { + return ivCurrentCursorPH.getBoundingRect(); + } + + /** + */ + private void sync(boolean blinkingShapeOnly, Graphics aGc, boolean showIt) { + if (DEBUG >= 1) { + if (!SwingUtilities.isEventDispatchThread()) + throw new IllegalStateException(); + } + synchronized (ivCursorsPH) { + Graphics gc = (aGc != null) ? aGc : + (XIUtil.is1dot2 && !XIUtil.is1dot3) ? null : getGraphics(); + try { + // remove old place-holders + for (Iterator e = ivCursorsPH.iterator(); e.hasNext(); ) { + e.next().drawShapes(false, gc, false); + } + ivCursorsPH.clear(); + // draw (or hide) the current one + ivCurrentCursorPH.drawShapes(blinkingShapeOnly, gc, showIt); + } + finally { + if (aGc == null && gc != null) + gc.dispose(); + } + } + } + + /** + */ + protected void beforePaint(Graphics g) { + // do nothing, cursor place-holders are removed in painting areas + } + + /** + */ + protected void afterPaint(Graphics g) { + // restore cursor place-holders in painting areas, if they were visible + if (DEBUG >= 1) { + if (!SwingUtilities.isEventDispatchThread()) + throw new IllegalStateException(); + } + // remove old place-holders + for (Iterator e = ivCursorsPH.iterator(); e.hasNext(); ) { + e.next().syncShapesAfterPaint(g); + } + ivCurrentCursorPH.syncShapesAfterPaint(g); + } + } + + ////////////////////////////////////////////////////////////////////////////// + + /** + */ + private class CursorPlaceHolder implements Serializable { + + private static final long serialVersionUID = 1L; + + private int ivCol; + private int ivRow; + + transient private CursorShape ivCursorShape; + transient private CursorShape ivFixedCursorShape; + + transient private boolean ivFixedCursorDrawed; + transient private boolean ivCursorDrawed; + + /** + */ + public CursorPlaceHolder(int col, int row) { + ivCol = col; + ivRow = row; + } + + public final int getCol() { return ivCol; } + public final int getRow() { return ivRow; } + + /** + */ + public Rectangle getBoundingRect() { + Dimension sz = ivCrtBuffer.getCharSize(); + Point pt = ivCrtBuffer.toPoint(ivCol, ivRow); + return new Rectangle(pt.x, pt.y - sz.height, sz.width, sz.height); + } + + /** + */ + private void retrieveShapes() { + // a cursorPlaceHolder is bounded always to the same shape + if (ivCursorShape == null) { + ivCursorShape = getCursorShape(); + if (ivCursorShape == null) + ivCursorShape = cvVoidCursorShape; + } + if (ivFixedCursorShape == null) { + ivFixedCursorShape = getFixedCursorShape(); + if (ivFixedCursorShape == null) + ivFixedCursorShape = cvVoidCursorShape; + } + } + + /** + * Draws the cursor calling drawCursorShape and drawFixedCursorShape. + */ + public void drawShapes(boolean blinkingShapeOnly, Graphics aGc, + boolean showIt) { + showIt = showIt && isCursorVisible(); + if (showIt == ivCursorDrawed && showIt == ivFixedCursorDrawed) + return; + + // a cursorPlaceHolder is bounded always to the same shape + retrieveShapes(); + + Graphics gc = (aGc != null) ? aGc : getGraphics(); + if (gc == null) + return; + try { + if (ivCursorDrawed != showIt) { + ivCursorShape.drawCursorShape(gc, getBoundingRect()); + ivCursorDrawed = showIt; + } + + if (ivFixedCursorDrawed != showIt && !blinkingShapeOnly) { + //!!V1.2 workaround + // there are problems with jdk 1.2.1, lines drawed outside the paint + // method are translated of 1 pixel respect lines drawed inside the + // paint method !!?? + if (XIUtil.is1dot2 && !XIUtil.is1dot3 && aGc == null) + gc.translate(-1, -1); + ivFixedCursorShape.drawCursorShape(gc, getBoundingRect()); + ivFixedCursorDrawed = showIt; + } + } + finally { + if (aGc == null) + gc.dispose(); + } + } + + /** + * Must be called always in the paint event. + */ + public void syncShapesAfterPaint(Graphics gc) { + if (gc == null) + throw new IllegalArgumentException(); + + // a cursorPlaceHolder is bounded always to the same shape + retrieveShapes(); + + if (ivCursorDrawed) { + ivCursorShape.drawCursorShape(gc, getBoundingRect()); + } + + if (ivFixedCursorDrawed) { + ivFixedCursorShape.drawCursorShape(gc, getBoundingRect()); + } + } + } +} diff --git a/net/infordata/em/crt/XICrtBeanInfo.java b/net/infordata/em/crt/XICrtBeanInfo.java new file mode 100644 index 0000000..88f200f --- /dev/null +++ b/net/infordata/em/crt/XICrtBeanInfo.java @@ -0,0 +1,84 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package net.infordata.em.crt; + +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.beans.SimpleBeanInfo; + +public class XICrtBeanInfo extends SimpleBeanInfo { + Class beanClass = XICrt.class; + String iconColor16x16Filename; + String iconColor32x32Filename; + String iconMono16x16Filename; + String iconMono32x32Filename; + + + public XICrtBeanInfo() { + } + + @Override + public PropertyDescriptor[] getPropertyDescriptors() { + try { + PropertyDescriptor _cursorVisible = new PropertyDescriptor("cursorVisible", beanClass, "isCursorVisible", "setCursorVisible"); + + PropertyDescriptor _font = new PropertyDescriptor("font", beanClass, "getFont", "setFont"); + + PropertyDescriptor[] pds = new PropertyDescriptor[] { + _cursorVisible, + _font, + }; + return pds; + } + catch (IntrospectionException ex) { + ex.printStackTrace(); + return null; + } + } + + @Override + public java.awt.Image getIcon(int iconKind) { + switch (iconKind) { + case BeanInfo.ICON_COLOR_16x16: + return iconColor16x16Filename != null ? loadImage(iconColor16x16Filename) : null; + case BeanInfo.ICON_COLOR_32x32: + return iconColor32x32Filename != null ? loadImage(iconColor32x32Filename) : null; + case BeanInfo.ICON_MONO_16x16: + return iconMono16x16Filename != null ? loadImage(iconMono16x16Filename) : null; + case BeanInfo.ICON_MONO_32x32: + return iconMono32x32Filename != null ? loadImage(iconMono32x32Filename) : null; + } + return null; + } + + @Override + public BeanInfo[] getAdditionalBeanInfo() { + Class superclass = beanClass.getSuperclass(); + try { + BeanInfo superBeanInfo = Introspector.getBeanInfo(superclass); + return new BeanInfo[] { superBeanInfo }; + } + catch (IntrospectionException ex) { + ex.printStackTrace(); + return null; + } + } +} + + diff --git a/net/infordata/em/crt/XICrtBuffer.java b/net/infordata/em/crt/XICrtBuffer.java new file mode 100644 index 0000000..a7f3acd --- /dev/null +++ b/net/infordata/em/crt/XICrtBuffer.java @@ -0,0 +1,599 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + */ + +/* +!!V 26/03/97 rel. 0.90 - start of revisions history. + 26/03/97 rel. 0.90 - changed to speed up drawing. + 10/04/97 rel. 0.93 - chars less than space are not drawed but are stored in ivCharBuffer. + 28/04/97 rel. _.__ - ivCharBuffer, ivAttrBuffer array from [cols][rows] to [rows][cols]. + 14/05/97 rel. 1.00 - first release. + 30/07/97 rel. 1.03b- bugs. + 13/01/98 rel. 1.05d- NT painting bug. + 14/01/98 rel. 1.06 - asynchronous paint on off-screen image. + 03/03/98 rel. _.___- SWING and reorganization. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + 29/07/99 rel. 1.14 - Rework on 3d look&feel. + */ + + +package net.infordata.em.crt; + + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Point; +import java.awt.Rectangle; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.PrintStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Implements an off-screen image buffer. + * To be used by XICrt. + * + * @see XICrt + * + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XICrtBuffer implements Serializable { + + private static final long serialVersionUID = 1L; + + private int ivNCols; + private int ivNRows; + + transient private Graphics ivGr; + transient private int ivCharW; + transient private int ivCharH; + transient private int ivCharD; + transient private int ivGrW; + transient private int ivGrH; + + private int ivDefAttr; // default char attribute + + // [rows][cols] + private char[][] ivCharBuffer; + private int[][] ivAttrBuffer; + + //!!1.06 + transient private List ivDirtyAreas = new ArrayList(20); + + //!!1.14 + transient private XICrt ivCrt; + + + /** + * Creates a XICrtBuffer with the given dimensions expressed in number of + * chars. + */ + public XICrtBuffer(int nCols, int nRows) { + ivNCols = nCols; + ivNRows = nRows; + ivCharBuffer = new char[ivNRows][ivNCols]; + ivAttrBuffer = new int[ivNRows][ivNCols]; + + clear(); + } + + + /** + * Creates a XICrtBuffer filling it with a portion of another one. + */ + public XICrtBuffer(XICrtBuffer from, int aC, int aR, int aW, int aH) { + this(aW, aH); + copyFrom(0, 0, from, aC, aR, aW, aH); + setDefAttr(from.getDefAttr()); + } + + + /** + * Returns a cloned XICrtBuffer (the new one needs initGraphics() to be + * displayed). + */ + @Override + public Object clone() { + XICrtBuffer aClone = new XICrtBuffer(this, 0, 0, ivNCols, ivNRows); + /* !!1.04 + XICrtBuffer aClone = new XICrtBuffer(ivNCols, ivNRows); + aClone.copyFrom(this); + */ + return aClone; + } + + + /** + */ + final void setCrt(XICrt crt) { + ivCrt = crt; + } + + + /** + */ + public final XICrt getCrt() { + return ivCrt; + } + + + /** + * Initializes the graphics area. + */ + public synchronized void setGraphics(Graphics gr) { + ivGr = gr; + if (ivGr != null) { + FontMetrics fontMetrics = ivGr.getFontMetrics(); + ivCharW = fontMetrics.charWidth('W'); + ivCharH = fontMetrics.getHeight(); + ivCharD = fontMetrics.getDescent(); + ivGrW = ivNCols * ivCharW; + ivGrH = ivNRows * ivCharH; + + copyFrom(this); // refresh !!1.06 required + } + else { + //!!1.03b + ivCharW = 1; // to avoid possible division by 0 in pending events + ivCharH = 1; + ivCharD = 1; + ivGrW = ivNCols * ivCharW; + ivGrH = ivNRows * ivCharH; + } + } + + + /** + * Dumps the buffer on System.out stream. + * Useful for debugging. + */ + public void dumpBuffer(PrintStream out) { + out.println("BUFFER DUMP"); + for (int r = 0; r < ivNRows; r++) { + for (int c = 0; c < ivNCols; c++) + out.print(ivCharBuffer[r][c]); + out.println(); + } + for (int r = 0; r < ivNRows; r++) { + for (int c = 0; c < ivNCols; c++) + out.print(Integer.toHexString(ivAttrBuffer[r][c]) + " "); + out.println(); + } + out.println("END BUFFER DUMP"); + } + + + /** + * Copy contents from another XICrtBuffer (can be itself). + */ + public void copyFrom(XICrtBuffer from) { + copyFrom(0, 0, from, 0, 0, from.ivNCols, from.ivNRows); + } + + + /** + * Copy contents from another XICrtBuffer (can be itself). + * @param col the destination column pos. + * @param row the destination row pos. + * @param from the source XICrtBuffer. + * @param aC the source column pos. + * @param aR the source row pos. + * @param aW the source dimension. + * @param aH the source dimension. + */ + public synchronized void copyFrom(int col, int row, + XICrtBuffer from, + int aC, int aR, int aW, int aH) { + aW = Math.min(aW, from.ivNCols - aC); + aH = Math.min(aH, from.ivNRows - aR); + int nCols = Math.min(ivNCols - col, aW); + int nRows = Math.min(ivNRows - row, aH); + int lastAttr; + int lastCol; + int lastRow; + StringBuilder str; + + for (int r = 0; r < nRows; r++) { + for (int c = 0; c < nCols; ) { + lastCol = col + c; + lastRow = row + r; + lastAttr = from.getAttrInternal(aC + c, aR + r); + str = new StringBuilder(); + + // group chars with the same attribute + for ( ; c < nCols && lastAttr == from.getAttrInternal(aC + c, aR + r); c++) + str.append(from.getChar(aC + c, aR + r)); + + drawString(new String(str), lastCol, lastRow, lastAttr); + } + } + } + + public synchronized void invalidateAll() { + addDirtyArea(new Rectangle(0, 0, ivNCols, ivNRows)); + } + + /** + * Clears the screen buffer. + */ + public synchronized void clear() { + for (int c = 0; c < ivNCols; c++) + for (int r = 0; r < ivNRows; r++) { + ivCharBuffer[r][c] = '\u0000'; + ivAttrBuffer[r][c] = ivDefAttr; + } + + ivDirtyAreas.clear(); + + if (ivGr != null) { + Graphics gr = ivGr.create(); //!!1.05d + try { + gr.setColor(getBackground(ivDefAttr)); + gr.fillRect(0, 0, ivGrW, ivGrH); + } + finally { + gr.dispose(); + } + } + } + + + /** + */ + public synchronized void scrollDown(int r1, int r2, int nRows) { + if ((r1 >= r2) || (nRows == 0)) + throw new IllegalArgumentException("ScrollDown()"); + + sync(); + + nRows = Math.max(nRows, r2 - r1); + + for (int r = r2; r > (r1 + nRows); r--) + for (int c = 0; c < ivNCols; c++) { + ivCharBuffer[r][c] = ivCharBuffer[r - nRows][c]; + ivAttrBuffer[r][c] = ivAttrBuffer[r - nRows][c]; + } + + for (int r = r1; r <= (r1 + nRows); r++) + for (int c = 0; c < ivNCols; c++) { + ivCharBuffer[r][c] = '\u0000'; + ivAttrBuffer[r][c] = ivDefAttr; + } + + if (ivGr != null) { + Graphics gr = ivGr.create(); //!!1.05d + try { + gr.copyArea(0, r1 * ivCharH, ivNCols * ivCharW, (r2 - r1) * ivCharH, + 0, ivCharH * nRows); + gr.setColor(getBackground(ivDefAttr)); + gr.fillRect(0, r1 * ivCharH, ivNCols * ivCharW, ivCharH * nRows); + } + finally { + gr.dispose(); + } + } + } + + + /** + */ + public synchronized void scrollUp(int r1, int r2, int nRows) { + if ((r1 >= r2) || (nRows == 0)) + throw new IllegalArgumentException("ScrollUp()"); + + sync(); + + nRows = Math.max(nRows, r2 - r1); + + for (int r = r1; r < (r2 - nRows); r++) + for (int c = 0; c < ivNCols; c++) { + ivCharBuffer[r][c] = ivCharBuffer[r + nRows][c]; + ivAttrBuffer[r][c] = ivAttrBuffer[r + nRows][c]; + } + + for (int r = r2; r >= (r2 - nRows); r--) + for (int c = 0; c < ivNCols; c++) { + ivCharBuffer[r][c] = '\u0000'; + ivAttrBuffer[r][c] = ivDefAttr; + } + + if (ivGr != null) { + Graphics gr = ivGr.create(); //!!1.05d + try { + gr.copyArea(0, (r1 + 1) * ivCharH, ivNCols * ivCharW, (r2 - r1) * ivCharH, + 0, -ivCharH * nRows); + gr.setColor(getBackground(ivDefAttr)); + gr.fillRect(0, (r2 - nRows + 1) * ivCharH, ivNCols * ivCharW, ivCharH * nRows); + } + finally { + gr.dispose(); + } + } + } + + + /** + * Returns the dimensions in chars. + */ + public Dimension getCrtSize() { + return new Dimension(ivNCols, ivNRows); + } + + + /** + * Returns the dimensions in pixels. + */ + public Dimension getSize() { + return new Dimension(ivGrW, ivGrH); + } + + + /** + */ + public Dimension getCharSize() { + return new Dimension(ivCharW, ivCharH); + } + + + /** + * Converts characters coordinates in pixels coordinates. + */ + public Point toPoint(int col, int row) { + return new Point(col * ivCharW, (row + 1) * ivCharH); + } + + + /** + * Uses the default attribute. + */ + public void drawString(String str, int col, int row) { + drawString(str, col, row, ivDefAttr); + } + + + /** + * Uses the given attribute. + */ + public synchronized void drawString(String aStr, int col, int row, + int aAttr) { + col = Math.max(0, Math.min(ivNCols - 1, col)); + row = Math.max(0, Math.min(ivNRows - 1, row)); + int len = Math.min(aStr.length(), ivNCols - col); + + if (len <= 0) + return; + + for (int i = 0; i < len; i++) { + ivCharBuffer[row][col + i] = aStr.charAt(i); + ivAttrBuffer[row][col + i] = aAttr; + } + + addDirtyArea(new Rectangle(col, row, len, 1)); + } + + + /** + */ + private void addDirtyArea(Rectangle newRt) { + Rectangle rt; + Rectangle rtG; + Rectangle res = new Rectangle(newRt); //!!V 03/03/98 + int count = 0; + for (Iterator e = ivDirtyAreas.iterator(); e.hasNext(); ) { + rt = (Rectangle)e.next(); + // used to see if rectangles are adiacent (x coord) + rtG = new Rectangle(rt); + rtG.grow(1, 0); + if (rtG.intersects(newRt)) { + e.remove(); + res = res.union(rt); + // no more than two rects can be joined (x coord) + if (++count >= 2) + break; + } + } + ivDirtyAreas.add(res); + } + + + /** + * To be called just before painting the offscreen image. + */ + public synchronized void sync() { + if (ivGr == null || ivDirtyAreas.isEmpty()) + return; + + Graphics gr = ivGr.create(); //!!1.05d + try { + Rectangle rt; + for (Iterator e = ivDirtyAreas.iterator(); e.hasNext(); ) { + rt = (Rectangle)e.next(); + + int lastAttr; + int lastCol; + int lastRow; + StringBuilder str; + + for (int r = 0; r < rt.height; r++) { + for (int c = 0; c < rt.width; ) { + lastCol = rt.x + c; + lastRow = rt.y + r; + lastAttr = getAttr(rt.x + c, rt.y + r); + str = new StringBuilder(); + + // group char with the same attribute to speed up drawing + for ( ; c < rt.width && lastAttr == getAttr(rt.x + c, rt.y + r); c++) + str.append(getChar(rt.x + c, rt.y + r)); + + _drawString(gr, new String(str), lastCol, lastRow, lastAttr); + } + } + + if (XICrt.DEBUG >= 2) { + gr.setColor(Color.yellow); + gr.drawRect(rt.x * ivCharW + 1, rt.y * ivCharH + 1, + rt.width * ivCharW - 3, rt.height * ivCharH - 3); + } + } + + ivDirtyAreas.clear(); + } + finally { + gr.dispose(); + } + } + + + /** + * Draws the given string on the graphics context (called by sync()). + */ + protected void _drawString(Graphics gr, String aStr, int col, int row, + int aAttr) { //!!1.06 + int len = aStr.length(); + + gr.setColor(getBackground(aAttr)); + gr.fillRect(col * ivCharW, row * ivCharH, ivCharW * len, ivCharH); + + // do not draw char less than space + StringBuilder strBuf = new StringBuilder(aStr); + for (int i = 0; i < strBuf.length(); i++) { + if (strBuf.charAt(i) < ' ') + strBuf.setCharAt(i, ' '); + } + String str = new String(strBuf); + + gr.setColor(getForeground(aAttr)); + gr.drawString(str.substring(0, len), col * ivCharW, + (row + 1) * ivCharH - ivCharD); + } + + + /** + */ + public String getString(int col, int row, int nChars) { + StringBuilder str = new StringBuilder(); + for (int i = 0; i < nChars; i++) { + str.append(getChar(col + i, row)); + } + return new String(str); + } + + + /** + */ + public String getString() { + char[] buf = new char[ivNRows * ivNCols]; + + for (int i = 0; i < ivNRows; i++) + System.arraycopy(ivCharBuffer[i], 0, buf, i * ivNCols, ivNCols); + + return new String(buf); + } + + + /** + * Background attribute to color mapping. + */ + protected Color getBackground(int aAttribute){ + return Color.red; + } + + + /** + * Foreground attribute to color mapping. + */ + protected Color getForeground(int aAttribute) { + return Color.blue; + } + + + /** + */ + public final int getAttrInternal(int col, int row) { + col = Math.max(0, Math.min(ivNCols - 1, col)); + row = Math.max(0, Math.min(ivNRows - 1, row)); + + return ivAttrBuffer[row][col]; + } + + + /** + */ + public int getAttr(int col, int row) { + return getAttrInternal(col, row); + } + + + /** + */ + public final char getChar(int col, int row) { + col = Math.max(0, Math.min(ivNCols - 1, col)); + row = Math.max(0, Math.min(ivNRows - 1, row)); + + return ivCharBuffer[row][col]; + } + + + /** + * Sets the default attribute. + */ + public void setDefAttr(int aAttr) { + ivDefAttr = aAttr; + } + + + /** + * Returns the default attribute. + */ + public final int getDefAttr() { + return ivDefAttr; + } + + + /** + */ + public Point toPoints(int aCol, int aRow) { + return new Point(aCol * ivCharW, aRow * ivCharH); + } + + + /** + */ + public Rectangle toPoints(int aCol, int aRow, int aNCols, int aNRows) { + return new Rectangle(aCol * ivCharW, aRow * ivCharH, + aNCols * ivCharW, aNRows * ivCharH); + } + + + /** + */ + void writeObject(ObjectOutputStream oos) throws IOException { + oos.defaultWriteObject(); + } + + void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { + ois.defaultReadObject(); + } +} diff --git a/net/infordata/em/crt5250/XI5250BaseField.java b/net/infordata/em/crt5250/XI5250BaseField.java new file mode 100644 index 0000000..64f9297 --- /dev/null +++ b/net/infordata/em/crt5250/XI5250BaseField.java @@ -0,0 +1,45 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 03/03/98 rel. _.___- SWING and reorganization. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.crt5250; + +import java.io.IOException; + + +/** + * Common base interface for XI5250FieldsList and XI5250Field. + * Only for possible future implementations. + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public interface XI5250BaseField { + /** + */ + public void init(); + + + /** + */ + public void saveTo(XI5250FieldSaver aSaver) throws IOException; +} \ No newline at end of file diff --git a/net/infordata/em/crt5250/XI5250Crt.java b/net/infordata/em/crt5250/XI5250Crt.java new file mode 100644 index 0000000..d10c734 --- /dev/null +++ b/net/infordata/em/crt5250/XI5250Crt.java @@ -0,0 +1,1780 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 24/03/97 rel. 0.90 - added XI5250CrtEventListener. + 16/04/97 rel. 0.94 - userError method added. + 27/05/97 rel. 1.00 - first release. + 30/05/97 rel. 1.00a- home key handled. + MOUSE_ENTERS_FIELD and MOUSE_EXITS_FIELD added. + 05/06/97 rel. 1.00c- reference cursor. + 23/07/97 rel. 1.03 - . + 25/07/97 rel. 1.03a- a bug in ...Multicaster. + 08/08/97 rel. 1.03d- translateKeyEvent() and processRawKeyEvent(). + 27/08/97 rel. 1.04 - clipboard support. + 24/09/97 rel. 1.05 - DNCX project. + 22/12/97 rel. 1.05b- . + 03/03/98 rel. _.___- SWING and reorganization. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + 04/02/99 rel. 1.11 - Swing 1.1 and jdk 1.2 support. + 11/06/99 rel. 1.12a- CursorShape interface has been introduced, some rework + on cursor handling. + 29/07/99 rel. 1.14 - Rework on 3d look. + */ + + +package net.infordata.em.crt5250; + + +import java.awt.AWTEvent; +import java.awt.AWTEventMulticaster; +import java.awt.AWTKeyStroke; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.KeyboardFocusManager; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.event.FocusEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.Serializable; +import java.util.EventListener; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.swing.JPanel; +import javax.swing.UIManager; + +import net.infordata.em.crt.XICrt; +import net.infordata.em.crt.XICrtBuffer; + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Adds capabilities required by 5250 emulation to XICrt. + * 5250 requires word-wrap and linear access to the buffer. + * Introduces also the 5250 input fields handling. + * It uses as off-screen buffer XI5250CrtBuffer. + * + * @see XI5250CrtBuffer + * @see XI5250Field + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XI5250Crt extends XICrt implements Serializable { + + private static final long serialVersionUID = 1L; + + // Debug level 0 = none, 1 = , 2 = detailed + static final int DEBUG = 0; + + /** + * Character used as place holder for 5250 attributes. + */ + public static final char ATTRIBUTE_PLACE_HOLDER = ''; + + /** + * If used as attribute it does' t change the attribute already present. + * @see #drawString() + */ + public static final int USE_PRESENT_ATTRIBUTE = 0; + + + // 5250 buffer address position + transient private int ivSBA; + + //!!2.00 transient private boolean ivHasFocus; + + /** + * The fields list. + */ + transient protected XI5250FieldsList ivFields = new XI5250FieldsList(this); + transient private XI5250Field ivCurrentField; + + private boolean ivInsertState; + + transient private XI5250CrtListener ivCrtListener; + + // used by XI5250Field to jump next KEY_TYPED event + transient boolean ivDropKeyChar; + + //!!0.95b + private int ivDefFieldsBorderStyle = XI5250Field.NO_BORDER; + + //!!1.00a + transient private XI5250Field ivFieldUnderMouse; + + //!!1.00c + private boolean ivRefCursor; + + //!!1.04 + transient private boolean ivDragging; + transient private boolean ivMousePressed; + transient private Point ivStartDragging; + transient private Rectangle ivSelectedArea; + + //!!1.04c + transient private XI5250Field ivHighLightedField; + + //!!1.04c properties + public static final String INSERT_STATE = "insertState"; + public static final String REFERENCE_CURSOR = "referenceCursor"; + public static final String SELECTED_AREA = "selectedArea"; + public static final String DEF_FIELDS_BORDER_STYLE = "defFieldsBorderStyle"; + + //!!1.12a + private static final CursorShape cvInsertCursorShape = new InsertCursorShape(); + private static final CursorShape cvNormalCursorShape = new NormalCursorShape(); + + transient private final CursorShape ivFixedCursorShape = new FixedCursorShape(); + + public static final String CODE_PAGE = "codePage"; + + public static final String DEFAULT_CODE_PAGE = "CP1144"; + private String ivCodePage = DEFAULT_CODE_PAGE; + transient private XIEbcdicTranslator ivTranslator = + XIEbcdicTranslator.getTranslator(DEFAULT_CODE_PAGE); + + /** + * Default constructor. + */ + public XI5250Crt() { + enableEvents(AWTEvent.MOUSE_EVENT_MASK); + enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK); + enableEvents(AWTEvent.KEY_EVENT_MASK); + enableEvents(AWTEvent.FOCUS_EVENT_MASK); + + //0.95b + setBackground(getDefBackground()); + + // jdk 1.4 tab-key and shift+tab-key should be delivered to the component + { + Set fks = getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); + Set newFks = new HashSet(); + for (AWTKeyStroke keyStroke : fks) { + if (keyStroke.getKeyCode() == KeyEvent.VK_TAB && + keyStroke.getModifiers() == 0) + continue; + newFks.add(keyStroke); + } + setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, newFks); + } + { + Set fks = getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + Set newFks = new HashSet(); + for (AWTKeyStroke keyStroke : fks) { + if (keyStroke.getKeyCode() == KeyEvent.VK_TAB && + (keyStroke.getModifiers() | KeyEvent.SHIFT_MASK) != 0) + continue; + newFks.add(keyStroke); + } + setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, newFks); + } + } + + + /** + * Usefull to get a static picture of the screen contents. + * Fields are not copied. + */ + public XI5250Crt getStaticClone() { + return getStaticClone(0, 0, getCrtSize().width, getCrtSize().height); + } + + + /** + * Usefull to get a static picture of the screen contents. + * Fields are not copied. + */ + public synchronized XI5250Crt getStaticClone(int col, int row, + int width, int height) { + XI5250Crt crt = new XI5250Crt(); + crt.setCrtBuffer(new XI5250CrtBuffer((XI5250CrtBuffer)getCrtBuffer(), + col, row, width, height)); + crt.setFont(getFont()); + crt.setBackground(getDefBackground()); + return crt; + } + + + /** + * Redefined to use XI5250CrtBuffer. + */ + @Override + protected XICrtBuffer createCrtBuffer(int nCols, int nRows) { + return new XI5250CrtBuffer(nCols, nRows); + } + + + /** + */ + @Override + public synchronized void setCrtSize(int nCols, int nRows) { + XI5250CrtBuffer oldCrt = (XI5250CrtBuffer)getCrtBuffer(); + + super.setCrtSize(nCols, nRows); + + XI5250CrtBuffer newCrt = (XI5250CrtBuffer)getCrtBuffer(); + if (oldCrt != newCrt) { + newCrt.setDefBackground(oldCrt.getDefBackground()); + } + } + + + /** + */ + @Override + protected CursorShape getCursorShape() { + return (ivInsertState) ? cvInsertCursorShape : cvNormalCursorShape; + } + + + /** + */ + @Override + protected CursorShape getFixedCursorShape() { + return (ivRefCursor) ? ivFixedCursorShape : null; + } + + + /** + * @see XI5250CrtListener + */ + public synchronized void addCrtListener(XI5250CrtListener l) { + ivCrtListener = Multicaster.add(ivCrtListener, l); + } + + + /** + * @see XI5250CrtListener + */ + public synchronized void removeCrtListener(XI5250CrtListener l) { + ivCrtListener = Multicaster.remove(ivCrtListener, l); + } + + + /** + * Routes XI5250CrtEvent to listeners. + */ + protected void processCrtEvent(XI5250CrtEvent e) { + if (ivCrtListener == null) + return; + + switch (e.getID()) { + case XI5250CrtEvent.FIELD_ACTIVATED: + ivCrtListener.fieldActivated(e); + break; + case XI5250CrtEvent.FIELD_DEACTIVATED: + ivCrtListener.fieldDeactivated(e); + break; + case XI5250CrtEvent.SIZE_CHANGED: + ivCrtListener.sizeChanged(e); + break; + case XI5250CrtEvent.KEY_EVENT: + ivCrtListener.keyEvent(e); + break; + case XI5250CrtEvent.MOUSE_ENTERS_FIELD: + ivCrtListener.mouseEntersField(e); + break; + case XI5250CrtEvent.MOUSE_EXITS_FIELD: + ivCrtListener.mouseExitsField(e); + break; + } + } + + + /** + * Calls the init method for all fields. + * @see XI5250FieldsList#init + */ + public void initAllFields() { + ivFields.init(); + setCursorPos(getCursorCol(), getCursorRow()); // to refresh the current-field + // NO repaint() needed + } + + + /** + * Adds an XI5250Field. + * @see XI5250FieldsList#addField + */ + public void addField(XI5250Field aField) { + ivFields.addField(aField); + // NO repaint() needed + } + + + /** + * Removes all fields. + */ + public void removeFields() { + try { + setCurrentField(null); //!!1.04c + setFieldUnderMouse(null); //!!1.04c + setHighLightedField(null); //!!1.04c + ivFields.removeNotify(); //!!V-23/06/97 + } + finally { + ivFields = new XI5250FieldsList(this); + } + // NO repaint() needed + } + + + /** + */ + public List getFields() { + return ivFields.getFields(); + } + + + /** + * Returns the field at the given index (null if none). + * Fields enumeration is based on their linear buffer position. + */ + public XI5250Field getField(int idx) { + return ivFields.getField(idx); + } + + + /** + * Returns the field present at the given position (null if none). + */ + public XI5250Field getFieldFromPos(int aCol, int aRow) { + return ivFields.fieldFromPos(aCol, aRow); + } + + + /** + * Gets the next field or the first one. + */ + public XI5250Field getNextFieldFromPos(int aCol, int aRow) { + return ivFields.nextFieldFromPos(aCol, aRow); + } + + + /** + * Gets the previous field or the last one. + */ + public XI5250Field getPrevFieldFromPos(int aCol, int aRow) { + return ivFields.prevFieldFromPos(aCol, aRow); + } + + + /** + * Returns the linear position of a string jumping fields contents + * (-1 if not found). + * @see #toColPos + * @see #toRowPos + */ + public int getLabelLinearPos(String aLabel) { + String str = getString(); + for (int pos = str.indexOf(aLabel); pos >= 0; + pos = str.indexOf(aLabel, pos + 1)) { + // if it is not present in a field + if (ivFields.fieldFromPos(toColPos(pos), toRowPos(pos)) == null) + return pos; + } + return -1; + } + + + /** + * Returns the field that follows a label (null if none). + * @see getLabelLinearPos + * @see getNextFieldFromPos + */ + public XI5250Field getFieldNextTo(String aLabel) { + int pos = getLabelLinearPos(aLabel); + if (pos < 0) + return null; + + return getNextFieldFromPos(toColPos(pos), toRowPos(pos)); + } + + + /** + * Called for example when the user tries to write outside of a field. + */ + protected void userError(int aError) { + Toolkit.getDefaultToolkit().beep(); + } + + + /** + */ + public void setSBA(int col, int row) { + setSBA(toLinearPos(col, row)); + } + + + /** + */ + public void setSBA(int aLPos) { + ivSBA = aLPos; + } + + + /** + */ + public int getSBA() { + return ivSBA; + } + + + /** + */ + public int getSBACol() { + return toColPos(ivSBA); + } + + + /** + */ + public int getSBARow() { + return toRowPos(ivSBA); + } + + + public void setCodePage(String cp) { + if (cp == null) + cp = DEFAULT_CODE_PAGE; + if (cp.equals(ivCodePage)) + return; + String old = ivCodePage; + ivTranslator = XIEbcdicTranslator.getTranslator(cp); + ivCodePage = cp; + + firePropertyChange(CODE_PAGE, old, ivCodePage); + } + + + public String getCodePage() { + return ivCodePage; + } + + + public final XIEbcdicTranslator getTranslator() { + if (ivTranslator != null) + return ivTranslator; + ivTranslator = XIEbcdicTranslator.getTranslator(ivCodePage); + return ivTranslator; + } + + + /** + * Changes the insert state. + */ + public void setInsertState(boolean aInsertState) { + if (aInsertState == ivInsertState) + return; + boolean wasCursorVisible = isCursorVisible(); + setCursorVisible(false); + boolean oldInsertState = ivInsertState; + ivInsertState = aInsertState; + setCursorVisible(wasCursorVisible); + + firePropertyChange(INSERT_STATE, oldInsertState, ivInsertState); + } + + + /** + */ + public boolean isInsertState() { + return ivInsertState; + } + + + /** + * Enables, disables reference cursor. + */ + public void setReferenceCursor(boolean aFlag) { + if (aFlag == ivRefCursor) + return; + boolean wasCursorVisible = isCursorVisible(); + setCursorVisible(false); + boolean oldRefCursor = ivRefCursor; + ivRefCursor = aFlag; + setCursorVisible(wasCursorVisible); + + firePropertyChange(REFERENCE_CURSOR, oldRefCursor, ivRefCursor); + } + + + /** + */ + public boolean isReferenceCursor() { + return ivRefCursor; + } + + + /** + * Changes the cursor position. + */ + @Override + public void setCursorPos(int aCol, int aRow) { + super.setCursorPos(aCol, aRow); + + XI5250Field field = ivFields.fieldFromPos(getCursorCol(), getCursorRow()); + setCurrentField(field); + } + + + /** + * Moves the cursor relative to the current position. + */ + public void moveCursor(int col, int row) { + col += getCursorCol(); + row += getCursorRow(); + + // indirizzo assoluto nel buffer lineare + int xx = toLinearPos(col, row); + if (xx == -1) + xx = toLinearPos(getCrtSize().width - 1, getCrtSize().height - 1); + else + if (xx < 0) + xx = toLinearPos(col, getCrtSize().height - 1); + + col = toColPos(xx); + row = toRowPos(xx); + + if (col < 0) col = getCrtSize().width - 1; + if (row < 0) row = getCrtSize().height - 1; + + setCursorPos(col % getCrtSize().width, row % getCrtSize().height); + } + + + /** + * Moves the cursor on the next field. + */ + public void cursorOnNextField() { + XI5250Field field = ivFields.nextFieldFromPos(getCursorCol(), getCursorRow()); + XI5250Field startField = field; + if (field != null) { + while (field.isBypassField()) { + field = ivFields.nextFieldFromPos(field.getCol(), field.getRow()); + if (field == startField) + break; + } + } + + if (field != null && !field.isBypassField()) + setCursorPos(field.getCol(), field.getRow()); + } + + + /** + * Moves the cursor on the previous field. + */ + public void cursorOnPrevField() { + XI5250Field field = ivFields.prevFieldFromPos(getCursorCol(), getCursorRow()); + XI5250Field startField = field; + if (field != null) { + while (field.isBypassField()) { + field = ivFields.prevFieldFromPos(field.getCol(), field.getRow()); + if (field == startField) + break; + } + } + + if (field != null && !field.isBypassField()) + setCursorPos(field.getCol(), field.getRow()); + } + + + /** + * Moves the cursor on the first field. + */ + public void cursorOnFirstField() { + XI5250Field field = ivFields.getField(0); + XI5250Field startField = field; + if (field != null) { + while (field.isBypassField()) { + field = ivFields.nextFieldFromPos(field.getCol(), field.getRow()); + if (field == startField) + break; + } + } + + if (field != null && !field.isBypassField()) + setCursorPos(field.getCol(), field.getRow()); + } + + + /** + */ + protected void setCurrentField(XI5250Field field) { //!!1.04c + if (field == ivCurrentField) + return; + + if (ivCurrentField != null) { + ivCurrentField.activated(false); + processCrtEvent(new XI5250CrtEvent(XI5250CrtEvent.FIELD_DEACTIVATED, this, + ivCurrentField)); + } + + ivCurrentField = field; + + if (ivCurrentField != null) { + ivCurrentField.activated(true); + processCrtEvent(new XI5250CrtEvent(XI5250CrtEvent.FIELD_ACTIVATED, this, + ivCurrentField)); + } + } + + + /** + * Returns the field under the input cursor (null if none). + */ + public XI5250Field getCurrentField() { //!!1.04c + return ivCurrentField; + } + + + /** + */ + public void setHighLightedField(XI5250Field field) { //!!1.04c + if (field == ivHighLightedField) + return; + + if (field != null && + (ivFields == null || (ivFields.fromFieldToIdx(field) < 0))) + throw new IllegalArgumentException("The given field isn' t actually present"); + + Rectangle rt; + + if (ivHighLightedField != null) { + rt = ivHighLightedField.getBoundingRect(); + rt.grow(4, 4); + repaint(rt.x, rt.y, rt.width, rt.height); + } + + ivHighLightedField = field; + + if (ivHighLightedField != null) { + rt = ivHighLightedField.getBoundingRect(); + rt.grow(4, 4); + repaint(rt.x, rt.y, rt.width, rt.height); + } + } + + + /** + */ + public XI5250Field getHighLightedField() { //!!1.04c + return ivHighLightedField; + } + + + /** + * Used internally to change the field under the mouse. + * It also fires the MOUSE_EXITS_FIELD and MOUSE_ENTERS_FIELD + */ + protected void setFieldUnderMouse(XI5250Field aField) { + if (aField == ivFieldUnderMouse) + return; + + if (ivFieldUnderMouse != null) { + processCrtEvent(new XI5250CrtEvent(XI5250CrtEvent.MOUSE_EXITS_FIELD, this, + ivFieldUnderMouse)); + } + + ivFieldUnderMouse = aField; + + if (ivFieldUnderMouse != null) { + processCrtEvent(new XI5250CrtEvent(XI5250CrtEvent.MOUSE_ENTERS_FIELD, this, + ivFieldUnderMouse)); + } + } + + + /** + * Returns the field under the mouse cursor (null if none). + */ + public XI5250Field getFieldUnderMouse() { + return ivFieldUnderMouse; + } + + + /** + */ + private void checkFieldUnderMouse(MouseEvent e) { + switch (e.getID()) { + // + case MouseEvent.MOUSE_EXITED: + setFieldUnderMouse(null); + break; + // + default: + int col = e.getX() / getCharSize().width; + int row = e.getY() / getCharSize().height; + + XI5250Field fld = getFieldFromPos(col, row); + + setFieldUnderMouse(fld); + break; + } + } + + + /** + */ + @Override + protected void processMouseEvent(MouseEvent e) { + switch (e.getID()) { + // + case MouseEvent.MOUSE_PRESSED: + requestFocus(); + if (ivMousePressed || (e.getModifiers() != MouseEvent.BUTTON1_MASK)) + break; + ivMousePressed = true; + // sets the start dragging row and col + ivStartDragging = new Point(assureColIn(e.getX() / getCharSize().width), + assureRowIn(e.getY() / getCharSize().height)); + break; + // + case MouseEvent.MOUSE_RELEASED: + if (!ivMousePressed) + break; + ivMousePressed = false; + + if (!ivDragging) { + setSelectedArea(null); + if ((new Rectangle(getCrtBufferSize())).contains(e.getPoint())) + setCursorPos(e.getX() / getCharSize().width, e.getY() / getCharSize().height); + } + else { + setSelectedArea(ivStartDragging, + new Point(assureColIn(e.getX() / getCharSize().width), + assureRowIn(e.getY() / getCharSize().height))); + } + ivDragging = false; + break; + } + super.processMouseEvent(e); + checkFieldUnderMouse(e); + } + + + /** + */ + @Override + protected void processMouseMotionEvent(MouseEvent e) { + switch (e.getID()) { + // + case MouseEvent.MOUSE_DRAGGED: + if (!ivMousePressed) + break; + + ivDragging = true; + setSelectedArea(ivStartDragging, + new Point(assureColIn(e.getX() / getCharSize().width), + assureRowIn(e.getY() / getCharSize().height))); + break; + } + super.processMouseMotionEvent(e); + checkFieldUnderMouse(e); + } + + + /** + */ + private void setSelectedArea(Point p1, Point p2) { + setSelectedArea(new Rectangle(Math.min(p1.x, p2.x), Math.min(p1.y, p2.y), + Math.abs(p1.x - p2.x) + 1, Math.abs(p1.y - p2.y) + 1)); + } + + + /** + */ + public void setSelectedArea(Rectangle ivRect) { + Rectangle oldSelectedArea; + + synchronized (this) { + if (ivSelectedArea != null && ivSelectedArea.equals(ivRect)) + return; + + if (ivSelectedArea != null) + repaint(ivSelectedArea.x * getCharSize().width, + ivSelectedArea.y * getCharSize().height, + ivSelectedArea.width * getCharSize().width, + ivSelectedArea.height * getCharSize().height); + + oldSelectedArea = ivSelectedArea; + ivSelectedArea = (ivRect == null) ? null : new Rectangle(ivRect); + + if (ivSelectedArea != null) + repaint(ivSelectedArea.x * getCharSize().width, + ivSelectedArea.y * getCharSize().height, + ivSelectedArea.width * getCharSize().width, + ivSelectedArea.height * getCharSize().height); + } + + firePropertyChange(SELECTED_AREA, oldSelectedArea, ivSelectedArea); + } + + + /** + * Returns the selected area (null if none). + */ + public Rectangle getSelectedArea() { + return (ivSelectedArea == null) ? null : new Rectangle(ivSelectedArea); + } + + + /** + */ + private static void drawHorzLine(int inc, Graphics gc, int x, int y, int dx) { + Graphics2D g2 = (Graphics2D)gc; + float dash[] = { 6f }; + BasicStroke b = new BasicStroke(1.0f, BasicStroke.CAP_BUTT, + BasicStroke.JOIN_MITER, 10.0f, dash, 0.0f); + g2.setStroke(b); + g2.drawLine(x, y, x + dx, y); + +// boolean draw = true; +// +// for (int i = 0; i < dx; i += inc) { +// if (draw) +// gc.drawLine(x + i, y, x + i + inc, y); +// +// draw = !draw; +// } + } + + /** + */ + private static void drawVertLine(int inc, Graphics gc, int x, int y, int dy) { + Graphics2D g2 = (Graphics2D)gc; + float dash[] = { 6f }; + BasicStroke b = new BasicStroke(1.0f, BasicStroke.CAP_BUTT, + BasicStroke.JOIN_MITER, 10.0f, dash, 0.0f); + g2.setStroke(b); + g2.drawLine(x, y, x, y + dy); + +// boolean draw = true; +// +// for (int i = 0; i < dy; i += inc) { +// if (draw) +// gc.drawLine(x, y + i, x, y + i + inc); +// +// draw = !draw; +// } + } + + + /** + */ + private void drawSelectedArea(Graphics aGc) { + Rectangle rt = new Rectangle(ivSelectedArea.x * getCharSize().width, + ivSelectedArea.y * getCharSize().height, + ivSelectedArea.width * getCharSize().width, + ivSelectedArea.height * getCharSize().height); + + Graphics gg = aGc.create(); + + gg.setColor(Color.yellow); + gg.setXORMode(Color.black); + + gg.clipRect(rt.x, rt.y, rt.width, rt.height); + + //drawVertLine(5, gg, rt.x, rt.y, rt.height); + //drawHorzLine(5, gg, rt.x, rt.y, rt.width); + + //drawVertLine(5, gg, rt.x + rt.width - 1, rt.y, rt.height); + //drawHorzLine(5, gg, rt.x, rt.y + rt.height - 1, rt.width); + + drawVertLine(5, gg, rt.x + 1, rt.y + 1, rt.height); + drawHorzLine(5, gg, rt.x + 1, rt.y + 1, rt.width); + + drawVertLine(5, gg, rt.x + rt.width - 1, rt.y + 1, rt.height); + drawHorzLine(5, gg, rt.x + 1, rt.y + rt.height - 1, rt.width); + + gg.dispose(); + } + + + /** + */ + public static boolean isCharKey(KeyEvent e) { + boolean res = + (e.getKeyChar() != KeyEvent.CHAR_UNDEFINED && + e.getKeyChar() >= ' ' && + e.getKeyChar() != '\uFFFF' && // jdk 1.2 + e.getKeyCode() != KeyEvent.VK_DELETE && + e.getKeyChar() != KeyEvent.VK_DELETE && //!!1.15c linux jdk 1.2.2 + e.getKeyCode() != KeyEvent.VK_ADD); + return res; + } + + + /** + */ + @Override + protected synchronized void processKeyEvent(KeyEvent e) { + processRawKeyEvent(translateKeyEvent(e)); + if (!e.isConsumed()) + super.processKeyEvent(e); + } + + + /** + * Exit usefull for keyboard remapping. + */ + protected KeyEvent translateKeyEvent(KeyEvent e) { + return e; + } + + + /** + * Call this method if you want to submit a raw key event + * (ie. jump the translation process). + */ + public synchronized void processRawKeyEvent(KeyEvent e) { + doProcessKeyEvent(e); + } + + + /** + * Must be used instead of dispatchEvent to generate automatic key code (auto-enter ...). + * If cursor is over a field it calls XI5250Field.processKeyEvent. + */ + protected synchronized void doProcessKeyEvent(KeyEvent e) { + XI5250Field field = ivFields.fieldFromPos(getCursorCol(), getCursorRow()); + if (field != null && !field.isBypassField()) + field.processKeyEvent(e); + + if (e.isConsumed()) + return; + + processCrtEvent(new XI5250CrtEvent(XI5250CrtEvent.KEY_EVENT, this, + ivCurrentField, e)); + + if (e.isConsumed()) + return; + + boolean res = false; + + switch (e.getID()) { + // + case KeyEvent.KEY_PRESSED: + switch (e.getKeyCode()) { + // + case KeyEvent.VK_UP: + res = processKeyUp(e.getModifiers()); + break; + // + case KeyEvent.VK_DOWN: + res = processKeyDown(e.getModifiers()); + break; + // +// case KeyEvent.VK_BACK_SPACE: + case KeyEvent.VK_LEFT: + res = processKeyLeft(e.getModifiers()); + break; + // + case KeyEvent.VK_RIGHT: + res = processKeyRight(e.getModifiers()); + break; + // + case KeyEvent.VK_TAB: + res = processKeyTab(e.getModifiers()); + break; + // + case KeyEvent.VK_INSERT: + res = processKeyIns(e.getModifiers()); + break; + // + case KeyEvent.VK_HOME: + res = processKeyHome(e.getModifiers()); + break; + } + if (res) + e.consume(); + break; + } + } + + + /** + */ + protected boolean processKeyUp(int aModifier) { + switch (aModifier) { + case 0: + moveCursor(0, -1); + return true; + } + return false; + } + + + /** + */ + protected boolean processKeyDown(int aModifier) { + switch (aModifier) { + case 0: + moveCursor(0, 1); + return true; + } + return false; + } + + + /** + */ + protected boolean processKeyLeft(int aModifier) { + switch (aModifier) { + case 0: + moveCursor(-1, 0); + return true; + } + return false; + } + + + /** + */ + protected boolean processKeyRight(int aModifier) { + switch (aModifier) { + case 0: + moveCursor(1, 0); + return true; + } + return false; + } + + + /** + */ + protected boolean processKeyTab(int aModifier) { + switch (aModifier) { + case 0: + cursorOnNextField(); + return true; + case KeyEvent.SHIFT_MASK: + cursorOnPrevField(); + return true; + } + return false; + } + + + /** + */ + protected boolean processKeyIns(int aModifier) { + switch (aModifier) { + case 0: + setInsertState(!ivInsertState); + return true; + case KeyEvent.CTRL_MASK: + doCopy(); + return true; + case KeyEvent.SHIFT_MASK: + doPaste(); + return true; + } + return false; + } + + + /** + */ + protected boolean processKeyHome(int aModifier) { + switch (aModifier) { + case 0: + cursorOnFirstField(); + return true; + case KeyEvent.SHIFT_MASK: //!!1.00c + setReferenceCursor(!isReferenceCursor()); + return true; + case KeyEvent.CTRL_MASK: + if (DEBUG >= 1) { + getCrtBuffer().dumpBuffer(System.out); + return true; + } + break; + case KeyEvent.CTRL_MASK | KeyEvent.SHIFT_MASK: + if (DEBUG >= 1) { + repaint(); + return true; + } + break; + } + return false; + } + + + /** + */ + @Override + protected void processFocusEvent(FocusEvent e) { + switch (e.getID()) { + // + case FocusEvent.FOCUS_GAINED: + setCursorVisible(true); + break; + // + case FocusEvent.FOCUS_LOST: + setCursorVisible(false); + break; + } + super.processFocusEvent(e); + } + + + /** + * Returns true. + */ + public boolean isFocusTraverseable() { + return true; + } + + + /** + * Redefined because 5250 works with line wrap. + */ + @Override + public void drawString(String str, int col, int row, int aAttr) { + int lines = ((col + str.length()) / getCrtSize().width + 1); + + if (lines <= 1) + super.drawString(str, col, row, aAttr); + else { + XICrtBuffer crtBuffer = getCrtBuffer(); + + crtBuffer.drawString(str, col, row, aAttr); + repaint(0 * crtBuffer.getCharSize().width, + row * crtBuffer.getCharSize().height, + crtBuffer.getSize().width, + lines * crtBuffer.getCharSize().height); + } + } + + + /** + * Converts x-y coord to buffer linear position. + */ + public final int toLinearPos(int aCol, int aRow) { + return ((XI5250CrtBuffer)getCrtBuffer()).toLinearPos(aCol, aRow); + } + + + /** + * Converts buffer linear position to x-y coord. + */ + public final int toColPos(int aPos) { + return ((XI5250CrtBuffer)getCrtBuffer()).toColPos(aPos); + } + + + /** + * Converts buffer linear position to x-y coord. + */ + public final int toRowPos(int aPos) { + return ((XI5250CrtBuffer)getCrtBuffer()).toRowPos(aPos); + } + + + /** + * If the font is really changed then a SIZE_CHANGED event is fired. + */ + @Override + public void setFont(Font aFont) { + Font oldFont = getFont(); + super.setFont(aFont); + // check if font is changed + if (oldFont != getFont()) { + processCrtEvent(new XI5250CrtEvent(XI5250CrtEvent.SIZE_CHANGED, this, + ivCurrentField)); + if (ivFields != null) + ivFields.resized(); + } + } + + + /** + * Usefull to add paint over the normal 5250 screen. + */ + @Override + protected void foregroundPaint(Graphics g) { + ivFields.paint(g); + + super.foregroundPaint(g); + + if (ivHighLightedField != null) { //!!1.04c + Rectangle rt = ivHighLightedField.getBoundingRect(); + g.setColor(Color.red.brighter().brighter()); + rt.grow(1, 1); + g.drawRoundRect(rt.x, rt.y, rt.width, rt.height, 4, 4); + rt.grow(1, 1); + g.drawRoundRect(rt.x, rt.y, rt.width, rt.height, 4, 4); + } + + if (ivSelectedArea != null) + drawSelectedArea(g); + } + + + /** + * Changes the default fields border style. + * @see XI5250Field#getUsedBorderStyle + */ + public void setDefFieldsBorderStyle(int aStyle) { + if (aStyle == ivDefFieldsBorderStyle) + return; + + if (aStyle <= XI5250Field.DEFAULT_BORDER || + aStyle > XI5250Field.LOWERED_BORDER) + throw new IllegalArgumentException("Wrong border style argument"); + + int oldDefFieldsBorderStyle = ivDefFieldsBorderStyle; + ivDefFieldsBorderStyle = aStyle; + repaint(); + + firePropertyChange(DEF_FIELDS_BORDER_STYLE, oldDefFieldsBorderStyle, + ivDefFieldsBorderStyle); + } + + + /** + * Returns the default fields border style. + */ + public int getDefFieldsBorderStyle() { + return ivDefFieldsBorderStyle; + } + + + /** + * Changes the default background. + * To add 3D Fx : + *
+   *   crt.setDefBackground(SystemColor.control);
+   *   crt.setDefFieldsBorderStyle(XI5250Field.LOWERED_BORDER);
+   * 
+ * @see XI5250CrtBuffer#setDefBackground + */ + public synchronized void setDefBackground(Color aColor) { + XI5250CrtBuffer ivBuf = (XI5250CrtBuffer)getCrtBuffer(); + + if (ivBuf.getDefBackground().equals(aColor)) + return; + + ivBuf.setDefBackground(aColor); + setBackground(ivBuf.getDefBackground()); + ivBuf.copyFrom(ivBuf); + repaint(); + } + + + /** + * Retruns the default background color. + */ + public Color getDefBackground() { + return ((XI5250CrtBuffer)getCrtBuffer()).getDefBackground(); + } + + + /** + * Copies the selected area into the clipboard. + */ + protected synchronized void doCopy() { + if (ivSelectedArea == null) + return; + + Clipboard clipboard = getToolkit().getSystemClipboard(); + + /*!!V This approach will be used when the jdk bug Id4066902 disappear. + XI5250Crt crt = getStaticClone(ivSelectedArea.x, ivSelectedArea.y, + ivSelectedArea.width, ivSelectedArea.height); + + clipboard.setContents(crt, crt); + */ + + //!!V To be replaced + StringBuilder strBuf = new StringBuilder(); + for (int r = ivSelectedArea.y; + r < (ivSelectedArea.y + ivSelectedArea.height); r++) { + strBuf.append(getString(ivSelectedArea.x, r, ivSelectedArea.width)); + + if (r < (ivSelectedArea.y + ivSelectedArea.height - 1)) + strBuf.append("\n"); + } + + for (int i = 0; i < strBuf.length(); i++) + if (strBuf.charAt(i) < ' ' && strBuf.charAt(i) != '\n') + strBuf.setCharAt(i, ' '); + + String str = new String(strBuf); + + StringSelection contents = new StringSelection(str); + clipboard.setContents(contents, contents); + + setSelectedArea(null); + } + + + /** + */ + public boolean isPasteable() { + Clipboard clipboard = getToolkit().getSystemClipboard(); + + Transferable content = clipboard.getContents(this); + + return (content != null && content.isDataFlavorSupported(DataFlavor.stringFlavor)); + } + + + /** + * Inserts the clipboard contents. + */ + protected synchronized void doPaste() { + if (!isPasteable()) + return; + + Clipboard clipboard = getToolkit().getSystemClipboard(); + + Transferable content = clipboard.getContents(this); + + try { + String str = (String)content.getTransferData(DataFlavor.stringFlavor); + + int col = getCursorCol(); + int row = getCursorRow(); + boolean error = false; + XI5250Field field; + + for (int i = 0; i < str.length(); i++) { + char ch = str.charAt(i); + if (ch == '\n') { + col = getCursorCol(); + row++; + } + else if (ch < ' ') { + error = true; + col++; + } + else { + if ((col >= 0) && (col < getCrtSize().width) && + (row >= 0) && (row < getCrtSize().height) && + (field = getFieldFromPos(col, row)) != null) { + if (field.insertChar(ch, col, row, false, true) != 0) + error = true; + } + else + error = true; + col++; + } + } + + if (error) + Toolkit.getDefaultToolkit().beep(); //!!V richiamare userError ?? + } + catch (Exception ex) { + } + } + + +// /** +// */ +// void writeObject(ObjectOutputStream oos) throws IOException { +// oos.defaultWriteObject(); +// } +// +// void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { +// ois.defaultReadObject(); +// } + + + /** + * Used only for test purposes. + */ + public static void main(String[] argv) { + + XI5250Crt crt = new XI5250Crt(); + + XI5250CrtFrame frm = new XI5250CrtFrame("TEST", crt); + frm.addWindowListener(new WindowAdapter() { + @Override + public void windowClosed(WindowEvent e) { + System.out.println("END."); + System.exit(0); + } + }); + + crt.setCursorPos(1, 2); + + crt.drawString("eccoci", 1, 2); + crt.addField(new XI5250Field(crt, new byte[2], new byte[2], 1, 2, 6, -1)); + + crt.drawString("green", 2, 0, 0x20); + crt.drawString("green", 10, 0, 0x21); + + crt.drawString("redred", 20, 0, 0x28); + crt.drawString("redred", 30, 0, 0x29); + + crt.drawString("redred", 40, 0, 0x2A); + crt.drawString("redred", 50, 0, 0x2B); + + crt.drawString("blue", 0, 1, 0x3A); + crt.drawString("blue", 10, 1, 0x3B); + + crt.drawString("turquoise", 20, 1, 0x30); + crt.drawString("turquoise", 30, 1, 0x31); + + crt.drawString("yellow", 40, 1, 0x36); + crt.drawString("yellow", 50, 1, 0x33); + + crt.drawString("pink", 60, 1, 0x38); + crt.drawString("pink", 70, 1, 0x39); + + crt.drawString("XYZ", 79, 22, 0x34); + crt.drawString("X", 79, 23); + + System.out.println(crt.getString(79, 22, 3)); + + crt.addField(new XI5250Field(crt, new byte[2], new byte[2], 1, 6, 10, -1)); + crt.drawString("eccociABCD", 1, 6); + + { + XI5250Field fld = new XI5250Field(crt, new byte[2], new byte[2], 21, 3, 170, -1); + fld.setBorderStyle(XI5250Field.LOWERED_BORDER); + crt.addField(fld); + + crt.setHighLightedField(fld); + + crt.drawString(ATTRIBUTE_PLACE_HOLDER + "eccoci 0 1 2 3 4 5 6 7 8 9 0", 20, 3, 0x34); + crt.drawString("FINE", 1, 5); + } + + { + // signed numeric + byte[] FFW = {0x07, 0x00}; + XI5250Field fld = new XI5250Field(crt, FFW, new byte[2], 1, 7, 6, -1); + crt.addField(fld); + crt.drawString(ATTRIBUTE_PLACE_HOLDER + "", 0, 7, 0x34); + } + + { + // numeric only + byte[] FFW = {0x03, 0x06}; + crt.addField(new XI5250Field(crt, FFW, new byte[2], 1, 8, 6, -1)); + crt.drawString(ATTRIBUTE_PLACE_HOLDER + "", 0, 8, 0x34); + } + + crt.initAllFields(); + + crt.setDefFieldsBorderStyle(XI5250Field.LOWERED_BORDER); + //!!1.14 crt.setDefBackground(SystemColor.control); + crt.setDefBackground(UIManager.getColor("control")); + + frm.setBounds(0, 0, 728, 512); + frm.centerOnScreen(); + frm.setVisible(true); + + crt.setReferenceCursor(true); + +// int i = 0; +// XI5250Crt sCrt = null; + + crt.setBlinkingCursor(true); + + while (true) { + try { + Thread.sleep(10000); + //crt.setFont(new Font("Monospaced", Font.BOLD, ((i++ % 2) == 0) ? 10 : 14)); + //crt.setDefBackground(((i++ % 2) == 0) ? SystemColor.control : SystemColor.black); + + /* + if ((i % 2) != 0) + crt.setCrtSize(132, 27); + else + crt.setCrtSize(80, 24); + */ + + /* + if (sCrt != null) + frm.remove(sCrt); + sCrt = crt.getStaticClone(); + frm.add("West", sCrt); + frm.validate(); + */ + //crt.setBlinkingCursor(!crt.isBlinkingCursor()); + } + catch (InterruptedException ex) { + break; + } + } + } + + + ////////////////////////////////////////////////////////////////////////////// + + /** + * Multicast Listener for XI5250Crt + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ + private static class Multicaster extends AWTEventMulticaster + implements XI5250CrtListener { + + protected Multicaster(EventListener a, EventListener b) { + super(a, b); + } + + + //!!1.03a + @Override + protected EventListener remove(EventListener oldl) { + if (oldl == a) return b; + if (oldl == b) return a; + EventListener a2 = removeInternal(a, oldl); + EventListener b2 = removeInternal(b, oldl); + if (a2 == a && b2 == b) + return this; + return add((XI5250CrtListener)a2, (XI5250CrtListener)b2); + } + + + public static XI5250CrtListener add(XI5250CrtListener a, + XI5250CrtListener b) { + if (a == null) return b; + if (b == null) return a; + return new Multicaster(a, b); + } + + + public static XI5250CrtListener remove(XI5250CrtListener a, + XI5250CrtListener b) { + return (XI5250CrtListener)removeInternal(a, b); + } + + + /** + */ + public void fieldActivated(XI5250CrtEvent e) { + ((XI5250CrtListener)a).fieldActivated(e); + ((XI5250CrtListener)b).fieldActivated(e); + } + + + public void fieldDeactivated(XI5250CrtEvent e) { + ((XI5250CrtListener)a).fieldDeactivated(e); + ((XI5250CrtListener)b).fieldDeactivated(e); + } + + + public void sizeChanged(XI5250CrtEvent e) { + ((XI5250CrtListener)a).sizeChanged(e); + ((XI5250CrtListener)b).sizeChanged(e); + } + + + public void keyEvent(XI5250CrtEvent e) { + ((XI5250CrtListener)a).keyEvent(e); + ((XI5250CrtListener)b).keyEvent(e); + } + + + public void mouseEntersField(XI5250CrtEvent e) { + ((XI5250CrtListener)a).mouseEntersField(e); + ((XI5250CrtListener)b).mouseEntersField(e); + } + + + public void mouseExitsField(XI5250CrtEvent e) { + ((XI5250CrtListener)a).mouseExitsField(e); + ((XI5250CrtListener)b).mouseExitsField(e); + } + } + + + ////////////////////////////////////////////////////////////////////////////// + + /** + * Draws fixed cursor shapes for normal and insert state. + */ + private class FixedCursorShape implements CursorShape { + + /** + */ + public void drawCursorShape(Graphics gc, Rectangle aRt) { + Dimension dim = getCrtBufferSize(); + Graphics gg = gc.create(0, 0, dim.width, dim.height); + try { + Rectangle rt = new Rectangle(aRt); //!!0.95b + rt.grow(-1, -1); + + gg.setColor(Color.white); + gg.setXORMode(Color.black); + + drawVertLine(9, gg, rt.x, 0, dim.height); + drawHorzLine(9, gg, 0, rt.y + rt.height - 1, dim.width); + } + finally { + gg.dispose(); + } + } + } + + + ////////////////////////////////////////////////////////////////////////////// + + /** + * Draws blinking cursor shapes for normal state. + */ + private static class NormalCursorShape implements CursorShape { + + /** + */ + public void drawCursorShape(Graphics gc, Rectangle aRt) { + Rectangle rt = new Rectangle(aRt); //!!0.95b + rt.grow(-1, -1); + + gc.setColor(Color.white); + gc.setXORMode(Color.black); + + //!!1.05b + int dy = (rt.height / 10); + gc.fillRect(rt.x, rt.y + rt.height - dy * 3, + rt.width, dy * 3); + + gc.setPaintMode(); + } + } + + + ////////////////////////////////////////////////////////////////////////////// + + /** + * Draws blinking cursor shapes for Insert state. + */ + private static class InsertCursorShape implements CursorShape { + + /** + */ + public void drawCursorShape(Graphics gc, Rectangle aRt) { + Rectangle rt = new Rectangle(aRt); //!!0.95b + rt.grow(-1, -1); + + gc.setColor(Color.white); + gc.setXORMode(Color.black); + + //!!1.05b + int dy = (rt.height / 10); + /*!!1.15b + gc.fillPolygon(new int[] {rt.x, + rt.x, + rt.x + rt.width, + rt.x + rt.width}, + new int[] {rt.y + rt.height, + rt.y + rt.height - dy * 6, + rt.y + rt.height - dy * 3, + rt.y + rt.height}, + 4); + */ + gc.fillRect(rt.x, rt.y + rt.height - dy * 5, + rt.width, dy * 5); + + gc.setPaintMode(); + } + } + + + ////////////////////////////////////////////////////////////////////////////// + + /** + */ + public static class SupportPanel extends JPanel { + + private static final long serialVersionUID = 1L; + + private XI5250Crt ivCrt; + + public SupportPanel(XI5250Crt crt) { + super(null); + if (crt == null) + throw new IllegalArgumentException(); + ivCrt = crt; + add(crt); + } + + @Override + protected void addImpl(Component comp, Object constraints, int index) { + if (getComponentCount() > 0) + throw new IllegalStateException("This panel doesn't support components"); + super.addImpl(comp, constraints, index); + } + + int count = 0; //!!P + @Override + public void doLayout() { + //!!PSystem.out.println("!!P doLayout() " + count++); + //!!P(new Exception()).printStackTrace(); + synchronized (getTreeLock()) { + Insets insets = getInsets(); + Dimension size = getSize(); + size.width -= insets.left + insets.right; + size.height -= insets.top + insets.bottom; + ivCrt.setSize(size); + ivCrt.invalidate(); + Dimension pSize = ivCrt.getPreferredSize(); + ivCrt.setBounds(Math.max(insets.left, (size.width - pSize.width) / 2), + Math.max(insets.top, (size.height - pSize.height) / 2), + pSize.width, + pSize.height); + } + } + + @Override + public Dimension getPreferredSize() { + Insets insets = getInsets(); + Dimension pSize = ivCrt.getPreferredSize(); + pSize.width += insets.left + insets.right; + pSize.height += insets.top + insets.bottom; + return pSize; + } + + /*!!NO + private static Border cvBorder = BorderFactory.createEtchedBorder(); + + protected void paintBorder(Graphics gr) { + super.paintBorder(gr); + Rectangle rt = ivCrt.getBounds(); + rt.grow(1, 1); + //gr.setColor(ivCrt.getBackground().darker()); + //gr.drawRect(rt.x, rt.y, rt.width, rt.height); + cvBorder.paintBorder(this, gr, rt.x, rt.y, rt.width, rt.height); + } + */ + } +} diff --git a/net/infordata/em/crt5250/XI5250CrtAdapter.java b/net/infordata/em/crt5250/XI5250CrtAdapter.java new file mode 100644 index 0000000..a4437cf --- /dev/null +++ b/net/infordata/em/crt5250/XI5250CrtAdapter.java @@ -0,0 +1,75 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 03/03/98 rel. _.___- SWING and reorganization. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.crt5250; + + +/** + * XI5250CrtListener adapter. + * @see XI5250CrtListener + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XI5250CrtAdapter implements XI5250CrtListener { + /** + * @see XI5250CrtEvent#FIELD_ACTIVATED + */ + public void fieldActivated(XI5250CrtEvent e) { + } + + + /** + * @see XI5250CrtEvent#FIELD_DEACTIVATED + */ + public void fieldDeactivated(XI5250CrtEvent e) { + } + + + /** + * @see XI5250CrtEvent#SIZE_CHANGED + */ + public void sizeChanged(XI5250CrtEvent e) { + } + + + /** + * @see XI5250CrtEvent#KEY_EVENT + */ + public void keyEvent(XI5250CrtEvent e) { + } + + + /** + * @see XI5250CrtEvent#MOUSE_ENTERS_FIELD + */ + public void mouseEntersField(XI5250CrtEvent e) { + } + + + /** + * @see XI5250CrtEvent#MOUSE_EXITS_FIELD + */ + public void mouseExitsField(XI5250CrtEvent e) { + } +} diff --git a/net/infordata/em/crt5250/XI5250CrtBeanInfo.java b/net/infordata/em/crt5250/XI5250CrtBeanInfo.java new file mode 100644 index 0000000..7718a06 --- /dev/null +++ b/net/infordata/em/crt5250/XI5250CrtBeanInfo.java @@ -0,0 +1,97 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +package net.infordata.em.crt5250; + +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.beans.SimpleBeanInfo; + +public class XI5250CrtBeanInfo extends SimpleBeanInfo { + Class beanClass = XI5250Crt.class; + String iconColor16x16Filename; + String iconColor32x32Filename; + String iconMono16x16Filename; + String iconMono32x32Filename; + + + public XI5250CrtBeanInfo() { + } + + @Override + public PropertyDescriptor[] getPropertyDescriptors() { + try { + PropertyDescriptor _defBackground = new PropertyDescriptor("defBackground", beanClass, "getDefBackground", "setDefBackground"); + + PropertyDescriptor _defFieldsBorderStyle = new PropertyDescriptor("defFieldsBorderStyle", beanClass, "getDefFieldsBorderStyle", "setDefFieldsBorderStyle"); + + PropertyDescriptor _font = new PropertyDescriptor("font", beanClass, null, "setFont"); + + PropertyDescriptor _insertState = new PropertyDescriptor("insertState", beanClass, "isInsertState", "setInsertState"); + + PropertyDescriptor _referenceCursor = new PropertyDescriptor("referenceCursor", beanClass, "isReferenceCursor", "setReferenceCursor"); + + PropertyDescriptor _codePage = new PropertyDescriptor("codePage", beanClass, "getCodePage", "setCodePage"); + + PropertyDescriptor[] pds = new PropertyDescriptor[] { + _defBackground, + _defFieldsBorderStyle, + _font, + _insertState, + _referenceCursor, + _codePage, + }; + return pds; + } + catch (IntrospectionException ex) { + ex.printStackTrace(); + return null; + } + } + + @Override + public java.awt.Image getIcon(int iconKind) { + switch (iconKind) { + case BeanInfo.ICON_COLOR_16x16: + return iconColor16x16Filename != null ? loadImage(iconColor16x16Filename) : null; + case BeanInfo.ICON_COLOR_32x32: + return iconColor32x32Filename != null ? loadImage(iconColor32x32Filename) : null; + case BeanInfo.ICON_MONO_16x16: + return iconMono16x16Filename != null ? loadImage(iconMono16x16Filename) : null; + case BeanInfo.ICON_MONO_32x32: + return iconMono32x32Filename != null ? loadImage(iconMono32x32Filename) : null; + } + return null; + } + + @Override + public BeanInfo[] getAdditionalBeanInfo() { + Class superclass = beanClass.getSuperclass(); + try { + BeanInfo superBeanInfo = Introspector.getBeanInfo(superclass); + return new BeanInfo[] { superBeanInfo }; + } + catch (IntrospectionException ex) { + ex.printStackTrace(); + return null; + } + } +} + + \ No newline at end of file diff --git a/net/infordata/em/crt5250/XI5250CrtBuffer.java b/net/infordata/em/crt5250/XI5250CrtBuffer.java new file mode 100644 index 0000000..bb73177 --- /dev/null +++ b/net/infordata/em/crt5250/XI5250CrtBuffer.java @@ -0,0 +1,676 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 26/03/97 rel. 0.90 - start of revisions history. + 26/03/97 rel. 0.90 - changed to speed up drawing. + 10/04/97 rel. 0.93 - some fixes to add SignedNumeric fields handling. + 27/05/97 rel. 1.00 - first release. + 13/01/98 rel. 1.05d- NT painting bug. + 14/01/98 rel. 1.06 - asynchronous paint on off-screen image. + 03/03/98 rel. _.___- SWING and reorganization. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + 29/07/99 rel. 1.14 - Rework on 3d look&feel. + */ + + +package net.infordata.em.crt5250; + + +import java.awt.Color; +import java.awt.Graphics; +import java.io.Serializable; + +import net.infordata.em.crt.XICrtBuffer; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Adds capabilities required by 5250 emulation to XICrtBuffer. + * To be used by XI5250Crt. + * + * @see XI5250Crt + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XI5250CrtBuffer extends XICrtBuffer implements Serializable { + + + private static final long serialVersionUID = 1L; + + //!!0.95c + public static final int GRAY_INTENSITY = colorAsIntensity(Color.gray); + + //!!0.95b + private ColorWrapper ivBackColor = new ColorWrapper(Color.black); + + /** + * to be used with dark background + */ + private static final Color blue = new Color(128, 128, 255); + + /** + * The character foreground color map used with dark background colors + */ + private final Color[][] DK_FORE_COLORS_MAP = { + { + // normal reverse + Color.green, ivBackColor, + Color.white, ivBackColor, + Color.green, ivBackColor, // underscore + Color.white, // underscore + ivBackColor, // invisible + Color.red, ivBackColor, + Color.red.brighter(), ivBackColor, // blink + Color.red, ivBackColor, // underscore + Color.red.brighter(), // blink, underscore + ivBackColor, // invisible + Color.cyan, ivBackColor, // column separator + Color.yellow, ivBackColor, // column separator + Color.cyan, ivBackColor, // column separator, underscore + Color.yellow, // column separator, underscore + ivBackColor, // invisible + Color.pink, ivBackColor, + blue, ivBackColor, + Color.pink, ivBackColor, // underscore + blue, // underscore + ivBackColor // invisible + } + }; + /** + * The character background color map used with dark background colors + */ + private final Color[][] DK_BACK_COLORS_MAP = { + { + // normal reverse + ivBackColor, Color.green, + ivBackColor, Color.white, + ivBackColor, Color.green, // underscore + ivBackColor, // underscore + ivBackColor, // invisible + ivBackColor, Color.red, + ivBackColor, Color.red.brighter(), // blink + ivBackColor, Color.red, // underscore + ivBackColor, // blink, underscore + ivBackColor, // invisible + ivBackColor, Color.cyan, // column separator + ivBackColor, Color.yellow,// column separator + ivBackColor, Color.cyan, // column separator, underscore + ivBackColor, // column separator, underscore + ivBackColor, // invisible + ivBackColor, Color.pink, + ivBackColor, blue, + ivBackColor, Color.pink, // underscore + ivBackColor, // underscore + ivBackColor // invisible + } + }; + + /** + * The character foreground color map used with bright background colors + */ + private final Color[][] LT_FORE_COLORS_MAP = { + { + // normal reverse + Color.green.darker().darker(), ivBackColor, + Color.darkGray, ivBackColor, + Color.green.darker().darker(), ivBackColor, // underscore + Color.darkGray, // underscore + ivBackColor, // invisible + Color.red, ivBackColor, + Color.red.brighter(), ivBackColor, // blink + Color.red, ivBackColor, // underscore + Color.red.brighter(), // blink, underscore + ivBackColor, // invisible + Color.blue, ivBackColor, // column separator + Color.yellow.darker(), ivBackColor, // column separator + Color.blue, ivBackColor, // column separator, underscore + Color.yellow.darker(), // column separator, underscore + ivBackColor, // invisible + Color.pink.darker(), ivBackColor, + blue.darker(), ivBackColor, + Color.pink.darker(), ivBackColor, // underscore + blue.darker(), // underscore + ivBackColor // invisible + }, + { //** input fields color map + // normal reverse + Color.green.darker().darker(), Color.white, + Color.darkGray, Color.white, + Color.green.darker().darker(), Color.white, // underscore + Color.darkGray, // underscore + Color.white, // invisible + Color.red, Color.white, + Color.red.brighter(), Color.white, // blink + Color.red, Color.white, // underscore + Color.red.brighter(), // blink, underscore + Color.white, // invisible + Color.blue, Color.white, // column separator + Color.yellow.darker(), Color.white, // column separator + Color.blue, Color.white, // column separator, underscore + Color.yellow.darker(), // column separator, underscore + ivBackColor, // invisible + Color.pink.darker(), Color.white, + blue.darker(), Color.white, + Color.pink.darker(), Color.white, // underscore + blue.darker(), // underscore + ivBackColor // invisible + } + }; + /** + * The character background color map used with bright background colors + */ + private final Color[][] LT_BACK_COLORS_MAP = { + { + // normal reverse + ivBackColor, Color.green.darker().darker(), + ivBackColor, Color.darkGray, + ivBackColor, Color.green.darker().darker(), // underscore + ivBackColor, // underscore + ivBackColor, // invisible + ivBackColor, Color.red, + ivBackColor, Color.red.brighter(), // blink + ivBackColor, Color.red, // underscore + ivBackColor, // blink, underscore + ivBackColor, // invisible + ivBackColor, Color.blue, // column separator + ivBackColor, Color.yellow.darker(),// column separator + ivBackColor, Color.blue, // column separator, underscore + ivBackColor, // column separator, underscore + ivBackColor, // invisible + ivBackColor, Color.pink.darker(), + ivBackColor, blue.darker(), + ivBackColor, Color.pink.darker(), // underscore + ivBackColor, // underscore + ivBackColor // invisible + }, + { //** input fields color map + // normal reverse + Color.white, Color.green.darker().darker(), + Color.white, Color.darkGray, + Color.white, Color.green.darker().darker(), // underscore + Color.white, // underscore + Color.white, // invisible + Color.white, Color.red, + Color.white, Color.red.brighter(), // blink + Color.white, Color.red, // underscore + Color.white, // blink, underscore + Color.white, // invisible + Color.white, Color.blue, // column separator + Color.white, Color.yellow.darker(),// column separator + Color.white, Color.blue, // column separator, underscore + Color.white, // column separator, underscore + Color.white, // invisible + Color.white, Color.pink.darker(), + Color.white, blue.darker(), + Color.white, Color.pink.darker(), // underscore + Color.white, // underscore + Color.white // invisible + } + }; + + + private Color[][] ivForegroundColorsMap = DK_FORE_COLORS_MAP; + private Color[][] ivBackgroundColorsMap = DK_BACK_COLORS_MAP; + + /** + * 5250 Extra char attribute + */ + static final int UNDERSCORE = 0x01; + /** + * 5250 Extra char attribute + */ + static final int COLUMN_SEPARATOR = 0x02; + + static final int[] EXTRA_ATTR_MAP = { + // normal reverse + 0x00, + 0x00, + 0x00, + 0x00, + UNDERSCORE, + UNDERSCORE, + UNDERSCORE, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + UNDERSCORE, + UNDERSCORE, + UNDERSCORE, + 0x00, + COLUMN_SEPARATOR, + COLUMN_SEPARATOR, + COLUMN_SEPARATOR, + COLUMN_SEPARATOR, + COLUMN_SEPARATOR | UNDERSCORE, + COLUMN_SEPARATOR | UNDERSCORE, + COLUMN_SEPARATOR | UNDERSCORE, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + UNDERSCORE, + UNDERSCORE, + UNDERSCORE, + 0x00 + }; + + + /** + * Contructs a XI5250CrtBuffer with the given dimensions expressed in number of chars. + */ + public XI5250CrtBuffer(int nCols, int nRows) { + super(nCols, nRows); + setDefAttr(0x20); + clear(); // sets new attribute + } + + + /** + * Creates a XI5250CrtBuffer from a portion of another one. + */ + public XI5250CrtBuffer(XI5250CrtBuffer from, int aC, int aR, int aW, int aH) { + super(from, aC, aR, aW, aH); + setDefBackground(from.getDefBackground()); + } + + + /** + * Returns a cloned XICrtBuffer (the new one needs initGraphics() to be + * displayed). + */ + @Override + public Object clone() { + XI5250CrtBuffer aClone = new XI5250CrtBuffer(this, 0, 0, + getCrtSize().width, getCrtSize().height); + /* !!1.04 + XI5250CrtBuffer aClone = new XI5250CrtBuffer(getCrtSize().width, getCrtSize().height); + aClone.setDefBackground(getDefBackground()); //!!0.95b + aClone.copyFrom(this); + */ + return aClone; + } + + + /** + * Handles lines wrap. + */ + @Override + public synchronized void drawString(String aStr, int col, int row, + int aAttr) { + int lPos = toLinearPos(col, row); + col = toColPos(lPos); + row = toRowPos(lPos); + + // if attribute == USE_PRESENT_ATTRIBUTE then get previous attribute + if (aAttr == XI5250Crt.USE_PRESENT_ATTRIBUTE) + aAttr = getAttr(col, row); + + // split line to handle wrap + int len = aStr.length(); + int x = col; + int y = row; + int dx; + int i = 0; + int maxW = getCrtSize().width; + + while (len > 0) { + dx = Math.min(maxW - x, len); + + super.drawString(aStr.substring(i, i + dx), x, y, aAttr); + + i += dx; + len -= dx; + x = 0; + ++y; + } + } + + + /** + * Draws attribute place-holder char. + */ + protected void _drawAttributePlaceHolder(Graphics gr, int col, int row, + int aAttr) { + int lPos = toLinearPos(col, row); + col = toColPos(lPos); + row = toRowPos(lPos); + + int charW = getCharSize().width; + int charH = getCharSize().height; + + gr.setColor(getBackground(0x20)); + gr.fillRect(col * charW, row * charH, charW, charH); + + if (XI5250Crt.DEBUG >= 2) { // to see them + gr.setColor(getForeground(0x20)); + gr.drawString("#", col * charW, (row + 1) * charH); + } + } + + + /** + * Draws 5250 extra attribute (UNDERLINE and COLUMN_SEPARATOR). + */ + protected void _drawExtraAttribute(Graphics gr, int col, int row, int len, + int aAttr) { + int extra = getExtraCharAttribute(aAttr); + int dy = 2; //!!0.95b + + int charW = getCharSize().width; + int charH = getCharSize().height; + + gr.setColor(getForeground(aAttr)); + + if ((extra & UNDERSCORE) != 0) { + gr.drawLine(col * charW, (row + 1) * charH - dy - 1, + (col + len) * charW - 1, (row + 1) * charH - dy - 1); + } + + if ((extra & COLUMN_SEPARATOR) != 0) { + gr.setColor(getForeground(0x22)); + + for (int i = 0; i < len; i++) { + gr.drawLine((col + i) * charW, (row + 1) * charH - dy, + (col + i) * charW, (row + 1) * charH - dy); + + gr.drawLine((col + i + 1) * charW - 1, (row + 1) * charH - dy, + (col + i + 1) * charW - 1, (row + 1) * charH - dy); + } + } + } + + + /** + * Splits string to detect attribute place-holder presence. + */ + @Override + protected void _drawString(Graphics gr, String aStr, int col, int row, + int aAttr) { + if (aStr.length() <= 0) + return; + + int pos = -1; + for (int i = 0; i < aStr.length(); i++) { + if (aStr.charAt(i) == XI5250Crt.ATTRIBUTE_PLACE_HOLDER) { + pos = i; + break; + } + } + + if (pos == -1) { + super._drawString(gr, aStr, col, row, aAttr); + _drawExtraAttribute(gr, col, row, aStr.length(), aAttr); + } + else { + // draw string portion before attribute place-holder + if (pos > 0) { + super._drawString(gr, aStr, col, row, aAttr); + _drawExtraAttribute(gr, col, row, aStr.length(), aAttr); + } + // draw attribute place-holder + _drawAttributePlaceHolder(gr, col + pos, row, aAttr); + // draw string portion after attribute place-holder + if (pos < (aStr.length() - 1)) + _drawString(gr, aStr.substring(pos + 1), col + pos + 1, row, aAttr); + } + } + + + /** + * Can be used to verify the presence of a string in the buffer. + * Redefined to implement lines wrap. + * @see String#indexOf + */ + @Override + public String getString(int col, int row, int nChars) { + StringBuilder str = new StringBuilder(); + for (int i = 0; i < nChars; i++) { + int j = toLinearPos(col + i, row); + str.append(getChar(toColPos(j), toRowPos(j))); + } + return new String(str); + } + + + /** + * Attribute to color mapping. + */ + @Override + protected Color getBackground(int aAttribute) { + // see SA21-9247-6 pg 2-143 + int mapIdx = Math.min(ivBackgroundColorsMap.length - 1, + getColorMapIdx(aAttribute)); + return ivBackgroundColorsMap[mapIdx] + [getColorAttributeIdx(aAttribute) - 0x20]; + } + + + /** + * Attribute to color mapping. + */ + @Override + protected Color getForeground(int aAttribute) { + // see SA21-9247-6 pg 2-143 + int mapIdx = Math.min(ivForegroundColorsMap.length - 1, + getColorMapIdx(aAttribute)); + return ivForegroundColorsMap[mapIdx] + [getColorAttributeIdx(aAttribute) - 0x20]; + } + + + /** + * Attribute to extra char attribute mapping. + */ + protected int getExtraCharAttribute(int aAttribute) { + return EXTRA_ATTR_MAP[getColorAttributeIdx(aAttribute) - 0x20]; + } + + + /** + */ + protected final byte getColorMapIdx(int aAttribute) { + return (byte)((aAttribute >> 24) & 0xFF); + } + + + /** + */ + protected final int getColorAttributeIdx(int aAttribute) { + return aAttribute & 0x00FFFFFF; + } + + + /** + */ + @Override + public int getAttr(int col, int row) { + int attr = super.getAttr(col, row); + XI5250Crt crt = (XI5250Crt)getCrt(); + if (crt != null) { + //!!1.14 change color table + XI5250Field field = crt.getFieldFromPos(col, row); + if (field != null && !field.isOrgBypassField()) + attr |= (1 << 24); + } + return attr; + } + + + /** + * Converts x-y coord to buffer linear position. + */ + public final int toLinearPos(int aCol, int aRow) { + return (aRow * getCrtSize().width) + aCol; + } + + + /** + * Converts buffer linear position to x-y coord. + */ + public final int toColPos(int aPos) { + return aPos % getCrtSize().width; + } + + + /** + * Converts buffer linear position to x-y coord. + */ + public final int toRowPos(int aPos) { + return aPos / getCrtSize().width; + } + + + /** + * Converts color to an intensity value (0 to 1000) + * @see #setDefBackground + */ + public static final int colorAsIntensity(Color aColor) { + float[] hsb = Color.RGBtoHSB(aColor.getRed(), aColor.getGreen(), + aColor.getBlue(), null); + return (int)(hsb[2] * 1000); + } + + + /** + * Changes the default background color. + * The new color intensity is used to choose which colors table must be used. + */ + public void setDefBackground(Color aColor) { + if (ivBackColor.equals(aColor)) + return; + + // check if background color intensity (referred to GRAY_INTENSITY) + // has changed + if ((colorAsIntensity(ivBackColor) >= GRAY_INTENSITY) != + (colorAsIntensity(aColor) >= GRAY_INTENSITY)) { + boolean dark = (colorAsIntensity(aColor) < GRAY_INTENSITY); + + ivBackgroundColorsMap = (dark) ? DK_BACK_COLORS_MAP : LT_BACK_COLORS_MAP; + ivForegroundColorsMap = (dark) ? DK_FORE_COLORS_MAP : LT_FORE_COLORS_MAP; + } + + ivBackColor.setColor(aColor); + } + + + /** + */ + public Color getDefBackground() { + return ivBackColor.getColor(); + } + + +// /** +// */ +// void writeObject(ObjectOutputStream oos) throws IOException { +// oos.defaultWriteObject(); +// } +// +// void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { +// ois.defaultReadObject(); +// } + + + ////////////////////////////////////////////////////////////////////////////// + + /** + * Simply routes all method calls to the contained color methods + */ + private static class ColorWrapper extends Color implements Serializable { + + private static final long serialVersionUID = 1L; + + private Color ivColor; + + + /** + */ + public ColorWrapper(Color aColor) { + super(0); + ivColor = aColor; + } + + + /** + */ + public void setColor(Color aColor) { + ivColor = aColor; + } + + + /** + */ + public Color getColor() { + return ivColor; + } + + + /** + */ + @Override + public int getRed() { + return ivColor.getRed(); + } + + @Override + public int getGreen() { + return ivColor.getGreen(); + } + + @Override + public int getBlue() { + return ivColor.getBlue(); + } + + @Override + public int getRGB() { + return ivColor.getRGB(); + } + + @Override + public Color brighter() { + return ivColor.brighter(); + } + + @Override + public Color darker() { + return ivColor.darker(); + } + + @Override + public int hashCode() { + return ivColor.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return ivColor.equals(obj); + } + + @Override + public String toString() { + return ivColor.toString(); + } + } +} + diff --git a/net/infordata/em/crt5250/XI5250CrtCtrl.java b/net/infordata/em/crt5250/XI5250CrtCtrl.java new file mode 100644 index 0000000..6e7e261 --- /dev/null +++ b/net/infordata/em/crt5250/XI5250CrtCtrl.java @@ -0,0 +1,275 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** +!!V 15/06/99 rel. 1.13 - creation. + */ + + +package net.infordata.em.crt5250; + + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.SystemColor; +import java.awt.event.KeyEvent; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +import net.infordata.em.util.XICommand; +import net.infordata.em.util.XICommandMgr; + + +/** + * Handles common commands. + */ +public class XI5250CrtCtrl { + + private static final Logger LOGGER = Logger.getLogger(XI5250CrtCtrl.class.getName()); + + private XI5250Crt ivCrt; + + private XICommandMgr ivCommandMgr = new XICommandMgr(); + + + public static final String SWITCH_3DFX_CMD = "SWITCH_3DFX_CMD"; + public static final String REFERENCE_CURSOR_CMD = "REFERENCE_CURSOR_CMD"; + + public static final String COPY_CMD = "COPY_CMD"; + public static final String PASTE_CMD = "PASTE_CMD"; + + public static final String PRINT_CMD = "PRINT_CMD"; + + /** + */ + public XI5250CrtCtrl(XI5250Crt aCrt) { + if (aCrt == null) + throw new IllegalArgumentException("An XI5250Crt instance is required."); + + ivCrt = aCrt; + + ivCrt.addPropertyChangeListener(new PropertyListener()); + + // Copy command + getCommandMgr().enableCommand( + COPY_CMD, ivCrt.getSelectedArea() != null); + getCommandMgr().setCommand(COPY_CMD, new XICommand() { + public void execute() { + processCopyCmd(); + } + }); + + // Paste command + getCommandMgr().setCommand(PASTE_CMD, new XICommand() { + public void execute() { + processPasteCmd(); + } + }); + + // 3Dfx command + getCommandMgr().setCommandState(SWITCH_3DFX_CMD, is3DFX()); + getCommandMgr().setCommand(SWITCH_3DFX_CMD, new XICommand() { + public void execute() { + processSwitch3dFxCmd(); + } + }); + + // Reference cursor command + getCommandMgr().setCommandState( + REFERENCE_CURSOR_CMD, ivCrt.isReferenceCursor()); + getCommandMgr().setCommand(REFERENCE_CURSOR_CMD, new XICommand() { + public void execute() { + processReferenceCursorCmd(); + } + }); + + // Print command + getCommandMgr().setCommand(PRINT_CMD, new XICommand() { + public void execute() { + processPrintCmd(); + } + }); + } + + + /** + */ + public final XI5250Crt getCrt() { + return ivCrt; + } + + + /** + */ + public final XICommandMgr getCommandMgr() { + return ivCommandMgr; + } + + + /** + */ + public final boolean is3DFX() { + return + (getCrt().getDefFieldsBorderStyle() == XI5250Field.LOWERED_BORDER); + } + + + /** + */ + protected void processCopyCmd() { + getCrt().processRawKeyEvent( + new KeyEvent(getCrt(), KeyEvent.KEY_PRESSED, + 0, KeyEvent.CTRL_MASK, KeyEvent.VK_INSERT, (char)KeyEvent.VK_INSERT)); + } + + + /** + */ + protected void processPasteCmd() { + getCrt().processRawKeyEvent( + new KeyEvent(getCrt(), KeyEvent.KEY_PRESSED, + 0, KeyEvent.SHIFT_MASK, KeyEvent.VK_INSERT, (char)KeyEvent.VK_INSERT)); + } + + + /** + */ + protected void processSwitch3dFxCmd() { + boolean flag = getCommandMgr().getCommandState(SWITCH_3DFX_CMD); + + if (flag) { + getCrt().setDefFieldsBorderStyle(XI5250Field.LOWERED_BORDER); + getCrt().setDefBackground(UIManager.getColor("control")); + } + else { + getCrt().setDefFieldsBorderStyle(XI5250Field.NO_BORDER); + getCrt().setDefBackground(SystemColor.black); + } + } + + + /** + */ + protected void processReferenceCursorCmd() { + boolean flag = getCommandMgr().getCommandState(REFERENCE_CURSOR_CMD); + + getCrt().setReferenceCursor(flag); + } + + + /** + */ + protected void emulatorPropertyChanged(PropertyChangeEvent e) { + String propertyName = e.getPropertyName(); + + if (propertyName == XI5250Crt.SELECTED_AREA) { + getCommandMgr().enableCommand( + COPY_CMD, getCrt().getSelectedArea() != null); + } + else if (propertyName == XI5250Crt.DEF_FIELDS_BORDER_STYLE) { + getCommandMgr().setCommandState(SWITCH_3DFX_CMD, is3DFX()); + } + else if (propertyName == XI5250Crt.REFERENCE_CURSOR) { + getCommandMgr().setCommandState( + REFERENCE_CURSOR_CMD, getCrt().isReferenceCursor()); + } + } + + + /** + */ + protected void processPrintCmd() { + PrinterJob job = PrinterJob.getPrinterJob(); + job.setPrintable(new Printable() { + public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) + throws PrinterException { + if (pageIndex > 0) { + return NO_SUCH_PAGE; + } + final int imgWidth = (int)pageFormat.getImageableWidth(); + final int imgHeight = (int)pageFormat.getImageableHeight(); + final XI5250Crt crt = getCrt(); + Graphics2D g2d = (Graphics2D)graphics; + g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY()); + double scale; + { + int w = crt.getSize().width; + int h = crt.getSize().height; + scale = Math.min(((double)imgWidth) / w, ((double)imgHeight) / h); + g2d.scale(scale, scale); + } + synchronized (crt.getTreeLock()) { + synchronized (crt) { + Color oldBG = crt.getDefBackground(); + //int oldBS = crt.getDefFieldsBorderStyle(); + try { + //crt.setDefFieldsBorderStyle(XI5250Field.NO_BORDER); + crt.setDefBackground(SystemColor.white); + crt.printAll(g2d); + } + finally { + //crt.setDefFieldsBorderStyle(oldBS); + crt.setDefBackground(oldBG); + } + } + } + return PAGE_EXISTS; } + }); + boolean doPrint = job.printDialog(); + if (doPrint) { + try { + job.print(); + } + catch (final PrinterException ex) { + LOGGER.log(Level.SEVERE, "catchedException()", ex); + SwingUtilities.invokeLater(new Runnable() { + public void run() { + JOptionPane.showMessageDialog(getCrt(), + ex.getMessage() + "\nSee the log for details ", + "ERROR", JOptionPane.ERROR_MESSAGE); + } + }); + } + } + } + + + ////////////////////////////////////////////////////////////////////////////// + + /** + * Usata per sincronizzare i comandi con le property dell' emulatore. + */ + class PropertyListener implements PropertyChangeListener { + + public void propertyChange(PropertyChangeEvent e) { + emulatorPropertyChanged(e); + } + } +} + + diff --git a/net/infordata/em/crt5250/XI5250CrtEvent.java b/net/infordata/em/crt5250/XI5250CrtEvent.java new file mode 100644 index 0000000..00f00c4 --- /dev/null +++ b/net/infordata/em/crt5250/XI5250CrtEvent.java @@ -0,0 +1,128 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 03/03/98 rel. _.___- SWING and reorganization. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.crt5250; + + +import java.awt.event.KeyEvent; +import java.util.EventObject; + + +/** + */ +public class XI5250CrtEvent extends EventObject { + + private static final long serialVersionUID = 1L; + + /** + * A field has been activated. + */ + public static final int FIELD_ACTIVATED = 0; + /** + * A field has been deactivated. + */ + public static final int FIELD_DEACTIVATED = FIELD_ACTIVATED + 1; + /** + * The crt real-size is changed (ie. the font size is changed) (this event is posted). + */ + public static final int SIZE_CHANGED = FIELD_ACTIVATED + 2; + /** + * A key has been pressed. + * !!! Use this event instead of AWT KeyEvent !!!. + */ + public static final int KEY_EVENT = FIELD_ACTIVATED + 3; + /** + * Mouse enters the field area. + */ + public static final int MOUSE_ENTERS_FIELD = FIELD_ACTIVATED + 4; + /** + * Mouse exits from a field area. + */ + public static final int MOUSE_EXITS_FIELD = FIELD_ACTIVATED + 5; + + + private static final String[] cvIdDescr = {"FIELD_ACTIVATED", + "FIELD_DEACTIVATED", + "SIZE_CHANGED", + "KEY_EVENT", + "MOUSE_ENTERS_FIELD", + "MOUSE_EXITS_FIELD"}; + + private int ivId; + private XI5250Field ivField; + private KeyEvent ivKeyEvent; + + + /** + */ + protected XI5250CrtEvent(int aId, XI5250Crt aCrt, XI5250Field aField, + KeyEvent aKeyEvent) { + super(aCrt); + ivId = aId; + ivField = aField; + ivKeyEvent = aKeyEvent; + } + + + /** + */ + public XI5250CrtEvent(int aId, XI5250Crt aCrt, XI5250Field aField) { + this(aId, aCrt, aField, null); + } + + + /** + */ + public final int getID() { + return ivId; + } + + + /** + */ + public final XI5250Crt getCrt() { + return (XI5250Crt)getSource(); + } + + + /** + */ + public final XI5250Field getField() { + return ivField; + } + + + /** + */ + public final KeyEvent getKeyEvent() { + return ivKeyEvent; + } + + + /** + */ + @Override + public String toString() { + return super.toString() + "[" + cvIdDescr[getID()] + "," + ivField + "]"; + } +} \ No newline at end of file diff --git a/net/infordata/em/crt5250/XI5250CrtFrame.java b/net/infordata/em/crt5250/XI5250CrtFrame.java new file mode 100644 index 0000000..11df5a3 --- /dev/null +++ b/net/infordata/em/crt5250/XI5250CrtFrame.java @@ -0,0 +1,371 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** +!!V 15/06/99 rel. 1.13 - creation. + */ + + +package net.infordata.em.crt5250; + + +import java.awt.AWTEvent; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Toolkit; +import java.awt.event.WindowEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.ResourceBundle; + +import javax.swing.AbstractButton; +import javax.swing.JButton; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JToggleButton; +import javax.swing.JToolBar; +import javax.swing.SwingUtilities; + +import net.infordata.em.tn5250.XI5250EmulatorCtrl; +import net.infordata.em.util.XICommand; +import net.infordata.em.util.XICommandMgr; +import net.infordata.em.util.XIUtil; + + + +/** + */ +public class XI5250CrtFrame extends JFrame { + + + private static final long serialVersionUID = 1L; + + // images + private static XIImagesBdl cvImagesBdl = XIImagesBdl.getImagesBdl(); + + private static ResourceBundle cvRes = + ResourceBundle.getBundle("net.infordata.em.crt5250.resources.Res"); + + private boolean ivPending; + private boolean ivOpened; + + private boolean ivFirstTime = true; //!!1.11 + private boolean ivSizeControlledFrame = false; //!!1.11 + + private XI5250CrtCtrl ivCrtCtrl; + + public static final String EXIT_CMD = "EXIT_CMD"; + + + /** + */ + public XI5250CrtFrame(String aTitle, XI5250Crt aCrt) { + this(aTitle, aCrt, false); + } + + + /** + */ + public XI5250CrtFrame(String aTitle, XI5250Crt aCrt, + boolean sizeControlledFrame) { + super(aTitle); + + ivSizeControlledFrame = sizeControlledFrame; + + if (aCrt == null) + throw new IllegalArgumentException("An XI5250Crt instance is required."); + + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + + ivCrtCtrl = createController(aCrt); + + enableEvents(AWTEvent.WINDOW_EVENT_MASK); + + JPanel panel = new XI5250Crt.SupportPanel(getCrt()); + panel.setBackground(getCrt().getBackground()); + getContentPane().add(panel, BorderLayout.CENTER); + + getCrt().addPropertyChangeListener(new PropertyChangeListener() { + public void propertyChange(PropertyChangeEvent evt) { + emulatorPropertyChanged(evt); + } + }); + + // + JToolBar toolBar = createToolBar(); + JMenuBar menuBar = createMenuBar(); + + setJMenuBar(menuBar); + getContentPane().add(toolBar, BorderLayout.NORTH); + + // Exit command + getCommandMgr().setCommand(EXIT_CMD, new XICommand() { + public void execute() { + processExitCmd(); + } + }); + } + + + public void doNotPackOnStartup() { + ivFirstTime = false; + } + + + /** + */ + protected void processExitCmd() { + setVisible(false); + dispose(); + } + + + /** + */ + protected XI5250CrtCtrl createController(XI5250Crt crt) { + return new XI5250CrtCtrl(crt); + } + + + /** + */ + protected final XI5250CrtCtrl getCrtCtrl() { + return ivCrtCtrl; + } + + + /** + */ + public final XI5250Crt getCrt() { + return ivCrtCtrl.getCrt(); + } + + + /** + */ + private void emulatorPropertyChanged(PropertyChangeEvent evt) { + String propertyName = evt.getPropertyName(); + if ("background".equals(propertyName)) + getCrt().getParent().setBackground(getCrt().getBackground()); + else if ("font".equals(propertyName) || + XI5250Crt.CRT_SIZE.equals(propertyName)) { + getCrt().revalidate(); + sizeChanged(); + } + } + + + /** + */ + public final XICommandMgr getCommandMgr() { + return ivCrtCtrl.getCommandMgr(); + } + + + /** + */ + @Override + public void invalidate() { + super.invalidate(); + sizeChanged(); + } + + + /** + */ + protected void sizeChanged() { + if (ivOpened && !ivPending) { + ivPending = true; + SwingUtilities.invokeLater(new Runnable() { + public void run() { + try { + if (ivFirstTime || ivSizeControlledFrame) { + ivFirstTime = false; + pack(); //!!1.03b + } + } + finally { + ivPending = false; + } + } + }); + } + } + + + /** + */ + public void centerOnScreen() { + Dimension ss = Toolkit.getDefaultToolkit().getScreenSize(); + Dimension dim = getSize(); + + setBounds((ss.width - dim.width) / 2, (ss.height - dim.height) / 2 , + dim.width, dim.height); + } + + + /** + */ + public void centerOnScreen(int perc) { + Dimension ss = Toolkit.getDefaultToolkit().getScreenSize(); + Dimension dim = getSize(); + dim.width = (ss.width * perc) / 100; + dim.height = (ss.height * perc) / 100; + + setBounds((ss.width - dim.width) / 2, (ss.height - dim.height) / 2 , + dim.width, dim.height); + } + + + /** + */ + @Override + protected void processWindowEvent(WindowEvent e) { + switch(e.getID()) { + case WindowEvent.WINDOW_OPENED: + getCrt().requestFocus(); + ivOpened = true; + sizeChanged(); + break; + case WindowEvent.WINDOW_CLOSING: + getCommandMgr().dispatchCommand(EXIT_CMD); + break; + case WindowEvent.WINDOW_CLOSED: + break; + } + super.processWindowEvent(e); + } + + + /** + */ + protected JMenuBar createMenuBar() { + String str; + + str = cvRes.getString("TXT_Edit"); + JMenu editMenu = new JMenu(XIUtil.removeMnemonics(str)); + editMenu.setMnemonic(XIUtil.getMnemonic(str)); + { + JMenuItem copyItem = + new JMenuItem(cvRes.getString("TXT_Copy")); + JMenuItem pasteItem = + new JMenuItem(cvRes.getString("TXT_Paste")); + JMenuItem printItem = + new JMenuItem(cvRes.getString("TXT_Print")); + + editMenu.add(copyItem); + editMenu.add(pasteItem); + editMenu.addSeparator(); + editMenu.add(printItem); + + getCommandMgr().handleCommand(copyItem, + XI5250CrtCtrl.COPY_CMD); + getCommandMgr().handleCommand(pasteItem, + XI5250CrtCtrl.PASTE_CMD); + getCommandMgr().handleCommand(printItem, + XI5250EmulatorCtrl.PRINT_CMD); + } + + str = cvRes.getString("TXT_Options"); + JMenu optionsMenu = new JMenu(XIUtil.removeMnemonics(str)); + optionsMenu.setMnemonic(XIUtil.getMnemonic(str)); + { + JCheckBoxMenuItem switch3DfxItem = + new JCheckBoxMenuItem(cvRes.getString("TXT_3dFx")); + JCheckBoxMenuItem referenceCursorItem = + new JCheckBoxMenuItem(cvRes.getString("TXT_RefCursor")); + + optionsMenu.add(switch3DfxItem); + optionsMenu.add(referenceCursorItem); + + getCommandMgr().handleCommand(switch3DfxItem, + XI5250CrtCtrl.SWITCH_3DFX_CMD); + getCommandMgr().handleCommand(referenceCursorItem, + XI5250CrtCtrl.REFERENCE_CURSOR_CMD); + } + + JMenuBar menuBar = new JMenuBar(); + menuBar.add(editMenu); + menuBar.add(optionsMenu); + return menuBar; + } + + + /** + * Inserisce nella tool-bar i bottoni di default. + */ + protected JToolBar createToolBar() { + // bottoni della tool-bar + AbstractButton[] buttons = new AbstractButton[] { + new JButton(cvImagesBdl.getIcon("Copy")), + new JButton(cvImagesBdl.getIcon("Paste")), + null, + new JButton(cvImagesBdl.getIcon("Print")), + null, + new JToggleButton(cvImagesBdl.getIcon("3dFx")), + new JToggleButton(cvImagesBdl.getIcon("RefCursor")), + }; + // action commands associati con i bottoni della tool-bar. + String[] buttonsActCmd = new String[] { + XI5250CrtCtrl.COPY_CMD, + XI5250CrtCtrl.PASTE_CMD, + null, + XI5250EmulatorCtrl.PRINT_CMD, + null, + XI5250CrtCtrl.SWITCH_3DFX_CMD, + XI5250CrtCtrl.REFERENCE_CURSOR_CMD, + }; + // Hint associati ad i vari bottoni. + String[] buttonHints = new String[] { + cvRes.getString("TXT_Copy"), + cvRes.getString("TXT_Paste"), + null, + cvRes.getString("TXT_Print"), + null, + cvRes.getString("TXT_3dFx"), + cvRes.getString("TXT_RefCursor"), + }; + + JToolBar toolBar = new JToolBar(); + toolBar.setFloatable(false); + + Dimension size = new Dimension(26, 26); + + for (int i = 0; i < buttons.length; i++) { + if (buttons[i] != null) { + AbstractButton button = (AbstractButton)buttons[i]; + toolBar.add(button); + button.setToolTipText(buttonHints[i]); + button.setMinimumSize(size); + button.setPreferredSize(size); + button.setMaximumSize(size); + button.setRequestFocusEnabled(false); + getCommandMgr().handleCommand(button, buttonsActCmd[i]); + } + else + toolBar.addSeparator(); + } + + return toolBar; + } +} + + diff --git a/net/infordata/em/crt5250/XI5250CrtListener.java b/net/infordata/em/crt5250/XI5250CrtListener.java new file mode 100644 index 0000000..e60ebd7 --- /dev/null +++ b/net/infordata/em/crt5250/XI5250CrtListener.java @@ -0,0 +1,72 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/** +!!V 03/03/98 rel. _.___- SWING and reorganization. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.crt5250; + + +import java.util.EventListener; + + +/** + * XI5250CrtEvent listener + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public interface XI5250CrtListener extends EventListener { + + /** + * @see XI5250CrtEvent#FIELD_ACTIVATED + */ + public void fieldActivated(XI5250CrtEvent e); + + + /** + * @see XI5250CrtEvent#FIELD_DEACTIVATED + */ + public void fieldDeactivated(XI5250CrtEvent e); + + + /** + * @see XI5250CrtEvent#SIZE_CHANGED + */ + public void sizeChanged(XI5250CrtEvent e); + + + /** + * @see XI5250CrtEvent#KEY_EVENT + */ + public void keyEvent(XI5250CrtEvent e); + + + /** + * @see XI5250CrtEvent#MOUSE_ENTERS_FIELD + */ + public void mouseEntersField(XI5250CrtEvent e); + + + /** + * @see XI5250CrtEvent#MOUSE_EXITS_FIELD + */ + public void mouseExitsField(XI5250CrtEvent e); +} diff --git a/net/infordata/em/crt5250/XI5250Field.java b/net/infordata/em/crt5250/XI5250Field.java new file mode 100644 index 0000000..04c9a7f --- /dev/null +++ b/net/infordata/em/crt5250/XI5250Field.java @@ -0,0 +1,1419 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 10/04/97 rel. 0.93 - some fixes to add SignedNumeric fields handling. + 16/04/97 rel. 0.94 - userError method added. + 08/05/97 rel. 0.95b- + 27/05/97 rel. 1.00 - first release. + 25/07/97 rel. 1.03a- a bug in ...Multicaster. + 06/08/97 rel. 1.03c- bug fix. + 27/08/97 rel. 1.04 - clipboard support. + 03/03/98 rel. _.___- SWING and reorganization. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + 29/07/99 rel. 1.14 - Rework on 3d look&feel. + */ + + +package net.infordata.em.crt5250; + + +import java.awt.AWTEventMulticaster; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.event.KeyEvent; +import java.io.IOException; +import java.util.EventListener; + +import net.infordata.em.tnprot.XITelnet; + + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Implements behaviour of 5250 fields with some extensions. + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XI5250Field implements XI5250BaseField { + + //!!0.95b border styles + /** + * Uses default border definition. + * @see #setBorderStyle + * @see XI5250Crt#setDefFieldsBorderStyle + */ + public static final int DEFAULT_BORDER = 0; + /** + * No border. + * @see #setBorderStyle + * @see XI5250Crt#setDefFieldsBorderStyle + */ + public static final int NO_BORDER = 1; + /** + * Raised border. + * @see #setBorderStyle + * @see XI5250Crt#setDefFieldsBorderStyle + */ + public static final int RAISED_BORDER = 2; + /** + * Lowered border. + * @see #setBorderStyle + * @see XI5250Crt#setDefFieldsBorderStyle + */ + public static final int LOWERED_BORDER = 3; + + private XI5250Crt ivCrt; + private byte[] ivFFW; + private byte[] ivFCW; + private int ivCol; + private int ivRow; + + //!!0.95b ivInputLen rapresent the length of the input area + private int ivInputLen; + //!!0.95b this is the real field length + private int ivLength; + + private int ivAttr; + + // valid only after updateStr() call + private String ivStr; + private int ivFldPos; + private int ivCurPos; + private int ivPos; + + //!!0.95 + private XI5250FieldListener ivFieldListener; + private XI5250FieldPaintListener ivFieldPaintListener; + + private boolean ivEnabled = true; + + //!!0.95b + private int ivBorderStyle = DEFAULT_BORDER; + + + /** + * @param aCrt the containing XI5250Crt + * @param aCol the field position + * @param aRow the field position + * @param aLen the field length + * @param aAttr the field color attribute + */ + public XI5250Field(XI5250Crt aCrt, int aCol, int aRow, int aLen, int aAttr) { + this(aCrt, new byte[2], new byte[2], aCol, aRow, aLen, aAttr); + } + + + /** + * @param aCrt the containing XI5250Crt + * @param aFFW see IBM 5250 function reference manual page 2-68 + * @param aFCW see IBM 5250 function reference manual page 2-65 + * @param aCol the field position + * @param aRow the field position + * @param aLen the field length + * @param aAttr the field color attribute + */ + public XI5250Field(XI5250Crt aCrt, byte[] aFFW, byte[] aFCW, + int aCol, int aRow, int aLen, int aAttr) { + ivCrt = aCrt; + ivFFW = aFFW; + ivFCW = aFCW; + ivCol = aCol; + ivRow = aRow; + ivInputLen = aLen; + ivLength = aLen; + ivAttr = aAttr; + + if (isSignedNumeric()) + --ivInputLen; + } + + + /** + */ + protected void removeNotify() { +//!!V never ivCrt = null; + } + + + /** + * XI5250FieldListener handling + */ + public synchronized void addFieldListener(XI5250FieldListener l) { + ivFieldListener = (XI5250FieldListener)Multicaster.add(ivFieldListener, l); + } + + + /** + * XI5250FieldListener handling + */ + public synchronized void removeFieldListener(XI5250FieldListener l) { + ivFieldListener = (XI5250FieldListener)Multicaster. + remove(ivFieldListener, l); + } + + + /** + * Routes XI5250FieldEvent to listeners + */ + protected void processFieldEvent(XI5250FieldEvent e) { + if (ivFieldListener == null) + return; + + switch (e.getID()) { + // + case XI5250FieldEvent.ACTIVATED: + ivFieldListener.activated(e); + break; + // + case XI5250FieldEvent.DEACTIVATED: + ivFieldListener.deactivated(e); + break; + // + case XI5250FieldEvent.VALUE_CHANGED: + ivFieldListener.valueChanged(e); + break; + // + case XI5250FieldEvent.ENABLED_STATE_CHANGED: + ivFieldListener.enabledStateChanged(e); + break; + // + case XI5250FieldEvent.KEY_EVENT: + ivFieldListener.keyEvent(e); + break; + } + } + + + /** + * XI5250FieldPaintListener handling + */ + public synchronized void addFieldPaintListener(XI5250FieldPaintListener l) { + ivFieldPaintListener = + (XI5250FieldPaintListener)Multicaster. + add(ivFieldPaintListener, l); + } + + + /** + * XI5250FieldPaintListener handling + */ + public synchronized void removeFieldPaintListener(XI5250FieldPaintListener l) { + ivFieldPaintListener = + (XI5250FieldPaintListener)Multicaster. + remove(ivFieldPaintListener, l); + } + + + /** + * routes XI5250FieldPaintEvent to listeners + */ + protected void processFieldPaintEvent(XI5250FieldPaintEvent e) { + if (ivFieldPaintListener == null) + return; + + switch (e.getID()) { + // + case XI5250FieldPaintEvent.FIELD_PAINT: + ivFieldPaintListener.fieldPaint(e); + break; + // + case XI5250FieldPaintEvent.ROW_PAINT: + ivFieldPaintListener.rowPaint(e); + break; + } + } + + + /** + */ + public final XI5250Crt getCrt() { + return ivCrt; + } + + + /** + * Initializes the field. + * It is called after that the 5250 panel construction has ended to let the field + * refresh its color attribute. + */ + public void init() { + updateStr(); + + // Is color attribute changed ? + int newAttr = ivCrt.getAttr(ivCrt.toColPos(ivFldPos - 1), ivCrt.toRowPos(ivFldPos - 1)); + if (newAttr != ivAttr) { + ivAttr = newAttr; + String str = getString(); + int from = 0; + while (true) { + int idx = str.indexOf(XI5250Crt.ATTRIBUTE_PLACE_HOLDER, from); + if (idx < 0) { + ivCrt.drawString(str.substring(from), + ivCrt.toColPos(ivFldPos + from), ivCrt.toRowPos(ivFldPos + from), newAttr); + break; + } + ivCrt.drawString(str.substring(from, idx), + ivCrt.toColPos(ivFldPos + from), ivCrt.toRowPos(ivFldPos + from), newAttr); + newAttr = ivCrt.getAttr(ivCrt.toColPos(ivFldPos + idx), ivCrt.toRowPos(ivFldPos + idx)); + ivCrt.drawString(String.valueOf(XI5250Crt.ATTRIBUTE_PLACE_HOLDER), + ivCrt.toColPos(ivFldPos + idx), ivCrt.toRowPos(ivFldPos + idx), newAttr); + from = idx + 1; + } + } + } + + + /** + * Used for example to write field contents to the 5250 stream. + * If needed some internal attribute can be exposed. + */ + public void saveTo(XI5250FieldSaver aSaver) throws IOException { + // no getTrimmedString() + aSaver.write(this, getString()); + } + + + /** + * Clear field to nulls. + */ + public void clear() { + char[] chs = new char[ivLength]; + for (int i = 0; i < chs.length; i++) + chs[i] = '\u0000'; + ivCrt.drawString(new String(chs), ivCol, ivRow, XI5250Crt.USE_PRESENT_ATTRIBUTE); + } + + + /** + * Changes the field contents. + */ + public void setString(String aStr) { + if (aStr == getTrimmedString()) + return; + + /* !!1.04e + ivCrt.drawString(aStr, ivCol, ivRow, XI5250Crt.USE_PRESENT_ATTRIBUTE); + setMDTOn(); + */ + + int s = ivCrt.toLinearPos(ivCol, ivRow); + char ch; + int col, row; + for (int i = 0; i < aStr.length() && i < ivInputLen; i++) { + ch = aStr.charAt(i); + col = ivCrt.toColPos(s + i); + row = ivCrt.toRowPos(s + i); + insertChar(ch, col, row, false, false); + } + } + + + /** + * Returns value of the field as String. + * NOTE: signed numeric are followed by sign char + */ + public String getString() { + String str = ivCrt.getString(ivCol, ivRow, ivLength); + + return str; + } + + + /** + * Returns value of the field as String, all trailing nulls and blankes are cutted off. + * NOTE: signed numeric are followed by sign char + */ + public String getTrimmedString() { + String str = getString(); + int i; + + // exclude trailing null and blank chars + for (i = str.length() - 1; (i >= 0) && ((str.charAt(i) == '\u0000') || + (str.charAt(i) == ' ')); i--) + ; + + return (i < 0) ? "" : str.substring(0, i + 1); + } + + + /** + * Returns the Field Format Word. + */ + public byte getFFW(int i) { + return ivFFW[i]; + } + + + /** + * Returns the Field Control Word. + */ + public byte getFCW(int i) { + return ivFCW[i]; + } + + + /** + * The field column position. + */ + public int getCol() { + return ivCol; + } + + + /** + * The field row position. + */ + public int getRow() { + return ivRow; + } + + + /** + * The field length. + */ + public int getLength() { + return ivLength; + } + + + /** + * Called every time the field contents changes. + * It fires the XI5250FieldEvent.VALUE_CHANGED event. + */ + protected void setMDTOn() { + ivFFW[0] |= 0x08; + processFieldEvent(new XI5250FieldEvent(XI5250FieldEvent.VALUE_CHANGED, this)); + } + + + /** + */ + public void resetMDT() { + ivFFW[0] &= ~0x08; + } + + + /** + * True if it was created as bypass field + */ + public boolean isOrgBypassField() { + return ((ivFFW[0] & 0x20) != 0); + } + + + /** + * True if it was created or it became a bypass field + * return (isOrgBypassField() || (!isEnabled()); + * @see #isEnabled() + */ + public boolean isBypassField() { + return (isOrgBypassField() || !isEnabled()); + } + + + /** + * Used to query Field Format Word flags. + */ + public boolean isDupEnabled() { + return ((ivFFW[0] & 0x10) != 0); + } + + + /** + * Used to query Field Format Word flags. + */ + public boolean isMDTOn() { + return ((ivFFW[0] & 0x08) != 0); + } + + + /** + * Used to query Field Format Word flags. + */ + public boolean isAlphabeticShift() { + return ((ivFFW[0] & 0x07) == 0); + } + + + /** + * Used to query Field Format Word flags. + */ + public boolean isAlphabeticOnly() { + return ((ivFFW[0] & 0x07) == 0x01); + } + + + /** + * Used to query Field Format Word flags. + */ + public boolean isNumericShift() { + return ((ivFFW[0] & 0x07) == 0x02); + } + + + /** + * Used to query Field Format Word flags. + */ + public boolean isNumericOnly() { + return ((ivFFW[0] & 0x07) == 0x03); + } + + + /** + * Used to query Field Format Word flags. + */ + public boolean isDigitsOnly() { + return ((ivFFW[0] & 0x07) == 0x05); + } + + + /** + * Used to query Field Format Word flags.
+ * Magnetic stripe reader, selector light pen, ... + */ + public boolean isIOOnly() { + return ((ivFFW[0] & 0x07) == 0x06); + } + + + /** + * Used to query Field Format Word flags. + */ + public boolean isSignedNumeric() { + return ((ivFFW[0] & 0x07) == 0x07); + } + + + /** + * Used to query Field Format Word flags. + */ + public boolean isAutoEnter() { + return ((ivFFW[1] & 0x80) != 0); + } + + + /** + * Used to query Field Format Word flags. + */ + public boolean isExitRequired() { + return ((ivFFW[1] & 0x40) != 0); + } + + + /** + * Used to query Field Format Word flags. + */ + public boolean isMonocase() { + return ((ivFFW[1] & 0x20) != 0); + } + + + /** + * Used to query Field Format Word flags. + */ + public boolean isMandatoryEnter() { + return ((ivFFW[1] & 0x08) != 0); + } + + + /** + * Used to query Field Format Word flags. + */ + public boolean isRightAdjustZeroFill() { + return ((ivFFW[1] & 0x07) == 0x05); + } + + + /** + * Used to query Field Format Word flags. + */ + public boolean isRightAdjustBlankFill() { + return ((ivFFW[1] & 0x07) == 0x06); + } + + + /** + * Used to query Field Format Word flags. + */ + public boolean isMandatoryFill() { + return ((ivFFW[1] & 0x07) == 0x07); + } + + + /** + * Key used to order fields in XI5250FieldsList. + * Simply returns the field linear position in the 5250 buffer. + */ + protected int getSortKey() { + return ivCrt.toLinearPos(ivCol, ivRow); + } + + + /** + */ + private void updateStr() { + ivStr = ivCrt.getString(ivCol, ivRow, ivInputLen); + //!!V se lunghezza stringa = 0 generare eccezione + ivFldPos = ivCrt.toLinearPos(ivCol, ivRow); + ivCurPos = ivCrt.toLinearPos(ivCrt.getCursorCol(), ivCrt.getCursorRow()); + ivPos = ivCurPos - ivFldPos; + } + + + /** + */ + protected void processKeyEvent(KeyEvent e) { + //!!1.04c + processFieldEvent(new XI5250FieldEvent(XI5250FieldEvent.KEY_EVENT, + this, e)); + + if (e.isConsumed()) + return; + + switch (e.getID()) { + // + case KeyEvent.KEY_TYPED: + if (XI5250Crt.isCharKey(e)) { + if (processKeyChar(e.getKeyChar())) + e.consume(); + } + break; + // + case KeyEvent.KEY_PRESSED: + if (processOtherKey(e)) + e.consume(); + break; + // + case KeyEvent.KEY_RELEASED: + ivCrt.ivDropKeyChar = false; + break; + } + } + + + /** + */ + protected int insertChar(char aCh, int col, int row, + boolean insert, boolean fromKeyboard) {//!!1.04 + if (isIOOnly() && fromKeyboard) { + return 4; // Do not accept keyboard input + } + + if ((isDigitsOnly() && !(aCh >= '0' && aCh <= '9'))) { + // 10 = only chars between 0 and 9 + return 10; + } + + if ((isSignedNumeric() && !(aCh >= '0' && aCh <= '9')) || + (isNumericOnly() && !((aCh >= '0' && aCh <= '9') || + aCh == ' ' || aCh == '+' || aCh == '-' || + aCh == '.' || aCh == ',')) + ) { + // 9 = numeric field + return 9; + } + + if (isMonocase()) + aCh = Character.toUpperCase(aCh); + + updateStr(); + + ivCurPos = ivCrt.toLinearPos(col, row); + ivPos = ivCurPos - ivFldPos; + + if (ivPos < 0 || ivPos >= ivLength) + throw new IllegalStateException(""); + + StringBuilder strBuf = new StringBuilder(ivStr); + + if (!insert) { + strBuf.setCharAt(ivPos, aCh); + + ivCrt.drawString(new String(strBuf).substring(ivPos, ivPos + 1), + col, row, ivAttr); + } + else { + if (strBuf.charAt(ivInputLen - 1) != '\u0000' && + strBuf.charAt(ivInputLen - 1) != ' ') { + // 12 = field is full + return 12; + } + else { + strBuf.insert(ivPos, aCh); + ivCrt.drawString(new String(strBuf).substring(ivPos, ivInputLen), + col, row, ivAttr); + } + } + + setMDTOn(); // field modified + return 0; + } + + + /** + */ + protected boolean processKeyChar(char aCh) { + if (ivCrt.ivDropKeyChar) { + ivCrt.ivDropKeyChar = false; + return true; + } + + int error = insertChar(aCh, ivCrt.getCursorCol(), ivCrt.getCursorRow(), + ivCrt.isInsertState(), true); + if (error > 0) { + ivCrt.userError(error); + return true; + } + + // is cursor on last char ?? + if (ivPos < (ivInputLen - 1)) + ivCrt.moveCursor(1, 0); + else { + // send auto enter (-1 as modifier) see XI5250Emulator.processKeyEnter() + if (isAutoEnter()) + ivCrt.doProcessKeyEvent(new KeyEvent(ivCrt, KeyEvent.KEY_PRESSED, 0, + -1, KeyEvent.VK_ENTER, (char)KeyEvent.VK_ENTER)); + // send auto tab + else if (!isExitRequired()) + ivCrt.doProcessKeyEvent(new KeyEvent(ivCrt, KeyEvent.KEY_PRESSED, 0, 0, + KeyEvent.VK_TAB, (char)KeyEvent.VK_TAB)); + } + + return true; + } + /*!!1.04 + protected boolean processKeyChar(char aCh) { + if (ivCrt.ivDropKeyChar) { + ivCrt.ivDropKeyChar = false; + return true; + } + + if ((isDigitsOnly() && !(aCh >= '0' && aCh <= '9'))) { + // 10 = only chars between 0 and 9 + ivCrt.userError(10); + return true; + } + + if ((isSignedNumeric() && !(aCh >= '0' && aCh <= '9')) || + (isNumericOnly() && !((aCh >= '0' && aCh <= '9') || + aCh == ' ' || aCh == '+' || aCh == '-' || + aCh == '.' || aCh == ',')) + ) { + // 9 = numeric field + ivCrt.userError(9); + return true; + } + + if (isMonocase()) + aCh = Character.toUpperCase(aCh); + + updateStr(); + StringBuilder strBuf = new StringBuilder(ivStr); + + if (!ivCrt.isInsertState()) { + strBuf.setCharAt(ivPos, aCh); + + ivCrt.drawString(new String(strBuf).substring(ivPos, ivPos + 1), + ivCrt.getCursorCol(), ivCrt.getCursorRow(), ivAttr); + } + else { + if (strBuf.charAt(ivInputLen - 1) != '\u0000' && + strBuf.charAt(ivInputLen - 1) != ' ') { + // 12 = field is full + ivCrt.userError(12); + return true; + } + else { + strBuf.insert(ivPos, aCh); + ivCrt.drawString(new String(strBuf).substring(ivPos, ivInputLen), + ivCrt.getCursorCol(), ivCrt.getCursorRow(), ivAttr); + } + } + + setMDTOn(); // field modified + + // is cursor on last char ?? + if (ivPos < (ivInputLen - 1)) + ivCrt.moveCursor(1, 0); + else { + // send auto enter (-1 as modifier) + if (isAutoEnter()) + ivCrt.doProcessKeyEvent(new KeyEvent(ivCrt, KeyEvent.KEY_PRESSED, 0, + -1, KeyEvent.VK_ENTER)); + // send auto tab + else if (!isExitRequired()) + ivCrt.doProcessKeyEvent(new KeyEvent(ivCrt, KeyEvent.KEY_PRESSED, 0, 0, + KeyEvent.VK_TAB)); + } + + return true; + } + */ + + + /** + */ + protected boolean processOtherKey(KeyEvent e) { + switch (e.getKeyCode()) { + case KeyEvent.VK_BACK_SPACE: + return processBackSpace(e.getModifiers()); + // + case KeyEvent.VK_DELETE: + return processDelete(e.getModifiers()); + // + case KeyEvent.VK_ADD: + ivCrt.ivDropKeyChar = true; + doFieldExit(false); + return true; + // + case KeyEvent.VK_SUBTRACT: + ivCrt.ivDropKeyChar = true; + if (isNumericOnly() || isSignedNumeric()) { + doFieldExit(true); + return true; + } + // 16 = field- not valid + ivCrt.userError(16); + return true; + // + case KeyEvent.VK_ENTER: + return processEnter(e.getModifiers()); + // + case KeyEvent.VK_END: + return processEnd(e.getModifiers()); + } + return false; + } + + + /** + */ + protected boolean processBackSpace(int aModifier) { + switch (aModifier) { + case 0: + updateStr(); + if (ivPos == 0) { + ivCrt.doProcessKeyEvent(new KeyEvent(ivCrt, KeyEvent.KEY_PRESSED, 0, KeyEvent.SHIFT_MASK, + KeyEvent.VK_TAB, (char)KeyEvent.VK_TAB)); + } + else { + ivCrt.moveCursor(-1, 0); + } + return true; + case KeyEvent.SHIFT_MASK: + updateStr(); + if (ivPos == 0) { + } + else { + ivCrt.moveCursor(-1, 0); + updateStr(); + StringBuilder strBuf = new StringBuilder(ivStr); + for (int i = ivPos + 1; i < ivStr.length(); i++) + strBuf.setCharAt(i - 1, strBuf.charAt(i)); + strBuf.setCharAt(ivStr.length() - 1, '\u0000'); + + ivCrt.drawString(new String(strBuf).substring(ivPos), + ivCrt.getCursorCol(), ivCrt.getCursorRow(), ivAttr); + + setMDTOn(); // field modified + } + return true; + } + return false; + } + + + /** + */ + protected boolean processDelete(int aModifier) { + switch (aModifier) { + case 0: + updateStr(); + StringBuilder strBuf = new StringBuilder(ivStr); + for (int i = ivPos + 1; i < ivStr.length(); i++) + strBuf.setCharAt(i - 1, strBuf.charAt(i)); + strBuf.setCharAt(ivStr.length() - 1, '\u0000'); + + ivCrt.drawString(new String(strBuf).substring(ivPos), + ivCrt.getCursorCol(), ivCrt.getCursorRow(), ivAttr); + + setMDTOn(); // field modified + return true; + } + return false; + } + + + /** + */ + protected boolean processEnter(int aModifier) { + switch (aModifier) { + case KeyEvent.SHIFT_MASK: + doFieldExit(false); + return true; + } + return false; + } + + + /** + */ + private void doFieldExit(boolean isMinus) { + XIEbcdicTranslator translator = getCrt().getTranslator(); + + updateStr(); + StringBuilder strBuf = new StringBuilder(ivStr); + + for (int i = ivPos; i < ivStr.length(); i++) + strBuf.setCharAt(i, '\u0000'); + + for ( ; ivPos > 0 && strBuf.charAt(ivPos - 1) == '\u0000'; ivPos--) + ; + + // see IBM 5250 function reference manual page 2-70 + if (isNumericOnly()) { + if (isMinus && ivPos > 0) { + char ch = strBuf.charAt(ivPos - 1); + if (ch != '+' && ch != '-' && ch != '.' && ch != ',' && ch != ' ') { + byte xx = translator.toEBCDIC(strBuf.charAt(ivPos - 1)); + xx &= 0x0F; + xx |= 0xD0; + strBuf.setCharAt(ivPos - 1, translator.toChar(xx)); + } + else { + ivCrt.userError(26); + return ; + } + } + } + + if (isRightAdjustZeroFill() || isRightAdjustBlankFill() || + isSignedNumeric()) { + int i; + + // right allign + for (i = 0; i < ivPos; i++) + strBuf.setCharAt(ivStr.length() - i - 1, strBuf.charAt(ivPos - i - 1)); + + for (i = ivStr.length() - ivPos - 1; i >= 0; i--) + strBuf.setCharAt(i, (isRightAdjustZeroFill()) ? '0' : ' '); + + String str = new String(strBuf); + + // see IBM 5250 function reference manual page 2-70 + if (isSignedNumeric()) + str += (isMinus) ? '-' : '\u0000'; + + ivCrt.drawString(str, ivCol, ivRow, ivAttr); + + } + else { + ivCrt.drawString(new String(strBuf).substring(ivPos), + ivCrt.getCursorCol(), ivCrt.getCursorRow(), ivAttr); + } + + setMDTOn(); // field modified + + // send tab + ivCrt.doProcessKeyEvent(new KeyEvent(ivCrt, KeyEvent.KEY_PRESSED, 0, 0, + KeyEvent.VK_TAB, (char)KeyEvent.VK_TAB)); + } + + + /** + */ + protected boolean processEnd(int aModifier) { + switch (aModifier) { + case 0: + int i; + updateStr(); + for (i = ivStr.length() - 1; (i >= 0) && (ivStr.charAt(i) <= ' '); i--) + ; + int xx = ivCrt.toLinearPos(ivCol, ivRow) + Math.min(i + 1, ivInputLen - 1); + ivCrt.setCursorPos(ivCrt.toColPos(xx), ivCrt.toRowPos(xx)); + return true; + case KeyEvent.SHIFT_MASK: + updateStr(); + StringBuilder strBuf = new StringBuilder(ivStr); + for (int j = ivPos; j < ivStr.length(); j++) + strBuf.setCharAt(j, '\u0000'); + + ivCrt.drawString(new String(strBuf).substring(ivPos), + ivCrt.getCursorCol(), ivCrt.getCursorRow(), ivAttr); + + setMDTOn(); // field modified + return true; + } + return false; + } + + + /** + * Returns the number of rows occupied by this field + * NOTE: a field can be wrapped on more than one line + */ + public int getNRows() { + return ((ivCol + ivLength - 1) / ivCrt.getCrtSize().width + 1); //!!1.03c + } + + + /** + * Returns the bounding rectangle (in pixel). + */ + public Rectangle getBoundingRect() { + Dimension charSize = ivCrt.getCharSize(); + int rows = getNRows(); + + if (rows <= 1) + return new Rectangle(ivCol * charSize.width, + ivRow * charSize.height, + ivLength * charSize.width, + rows * charSize.height); + else + return new Rectangle(0 * charSize.width, + ivRow * charSize.height, + //!!1.04c ivCrt.getSize().width, + ivCrt.getCrtBufferSize().width, + rows * charSize.height); + } + + + /** + * Returns all the rows occupied by the fields. + * NOTE: coordinates are expressed in chars. + */ + public Rectangle[] getRows() { + int rows = getNRows(); + //Dimension charSize = ivCrt.getCharSize(); + Rectangle[] rcts = new Rectangle[rows]; + + // split line to handle wrap + int len = ivLength; + int x = ivCol; + int y = ivRow; + int dx; + int i = 0; + + while (len > 0) { + dx = Math.min(ivCrt.getCrtSize().width - x, len); + + rcts[i++] = new Rectangle(x, y, dx, 1); + + len -= dx; + x = 0; + ++y; + } + + return rcts; + } + + + /** + * Returns all the rectangles that the field is composed of. + * NOTE: coordinates are expressed in pixel and are relative to XI5250Crt panel. + */ + public Rectangle[] getRowsRects() { + Rectangle[] rcts = getRows(); + + for (int i = 0; i < rcts.length; i++) + rcts[i] = ivCrt.toPoints(rcts[i].x, rcts[i].y, rcts[i].width, rcts[i].height); + + return rcts; + } + + + /** + * Repaint the field. + */ + public void repaint() { + Rectangle rt = getBoundingRect(); + ivCrt.repaint(rt.x, rt.y, rt.width, rt.height); + } + + + /** + * Coordinates are relative to the field bounding rectangle + */ + protected void paint(Graphics g) { + processFieldPaintEvent( + new XI5250FieldPaintEvent(XI5250FieldPaintEvent.ROW_PAINT, + this, g)); + + Rectangle clip = g.getClipBounds(); + if (clip == null) + return; + + Rectangle[] rowsRects = getRowsRects(); + + // request a paint for each row + for (int j = 0; j < rowsRects.length; j++) { + Rectangle fr = new Rectangle(rowsRects[j]); + // coord relative to field bounding rect position + fr.translate(-getBoundingRect().x, -getBoundingRect().y); + + if (clip.intersects(fr)) { + Graphics fg = g.create(); + // set new clipping rectangle, but do not translate origin + fg.clipRect(fr.x, fr.y, fr.width, fr.height); + try { + rowPaint(fg); + } + finally { + fg.dispose(); + } + } + } + + if (!isOrgBypassField()) + drawBorder(g); + } + + + /** + * Draws the field borders (a field can be splitted on more than one crt + * line). + */ + protected void drawBorder(Graphics g) { + int borderStyle = getUsedBorderStyle(); + if (borderStyle <= NO_BORDER) + return; + + Rectangle[] rowsRects = getRowsRects(); + + for (int i = 0; i < rowsRects.length; i++) + rowsRects[i].translate(-getBoundingRect().x, -getBoundingRect().y); + + Color bg = getCrt().getDefBackground(); + Color cl1, cl2; + if (isCurrentField()) { + cl1 = (borderStyle == RAISED_BORDER) ? bg.darker().darker().darker() : + bg.darker(); + cl2 = (borderStyle == RAISED_BORDER) ? bg.darker() : + bg.darker().darker().darker(); + } + else { + cl1 = (borderStyle == RAISED_BORDER) ? bg.darker() : + bg; + cl2 = (borderStyle == RAISED_BORDER) ? bg : + bg.darker(); + } + + switch (rowsRects.length) { + // + case 0: + break; + // + case 1: + g.setColor(cl1); + g.drawLine(rowsRects[0].x, + rowsRects[0].y, + rowsRects[0].x, + rowsRects[0].y + rowsRects[0].height - 1); + g.drawLine(rowsRects[0].x, + rowsRects[0].y, + rowsRects[0].x + rowsRects[0].width - 1, + rowsRects[0].y); + + g.setColor(cl2); + g.drawLine(rowsRects[0].x + rowsRects[0].width - 1, + rowsRects[0].y, + rowsRects[0].x + rowsRects[0].width - 1, + rowsRects[0].y + rowsRects[0].height - 1); + g.drawLine(rowsRects[0].x, + rowsRects[0].y + rowsRects[0].height - 1, + rowsRects[0].x + rowsRects[0].width - 1, + rowsRects[0].y + rowsRects[0].height - 1); + break; + // + case 2: + int dx = Math.max(0, (rowsRects[1].x + rowsRects[1].width - 1) - rowsRects[0].x); + + g.setColor(cl1); + g.drawLine(rowsRects[0].x, + rowsRects[0].y, + rowsRects[0].x, + rowsRects[0].y + rowsRects[0].height - 1); + g.drawLine(rowsRects[0].x, + rowsRects[0].y, + rowsRects[0].x + rowsRects[0].width - 1, + rowsRects[0].y); + + g.drawLine(rowsRects[1].x, + rowsRects[1].y, + rowsRects[1].x + rowsRects[1].width - 1 - dx, + rowsRects[1].y); + + g.setColor(cl2); + g.drawLine(rowsRects[1].x + rowsRects[1].width - 1, + rowsRects[1].y, + rowsRects[1].x + rowsRects[1].width - 1, + rowsRects[1].y + rowsRects[1].height - 1); + g.drawLine(rowsRects[1].x, + rowsRects[1].y + rowsRects[1].height - 1, + rowsRects[1].x + rowsRects[1].width - 1, + rowsRects[1].y + rowsRects[1].height - 1); + + g.drawLine(rowsRects[0].x + dx, + rowsRects[0].y + rowsRects[0].height - 1, + rowsRects[0].x + rowsRects[0].width - 1, + rowsRects[0].y + rowsRects[0].height - 1); + break; + // + default: + int l = rowsRects.length - 1; + + g.setColor(cl1); + g.drawLine(rowsRects[0].x, + rowsRects[0].y, + rowsRects[0].x, + rowsRects[0].y + rowsRects[0].height - 1); + g.drawLine(rowsRects[0].x, + rowsRects[0].y, + rowsRects[0].x + rowsRects[0].width - 1, + rowsRects[0].y); + + g.drawLine(rowsRects[1].x, + rowsRects[0].y + rowsRects[0].height - 1, + rowsRects[0].x, + rowsRects[0].y + rowsRects[0].height - 1); + + g.setColor(cl2); + g.drawLine(rowsRects[l].x + rowsRects[l].width - 1, + rowsRects[l].y, + rowsRects[l].x + rowsRects[l].width - 1, + rowsRects[l].y + rowsRects[l].height - 1); + g.drawLine(rowsRects[l].x, + rowsRects[l].y + rowsRects[l].height - 1, + rowsRects[l].x + rowsRects[l].width - 1, + rowsRects[l].y + rowsRects[l].height - 1); + + g.drawLine(rowsRects[l].x + rowsRects[l].width - 1, + rowsRects[l - 1].y + rowsRects[l - 1].height - 1, + rowsRects[l - 1].x + rowsRects[l - 1].width - 1, + rowsRects[l - 1].y + rowsRects[l - 1].height - 1); + break; + } + } + + + /** + * Called for each rectangle returned by getRowsRects. + * Coordinates are relative to the field bounding rectangle. + * @see #getRowsRects + */ + protected void rowPaint(Graphics g) { + processFieldPaintEvent(new XI5250FieldPaintEvent(XI5250FieldPaintEvent.ROW_PAINT, + this, g)); + if (!ivEnabled) { + Rectangle rt = getBoundingRect(); + g.setColor(Color.white); + + int hh = rt.height; + for (int x = -hh; x < rt.width; x += 8) + g.drawLine(x, hh, x + hh, 0); + } + } + + + /** + * Field has changed its dimensions. + */ + protected void resized() { + } + + + /** + * Field has changed its activated (focus) state. + */ + protected void activated(boolean activated) { + repaint(); //!!1.15 + processFieldEvent(new XI5250FieldEvent((activated) ? XI5250FieldEvent.ACTIVATED : + XI5250FieldEvent.DEACTIVATED, + this)); + + } + + + /** + */ + public final boolean isCurrentField() { + return ivCrt.getCurrentField() == this; + } + + + /** + * Enable or disable the field. + */ + public void setEnabled(boolean flag) { + if (flag == ivEnabled) + return; + ivEnabled = flag; + repaint(); + processFieldEvent( + new XI5250FieldEvent(XI5250FieldEvent.ENABLED_STATE_CHANGED, this)); + } + + + /** + */ + public boolean isEnabled() { + return ivEnabled; + } + + + /** + * Changes the field border style. + */ + public void setBorderStyle(int aStyle) { + if (aStyle == ivBorderStyle) + return; + + if (aStyle < DEFAULT_BORDER || aStyle > LOWERED_BORDER) + throw new IllegalArgumentException("Wrong border style argument"); + + ivBorderStyle = aStyle; + repaint(); + } + + + /** + * @see #getUsedBorderStyle + */ + public int getBorderStyle() { + return ivBorderStyle; + } + + + /** + * Returns the real used border style. + * It takes care of the default border style defined with + * XI5250Crt.setDefFieldsBorderStyle + * @see XI5250Crt#setDefFieldsBorderStyle + */ + public int getUsedBorderStyle() { + int style = getBorderStyle(); + return (style != DEFAULT_BORDER) ? style : ivCrt.getDefFieldsBorderStyle(); + } + + + /** + */ + @Override + public String toString() { + return super.toString() + " [FFW=[" + XITelnet.toHex(ivFFW[0]) + "," + + XITelnet.toHex(ivFFW[1]) + "]," + + "FCW=[" + XITelnet.toHex(ivFCW[0]) + "," + + XITelnet.toHex(ivFCW[1]) + "]," + + "Attr=" + XITelnet.toHex((byte)ivAttr) + "," + + "(" + ivCol + "," + ivRow + ")" + + "Len=" + ivLength + "]"; + } + + + ////////////////////////////////////////////////////////////////////////////// + + /** + * Multicast Listener for XI5250Field + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ + private static class Multicaster extends AWTEventMulticaster + implements XI5250FieldListener, + XI5250FieldPaintListener { + + + protected Multicaster(EventListener a, EventListener b) { + super(a, b); + } + + + //!!1.03a + @Override + protected EventListener remove(EventListener oldl) { + if (oldl == a) return b; + if (oldl == b) return a; + EventListener a2 = removeInternal(a, oldl); + EventListener b2 = removeInternal(b, oldl); + if (a2 == a && b2 == b) + return this; + return add(a2, b2); + } + + + public static EventListener add(EventListener a, EventListener b) { + if (a == null) return b; + if (b == null) return a; + return new Multicaster(a, b); + } + + + public static EventListener remove(EventListener a, EventListener b) { + return removeInternal(a, b); + } + + + /** + */ + public void activated(XI5250FieldEvent e) { + ((XI5250FieldListener)a).activated(e); + ((XI5250FieldListener)b).activated(e); + } + + + public void deactivated(XI5250FieldEvent e) { + ((XI5250FieldListener)a).deactivated(e); + ((XI5250FieldListener)b).deactivated(e); + } + + + public void valueChanged(XI5250FieldEvent e) { + ((XI5250FieldListener)a).valueChanged(e); + ((XI5250FieldListener)b).valueChanged(e); + } + + + public void enabledStateChanged(XI5250FieldEvent e) { + ((XI5250FieldListener)a).enabledStateChanged(e); + ((XI5250FieldListener)b).enabledStateChanged(e); + } + + + public void keyEvent(XI5250FieldEvent e) { + ((XI5250FieldListener)a).keyEvent(e); + ((XI5250FieldListener)b).keyEvent(e); + } + + + /** + */ + public void fieldPaint(XI5250FieldPaintEvent e) { + ((XI5250FieldPaintListener)a).fieldPaint(e); + ((XI5250FieldPaintListener)b).fieldPaint(e); + } + + + public void rowPaint(XI5250FieldPaintEvent e) { + ((XI5250FieldPaintListener)a).rowPaint(e); + ((XI5250FieldPaintListener)b).rowPaint(e); + } + } +} diff --git a/net/infordata/em/crt5250/XI5250FieldAdapter.java b/net/infordata/em/crt5250/XI5250FieldAdapter.java new file mode 100644 index 0000000..0591935 --- /dev/null +++ b/net/infordata/em/crt5250/XI5250FieldAdapter.java @@ -0,0 +1,67 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 14/05/97 rel. 0.96d- removed SIZE_CHANGED. + 27/05/97 rel. 1.00 - first release. + 03/03/98 rel. _.___- SWING and reorganization. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.crt5250; + + +/** + * XI5250FieldListener adapter. + * @see XI5250FieldListener + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XI5250FieldAdapter implements XI5250FieldListener { + + + /** + */ + public void activated(XI5250FieldEvent e) { + } + + + /** + */ + public void deactivated(XI5250FieldEvent e) { + } + + + /** + */ + public void valueChanged(XI5250FieldEvent e) { + } + + + /** + */ + public void enabledStateChanged(XI5250FieldEvent e) { + } + + + /** + */ + public void keyEvent(XI5250FieldEvent e) { + } +} \ No newline at end of file diff --git a/net/infordata/em/crt5250/XI5250FieldEvent.java b/net/infordata/em/crt5250/XI5250FieldEvent.java new file mode 100644 index 0000000..7af49f1 --- /dev/null +++ b/net/infordata/em/crt5250/XI5250FieldEvent.java @@ -0,0 +1,118 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 14/05/97 rel. 0.96d- removed SIZE_CHANGED. + 27/05/97 rel. 1.00 - first release. + 03/03/98 rel. _.___- SWING and reorganization. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.crt5250; + + +import java.awt.event.KeyEvent; +import java.util.EventObject; + + +/** + * XI5250Field notification event. + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XI5250FieldEvent extends EventObject { + + + private static final long serialVersionUID = 1L; + + /** + * The field has been activated (ie. the cursor enters the field area) + */ + public static final int ACTIVATED = 0; + /** + * The field has been deactivated (ie. the cursor exits the field area) + */ + public static final int DEACTIVATED = 1; + /** + * The field value has been changed. + */ + public static final int VALUE_CHANGED = 2; + /** + * The field enabled state has changed. + */ + public static final int ENABLED_STATE_CHANGED = 3; + /** + */ + public static final int KEY_EVENT = 4; + + + private static final String[] cvIdDescr = {"ACTIVATED", + "DEACTIVATED", + "VALUE_CHANGED", + "ENABLED_STATE_CHANGED", + "KEY_EVENT"}; + + private int ivId; + private KeyEvent ivKeyEvent; + + + /** + */ + public XI5250FieldEvent(int aId, XI5250Field aField) { + super(aField); + ivId = aId; + } + + + /** + */ + public XI5250FieldEvent(int aId, XI5250Field aField, KeyEvent ke) { + this(aId, aField); + ivKeyEvent = ke; + } + + + /** + */ + public final int getID() { + return ivId; + } + + + /** + */ + public final XI5250Field getField() { + return (XI5250Field)getSource(); + } + + + /** + */ + public final KeyEvent getKeyEvent() { + return ivKeyEvent; + } + + + /** + */ + @Override + public String toString() { + return super.toString() + "[" + cvIdDescr[ivId] + "," + getSource() + "]"; + } +} \ No newline at end of file diff --git a/net/infordata/em/crt5250/XI5250FieldListener.java b/net/infordata/em/crt5250/XI5250FieldListener.java new file mode 100644 index 0000000..9583aeb --- /dev/null +++ b/net/infordata/em/crt5250/XI5250FieldListener.java @@ -0,0 +1,68 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 14/05/97 rel. 0.96d- removed SIZE_CHANGED. + 27/05/97 rel. 1.00 - first release. + 03/03/98 rel. _.___- SWING and reorganization. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.crt5250; + + +import java.util.EventListener; + + +/** + * Listener for XI5250FieldEvent. + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public interface XI5250FieldListener extends EventListener { + /** + * Input cursor enters in the field area + */ + public void activated(XI5250FieldEvent e); + + + /** + * Input cursor exits from the input area + */ + public void deactivated(XI5250FieldEvent e); + + + /** + * Field value is changed + */ + public void valueChanged(XI5250FieldEvent e); + + + /** + * Field enabled state is changed using setEnabled method + * @see XI5250Field#setEnabled + * @see XI5250Field#isEnabled + */ + public void enabledStateChanged(XI5250FieldEvent e); + + + /** + */ + public void keyEvent(XI5250FieldEvent e); +} \ No newline at end of file diff --git a/net/infordata/em/crt5250/XI5250FieldPaintAdapter.java b/net/infordata/em/crt5250/XI5250FieldPaintAdapter.java new file mode 100644 index 0000000..832450c --- /dev/null +++ b/net/infordata/em/crt5250/XI5250FieldPaintAdapter.java @@ -0,0 +1,45 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 27/05/97 rel. 1.00 - first release. + 03/03/98 rel. _.___- SWING and reorganization. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.crt5250; + + +/** + * XI5250FieldPaintListener adapter. + * @see XI5250FieldPaintListener + */ +public class XI5250FieldPaintAdapter implements XI5250FieldPaintListener { + + + /** + */ + public void fieldPaint(XI5250FieldPaintEvent e) { + } + + + /** + */ + public void rowPaint(XI5250FieldPaintEvent e) { + } +} \ No newline at end of file diff --git a/net/infordata/em/crt5250/XI5250FieldPaintEvent.java b/net/infordata/em/crt5250/XI5250FieldPaintEvent.java new file mode 100644 index 0000000..a85fac2 --- /dev/null +++ b/net/infordata/em/crt5250/XI5250FieldPaintEvent.java @@ -0,0 +1,95 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 27/05/97 rel. 1.00 - first release. + 03/03/98 rel. _.___- SWING and reorganization. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.crt5250; + + +import java.awt.Graphics; +import java.util.EventObject; + + +/** + * XI5250Field painting event. + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XI5250FieldPaintEvent extends EventObject { + + private static final long serialVersionUID = 1L; + + /** + * Paint at field level can be added. + */ + public static final int FIELD_PAINT = 0; + /** + * Paint at field singol row level can be added. + */ + public static final int ROW_PAINT = 1; + + private static final String[] cvIdDescr = {"FIELD_PAINT", + "ROW_PAINT"}; + + private int ivId; + private Graphics ivGr; + + + /** + */ + public XI5250FieldPaintEvent(int aId, XI5250Field aField, Graphics aGr) { + super(aField); + ivId = aId; + ivGr = aGr; + } + + + /** + */ + public int getID() { + return ivId; + } + + + /** + * Returns the Graphics that can be used to paint. + */ + public Graphics getGraphics() { + return ivGr; + } + + + /** + */ + public XI5250Field getField() { + return (XI5250Field)getSource(); + } + + + /** + */ + @Override + public String toString() { + return super.toString() + "[" + cvIdDescr[ivId] + "," + getSource() + "]"; + } +} \ No newline at end of file diff --git a/net/infordata/em/crt5250/XI5250FieldPaintListener.java b/net/infordata/em/crt5250/XI5250FieldPaintListener.java new file mode 100644 index 0000000..5fa6a5d --- /dev/null +++ b/net/infordata/em/crt5250/XI5250FieldPaintListener.java @@ -0,0 +1,55 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 27/05/97 rel. 1.00 - first release. + 03/03/98 rel. _.___- SWING and reorganization. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.crt5250; + + +import java.util.EventListener; + + +/** + * Usefull to add some paint over a field. + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public interface XI5250FieldPaintListener extends EventListener { + + + /** + * One event for paint, the bounding rectangle is setted as the clip region. + * Coordinate are relative to the field bounding rectangle + * @see XI5250Field#getBoundingRect + */ + public void fieldPaint(XI5250FieldPaintEvent e); + + + /** + * One event for each row that makes up the field + * (a field can be splitted over multiple rows) + * Coordinate are relative to the field bounding rectangle + * @see XI5250Field#getRowsRects + */ + public void rowPaint(XI5250FieldPaintEvent e); +} \ No newline at end of file diff --git a/net/infordata/em/crt5250/XI5250FieldSaver.java b/net/infordata/em/crt5250/XI5250FieldSaver.java new file mode 100644 index 0000000..60d65bb --- /dev/null +++ b/net/infordata/em/crt5250/XI5250FieldSaver.java @@ -0,0 +1,44 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + 03/03/98 rel. _.___- SWING and reorganization. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.crt5250; + + +import java.io.IOException; + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Interface that must be implemented to save XI5250 field status. + * + * @see XI5250Field#saveTo + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public interface XI5250FieldSaver { + /** + * + */ + public void write(XI5250Field aField, String aStr) throws IOException; +} \ No newline at end of file diff --git a/net/infordata/em/crt5250/XI5250FieldsList.java b/net/infordata/em/crt5250/XI5250FieldsList.java new file mode 100644 index 0000000..b7a5a37 --- /dev/null +++ b/net/infordata/em/crt5250/XI5250FieldsList.java @@ -0,0 +1,310 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 27/05/97 rel. 1.00 - first release. + 03/03/98 rel. _.___- SWING and reorganization. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.crt5250; + + +import java.awt.Graphics; +import java.awt.Rectangle; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + + + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * It is used by XI5250Crt to handle the XI5250Field collection. + * + * @see XI5250Crt + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XI5250FieldsList implements XI5250BaseField, Cloneable { + private XI5250Crt ivCrt; + private ArrayList ivFields = new ArrayList(40); + private List ivROFields = Collections.unmodifiableList(ivFields); + + /** + */ + public XI5250FieldsList(XI5250Crt aCrt) { + ivCrt = aCrt; + } + + + /** + * Returns a cloned XI5250FieldList + */ + @Override + @SuppressWarnings("unchecked") + public Object clone() { + try { + XI5250FieldsList aClone = (XI5250FieldsList)super.clone(); + // non clono singoli campi perchè vengono sempre ricreati da 0 e mai modificati + aClone.ivFields = (ArrayList)ivFields.clone(); + aClone.ivROFields = Collections.unmodifiableList(aClone.ivFields); + return aClone; + } + catch (CloneNotSupportedException e) { + throw new InternalError(); + } + } + + + /** + * Calls init for each field it owns. + * @see XI5250Field#init + */ + public void init() { + for (int i = 0; i < ivFields.size(); i++) + ivFields.get(i).init(); + } + + + /** + * Calls removeNotify for each field it owns. + */ + public void removeNotify() { + for (int i = 0; i < ivFields.size(); i++) + ivFields.get(i).removeNotify(); + } + + + /** + * Calls saveTo for each field it owns. + * @see XI5250Field#saveTo + */ + public void saveTo(XI5250FieldSaver aSaver) throws IOException { + for (int i = 0; i < ivFields.size(); i++) + ivFields.get(i).saveTo(aSaver); + } + + + /** + * Calls resized for each field it owns. + * @see XI5250Field#resized + */ + public void resized() { + for (int i = 0; i < ivFields.size(); i++) + ivFields.get(i).resized(); + } + + + /** + * Lets fields paint themselves. + */ + public void paint(Graphics g) { + XI5250Field field = null; + Rectangle clip = g.getClipBounds(); + + for (int i = 0; i < ivFields.size(); i++) { + field = ivFields.get(i); + Rectangle fr = field.getBoundingRect(); + + if (clip.intersects(fr)) { + Graphics fg = g.create(fr.x, fr.y, fr.width, fr.height); + try { + field.paint(fg); + } + finally { + fg.dispose(); + } + } + } + } + + + /** + * Ricerca campo che inizia da tale posizione, se non lo trova + * ritorna un numero negativo che trasformandolo con la formula + * idx = (-idx) - 1 indica la posizione nel vettore dove dovrebbe + * essere inserito + */ + private int searchField(int aCol, int aRow) { + int kk = ivCrt.toLinearPos(aCol, aRow); + int min = 0; + int max = ivFields.size(); + int med = (max + min) / 2; + XI5250Field field; + // ricerca binaria + while ((med < ivFields.size()) && (min <= max)) { + field = ivFields.get(med); + if (field.getSortKey() == kk) + return med; + else if (field.getSortKey() > kk) + max = med - 1; + else + min = med + 1; + + med = (max + min) / 2; + } + // non esiste quindi + return -(min + 1); + } + + + /** + * Adds a field to the fields collection. + */ + public void addField(XI5250Field aField) { + /* + // !!V già presente in quella posizione, oppure overlapping, + // sollevare una eccezione invece di return ?? + if (fieldFromPos(aField.ivCol, aField.ivRow) != null) + return; + */ + + // !!V già presente in quella posizione, oppure overlapping, + // viene sostituito il campo + XI5250Field field = fieldFromPos(aField.getCol(), aField.getRow()); + if (field != null) { + ivFields.set(fromFieldToIdx(field), aField); + } + else { + int idx = searchField(aField.getCol(), aField.getRow()); + idx = (-idx) - 1; + ivFields.add(idx, aField); + } + } + + + /** + * Campo presente in tale posizione oppure precedente + */ + private XI5250Field prevFieldFromPosInternal(int aCol, int aRow) { + int idx = searchField(aCol, aRow); + if (idx >= 0) + return ivFields.get(idx); + + idx = (-idx) - 1; + + if (idx == 0) + return null; + + // accedo al precedente + return ivFields.get(idx - 1); + } + + + /** + * Ritorna indice del campo + */ + protected int fromFieldToIdx(XI5250Field aField) { + XI5250Field field; + int i = 0; + for (Iterator e = ivFields.iterator(); e.hasNext(); i++) { + field = e.next(); + if (field == aField) + return i; + } + return -1; + } + + + /** + * Returns the field present in the given position, null if none. + */ + public XI5250Field fieldFromPos(int aCol, int aRow) { + // accedo al precedente + XI5250Field field = prevFieldFromPosInternal(aCol, aRow); + if (field == null) + return null; + + int kk = ivCrt.toLinearPos(aCol, aRow); + int fk = field.getSortKey(); + // verifico che posizione sia sul campo + if ((kk >= fk) && (kk < (fk + field.getLength()))) + return field; + else + return null; + } + + + /** + */ + public XI5250Field nextFieldFromPos(int aCol, int aRow) { + if (ivFields.isEmpty()) + return null; + // accedo al precedente + XI5250Field field = prevFieldFromPosInternal(aCol, aRow); + if (field == null || field == ivFields.get(ivFields.size() - 1)) + return ((!ivFields.isEmpty()) ? ivFields.get(0) : + null); + + int idx = fromFieldToIdx(field); + return ivFields.get(idx + 1); + } + + + /** + */ + public XI5250Field prevFieldFromPos(int aCol, int aRow) { + if (ivFields.isEmpty()) + return null; + XI5250Field field = fieldFromPos(aCol, aRow); + // caso cursore sul campo + if (field != null) { + if (field == ivFields.get(0)) + return ivFields.get(ivFields.size() - 1); + + int idx = fromFieldToIdx(field); + idx = (idx == 0) ? (ivFields.size() - 1) : idx - 1; + return ivFields.get(idx); + } + + // caso cursore non sul campo + // accedo al precedente + field = prevFieldFromPosInternal(aCol, aRow); + if (field == null) + return ((!ivFields.isEmpty()) ? ivFields.get(ivFields.size() - 1) : null); + + return field; + } + + + /** + */ + public List getFields() { + return ivROFields; + } + + + /** + * Returns the field at the given index (null if none). + * Fields enumeration is based on their linear buffer position. + */ + public XI5250Field getField(int idx) { + try { + return (XI5250Field)ivFields.get(idx); + } + catch (ArrayIndexOutOfBoundsException ex) { + return null; + } + } +} \ No newline at end of file diff --git a/net/infordata/em/crt5250/XIEbcdicNTranslator.java b/net/infordata/em/crt5250/XIEbcdicNTranslator.java new file mode 100644 index 0000000..0f9099a --- /dev/null +++ b/net/infordata/em/crt5250/XIEbcdicNTranslator.java @@ -0,0 +1,1070 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 10/04/97 rel. 0.93 - moved to crt5250 package. + 16/04/97 rel. 0.94 - toPacked method added. + 28/04/97 rel. 0.94c- corrected problem with underscore. + 27/05/97 rel. 1.00 - first release. + 25/07/97 rel. 1.03a- '|' char mapping. + 03/03/98 rel. _.___- SWING and reorganization. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.crt5250; + + +/** + * http://www-03.ibm.com/systems/i/software/globalization/ccsid.html + * http://www-306.ibm.com/software/globalization/ccsid/ccsid_registered.jsp + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XIEbcdicNTranslator extends XIEbcdicTranslator { + + private final int[] ivEbcdicToChar; + private final int[] ivCharToEbcdic = new int[65536]; + + /** + */ + protected XIEbcdicNTranslator(int[] ebcdic) { + ivEbcdicToChar = ebcdic; + for (int i = ivEbcdicToChar.length - 1; i >=0; i--) + ivCharToEbcdic[ivEbcdicToChar[i]] = i; + } + + + /** + * From ebcdic code to char + */ + @Override + public char toChar(byte aEbcdicChar) { + return (char)ivEbcdicToChar[toInt(aEbcdicChar)]; + } + + + /** + * From char to ebcdic code + */ + @Override + public byte toEBCDIC(char aChar) { + return (byte)ivCharToEbcdic[ + Math.max(0, Math.min(ivCharToEbcdic.length - 1, (int)aChar))]; + } + + ////// + + private static class Euro extends XIEbcdicNTranslator { + + private final byte ivEbcdicEuro; + + protected Euro(int[] ebcdic, byte ebcdicEuro) { + super(ebcdic); + ivEbcdicEuro = ebcdicEuro; + } + + @Override + public char toChar(byte aEbcdicChar) { + if (aEbcdicChar == ivEbcdicEuro) + return '€'; + return super.toChar(aEbcdicChar); + } + @Override + public byte toEBCDIC(char aChar) { + if (aChar == '€') + return ivEbcdicEuro; + return super.toEBCDIC(aChar); + } + } + + ////// + + private static final int[] CP37 = { + 0, 1, 2, 3, 156, 9, 134, 127, /* 0 - 7 */ + 151, 141, 142, 11, 12, 13, 14, 15, /* 8 - 15 */ + 16, 17, 18, 19, 157, 133, 8, 135, /* 16 - 23 */ + 24, 25, 146, 143, 28, 29, 30, 31, /* 24 - 31 */ + 128, 129, 130, 131, 132, 10, 23, 27, /* 32 - 39 */ + 136, 137, 138, 139, 140, 5, 6, 7, /* 40 - 47 */ + 144, 145, 22, 147, 148, 149, 150, 4, /* 48 - 55 */ + 152, 153, 154, 155, 20, 21, 158, 26, /* 56 - 63 */ + 32, 160, 226, 228, 224, 225, 227, 229, /* 64 - 71 */ + 231, 241, 162, 46, 60, 40, 43, 124, /* 72 - 79 */ + 38, 233, 234, 235, 232, 237, 238, 239, /* 80 - 87 */ + 236, 223, 33, 36, 42, 41, 59, 172, /* 88 - 95 */ + 45, 47, 194, 196, 192, 193, 195, 197, /* 96 - 103 */ + 199, 209, 166, 44, 37, 95, 62, 63, /* 104 - 111 */ + 248, 201, 202, 203, 200, 205, 206, 207, /* 112 - 119 */ + 204, 96, 58, 35, 64, 39, 61, 34, /* 120 - 127 */ + 216, 97, 98, 99, 100, 101, 102, 103, /* 128 - 135 */ + 104, 105, 171, 187, 240, 253, 254, 177, /* 136 - 143 */ + 176, 106, 107, 108, 109, 110, 111, 112, /* 144 - 151 */ + 113, 114, 170, 186, 230, 184, 198, 164, /* 152 - 159 */ + 181, 126, 115, 116, 117, 118, 119, 120, /* 160 - 167 */ + 121, 122, 161, 191, 208, 221, 222, 174, /* 168 - 175 */ + 94, 163, 165, 183, 169, 167, 182, 188, /* 176 - 183 */ + 189, 190, 91, 93, 175, 168, 180, 215, /* 184 - 191 */ + 123, 65, 66, 67, 68, 69, 70, 71, /* 192 - 199 */ + 72, 73, 173, 244, 246, 242, 243, 245, /* 200 - 207 */ + 125, 74, 75, 76, 77, 78, 79, 80, /* 208 - 215 */ + 81, 82, 185, 251, 252, 249, 250, 255, /* 216 - 223 */ + 92, 247, 83, 84, 85, 86, 87, 88, /* 224 - 231 */ + 89, 90, 178, 212, 214, 210, 211, 213, /* 232 - 239 */ + 48, 49, 50, 51, 52, 53, 54, 55, /* 240 - 247 */ + 56, 57, 179, 219, 220, 217, 218, 0, /* 248 - 255 */ + }; + + private static final int[] CP273 = { + 0, 1, 2, 3, 156, 9, 134, 127, /* 0 - 7 */ + 151, 141, 142, 11, 12, 13, 14, 15, /* 8 - 15 */ + 16, 17, 18, 19, 157, 133, 8, 135, /* 16 - 23 */ + 24, 25, 146, 143, 28, 29, 30, 31, /* 24 - 31 */ + 128, 129, 130, 131, 132, 10, 23, 27, /* 32 - 39 */ + 136, 137, 138, 139, 140, 5, 6, 7, /* 40 - 47 */ + 144, 145, 22, 147, 148, 149, 150, 4, /* 48 - 55 */ + 152, 153, 154, 155, 20, 21, 158, 26, /* 56 - 63 */ + 32, 160, 226, 123, 224, 225, 227, 229, /* 64 - 71 */ + 231, 241, 196, 46, 60, 40, 43, 33, /* 72 - 79 */ + 38, 233, 234, 235, 232, 237, 238, 239, /* 80 - 87 */ + 236, 126, 220, 36, 42, 41, 59, 94, /* 88 - 95 */ + 45, 47, 194, 91, 192, 193, 195, 197, /* 96 - 103 */ + 199, 209, 246, 44, 37, 95, 62, 63, /* 104 - 111 */ + 248, 201, 202, 203, 200, 205, 206, 207, /* 112 - 119 */ + 204, 96, 58, 35, 167, 39, 61, 34, /* 120 - 127 */ + 216, 97, 98, 99, 100, 101, 102, 103, /* 128 - 135 */ + 104, 105, 171, 187, 240, 253, 254, 177, /* 136 - 143 */ + 176, 106, 107, 108, 109, 110, 111, 112, /* 144 - 151 */ + 113, 114, 170, 186, 230, 184, 198, 164, /* 152 - 159 */ + 181, 223, 115, 116, 117, 118, 119, 120, /* 160 - 167 */ + 121, 122, 161, 191, 208, 221, 222, 174, /* 168 - 175 */ + 162, 163, 165, 183, 169, 64, 182, 188, /* 176 - 183 */ + 189, 190, 172, 124, 175, 168, 180, 215, /* 184 - 191 */ + 228, 65, 66, 67, 68, 69, 70, 71, /* 192 - 199 */ + 72, 73, 173, 244, 166, 242, 243, 245, /* 200 - 207 */ + 252, 74, 75, 76, 77, 78, 79, 80, /* 208 - 215 */ + 81, 82, 185, 251, 125, 249, 250, 255, /* 216 - 223 */ + 214, 247, 83, 84, 85, 86, 87, 88, /* 224 - 231 */ + 89, 90, 178, 212, 92, 210, 211, 213, /* 232 - 239 */ + 48, 49, 50, 51, 52, 53, 54, 55, /* 240 - 247 */ + 56, 57, 179, 219, 93, 217, 218, 0, /* 248 - 255 */ + }; + + private static final int[] CP277 = { + 0, 1, 2, 3, 156, 9, 134, 127, /* 0 - 7 */ + 151, 141, 142, 11, 12, 13, 14, 15, /* 8 - 15 */ + 16, 17, 18, 19, 157, 133, 8, 135, /* 16 - 23 */ + 24, 25, 146, 143, 28, 29, 30, 31, /* 24 - 31 */ + 128, 129, 130, 131, 132, 10, 23, 27, /* 32 - 39 */ + 136, 137, 138, 139, 140, 5, 6, 7, /* 40 - 47 */ + 144, 145, 22, 147, 148, 149, 150, 4, /* 48 - 55 */ + 152, 153, 154, 155, 20, 21, 158, 26, /* 56 - 63 */ + 32, 160, 226, 228, 224, 225, 227, 125, /* 64 - 71 */ + 231, 241, 35, 46, 60, 40, 43, 33, /* 72 - 79 */ + 38, 233, 234, 235, 232, 237, 238, 239, /* 80 - 87 */ + 236, 223, 164, 197, 42, 41, 59, 94, /* 88 - 95 */ + 45, 47, 194, 196, 192, 193, 195, 36, /* 96 - 103 */ + 199, 209, 248, 44, 37, 95, 62, 63, /* 104 - 111 */ + 166, 201, 202, 203, 200, 205, 206, 207, /* 112 - 119 */ + 204, 96, 58, 198, 216, 39, 61, 34, /* 120 - 127 */ + 64, 97, 98, 99, 100, 101, 102, 103, /* 128 - 135 */ + 104, 105, 171, 187, 240, 253, 254, 177, /* 136 - 143 */ + 176, 106, 107, 108, 109, 110, 111, 112, /* 144 - 151 */ + 113, 114, 170, 186, 123, 184, 91, 93, /* 152 - 159 */ + 181, 252, 115, 116, 117, 118, 119, 120, /* 160 - 167 */ + 121, 122, 161, 191, 208, 221, 222, 174, /* 168 - 175 */ + 162, 163, 165, 183, 169, 167, 182, 188, /* 176 - 183 */ + 189, 190, 172, 124, 175, 168, 180, 215, /* 184 - 191 */ + 230, 65, 66, 67, 68, 69, 70, 71, /* 192 - 199 */ + 72, 73, 173, 244, 246, 242, 243, 245, /* 200 - 207 */ + 229, 74, 75, 76, 77, 78, 79, 80, /* 208 - 215 */ + 81, 82, 185, 251, 126, 249, 250, 255, /* 216 - 223 */ + 92, 247, 83, 84, 85, 86, 87, 88, /* 224 - 231 */ + 89, 90, 178, 212, 214, 210, 211, 213, /* 232 - 239 */ + 48, 49, 50, 51, 52, 53, 54, 55, /* 240 - 247 */ + 56, 57, 179, 219, 220, 217, 218, 0, /* 248 - 255 */ + }; + + private static final int[] CP278 = { + 0, 1, 2, 3, 156, 9, 134, 127, /* 0 - 7 */ + 151, 141, 142, 11, 12, 13, 14, 15, /* 8 - 15 */ + 16, 17, 18, 19, 157, 133, 8, 135, /* 16 - 23 */ + 24, 25, 146, 143, 28, 29, 30, 31, /* 24 - 31 */ + 128, 129, 130, 131, 132, 10, 23, 27, /* 32 - 39 */ + 136, 137, 138, 139, 140, 5, 6, 7, /* 40 - 47 */ + 144, 145, 22, 147, 148, 149, 150, 4, /* 48 - 55 */ + 152, 153, 154, 155, 20, 21, 158, 26, /* 56 - 63 */ + 32, 160, 226, 123, 224, 225, 227, 125, /* 64 - 71 */ + 231, 241, 167, 46, 60, 40, 43, 33, /* 72 - 79 */ + 38, 96, 234, 235, 232, 237, 238, 239, /* 80 - 87 */ + 236, 223, 164, 197, 42, 41, 59, 94, /* 88 - 95 */ + 45, 47, 194, 35, 192, 193, 195, 36, /* 96 - 103 */ + 199, 209, 246, 44, 37, 95, 62, 63, /* 104 - 111 */ + 248, 201, 202, 203, 200, 205, 206, 207, /* 112 - 119 */ + 204, 233, 58, 196, 214, 39, 61, 34, /* 120 - 127 */ + 216, 97, 98, 99, 100, 101, 102, 103, /* 128 - 135 */ + 104, 105, 171, 187, 240, 253, 254, 177, /* 136 - 143 */ + 176, 106, 107, 108, 109, 110, 111, 112, /* 144 - 151 */ + 113, 114, 170, 186, 230, 184, 198, 93, /* 152 - 159 */ + 181, 252, 115, 116, 117, 118, 119, 120, /* 160 - 167 */ + 121, 122, 161, 191, 208, 221, 222, 174, /* 168 - 175 */ + 162, 163, 165, 183, 169, 91, 182, 188, /* 176 - 183 */ + 189, 190, 172, 124, 175, 168, 180, 215, /* 184 - 191 */ + 228, 65, 66, 67, 68, 69, 70, 71, /* 192 - 199 */ + 72, 73, 173, 244, 166, 242, 243, 245, /* 200 - 207 */ + 229, 74, 75, 76, 77, 78, 79, 80, /* 208 - 215 */ + 81, 82, 185, 251, 126, 249, 250, 255, /* 216 - 223 */ + 92, 247, 83, 84, 85, 86, 87, 88, /* 224 - 231 */ + 89, 90, 178, 212, 64, 210, 211, 213, /* 232 - 239 */ + 48, 49, 50, 51, 52, 53, 54, 55, /* 240 - 247 */ + 56, 57, 179, 219, 220, 217, 218, 0, /* 248 - 255 */ + }; + + private static final int[] CP280 = { + 0, 1, 2, 3, 156, 9, 134, 127, /* 0 - 7 */ + 151, 141, 142, 11, 12, 13, 14, 15, /* 8 - 15 */ + 16, 17, 18, 19, 157, 133, 8, 135, /* 16 - 23 */ + 24, 25, 146, 143, 28, 29, 30, 31, /* 24 - 31 */ + 128, 129, 130, 131, 132, 10, 23, 27, /* 32 - 39 */ + 136, 137, 138, 139, 140, 5, 6, 7, /* 40 - 47 */ + 144, 145, 22, 147, 148, 149, 150, 4, /* 48 - 55 */ + 152, 153, 154, 155, 20, 21, 158, 26, /* 56 - 63 */ + 32, 160, 226, 228, 123, 225, 227, 229, /* 64 - 71 */ + 92, 241, 176, 46, 60, 40, 43, 33, /* 72 - 79 */ + 38, 93, 234, 235, 125, 237, 238, 239, /* 80 - 87 */ + 126, 223, 233, 36, 42, 41, 59, 94, /* 88 - 95 */ + 45, 47, 194, 196, 192, 193, 195, 197, /* 96 - 103 */ + 199, 209, 242, 44, 37, 95, 62, 63, /* 104 - 111 */ + 248, 201, 202, 203, 200, 205, 206, 207, /* 112 - 119 */ + 204, 249, 58, 163, 167, 39, 61, 34, /* 120 - 127 */ + 216, 97, 98, 99, 100, 101, 102, 103, /* 128 - 135 */ + 104, 105, 171, 187, 240, 253, 254, 177, /* 136 - 143 */ + 91, 106, 107, 108, 109, 110, 111, 112, /* 144 - 151 */ + 113, 114, 170, 186, 230, 184, 198, 164, /* 152 - 159 */ + 181, 236, 115, 116, 117, 118, 119, 120, /* 160 - 167 */ + 121, 122, 161, 191, 208, 221, 222, 174, /* 168 - 175 */ + 162, 35, 165, 183, 169, 64, 182, 188, /* 176 - 183 */ + 189, 190, 172, 124, 175, 168, 180, 215, /* 184 - 191 */ + 224, 65, 66, 67, 68, 69, 70, 71, /* 192 - 199 */ + 72, 73, 173, 244, 246, 166, 243, 245, /* 200 - 207 */ + 232, 74, 75, 76, 77, 78, 79, 80, /* 208 - 215 */ + 81, 82, 185, 251, 252, 96, 250, 255, /* 216 - 223 */ + 231, 247, 83, 84, 85, 86, 87, 88, /* 224 - 231 */ + 89, 90, 178, 212, 214, 210, 211, 213, /* 232 - 239 */ + 48, 49, 50, 51, 52, 53, 54, 55, /* 240 - 247 */ + 56, 57, 179, 219, 220, 217, 218, 0, /* 248 - 255 */ + }; + + private static final int[] CP284 = { + 0, 1, 2, 3, 156, 9, 134, 127, /* 0 - 7 */ + 151, 141, 142, 11, 12, 13, 14, 15, /* 8 - 15 */ + 16, 17, 18, 19, 157, 133, 8, 135, /* 16 - 23 */ + 24, 25, 146, 143, 28, 29, 30, 31, /* 24 - 31 */ + 128, 129, 130, 131, 132, 10, 23, 27, /* 32 - 39 */ + 136, 137, 138, 139, 140, 5, 6, 7, /* 40 - 47 */ + 144, 145, 22, 147, 148, 149, 150, 4, /* 48 - 55 */ + 152, 153, 154, 155, 20, 21, 158, 26, /* 56 - 63 */ + 32, 160, 226, 228, 224, 225, 227, 229, /* 64 - 71 */ + 231, 166, 91, 46, 60, 40, 43, 124, /* 72 - 79 */ + 38, 233, 234, 235, 232, 237, 238, 239, /* 80 - 87 */ + 236, 223, 93, 36, 42, 41, 59, 172, /* 88 - 95 */ + 45, 47, 194, 196, 192, 193, 195, 197, /* 96 - 103 */ + 199, 35, 241, 44, 37, 95, 62, 63, /* 104 - 111 */ + 248, 201, 202, 203, 200, 205, 206, 207, /* 112 - 119 */ + 204, 96, 58, 209, 64, 39, 61, 34, /* 120 - 127 */ + 216, 97, 98, 99, 100, 101, 102, 103, /* 128 - 135 */ + 104, 105, 171, 187, 240, 253, 254, 177, /* 136 - 143 */ + 176, 106, 107, 108, 109, 110, 111, 112, /* 144 - 151 */ + 113, 114, 170, 186, 230, 184, 198, 164, /* 152 - 159 */ + 181, 168, 115, 116, 117, 118, 119, 120, /* 160 - 167 */ + 121, 122, 161, 191, 208, 221, 222, 174, /* 168 - 175 */ + 162, 163, 165, 183, 169, 167, 182, 188, /* 176 - 183 */ + 189, 190, 94, 33, 175, 126, 180, 215, /* 184 - 191 */ + 123, 65, 66, 67, 68, 69, 70, 71, /* 192 - 199 */ + 72, 73, 173, 244, 246, 242, 243, 245, /* 200 - 207 */ + 125, 74, 75, 76, 77, 78, 79, 80, /* 208 - 215 */ + 81, 82, 185, 251, 252, 249, 250, 255, /* 216 - 223 */ + 92, 247, 83, 84, 85, 86, 87, 88, /* 224 - 231 */ + 89, 90, 178, 212, 214, 210, 211, 213, /* 232 - 239 */ + 48, 49, 50, 51, 52, 53, 54, 55, /* 240 - 247 */ + 56, 57, 179, 219, 220, 217, 218, 0, /* 248 - 255 */ + }; + + private static final int[] CP285 = { + 0, 1, 2, 3, 156, 9, 134, 127, /* 0 - 7 */ + 151, 141, 142, 11, 12, 13, 14, 15, /* 8 - 15 */ + 16, 17, 18, 19, 157, 133, 8, 135, /* 16 - 23 */ + 24, 25, 146, 143, 28, 29, 30, 31, /* 24 - 31 */ + 128, 129, 130, 131, 132, 10, 23, 27, /* 32 - 39 */ + 136, 137, 138, 139, 140, 5, 6, 7, /* 40 - 47 */ + 144, 145, 22, 147, 148, 149, 150, 4, /* 48 - 55 */ + 152, 153, 154, 155, 20, 21, 158, 26, /* 56 - 63 */ + 32, 160, 226, 228, 224, 225, 227, 229, /* 64 - 71 */ + 231, 241, 36, 46, 60, 40, 43, 124, /* 72 - 79 */ + 38, 233, 234, 235, 232, 237, 238, 239, /* 80 - 87 */ + 236, 223, 33, 163, 42, 41, 59, 172, /* 88 - 95 */ + 45, 47, 194, 196, 192, 193, 195, 197, /* 96 - 103 */ + 199, 209, 166, 44, 37, 95, 62, 63, /* 104 - 111 */ + 248, 201, 202, 203, 200, 205, 206, 207, /* 112 - 119 */ + 204, 96, 58, 35, 64, 39, 61, 34, /* 120 - 127 */ + 216, 97, 98, 99, 100, 101, 102, 103, /* 128 - 135 */ + 104, 105, 171, 187, 240, 253, 254, 177, /* 136 - 143 */ + 176, 106, 107, 108, 109, 110, 111, 112, /* 144 - 151 */ + 113, 114, 170, 186, 230, 184, 198, 164, /* 152 - 159 */ + 181, 175, 115, 116, 117, 118, 119, 120, /* 160 - 167 */ + 121, 122, 161, 191, 208, 221, 222, 174, /* 168 - 175 */ + 162, 91, 165, 183, 169, 167, 182, 188, /* 176 - 183 */ + 189, 190, 94, 93, 126, 168, 180, 215, /* 184 - 191 */ + 123, 65, 66, 67, 68, 69, 70, 71, /* 192 - 199 */ + 72, 73, 173, 244, 246, 242, 243, 245, /* 200 - 207 */ + 125, 74, 75, 76, 77, 78, 79, 80, /* 208 - 215 */ + 81, 82, 185, 251, 252, 249, 250, 255, /* 216 - 223 */ + 92, 247, 83, 84, 85, 86, 87, 88, /* 224 - 231 */ + 89, 90, 178, 212, 214, 210, 211, 213, /* 232 - 239 */ + 48, 49, 50, 51, 52, 53, 54, 55, /* 240 - 247 */ + 56, 57, 179, 219, 220, 217, 218, 0, /* 248 - 255 */ + }; + + private static final int[] CP297 = { + 0, 1, 2, 3, 156, 9, 134, 127, /* 0 - 7 */ + 151, 141, 142, 11, 12, 13, 14, 15, /* 8 - 15 */ + 16, 17, 18, 19, 157, 133, 8, 135, /* 16 - 23 */ + 24, 25, 146, 143, 28, 29, 30, 31, /* 24 - 31 */ + 128, 129, 130, 131, 132, 10, 23, 27, /* 32 - 39 */ + 136, 137, 138, 139, 140, 5, 6, 7, /* 40 - 47 */ + 144, 145, 22, 147, 148, 149, 150, 4, /* 48 - 55 */ + 152, 153, 154, 155, 20, 21, 158, 26, /* 56 - 63 */ + 32, 160, 226, 228, 64, 225, 227, 229, /* 64 - 71 */ + 92, 241, 176, 46, 60, 40, 43, 33, /* 72 - 79 */ + 38, 123, 234, 235, 125, 237, 238, 239, /* 80 - 87 */ + 236, 223, 167, 36, 42, 41, 59, 94, /* 88 - 95 */ + 45, 47, 194, 196, 192, 193, 195, 197, /* 96 - 103 */ + 199, 209, 249, 44, 37, 95, 62, 63, /* 104 - 111 */ + 248, 201, 202, 203, 200, 205, 206, 207, /* 112 - 119 */ + 204, 181, 58, 163, 224, 39, 61, 34, /* 120 - 127 */ + 216, 97, 98, 99, 100, 101, 102, 103, /* 128 - 135 */ + 104, 105, 171, 187, 240, 253, 254, 177, /* 136 - 143 */ + 91, 106, 107, 108, 109, 110, 111, 112, /* 144 - 151 */ + 113, 114, 170, 186, 230, 184, 198, 164, /* 152 - 159 */ + 96, 168, 115, 116, 117, 118, 119, 120, /* 160 - 167 */ + 121, 122, 161, 191, 208, 221, 222, 174, /* 168 - 175 */ + 162, 35, 165, 183, 169, 93, 182, 188, /* 176 - 183 */ + 189, 190, 172, 124, 175, 126, 180, 215, /* 184 - 191 */ + 233, 65, 66, 67, 68, 69, 70, 71, /* 192 - 199 */ + 72, 73, 173, 244, 246, 242, 243, 245, /* 200 - 207 */ + 232, 74, 75, 76, 77, 78, 79, 80, /* 208 - 215 */ + 81, 82, 185, 251, 252, 166, 250, 255, /* 216 - 223 */ + 231, 247, 83, 84, 85, 86, 87, 88, /* 224 - 231 */ + 89, 90, 178, 212, 214, 210, 211, 213, /* 232 - 239 */ + 48, 49, 50, 51, 52, 53, 54, 55, /* 240 - 247 */ + 56, 57, 179, 219, 220, 217, 218, 0, /* 248 - 255 */ + }; + + private static final int[] CP424 = { + 0, 1, 2, 3, 156, 9, 134, 127, /* 0 - 7 */ + 151, 141, 142, 11, 12, 13, 14, 15, /* 8 - 15 */ + 16, 17, 18, 19, 157, 133, 8, 135, /* 16 - 23 */ + 24, 25, 146, 143, 28, 29, 30, 31, /* 24 - 31 */ + 128, 129, 130, 131, 132, 10, 23, 27, /* 32 - 39 */ + 136, 137, 138, 139, 140, 5, 6, 7, /* 40 - 47 */ + 144, 145, 22, 147, 148, 149, 150, 4, /* 48 - 55 */ + 152, 153, 154, 155, 20, 21, 158, 26, /* 56 - 63 */ + 32, 193, 194, 195, 196, 197, 198, 199, /* 64 - 71 */ + 200, 201, 162, 46, 60, 40, 43, 124, /* 72 - 79 */ + 38, 216, 217, 226, 227, 228, 229, 230, /* 80 - 87 */ + 231, 232, 33, 36, 42, 41, 59, 172, /* 88 - 95 */ + 45, 47, 233, 192, 186, 161, 210, 191, /* 96 - 103 */ + 212, 213, 166, 44, 37, 95, 62, 63, /* 104 - 111 */ + 242, 248, 249, 209, 160, 255, 234, 241, /* 112 - 119 */ + 177, 96, 58, 35, 64, 39, 61, 34, /* 120 - 127 */ + 214, 97, 98, 99, 100, 101, 102, 103, /* 128 - 135 */ + 104, 105, 171, 187, 246, 211, 243, 208, /* 136 - 143 */ + 176, 106, 107, 108, 109, 110, 111, 112, /* 144 - 151 */ + 113, 114, 218, 240, 225, 184, 245, 164, /* 152 - 159 */ + 181, 126, 115, 116, 117, 118, 119, 120, /* 160 - 167 */ + 121, 122, 170, 224, 244, 202, 175, 174, /* 168 - 175 */ + 94, 163, 165, 183, 169, 167, 182, 188, /* 176 - 183 */ + 189, 190, 91, 93, 250, 168, 180, 215, /* 184 - 191 */ + 123, 65, 66, 67, 68, 69, 70, 71, /* 192 - 199 */ + 72, 73, 173, 203, 204, 205, 206, 207, /* 200 - 207 */ + 125, 74, 75, 76, 77, 78, 79, 80, /* 208 - 215 */ + 81, 82, 185, 219, 220, 221, 222, 223, /* 216 - 223 */ + 92, 247, 83, 84, 85, 86, 87, 88, /* 224 - 231 */ + 89, 90, 178, 235, 236, 237, 238, 239, /* 232 - 239 */ + 48, 49, 50, 51, 52, 53, 54, 55, /* 240 - 247 */ + 56, 57, 179, 251, 252, 253, 254, 0, /* 248 - 255 */ + }; + + private static final int[] CP500 = { + 0, 1, 2, 3, 156, 9, 134, 127, /* 0 - 7 */ + 151, 141, 142, 11, 12, 13, 14, 15, /* 8 - 15 */ + 16, 17, 18, 19, 157, 133, 8, 135, /* 16 - 23 */ + 24, 25, 146, 143, 28, 29, 30, 31, /* 24 - 31 */ + 128, 129, 130, 131, 132, 10, 23, 27, /* 32 - 39 */ + 136, 137, 138, 139, 140, 5, 6, 7, /* 40 - 47 */ + 144, 145, 22, 147, 148, 149, 150, 4, /* 48 - 55 */ + 152, 153, 154, 155, 20, 21, 158, 26, /* 56 - 63 */ + 32, 160, 226, 228, 224, 225, 227, 229, /* 64 - 71 */ + 231, 241, 91, 46, 60, 40, 43, 33, /* 72 - 79 */ + 38, 233, 234, 235, 232, 237, 238, 239, /* 80 - 87 */ + 236, 223, 93, 36, 42, 41, 59, 94, /* 88 - 95 */ + 45, 47, 194, 196, 192, 193, 195, 197, /* 96 - 103 */ + 199, 209, 166, 44, 37, 95, 62, 63, /* 104 - 111 */ + 248, 201, 202, 203, 200, 205, 206, 207, /* 112 - 119 */ + 204, 96, 58, 35, 64, 39, 61, 34, /* 120 - 127 */ + 216, 97, 98, 99, 100, 101, 102, 103, /* 128 - 135 */ + 104, 105, 171, 187, 240, 253, 254, 177, /* 136 - 143 */ + 176, 106, 107, 108, 109, 110, 111, 112, /* 144 - 151 */ + 113, 114, 170, 186, 230, 184, 198, 164, /* 152 - 159 */ + 181, 126, 115, 116, 117, 118, 119, 120, /* 160 - 167 */ + 121, 122, 161, 191, 208, 221, 222, 174, /* 168 - 175 */ + 162, 163, 165, 183, 169, 167, 182, 188, /* 176 - 183 */ + 189, 190, 172, 124, 175, 168, 180, 215, /* 184 - 191 */ + 123, 65, 66, 67, 68, 69, 70, 71, /* 192 - 199 */ + 72, 73, 173, 244, 246, 242, 243, 245, /* 200 - 207 */ + 125, 74, 75, 76, 77, 78, 79, 80, /* 208 - 215 */ + 81, 82, 185, 251, 252, 249, 250, 255, /* 216 - 223 */ + 92, 247, 83, 84, 85, 86, 87, 88, /* 224 - 231 */ + 89, 90, 178, 212, 214, 210, 211, 213, /* 232 - 239 */ + 48, 49, 50, 51, 52, 53, 54, 55, /* 240 - 247 */ + 56, 57, 179, 219, 220, 217, 218, 0, /* 248 - 255 */ + }; + + private static final int[] CP850 = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + '\b', '\t', '\n', 0x000B, '\f', '\r', 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001C, 0x001B, 0x007F, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, '\"', 0x0023, 0x0024, 0x0025, 0x0026, '\'', + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, '\\', 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x001A, + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, + 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, + 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, + 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, + 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, + 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4, + 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, + 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0, + }; + + private static final int[] CP870 = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x009C, '\t', 0x0086, 0x007F, + 0x0097, 0x008D, 0x008E, 0x000B, '\f', '\r', 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x009D, 0x0085, '\b', 0x0087, + 0x0018, 0x0019, 0x0092, 0x008F, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, '\n', 0x0017, 0x001B, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x0005, 0x0006, 0x0007, + 0x0090, 0x0091, 0x0016, 0x0093, 0x0094, 0x0095, 0x0096, 0x0004, + 0x0098, 0x0099, 0x009A, 0x009B, 0x0014, 0x0015, 0x009E, 0x001A, + 0x0020, 0x00A0, 0x00E2, 0x00E4, 0x0163, 0x00E1, 0x0103, 0x010D, + 0x00E7, 0x0107, 0x005B, 0x002E, 0x003C, 0x0028, 0x002B, 0x0021, + 0x0026, 0x00E9, 0x0119, 0x00EB, 0x016F, 0x00ED, 0x00EE, 0x013E, + 0x013A, 0x00DF, 0x005D, 0x0024, 0x002A, 0x0029, 0x003B, 0x005E, + 0x002D, 0x002F, 0x00C2, 0x00C4, 0x02DD, 0x00C1, 0x0102, 0x010C, + 0x00C7, 0x0106, 0x007C, 0x002C, 0x0025, 0x005F, 0x003E, 0x003F, + 0x02C7, 0x00C9, 0x0118, 0x00CB, 0x016E, 0x00CD, 0x00CE, 0x013D, + 0x0139, 0x0060, 0x003A, 0x0023, 0x0040, '\'', 0x003D, '\"', + 0x02D8, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x015B, 0x0148, 0x0111, 0x00FD, 0x0159, 0x015F, + 0x00B0, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, + 0x0071, 0x0072, 0x0142, 0x0144, 0x0161, 0x00B8, 0x02DB, 0x00A4, + 0x0105, 0x007E, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, + 0x0079, 0x007A, 0x015A, 0x0147, 0x0110, 0x00DD, 0x0158, 0x015E, + 0x02D9, 0x0104, 0x017C, 0x0162, 0x017B, 0x00A7, 0x017E, 0x017A, + 0x017D, 0x0179, 0x0141, 0x0143, 0x0160, 0x00A8, 0x00B4, 0x00D7, + 0x007B, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x00AD, 0x00F4, 0x00F6, 0x0155, 0x00F3, 0x0151, + 0x007D, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050, + 0x0051, 0x0052, 0x011A, 0x0171, 0x00FC, 0x0165, 0x00FA, 0x011B, + '\\', 0x00F7, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, + 0x0059, 0x005A, 0x010F, 0x00D4, 0x00D6, 0x0154, 0x00D3, 0x0150, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x010E, 0x0170, 0x00DC, 0x0164, 0x00DA, 0x009F, + }; + + private static final int[] CP838 = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x009C, '\t', 0x0086, 0x007F, + 0x0097, 0x008D, 0x008E, 0x000B, '\f', '\r', 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x009D, 0x0085, '\b', 0x0087, + 0x0018, 0x0019, 0x0092, 0x008F, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, '\n', 0x0017, 0x001B, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x0005, 0x0006, 0x0007, + 0x0090, 0x0091, 0x0016, 0x0093, 0x0094, 0x0095, 0x0096, 0x0004, + 0x0098, 0x0099, 0x009A, 0x009B, 0x0014, 0x0015, 0x009E, 0x001A, + 0x0020, 0x00A0, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, + 0x0E07, 0x005B, 0x00A2, 0x002E, 0x003C, 0x0028, 0x002B, 0x007C, + 0x0026, 0x0E48, 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, + 0x0E0E, 0x005D, 0x0021, 0x0024, 0x002A, 0x0029, 0x003B, 0x00AC, + 0x002D, 0x002F, 0x0E0F, 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, + 0x0E15, 0x005E, 0x00A6, 0x002C, 0x0025, 0x005F, 0x003E, 0x003F, + 0x0E3F, 0x0E4E, 0x0E16, 0x0E17, 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, + 0x0E1C, 0x0060, 0x003A, 0x0023, 0x0040, '\'', 0x003D, '\"', + 0x0E4F, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x0E1D, 0x0E1E, 0x0E1F, 0x0E20, 0x0E21, 0x0E22, + 0x0E5A, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, + 0x0071, 0x0072, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27, 0x0E28, + 0x0E5B, 0x007E, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, + 0x0079, 0x007A, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, + 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57, + 0x0E58, 0x0E59, 0x0E2F, 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, + 0x007B, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x0E49, 0x0E35, 0x0E36, 0x0E37, 0x0E38, 0x0E39, + 0x007D, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050, + 0x0051, 0x0052, 0x0E3A, 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, + '\\', 0x0E4A, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, + 0x0059, 0x005A, 0x0E45, 0x0E46, 0x0E47, 0x0E48, 0x0E49, 0x0E4A, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4B, 0x0E4C, 0x009F + }; + + public static final XIEbcdicNTranslator TRANSLATOR_CP37 = + new XIEbcdicNTranslator(CP37); + public static final XIEbcdicNTranslator TRANSLATOR_CP273 = + new XIEbcdicNTranslator(CP273); + public static final XIEbcdicNTranslator TRANSLATOR_CP277 = + new XIEbcdicNTranslator(CP277); + public static final XIEbcdicNTranslator TRANSLATOR_CP278 = + new XIEbcdicNTranslator(CP278); + public static final XIEbcdicNTranslator TRANSLATOR_CP280 = + new XIEbcdicNTranslator(CP280); + public static final XIEbcdicNTranslator TRANSLATOR_CP284 = + new XIEbcdicNTranslator(CP284); + public static final XIEbcdicNTranslator TRANSLATOR_CP285 = + new XIEbcdicNTranslator(CP285); + public static final XIEbcdicNTranslator TRANSLATOR_CP297 = + new XIEbcdicNTranslator(CP297); + public static final XIEbcdicNTranslator TRANSLATOR_CP424 = + new XIEbcdicNTranslator(CP424); + public static final XIEbcdicNTranslator TRANSLATOR_CP500 = + new XIEbcdicNTranslator(CP500); + public static final XIEbcdicNTranslator TRANSLATOR_CP850 = + new XIEbcdicNTranslator(CP850); + public static final XIEbcdicNTranslator TRANSLATOR_CP870 = + new XIEbcdicNTranslator(CP870); + public static final XIEbcdicNTranslator TRANSLATOR_CP838 = + new XIEbcdicNTranslator(CP838); + // Derived with € + public static final XIEbcdicNTranslator TRANSLATOR_CP1140 = + new XIEbcdicNTranslator.Euro(CP37, (byte)159); + public static final XIEbcdicNTranslator TRANSLATOR_CP1141 = + new XIEbcdicNTranslator.Euro(CP273, (byte)159); + public static final XIEbcdicNTranslator TRANSLATOR_CP1144 = + new XIEbcdicNTranslator.Euro(CP280, (byte)159); + public static final XIEbcdicNTranslator TRANSLATOR_CP1147 = + new XIEbcdicNTranslator.Euro(CP297, (byte)159); + public static final XIEbcdicNTranslator TRANSLATOR_CP1153 = + new XIEbcdicNTranslator.Euro(CP870, (byte)159); + public static final XIEbcdicNTranslator TRANSLATOR_CP1160 = + new XIEbcdicNTranslator.Euro(CP838, (byte)0xFE); + + ////// + + private static final int[] SCP2CP(String scp) { + if (scp.length() != 256) + throw new IllegalArgumentException(); + int[] res = new int[scp.length()]; + for (int i = 0; i < res.length; i++) { + res[i] = scp.charAt(i); + } + return res; + } + + private static final String SCP1025 = + "\u0000\u0001\u0002\u0003\u009C\t\u0086\u007F\u0097\u008D\u008E\u000B\f\r\u000E\u000F" + + "\u0010\u0011\u0012\u0013\u009D\u0085\b\u0087\u0018\u0019\u0092\u008F\u001C\u001D\u001E\u001F" + + "\u0080\u0081\u0082\u0083\u0084\n\u0017\u001B\u0088\u0089\u008A\u008B\u008C\u0005\u0006\u0007" + + "\u0090\u0091\u0016\u0093\u0094\u0095\u0096\u0004\u0098\u0099\u009A\u009B\u0014\u0015\u009E\u001A" + + "\u0020\u00A0\u0452\u0453\u0451\u0454\u0455\u0456\u0457\u0458\u005B\u002E\u003C\u0028\u002B\u0021" + + "\u0026\u0459\u045A\u045B\u045C\u045E\u045F\u042A\u2116\u0402\u005D\u0024\u002A\u0029\u003B\u005E" + + "\u002D\u002F\u0403\u0401\u0404\u0405\u0406\u0407\u0408\u0409\u007C\u002C\u0025\u005F\u003E\u003F" + + "\u040A\u040B\u040C\u00AD\u040E\u040F\u044E\u0430\u0431\u0060\u003A\u0023\u0040\'\u003D\"" + + "\u0446\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u0434\u0435\u0444\u0433\u0445\u0438" + + "\u0439\u006A\u006B\u006C\u006D\u006E\u006F\u0070\u0071\u0072\u043A\u043B\u043C\u043D\u043E\u043F" + + "\u044F\u007E\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007A\u0440\u0441\u0442\u0443\u0436\u0432" + + "\u044C\u044B\u0437\u0448\u044D\u0449\u0447\u044A\u042E\u0410\u0411\u0426\u0414\u0415\u0424\u0413" + + "\u007B\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u0425\u0418\u0419\u041A\u041B\u041C" + + "\u007D\u004A\u004B\u004C\u004D\u004E\u004F\u0050\u0051\u0052\u041D\u041E\u041F\u042F\u0420\u0421" + + "\\\u00A7\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005A\u0422\u0423\u0416\u0412\u042C\u042B" + + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u0417\u0428\u042D\u0429\u0427\u009F"; + + private static final String SCP1026 = + "\u0000\u0001\u0002\u0003\u009C\t\u0086\u007F\u0097\u008D\u008E\u000B\f\r\u000E\u000F" + + "\u0010\u0011\u0012\u0013\u009D\u0085\b\u0087\u0018\u0019\u0092\u008F\u001C\u001D\u001E\u001F" + + "\u0080\u0081\u0082\u0083\u0084\n\u0017\u001B\u0088\u0089\u008A\u008B\u008C\u0005\u0006\u0007" + + "\u0090\u0091\u0016\u0093\u0094\u0095\u0096\u0004\u0098\u0099\u009A\u009B\u0014\u0015\u009E\u001A" + + "\u0020\u00A0\u00E2\u00E4\u00E0\u00E1\u00E3\u00E5\u007B\u00F1\u00C7\u002E\u003C\u0028\u002B\u0021" + + "\u0026\u00E9\u00EA\u00EB\u00E8\u00ED\u00EE\u00EF\u00EC\u00DF\u011E\u0130\u002A\u0029\u003B\u005E" + + "\u002D\u002F\u00C2\u00C4\u00C0\u00C1\u00C3\u00C5\u005B\u00D1\u015F\u002C\u0025\u005F\u003E\u003F" + + "\u00F8\u00C9\u00CA\u00CB\u00C8\u00CD\u00CE\u00CF\u00CC\u0131\u003A\u00D6\u015E\'\u003D\u00DC" + + "\u00D8\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u00AB\u00BB\u007D\u0060\u00A6\u00B1" + + "\u00B0\u006A\u006B\u006C\u006D\u006E\u006F\u0070\u0071\u0072\u00AA\u00BA\u00E6\u00B8\u00C6\u00A4" + + "\u00B5\u00F6\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007A\u00A1\u00BF\u005D\u0024\u0040\u00AE" + + "\u00A2\u00A3\u00A5\u00B7\u00A9\u00A7\u00B6\u00BC\u00BD\u00BE\u00AC\u007C\u00AF\u00A8\u00B4\u00D7" + + "\u00E7\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u00AD\u00F4\u007E\u00F2\u00F3\u00F5" + + "\u011F\u004A\u004B\u004C\u004D\u004E\u004F\u0050\u0051\u0052\u00B9\u00FB\\\u00F9\u00FA\u00FF" + + "\u00FC\u00F7\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005A\u00B2\u00D4\u0023\u00D2\u00D3\u00D5" + + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u00B3\u00DB\"\u00D9\u00DA\u009F"; + + private static final String SCP1112 = + "\u0000\u0001\u0002\u0003\u009C\t\u0086\u007F\u0097\u008D\u008E\u000B\f\r\u000E\u000F" + + "\u0010\u0011\u0012\u0013\u009D\u0085\b\u0087\u0018\u0019\u0092\u008F\u001C\u001D\u001E\u001F" + + "\u0080\u0081\u0082\u0083\u0084\n\u0017\u001B\u0088\u0089\u008A\u008B\u008C\u0005\u0006\u0007" + + "\u0090\u0091\u0016\u0093\u0094\u0095\u0096\u0004\u0098\u0099\u009A\u009B\u0014\u0015\u009E\u001A" + + "\u0020\u00A0\u0161\u00E4\u0105\u012F\u016B\u00E5\u0113\u017E\u00A2\u002E\u003C\u0028\u002B\u007C" + + "\u0026\u00E9\u0119\u0117\u010D\u0173\u201E\u201C\u0123\u00DF\u0021\u0024\u002A\u0029\u003B\u00AC" + + "\u002D\u002F\u0160\u00C4\u0104\u012E\u016A\u00C5\u0112\u017D\u00A6\u002C\u0025\u005F\u003E\u003F" + + "\u00F8\u00C9\u0118\u0116\u010C\u0172\u012A\u013B\u0122\u0060\u003A\u0023\u0040\'\u003D\"" + + "\u00D8\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u00AB\u00BB\u0101\u017C\u0144\u00B1" + + "\u00B0\u006A\u006B\u006C\u006D\u006E\u006F\u0070\u0071\u0072\u0156\u0157\u00E6\u0137\u00C6\u00A4" + + "\u00B5\u007E\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007A\u201D\u017A\u0100\u017B\u0143\u00AE" + + "\u005E\u00A3\u012B\u00B7\u00A9\u00A7\u00B6\u00BC\u00BD\u00BE\u005B\u005D\u0179\u0136\u013C\u00D7" + + "\u007B\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u00AD\u014D\u00F6\u0146\u00F3\u00F5" + + "\u007D\u004A\u004B\u004C\u004D\u004E\u004F\u0050\u0051\u0052\u00B9\u0107\u00FC\u0142\u015B\u2019" + + "\\\u00F7\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005A\u00B2\u014C\u00D6\u0145\u00D3\u00D5" + + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u00B3\u0106\u00DC\u0141\u015A\u009F"; + + private static final String SCP1122 = + "\u0000\u0001\u0002\u0003\u009C\t\u0086\u007F\u0097\u008D\u008E\u000B\f\r\u000E\u000F" + + "\u0010\u0011\u0012\u0013\u009D\u0085\b\u0087\u0018\u0019\u0092\u008F\u001C\u001D\u001E\u001F" + + "\u0080\u0081\u0082\u0083\u0084\n\u0017\u001B\u0088\u0089\u008A\u008B\u008C\u0005\u0006\u0007" + + "\u0090\u0091\u0016\u0093\u0094\u0095\u0096\u0004\u0098\u0099\u009A\u009B\u0014\u0015\u009E\u001A" + + "\u0020\u00A0\u00E2\u007B\u00E0\u00E1\u00E3\u007D\u00E7\u00F1\u00A7\u002E\u003C\u0028\u002B\u0021" + + "\u0026\u0060\u00EA\u00EB\u00E8\u00ED\u00EE\u00EF\u00EC\u00DF\u00A4\u00C5\u002A\u0029\u003B\u005E" + + "\u002D\u002F\u00C2\u0023\u00C0\u00C1\u00C3\u0024\u00C7\u00D1\u00F6\u002C\u0025\u005F\u003E\u003F" + + "\u00F8\\\u00CA\u00CB\u00C8\u00CD\u00CE\u00CF\u00CC\u00E9\u003A\u00C4\u00D6\'\u003D\"" + + "\u00D8\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u00AB\u00BB\u0161\u00FD\u017E\u00B1" + + "\u00B0\u006A\u006B\u006C\u006D\u006E\u006F\u0070\u0071\u0072\u00AA\u00BA\u00E6\u00B8\u00C6\u005D" + + "\u00B5\u00FC\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007A\u00A1\u00BF\u0160\u00DD\u017D\u00AE" + + "\u00A2\u00A3\u00A5\u00B7\u00A9\u005B\u00B6\u00BC\u00BD\u00BE\u00AC\u007C\u00AF\u00A8\u00B4\u00D7" + + "\u00E4\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u00AD\u00F4\u00A6\u00F2\u00F3\u00F5" + + "\u00E5\u004A\u004B\u004C\u004D\u004E\u004F\u0050\u0051\u0052\u00B9\u00FB\u007E\u00F9\u00FA\u00FF" + + "\u00C9\u00F7\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005A\u00B2\u00D4\u0040\u00D2\u00D3\u00D5" + + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u00B3\u00DB\u00DC\u00D9\u00DA\u009F"; + + private static final String SCP1123 = + "\u0000\u0001\u0002\u0003\u009C\t\u0086\u007F\u0097\u008D\u008E\u000B\f\r\u000E\u000F" + + "\u0010\u0011\u0012\u0013\u009D\u0085\b\u0087\u0018\u0019\u0092\u008F\u001C\u001D\u001E\u001F" + + "\u0080\u0081\u0082\u0083\u0084\n\u0017\u001B\u0088\u0089\u008A\u008B\u008C\u0005\u0006\u0007" + + "\u0090\u0091\u0016\u0093\u0094\u0095\u0096\u0004\u0098\u0099\u009A\u009B\u0014\u0015\u009E\u001A" + + "\u0020\u00A0\u0452\u0491\u0451\u0454\u0455\u0456\u0457\u0458\u005B\u002E\u003C\u0028\u002B\u0021" + + "\u0026\u0459\u045A\u045B\u045C\u045E\u045F\u042A\u2116\u0402\u005D\u0024\u002A\u0029\u003B\u005E" + + "\u002D\u002F\u0490\u0401\u0404\u0405\u0406\u0407\u0408\u0409\u007C\u002C\u0025\u005F\u003E\u003F" + + "\u040A\u040B\u040C\u00AD\u040E\u040F\u044E\u0430\u0431\u0060\u003A\u0023\u0040\'\u003D\"" + + "\u0446\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u0434\u0435\u0444\u0433\u0445\u0438" + + "\u0439\u006A\u006B\u006C\u006D\u006E\u006F\u0070\u0071\u0072\u043A\u043B\u043C\u043D\u043E\u043F" + + "\u044F\u007E\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007A\u0440\u0441\u0442\u0443\u0436\u0432" + + "\u044C\u044B\u0437\u0448\u044D\u0449\u0447\u044A\u042E\u0410\u0411\u0426\u0414\u0415\u0424\u0413" + + "\u007B\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u0425\u0418\u0419\u041A\u041B\u041C" + + "\u007D\u004A\u004B\u004C\u004D\u004E\u004F\u0050\u0051\u0052\u041D\u041E\u041F\u042F\u0420\u0421" + + "\\\u00A7\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005A\u0422\u0423\u0416\u0412\u042C\u042B" + + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u0417\u0428\u042D\u0429\u0427\u009F"; + + private static final String SCP1125 = + "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000B\f\r\u000E\u000F" + + "\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001C\u001B\u007F\u001D\u001E\u001F" + + "\u0020\u0021\"\u0023\u0024\u0025\u0026\'\u0028\u0029\u002A\u002B\u002C\u002D\u002E\u002F" + + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u003A\u003B\u003C\u003D\u003E\u003F" + + "\u0040\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u004A\u004B\u004C\u004D\u004E\u004F" + + "\u0050\u0051\u0052\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005A\u005B\\\u005D\u005E\u005F" + + "\u0060\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u006A\u006B\u006C\u006D\u006E\u006F" + + "\u0070\u0071\u0072\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007A\u007B\u007C\u007D\u007E\u001A" + + "\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0417\u0418\u0419\u041A\u041B\u041C\u041D\u041E\u041F" + + "\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042A\u042B\u042C\u042D\u042E\u042F" + + "\u0430\u0431\u0432\u0433\u0434\u0435\u0436\u0437\u0438\u0439\u043A\u043B\u043C\u043D\u043E\u043F" + + "\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255D\u255C\u255B\u2510" + + "\u2514\u2534\u252C\u251C\u2500\u253C\u255E\u255F\u255A\u2554\u2569\u2566\u2560\u2550\u256C\u2567" + + "\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256B\u256A\u2518\u250C\u2588\u2584\u258C\u2590\u2580" + + "\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044A\u044B\u044C\u044D\u044E\u044F" + + "\u0401\u0451\u0490\u0491\u0404\u0454\u0406\u0456\u0407\u0457\u00F7\u00B1\u2116\u00A4\u25A0\u00A0"; + + private static final String SCP1130 = + "\u0000\u0001\u0002\u0003\u009C\t\u0086\u007F\u0097\u008D\u008E\u000B\f\r\u000E\u000F" + + "\u0010\u0011\u0012\u0013\u009D\u0085\b\u0087\u0018\u0019\u0092\u008F\u001C\u001D\u001E\u001F" + + "\u0080\u0081\u0082\u0083\u0084\n\u0017\u001B\u0088\u0089\u008A\u008B\u008C\u0005\u0006\u0007" + + "\u0090\u0091\u0016\u0093\u0094\u0095\u0096\u0004\u0098\u0099\u009A\u009B\u0014\u0015\u009E\u001A" + + "\u0020\u00A0\u00E2\u00E4\u00E0\u00E1\u0103\u00E5\u00E7\u00F1\u005B\u002E\u003C\u0028\u002B\u0021" + + "\u0026\u00E9\u00EA\u00EB\u00E8\u00ED\u00EE\u00EF\u0303\u00DF\u005D\u0024\u002A\u0029\u003B\u005E" + + "\u002D\u002F\u00C2\u00C4\u00C0\u00C1\u0102\u00C5\u00C7\u00D1\u00A6\u002C\u0025\u005F\u003E\u003F" + + "\u00F8\u00C9\u00CA\u00CB\u00C8\u00CD\u00CE\u00CF\u20AB\u0060\u003A\u0023\u0040\'\u003D\"" + + "\u00D8\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u00AB\u00BB\u0111\u0309\u0300\u00B1" + + "\u00B0\u006A\u006B\u006C\u006D\u006E\u006F\u0070\u0071\u0072\u00AA\u00BA\u00E6\u0152\u00C6\u00A4" + + "\u00B5\u007E\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007A\u00A1\u00BF\u0110\u0323\u0301\u00AE" + + "\u00A2\u00A3\u00A5\u00B7\u00A9\u00A7\u00B6\u00BC\u00BD\u00BE\u00AC\u007C\u00AF\u0153\u0178\u00D7" + + "\u007B\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u00AD\u00F4\u00F6\u01B0\u00F3\u01A1" + + "\u007D\u004A\u004B\u004C\u004D\u004E\u004F\u0050\u0051\u0052\u00B9\u00FB\u00FC\u00F9\u00FA\u00FF" + + "\\\u00F7\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005A\u00B2\u00D4\u00D6\u01AF\u00D3\u01A0" + + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u00B3\u00DB\u00DC\u00D9\u00DA\u009F"; + + private static final String SCP1132 = + "\u0000\u0001\u0002\u0003\u009C\t\u0086\u007F\u0097\u008D\u008E\u000B\f\r\u000E\u000F" + + "\u0010\u0011\u0012\u0013\u009D\u0085\b\u0087\u0018\u0019\u0092\u008F\u001C\u001D\u001E\u001F" + + "\u0080\u0081\u0082\u0083\u0084\n\u0017\u001B\u0088\u0089\u008A\u008B\u008C\u0005\u0006\u0007" + + "\u0090\u0091\u0016\u0093\u0094\u0095\u0096\u0004\u0098\u0099\u009A\u009B\u0014\u0015\u009E\u001A" + + "\u0020\u00A0\u0E81\u0E82\u0E84\u0E87\u0E88\u0EAA\u0E8A\u005B\u00A2\u002E\u003C\u0028\u002B\u007C" + + "\u0026\u001A\u0E8D\u0E94\u0E95\u0E96\u0E97\u0E99\u0E9A\u005D\u0021\u0024\u002A\u0029\u003B\u00AC" + + "\u002D\u002F\u0E9B\u0E9C\u0E9D\u0E9E\u0E9F\u0EA1\u0EA2\u005E\u00A6\u002C\u0025\u005F\u003E\u003F" + + "\u006B\u001A\u0EA3\u0EA5\u0EA7\u0EAB\u0EAD\u0EAE\u001A\u0060\u003A\u0023\u0040\'\u003D\"" + + "\u001A\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u001A\u001A\u0EAF\u0EB0\u0EB2\u0EB3" + + "\u001A\u006A\u006B\u006C\u006D\u006E\u006F\u0070\u0071\u0072\u0EB4\u0EB5\u0EB6\u0EB7\u0EB8\u0EB9" + + "\u001A\u007E\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007A\u0EBC\u0EB1\u0EBB\u0EBD\u001A\u001A" + + "\u0ED0\u0ED1\u0ED2\u0ED3\u0ED4\u0ED5\u0ED6\u0ED7\u0ED8\u0ED9\u001A\u0EC0\u0EC1\u0EC2\u0EC3\u0EC4" + + "\u007B\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u001A\u0EC8\u0EC9\u0ECA\u0ECB\u0ECC" + + "\u007D\u004A\u004B\u004C\u004D\u004E\u004F\u0050\u0051\u0052\u0ECD\u0EC6\u001A\u0EDC\u0EDD\u001A" + + "\\\u001A\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005A\u001A\u001A\u001A\u001A\u001A\u001A" + + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u001A\u001A\u001A\u001A\u001A\u009F"; + + private static final String SCP1137 = + "\u0000\u0001\u0002\u0003\u009C\t\u0086\u007F\u0097\u008D\u008E\u000B\f\r\u000E\u000F" + + "\u0010\u0011\u0012\u0013\u009D\u0085\b\u0087\u0018\u0019\u0092\u008F\u001C\u001D\u001E\u001F" + + "\u0080\u0081\u0082\u0083\u0084\n\u0017\u001B\u0088\u0089\u008A\u008B\u008C\u0005\u0006\u0007" + + "\u0090\u0091\u0016\u0093\u0094\u0095\u0096\u0004\u0098\u0099\u009A\u009B\u0014\u0015\u009E\u001A" + + "\u0020\u00A0\u0901\u0902\u0903\u0905\u0906\u0907\u0908\u0909\u090A\u002E\u003C\u0028\u002B\u007C" + + "\u0026\u090B\u090C\u090D\u090E\u090F\u0910\u0911\u0912\u0913\u0021\u0024\u002A\u0029\u003B\u005E" + + "\u002D\u002F\u0914\u0915\u0916\u0917\u0918\u0919\u091A\u091B\u091C\u002C\u0025\u005F\u003E\u003F" + + "\u091D\u091E\u091F\u0920\u0921\u0922\u0923\u0924\u0925\u0060\u003A\u0023\u0040\'\u003D\"" + + "\u0926\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u0927\u0928\u092A\u092B\u092C\u092D" + + "\u092E\u006A\u006B\u006C\u006D\u006E\u006F\u0070\u0071\u0072\u092F\u0930\u0932\u0933\u0935\u0936" + + "\u200C\u007E\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007A\u0937\u0938\u0939\u005B\u093C\u093D" + + "\u093E\u093F\u0940\u0941\u0942\u0943\u0944\u0945\u0946\u0947\u0948\u0949\u094A\u005D\u094B\u094C" + + "\u007B\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u094D\u0950\u0951\u0952\u001A\u001A" + + "\u007D\u004A\u004B\u004C\u004D\u004E\u004F\u0050\u0051\u0052\u0960\u0961\u0962\u0963\u0964\u0965" + + "\\\u200D\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005A\u0966\u0967\u0968\u0969\u096A\u096B" + + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u096C\u096D\u096E\u096F\u0970\u009F"; + + private static final String SCP1142 = + "\u0000\u0001\u0002\u0003\u009C\t\u0086\u007F\u0097\u008D\u008E\u000B\f\r\u000E\u000F" + + "\u0010\u0011\u0012\u0013\u009D\u0085\b\u0087\u0018\u0019\u0092\u008F\u001C\u001D\u001E\u001F" + + "\u0080\u0081\u0082\u0083\u0084\n\u0017\u001B\u0088\u0089\u008A\u008B\u008C\u0005\u0006\u0007" + + "\u0090\u0091\u0016\u0093\u0094\u0095\u0096\u0004\u0098\u0099\u009A\u009B\u0014\u0015\u009E\u001A" + + "\u0020\u00A0\u00E2\u00E4\u00E0\u00E1\u00E3\u007D\u00E7\u00F1\u0023\u002E\u003C\u0028\u002B\u0021" + + "\u0026\u00E9\u00EA\u00EB\u00E8\u00ED\u00EE\u00EF\u00EC\u00DF\u20AC\u00C5\u002A\u0029\u003B\u005E" + + "\u002D\u002F\u00C2\u00C4\u00C0\u00C1\u00C3\u0024\u00C7\u00D1\u00F8\u002C\u0025\u005F\u003E\u003F" + + "\u00A6\u00C9\u00CA\u00CB\u00C8\u00CD\u00CE\u00CF\u00CC\u0060\u003A\u00C6\u00D8\'\u003D\"" + + "\u0040\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u00AB\u00BB\u00F0\u00FD\u00FE\u00B1" + + "\u00B0\u006A\u006B\u006C\u006D\u006E\u006F\u0070\u0071\u0072\u00AA\u00BA\u007B\u00B8\u005B\u005D" + + "\u00B5\u00FC\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007A\u00A1\u00BF\u00D0\u00DD\u00DE\u00AE" + + "\u00A2\u00A3\u00A5\u00B7\u00A9\u00A7\u00B6\u00BC\u00BD\u00BE\u00AC\u007C\u00AF\u00A8\u00B4\u00D7" + + "\u00E6\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u00AD\u00F4\u00F6\u00F2\u00F3\u00F5" + + "\u00E5\u004A\u004B\u004C\u004D\u004E\u004F\u0050\u0051\u0052\u00B9\u00FB\u007E\u00F9\u00FA\u00FF" + + "\\\u00F7\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005A\u00B2\u00D4\u00D6\u00D2\u00D3\u00D5" + + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u00B3\u00DB\u00DC\u00D9\u00DA\u009F"; + + private static final String SCP1145 = + "\u0000\u0001\u0002\u0003\u009C\t\u0086\u007F\u0097\u008D\u008E\u000B\f\r\u000E\u000F" + + "\u0010\u0011\u0012\u0013\u009D\u0085\b\u0087\u0018\u0019\u0092\u008F\u001C\u001D\u001E\u001F" + + "\u0080\u0081\u0082\u0083\u0084\n\u0017\u001B\u0088\u0089\u008A\u008B\u008C\u0005\u0006\u0007" + + "\u0090\u0091\u0016\u0093\u0094\u0095\u0096\u0004\u0098\u0099\u009A\u009B\u0014\u0015\u009E\u001A" + + "\u0020\u00A0\u00E2\u00E4\u00E0\u00E1\u00E3\u00E5\u00E7\u00A6\u005B\u002E\u003C\u0028\u002B\u007C" + + "\u0026\u00E9\u00EA\u00EB\u00E8\u00ED\u00EE\u00EF\u00EC\u00DF\u005D\u0024\u002A\u0029\u003B\u00AC" + + "\u002D\u002F\u00C2\u00C4\u00C0\u00C1\u00C3\u00C5\u00C7\u0023\u00F1\u002C\u0025\u005F\u003E\u003F" + + "\u00F8\u00C9\u00CA\u00CB\u00C8\u00CD\u00CE\u00CF\u00CC\u0060\u003A\u00D1\u0040\'\u003D\"" + + "\u00D8\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u00AB\u00BB\u00F0\u00FD\u00FE\u00B1" + + "\u00B0\u006A\u006B\u006C\u006D\u006E\u006F\u0070\u0071\u0072\u00AA\u00BA\u00E6\u00B8\u00C6\u20AC" + + "\u00B5\u00A8\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007A\u00A1\u00BF\u00D0\u00DD\u00DE\u00AE" + + "\u00A2\u00A3\u00A5\u00B7\u00A9\u00A7\u00B6\u00BC\u00BD\u00BE\u005E\u0021\u00AF\u007E\u00B4\u00D7" + + "\u007B\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u00AD\u00F4\u00F6\u00F2\u00F3\u00F5" + + "\u007D\u004A\u004B\u004C\u004D\u004E\u004F\u0050\u0051\u0052\u00B9\u00FB\u00FC\u00F9\u00FA\u00FF" + + "\\\u00F7\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005A\u00B2\u00D4\u00D6\u00D2\u00D3\u00D5" + + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u00B3\u00DB\u00DC\u00D9\u00DA\u009F"; + + private static final String SCP1146 = + "\u0000\u0001\u0002\u0003\u009C\t\u0086\u007F\u0097\u008D\u008E\u000B\f\r\u000E\u000F" + + "\u0010\u0011\u0012\u0013\u009D\u0085\b\u0087\u0018\u0019\u0092\u008F\u001C\u001D\u001E\u001F" + + "\u0080\u0081\u0082\u0083\u0084\n\u0017\u001B\u0088\u0089\u008A\u008B\u008C\u0005\u0006\u0007" + + "\u0090\u0091\u0016\u0093\u0094\u0095\u0096\u0004\u0098\u0099\u009A\u009B\u0014\u0015\u009E\u001A" + + "\u0020\u00A0\u00E2\u00E4\u00E0\u00E1\u00E3\u00E5\u00E7\u00F1\u0024\u002E\u003C\u0028\u002B\u007C" + + "\u0026\u00E9\u00EA\u00EB\u00E8\u00ED\u00EE\u00EF\u00EC\u00DF\u0021\u00A3\u002A\u0029\u003B\u00AC" + + "\u002D\u002F\u00C2\u00C4\u00C0\u00C1\u00C3\u00C5\u00C7\u00D1\u00A6\u002C\u0025\u005F\u003E\u003F" + + "\u00F8\u00C9\u00CA\u00CB\u00C8\u00CD\u00CE\u00CF\u00CC\u0060\u003A\u0023\u0040\'\u003D\"" + + "\u00D8\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u00AB\u00BB\u00F0\u00FD\u00FE\u00B1" + + "\u00B0\u006A\u006B\u006C\u006D\u006E\u006F\u0070\u0071\u0072\u00AA\u00BA\u00E6\u00B8\u00C6\u20AC" + + "\u00B5\u00AF\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007A\u00A1\u00BF\u00D0\u00DD\u00DE\u00AE" + + "\u00A2\u005B\u00A5\u00B7\u00A9\u00A7\u00B6\u00BC\u00BD\u00BE\u005E\u005D\u007E\u00A8\u00B4\u00D7" + + "\u007B\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u00AD\u00F4\u00F6\u00F2\u00F3\u00F5" + + "\u007D\u004A\u004B\u004C\u004D\u004E\u004F\u0050\u0051\u0052\u00B9\u00FB\u00FC\u00F9\u00FA\u00FF" + + "\\\u00F7\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005A\u00B2\u00D4\u00D6\u00D2\u00D3\u00D5" + + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u00B3\u00DB\u00DC\u00D9\u00DA\u009F"; + + private static final String SCP1148 = + "\u0000\u0001\u0002\u0003\u009C\t\u0086\u007F\u0097\u008D\u008E\u000B\f\r\u000E\u000F" + + "\u0010\u0011\u0012\u0013\u009D\u0085\b\u0087\u0018\u0019\u0092\u008F\u001C\u001D\u001E\u001F" + + "\u0080\u0081\u0082\u0083\u0084\n\u0017\u001B\u0088\u0089\u008A\u008B\u008C\u0005\u0006\u0007" + + "\u0090\u0091\u0016\u0093\u0094\u0095\u0096\u0004\u0098\u0099\u009A\u009B\u0014\u0015\u009E\u001A" + + "\u0020\u00A0\u00E2\u00E4\u00E0\u00E1\u00E3\u00E5\u00E7\u00F1\u005B\u002E\u003C\u0028\u002B\u0021" + + "\u0026\u00E9\u00EA\u00EB\u00E8\u00ED\u00EE\u00EF\u00EC\u00DF\u005D\u0024\u002A\u0029\u003B\u005E" + + "\u002D\u002F\u00C2\u00C4\u00C0\u00C1\u00C3\u00C5\u00C7\u00D1\u00A6\u002C\u0025\u005F\u003E\u003F" + + "\u00F8\u00C9\u00CA\u00CB\u00C8\u00CD\u00CE\u00CF\u00CC\u0060\u003A\u0023\u0040\'\u003D\"" + + "\u00D8\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u00AB\u00BB\u00F0\u00FD\u00FE\u00B1" + + "\u00B0\u006A\u006B\u006C\u006D\u006E\u006F\u0070\u0071\u0072\u00AA\u00BA\u00E6\u00B8\u00C6\u20AC" + + "\u00B5\u007E\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007A\u00A1\u00BF\u00D0\u00DD\u00DE\u00AE" + + "\u00A2\u00A3\u00A5\u00B7\u00A9\u00A7\u00B6\u00BC\u00BD\u00BE\u00AC\u007C\u00AF\u00A8\u00B4\u00D7" + + "\u007B\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u00AD\u00F4\u00F6\u00F2\u00F3\u00F5" + + "\u007D\u004A\u004B\u004C\u004D\u004E\u004F\u0050\u0051\u0052\u00B9\u00FB\u00FC\u00F9\u00FA\u00FF" + + "\\\u00F7\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005A\u00B2\u00D4\u00D6\u00D2\u00D3\u00D5" + + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u00B3\u00DB\u00DC\u00D9\u00DA\u009F"; + + private static final String SCP1149 = + "\u0000\u0001\u0002\u0003\u009C\t\u0086\u007F\u0097\u008D\u008E\u000B\f\r\u000E\u000F" + + "\u0010\u0011\u0012\u0013\u009D\u0085\b\u0087\u0018\u0019\u0092\u008F\u001C\u001D\u001E\u001F" + + "\u0080\u0081\u0082\u0083\u0084\n\u0017\u001B\u0088\u0089\u008A\u008B\u008C\u0005\u0006\u0007" + + "\u0090\u0091\u0016\u0093\u0094\u0095\u0096\u0004\u0098\u0099\u009A\u009B\u0014\u0015\u009E\u001A" + + "\u0020\u00A0\u00E2\u00E4\u00E0\u00E1\u00E3\u00E5\u00E7\u00F1\u00DE\u002E\u003C\u0028\u002B\u0021" + + "\u0026\u00E9\u00EA\u00EB\u00E8\u00ED\u00EE\u00EF\u00EC\u00DF\u00C6\u0024\u002A\u0029\u003B\u00D6" + + "\u002D\u002F\u00C2\u00C4\u00C0\u00C1\u00C3\u00C5\u00C7\u00D1\u00A6\u002C\u0025\u005F\u003E\u003F" + + "\u00F8\u00C9\u00CA\u00CB\u00C8\u00CD\u00CE\u00CF\u00CC\u00F0\u003A\u0023\u00D0\'\u003D\"" + + "\u00D8\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u00AB\u00BB\u0060\u00FD\u007B\u00B1" + + "\u00B0\u006A\u006B\u006C\u006D\u006E\u006F\u0070\u0071\u0072\u00AA\u00BA\u007D\u00B8\u005D\u20AC" + + "\u00B5\u00F6\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007A\u00A1\u00BF\u0040\u00DD\u005B\u00AE" + + "\u00A2\u00A3\u00A5\u00B7\u00A9\u00A7\u00B6\u00BC\u00BD\u00BE\u00AC\u007C\u00AF\u00A8\\\u00D7" + + "\u00FE\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u00AD\u00F4\u007E\u00F2\u00F3\u00F5" + + "\u00E6\u004A\u004B\u004C\u004D\u004E\u004F\u0050\u0051\u0052\u00B9\u00FB\u00FC\u00F9\u00FA\u00FF" + + "\u00B4\u00F7\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005A\u00B2\u00D4\u005E\u00D2\u00D3\u00D5" + + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u00B3\u00DB\u00DC\u00D9\u00DA\u009F"; + + private static final String SCP1154 = + "\u0000\u0001\u0002\u0003\u009C\t\u0086\u007F\u0097\u008D\u008E\u000B\f\r\u000E\u000F" + + "\u0010\u0011\u0012\u0013\u009D\u0085\b\u0087\u0018\u0019\u0092\u008F\u001C\u001D\u001E\u001F" + + "\u0080\u0081\u0082\u0083\u0084\n\u0017\u001B\u0088\u0089\u008A\u008B\u008C\u0005\u0006\u0007" + + "\u0090\u0091\u0016\u0093\u0094\u0095\u0096\u0004\u0098\u0099\u009A\u009B\u0014\u0015\u009E\u001A" + + "\u0020\u00A0\u0452\u0453\u0451\u0454\u0455\u0456\u0457\u0458\u005B\u002E\u003C\u0028\u002B\u0021" + + "\u0026\u0459\u045A\u045B\u045C\u045E\u045F\u042A\u2116\u0402\u005D\u0024\u002A\u0029\u003B\u005E" + + "\u002D\u002F\u0403\u0401\u0404\u0405\u0406\u0407\u0408\u0409\u007C\u002C\u0025\u005F\u003E\u003F" + + "\u040A\u040B\u040C\u00AD\u040E\u040F\u044E\u0430\u0431\u0060\u003A\u0023\u0040\'\u003D\"" + + "\u0446\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u0434\u0435\u0444\u0433\u0445\u0438" + + "\u0439\u006A\u006B\u006C\u006D\u006E\u006F\u0070\u0071\u0072\u043A\u043B\u043C\u043D\u043E\u043F" + + "\u044F\u007E\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007A\u0440\u0441\u0442\u0443\u0436\u0432" + + "\u044C\u044B\u0437\u0448\u044D\u0449\u0447\u044A\u042E\u0410\u0411\u0426\u0414\u0415\u0424\u0413" + + "\u007B\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u0425\u0418\u0419\u041A\u041B\u041C" + + "\u007D\u004A\u004B\u004C\u004D\u004E\u004F\u0050\u0051\u0052\u041D\u041E\u041F\u042F\u0420\u0421" + + "\\\u20AC\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005A\u0422\u0423\u0416\u0412\u042C\u042B" + + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u0417\u0428\u042D\u0429\u0427\u009F"; + + private static final String SCP1155 = + "\u0000\u0001\u0002\u0003\u009C\t\u0086\u007F\u0097\u008D\u008E\u000B\f\r\u000E\u000F" + + "\u0010\u0011\u0012\u0013\u009D\u0085\b\u0087\u0018\u0019\u0092\u008F\u001C\u001D\u001E\u001F" + + "\u0080\u0081\u0082\u0083\u0084\n\u0017\u001B\u0088\u0089\u008A\u008B\u008C\u0005\u0006\u0007" + + "\u0090\u0091\u0016\u0093\u0094\u0095\u0096\u0004\u0098\u0099\u009A\u009B\u0014\u0015\u009E\u001A" + + "\u0020\u00A0\u00E2\u00E4\u00E0\u00E1\u00E3\u00E5\u007B\u00F1\u00C7\u002E\u003C\u0028\u002B\u0021" + + "\u0026\u00E9\u00EA\u00EB\u00E8\u00ED\u00EE\u00EF\u00EC\u00DF\u011E\u0130\u002A\u0029\u003B\u005E" + + "\u002D\u002F\u00C2\u00C4\u00C0\u00C1\u00C3\u00C5\u005B\u00D1\u015F\u002C\u0025\u005F\u003E\u003F" + + "\u00F8\u00C9\u00CA\u00CB\u00C8\u00CD\u00CE\u00CF\u00CC\u0131\u003A\u00D6\u015E\'\u003D\u00DC" + + "\u00D8\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u00AB\u00BB\u007D\u0060\u00A6\u00B1" + + "\u00B0\u006A\u006B\u006C\u006D\u006E\u006F\u0070\u0071\u0072\u00AA\u00BA\u00E6\u00B8\u00C6\u20AC" + + "\u00B5\u00F6\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007A\u00A1\u00BF\u005D\u0024\u0040\u00AE" + + "\u00A2\u00A3\u00A5\u00B7\u00A9\u00A7\u00B6\u00BC\u00BD\u00BE\u00AC\u007C\u00AF\u00A8\u00B4\u00D7" + + "\u00E7\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u00AD\u00F4\u007E\u00F2\u00F3\u00F5" + + "\u011F\u004A\u004B\u004C\u004D\u004E\u004F\u0050\u0051\u0052\u00B9\u00FB\\\u00F9\u00FA\u00FF" + + "\u00FC\u00F7\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005A\u00B2\u00D4\u0023\u00D2\u00D3\u00D5" + + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u00B3\u00DB\"\u00D9\u00DA\u009F"; + + private static final String SCP1156 = + "\u0000\u0001\u0002\u0003\u009C\t\u0086\u007F\u0097\u008D\u008E\u000B\f\r\u000E\u000F" + + "\u0010\u0011\u0012\u0013\u009D\u0085\b\u0087\u0018\u0019\u0092\u008F\u001C\u001D\u001E\u001F" + + "\u0080\u0081\u0082\u0083\u0084\n\u0017\u001B\u0088\u0089\u008A\u008B\u008C\u0005\u0006\u0007" + + "\u0090\u0091\u0016\u0093\u0094\u0095\u0096\u0004\u0098\u0099\u009A\u009B\u0014\u0015\u009E\u001A" + + "\u0020\u00A0\u0161\u00E4\u0105\u012F\u016B\u00E5\u0113\u017E\u00A2\u002E\u003C\u0028\u002B\u007C" + + "\u0026\u00E9\u0119\u0117\u010D\u0173\u201E\u201C\u0123\u00DF\u0021\u0024\u002A\u0029\u003B\u00AC" + + "\u002D\u002F\u0160\u00C4\u0104\u012E\u016A\u00C5\u0112\u017D\u00A6\u002C\u0025\u005F\u003E\u003F" + + "\u00F8\u00C9\u0118\u0116\u010C\u0172\u012A\u013B\u0122\u0060\u003A\u0023\u0040\'\u003D\"" + + "\u00D8\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u00AB\u00BB\u0101\u017C\u0144\u00B1" + + "\u00B0\u006A\u006B\u006C\u006D\u006E\u006F\u0070\u0071\u0072\u0156\u0157\u00E6\u0137\u00C6\u20AC" + + "\u00B5\u007E\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007A\u201D\u017A\u0100\u017B\u0143\u00AE" + + "\u005E\u00A3\u012B\u00B7\u00A9\u00A7\u00B6\u00BC\u00BD\u00BE\u005B\u005D\u0179\u0136\u013C\u00D7" + + "\u007B\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u00AD\u014D\u00F6\u0146\u00F3\u00F5" + + "\u007D\u004A\u004B\u004C\u004D\u004E\u004F\u0050\u0051\u0052\u00B9\u0107\u00FC\u0142\u015B\u2019" + + "\\\u00F7\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005A\u00B2\u014C\u00D6\u0145\u00D3\u00D5" + + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u00B3\u0106\u00DC\u0141\u015A\u009F"; + + private static final String SCP1157 = + "\u0000\u0001\u0002\u0003\u009C\t\u0086\u007F\u0097\u008D\u008E\u000B\f\r\u000E\u000F" + + "\u0010\u0011\u0012\u0013\u009D\u0085\b\u0087\u0018\u0019\u0092\u008F\u001C\u001D\u001E\u001F" + + "\u0080\u0081\u0082\u0083\u0084\n\u0017\u001B\u0088\u0089\u008A\u008B\u008C\u0005\u0006\u0007" + + "\u0090\u0091\u0016\u0093\u0094\u0095\u0096\u0004\u0098\u0099\u009A\u009B\u0014\u0015\u009E\u001A" + + "\u0020\u00A0\u00E2\u007B\u00E0\u00E1\u00E3\u007D\u00E7\u00F1\u00A7\u002E\u003C\u0028\u002B\u0021" + + "\u0026\u0060\u00EA\u00EB\u00E8\u00ED\u00EE\u00EF\u00EC\u00DF\u20AC\u00C5\u002A\u0029\u003B\u005E" + + "\u002D\u002F\u00C2\u0023\u00C0\u00C1\u00C3\u0024\u00C7\u00D1\u00F6\u002C\u0025\u005F\u003E\u003F" + + "\u00F8\\\u00CA\u00CB\u00C8\u00CD\u00CE\u00CF\u00CC\u00E9\u003A\u00C4\u00D6\'\u003D\"" + + "\u00D8\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u00AB\u00BB\u0161\u00FD\u017E\u00B1" + + "\u00B0\u006A\u006B\u006C\u006D\u006E\u006F\u0070\u0071\u0072\u00AA\u00BA\u00E6\u00B8\u00C6\u005D" + + "\u00B5\u00FC\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007A\u00A1\u00BF\u0160\u00DD\u017D\u00AE" + + "\u00A2\u00A3\u00A5\u00B7\u00A9\u005B\u00B6\u00BC\u00BD\u00BE\u00AC\u007C\u00AF\u00A8\u00B4\u00D7" + + "\u00E4\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u00AD\u00F4\u00A6\u00F2\u00F3\u00F5" + + "\u00E5\u004A\u004B\u004C\u004D\u004E\u004F\u0050\u0051\u0052\u00B9\u00FB\u007E\u00F9\u00FA\u00FF" + + "\u00C9\u00F7\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005A\u00B2\u00D4\u0040\u00D2\u00D3\u00D5" + + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u00B3\u00DB\u00DC\u00D9\u00DA\u009F"; + + private static final String SCP1158 = + "\u0000\u0001\u0002\u0003\u009C\t\u0086\u007F\u0097\u008D\u008E\u000B\f\r\u000E\u000F" + + "\u0010\u0011\u0012\u0013\u009D\u0085\b\u0087\u0018\u0019\u0092\u008F\u001C\u001D\u001E\u001F" + + "\u0080\u0081\u0082\u0083\u0084\n\u0017\u001B\u0088\u0089\u008A\u008B\u008C\u0005\u0006\u0007" + + "\u0090\u0091\u0016\u0093\u0094\u0095\u0096\u0004\u0098\u0099\u009A\u009B\u0014\u0015\u009E\u001A" + + "\u0020\u00A0\u0452\u0491\u0451\u0454\u0455\u0456\u0457\u0458\u005B\u002E\u003C\u0028\u002B\u0021" + + "\u0026\u0459\u045A\u045B\u045C\u045E\u045F\u042A\u2116\u0402\u005D\u0024\u002A\u0029\u003B\u005E" + + "\u002D\u002F\u0490\u0401\u0404\u0405\u0406\u0407\u0408\u0409\u007C\u002C\u0025\u005F\u003E\u003F" + + "\u040A\u040B\u040C\u00AD\u040E\u040F\u044E\u0430\u0431\u0060\u003A\u0023\u0040\'\u003D\"" + + "\u0446\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u0434\u0435\u0444\u0433\u0445\u0438" + + "\u0439\u006A\u006B\u006C\u006D\u006E\u006F\u0070\u0071\u0072\u043A\u043B\u043C\u043D\u043E\u043F" + + "\u044F\u007E\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007A\u0440\u0441\u0442\u0443\u0436\u0432" + + "\u044C\u044B\u0437\u0448\u044D\u0449\u0447\u044A\u042E\u0410\u0411\u0426\u0414\u0415\u0424\u0413" + + "\u007B\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u0425\u0418\u0419\u041A\u041B\u041C" + + "\u007D\u004A\u004B\u004C\u004D\u004E\u004F\u0050\u0051\u0052\u041D\u041E\u041F\u042F\u0420\u0421" + + "\\\u20AC\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005A\u0422\u0423\u0416\u0412\u042C\u042B" + + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u0417\u0428\u042D\u0429\u0427\u009F"; + + private static final String SCP1164 = + "\u0000\u0001\u0002\u0003\u009C\t\u0086\u007F\u0097\u008D\u008E\u000B\f\r\u000E\u000F" + + "\u0010\u0011\u0012\u0013\u009D\u0085\b\u0087\u0018\u0019\u0092\u008F\u001C\u001D\u001E\u001F" + + "\u0080\u0081\u0082\u0083\u0084\n\u0017\u001B\u0088\u0089\u008A\u008B\u008C\u0005\u0006\u0007" + + "\u0090\u0091\u0016\u0093\u0094\u0095\u0096\u0004\u0098\u0099\u009A\u009B\u0014\u0015\u009E\u001A" + + "\u0020\u00A0\u00E2\u00E4\u00E0\u00E1\u0103\u00E5\u00E7\u00F1\u005B\u002E\u003C\u0028\u002B\u0021" + + "\u0026\u00E9\u00EA\u00EB\u00E8\u00ED\u00EE\u00EF\u0303\u00DF\u005D\u0024\u002A\u0029\u003B\u005E" + + "\u002D\u002F\u00C2\u00C4\u00C0\u00C1\u0102\u00C5\u00C7\u00D1\u00A6\u002C\u0025\u005F\u003E\u003F" + + "\u00F8\u00C9\u00CA\u00CB\u00C8\u00CD\u00CE\u00CF\u20AB\u0060\u003A\u0023\u0040\'\u003D\"" + + "\u00D8\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u00AB\u00BB\u0111\u0309\u0300\u00B1" + + "\u00B0\u006A\u006B\u006C\u006D\u006E\u006F\u0070\u0071\u0072\u00AA\u00BA\u00E6\u0152\u00C6\u20AC" + + "\u00B5\u007E\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007A\u00A1\u00BF\u0110\u0323\u0301\u00AE" + + "\u00A2\u00A3\u00A5\u00B7\u00A9\u00A7\u00B6\u00BC\u00BD\u00BE\u00AC\u007C\u00AF\u0153\u0178\u00D7" + + "\u007B\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u00AD\u00F4\u00F6\u01B0\u00F3\u01A1" + + "\u007D\u004A\u004B\u004C\u004D\u004E\u004F\u0050\u0051\u0052\u00B9\u00FB\u00FC\u00F9\u00FA\u00FF" + + "\\\u00F7\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005A\u00B2\u00D4\u00D6\u01AF\u00D3\u01A0" + + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u00B3\u00DB\u00DC\u00D9\u00DA\u009F"; + + private static final String SCP420 = + "\u0000\u0001\u0002\u0003\u009C\t\u0086\u007F\u0097\u008D\u008E\u000B\f\r\u000E\u000F" + + "\u0010\u0011\u0012\u0013\u009D\u0085\b\u0087\u0018\u0019\u0092\u008F\u001C\u001D\u001E\u001F" + + "\u0080\u0081\u0082\u0083\u0084\n\u0017\u001B\u0088\u0089\u008A\u008B\u008C\u0005\u0006\u0007" + + "\u0090\u0091\u0016\u0093\u0094\u0095\u0096\u0004\u0098\u0099\u009A\u009B\u0014\u0015\u009E\u001A" + + "\u0020\u00A0\u0651\uFE7D\u0640\u200B\u0621\u0622\uFE82\u0623\u00A2\u002E\u003C\u0028\u002B\u007C" + + "\u0026\uFE84\u0624\u001A\u001A\u0626\u0627\uFE8E\u0628\uFE91\u0021\u0024\u002A\u0029\u003B\u00AC" + + "\u002D\u002F\u0629\u062A\uFE97\u062B\uFE9B\u062C\uFE9F\u062D\u00A6\u002C\u0025\u005F\u003E\u003F" + + "\uFEA3\u062E\uFEA7\u062F\u0630\u0631\u0632\u0633\uFEB3\u060C\u003A\u0023\u0040\'\u003D\"" + + "\u0634\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\uFEB7\u0635\uFEBB\u0636\uFEBF\u0637" + + "\u0638\u006A\u006B\u006C\u006D\u006E\u006F\u0070\u0071\u0072\u0639\uFECA\uFECB\uFECC\u063A\uFECE" + + "\uFECF\u00F7\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007A\uFED0\u0641\uFED3\u0642\uFED7\u0643" + + "\uFEDB\u0644\uFEF5\uFEF6\uFEF7\uFEF8\u001A\u001A\uFEFB\uFEFC\uFEDF\u0645\uFEE3\u0646\uFEE7\u0647" + + "\u061B\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u00AD\uFEEB\u001A\uFEEC\u001A\u0648" + + "\u061F\u004A\u004B\u004C\u004D\u004E\u004F\u0050\u0051\u0052\u0649\uFEF0\u064A\uFEF2\uFEF3\u0660" + + "\u00D7\u2007\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005A\u0661\u0662\u001A\u0663\u0664\u0665" + + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u20AC\u0666\u0667\u0668\u0669\u009F"; + + private static final String SCP871 = + "\u0000\u0001\u0002\u0003\u009C\t\u0086\u007F\u0097\u008D\u008E\u000B\f\r\u000E\u000F" + + "\u0010\u0011\u0012\u0013\u009D\u0085\b\u0087\u0018\u0019\u0092\u008F\u001C\u001D\u001E\u001F" + + "\u0080\u0081\u0082\u0083\u0084\n\u0017\u001B\u0088\u0089\u008A\u008B\u008C\u0005\u0006\u0007" + + "\u0090\u0091\u0016\u0093\u0094\u0095\u0096\u0004\u0098\u0099\u009A\u009B\u0014\u0015\u009E\u001A" + + "\u0020\u00A0\u00E2\u00E4\u00E0\u00E1\u00E3\u00E5\u00E7\u00F1\u00DE\u002E\u003C\u0028\u002B\u0021" + + "\u0026\u00E9\u00EA\u00EB\u00E8\u00ED\u00EE\u00EF\u00EC\u00DF\u00C6\u0024\u002A\u0029\u003B\u00D6" + + "\u002D\u002F\u00C2\u00C4\u00C0\u00C1\u00C3\u00C5\u00C7\u00D1\u00A6\u002C\u0025\u005F\u003E\u003F" + + "\u00F8\u00C9\u00CA\u00CB\u00C8\u00CD\u00CE\u00CF\u00CC\u00F0\u003A\u0023\u00D0\'\u003D\"" + + "\u00D8\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u00AB\u00BB\u0060\u00FD\u007B\u00B1" + + "\u00B0\u006A\u006B\u006C\u006D\u006E\u006F\u0070\u0071\u0072\u00AA\u00BA\u007D\u00B8\u005D\u00A4" + + "\u00B5\u00F6\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007A\u00A1\u00BF\u0040\u00DD\u005B\u00AE" + + "\u00A2\u00A3\u00A5\u00B7\u00A9\u00A7\u00B6\u00BC\u00BD\u00BE\u00AC\u007C\u00AF\u00A8\\\u00D7" + + "\u00FE\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u00AD\u00F4\u007E\u00F2\u00F3\u00F5" + + "\u00E6\u004A\u004B\u004C\u004D\u004E\u004F\u0050\u0051\u0052\u00B9\u00FB\u00FC\u00F9\u00FA\u00FF" + + "\u00B4\u00F7\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005A\u00B2\u00D4\u005E\u00D2\u00D3\u00D5" + + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u00B3\u00DB\u00DC\u00D9\u00DA\u009F"; + + private static final String SCP875 = + "\u0000\u0001\u0002\u0003\u009C\t\u0086\u007F\u0097\u008D\u008E\u000B\f\r\u000E\u000F" + + "\u0010\u0011\u0012\u0013\u009D\u0085\b\u0087\u0018\u0019\u0092\u008F\u001C\u001D\u001E\u001F" + + "\u0080\u0081\u0082\u0083\u0084\n\u0017\u001B\u0088\u0089\u008A\u008B\u008C\u0005\u0006\u0007" + + "\u0090\u0091\u0016\u0093\u0094\u0095\u0096\u0004\u0098\u0099\u009A\u009B\u0014\u0015\u009E\u001A" + + "\u0020\u0391\u0392\u0393\u0394\u0395\u0396\u0397\u0398\u0399\u005B\u002E\u003C\u0028\u002B\u0021" + + "\u0026\u039A\u039B\u039C\u039D\u039E\u039F\u03A0\u03A1\u03A3\u005D\u0024\u002A\u0029\u003B\u005E" + + "\u002D\u002F\u03A4\u03A5\u03A6\u03A7\u03A8\u03A9\u03AA\u03AB\u007C\u002C\u0025\u005F\u003E\u003F" + + "\u00A8\u0386\u0388\u0389\u00A0\u038A\u038C\u038E\u038F\u0060\u003A\u0023\u0040\'\u003D\"" + + "\u0385\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u03B1\u03B2\u03B3\u03B4\u03B5\u03B6" + + "\u00B0\u006A\u006B\u006C\u006D\u006E\u006F\u0070\u0071\u0072\u03B7\u03B8\u03B9\u03BA\u03BB\u03BC" + + "\u00B4\u007E\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007A\u03BD\u03BE\u03BF\u03C0\u03C1\u03C3" + + "\u00A3\u03AC\u03AD\u03AE\u03CA\u03AF\u03CC\u03CD\u03CB\u03CE\u03C2\u03C4\u03C5\u03C6\u03C7\u03C8" + + "\u007B\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u00AD\u03C9\u0390\u03B0\u2018\u2015" + + "\u007D\u004A\u004B\u004C\u004D\u004E\u004F\u0050\u0051\u0052\u00B1\u00BD\u001A\u0387\u2019\u00A6" + + "\\\u001A\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005A\u00B2\u00A7\u001A\u001A\u00AB\u00AC" + + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u00B3\u00A9\u001A\u001A\u00BB\u009F"; + + public static final XIEbcdicNTranslator TRANSLATOR_CP1025 = + new XIEbcdicNTranslator(SCP2CP(SCP1025)); + public static final XIEbcdicNTranslator TRANSLATOR_CP1026 = + new XIEbcdicNTranslator(SCP2CP(SCP1026)); + + public static final XIEbcdicNTranslator TRANSLATOR_CP1112 = + new XIEbcdicNTranslator(SCP2CP(SCP1112)); + public static final XIEbcdicNTranslator TRANSLATOR_CP1122 = + new XIEbcdicNTranslator(SCP2CP(SCP1122)); + public static final XIEbcdicNTranslator TRANSLATOR_CP1123 = + new XIEbcdicNTranslator(SCP2CP(SCP1123)); + public static final XIEbcdicNTranslator TRANSLATOR_CP1125 = + new XIEbcdicNTranslator(SCP2CP(SCP1125)); + + public static final XIEbcdicNTranslator TRANSLATOR_CP1130 = + new XIEbcdicNTranslator(SCP2CP(SCP1130)); + public static final XIEbcdicNTranslator TRANSLATOR_CP1132 = + new XIEbcdicNTranslator(SCP2CP(SCP1132)); + public static final XIEbcdicNTranslator TRANSLATOR_CP1137 = + new XIEbcdicNTranslator(SCP2CP(SCP1137)); + + public static final XIEbcdicNTranslator TRANSLATOR_CP1142 = + new XIEbcdicNTranslator(SCP2CP(SCP1142)); + public static final XIEbcdicNTranslator TRANSLATOR_CP1145 = + new XIEbcdicNTranslator(SCP2CP(SCP1145)); + public static final XIEbcdicNTranslator TRANSLATOR_CP1146 = + new XIEbcdicNTranslator(SCP2CP(SCP1146)); + public static final XIEbcdicNTranslator TRANSLATOR_CP1148 = + new XIEbcdicNTranslator(SCP2CP(SCP1148)); + public static final XIEbcdicNTranslator TRANSLATOR_CP1149 = + new XIEbcdicNTranslator(SCP2CP(SCP1149)); + + public static final XIEbcdicNTranslator TRANSLATOR_CP1154 = + new XIEbcdicNTranslator(SCP2CP(SCP1154)); + public static final XIEbcdicNTranslator TRANSLATOR_CP1155 = + new XIEbcdicNTranslator(SCP2CP(SCP1155)); + public static final XIEbcdicNTranslator TRANSLATOR_CP1156 = + new XIEbcdicNTranslator(SCP2CP(SCP1156)); + public static final XIEbcdicNTranslator TRANSLATOR_CP1157 = + new XIEbcdicNTranslator(SCP2CP(SCP1157)); + public static final XIEbcdicNTranslator TRANSLATOR_CP1158 = + new XIEbcdicNTranslator(SCP2CP(SCP1158)); + + public static final XIEbcdicNTranslator TRANSLATOR_CP1164 = + new XIEbcdicNTranslator(SCP2CP(SCP1164)); + + public static final XIEbcdicNTranslator TRANSLATOR_CP420 = + new XIEbcdicNTranslator(SCP2CP(SCP420)); + public static final XIEbcdicNTranslator TRANSLATOR_CP871 = + new XIEbcdicNTranslator(SCP2CP(SCP871)); + public static final XIEbcdicNTranslator TRANSLATOR_CP875 = + new XIEbcdicNTranslator(SCP2CP(SCP875)); +} diff --git a/net/infordata/em/crt5250/XIEbcdicTranslator.java b/net/infordata/em/crt5250/XIEbcdicTranslator.java new file mode 100644 index 0000000..d4b9764 --- /dev/null +++ b/net/infordata/em/crt5250/XIEbcdicTranslator.java @@ -0,0 +1,273 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 10/04/97 rel. 0.93 - moved to crt5250 package. + 16/04/97 rel. 0.94 - toPacked method added. + 28/04/97 rel. 0.94c- corrected problem with underscore. + 27/05/97 rel. 1.00 - first release. + 25/07/97 rel. 1.03a- '|' char mapping. + 03/03/98 rel. _.___- SWING and reorganization. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.crt5250; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + + +/** + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public abstract class XIEbcdicTranslator { + + + private static final Map cvRegistry = + Collections.synchronizedMap(new LinkedHashMap()); + private static final Map cvRORegistry = + Collections.unmodifiableMap(cvRegistry); + + + static { + registerTranslator("CP37", XIEbcdicNTranslator.TRANSLATOR_CP37); + registerTranslator("CP273", XIEbcdicNTranslator.TRANSLATOR_CP273); + registerTranslator("CP277", XIEbcdicNTranslator.TRANSLATOR_CP277); + registerTranslator("CP278", XIEbcdicNTranslator.TRANSLATOR_CP278); + registerTranslator("CP280", XIEbcdicNTranslator.TRANSLATOR_CP280); + registerTranslator("CP284", XIEbcdicNTranslator.TRANSLATOR_CP284); + registerTranslator("CP285", XIEbcdicNTranslator.TRANSLATOR_CP285); + registerTranslator("CP297", XIEbcdicNTranslator.TRANSLATOR_CP297); + registerTranslator("CP424", XIEbcdicNTranslator.TRANSLATOR_CP424); + registerTranslator("CP500", XIEbcdicNTranslator.TRANSLATOR_CP500); + registerTranslator("CP850", XIEbcdicNTranslator.TRANSLATOR_CP850); + registerTranslator("CP870", XIEbcdicNTranslator.TRANSLATOR_CP870); + registerTranslator("CP838", XIEbcdicNTranslator.TRANSLATOR_CP838); + registerTranslator("CP1140", XIEbcdicNTranslator.TRANSLATOR_CP1140); + registerTranslator("CP1141", XIEbcdicNTranslator.TRANSLATOR_CP1141); + registerTranslator("CP1144", XIEbcdicNTranslator.TRANSLATOR_CP1144); + registerTranslator("CP1147", XIEbcdicNTranslator.TRANSLATOR_CP1147); + registerTranslator("CP1153", XIEbcdicNTranslator.TRANSLATOR_CP1153); + registerTranslator("CP1160", XIEbcdicNTranslator.TRANSLATOR_CP1160); + // + registerTranslator("CP1025", XIEbcdicNTranslator.TRANSLATOR_CP1025); + registerTranslator("CP1026", XIEbcdicNTranslator.TRANSLATOR_CP1026); + + registerTranslator("CP1112", XIEbcdicNTranslator.TRANSLATOR_CP1112); + registerTranslator("CP1122", XIEbcdicNTranslator.TRANSLATOR_CP1122); + registerTranslator("CP1123", XIEbcdicNTranslator.TRANSLATOR_CP1123); + registerTranslator("CP1125", XIEbcdicNTranslator.TRANSLATOR_CP1125); + + registerTranslator("CP1130", XIEbcdicNTranslator.TRANSLATOR_CP1130); + registerTranslator("CP1132", XIEbcdicNTranslator.TRANSLATOR_CP1132); + registerTranslator("CP1137", XIEbcdicNTranslator.TRANSLATOR_CP1137); + + registerTranslator("CP1142", XIEbcdicNTranslator.TRANSLATOR_CP1142); + registerTranslator("CP1145", XIEbcdicNTranslator.TRANSLATOR_CP1145); + registerTranslator("CP1146", XIEbcdicNTranslator.TRANSLATOR_CP1146); + registerTranslator("CP1148", XIEbcdicNTranslator.TRANSLATOR_CP1148); + registerTranslator("CP1149", XIEbcdicNTranslator.TRANSLATOR_CP1149); + + registerTranslator("CP1154", XIEbcdicNTranslator.TRANSLATOR_CP1154); + registerTranslator("CP1155", XIEbcdicNTranslator.TRANSLATOR_CP1155); + registerTranslator("CP1156", XIEbcdicNTranslator.TRANSLATOR_CP1156); + registerTranslator("CP1157", XIEbcdicNTranslator.TRANSLATOR_CP1157); + registerTranslator("CP1158", XIEbcdicNTranslator.TRANSLATOR_CP1158); + + registerTranslator("CP1164", XIEbcdicNTranslator.TRANSLATOR_CP1164); + + registerTranslator("CP420", XIEbcdicNTranslator.TRANSLATOR_CP420); + registerTranslator("CP871", XIEbcdicNTranslator.TRANSLATOR_CP871); + registerTranslator("CP875", XIEbcdicNTranslator.TRANSLATOR_CP875); + } + + + /** + */ + protected XIEbcdicTranslator() { + } + + + /** + */ + public static synchronized void registerTranslator(String id, + XIEbcdicTranslator tr) { + if (id == null) + throw new NullPointerException("id is null"); + if (tr == null) + throw new NullPointerException("tr is null"); + if (cvRegistry.containsKey(id.toLowerCase())) + throw new IllegalArgumentException("Translator " + id.toLowerCase() + " already registered"); + cvRegistry.put(id.toLowerCase(), tr); + } + + + /** + * @return a read-only map of registered translators + */ + public static Map getRegisteredTranslators() { + return cvRORegistry; + } + + + /** + * Returns the XIEbcdicTranslator. + */ + public static XIEbcdicTranslator getTranslator(String id) { + return cvRegistry.get(id.toLowerCase()); + } + + + /** + * Converts byte to int without sign. + */ + public static final int toInt(byte bb) { + return ((int)bb & 0xff); + } + + + /** + * Converts byte to hex rapresentation + */ + public static final String toHex(byte bb) { + String hex = Integer.toString(toInt(bb), 16); + return "00".substring(hex.length()) + hex; + } + + + /** + * From ebcdic code to char + */ + public abstract char toChar(byte aEbcdicChar); + + + /** + * From char to ebcdic code + */ + public abstract byte toEBCDIC(char aChar); + + + /** + * From String to ebcdic string + */ + public byte[] toText(String aString, int aLen) { + byte[] bb = new byte[aLen]; + int i; + int len = Math.min(aLen, aString.length()); + + for (i = 0; i < len; i++) + bb[i] = toEBCDIC(aString.charAt(i)); + // fill with space + for (i = len; i < aLen; i++) + bb[i] = toEBCDIC(' '); + + return bb; + } + + + /** + * From int to ebcdic numeric not packed + */ + public byte[] toNumeric(int aNum, int aLen) { + byte[] bb = new byte[aLen]; + int i; + + for (i = aLen - 1; i >= 0; i--) { + bb[i] = toEBCDIC((char)(((int)'0') + (aNum % 10))); + aNum /= 10; + } + + return bb; + } + + + /** + * From int to packed + */ + public byte[] toPacked(int aNum, int aLen) { + byte[] res = new byte[(aLen + 1) / 2]; + int x; + + for (int i = res.length - 1; i >= 0; i--) { + if (i == res.length - 1 && aNum < 0) { + res[i] = (byte)0x0D; + } + else { + x = aNum % 10; + aNum /= 10; + res[i] = (byte)x; + } + + x = aNum % 10; + aNum /= 10; + res[i] |= (byte)(x << 4); + } + + return res; + } + + + /** + * From ebcdic string to String + */ + public String toString(byte[] aBuf, int aOfs, int aLen) { + String str = ""; + int i; + + for (i = aOfs; i < (aOfs + aLen); i++) + str += toChar(aBuf[i]); + + // strip trailing blanks + for (i = str.length() - 1; (i >= 0) && (str.charAt(i) == ' '); i--) + ; + + return str.substring(0, Math.max(0, Math.min(str.length(), i + 1))); + } + + + /** + * From ebcdic numeric not packed to int + */ + public int toInt(byte[] aBuf, int aOfs, int aLen) { + String str = toString(aBuf, aOfs, aLen); + return Integer.parseInt(str); + } + + + /** + * From ebcdic packed to int + */ + public int toIntFromPacked(byte[] aBuf, int aOfs, int aLen) { + int res = 0; + + for (int i = aOfs; i < (aOfs + aLen); i++) { + res = (res * 100) + ((aBuf[i] >> 4 & 0x0F) * 10); + + if ((aBuf[i] & 0x0F) == 0x0D) + res /= -10; + else if ((aBuf[i] & 0x0F) == 0x0F) + res /= 10; + else + res += (aBuf[i] & 0x0F); + } + + return res; + } +} \ No newline at end of file diff --git a/net/infordata/em/crt5250/XIImagesBdl.java b/net/infordata/em/crt5250/XIImagesBdl.java new file mode 100644 index 0000000..bdfed1c --- /dev/null +++ b/net/infordata/em/crt5250/XIImagesBdl.java @@ -0,0 +1,124 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** +!!V 15/06/99 rel. 1.13 - creation. + */ + + +package net.infordata.em.crt5250; + +import java.awt.Image; +import java.util.HashMap; +import java.util.ListResourceBundle; +import java.util.Map; + +import javax.swing.Icon; +import javax.swing.ImageIcon; + +import net.infordata.em.util.XIUtil; + + + +/** + * The image bundle. + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XIImagesBdl extends ListResourceBundle { + + private static XIImagesBdl cvImagesBdl; + + private static Object[][] cvContents = null; + + static { + try { + cvContents = new Object[][] { + {"ShiftDown", + XIUtil.createImage( + XIImagesBdl.class, "resources/ShiftDown.gif")}, + {"CapsLock", + XIUtil.createImage( + XIImagesBdl.class, "resources/CapsLock.gif")}, + // + {"3dFx", + XIUtil.createImage( + XIImagesBdl.class, "resources/3dFx.gif")}, + {"Copy", + XIUtil.createImage( + XIImagesBdl.class, "resources/Copy.gif")}, + {"Paste", + XIUtil.createImage( + XIImagesBdl.class, "resources/Paste.gif")}, + {"RefCursor", + XIUtil.createImage( + XIImagesBdl.class, "resources/RefCursor.gif")}, + {"Print", + XIUtil.createImage( + XIImagesBdl.class, "resources/Print.gif")}, + // + {"Logo", + XIUtil.createImage( + XIImagesBdl.class, "resources/Logo.gif")}, + }; + } + catch (RuntimeException ex) { + throw ex; + } + } + + + private XIImagesBdl() { + } + + + public static XIImagesBdl getImagesBdl() { + if (cvImagesBdl == null) { + cvImagesBdl = new XIImagesBdl(); + } + + return cvImagesBdl; + } + + + @Override + public Object[][] getContents() { + return cvContents; + } + + + /** + */ + public final Image getImage(String anImageName) { + return ((ImageIcon)getIcon(anImageName)).getImage(); + } + + + private Map ivIcons = new HashMap(); + + /** + */ + public synchronized final Icon getIcon(String anImageName) { + Icon icon = (Icon)ivIcons.get(anImageName); + if (icon == null) { + icon = new ImageIcon((Image)getObject(anImageName)); + ivIcons.put(anImageName, icon); + } + return icon; + } +} diff --git a/net/infordata/em/crt5250/resources/3dFx.gif b/net/infordata/em/crt5250/resources/3dFx.gif new file mode 100644 index 0000000000000000000000000000000000000000..3a83dfd2d1a70e4bf25160d34df8690d3add1298 GIT binary patch literal 1029 zcmZ?wbhEHb6k!ly_|5S;2UKZK8Y(lLdnV11mQd+p0SbPAZ&pMG{Zxa7;YHKF3OZ*OCbV@rQU6 z6NFr6eQ98674i0~IB}J!frVX5>x6?*Gt)%j|BMF`4lZqB=2B1FuyXU_J4>uTa^3my z?b!*|dRMuCf`kW5yBO}BTl-;sQ7R{!6#tUfi#Bod@aRZ8tp1r4%T=N&6R~#J7bmU_ i>H#x0?Ams;kxS%4oULMG%WZDKFbj@779W6tU=08eW1esT literal 0 HcmV?d00001 diff --git a/net/infordata/em/crt5250/resources/CapsLock.gif b/net/infordata/em/crt5250/resources/CapsLock.gif new file mode 100644 index 0000000000000000000000000000000000000000..b672b9f924161ddd02677e67676bde41dfc01e4b GIT binary patch literal 903 zcmXYwJ7|q75&eEYgbj0NiF{oVuUMEQRK5PE{-X~+YqeUvUT-uS&1Q3CWTe$< zwcG7Zr!zY{J3T!;F)`8YcH>4BGc#Lq*T2V)t+(6TThBJ`s7Mkq5r>?Lsw5Rtag``B zO_GvW5>FE4shT7cGjWqBnd*{U%*9=TeTaoPv~xWQkiip;0-&l%)l^+I3LfW_)RKDA zDDZ@nshPTI6gIq0uIB2lQ8H7gg?eZdq7a8E)CxYBfKZh(#cLo*IqBz_wBm)>cp3x>~BxjJ`eS(!NzE9 zZDpwaZs5p)TL;H~UwXf~=g`v&8#C+Y?~P9Fy}x;F?Bngu{PCN%`t{Aq$;(UEH-D|4 bd2sZ~)fZ2ikEd2n9bQ`Ky!@8GwbTCqLC>EW literal 0 HcmV?d00001 diff --git a/net/infordata/em/crt5250/resources/Copy.gif b/net/infordata/em/crt5250/resources/Copy.gif new file mode 100644 index 0000000000000000000000000000000000000000..971934aadc4943132a4776468ae6a224f556e322 GIT binary patch literal 153 zcmZ?wbhEHb6k!ly*vtR|4Pe{=rW$~}hK2(N4m310{0EBvXZR1MfHaT=1d2ad7#SFt z8FYY>Kodk57+Bm2PI#`~Ymv>f>%Q=Z9)ET|B~7LWyMzkPOjLF}JpJ~~CB6|W<2*%v n2bM6%y-noN&7H@$S?I2Awsc0xs=#}jjy}rt(VML=$Y2csLN7O4 literal 0 HcmV?d00001 diff --git a/net/infordata/em/crt5250/resources/Logo.gif b/net/infordata/em/crt5250/resources/Logo.gif new file mode 100644 index 0000000000000000000000000000000000000000..6a8eb11388edf3d557d53f194136d77c51c6ea58 GIT binary patch literal 1969 zcmX9-2~bl<7+wO^5JT{&0v<@f${|JY*>VUP!E#6uMvGF$3W9kBtCk*9k=l@;Mg-I- z5`8F;;Sf;^!K2WUkyw;-g;u9PsgyvF(1?LhiXhXx{(0S*%^C zIN0CcpFS?8V`92dJ|3gTyPI{o?(eH)1VSW26haul2}BTxBoIX)Ody)MBS=J&h$0at z5zRa$C`3|-q7bGK&2$nNkr+`JVT@=v(}E0Qi4{9ZnU9pOBDn z^ypEkR4SLtJ32b<+_}@!)6?JIuhnYxdcDzToSB)S=Oz@2a z=M9xU+6Vcr1FK}cHNwc8(4=P7sLWZF?z?{E(U1AMrmW3;>9%8EIz?XoH?e)=hF?np zkNJHOeAab5p*4MK*myDSpOT)M#HNgQezNs^DoVV(d{!^B3oBsRPL#G7)q#2Z{@==4 z>S_iWkGH)Edb#ItLZ)#fwWwu}W8mYDUbuhbEA!EGh~9er&hsAcgwuxf2(ixI@j<$( z_i>Z&xZtYg%Eet*qZ)pA^+)|z+ECBhBGv85KmFxvqM!DEqcTKvKT-Yo_c2pnZSrZ` zfhqlOJ^Mec{A6xwT+?LAT^;>EwS~iddMjZ-9CTv(rM9Cax>0mIb151f=xS_)1n0Rq ziDzt5G!nLBTw)gY{cKGZFVu~nxo}6y{u4{%d)1aaKlPv`XYc505$DoO32VU>KPSsY zf(b$HLT`2AnT;&PkZ9(VQo!aFZ+Wk(l#(gwumTh^j?pkbs zLSXei$0Nm(&$B?Kyp0HD+mw$Yv``UOQ5xm-3liB5^|&hJ;P2XVERMCl zHelNBNL9eR+~M<^79USj$IqKfK5MeBa=Db!-MjAoLxbP-dbCM(xGB~YV5qf^RIMxM z+!^tCvxTMoSXNMTUUgkk^WF{0!P0BqIUjYZ40%IY+eeh!?4D>_xAHUzI!c~76S@2WYiX{bE!1wTy4iwENvxj>dU*KE^1HJqD}?&iyR6GDMF&m_HuHZP z-D~MEK3e|TW4%7QHPUI2@KV32cI`Ui@#0#UmqI&Vst))|Z8Du~-pU#98?%<43n*;7 zW2l}i(>-ap-}&-T-QRh3HFHLVUG&!lgWIbG4TbCd10T6KpH~dw#@w{doE1F!WxuQG z-d|lVhNEx(`8??MvwI;9%6gqbH(L`vu|&~5_CX_S2&Y)DiEk*cd|-L1?MR=;Ktb^C z+uVIsLYqS}Rr!nel#*9b--Zlc?R$p8D!ilCF5kuNkb5jO%x5jkMn%)|rp-Y&Ke)J_ zCCHU(P_PaE^s1d=2S-h*jn5acZaCH^?7hdktZ`WW-Tm^lF%qu~V{Rh1%zm9fvZ2tJ zm-1nmLra{5KXYQ$cePw{B;2++?z&?-E^~a{+7ieb@!=c8RhJP0 t{U$HS^2*n^Mzn2@pS*Ylm#_70Yuk}AnXlkhxP?Wu?<}0WL~+?@(|=SR#!3JH literal 0 HcmV?d00001 diff --git a/net/infordata/em/crt5250/resources/Paste.gif b/net/infordata/em/crt5250/resources/Paste.gif new file mode 100644 index 0000000000000000000000000000000000000000..e0321b505b6536e168272e7853e7b48e4095ce51 GIT binary patch literal 173 zcmZ?wbhEHb6k!ly*vtR|4Pe{=rW$~}hK2(N4m310{0EBvXZR1MfHaT=1d2ad7#SFt z8FYY>Kodk57+9hTPI#`~Yw=pQk^Rnd-ENMkh6WCYn@rk8K?c=#Ds25%=2WeURbQqh z)Y=?3@j#Bygsl<}9hVvfx*go|Yle_k;MD0i_g>l*ohR<&(la}IgT~pvS#v7->dqf` IVPLQZ04(1^r2qf` literal 0 HcmV?d00001 diff --git a/net/infordata/em/crt5250/resources/Print.gif b/net/infordata/em/crt5250/resources/Print.gif new file mode 100644 index 0000000000000000000000000000000000000000..428877a5f2385586e9540744ce4d47c39234200e GIT binary patch literal 155 zcmZ?wbhEHb6k-r!*vtR|4Pe{=rW$~}hK2(N4m310{0EBvXZR1MfHaT=1d2ad7#SFt z8FYY>Kof)*7+5?CPI#`~d!y;BC7ZuS+kx*T36+hDS7fD&=ZoH+$3DSdW7c!6yNMnu pulgp%x|XsI@WP-;^96-#-=v?IOp+use!Q#&K_w5cz$%AbU{;E`_

Ik8l#aJ;SMjbyivl^>L)TpBi`rr$KU<4MJj8VV_ z7`jo8JRT61S(w#n!(iO4WwESIDtI7mg+*AMa?nDxRTgD+M!+W+11BIIav>3#AOfsG z6TCnKlK~BEfT0`Z$m0Pa)~YiR3NaXW5v$Hq2nG+NMXfrEu@GzkmcwKC3NK+E+=4yu z0|r1bB!V=sz#25c3q&v((7*;5x>1fi9@MQW48tgj;3h<3HeS^^i&bN{SSB`x73pT; zdEVgQU~!*H>JFUvhuHULYY9;)Hj5~J6O@{y?WuUV+h4er+Ld0q`|Lp*mDP96R$U

br4!_w`h&VQvZyW_Vv8qX9yrpnuvXX;O{zn*x%e&pWKb3Zpf z-TAgMTUk=}@Lh%$OE&Ud_q%$YER5}Z-oN^zwfWT8w%zIK))%?n(Z9*WiC5h6d9>#% QznS@UzVLLobPFB+53i=5g8%>k literal 0 HcmV?d00001 diff --git a/net/infordata/em/crt5250/resources/Res.properties b/net/infordata/em/crt5250/resources/Res.properties new file mode 100644 index 0000000..dfc20cd --- /dev/null +++ b/net/infordata/em/crt5250/resources/Res.properties @@ -0,0 +1,13 @@ +# crt5250 + +TXT_Copy = Copy +TXT_Options = &Options +TXT_RefCursor = Ref. cursor +TXT_Exit = Exit +TXT_Paste = Paste +TXT_Edit = &Edit +TXT_3dFx = 3dFx + +TXT_Print = Print + + diff --git a/net/infordata/em/crt5250/resources/Res_it.properties b/net/infordata/em/crt5250/resources/Res_it.properties new file mode 100644 index 0000000..35410af --- /dev/null +++ b/net/infordata/em/crt5250/resources/Res_it.properties @@ -0,0 +1,12 @@ +# crt5250 + +TXT_Copy = Copia +TXT_Options = &Opzioni +TXT_RefCursor = Cursore di riferimento +TXT_Exit = Chiudi +TXT_Paste = Incolla +TXT_Edit = &Modifica +TXT_3dFx = 3dFx + +TXT_Print = Stampa pannello + diff --git a/net/infordata/em/crt5250/resources/ShiftDown.gif b/net/infordata/em/crt5250/resources/ShiftDown.gif new file mode 100644 index 0000000000000000000000000000000000000000..ea2d61b8c9e5513d1ee6b3e96774df60cba835fb GIT binary patch literal 220 zcmZ?wbhEHbRA5kIXyIc3f(9S}kw6Tk8bD$W3=R$q4gVP&fUN%@{Qv)f0|)*y02x3G zrGSF?f#OdVMg|6X1|6V93?MrhSR)^(_oZac%UHE8=k>k~o`Hqd*I%uLu;X^X;HJZYQGx^MY?r*Gx+k5zAf T>wenm+St_G(%ROl$Y2csV-9W| literal 0 HcmV?d00001 diff --git a/net/infordata/em/tn5250/Test.java b/net/infordata/em/tn5250/Test.java new file mode 100644 index 0000000..338f9aa --- /dev/null +++ b/net/infordata/em/tn5250/Test.java @@ -0,0 +1,126 @@ +package net.infordata.em.tn5250; + +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.lang.reflect.InvocationTargetException; + +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +import net.infordata.em.crt5250.XI5250Field; +import net.infordata.em.crt5250.XIEbcdicTranslator; + + +public class Test { + + private Test() { } + + private static void usageError(String msg) { + System.err.println(msg); + System.err.println("Usage: [-3dFX] [-altFKeyRemap] [-cp codepage] host-name"); + System.err.println("Supported code pages:"); + for (String cp : XIEbcdicTranslator.getRegisteredTranslators().keySet()) { + System.err.println(" " + cp + + (XI5250Emulator.DEFAULT_CODE_PAGE.equalsIgnoreCase(cp)? " default" : "")); + } + System.exit(1); + } + + /** + * Used only for test purposes. + */ + public static void main(String[] args) { + + /*!!1.12 + if (System.getProperty("java.version").compareTo("1.1.1") < 0 || + System.getProperty("java.version").compareTo("1.1_Final") == 0) { + System.err.println("!!! Use JDK 1.1.1 or newer !!!"); + } + */ +// checkJDK(); + + boolean pUse3dFX = false; + boolean pAltFKeyRemap = false; + + String arg; + String pHost = null; + boolean expectCP = false; + String cp = null; + for (int i = 0; i < args.length; i++) { + arg = args[i]; + if (arg.startsWith("-")) { + if ("-3dfx".equalsIgnoreCase(arg)) + pUse3dFX = true; + else if ("-altFKeyRemap".equalsIgnoreCase(arg)) + pAltFKeyRemap = true; + else if ("-cp".equalsIgnoreCase(arg)) + expectCP = true; + else + usageError("Wrong option: " + arg); + } + else if (expectCP) { + expectCP = false; + if (XIEbcdicTranslator.getTranslator(arg) == null) + usageError("Unknown codepage: " + arg); + cp = arg; + } + else { + if (pHost == null) + pHost = arg; + else + usageError("Too many host names."); + } + } + if (expectCP) + usageError("A code page is expected"); + + final boolean altFKeyRemap = pAltFKeyRemap; + final boolean use3dFX = pUse3dFX; + final String host = pHost; + final String codePage = cp; + try { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + XI5250Emulator em = new XI5250Emulator(); + em.setTerminalType("IBM-3477-FC"); + em.setKeyboardQueue(true); + + em.setAltFKeyRemap(altFKeyRemap); + em.setCodePage(codePage); + + if (host != null) { + em.setHost(host); + em.setActive(true); + } + + XI5250Frame frm = new XI5250Frame("xtn5250mg" + " " + + XI5250Emulator.VERSION, em); + frm.addWindowListener(new WindowAdapter() { + @Override + public void windowClosed(WindowEvent e) { + System.exit(0); + } + }); + + //3D FX + if (use3dFX) { + em.setDefFieldsBorderStyle(XI5250Field.LOWERED_BORDER); + em.setDefBackground(UIManager.getColor("control")); + } + + //frm.setBounds(0, 0, 570, 510); + frm.centerOnScreen(70); + frm.setVisible(true); + } + }); + } + catch (InterruptedException ex) { + ex.printStackTrace(); + } + catch (InvocationTargetException ex) { + ex.printStackTrace(); + } + + } + +} diff --git a/net/infordata/em/tn5250/XI5250Applet.java b/net/infordata/em/tn5250/XI5250Applet.java new file mode 100644 index 0000000..4ecc351 --- /dev/null +++ b/net/infordata/em/tn5250/XI5250Applet.java @@ -0,0 +1,544 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** +!!V 09/07/98 rel. 1.10 - creation. + 05/02/99 rel. 1.11 - Swing 1.1 bug work-around. + 08/06/99 rel. 1.11a- The emulator is centered. + */ + + +package net.infordata.em.tn5250; + + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.event.WindowEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.ResourceBundle; + +import javax.swing.AbstractButton; +import javax.swing.JApplet; +import javax.swing.JButton; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JToggleButton; +import javax.swing.JToolBar; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +import net.infordata.em.crt5250.XI5250Crt; +import net.infordata.em.crt5250.XI5250Field; +import net.infordata.em.util.XICommand; +import net.infordata.em.util.XICommandMgr; +import net.infordata.em.util.XIUtil; + + +/** + */ +public class XI5250Applet extends JApplet { + + private static final long serialVersionUID = 1L; + + private static final int DEBUG = 0; + + // if true the emulation frame survives to the applet dead, + // !!VERIFY: a stopped applet causes event dispatching problems + private static final boolean UNDEAD_FRAME = false; + + // images + private static XIImagesBdl cvImagesBdl = XIImagesBdl.getImagesBdl(); + + private static ResourceBundle cvRes = + ResourceBundle.getBundle("net.infordata.em.tn5250.resources.Res"); + + private XI5250EmulatorCtrl ivEmulatorCtrl; + private EmulatorFrame ivFrame; + private boolean ivFirstTime = true; + + private boolean ivDestroyed = false; + + private PropertyChangeListener ivPropertyChangeListener = + new PropertyChangeListener() { + public void propertyChange(PropertyChangeEvent evt) { + emulatorPropertyChanged(evt); + } + }; + + public static final String INFRAME_CMD = "INFRAME_CMD"; + + protected XI5250Emulator createEmulator() { + return new XI5250Emulator(); + } + + /** + */ + @Override + public void init() { + if (DEBUG >= 1) + System.out.println("init()"); + + /*!!1.12 + if (System.getProperty("java.version").compareTo("1.1.1") < 0 || + System.getProperty("java.version").compareTo("1.1_Final") == 0) { + System.err.println("!!! Use JDK 1.1.1 or newer !!!"); + } + */ +// XI5250Emulator.checkJDK(); + + String host = null; + host = getParameter("host"); + + /* + if (host == null) { + System.err.println("Host name or ip address is required."); + System.exit(-1); + } + */ + + boolean inplace = true; + { + String ss = getParameter("inplace"); + if (ss != null && "false".equals(ss.toLowerCase())) + inplace = false; + } + + final boolean p3dFX = "true".equalsIgnoreCase(getParameter("3dFX")); + final boolean altFKeyRemap = "true".equalsIgnoreCase(getParameter("altFKeyRemap")); + final String codePage = getParameter("codePage"); + final boolean requestFocus = !"false".equalsIgnoreCase(getParameter("requestFocus")); + final boolean pSTRPCCMD = "true".equalsIgnoreCase(getParameter("STRPCCMD")); + final String deviceName = getParameter("devName"); + + ivEmulatorCtrl = new XI5250EmulatorCtrl(createEmulator()); + getEmulator().setTerminalType("IBM-3477-FC"); + getEmulator().setHost(host); + //3D FX + if (p3dFX) { + getEmulator().setDefFieldsBorderStyle(XI5250Field.LOWERED_BORDER); + getEmulator().setDefBackground(UIManager.getColor("control")); + } + getEmulator().setAltFKeyRemap(altFKeyRemap); + getEmulator().setCodePage(codePage); + getEmulator().setStrPcCmdEnabled(pSTRPCCMD); + if (deviceName != null) + getEmulator().setTelnetEnv("\u0003DEVNAME\u0001" + deviceName); + + //!! 1.11a execution moved to the EventQueueThread + if (inplace) + SwingUtilities.invokeLater(new Runnable() { + public void run() { + emulatorInPlace(); + if (requestFocus) + getEmulator().requestFocusInWindow(); + } + }); + else + SwingUtilities.invokeLater(new Runnable() { + public void run() { + emulatorInFrame(); + if (requestFocus) + getEmulator().requestFocusInWindow(); + } + }); + + // InFrame command + getCommandMgr().enableCommand( + INFRAME_CMD, ivFrame == null); + getCommandMgr().setCommand(INFRAME_CMD, new XICommand() { + public void execute() { + processInFrameCmd(); + } + }); + } + + + /** + */ + @Override + public void start() { + if (DEBUG >= 1) + System.out.println("start()"); + + if (getEmulator().getHost() != null) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + getEmulator().setActive(true); + } + }); + } + } + + + /** + */ + @Override + public void stop() { + if (DEBUG >= 1) + System.out.println("stop()"); + } + + + /** + */ + @Override + public void destroy() { + if (DEBUG >= 1) + System.out.println("destroy()"); + + ivDestroyed = true; + if (!UNDEAD_FRAME || ivFrame == null) { + emulatorInPlace(); + getEmulator().setActive(false); + } + } + + + /** + */ + public final XI5250Emulator getEmulator() { + return ivEmulatorCtrl.getEmulator(); + } + + + /** + */ + public final XICommandMgr getCommandMgr() { + return ivEmulatorCtrl.getCommandMgr(); + } + + + /** + */ + protected void processInFrameCmd() { + emulatorInFrame(); + } + + + /** + */ + protected void emulatorInPlace() { + if (!ivFirstTime && ivFrame == null) + return; + + ivFirstTime = false; + + if (DEBUG >= 1) + System.out.println("inplace"); + + if (ivFrame != null) { + ivFrame.setJMenuBar(null); // work around for a Swing 1.1 bug + + ivFrame.dispose(); + ivFrame = null; + } + + getCommandMgr().enableCommand(INFRAME_CMD, true); + + JToolBar toolBar = createToolBar(); + JMenuBar menuBar = createMenuBar(); + + setJMenuBar(menuBar); + getContentPane().setLayout(new BorderLayout()); + getContentPane().add(toolBar, BorderLayout.NORTH); + + JPanel panel = new XI5250Emulator.SupportPanel(getEmulator()); + panel.setBackground(getEmulator().getBackground()); + getContentPane().add(panel, BorderLayout.CENTER); + + getEmulator().addPropertyChangeListener(ivPropertyChangeListener); + } + + + /** + */ + protected void emulatorInFrame() { + if (ivFrame != null) + return; + + if (DEBUG >= 1) + System.out.println("inframe"); + + getCommandMgr().enableCommand(INFRAME_CMD, false); + + getEmulator().removePropertyChangeListener(ivPropertyChangeListener); + setJMenuBar(null); + getContentPane().removeAll(); + validate(); + repaint(); + + ivFrame = new EmulatorFrame("xtn5250mg" + " " + + XI5250Emulator.VERSION, + getEmulator()); + ivFrame.setBounds(0, 0, 648, 506); + ivFrame.centerOnScreen(); + ivFrame.setVisible(true); + } + + + /** + */ + private void frameClosed() { + if (DEBUG >= 1) + System.out.println("frameClosed()"); + + if (UNDEAD_FRAME && ivDestroyed) + getEmulator().setActive(false); + else { + emulatorInPlace(); + invalidate(); + validate(); + getEmulator().requestFocusInWindow(); + } + } + + + /** + */ + private void emulatorPropertyChanged(PropertyChangeEvent evt) { + String propertyName = evt.getPropertyName(); + if ("background".equals(propertyName)) + getEmulator().getParent().setBackground(getEmulator().getBackground()); + else if ("font".equals(propertyName) || + XI5250Crt.CRT_SIZE.equals(propertyName)) + getEmulator().revalidate(); + } + + + /** + */ + private JMenuBar createMenuBar() { + String str; + + str = cvRes.getString("TXT_Communications"); + JMenu commMenu = new JMenu(XIUtil.removeMnemonics(str)); + commMenu.setMnemonic(XIUtil.getMnemonic(str)); + { + JMenuItem connItem = + new JMenuItem(cvRes.getString("TXT_Connect")); + JMenuItem disconnItem = + new JMenuItem(cvRes.getString("TXT_Disconnect")); + JMenuItem aboutItem = + new JMenuItem(cvRes.getString("TXT_About")); + + commMenu.add(connItem); + commMenu.add(disconnItem); + commMenu.addSeparator(); + commMenu.add(aboutItem); + + getCommandMgr().handleCommand(connItem, + XI5250EmulatorCtrl.CONNECT_CMD); + getCommandMgr().handleCommand(disconnItem, + XI5250EmulatorCtrl.DISCONNECT_CMD); + getCommandMgr().handleCommand(aboutItem, + XI5250EmulatorCtrl.ABOUT_CMD); + } + + str = cvRes.getString("TXT_Edit"); + JMenu editMenu = new JMenu(XIUtil.removeMnemonics(str)); + editMenu.setMnemonic(XIUtil.getMnemonic(str)); + { + JMenuItem copyItem = + new JMenuItem(cvRes.getString("TXT_Copy")); + JMenuItem pasteItem = + new JMenuItem(cvRes.getString("TXT_Paste")); + JMenuItem snapShotItem = + new JMenuItem(cvRes.getString("TXT_SnapShot")); + JMenuItem printItem = + new JMenuItem(cvRes.getString("TXT_Print")); + + editMenu.add(copyItem); + editMenu.add(pasteItem); + editMenu.addSeparator(); + editMenu.add(snapShotItem); + editMenu.addSeparator(); + editMenu.add(printItem); + + getCommandMgr().handleCommand(copyItem, + XI5250EmulatorCtrl.COPY_CMD); + getCommandMgr().handleCommand(pasteItem, + XI5250EmulatorCtrl.PASTE_CMD); + getCommandMgr().handleCommand(snapShotItem, + XI5250EmulatorCtrl.SNAPSHOT_CMD); + getCommandMgr().handleCommand(printItem, + XI5250EmulatorCtrl.PRINT_CMD); + } + + str = cvRes.getString("TXT_Options"); + JMenu optionsMenu = new JMenu(XIUtil.removeMnemonics(str)); + optionsMenu.setMnemonic(XIUtil.getMnemonic(str)); + { + JMenuItem inFrameItem = + new JMenuItem(cvRes.getString("TXT_InFrame")); + JCheckBoxMenuItem switch3DfxItem = + new JCheckBoxMenuItem(cvRes.getString("TXT_3dFx")); + JCheckBoxMenuItem referenceCursorItem = + new JCheckBoxMenuItem(cvRes.getString("TXT_RefCursor")); + + optionsMenu.add(inFrameItem); + optionsMenu.addSeparator(); + optionsMenu.add(switch3DfxItem); + optionsMenu.add(referenceCursorItem); + + getCommandMgr().handleCommand(inFrameItem, + INFRAME_CMD); + getCommandMgr().handleCommand(switch3DfxItem, + XI5250EmulatorCtrl.SWITCH_3DFX_CMD); + getCommandMgr().handleCommand(referenceCursorItem, + XI5250EmulatorCtrl.REFERENCE_CURSOR_CMD); + } + + JMenuBar menuBar = new JMenuBar(); + menuBar.add(commMenu); + menuBar.add(editMenu); + menuBar.add(optionsMenu); + return menuBar; + } + + + /** + * Inserisce nella tool-bar i bottoni di default. + */ + private JToolBar createToolBar() { + // bottoni della tool-bar + AbstractButton[] buttons = new AbstractButton[] { + new JButton(cvImagesBdl.getIcon("Connect")), + new JButton(cvImagesBdl.getIcon("Disconnect")), + null, + new JButton(cvImagesBdl.getIcon("Copy")), + new JButton(cvImagesBdl.getIcon("Paste")), + null, + new JButton(cvImagesBdl.getIcon("SnapShot")), + new JButton(cvImagesBdl.getIcon("Print")), + null, + new JButton(cvImagesBdl.getIcon("InFrame")), + null, + new JToggleButton(cvImagesBdl.getIcon("3dFx")), + new JToggleButton(cvImagesBdl.getIcon("RefCursor")), + }; + // action commands associati con i bottoni della tool-bar. + String[] buttonsActCmd = new String[] { + XI5250EmulatorCtrl.CONNECT_CMD, + XI5250EmulatorCtrl.DISCONNECT_CMD, + null, + XI5250EmulatorCtrl.COPY_CMD, + XI5250EmulatorCtrl.PASTE_CMD, + null, + XI5250EmulatorCtrl.SNAPSHOT_CMD, + XI5250EmulatorCtrl.PRINT_CMD, + null, + INFRAME_CMD, + null, + XI5250EmulatorCtrl.SWITCH_3DFX_CMD, + XI5250EmulatorCtrl.REFERENCE_CURSOR_CMD, + }; + // Hint associati ad i vari bottoni. + String[] buttonHints = new String[] { + cvRes.getString("TXT_Connect"), + cvRes.getString("TXT_Disconnect"), + null, + cvRes.getString("TXT_Copy"), + cvRes.getString("TXT_Paste"), + null, + cvRes.getString("TXT_SnapShot"), + cvRes.getString("TXT_Print"), + null, + cvRes.getString("TXT_InFrame"), + null, + cvRes.getString("TXT_3dFx"), + cvRes.getString("TXT_RefCursor"), + }; + + JToolBar toolBar = new JToolBar(); + toolBar.setFloatable(false); + + Dimension size = new Dimension(26, 26); + + for (int i = 0; i < buttons.length; i++) { + if (buttons[i] != null) { + AbstractButton button = (AbstractButton)buttons[i]; + toolBar.add(button); + button.setToolTipText(buttonHints[i]); + button.setMinimumSize(size); + button.setPreferredSize(size); + button.setMaximumSize(size); + button.setRequestFocusEnabled(false); + getCommandMgr().handleCommand(button, buttonsActCmd[i]); + } + else + toolBar.addSeparator(); + } + + return toolBar; + } + + + /** + */ + @Override + public void paint(Graphics g) { + super.paint(g); + if (ivFrame != null) { + Rectangle rt = getBounds(); + g.setColor(Color.darkGray); + + int hh = rt.height; + for (int x = -hh; x < rt.width; x += 16) + g.drawLine(x, hh, x + hh, 0); + } + } + + + /////////////////////////////////////////////////////////////////////////////// + + /** + */ + private class EmulatorFrame extends XI5250Frame { + + private static final long serialVersionUID = 1L; + + public EmulatorFrame(String aTitle, XI5250Emulator aCrt) { + super(aTitle, aCrt); + } + + @Override + protected void processExitCmd() { + if (UNDEAD_FRAME && ivDestroyed) + super.processExitCmd(); + else + dispose(); + } + + @Override + protected void processWindowEvent(WindowEvent e) { + switch(e.getID()) { + case WindowEvent.WINDOW_CLOSED: + XI5250Applet.this.frameClosed(); + return; + } + super.processWindowEvent(e); + } + } +} + diff --git a/net/infordata/em/tn5250/XI5250Cmd.java b/net/infordata/em/tn5250/XI5250Cmd.java new file mode 100644 index 0000000..ca778c6 --- /dev/null +++ b/net/infordata/em/tn5250/XI5250Cmd.java @@ -0,0 +1,60 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.InputStream; + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Abstract class for all 5250 commands + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public abstract class XI5250Cmd { + + protected XI5250Emulator ivEmulator; + + + protected void init(XI5250Emulator aEmulator) { + ivEmulator = aEmulator; + } + + + /** + * @exception XI5250Exception raised if command parameters are wrong. + */ + protected abstract void readFrom5250Stream(InputStream inStream) + throws IOException, XI5250Exception; + + + protected abstract void execute(); + + + protected void executePending(int anAidCode, boolean isMasked) { + throw new RuntimeException("executePending() not supported"); + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XI5250CmdList.java b/net/infordata/em/tn5250/XI5250CmdList.java new file mode 100644 index 0000000..ebb8f11 --- /dev/null +++ b/net/infordata/em/tn5250/XI5250CmdList.java @@ -0,0 +1,181 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.infordata.em.tnprot.XITelnet; + + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * 5250 Commands list (Works like a macro command). + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XI5250CmdList extends XI5250Cmd { + + private static final Logger LOGGER = Logger.getLogger(XI5250CmdList.class.getName()); + + private static Class[] cv5250CmdClasses = new Class[256];; + + protected List ivCmdVect; + + // flags used across command execution + protected boolean ivICOrderExecuted; + + + static { + cv5250CmdClasses[XITelnet.toInt(XI5250Emulator.CMD_READ_IMMEDIATE)] = + XIReadImmediateCmd.class; + cv5250CmdClasses[XITelnet.toInt(XI5250Emulator.CMD_READ_FIELDS)] = + XIReadFieldsCmd.class; + cv5250CmdClasses[XITelnet.toInt(XI5250Emulator.CMD_READ_MDT_FIELDS)] = + XIReadMdtFieldsCmd.class; + cv5250CmdClasses[XITelnet.toInt(XI5250Emulator.CMD_READ_SCREEN)] = + XIReadScreenCmd.class; + cv5250CmdClasses[XITelnet.toInt(XI5250Emulator.CMD_SAVE_SCREEN)] = + XISaveScreenCmd.class; + + cv5250CmdClasses[XITelnet.toInt(XI5250Emulator.CMD_CLEAR_FMT_TABLE)] = + XIClearFmtTableCmd.class; + cv5250CmdClasses[XITelnet.toInt(XI5250Emulator.CMD_CLEAR_UNIT)] = + XIClearUnitCmd.class; + cv5250CmdClasses[XITelnet.toInt(XI5250Emulator.CMD_CLEAR_UNIT_ALT)] = + XIClearUnitAltCmd.class; + cv5250CmdClasses[XITelnet.toInt(XI5250Emulator.CMD_RESTORE_SCREEN)] = + XIRestoreScreenCmd.class; + cv5250CmdClasses[XITelnet.toInt(XI5250Emulator.CMD_ROLL)] = + XIRollCmd.class; + cv5250CmdClasses[XITelnet.toInt(XI5250Emulator.CMD_WRITE_ERROR_CODE)] = + XIWriteErrorCodeCmd.class; + cv5250CmdClasses[XITelnet.toInt(XI5250Emulator.CMD_WRITE_TO_DISPLAY)] = + XIWriteToDisplayCmd.class; + + cv5250CmdClasses[XITelnet.toInt(XI5250Emulator.CMD_QUERY_DEVICE)] = + XIQueryCmd.class; + } + + + /** + */ + protected XI5250CmdList(XI5250Emulator aEmulator) { + init(aEmulator); + } + + + /** + * @exception XI5250Exception raised if command parameters are wrong. + */ + @Override + protected void readFrom5250Stream(InputStream inStream) + throws IOException, XI5250Exception { + int bb; + XI5250Cmd cmd; + ivCmdVect = new ArrayList(100); + + if (LOGGER.isLoggable(Level.FINER)) + LOGGER.finer("START OF COMMANDS LIST"); + + // jump until ESC is found + while ((bb = inStream.read()) != -1 && (byte)bb != XI5250Emulator.ESC) + ; + + // start from 1 because ESC is already read + for (int i = 1; (bb = inStream.read()) != -1; i++) { + switch (i % 2) { + case 0: + if ((byte)bb != XI5250Emulator.ESC) + throw new XI5250Exception("Malformed 5250 packet", XI5250Emulator.ERR_INVALID_COMMAND); + break; + case 1: + try { + cmd = createCmdInstance(XITelnet.toInt((byte)bb)); + } + catch (Exception ex) { + throw new RuntimeException(ex); + } + + if (cmd != null) { + cmd.init(ivEmulator); + cmd.readFrom5250Stream(inStream); + + if (LOGGER.isLoggable(Level.FINER)) + LOGGER.finer("" + cmd); + + ivCmdVect.add(cmd); + } + else { + throw new XI5250Exception("Command not supported : 0x" + + XITelnet.toHex((byte)bb), + XI5250Emulator.ERR_INVALID_COMMAND); + } + break; + } + } + } + + + /** + */ + @Override + protected void execute() { + for (int i = 0; i < ivCmdVect.size(); i++) + ivCmdVect.get(i).execute(); + } + + + /** + * Creates the 5250 command related to the given 5250 command id. + * @exception IllegalAccessException . + * @exception InstantiationException . + */ + protected XI5250Cmd createCmdInstance(int aCmd) + throws IllegalAccessException, InstantiationException { + Class cls; + + cls = cv5250CmdClasses[aCmd]; + if (cls != null) + return (XI5250Cmd)cls.newInstance(); + else + return null; + } + + + /** + */ + @Override + public String toString() { + String ss = super.toString() + ivCmdVect.toString(); + return ss; + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XI5250Emulator.java b/net/infordata/em/tn5250/XI5250Emulator.java new file mode 100644 index 0000000..c42337a --- /dev/null +++ b/net/infordata/em/tn5250/XI5250Emulator.java @@ -0,0 +1,2099 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 20/03/97 rel. 0.90 - start of revisions history. + 28/03/97 rel. 0.91 - keyboard events can be queued (setKeyboardQueue(true)) + 08/04/97 rel. 0.92a- system request handled like IBM personal-communications. + 10/04/97 rel. 0.93 - some fix to add SignedNumeric fields handling. + Error row is saved when the emulator enters PRE_HELP state, it is + restored on exit. + 16/04/97 rel. 0.94 - userError method added. + rel. 0.95... work in progress + 27/05/97 rel. 1.00 - first release. + 04/06/97 rel. 1.00b- create5250Field method added. + 05/06/97 rel. 1.00c- reference cursor. + 19/06/97 rel. 1.01 - uses XITelnet version 1.01 with telnet proxy support. + 27/07/97 rel. 1.01b- when a packet is received and the emulator is in + ST_SYSTEM_REQUEST state then it switches-back to the previous + state. + The CTRL key (restore) clears the keyboard queue. + 08/07/97 rel. 1.01c- reference cursor. + clearKeyboardQueue() method added. + 14/07/97 rel. 1.02 - added support for 27x132 terminal type (IBM-3477-FC), + to use this feature call the method setTerminalType(). + 15/07/97 rel. 1.02c- XIDataOrd includes 0x1F char. + 16/07/97 rel. 1.02d- XI5250Emulator doesn't implement the XITelnetEmulator + interface publically. + 17/07/97 rel. 1.02e- . + 23/07/97 rel. 1.03 - . + 25/07/97 rel. 1.03a- a bug in ...Multicaster. + 30/07/97 rel. 1.03b- bugs. + 06/08/97 rel. 1.03c- bug fix. + Double-buffering in XICrt class. + 08/08/97 rel. 1.03d- translateKeyEvent() and processRawKeyEvent(). + 28/08/97 rel. 1.04 - clipboard support added. + 02/09/97 rel. 1.04a- bug fix - XIReadFieldsCmd, XIReadImmediateCmd. + 24/09/97 rel. 1.05 - DNCX project. + 03/10/97 rel. 1.05a- bug fix (XISOHOrd). + 13/01/98 rel. 1.05d- NT painting bug (see crt.XICrtBuffer). + 14/01/98 rel. 1.06 - asynchronous paint on off-screen image + (see crt.XICrtBuffer). + 15/01/98 rel. 1.06a- bug fix (XIRestoreScreenCmd, XISaveScreenCmd). + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + 07/07/98 rel. 1.07 - XIImagesBdl uses XIUtil.createImage(). + 09/07/98 rel. 1.10 - XI5250Applet. + 04/02/99 rel. 1.11 - Swing 1.1 and jdk 1.2 support. + 08/06/99 rel. 1.11a- Some adjustment to XI5250Applet. + 08/06/99 rel. 1.13 - Snap-shot. + 23/06/99 rel. 1.13a- See XI5250Crt. + Mnemonics (short-cut) added to menu items. + 29/07/99 rel. 1.14 - Rework on 3d look&feel. + 02/08/99 rel. 1.15 - Rework on 3d look&feel, removed subpackage statusbar.*. + 06/09/99 rel. 1.15a- Missing action in restoreMemento(). + 02/05/00 rel. 1.15b- Jdk 1.3rc2. + 23/11/00 rel. 1.15d- Jdk 1.3. +*/ + + +package net.infordata.em.tn5250; + + +import java.awt.AWTEvent; +import java.awt.AWTEventMulticaster; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Toolkit; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.Serializable; +import java.util.EventListener; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; + +import net.infordata.em.crt5250.XI5250Crt; +import net.infordata.em.crt5250.XI5250CrtBuffer; +import net.infordata.em.crt5250.XI5250Field; +import net.infordata.em.crt5250.XI5250FieldsList; +import net.infordata.em.crt5250.XIEbcdicTranslator; +import net.infordata.em.tnprot.XITelnet; +import net.infordata.em.tnprot.XITelnetEmulator; + + +//////////////////////////////////////////////////////////////////////////////// + +/** + * THE 5250 EMULATOR. + *

+ * How to use it:
+ *
+ * XI5250Emulator em  = new XI5250Emulator();
+ *
+ * em.setKeyboardQueue(true);
+ * em.setHost("AS400-HostName-Or-IpAddress");
+ * em.setActive(true);
+ *
+ * 
+ * + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XI5250Emulator extends XI5250Crt implements Serializable { + + private static final Logger LOGGER = Logger.getLogger(XI5250Emulator.class.getName()); + + private static final long serialVersionUID = 1L; + + public static final String VERSION = "0.1 (1.19i)"; + + public static final int MAX_ROWS = 27; + public static final int MAX_COLS = 132; + + // opcodes + protected static final byte OPCODE_NOP = (byte)0x00; + protected static final byte OPCODE_INVITE_OPERATION = (byte)0x01; + protected static final byte OPCODE_OUTPUT_ONLY = (byte)0x02; + protected static final byte OPCODE_PUT_GET = (byte)0x03; + protected static final byte OPCODE_SAVE_SCREEN = (byte)0x04; + protected static final byte OPCODE_RESTORE_SCREEN = (byte)0x05; + protected static final byte OPCODE_READ_IMM = (byte)0x06; + protected static final byte OPCODE_RESERVED1 = (byte)0x07; + protected static final byte OPCODE_READ_SCREEN = (byte)0x08; + protected static final byte OPCODE_RESERVED2 = (byte)0x09; + protected static final byte OPCODE_CANCEL_INVITE = (byte)0x0A; + protected static final byte OPCODE_TURN_ON_MSG = (byte)0x0B; + protected static final byte OPCODE_TURN_OFF_MSG = (byte)0x0C; + protected static final String[] OPCODE = + {"No operation", + "Invite operation", + "Output only", + "Put/Get Operation", + "Save screen operation", + "Restore screen operation", + "Read immediate operation", + "Reserved 1", + "Read screen operation", + "Reserved 2", + "Cancel invite operation", + "Turn ON message light", + "Turn OFF message light"}; + + // 5250 stream parsing errors + protected static final int ERR_INVALID_COMMAND = 10030101; + protected static final int ERR_INVALID_CLEAR_UNIT_ALT = 10030105; + protected static final int ERR_INVALID_SOH_LENGTH = 10050131; + protected static final int ERR_INVALID_ROW_COL_ADDR = 10050122; + protected static final int ERR_INVALID_EXT_ATTR_TYPE = 10050132; + protected static final int ERR_INVALID_SF_CLASS_TYPE = 10050111; + + // flags + protected static final byte FLAG_HLP = (byte)0x01; + protected static final byte FLAG_TRQ = (byte)0x02; + protected static final byte FLAG_SRQ = (byte)0x04; + protected static final byte FLAG_ATN = (byte)0x40; + protected static final byte FLAG_ERR = (byte)0x80; + + protected static final byte ESC = (byte)0x04; + // read commands + protected static final byte CMD_QUERY_DEVICE = (byte)0xF3; + protected static final byte CMD_READ_IMMEDIATE = (byte)0x72; + protected static final byte CMD_READ_FIELDS = (byte)0x42; + protected static final byte CMD_READ_MDT_FIELDS = (byte)0x52; + protected static final byte CMD_READ_SCREEN = (byte)0x62; + protected static final byte CMD_SAVE_SCREEN = (byte)0x02; + // output commands + protected static final byte CMD_CLEAR_FMT_TABLE = (byte)0x50; + protected static final byte CMD_CLEAR_UNIT = (byte)0x40; + protected static final byte CMD_CLEAR_UNIT_ALT = (byte)0x20; + protected static final byte CMD_RESTORE_SCREEN = (byte)0x12; + protected static final byte CMD_ROLL = (byte)0x23; + protected static final byte CMD_WRITE_ERROR_CODE= (byte)0x21; + protected static final byte CMD_WRITE_TO_DISPLAY= (byte)0x11; + + // orders + // see http://publibfp.boulder.ibm.com/cgi-bin/bookmgr/BOOKS/co2e2001/15.6.3?DT=19950629163252 + protected static final byte ORD_SBA = (byte)0x11; // Set buffer address + protected static final byte ORD_IC = (byte)0x13; // Insert cursor + protected static final byte ORD_MC = (byte)0x14; // Move cursor + protected static final byte ORD_RA = (byte)0x02; // Repeat to address + protected static final byte ORD_EA = (byte)0x03; // Erase to address + protected static final byte ORD_SOH = (byte)0x01; // Start of header + protected static final byte ORD_TD = (byte)0x10; // Transparent data + protected static final byte ORD_WEA = (byte)0x12; // Write extended attributes + protected static final byte ORD_SF = (byte)0x1D; // Start of field + protected static final byte ORD_WDSF = (byte)0x15; // Write to Display Structured Field + + protected static final byte[] STRPCCMD = new byte[] { + (byte)0x27, (byte)0x80, (byte)0xfc, (byte)0xd7, (byte)0xc3, (byte)0xd6, (byte)0x40, (byte)0x83, (byte)0x80, (byte)0xa1, (byte)0x80 + }; // Start PC Command + protected static final byte[] ENDSTRPCCMD = new byte[] { + (byte)0x27, (byte)0x00, (byte)0xfc, (byte)0xd7, (byte)0xc3, (byte)0xd6, (byte)0x40, (byte)0x83, (byte)0x80, (byte)0x82, (byte)0x00 + }; // Start PC Command + + // aid codes + public static final byte AID_COMMAND = (byte)0x31; + public static final byte AID_FUNCTION = (byte)0x32; + public static final byte AID_F3 = (byte)0x33; + public static final byte AID_F4 = (byte)0x34; + public static final byte AID_F5 = (byte)0x35; + public static final byte AID_F6 = (byte)0x36; + public static final byte AID_F7 = (byte)0x37; + public static final byte AID_F8 = (byte)0x38; + public static final byte AID_F9 = (byte)0x39; + public static final byte AID_F10 = (byte)0x3A; + public static final byte AID_F11 = (byte)0x3B; + public static final byte AID_F12 = (byte)0x3C; + public static final byte AID_F13 = (byte)0xB1; + public static final byte AID_F14 = (byte)0xB2; + public static final byte AID_F15 = (byte)0xB3; + public static final byte AID_F16 = (byte)0xB4; + public static final byte AID_F17 = (byte)0xB5; + public static final byte AID_F18 = (byte)0xB6; + public static final byte AID_F19 = (byte)0xB7; + public static final byte AID_F20 = (byte)0xB8; + public static final byte AID_F21 = (byte)0xB9; + public static final byte AID_F22 = (byte)0xBA; + public static final byte AID_F23 = (byte)0xBB; + public static final byte AID_F24 = (byte)0xBC; + public static final byte AID_CLEAR = (byte)0xBD; + public static final byte AID_ENTER = (byte)0xF1; + public static final byte AID_HELP = (byte)0xF3; + public static final byte AID_ROLL_DN = (byte)0xF4; + public static final byte AID_ROLL_UP = (byte)0xF5; + public static final byte AID_PRINT = (byte)0xF6; + public static final byte AID_REC_BACKSP= (byte)0xF8; + public static final byte AID_AUTO_ENTER= (byte)0x3F; + + // emulator state + // state less than 0 are not saved in ivPrevState + public static final int ST_NULL = -2; + public static final int ST_TEMPORARY_LOCK = -1; + public static final int ST_HARDWARE_ERROR = 0; + public static final int ST_NORMAL_LOCKED = 1; + public static final int ST_NORMAL_UNLOCKED = 2; + public static final int ST_POST_HELP = 3; + public static final int ST_POWER_ON = 4; + public static final int ST_PRE_HELP = 5; + public static final int ST_SS_MESSAGE = 6; + public static final int ST_SYSTEM_REQUEST = 7; + public static final int ST_POWERED = 8; //!!1.01 + + private static final String[] ST_DESCRIPTION = + {"ST_NULL", + "ST_TEMPORARY_LOCK", + "ST_HARDWARE_ERROR", + "ST_NORMAL_LOCKED", + "ST_NORMAL_UNLOCKED", + "ST_POST_HELP", + "ST_POWER_ON", + "ST_PRE_HELP", + "ST_SS_MESSAGE", + "ST_SYSTEM_REQUEST", + "ST_POWERED"}; + + // telnet connection + transient private XITelnet ivTelnet; + transient private byte[] ivRXBuf = new byte[1024 * 8]; + transient private int ivRXBufLen; + + // one bit for each function key + transient private int ivFunctionKeysMask; + + /** + * The current commands list. + */ + transient XI5250CmdList ivCmdList; + /** + * The pending command (used when an aid code is pressed). + */ + transient XI5250Cmd ivPendingCmd; + + // current and previouos state + transient private int ivState = ST_NULL; + transient private int ivPrevState = ST_NULL; + + transient private int ivErrorRow; + + transient private XI5250StatusBar ivStatusBar; + + // + //!!1.06a protected Vector ivSavedScreenList = new Vector(10, 5); + //!!!.06a replace the vector with a circular buffer + transient protected XI5250EmulatorMemento[] ivSavedScreens = + new XI5250EmulatorMemento[10]; + transient protected int ivSavedScreensIdx = 0; + + //!!0.91 + transient KeyEventQueue ivKeybEventQueue; + transient KeyEventDispatchThread ivKeybThread; + + //!!0.92 used when the user switches to SYSTEM_REQUEST state + transient private XI5250EmulatorMemento ivSysReqMemento; + transient private XI5250Field ivSysReqField; + + //!!0.93 used when the emulator switch to PRE_HELP state + transient private XI5250CrtBuffer ivPreHelpErrorLine; + + //!!0.95 + transient private XI5250EmulatorListener ivEmulatorListener; + + //!!1.02 + private String ivTermType; + private String ivTelnetEnv; + + //!!1.02d + transient private TelnetEmulator ivTelnetEmulator = new TelnetEmulator(); + + //!!1.03a + /** + * Used when switching from 24x80 to ... + */ + transient protected Font ivPrevFont; + + //!!1.04c + public static final String ACTIVE = "active"; + public static final String TERMINAL_TYPE = "terminalType"; + public static final String ALTFKEY_REMAP = "altFKeyRemap"; + + public static final String TELNET_ENV = "telnetEnv"; + + public static final String STRPCCMD_ENABLED = "strPcCmd"; + + //!!1.07 + private String ivHost; + + private boolean ivAltFKeyRemap; + + private boolean ivStrPcCmdEnabled; + private boolean ivReceivedStrPcCmd; + private boolean ivReceivedEndStrPcCmd; + + /** + * Default contructor. + */ + public XI5250Emulator() { + ivStatusBar = new XI5250StatusBar(); + ivStatusBar.setVisible(false); + add(ivStatusBar); + + enableEvents(AWTEvent.COMPONENT_EVENT_MASK); //!!1.03 + + setTerminalType("IBM-3179-2"); + + setState(ST_POWER_ON); + + setErrorRow(getCrtSize().height - 1); + + setKeyboardQueue(true); + } + + + /** + * XI5250EmulatorListener handling + */ + public synchronized void addEmulatorListener(XI5250EmulatorListener l) { + ivEmulatorListener = Multicaster.add(ivEmulatorListener, l); + } + + + /** + * XI5250EmulatorListener handling + */ + public synchronized void removeEmulatorListener(XI5250EmulatorListener l) { + ivEmulatorListener = Multicaster.remove(ivEmulatorListener, l); + } + + + /** + * Routes XI5250EmulatorEvent to listeners + */ + protected void processEmulatorEvent(XI5250EmulatorEvent e) { + if (ivEmulatorListener == null) + return; + + switch (e.getID()) { + // + case XI5250EmulatorEvent.CONNECTING: + ivEmulatorListener.connecting(e); + break; + // + case XI5250EmulatorEvent.CONNECTED: + ivEmulatorListener.connected(e); + break; + // + case XI5250EmulatorEvent.DISCONNECTED: + ivEmulatorListener.disconnected(e); + break; + // + case XI5250EmulatorEvent.STATE_CHANGED: + ivEmulatorListener.stateChanged(e); + break; + // + case XI5250EmulatorEvent.NEW_PANEL_RECEIVED: + ivEmulatorListener.newPanelReceived(e); + break; + // + case XI5250EmulatorEvent.FIELDS_REMOVED: + ivEmulatorListener.fieldsRemoved(e); + break; + // + case XI5250EmulatorEvent.DATA_SENDED: + ivEmulatorListener.dataSended(e); + break; + } + } + + + /** + * Redefined to move the status bar. + protected void processCrtEvent(XI5250CrtEvent e) { + switch (e.getID()) { + case XI5250CrtEvent.SIZE_CHANGED: + if (ivStatusBar != null) + moveStatusBar(); + break; + } + super.processCrtEvent(e); + } + */ + + + /** + * Redefined to move the status bar. + */ + @Override + public void doLayout() { + super.doLayout(); + moveStatusBar(); + } + + + /** + */ + private void moveStatusBar() { + synchronized (getTreeLock()) { + ivStatusBar.setFont(getFont()); + ivStatusBar.setBounds(0, getCrtBufferSize().height, + getCrtBufferSize().width, + getCharSize().height + 4); + ivStatusBar.setVisible(true); + } + } + + + /** + * Sets the host name, a previuos open connection is closed. + */ + public synchronized void setHost(String aHost) { + if (aHost == ivHost || + (aHost != null && aHost.equals(ivHost))) + return; + + setActive(false); + ivHost = aHost; + } + + + /** + * Returns the host name. + */ + public final String getHost() { + return ivHost; + } + + + /** + * Activate or deactivate the connection. + */ + public void setActive(boolean activate) { + boolean wasActive; + synchronized (this) { + wasActive = isActive(); + if (activate == wasActive) + return; + + if (activate) { + ivTelnet = new XITelnet(ivHost); + ivTelnet.setEmulator(ivTelnetEmulator); + ivTelnet.connect(); + } + else { + ivTelnet.disconnect(); + ivTelnet.setEmulator(null); + ivTelnet = null; + } + } + + firePropertyChange(ACTIVE, wasActive, isActive()); + } + + + /** + * True if the connection is active. + */ + public boolean isActive() { + return (ivTelnet == null) ? false : ivTelnet.isConnected(); + } + + + /** + * Sets the terminal type. + *
+   * Valid values are:
+   * IBM-3179-2  : 24x80  color display (DEFAULT)
+   * IBM-3477-FC : 27x132 color display
+   * 
+ */ + public void setTerminalType(String aTermType) { + if (aTermType != null && aTermType.equals(ivTermType)) + return; + + if (isActive()) + throw new IllegalArgumentException( + "Cannot change the terminal type, close the connection first."); + + if (!"IBM-3179-2".equals(aTermType) && !"IBM-3477-FC".equals(aTermType)) + throw new IllegalArgumentException( + "Wrong terminal type, valid values are IBM-3179-2 or IBM-3477-FC."); + + String oldTermType = ivTermType; + ivTermType = aTermType; + + firePropertyChange(TERMINAL_TYPE, oldTermType, ivTermType); + } + + + /** + */ + public String getTerminalType() { + return ivTermType; + } + + + /** + * See: http://www.faqs.org/rfcs/rfc2877.html and + * http://www.faqs.org/rfcs/rfc1572.html + */ + public void setTelnetEnv(String env) { + if (env != null && env.equals(ivTelnetEnv)) + return; + + if (isActive()) + throw new IllegalArgumentException( + "Cannot change the device name, close the connection first."); + + String old = ivTelnetEnv; + ivTelnetEnv = env; + + firePropertyChange(TELNET_ENV, old, ivTelnetEnv); + } + + + /** + */ + public String getTelnetEnv() { + return ivTelnetEnv; + } + + + /** + * @param value - if true FKEYS are accepted even if pressed in combination + * with the ALT key (usefull with platforms where FKEYS can be captured by + * the OS itself, such as MAX-OSX). + */ + public void setAltFKeyRemap(boolean value) { + if (value == ivAltFKeyRemap) + return; + boolean old = ivAltFKeyRemap; + ivAltFKeyRemap = value; + firePropertyChange(ALTFKEY_REMAP, old, ivAltFKeyRemap); + } + + public boolean getAltFKeyRemap() { + return ivAltFKeyRemap; + } + + /** + * @param value - if true the STRPCCMD order is enabled. + */ + public void setStrPcCmdEnabled(boolean value) { + if (value == ivStrPcCmdEnabled) + return; + boolean old = ivStrPcCmdEnabled; + ivStrPcCmdEnabled = value; + firePropertyChange(STRPCCMD_ENABLED, old, ivStrPcCmdEnabled); + } + + public boolean isStrPcCmdEnabled() { + return ivStrPcCmdEnabled; + } + + /** + * Moves the cursor to the given position. + * It updates also the status bar area with the new cursor coordinates. + */ + @Override + public void setCursorPos(int aCol, int aRow) { + super.setCursorPos(aCol, aRow); + + SwingUtilities.invokeLater(new Runnable() { + public void run() { + ivStatusBar.setCoordArea(getCursorCol() + 1, getCursorRow() + 1); + } + }); + } + + + /** + * Redefined to take care of the status-bar presence + */ + @Override + public Dimension getPreferredSize() { + Dimension size = super.getPreferredSize(); + size.height += getCharSize().height + 4; + return size; + } + + + /** + * Redefined to take care of the status-bar presence + */ + @Override + public Dimension getMinimumSize() { + Dimension size = super.getMinimumSize(); + size.height += getMinCharSize().height + 4; + return size; + } + + + /** + * Redefined to take care of the status-bar presence + * @see crt.XICrt#getTestSize + */ + @Override + protected Dimension getTestSize(Font aFont) { + FontMetrics fm = getFontMetrics(aFont); + Dimension res = new Dimension(fm.charWidth('W') * getCrtSize().width, + fm.getHeight() * (getCrtSize().height + 1) + 4); + return res; + } + + + /** + * Factory method for XI5250Field creation. + */ + protected XI5250Field create5250Field(byte[] aFFW, byte[] aFCW, + int aCol, int aRow, + int aLen, int aAttr) { + return new XI5250Field(this, aFFW, aFCW, aCol, aRow, aLen, aAttr); + } + + + /** + * Creates a XI5250EmulatorMemento instance. + * It is like a snapshot of the current internal state. + */ + public synchronized XI5250EmulatorMemento createMemento() { + return new XI5250EmulatorMemento((XI5250FieldsList)ivFields.clone(), + ivFunctionKeysMask, ivPendingCmd, + ivState, ivPrevState, + getCursorCol(), getCursorRow(), + ivErrorRow, + (XI5250CrtBuffer)getCrtBuffer().clone()); + } + + + /** + * Restores the internal state to a previous saved state. + */ + public void restoreMemento(XI5250EmulatorMemento aMemento) { + //!!0.95 this statement avoids deadlocks with component resizing. + synchronized (getTreeLock()) { + synchronized (this) { + Dimension dim = aMemento.ivCrtBuffer.getCrtSize(); + setCrtSize(dim.width, dim.height); //1.15a + + ivFields = aMemento.ivFields; + ivFunctionKeysMask = aMemento.ivFunctionKeysMask; + ivPendingCmd = aMemento.ivPendingCmd; + setState(aMemento.ivState); + ivPrevState = aMemento.ivPrevState; + setErrorRow(aMemento.ivErrorRow); + setCursorPos(aMemento.ivCol, aMemento.ivRow); + getCrtBuffer().copyFrom(aMemento.ivCrtBuffer); + + processEmulatorEvent(new XI5250EmulatorEvent(XI5250EmulatorEvent.NEW_PANEL_RECEIVED, + this)); + } + } + repaint(); + } + + + /** + * Works as createMemento but it is used when it switches to the System Request State. + */ + protected synchronized XI5250EmulatorMemento createSysReqMemento() { + return new XI5250EmulatorMemento((XI5250FieldsList)ivFields.clone(), + ivFunctionKeysMask, ivPendingCmd, + ivState, ivPrevState, + getCursorCol(), getCursorRow(), + ivErrorRow, + new XI5250CrtBuffer( + (XI5250CrtBuffer)getCrtBuffer(), + 0, ivErrorRow, getCrtSize().width, 1)); + } + + + /** + * @see #createSysReqMemento + */ + protected void restoreSysReqMemento(XI5250EmulatorMemento aMemento) { + //!!0.95 this statement avoids deadlocks with component resizing + synchronized (getTreeLock()) { + synchronized (this) { + ivFields = aMemento.ivFields; + ivFunctionKeysMask = aMemento.ivFunctionKeysMask; + ivPendingCmd = aMemento.ivPendingCmd; + //!! NO + //setState(aMemento.ivState); + //ivPrevState = aMemento.ivPrevState; + setErrorRow(aMemento.ivErrorRow); + setCursorPos(aMemento.ivCol, aMemento.ivRow); + + getCrtBuffer().copyFrom(0, ivErrorRow, aMemento.ivCrtBuffer, 0, 0, + getCrtSize().width, 1); + + processEmulatorEvent( + new XI5250EmulatorEvent(XI5250EmulatorEvent.NEW_PANEL_RECEIVED, + this)); + } + } + repaint(); + } + + + /** + * Called by XITelnet just before trying to connect. + * Sets the 5250 telnet requested flags (ie. TELOPT_BINARY, TELOPT_TTYPE, TELOPT_EOR). + * Fires the XI5250EmulatorEvent.CONNECTING event. + */ + protected void connecting() { + if (LOGGER.isLoggable(Level.FINE)) + LOGGER.fine("connecting()"); + + // sets required telnet options + ivTelnet.setTerminalType(ivTermType); + + if (ivTelnetEnv != null) + ivTelnet.setEnvironment(ivTelnetEnv); + + ivTelnet.setLocalReqFlag(XITelnet.TELOPT_BINARY, true); + ivTelnet.setLocalReqFlag(XITelnet.TELOPT_TTYPE, true); + ivTelnet.setLocalReqFlag(XITelnet.TELOPT_EOR, true); + + ivTelnet.setRemoteReqFlag(XITelnet.TELOPT_BINARY, true); + ivTelnet.setRemoteReqFlag(XITelnet.TELOPT_EOR, true); + + processEmulatorEvent( + new XI5250EmulatorEvent(XI5250EmulatorEvent.CONNECTING, this)); + } + + + /** + * Called by XITelnet when a connection is established. + * Fires the XI5250EmulatorEvent.CONNECTED event. + */ + protected void connected() { + if (LOGGER.isLoggable(Level.FINE)) + LOGGER.fine("connected()"); + + processEmulatorEvent( + new XI5250EmulatorEvent(XI5250EmulatorEvent.CONNECTED, this)); + } + + + /** + * Called by XITelnet when a connection is closed. + * Fires the XI5250EmulatorEvent.DISCONNECTED event. + */ + protected void disconnected() { + if (LOGGER.isLoggable(Level.FINE)) + LOGGER.fine("disconnected()"); + + { //!!1.07 + setState(ST_POWER_ON); + setDefAttr(0x20); + clear(); + removeFields(); + setCursorPos(0, 0); + } + + processEmulatorEvent( + new XI5250EmulatorEvent(XI5250EmulatorEvent.DISCONNECTED, this)); + } + + + /** + * Called by XITelnet when an IOException is catched. + */ + protected void catchedIOException(final IOException ex) { + if (LOGGER.isLoggable(Level.WARNING)) + LOGGER.log(Level.WARNING, "catchedIOException()", ex); + SwingUtilities.invokeLater(new Runnable() { + public void run() { + JOptionPane.showMessageDialog(XI5250Emulator.this, + ex.getClass().getName() + "\n" + + ex.getMessage() + + "\nSee the log for details ", + "WARNING", JOptionPane.WARNING_MESSAGE); + } + }); + } + + /** + * Called when 5250 stream parsing exception is catched. + * @param ex + */ + protected void catched5250Exception(XI5250Exception ex) { + if (LOGGER.isLoggable(Level.FINE)) + LOGGER.log(Level.FINE, "catched5250Exception()", ex); + send5250Error(ex.getErrorCode()); + } + + /** + * Called when an generic exception is catched. + * @param ex + */ + protected void catchedException(final Throwable ex) { + LOGGER.log(Level.SEVERE, "catchedException()", ex); + SwingUtilities.invokeLater(new Runnable() { + public void run() { + JOptionPane.showMessageDialog(XI5250Emulator.this, + ex.getMessage() + "\nSee the log for details ", + "ERROR", JOptionPane.ERROR_MESSAGE); + } + }); + } + + /** + */ + protected void receivedData(byte[] buf, int len) { + if (getState() == ST_POWER_ON) { + if (LOGGER.isLoggable(Level.WARNING)) + LOGGER.log(Level.WARNING, "Discarding received data len: " + len); + return; + } + + // eventuali eccezioni di overflow vengono generate dal linguaggio in automatico + System.arraycopy(buf, 0, ivRXBuf, ivRXBufLen, len); + ivRXBufLen += len; + } + + + /** + * Processes the 5250 received stream creating a new XI5250CmdList. + *
+   * this is a simplified version of what it does:
+   *
+   *   ...
+   *   XI5250CmdList cmdList = createCmdList(this);  // creates a new command list
+   *   ...
+   *   cmdList.readFrom5250Stream(dataStream);       // construct commands from the 5250 data stream
+   *   ...
+   *   cmdList.execute();                            // execute all commands
+   *   ...
+   *   initAllFields();                              // input fields inizialization
+   *   ...
+   *   ...                  // fires XI5250EmulatorEvent.NEW_PANEL_RECEIVED event
+   *
+   * 
+ */ + protected void receivedEOR() { + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.fine("receivedEOR()"); + + if (LOGGER.isLoggable(Level.FINER)) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < ivRXBufLen; i++) + sb.append(XITelnet.toHex(ivRXBuf[i]) + " "); + LOGGER.finer(sb.toString()); + } + } + + // verify packet header + int packetLen = (XITelnet.toInt(ivRXBuf[0]) << 8) + + XITelnet.toInt(ivRXBuf[1]); + if (packetLen != ivRXBufLen || ivRXBuf[2] != (byte)0x12 || + ivRXBuf[3] != (byte)0xA0) { + //TODO ?? + if (LOGGER.isLoggable(Level.FINE)) + LOGGER.fine("malformed packet"); + + ivRXBufLen = 0; + return; + } + + // variable header part + int varHdrLen = XITelnet.toInt(ivRXBuf[6]); + int dataStart = 6 + varHdrLen; // start of data + @SuppressWarnings("unused") + final boolean errFlag = (ivRXBuf[7] & FLAG_ERR) != 0; // data stream output error + @SuppressWarnings("unused") + final boolean atnFlag = (ivRXBuf[7] & FLAG_ATN) != 0; // attention key pressed + @SuppressWarnings("unused") + final boolean srqFlag = (ivRXBuf[7] & FLAG_SRQ) != 0; // system request key pressed + @SuppressWarnings("unused") + final boolean trqFlag = (ivRXBuf[7] & FLAG_TRQ) != 0; // test request key + @SuppressWarnings("unused") + final boolean hlpFlag = (ivRXBuf[7] & FLAG_HLP) != 0; // help error state + + byte opCode = ivRXBuf[9]; + + ByteArrayInputStream dataStream = new ByteArrayInputStream(ivRXBuf, dataStart, + ivRXBufLen - dataStart); + if (LOGGER.isLoggable(Level.FINE)) + LOGGER.fine("OPCODE : " + OPCODE[opCode]); + + switch (opCode) { + // + case OPCODE_NOP: + case OPCODE_RESERVED1: + case OPCODE_RESERVED2: + break; + // + case OPCODE_OUTPUT_ONLY: + case OPCODE_PUT_GET: + case OPCODE_READ_SCREEN: + case OPCODE_SAVE_SCREEN: + case OPCODE_RESTORE_SCREEN: + case OPCODE_READ_IMM: + case OPCODE_INVITE_OPERATION: + ivReceivedStrPcCmd = false; + ivReceivedEndStrPcCmd = false; + // read command list + XI5250CmdList cmdList = createCmdList(this); + try { + cmdList.readFrom5250Stream(dataStream); + ivCmdList = cmdList; + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + //!!0.95 this statement avoids deadlocks during component resizing + synchronized (getTreeLock()) { + synchronized (this) { + if (getState() == ST_SYSTEM_REQUEST) //!!1.01b + setPrevState(); + + setFreeze(true); + try { + ivCmdList.execute(); + // input fields initialization + initAllFields(); + + processEmulatorEvent( + new XI5250EmulatorEvent( + XI5250EmulatorEvent.NEW_PANEL_RECEIVED, + XI5250Emulator.this)); + } + finally { + setFreeze(false); + } + } + } + if (ivReceivedStrPcCmd) { + char ctrlChar = getChar(0, 0); + boolean wait = !(ctrlChar == 'a'); + String cmd = getString(1, 0, 132 - STRPCCMD.length); + { + int k = cmd.length() - 1; + for ( ; k >= 0; k--) { + char ch = cmd.charAt(k); + if (!Character.isISOControl(ch) && !Character.isWhitespace(ch)) + break; + } + cmd = cmd.substring(0, k + 1); + } + try { + if (LOGGER.isLoggable(Level.INFO)) { + if (wait) + LOGGER.info("Executing and waiting for local command: " + cmd); + else + LOGGER.info("Executing local command: " + cmd); + } + try { + strPcCmd(wait, cmd); + } + catch (IOException ex) { + catchedIOException(ex); + } + catch (InterruptedException ex) { + catchedException(ex); + } + } + finally { + // AUTOENTER + processRawKeyEvent( + new KeyEvent(XI5250Emulator.this, KeyEvent.KEY_PRESSED, + 0, -1, KeyEvent.VK_ENTER, KeyEvent.CHAR_UNDEFINED)); + } + } + else if (ivReceivedEndStrPcCmd) { + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("Received STRPCCMD shutdown" ); + } + // AUTOENTER + processRawKeyEvent( + new KeyEvent(XI5250Emulator.this, KeyEvent.KEY_PRESSED, + 0, -1, KeyEvent.VK_ENTER, KeyEvent.CHAR_UNDEFINED)); + } + } + }); + } + catch (IOException ex) { + catchedException(ex); + } + catch (XI5250Exception ex) { + catched5250Exception(ex); + } + catch (Exception ex) { + catchedException(ex); + } + + if (LOGGER.isLoggable(Level.FINER)) + LOGGER.finer("" + cmdList); + + break; + // + case OPCODE_CANCEL_INVITE: + receivedCancelInvite(); + break; + // + case OPCODE_TURN_ON_MSG: + case OPCODE_TURN_OFF_MSG: + switchMsgLight(opCode == OPCODE_TURN_ON_MSG); + break; + // + default: + throw new RuntimeException("Illegal 5250 opcode received"); + } + + ivRXBufLen = 0; + } + + + /** + */ + protected void localFlagsChanged(byte aIACOpt) { + } + + + /** + */ + protected void remoteFlagsChanged(byte aIACOpt) { + if (aIACOpt == XITelnet.TELOPT_EOR && + ivTelnet.isRemoteFlagON(XITelnet.TELOPT_EOR)) + setState(ST_POWERED); + } + + + /** + */ + protected void unhandledRequest(byte aIACOpt, String aIACStr) { + if (LOGGER.isLoggable(Level.FINE)) + LOGGER.fine("unhandledRequest()"); + } + + + /** + * Turns on or off the message icon on the status bar. + */ + protected void switchMsgLight(boolean turnOn) { + ivStatusBar.setMessageArea((turnOn) ? XI5250StatusBar.MESSAGE_ON : + XI5250StatusBar.MESSAGE_OFF); + } + + + /** + * Answers to cancel invite request. + */ + protected void receivedCancelInvite() { + ivPendingCmd = null; + + send5250Packet((byte)0x00, OPCODE_CANCEL_INVITE, null); + } + + + /** + * Enables or disables the keyboard queue. (DEFAULT enabled) + */ + public synchronized void setKeyboardQueue(boolean flag) { + if (flag == isKeyboardQueue()) + return; + + if (flag) { + ivKeybEventQueue = new KeyEventQueue(); + startKeybThread(); + } + else { + ivKeybEventQueue = null; + stopKeybThread(); + } + } + + + /** + */ + public boolean isKeyboardQueue() { + return (ivKeybEventQueue != null); + } + + + /** + * Removes all entries in keyboard queue. + */ + public void clearKeyboardQueue() { + if (ivKeybEventQueue != null) + ivKeybEventQueue.removeAll(); + } + + + /** + */ + protected void startKeybThread() { + if (!isKeyboardQueue() || ivKeybThread != null) + return; + + if (LOGGER.isLoggable(Level.FINE)) + LOGGER.fine("startKeybThread()"); + + ivKeybThread = new KeyEventDispatchThread(this); + ivKeybThread.start(); + } + + + /** + */ + protected void stopKeybThread() { + if (!isKeyboardQueue() || ivKeybThread == null) + return; + + if (LOGGER.isLoggable(Level.FINE)) + LOGGER.fine("stopKeybThread()"); + + ivKeybThread.stopDispatching(); + ivKeybThread = null; + } + + + /** + * Changes the emulator state. + */ + protected synchronized void setState(int aState) { + if (aState == ivState) + return; + + int oldState = ivState; + + // ST_TEMPORARY_LOCK must not be saved !!! + if (ivState >= 0) + ivPrevState = ivState; + ivState = aState; + ivStatusBar.setStateArea(aState); + + if (LOGGER.isLoggable(Level.FINE)) + LOGGER.fine("ivPrevState = " + ST_DESCRIPTION[ivPrevState - ST_NULL] + " " + + "ivState = " + ST_DESCRIPTION[ivState - ST_NULL]); + + // things to do after exiting from a state + switch (oldState) { + // + case ST_SYSTEM_REQUEST: + restoreSysReqMemento(ivSysReqMemento); + ivSysReqMemento = null; + ivSysReqField = null; + break; + // + case ST_PRE_HELP: + // restore error row + getCrtBuffer().copyFrom(0, ivErrorRow, ivPreHelpErrorLine, + 0, 0, getCrtSize().width, 1); + repaint(); + break; + } + + // things to do after entering a new state + switch (aState) { + // + case ST_POWER_ON: + ivStatusBar.setFlashArea(true); + break; + // + case ST_POWERED: + ivStatusBar.setFlashArea(false); + break; + // + case ST_TEMPORARY_LOCK: + case ST_NORMAL_LOCKED: + stopKeybThread(); + break; + // + case ST_SYSTEM_REQUEST: + ivSysReqMemento = createSysReqMemento(); + removeFields(); + ivPendingCmd = null; //!!0.92a + drawString(String.valueOf(XI5250Emulator.ATTRIBUTE_PLACE_HOLDER), + 0, ivErrorRow, 0x34); + ivSysReqField = + new XI5250Field(this, 1, ivErrorRow, getCrtSize().width - 2, -1); + addField(ivSysReqField); + initAllFields(); + ivSysReqField.clear(); + setCursorPos(1, ivErrorRow); + startKeybThread(); + break; + // + case ST_PRE_HELP: + // save error row + ivPreHelpErrorLine = new XI5250CrtBuffer((XI5250CrtBuffer)getCrtBuffer(), + 0, ivErrorRow, + getCrtSize().width, 1); + startKeybThread(); + break; + // + default: + startKeybThread(); + break; + } + + processEmulatorEvent(new XI5250EmulatorEvent(XI5250EmulatorEvent.STATE_CHANGED, this)); + } + + + /** + * Returns the current emulator state. + */ + public int getState() { + return ivState; + } + + + /** + * Switches back to the previous state. + */ + protected void setPrevState() { + setState(ivPrevState); + } + + + /** + */ + public int getPrevState() { + return ivPrevState; + } + + + /** + * Factory method for XI5250CmdList class. + */ + protected XI5250CmdList createCmdList(XI5250Emulator aEm) { + return new XI5250CmdList(aEm); + } + + + /** + * Factory method for XI5250OrdList class + */ + protected XI5250OrdList createOrdList(XI5250Emulator aEm) { + return new XI5250OrdList(aEm); + } + + + /** + * Changes the error row. + */ + protected void setErrorRow(int aRow) { + ivErrorRow = Math.min(aRow, getCrtSize().height - 1); + } + + + /** + */ + protected int getErrorRow() { + return ivErrorRow; + } + + + /** + */ + protected void setFunctionKeysMask(int aMask) { + ivFunctionKeysMask = aMask; + } + + + /** + */ + protected boolean isMasterMDTSet() { + //TODO ?? + return true; + } + + + /** + * DO NOT USE, reserved for commands and orders + * Sends a 5250 data stream. + */ + public void send5250Packet(byte flags, byte opcode, byte[] buf, int aLen) { + byte[] cBuf = {(byte)0x00, (byte)0x00, //len + (byte)0x12, (byte)0xA0, + (byte)0x00, (byte)0x00, + (byte)0x04, flags, + (byte)0x00, opcode}; + int len = aLen + cBuf.length; + + cBuf[0] = (byte)((len & 0xFF00)>> 8); + cBuf[1] = (byte)(len & 0x00FF); + + try { + ivTelnet.send(cBuf); + if (buf != null && aLen != 0) + ivTelnet.send(buf, aLen); + ivTelnet.sendEOR(); + } + catch (IOException ex) { + catchedIOException(ex); + } + } + + + /** + * DO NOT USE, reserved for commands and orders + * Sends a 5250 data stream. + */ + public void send5250Packet(byte flags, byte opcode, byte[] buf) { + send5250Packet(flags, opcode, buf, (buf != null) ? buf.length : 0); + } + + + /** + */ + public void send5250UserError(int aErrorCode) { + XIEbcdicTranslator translator = getTranslator(); + byte[] buf = translator.toPacked(aErrorCode, 4); + + send5250Packet(FLAG_HLP, OPCODE_NOP, buf); + } + + + /** + * DO NOT USE, reserved for commands and orders + * Sends a 5250 error decoding request. + */ + public void send5250Error(int aErrorCode) { + XIEbcdicTranslator translator = getTranslator(); + byte[] buf = translator.toPacked(aErrorCode, 8); + + send5250Packet(FLAG_ERR, OPCODE_NOP, buf); + } + + + /** + * DO NOT USE, reserved for commands and orders + * Sends a 5250 data-stream. + * To store in the output stream the fields content uses an instance of XIFieldTo5250Stream. + * @see XIFieldTo5250Stream + * + * @param anAidCode the aid code to use AID_... + * @param includeFields fields content must be sended + * @param includeMDTOnly send only modified fields + */ + public void send5250Data(int anAidCode, boolean includeFields, + boolean includeMDTOnly) { + ByteArrayOutputStream out = new ByteArrayOutputStream(1024); + byte[] cBuf = {(byte)(getCursorRow() + 1), (byte)(getCursorCol() + 1), + (byte)anAidCode}; + + try { + out.write(cBuf); + + if (includeFields) + ivFields.saveTo(new XIFieldTo5250Stream(this, out, includeMDTOnly)); + + byte[] buf = out.toByteArray(); + + if (LOGGER.isLoggable(Level.FINER)) { + LOGGER.finer("---->Send5250Data"); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < buf.length; i++) + sb.append(XITelnet.toHex(buf[i]) + " "); + LOGGER.finer(sb.toString()); + } + + send5250Packet((byte)0x00, OPCODE_NOP, buf); + + processEmulatorEvent(new XI5250EmulatorEvent(XI5250EmulatorEvent.DATA_SENDED, + this, (byte)anAidCode)); + } + catch (IOException ex) { + catchedIOException(ex); + } + } + + + /** + * DO NOT USE, reserved for commands and orders + */ + public void send5250SavedScreen(int aScreenNum) { + byte[] cBuf = {ESC, CMD_RESTORE_SCREEN, (byte)aScreenNum}; + + send5250Packet((byte)0x00, OPCODE_SAVE_SCREEN, cBuf); + } + + + /** + * DO NOT USE, reserved for commands and orders + */ + public void send5250Screen() { + XIEbcdicTranslator translator = getTranslator(); + ByteArrayOutputStream out = new ByteArrayOutputStream(1024); + + for (int row = 0; row < getCrtSize().height; row++) { + for (int col = 0; col < getCrtSize().width; col++) { + char ch = getChar(col, row); + if (ch == ATTRIBUTE_PLACE_HOLDER) { + ch = (char)getAttr(col, row); + out.write((byte)ch); + } + else + out.write(translator.toEBCDIC(ch)); + } + } + + byte[] buf = out.toByteArray(); + + send5250Packet((byte)0x00, OPCODE_READ_SCREEN, buf); + } + + + /** + * Updates the status-bar shift area. + */ + protected void updateStatusBar(InputEvent e) { + ivStatusBar.setShiftArea((e.isShiftDown()) ? + XI5250StatusBar.SHIFT_DOWN : + XI5250StatusBar.SHIFT_UP); + } + + + /** + * DO NOT USE, reserved for commands and orders + * Removes all fields. + */ + @Override + public void removeFields() { + super.removeFields(); + processEmulatorEvent(new XI5250EmulatorEvent(XI5250EmulatorEvent.FIELDS_REMOVED, this)); + } + + + /** + * Redefined to request 5250 error decoding. + */ + @Override + protected void userError(int aError) { + Toolkit.getDefaultToolkit().beep(); + setState(ST_PRE_HELP); + send5250UserError(aError); + } + + + /** + */ + @Override + protected void processMouseEvent(MouseEvent e) { + updateStatusBar(e); + super.processMouseEvent(e); + } + + + /** + */ + @Override + protected void processKeyEvent(KeyEvent e) { + updateStatusBar(e); + super.processKeyEvent(e); + } + + + /** + * Avoid concurrent access with the synchronized part of receivedEOR() method. + * When we get there the translation process has already been done. + */ + @Override + public synchronized void processRawKeyEvent(KeyEvent e) { + // keyboard handling that doesn' t depends on 5250 state + switch (e.getID()) { + // + case KeyEvent.KEY_PRESSED: + switch (e.getKeyCode()) { + // + case KeyEvent.VK_ESCAPE: + if (ivKeybEventQueue != null) + ivKeybEventQueue.removeAll(); + + // SysReq + if (e.getModifiers() == KeyEvent.SHIFT_MASK) + setState(ST_SYSTEM_REQUEST); + break; + // + case KeyEvent.VK_CONTROL: //!!1.01b + if (e.getModifiers() == KeyEvent.CTRL_MASK && ivKeybEventQueue != null) + ivKeybEventQueue.removeAll(); + break; + } + break; + } + + if (ivKeybEventQueue == null) + doProcessKeyEvent(e); + else + ivKeybEventQueue.postEvent(new KeyEvent(e.getComponent(), e.getID(), + e.getWhen(), e.getModifiers(), + e.getKeyCode(), e.getKeyChar())); + + //!!1.13a consume anything, except ALT+... key combinations + if ((e.getModifiers() & KeyEvent.ALT_MASK) == 0) + e.consume(); + } + + + /** + * Here is where the real keyboard handling is done. + * If the keyboard queue is enabled we get there when it is safe to handle the key event. + */ + @Override + protected synchronized void doProcessKeyEvent(KeyEvent e) { + // pre + switch (e.getID()) { + // + case KeyEvent.KEY_PRESSED: + if (getState() == ST_PRE_HELP && !isCharKey(e)) + setPrevState(); + break; + } + + // keyboard handling that depends on 5250 state + switch (getState()) { + // + case ST_TEMPORARY_LOCK: + case ST_NORMAL_LOCKED: + break; + // + case ST_SYSTEM_REQUEST: + processKeySystemRequest(e); + break; + // + case ST_NORMAL_UNLOCKED: + processKeyNormalUnlocked(e); + break; + } + } + + + /** + * Keyboard handling during the System request state. + */ + protected boolean processKeySystemRequest(KeyEvent e) { + super.doProcessKeyEvent(e); + if (e.isConsumed()) + return true; + + boolean res = false; + switch (e.getID()) { + // + case KeyEvent.KEY_TYPED: + if (isCharKey(e)) { + // if we get there then a key has been pressed outside of an input field + setPrevState(); + userError(5); + res = true; + } + break; + // + case KeyEvent.KEY_PRESSED: + switch (e.getKeyCode()) { + case KeyEvent.VK_ESCAPE: + if (e.getModifiers() == 0) + setPrevState(); + break; + // + case KeyEvent.VK_ENTER: + String aStr = ivSysReqField.getString(); + setPrevState(); + int i; + + // exclude trailing null chars + for (i = aStr.length() - 1; (i >= 0) && (aStr.charAt(i) == '\u0000'); i--) + ; + + byte[] buf = getTranslator().toText(aStr, i + 1); + + if (LOGGER.isLoggable(Level.FINER)) { + LOGGER.finer("---->Send5250SysReq"); + StringBuilder sb = new StringBuilder(); + for (i = 0; i < buf.length; i++) + sb.append(XITelnet.toHex(buf[i]) + " "); + LOGGER.finer(sb.toString()); + } + + send5250Packet(FLAG_SRQ, OPCODE_NOP, buf); + break; + } + break; + } + + return res; + } + + + /** + * Keyboard handling during the Normal unlocked state. + */ + protected boolean processKeyNormalUnlocked(KeyEvent e) { + super.doProcessKeyEvent(e); + if (e.isConsumed()) + return true; + + boolean res = false; + switch (e.getID()) { + // + case KeyEvent.KEY_TYPED: + if (isCharKey(e)) { + // if we get there then a key was pressed outside of an input field + userError(5); + res = true; + } + break; + // + case KeyEvent.KEY_PRESSED: + switch (e.getKeyCode()) { + // + case KeyEvent.VK_ESCAPE: + // Attn + if (e.getModifiers() == 0) + send5250Packet(FLAG_ATN, OPCODE_NOP, null); + break; + // + case KeyEvent.VK_ENTER: + res = processKeyEnter(e.getModifiers()); + break; + // + case KeyEvent.VK_F1: + case KeyEvent.VK_F2: + case KeyEvent.VK_F3: + case KeyEvent.VK_F4: + case KeyEvent.VK_F5: + case KeyEvent.VK_F6: + case KeyEvent.VK_F7: + case KeyEvent.VK_F8: + case KeyEvent.VK_F9: + case KeyEvent.VK_F10: + case KeyEvent.VK_F11: + case KeyEvent.VK_F12: + res = processKeyFXX(e.getKeyCode(), e.getModifiers()); + break; + // + case KeyEvent.VK_PAGE_UP: + case KeyEvent.VK_PAGE_DOWN: + res = processKeyPageXX(e.getKeyCode(), e.getModifiers()); + break; + // + case KeyEvent.VK_PAUSE: + res = processKeyPause(e.getModifiers()); + break; + } + break; + } + + return res; + } + + + private static final int AUTO_ENTER_MODIFIERS = (new KeyEvent(new JLabel(""), + KeyEvent.KEY_PRESSED, 0, -1, KeyEvent.VK_ENTER, (char)KeyEvent.VK_ENTER)).getModifiers(); + + /** + */ + protected boolean processKeyEnter(int aModifier) { + // Cannot detect -1 modifier directly + if (aModifier != 0 && aModifier != AUTO_ENTER_MODIFIERS) + return false; + + if (ivPendingCmd != null) + ivPendingCmd.executePending( + (aModifier != AUTO_ENTER_MODIFIERS) ? AID_ENTER : AID_AUTO_ENTER, false); + + return true; + } + + + /** + */ + protected boolean processKeyFXX(int aKey, int aModifier) { + int ofs = aKey - KeyEvent.VK_F1; + int aidCode; + if (aModifier == 0) + aidCode = AID_COMMAND + ofs; + else if (aModifier == KeyEvent.SHIFT_MASK) + aidCode = AID_F13 + ofs; + else if (aModifier == KeyEvent.ALT_MASK && aKey == KeyEvent.VK_F1) + aidCode = AID_HELP; + else + return false; + + int mask = 1 << ofs; + + if (ivPendingCmd != null) + ivPendingCmd.executePending(aidCode, ((ivFunctionKeysMask & mask) != 0)); + return true; + } + + + /** + */ + protected boolean processKeyPageXX(int aKey, int aModifier) { + if (aModifier != 0) + return false; + + if (ivPendingCmd != null) + ivPendingCmd.executePending((aKey == KeyEvent.VK_PAGE_UP) ? AID_ROLL_DN : + AID_ROLL_UP, + false); + + return true; + } + + /** + */ + protected boolean processKeyPause(int aModifier) { + if (aModifier != 0) + return false; + + if (ivPendingCmd != null) + ivPendingCmd.executePending(AID_CLEAR, false); + + return true; + } + + /** + * Exit usefull for keyboard remapping. + */ + @SuppressWarnings("deprecation") + @Override + protected KeyEvent translateKeyEvent(KeyEvent e) { + if (!getAltFKeyRemap()) + return e; + if (e.getKeyCode() >= KeyEvent.VK_F1 && e.getKeyCode () <= KeyEvent.VK_F12) { + // ALT+SHIFT+Fx replaces ALT+Fx + if ((e.getModifiers() & KeyEvent.ALT_MASK) != 0 && + (e.getModifiers() & KeyEvent.SHIFT_MASK) != 0) { + e.setModifiers(e.getModifiers() & ~KeyEvent.SHIFT_MASK); + } + // ALT+Fx replaces Fx + else if ((e.getModifiers() & KeyEvent.ALT_MASK) != 0) { + e.setModifiers(e.getModifiers() & ~KeyEvent.ALT_MASK); + } + } + return e; + } + + /** + */ + @Override + protected void finalize() throws Throwable { + setActive(false); + super.finalize(); + } + + + void receivedStrPcCmd() { + if (!isStrPcCmdEnabled()) + throw new IllegalStateException(); + ivReceivedStrPcCmd = true; + } + void receivedEndStrPcCmd() { + if (!isStrPcCmdEnabled()) + throw new IllegalStateException(); + ivReceivedEndStrPcCmd = true; + } + + /** + * @param wait + * @param cmd + * @return the process return code if wait is true, otherwise 0 + * @throws IOException + * @throws InterruptedException + */ + protected int strPcCmd(boolean wait, String cmd) throws IOException, InterruptedException { + Process proc = Runtime.getRuntime().exec(cmd); + return wait ? proc.waitFor() : 0; + } + + + ////////////////////////////////////////////////////////////////////////////// + + /** + * Multicast Listener for XI5250Emulator + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ + private static class Multicaster extends AWTEventMulticaster + implements XI5250EmulatorListener { + + protected Multicaster(EventListener a, EventListener b) { + super(a, b); + } + + + //!!1.03a + @Override + protected EventListener remove(EventListener oldl) { + if (oldl == a) return b; + if (oldl == b) return a; + EventListener a2 = removeInternal(a, oldl); + EventListener b2 = removeInternal(b, oldl); + if (a2 == a && b2 == b) + return this; + return add((XI5250EmulatorListener)a2, (XI5250EmulatorListener)b2); + } + + + public static XI5250EmulatorListener add(XI5250EmulatorListener a, + XI5250EmulatorListener b) { + if (a == null) return b; + if (b == null) return a; + return new Multicaster(a, b); + } + + + public static XI5250EmulatorListener remove(XI5250EmulatorListener a, + XI5250EmulatorListener b) { + return (XI5250EmulatorListener)removeInternal(a, b); + } + + + /** + */ + public void connecting(XI5250EmulatorEvent e) { + ((XI5250EmulatorListener)a).connecting(e); + ((XI5250EmulatorListener)b).connecting(e); + } + + + /** + */ + public void connected(XI5250EmulatorEvent e) { + ((XI5250EmulatorListener)a).connected(e); + ((XI5250EmulatorListener)b).connected(e); + } + + + /** + */ + public void disconnected(XI5250EmulatorEvent e) { + ((XI5250EmulatorListener)a).disconnected(e); + ((XI5250EmulatorListener)b).disconnected(e); + } + + + /** + */ + public void stateChanged(XI5250EmulatorEvent e) { + ((XI5250EmulatorListener)a).stateChanged(e); + ((XI5250EmulatorListener)b).stateChanged(e); + } + + + /** + */ + public void newPanelReceived(XI5250EmulatorEvent e) { + ((XI5250EmulatorListener)a).newPanelReceived(e); + ((XI5250EmulatorListener)b).newPanelReceived(e); + } + + + /** + */ + public void fieldsRemoved(XI5250EmulatorEvent e) { + ((XI5250EmulatorListener)a).fieldsRemoved(e); + ((XI5250EmulatorListener)b).fieldsRemoved(e); + } + + + /** + */ + public void dataSended(XI5250EmulatorEvent e) { + ((XI5250EmulatorListener)a).dataSended(e); + ((XI5250EmulatorListener)b).dataSended(e); + } + } + + + ////////////////////////////////////////////////////////////////////////////// + + /** + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ + protected static class KeyEventQueueItem { + AWTEvent ivEvent; + int ivId; + KeyEventQueueItem ivNext; + + + public KeyEventQueueItem(AWTEvent evt) { + ivEvent = evt; + ivId = evt.getID(); + } + } + + + ////////////////////////////////////////////////////////////////////////////// + + /** + * Implements a circular Queue. + * It is used when keyboard buffering is on. + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ + protected static class KeyEventQueue { + + private KeyEventQueueItem ivQueue; + + + public KeyEventQueue() { + } + + + public synchronized void postEvent(AWTEvent theEvent) { + KeyEventQueueItem eqi = new KeyEventQueueItem(theEvent); + if (ivQueue == null) { + ivQueue = eqi; + ivQueue.ivNext = ivQueue; + notifyAll(); + } + else { + eqi.ivNext = ivQueue.ivNext; + ivQueue.ivNext = eqi; + ivQueue = eqi; + } + } + + + public synchronized AWTEvent getNextEvent() throws InterruptedException { + while (ivQueue == null) + wait(); + + KeyEventQueueItem eqi = ivQueue.ivNext; + if (eqi == ivQueue) + ivQueue = null; + else + ivQueue.ivNext = eqi.ivNext; + return eqi.ivEvent; + } + + + public synchronized void removeAll() { + ivQueue = null; + } + } + + + ////////////////////////////////////////////////////////////////////////////// + + /** + * When keyboard buffering is on all keys are posted in a KeyEventQueue. + * This thread dispatches such key events to the doProcessKeyEvent method of XI5250Emulator. + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ + protected static class KeyEventDispatchThread extends Thread { + + protected XI5250Emulator ivEmulator; + protected boolean ivStop = false; + + + /** + */ + public KeyEventDispatchThread(XI5250Emulator aEmulator) { + super("5250 Keyboard event dispatching thread"); + ivEmulator = aEmulator; + } + + + public void stopDispatching() { + ivStop = true; + if (this != Thread.currentThread()) { //!!V 06/07/98 + interrupt(); + } + } + + + /** + */ + @Override + public void run() { + while (!ivStop && ivEmulator.isKeyboardQueue()) { + try { + final KeyEvent e = (KeyEvent)ivEmulator.ivKeybEventQueue.getNextEvent(); + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + synchronized (ivEmulator.getTreeLock()) { // just to avoid dead-locks + ivEmulator.doProcessKeyEvent(e); + } + } + }); + } + catch (InterruptedException ex) { + continue; + } + catch (ThreadDeath ex) { + throw ex; + } + catch (Throwable ex) { + System.err.println( + "Exception occurred during 5250 keyboard event dispatching:"); + ex.printStackTrace(); + } + } + } + } + + + ////////////////////////////////////////////////////////////////////////////// + + /** + */ + class TelnetEmulator implements XITelnetEmulator { + + public final void connecting() { + XI5250Emulator.this.connecting(); + } + + public final void connected() { + XI5250Emulator.this.connected(); + } + + public final void disconnected() { + XI5250Emulator.this.disconnected(); + } + + public final void catchedIOException(IOException ex) { + XI5250Emulator.this.catchedIOException(ex); + } + + public final void receivedData(byte[] buf, int len) { + XI5250Emulator.this.receivedData(buf, len); + } + + public final void receivedEOR() { + XI5250Emulator.this.receivedEOR(); + } + + public final void unhandledRequest(byte aIACOpt, String aIACStr) { + XI5250Emulator.this.unhandledRequest(aIACOpt, aIACStr); + } + + public final void localFlagsChanged(byte aIACOpt) { + XI5250Emulator.this.localFlagsChanged(aIACOpt); + } + + public final void remoteFlagsChanged(byte aIACOpt) { + XI5250Emulator.this.remoteFlagsChanged(aIACOpt); + } + } +} diff --git a/net/infordata/em/tn5250/XI5250EmulatorAdapter.java b/net/infordata/em/tn5250/XI5250EmulatorAdapter.java new file mode 100644 index 0000000..3732690 --- /dev/null +++ b/net/infordata/em/tn5250/XI5250EmulatorAdapter.java @@ -0,0 +1,74 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +/** + * XI5250EmulatorListener adapter. + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XI5250EmulatorAdapter implements XI5250EmulatorListener { + + /** + */ + public void connecting(XI5250EmulatorEvent e) { + } + + + /** + */ + public void connected(XI5250EmulatorEvent e) { + } + + + /** + */ + public void disconnected(XI5250EmulatorEvent e) { + } + + + /** + */ + public void stateChanged(XI5250EmulatorEvent e) { + } + + + /** + */ + public void newPanelReceived(XI5250EmulatorEvent e) { + } + + + /** + */ + public void fieldsRemoved(XI5250EmulatorEvent e) { + } + + + /** + */ + public void dataSended(XI5250EmulatorEvent e) { + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XI5250EmulatorBeanInfo.java b/net/infordata/em/tn5250/XI5250EmulatorBeanInfo.java new file mode 100644 index 0000000..6fcb71d --- /dev/null +++ b/net/infordata/em/tn5250/XI5250EmulatorBeanInfo.java @@ -0,0 +1,102 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + + +package net.infordata.em.tn5250; + +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.beans.SimpleBeanInfo; + +public class XI5250EmulatorBeanInfo extends SimpleBeanInfo { + Class beanClass = XI5250Emulator.class; + String iconColor16x16Filename = "resources/XI5250Emulator_16.gif"; + String iconColor32x32Filename = "resources/XI5250Emulator_32.gif"; + String iconMono16x16Filename; + String iconMono32x32Filename; + + + public XI5250EmulatorBeanInfo() { + } + + @Override + public PropertyDescriptor[] getPropertyDescriptors() { + try { + PropertyDescriptor _active = + new PropertyDescriptor("active", beanClass, "isActive", "setActive"); + + PropertyDescriptor _host = + new PropertyDescriptor("host", beanClass, "getHost", "setHost"); + + PropertyDescriptor _keyboardQueue = + new PropertyDescriptor("keyboardQueue", beanClass, + "isKeyboardQueue", "setKeyboardQueue"); + + PropertyDescriptor _terminalType = + new PropertyDescriptor("terminalType", beanClass, + "getTerminalType", "setTerminalType"); + + PropertyDescriptor _altFKeyRemap = + new PropertyDescriptor("altFKeyRemap", beanClass, + "getAltFKeyRemap", "setAltFKeyRemap"); + + PropertyDescriptor[] pds = new PropertyDescriptor[] { + _active, + _host, + _keyboardQueue, + _terminalType, + _altFKeyRemap, + }; + return pds; + } + catch (IntrospectionException ex) { + ex.printStackTrace(); + return null; + } + } + + @Override + public java.awt.Image getIcon(int iconKind) { + switch (iconKind) { + case BeanInfo.ICON_COLOR_16x16: + return iconColor16x16Filename != null ? loadImage(iconColor16x16Filename) : null; + case BeanInfo.ICON_COLOR_32x32: + return iconColor32x32Filename != null ? loadImage(iconColor32x32Filename) : null; + case BeanInfo.ICON_MONO_16x16: + return iconMono16x16Filename != null ? loadImage(iconMono16x16Filename) : null; + case BeanInfo.ICON_MONO_32x32: + return iconMono32x32Filename != null ? loadImage(iconMono32x32Filename) : null; + } + return null; + } + + @Override + public BeanInfo[] getAdditionalBeanInfo() { + Class superclass = beanClass.getSuperclass(); + try { + BeanInfo superBeanInfo = Introspector.getBeanInfo(superclass); + return new BeanInfo[] { superBeanInfo }; + } + catch (IntrospectionException ex) { + ex.printStackTrace(); + return null; + } + } +} + diff --git a/net/infordata/em/tn5250/XI5250EmulatorCtrl.java b/net/infordata/em/tn5250/XI5250EmulatorCtrl.java new file mode 100644 index 0000000..7555422 --- /dev/null +++ b/net/infordata/em/tn5250/XI5250EmulatorCtrl.java @@ -0,0 +1,204 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** +!!V 09/07/98 rel. 1.10 - creation. + */ + + +package net.infordata.em.tn5250; + + +import java.util.ResourceBundle; + +import javax.swing.JOptionPane; + +import net.infordata.em.crt5250.XI5250Crt; +import net.infordata.em.crt5250.XI5250CrtCtrl; +import net.infordata.em.crt5250.XI5250CrtFrame; +import net.infordata.em.util.XICommand; + + +/** + * Handles common commands shared by XI5250Frame and XI5250Applet. + */ +public class XI5250EmulatorCtrl extends XI5250CrtCtrl { + + // images + private static XIImagesBdl cvImagesBdl = + net.infordata.em.tn5250.XIImagesBdl.getImagesBdl(); + + private static ResourceBundle cvRes = + ResourceBundle.getBundle("net.infordata.em.tn5250.resources.Res"); + + public static final String CONNECT_CMD = "CONNECT_CMD"; + public static final String DISCONNECT_CMD = "DISCONNECT_CMD"; + + public static final String ABOUT_CMD = "ABOUT_CMD"; + + public static final String SNAPSHOT_CMD = "SNAPSHOT_CMD"; + + private int ivSnapShotCount = 0; + + + /** + */ + public XI5250EmulatorCtrl(XI5250Emulator aCrt) { + super(aCrt); + + getEmulator().addEmulatorListener(new EmulatorListener()); + + // Connect command + getCommandMgr().enableCommand( + CONNECT_CMD, !getEmulator().isActive()); + getCommandMgr().setCommand(CONNECT_CMD, new XICommand() { + public void execute() { + processConnectCmd(); + } + }); + + // Disconnect command + getCommandMgr().enableCommand( + DISCONNECT_CMD, getEmulator().isActive()); + getCommandMgr().setCommand(DISCONNECT_CMD, new XICommand() { + public void execute() { + processDisconnectCmd(); + } + }); + + // About command + getCommandMgr().setCommand(ABOUT_CMD, new XICommand() { + public void execute() { + processAboutCmd(); + } + }); + + // Snapshot command + getCommandMgr().setCommand(SNAPSHOT_CMD, new XICommand() { + public void execute() { + processSnapShotCmd(); + } + }); + } + + + /** + */ + public final XI5250Emulator getEmulator() { + return (XI5250Emulator)getCrt(); + } + + + /** + */ + protected void processConnectCmd() { + if (!getEmulator().isActive()) { + Object ret = JOptionPane.showInputDialog( + getEmulator(), + cvRes.getString("TXT_HostNameInput"), + "", JOptionPane.QUESTION_MESSAGE, null, + null, getEmulator().getHost()); + if (ret == null) + return; + getEmulator().setHost((String)ret); + } + getEmulator().setActive(true); + } + + + /** + */ + protected void processDisconnectCmd() { + if (getEmulator().isActive()) { + int ret = JOptionPane.showConfirmDialog( + getEmulator(), + cvRes.getString("TXT_ConfirmDisconnect"), + "", JOptionPane.YES_NO_OPTION); + if (ret == JOptionPane.NO_OPTION) + return; + } + getEmulator().setActive(false); + } + + + /** + */ + protected void processAboutCmd() { + String forkedFrom = cvRes.getString("TXT_Forked").replaceFirst("%1s", "xtn5250"); + forkedFrom = forkedFrom.replaceFirst("%2s", "Infordata S.p.A."); + JOptionPane.showMessageDialog(getEmulator(), + cvRes.getString("TXT_Version").replaceFirst("%1s", XI5250Emulator.VERSION) + "\n" + + "\n" + + "Mahefa Randimbisoa http://xtn5250mg.sf.net\n" + + "\n" + + forkedFrom + "\n" + + "http://xtn5250.sourceforge.net", + cvRes.getString("TXT_About"), + JOptionPane.INFORMATION_MESSAGE, + cvImagesBdl.getIcon("Logo")); + } + + + /** + */ + protected void processSnapShotCmd() { + XI5250Crt clone = getEmulator().getStaticClone(); + String title = cvRes.getString("TXT_SnapShot") + " " + getEmulator().getHost() + " #" + + (++ivSnapShotCount); + XI5250CrtFrame frm = new XI5250CrtFrame(title, clone); + frm.setBounds(0, 0, 728, 512); + frm.centerOnScreen(); + frm.setVisible(true); + } + + + ////////////////////////////////////////////////////////////////////////////// + + /** + * Usata per sincronizzare i comandi con lo stato dell' emulator. + */ + class EmulatorListener extends XI5250EmulatorAdapter { + + protected void enableCmd() { + getCommandMgr().enableCommand( + CONNECT_CMD, !getEmulator().isActive()); + getCommandMgr().enableCommand( + DISCONNECT_CMD, getEmulator().isActive()); + } + + @Override + public void connecting(XI5250EmulatorEvent e) { + enableCmd(); + } + + @Override + public void connected(XI5250EmulatorEvent e) { + enableCmd(); + } + + @Override + public void disconnected(XI5250EmulatorEvent e) { + enableCmd(); + } + + @Override + public void stateChanged(XI5250EmulatorEvent e) { + } + } +} + + diff --git a/net/infordata/em/tn5250/XI5250EmulatorEvent.java b/net/infordata/em/tn5250/XI5250EmulatorEvent.java new file mode 100644 index 0000000..b7e9e30 --- /dev/null +++ b/net/infordata/em/tn5250/XI5250EmulatorEvent.java @@ -0,0 +1,124 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.util.EventObject; + + +/** + * XI5250Emulator notification event. + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XI5250EmulatorEvent extends EventObject { + + private static final long serialVersionUID = 1L; + + /** + * Fired just before trying to connect. + */ + public static final int CONNECTING = 0; + /** + * Connection established. + */ + public static final int CONNECTED = 1; + /** + * Connection closed. + */ + public static final int DISCONNECTED = 2; + /** + * Internal state is changed. + */ + public static final int STATE_CHANGED = 3; + /** + * A new 5250 panel has been received and it is ready for the user. + */ + public static final int NEW_PANEL_RECEIVED = 4; + /** + * Fields removed. + */ + public static final int FIELDS_REMOVED = 5; + /** + * Data have been sended (ie. an aid-code was pressed) + */ + public static final int DATA_SENDED = 6; + + protected static final String[] cvIdDescr = {"CONNECTING", + "CONNECTED", + "DISCONNECTED", + "STATE_CHANGED", + "NEW_PANEL_RECEIVED", + "FIELDS_REMOVED", + "DATA_SENDED"}; + + protected int ivId; + protected byte ivAidCode; + + + /** + */ + public XI5250EmulatorEvent(int aId, XI5250Emulator aEm) { + super(aEm); + ivId = aId; + } + + + /** + */ + public XI5250EmulatorEvent(int aId, XI5250Emulator aEm, byte anAidCode) { + this(aId, aEm); + ivAidCode = anAidCode; + } + + + /** + */ + public int getID() { + return ivId; + } + + + /** + */ + public XI5250Emulator get5250Emulator() { + return (XI5250Emulator)getSource(); + } + + + /** + * The aid code (DATA_SENDED event) + */ + public byte getAidCode() { + return ivAidCode; + } + + + /** + */ + @Override + public String toString() { + return super.toString() + "[" + cvIdDescr[ivId] + "]"; + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XI5250EmulatorListener.java b/net/infordata/em/tn5250/XI5250EmulatorListener.java new file mode 100644 index 0000000..70420c1 --- /dev/null +++ b/net/infordata/em/tn5250/XI5250EmulatorListener.java @@ -0,0 +1,77 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.util.EventListener; + + +/** + * Listener for XI5250EmulatorEvent. + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public interface XI5250EmulatorListener extends EventListener { + + /** + * @see XI5250EmulatorEvent#CONNECTING + */ + public void connecting(XI5250EmulatorEvent e); + + + /** + * @see XI5250EmulatorEvent#CONNECTED + */ + public void connected(XI5250EmulatorEvent e); + + + /** + * @see XI5250EmulatorEvent#DISCONNECTED + */ + public void disconnected(XI5250EmulatorEvent e); + + + /** + * @see XI5250EmulatorEvent#STATE_CHANGED + */ + public void stateChanged(XI5250EmulatorEvent e); + + + /** + * @see XI5250EmulatorEvent#NEW_PANEL_RECEIVED + */ + public void newPanelReceived(XI5250EmulatorEvent e); + + + /** + * @see XI5250EmulatorEvent#FIELDS_REMOVED + */ + public void fieldsRemoved(XI5250EmulatorEvent e); + + + /** + * @see XI5250EmulatorEvent#DATA_SENDED + */ + public void dataSended(XI5250EmulatorEvent e); +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XI5250EmulatorMemento.java b/net/infordata/em/tn5250/XI5250EmulatorMemento.java new file mode 100644 index 0000000..20d7ac1 --- /dev/null +++ b/net/infordata/em/tn5250/XI5250EmulatorMemento.java @@ -0,0 +1,83 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import net.infordata.em.crt5250.XI5250CrtBuffer; +import net.infordata.em.crt5250.XI5250FieldsList; + + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Used to store, without exposing it, the internal state of XI5250Emulator. + * + * @see XI5250Emulator#createMemento + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XI5250EmulatorMemento { + + protected XI5250FieldsList ivFields; + + protected int ivFunctionKeysMask; + + protected XI5250Cmd ivPendingCmd; + + protected int ivState; + protected int ivPrevState; + + protected int ivCol; + protected int ivRow; + + protected int ivErrorRow; + + // from super classes + protected XI5250CrtBuffer ivCrtBuffer; + + + public XI5250EmulatorMemento(XI5250FieldsList aFieldList, + int aFunctionKeysMask, XI5250Cmd aPendingCmd, + int aState, int aPrevState, + int aCol, int aRow, + int aErrorRow, + XI5250CrtBuffer aCrtBuffer) { + ivFields = aFieldList; + + ivFunctionKeysMask = aFunctionKeysMask; + + ivPendingCmd = aPendingCmd; + + ivState = aState; + ivPrevState = aPrevState; + + ivCol = aCol; + ivRow = aRow; + + ivErrorRow = aErrorRow; + + ivCrtBuffer = aCrtBuffer; + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XI5250Exception.java b/net/infordata/em/tn5250/XI5250Exception.java new file mode 100644 index 0000000..e260ed6 --- /dev/null +++ b/net/infordata/em/tn5250/XI5250Exception.java @@ -0,0 +1,47 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +/** + * Used internally.
+ * It is raised if an error is detected while reading and parsing the 5250 stream. + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XI5250Exception extends Exception { + + private static final long serialVersionUID = 1L; + + private final int ivErrorCode; + + public XI5250Exception(String s, int errorCode) { + super(s); + ivErrorCode = errorCode; + } + + public final int getErrorCode() { + return ivErrorCode; + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XI5250Frame.java b/net/infordata/em/tn5250/XI5250Frame.java new file mode 100644 index 0000000..0cd2bdc --- /dev/null +++ b/net/infordata/em/tn5250/XI5250Frame.java @@ -0,0 +1,331 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** +!!V 07/07/98 rel. 1.07 - creation. + 04/02/99 rel. 1.11 - Swing 1.1 + ivSizeControlledFrame. + */ + + +package net.infordata.em.tn5250; + + +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.awt.event.WindowEvent; +import java.util.ResourceBundle; + +import javax.swing.AbstractButton; +import javax.swing.JButton; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JToggleButton; +import javax.swing.JToolBar; +import javax.swing.KeyStroke; +import javax.swing.SwingUtilities; + +import net.infordata.em.crt5250.XI5250Crt; +import net.infordata.em.crt5250.XI5250CrtCtrl; +import net.infordata.em.crt5250.XI5250CrtFrame; +import net.infordata.em.util.XIUtil; + + + +/** + */ +public class XI5250Frame extends XI5250CrtFrame { + + private static final long serialVersionUID = 1L; + + // images + private static XIImagesBdl cvImagesBdl = + net.infordata.em.tn5250.XIImagesBdl.getImagesBdl(); + + private static ResourceBundle cvRes = + ResourceBundle.getBundle("net.infordata.em.tn5250.resources.Res"); + + private final String ivTitle; + + /** + */ + public XI5250Frame(String aTitle, XI5250Emulator aCrt) { + super(aTitle, aCrt); + ivTitle = aTitle; + init(aCrt); + } + + + /** + */ + public XI5250Frame(String aTitle, XI5250Emulator aCrt, + boolean sizeControlledFrame) { + super(aTitle, aCrt, sizeControlledFrame); + ivTitle = aTitle; + init(aCrt); + } + + + private void init(XI5250Emulator aCrt) { + if (aCrt.isActive()) + setTitle("*" + aCrt.getHost() + " - " + ivTitle); + aCrt.addEmulatorListener(new XI5250EmulatorAdapter() { + @Override + public void connected(XI5250EmulatorEvent e) { + setTitle("~" + e.get5250Emulator().getHost() + " - " + ivTitle); + } + + @Override + public void disconnected(XI5250EmulatorEvent e) { + setTitle("! " + ivTitle); + } + }); + } + + + /** + */ + @Override + protected XI5250CrtCtrl createController(XI5250Crt crt) { + return new XI5250EmulatorCtrl((XI5250Emulator)crt); + } + + + /** + */ + protected final XI5250EmulatorCtrl getEmulatorCtrl() { + return (XI5250EmulatorCtrl)getCrtCtrl(); + } + + + /** + */ + public final XI5250Emulator getEmulator() { + return getEmulatorCtrl().getEmulator(); + } + + + /** + */ + @Override + protected void processExitCmd() { + if (getEmulator().isActive()) { + //!!1.13a otherwise a dead-lock may occur !! + SwingUtilities.invokeLater(new Runnable() { + public void run() { + int ret = JOptionPane.showConfirmDialog( + XI5250Frame.this, + cvRes.getString("TXT_ConfirmExit"), + "", JOptionPane.YES_NO_OPTION); + if (ret != JOptionPane.NO_OPTION) { + setVisible(false); + dispose(); + } + } + }); + } + else { + setVisible(false); + dispose(); + } + } + + + /** + */ + @Override + protected void processWindowEvent(WindowEvent e) { + super.processWindowEvent(e); + switch(e.getID()) { + case WindowEvent.WINDOW_OPENED: + if (getEmulator().getHost() == null) + getCommandMgr().dispatchCommand(XI5250EmulatorCtrl.CONNECT_CMD); + break; + } + } + + + /** + */ + @Override + protected JMenuBar createMenuBar() { + String str; + + str = cvRes.getString("TXT_Communications"); + JMenu commMenu = new JMenu(XIUtil.removeMnemonics(str)); + commMenu.setMnemonic(XIUtil.getMnemonic(str)); + { + JMenuItem connItem = + new JMenuItem(cvRes.getString("TXT_Connect")); + JMenuItem disconnItem = + new JMenuItem(cvRes.getString("TXT_Disconnect")); + JMenuItem aboutItem = + new JMenuItem(cvRes.getString("TXT_About")); + JMenuItem exitItem = + new JMenuItem(cvRes.getString("TXT_Exit")); + exitItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F4, + ActionEvent.ALT_MASK)); + + commMenu.add(connItem); + commMenu.add(disconnItem); + commMenu.addSeparator(); + commMenu.add(aboutItem); + commMenu.addSeparator(); + commMenu.add(exitItem); + + getCommandMgr().handleCommand(connItem, + XI5250EmulatorCtrl.CONNECT_CMD); + getCommandMgr().handleCommand(disconnItem, + XI5250EmulatorCtrl.DISCONNECT_CMD); + getCommandMgr().handleCommand(aboutItem, + XI5250EmulatorCtrl.ABOUT_CMD); + getCommandMgr().handleCommand(exitItem, + EXIT_CMD); + } + + str = cvRes.getString("TXT_Edit"); + JMenu editMenu = new JMenu(XIUtil.removeMnemonics(str)); + editMenu.setMnemonic(XIUtil.getMnemonic(str)); + { + JMenuItem copyItem = + new JMenuItem(cvRes.getString("TXT_Copy")); + JMenuItem pasteItem = + new JMenuItem(cvRes.getString("TXT_Paste")); + JMenuItem snapShotItem = + new JMenuItem(cvRes.getString("TXT_SnapShot")); + JMenuItem printItem = + new JMenuItem(cvRes.getString("TXT_Print")); + + editMenu.add(copyItem); + editMenu.add(pasteItem); + editMenu.addSeparator(); + editMenu.add(snapShotItem); + editMenu.addSeparator(); + editMenu.add(printItem); + + getCommandMgr().handleCommand(copyItem, + XI5250EmulatorCtrl.COPY_CMD); + getCommandMgr().handleCommand(pasteItem, + XI5250EmulatorCtrl.PASTE_CMD); + getCommandMgr().handleCommand(snapShotItem, + XI5250EmulatorCtrl.SNAPSHOT_CMD); + getCommandMgr().handleCommand(printItem, + XI5250EmulatorCtrl.PRINT_CMD); + } + + str = cvRes.getString("TXT_Options"); + JMenu optionsMenu = new JMenu(XIUtil.removeMnemonics(str)); + optionsMenu.setMnemonic(XIUtil.getMnemonic(str)); + { + JCheckBoxMenuItem switch3DfxItem = + new JCheckBoxMenuItem(cvRes.getString("TXT_3dFx")); + JCheckBoxMenuItem referenceCursorItem = + new JCheckBoxMenuItem(cvRes.getString("TXT_RefCursor")); + + optionsMenu.add(switch3DfxItem); + optionsMenu.add(referenceCursorItem); + + getCommandMgr().handleCommand(switch3DfxItem, + XI5250EmulatorCtrl.SWITCH_3DFX_CMD); + getCommandMgr().handleCommand(referenceCursorItem, + XI5250EmulatorCtrl.REFERENCE_CURSOR_CMD); + } + + JMenuBar menuBar = new JMenuBar(); + menuBar.add(commMenu); + menuBar.add(editMenu); + menuBar.add(optionsMenu); + return menuBar; + } + + + /** + * Inserisce nella tool-bar i bottoni di default. + */ + @Override + protected JToolBar createToolBar() { + // bottoni della tool-bar + AbstractButton[] buttons = new AbstractButton[] { + new JButton(cvImagesBdl.getIcon("Connect")), + new JButton(cvImagesBdl.getIcon("Disconnect")), + null, + new JButton(cvImagesBdl.getIcon("Copy")), + new JButton(cvImagesBdl.getIcon("Paste")), + null, + new JButton(cvImagesBdl.getIcon("SnapShot")), + new JButton(cvImagesBdl.getIcon("Print")), + null, + new JToggleButton(cvImagesBdl.getIcon("3dFx")), + new JToggleButton(cvImagesBdl.getIcon("RefCursor")), + }; + // action commands associati con i bottoni della tool-bar. + String[] buttonsActCmd = new String[] { + XI5250EmulatorCtrl.CONNECT_CMD, + XI5250EmulatorCtrl.DISCONNECT_CMD, + null, + XI5250EmulatorCtrl.COPY_CMD, + XI5250EmulatorCtrl.PASTE_CMD, + null, + XI5250EmulatorCtrl.SNAPSHOT_CMD, + XI5250EmulatorCtrl.PRINT_CMD, + null, + XI5250EmulatorCtrl.SWITCH_3DFX_CMD, + XI5250EmulatorCtrl.REFERENCE_CURSOR_CMD, + }; + // Hint associati ad i vari bottoni. + String[] buttonHints = new String[] { + cvRes.getString("TXT_Connect"), + cvRes.getString("TXT_Disconnect"), + null, + cvRes.getString("TXT_Copy"), + cvRes.getString("TXT_Paste"), + null, + cvRes.getString("TXT_SnapShot"), + cvRes.getString("TXT_Print"), + null, + cvRes.getString("TXT_3dFx"), + cvRes.getString("TXT_RefCursor"), + }; + + JToolBar toolBar = new JToolBar(); + toolBar.setFloatable(false); + + Dimension size = new Dimension(26, 26); + + for (int i = 0; i < buttons.length; i++) { + if (buttons[i] != null) { + AbstractButton button = (AbstractButton)buttons[i]; + toolBar.add(button); + button.setToolTipText(buttonHints[i]); + button.setMinimumSize(size); + button.setPreferredSize(size); + button.setMaximumSize(size); + button.setRequestFocusEnabled(false); + getCommandMgr().handleCommand(button, buttonsActCmd[i]); + } + else + toolBar.addSeparator(); + } + + return toolBar; + } +} + + diff --git a/net/infordata/em/tn5250/XI5250Ord.java b/net/infordata/em/tn5250/XI5250Ord.java new file mode 100644 index 0000000..ff596a4 --- /dev/null +++ b/net/infordata/em/tn5250/XI5250Ord.java @@ -0,0 +1,55 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.InputStream; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Abstract base class for all 5250 Orders + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public abstract class XI5250Ord { + protected XI5250Emulator ivEmulator; + + + protected void init(XI5250Emulator aEmulator) { + ivEmulator = aEmulator; + } + + + /** + * @exception XI5250Exception raised if order parameters are wrong. + */ + protected abstract void readFrom5250Stream(InputStream inStream) + throws IOException, XI5250Exception; + + + protected abstract void execute(); +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XI5250OrdList.java b/net/infordata/em/tn5250/XI5250OrdList.java new file mode 100644 index 0000000..7cff551 --- /dev/null +++ b/net/infordata/em/tn5250/XI5250OrdList.java @@ -0,0 +1,206 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 15/07/97 rel. 1.02c- XIDataOrd includes 0x1F char. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.infordata.em.tnprot.XITelnet; + + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * 5250 Orders list. + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XI5250OrdList extends XI5250Ord { + + private static final Logger LOGGER = Logger.getLogger(XI5250OrdList.class.getName()); + + private static Class[] cv5250OrdClasses = new Class[256]; + + protected List ivOrdVect; + + protected boolean[] ivOrdPresent = new boolean[256]; + + + static { + cv5250OrdClasses[XI5250Emulator.ORD_IC] = XIICOrd.class; + cv5250OrdClasses[XI5250Emulator.ORD_RA] = XIRAOrd.class; + cv5250OrdClasses[XI5250Emulator.ORD_SBA] = XISBAOrd.class; + cv5250OrdClasses[XI5250Emulator.ORD_SF] = XISFOrd.class; + cv5250OrdClasses[XI5250Emulator.ORD_SOH] = XISOHOrd.class; + cv5250OrdClasses[XI5250Emulator.ORD_MC] = XIMCOrd.class; + cv5250OrdClasses[XI5250Emulator.ORD_EA] = XIEAOrd.class; + cv5250OrdClasses[XI5250Emulator.ORD_TD] = XITDOrd.class; + cv5250OrdClasses[XI5250Emulator.ORD_WEA] = XIWEAOrd.class; + cv5250OrdClasses[XI5250Emulator.ORD_WDSF] = XIWdsfOrd.class; + } + + + /** + */ + protected XI5250OrdList(XI5250Emulator aEmulator) { + init(aEmulator); + } + + + /** + */ + public boolean isOrderPresent(byte aOrder) { + return ivOrdPresent[aOrder]; + } + + + /** + * @exception XI5250Exception raised if order parameters are wrong. + */ + @Override + protected void readFrom5250Stream(InputStream inStream) + throws IOException, XI5250Exception { + + int bb; + XI5250Ord ord; + ivOrdVect = new ArrayList(100); + + if (LOGGER.isLoggable(Level.FINER)) + LOGGER.finer(" START OF ORDERS LIST"); + + for (int i = 0; ; i++) { + inStream.mark(1); + if ((bb = inStream.read()) == -1) + break; + + if ((byte)bb == XI5250Emulator.ESC) { + inStream.reset(); + break; + } + + if (XIDataOrd.isDataCharacter(bb)) { + inStream.reset(); // need it (it is also the color attribute) + if (ivEmulator.isStrPcCmdEnabled()) { + inStream.mark(XI5250Emulator.STRPCCMD.length); + byte[] lhbb = new byte[XI5250Emulator.STRPCCMD.length]; + int sz = inStream.read(lhbb); + if (sz == XI5250Emulator.STRPCCMD.length) { + if (Arrays.equals(lhbb, XI5250Emulator.STRPCCMD)) { + ivEmulator.receivedStrPcCmd(); + } + else if (Arrays.equals(lhbb, XI5250Emulator.ENDSTRPCCMD)) { + ivEmulator.receivedEndStrPcCmd(); + } + else { + inStream.reset(); + } + } + else { + inStream.reset(); + } + } + } + else + ivOrdPresent[bb] = true; // remember orders present + + try { + ord = createOrdInstance(bb); + } + catch (Exception ex) { + throw new RuntimeException(ex); + } + + if (ord != null) { + ord.init(ivEmulator); + ord.readFrom5250Stream(inStream); + + if (LOGGER.isLoggable(Level.FINER)) + LOGGER.finer(" " + ord); + + ivOrdVect.add(ord); + } + else { + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.fine("Order not supported : 0x" + XITelnet.toHex((byte)bb)); + for (int ii = 0; ii < ivOrdVect.size(); ii++) { + LOGGER.fine("Prev. order[" + ii + "]: " + ivOrdVect.get(ii)); + } + byte[] buf = new byte[10]; + int count = inStream.read(buf); + LOGGER.fine("Next " + count + " bytes: " + XITelnet.toHex(buf, count)); + } + throw new XI5250Exception("Order not supported : 0x" + XITelnet.toHex((byte)bb), + XI5250Emulator.ERR_INVALID_COMMAND); + } + } + } + + + /** + */ + @Override + protected void execute() { + for (int i = 0; i < ivOrdVect.size(); i++) + ivOrdVect.get(i).execute(); + } + + + /** + * Creates the 5250 order instance related to the given 5250 order id. + * @exception IllegalAccessException . + * @exception InstantiationException . + */ + public XI5250Ord createOrdInstance(int aOrd) + throws IllegalAccessException, InstantiationException { + + Class cls; + + if (XIDataOrd.isDataCharacter(aOrd)) + cls = XIDataOrd.class; + else + cls = cv5250OrdClasses[aOrd]; + + if (cls != null) + return (XI5250Ord)cls.newInstance(); + else + return null; + } + + + /** + */ + @Override + public String toString() { + String ss = super.toString() + ivOrdVect.toString(); + return ss; + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XI5250StatusBar.java b/net/infordata/em/tn5250/XI5250StatusBar.java new file mode 100644 index 0000000..f1a871e --- /dev/null +++ b/net/infordata/em/tn5250/XI5250StatusBar.java @@ -0,0 +1,358 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + 30/07/99 rel. 1.14b- removed statusbar.* sub package. + */ + +package net.infordata.em.tn5250; + +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Insets; + +import javax.swing.BorderFactory; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.border.Border; + +import net.infordata.em.util.XIRatioLayout; + + + +/** + * The 5250 status bar. + */ +public class XI5250StatusBar extends JPanel { + + private static final long serialVersionUID = 1L; + + // + public final static int SHIFT_UP = 0; + public final static int SHIFT_DOWN = 1; + + // + public final static int CAPS_LOCK_UP = 0; + public final static int CAPS_LOCK_DOWN = 1; + + // + public final static int MESSAGE_OFF = 0; + public final static int MESSAGE_ON = 1; + + // images + static XIImagesBdl cvImagesBdl = XIImagesBdl.getImagesBdl(); + + private static Image + cvTemporaryLockImage = cvImagesBdl.getImage("TemporaryLock"); + private static Image + cvNormalLockImage = cvImagesBdl.getImage("NormalLock"); + private static Image + cvHelpImage = cvImagesBdl.getImage("Help"); + private static Image + cvShiftDownImage = cvImagesBdl.getImage("ShiftDown"); + private static Image + cvCapsLockImage = cvImagesBdl.getImage("CapsLock"); + private static Image + cvMessageImage = cvImagesBdl.getImage("Message"); + private static Image + cvFlashImage = cvImagesBdl.getImage("Flash"); + + // status bar components + private TextAndImage ivFlashArea; + private TextAndImage ivStateArea; + private TextAndImage ivMessageArea; + private TextAndImage ivShiftArea; + private TextAndImage ivCapsLockArea; + private JLabel ivCoordArea; + + private boolean ivFlashOn; + private int ivShiftAreaState = -1; + private int ivState = XI5250Emulator.ST_NULL; + + + /** + */ + public XI5250StatusBar() { + super(new XIRatioLayout(4)); + setBorder(BorderFactory.createRaisedBevelBorder()); + + // add components + addComponents(); + } + + + /** + */ + @Override + public boolean isValidateRoot() { + return true; + } + + + /** + */ + public void addComponents() { + Border border = BorderFactory.createEtchedBorder(); + + ivFlashArea = new TextAndImage(TextAndImage.CENTER); + ivFlashArea.setBorder(border); + add(ivFlashArea, new XIRatioLayout.Constraints(0.03f)); + + JComponent dummyArea = new TextAndImage(TextAndImage.CENTER); + dummyArea.setBorder(border); + add(dummyArea, new XIRatioLayout.Constraints(0.03f)); + + // STATE AREA + ivStateArea = new TextAndImage(); + ivStateArea.setBorder(border); + add(ivStateArea, new XIRatioLayout.Constraints(0.3f)); + + // MESSAGE AREA + ivMessageArea = new TextAndImage(TextAndImage.CENTER); + ivMessageArea.setBorder(border); + add(ivMessageArea, new XIRatioLayout.Constraints(0.03f)); + + // SHIFT AREA + ivShiftArea = new TextAndImage(TextAndImage.CENTER); + ivShiftArea.setBorder(border); + add(ivShiftArea, new XIRatioLayout.Constraints(0.03f)); + + // CAPS LOCK AREA + ivCapsLockArea = new TextAndImage(TextAndImage.CENTER); + ivCapsLockArea.setBorder(border); + add(ivCapsLockArea, new XIRatioLayout.Constraints(0.03f)); + + // COORD AREA + ivCoordArea = new JLabel(null, null, JLabel.RIGHT); + ivCoordArea.setFont(null); + ivCoordArea.setBorder(border); + add(ivCoordArea, new XIRatioLayout.Constraints(0.15f, XIRatioLayout.RIGHT)); + } + + + /** + */ + public void setCoordArea(int aCol, int aRow) { + ivCoordArea.setText(aRow + " / " + aCol + " "); + } + + + /** + */ + public void setFlashArea(boolean flag) { + if (flag == ivFlashOn) + return; + + ivFlashOn = flag; + + if (flag) + ivFlashArea.setImage(cvFlashImage); + else + ivFlashArea.setImage(null); + } + + + /** + */ + public void setShiftArea(int aState) { + if (aState == ivShiftAreaState) + return; + + ivShiftAreaState = aState; + + if (aState == SHIFT_DOWN) + ivShiftArea.setImage(cvShiftDownImage); + else + ivShiftArea.setImage(null); + } + + + /** + */ + public void setCapsLockArea(int aState) { + if (aState == CAPS_LOCK_DOWN) { + ivCapsLockArea.setImage(cvCapsLockImage); + } + else { + ivCapsLockArea.setImage(null); + } + } + + + /** + */ + public void setMessageArea(int aState) { + if (aState == MESSAGE_ON) { + ivMessageArea.setImage(cvMessageImage); + } + else { + ivMessageArea.setImage(null); + } + } + + + /** + */ + public void setStateArea(int aState) { + if (aState == ivState) + return; + + switch (aState) { + + case XI5250Emulator.ST_HARDWARE_ERROR: + ivStateArea.setImage(null); + ivStateArea.setText("HARDWARE_ERROR"); + break; + + case XI5250Emulator.ST_NORMAL_LOCKED: + ivStateArea.setImage(cvNormalLockImage); + ivStateArea.setText("SYSTEM"); + break; + + case XI5250Emulator.ST_NORMAL_UNLOCKED: + ivStateArea.setImage(null); + ivStateArea.setText(""); + break; + + case XI5250Emulator.ST_POST_HELP: + ivStateArea.setImage(null); + ivStateArea.setText("POST_HELP"); + break; + + case XI5250Emulator.ST_POWER_ON: + ivStateArea.setImage(null); + ivStateArea.setText(""); + break; + + case XI5250Emulator.ST_PRE_HELP: + ivStateArea.setImage(cvHelpImage); + ivStateArea.setText(""); + break; + + case XI5250Emulator.ST_SS_MESSAGE: + ivStateArea.setImage(null); + ivStateArea.setText("SS_MESSAGE"); + break; + + case XI5250Emulator.ST_SYSTEM_REQUEST: + ivStateArea.setImage(null); + ivStateArea.setText("SYSTEM_REQUEST"); + break; + + case XI5250Emulator.ST_TEMPORARY_LOCK: + ivStateArea.setImage(cvTemporaryLockImage); + ivStateArea.setText(""); + break; + } + } + + + /** + public void revalidate() { + // otherwise causes interferences with the emulator when it tries to + // force the position and the size of the status bar + } + */ + + + ////////////////////////////////////////////////////////////////////////////// + + /** + */ + protected static class TextAndImage extends JComponent { + + private static final long serialVersionUID = 1L; + + public static final int LEFT = 0; + public static final int CENTER = 1; + + private Image ivImage = null; + private String ivText = null; + + private int ivAlignment; + + private final int ivHGap = 2; + + + public TextAndImage(int alignment) { + ivAlignment = alignment; + } + + + public TextAndImage() { + this(LEFT); + } + + + public void setText(String aText) { + ivText = aText; + repaint(); + } + + + public void setImage(Image aImage) { + ivImage = aImage; + repaint(); + } + + + @Override + public void paintComponent(Graphics gr) { + + Insets insets = getInsets(); + int imageWidth = 0; + int imageHeight = 0; + int textWidth = 0; + Dimension dim = getSize(); + FontMetrics fm = null; + + if ((ivImage != null)) { + int w = ivImage.getWidth(this); + int h = ivImage.getHeight(this); + imageHeight = dim.height - insets.top - insets.bottom; + imageWidth = w * imageHeight / h; + } + + if (ivText != null && ivText.length() != 0) { + fm = gr.getFontMetrics(); + textWidth = fm.stringWidth(ivText); + } + + int width = imageWidth + textWidth + + ((ivImage != null && fm != null) ? ivHGap : 0); + int x = insets.left; + if (ivAlignment == CENTER) + x = (dim.width - width) / 2; + + if ((ivImage != null)) { + gr.drawImage(ivImage, x, insets.top, + imageWidth, imageHeight, this); + x += imageWidth + ivHGap; + } + + if (fm != null) { + gr.setColor(getForeground()); + int y = (dim.height + fm.getHeight()) / 2; + gr.drawString(ivText, x, y - fm.getDescent()); + } + } + } +} diff --git a/net/infordata/em/tn5250/XICCCmd.java b/net/infordata/em/tn5250/XICCCmd.java new file mode 100644 index 0000000..13b2f48 --- /dev/null +++ b/net/infordata/em/tn5250/XICCCmd.java @@ -0,0 +1,152 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + 01/09/97 rel. 1.04a- executeCC1() implemented. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.awt.Toolkit; +import java.io.IOException; +import java.io.InputStream; +import java.util.Iterator; + +import net.infordata.em.crt5250.XI5250Field; +import net.infordata.em.tnprot.XITelnet; + + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Abstract base class for all 5250 commands with CC parameter. + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public abstract class XICCCmd extends XI5250Cmd { + + protected byte[] ivCC; + + + /** + * @exception XI5250Exception raised if command parameters are wrong. + */ + @Override + protected abstract void readFrom5250Stream(InputStream inStream) + throws IOException, XI5250Exception; + + + @Override + protected abstract void execute(); + + + /** + * @exception XI5250Exception raised if command parameters are wrong. + */ + protected void readCC(InputStream inStream) + throws IOException, XI5250Exception { + + int bb; + int i; + ivCC = new byte[2]; + + for (i = 0; (i < 2) && ((bb = inStream.read()) != -1); i++) + ivCC[i] = (byte)bb; + + if (i < 2) + throw new XI5250Exception("CC required", XI5250Emulator.ERR_INVALID_COMMAND); + } + + + protected void executeCC1() { + //!!1.04a + int cc1 = ivCC[0] & 0xE0; + + // reset pending aid; lock keyboard + if (cc1 != 0) { + ivEmulator.ivPendingCmd = null; + ivEmulator.setState(XI5250Emulator.ST_NORMAL_LOCKED); + } + + // clear master mdt; reset mdt in nonbypass-fields + if (cc1 == 0x40 || cc1 == 0xA0 || cc1 == 0xC0) { + //!!V gestire master mdt + XI5250Field field; + for (Iterator e = ivEmulator.getFields().iterator(); e.hasNext(); ) { + field = e.next(); + if (!field.isOrgBypassField()) + field.resetMDT(); + } + } + + // clear master mdt; reset mdt in all fields + if (cc1 == 0x60 || cc1 == 0xE0) { + //!!V gestire master mdt + XI5250Field field; + for (Iterator e = ivEmulator.getFields().iterator(); e.hasNext(); ) { + field = e.next(); + field.resetMDT(); + } + } + + // null nonbypass-fields with mdt on + if (cc1 == 0x80 || cc1 == 0xC0) { + XI5250Field field; + for (Iterator e = ivEmulator.getFields().iterator(); e.hasNext(); ) { + field = e.next(); + if (!field.isOrgBypassField() && field.isMDTOn()) + field.clear(); + } + } + + // null all nonbypass-fields + if (cc1 == 0xA0 || cc1 == 0xE0) { + XI5250Field field; + for (Iterator e = ivEmulator.getFields().iterator(); e.hasNext(); ) { + field = e.next(); + if (!field.isBypassField()) + field.clear(); + } + } + } + + + protected void executeCC2() { + if ((ivCC[1] & 0x10) != 0) + ivEmulator.setBlinkingCursor(true); + else if ((ivCC[1] & 0x20) != 0) + ivEmulator.setBlinkingCursor(false); + + // unlock the keyboard + if ((ivCC[1] & 0x08) != 0) + ivEmulator.setState(XI5250Emulator.ST_NORMAL_UNLOCKED); + + if ((ivCC[1] & 0x04) != 0) + Toolkit.getDefaultToolkit().beep(); + } + + + @Override + public String toString() { + return super.toString() + " [CC=[" + XITelnet.toHex(ivCC[0]) + "," + XITelnet.toHex(ivCC[1]) + "]]"; + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XIClearFmtTableCmd.java b/net/infordata/em/tn5250/XIClearFmtTableCmd.java new file mode 100644 index 0000000..140e4cf --- /dev/null +++ b/net/infordata/em/tn5250/XIClearFmtTableCmd.java @@ -0,0 +1,53 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.InputStream; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Clear Format Table + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XIClearFmtTableCmd extends XI5250Cmd { + + @Override + protected void readFrom5250Stream(InputStream inStream) { + } + + + @Override + protected void execute() { + ivEmulator.setState(XI5250Emulator.ST_NORMAL_LOCKED); + ivEmulator.ivPendingCmd = null; + + ivEmulator.setDefAttr(0x20); + ivEmulator.removeFields(); + ivEmulator.setErrorRow(ivEmulator.getCrtSize().height - 1); + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XIClearUnitAltCmd.java b/net/infordata/em/tn5250/XIClearUnitAltCmd.java new file mode 100644 index 0000000..93d3f97 --- /dev/null +++ b/net/infordata/em/tn5250/XIClearUnitAltCmd.java @@ -0,0 +1,70 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 14/07/97 rel. 1.02 - added support for 27x132 terminal type (IBM-3477-FC). + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.awt.Font; +import java.io.IOException; +import java.io.InputStream; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Clear Unit Alternative + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XIClearUnitAltCmd extends XI5250Cmd { + + protected int ivPar; + + @Override + protected void readFrom5250Stream(InputStream inStream) throws IOException, XI5250Exception { + ivPar = Math.max(0, inStream.read()); //!!1.02 + if (ivPar != 0x00 && ivPar != 0x80) + throw new XI5250Exception("Invalid clear unit param: " + ivPar, + XI5250Emulator.ERR_INVALID_CLEAR_UNIT_ALT); + } + + + @Override + protected void execute() { + ivEmulator.setState(XI5250Emulator.ST_NORMAL_LOCKED); + ivEmulator.ivPendingCmd = null; + + if (ivEmulator.ivPrevFont == null) { //!!1.04a + Font ft = ivEmulator.getFont(); + ivEmulator.ivPrevFont = new Font(ft.getName(), ft.getStyle(), ft.getSize()); //!!1.03a + } + + ivEmulator.setCrtSize(132, 27); //!!1.02 + + ivEmulator.setDefAttr(0x20); + ivEmulator.clear(); + ivEmulator.removeFields(); + ivEmulator.setErrorRow(ivEmulator.getCrtSize().height - 1); + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XIClearUnitCmd.java b/net/infordata/em/tn5250/XIClearUnitCmd.java new file mode 100644 index 0000000..47e0ca1 --- /dev/null +++ b/net/infordata/em/tn5250/XIClearUnitCmd.java @@ -0,0 +1,63 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 14/07/97 rel. 1.02 - added support for 27x132 terminal type (IBM-3477-FC). + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.InputStream; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * 5250 Clear unit command + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XIClearUnitCmd extends XI5250Cmd { + + @Override + protected void readFrom5250Stream(InputStream inStream) { + } + + + @Override + protected void execute() { + ivEmulator.setState(XI5250Emulator.ST_NORMAL_LOCKED); + ivEmulator.ivPendingCmd = null; + + ivEmulator.setCrtSize(80, 24); //!!1.02 + + ivEmulator.setDefAttr(0x20); + ivEmulator.clear(); + ivEmulator.removeFields(); + ivEmulator.setErrorRow(ivEmulator.getCrtSize().height - 1); + + // switch back to the previous used font + if (ivEmulator.ivPrevFont != null) { //!!1.03a + ivEmulator.setFont(ivEmulator.ivPrevFont); + ivEmulator.ivPrevFont = null; + } + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XIDataOrd.java b/net/infordata/em/tn5250/XIDataOrd.java new file mode 100644 index 0000000..f910c8f --- /dev/null +++ b/net/infordata/em/tn5250/XIDataOrd.java @@ -0,0 +1,130 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 15/07/97 rel. 1.02c- XIDataOrd includes 0x1F char. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.InputStream; + +import net.infordata.em.crt5250.XIEbcdicTranslator; +import net.infordata.em.tnprot.XITelnet; + + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * 5250 Data Order + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XIDataOrd extends XI5250Ord { + + protected String ivData; + protected byte ivColor; + + /** + * see http://publibfp.boulder.ibm.com/cgi-bin/bookmgr/BOOKS/co2e2001/15.6.2?SHELF=&DT=19950629163252&CASE= + * and IBM SA21-9247-6 pg. 2.13 + */ + public static final boolean isDataCharacter(int bb) { + // 0x1F instead of 0x20 and keep 0xFF chars +// return (bb == 0x00 || bb == 0x1C || bb == 0x1E || bb == 0x0E || bb == 0x0F || +// (bb >= 0x1F && bb <= 0xFF)); + switch (bb) { + case XI5250Emulator.ORD_IC: + case XI5250Emulator.ORD_RA: + case XI5250Emulator.ORD_SBA: + case XI5250Emulator.ORD_SF: + case XI5250Emulator.ORD_SOH: + case XI5250Emulator.ORD_MC: + case XI5250Emulator.ORD_EA: + case XI5250Emulator.ORD_TD: + case XI5250Emulator.ORD_WEA: + case XI5250Emulator.ORD_WDSF: + case XI5250Emulator.ESC: + return false; + default: + return true; + } + } + + @Override + protected void readFrom5250Stream(InputStream inStream) throws IOException { + XIEbcdicTranslator translator = ivEmulator.getTranslator(); + int bb; + + ivColor = 0; + StringBuilder sb = new StringBuilder(128); + + for (int i = 0; ; i++) { + inStream.mark(1); + bb = inStream.read(); + + if (bb == -1) + break; + + // see IBM SA21-9247-6 pg. 2.13 + if (isDataCharacter(bb)) { + // is it a color ? + if (bb > 0x1F && bb <= 0x3F) { + if (i == 0) + ivColor = (byte)bb; + else { + // cut string if different color + inStream.reset(); + break; + } + } + else + sb.append(translator.toChar((byte)bb)); + } + else { + inStream.reset(); + break; + } + } + ivData = sb.toString(); + } + + + @Override + protected void execute() { + if (ivColor != 0) { + ivEmulator.setDefAttr(XITelnet.toInt(ivColor)); + ivEmulator.drawString(String.valueOf(XI5250Emulator.ATTRIBUTE_PLACE_HOLDER), + ivEmulator.getSBACol(), ivEmulator.getSBARow()); + ivEmulator.setSBA(ivEmulator.getSBA() + 1); + } + ivEmulator.drawString(ivData, ivEmulator.getSBACol(), ivEmulator.getSBARow()); + ivEmulator.setSBA(ivEmulator.getSBA() + ivData.length()); + } + + + @Override + public String toString() { + return super.toString() + " [" + XITelnet.toHex(ivColor) + "," + ",\"" + ivData + "\"" + "]"; + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XIEAOrd.java b/net/infordata/em/tn5250/XIEAOrd.java new file mode 100644 index 0000000..ece0791 --- /dev/null +++ b/net/infordata/em/tn5250/XIEAOrd.java @@ -0,0 +1,87 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.InputStream; + +import net.infordata.em.tnprot.XITelnet; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * EA - Erase to address + * TODO + * + * see: http://publibfp.boulder.ibm.com/cgi-bin/bookmgr/BOOKS/co2e2001/15.6.8?DT=19950629163252 + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XIEAOrd extends XI5250Ord { + + protected int ivRow; + protected int ivCol; + protected int ivLen; + + protected byte[] ivAttributeTypes; + + + /** + * @exception XI5250Exception raised if order parameters are wrong. + */ + @Override + protected void readFrom5250Stream(InputStream inStream) + throws IOException, XI5250Exception { + { + byte[] buf = new byte[3]; + if (inStream.read(buf) < buf.length) + throw new XI5250Exception("EOF reached", XI5250Emulator.ERR_INVALID_ROW_COL_ADDR); + ivRow = XITelnet.toInt(buf[0]); + ivCol = XITelnet.toInt(buf[1]); + ivLen = XITelnet.toInt(buf[2]); + } + if (ivLen < 2 || ivLen > 5) + throw new XI5250Exception("Invalid len: " + ivLen, XI5250Emulator.ERR_INVALID_ROW_COL_ADDR); + ivLen--; + ivAttributeTypes = new byte[ivLen]; + if (inStream.read(ivAttributeTypes) < ivLen) + throw new XI5250Exception("EOF reached", XI5250Emulator.ERR_INVALID_ROW_COL_ADDR); + } + + + @Override + protected void execute() { + //TODO + throw new IllegalStateException("Not supported"); + } + + + @Override + public String toString() { + return super.toString() + " [" + ivRow + "," + ivCol + "," + ivLen + "," + ",[" + + XITelnet.toHex(ivAttributeTypes) + "]" + "]"; + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XIFieldTo5250Stream.java b/net/infordata/em/tn5250/XIFieldTo5250Stream.java new file mode 100644 index 0000000..484d5fa --- /dev/null +++ b/net/infordata/em/tn5250/XIFieldTo5250Stream.java @@ -0,0 +1,157 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 10/04/97 rel. 0.93 - some fix to add SignedNumeric fields handling. + 06/08/97 rel. 1.03c- bug fix. + 02/09/97 rel. 1.04a- changed to make XIReadFieldsCmd and XIReadImmediateCmd work. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.OutputStream; + +import net.infordata.em.crt5250.XI5250Field; +import net.infordata.em.crt5250.XI5250FieldSaver; +import net.infordata.em.crt5250.XIEbcdicTranslator; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Implements XI5250FieldSaver to write fields content to an OutputStream. + * + * @see XI5250Emulator#send5250Data + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XIFieldTo5250Stream implements XI5250FieldSaver { + + XI5250Emulator ivEmulator; + OutputStream ivOut; + boolean ivOnlyMDT; + + + /** + */ + public XIFieldTo5250Stream(XI5250Emulator aEmulator, OutputStream aOutStream, + boolean onlyMDT) { + ivEmulator = aEmulator; + ivOut = aOutStream; + ivOnlyMDT = onlyMDT; + } + + + /** + * + */ + public void write(XI5250Field aField, String aStr) + throws IOException { + if (ivOnlyMDT && !aField.isMDTOn()) + return; + + XIEbcdicTranslator translator = ivEmulator.getTranslator(); + + // requires some special handling + // see IBM 5250 function reference manual page 2-70 + if (aStr.length() > 0) { + if (aField.isSignedNumeric()) { + StringBuilder strBuf = new StringBuilder(aStr); + int i; + + // find last digit char + for (i = strBuf.length() - 1; + (i >= 0) && !Character.isDigit(strBuf.charAt(i)); i--) + ; + + // replace non digit chars between digit char with zeroes + for (int j = i - 1; j >= 0; j--) + if (!Character.isDigit(strBuf.charAt(j))) + strBuf.setCharAt(j, '0'); + + if (strBuf.charAt(strBuf.length() - 1) == '-') { + if (i >= 0) { + byte xx = translator.toEBCDIC(strBuf.charAt(i)); + xx &= 0x0F; + xx |= 0xD0; + strBuf.setCharAt(i, translator.toChar(xx)); + aStr = new String(strBuf).substring(0, strBuf.length() - 1); + } + else + aStr = ""; + } + else + aStr = new String(strBuf); + } + } + + int i = aStr.length() - 1; + + if (ivOnlyMDT) { //!!1.04a + byte[] cBuf = {XI5250Emulator.ORD_SBA, + (byte)(aField.getRow() + 1), + (byte)(aField.getCol() + 1)}; + + ivOut.write(cBuf); + + // exclude trailing null chars + for (; (i >= 0) && (aStr.charAt(i) == '\u0000'); i--) + ; + } + + byte[] strBuf = new byte[i + 1]; + { + int linearPos = ivEmulator.toLinearPos(aField.getCol(), aField.getRow()); + int j; + int len = Math.min(i + 1, aStr.length()); + byte space = translator.toEBCDIC(' '); + + for (j = 0; j < len; j++) { + char ch = aStr.charAt(j); + if (ch == XI5250Emulator.ATTRIBUTE_PLACE_HOLDER) { + ch = (char)ivEmulator.getAttr(ivEmulator.toColPos(linearPos + j), + ivEmulator.toRowPos(linearPos + j)); + strBuf[j] = (byte)ch; // leave attributes as is + } + else if (ch == '\u0000') { + strBuf[j] = space; + } + else { + strBuf[j] = translator.toEBCDIC(ch); + } + } + // fill with space + for (j = len; j < i + 1; j++) + strBuf[j] = space; + } + + if (i >= 0) { + for (int j = 0; j < (i + 1); j++) { + // convert nulls to EBCDIC spaces + if (strBuf[j] == 0) + strBuf[j] = 0x40; + } + + ivOut.write(strBuf, 0, i + 1); + } + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XIICOrd.java b/net/infordata/em/tn5250/XIICOrd.java new file mode 100644 index 0000000..735a941 --- /dev/null +++ b/net/infordata/em/tn5250/XIICOrd.java @@ -0,0 +1,66 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.InputStream; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * 5250 IC Order + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XIICOrd extends XI5250Ord { + + protected int ivRow, ivCol; + + + @Override + protected void readFrom5250Stream(InputStream inStream) throws IOException, XI5250Exception { + ivRow = Math.max(0, inStream.read()); + ivCol = Math.max(0, inStream.read()); + // Cannot deal with real dimensions, since they can be not applied yet + if (ivRow <= 0 || ivRow > XI5250Emulator.MAX_ROWS || + ivCol <= 0 || ivCol > XI5250Emulator.MAX_COLS) + throw new XI5250Exception("Invalid screen coord: " + ivRow + "," + ivCol, + XI5250Emulator.ERR_INVALID_ROW_COL_ADDR); + } + + + @Override + protected void execute() { + ivEmulator.setCursorPos(ivCol - 1, ivRow - 1); + ivEmulator.ivCmdList.ivICOrderExecuted = true; + } + + + @Override + public String toString() { + return super.toString() + " [" + ivRow + "," + ivCol + "]"; + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XIImagesBdl.java b/net/infordata/em/tn5250/XIImagesBdl.java new file mode 100644 index 0000000..278e8c7 --- /dev/null +++ b/net/infordata/em/tn5250/XIImagesBdl.java @@ -0,0 +1,134 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + 07/07/98 rel. 1.07 - Uses XIUtil.createImage(), the old approach doesn' t + work at design time. + 15/06/99 rel. 1.13 - Introduced crt5250 bundle. + */ + + +package net.infordata.em.tn5250; + +import java.awt.Image; +import java.util.HashMap; +import java.util.ListResourceBundle; +import java.util.Map; + +import javax.swing.Icon; +import javax.swing.ImageIcon; + +import net.infordata.em.util.XIUtil; + + +/** + * The image bundle. + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XIImagesBdl extends ListResourceBundle { + + private static XIImagesBdl cvImagesBdl; + + private static Object[][] cvContents = null; + + static { + try { + Object[][] contents = new Object[][] { + {"TemporaryLock", + XIUtil.createImage( + XIImagesBdl.class, "resources/TemporaryLockState.gif")}, + {"NormalLock", + XIUtil.createImage( + XIImagesBdl.class, "resources/NormalLockState.gif")}, + {"Help", + XIUtil.createImage( + XIImagesBdl.class, "resources/HelpState.gif")}, + {"Message", + XIUtil.createImage( + XIImagesBdl.class, "resources/Message.gif")}, + {"Flash", + XIUtil.createImage( + XIImagesBdl.class, "resources/Flash.gif")}, + // + {"Connect", + XIUtil.createImage( + XIImagesBdl.class, "resources/Connect.gif")}, + {"Disconnect", + XIUtil.createImage( + XIImagesBdl.class, "resources/Disconnect.gif")}, + {"InFrame", + XIUtil.createImage( + XIImagesBdl.class, "resources/InFrame.gif")}, + {"SnapShot", + XIUtil.createImage( + XIImagesBdl.class, "resources/SnapShot.gif")}, + }; + + Object[][] superContents = + net.infordata.em.crt5250.XIImagesBdl.getImagesBdl().getContents(); + cvContents = new Object[superContents.length + contents.length][2]; + System.arraycopy(superContents, 0, cvContents, 0, superContents.length); + System.arraycopy(contents, 0, cvContents, superContents.length, contents.length); + } + catch (RuntimeException ex) { + throw ex; + } + } + + + private XIImagesBdl() { + } + + + public static XIImagesBdl getImagesBdl() { + if (cvImagesBdl == null) { + cvImagesBdl = new XIImagesBdl(); + } + + return cvImagesBdl; + } + + + @Override + public Object[][] getContents() { + return cvContents; + } + + + /** + */ + public final Image getImage(String anImageName) { + return ((ImageIcon)getIcon(anImageName)).getImage(); + } + + + private Map ivIcons = new HashMap(); + + /** + */ + public synchronized final Icon getIcon(String anImageName) { + Icon icon = (Icon)ivIcons.get(anImageName); + if (icon == null) { + icon = new ImageIcon((Image)getObject(anImageName)); + ivIcons.put(anImageName, icon); + } + return icon; + } +} diff --git a/net/infordata/em/tn5250/XIMCOrd.java b/net/infordata/em/tn5250/XIMCOrd.java new file mode 100644 index 0000000..f23a019 --- /dev/null +++ b/net/infordata/em/tn5250/XIMCOrd.java @@ -0,0 +1,71 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.InputStream; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * MC - Move cursor + * + * see: http://publibfp.boulder.ibm.com/cgi-bin/bookmgr/BOOKS/co2e2001/15.6.6?DT=19950629163252 + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XIMCOrd extends XI5250Ord { + + protected int ivRow, ivCol; + + + /** + * @exception XI5250Exception raised if order parameters are wrong. + */ + @Override + protected void readFrom5250Stream(InputStream inStream) + throws IOException, XI5250Exception { + ivRow = Math.max(0, inStream.read()); + ivCol = Math.max(0, inStream.read()); + // Cannot deal with real dimensions, since they can be not applied yet + if (ivRow <= 0 || ivRow > XI5250Emulator.MAX_ROWS || + ivCol <= 0 || ivCol > XI5250Emulator.MAX_COLS) + throw new XI5250Exception("Invalid screen coord: " + ivRow + "," + ivCol, + XI5250Emulator.ERR_INVALID_ROW_COL_ADDR); + } + + + @Override + protected void execute() { + ivEmulator.setCursorPos(ivCol - 1, ivRow - 1); + } + + + @Override + public String toString() { + return super.toString() + " [" + ivRow + "," + ivCol + "]"; + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XIQueryCmd.java b/net/infordata/em/tn5250/XIQueryCmd.java new file mode 100644 index 0000000..e437d17 --- /dev/null +++ b/net/infordata/em/tn5250/XIQueryCmd.java @@ -0,0 +1,90 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.InputStream; + +import net.infordata.em.crt5250.XIEbcdicTranslator; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * 5250 Query command. + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XIQueryCmd extends XI5250Cmd { + protected int[] ivPar = new int[5]; + + + @Override + protected void readFrom5250Stream(InputStream inStream) throws IOException { + for (int i = 0; i < 5; i++) + ivPar[i] = inStream.read(); + + if (ivPar[0] != 0x00 || ivPar[1] != 0x05 || + ivPar[2] != 0xD9 || ivPar[3] != 0x70 || + ivPar[4] != 0x00) + ; //!!V gestire errori + } + + + @Override + protected void execute() { + XIEbcdicTranslator trans = ivEmulator.getTranslator(); + // see rfc 1205 + byte[] buf = { + (byte)0x00, (byte)0x00, + (byte)0x88, + (byte)0x00, (byte)0x3A, + (byte)0xD9, + (byte)0x70, + (byte)0x80, + (byte)0x06, (byte)0x00, // any other 5250 emulator + (byte)0x01, (byte)0x01, (byte)0x00, // version + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x01, + (byte)trans.toEBCDIC('5'), (byte)trans.toEBCDIC('2'), (byte)trans.toEBCDIC('5'), (byte)trans.toEBCDIC('1'), // 5251 + (byte)trans.toEBCDIC('0'), (byte)trans.toEBCDIC('1'), (byte)trans.toEBCDIC('1'), + (byte)0x02, (byte)0x00, // keyboard + (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // S/N + (byte)0x01, (byte)0x00, // max input fields + (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x01, // Row 1 e col 1 support + (byte)(0x03 | 0x40), // 24x80 and 27x132 color supported + (byte)0x00, // reserved + (byte)0x00, + (byte)0x00, //0x07, // enhanced mode ?? + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00}; + + ivEmulator.send5250Packet((byte)0x00, (byte)0x00, buf); + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XIRAOrd.java b/net/infordata/em/tn5250/XIRAOrd.java new file mode 100644 index 0000000..791822d --- /dev/null +++ b/net/infordata/em/tn5250/XIRAOrd.java @@ -0,0 +1,75 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.InputStream; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * 5250 RA Order + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XIRAOrd extends XI5250Ord { + + protected int ivEndRow, ivEndCol; + protected char ivChar; + + + @Override + protected void readFrom5250Stream(InputStream inStream) throws IOException, XI5250Exception { + ivEndRow = Math.max(0, inStream.read()); + ivEndCol = Math.max(0, inStream.read()); + ivChar = ivEmulator.getTranslator().toChar((byte)Math.max(0, inStream.read())); + // Cannot deal with real dimensions, since they can be not applied yet + if (ivEndRow <= 0 || ivEndRow > XI5250Emulator.MAX_ROWS || + ivEndCol <= 0 || ivEndCol > XI5250Emulator.MAX_COLS) + throw new XI5250Exception("Invalid screen coord: " + ivEndRow + "," + ivEndCol, + XI5250Emulator.ERR_INVALID_ROW_COL_ADDR); + } + + + @Override + protected void execute() { + int start = ivEmulator.toLinearPos(ivEmulator.getSBACol(), ivEmulator.getSBARow()); + int end = ivEmulator.toLinearPos(ivEndCol - 1, ivEndRow - 1); + StringBuilder str = new StringBuilder(end - start + 1); + for (int i = 0; i < (end - start + 1); i++) + str.append(ivChar); + + ivEmulator.drawString(str.toString(), ivEmulator.getSBACol(), ivEmulator.getSBARow()); + ivEmulator.setSBA(ivEmulator.getSBA() + (end - start + 1)); + } + + + @Override + public String toString() { + return super.toString() + + " [" + ivEndRow + "," + ivEndCol + ",'" + ivChar + "'" + "]"; + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XIReadFieldsCmd.java b/net/infordata/em/tn5250/XIReadFieldsCmd.java new file mode 100644 index 0000000..0293779 --- /dev/null +++ b/net/infordata/em/tn5250/XIReadFieldsCmd.java @@ -0,0 +1,63 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.InputStream; + + +//////////////////////////////////////////////////////////////////////////////// + +/** + * 5250 Read fields + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XIReadFieldsCmd extends XICCCmd { + /** + * @exception XI5250Exception raised if command parameters are wrong. + */ + @Override + protected void readFrom5250Stream(InputStream inStream) + throws IOException, XI5250Exception { + readCC(inStream); + } + + + @Override + protected void execute() { + ivEmulator.ivPendingCmd = this; + executeCC1(); + executeCC2(); + } + + @Override + protected void executePending(int anAidCode, boolean isMasked) { + ivEmulator.setState(XI5250Emulator.ST_TEMPORARY_LOCK); + ivEmulator.send5250Data(anAidCode, ivEmulator.isMasterMDTSet() && !isMasked, false); + //!!0.92a ivEmulator.ivPendingCmd = null; + //ivEmulator.removeFields(); + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XIReadImmediateCmd.java b/net/infordata/em/tn5250/XIReadImmediateCmd.java new file mode 100644 index 0000000..d8c34cd --- /dev/null +++ b/net/infordata/em/tn5250/XIReadImmediateCmd.java @@ -0,0 +1,49 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.InputStream; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * 5250 Read Immediate + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XIReadImmediateCmd extends XI5250Cmd { + + @Override + protected void readFrom5250Stream(InputStream inStream) throws IOException { + } + + + @Override + protected void execute() { + ivEmulator.send5250Data(0x00, ivEmulator.isMasterMDTSet(), false); + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XIReadMdtFieldsCmd.java b/net/infordata/em/tn5250/XIReadMdtFieldsCmd.java new file mode 100644 index 0000000..d394d2c --- /dev/null +++ b/net/infordata/em/tn5250/XIReadMdtFieldsCmd.java @@ -0,0 +1,65 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.InputStream; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * 5250 Read MDT fields command + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XIReadMdtFieldsCmd extends XICCCmd { + /** + * @exception XI5250Exception raised if command parameters are wrong. + */ + @Override + protected void readFrom5250Stream(InputStream inStream) + throws IOException, XI5250Exception { + readCC(inStream); + } + + + @Override + protected void execute() { + ivEmulator.ivPendingCmd = this; + executeCC1(); + executeCC2(); + } + + + @Override + protected void executePending(int anAidCode, boolean isMasked) { + ivEmulator.setState(XI5250Emulator.ST_TEMPORARY_LOCK); + ivEmulator.send5250Data(anAidCode, + ivEmulator.isMasterMDTSet() && !isMasked, true); + //!!0.92a ivEmulator.ivPendingCmd = null; + //!!V1 ivEmulator.removeFields(); + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XIReadScreenCmd.java b/net/infordata/em/tn5250/XIReadScreenCmd.java new file mode 100644 index 0000000..8540bb2 --- /dev/null +++ b/net/infordata/em/tn5250/XIReadScreenCmd.java @@ -0,0 +1,49 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.InputStream; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * 5250 read screen command + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XIReadScreenCmd extends XI5250Cmd { + + @Override + protected void readFrom5250Stream(InputStream inStream) throws IOException { + } + + + @Override + protected void execute() { + ivEmulator.send5250Screen(); + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XIRestoreScreenCmd.java b/net/infordata/em/tn5250/XIRestoreScreenCmd.java new file mode 100644 index 0000000..4c2bf8f --- /dev/null +++ b/net/infordata/em/tn5250/XIRestoreScreenCmd.java @@ -0,0 +1,71 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.InputStream; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * 5250 Restore screen command + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XIRestoreScreenCmd extends XI5250Cmd { + + protected int ivPos; + + + /** + * @exception XI5250Exception raised if command parameters are wrong. + */ + @Override + protected void readFrom5250Stream(InputStream inStream) + throws IOException, XI5250Exception { + ivPos = inStream.read(); + if (ivPos == -1) + throw new XI5250Exception("Restore screen position required", + XI5250Emulator.ERR_INVALID_COMMAND); + } + + + @Override + protected void execute() { + try { + /*!!1.06a + XI5250EmulatorMemento mm = (XI5250EmulatorMemento)ivEmulator.ivSavedScreenList.elementAt(ivPos); + ivEmulator.ivSavedScreenList.setSize(ivPos + 1); + */ + //!!1.06a + XI5250EmulatorMemento mm = ivEmulator.ivSavedScreens[ivPos]; + + ivEmulator.restoreMemento(mm); + } + catch (ArrayIndexOutOfBoundsException ex) { + } + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XIRollCmd.java b/net/infordata/em/tn5250/XIRollCmd.java new file mode 100644 index 0000000..db04b90 --- /dev/null +++ b/net/infordata/em/tn5250/XIRollCmd.java @@ -0,0 +1,79 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.InputStream; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * 5250 Roll command + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XIRollCmd extends XI5250Cmd { + + boolean ivDown; + int ivNRows; + int ivTopRow; + int ivBottomRow; + + + /** + * @exception XI5250Exception raised if command parameters are wrong. + */ + @Override + protected void readFrom5250Stream(InputStream inStream) + throws IOException, XI5250Exception { + int[] bb = new int[3]; + int i; + + for (i = 0; i < 3 && (bb[i] = inStream.read()) >= 0; i++) + ; + + if (i < 3) + throw new XI5250Exception("Roll parameter missing", + XI5250Emulator.ERR_INVALID_ROW_COL_ADDR); + + ivDown = ((bb[0] & 0x80) != 0); + + ivNRows = (bb[0] & 0x1F); + + ivTopRow = bb[1]; + ivBottomRow = bb[2]; + + if (ivTopRow > ivBottomRow) + throw new XI5250Exception("TopRow greater then BottomRow", + XI5250Emulator.ERR_INVALID_ROW_COL_ADDR); + } + + + @Override + protected void execute() { + ivEmulator.scroll(ivDown, ivTopRow - 1, ivBottomRow, ivNRows); + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XISBAOrd.java b/net/infordata/em/tn5250/XISBAOrd.java new file mode 100644 index 0000000..aa709db --- /dev/null +++ b/net/infordata/em/tn5250/XISBAOrd.java @@ -0,0 +1,65 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.InputStream; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * 5250 SBA Order + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XISBAOrd extends XI5250Ord { + + protected int ivRow, ivCol; + + + @Override + protected void readFrom5250Stream(InputStream inStream) throws IOException, XI5250Exception { + ivRow = Math.max(0, inStream.read()); + ivCol = Math.max(0, inStream.read()); + // Cannot deal with real dimensions, since they can be not applied yet + if (ivRow <= 0 || ivRow > XI5250Emulator.MAX_ROWS || + ivCol <= 0 || ivCol > XI5250Emulator.MAX_COLS) + throw new XI5250Exception("Invalid screen coord: " + ivRow + "," + ivCol, + XI5250Emulator.ERR_INVALID_ROW_COL_ADDR); + } + + + @Override + protected void execute() { + ivEmulator.setSBA(ivCol - 1, ivRow - 1); + } + + + @Override + public String toString() { + return super.toString() + " [" + ivRow + "," + ivCol + "]"; + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XISFOrd.java b/net/infordata/em/tn5250/XISFOrd.java new file mode 100644 index 0000000..d1605a0 --- /dev/null +++ b/net/infordata/em/tn5250/XISFOrd.java @@ -0,0 +1,106 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 04/06/97 rel. 1.00b- uses XI5250Emulator create5250Field factory method. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.InputStream; + +import net.infordata.em.tnprot.XITelnet; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * 5250 SF Order + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XISFOrd extends XI5250Ord { + + protected byte[] FFW = new byte[2]; + protected byte[] FCW = new byte[2]; + protected byte ivScreenAttr; + protected int ivFieldLen; + + + @Override + protected void readFrom5250Stream(InputStream inStream) throws IOException { + byte bb; + + inStream.mark(1); + bb = (byte)Math.max(0, inStream.read()); + // check if FFW is present + if ((bb & 0xC0) == 0x40) { + FFW[0] = bb; + FFW[1] = (byte)Math.max(0, inStream.read()); + + inStream.mark(1); + bb = (byte)Math.max(0, inStream.read()); + // check if FCW is present + if ((bb & 0xC0) == 0x80) { + FCW[0] = bb; + FCW[1] = (byte)Math.max(0, inStream.read()); + } + else + inStream.reset(); + } + else + inStream.reset(); + + ivScreenAttr = (byte)Math.max(0, inStream.read()); + ivFieldLen = (Math.max(0, inStream.read()) << 8) + Math.max(0, inStream.read()); + //!!V effettuare check dei parametri + } + + + @Override + protected void execute() { + if (ivScreenAttr != 0) { + //NO ivEmulator.setDefAttr(XITelnet.toInt(ivScreenAttr)); + ivEmulator.drawString(String.valueOf(XI5250Emulator.ATTRIBUTE_PLACE_HOLDER), + ivEmulator.getSBACol(), ivEmulator.getSBARow(), + ivScreenAttr); + ivEmulator.setSBA(ivEmulator.getSBA() + 1); + } + + // -1 to force attribute reload + ivEmulator.addField(ivEmulator.create5250Field((byte[])FFW.clone(), + (byte[])FCW.clone(), + ivEmulator.getSBACol(), + ivEmulator.getSBARow(), + ivFieldLen, -1)); + } + + + @Override + public String toString() { + return super.toString() + " [FFW=[" + XITelnet.toHex(FFW[0]) + "," + + XITelnet.toHex(FFW[1]) + "]," + + "FCW=[" + XITelnet.toHex(FCW[0]) + "," + + XITelnet.toHex(FCW[1]) + "]," + + XITelnet.toHex(ivScreenAttr) + "," + ivFieldLen + "]"; + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XISOHOrd.java b/net/infordata/em/tn5250/XISOHOrd.java new file mode 100644 index 0000000..6724f04 --- /dev/null +++ b/net/infordata/em/tn5250/XISOHOrd.java @@ -0,0 +1,102 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.InputStream; + +import net.infordata.em.tnprot.XITelnet; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * 5250 SOH Order + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XISOHOrd extends XI5250Ord { + + protected byte[] ivData; + protected int ivLen; + + + /** + * @exception XI5250Exception raised if order parameters are wrong. + */ + @Override + protected void readFrom5250Stream(InputStream inStream) + throws IOException, XI5250Exception { + int i = 0; + int bb; + + ivLen = inStream.read(); + if (ivLen > 0) { + ivData = new byte[ivLen]; + for (i = 0; (i < ivLen) && ((bb = inStream.read()) != -1); i++) + ivData[i] = (byte)bb; + } + // parameters check + if (ivLen < 0 || ivLen > 7 || i < ivLen) + throw new XI5250Exception("Bad SOH Order", XI5250Emulator.ERR_INVALID_SOH_LENGTH); + } + + + @Override + protected void execute() { + // I didn' t found them on docs, but i need them + ivEmulator.ivCmdList.ivICOrderExecuted = false; + ivEmulator.removeFields(); + + ivEmulator.ivPendingCmd = null; //!!0.92a + + if (ivLen >= 2) { + // resequencing byte present + if (ivLen >= 3) { + // error line address present + if (ivLen >= 4) { + ivEmulator.setErrorRow(ivData[3] - 1); + // function keys mask present + if (ivLen >= 7) { + int xx = XITelnet.toInt(ivData[4]) << 16 | //!!1.05a + XITelnet.toInt(ivData[5]) << 8 | + XITelnet.toInt(ivData[6]); + + ivEmulator.setFunctionKeysMask(xx); + } + } + } + } + } + + + @Override + public String toString() { + String str = ""; + for (int i = 0; i < ivLen; i++) + str += XITelnet.toHex(ivData[i]) + ","; + return super.toString() + " [" + ivLen + ",[" + str + "]]"; + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XISaveScreenCmd.java b/net/infordata/em/tn5250/XISaveScreenCmd.java new file mode 100644 index 0000000..29014a1 --- /dev/null +++ b/net/infordata/em/tn5250/XISaveScreenCmd.java @@ -0,0 +1,57 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.InputStream; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * 5250 Save screen command + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XISaveScreenCmd extends XI5250Cmd { + + @Override + protected void readFrom5250Stream(InputStream inStream) throws IOException { + } + + + @Override + protected void execute() { + /*!!1.06a + int pos = ivEmulator.ivSavedScreenList.size(); + ivEmulator.ivSavedScreenList.addElement(ivEmulator.createMemento()); + */ + //!!1.06a + int pos = (ivEmulator.ivSavedScreensIdx++) % ivEmulator.ivSavedScreens.length; + ivEmulator.ivSavedScreens[pos] = ivEmulator.createMemento(); + + ivEmulator.send5250SavedScreen(pos); + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XITDOrd.java b/net/infordata/em/tn5250/XITDOrd.java new file mode 100644 index 0000000..6c9e2ad --- /dev/null +++ b/net/infordata/em/tn5250/XITDOrd.java @@ -0,0 +1,90 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.InputStream; + +import net.infordata.em.crt5250.XIEbcdicTranslator; +import net.infordata.em.tnprot.XITelnet; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * TD - Transparent data + * + * see: http://publibfp.boulder.ibm.com/cgi-bin/bookmgr/BOOKS/co2e2001/15.6.10?DT=19950629163252 + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XITDOrd extends XI5250Ord { + + protected String ivData; + protected int ivLen; + + /** + * @exception XI5250Exception raised if order parameters are wrong. + */ + @Override + protected void readFrom5250Stream(InputStream inStream) + throws IOException, XI5250Exception { + { + byte[] buf = new byte[2]; + if (inStream.read(buf) < buf.length) + throw new XI5250Exception("EOF reached", XI5250Emulator.ERR_INVALID_ROW_COL_ADDR); + ivLen = (XITelnet.toInt(buf[0]) << 8) | XITelnet.toInt(buf[1]); + // Cannot deal with real dimensions, since they can be not applied yet + if (ivLen < 0 || ivLen > (XI5250Emulator.MAX_ROWS * XI5250Emulator.MAX_COLS)) + throw new XI5250Exception("Invalid len", XI5250Emulator.ERR_INVALID_ROW_COL_ADDR); + } + { + byte[] buf = new byte[ivLen]; + int count = inStream.read(buf); + if (count < buf.length) + throw new XI5250Exception("EOF reached, requested: " + ivLen + + " readden:" + count, XI5250Emulator.ERR_INVALID_ROW_COL_ADDR); + XIEbcdicTranslator translator = ivEmulator.getTranslator(); + StringBuilder sb = new StringBuilder(ivLen); + for (int i = 0; i < count ; i++) { + sb.append(translator.toChar(buf[i])); + } + ivData = sb.toString(); + } + } + + + @Override + protected void execute() { + ivEmulator.drawString(ivData, ivEmulator.getSBACol(), ivEmulator.getSBARow()); + ivEmulator.setSBA(ivEmulator.getSBA() + ivData.length()); + } + + + @Override + public String toString() { + return super.toString() + " [" + ivLen + ",\"" + ivData + "\"" + "]"; + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XIWEAOrd.java b/net/infordata/em/tn5250/XIWEAOrd.java new file mode 100644 index 0000000..4c25cb9 --- /dev/null +++ b/net/infordata/em/tn5250/XIWEAOrd.java @@ -0,0 +1,82 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.InputStream; + +import net.infordata.em.tnprot.XITelnet; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * WEA - Write extended attribute + * TODO + * + * see: http://publibfp.boulder.ibm.com/cgi-bin/bookmgr/BOOKS/co2e2001/15.6.11?DT=19950629163252 + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XIWEAOrd extends XI5250Ord { + + protected byte ivAttributeType; + protected byte ivAttribute; + + /** + * @exception XI5250Exception raised if order parameters are wrong. + */ + @Override + protected void readFrom5250Stream(InputStream inStream) + throws IOException, XI5250Exception { + // If not in enhanced mode ... + if (true) + throw new XI5250Exception("Not supported", XI5250Emulator.ERR_INVALID_ROW_COL_ADDR); + { + byte[] buf = new byte[2]; + if (inStream.read(buf) < buf.length) + throw new XI5250Exception("EOF reached", XI5250Emulator.ERR_INVALID_EXT_ATTR_TYPE); + ivAttributeType = buf[0]; + ivAttribute = buf[1]; + if (ivAttributeType != 0x01 && ivAttributeType != 0x03 && ivAttributeType != 0x05) + throw new XI5250Exception("Invalid attr type: " + XITelnet.toHex(ivAttributeType), + XI5250Emulator.ERR_INVALID_EXT_ATTR_TYPE); + } + } + + + @Override + protected void execute() { + //TODO + throw new IllegalStateException("Not supported"); + } + + + @Override + public String toString() { + return super.toString() + " [" + XITelnet.toHex(ivAttributeType) + "," + + XITelnet.toHex(ivAttribute) + "]"; + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XIWdsfOrd.java b/net/infordata/em/tn5250/XIWdsfOrd.java new file mode 100644 index 0000000..18c030b --- /dev/null +++ b/net/infordata/em/tn5250/XIWdsfOrd.java @@ -0,0 +1,65 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.InputStream; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * WDSF - Write to Display Structured Field + * TODO + * + * see: http://publibfp.boulder.ibm.com/cgi-bin/bookmgr/BOOKS/co2e2001/15.6.13?DT=19950629163252 + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XIWdsfOrd extends XI5250Ord { + + /** + * @exception XI5250Exception raised if order parameters are wrong. + */ + @Override + protected void readFrom5250Stream(InputStream inStream) + throws IOException, XI5250Exception { + // If not in enhanced mode ... + if (true) + throw new XI5250Exception("Not supported", XI5250Emulator.ERR_INVALID_ROW_COL_ADDR); + } + + + @Override + protected void execute() { + throw new IllegalStateException("Not supported"); + } + + + @Override + public String toString() { + return super.toString(); + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XIWriteErrorCodeCmd.java b/net/infordata/em/tn5250/XIWriteErrorCodeCmd.java new file mode 100644 index 0000000..ded5411 --- /dev/null +++ b/net/infordata/em/tn5250/XIWriteErrorCodeCmd.java @@ -0,0 +1,64 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 12/05/97 rel. 0.95d- setDefAttr() to 0x20. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.InputStream; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * 5250 Write error code command + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XIWriteErrorCodeCmd extends XI5250Cmd { + + protected XI5250OrdList ivOrdList; + + + /** + * @exception XI5250Exception raised if command parameters are wrong. + */ + @Override + protected void readFrom5250Stream(InputStream inStream) + throws IOException, XI5250Exception { + ivOrdList = ivEmulator.createOrdList(ivEmulator); + ivOrdList.readFrom5250Stream(inStream); + } + + + @Override + protected void execute() { + ivEmulator.setState(XI5250Emulator.ST_PRE_HELP); + + ivEmulator.setDefAttr(0x20); //!!0.95d + + ivEmulator.setSBA(0, ivEmulator.getErrorRow()); + ivOrdList.execute(); + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/XIWriteToDisplayCmd.java b/net/infordata/em/tn5250/XIWriteToDisplayCmd.java new file mode 100644 index 0000000..e2c02c5 --- /dev/null +++ b/net/infordata/em/tn5250/XIWriteToDisplayCmd.java @@ -0,0 +1,97 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250; + + +import java.io.IOException; +import java.io.InputStream; +import java.util.Iterator; + +import net.infordata.em.crt5250.XI5250Field; + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * 5250 write to display command + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XIWriteToDisplayCmd extends XICCCmd { + + protected XI5250OrdList ivOrdList; + + + /** + * @exception XI5250Exception raised if command parameters are wrong. + */ + @Override + protected void readFrom5250Stream(InputStream inStream) + throws IOException, XI5250Exception { + readCC(inStream); + + ivOrdList = ivEmulator.createOrdList(ivEmulator); + ivOrdList.readFrom5250Stream(inStream); + } + + + /** + */ + @Override + protected void execute() { + //ivEmulator.setSBA(0, 0); + + executeCC1(); + + // if format table is going to be altered then enter NORMAL_LOCKED state + if (ivOrdList.isOrderPresent(XI5250Emulator.ORD_SF) || + ivOrdList.isOrderPresent(XI5250Emulator.ORD_SOH)) { + ivEmulator.setState(XI5250Emulator.ST_NORMAL_LOCKED); + } + + ivOrdList.execute(); + + if (ivEmulator.getState() != XI5250Emulator.ST_NORMAL_UNLOCKED) { + //if (!ivOrdList.isOrderPresent(XI5250Emulator.ORD_IC)) + if (!ivEmulator.ivCmdList.ivICOrderExecuted) { + // search first not bypass field + XI5250Field field; + boolean found = false; + for (Iterator e = ivEmulator.getFields().iterator(); e.hasNext(); ) { + field = e.next(); + if (!field.isBypassField()) { + ivEmulator.setCursorPos(field.getCol(), field.getRow()); + found = true; + break; + } + } + + if (!found) + ivEmulator.setCursorPos(0, 0); + } + } + + executeCC2(); + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250/resources/Connect.gif b/net/infordata/em/tn5250/resources/Connect.gif new file mode 100644 index 0000000000000000000000000000000000000000..1e4abefa183c645039febb7c504774f6f9e8ad85 GIT binary patch literal 166 zcmZ?wbhEHb6k!ly*vtR|4Pe{=rW$~}hK2(N4m310{0EBvXZR1MfHaT=1d2ad7#SFt z8FYY>Kodk57+8V}PI#`~Ymv>f>wi3}OiJb~22&-44w;uGVkNoa{A=V~Uq7^xKodk57+8D@PI#`~Ymv>f>wi3}OiJb~22&-44w;uGVkNoa{A=V~Uq7^xJb#_> un2NE|fgP^}XF4tC?~<`AK7R1k!M9cMH!o)ToXVQIu(#@L-fnh525SJJ5Ic?l literal 0 HcmV?d00001 diff --git a/net/infordata/em/tn5250/resources/Flash.gif b/net/infordata/em/tn5250/resources/Flash.gif new file mode 100644 index 0000000000000000000000000000000000000000..11b76fa754087cf8be3528010eb3fe1c18a5049d GIT binary patch literal 186 zcmZ?wbhEHb)ML4AubB5>m$i literal 0 HcmV?d00001 diff --git a/net/infordata/em/tn5250/resources/HelpState.gif b/net/infordata/em/tn5250/resources/HelpState.gif new file mode 100644 index 0000000000000000000000000000000000000000..75d0d5de553abf5f49d5a55372174e00da2ba01f GIT binary patch literal 221 zcmZ?wbhEHbRAEqIc+ATH1pC2wKbYDN%&P;)!i1?&sP8QQ4dS_**kCLq9w25)_mQyX6K!Xy5_}e|J(HCe`lN* zwIC))dpjGzBY%C z*Ct058cVk{h4?qBwdu#IYIbp_PRvN0pfRb(aMldNijMis3m5gyUOLrx#p*R{l>`~A E0Rn|$i~s-t literal 0 HcmV?d00001 diff --git a/net/infordata/em/tn5250/resources/InFrame.gif b/net/infordata/em/tn5250/resources/InFrame.gif new file mode 100644 index 0000000000000000000000000000000000000000..11edd6bae6de90856ab522079350368a77cf127a GIT binary patch literal 165 zcmZ?wbhEHb6k!ly*vtR|4Pe{=rW$~}hK2(N4m310{0EBvXZR1MfHaT=1d2ad7#SFt z8FYY>Kodk57+8V|PI#`~dt=kt-RUAqeJPzS4y)F^wiGSUInN)up(5&v{(>J}2?889 zZWdW2zgHI#nmS3kh*j2OxmBFViJVod!gVBmU*!|%-%_==EcM=p9W{LY3=Gx)d#OH! literal 0 HcmV?d00001 diff --git a/net/infordata/em/tn5250/resources/Message.gif b/net/infordata/em/tn5250/resources/Message.gif new file mode 100644 index 0000000000000000000000000000000000000000..609762a5b9d318aa84bb2fb4a5c746ff8f1fcb5e GIT binary patch literal 225 zcmZ?wbhEHblw%NMXkh?>1|R^DKn$fCKw=II4h{?r{}~*Btp6bV|Nnsl2mUhv89)rw zM-))}$->CMAkUx!QVp_`fi>=ddS6QByo^=raDe13qsfJfcI z`#CQ(Kof)*7+5R|PI#`~YZ0t^<*BGT$FvTgMFnk(t(IipRN6ePudwX-jdgq1M(ImD Z@ho$hcYeDdQ>>20DGkSf`WqY!)&RnRGXwwt literal 0 HcmV?d00001 diff --git a/net/infordata/em/tn5250/resources/Res.properties b/net/infordata/em/tn5250/resources/Res.properties new file mode 100644 index 0000000..cd867d1 --- /dev/null +++ b/net/infordata/em/tn5250/resources/Res.properties @@ -0,0 +1,28 @@ +# tn5250 + +TXT_Copy = Copy +TXT_Options = &Options +TXT_RefCursor = Ref. cursor +TXT_Exit = Exit +TXT_Paste = Paste +TXT_Edit = &Edit +TXT_3dFx = 3dFx + +TXT_About = About + +TXT_ConfirmExit = Confirm exit + +TXT_Communications = &Communications +TXT_Connect = Connect +TXT_Disconnect = Disconnect + +TXT_ConfirmDisconnect = Close connection +TXT_HostNameInput = Enter host-name or ip-address + +TXT_InFrame = Emulator in window + +TXT_SnapShot = Snap-shot +TXT_Print = Print +TXT_Forked = Forked from %1s by %2s +TXT_Version = Version %1s + diff --git a/net/infordata/em/tn5250/resources/Res_fr.properties b/net/infordata/em/tn5250/resources/Res_fr.properties new file mode 100644 index 0000000..e40112e --- /dev/null +++ b/net/infordata/em/tn5250/resources/Res_fr.properties @@ -0,0 +1,27 @@ +# tn5250 + +TXT_Copy = Copier +TXT_Options = &Options +TXT_RefCursor = Réf. curseur +TXT_Exit = Quitter +TXT_Paste = Coller +TXT_Edit = &Editer +TXT_3dFx = Effets 3D + +TXT_About = A propos + +TXT_ConfirmExit = Confirmer clôture + +TXT_Communications = &Communications +TXT_Connect = Connecter +TXT_Disconnect = Déconnecter + +TXT_ConfirmDisconnect = Fermer la connexion +TXT_HostNameInput = Entrer adresse ip ou nom serveur + +TXT_InFrame = Emulateur dans une fenêtre + +TXT_SnapShot = Copie-écran +TXT_Print = Imprimer +TXT_Forked = Un fork du projet %1s de %2s +TXT_Version = Version %1s diff --git a/net/infordata/em/tn5250/resources/Res_it.properties b/net/infordata/em/tn5250/resources/Res_it.properties new file mode 100644 index 0000000..8136c4f --- /dev/null +++ b/net/infordata/em/tn5250/resources/Res_it.properties @@ -0,0 +1,26 @@ +# tn5250 + +TXT_Copy = Copia +TXT_Options = &Opzioni +TXT_RefCursor = Cursore di riferimento +TXT_Exit = Chiudi +TXT_Paste = Incolla +TXT_Edit = &Modifica +TXT_3dFx = 3dFx + +TXT_About = Informazioni + +TXT_ConfirmExit = Confermi chiusura + +TXT_Communications = &Collegamento +TXT_Connect = Connetti +TXT_Disconnect = Disconnetti + +TXT_ConfirmDisconnect = Chiudo connessione +TXT_HostNameInput = Immetti nome host o indirizzo IP + +TXT_InFrame = Emulatore in finestra + +TXT_SnapShot = Foto pannello +TXT_Print = Stampa pannello + diff --git a/net/infordata/em/tn5250/resources/SnapShot.gif b/net/infordata/em/tn5250/resources/SnapShot.gif new file mode 100644 index 0000000000000000000000000000000000000000..db80175480dfb49b7e0ffe29d793b90a3e9c87f9 GIT binary patch literal 926 zcmZ?wbhEHb6k!ly_|5H44fP?9vc=MY~~Qwia8OW*wD@(=A^<<_{gP+K`4VIK_Qu` zPtHE+PR4>ICnw1<@<`0s^tfRv+n*Og%X}6Eubd~-wKeVN`h;$w2G4CeH`_8UuacDzV6X-Nta>E^ literal 0 HcmV?d00001 diff --git a/net/infordata/em/tn5250/resources/TemporaryLockState.gif b/net/infordata/em/tn5250/resources/TemporaryLockState.gif new file mode 100644 index 0000000000000000000000000000000000000000..605e2a501f6875364ed237a983e05fd8fcb14868 GIT binary patch literal 227 zcmZ?wbhEHbRAEqIc+ABB1Px%^0Hzv%yoQDY2M#neH2h~^_>Tb;f3h$#Fz_?z05t(k zP+?$TnegGH=jy!{ug~uOpCF;;DKJ6FeOAVHwp-b=?nzHK-g}aGQoi$!AHKQq&)Vb9|CdKobNQ7+72iPI#_nvBn+a literal 0 HcmV?d00001 diff --git a/net/infordata/em/tn5250/resources/XI5250Emulator_32.gif b/net/infordata/em/tn5250/resources/XI5250Emulator_32.gif new file mode 100644 index 0000000000000000000000000000000000000000..7ff4e4dba79def12290b15117322a2cdb4bc02b5 GIT binary patch literal 254 zcmZ?wbhEHbRA5kG*vtR|4Pe{=rW$~}hK2(N4m310{0EBvXZR1MfHaT=1d2ad7#SFt z8FYY>Kob-g7+6*pobX(|*W&fr-T$Q&`cg9I2^Xx%dA-j-VdaU;`zI9nvmX9Gut4C) zg|mFEvnPdUysJ8$aruPvERhHu2g66xmifOvx%=xR_Xo*Eckb@m@3*!0%-Y$Pu72Gb zyYKkt;+lM)`hY;MineyM&LpMC)Y7O48LfTIWhKoFy;T!)CzMSM>8eSe*|KE%!pUpX r=XRTK*r?vi!M|hYuHAcfS|%DCJfvf7v&CEC ivButtons = new ArrayList(); + + public PSHBTNCHCHandler(XI5250PanelsDispatcher disp) { + super(disp, ""); + } + + @Override + protected void sizeChanged() { + super.sizeChanged(); + final XI5250EmulatorExt em = getEmulator(); + for (JButton btn : ivButtons) { + btn.setFont(ivFontsCache.getFont( + Math.max(1, em.getFont().getSize() - 2))); + } + } + + @Override + protected boolean detailedTest() { + return true; + } + + @Override + protected void start() { + ivButtons.clear(); + final XI5250EmulatorExt em = getEmulator(); + final int crtWidth = em.getCrtSize().width; + for (Iterator e = getFields().iterator(); e.hasNext(); ) { + final XI5250Field field = e.next(); + if (field.isIOOnly()) { + final int col = field.getCol() - 1; + final int row = field.getRow(); + if (col >= 0 && + "<".equals(em.getString(col, row, 1))) { + final int len; + { + final int fieldEnd = col + field.getLength(); + String str = em.getString(fieldEnd + 1, row, crtWidth - fieldEnd); + int idx = str.indexOf(">"); + len = (idx < 0) ? -1 : idx + 2 + 1; + } + if (len > 0) { + final String txt = em.getString(col + 1, row, len - 2); + JButton btn = new JButton(txt); + if (ivFontsCache == null) + ivFontsCache = new FontsCache(btn.getFont()); + btn.setFont(ivFontsCache.getFont(Math.max(1, em.getFont().getSize() - 2))); + btn.setMargin(new Insets(2, 2, 2, 2)); + btn.setFocusable(false); + btn.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + em.setCursorPos(field.getCol(), field.getRow()); + em.requestFocusInWindow(); + em.processRawKeyEvent(new KeyEvent(em, KeyEvent.KEY_PRESSED, 0, + 0, KeyEvent.VK_ENTER, (char)KeyEvent.VK_ENTER)); + } + }); + ivButtons.add(btn); + new XI5250PanelConnection(this, + btn, col, row, len, 1); + } + } + } + } + } + + @Override + protected void stop() { + ivButtons.clear(); + } + + /////// + + private static class FontsCache { + + private Font[] ivFonts = new Font[XICrt.MAX_FONT_SIZE - XICrt.MIN_FONT_SIZE + 1]; + private Font ivFont; + + + public FontsCache(Font font) { + ivFont = font; + } + + + public Font getFont(int size) { + if (ivFonts[size - XICrt.MIN_FONT_SIZE] == null) { + ivFonts[size - XICrt.MIN_FONT_SIZE] = + new Font(ivFont.getName(), + ivFont.getStyle(), + size); + } + return ivFonts[size - XICrt.MIN_FONT_SIZE]; + } + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250ext/Test.java b/net/infordata/em/tn5250ext/Test.java new file mode 100644 index 0000000..0bcab6b --- /dev/null +++ b/net/infordata/em/tn5250ext/Test.java @@ -0,0 +1,184 @@ +package net.infordata.em.tn5250ext; + +import java.awt.Font; +import java.awt.Insets; +import java.awt.SystemColor; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.swing.JButton; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; + +import net.infordata.em.crt.XICrt; +import net.infordata.em.crt5250.XI5250Field; +import net.infordata.em.tn5250.XI5250Emulator; +import net.infordata.em.tn5250.XI5250Frame; + + +public class Test { + + private Test() { } + + /** + * @param args + */ + public static void main(String[] argv) { + XI5250EmulatorExt em = new XI5250EmulatorExt(); + em.setTerminalType("IBM-3477-FC"); + em.setKeyboardQueue(true); + + em.setHintOnActiveField(true); + XI5250PanelsDispatcher disp = new XI5250SimplePanelsDispatcher(em); + new TestHandler(disp); + + if (argv.length >= 1) { + em.setHost(argv[0]); + em.setActive(true); + } + + XI5250Frame frm = new XI5250Frame("tn5250ext" + " " + + XI5250Emulator.VERSION, em); + + //3D FX + if (argv.length >= 2 && "3DFX".equals(argv[1].toUpperCase())) { + em.setDefFieldsBorderStyle(XI5250Field.LOWERED_BORDER); + em.setDefBackground(SystemColor.control); + } + + frm.addWindowListener(new WindowAdapter() { + @Override + public void windowClosed(WindowEvent e) { + System.exit(0); + } + }); + frm.setBounds(0, 0, 570, 510); + frm.centerOnScreen(); + frm.setVisible(true); + } + + ////////////////////////////////////////////////////////////////////////////// + + /** + */ + private static class TestHandler extends XI5250PanelHandler { + + private FontsCache ivFontsCache; + private List ivButtons = new ArrayList(); + + public TestHandler(XI5250PanelsDispatcher disp) { + super(disp, ""); + } + + @Override + protected void sizeChanged() { + super.sizeChanged(); + final XI5250EmulatorExt em = getEmulator(); + for (JButton btn : ivButtons) { + btn.setFont(ivFontsCache.getFont( + Math.max(1, em.getFont().getSize() - 2))); + } + } + + @Override + protected boolean detailedTest() { + return true; + } + + @Override + protected void start() { + ivButtons.clear(); + final XI5250EmulatorExt em = getEmulator(); + final int crtWidth = em.getCrtSize().width; + for (Iterator e = getFields().iterator(); e.hasNext(); ) { + final XI5250Field field = e.next(); + boolean isButton = false; + if (field.isIOOnly()) { + final int col = field.getCol() - 1; + final int row = field.getRow(); + if (col >= 0 && + "<".equals(em.getString(col, row, 1))) { + final int len; + { + final int fieldEnd = col + field.getLength(); + String str = em.getString(fieldEnd + 1, row, crtWidth - fieldEnd); + int idx = str.indexOf(">"); + len = (idx < 0) ? -1 : idx + 2 + 1; + } + if (len > 0) { + isButton = true; + final String txt = em.getString(col + 1, row, len - 2); + JButton btn = new JButton(txt); + if (ivFontsCache == null) + ivFontsCache = new FontsCache(btn.getFont()); + btn.setFont(ivFontsCache.getFont(Math.max(1, em.getFont().getSize() - 2))); + btn.setMargin(new Insets(2, 2, 2, 2)); + btn.setFocusable(false); + btn.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + em.setCursorPos(field.getCol(), field.getRow()); + em.requestFocusInWindow(); + em.processRawKeyEvent(new KeyEvent(em, KeyEvent.KEY_PRESSED, 0, + 0, KeyEvent.VK_ENTER, (char)KeyEvent.VK_ENTER)); + } + }); + ivButtons.add(btn); + new XI5250PanelConnection(this, + btn, col, row, len, 1); + } + } + } + + if (!isButton) { + setFieldHint(field, new XIHint(field.toString())); + + JPopupMenu pm = new JPopupMenu(); + pm.add(new JMenuItem(field.toString())); + setFieldPopupMenu(field, pm); + + JButton btn = new JButton(); + new XI5250FieldConnection(this, field, btn); + } + + new XI5250PanelConnection(this, + new JButton("+-"), + 15, 15, 10, 6); + } + } + + @Override + protected void stop() { + ivButtons.clear(); + } + } + + /////// + + private static class FontsCache { + + private Font[] ivFonts = new Font[XICrt.MAX_FONT_SIZE - XICrt.MIN_FONT_SIZE + 1]; + private Font ivFont; + + + public FontsCache(Font font) { + ivFont = font; + } + + + public Font getFont(int size) { + if (ivFonts[size - XICrt.MIN_FONT_SIZE] == null) { + ivFonts[size - XICrt.MIN_FONT_SIZE] = + new Font(ivFont.getName(), + ivFont.getStyle(), + size); + } + return ivFonts[size - XICrt.MIN_FONT_SIZE]; + } + } +} diff --git a/net/infordata/em/tn5250ext/XI5250AppletExt.java b/net/infordata/em/tn5250ext/XI5250AppletExt.java new file mode 100644 index 0000000..2d37b1c --- /dev/null +++ b/net/infordata/em/tn5250ext/XI5250AppletExt.java @@ -0,0 +1,74 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package net.infordata.em.tn5250ext; + +import net.infordata.em.tn5250.XI5250Applet; + + +public class XI5250AppletExt extends XI5250Applet { + + private static final long serialVersionUID = 1L; + + @Override + protected XI5250EmulatorExt createEmulator() { + return new XI5250EmulatorExt(); + } + + @Override + public void init() { + super.init(); + final boolean pPSHBTNCHC = "true".equalsIgnoreCase(getParameter("PSHBTNCHC")); + if (pPSHBTNCHC) { + XI5250EmulatorExt emext = getEmulatorExt(); + PanelsDispatcher disp = new PanelsDispatcher(); + disp.setEmulator(emext); + new PSHBTNCHCHandler(disp); + } + } + + /** + */ + public final XI5250EmulatorExt getEmulatorExt() { + return (XI5250EmulatorExt)super.getEmulator(); + } + + ////// + + private static class PanelsDispatcher extends XI5250PanelsDispatcher { + + private XI5250PanelHandler ivHandler; + + @Override + public synchronized void addPanelHandler(XI5250PanelHandler panel) { + if (ivHandler != null) + throw new IllegalArgumentException("Handler already setted"); + ivHandler = panel; + } + + @Override + protected synchronized XI5250PanelHandler getCurrentPanelHandler() { + return ivHandler; + } + + @Override + public synchronized void removePanelHandler(XI5250PanelHandler panel) { + if (ivHandler != panel) + throw new IllegalArgumentException("Not the registered handler " + panel); + ivHandler = null; + } + } +} diff --git a/net/infordata/em/tn5250ext/XI5250EmulatorExt.java b/net/infordata/em/tn5250ext/XI5250EmulatorExt.java new file mode 100644 index 0000000..376ab24 --- /dev/null +++ b/net/infordata/em/tn5250ext/XI5250EmulatorExt.java @@ -0,0 +1,147 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 09/09/97 rel. 1.04c- creation. + 24/09/97 rel. 1.05 - DNCX project. + *** + 10/07/98 rel. _.___- Swing, JBuilder2 e VSS. +*/ + + +package net.infordata.em.tn5250ext; + + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; + +import net.infordata.em.tn5250.XI5250Emulator; + + +/** + * THE 5250 EMULATOR extension. + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XI5250EmulatorExt extends XI5250Emulator implements Serializable { + + private static final long serialVersionUID = 1L; + + private boolean ivShowHints = true; + private boolean ivHintOnActiveField = false; + + transient private ArrayList ivDispatchers = + new ArrayList(); + + public static final String SHOW_HINTS = "showHints"; + public static final String HINT_ON_ACTIVE_FIELD = "hintOnActiveField"; + + + /** + * Default contructor. + */ + public XI5250EmulatorExt() { + } + + + /** + */ + protected synchronized void addDispatcher(XI5250PanelsDispatcher aDispatcher) { + if (!ivDispatchers.contains(aDispatcher)) + ivDispatchers.add(aDispatcher); + } + + + /** + */ + protected synchronized void removeDispatcher(XI5250PanelsDispatcher aDispatcher) { + ivDispatchers.remove(aDispatcher); + } + + + /** + */ + protected synchronized void refreshHint() { + XI5250PanelsDispatcher disp; + XI5250PanelHandler hndl; + for (Iterator en = ivDispatchers.iterator(); en.hasNext(); ) { + disp = en.next(); + hndl = disp.getCurrentPanelHandler(); + + if (hndl != null) + hndl.refreshHint(); + } + } + + + /** + * Enables or disables the fields hints showing (default true). + */ + public void setShowHints(boolean aFlag) { + if (ivShowHints == aFlag) + return; + + boolean oldShowHints = ivShowHints; + ivShowHints = aFlag; + + //!!1.04d refreshHint(); + + firePropertyChange(SHOW_HINTS, oldShowHints, ivShowHints); + } + + + /** + */ + public boolean getShowHints() { + return ivShowHints; + } + + + /** + */ + public void setHintOnActiveField(boolean aFlag) { + if (ivHintOnActiveField == aFlag) + return; + + boolean oldHintOnActiveField = ivHintOnActiveField; + ivHintOnActiveField = aFlag; + + //!!1.04d refreshHint(); + + firePropertyChange(HINT_ON_ACTIVE_FIELD, + oldHintOnActiveField, ivHintOnActiveField); + } + + + /** + */ + public boolean isHintOnActiveField() { + return ivHintOnActiveField; + } + + +// /** +// */ +// void writeObject(ObjectOutputStream oos) throws IOException { +// oos.defaultWriteObject(); +// } +// +// void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { +// ois.defaultReadObject(); +// } +} diff --git a/net/infordata/em/tn5250ext/XI5250EmulatorExtBeanInfo.java b/net/infordata/em/tn5250ext/XI5250EmulatorExtBeanInfo.java new file mode 100644 index 0000000..406517d --- /dev/null +++ b/net/infordata/em/tn5250ext/XI5250EmulatorExtBeanInfo.java @@ -0,0 +1,97 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 09/09/97 rel. 1.04c- creation. + 24/09/97 rel. 1.05 - DNCX project. + *** + 10/07/98 rel. _.___- Swing, JBuilder2 e VSS. +*/ + + +package net.infordata.em.tn5250ext; + + +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.beans.SimpleBeanInfo; + + +public class XI5250EmulatorExtBeanInfo extends SimpleBeanInfo { + Class beanClass = XI5250EmulatorExt.class; + String iconColor16x16Filename; + String iconColor32x32Filename; + String iconMono16x16Filename; + String iconMono32x32Filename; + + + public XI5250EmulatorExtBeanInfo() { + } + + @Override + public PropertyDescriptor[] getPropertyDescriptors() { + try { + PropertyDescriptor _hintOnActiveField = + new PropertyDescriptor("hintOnActiveField", beanClass, + "isHintOnActiveField", "setHintOnActiveField"); + + PropertyDescriptor _showHints = + new PropertyDescriptor("showHints", beanClass, "getShowHints", + "setShowHints"); + + PropertyDescriptor[] pds = new PropertyDescriptor[] { + _hintOnActiveField, + _showHints, + }; + return pds; + } + catch (IntrospectionException ex) { + ex.printStackTrace(); + return null; + } + } + + @Override + public java.awt.Image getIcon(int iconKind) { + switch (iconKind) { + case BeanInfo.ICON_COLOR_16x16: + return iconColor16x16Filename != null ? loadImage(iconColor16x16Filename) : null; + case BeanInfo.ICON_COLOR_32x32: + return iconColor32x32Filename != null ? loadImage(iconColor32x32Filename) : null; + case BeanInfo.ICON_MONO_16x16: + return iconMono16x16Filename != null ? loadImage(iconMono16x16Filename) : null; + case BeanInfo.ICON_MONO_32x32: + return iconMono32x32Filename != null ? loadImage(iconMono32x32Filename) : null; + } + return null; + } + + @Override + public BeanInfo[] getAdditionalBeanInfo() { + Class superclass = beanClass.getSuperclass(); + try { + BeanInfo superBeanInfo = Introspector.getBeanInfo(superclass); + return new BeanInfo[] { superBeanInfo }; + } + catch (IntrospectionException ex) { + ex.printStackTrace(); + return null; + } + } +} + diff --git a/net/infordata/em/tn5250ext/XI5250FieldConnection.java b/net/infordata/em/tn5250ext/XI5250FieldConnection.java new file mode 100644 index 0000000..9ebca00 --- /dev/null +++ b/net/infordata/em/tn5250ext/XI5250FieldConnection.java @@ -0,0 +1,96 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 10/07/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250ext; + + +import java.awt.Component; +import java.awt.Point; +import java.awt.Rectangle; + +import net.infordata.em.crt5250.XI5250Field; + + +/** + * Connect an AWT Component to a XI5250Field + * moving and resizing the Component as the field grows or shrinks. + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XI5250FieldConnection { + private Component ivComponent; + + private int ivColsDelta; + private int ivRowsDelta; + private int ivNCols; + private int ivNRows; + + + /** + */ + public XI5250FieldConnection(XI5250PanelHandler aPanelHndl, XI5250Field aField, + Component aComponent, + int aColsDelta, int aRowsDelta, + int aNCols, int aNRows) { + ivColsDelta = aColsDelta; + ivRowsDelta = aRowsDelta; + ivNCols = aNCols; + ivNRows = aNRows; + ivComponent = aComponent; + aPanelHndl.connect(aField, this); + } + + + /** + */ + public XI5250FieldConnection(XI5250PanelHandler aPanelHndl, + XI5250Field aField, + Component aComponent) { + this(aPanelHndl, aField, aComponent, 0, 0, 1, 1); + } + + + /** + */ + protected void recalcBounds(XI5250EmulatorExt aEm, XI5250Field aField) { + Rectangle[] rcts = aField.getRows(); + // use the last row + Rectangle rct = rcts[rcts.length - 1]; + + int bufPos = aEm.toLinearPos(rct.x + rct.width, rct.y); + bufPos += aEm.toLinearPos(ivColsDelta, ivRowsDelta); + + Point pt = aEm.toPoints(aEm.toColPos(bufPos), aEm.toRowPos(bufPos)); + + ivComponent.setBounds(pt.x, pt.y, + ivNCols * aEm.getCharSize().width, + ivNRows * aEm.getCharSize().height); + } + + + /** + */ + public final Component getComponent() { + return ivComponent; + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250ext/XI5250PanelConnection.java b/net/infordata/em/tn5250ext/XI5250PanelConnection.java new file mode 100644 index 0000000..809354a --- /dev/null +++ b/net/infordata/em/tn5250ext/XI5250PanelConnection.java @@ -0,0 +1,81 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 10/07/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250ext; + + +import java.awt.Component; +import java.awt.Point; + + +/** + * Connect an AWT Component to the XI5250EmulatorExt panel + * moving and resizing the Component as the font size changes. + *
+ *   new XI5250PanelConnection(this, new XIImage(logo), 29, 12, 20, 10);
+ * 
+ * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XI5250PanelConnection { + + private Component ivComponent; + + private int ivCol; + private int ivRow; + private int ivNCols; + private int ivNRows; + + + /** + */ + public XI5250PanelConnection(XI5250PanelHandler aPanelHndl, + Component aComponent, + int aCol, int aRow, + int aNCols, int aNRows) { + ivCol = aCol; + ivRow = aRow; + ivNCols = aNCols; + ivNRows = aNRows; + ivComponent = aComponent; + aPanelHndl.connect(this); + } + + + /** + */ + protected void recalcBounds(XI5250EmulatorExt aEm) { + Point pt = aEm.toPoints(ivCol, ivRow); + + ivComponent.setBounds(pt.x, pt.y, + ivNCols * aEm.getCharSize().width, + ivNRows * aEm.getCharSize().height); + } + + + /** + */ + public final Component getComponent() { + return ivComponent; + } +} \ No newline at end of file diff --git a/net/infordata/em/tn5250ext/XI5250PanelHandler.java b/net/infordata/em/tn5250ext/XI5250PanelHandler.java new file mode 100644 index 0000000..8a60649 --- /dev/null +++ b/net/infordata/em/tn5250ext/XI5250PanelHandler.java @@ -0,0 +1,885 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 14/05/97 rel. 0.96d- uses VALIDATE_PENDING. + 30/05/97 rel. 1.00 - . + 24/09/97 rel. 1.05 - DNCX project (PopupMenu). + 06/10/97 rel. 1.05b- Hint window is forced to stay into the screen + boundaries. + *** + 10/07/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250ext; + + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.swing.JPopupMenu; + +import net.infordata.em.crt5250.XI5250CrtAdapter; +import net.infordata.em.crt5250.XI5250CrtEvent; +import net.infordata.em.crt5250.XI5250Field; + + +/** + * Abstract base class for all classes created to control 5250 panels. + * + *
+ * example:
+ *
+ *  //
+ *  class XARegistrazioniIVA extends XI5250PanelHandler {
+ *    XI5250Field ivCtv;
+ *    XI5250Field ivCambio;
+ *    XI5250Field ivDivisa;
+ *
+ *    //
+ *    class FieldAdapter extends XI5250FieldAdapter {
+ *      public void valueChanged(XI5250FieldEvent e) {
+ *        // Has the divisa field value changed ??
+ *        if (e.getField() == ivDivisa)
+ *          handleDivisa();
+ *      }
+ *    }
+ *
+ *    //
+ *    public XARegistrazioniIVA(XI5250PanelsDispatcher aPanelsDisp,
+ *                              String aKey) {
+ *      super(aPanelsDisp, aKey);
+ *    }
+ *
+ *    //
+ *    public boolean detailedTest() {
+ *      return checkField(getFieldNextTo("Causale"), 3) &&
+ *             checkField(getFieldNextTo("Cliente"), 6);
+ *    }
+ *
+ *    //
+ *    public void start() {
+ *      // Dt reg
+ *      XI5250Field fld = getFieldNextTo("Dt reg");
+ *      if (checkField(fld, 8)) {
+ *        XIButton btn = new XICalendarButton(fld, "dd/MM/yy");
+ *        new XI5250FieldConnection(this, fld, btn);
+ *
+ *        setFieldHint(fld, new XIHint("The posting date"));
+ *      }
+ *
+ *      // cliente
+ *      fld = getFieldNextTo("Cliente");
+ *      if (checkField(fld, 6)) {
+ *        XIButton btn = new XIButton();
+ *        new XI5250FieldConnection(this, fld, btn);
+ *      }
+ *
+ *      // Data doc.
+ *      fld = getFieldNextTo("Data doc.");
+ *      if (checkField(fld, 6)) {
+ *        XIButton btn = new XICalendarButton(fld, "ddMMyy");
+ *        new XI5250FieldConnection(this, fld, btn);
+ *      }
+ *
+ *      // Divisa
+ *      fld = getFieldNextTo("Divisa");
+ *      if (checkField(fld, 4)) {
+ *        ivDivisa = fld;
+ *        ivDivisa.addFieldListener(new FieldAdapter());
+ *      }
+ *
+ *      // Cambio
+ *      fld = getFieldNextTo("Cambio");
+ *      if (checkField(fld, 8)) {
+ *        ivCambio = fld;
+ *      }
+ *
+ *      // Ctv
+ *      fld = getFieldNextTo("Ctv");
+ *      if (checkField(fld, 11)) {
+ *        ivCtv = fld;
+ *      }
+ *
+ *      //
+ *      if (ivDivisa != null)
+ *        handleDivisa();
+ *    }
+ *
+ *    //
+ *    public void stop() {
+ *      ivCtv = null;
+ *      ivCambio = null;
+ *      ivDivisa = null;
+ *    }
+ *
+ *    //
+ *    protected void handleDivisa() {
+ *      String  str = ivDivisa.getTrimmedString();
+ *      boolean enable = !(str.equals("") || str.equals("*"));
+ *
+ *      if (ivCambio != null)
+ *        ivCambio.setEnabled(enable);
+ *
+ *      if (ivCtv != null)
+ *        ivCtv.setEnabled(enable);
+ *    }
+ *  }
+ *
+ * 
+ * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public abstract class XI5250PanelHandler { + + private String ivTitle; + + transient private XI5250PanelsDispatcher ivDispatcher; + + // Hash table used to mantain relations between XI5250Fields and + // XI5250FieldConnections + transient private HashMap ivConnections; + + // Hash table used to mantain relations between Components and + // XI5250PanelConnections + transient private HashMap ivPanelConnections; + + transient private int ivInvalidateCount; + + transient private CrtAdapter ivCrtAdapter; + + //!!1.00 + transient private HashMap ivHints; + transient private XIHintWindow ivHintWindow; + transient private javax.swing.Timer ivHintTimer; + transient private int ivHintDelay = 1000; + + //!!1.04d + transient private XIHint ivLastHint; + transient private HintThread ivHintThread; + + //!!V-23/09/97 + transient private HashMap ivPopupMenus; + transient private ArrayList ivPopupList; + transient private MouseListener ivMouseListener; + + + ////////////////////////////////////////////////////////////////////////////// + + /** + */ + transient private ComponentListener ivHintListener = new ComponentAdapter() { + @Override + public void componentHidden(ComponentEvent aEvent) { + // ivHintWindow potrebbe essere null + ((XIHintWindow)aEvent.getSource()). + removeComponentListener(ivHintListener); + XI5250PanelHandler.this.hideHint(); + } + }; + + + ////////////////////////////////////////////////////////////////////////////// + + /** + */ + class EmulatorMouseListener extends MouseAdapter { + @Override + public void mousePressed(MouseEvent e) { + XI5250PanelHandler.this.mousePressed(e); + } + + @Override + public void mouseReleased(MouseEvent e) { + XI5250PanelHandler.this.mouseReleased(e); + } + }; + + + ////////////////////////////////////////////////////////////////////////////// + + /** + * Registers itself in the provided XI5250PanelsDispatcher. + */ + public XI5250PanelHandler(XI5250PanelsDispatcher aPanelDisp) { + this(aPanelDisp, null); + } + + /** + * Registers itself in the provided XI5250PanelsDispatcher. + * @param aPanelTitle is the string that is used by {@link XI5250SimplePanelsDispatcher} + * in the first step of the panel handler search. + * + * @see XI5250PanelsDispatcher#addPanelHandler + * @see XI5250PanelsDispatcher#getCurrentPanelHandler + */ + public XI5250PanelHandler(XI5250PanelsDispatcher aPanelDisp, + String aPanelTitle) { + ivDispatcher = aPanelDisp; + ivTitle = aPanelTitle; + + ivDispatcher.addPanelHandler(this); + } + + + /** + * Returns the related XI5250EmulatorExt. + */ + public final XI5250EmulatorExt getEmulator() { + return ivDispatcher.getEmulator(); + } + + + /** + * Returns a Map that can be used to store data shared by different + * XI5250Panel instances. + * @see XI5250PanelsDispatcher#getSharedData + */ + public Map getSharedData() { + return ivDispatcher.getSharedData(); + } + + + /** + */ + public String getTitle() { + return ivTitle; + } + + + /** + * Returns the Window containing the given component. + */ + public static Window getWindow(Component aComp) { + Component comp = aComp; + while (comp != null && !(comp instanceof Window)) + comp = comp.getParent(); + return (Window)comp; + } + + + /** + * Just to make {@link #detailedTest()} public without breaking compatibility with the past. + */ + public final boolean panelMatched() { + return detailedTest(); + } + + + /** + * Check if this is really the panel we are waiting for. + * Normally it' s enough to check the presence and length of a couple of + * fields. + *
+   *    //
+   *    public boolean detailedTest() {
+   *      return checkField(getFieldNextTo("Causale"), 3) &&
+   *             checkField(getFieldNextTo("Cliente"), 6);
+   *    }
+   * 
+ */ + protected abstract boolean detailedTest(); + + + /** + * Begin handling the 5250 panel. + */ + protected abstract void start(); + + + /** + * Stop handling the 5250 panel. + * All references to XI5250Fields must be initialized to null. + */ + protected abstract void stop(); + + + /** + * Called just after that the 5250 panel contents has been sended to host. + * @param anAidCode the aid code (ie XI5250Emulator.AID_F3, ...) + */ + protected void dataSended(byte anAidCode) { + } + + + /** + */ + final void startInternal() { + XI5250EmulatorExt em = getEmulator(); + + ivCrtAdapter = new CrtAdapter(); + em.addCrtListener(ivCrtAdapter); + + em.addMouseListener(ivMouseListener = new EmulatorMouseListener()); + + start(); + + validate(); + } + + + /** + * calls stop() and then removes all added components and XI5250Connections + */ + final void stopInternal() { + try { + stop(); + } + finally { + //!!1.04d + if (ivHintThread != null) { + ivHintThread.interrupt(); + ivHintThread = null; + } + + hideHint(); + ivHints = null; + + XI5250EmulatorExt em = getEmulator(); + + em.removeMouseListener(ivMouseListener); + + em.removeCrtListener(ivCrtAdapter); + + // remove all XI5250PanelConnections + if (ivPanelConnections != null) { + XI5250PanelConnection c; + for (Iterator e = ivPanelConnections.values().iterator(); + e.hasNext(); ) { + c = e.next(); + em.remove(c.getComponent()); + } + ivPanelConnections = null; + } + + // remove all XI5250FieldConnections + if (ivConnections != null) { + XI5250FieldConnection c; + for (Iterator e = ivConnections.values().iterator(); + e.hasNext(); ) { + c = e.next(); + em.remove(c.getComponent()); + } + ivConnections = null; + } + + // remove all PopupMenu + if (ivPopupList != null) { + JPopupMenu c; + for (Iterator e = ivPopupList.iterator(); e.hasNext(); ) { + c = e.next(); + em.remove(c); + } + ivPopupMenus = null; + ivPopupList = null; + } + } + } + + + /** + * It is used by XI5250FieldConnection to register itself to be called when a + * layout validate is required + */ + void connect(XI5250Field aField, XI5250FieldConnection aConnection) { + XI5250EmulatorExt em = getEmulator(); + + if (ivConnections == null) + ivConnections = new HashMap(); + + XI5250FieldConnection c = + ivConnections.put(aField, aConnection); + + if (c != null) + em.remove(c.getComponent()); + + em.add(aConnection.getComponent()); + + invalidate(); + } + + + /** + * It is used by XI5250PanelConnection to register itself to be called when a + * layout validate is required + */ + void connect(XI5250PanelConnection aConnection) { + XI5250EmulatorExt em = getEmulator(); + + if (ivPanelConnections == null) + ivPanelConnections = new HashMap(); + + XI5250PanelConnection c = (XI5250PanelConnection) + ivPanelConnections.put(aConnection.getComponent(), + aConnection); + + if (c == null) + em.add(aConnection.getComponent()); + + invalidate(); + } + + + /** + * @see #validate + */ + public void invalidate() { + ++ivInvalidateCount; + } + + + /** + * Implements a mechanism like the one present in AWT Container classes, but + * instead of using a LayoutManager it uses XI5250PanelConnection and + * XI5250FieldConnection to place components on the panel. + */ + public void validate() { + if (ivInvalidateCount <= 0) + return; + + ivInvalidateCount = 0; + + XI5250EmulatorExt em = getEmulator(); + + synchronized (em.getTreeLock()) { + // validate all panel-connections + if (ivPanelConnections != null) { + XI5250PanelConnection conn; + for (Iterator en = ivPanelConnections.values().iterator(); + en.hasNext(); ) { + conn = en.next(); + conn.recalcBounds(em); + } + } + + // validate all field-connections + if (ivConnections != null) { + XI5250Field fld; + XI5250FieldConnection conn; + for (Iterator en = ivConnections.keySet().iterator(); en.hasNext(); ) { + fld = en.next(); + conn = ivConnections.get(fld); + conn.recalcBounds(em, fld); + } + } + } + } + + + /** + * Called when the input cursor enters a field area. + */ + protected void fieldActivated(XI5250Field aField) { + /*!!1.04d + if (getEmulator().isHintOnActiveField()) + setCurrentHint(aField); + */ + } + + + /** + * Called when the cursor exits from field area. + */ + protected void fieldDeactivated(XI5250Field aField) { + /*!!1.04d + if (getEmulator().isHintOnActiveField()) + setCurrentHint(null); + */ + } + + + /** + * Called when the font size of the emulator changes. + * Forces a validate. + */ + protected void sizeChanged() { + invalidate(); + validate(); + + hideHint(); + } + + + /** + * Called just before processing a key event. + */ + protected void keyEvent(KeyEvent e) { + } + + + /** + * Called to activate an hint over a field. + */ + /*!!1.04d + protected void setCurrentHint(XI5250Field aField) + { + XIHint hint = (aField == null || ivHints == null) ? null : + (XIHint)ivHints.get(aField); + + if (hint != null) + showHint(hint, aField); + else + hideHint(); + } + */ + + + /** + */ + protected void refreshHint() { + if (!getEmulator().hasFocus()) + hideHint(); + + // campo attuale + XI5250Field field = ((!getEmulator().getShowHints()) ? + null : + getEmulator().isHintOnActiveField() ? + getEmulator().getCurrentField() : + getEmulator().getFieldUnderMouse()); + + // hint attuale + XIHint hint = (field == null || ivHints == null) ? + null : + (XIHint)ivHints.get(field); + + if (hint == ivLastHint) + return; + + if (hint != null) + showHint(hint, field); + else + hideHint(); + + ivLastHint = hint; + } + + + /** + */ + private void showHint(XIHint aHint, XI5250Field aField) { + synchronized (ivDispatcher.getTreeLock()) { + hideHint(); + + if (!getEmulator().getShowHints()) + return; + + ivHintWindow = new XIHintWindow(aHint, getEmulator()); + } + int delay = ivHintDelay; + if (getEmulator().isHintOnActiveField()) + delay /= 2; + + ivHintTimer = new javax.swing.Timer(delay, new HintTimer(aField)); + ivHintTimer.setRepeats(false); + ivHintTimer.start(); + } + + + /** + */ + private void hideHint() { + synchronized (ivDispatcher.getTreeLock()) { + ivLastHint = null; //!!1.04d + + if (ivHintTimer != null) { + ivHintTimer.stop(); + ivHintTimer = null; + } + + if (ivHintWindow != null) { + ivHintWindow.setVisible(false); + ivHintWindow = null; + } + } + } + + + /** + * Called when the mouse cursor enters the field area. + */ + protected void mouseEntersField(XI5250Field aField) { + /*!!1.04d + if (!getEmulator().isHintOnActiveField()) + setCurrentHint(aField); + */ + } + + + /** + * Called when the mouse cursor exits from field area. + */ + protected void mouseExitsField(XI5250Field aField) { + /*!!1.04d + if (!getEmulator().isHintOnActiveField()) + setCurrentHint(null); + */ + } + + + /** + * Sets the field relative XIHint (null to remove). + *
+   * ex:
+   *   setFieldHint(getFieldNextTo("Cust."),
+   *                new XIHint("The new customer"));
+   * 
+ */ + public void setFieldHint(XI5250Field aField, XIHint aHint) { + if (aField == null) + return; + + if (ivHints == null) { + ivHints = new HashMap(); + } + + if (aHint == null) + ivHints.remove(aField); + else + ivHints.put(aField, aHint); + + if (!ivHints.isEmpty()) { + if (ivHintThread == null) { + //!!1.04d + ivHintThread = new HintThread(); + ivHintThread.setPriority(Thread.NORM_PRIORITY - 1); + ivHintThread.start(); + } + } + else { + if (ivHintThread != null) { + ivHintThread.interrupt(); + ivHintThread = null; + } + } + } + + + /** + * Sets the field relative JPopupMenu (null to remove). + */ + public void setFieldPopupMenu(XI5250Field aField, JPopupMenu aPopupMenu) { + if (aField == null) + return; + + if (ivPopupMenus == null) + ivPopupMenus = new HashMap(); + + if (ivPopupList == null) + ivPopupList = new ArrayList(10); + + if (aPopupMenu == null) + ivPopupMenus.remove(aField); + else + ivPopupMenus.put(aField, aPopupMenu); + + if (!ivPopupList.contains(aPopupMenu)) { + ivPopupList.add(aPopupMenu); + getEmulator().add(aPopupMenu); + } + } + + + /** + */ + protected void mousePressed(MouseEvent e) { + } + + + /** + */ + protected void mouseReleased(MouseEvent e) { + XI5250Field fld = getEmulator().getFieldUnderMouse(); + if (fld != null && ivPopupMenus != null && + e.isPopupTrigger()) { + JPopupMenu pop = (JPopupMenu)ivPopupMenus.get(fld); + if (pop != null) + pop.show(getEmulator(), e.getX(), e.getY()); + } + } + + + /** + */ + public String getString(int col, int row, int nChars) { + return getEmulator().getString(col, row, nChars); + } + + + /** + * Returns an Enumeration of all the fields present on the panel. + */ + public final List getFields() { + return getEmulator().getFields(); + } + + + /** + * Returns the field present at the given position (null if none). + */ + public final XI5250Field getFieldFromPos(int aCol, int aRow) { + return getEmulator().getFieldFromPos(aCol, aRow); + } + + + /** + * Returns the field next to the given label (null if none). + */ + public final XI5250Field getFieldNextTo(String aLabel) { + return getEmulator().getFieldNextTo(aLabel); + } + + + /** + * Verifies the presence of the given label. + */ + public final boolean isLabelPresent(String aLabel) { + return (getEmulator().getLabelLinearPos(aLabel) >= 0); + } + + + /** + * Checks that: the field is different from null, it isn' t a bypass field + * and it has the required length. + */ + public boolean checkField(XI5250Field aField, int aLen) { + return (aField != null && !aField.isOrgBypassField() && + aField.getLength() == aLen); + } + + + ////////////////////////////////////////////////////////////////////////////// + + /** + */ + class CrtAdapter extends XI5250CrtAdapter { + + @Override + public void fieldActivated(XI5250CrtEvent e) { + XI5250PanelHandler.this.fieldActivated(e.getField()); + } + + @Override + public void fieldDeactivated(XI5250CrtEvent e) { + XI5250PanelHandler.this.fieldDeactivated(e.getField()); + } + + @Override + public void sizeChanged(XI5250CrtEvent e) { + XI5250PanelHandler.this.sizeChanged(); + } + + @Override + public void keyEvent(XI5250CrtEvent e) { + XI5250PanelHandler.this.keyEvent(e.getKeyEvent()); + } + + @Override + public void mouseEntersField(XI5250CrtEvent e) { + XI5250PanelHandler.this.mouseEntersField(e.getField()); + } + + @Override + public void mouseExitsField(XI5250CrtEvent e) { + XI5250PanelHandler.this.mouseExitsField(e.getField()); + } + } + + + ////////////////////////////////////////////////////////////////////////////// + + /** + */ + class HintTimer implements ActionListener { + + private XI5250Field ivField; + + public HintTimer(XI5250Field aField) { + ivField = aField; + } + + public void actionPerformed(ActionEvent anEvent) { + synchronized (ivDispatcher.getTreeLock()) { + if (ivHintWindow != null && getEmulator().hasFocus()) { + { + Point pt = getEmulator().getLocationOnScreen(); + Rectangle[] rcts = ivField.getRowsRects(); + Rectangle rct = rcts[rcts.length - 1]; + + pt.translate(rct.x, rct.y + rct.height); + + pt.translate(-4, 4); + + Dimension ss = Toolkit.getDefaultToolkit().getScreenSize(); + + //!!1.05b + pt.x = Math.max(0, Math.min(ss.width - ivHintWindow.getSize().width, pt.x)); + pt.y = Math.max(0, Math.min(ss.height - ivHintWindow.getSize().height, pt.y)); + + ivHintWindow.setLocation(pt.x, pt.y); + } + + ivHintWindow.setVisible(true); + // potrebbe non essere visibile (vedi XIHintWindow) + if (!ivHintWindow.isVisible()) + hideHint(); + else + ivHintWindow.addComponentListener(ivHintListener); + } + } + } + } + + + ////////////////////////////////////////////////////////////////////////////// + + /** + */ + class HintThread extends Thread { + @Override + public void run() { + while (true) { + try { + Thread.sleep(250); + } + catch (InterruptedException ex) { + break; + } + + refreshHint(); + } + } + } +} diff --git a/net/infordata/em/tn5250ext/XI5250PanelsDispatcher.java b/net/infordata/em/tn5250ext/XI5250PanelsDispatcher.java new file mode 100644 index 0000000..c96c0dc --- /dev/null +++ b/net/infordata/em/tn5250ext/XI5250PanelsDispatcher.java @@ -0,0 +1,223 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 06/08/97 rel. 1.00a- bug fix. + 06/10/97 rel. 1.05b- newPanelReceived event sended also in the PRE_HELP state. + *** + 10/07/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250ext; + + +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Logger; + +import net.infordata.em.tn5250.XI5250EmulatorAdapter; +import net.infordata.em.tn5250.XI5250EmulatorEvent; + + +/** + * Maintains a set of XI5250PanelHandler and activates them when the related 5250 + * screen (or panel) is received. + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public abstract class XI5250PanelsDispatcher { + + protected static final Logger LOGGER = Logger.getLogger(XI5250PanelsDispatcher.class.getName()); + + transient private XI5250EmulatorExt ivEm; + transient private EmulatorAdapter ivEmulatorAdapter; + + /** + * The current XI5250PanelHandler. + */ + transient private XI5250PanelHandler ivPanelHndl; + + transient private HashMap ivSharedData; + + + /** + * Creates a XI5250PanelsDispatcher. + */ + public XI5250PanelsDispatcher() { + } + + + /** + * Creates a XI5250PanelsDispatcher to handle panels of the given + * XI5250Emulator instance. + */ + public XI5250PanelsDispatcher(XI5250EmulatorExt aEmulator) { + this(); + setEmulator(aEmulator); + } + + + /** + */ + public synchronized void setEmulator(XI5250EmulatorExt aEmulator) { + if (ivEm == aEmulator) + return; + + if (ivEm != null) { + setPanelHndl(null); //!!1.00a + ivEm.removeEmulatorListener(ivEmulatorAdapter); + ivEm.removeDispatcher(this); + } + + ivEmulatorAdapter = null; + ivEm = aEmulator; + + if (ivEm != null) { + ivEm.addDispatcher(this); + ivEm.addEmulatorListener((ivEmulatorAdapter = new EmulatorAdapter())); + } + } + + /** + */ + public final XI5250EmulatorExt getEmulator() { + return ivEm; + } + + public final Object getTreeLock() { + return ivEm.getTreeLock(); + } + + /** + * Adds the given XI5250PanelHandler instance to the list of panel handlers + * waiting to be activated. + */ + public abstract void addPanelHandler(XI5250PanelHandler aPanel); + + /** + * Removes the panel handler. + */ + public abstract void removePanelHandler(XI5250PanelHandler aPanel); + + /** + * Searches the XI5250PanelHandler instace related to the current 5250 panel.
+ * @see XI5250PanelHandler#detailedTest + */ + protected abstract XI5250PanelHandler getCurrentPanelHandler(); + + /** + * Returns a Map that can be used to store data shared by different + * XI5250Panel instances. + */ + public final Map getSharedData() { + if (ivSharedData == null) + ivSharedData = new HashMap(); + + return ivSharedData; + } + + + /** + * A new panel has been received so try to find the relative + * XI5250PanelHandler using getCurrentPanelHandler method. + * + * @see #getCurrentPanelHandler + */ + protected synchronized void newPanelReceived() { + if (ivEm.getState() == XI5250EmulatorExt.ST_NORMAL_UNLOCKED || + ivEm.getState() == XI5250EmulatorExt.ST_PRE_HELP) { //!!1.05b + XI5250PanelHandler panelHndl = getCurrentPanelHandler(); + + if (panelHndl != null) + setPanelHndl(panelHndl); + } + } + + + /** + */ + private void fieldsRemoved() { + // destroy old panel handler + setPanelHndl(null); + } + + + /** + */ + private void dataSended(byte anAidCode) { + if (ivPanelHndl != null) + ivPanelHndl.dataSended(anAidCode); + } + + + /** + * Used to set the current XI5250PanelHandler and to stop the previous one. + */ + protected void setPanelHndl(XI5250PanelHandler aPanelHndl) { + if (aPanelHndl == ivPanelHndl) + return; + + if (ivPanelHndl != null) + ivPanelHndl.stopInternal(); + + ivPanelHndl = aPanelHndl; + + if (ivPanelHndl != null) + ivPanelHndl.startInternal(); + } + + + /** + * Returns the current active panel handler (none if null) + */ + protected XI5250PanelHandler getCurrentPanelHndl() { + return ivPanelHndl; + } + + + ////////////////////////////////////////////////////////////////////////////// + + /** + */ + class EmulatorAdapter extends XI5250EmulatorAdapter { + + @Override + public void stateChanged(XI5250EmulatorEvent e) { + } + + @Override + public void disconnected(XI5250EmulatorEvent e) { + XI5250PanelsDispatcher.this.fieldsRemoved(); + } + + @Override + public void newPanelReceived(XI5250EmulatorEvent e) { + XI5250PanelsDispatcher.this.newPanelReceived(); + } + + @Override + public void fieldsRemoved(XI5250EmulatorEvent e) { + XI5250PanelsDispatcher.this.fieldsRemoved(); + } + + @Override + public void dataSended(XI5250EmulatorEvent e) { + XI5250PanelsDispatcher.this.dataSended(e.getAidCode()); + } + } +} diff --git a/net/infordata/em/tn5250ext/XI5250SimplePanelsDispatcher.java b/net/infordata/em/tn5250ext/XI5250SimplePanelsDispatcher.java new file mode 100644 index 0000000..3aa230a --- /dev/null +++ b/net/infordata/em/tn5250ext/XI5250SimplePanelsDispatcher.java @@ -0,0 +1,196 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 06/08/97 rel. 1.00a- bug fix. + 06/10/97 rel. 1.05b- newPanelReceived event sended also in the PRE_HELP state. + *** + 10/07/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250ext; + + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.StringTokenizer; +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.infordata.em.tn5250.XI5250Emulator; + + +/** + * Mantains a set of XI5250PanelHandler and activates them when the related 5250 + * screen (or panel) is received. + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XI5250SimplePanelsDispatcher extends XI5250PanelsDispatcher { + + private static final Logger LOGGER = Logger.getLogger(XI5250SimplePanelsDispatcher.class.getName()); + + transient private static String DELIMITERS; + + /** + * Contains relations between XI5250PanelHandler and a tokenized version of + * the related 5250 screen first line. + * It really contains Vectors of XI5250PanelHandler (one to many relation) + */ + transient private HashMap> ivPanels; + + /** + */ + static { + DELIMITERS = ""; + for (int i = 0; i <= 32; i++) + DELIMITERS += (char)i; + } + + + /** + * Creates a XI5250SimplePanelsDispatcher. + */ + public XI5250SimplePanelsDispatcher() { + } + + + /** + * Creates a XI5250SimplePanelsDispatcher to handle panels of the given + * XI5250Emulator instance. + */ + public XI5250SimplePanelsDispatcher(XI5250EmulatorExt aEmulator) { + super(aEmulator); + } + + + /** + */ + private static String calcKey(String str, int excludeTokens) { + String res = ""; + StringTokenizer st = new StringTokenizer(str, DELIMITERS); + int n = Math.max(0, st.countTokens() - excludeTokens); + + for (int i = n - 1; i>= 0; i--) + res += " " + st.nextToken(); + + return res; + } + + + /** + * Adds the given XI5250PanelHandler instance to the list of panel handlers + * waiting to be activated. + */ + @Override + public synchronized void addPanelHandler(XI5250PanelHandler aPanel) { + if (ivPanels == null) + ivPanels = new HashMap>(); + + String key = calcKey(aPanel.getTitle(), 0); + + if (LOGGER.isLoggable(Level.FINER)) + LOGGER.finer("addPanelHandler: [" + key + "] " + aPanel); + + ArrayList vt = ivPanels.get(key); + + if (vt == null) { + vt = new ArrayList(10); + ivPanels.put(key, vt); + } + + if (!vt.contains(aPanel)) + vt.add(aPanel); + } + + + /** + * Removes the panel handler. + */ + @Override + public synchronized void removePanelHandler(XI5250PanelHandler aPanel) { + if (ivPanels == null) + return; + + String key = calcKey(aPanel.getTitle(), 0); + + if (LOGGER.isLoggable(Level.FINER)) + LOGGER.finer("removePanelHandler: [" + + key + "] " + aPanel); + + ArrayList vt = ivPanels.get(key); + + if (vt == null) + return; + + vt.remove(aPanel); + + if (vt.size() <= 0) + ivPanels.remove(key); + } + + + /** + * Searches the XI5250PanelHandler instace related to the current 5250 panel. + * Uses a two step search. + * First step is based on the contents of the first line present on screen + * then the detailedTest() method provided by XI5250PanelHandler is used. + * @see XI5250PanelHandler#detailedTest + */ + @Override + protected synchronized XI5250PanelHandler getCurrentPanelHandler() { + final XI5250Emulator em = getEmulator(); + String title = em.getString().substring(0, em.getCrtSize().width); + + int j = 0; + String key; + ArrayList vt; + + // first step + // find the XI5250PanelHandler vector using as key the tokenized title + // minus j ending tokens + do { + key = calcKey(title, j++); + vt = ivPanels.get(key); + + if (LOGGER.isLoggable(Level.FINER)) + LOGGER.finer("try [" + key + "] " + + ((vt != null) ? "found" : "next")); + } + while (vt == null && key != null && key.length() > 0); + + if (vt == null) + return null; + + XI5250PanelHandler panelHndl; + + // second step + for (int i = vt.size() - 1; i >= 0; i--) { + panelHndl = vt.get(i); + if (panelHndl.detailedTest()) { + // increase priority + vt.remove(panelHndl); + vt.add(panelHndl); + + return panelHndl; + } + } + + return null; + } +} diff --git a/net/infordata/em/tn5250ext/XIHint.java b/net/infordata/em/tn5250ext/XIHint.java new file mode 100644 index 0000000..3a10051 --- /dev/null +++ b/net/infordata/em/tn5250ext/XIHint.java @@ -0,0 +1,365 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 10/07/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250ext; + + +import java.awt.*; +import java.util.*; + +import javax.swing.*; + + +/** + * XIHint è la classe che descrive le caratteristiche di un Hint. + * Utilizzando i caratteri di controllo è possibile andare a capo inserire + * parole in grasseto, corsivo o entrambi. + * I caratteri di controllo sono: + * - \n : per andare a capo; + * - # : per inserire il testo in grassetto; + * - @ : per inserire il testo in corsivo; + * Per esempio questo testo è: #grassetto grassetto# @corsivo corsivo corsivo@\n + * a capo #@grassetto corsivo# corsivo@ normale. + * + * @see XIPanel + * @see XIHintWindow + */ +public class XIHint extends JComponent { + + private static final long serialVersionUID = 1L; + + // !!CM 06/08/97 +// private final static int DEFAULT_MAX_WIDTH = 300; + + private String ivText = null; + + // !!CM 06/08/97 + private int ivMaxWidth = 0; + + private Font ivFont = null; +// private FontMetrics ivFontMetrics = null; + + private int ivSpaceLine = 1; + private int ivSpaceUp = 1; + private int ivSpaceDown = 2; + private int ivSpaceRight = 2; + private int ivSpaceLeft = 4; + private int ivHeightShortText; + + private ArrayList ivVectorLines; + + // !!0.83/CM - 30/04/97 + private Font ivFBold; + private Font ivFItalic; + private Font ivFBoldItalic; + + + /** + */ + public XIHint(String aText) { + this(aText, 0); + } + + + /** + */ + public XIHint(String aText, int aWidth) { + ivText = aText; + + ivFont = new Font("Helvetica", Font.PLAIN, 11); + + ivFBold = new Font(ivFont.getName(), Font.BOLD, ivFont.getSize()); + ivFItalic = new Font(ivFont.getName(), Font.ITALIC, ivFont.getSize()); + ivFBoldItalic = new Font(ivFont.getName(), (Font.BOLD|Font.ITALIC), + ivFont.getSize()); + +// ivFontMetrics = Toolkit.getDefaultToolkit().getFontMetrics(ivFont); + + ivMaxWidth = aWidth; + + ivVectorLines = calculateLines(ivText, ivFont); + } + + + /** + */ + @Override + public Dimension getPreferredSize() { + int x = ivSpaceLeft; + int y = ivSpaceUp; + + x += getTextSize(ivFont).width + 2; + y = getTextSize(ivFont).height + 2; + + x += ivSpaceRight; + y += ivSpaceDown; + + return new Dimension(x, y); + } + + + /** + */ + public String getText() { + return ivText; + } + + + /** + */ + @Override + protected void paintComponent(Graphics aGraphics) { +// Dimension vDim = getSize(); +// String vText; + int vXPos = 0; + + aGraphics.setFont(ivFont); + aGraphics.setColor(Color.black); + + drawMultiLineString(aGraphics, ivVectorLines, + ivFont, vXPos + ivSpaceLeft, ivSpaceUp); + } + + + //!!CM 06/08/97 BEGIN + @SuppressWarnings("deprecation") + private int strWidth(String str, Font f) { + + return Toolkit.getDefaultToolkit().getFontMetrics(f).stringWidth(str); + } + + + @SuppressWarnings("deprecation") + private int strHeight(Font f) { + + return Toolkit.getDefaultToolkit().getFontMetrics(f).getHeight(); + } + + + @SuppressWarnings("deprecation") + private FontMetrics fontMetrics(Font f) { + + return Toolkit.getDefaultToolkit().getFontMetrics(f); + } + + + private Dimension textDim(ArrayList v, Font f) { + + int maxW = 0; + int lineW = 0; + int h = 0; + + boolean bold = false; + boolean italic = false; +// boolean boldItalic = false; + + + for (int i = 0; i < v.size(); i++) { + + String str = v.get(i); + + if (isEscapeChar(str, "#") || + isEscapeChar(str, "@")) { + + StringTokenizer st = new StringTokenizer(str, "#@", true); + + while (st.hasMoreElements()) { + String token = st.nextToken(); + + if ("#".equals(token)) { + if (bold) { + bold = false; + } + else { + bold = true; + } + } + else if ("@".equals(token)) { + if (italic) { + italic = false; + } + else { + italic = true; + } + } + else { + if (bold && italic) { + lineW += strWidth(token, ivFBoldItalic); + } + else if (bold) { + lineW += strWidth(token, ivFBold); + } + else if (italic) { + lineW += strWidth(token, ivFItalic); + } + else { + lineW += strWidth(token, f); + } + } + } + } + else { + lineW = strWidth(str, f); + } + + maxW = Math.max(maxW, lineW); + lineW = 0; + h += strHeight(f) - fontMetrics(f).getDescent() + ivSpaceLine; + } + + return new Dimension(maxW, h); + } + + + private boolean isEscapeChar(String text, String escChar) { + + if (escChar == null) { + return false; + } + + StringTokenizer st = new StringTokenizer(text, escChar, true); + + while (st.hasMoreTokens()) { + if (escChar.equals(st.nextToken())) { + return true; + } + } + + return false; + } + + + public Dimension getTextSize(Font f) { + + return new Dimension(textDim(ivVectorLines, f)); + } + + + private void drawMultiLineString(Graphics g, ArrayList v, + Font f, + int x, int y) { + + int xBegin = x; + + boolean bold = false; + boolean italic = false; +// boolean boldItalic = false; + + for (int i = 0; i < v.size(); i++) { + y += ivHeightShortText - fontMetrics(f).getDescent(); + StringTokenizer st = new StringTokenizer(v.get(i), "#@", true); + + while (st.hasMoreElements()) { + String token = st.nextToken(); + + if ("#".equals(token)) { + if (bold) { + bold = false; + } + else { + bold = true; + } + } + else if ("@".equals(token)) { + if (italic) { + italic = false; + } + else { + italic = true; + } + } + else { + if (bold && italic) { + g.setFont(ivFBoldItalic); + } + else if (bold) { + g.setFont(ivFBold); + } + else if (italic) { + g.setFont(ivFItalic); + } + else { + g.setFont(f); + } + + g.drawString(token, x, y); + x += strWidth(token, g.getFont()); + } + } + + x = xBegin; + y += ivSpaceLine; + } + } + + + private ArrayList calculateLines(String text, Font f) { + + StringTokenizer st = new StringTokenizer(text, "\n"); + ArrayList v = new ArrayList(10); + + ivHeightShortText = strHeight(f); + + while (st.hasMoreTokens()) { + + String token = st.nextToken(); + + if ((ivMaxWidth > 0) && (strWidth(token, f) > ivMaxWidth)) { + StringTokenizer subSt = new StringTokenizer(token); + String subToken = ""; + + while (subSt.hasMoreTokens()) { + String str1 = subSt.nextToken(); + + if (strWidth((subToken + str1), f) < ivMaxWidth) { + subToken += str1 + " "; + } + else { + v.add(trimRight(subToken)); + subToken = str1 + " "; + } + } + + v.add(trimRight(subToken)); + } + else { + v.add(trimRight(token)); + } + } + + return v; + } + + + private String trimRight(String str) { + + String str1 = str; + + while (str.endsWith(" ")) { + str1 = str.substring(0, str.length() - 1); + str = str1; + } + + return str1; + } + //!!CM 06/08/97 END +} diff --git a/net/infordata/em/tn5250ext/XIHintWindow.java b/net/infordata/em/tn5250ext/XIHintWindow.java new file mode 100644 index 0000000..85c0877 --- /dev/null +++ b/net/infordata/em/tn5250ext/XIHintWindow.java @@ -0,0 +1,136 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** + 10/07/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250ext; + + +import java.awt.*; +import java.awt.event.*; + +import javax.swing.*; + +import net.infordata.em.util.*; + + + +/** + */ +public class XIHintWindow extends JWindow { + + private static final long serialVersionUID = 1L; + +// private XIHint ivHint; + private Component ivComponent; + + private WinAdapter ivWinAdapter = new WinAdapter(); + + + /** + */ + public XIHintWindow(XIHint aHint, Component aComponent) { + + super(XIUtil.getFrame(aComponent)); + + if (aHint == null || aComponent == null) { + throw new IllegalArgumentException(); + } + + addComponentListener(new CompAdapter()); + + Point vLocation; + + ivComponent = aComponent; + + vLocation = ivComponent.getLocationOnScreen(); + vLocation.y += ivComponent.getSize().height + 4; + + setLocation(vLocation); + + getContentPane().setBackground(new Color(255, 250 , 180)); + + getContentPane().add(aHint); + setSize(aHint.getPreferredSize()); + } + + + /** + * Visibile solo se la frame associata è attiva + */ + @Override + public void setVisible(boolean b) { + //!!V TODO dovrebbe essere visibile solo se la frame alla quale è associato + // è attiva + super.setVisible(b); + } + + + ////////////////////////////////////////////////////////////////////////////// + + /** + */ + class CompAdapter extends ComponentAdapter { + + @Override + public void componentResized(ComponentEvent aEvent) { + if (aEvent.getSource() == getParent()) { + setVisible(false); + } + } + + @Override + public void componentMoved(ComponentEvent aEvent) { + if (aEvent.getSource() == getParent()) { + setVisible(false); + } + } + + @Override + public void componentShown(ComponentEvent aEvent) { + if (aEvent.getSource() == XIHintWindow.this) { + Frame frm = (Frame)getParent(); + frm.addComponentListener(this); + frm.addWindowListener(ivWinAdapter); + } + } + + @Override + public void componentHidden(ComponentEvent aEvent) { + if (aEvent.getSource() == XIHintWindow.this) { + Frame frm = (Frame)getParent(); + frm.removeWindowListener(ivWinAdapter); + frm.removeComponentListener(this); + } + } + } + + + ////////////////////////////////////////////////////////////////////////////// + + /** + */ + class WinAdapter extends WindowAdapter { + @Override + public void windowDeactivated(WindowEvent aEvent) { + setVisible(false); + } + } +} diff --git a/net/infordata/em/tn5250ext/XIImage.java b/net/infordata/em/tn5250ext/XIImage.java new file mode 100644 index 0000000..515b45a --- /dev/null +++ b/net/infordata/em/tn5250ext/XIImage.java @@ -0,0 +1,78 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + */ + +/* + *** + 10/07/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tn5250ext; + + +import java.awt.*; + +import javax.swing.*; + + +/** + * + * @version + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XIImage extends JComponent { + + private static final long serialVersionUID = 1L; + + private Image ivImage; + + + /** + */ + public XIImage(Image anImage) { + setImage(anImage); + } + + + /** + */ + public void setImage(Image anImage) { + if (anImage == ivImage) + return; + + ivImage = anImage; + repaint(); + } + + + /** + */ + @Override + public void update(Graphics gr) { + paint(gr); + } + + + /** + */ + @Override + public void paintComponent(Graphics gr) { + Dimension dim = getSize(); + + if (ivImage != null) + gr.drawImage(ivImage, 0, 0, dim.width, dim.height, this); + } +} \ No newline at end of file diff --git a/net/infordata/em/tnprot/XITelnet.java b/net/infordata/em/tnprot/XITelnet.java new file mode 100644 index 0000000..00b9b97 --- /dev/null +++ b/net/infordata/em/tnprot/XITelnet.java @@ -0,0 +1,933 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 07/04/97 rel. 1.00 - start of revisions history. + 14/05/97 rel. 1.00a- ... + 19/05/97 rel. 1.01 - added support for telnet proxy. + 15/07/07 rel. 1.02c- removed throws UnknownHostException form connect method. + finalize() method added. + 24/09/97 rel. 1.05 - DNCX project. + 03/03/98 rel. _.___- SWING and reorganization. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tnprot; + + +import java.io.IOException; +import java.io.InputStream; +import java.io.InterruptedIOException; +import java.io.OutputStream; +import java.net.Socket; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; +import java.util.logging.Level; +import java.util.logging.Logger; + + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Handles a telnet protocol connection. + * A telnet emulator must implement XITelnetEmulator interface to receive notification + * about the telnet connection. + * Supports RFC885 End of record. + * + * @see XITelnetEmulator + * + * @author Valentino Proietti - Infordata S.p.A. + */ +public class XITelnet { + + private static final Logger LOGGER = Logger.getLogger(XITelnet.class.getName()); + + /** + * Telnet options or flags. + */ + public static final byte TELOPT_BINARY = 0; + public static final byte TELOPT_ECHO = 1; + public static final byte TELOPT_RCP = 2; + public static final byte TELOPT_SGA = 3; + public static final byte TELOPT_NAMS = 4; + public static final byte TELOPT_STATUS = 5; + public static final byte TELOPT_TM = 6; + public static final byte TELOPT_RCTE = 7; + public static final byte TELOPT_NAOL = 8; + public static final byte TELOPT_NAOP = 9; + public static final byte TELOPT_NAOCRD = 10; + public static final byte TELOPT_NAOHTS = 11; + public static final byte TELOPT_NAOHTD = 12; + public static final byte TELOPT_NAOFFD = 13; + public static final byte TELOPT_NAOVTS = 14; + public static final byte TELOPT_NAOVTD = 15; + public static final byte TELOPT_NAOLFD = 16; + public static final byte TELOPT_XASCII = 17; + public static final byte TELOPT_LOGOUT = 18; + public static final byte TELOPT_BM = 19; + public static final byte TELOPT_DET = 20; + public static final byte TELOPT_SUPDUP = 21; + public static final byte TELOPT_SUPDUPOUTPUT = 22; + public static final byte TELOPT_SNDLOC = 23; + public static final byte TELOPT_TTYPE = 24; + public static final byte TELOPT_EOR = 25; + public static final byte TELOPT_TUID = 26; + public static final byte TELOPT_OUTMRK = 27; + public static final byte TELOPT_TTYLOC = 28; + public static final byte TELOPT_3270REGIME = 29; + public static final byte TELOPT_X3PAD = 30; + public static final byte TELOPT_NAWS = 31; + public static final byte TELOPT_TSPEED = 32; + public static final byte TELOPT_LFLOW = 33; + public static final byte TELOPT_LINEMODE = 34; + public static final byte TELOPT_XDISPLOC = 35; + public static final byte TELOPT_OLD_ENVIRON = 36; + public static final byte TELOPT_AUTHENTICATION = 37; + public static final byte TELOPT_ENCRYPT = 38; + public static final byte TELOPT_NEW_ENVIRON = 39; + public static final String[] TELOPT = + {"BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME", + "STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP", "NAOCRD", + "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS", "NAOVTD", "NAOLFD", + "EXTEND ASCII", "LOGOUT", "BYTE MACRO", + "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT", + "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD", + "TACACS UID", "OUTPUT MARKING", "TTYLOC", "3270 REGIME", + "X.3 PAD", "NAWS", "TSPEED", "LFLOW", "LINEMODE", + "XDISPLOC", "OLD-ENVIRON", "AUTHENTICATION", "ENCRYPT", + "NEW-ENVIRON", "" }; + + /** + * Telnet escapes + */ + static final byte IAC = (byte)0xFF; + static final byte DONT = (byte)0xFE; + static final byte DO = (byte)0xFD; + static final byte WONT = (byte)0xFC; + static final byte WILL = (byte)0xFB; + static final byte SB = (byte)0xFA; + static final byte SE = (byte)0xF0; + static final byte EOR = (byte)0xEF; + static final String[] TELCMD = { + "IAC", "DONT", "DO", "WONT", + "WILL", "SB", "GA", "EL", + "EC", "AYT", "AO", "IP", + "BRK", "DATA MARK", "NOP", "SE", + "EOR"}; + + static final byte SEND = (byte)0x01; + static final byte IS = (byte)0x00; + + // parser states for IAC sequences + static final int SIAC_START = 0; + static final int SIAC_WCMD = 1; + static final int SIAC_WOPT = 2; + static final int SIAC_WSTR = 3; + + private String ivHost; + private int ivPort; + + /** + * if null then the connection is closed + */ + transient private Socket ivSocket; + transient private InputStream ivIn; + transient private OutputStream ivOut; + transient private RxThread ivReadTh; + + transient private byte ivIACCmd; + transient private byte ivIACOpt; + transient private String ivIACStr; + + transient private boolean[] ivLocalFlags = new boolean[128]; + transient private boolean[] ivRemoteFlags = new boolean[128]; + + private boolean[] ivLocalReqFlags = new boolean[128]; + private boolean[] ivRemoteReqFlags = new boolean[128]; + + private String ivTermType; + private String ivEnvironment; + + transient private int ivIACParserStatus = SIAC_START; + + private XITelnetEmulator ivEmulator; + + transient private String ivFirstHost; //!!1.01 + transient private String ivSecondHost; //!!1.01 + + transient private boolean ivUsed = false; //!!1.07 + + /** + * Converts byte to int without sign + */ + public static final int toInt(byte bb) { + return ((int)bb & 0xff); + } + + + /** + * Converts byte to hexadecimal string rappresentation + */ + public static final String toHex(byte bb) { + String hex = Integer.toString(toInt(bb), 16); + return "00".substring(hex.length()) + hex; + } + + public static final String toHex(byte[] buf, int len) { + StringBuilder sb = new StringBuilder(len * 4); + for (int i = 0; i < len; i++) { + sb.append(toHex(buf[i])).append(' '); + } + return sb.toString(); + } + + public static final String toHex(byte[] buf) { + return toHex(buf, buf.length); + } + + + /** + * Uses telnet default port for socket connection. + */ + public XITelnet(String aHost) { + this(aHost, 23); + } + + + /** + * Uses the given port for socket connection. + */ + public XITelnet(String aHost, int aPort) { + if (aHost == null) + throw new IllegalArgumentException("Host cannot be null"); + + ivHost = aHost; + ivPort = aPort; + + try { + StringTokenizer st = new StringTokenizer(ivHost, ":"); + ivHost = st.nextToken(); + ivPort = Integer.parseInt(st.nextToken()); + } + catch (NoSuchElementException ex) { + } + + try { + StringTokenizer st = new StringTokenizer(ivHost, "#"); + ivFirstHost = st.nextToken(); + ivSecondHost = st.nextToken(); + } + catch (NoSuchElementException ex) { + } + } + + + /** + * Returns the host-name or ip address. + */ + public String getHost() { + return ivHost; + } + + + /** + * Returns the telnet port. + */ + public int getPort() { + return ivPort; + } + + + /** + * Sets the receiving notifications XITelnetEmulator instance. + */ + public void setEmulator(XITelnetEmulator aEmulator) { + ivEmulator = aEmulator; + } + + + /** + */ + public boolean isConnected() { + return (ivSocket != null); + } + + + /** + * Sets the telnet terminal type option. + * Must be used before that a connection is established. + */ + public void setTerminalType(String aTerminalType) { + if (isConnected()) + throw new IllegalArgumentException("Telnet already connected"); + + setLocalReqFlag(TELOPT_TTYPE, true); + ivTermType = aTerminalType; + } + + + /** + */ + public String getTerminalType() { + return ivTermType; + } + + + /** + * Sets the telnet environment option. + * Must be used before that a connection is established. + */ + public void setEnvironment(String aEnv) { + if (isConnected()) + throw new IllegalArgumentException("Telnet already connected"); + + setLocalReqFlag(TELOPT_NEW_ENVIRON, true); + ivEnvironment = aEnv; + } + + + /** + */ + public String getEnvironment() { + return ivEnvironment; + } + + + /** + * Sets the local requested flags. + * Must be used before that a connection is established. + * + * @param flag use a TELOPT_ constant. + * @param b to be requested ? + */ + public void setLocalReqFlag(byte flag, boolean b) { + if (isConnected()) + throw new IllegalArgumentException("Telnet already connected"); + + ivLocalReqFlags[flag] = b; + } + + + /** + * Sets the remote requested flags. + * Must be used before that a connection is established. + * + * @param flag use a TELOPT_ constant. + * @param b to be requested ? + */ + public void setRemoteReqFlag(byte flag, boolean b) { + if (isConnected()) + throw new IllegalArgumentException("Telnet already connected"); + + ivRemoteReqFlags[flag] = b; + } + + + /** + * Can be used to query a local flag status. + */ + public boolean isLocalFlagON(byte flag) { + return ivLocalFlags[flag]; + } + + + /** + * Can be used to query a remote flag status. + */ + public boolean isRemoteFlagON(byte flag) { + return ivRemoteFlags[flag]; + } + + + /** + * Tryes to establish a telnet connection. + * If a connection is already established then a call to disconnect() is maded. + */ + public synchronized void connect() { + if (ivUsed) + throw new IllegalArgumentException("XITelnet cannot be recycled"); + + disconnect(); + + connecting(); + + try { + ivSocket = new Socket(ivFirstHost, ivPort); + ivSocket.setKeepAlive(true); + + ivIn = ivSocket.getInputStream(); + ivOut = ivSocket.getOutputStream(); + + ivReadTh = new RxThread(); + ivReadTh.start(); + + ivUsed = true; + + // avvio scambio caratteristiche con server + /* NO!!! da problemi con AS/400 + for (int i = 0; i < ivRemoteReqFlags.length; i++) { + if (ivRemoteReqFlags[i]) + sendIACCmd(DO, (byte)i); + } + for (int i = 0; i < ivLocalReqFlags.length; i++) { + if (ivLocalReqFlags[i]) + sendIACCmd(WILL, (byte)i); + } + */ + + connected(); + } + catch (IOException ex) { + catchedIOException(ex); + } + } + + + /** + */ + private void closeSocket() { + if (ivSocket != null) { + try { + if (LOGGER.isLoggable(Level.FINE)) + LOGGER.fine("closing..."); + ivSocket.close(); + } + catch (IOException ex) { + // non richiamare catchedIOException(); + } + ivSocket = null; + ivIn = null; + ivOut = null; + + disconnected(); + } + } + + + /** + * Closes the telnet connection. + */ + public synchronized void disconnect() { //!!V 03/03/98 + if (ivReadTh != null) { + ivReadTh.terminate(); + ivReadTh = null; + } + closeSocket(); + } + + + /** + * Telnet IAC parser. + */ + protected int processIAC(byte bb) throws IOException { + int res = 1; + + switch (ivIACParserStatus) { + // + case SIAC_START: + switch (bb) { + case IAC: + if (LOGGER.isLoggable(Level.FINE)) + LOGGER.fine("IAC"); + + ivIACParserStatus = SIAC_WCMD; + res = 0; + break; + } + break; + // CMD + case SIAC_WCMD: + if (LOGGER.isLoggable(Level.FINE)) { + StringBuilder sb = new StringBuilder(); + sb.append(" r " + bb + " "); + try { + sb.append(TELCMD[-(bb + 1)] + " "); + } + catch (Exception ex) { + } + LOGGER.fine(sb.toString()); + } + + switch (bb) { + // + case IAC: + ivIACParserStatus = SIAC_START; + break; + // + case EOR: + ivIACParserStatus = SIAC_START; + res = 0; + if (ivLocalFlags[TELOPT_EOR]) + receivedEOR(); + break; + // + case WILL: + case WONT: + case DO: + case DONT: + ivIACCmd = bb; + ivIACParserStatus = SIAC_WOPT; + res = 0; + break; + // + case SB: + ivIACStr = ""; + ivIACCmd = bb; + ivIACParserStatus = SIAC_WOPT; + res = 0; + break; + // + case SE: + ivIACParserStatus = SIAC_START; + + if (LOGGER.isLoggable(Level.FINE)) + LOGGER.fine("SE " + TELOPT[ivIACOpt]); + + res = 0; + if (ivLocalFlags[ivIACOpt]) { + switch (ivIACOpt) { + case TELOPT_TTYPE: + sendIACStr(SB, TELOPT_TTYPE, true, ivTermType); + break; + case TELOPT_NEW_ENVIRON: + sendIACStr(SB, TELOPT_NEW_ENVIRON, true, ivEnvironment); + break; + default: + unhandledRequest(ivIACOpt, ivIACStr); + break; + } + } + break; + // + default: + ivIACParserStatus = SIAC_START; + res = 0; + break; + } + break; + // OPT + case SIAC_WOPT: + ivIACOpt = bb; + + if (LOGGER.isLoggable(Level.FINE)) + LOGGER.fine(TELOPT[ivIACOpt]); + + res = 0; + switch (ivIACCmd) { + case SB: + break; + case DONT: + if (ivLocalFlags[ivIACOpt]) { + ivLocalFlags[ivIACOpt] = false; + sendIACCmd(WONT, ivIACOpt); + + localFlagsChanged(ivIACOpt); + } + break; + case DO: + // opzione locale accettabile + if (ivLocalReqFlags[ivIACOpt]) { + if (!ivLocalFlags[ivIACOpt]) { + ivLocalFlags[ivIACOpt] = true; + sendIACCmd(WILL, ivIACOpt); + + localFlagsChanged(ivIACOpt); + } + } + else + sendIACCmd(WONT, ivIACOpt); + break; + case WONT: + if (ivRemoteFlags[ivIACOpt]) { + ivRemoteFlags[ivIACOpt] = false; + sendIACCmd(DONT, ivIACOpt); + + remoteFlagsChanged(ivIACOpt); + } + break; + case WILL: + // opzione remota accettabile + if (ivRemoteReqFlags[ivIACOpt]) { + if (!ivRemoteFlags[ivIACOpt]) { + ivRemoteFlags[ivIACOpt] = true; + sendIACCmd(DO, ivIACOpt); + + remoteFlagsChanged(ivIACOpt); + } + } + else + sendIACCmd(DONT, ivIACOpt); + break; + } + + if (ivIACCmd != SB) + ivIACParserStatus = SIAC_START; + else + ivIACParserStatus = SIAC_WSTR; + break; + // + case SIAC_WSTR: + res = 0; + switch (bb) { + case IAC: + ivIACParserStatus = SIAC_WCMD; + break; + default: + ivIACStr += (char)bb; + break; + } + break; + } + + return res; + } + + + /** + * Sends an telnet EOR sequence. + */ + public void sendEOR() throws IOException { + byte[] buf = {IAC, EOR}; + + try { + ivOut.write(buf); + ivOut.flush(); + } + catch (IOException ex) { + catchedIOException(ex); + } + } + + + /** + * Sends a telnet IAC sequence. + */ + public void sendIACCmd(byte aCmd, byte aOpt) { + if (LOGGER.isLoggable(Level.FINE)) + LOGGER.fine(" t " + aCmd + " " + TELCMD[-(aCmd + 1)] + " " + + TELOPT[aOpt]); + + byte[] buf = {IAC, aCmd, aOpt}; + + try { + ivOut.write(buf); + ivOut.flush(); + } + catch (IOException ex) { + catchedIOException(ex); + } + } + + + /** + * Sends a telnet IAC sequence with a string argument. + */ + public void sendIACStr(byte aCmd, byte aOpt, boolean sendIS, String aString) { + if (LOGGER.isLoggable(Level.FINE)) + LOGGER.fine("t " + aCmd + " " + TELCMD[-(aCmd + 1)] + " " + + TELOPT[aOpt] + " " + aString); + + byte[] endBuf = {IAC, SE}; + byte[] startBuf = + sendIS ? new byte[] {IAC, aCmd, aOpt, IS} : new byte[] {IAC, aCmd, aOpt}; +// String str = new String(startBuf) + aString + new String(endBuf); +// byte[] buf = str.getBytes(); + + try { + ivOut.write(startBuf); + ivOut.write(aString.getBytes()); + ivOut.write(endBuf); + ivOut.flush(); + } + catch (IOException ex) { + catchedIOException(ex); + } + } + + + /** + * Sends a data buffer (IAC bytes are doubled). + */ + public void send(byte[] aBuf, int aLen) { + try { + for (int i = 0; i < aLen; i++) { + ivOut.write(aBuf[i]); + if (aBuf[i] == IAC) + ivOut.write(IAC); + } + } + catch (IOException ex) { + catchedIOException(ex); + } + } + + + /** + * Sends a data buffer (IAC bytes are doubled). + */ + public void send(byte[] aBuf) { + send(aBuf, aBuf.length); + } + + + /** + * Flushes output buffer. + */ + public void flush() { + try { + ivOut.flush(); + } + catch (IOException ex) { + catchedIOException(ex); + } + } + + + /** + * Called just before trying to connect. + */ + protected void connecting() { + if (ivEmulator != null) + ivEmulator.connecting(); + } + + + /** + * Called after that a connection is established. + */ + protected void connected() { + if (ivSecondHost != null && !ivSecondHost.equals("")) + send((new String(ivSecondHost + "\n")).getBytes()); + + if (ivEmulator != null) + ivEmulator.connected(); + } + + + /** + * Called after that the connection is closed. + */ + protected void disconnected() { + if (ivEmulator != null) + ivEmulator.disconnected(); + } + + + /** + * Called when an IOException is catched. + */ + protected synchronized void catchedIOException(IOException ex) { + if (LOGGER.isLoggable(Level.FINE)) + LOGGER.log(Level.FINE, "" , ex); + + try { + if (ivEmulator != null) + ivEmulator.catchedIOException(ex); + } + finally { + disconnect(); + } + } + + + /** + * Called when an unhandled IAC request is received. + */ + protected void unhandledRequest(byte aIACOpt, String aIACStr) { + if (ivEmulator != null) + ivEmulator.unhandledRequest(aIACOpt, aIACStr); + } + + + /** + * Called when a local flags has been changed. + */ + protected void localFlagsChanged(byte aIACOpt) { + if (ivEmulator != null) + ivEmulator.localFlagsChanged(aIACOpt); + } + + + /** + * Called when a remote flags has been changed. + */ + protected void remoteFlagsChanged(byte aIACOpt) { + if (ivEmulator != null) + ivEmulator.remoteFlagsChanged(aIACOpt); + } + + + /** + * Called when data are received. + * Data are already cleared from IAC sequence. + * NOTE: receivedData is always called in the receiving thread. + */ + protected void receivedData(byte[] buf, int len) { + if (LOGGER.isLoggable(Level.FINEST)) { + LOGGER.finest(toHex(buf, len)); + } + + if (ivEmulator != null) + ivEmulator.receivedData(buf, len); + } + + + /** + * Called when a telnet EOR sequence is received. + * NOTE: receivedEOR is always called in the receiving thread. + */ + protected void receivedEOR() { + if (LOGGER.isLoggable(Level.FINE)) + LOGGER.fine("EOR"); + + if (ivEmulator != null) + ivEmulator.receivedEOR(); + } + + + /** + */ + @Override + protected void finalize() throws Throwable { + disconnect(); + super.finalize(); + } + + + /** + * Only for test purposes. + */ +// static void showFlagsStatus(boolean[] aFlags) { +// for (int i = TELOPT_BINARY; i <= TELOPT_NEW_ENVIRON; i++) { +// Diagnostic.getOut().print(TELOPT[i] + " " + aFlags[i] + " - "); +// if ((i % 3) == 0) +// Diagnostic.getOut().println(); +// } +// Diagnostic.getOut().println(); +// } + + + /** + * Used only for test purposes. + */ + public static void main(String[] argv) { + XITelnet tn = new XITelnet("192.168.0.1#192.168.0.4"); + tn.setTerminalType("IBM-3477-FC"); + + tn.setLocalReqFlag(TELOPT_BINARY, true); + tn.setLocalReqFlag(TELOPT_TTYPE, true); + //tn.setLocalReqFlag(TELOPT_NEW_ENVIRON, true); + tn.setLocalReqFlag(TELOPT_EOR, true); + + tn.setRemoteReqFlag(TELOPT_BINARY, true); + //tn.setRemoteReqFlag(TELOPT_ECHO, true); + //tn.setRemoteReqFlag(TELOPT_SGA, true); + //tn.setRemoteReqFlag(TELOPT_STATUS, true); + tn.setRemoteReqFlag(TELOPT_EOR, true); + + try { + tn.connect(); + + Thread.sleep(10000); + + tn.disconnect(); + } + catch (Exception ex) { + ex.printStackTrace(); + } + } + + + ////////////////////////////////////////////////////////////////////////////// + + /** + */ + class RxThread extends Thread { + + private boolean ivTerminate = false; + + + /** + */ + public RxThread() { + super("XITelnet rx thread"); + } + + + /** + */ + public void terminate() { + ivTerminate = true; + if (this != Thread.currentThread()) { //!!V 03/03/98 + interrupt(); + } + } + + + /** + * The receiving thread. + */ + @Override + public void run() { + byte[] buf = new byte[1024]; + byte[] rBuf = new byte[1024]; + int len = 0; + int i, j; + + try { + while(!ivTerminate) { + try { + len = ivIn.read(buf); + } + catch (InterruptedIOException iex) { //!!V 03/03/98 + len = 0; + } + + // process all IAC commands + for (i = 0, j = 0; i < len; i++) { + rBuf[j] = buf[i]; + if ((ivIACParserStatus != SIAC_START) || (buf[i] == IAC)) { + // if a IAC is received then split rx buffer + if ((ivIACParserStatus == SIAC_START) && (buf[i] == IAC)) { + if (j > 0) + receivedData(rBuf, j); + j = 0; + } + j += processIAC(buf[i]); + } + else + ++j; + } + + if (j > 0) + receivedData(rBuf, j); + } + } + catch (IOException ex) { + if (!ivTerminate) + catchedIOException(ex); + } + /* + catch (ThreadDeath ex) { + throw ex; + } + */ + } + } +} diff --git a/net/infordata/em/tnprot/XITelnetEmulator.java b/net/infordata/em/tnprot/XITelnetEmulator.java new file mode 100644 index 0000000..392bbfc --- /dev/null +++ b/net/infordata/em/tnprot/XITelnetEmulator.java @@ -0,0 +1,86 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +!!V 14/05/97 rel. 1.00a- ... + 03/03/98 rel. _.___- SWING and reorganization. + *** + 30/06/98 rel. _.___- Swing, JBuilder2 e VSS. + */ + + +package net.infordata.em.tnprot; + + +import java.io.IOException; + + +/** + * Interface that must be implemented by an emulator to receive notification from XITelnet. + * + * @see XITelnet + * + * @version 1.00a + * @author Valentino Proietti - Infordada S.p.A. + */ +public interface XITelnetEmulator { + /** + * @see XITelnet#connecting + */ + public void connecting(); + + /** + * @see XITelnet#connected + */ + public void connected(); + + /** + * @see XITelnet#disconnected + */ + public void disconnected(); + + /** + * @see XITelnet#catchedIOException + */ + public void catchedIOException(IOException ex); + + /** + * @see XITelnet#receivedData + */ + public void receivedData(byte[] buf, int len); + + /** + * @see XITelnet#receivedEOR + */ + public void receivedEOR(); + + /** + * @see XITelnet#unhandledRequest + */ + public void unhandledRequest(byte aIACOpt, String aIACStr); + + + /** + * @see XITelnet#localFlagsChanged + */ + public void localFlagsChanged(byte aIACOpt); + + + /** + * @see XITelnet#remoteFlagsChanged + */ + public void remoteFlagsChanged(byte aIACOpt); +} \ No newline at end of file diff --git a/net/infordata/em/util/XICommand.java b/net/infordata/em/util/XICommand.java new file mode 100644 index 0000000..aca56b5 --- /dev/null +++ b/net/infordata/em/util/XICommand.java @@ -0,0 +1,34 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** +!!V 07/07/98 rel. 1.07 - creation. + */ + + +package net.infordata.em.util; + + +/** + */ +public interface XICommand { + + /** + */ + public void execute(); +} + diff --git a/net/infordata/em/util/XICommandMgr.java b/net/infordata/em/util/XICommandMgr.java new file mode 100644 index 0000000..b18fb42 --- /dev/null +++ b/net/infordata/em/util/XICommandMgr.java @@ -0,0 +1,407 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** +!!V 07/07/98 rel. 1.07 - creation. + */ + + +package net.infordata.em.util; + +import java.awt.Button; +import java.awt.CheckboxMenuItem; +import java.awt.MenuItem; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.swing.AbstractButton; + + +/** + */ +public class XICommandMgr { + + private static final Logger LOGGER = Logger.getLogger(XICommandMgr.class.getName()); + + // relazione action-command -> XICommand + private Map ivActCmd2Cmd = new HashMap(); + + // action-commands disabilitati + private List ivDisabledActCmd = new ArrayList(); + + // relazione oggetto -> action-command + private Map ivObj2ActCmd = new HashMap(); + + // action-command -> boolean value + private Map ivActCmd2Value = new HashMap(); + + // lock per gestione action commands + private Object ivActCmdLock = new Object(); + + // + private ActionListener ivActionListener = new ActionListener() { + public void actionPerformed(ActionEvent e) { + XICommandMgr.this.actionPerformed(e); + } + }; + + // usato per sopperire ad un buco delle AWT - CheckboxMenuItem non inviano + // action command + private ItemListener ivItemListener; + + + ////////////////////////////////////////////////////////////////////////////// + + /** + */ + public XICommandMgr() { + + ivItemListener = new ItemListener() { + public void itemStateChanged(ItemEvent e) { + XICommandMgr.this.actionPerformed(new ActionEvent(e.getSource(), + ActionEvent.ACTION_PERFORMED, + null)); + } + }; + } + + + /** + * L' ActionListener utilizzato per la gestione degli action command. + */ + public ActionListener getActionListener() { + return ivActionListener; + } + + + /** + */ + private void actionPerformed(ActionEvent e) { + + if (LOGGER.isLoggable(Level.FINER)) + LOGGER.finer("" + e); + + String actCmd = (String)ivObj2ActCmd.get(e.getSource()); + + // se l' oggetto sorgente dell' evento non ha un action command associato lo prelevo + // dall' evento stesso + if (actCmd == null) + actCmd = e.getActionCommand(); + + if (actCmd != null) + dispatchCommand(e.getSource(), actCmd); + } + + + /** + */ + public void dispatchCommand(String cmd) { + dispatchCommand(null, cmd); + } + + + /** + */ + protected void dispatchCommand(Object cmp, String cmd) { + + if (LOGGER.isLoggable(Level.FINE)) + LOGGER.fine("dispatchCommand " + cmp + " " + cmd); + + boolean flag; + + synchronized (ivActCmdLock) { + + // stato associato al comando + boolean flagCmd = getCommandState(cmd); + + // stato associato al componente + boolean flagCmp = !flagCmd; + if (cmp instanceof CheckboxMenuItem) + flagCmp = ((CheckboxMenuItem)cmp).getState(); + //!!V NON SERVE else if (cmp instanceof AbstractButton) + //!!V NON SERVE flagCmp = ((AbstractButton)cmp).isSelected(); + + boolean enabled = isCommandEnabled(cmd); + + flag = (enabled) ? flagCmp : flagCmd; + } + + setCommandState(cmd, flag); + } + + + /** + */ + public void setCommandState(String cmd, boolean value) { + + if (LOGGER.isLoggable(Level.FINE)) + LOGGER.fine("setCommandState " + cmd + " " + value); + + boolean oldCmdState; + + synchronized (ivActCmdLock) { + + oldCmdState = getCommandState(cmd); + + ivActCmd2Value.put(cmd, new Boolean(value)); + + // sincronizzo lo stato di tutti gli oggetti associati al comando + Object obj; + for (Iterator e = ivObj2ActCmd.keySet().iterator(); e.hasNext(); ) { + obj = e.next(); + + if (cmd.equals(ivObj2ActCmd.get(obj))) { + + if (obj instanceof AbstractButton && + ((AbstractButton)obj).isSelected() != value) { + ((AbstractButton)obj).setSelected(value); + } + else if (obj instanceof CheckboxMenuItem && + ((CheckboxMenuItem)obj).getState() != value) { + ((CheckboxMenuItem)obj).setState(value); + } + } + } + } + + if (value != oldCmdState) + processCommand(cmd); + } + + + /** + * Ritorna lo stato associato al comando + */ + public boolean getCommandState(String cmd) { + Boolean app = (Boolean)ivActCmd2Value.get(cmd); + + return (app != null) ? app.booleanValue() : false; + } + + + /** + * Ricerca l' XACommand associato con l' action command cmd e, se presente, lo esegue + * chiamandone il metodo execute. + * + * @see MenuItem#setActionCommand + * @see Button#setActionCommand + * @see XIBaseButton#setActionCommand + */ + protected void processCommand(String anActCmd) { + + if (LOGGER.isLoggable(Level.FINE)) + LOGGER.fine("processActionCommand " + anActCmd); + + XICommand command = getCommand(anActCmd); + if (command != null) + command.execute(); + } + + + /** + * Richiamata dagli altri metodi handleCommand. + */ + private void handleActionCommand(Object obj, String anActionCommand) { + if (obj == null) + throw new IllegalArgumentException("anObj can't be null"); + + if (anActionCommand != null) { + ivObj2ActCmd.put(obj, anActionCommand); + // reinizializzo stato comando + setCommandState(anActionCommand, getCommandState(anActionCommand)); + } + else + ivObj2ActCmd.remove(obj); + } + + + /** + * Associa un ActionCommand ad un MenuItem e lo inserisce nella gestione di XACommandManager, + * se anActionCommand è null allora elimina l' oggetto da tale gestione. + */ + public void handleCommand(MenuItem aMenuItem, String anActionCommand) { + + synchronized (ivActCmdLock) { + handleActionCommand((Object)aMenuItem, anActionCommand); + + aMenuItem.setActionCommand(anActionCommand); + if (anActionCommand != null) { + aMenuItem.addActionListener(ivActionListener); + aMenuItem.setEnabled(isCommandEnabled(anActionCommand)); + } + else + aMenuItem.removeActionListener(ivActionListener); + } + } + + + /** + * Associa un ActionCommand ad un CheckboxMenuItem e lo inserisce nella gestione di XACommandManager, + * se anActionCommand è null allora elimina l' oggetto da tale gestione. + */ + public void handleCommand(CheckboxMenuItem aMenuItem, String anActionCommand) { + + synchronized (ivActCmdLock) { + handleActionCommand((Object)aMenuItem, anActionCommand); + + aMenuItem.setActionCommand(anActionCommand); + if (anActionCommand != null) { + aMenuItem.addItemListener(ivItemListener); + aMenuItem.setEnabled(isCommandEnabled(anActionCommand)); + } + else + aMenuItem.removeItemListener(ivItemListener); + } + } + + + /** + * Associa un ActionCommand ad un Button. + */ + public void handleCommand(Button aButton, String anActionCommand) { + + synchronized (ivActCmdLock) { + handleActionCommand((Object)aButton, anActionCommand); + + aButton.setActionCommand(anActionCommand); + if (anActionCommand != null) { + aButton.addActionListener(ivActionListener); + aButton.setEnabled(isCommandEnabled(anActionCommand)); + } + else + aButton.removeActionListener(ivActionListener); + } + } + + + /** + * Associa un ActionCommand ad un AbstractButton. + */ + public void handleCommand(AbstractButton aButton, String anActionCommand) { + + synchronized (ivActCmdLock) { + handleActionCommand((Object)aButton, anActionCommand); + + aButton.setActionCommand(anActionCommand); + if (anActionCommand != null) { + aButton.addActionListener(ivActionListener); + aButton.setEnabled(isCommandEnabled(anActionCommand)); + } + else + aButton.removeActionListener(ivActionListener); + } + } + + + /** + * Abilita o disabilita un action-command e tutti i controlli ad esso associati. + */ + public void enableCommand(String anActionCommand, boolean toBeEnabled) { + + if (anActionCommand == null) + throw new IllegalArgumentException("The ActionCommand can't be null."); + + synchronized (ivActCmdLock) { + // verifico se action-command è già nello stato voluto + if (toBeEnabled == isCommandEnabled(anActionCommand)) + return; + + if (LOGGER.isLoggable(Level.FINE)) + LOGGER.fine(anActionCommand + " " + (toBeEnabled ? "enabled" : "disabled")); + + if (toBeEnabled) + ivDisabledActCmd.remove(anActionCommand); + else + ivDisabledActCmd.add(anActionCommand); + + // abilito/disabilito tutti gli oggetti associati ad un determinato action-command + Object obj; + for (Iterator e = ivObj2ActCmd.keySet().iterator(); e.hasNext(); ) { + obj = e.next(); + + if (anActionCommand.equals(ivObj2ActCmd.get(obj))) { + + if (obj instanceof MenuItem) + ((MenuItem)obj).setEnabled(toBeEnabled); + else if (obj instanceof Button) + ((Button)obj).setEnabled(toBeEnabled); + else if (obj instanceof AbstractButton) + ((AbstractButton)obj).setEnabled(toBeEnabled); + else + throw new IllegalStateException("An invalid class type was found."); + } + } + } + } + + + /** + */ + public final boolean isCommandEnabled(String anActionCommand) { + return !ivDisabledActCmd.contains(anActionCommand); + } + + + /** + * Utilizzato per associare una instanza di una classe che implementa l' + * interfaccia XACommand ad un action command (sia esso generato da un menù o da un bottone) + *
+   * es.  
+   * // NB: in questo esempio viene utilizzata una inner-class, normalmente è consigliabile
+   * // utilizzare una classe normale o una nested class.
+   * 
+   * XAMainFrame frm = new XAMainFrame();
+   * frm.setCommand(XAMainFrame.NEW_CMD, 
+   *                new XACommand()
+   *                {
+   *                  public void execute()
+   *                  {
+   *                    System.out.println("Comando eseguito");
+   *                  }
+   *                });
+   * frm.show();              
+   * 
+ */ + public void setCommand(String anActionCommand, XICommand aCommand) { + + if (anActionCommand == null) + throw new IllegalArgumentException("The ActionCommand can't be null."); + + if (LOGGER.isLoggable(Level.FINE)) + LOGGER.fine(aCommand + " -> " + anActionCommand); + + ivActCmd2Cmd.put(anActionCommand, aCommand); + } + + + /** + * Ritorna l' instanza di XACommand associata con l' action command (null se nessuno). + */ + public XICommand getCommand(String anActionCommand) { + + return (XICommand)ivActCmd2Cmd.get(anActionCommand); + } +} diff --git a/net/infordata/em/util/XIRatioLayout.java b/net/infordata/em/util/XIRatioLayout.java new file mode 100644 index 0000000..4195f5d --- /dev/null +++ b/net/infordata/em/util/XIRatioLayout.java @@ -0,0 +1,344 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** +!!V 29/07/99 rel. 1.15 - creation. + */ + + +package net.infordata.em.util; + + +import java.awt.Button; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Insets; +import java.awt.LayoutManager2; +import java.awt.Panel; +import java.awt.Point; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + + +/** + */ +public class XIRatioLayout implements LayoutManager2, java.io.Serializable { + + private static final long serialVersionUID = 1L; + + public static final int LEFT = 0; + + public static final int CENTER = 1; + + public static final int RIGHT = 2; + + private int ivHGap; + + private Map ivConstraints = new HashMap(); + + + /** + */ + public XIRatioLayout() { + this(0); + } + + + /** + */ + public XIRatioLayout(int hgap) { + ivHGap = hgap; + } + + + /** + */ + public final int getHGap() { + return ivHGap; + } + + + /** + */ + public void addLayoutComponent(String aDescriptor, Component comp) { + Float fl = Float.valueOf(aDescriptor); + addLayoutComponent(comp, new Constraints(fl.floatValue(), LEFT)); + } + + + /** + */ + public void addLayoutComponent(Component comp, Object constraints) { + if (constraints != null && !(constraints instanceof Constraints)) + throw new IllegalArgumentException("XIRatioLayout.Constraints expected"); + ivConstraints.put(comp, (Constraints)constraints); + } + + + /** + */ + public void removeLayoutComponent(Component comp) { + ivConstraints.remove(comp); + } + + + private static final int PREFERRED = 0; + private static final int MINIMUM = 1; + private static final int MAXIMUM = 2; + + private Dimension layoutSize(Container parent, int type) { + Insets insets; + int[] nComps = new int[3]; + int maxW, maxH; + + synchronized (parent.getTreeLock()) { + insets = parent.getInsets(); + maxW = insets.left + insets.right; + maxH = insets.top + insets.bottom; + + { + int n = parent.getComponentCount(); + Component comp; + Constraints constr; + for (int i = 0; i < n; i++) { + comp = parent.getComponent(i); + if (comp.isVisible()) { + constr = (Constraints)ivConstraints.get(comp); + if (constr != null) { + ++nComps[constr.getAlignment()]; + } + else { + Dimension dim; + switch (type) { + case PREFERRED: + dim = comp.getPreferredSize(); + break; + case MINIMUM: + dim = comp.getMinimumSize(); + break; + case MAXIMUM: + dim = comp.getMaximumSize(); + break; + default: + throw new IllegalStateException(); + } + Point loc = comp.getLocation(); + maxW = Math.max(maxW, loc.x + dim.width - 1); + maxH = Math.max(maxH, loc.y + dim.height - 1); + } + } + } + } + } + + int w = insets.left + insets.right; + for (int i = LEFT; i <= RIGHT; i++) + if (nComps[i] > 0) + w -= (nComps[i] - 1) * ivHGap; + + maxW = Math.max(maxW, w); + + return new Dimension(maxW, maxH); + } + + + /** + */ + public Dimension preferredLayoutSize(Container parent) { + return layoutSize(parent, PREFERRED); + } + + + /** + */ + public Dimension minimumLayoutSize(Container parent) { + return layoutSize(parent, MINIMUM); + } + + + /** + */ + public Dimension maximumLayoutSize(Container parent) { + return layoutSize(parent, MAXIMUM); + } + + + /** + */ + @SuppressWarnings("unchecked") + public void layoutContainer(Container parent) { + Insets insets; + ArrayList[] comps; + ArrayList[] constrs; + Dimension parentDim; + + synchronized (parent.getTreeLock()) { + insets = parent.getInsets(); + comps = new ArrayList[3]; // LEFT, CENTER and RIGHT + constrs = new ArrayList[3]; // LEFT, CENTER and RIGHT + + { + int nComps = parent.getComponentCount(); + for (int i = LEFT; i <= RIGHT; i++) { + comps[i] = new ArrayList(nComps); + constrs[i] = new ArrayList(nComps); + } + Component comp; + Constraints constr; + for (int i = 0; i < nComps; i++) { + comp = parent.getComponent(i); + if (comp.isVisible()) { + constr = (Constraints)ivConstraints.get(comp); + if (constr != null) { + comps[constr.getAlignment()].add(comp); + constrs[constr.getAlignment()].add(constr); + } + } + } + } + + parentDim = parent.getSize(); + } + + if (comps[LEFT].size() == 0 && comps[CENTER].size() == 0 && + comps[RIGHT].size() == 0) + return; + + int maxW = parentDim.width - (insets.left + insets.right); + int maxH = parentDim.height - (insets.top + insets.bottom); + for (int i = LEFT; i <= RIGHT; i++) + if (comps[i].size() > 0) + maxW -= (comps[i].size() - 1) * ivHGap; + + Component comp; + Constraints constr; + int[] totW = new int[3]; + + for (int i = LEFT; i <= RIGHT; i++) { + for (int j = 0; j < comps[i].size(); j++) { + comp = (Component)comps[i].get(j); + constr = (Constraints)constrs[i].get(j); + comp.setSize(Math.round(maxW * constr.getHRatio()), maxH); + totW[i] += comp.getSize().width; + } + } + + if (comps[LEFT].size() > 0) { //LEFT ALIGNED + int x = insets.left; + Dimension dim; + for (int j = 0; j < comps[LEFT].size(); j++) { + comp = (Component)comps[LEFT].get(j); + dim = comp.getSize(); + comp.setLocation(x, insets.top); + x += (dim.width + ivHGap); + } + } + + if (comps[RIGHT].size() > 0) { //RIGHT ALIGNED + int x = parentDim.width - insets.right; + Dimension dim; + for (int j = 0; j < comps[RIGHT].size(); j++) { + comp = (Component)comps[RIGHT].get(j); + dim = comp.getSize(); + comp.setLocation(x - dim.width, insets.top); + x -= (dim.width + ivHGap); + } + } + + if (comps[CENTER].size() > 0) { //CENTERED + int x = (parentDim.width - totW[CENTER] - + (comps[CENTER].size() - 1) * ivHGap) / 2; + Dimension dim; + for (int j = 0; j < comps[CENTER].size(); j++) { + comp = (Component)comps[CENTER].get(j); + dim = comp.getSize(); + comp.setLocation(x, insets.top); + x += (dim.width + ivHGap); + } + } + } + + + /** + */ + public float getLayoutAlignmentX(Container target) { + return 0.5f; + } + + + /** + */ + public float getLayoutAlignmentY(Container target) { + return 0.5f; + } + + + /** + */ + public void invalidateLayout(Container target) { + } + + + /** + */ + public static void main(String[] args) { + Frame frame = new Frame("TEST XIRatioLayout"); + Panel panel = new Panel(new XIRatioLayout(4)); + panel.add(new Button("L1"), new Constraints(0.1F, LEFT)); + panel.add(new Button("L2"), new Constraints(0.2F, LEFT)); + panel.add(new Button("R1"), new Constraints(0.1F, RIGHT)); + panel.add(new Button("R2"), new Constraints(0.2F, RIGHT)); + panel.add(new Button("C1"), new Constraints(0.2F, CENTER)); + panel.add(new Button("C2"), new Constraints(0.2F, CENTER)); + frame.add(panel); + frame.setBounds(0, 0, 200, 200); + frame.setVisible(true); + } + + + ////////////////////////////////////////////////////////////////////////////// + + public static class Constraints implements java.io.Serializable { + + private static final long serialVersionUID = 1L; + + private float ivHRatio; + private int ivAlign; + + public Constraints(float hRatio) { + this(hRatio, LEFT); + } + + public Constraints(float hRatio, int alignment) { + if (alignment < LEFT || alignment > RIGHT) + throw new IllegalArgumentException(); + ivHRatio = hRatio; + ivAlign = alignment; + } + + public final float getHRatio() { + return ivHRatio; + } + + public final int getAlignment() { + return ivAlign; + } + } +} \ No newline at end of file diff --git a/net/infordata/em/util/XIUtil.java b/net/infordata/em/util/XIUtil.java new file mode 100644 index 0000000..871667c --- /dev/null +++ b/net/infordata/em/util/XIUtil.java @@ -0,0 +1,196 @@ +/* +Copyright 2007 Infordata S.p.A. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + *** +!!V 07/07/98 rel. 1.07 - creation. + 02/05/00 rel. 1.15b- Jdk 1.3rc2. + */ + + +package net.infordata.em.util; + + +import java.applet.Applet; +import java.awt.Component; +import java.awt.Frame; +import java.awt.Image; +import java.awt.Toolkit; +import java.awt.Window; +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Method; + + +/** + */ +public class XIUtil { + + + public static final boolean is1dot2 = is1dot2(); + public static final boolean is1dot3 = is1dot3(); + + private static boolean is1dot2() { + try { + // Test if method introduced in 1.2 is available. + Method m = Class.class.getMethod("getProtectionDomain"); + return (m != null); + } + catch (NoSuchMethodException e) { + return false; + } + } + + private static boolean is1dot3() { + try { + // Test if method introduced in 1.3 is available. + Method m = Runtime.class.getMethod("addShutdownHook", + new Class[] {Thread.class}); + return (m != null); + } + catch (NoSuchMethodException e) { + return false; + } + } + + + /** + */ + private XIUtil() { + } + + + /** + */ + public static final Frame getFrame(Component aComponent) { + Component comp = aComponent; + while (comp != null && !(comp instanceof Frame)) + comp = comp.getParent(); + return (Frame)comp; + } + + + /** + */ + public static final Window getWindow(Component aComponent) { + Component comp = aComponent; + while (comp != null && !(comp instanceof Window)) + comp = comp.getParent(); + return (Window)comp; + } + + + /** + */ + public static final Applet getApplet(Component aComponent) { + Component comp = aComponent; + while (comp != null && !(comp instanceof Applet)) + comp = comp.getParent(); + return (Applet)comp; + } + + + /** + */ + public static Image createImage(final Class baseClass, + final String gifFile) { + byte[] buffer = null; + try { + /* Copy resource into a byte array. This is + * necessary because several browsers consider + * Class.getResource a security risk because it + * can be used to load additional classes. + * Class.getResourceAsStream just returns raw + * bytes, which we can convert to an image. + */ + InputStream resource = baseClass.getResourceAsStream(gifFile); + if (resource == null) { + throw new IllegalArgumentException(baseClass.getName() + "/" + + gifFile + " not found."); + } + BufferedInputStream in = new BufferedInputStream(resource); + ByteArrayOutputStream out = new ByteArrayOutputStream(1024); + buffer = new byte[1024]; + int n; + while ((n = in.read(buffer)) > 0) { + out.write(buffer, 0, n); + } + in.close(); + out.flush(); + + buffer = out.toByteArray(); + if (buffer.length == 0) { + throw new IllegalStateException("warning: " + gifFile + + " is zero-length"); + } + } + catch (IOException ex) { + throw new IllegalStateException(ex.toString()); + } + + return Toolkit.getDefaultToolkit().createImage(buffer); + } + + + /** + */ + public static char getMnemonic(String str) { + char ch; + int state = 0; + for (int i = 0; i < str.length(); i++) { + ch = str.charAt(i); + switch (state) { + case 0: + if (ch == '&') + state = 1; + break; + case 1: + if (ch != '&') + return ch; + state = 0; + break; + } + } + return '\u0000'; + } + + + /** + */ + public static String removeMnemonics(String str) { + StringBuilder sb = new StringBuilder(str.length()); + char ch; + int state = 0; + for (int i = 0; i < str.length(); i++) { + ch = str.charAt(i); + switch (state) { + case 0: + if (ch == '&') + state = 1; + else + sb.append(ch); + break; + case 1: + sb.append(ch); + state = 0; + break; + } + } + return sb.toString(); + } +} \ No newline at end of file diff --git a/res/res/Monospaced b/res/res/Monospaced new file mode 100644 index 0000000000000000000000000000000000000000..348889828d894b9b57fb6435497d5c034448cb1b GIT binary patch literal 58464 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