Add facade classes for 3rd party programs
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
package com.ibm.eNetwork.ECL;
|
||||
|
||||
import com.ibm.eNetwork.ECL.event.ECLEvent;
|
||||
|
||||
/**
|
||||
* Communications event matching IBM Host On-Demand ECLCommEvent.
|
||||
*/
|
||||
public class ECLCommEvent extends ECLEvent {
|
||||
|
||||
private final boolean status;
|
||||
private final int eventType;
|
||||
|
||||
public ECLCommEvent(Object object, boolean status) {
|
||||
super(object);
|
||||
this.status = status;
|
||||
this.eventType = status ? 1 : 2;
|
||||
}
|
||||
|
||||
public ECLCommEvent(Object object, int eventType, boolean status) {
|
||||
super(object);
|
||||
this.eventType = eventType;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public boolean connected() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
public int getEventType() {
|
||||
return this.eventType;
|
||||
}
|
||||
|
||||
public ECLConnection GetConnection() {
|
||||
Object src = GetSource();
|
||||
if (src instanceof ECLConnection) return (ECLConnection) src;
|
||||
if (src instanceof haus.nightmare.lib3270j.ecl.ECLConnection) {
|
||||
return new ECLConnection((haus.nightmare.lib3270j.ecl.ECLConnection) src);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.ibm.eNetwork.ECL;
|
||||
|
||||
/**
|
||||
* Communications notification interface matching IBM Host On-Demand ECLCommNotify.
|
||||
*/
|
||||
public interface ECLCommNotify {
|
||||
void NotifyEvent(ECLConnection conn, boolean connected);
|
||||
default void NotifyStop(ECLConnection conn, int reason) {}
|
||||
default void NotifyError(ECLConnection conn, ECLErr err) {}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.ibm.eNetwork.ECL;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
* Communications and connection management facade matching IBM Host On-Demand ECLConnection.
|
||||
*/
|
||||
public class ECLConnection extends haus.nightmare.lib3270j.ecl.ECLConnection implements ECLConstants {
|
||||
|
||||
private final List<ECLCommNotify> commNotifies = new CopyOnWriteArrayList<>();
|
||||
|
||||
public ECLConnection() {
|
||||
super();
|
||||
setupListener();
|
||||
}
|
||||
|
||||
public ECLConnection(Properties props) {
|
||||
super(props);
|
||||
setupListener();
|
||||
}
|
||||
|
||||
public ECLConnection(String host, int port) {
|
||||
super(host, port);
|
||||
setupListener();
|
||||
}
|
||||
|
||||
public ECLConnection(haus.nightmare.lib3270j.ecl.ECLSession session) {
|
||||
super(session);
|
||||
setupListener();
|
||||
}
|
||||
|
||||
public ECLConnection(haus.nightmare.lib3270j.ecl.ECLConnection delegate) {
|
||||
super(delegate != null ? delegate.getSession() : null);
|
||||
setupListener();
|
||||
}
|
||||
|
||||
private void setupListener() {
|
||||
RegisterCommEvent(new haus.nightmare.lib3270j.ecl.ECLCommListener() {
|
||||
@Override
|
||||
public void CommNotifyEvent(haus.nightmare.lib3270j.ecl.ECLCommEvent event) {
|
||||
boolean conn = event != null && event.isConnected();
|
||||
for (ECLCommNotify n : commNotifies) {
|
||||
try {
|
||||
n.NotifyEvent(ECLConnection.this, conn);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void RegisterCommEvent(ECLCommNotify notify) {
|
||||
if (notify != null && !commNotifies.contains(notify)) {
|
||||
commNotifies.add(notify);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerCommEvent(ECLCommNotify notify) { RegisterCommEvent(notify); }
|
||||
|
||||
public void UnregisterCommEvent(ECLCommNotify notify) {
|
||||
if (notify != null) {
|
||||
commNotifies.remove(notify);
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterCommEvent(ECLCommNotify notify) { UnregisterCommEvent(notify); }
|
||||
|
||||
@Override
|
||||
public void StartCommunication() throws IOException {
|
||||
super.StartCommunication();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void StopCommunication() {
|
||||
super.StopCommunication();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package com.ibm.eNetwork.ECL;
|
||||
|
||||
/**
|
||||
* IBM Host Access Class Library (HACL) common constants.
|
||||
* Conforms 1:1 to IBM Host On-Demand com.ibm.eNetwork.ECL.ECLConstants.
|
||||
*/
|
||||
public interface ECLConstants extends haus.nightmare.lib3270j.ecl.ECLConstants {
|
||||
|
||||
// Presentation space logical planes (HoD bitmask values)
|
||||
int TEXT_PLANE = 1;
|
||||
int COLOR_PLANE = 2;
|
||||
int DBCS_PLANE = 4;
|
||||
int GRID_PLANE = 8;
|
||||
int FIELD_PLANE = 16;
|
||||
int EXFIELD_PLANE = 32;
|
||||
int NLS_PLANE = 64;
|
||||
int HOST_PLANE = 128;
|
||||
int RAWTEXT_PLANE = 256;
|
||||
int COLOR_ATTRIBUTES_PLANE = 512;
|
||||
int ALL_PLANES = 319;
|
||||
|
||||
// Search directions
|
||||
int SEARCH_FORWARD = 1;
|
||||
int SEARCH_BACKWARD = 2;
|
||||
|
||||
// Field filters
|
||||
int ALL_FIELDS = 0;
|
||||
int MODIFIED_FIELD = 1;
|
||||
int ALPHANUM_FIELD = 2;
|
||||
int HILIGHT_FIELD = 16;
|
||||
int PROTECTED_FIELD = 32;
|
||||
int DISPLAYABLE_FIELD = 64;
|
||||
int PENDETECTABLE_FIELD = 128;
|
||||
int UNMODIFIED_FIELD = 256;
|
||||
int NUMERIC_FIELD = 512;
|
||||
int LOLIGHT_FIELD = 4096;
|
||||
int UNPROTECTED_FIELD = 8192;
|
||||
int NON_DISPLAYABLE_FIELD = 16384;
|
||||
int NON_PENDETECTABLE_FIELD = 32768;
|
||||
|
||||
// Standard Mnemonics Constants
|
||||
String ENTER_STR = "[enter]";
|
||||
String CLEAR_STR = "[clear]";
|
||||
String RESET_STR = "[reset]";
|
||||
String TAB_STR = "[tab]";
|
||||
String FWDTAB_STR = "[tab]";
|
||||
String BACKTAB_STR = "[backtab]";
|
||||
String BACKSP_STR = "[backspace]";
|
||||
String DELCHAR_STR = "[delete]";
|
||||
String INSERT_STR = "[insert]";
|
||||
String HOME_STR = "[home]";
|
||||
String NEWLINE_STR = "[newline]";
|
||||
String ENDLINE_STR = "[eof]";
|
||||
String ERASEEOF_STR = "[eraseeof]";
|
||||
String ERASEFLD_STR = "[erasefld]";
|
||||
String ERASEINPUT_STR = "[erinp]";
|
||||
String ATTN_STR = "[attn]";
|
||||
String SYSREQ_STR = "[sysreq]";
|
||||
String DUP_STR = "[dup]";
|
||||
String FLDMRK_STR = "[fieldmark]";
|
||||
String PA1_STR = "[pa1]";
|
||||
String PA2_STR = "[pa2]";
|
||||
String PA3_STR = "[pa3]";
|
||||
String CURUP_STR = "[up]";
|
||||
String CURDOWN_STR = "[down]";
|
||||
String CURLEFT_STR = "[left]";
|
||||
String CURRIGHT_STR = "[right]";
|
||||
String PAGEUP_STR = "[pageup]";
|
||||
String PAGEDWN_STR = "[pagedn]";
|
||||
String COPY_STR = "[copy]";
|
||||
String PASTE_STR = "[paste]";
|
||||
String CUT_STR = "[cut]";
|
||||
String SELECTALL_STR = "[selectall]";
|
||||
|
||||
// Function keys F1 - F24
|
||||
String F1_STR = "[pf1]";
|
||||
String F2_STR = "[pf2]";
|
||||
String F3_STR = "[pf3]";
|
||||
String F4_STR = "[pf4]";
|
||||
String F5_STR = "[pf5]";
|
||||
String F6_STR = "[pf6]";
|
||||
String F7_STR = "[pf7]";
|
||||
String F8_STR = "[pf8]";
|
||||
String F9_STR = "[pf9]";
|
||||
String F10_STR = "[pf10]";
|
||||
String F11_STR = "[pf11]";
|
||||
String F12_STR = "[pf12]";
|
||||
String F13_STR = "[pf13]";
|
||||
String F14_STR = "[pf14]";
|
||||
String F15_STR = "[pf15]";
|
||||
String F16_STR = "[pf16]";
|
||||
String F17_STR = "[pf17]";
|
||||
String F18_STR = "[pf18]";
|
||||
String F19_STR = "[pf19]";
|
||||
String F20_STR = "[pf20]";
|
||||
String F21_STR = "[pf21]";
|
||||
String F22_STR = "[pf22]";
|
||||
String F23_STR = "[pf23]";
|
||||
String F24_STR = "[pf24]";
|
||||
|
||||
// Shift F1 - F24
|
||||
String SHIFT_F1_STR = "[Spf1]";
|
||||
String SHIFT_F2_STR = "[Spf2]";
|
||||
String SHIFT_F3_STR = "[Spf3]";
|
||||
String SHIFT_F4_STR = "[Spf4]";
|
||||
String SHIFT_F5_STR = "[Spf5]";
|
||||
String SHIFT_F6_STR = "[Spf6]";
|
||||
String SHIFT_F7_STR = "[Spf7]";
|
||||
String SHIFT_F8_STR = "[Spf8]";
|
||||
String SHIFT_F9_STR = "[Spf9]";
|
||||
String SHIFT_F10_STR = "[Spf10]";
|
||||
String SHIFT_F11_STR = "[Spf11]";
|
||||
String SHIFT_F12_STR = "[Spf12]";
|
||||
String SHIFT_F13_STR = "[Spf13]";
|
||||
String SHIFT_F14_STR = "[Spf14]";
|
||||
String SHIFT_F15_STR = "[Spf15]";
|
||||
String SHIFT_F16_STR = "[Spf16]";
|
||||
String SHIFT_F17_STR = "[Spf17]";
|
||||
String SHIFT_F18_STR = "[Spf18]";
|
||||
String SHIFT_F19_STR = "[Spf19]";
|
||||
String SHIFT_F20_STR = "[Spf20]";
|
||||
|
||||
// Field attributes
|
||||
short ATTR_PROTECTED = 32;
|
||||
short ATTR_ALPHANUM = 16;
|
||||
short ATTR_DISPLAY1 = 8;
|
||||
short ATTR_DISPLAY2 = 4;
|
||||
short ATTR_MDT = 1;
|
||||
|
||||
// Extended attributes
|
||||
short EXT_ATTR_3270_UNDERLINE = 192;
|
||||
short EXT_ATTR_3270_REVERSE = 128;
|
||||
short EXT_ATTR_3270_BLINK = 64;
|
||||
short EXT_ATTR_3270_EBCDIC = 0;
|
||||
|
||||
// Timeout
|
||||
int NO_TIMEOUT = -1;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.ibm.eNetwork.ECL;
|
||||
|
||||
/**
|
||||
* IBM Host Access Class Library (HACL) ECLErr checked exception facade.
|
||||
* Conforms 1:1 to IBM Host On-Demand com.ibm.eNetwork.ECL.ECLErr.
|
||||
*/
|
||||
public class ECLErr extends haus.nightmare.lib3270j.ecl.ECLErr {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ECLErr() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ECLErr(String text) {
|
||||
super(text);
|
||||
}
|
||||
|
||||
public ECLErr(String location, String msgNum) {
|
||||
super(location, msgNum);
|
||||
}
|
||||
|
||||
public ECLErr(String location, String msgNum, String insert) {
|
||||
super(location, msgNum, insert);
|
||||
}
|
||||
|
||||
public ECLErr(String location, String msgNum, String insert1, String insert2) {
|
||||
super(location, msgNum, insert1, insert2);
|
||||
}
|
||||
|
||||
public ECLErr(String location, String msgNum, String insert1, String insert2, boolean log) {
|
||||
super(location, msgNum, insert1, insert2, log);
|
||||
}
|
||||
|
||||
public ECLErr(String location, String msgNum, String insert1, String insert2, String insert3) {
|
||||
super(location, msgNum, insert1, insert2, insert3);
|
||||
}
|
||||
|
||||
public ECLErr(String location, String msgNum, int reasonCode) {
|
||||
super(location, msgNum, reasonCode);
|
||||
}
|
||||
|
||||
public ECLErr(String location, String msgNum, String insert1, int reasonCode) {
|
||||
super(location, msgNum, insert1, reasonCode);
|
||||
}
|
||||
|
||||
public ECLErr(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public ECLErr(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
package com.ibm.eNetwork.ECL;
|
||||
|
||||
/**
|
||||
* Discrete 3270 field facade matching IBM Host On-Demand ECLField.
|
||||
*/
|
||||
public class ECLField extends haus.nightmare.lib3270j.ecl.ECLField implements ECLConstants {
|
||||
|
||||
private final haus.nightmare.lib3270j.ecl.ECLField delegate;
|
||||
|
||||
public ECLField(haus.nightmare.lib3270j.ecl.ECLField delegate) {
|
||||
super(delegate != null ? delegate.getPS() : null,
|
||||
delegate != null ? delegate.getStart() : 0,
|
||||
delegate != null ? delegate.getDataStart() : 0,
|
||||
delegate != null ? delegate.getEnd() : 0,
|
||||
delegate != null ? delegate.getLength() : 0,
|
||||
(byte) (delegate != null ? delegate.getAttribute() : 0));
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public int GetStart() {
|
||||
return delegate != null ? delegate.GetStart() + 1 : 1;
|
||||
}
|
||||
|
||||
public int getStart() { return GetStart(); }
|
||||
|
||||
public int GetStartRow() {
|
||||
return delegate != null ? delegate.GetStartRow() + 1 : 1;
|
||||
}
|
||||
|
||||
public int getStartRow() { return GetStartRow(); }
|
||||
|
||||
public int GetStartCol() {
|
||||
return delegate != null ? delegate.GetStartCol() + 1 : 1;
|
||||
}
|
||||
|
||||
public int getStartCol() { return GetStartCol(); }
|
||||
|
||||
public int GetEnd() {
|
||||
return delegate != null ? delegate.GetEnd() + 1 : 1;
|
||||
}
|
||||
|
||||
public int getEnd() { return GetEnd(); }
|
||||
|
||||
public int GetEndRow() {
|
||||
return delegate != null ? delegate.GetEndRow() + 1 : 1;
|
||||
}
|
||||
|
||||
public int getEndRow() { return GetEndRow(); }
|
||||
|
||||
public int GetEndCol() {
|
||||
return delegate != null ? delegate.GetEndCol() + 1 : 1;
|
||||
}
|
||||
|
||||
public int getEndCol() { return GetEndCol(); }
|
||||
|
||||
public int GetLength() {
|
||||
return delegate != null ? delegate.GetLength() : 0;
|
||||
}
|
||||
|
||||
public int getLength() { return GetLength(); }
|
||||
|
||||
public String GetString() {
|
||||
return delegate != null ? delegate.getString() : "";
|
||||
}
|
||||
|
||||
public String getString() { return GetString(); }
|
||||
|
||||
public int GetString(char[] buffer, int len) throws ECLErr {
|
||||
if (buffer == null) throw new ECLErr("ECLField:GetString", "ECL0011", "1");
|
||||
String text = GetString();
|
||||
int count = Math.min(len, Math.min(buffer.length, text.length()));
|
||||
for (int i = 0; i < count; i++) {
|
||||
buffer[i] = text.charAt(i);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public void SetString(String text) throws ECLErr {
|
||||
if (delegate != null) {
|
||||
delegate.setText(text);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetText(String text) throws ECLErr {
|
||||
SetString(text);
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
if (delegate != null) {
|
||||
delegate.setText(text);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean IsModified() {
|
||||
return delegate != null && delegate.isModified();
|
||||
}
|
||||
|
||||
public boolean isModified() { return IsModified(); }
|
||||
|
||||
public boolean IsProtected() {
|
||||
return delegate != null && delegate.isProtected();
|
||||
}
|
||||
|
||||
public boolean isProtected() { return IsProtected(); }
|
||||
|
||||
public boolean IsNumeric() {
|
||||
return delegate != null && delegate.isNumeric();
|
||||
}
|
||||
|
||||
public boolean isNumeric() { return IsNumeric(); }
|
||||
|
||||
public boolean IsHighIntensity() {
|
||||
return delegate != null && delegate.isHighIntensity();
|
||||
}
|
||||
|
||||
public boolean isHighIntensity() { return IsHighIntensity(); }
|
||||
|
||||
public boolean IsPenDetectable() {
|
||||
return delegate != null && delegate.isPenDetectable();
|
||||
}
|
||||
|
||||
public boolean isPenDetectable() { return IsPenDetectable(); }
|
||||
|
||||
public boolean IsDisplay() {
|
||||
return delegate != null && delegate.isDisplay();
|
||||
}
|
||||
|
||||
public boolean isDisplay() { return IsDisplay(); }
|
||||
|
||||
public short GetAttribute() {
|
||||
return delegate != null ? (short) (delegate.getAttribute() & 0xFF) : 0;
|
||||
}
|
||||
|
||||
public short getAttribute() { return GetAttribute(); }
|
||||
|
||||
public haus.nightmare.lib3270j.ecl.ECLField getDelegate() { return delegate; }
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package com.ibm.eNetwork.ECL;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* Collection of 3270 fields matching IBM Host On-Demand ECLFieldList.
|
||||
*/
|
||||
public class ECLFieldList extends Vector<ECLField> implements ECLConstants {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final haus.nightmare.lib3270j.ecl.ECLFieldList delegate;
|
||||
private final ECLPS ps;
|
||||
|
||||
public ECLFieldList(haus.nightmare.lib3270j.ecl.ECLFieldList delegate, ECLPS ps) {
|
||||
this.delegate = delegate;
|
||||
this.ps = ps;
|
||||
refreshFields();
|
||||
}
|
||||
|
||||
public ECLFieldList(haus.nightmare.lib3270j.ecl.ECLFieldList delegate) {
|
||||
this(delegate, null);
|
||||
}
|
||||
|
||||
private void refreshFields() {
|
||||
clear();
|
||||
if (delegate != null) {
|
||||
delegate.refresh();
|
||||
for (haus.nightmare.lib3270j.ecl.ECLField f : delegate.getFields()) {
|
||||
add(new ECLField(f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Refresh() {
|
||||
refreshFields();
|
||||
}
|
||||
|
||||
public void Refresh(int planes) throws ECLErr {
|
||||
refreshFields();
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
refreshFields();
|
||||
}
|
||||
|
||||
public int GetFieldCount() {
|
||||
return size();
|
||||
}
|
||||
|
||||
public int getFieldCount() { return GetFieldCount(); }
|
||||
|
||||
public ECLField GetFirstField() {
|
||||
return GetFirstField(0);
|
||||
}
|
||||
|
||||
public ECLField GetFirstField(int filter) {
|
||||
for (ECLField f : this) {
|
||||
if (matchesFilter(f, filter)) return f;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ECLField GetNextField(ECLField current) {
|
||||
return GetNextField(current, 0);
|
||||
}
|
||||
|
||||
public ECLField GetNextField(ECLField current, int filter) {
|
||||
if (current == null) return GetFirstField(filter);
|
||||
int idx = indexOf(current);
|
||||
if (idx >= 0) {
|
||||
for (int i = idx + 1; i < size(); i++) {
|
||||
ECLField f = get(i);
|
||||
if (matchesFilter(f, filter)) return f;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ECLField FindField(int pos) throws ECLErr {
|
||||
if (ps != null && (pos < 1 || pos > ps.GetSize())) {
|
||||
throw new ECLErr("ECLFieldList:FindField", "ECL0010", "1", String.valueOf(pos));
|
||||
}
|
||||
for (ECLField f : this) {
|
||||
int start = f.GetStart();
|
||||
int end = f.GetEnd();
|
||||
if (start <= end) {
|
||||
if (pos >= start && pos <= end) return f;
|
||||
} else {
|
||||
// Wrapped field
|
||||
if (pos >= start || pos <= end) return f;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ECLField FindField(int row, int col) throws ECLErr {
|
||||
if (ps == null) return null;
|
||||
int pos = ps.ConvertRowColToPos(row, col);
|
||||
return FindField(pos);
|
||||
}
|
||||
|
||||
private boolean matchesFilter(ECLField f, int filter) {
|
||||
if (filter == 0 || filter == ALL_FIELDS) return true;
|
||||
if ((filter & MODIFIED_FIELD) != 0 && !f.IsModified()) return false;
|
||||
if ((filter & PROTECTED_FIELD) != 0 && !f.IsProtected()) return false;
|
||||
if ((filter & UNPROTECTED_FIELD) != 0 && f.IsProtected()) return false;
|
||||
if ((filter & NUMERIC_FIELD) != 0 && !f.IsNumeric()) return false;
|
||||
if ((filter & HILIGHT_FIELD) != 0 && !f.IsHighIntensity()) return false;
|
||||
if ((filter & DISPLAYABLE_FIELD) != 0 && !f.IsDisplay()) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.ibm.eNetwork.ECL;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Host Print Session facade matching IBM Host On-Demand ECLHostPrintSession.
|
||||
*/
|
||||
public class ECLHostPrintSession extends ECLSession {
|
||||
|
||||
public static final String SESSION_PRINT_SESSION_LABEL_DEFAULT = "";
|
||||
public static final String SESSION_PRINT_SESSION_TYPE_DEFAULT = "5";
|
||||
public static final String SESSION_PRINT_SESSION_HOST_DEFAULT = "";
|
||||
public static final String SESSION_PRINT_SESSION_HOST_PORT_DEFAULT = "23";
|
||||
public static final String SESSION_PRINT_SESSION_LU_NAME_DEFAULT = "";
|
||||
public static final String SESSION_PRINT_SESSION_AUTOCONNECT_DEFAULT = "true";
|
||||
public static final String SESSION_PRINT_SESSION_AUTORECONNECT_DEFAULT = "true";
|
||||
public static final String SESSION_LU_TYPE = "printerLUType";
|
||||
|
||||
public ECLHostPrintSession(Properties properties) throws ECLErr {
|
||||
super(properties);
|
||||
}
|
||||
|
||||
public ECLHostPrintSession() throws ECLErr {
|
||||
super();
|
||||
}
|
||||
|
||||
public void cancelPrintJob() {
|
||||
ECLPS ps = GetPS();
|
||||
if (ps != null) {
|
||||
try {
|
||||
ps.SendKeys("[cancelpjob]");
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
public void CancelPrintJob() {
|
||||
cancelPrintJob();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package com.ibm.eNetwork.ECL;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
* Operator Information Area facade matching IBM Host On-Demand ECLOIA.
|
||||
*/
|
||||
public class ECLOIA implements ECLConstants {
|
||||
|
||||
private final haus.nightmare.lib3270j.ecl.ECLOIA delegate;
|
||||
private final List<ECLOIANotify> oiaNotifies = new CopyOnWriteArrayList<>();
|
||||
|
||||
public ECLOIA(haus.nightmare.lib3270j.ecl.ECLOIA delegate) {
|
||||
this.delegate = delegate;
|
||||
if (delegate != null) {
|
||||
delegate.RegisterOIAEvent(new haus.nightmare.lib3270j.ecl.ECLOIAListener() {
|
||||
@Override
|
||||
public void OIANotifyEvent(haus.nightmare.lib3270j.ecl.ECLOIAEvent event) {
|
||||
ECLOIAEvent facadeEvt = new ECLOIAEvent(event);
|
||||
for (ECLOIANotify n : oiaNotifies) {
|
||||
try {
|
||||
n.OIANotifyEvent(facadeEvt);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void RegisterOIAEvent(ECLOIANotify notify) {
|
||||
if (notify != null && !oiaNotifies.contains(notify)) {
|
||||
oiaNotifies.add(notify);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerOIAEvent(ECLOIANotify notify) { RegisterOIAEvent(notify); }
|
||||
|
||||
public void RegisterOIAEvent(haus.nightmare.lib3270j.ecl.ECLOIAListener listener) {
|
||||
if (delegate != null) {
|
||||
delegate.RegisterOIAEvent(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public void UnregisterOIAEvent(ECLOIANotify notify) {
|
||||
if (notify != null) {
|
||||
oiaNotifies.remove(notify);
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterOIAEvent(ECLOIANotify notify) { UnregisterOIAEvent(notify); }
|
||||
|
||||
public void UnregisterOIAEvent(haus.nightmare.lib3270j.ecl.ECLOIAListener listener) {
|
||||
if (delegate != null) {
|
||||
delegate.UnregisterOIAEvent(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean IsAlphanumeric() {
|
||||
return delegate != null && delegate.IsAlphanumeric();
|
||||
}
|
||||
|
||||
public boolean isAlphanumeric() { return IsAlphanumeric(); }
|
||||
|
||||
public boolean IsNumeric() {
|
||||
return delegate != null && delegate.IsNumeric();
|
||||
}
|
||||
|
||||
public boolean isNumeric() { return IsNumeric(); }
|
||||
|
||||
public boolean IsDBCS() {
|
||||
return delegate != null && delegate.IsDBCS();
|
||||
}
|
||||
|
||||
public boolean isDBCS() { return IsDBCS(); }
|
||||
|
||||
public boolean IsInsertMode() {
|
||||
return delegate != null && delegate.IsInsertMode();
|
||||
}
|
||||
|
||||
public boolean isInsertMode() { return IsInsertMode(); }
|
||||
|
||||
public boolean IsCommError() {
|
||||
return delegate != null && delegate.IsCommError();
|
||||
}
|
||||
|
||||
public boolean isCommError() { return IsCommError(); }
|
||||
|
||||
public boolean IsKeyLocked() {
|
||||
return delegate != null && delegate.isKeyLocked();
|
||||
}
|
||||
|
||||
public boolean isKeyLocked() { return IsKeyLocked(); }
|
||||
|
||||
public boolean IsMessageWaiting() {
|
||||
return delegate != null && delegate.IsMessageWaiting();
|
||||
}
|
||||
|
||||
public boolean isMessageWaiting() { return IsMessageWaiting(); }
|
||||
|
||||
public int GetInputInhibited() {
|
||||
return delegate != null ? delegate.getInputInhibited() : 0;
|
||||
}
|
||||
|
||||
public int getInputInhibited() { return GetInputInhibited(); }
|
||||
|
||||
public int GetAlphanumericType() {
|
||||
return delegate != null ? delegate.getAlphanumericType() : 0;
|
||||
}
|
||||
|
||||
public int getAlphanumericType() { return GetAlphanumericType(); }
|
||||
|
||||
public boolean WaitForInput(long timeout) {
|
||||
return delegate != null && delegate.WaitForInput(timeout);
|
||||
}
|
||||
|
||||
public boolean WaitForSystemAvailable(long timeout) {
|
||||
return delegate != null && delegate.WaitForSystemAvailable(timeout);
|
||||
}
|
||||
|
||||
public boolean WaitForAppAvailable(long timeout) {
|
||||
return delegate != null && delegate.WaitForAppAvailable(timeout);
|
||||
}
|
||||
|
||||
public boolean WaitForTransition(long timeout) {
|
||||
return delegate != null && delegate.WaitForTransition(timeout);
|
||||
}
|
||||
|
||||
public haus.nightmare.lib3270j.ecl.ECLOIA getDelegate() { return delegate; }
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.ibm.eNetwork.ECL;
|
||||
|
||||
import com.ibm.eNetwork.ECL.event.ECLEvent;
|
||||
|
||||
/**
|
||||
* Event object dispatched on Operator Information Area (ECLOIA) status changes matching IBM HoD.
|
||||
*/
|
||||
public class ECLOIAEvent extends ECLEvent {
|
||||
|
||||
public String data;
|
||||
public long newState;
|
||||
public long changedMask;
|
||||
|
||||
private int inputInhibited = 0;
|
||||
private int alphanumericType = 0;
|
||||
private boolean insertMode = false;
|
||||
|
||||
public ECLOIAEvent(Object source, long newState, long changedMask, String data) {
|
||||
super(source);
|
||||
this.newState = newState;
|
||||
this.changedMask = changedMask;
|
||||
this.data = data != null ? data : "";
|
||||
}
|
||||
|
||||
public ECLOIAEvent(Object source, int eventType, int inputInhibited, int alphanumericType,
|
||||
boolean insertMode, String statusString) {
|
||||
super(source);
|
||||
this.inputInhibited = inputInhibited;
|
||||
this.alphanumericType = alphanumericType;
|
||||
this.insertMode = insertMode;
|
||||
this.data = statusString != null ? statusString : "";
|
||||
this.newState = inputInhibited;
|
||||
this.changedMask = eventType;
|
||||
}
|
||||
|
||||
public ECLOIAEvent(haus.nightmare.lib3270j.ecl.ECLOIAEvent delegate) {
|
||||
super(delegate != null ? delegate.getSource() : null);
|
||||
if (delegate != null) {
|
||||
this.inputInhibited = delegate.getInputInhibited();
|
||||
this.alphanumericType = delegate.getAlphanumericType();
|
||||
this.insertMode = delegate.isInsertMode();
|
||||
this.data = delegate.getStatusString();
|
||||
this.newState = delegate.getInputInhibited();
|
||||
this.changedMask = delegate.getEventType();
|
||||
}
|
||||
}
|
||||
|
||||
public ECLOIA GetOIA() {
|
||||
Object src = GetSource();
|
||||
if (src instanceof ECLOIA) {
|
||||
return (ECLOIA) src;
|
||||
} else if (src instanceof haus.nightmare.lib3270j.ecl.ECLOIA) {
|
||||
return new ECLOIA((haus.nightmare.lib3270j.ecl.ECLOIA) src);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ECLOIA getOIA() { return GetOIA(); }
|
||||
|
||||
public int GetInputInhibited() { return inputInhibited; }
|
||||
public int getInputInhibited() { return inputInhibited; }
|
||||
|
||||
public int GetAlphanumericType() { return alphanumericType; }
|
||||
public int getAlphanumericType() { return alphanumericType; }
|
||||
|
||||
public boolean IsInsertMode() { return insertMode; }
|
||||
public boolean isInsertMode() { return insertMode; }
|
||||
|
||||
public boolean IsInputInhibited() { return inputInhibited != 0; }
|
||||
public boolean isInputInhibited() { return IsInputInhibited(); }
|
||||
|
||||
public String GetStatusString() { return data; }
|
||||
public String getStatusString() { return data; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ECLOIAEvent: changedMask=0x" + Long.toHexString(this.changedMask) +
|
||||
", newState=0x" + Long.toHexString(this.newState) + ", data=" + this.data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.ibm.eNetwork.ECL;
|
||||
|
||||
/**
|
||||
* Operator Information Area notification interface matching IBM Host On-Demand ECLOIANotify.
|
||||
*/
|
||||
public interface ECLOIANotify {
|
||||
void NotifyEvent(ECLOIA oia, int inhibitReason, int state, String text);
|
||||
default void NotifyStop(ECLOIA oia, int reason) {}
|
||||
default void NotifyError(ECLOIA oia, ECLErr err) {}
|
||||
default void OIANotifyStop(ECLOIA oia, int reason) { NotifyStop(oia, reason); }
|
||||
default void OIANotifyError(ECLOIA oia, ECLErr err) { NotifyError(oia, err); }
|
||||
default void OIANotifyEvent(ECLOIAEvent event) {
|
||||
if (event != null) {
|
||||
NotifyEvent(event.GetOIA(), event.GetInputInhibited(), 0, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,514 @@
|
||||
package com.ibm.eNetwork.ECL;
|
||||
|
||||
import com.ibm.eNetwork.ECL.event.ECLPSListener;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Presentation Space facade matching IBM Host On-Demand ECLPS.
|
||||
* Provides 1-based indexing, method signature parity, and checked ECLErr exception semantics.
|
||||
*/
|
||||
public class ECLPS implements ECLConstants, Serializable, Cloneable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final haus.nightmare.lib3270j.ecl.ECLPS delegate;
|
||||
|
||||
public ECLPS(haus.nightmare.lib3270j.ecl.ECLPS delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public ECLPS(haus.nightmare.lib3270j.ecl.ECLSession session) {
|
||||
this(session != null ? session.GetPS() : null);
|
||||
}
|
||||
|
||||
public ECLPS(ECLSession session) {
|
||||
this(session != null ? session.getDelegate() : null);
|
||||
}
|
||||
|
||||
public haus.nightmare.lib3270j.ecl.ECLPS getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
// ========== Dimensions & Position Conversion (1-based) ==========
|
||||
|
||||
public int GetSize() {
|
||||
return delegate != null ? delegate.GetSize() : 0;
|
||||
}
|
||||
|
||||
public int getSize() { return GetSize(); }
|
||||
|
||||
public int GetRows() {
|
||||
return delegate != null ? delegate.GetRows() : 0;
|
||||
}
|
||||
|
||||
public int getRows() { return GetRows(); }
|
||||
|
||||
public int GetCols() {
|
||||
return delegate != null ? delegate.GetCols() : 0;
|
||||
}
|
||||
|
||||
public int getCols() { return GetCols(); }
|
||||
|
||||
public int GetSizeRows() { return GetRows(); }
|
||||
public int GetSizeCols() { return GetCols(); }
|
||||
|
||||
public int ConvertRowColToPos(int row, int col) throws ECLErr {
|
||||
if (delegate != null) {
|
||||
try {
|
||||
return delegate.ConvertRowColToPos(row, col);
|
||||
} catch (haus.nightmare.lib3270j.ecl.ECLErr e) {
|
||||
throw new ECLErr(e.getMessage());
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int convertRowColToPos(int row, int col) throws ECLErr {
|
||||
return ConvertRowColToPos(row, col);
|
||||
}
|
||||
|
||||
public int ConvertPosToRow(int pos) throws ECLErr {
|
||||
if (delegate != null) {
|
||||
try {
|
||||
return delegate.ConvertPosToRow(pos);
|
||||
} catch (haus.nightmare.lib3270j.ecl.ECLErr e) {
|
||||
throw new ECLErr(e.getMessage());
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int convertPosToRow(int pos) throws ECLErr {
|
||||
return ConvertPosToRow(pos);
|
||||
}
|
||||
|
||||
public int ConvertPosToCol(int pos) throws ECLErr {
|
||||
if (delegate != null) {
|
||||
try {
|
||||
return delegate.ConvertPosToCol(pos);
|
||||
} catch (haus.nightmare.lib3270j.ecl.ECLErr e) {
|
||||
throw new ECLErr(e.getMessage());
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int convertPosToCol(int pos) throws ECLErr {
|
||||
return ConvertPosToCol(pos);
|
||||
}
|
||||
|
||||
public void ConvertPosToRowCol(int pos, int[] rowCol) throws ECLErr {
|
||||
if (delegate != null) {
|
||||
try {
|
||||
delegate.ConvertPosToRowCol(pos, rowCol);
|
||||
} catch (haus.nightmare.lib3270j.ecl.ECLErr e) {
|
||||
throw new ECLErr(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void convertPosToRowCol(int pos, int[] rowCol) throws ECLErr {
|
||||
ConvertPosToRowCol(pos, rowCol);
|
||||
}
|
||||
|
||||
public int[] ConvertPosToRowCol(int pos) throws ECLErr {
|
||||
if (delegate != null) {
|
||||
try {
|
||||
return delegate.ConvertPosToRowCol(pos);
|
||||
} catch (haus.nightmare.lib3270j.ecl.ECLErr e) {
|
||||
throw new ECLErr(e.getMessage());
|
||||
}
|
||||
}
|
||||
return new int[]{1, 1};
|
||||
}
|
||||
|
||||
public int[] convertPosToRowCol(int pos) throws ECLErr {
|
||||
return ConvertPosToRowCol(pos);
|
||||
}
|
||||
|
||||
// ========== Cursor Operations (1-based) ==========
|
||||
|
||||
public int GetCursorPos() {
|
||||
return delegate != null ? delegate.GetCursorPos() : 1;
|
||||
}
|
||||
|
||||
public int getCursorPos() { return GetCursorPos(); }
|
||||
|
||||
public int GetCursorRow() {
|
||||
return delegate != null ? delegate.GetCursorRow() : 1;
|
||||
}
|
||||
|
||||
public int getCursorRow() { return GetCursorRow(); }
|
||||
|
||||
public int GetCursorCol() {
|
||||
return delegate != null ? delegate.GetCursorCol() : 1;
|
||||
}
|
||||
|
||||
public int getCursorCol() { return GetCursorCol(); }
|
||||
|
||||
public void SetCursorPos(int pos) throws ECLErr {
|
||||
if (delegate != null) {
|
||||
try {
|
||||
delegate.SetCursorPos(pos);
|
||||
} catch (haus.nightmare.lib3270j.ecl.ECLErr e) {
|
||||
throw new ECLErr(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setCursorPos(int pos) throws ECLErr {
|
||||
SetCursorPos(pos);
|
||||
}
|
||||
|
||||
public void SetCursorPos(int row, int col) throws ECLErr {
|
||||
if (delegate != null) {
|
||||
try {
|
||||
delegate.SetCursorPos(row, col);
|
||||
} catch (haus.nightmare.lib3270j.ecl.ECLErr e) {
|
||||
throw new ECLErr(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setCursorPos(int row, int col) throws ECLErr {
|
||||
SetCursorPos(row, col);
|
||||
}
|
||||
|
||||
// ========== GetString & SetString Operations (1-based) ==========
|
||||
|
||||
public int GetString(char[] buffer, int len, int pos) throws ECLErr {
|
||||
return GetString(buffer, len, pos, len);
|
||||
}
|
||||
|
||||
public int GetString(char[] buffer, int len, int pos, int length) throws ECLErr {
|
||||
if (delegate != null) {
|
||||
try {
|
||||
return delegate.GetString(buffer, len, pos, length);
|
||||
} catch (haus.nightmare.lib3270j.ecl.ECLErr e) {
|
||||
throw new ECLErr(e.getMessage());
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int GetString(char[] buffer, int len, int row, int col, int length) throws ECLErr {
|
||||
return GetString(buffer, len, ConvertRowColToPos(row, col), length);
|
||||
}
|
||||
|
||||
public String GetString(int pos, int length) throws ECLErr {
|
||||
if (delegate != null) {
|
||||
try {
|
||||
return delegate.GetString(pos, length);
|
||||
} catch (haus.nightmare.lib3270j.ecl.ECLErr e) {
|
||||
throw new ECLErr(e.getMessage());
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getString(int pos, int length) throws ECLErr {
|
||||
return GetString(pos, length);
|
||||
}
|
||||
|
||||
public String GetString(int row, int col, int length) throws ECLErr {
|
||||
return GetString(ConvertRowColToPos(row, col), length);
|
||||
}
|
||||
|
||||
public String getString(int row, int col, int length) throws ECLErr {
|
||||
return GetString(row, col, length);
|
||||
}
|
||||
|
||||
public void SetString(String text, int pos) throws ECLErr {
|
||||
if (delegate != null) {
|
||||
try {
|
||||
delegate.SetString(text, pos);
|
||||
} catch (haus.nightmare.lib3270j.ecl.ECLErr e) {
|
||||
throw new ECLErr(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setString(String text, int pos) throws ECLErr {
|
||||
SetString(text, pos);
|
||||
}
|
||||
|
||||
public void SetString(String text, int row, int col) throws ECLErr {
|
||||
SetString(text, ConvertRowColToPos(row, col));
|
||||
}
|
||||
|
||||
public void setString(String text, int row, int col) throws ECLErr {
|
||||
SetString(text, row, col);
|
||||
}
|
||||
|
||||
public void SetString(String text) throws ECLErr {
|
||||
SetString(text, GetCursorPos());
|
||||
}
|
||||
|
||||
public void setString(String text) throws ECLErr {
|
||||
SetString(text);
|
||||
}
|
||||
|
||||
public void SetText(String text, int pos) throws ECLErr {
|
||||
SetString(text, pos);
|
||||
}
|
||||
|
||||
public void SetText(String text, int row, int col) throws ECLErr {
|
||||
SetString(text, row, col);
|
||||
}
|
||||
|
||||
public void setText(String text, int pos) {
|
||||
if (delegate != null) delegate.setText(text, pos);
|
||||
}
|
||||
|
||||
public void setText(String text, int row, int col) {
|
||||
if (delegate != null) delegate.setText(text, row, col);
|
||||
}
|
||||
|
||||
// ========== Search Operations (1-based) ==========
|
||||
|
||||
public int SearchText(String text, int dir, int startPos) {
|
||||
return delegate != null ? delegate.SearchText(text, dir, startPos) : 0;
|
||||
}
|
||||
|
||||
public int SearchText(String text, int dir) {
|
||||
return delegate != null ? delegate.SearchText(text, dir) : 0;
|
||||
}
|
||||
|
||||
public int SearchText(String text) {
|
||||
return delegate != null ? delegate.SearchText(text) : 0;
|
||||
}
|
||||
|
||||
public int SearchText(String text, int row, int col, int dir) throws ECLErr {
|
||||
return SearchText(text, dir, ConvertRowColToPos(row, col));
|
||||
}
|
||||
|
||||
public int SearchString(String text, int dir, int startPos) {
|
||||
return SearchText(text, dir, startPos);
|
||||
}
|
||||
|
||||
public int SearchString(String text, int dir) {
|
||||
return SearchText(text, dir);
|
||||
}
|
||||
|
||||
public int SearchString(String text) {
|
||||
return SearchText(text);
|
||||
}
|
||||
|
||||
public int SearchString(String text, int row, int col, int dir) throws ECLErr {
|
||||
return SearchText(text, row, col, dir);
|
||||
}
|
||||
|
||||
public int SearchPS(String text) {
|
||||
return delegate != null ? delegate.SearchPS(text) : 0;
|
||||
}
|
||||
|
||||
public int SearchPS(String text, int startPos) {
|
||||
return delegate != null ? delegate.SearchPS(text, startPos) : 0;
|
||||
}
|
||||
|
||||
public int SearchPSExt(String text, int startPos, int endPos, int dir, boolean ignoreCase, boolean wrap) {
|
||||
return delegate != null ? delegate.SearchPSExt(text, startPos, endPos, dir, ignoreCase, wrap) : 0;
|
||||
}
|
||||
|
||||
// ========== Keystrokes & Mnemonics ==========
|
||||
|
||||
public void SendKeys(String keys) {
|
||||
if (delegate != null) delegate.SendKeys(keys);
|
||||
}
|
||||
|
||||
public void sendKeys(String keys) { SendKeys(keys); }
|
||||
|
||||
public void SendKeys(String keys, int pos) {
|
||||
if (delegate != null) delegate.SendKeys(keys, pos);
|
||||
}
|
||||
|
||||
public void sendKeys(String keys, int pos) { SendKeys(keys, pos); }
|
||||
|
||||
public void SendKeys(String keys, int row, int col) {
|
||||
if (delegate != null) delegate.SendKeys(keys, row, col);
|
||||
}
|
||||
|
||||
public void sendKeys(String keys, int row, int col) { SendKeys(keys, row, col); }
|
||||
|
||||
public void SendCharacters(String keys) {
|
||||
if (delegate != null) delegate.SendCharacters(keys);
|
||||
}
|
||||
|
||||
public void sendCharacters(String keys) { SendCharacters(keys); }
|
||||
|
||||
public void SendCharacters(String keys, int delayMs) {
|
||||
if (delegate != null) delegate.SendCharacters(keys, delayMs);
|
||||
}
|
||||
|
||||
public void sendCharacters(String keys, int delayMs) { SendCharacters(keys, delayMs); }
|
||||
|
||||
public void SendCharacters(String keys, int pos, int delayMs) {
|
||||
if (delegate != null) delegate.SendCharacters(keys, pos, delayMs);
|
||||
}
|
||||
|
||||
public void sendCharacters(String keys, int pos, int delayMs) { SendCharacters(keys, pos, delayMs); }
|
||||
|
||||
public void SendCharacters(String keys, int row, int col, int delayMs) {
|
||||
if (delegate != null) delegate.SendCharacters(keys, row, col, delayMs);
|
||||
}
|
||||
|
||||
public void sendCharacters(String keys, int row, int col, int delayMs) { SendCharacters(keys, row, col, delayMs); }
|
||||
|
||||
public String[] GetSendKeyMnemonics() {
|
||||
return delegate != null ? delegate.GetSendKeyMnemonics() : new String[0];
|
||||
}
|
||||
|
||||
public String[] getSendKeyMnemonics() { return GetSendKeyMnemonics(); }
|
||||
|
||||
// ========== Field Operations ==========
|
||||
|
||||
public ECLFieldList GetFieldList() {
|
||||
haus.nightmare.lib3270j.ecl.ECLFieldList fl = delegate != null ? delegate.GetFieldList() : null;
|
||||
return new ECLFieldList(fl, this);
|
||||
}
|
||||
|
||||
public ECLFieldList getFieldList() { return GetFieldList(); }
|
||||
|
||||
public ECLField GetField(int pos) throws ECLErr {
|
||||
return GetFieldList().FindField(pos);
|
||||
}
|
||||
|
||||
public ECLField getField(int pos) throws ECLErr { return GetField(pos); }
|
||||
|
||||
public ECLField GetField(int row, int col) throws ECLErr {
|
||||
return GetFieldList().FindField(row, col);
|
||||
}
|
||||
|
||||
public ECLField getField(int row, int col) throws ECLErr { return GetField(row, col); }
|
||||
|
||||
public ECLField GetFirstField() {
|
||||
return GetFieldList().GetFirstField();
|
||||
}
|
||||
|
||||
public ECLField getFirstField() { return GetFirstField(); }
|
||||
|
||||
public ECLField GetNextField(ECLField prev) {
|
||||
return GetFieldList().GetNextField(prev);
|
||||
}
|
||||
|
||||
public ECLField getNextField(ECLField prev) { return GetNextField(prev); }
|
||||
|
||||
// ========== Listener Overloads for HoD Interfaces ==========
|
||||
|
||||
public void RegisterPSEvent(ECLPSNotify notify) {
|
||||
if (delegate != null) delegate.RegisterPSEvent(notify);
|
||||
}
|
||||
|
||||
public void registerPSEvent(ECLPSNotify notify) { RegisterPSEvent(notify); }
|
||||
|
||||
public void RegisterPSEvent(ECLPSNotify notify, int eventType) {
|
||||
if (delegate != null) delegate.RegisterPSEvent(notify, eventType);
|
||||
}
|
||||
|
||||
public void registerPSEvent(ECLPSNotify notify, int eventType) { RegisterPSEvent(notify, eventType); }
|
||||
|
||||
public void RegisterPSEvent(ECLPSNotify notify, ECLScreenDesc desc) {
|
||||
if (delegate != null) delegate.RegisterPSEvent(notify, desc);
|
||||
}
|
||||
|
||||
public void registerPSEvent(ECLPSNotify notify, ECLScreenDesc desc) { RegisterPSEvent(notify, desc); }
|
||||
|
||||
public void RegisterPSEvent(ECLPSNotify notify, ECLScreenDesc desc, int eventType) {
|
||||
if (delegate != null) delegate.RegisterPSEvent(notify, desc, eventType);
|
||||
}
|
||||
|
||||
public void registerPSEvent(ECLPSNotify notify, ECLScreenDesc desc, int eventType) { RegisterPSEvent(notify, desc, eventType); }
|
||||
|
||||
public void UnregisterPSEvent(ECLPSNotify notify) {
|
||||
if (delegate != null) delegate.UnregisterPSEvent(notify);
|
||||
}
|
||||
|
||||
public void unregisterPSEvent(ECLPSNotify notify) { UnregisterPSEvent(notify); }
|
||||
|
||||
public void RegisterPSEvent(ECLPSListener listener) {
|
||||
if (delegate != null) delegate.RegisterPSEvent(listener);
|
||||
}
|
||||
|
||||
public void registerPSEvent(ECLPSListener listener) { RegisterPSEvent(listener); }
|
||||
|
||||
public void UnregisterPSEvent(ECLPSListener listener) {
|
||||
if (delegate != null) delegate.UnregisterPSEvent(listener);
|
||||
}
|
||||
|
||||
public void unregisterPSEvent(ECLPSListener listener) { UnregisterPSEvent(listener); }
|
||||
|
||||
// ========== Synchronization & Waits ==========
|
||||
|
||||
public boolean WaitForScreen(ECLScreenDesc desc, long timeoutMs) {
|
||||
return delegate != null && delegate.WaitForScreen(desc, timeoutMs);
|
||||
}
|
||||
|
||||
public boolean waitForScreen(ECLScreenDesc desc, long timeoutMs) { return WaitForScreen(desc, timeoutMs); }
|
||||
|
||||
public boolean WaitForScreen(ECLScreenDesc desc) {
|
||||
return delegate != null && delegate.WaitForScreen(desc);
|
||||
}
|
||||
|
||||
public boolean waitForScreen(ECLScreenDesc desc) { return WaitForScreen(desc); }
|
||||
|
||||
public boolean WaitWhileScreen(ECLScreenDesc desc, long timeoutMs) {
|
||||
return delegate != null && delegate.WaitWhileScreen(desc, timeoutMs);
|
||||
}
|
||||
|
||||
public boolean waitWhileScreen(ECLScreenDesc desc, long timeoutMs) { return WaitWhileScreen(desc, timeoutMs); }
|
||||
|
||||
public boolean WaitWhileScreen(ECLScreenDesc desc) {
|
||||
return delegate != null && delegate.WaitWhileScreen(desc);
|
||||
}
|
||||
|
||||
public boolean waitWhileScreen(ECLScreenDesc desc) { return WaitWhileScreen(desc); }
|
||||
|
||||
public boolean WaitForString(String text, long timeoutMs) {
|
||||
return delegate != null && delegate.WaitForString(text, timeoutMs);
|
||||
}
|
||||
|
||||
public boolean waitForString(String text, long timeoutMs) { return WaitForString(text, timeoutMs); }
|
||||
|
||||
public boolean WaitForString(String text) {
|
||||
return delegate != null && delegate.WaitForString(text);
|
||||
}
|
||||
|
||||
public boolean waitForString(String text) { return WaitForString(text); }
|
||||
|
||||
public boolean WaitForString(String text, int row, int col, long timeoutMs) {
|
||||
return delegate != null && delegate.WaitForString(text, row, col, timeoutMs);
|
||||
}
|
||||
|
||||
public boolean waitForString(String text, int row, int col, long timeoutMs) { return WaitForString(text, row, col, timeoutMs); }
|
||||
|
||||
public boolean WaitForCursor(int row, int col, long timeoutMs) {
|
||||
return delegate != null && delegate.WaitForCursor(row, col, timeoutMs);
|
||||
}
|
||||
|
||||
public boolean waitForCursor(int row, int col, long timeoutMs) { return WaitForCursor(row, col, timeoutMs); }
|
||||
|
||||
// ========== Screen Update Inquiries ==========
|
||||
|
||||
public ECLPSUpdate GetScreen(int startRow, int startCol, int length) throws ECLErr {
|
||||
return GetScreen(startRow, startCol, length, false);
|
||||
}
|
||||
|
||||
public ECLPSUpdate GetScreen(int startRow, int startCol, int length, boolean fillNulls) throws ECLErr {
|
||||
int pos = ConvertRowColToPos(startRow, startCol);
|
||||
char[] buf = new char[length];
|
||||
GetString(buf, length, pos, length);
|
||||
if (fillNulls) {
|
||||
for (int i = 0; i < buf.length; i++) {
|
||||
if (buf[i] == '\0') buf[i] = ' ';
|
||||
}
|
||||
}
|
||||
int endPos = pos + length - 1;
|
||||
int endRow = ConvertPosToRow(endPos);
|
||||
int endCol = ConvertPosToCol(endPos);
|
||||
return new ECLPSUpdate(this, startRow, startCol, endRow, endCol, new String(buf));
|
||||
}
|
||||
|
||||
public int GetScreen(char[] buffer, int len, int row, int col, int length, int plane) {
|
||||
return delegate.GetScreen(buffer, len, row, col, length, plane);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.ibm.eNetwork.ECL;
|
||||
|
||||
/**
|
||||
* Presentation space notification interface matching IBM Host On-Demand ECLPSNotify.
|
||||
*/
|
||||
public interface ECLPSNotify {
|
||||
void NotifyEvent(ECLPS ps);
|
||||
default void NotifyStop(ECLPS ps, int reason) {}
|
||||
default void NotifyError(ECLPS ps, ECLErr err) {}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.ibm.eNetwork.ECL;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Conforms to IBM Host On-Demand ECLPSUpdate.
|
||||
*/
|
||||
public class ECLPSUpdate implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final haus.nightmare.lib3270j.ecl.ECLPSUpdate delegate;
|
||||
private final int startRow;
|
||||
private final int startCol;
|
||||
private final int endRow;
|
||||
private final int endCol;
|
||||
private final int start;
|
||||
private final int end;
|
||||
private final boolean fullUpdate;
|
||||
private final String text;
|
||||
private final transient ECLPS ps;
|
||||
|
||||
public ECLPSUpdate(ECLPS ps, int startRow, int startCol, int endRow, int endCol,
|
||||
int start, int end, boolean fullUpdate, String text) {
|
||||
this.ps = ps;
|
||||
this.startRow = startRow;
|
||||
this.startCol = startCol;
|
||||
this.endRow = endRow;
|
||||
this.endCol = endCol;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.fullUpdate = fullUpdate;
|
||||
this.text = text != null ? text : "";
|
||||
this.delegate = null;
|
||||
}
|
||||
|
||||
public ECLPSUpdate(ECLPS ps, int startRow, int startCol, int endRow, int endCol, String text) {
|
||||
this(ps, startRow, startCol, endRow, endCol, 0, 0, false, text);
|
||||
}
|
||||
|
||||
public ECLPSUpdate(int startRow, int startCol, int endRow, int endCol, String text) {
|
||||
this(null, startRow, startCol, endRow, endCol, 0, 0, false, text);
|
||||
}
|
||||
|
||||
public ECLPSUpdate(haus.nightmare.lib3270j.ecl.ECLPSUpdate delegate) {
|
||||
this.delegate = delegate;
|
||||
this.ps = (delegate != null && delegate.getPS() != null) ? new ECLPS(delegate.getPS()) : null;
|
||||
this.startRow = delegate != null ? delegate.getStartRow() : 0;
|
||||
this.startCol = delegate != null ? delegate.getStartCol() : 0;
|
||||
this.endRow = delegate != null ? delegate.getEndRow() : 0;
|
||||
this.endCol = delegate != null ? delegate.getEndCol() : 0;
|
||||
this.start = delegate != null ? delegate.getStart() : 0;
|
||||
this.end = delegate != null ? delegate.getEnd() : 0;
|
||||
this.fullUpdate = delegate != null && delegate.isFullUpdate();
|
||||
this.text = delegate != null ? delegate.getText() : "";
|
||||
}
|
||||
|
||||
public ECLPS getPS() { return ps; }
|
||||
public ECLPS GetPS() { return ps; }
|
||||
|
||||
public int getStartRow() { return startRow; }
|
||||
public int GetStartRow() { return startRow + 1; }
|
||||
|
||||
public int getStartCol() { return startCol; }
|
||||
public int GetStartCol() { return startCol + 1; }
|
||||
|
||||
public int getEndRow() { return endRow; }
|
||||
public int GetEndRow() { return endRow + 1; }
|
||||
|
||||
public int getEndCol() { return endCol; }
|
||||
public int GetEndCol() { return endCol + 1; }
|
||||
|
||||
public int getStart() { return start; }
|
||||
public int GetStart() { return start + 1; }
|
||||
|
||||
public int getEnd() { return end; }
|
||||
public int GetEnd() { return end + 1; }
|
||||
|
||||
public boolean isFullUpdate() { return fullUpdate; }
|
||||
public boolean IsFullUpdate() { return fullUpdate; }
|
||||
|
||||
public String getText() { return text; }
|
||||
public String GetText() { return text; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("ECLPSUpdate[start=(%d,%d), end=(%d,%d), full=%b]",
|
||||
startRow, startCol, endRow, endCol, fullUpdate);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.ibm.eNetwork.ECL;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Screen descriptor matching engine facade matching IBM Host On-Demand ECLScreenDesc.
|
||||
*/
|
||||
public class ECLScreenDesc extends haus.nightmare.lib3270j.ecl.ECLScreenDesc implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ECLScreenDesc() {
|
||||
super();
|
||||
}
|
||||
|
||||
public boolean Matches(ECLPS ps, ECLOIA oia) {
|
||||
haus.nightmare.lib3270j.ecl.ECLPS p = (ps != null) ? ps.getDelegate() : null;
|
||||
haus.nightmare.lib3270j.ecl.ECLOIA o = (oia != null) ? oia.getDelegate() : null;
|
||||
return super.Matches(p, o);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.ibm.eNetwork.ECL;
|
||||
|
||||
/**
|
||||
* Listener interface for ECLScreenReco matching notifications matching IBM HoD.
|
||||
*/
|
||||
public interface ECLScreenNotify {
|
||||
void screenMatching(ECLScreenRecoEvent event);
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.ibm.eNetwork.ECL;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Screen recognition facade matching IBM Host On-Demand ECLScreenReco.
|
||||
*/
|
||||
public class ECLScreenReco {
|
||||
|
||||
private final haus.nightmare.lib3270j.ecl.ECLScreenReco delegate;
|
||||
private final ECLPS ps;
|
||||
private final Map<ECLScreenDesc, ECLScreenNotify> notifyMap = new ConcurrentHashMap<>();
|
||||
|
||||
public ECLScreenReco() {
|
||||
this((ECLPS) null);
|
||||
}
|
||||
|
||||
public ECLScreenReco(ECLSession session) {
|
||||
this(session != null ? session.GetPS() : null);
|
||||
}
|
||||
|
||||
public ECLScreenReco(ECLPS ps) {
|
||||
this(ps, (ECLOIA) null);
|
||||
}
|
||||
|
||||
public ECLScreenReco(ECLPS ps, ECLOIA oia) {
|
||||
this.ps = ps;
|
||||
this.delegate = new haus.nightmare.lib3270j.ecl.ECLScreenReco(ps != null ? ps.getDelegate() : null,
|
||||
oia != null ? oia.getDelegate() : null);
|
||||
}
|
||||
|
||||
public ECLScreenReco(haus.nightmare.lib3270j.ecl.ECLScreenReco delegate) {
|
||||
this.delegate = delegate;
|
||||
this.ps = null;
|
||||
}
|
||||
|
||||
public void RegisterScreen(ECLScreenDesc desc, ECLScreenNotify notify) {
|
||||
if (desc != null && notify != null) {
|
||||
notifyMap.put(desc, notify);
|
||||
if (delegate != null) {
|
||||
delegate.RegisterScreen(desc, event -> notify.screenMatching(new ECLScreenRecoEvent(this, desc, ps)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void registerScreen(ECLScreenDesc desc, ECLScreenNotify notify) {
|
||||
RegisterScreen(desc, notify);
|
||||
}
|
||||
|
||||
public void UnregisterScreen(ECLScreenDesc desc) {
|
||||
if (desc != null) {
|
||||
notifyMap.remove(desc);
|
||||
if (delegate != null) {
|
||||
delegate.UnregisterScreen(desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterScreen(ECLScreenDesc desc) {
|
||||
UnregisterScreen(desc);
|
||||
}
|
||||
|
||||
public boolean IsMatch(ECLScreenDesc desc) {
|
||||
if (delegate != null) {
|
||||
return delegate.IsMatch(desc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean IsMatch(ECLPS ps, ECLScreenDesc desc) {
|
||||
if (ps == null) return false;
|
||||
if (desc == null) return true;
|
||||
return desc.Matches(ps, (ECLOIA) null);
|
||||
}
|
||||
|
||||
public haus.nightmare.lib3270j.ecl.ECLScreenReco getDelegate() { return delegate; }
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.ibm.eNetwork.ECL;
|
||||
|
||||
import com.ibm.eNetwork.ECL.event.ECLEvent;
|
||||
|
||||
/**
|
||||
* Event delivered when an ECLScreenDesc matches the Presentation Space.
|
||||
*/
|
||||
public class ECLScreenRecoEvent extends ECLEvent {
|
||||
|
||||
private final ECLScreenReco source;
|
||||
private final ECLScreenDesc screenDesc;
|
||||
private final ECLPS ps;
|
||||
|
||||
public ECLScreenRecoEvent(ECLScreenReco source, ECLScreenDesc screenDesc, ECLPS ps) {
|
||||
super(source);
|
||||
this.source = source;
|
||||
this.screenDesc = screenDesc;
|
||||
this.ps = ps;
|
||||
}
|
||||
|
||||
public ECLScreenRecoEvent(Object source, ECLPS ps) {
|
||||
super(source);
|
||||
this.source = (source instanceof ECLScreenReco) ? (ECLScreenReco) source : null;
|
||||
this.screenDesc = null;
|
||||
this.ps = ps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object GetSource() { return source != null ? source : super.GetSource(); }
|
||||
|
||||
public ECLScreenReco GetScreenReco() { return source; }
|
||||
public ECLScreenReco getScreenReco() { return source; }
|
||||
|
||||
public ECLScreenDesc GetScreenDesc() { return screenDesc; }
|
||||
public ECLScreenDesc getScreenDesc() { return screenDesc; }
|
||||
|
||||
public ECLPS GetPS() { return ps; }
|
||||
public ECLPS getPS() { return ps; }
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
package com.ibm.eNetwork.ECL;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Top-level session facade matching IBM Host On-Demand ECLSession.
|
||||
* Extends ECLConnection and provides access to Presentation Space (ECLPS),
|
||||
* Operator Information Area (ECLOIA), File Transfer (ECLXfer), and Screen Recognition (ECLScreenReco).
|
||||
*/
|
||||
public class ECLSession extends ECLConnection implements ECLConstants {
|
||||
|
||||
public static final String SESSION_NAME = "SESSION_NAME";
|
||||
public static final String SESSION_LABEL = "SESSION_LABEL";
|
||||
public static final String SESSION_TYPE = "SESSION_TYPE";
|
||||
public static final String SESSION_HOST = "SESSION_HOST";
|
||||
public static final String SESSION_HOST_PORT = "SESSION_HOST_PORT";
|
||||
public static final String SESSION_PORT = "SESSION_PORT";
|
||||
public static final String SESSION_PS_SIZE = "SESSION_PS_SIZE";
|
||||
public static final String SESSION_CODE_PAGE = "SESSION_CODE_PAGE";
|
||||
public static final String SESSION_SSL = "SESSION_SSL";
|
||||
public static final String SESSION_SECURITY_PROTOCOL = "SESSION_SECURITY_PROTOCOL";
|
||||
public static final String SESSION_TLS_PROTOCOL_VERSION = "tlsProtocolVersion";
|
||||
public static final String SESSION_LU_NAME = "SESSION_LU_NAME";
|
||||
public static final String SESSION_TN3270E = "SESSION_TN3270E";
|
||||
public static final String SESSION_AUTO_CONNECT = "SESSION_AUTO_CONNECT";
|
||||
public static final String SESSION_AUTORECONNECT = "SESSION_AUTORECONNECT";
|
||||
public static final String SESSION_RECONNECT_RETRIES = "SESSION_RECONNECT_RETRIES";
|
||||
public static final String SESSION_KEEPALIVE = "SESSION_KEEPALIVE";
|
||||
public static final String KEY_KEEPALIVE_TYPE = "keepAliveType";
|
||||
public static final String KEY_KEEPALIVE_TIMEOUT = "keepAliveTimeout";
|
||||
public static final String SESSION_AUTO_SYS_UNLOCK = "autoSysUnlock";
|
||||
public static final String ENABLE_PASTE_FROM_EXCEL = "enablePasteFromExcel";
|
||||
public static final String PASTE_TAB_OPTIONS = "pasteTabOptions";
|
||||
public static final String PASTE_STOP_AT_PROTECTED_LINE = "pasteStopAtProtectedLine";
|
||||
public static final String BLOCK_PASTE = "blockPaste";
|
||||
public static final String PASTE_FIELD_WRAP = "pasteFieldWrap";
|
||||
public static final String PASTE_LINE_WRAP = "pasteLineWrap";
|
||||
|
||||
private final haus.nightmare.lib3270j.ecl.ECLSession delegate;
|
||||
private final ECLPS ps;
|
||||
private final ECLOIA oia;
|
||||
private final ECLXfer xfer;
|
||||
private final ECLScreenReco screenReco;
|
||||
|
||||
public ECLSession(Properties properties) throws ECLErr {
|
||||
super(properties);
|
||||
this.delegate = new haus.nightmare.lib3270j.ecl.ECLSession(properties);
|
||||
this.ps = new ECLPS(delegate.getPS());
|
||||
this.oia = new ECLOIA(delegate.getOIA());
|
||||
this.xfer = new ECLXfer(delegate.getXfer());
|
||||
this.screenReco = new ECLScreenReco(this.ps, this.oia);
|
||||
}
|
||||
|
||||
public ECLSession() throws ECLErr {
|
||||
this(new Properties());
|
||||
}
|
||||
|
||||
public ECLSession(String host, int port) throws ECLErr {
|
||||
super(host, port);
|
||||
Properties props = new Properties();
|
||||
if (host != null) props.setProperty(SESSION_HOST, host);
|
||||
props.setProperty(SESSION_PORT, String.valueOf(port));
|
||||
this.delegate = new haus.nightmare.lib3270j.ecl.ECLSession(props);
|
||||
this.ps = new ECLPS(delegate.getPS());
|
||||
this.oia = new ECLOIA(delegate.getOIA());
|
||||
this.xfer = new ECLXfer(delegate.getXfer());
|
||||
this.screenReco = new ECLScreenReco(this.ps, this.oia);
|
||||
}
|
||||
|
||||
public ECLSession(haus.nightmare.lib3270j.ecl.ECLSession delegate) {
|
||||
super(delegate);
|
||||
this.delegate = delegate;
|
||||
this.ps = new ECLPS(delegate != null ? delegate.getPS() : null);
|
||||
this.oia = new ECLOIA(delegate != null ? delegate.getOIA() : null);
|
||||
this.xfer = new ECLXfer(delegate != null ? delegate.getXfer() : null);
|
||||
this.screenReco = new ECLScreenReco(this.ps, this.oia);
|
||||
}
|
||||
|
||||
public ECLPS GetPS() {
|
||||
return ps;
|
||||
}
|
||||
|
||||
public ECLPS getPS() {
|
||||
return ps;
|
||||
}
|
||||
|
||||
public ECLOIA GetOIA() {
|
||||
return oia;
|
||||
}
|
||||
|
||||
public ECLOIA getOIA() {
|
||||
return oia;
|
||||
}
|
||||
|
||||
public ECLXfer GetXfer() {
|
||||
return xfer;
|
||||
}
|
||||
|
||||
public ECLXfer getXfer() {
|
||||
return xfer;
|
||||
}
|
||||
|
||||
public ECLScreenReco GetScreenReco() {
|
||||
return screenReco;
|
||||
}
|
||||
|
||||
public ECLScreenReco getScreenReco() {
|
||||
return screenReco;
|
||||
}
|
||||
|
||||
public ECLConnection GetConnection() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public ECLConnection getConnection() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public haus.nightmare.lib3270j.ecl.ECLSession getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void StartCommunication() throws IOException {
|
||||
if (delegate != null) {
|
||||
delegate.StartCommunication();
|
||||
} else {
|
||||
super.StartCommunication();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void StopCommunication() {
|
||||
if (delegate != null) {
|
||||
delegate.StopCommunication();
|
||||
} else {
|
||||
super.StopCommunication();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean StartCommunicationWithBlocking(long timeout) throws InterruptedException, ECLErr {
|
||||
return StartCommunicationWithBlocking(timeout, (ECLScreenDesc) null);
|
||||
}
|
||||
|
||||
public boolean startCommunicationWithBlocking(long timeout) throws InterruptedException, ECLErr {
|
||||
return StartCommunicationWithBlocking(timeout);
|
||||
}
|
||||
|
||||
public boolean StartCommunicationWithBlocking(long timeout, ECLScreenDesc desc) throws InterruptedException, ECLErr {
|
||||
if (delegate != null) {
|
||||
try {
|
||||
return delegate.StartCommunicationWithBlocking(timeout, desc);
|
||||
} catch (IOException e) {
|
||||
throw new ECLErr("ECLSession.StartCommunicationWithBlocking", "ECL0001", e.getMessage());
|
||||
} catch (haus.nightmare.lib3270j.ecl.ECLErr e) {
|
||||
throw new ECLErr(e.getMessage());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean startCommunicationWithBlocking(long timeout, ECLScreenDesc desc) throws InterruptedException, ECLErr {
|
||||
return StartCommunicationWithBlocking(timeout, desc);
|
||||
}
|
||||
|
||||
public boolean RestartCommunicationWithBlocking(long timeout) throws InterruptedException, ECLErr {
|
||||
if (delegate != null) {
|
||||
try {
|
||||
return delegate.RestartCommunicationWithBlocking(timeout);
|
||||
} catch (IOException e) {
|
||||
throw new ECLErr("ECLSession.RestartCommunicationWithBlocking", "ECL0001", e.getMessage());
|
||||
} catch (haus.nightmare.lib3270j.ecl.ECLErr e) {
|
||||
throw new ECLErr(e.getMessage());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean restartCommunicationWithBlocking(long timeout) throws InterruptedException, ECLErr {
|
||||
return RestartCommunicationWithBlocking(timeout);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
if (delegate != null) {
|
||||
delegate.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.ibm.eNetwork.ECL;
|
||||
|
||||
import com.ibm.eNetwork.ECL.event.ECLXferListener;
|
||||
|
||||
/**
|
||||
* File transfer facade matching IBM Host On-Demand ECLXfer.
|
||||
*/
|
||||
public class ECLXfer {
|
||||
|
||||
private final haus.nightmare.lib3270j.ecl.ECLXfer delegate;
|
||||
|
||||
public ECLXfer(ECLSession session, Boolean bidi) {
|
||||
this.delegate = (session != null && session.getDelegate() != null)
|
||||
? session.getDelegate().GetXfer() : null;
|
||||
}
|
||||
|
||||
public ECLXfer(haus.nightmare.lib3270j.ecl.ECLXfer delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public void SendFile(String localFile, String hostFile, String options) throws ECLErr {
|
||||
if (delegate != null) {
|
||||
int rc = delegate.SendFile(localFile, hostFile, options);
|
||||
if (rc != 0) {
|
||||
throw new ECLErr("ECLXfer:SendFile", "ECL0150", String.valueOf(rc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ReceiveFile(String localFile, String hostFile, String options) throws ECLErr {
|
||||
if (delegate != null) {
|
||||
int rc = delegate.ReceiveFile(localFile, hostFile, options);
|
||||
if (rc != 0) {
|
||||
throw new ECLErr("ECLXfer:ReceiveFile", "ECL0150", String.valueOf(rc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Cancel() {
|
||||
if (delegate != null) {
|
||||
delegate.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
public void RegisterXferEvent(ECLXferListener listener) {
|
||||
// Can bridge listener if needed
|
||||
}
|
||||
|
||||
public void UnregisterXferEvent(ECLXferListener listener) {
|
||||
// Can bridge listener if needed
|
||||
}
|
||||
|
||||
public haus.nightmare.lib3270j.ecl.ECLXfer getDelegate() { return delegate; }
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.ibm.eNetwork.ECL.event;
|
||||
|
||||
/**
|
||||
* Base event class matching IBM Host On-Demand ECLEvent.
|
||||
*/
|
||||
public class ECLEvent {
|
||||
private final Object originator;
|
||||
|
||||
public ECLEvent(Object object) {
|
||||
this.originator = object;
|
||||
}
|
||||
|
||||
public Object GetSource() {
|
||||
return this.originator;
|
||||
}
|
||||
|
||||
public Object getSource() {
|
||||
return this.originator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + ": " + (this.originator != null ? this.originator.toString() : "null");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package com.ibm.eNetwork.ECL.event;
|
||||
|
||||
import com.ibm.eNetwork.ECL.ECLPS;
|
||||
import com.ibm.eNetwork.ECL.ECLPSUpdate;
|
||||
|
||||
/**
|
||||
* Presentation Space event class matching IBM Host On-Demand ECLPSEvent.
|
||||
*/
|
||||
public class ECLPSEvent extends ECLEvent {
|
||||
|
||||
public static final int USER_EVENTS = 1;
|
||||
public static final int HOST_EVENTS = 2;
|
||||
public static final int ALL_EVENTS = 3;
|
||||
|
||||
private int type = 0;
|
||||
private int start = 1;
|
||||
private int end = 1;
|
||||
private int startRow = 1;
|
||||
private int startCol = 1;
|
||||
private int endRow = 1;
|
||||
private int endCol = 1;
|
||||
private int oldCursorPos = 1;
|
||||
private int newCursorPos = 1;
|
||||
private boolean fullUpdate = true;
|
||||
private boolean cursorVisible = true;
|
||||
private int ringCounter = 0;
|
||||
private ECLPSUpdate psUpdate = null;
|
||||
private haus.nightmare.lib3270j.ecl.ECLPSEvent delegate = null;
|
||||
|
||||
public ECLPSEvent(Object source) {
|
||||
super(source);
|
||||
if (source instanceof ECLPS) {
|
||||
ECLPS ps = (ECLPS) source;
|
||||
this.end = ps.GetSize();
|
||||
this.endRow = ps.GetRows();
|
||||
this.endCol = ps.GetCols();
|
||||
this.newCursorPos = ps.GetCursorPos();
|
||||
} else if (source instanceof haus.nightmare.lib3270j.ecl.ECLPS) {
|
||||
haus.nightmare.lib3270j.ecl.ECLPS ps = (haus.nightmare.lib3270j.ecl.ECLPS) source;
|
||||
this.end = ps.GetSize();
|
||||
this.endRow = ps.GetRows();
|
||||
this.endCol = ps.GetCols();
|
||||
this.newCursorPos = ps.GetCursorPos();
|
||||
}
|
||||
}
|
||||
|
||||
public ECLPSEvent(Object source, int type) {
|
||||
this(source);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public ECLPSEvent(haus.nightmare.lib3270j.ecl.ECLPSEvent delegate) {
|
||||
super(delegate != null ? delegate.getSource() : null);
|
||||
this.delegate = delegate;
|
||||
if (delegate != null) {
|
||||
this.type = delegate.getType();
|
||||
this.start = delegate.getStart();
|
||||
this.end = delegate.getEnd();
|
||||
this.startRow = delegate.getStartRow();
|
||||
this.startCol = delegate.getStartCol();
|
||||
this.endRow = delegate.getEndRow();
|
||||
this.endCol = delegate.getEndCol();
|
||||
this.oldCursorPos = delegate.getOldCursorAddress() + 1;
|
||||
this.newCursorPos = delegate.getNewCursorAddress() + 1;
|
||||
this.fullUpdate = delegate.isFullUpdate();
|
||||
this.cursorVisible = delegate.isCursorVisible();
|
||||
this.ringCounter = delegate.getRingCounter();
|
||||
if (delegate.getPSUpdate() != null) {
|
||||
this.psUpdate = new ECLPSUpdate(delegate.getPSUpdate());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int GetType() { return type; }
|
||||
public int getType() { return type; }
|
||||
|
||||
public ECLPS GetPS() {
|
||||
Object src = GetSource();
|
||||
if (src instanceof ECLPS) {
|
||||
return (ECLPS) src;
|
||||
} else if (src instanceof haus.nightmare.lib3270j.ecl.ECLPS) {
|
||||
return new ECLPS((haus.nightmare.lib3270j.ecl.ECLPS) src);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void SetStart(int start) { this.start = start; }
|
||||
public int GetStart() { return start; }
|
||||
public int getStart() { return start; }
|
||||
|
||||
public int GetStartRow() { return startRow; }
|
||||
public int getStartRow() { return startRow; }
|
||||
|
||||
public int GetStartCol() { return startCol; }
|
||||
public int getStartCol() { return startCol; }
|
||||
|
||||
public void SetEnd(int end) { this.end = end; }
|
||||
public int GetEnd() { return end; }
|
||||
public int getEnd() { return end; }
|
||||
|
||||
public int GetEndRow() { return endRow; }
|
||||
public int getEndRow() { return endRow; }
|
||||
|
||||
public int GetEndCol() { return endCol; }
|
||||
public int getEndCol() { return endCol; }
|
||||
|
||||
public int GetOldCursorPos() { return oldCursorPos; }
|
||||
public int getOldCursorPos() { return oldCursorPos; }
|
||||
|
||||
public int GetNewCursorPos() { return newCursorPos; }
|
||||
public int getNewCursorPos() { return newCursorPos; }
|
||||
|
||||
public boolean IsFullUpdate() { return fullUpdate; }
|
||||
public boolean isFullUpdate() { return fullUpdate; }
|
||||
|
||||
public boolean IsCursorVisible() { return cursorVisible; }
|
||||
public boolean isCursorVisible() { return cursorVisible; }
|
||||
|
||||
public int GetRingCounter() { return ringCounter; }
|
||||
public int getRingCounter() { return ringCounter; }
|
||||
|
||||
public ECLPSUpdate GetPSUpdate() { return psUpdate; }
|
||||
public ECLPSUpdate getPSUpdate() { return psUpdate; }
|
||||
|
||||
public haus.nightmare.lib3270j.ecl.ECLPSEvent getDelegate() { return delegate; }
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.ibm.eNetwork.ECL.event;
|
||||
|
||||
import com.ibm.eNetwork.ECL.ECLErr;
|
||||
import com.ibm.eNetwork.ECL.ECLPS;
|
||||
|
||||
/**
|
||||
* Presentation Space listener interface matching IBM Host On-Demand ECLPSListener.
|
||||
*/
|
||||
public interface ECLPSListener {
|
||||
void PSNotifyEvent(ECLPSEvent event);
|
||||
default void PSNotifyStop(ECLPS ps, int reason) {}
|
||||
default void PSNotifyError(ECLPS ps, ECLErr err) {}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.ibm.eNetwork.ECL.event;
|
||||
|
||||
import com.ibm.eNetwork.ECL.ECLXfer;
|
||||
|
||||
/**
|
||||
* File transfer event matching IBM Host On-Demand ECLXferEvent.
|
||||
*/
|
||||
public class ECLXferEvent extends ECLEvent {
|
||||
|
||||
private final String sourceFile;
|
||||
private final String targetFile;
|
||||
private final boolean receive;
|
||||
private final long unitsDone;
|
||||
private final long unitsToDo;
|
||||
|
||||
public ECLXferEvent(Object source, long unitsDone, String sourceFile, String targetFile, boolean receive) {
|
||||
this(source, unitsDone, -1L, sourceFile, targetFile, receive);
|
||||
}
|
||||
|
||||
public ECLXferEvent(Object source, long unitsDone, long unitsToDo, String sourceFile, String targetFile, boolean receive) {
|
||||
super(source);
|
||||
this.unitsDone = unitsDone;
|
||||
this.unitsToDo = unitsToDo;
|
||||
this.sourceFile = sourceFile;
|
||||
this.targetFile = targetFile;
|
||||
this.receive = receive;
|
||||
}
|
||||
|
||||
public ECLXfer GetECLXfer() {
|
||||
Object src = GetSource();
|
||||
return (src instanceof ECLXfer) ? (ECLXfer) src : null;
|
||||
}
|
||||
|
||||
public String GetSourceFile() { return sourceFile; }
|
||||
public String getSourceFile() { return sourceFile; }
|
||||
|
||||
public String GetTargetFile() { return targetFile; }
|
||||
public String getTargetFile() { return targetFile; }
|
||||
|
||||
public long GetBytesSent() { return unitsDone; }
|
||||
public long getBytesSent() { return unitsDone; }
|
||||
|
||||
public long GetBytesToSend() { return unitsToDo; }
|
||||
public long getBytesToSend() { return unitsToDo; }
|
||||
|
||||
public boolean IsReceive() { return receive; }
|
||||
public boolean isReceive() { return receive; }
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.ibm.eNetwork.ECL.event;
|
||||
|
||||
import com.ibm.eNetwork.ECL.ECLErr;
|
||||
import com.ibm.eNetwork.ECL.ECLXfer;
|
||||
|
||||
/**
|
||||
* File transfer listener interface matching IBM Host On-Demand ECLXferListener.
|
||||
*/
|
||||
public interface ECLXferListener {
|
||||
void XferNotifyEvent(ECLXferEvent event);
|
||||
default void XferNotifyStop(ECLXfer xfer, int reason) {}
|
||||
default void XferNotifyError(ECLXfer xfer, ECLErr err) {}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.ibm.eNetwork.ECL.screenreco;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLSDAttrib drop-in facade.
|
||||
*/
|
||||
public class ECLSDAttrib extends haus.nightmare.lib3270j.ecl.screenreco.ECLSDAttrib {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ECLSDAttrib() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ECLSDAttrib(char attrib, int row, int col, int plane) {
|
||||
super(attrib, row, col, plane);
|
||||
}
|
||||
|
||||
public ECLSDAttrib(char attrib, int row, int col, int plane, boolean optional) {
|
||||
super(attrib, row, col, plane, optional);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.ibm.eNetwork.ECL.screenreco;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLSDBlock drop-in facade.
|
||||
*/
|
||||
public class ECLSDBlock extends haus.nightmare.lib3270j.ecl.screenreco.ECLSDBlock {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ECLSDBlock() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ECLSDBlock(int srow, int scol, boolean caseSense, boolean optional) {
|
||||
super(srow, scol, caseSense, optional);
|
||||
}
|
||||
|
||||
public ECLSDBlock(int srow, int scol, int erow, int ecol, boolean caseSense, boolean optional) {
|
||||
super(srow, scol, erow, ecol, caseSense, optional);
|
||||
}
|
||||
|
||||
public ECLSDBlock(String[] textLines, int srow, int scol, boolean caseSense) {
|
||||
super(textLines, srow, scol, caseSense);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.ibm.eNetwork.ECL.screenreco;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLSDBlockString drop-in facade.
|
||||
*/
|
||||
public class ECLSDBlockString extends haus.nightmare.lib3270j.ecl.screenreco.ECLSDBlockString {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ECLSDBlockString() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ECLSDBlockString(String text) {
|
||||
super(text);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.ibm.eNetwork.ECL.screenreco;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLSDChecksum drop-in facade.
|
||||
*/
|
||||
public class ECLSDChecksum extends haus.nightmare.lib3270j.ecl.screenreco.ECLSDChecksum {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ECLSDChecksum() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ECLSDChecksum(int value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
public ECLSDChecksum(int value, boolean optional) {
|
||||
super(value, optional);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.ibm.eNetwork.ECL.screenreco;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLSDCursor drop-in facade.
|
||||
*/
|
||||
public class ECLSDCursor extends haus.nightmare.lib3270j.ecl.screenreco.ECLSDCursor {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ECLSDCursor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ECLSDCursor(int row, int col) {
|
||||
super(row, col);
|
||||
}
|
||||
|
||||
public ECLSDCursor(int row, int col, boolean optional) {
|
||||
super(row, col, optional);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.ibm.eNetwork.ECL.screenreco;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLSDFields drop-in facade.
|
||||
*/
|
||||
public class ECLSDFields extends haus.nightmare.lib3270j.ecl.screenreco.ECLSDFields {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ECLSDFields() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ECLSDFields(int num) {
|
||||
super(num);
|
||||
}
|
||||
|
||||
public ECLSDFields(int num, boolean optional) {
|
||||
super(num, optional);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.ibm.eNetwork.ECL.screenreco;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLSDInputFields drop-in facade.
|
||||
*/
|
||||
public class ECLSDInputFields extends haus.nightmare.lib3270j.ecl.screenreco.ECLSDInputFields {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ECLSDInputFields() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ECLSDInputFields(int num) {
|
||||
super(num);
|
||||
}
|
||||
|
||||
public ECLSDInputFields(int num, boolean optional) {
|
||||
super(num, optional);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.ibm.eNetwork.ECL.screenreco;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLSDOIA drop-in facade.
|
||||
*/
|
||||
public class ECLSDOIA extends haus.nightmare.lib3270j.ecl.screenreco.ECLSDOIA {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ECLSDOIA() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ECLSDOIA(int type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
public ECLSDOIA(int type, boolean optional) {
|
||||
super(type, optional);
|
||||
}
|
||||
|
||||
public ECLSDOIA(String status, boolean optional) {
|
||||
super(status, optional);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.ibm.eNetwork.ECL.screenreco;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLSDString drop-in facade.
|
||||
*/
|
||||
public class ECLSDString extends haus.nightmare.lib3270j.ecl.screenreco.ECLSDString {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ECLSDString() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ECLSDString(String text) {
|
||||
super(text);
|
||||
}
|
||||
|
||||
public ECLSDString(String text, int row, int col) {
|
||||
super(text, row, col);
|
||||
}
|
||||
|
||||
public ECLSDString(String text, int row, int col, boolean caseSense) {
|
||||
super(text, row, col, caseSense);
|
||||
}
|
||||
|
||||
public ECLSDString(String text, int row, int col, boolean caseSense, boolean optional) {
|
||||
super(text, row, col, caseSense, optional);
|
||||
}
|
||||
|
||||
public ECLSDString(String text, int srow, int scol, int erow, int ecol, boolean caseSense, boolean optional) {
|
||||
super(text, srow, scol, erow, ecol, caseSense, optional);
|
||||
}
|
||||
|
||||
public ECLSDString(String text, int srow, int scol, int erow, int ecol, boolean caseSense, boolean optional, boolean wrap) {
|
||||
super(text, srow, scol, erow, ecol, caseSense, optional, wrap);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.ibm.eNetwork.ECL.screenreco;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLScreenDescriptor drop-in facade.
|
||||
*/
|
||||
public abstract class ECLScreenDescriptor extends haus.nightmare.lib3270j.ecl.screenreco.ECLScreenDescriptor {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected ECLScreenDescriptor() {
|
||||
super();
|
||||
}
|
||||
|
||||
protected ECLScreenDescriptor(boolean optional) {
|
||||
super(optional);
|
||||
}
|
||||
}
|
||||
@@ -77,6 +77,34 @@ public class ECLConnection {
|
||||
if (props != null) {
|
||||
this.properties.putAll(props);
|
||||
convertData(this.properties);
|
||||
|
||||
String h = this.properties.getProperty(ECLSession.SESSION_HOST);
|
||||
if (h == null) h = this.properties.getProperty("host");
|
||||
if (h == null) h = this.properties.getProperty("Host");
|
||||
if (h == null) h = this.properties.getProperty("SESSION_PRINT_SESSION_HOST");
|
||||
if (h != null && !h.trim().isEmpty()) this.host = h.trim();
|
||||
|
||||
String p = this.properties.getProperty(ECLSession.SESSION_PORT);
|
||||
if (p == null) p = this.properties.getProperty("port");
|
||||
if (p == null) p = this.properties.getProperty("Port");
|
||||
if (p == null) p = this.properties.getProperty("SESSION_HOST_PORT");
|
||||
if (p == null) p = this.properties.getProperty("SESSION_PRINT_SESSION_HOST_PORT");
|
||||
if (p != null && !p.trim().isEmpty()) {
|
||||
try { this.port = Integer.parseInt(p.trim()); } catch (NumberFormatException ignored) {}
|
||||
}
|
||||
|
||||
String cp = this.properties.getProperty(ECLSession.SESSION_CODE_PAGE);
|
||||
if (cp == null) cp = this.properties.getProperty("code_page");
|
||||
if (cp == null) cp = this.properties.getProperty("codepage");
|
||||
if (cp == null) cp = this.properties.getProperty("CodePage");
|
||||
if (cp != null && !cp.trim().isEmpty()) this.codePage = cp.trim();
|
||||
|
||||
String lu = this.properties.getProperty(ECLSession.SESSION_LU_NAME);
|
||||
if (lu == null) lu = this.properties.getProperty("lu_name");
|
||||
if (lu == null) lu = this.properties.getProperty("luname");
|
||||
if (lu == null) lu = this.properties.getProperty("SESSION_PRINT_SESSION_LU_NAME");
|
||||
if (lu != null && !lu.trim().isEmpty()) this.luName = lu.trim();
|
||||
|
||||
String asu = this.properties.getProperty(ECLSession.SESSION_AUTO_SYS_UNLOCK);
|
||||
if (asu != null) {
|
||||
this.autoSysUnlock = "true".equalsIgnoreCase(asu) || "1".equals(asu);
|
||||
|
||||
@@ -11,6 +11,8 @@ public class ECLErr extends Exception {
|
||||
private String id = "";
|
||||
private String text = "";
|
||||
|
||||
private int reasonCode = 0;
|
||||
|
||||
public ECLErr() {
|
||||
super();
|
||||
}
|
||||
@@ -20,6 +22,21 @@ public class ECLErr extends Exception {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public ECLErr(String location, String msgNum, int reasonCode) {
|
||||
super(formatMsg(location, msgNum, "Reason " + reasonCode));
|
||||
this.tag = location;
|
||||
this.id = msgNum;
|
||||
this.text = "Reason " + reasonCode;
|
||||
this.reasonCode = reasonCode;
|
||||
}
|
||||
|
||||
public ECLErr(String location, String msgNum) {
|
||||
super(formatMsg(location, msgNum, ""));
|
||||
this.tag = location;
|
||||
this.id = msgNum;
|
||||
this.text = "";
|
||||
}
|
||||
|
||||
public ECLErr(String tag, String id, String text) {
|
||||
super(formatMsg(tag, id, text));
|
||||
this.tag = tag;
|
||||
@@ -27,11 +44,30 @@ public class ECLErr extends Exception {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public ECLErr(String tag, String id, String text, String extra) {
|
||||
super(formatMsg(tag, id, text + " " + extra));
|
||||
this.tag = tag;
|
||||
this.id = id;
|
||||
this.text = text + " " + extra;
|
||||
public ECLErr(String location, String msgNum, String insert1, int reasonCode) {
|
||||
super(formatMsg(location, msgNum, insert1 + " (Reason " + reasonCode + ")"));
|
||||
this.tag = location;
|
||||
this.id = msgNum;
|
||||
this.text = insert1 + " (Reason " + reasonCode + ")";
|
||||
this.reasonCode = reasonCode;
|
||||
}
|
||||
|
||||
public ECLErr(String location, String msgNum, String insert1, String insert2, boolean log) {
|
||||
super(formatMsg(location, msgNum, insert1 + " " + insert2));
|
||||
this.tag = location;
|
||||
this.id = msgNum;
|
||||
this.text = insert1 + " " + insert2;
|
||||
}
|
||||
|
||||
public ECLErr(String location, String msgNum, String insert1, String insert2) {
|
||||
this(location, msgNum, insert1, insert2, false);
|
||||
}
|
||||
|
||||
public ECLErr(String location, String msgNum, String insert1, String insert2, String insert3) {
|
||||
super(formatMsg(location, msgNum, insert1 + " " + insert2 + " " + insert3));
|
||||
this.tag = location;
|
||||
this.id = msgNum;
|
||||
this.text = insert1 + " " + insert2 + " " + insert3;
|
||||
}
|
||||
|
||||
public ECLErr(Throwable cause) {
|
||||
@@ -57,14 +93,33 @@ public class ECLErr extends Exception {
|
||||
public String getID() { return id; }
|
||||
public String GetID() { return id; }
|
||||
|
||||
public String getLocation() { return tag; }
|
||||
public String GetLocation() { return tag; }
|
||||
|
||||
public int getReasonCode() { return reasonCode; }
|
||||
public int GetReasonCode() { return reasonCode; }
|
||||
|
||||
public int getMsgNumber() {
|
||||
if (id != null && id.length() >= 7 && id.startsWith("ECL")) {
|
||||
try {
|
||||
return Integer.parseInt(id.substring(3, 7));
|
||||
} catch (NumberFormatException ignored) {}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
public int GetMsgNumber() { return getMsgNumber(); }
|
||||
|
||||
public String getText() { return text; }
|
||||
public String GetText() { return text; }
|
||||
|
||||
public String getMsgText() { return getMessage(); }
|
||||
public String GetMsgText() { return getMessage(); }
|
||||
|
||||
public String getErrorText() { return getMessage(); }
|
||||
public String GetErrorText() { return getMessage(); }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ECLErr[tag=" + tag + ", id=" + id + ", text=" + text + "]";
|
||||
return "ECLErr[tag=" + tag + ", id=" + id + ", text=" + text + ", reasonCode=" + reasonCode + "]";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,10 @@ public class ECLField {
|
||||
this.attribute = attribute;
|
||||
}
|
||||
|
||||
public ECLPS getPS() { return ps; }
|
||||
public ECLPS GetPS() { return ps; }
|
||||
public byte getAttributeByte() { return attribute; }
|
||||
|
||||
/** Buffer address of the field attribute character. */
|
||||
public int getStart() { return startPos; }
|
||||
public int GetStart() { return getStart(); }
|
||||
@@ -154,6 +158,8 @@ public class ECLField {
|
||||
return ps.getString(dataStart, length);
|
||||
}
|
||||
public String GetText() { return getText(); }
|
||||
public String getString() { return getText(); }
|
||||
public String GetString() { return getText(); }
|
||||
|
||||
/**
|
||||
* Set the text contents of this field.
|
||||
@@ -162,7 +168,13 @@ public class ECLField {
|
||||
if (isProtected() || length <= 0) return;
|
||||
ps.setText(text, dataStart);
|
||||
}
|
||||
public void SetText(String text) { setText(text); }
|
||||
public void SetText(String text) throws ECLErr {
|
||||
if (isProtected()) {
|
||||
throw new ECLErr("ECLField:SetText", "ECL0015", "Field is protected");
|
||||
}
|
||||
setText(text);
|
||||
}
|
||||
public void SetString(String text) throws ECLErr { SetText(text); }
|
||||
|
||||
/**
|
||||
* Get selector light pen type.
|
||||
|
||||
@@ -7,15 +7,17 @@ import java.util.List;
|
||||
import haus.nightmare.lib3270j.screen.ScreenBuffer;
|
||||
import haus.nightmare.lib3270j.screen.ExtendedAttribute;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* Manages the collection of all 3270 fields currently present in the Presentation Space.
|
||||
* Conforms to IBM ECL ECLFieldList specification.
|
||||
*/
|
||||
public class ECLFieldList {
|
||||
public class ECLFieldList extends Vector<ECLField> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final ECLPS ps;
|
||||
private final ScreenBuffer screen;
|
||||
private final List<ECLField> fields = new ArrayList<>();
|
||||
|
||||
public ECLFieldList(ECLPS ps, ScreenBuffer screen) {
|
||||
this.ps = ps;
|
||||
@@ -23,11 +25,14 @@ public class ECLFieldList {
|
||||
refresh();
|
||||
}
|
||||
|
||||
public ECLPS getPS() { return ps; }
|
||||
public ScreenBuffer getScreenBuffer() { return screen; }
|
||||
|
||||
/**
|
||||
* Refresh the field list by scanning the presentation space buffer.
|
||||
*/
|
||||
public synchronized void refresh() {
|
||||
fields.clear();
|
||||
clear();
|
||||
if (screen == null || !screen.isFormatted()) {
|
||||
return;
|
||||
}
|
||||
@@ -66,35 +71,35 @@ public class ECLFieldList {
|
||||
}
|
||||
|
||||
byte faVal = screen.getCell(startPos).fa;
|
||||
fields.add(new ECLField(ps, startPos, dataStart, endPos, len, faVal));
|
||||
add(new ECLField(ps, startPos, dataStart, endPos, len, faVal));
|
||||
}
|
||||
}
|
||||
|
||||
public void Refresh() { refresh(); }
|
||||
|
||||
public synchronized int getFieldCount() {
|
||||
return fields.size();
|
||||
return size();
|
||||
}
|
||||
public int GetFieldCount() { return getFieldCount(); }
|
||||
|
||||
public synchronized List<ECLField> getFields() {
|
||||
return Collections.unmodifiableList(new ArrayList<>(fields));
|
||||
return Collections.unmodifiableList(new ArrayList<>(this));
|
||||
}
|
||||
public List<ECLField> GetFields() { return getFields(); }
|
||||
|
||||
public synchronized ECLField getFirstField() {
|
||||
if (fields.isEmpty()) return null;
|
||||
return fields.get(0);
|
||||
if (isEmpty()) return null;
|
||||
return get(0);
|
||||
}
|
||||
public ECLField GetFirstField() { return getFirstField(); }
|
||||
|
||||
public synchronized ECLField getNextField(ECLField prev) {
|
||||
if (prev == null || fields.isEmpty()) return getFirstField();
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
ECLField f = fields.get(i);
|
||||
if (prev == null || isEmpty()) return getFirstField();
|
||||
for (int i = 0; i < size(); i++) {
|
||||
ECLField f = get(i);
|
||||
if (f.equals(prev) || f.getStart() == prev.getStart()) {
|
||||
if (i + 1 < fields.size()) {
|
||||
return fields.get(i + 1);
|
||||
if (i + 1 < size()) {
|
||||
return get(i + 1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -107,12 +112,12 @@ public class ECLFieldList {
|
||||
* Find the field that contains the specified buffer position.
|
||||
*/
|
||||
public synchronized ECLField findField(int pos) {
|
||||
if (fields.isEmpty() || screen == null) return null;
|
||||
if (isEmpty() || screen == null) return null;
|
||||
int size = screen.getRows() * screen.getCols();
|
||||
if (size <= 0) return null;
|
||||
pos = ((pos % size) + size) % size;
|
||||
|
||||
for (ECLField f : fields) {
|
||||
for (ECLField f : this) {
|
||||
int start = f.getStart();
|
||||
int end = f.getEnd();
|
||||
if (start <= end) {
|
||||
@@ -140,14 +145,14 @@ public class ECLFieldList {
|
||||
* Get the field preceding the given field in the field list.
|
||||
*/
|
||||
public synchronized ECLField getPreviousField(ECLField next) {
|
||||
if (next == null || fields.isEmpty()) return null;
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
ECLField f = fields.get(i);
|
||||
if (next == null || isEmpty()) return null;
|
||||
for (int i = 0; i < size(); i++) {
|
||||
ECLField f = get(i);
|
||||
if (f.equals(next) || f.getStart() == next.getStart()) {
|
||||
if (i > 0) {
|
||||
return fields.get(i - 1);
|
||||
return get(i - 1);
|
||||
} else {
|
||||
return fields.get(fields.size() - 1);
|
||||
return get(size() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -195,29 +200,29 @@ public class ECLFieldList {
|
||||
* Find field containing the given text string.
|
||||
*/
|
||||
public synchronized ECLField findField(String text, int startPos) {
|
||||
if (text == null || text.isEmpty() || fields.isEmpty()) return null;
|
||||
if (text == null || text.isEmpty() || isEmpty()) return null;
|
||||
int size = screen.getRows() * screen.getCols();
|
||||
if (size <= 0) return null;
|
||||
startPos = ((startPos % size) + size) % size;
|
||||
|
||||
// Find starting index in field list
|
||||
int startIdx = 0;
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
if (fields.get(i).getStart() >= startPos) {
|
||||
for (int i = 0; i < size(); i++) {
|
||||
if (get(i).getStart() >= startPos) {
|
||||
startIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = startIdx; i < fields.size(); i++) {
|
||||
ECLField f = fields.get(i);
|
||||
for (int i = startIdx; i < size(); i++) {
|
||||
ECLField f = get(i);
|
||||
if (f.getText().contains(text)) {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
// Wrap around search to beginning of field list
|
||||
for (int i = 0; i < startIdx; i++) {
|
||||
ECLField f = fields.get(i);
|
||||
ECLField f = get(i);
|
||||
if (f.getText().contains(text)) {
|
||||
return f;
|
||||
}
|
||||
@@ -265,18 +270,18 @@ public class ECLFieldList {
|
||||
public boolean MatchAttributes(ECLField f, int mask) { return matchAttributes(f, mask); }
|
||||
|
||||
public synchronized ECLField locateField(int attrMask, ECLField prev) {
|
||||
if (fields.isEmpty()) return null;
|
||||
if (isEmpty()) return null;
|
||||
int startIndex = 0;
|
||||
if (prev != null) {
|
||||
int idx = fields.indexOf(prev);
|
||||
if (idx >= 0 && idx + 1 < fields.size()) {
|
||||
int idx = indexOf(prev);
|
||||
if (idx >= 0 && idx + 1 < size()) {
|
||||
startIndex = idx + 1;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
for (int i = startIndex; i < fields.size(); i++) {
|
||||
ECLField f = fields.get(i);
|
||||
for (int i = startIndex; i < size(); i++) {
|
||||
ECLField f = get(i);
|
||||
if (matchAttributes(f, attrMask)) {
|
||||
return f;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package haus.nightmare.lib3270j.ecl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
@@ -109,6 +110,8 @@ public class ECLOIA implements ECLConstants {
|
||||
session != null && session.getClient() != null ? session.getClient().getTelnetFSM() : null);
|
||||
}
|
||||
|
||||
private final List<com.ibm.eNetwork.ECL.ECLOIANotify> hodOiaNotifies = new CopyOnWriteArrayList<>();
|
||||
|
||||
public void RegisterOIAEvent(haus.nightmare.lib3270j.ecl.ECLOIANotify listener) {
|
||||
if (listener != null && !listeners.contains(listener)) {
|
||||
listeners.add(listener);
|
||||
@@ -132,6 +135,29 @@ public class ECLOIA implements ECLConstants {
|
||||
UnregisterOIAEvent(listener);
|
||||
}
|
||||
|
||||
public void RegisterOIAEvent(com.ibm.eNetwork.ECL.ECLOIANotify notify) {
|
||||
if (notify != null && !hodOiaNotifies.contains(notify)) {
|
||||
hodOiaNotifies.add(notify);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerOIAEvent(com.ibm.eNetwork.ECL.ECLOIANotify notify) {
|
||||
RegisterOIAEvent(notify);
|
||||
}
|
||||
|
||||
public void UnregisterOIAEvent(com.ibm.eNetwork.ECL.ECLOIANotify notify) {
|
||||
if (notify != null) {
|
||||
hodOiaNotifies.remove(notify);
|
||||
try {
|
||||
notify.NotifyStop(new com.ibm.eNetwork.ECL.ECLOIA(this), STOP_UNREGISTER);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterOIAEvent(com.ibm.eNetwork.ECL.ECLOIANotify notify) {
|
||||
UnregisterOIAEvent(notify);
|
||||
}
|
||||
|
||||
public void RegisterOIAEvent(ECLOIAListener listener) {
|
||||
if (listener != null && !oiaListeners.contains(listener)) {
|
||||
oiaListeners.add(listener);
|
||||
@@ -166,6 +192,14 @@ public class ECLOIA implements ECLConstants {
|
||||
l.OIANotifyError(this, err);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
for (com.ibm.eNetwork.ECL.ECLOIANotify l : hodOiaNotifies) {
|
||||
try {
|
||||
com.ibm.eNetwork.ECL.ECLErr ferr = (err instanceof com.ibm.eNetwork.ECL.ECLErr)
|
||||
? (com.ibm.eNetwork.ECL.ECLErr) err
|
||||
: new com.ibm.eNetwork.ECL.ECLErr(err.getMessage());
|
||||
l.NotifyError(new com.ibm.eNetwork.ECL.ECLOIA(this), ferr);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyOIAStop(int reason) {
|
||||
@@ -179,6 +213,11 @@ public class ECLOIA implements ECLConstants {
|
||||
l.OIANotifyStop(this, reason);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
for (com.ibm.eNetwork.ECL.ECLOIANotify l : hodOiaNotifies) {
|
||||
try {
|
||||
l.NotifyStop(new com.ibm.eNetwork.ECL.ECLOIA(this), reason);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
private final ReentrantLock oiaLock = new ReentrantLock();
|
||||
@@ -210,6 +249,11 @@ public class ECLOIA implements ECLConstants {
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
for (com.ibm.eNetwork.ECL.ECLOIANotify l : hodOiaNotifies) {
|
||||
try {
|
||||
l.OIANotifyEvent(new com.ibm.eNetwork.ECL.ECLOIAEvent(event));
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isInsertMode() {
|
||||
@@ -267,6 +311,11 @@ public class ECLOIA implements ECLConstants {
|
||||
public void setInputInhibited(int reason) {
|
||||
if (this.inhibitOverride != reason) {
|
||||
this.inhibitOverride = reason;
|
||||
if (reason == INHIBIT_NOT_INHIBITED && inputProcessor != null && inputProcessor.isKeyboardLocked()) {
|
||||
inputProcessor.setKeyboardLocked(false);
|
||||
} else if (reason == INHIBIT_SYSTEM_LOCK && inputProcessor != null && !inputProcessor.isKeyboardLocked()) {
|
||||
inputProcessor.setKeyboardLocked(true);
|
||||
}
|
||||
notifyOIAChanged();
|
||||
}
|
||||
}
|
||||
@@ -424,6 +473,14 @@ public class ECLOIA implements ECLConstants {
|
||||
return getInputInhibited();
|
||||
}
|
||||
|
||||
public boolean isKeyLocked() {
|
||||
return getInputInhibited() != INHIBIT_NOT_INHIBITED;
|
||||
}
|
||||
|
||||
public boolean IsKeyLocked() {
|
||||
return isKeyLocked();
|
||||
}
|
||||
|
||||
/**
|
||||
* Block until the keyboard becomes unlocked and ready for user input, or timeout expires.
|
||||
* @return true if keyboard unlocked, false if timeout occurred.
|
||||
|
||||
@@ -5,6 +5,7 @@ import haus.nightmare.lib3270j.input.InputProcessor;
|
||||
import haus.nightmare.lib3270j.listener.ScreenUpdateListener;
|
||||
import haus.nightmare.lib3270j.screen.ExtendedAttribute;
|
||||
import haus.nightmare.lib3270j.screen.ScreenBuffer;
|
||||
import haus.nightmare.lib3270j.ecl.util.SendKeyTokenizer;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
@@ -155,20 +156,94 @@ public class ECLPS implements ECLConstants {
|
||||
public ECLPSTHAIServices GetECLPSTHAIServices() { return thaiServices; }
|
||||
public ECLPSTHAIServices getTHAIServices() { return thaiServices; }
|
||||
|
||||
public int getSize() { return screen.getRows() * screen.getCols(); }
|
||||
public int getRows() { return screen.getRows(); }
|
||||
public int getCols() { return screen.getCols(); }
|
||||
public int getCursorPos(){ return screen.getCursorAddress(); }
|
||||
public int getCursorRow(){ return screen.getCursorRow(); }
|
||||
public int getCursorCol(){ return screen.getCursorCol(); }
|
||||
public int getSize() { return screen != null ? screen.getRows() * screen.getCols() : 0; }
|
||||
public int getRows() { return screen != null ? screen.getRows() : 0; }
|
||||
public int getCols() { return screen != null ? screen.getCols() : 0; }
|
||||
public int GetSize() { return getSize(); }
|
||||
public int GetRows() { return getRows(); }
|
||||
public int GetCols() { return getCols(); }
|
||||
public int GetSizeRows() { return getRows(); }
|
||||
public int GetSizeCols() { return getCols(); }
|
||||
|
||||
public int getCursorPos(){ return screen != null ? screen.getCursorAddress() : 0; }
|
||||
public int getCursorRow(){ return screen != null ? screen.getCursorRow() : 0; }
|
||||
public int getCursorCol(){ return screen != null ? screen.getCursorCol() : 0; }
|
||||
|
||||
public synchronized int GetCursorPos() {
|
||||
return (screen != null) ? screen.getCursorAddress() + 1 : 1;
|
||||
}
|
||||
|
||||
public synchronized int GetCursorRow() {
|
||||
return (screen != null) ? screen.getCursorRow() + 1 : 1;
|
||||
}
|
||||
|
||||
public synchronized int GetCursorCol() {
|
||||
return (screen != null) ? screen.getCursorCol() + 1 : 1;
|
||||
}
|
||||
|
||||
public void setCursorPos(int pos) {
|
||||
screen.setCursorAddress(pos);
|
||||
if (screen != null) {
|
||||
screen.setCursorAddress(pos);
|
||||
}
|
||||
}
|
||||
|
||||
public void setCursorPos(int row, int col) {
|
||||
int pos = screen.rowColToAddress(row, col);
|
||||
screen.setCursorAddress(pos);
|
||||
if (screen != null) {
|
||||
int pos = screen.rowColToAddress(row, col);
|
||||
screen.setCursorAddress(pos);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void SetCursorPos(int pos) throws com.ibm.eNetwork.ECL.ECLErr {
|
||||
if (pos < 1 || pos > getSize()) {
|
||||
throw new com.ibm.eNetwork.ECL.ECLErr("ECLPS:SetCursorPos", "ECL0010", "1", String.valueOf(pos));
|
||||
}
|
||||
setCursorPos(pos - 1);
|
||||
notifyCursorMoved(0, pos - 1);
|
||||
}
|
||||
|
||||
public synchronized void SetCursorPos(int row, int col) throws com.ibm.eNetwork.ECL.ECLErr {
|
||||
SetCursorPos(ConvertRowColToPos(row, col));
|
||||
}
|
||||
|
||||
public synchronized int ConvertPosToRow(int pos) throws com.ibm.eNetwork.ECL.ECLErr {
|
||||
if (pos < 1 || pos > getSize()) {
|
||||
throw new com.ibm.eNetwork.ECL.ECLErr("ECLPS:ConvertPosToRow", "ECL0010", "1", String.valueOf(pos));
|
||||
}
|
||||
int cols = getCols();
|
||||
return (cols > 0) ? ((pos - 1) / cols + 1) : 1;
|
||||
}
|
||||
|
||||
public synchronized int ConvertPosToCol(int pos) throws com.ibm.eNetwork.ECL.ECLErr {
|
||||
if (pos < 1 || pos > getSize()) {
|
||||
throw new com.ibm.eNetwork.ECL.ECLErr("ECLPS:ConvertPosToCol", "ECL0010", "1", String.valueOf(pos));
|
||||
}
|
||||
int cols = getCols();
|
||||
return (cols > 0) ? ((pos - 1) % cols + 1) : 1;
|
||||
}
|
||||
|
||||
public synchronized int ConvertRowColToPos(int row, int col) throws com.ibm.eNetwork.ECL.ECLErr {
|
||||
if (row < 1 || row > getRows()) {
|
||||
throw new com.ibm.eNetwork.ECL.ECLErr("ECLPS:ConvertRowColToPos", "ECL0010", "\"row\"", String.valueOf(row));
|
||||
}
|
||||
if (col < 1 || col > getCols()) {
|
||||
throw new com.ibm.eNetwork.ECL.ECLErr("ECLPS:ConvertRowColToPos", "ECL0010", "\"col\"", String.valueOf(col));
|
||||
}
|
||||
return (row - 1) * getCols() + col;
|
||||
}
|
||||
|
||||
public synchronized void ConvertPosToRowCol(int pos, int[] rowCol) throws com.ibm.eNetwork.ECL.ECLErr {
|
||||
if (rowCol == null || rowCol.length < 2) {
|
||||
throw new com.ibm.eNetwork.ECL.ECLErr("ECLPS:ConvertPosToRowCol", "ECL0010", "\"rowCol\"", "invalid array");
|
||||
}
|
||||
rowCol[0] = ConvertPosToRow(pos);
|
||||
rowCol[1] = ConvertPosToCol(pos);
|
||||
}
|
||||
|
||||
public synchronized int[] ConvertPosToRowCol(int pos) throws com.ibm.eNetwork.ECL.ECLErr {
|
||||
int[] rc = new int[2];
|
||||
ConvertPosToRowCol(pos, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -277,6 +352,60 @@ public class ECLPS implements ECLConstants {
|
||||
return getString(pos, length);
|
||||
}
|
||||
|
||||
public synchronized int GetString(char[] buffer, int len, int pos) throws com.ibm.eNetwork.ECL.ECLErr {
|
||||
return GetString(buffer, len, pos, len);
|
||||
}
|
||||
|
||||
public synchronized int GetString(char[] buffer, int len, int pos, int length) throws com.ibm.eNetwork.ECL.ECLErr {
|
||||
if (buffer == null) {
|
||||
throw new com.ibm.eNetwork.ECL.ECLErr("ECLPS:GetString", "ECL0011", "1");
|
||||
}
|
||||
int size = getSize();
|
||||
if (pos < 1 || pos > size) {
|
||||
throw new com.ibm.eNetwork.ECL.ECLErr("ECLPS:GetString", "ECL0010", "\"position\"", String.valueOf(pos));
|
||||
}
|
||||
if (len <= 0) {
|
||||
throw new com.ibm.eNetwork.ECL.ECLErr("ECLPS:GetString", "ECL0010", "\"bufferLength\"", String.valueOf(len));
|
||||
}
|
||||
if (length <= 0) {
|
||||
throw new com.ibm.eNetwork.ECL.ECLErr("ECLPS:GetString", "ECL0010", "\"length\"", String.valueOf(length));
|
||||
}
|
||||
int copyCount = Math.min(Math.min(buffer.length, len), Math.min(length, size - pos + 1));
|
||||
char[] temp = new char[copyCount];
|
||||
getPlane(PLANE_TEXT, temp, pos - 1, copyCount);
|
||||
System.arraycopy(temp, 0, buffer, 0, copyCount);
|
||||
return copyCount;
|
||||
}
|
||||
|
||||
public synchronized int GetString(char[] buffer, int len, int row, int col, int length) throws com.ibm.eNetwork.ECL.ECLErr {
|
||||
return GetString(buffer, len, ConvertRowColToPos(row, col), length);
|
||||
}
|
||||
|
||||
public synchronized String GetString(int pos, int length) throws com.ibm.eNetwork.ECL.ECLErr {
|
||||
int size = getSize();
|
||||
if (pos < 1 || pos > size) {
|
||||
throw new com.ibm.eNetwork.ECL.ECLErr("ECLPS:GetString", "ECL0010", "\"pos\"", String.valueOf(pos));
|
||||
}
|
||||
return getString(pos - 1, length);
|
||||
}
|
||||
|
||||
public synchronized String GetString(int row, int col, int length) throws com.ibm.eNetwork.ECL.ECLErr {
|
||||
return GetString(ConvertRowColToPos(row, col), length);
|
||||
}
|
||||
|
||||
public synchronized int GetScreen(char[] buffer, int len, int row, int col, int length, int plane) {
|
||||
if (buffer == null || len <= 0 || length <= 0 || screen == null) return 0;
|
||||
int r = (row > 0) ? row - 1 : 0;
|
||||
int c = (col > 0) ? col - 1 : 0;
|
||||
int pos = screen.rowColToAddress(r, c);
|
||||
int copyCount = Math.min(Math.min(buffer.length, len), length);
|
||||
return getPlane(plane, buffer, pos, copyCount);
|
||||
}
|
||||
|
||||
public int getScreen(char[] buffer, int len, int row, int col, int length, int plane) {
|
||||
return GetScreen(buffer, len, row, col, length, plane);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert text directly into unprotected fields in the presentation space starting at pos.
|
||||
*/
|
||||
@@ -319,6 +448,24 @@ public class ECLPS implements ECLConstants {
|
||||
setText(text, p);
|
||||
}
|
||||
|
||||
public synchronized void SetString(String text, int pos) throws com.ibm.eNetwork.ECL.ECLErr {
|
||||
if (text == null) {
|
||||
throw new com.ibm.eNetwork.ECL.ECLErr("ECLPS:SetString", "ECL0010", "\"text\"", "null");
|
||||
}
|
||||
if (pos < 1 || pos > getSize()) {
|
||||
throw new com.ibm.eNetwork.ECL.ECLErr("ECLPS:SetString", "ECL0010", "\"pos\"", String.valueOf(pos));
|
||||
}
|
||||
SetText(text, pos);
|
||||
}
|
||||
|
||||
public synchronized void SetString(String text, int row, int col) throws com.ibm.eNetwork.ECL.ECLErr {
|
||||
SetString(text, ConvertRowColToPos(row, col));
|
||||
}
|
||||
|
||||
public synchronized void SetString(String text) throws com.ibm.eNetwork.ECL.ECLErr {
|
||||
SetString(text, GetCursorPos());
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for a string in the presentation space (0-based indexing).
|
||||
* Returns 0-based position, or -1 if not found.
|
||||
@@ -500,6 +647,86 @@ public class ECLPS implements ECLConstants {
|
||||
return SearchPSExt(text, startRow, startCol, endRow, endCol, dir, ignoreCase, wrap);
|
||||
}
|
||||
|
||||
// ========== IBM HoD SearchText / SearchString (1-based API) ==========
|
||||
|
||||
public synchronized int SearchText(String text) {
|
||||
return SearchText(text, 1, SEARCH_FORWARD);
|
||||
}
|
||||
|
||||
public synchronized int searchText(String text) {
|
||||
return SearchText(text);
|
||||
}
|
||||
|
||||
public synchronized int SearchText(String text, int dir) {
|
||||
return dir == SEARCH_BACKWARD ? SearchText(text, getSize(), dir) : SearchText(text, 1, dir);
|
||||
}
|
||||
|
||||
public synchronized int searchText(String text, int dir) {
|
||||
return SearchText(text, dir);
|
||||
}
|
||||
|
||||
public synchronized int SearchText(String text, int arg1, int arg2) {
|
||||
int startPos;
|
||||
int dir;
|
||||
if (arg1 > 2) {
|
||||
startPos = arg1;
|
||||
dir = arg2;
|
||||
} else if (arg2 > 2) {
|
||||
dir = arg1;
|
||||
startPos = arg2;
|
||||
} else {
|
||||
dir = arg1;
|
||||
startPos = arg2;
|
||||
}
|
||||
if (text == null || text.isEmpty() || screen == null) return 0;
|
||||
int size = getSize();
|
||||
if (size <= 0) return 0;
|
||||
if (startPos < 1) startPos = 1;
|
||||
if (startPos > size) startPos = size;
|
||||
|
||||
char[] fullScreen = new char[size];
|
||||
getPlane(PLANE_TEXT, fullScreen, 0, size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (fullScreen[i] == '\0') fullScreen[i] = ' ';
|
||||
}
|
||||
String screenText = new String(fullScreen);
|
||||
int idx = (dir == SEARCH_BACKWARD) ? screenText.lastIndexOf(text, startPos - 1)
|
||||
: screenText.indexOf(text, startPos - 1);
|
||||
return idx == -1 ? 0 : idx + 1;
|
||||
}
|
||||
|
||||
public synchronized int searchText(String text, int arg1, int arg2) {
|
||||
return SearchText(text, arg1, arg2);
|
||||
}
|
||||
|
||||
public synchronized int SearchText(String text, int row, int col, int dir) throws com.ibm.eNetwork.ECL.ECLErr {
|
||||
return SearchText(text, ConvertRowColToPos(row, col), dir);
|
||||
}
|
||||
|
||||
public synchronized int searchText(String text, int row, int col, int dir) throws com.ibm.eNetwork.ECL.ECLErr {
|
||||
return SearchText(text, row, col, dir);
|
||||
}
|
||||
|
||||
public synchronized int SearchString(String text) {
|
||||
return SearchText(text);
|
||||
}
|
||||
|
||||
public synchronized int searchString(String text, int dir) {
|
||||
return SearchText(text, dir);
|
||||
}
|
||||
|
||||
public synchronized int SearchString(String text, int dir) {
|
||||
return SearchText(text, dir);
|
||||
}
|
||||
|
||||
public synchronized int SearchString(String text, int arg1, int arg2) {
|
||||
return SearchText(text, arg1, arg2);
|
||||
}
|
||||
|
||||
public synchronized int SearchString(String text, int row, int col, int dir) throws com.ibm.eNetwork.ECL.ECLErr {
|
||||
return SearchText(text, row, col, dir);
|
||||
}
|
||||
|
||||
private boolean matchesAt(String screenText, String target, int pos, int size) {
|
||||
int len = target.length();
|
||||
for (int j = 0; j < len; j++) {
|
||||
@@ -920,6 +1147,10 @@ public class ECLPS implements ECLConstants {
|
||||
// ========== ECLPS Event Listener Management ==========
|
||||
|
||||
private final java.util.List<ECLPSListener> psListeners = new java.util.concurrent.CopyOnWriteArrayList<>();
|
||||
private final java.util.List<com.ibm.eNetwork.ECL.ECLPSNotify> psNotifies = new java.util.concurrent.CopyOnWriteArrayList<>();
|
||||
private final java.util.Map<com.ibm.eNetwork.ECL.ECLPSNotify, Integer> notifyEventTypes = new java.util.concurrent.ConcurrentHashMap<>();
|
||||
private final java.util.Map<com.ibm.eNetwork.ECL.ECLPSNotify, Object> notifyDescriptors = new java.util.concurrent.ConcurrentHashMap<>();
|
||||
private final java.util.List<com.ibm.eNetwork.ECL.event.ECLPSListener> hodPsListeners = new java.util.concurrent.CopyOnWriteArrayList<>();
|
||||
|
||||
public boolean isCursorVisible() { return cursorVisible; }
|
||||
public boolean GetCursorVisible() { return cursorVisible; }
|
||||
@@ -1007,6 +1238,111 @@ public class ECLPS implements ECLConstants {
|
||||
UnregisterPSEvent(listener);
|
||||
}
|
||||
|
||||
public void RegisterPSEvent(com.ibm.eNetwork.ECL.ECLPSNotify notify) {
|
||||
RegisterPSEvent(notify, ALL_EVENTS);
|
||||
}
|
||||
|
||||
public void registerPSEvent(com.ibm.eNetwork.ECL.ECLPSNotify notify) {
|
||||
RegisterPSEvent(notify);
|
||||
}
|
||||
|
||||
public void RegisterPSEvent(com.ibm.eNetwork.ECL.ECLPSNotify notify, int eventType) {
|
||||
if (notify != null) {
|
||||
notifyEventTypes.put(notify, eventType);
|
||||
if (!psNotifies.contains(notify)) {
|
||||
psNotifies.add(notify);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void registerPSEvent(com.ibm.eNetwork.ECL.ECLPSNotify notify, int eventType) {
|
||||
RegisterPSEvent(notify, eventType);
|
||||
}
|
||||
|
||||
public void RegisterPSEvent(com.ibm.eNetwork.ECL.ECLPSNotify notify, ECLScreenDesc desc) {
|
||||
RegisterPSEvent(notify, desc, ALL_EVENTS);
|
||||
}
|
||||
|
||||
public void registerPSEvent(com.ibm.eNetwork.ECL.ECLPSNotify notify, ECLScreenDesc desc) {
|
||||
RegisterPSEvent(notify, desc);
|
||||
}
|
||||
|
||||
public void RegisterPSEvent(com.ibm.eNetwork.ECL.ECLPSNotify notify, ECLScreenDesc desc, int eventType) {
|
||||
if (notify != null) {
|
||||
if (desc != null) {
|
||||
notifyDescriptors.put(notify, desc);
|
||||
} else {
|
||||
notifyDescriptors.remove(notify);
|
||||
}
|
||||
notifyEventTypes.put(notify, eventType);
|
||||
if (!psNotifies.contains(notify)) {
|
||||
psNotifies.add(notify);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void registerPSEvent(com.ibm.eNetwork.ECL.ECLPSNotify notify, ECLScreenDesc desc, int eventType) {
|
||||
RegisterPSEvent(notify, desc, eventType);
|
||||
}
|
||||
|
||||
public void UnregisterPSEvent(com.ibm.eNetwork.ECL.ECLPSNotify notify) {
|
||||
if (notify != null) {
|
||||
psNotifies.remove(notify);
|
||||
notifyDescriptors.remove(notify);
|
||||
notifyEventTypes.remove(notify);
|
||||
try {
|
||||
notify.NotifyStop(new com.ibm.eNetwork.ECL.ECLPS(this), STOP_UNREGISTER);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterPSEvent(com.ibm.eNetwork.ECL.ECLPSNotify notify) {
|
||||
UnregisterPSEvent(notify);
|
||||
}
|
||||
|
||||
public void RegisterPSEvent(com.ibm.eNetwork.ECL.event.ECLPSListener listener) {
|
||||
if (listener != null && !hodPsListeners.contains(listener)) {
|
||||
hodPsListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerPSEvent(com.ibm.eNetwork.ECL.event.ECLPSListener listener) {
|
||||
RegisterPSEvent(listener);
|
||||
}
|
||||
|
||||
public void UnregisterPSEvent(com.ibm.eNetwork.ECL.event.ECLPSListener listener) {
|
||||
if (listener != null) {
|
||||
hodPsListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterPSEvent(com.ibm.eNetwork.ECL.event.ECLPSListener listener) {
|
||||
UnregisterPSEvent(listener);
|
||||
}
|
||||
|
||||
private static final String[] HACL_MNEMONICS = new String[]{
|
||||
"[attn]", "[backspace]", "[backtab]", "[clear]", "[down]", "[left]", "[right]", "[up]",
|
||||
"[delete]", "[enter]", "[tab]", "[eof]", "[eraseeof]", "[erasefld]", "[erinp]",
|
||||
"[pf1]", "[pf2]", "[pf3]", "[pf4]", "[pf5]", "[pf6]", "[pf7]", "[pf8]", "[pf9]",
|
||||
"[pf10]", "[pf11]", "[pf12]", "[pf13]", "[pf14]", "[pf15]", "[pf16]", "[pf17]",
|
||||
"[pf18]", "[pf19]", "[pf20]", "[pf21]", "[pf22]", "[pf23]", "[pf24]",
|
||||
"[newline]", "[pa1]", "[pa2]", "[pa3]", "[pagedn]", "[pageup]", "[sysreq]",
|
||||
"[wordleft]", "[wordright]", "[backtabword]", "[tabword]", "[previousword]",
|
||||
"[nextword]", "[deleteword]", "[insert]", "[home]", "[reset]", "[dup]",
|
||||
"[fieldmark]", "[fldext]", "[field+]", "[field-]", "[test]", "[help]",
|
||||
"[bof]", "[cursel]", "[selfld]", "[deselfld]", "[+cr]", "[altview]",
|
||||
"[printhost]", "[screenrev]", "[copy]", "[paste]", "[cut]", "[markleft]",
|
||||
"[markright]", "[markup]", "[markdown]", "[unmark]", "[enterreset]"
|
||||
};
|
||||
|
||||
public String[] GetSendKeyMnemonics() {
|
||||
return HACL_MNEMONICS.clone();
|
||||
}
|
||||
|
||||
public String[] getSendKeyMnemonics() {
|
||||
return GetSendKeyMnemonics();
|
||||
}
|
||||
|
||||
public void dispatchEvent(ECLPSEvent event) {
|
||||
notifyPSEvent(event);
|
||||
}
|
||||
@@ -1045,6 +1381,26 @@ public class ECLPS implements ECLConstants {
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
for (com.ibm.eNetwork.ECL.ECLPSNotify n : psNotifies) {
|
||||
Object d = notifyDescriptors.get(n);
|
||||
if (d instanceof ECLScreenDesc && !((ECLScreenDesc) d).Matches(this, session != null ? session.GetOIA() : null)) {
|
||||
continue;
|
||||
}
|
||||
int filter = notifyEventTypes.getOrDefault(n, ALL_EVENTS);
|
||||
int evtCategory = event.GetType();
|
||||
if (filter != ALL_EVENTS && (filter & evtCategory) == 0) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
n.NotifyEvent(new com.ibm.eNetwork.ECL.ECLPS(this));
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
for (com.ibm.eNetwork.ECL.event.ECLPSListener hl : hodPsListeners) {
|
||||
try {
|
||||
com.ibm.eNetwork.ECL.event.ECLPSEvent facadeEvt = new com.ibm.eNetwork.ECL.event.ECLPSEvent(event);
|
||||
hl.PSNotifyEvent(facadeEvt);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyPSError(ECLErr err) {
|
||||
@@ -1053,6 +1409,19 @@ public class ECLPS implements ECLConstants {
|
||||
l.PSNotifyError(this, err);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
com.ibm.eNetwork.ECL.ECLErr ferr = (err instanceof com.ibm.eNetwork.ECL.ECLErr)
|
||||
? (com.ibm.eNetwork.ECL.ECLErr) err
|
||||
: new com.ibm.eNetwork.ECL.ECLErr(err != null ? err.getMessage() : "");
|
||||
for (com.ibm.eNetwork.ECL.ECLPSNotify n : psNotifies) {
|
||||
try {
|
||||
n.NotifyError(new com.ibm.eNetwork.ECL.ECLPS(this), ferr);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
for (com.ibm.eNetwork.ECL.event.ECLPSListener hl : hodPsListeners) {
|
||||
try {
|
||||
hl.PSNotifyError(new com.ibm.eNetwork.ECL.ECLPS(this), ferr);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyPSStop(int reason) {
|
||||
@@ -1061,6 +1430,16 @@ public class ECLPS implements ECLConstants {
|
||||
l.PSNotifyStop(this, reason);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
for (com.ibm.eNetwork.ECL.ECLPSNotify n : psNotifies) {
|
||||
try {
|
||||
n.NotifyStop(new com.ibm.eNetwork.ECL.ECLPS(this), reason);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
for (com.ibm.eNetwork.ECL.event.ECLPSListener hl : hodPsListeners) {
|
||||
try {
|
||||
hl.PSNotifyStop(new com.ibm.eNetwork.ECL.ECLPS(this), reason);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyPSUpdate(int startRow, int startCol, int endRow, int endCol, boolean full) {
|
||||
@@ -1128,6 +1507,25 @@ public class ECLPS implements ECLConstants {
|
||||
sendKeys(keys);
|
||||
}
|
||||
|
||||
public void sendKeys(String keys, int pos) {
|
||||
if (pos >= 1 && pos <= getSize()) {
|
||||
setCursorPos(pos - 1);
|
||||
}
|
||||
sendKeys(keys);
|
||||
}
|
||||
|
||||
public void SendKeys(String keys, int pos) {
|
||||
sendKeys(keys, pos);
|
||||
}
|
||||
|
||||
public void SendKeysNoAid(String string, boolean bl) {
|
||||
sendKeys(string);
|
||||
}
|
||||
|
||||
public void SendKeysNoAid(String string, int row, int col, boolean bl) {
|
||||
sendKeys(string, row, col);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send keystrokes with configurable inter-character or inter-mnemonic delay.
|
||||
*/
|
||||
@@ -1154,6 +1552,17 @@ public class ECLPS implements ECLConstants {
|
||||
sendCharacters(keys, row, col, delayMs);
|
||||
}
|
||||
|
||||
public void sendCharacters(String keys, int pos, int delayMs) {
|
||||
if (pos >= 1 && pos <= getSize()) {
|
||||
setCursorPos(pos - 1);
|
||||
}
|
||||
sendCharacters(keys, delayMs);
|
||||
}
|
||||
|
||||
public void SendCharacters(String keys, int pos, int delayMs) {
|
||||
sendCharacters(keys, pos, delayMs);
|
||||
}
|
||||
|
||||
public void sendCharacters(String keys, int delayMs) {
|
||||
if (keys == null || keys.isEmpty()) return;
|
||||
if (delayMs <= 0) {
|
||||
@@ -1161,37 +1570,36 @@ public class ECLPS implements ECLConstants {
|
||||
return;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
int len = keys.length();
|
||||
while (i < len) {
|
||||
if (keys.charAt(i) == '[') {
|
||||
if (i + 1 < len && keys.charAt(i + 1) == '[') {
|
||||
// Escaped bracket "[["
|
||||
sendKeys("[");
|
||||
i += 2;
|
||||
try {
|
||||
SendKeyTokenizer tokenizer = new SendKeyTokenizer(keys);
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
String token = tokenizer.nextToken();
|
||||
if (token == null) break;
|
||||
|
||||
if (token.length() == 1) {
|
||||
if (inputProcessor != null) inputProcessor.typeCharacter(token.charAt(0));
|
||||
if (delayMs > 0 && tokenizer.hasMoreTokens()) {
|
||||
Thread.sleep(delayMs);
|
||||
}
|
||||
} else if (token.startsWith("[") && token.endsWith("]")) {
|
||||
if (inputProcessor != null) inputProcessor.executeMnemonicToken(token);
|
||||
if (delayMs > 0 && tokenizer.hasMoreTokens()) {
|
||||
Thread.sleep(delayMs);
|
||||
}
|
||||
} else {
|
||||
int close = keys.indexOf(']', i);
|
||||
if (close > i) {
|
||||
String mnemonic = keys.substring(i, close + 1);
|
||||
sendKeys(mnemonic);
|
||||
i = close + 1;
|
||||
} else {
|
||||
sendKeys(keys.substring(i, i + 1));
|
||||
i++;
|
||||
for (int i = 0; i < token.length(); i++) {
|
||||
if (inputProcessor != null) inputProcessor.typeCharacter(token.charAt(i));
|
||||
if (delayMs > 0 && (i < token.length() - 1 || tokenizer.hasMoreTokens())) {
|
||||
Thread.sleep(delayMs);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sendKeys(keys.substring(i, i + 1));
|
||||
i++;
|
||||
}
|
||||
|
||||
if (delayMs > 0 && i < len) {
|
||||
try {
|
||||
Thread.sleep(delayMs);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
break;
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
} catch (ECLErr e) {
|
||||
if (inputProcessor != null) {
|
||||
sendKeys(keys);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,6 +196,14 @@ public class ECLPSEvent extends EventObject {
|
||||
return getECLPSUpdate();
|
||||
}
|
||||
|
||||
public ECLPSUpdate getPSUpdate() {
|
||||
return getECLPSUpdate();
|
||||
}
|
||||
|
||||
public ECLPSUpdate GetPSUpdate() {
|
||||
return getECLPSUpdate();
|
||||
}
|
||||
|
||||
public ECLPS getPS() {
|
||||
return (getSource() instanceof ECLPS) ? (ECLPS) getSource() : null;
|
||||
}
|
||||
|
||||
@@ -1,279 +1,467 @@
|
||||
package haus.nightmare.lib3270j.ecl;
|
||||
|
||||
import haus.nightmare.lib3270j.Telnet3270Client;
|
||||
import haus.nightmare.lib3270j.screen.ScreenBuffer;
|
||||
import java.io.Serializable;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import haus.nightmare.lib3270j.Telnet3270Client;
|
||||
import haus.nightmare.lib3270j.ecl.screenreco.ECLSDAttrib;
|
||||
import haus.nightmare.lib3270j.ecl.screenreco.ECLSDBlock;
|
||||
import haus.nightmare.lib3270j.ecl.screenreco.ECLSDChecksum;
|
||||
import haus.nightmare.lib3270j.ecl.screenreco.ECLSDCursor;
|
||||
import haus.nightmare.lib3270j.ecl.screenreco.ECLSDFields;
|
||||
import haus.nightmare.lib3270j.ecl.screenreco.ECLSDInputFields;
|
||||
import haus.nightmare.lib3270j.ecl.screenreco.ECLSDOIA;
|
||||
import haus.nightmare.lib3270j.ecl.screenreco.ECLSDString;
|
||||
import haus.nightmare.lib3270j.ecl.screenreco.ECLScreenDescriptor;
|
||||
import haus.nightmare.lib3270j.screen.ScreenBuffer;
|
||||
|
||||
/**
|
||||
* Screen descriptor matching engine for IBM Host On-Demand ECL automation.
|
||||
* Screen descriptor composite matching engine for IBM Host On-Demand ECL automation.
|
||||
* Encapsulates criteria for matching host screens (strings, rectangular regions, cursor positions,
|
||||
* field counts, and OIA status).
|
||||
* field counts, OIA status, checksums, and attributes) and supports HACL XML schema serialization.
|
||||
*/
|
||||
public class ECLScreenDesc {
|
||||
public class ECLScreenDesc implements Serializable, Cloneable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final List<ScreenCondition> conditions = new ArrayList<>();
|
||||
|
||||
private interface ScreenCondition {
|
||||
boolean matches(ECLPS ps, ECLOIA oia);
|
||||
}
|
||||
private final List<ECLScreenDescriptor> descriptors = new CopyOnWriteArrayList<>();
|
||||
private String name = "";
|
||||
private boolean active = true;
|
||||
private boolean match = false;
|
||||
public boolean useOIAInhibitStatus = false;
|
||||
|
||||
public ECLScreenDesc() {}
|
||||
|
||||
/**
|
||||
* Clear all conditions from this descriptor.
|
||||
*/
|
||||
public synchronized void Clear() {
|
||||
conditions.clear();
|
||||
public ECLScreenDesc(String xml) {
|
||||
if (xml != null && !xml.trim().isEmpty()) {
|
||||
setXML(xml);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void clear() {
|
||||
Clear();
|
||||
}
|
||||
// ========== Descriptor Management ==========
|
||||
|
||||
/**
|
||||
* Add a condition that the given string must appear anywhere on the presentation space.
|
||||
*/
|
||||
public synchronized void AddString(String text) {
|
||||
public void AddDescriptor(ECLScreenDescriptor descriptor) {
|
||||
if (descriptor != null) {
|
||||
descriptors.add(descriptor);
|
||||
}
|
||||
}
|
||||
public void addDescriptor(ECLScreenDescriptor descriptor) { AddDescriptor(descriptor); }
|
||||
|
||||
public void RemoveDescriptor(ECLScreenDescriptor descriptor) {
|
||||
if (descriptor != null) {
|
||||
descriptors.remove(descriptor);
|
||||
}
|
||||
}
|
||||
public void removeDescriptor(ECLScreenDescriptor descriptor) { RemoveDescriptor(descriptor); }
|
||||
|
||||
public List<ECLScreenDescriptor> GetDescriptors() {
|
||||
return Collections.unmodifiableList(new ArrayList<>(descriptors));
|
||||
}
|
||||
public List<ECLScreenDescriptor> getDescriptors() { return GetDescriptors(); }
|
||||
|
||||
public ECLScreenDescriptor Get(int index) {
|
||||
return descriptors.get(index);
|
||||
}
|
||||
public ECLScreenDescriptor get(int index) { return Get(index); }
|
||||
|
||||
public int Size() { return descriptors.size(); }
|
||||
public int size() { return Size(); }
|
||||
public int getConditionCount() { return Size(); }
|
||||
|
||||
public void Clear() { descriptors.clear(); }
|
||||
public void clear() { Clear(); }
|
||||
|
||||
public String GetName() { return name; }
|
||||
public String getName() { return name; }
|
||||
public void SetName(String name) { this.name = (name != null) ? name : ""; }
|
||||
public void setName(String name) { SetName(name); }
|
||||
|
||||
public boolean IsActive() { return active; }
|
||||
public boolean isActive() { return active; }
|
||||
public void SetActive(boolean active) { this.active = active; }
|
||||
public void setActive(boolean active) { SetActive(active); }
|
||||
|
||||
public boolean IsMatch() { return match; }
|
||||
public boolean isMatch() { return match; }
|
||||
public void SetMatch(boolean match) { this.match = match; }
|
||||
public void setMatch(boolean match) { SetMatch(match); }
|
||||
|
||||
// ========== Programmatic Add* Methods ==========
|
||||
|
||||
public void AddString(String text) {
|
||||
if (text == null || text.isEmpty()) return;
|
||||
conditions.add((ps, oia) -> {
|
||||
if (ps == null) return false;
|
||||
return ps.searchString(text) >= 0;
|
||||
});
|
||||
AddDescriptor(new ECLSDString(text));
|
||||
}
|
||||
public void addString(String text) { AddString(text); }
|
||||
|
||||
public synchronized void addString(String text) {
|
||||
AddString(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a condition that text must appear at 1-based (row, col) position (case-insensitive by default).
|
||||
*/
|
||||
public synchronized void AddString(String text, int row, int col) {
|
||||
public void AddString(String text, int row, int col) {
|
||||
AddString(text, row, col, true);
|
||||
}
|
||||
public void addString(String text, int row, int col) { AddString(text, row, col); }
|
||||
|
||||
public synchronized void addString(String text, int row, int col) {
|
||||
AddString(text, row, col, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a condition that text must appear at (row, col) with case sensitivity control.
|
||||
* Note: 1-based indexing conforming to IBM ECL specification (row 1..rows, col 1..cols).
|
||||
*/
|
||||
public synchronized void AddString(String text, int row, int col, boolean caseSense) {
|
||||
public void AddString(String text, int row, int col, boolean caseSense) {
|
||||
if (text == null || text.isEmpty()) return;
|
||||
conditions.add((ps, oia) -> {
|
||||
if (ps == null) return false;
|
||||
int r = (row > 0) ? row - 1 : 0;
|
||||
int c = (col > 0) ? col - 1 : 0;
|
||||
String onScreen = ps.getString(r, c, text.length());
|
||||
return caseSense ? text.equals(onScreen) : text.equalsIgnoreCase(onScreen);
|
||||
});
|
||||
AddDescriptor(new ECLSDString(text, row, col, caseSense));
|
||||
}
|
||||
public void addString(String text, int row, int col, boolean caseSense) { AddString(text, row, col, caseSense); }
|
||||
|
||||
public synchronized void addString(String text, int row, int col, boolean caseSense) {
|
||||
AddString(text, row, col, caseSense);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a condition that text must appear at a 1-based linear buffer position.
|
||||
*/
|
||||
public synchronized void AddString(String text, int pos, boolean caseSense) {
|
||||
public void AddString(String text, int pos, boolean caseSense) {
|
||||
if (text == null || text.isEmpty()) return;
|
||||
conditions.add((ps, oia) -> {
|
||||
if (ps == null) return false;
|
||||
int p0 = (pos > 0) ? pos - 1 : 0;
|
||||
String onScreen = ps.getString(p0, text.length());
|
||||
return caseSense ? text.equals(onScreen) : text.equalsIgnoreCase(onScreen);
|
||||
});
|
||||
AddDescriptor(new ECLSDString(text, pos, caseSense));
|
||||
}
|
||||
public void addString(String text, int pos, boolean caseSense) { AddString(text, pos, caseSense); }
|
||||
|
||||
public synchronized void addString(String text, int pos, boolean caseSense) {
|
||||
AddString(text, pos, caseSense);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a condition that text must appear within a rectangular region.
|
||||
*/
|
||||
public synchronized void AddStringInRect(String text, int sRow, int sCol, int eRow, int eCol, boolean caseSense) {
|
||||
public void AddStringInRect(String text, int sRow, int sCol, int eRow, int eCol, boolean caseSense) {
|
||||
if (text == null || text.isEmpty()) return;
|
||||
conditions.add((ps, oia) -> {
|
||||
if (ps == null) return false;
|
||||
int sr = (sRow > 0) ? sRow - 1 : 0;
|
||||
int sc = (sCol > 0) ? sCol - 1 : 0;
|
||||
int er = (eRow > 0) ? eRow - 1 : 0;
|
||||
int ec = (eCol > 0) ? eCol - 1 : 0;
|
||||
String block = ps.copyString(sr, sc, er, ec);
|
||||
if (block == null) return false;
|
||||
return caseSense ? block.contains(text) : block.toLowerCase().contains(text.toLowerCase());
|
||||
});
|
||||
AddDescriptor(new ECLSDString(text, sRow, sCol, eRow, eCol, caseSense, false, false));
|
||||
}
|
||||
|
||||
public synchronized void addStringInRect(String text, int sRow, int sCol, int eRow, int eCol, boolean caseSense) {
|
||||
public void addStringInRect(String text, int sRow, int sCol, int eRow, int eCol, boolean caseSense) {
|
||||
AddStringInRect(text, sRow, sCol, eRow, eCol, caseSense);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a condition that the cursor must be located at 1-based (row, col).
|
||||
*/
|
||||
public synchronized void AddCursorPos(int row, int col) {
|
||||
conditions.add((ps, oia) -> {
|
||||
if (ps == null) return false;
|
||||
int r = (row > 0) ? row - 1 : 0;
|
||||
int c = (col > 0) ? col - 1 : 0;
|
||||
return ps.getCursorRow() == r && ps.getCursorCol() == c;
|
||||
});
|
||||
public void AddCursorPos(int row, int col) {
|
||||
AddDescriptor(new ECLSDCursor(row, col));
|
||||
}
|
||||
public void addCursorPos(int row, int col) { AddCursorPos(row, col); }
|
||||
|
||||
public synchronized void addCursorPos(int row, int col) {
|
||||
AddCursorPos(row, col);
|
||||
public void AddCursorPos(int pos) {
|
||||
AddDescriptor(new ECLSDCursor(pos));
|
||||
}
|
||||
public void addCursorPos(int pos) { AddCursorPos(pos); }
|
||||
|
||||
/**
|
||||
* Add a condition that the cursor must be located at 1-based linear buffer position.
|
||||
*/
|
||||
public synchronized void AddCursorPos(int pos) {
|
||||
conditions.add((ps, oia) -> {
|
||||
if (ps == null) return false;
|
||||
int p0 = (pos > 0) ? pos - 1 : 0;
|
||||
return ps.getCursorPos() == p0;
|
||||
});
|
||||
public void AddNumFields(int count) {
|
||||
AddDescriptor(new ECLSDFields(count));
|
||||
}
|
||||
public void addNumFields(int count) { AddNumFields(count); }
|
||||
|
||||
public synchronized void addCursorPos(int pos) {
|
||||
AddCursorPos(pos);
|
||||
public void AddNumInputFields(int count) {
|
||||
AddDescriptor(new ECLSDInputFields(count));
|
||||
}
|
||||
public void addNumInputFields(int count) { AddNumInputFields(count); }
|
||||
|
||||
/**
|
||||
* Add a condition on total field count on the formatted screen.
|
||||
*/
|
||||
public synchronized void AddNumFields(int count) {
|
||||
conditions.add((ps, oia) -> {
|
||||
if (ps == null) return false;
|
||||
return ps.getFieldList().getFieldCount() == count;
|
||||
});
|
||||
public void AddOIAStatus(int status) {
|
||||
ECLSDOIA oia = new ECLSDOIA();
|
||||
oia.setExplicitInhibitStatus(status);
|
||||
AddDescriptor(oia);
|
||||
}
|
||||
public void addOIAStatus(int status) { AddOIAStatus(status); }
|
||||
|
||||
public synchronized void addNumFields(int count) {
|
||||
AddNumFields(count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a condition on number of unprotected input fields on the screen.
|
||||
*/
|
||||
public synchronized void AddNumInputFields(int count) {
|
||||
conditions.add((ps, oia) -> {
|
||||
if (ps == null) return false;
|
||||
int inputCount = 0;
|
||||
for (ECLField f : ps.getFieldList().getFields()) {
|
||||
if (!f.isProtected()) {
|
||||
inputCount++;
|
||||
}
|
||||
}
|
||||
return inputCount == count;
|
||||
});
|
||||
}
|
||||
|
||||
public synchronized void addNumInputFields(int count) {
|
||||
AddNumInputFields(count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a condition on OIA inhibit status.
|
||||
*/
|
||||
public synchronized void AddOIAStatus(int status) {
|
||||
conditions.add((ps, oia) -> {
|
||||
if (oia == null) return true;
|
||||
return oia.getInputInhibited() == status;
|
||||
});
|
||||
}
|
||||
|
||||
public synchronized void addOIAStatus(int status) {
|
||||
public void AddOIAInhibitStatus(int status) {
|
||||
AddOIAStatus(status);
|
||||
}
|
||||
public void addOIAInhibitStatus(int status) { AddOIAInhibitStatus(status); }
|
||||
|
||||
public void AddAttrib(char c, int row, int col, int plane) {
|
||||
AddDescriptor(new ECLSDAttrib(c, row, col, plane));
|
||||
}
|
||||
public void addAttrib(char c, int row, int col, int plane) { AddAttrib(c, row, col, plane); }
|
||||
|
||||
public void AddAttrib(char c, int row, int col, int plane, boolean optional) {
|
||||
AddDescriptor(new ECLSDAttrib(c, row, col, plane, optional));
|
||||
}
|
||||
public void addAttrib(char c, int row, int col, int plane, boolean optional) {
|
||||
AddAttrib(c, row, col, plane, optional);
|
||||
}
|
||||
|
||||
public void AddFieldAttr(int pos, int attr) {
|
||||
AddDescriptor(new ECLScreenDescriptor() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Override
|
||||
protected boolean checkMatch(ECLPS ps, ECLOIA oia) {
|
||||
if (ps == null) return false;
|
||||
int p0 = (pos > 0) ? pos - 1 : 0;
|
||||
ECLField f = ps.getField(p0);
|
||||
if (f == null) return false;
|
||||
return ps.getFieldList().matchAttributes(f, attr);
|
||||
}
|
||||
@Override
|
||||
public String format(int indent, boolean full) {
|
||||
return "<attrib pos=\"" + pos + "\" attr=\"" + attr + "\" />";
|
||||
}
|
||||
});
|
||||
}
|
||||
public void addFieldAttr(int pos, int attr) { AddFieldAttr(pos, attr); }
|
||||
|
||||
public void AddFieldAttr(int row, int col, int attr) {
|
||||
AddDescriptor(new ECLScreenDescriptor() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Override
|
||||
protected boolean checkMatch(ECLPS ps, ECLOIA oia) {
|
||||
if (ps == null) return false;
|
||||
int r = (row > 0) ? row - 1 : 0;
|
||||
int c = (col > 0) ? col - 1 : 0;
|
||||
ECLField f = ps.getField(r, c);
|
||||
if (f == null) return false;
|
||||
return ps.getFieldList().matchAttributes(f, attr);
|
||||
}
|
||||
@Override
|
||||
public String format(int indent, boolean full) {
|
||||
return "<attrib row=\"" + row + "\" col=\"" + col + "\" attr=\"" + attr + "\" />";
|
||||
}
|
||||
});
|
||||
}
|
||||
public void addFieldAttr(int row, int col, int attr) { AddFieldAttr(row, col, attr); }
|
||||
|
||||
public void AddChecksum(int checksum) {
|
||||
AddDescriptor(new ECLSDChecksum(checksum));
|
||||
}
|
||||
public void addChecksum(int checksum) { AddChecksum(checksum); }
|
||||
|
||||
public void AddChecksum(int checksum, boolean optional) {
|
||||
AddDescriptor(new ECLSDChecksum(checksum, optional));
|
||||
}
|
||||
public void addChecksum(int checksum, boolean optional) { AddChecksum(checksum, optional); }
|
||||
|
||||
public void AddBlock(String[] strings, int sRow, int sCol, boolean caseSense) {
|
||||
AddDescriptor(new ECLSDBlock(strings, sRow, sCol, caseSense));
|
||||
}
|
||||
public void addBlock(String[] strings, int sRow, int sCol, boolean caseSense) {
|
||||
AddBlock(strings, sRow, sCol, caseSense);
|
||||
}
|
||||
|
||||
public void AddBlock(ECLSDBlock block) {
|
||||
AddDescriptor(block);
|
||||
}
|
||||
public void addBlock(ECLSDBlock block) { AddBlock(block); }
|
||||
|
||||
// ========== Matching Evaluation ==========
|
||||
|
||||
/**
|
||||
* Check if the current screen state matches all conditions in this descriptor.
|
||||
*/
|
||||
public synchronized boolean Matches(ECLPS ps, ECLOIA oia) {
|
||||
if (conditions.isEmpty()) {
|
||||
if (descriptors.isEmpty()) {
|
||||
this.match = true;
|
||||
return true;
|
||||
}
|
||||
for (ScreenCondition cond : conditions) {
|
||||
if (!cond.matches(ps, oia)) {
|
||||
return false;
|
||||
if (ps == null) {
|
||||
this.match = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean hasNonOptional = false;
|
||||
boolean allNonOptionalMatch = true;
|
||||
boolean hasOptional = false;
|
||||
boolean anyOptionalMatch = false;
|
||||
|
||||
for (ECLScreenDescriptor desc : descriptors) {
|
||||
boolean m = desc.matches(ps, oia);
|
||||
if (desc.isOptional()) {
|
||||
hasOptional = true;
|
||||
if (m) anyOptionalMatch = true;
|
||||
} else {
|
||||
hasNonOptional = true;
|
||||
if (!m) allNonOptionalMatch = false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
boolean res;
|
||||
if (hasNonOptional) {
|
||||
res = allNonOptionalMatch;
|
||||
} else if (hasOptional) {
|
||||
res = anyOptionalMatch;
|
||||
} else {
|
||||
res = true;
|
||||
}
|
||||
|
||||
this.match = res;
|
||||
return res;
|
||||
}
|
||||
|
||||
public boolean matches(ECLPS ps, ECLOIA oia) {
|
||||
return Matches(ps, oia);
|
||||
}
|
||||
public boolean matches(ECLPS ps, ECLOIA oia) { return Matches(ps, oia); }
|
||||
|
||||
public boolean Matches(ECLSession session) {
|
||||
if (session == null) return false;
|
||||
return Matches(session.GetPS(), session.GetOIA());
|
||||
}
|
||||
|
||||
public boolean matches(ECLSession session) {
|
||||
return Matches(session);
|
||||
}
|
||||
public boolean matches(ECLSession session) { return Matches(session); }
|
||||
|
||||
public boolean Matches(Telnet3270Client client) {
|
||||
if (client == null) return false;
|
||||
return Matches(client.getPS(), client.getOIA());
|
||||
}
|
||||
public boolean matches(Telnet3270Client client) { return Matches(client); }
|
||||
|
||||
public boolean matches(Telnet3270Client client) {
|
||||
return Matches(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a condition on field attributes at a 1-based buffer position.
|
||||
*/
|
||||
public synchronized void AddFieldAttr(int pos, int attr) {
|
||||
conditions.add((ps, oia) -> {
|
||||
if (ps == null) return false;
|
||||
int p0 = (pos > 0) ? pos - 1 : 0;
|
||||
ECLField f = ps.getField(p0);
|
||||
if (f == null) return false;
|
||||
return ps.getFieldList().matchAttributes(f, attr);
|
||||
});
|
||||
}
|
||||
public synchronized void addFieldAttr(int pos, int attr) {
|
||||
AddFieldAttr(pos, attr);
|
||||
}
|
||||
|
||||
public synchronized void AddFieldAttr(int row, int col, int attr) {
|
||||
conditions.add((ps, oia) -> {
|
||||
if (ps == null) return false;
|
||||
int r = (row > 0) ? row - 1 : 0;
|
||||
int c = (col > 0) ? col - 1 : 0;
|
||||
ECLField f = ps.getField(r, c);
|
||||
if (f == null) return false;
|
||||
return ps.getFieldList().matchAttributes(f, attr);
|
||||
});
|
||||
}
|
||||
public synchronized void addFieldAttr(int row, int col, int attr) {
|
||||
AddFieldAttr(row, col, attr);
|
||||
}
|
||||
|
||||
public boolean useOIAInhibitStatus = false;
|
||||
|
||||
/**
|
||||
* Check if a raw ScreenBuffer matches all criteria in this screen descriptor.
|
||||
*/
|
||||
public boolean Matches(ScreenBuffer buf) {
|
||||
if (buf == null) return false;
|
||||
return Matches(new ECLPS(buf, null, null), null);
|
||||
}
|
||||
public boolean matches(ScreenBuffer buf) {
|
||||
return Matches(buf);
|
||||
public boolean matches(ScreenBuffer buf) { return Matches(buf); }
|
||||
|
||||
// ========== XML Serialization & Parsing ==========
|
||||
|
||||
public String getXML() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("<description>\n");
|
||||
for (ECLScreenDescriptor desc : descriptors) {
|
||||
sb.append(" ").append(desc.format(0, false)).append("\n");
|
||||
}
|
||||
sb.append("</description>");
|
||||
return sb.toString();
|
||||
}
|
||||
public String GetXML() { return getXML(); }
|
||||
|
||||
public void setXML(String xml) {
|
||||
Clear();
|
||||
if (xml == null || xml.trim().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
try {
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
} catch (Throwable ignored) {}
|
||||
try {
|
||||
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
|
||||
} catch (Throwable ignored) {}
|
||||
try {
|
||||
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
|
||||
} catch (Throwable ignored) {}
|
||||
|
||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||
Document doc = builder.parse(new InputSource(new StringReader(xml.trim())));
|
||||
Element root = doc.getDocumentElement();
|
||||
|
||||
Element descElement = root;
|
||||
if (!root.getTagName().equalsIgnoreCase("description")) {
|
||||
NodeList list = root.getElementsByTagName("description");
|
||||
if (list.getLength() > 0) {
|
||||
descElement = (Element) list.item(0);
|
||||
}
|
||||
}
|
||||
|
||||
NodeList children = descElement.getChildNodes();
|
||||
for (int i = 0; i < children.getLength(); i++) {
|
||||
Node node = children.item(i);
|
||||
if (node.getNodeType() != Node.ELEMENT_NODE) continue;
|
||||
Element elem = (Element) node;
|
||||
String tag = elem.getTagName().toLowerCase();
|
||||
|
||||
boolean optional = "true".equalsIgnoreCase(elem.getAttribute("optional"));
|
||||
boolean invertmatch = "true".equalsIgnoreCase(elem.getAttribute("invertmatch"));
|
||||
String hostid = elem.getAttribute("hostid");
|
||||
|
||||
if (tag.equals("string")) {
|
||||
String value = elem.getAttribute("value");
|
||||
int row = parseIntAttr(elem, "row", 0);
|
||||
int col = parseIntAttr(elem, "col", 0);
|
||||
int erow = parseIntAttr(elem, "erow", -1);
|
||||
int ecol = parseIntAttr(elem, "ecol", -1);
|
||||
boolean casesense = "true".equalsIgnoreCase(elem.getAttribute("casesense"));
|
||||
boolean wrap = "true".equalsIgnoreCase(elem.getAttribute("wrap"));
|
||||
|
||||
ECLSDString s;
|
||||
if (row > 0 && col > 0) {
|
||||
if (erow > 0 || ecol > 0) {
|
||||
s = new ECLSDString(value, row, col, erow, ecol, casesense, optional, wrap);
|
||||
} else {
|
||||
s = new ECLSDString(value, row, col, casesense, optional);
|
||||
}
|
||||
} else {
|
||||
s = new ECLSDString(value);
|
||||
s.setCaseSense(casesense);
|
||||
s.setOptional(optional);
|
||||
}
|
||||
s.setInvertMatch(invertmatch);
|
||||
s.setHostid(hostid);
|
||||
AddDescriptor(s);
|
||||
} else if (tag.equals("cursor")) {
|
||||
int row = parseIntAttr(elem, "row", 1);
|
||||
int col = parseIntAttr(elem, "col", 1);
|
||||
int pos = parseIntAttr(elem, "position", -1);
|
||||
ECLSDCursor c;
|
||||
if (pos > 0) {
|
||||
c = new ECLSDCursor(pos, optional);
|
||||
} else {
|
||||
c = new ECLSDCursor(row, col, optional);
|
||||
}
|
||||
c.setInvertMatch(invertmatch);
|
||||
c.setHostid(hostid);
|
||||
AddDescriptor(c);
|
||||
} else if (tag.equals("numfields") || tag.equals("fields")) {
|
||||
int num = parseIntAttr(elem, elem.hasAttribute("number") ? "number" : "value", 0);
|
||||
ECLSDFields f = new ECLSDFields(num, optional);
|
||||
f.setInvertMatch(invertmatch);
|
||||
f.setHostid(hostid);
|
||||
AddDescriptor(f);
|
||||
} else if (tag.equals("numinputfields") || tag.equals("inputfields")) {
|
||||
int num = parseIntAttr(elem, elem.hasAttribute("number") ? "number" : "value", 0);
|
||||
ECLSDInputFields inf = new ECLSDInputFields(num, optional);
|
||||
inf.setInvertMatch(invertmatch);
|
||||
inf.setHostid(hostid);
|
||||
AddDescriptor(inf);
|
||||
} else if (tag.equals("oia")) {
|
||||
String status = elem.hasAttribute("status") ? elem.getAttribute("status") :
|
||||
(elem.hasAttribute("input") ? elem.getAttribute("input") : "NOTINHIBITED");
|
||||
ECLSDOIA oia = new ECLSDOIA(status, optional);
|
||||
oia.setInvertMatch(invertmatch);
|
||||
oia.setHostid(hostid);
|
||||
AddDescriptor(oia);
|
||||
} else if (tag.equals("checksum")) {
|
||||
int value = parseIntAttr(elem, "value", 0);
|
||||
ECLSDChecksum cs = new ECLSDChecksum(value, optional);
|
||||
cs.setInvertMatch(invertmatch);
|
||||
cs.setHostid(hostid);
|
||||
AddDescriptor(cs);
|
||||
} else if (tag.equals("attrib")) {
|
||||
String valStr = elem.getAttribute("value");
|
||||
char val = ECLSDAttrib.StringToAttrib(valStr);
|
||||
int row = parseIntAttr(elem, "row", 1);
|
||||
int col = parseIntAttr(elem, "col", 1);
|
||||
int plane = ECLSDAttrib.StringToPlane(elem.getAttribute("plane"));
|
||||
ECLSDAttrib attr = new ECLSDAttrib(val, row, col, plane, optional);
|
||||
attr.setInvertMatch(invertmatch);
|
||||
attr.setHostid(hostid);
|
||||
AddDescriptor(attr);
|
||||
} else if (tag.equals("block")) {
|
||||
int row = parseIntAttr(elem, "row", 1);
|
||||
int col = parseIntAttr(elem, "col", 1);
|
||||
int erow = parseIntAttr(elem, "erow", -1);
|
||||
int ecol = parseIntAttr(elem, "ecol", -1);
|
||||
boolean casesense = "true".equalsIgnoreCase(elem.getAttribute("casesense"));
|
||||
|
||||
ECLSDBlock blk;
|
||||
if (erow > 0 || ecol > 0) {
|
||||
blk = new ECLSDBlock(row, col, erow, ecol, casesense, optional);
|
||||
} else {
|
||||
blk = new ECLSDBlock(row, col, casesense, optional);
|
||||
}
|
||||
blk.setInvertMatch(invertmatch);
|
||||
blk.setHostid(hostid);
|
||||
|
||||
NodeList subList = elem.getElementsByTagName("string");
|
||||
for (int j = 0; j < subList.getLength(); j++) {
|
||||
Element strElem = (Element) subList.item(j);
|
||||
blk.addString(strElem.getAttribute("value"));
|
||||
}
|
||||
AddDescriptor(blk);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to parse ECLScreenDesc XML: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
public void SetXML(String xml) { setXML(xml); }
|
||||
|
||||
private static int parseIntAttr(Element elem, String attrName, int defaultVal) {
|
||||
if (!elem.hasAttribute(attrName)) return defaultVal;
|
||||
try {
|
||||
return Integer.parseInt(elem.getAttribute(attrName).trim());
|
||||
} catch (NumberFormatException e) {
|
||||
return defaultVal;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized int getConditionCount() {
|
||||
return conditions.size();
|
||||
@Override
|
||||
public String toString() {
|
||||
return getXML();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,21 +11,28 @@ public class ECLScreenReco {
|
||||
|
||||
private final ECLSession session;
|
||||
private final ECLPS ps;
|
||||
private final ECLOIA oia;
|
||||
private final Map<ECLScreenDesc, ECLScreenNotify> notifyMap = new ConcurrentHashMap<>();
|
||||
private final Map<ECLScreenDesc, ECLPSListener> listenerMap = new ConcurrentHashMap<>();
|
||||
private final ECLPSListener internalListener;
|
||||
private final ECLOIANotify internalOiaListener;
|
||||
|
||||
public ECLScreenReco() {
|
||||
this((ECLPS) null);
|
||||
}
|
||||
|
||||
public ECLScreenReco(ECLSession session) {
|
||||
this(session != null ? session.GetPS() : null);
|
||||
this(session != null ? session.GetPS() : null, session != null ? session.GetOIA() : null);
|
||||
}
|
||||
|
||||
public ECLScreenReco(ECLPS ps) {
|
||||
this(ps, (ECLOIA) null);
|
||||
}
|
||||
|
||||
public ECLScreenReco(ECLPS ps, ECLOIA oia) {
|
||||
this.ps = ps;
|
||||
this.session = (ps != null) ? ps.GetParent() : null;
|
||||
this.oia = (oia != null) ? oia : ((session != null) ? session.GetOIA() : null);
|
||||
|
||||
this.internalListener = new ECLPSListener() {
|
||||
@Override
|
||||
@@ -34,9 +41,14 @@ public class ECLScreenReco {
|
||||
}
|
||||
};
|
||||
|
||||
this.internalOiaListener = event -> checkAllScreens();
|
||||
|
||||
if (this.ps != null) {
|
||||
this.ps.RegisterPSEvent(this.internalListener);
|
||||
}
|
||||
if (this.oia != null) {
|
||||
this.oia.RegisterOIAEvent(this.internalOiaListener);
|
||||
}
|
||||
}
|
||||
|
||||
// ========== Static Recognition Helpers ==========
|
||||
@@ -95,6 +107,16 @@ public class ECLScreenReco {
|
||||
UnregisterScreen(desc, notify);
|
||||
}
|
||||
|
||||
public void UnregisterScreen(ECLScreenDesc desc) {
|
||||
if (desc != null) {
|
||||
notifyMap.remove(desc);
|
||||
listenerMap.remove(desc);
|
||||
}
|
||||
}
|
||||
public void unregisterScreen(ECLScreenDesc desc) {
|
||||
UnregisterScreen(desc);
|
||||
}
|
||||
|
||||
public void RegisterScreen(ECLScreenDesc desc, ECLPSListener listener) {
|
||||
if (desc != null && listener != null) {
|
||||
listenerMap.put(desc, listener);
|
||||
@@ -120,7 +142,10 @@ public class ECLScreenReco {
|
||||
}
|
||||
|
||||
public boolean IsMatch(ECLScreenDesc desc) {
|
||||
return IsMatch(ps, desc);
|
||||
if (desc == null) return true;
|
||||
if (ps == null) return false;
|
||||
ECLOIA activeOia = (oia != null) ? oia : ((ps.GetParent() != null) ? ps.GetParent().GetOIA() : null);
|
||||
return desc.Matches(ps, activeOia);
|
||||
}
|
||||
public boolean isMatch(ECLScreenDesc desc) {
|
||||
return IsMatch(desc);
|
||||
@@ -142,6 +167,9 @@ public class ECLScreenReco {
|
||||
if (ps != null && internalListener != null) {
|
||||
ps.UnregisterPSEvent(internalListener);
|
||||
}
|
||||
if (oia != null && internalOiaListener != null) {
|
||||
oia.UnregisterOIAEvent(internalOiaListener);
|
||||
}
|
||||
notifyMap.clear();
|
||||
listenerMap.clear();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
package haus.nightmare.lib3270j.ecl.screenreco;
|
||||
|
||||
import haus.nightmare.lib3270j.ecl.ECLOIA;
|
||||
import haus.nightmare.lib3270j.ecl.ECLPS;
|
||||
|
||||
/**
|
||||
* Screen descriptor matching field or presentation plane attributes matching IBM Host On-Demand ECLSDAttrib.
|
||||
*/
|
||||
public class ECLSDAttrib extends ECLScreenDescriptor {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final int TEXT_PLANE = 1;
|
||||
public static final int COLOR_PLANE = 2;
|
||||
public static final int DBCS_PLANE = 4;
|
||||
public static final int GRID_PLANE = 8;
|
||||
public static final int FIELD_PLANE = 16;
|
||||
public static final int EXFIELD_PLANE = 32;
|
||||
|
||||
private char attrib = 0x00;
|
||||
private int row = 1;
|
||||
private int col = 1;
|
||||
private int plane = FIELD_PLANE;
|
||||
|
||||
public ECLSDAttrib() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ECLSDAttrib(char attrib, int row, int col, int plane) {
|
||||
this(attrib, row, col, plane, false);
|
||||
}
|
||||
|
||||
public ECLSDAttrib(char attrib, int row, int col, int plane, boolean optional) {
|
||||
super(optional);
|
||||
this.attrib = attrib;
|
||||
this.row = row;
|
||||
this.col = col;
|
||||
this.plane = plane;
|
||||
}
|
||||
|
||||
public char getAttrib() { return attrib; }
|
||||
public char GetAttrib() { return attrib; }
|
||||
public void setAttrib(char attrib) { this.attrib = attrib; }
|
||||
public void SetAttrib(char attrib) { setAttrib(attrib); }
|
||||
|
||||
public int getRow() { return row; }
|
||||
public int GetRow() { return row; }
|
||||
public void setRow(int row) { this.row = row; }
|
||||
public void SetRow(int row) { setRow(row); }
|
||||
|
||||
public int getCol() { return col; }
|
||||
public int GetCol() { return col; }
|
||||
public void setCol(int col) { this.col = col; }
|
||||
public void SetCol(int col) { setCol(col); }
|
||||
|
||||
public int getPlane() { return plane; }
|
||||
public int GetPlane() { return plane; }
|
||||
public void setPlane(int plane) { this.plane = plane; }
|
||||
public void SetPlane(int plane) { setPlane(plane); }
|
||||
|
||||
public static String PlaneToString(int plane) {
|
||||
switch (plane) {
|
||||
case TEXT_PLANE: return "TEXT_PLANE";
|
||||
case COLOR_PLANE: return "COLOR_PLANE";
|
||||
case DBCS_PLANE: return "DBCS_PLANE";
|
||||
case GRID_PLANE: return "GRID_PLANE";
|
||||
case FIELD_PLANE: return "FIELD_PLANE";
|
||||
case EXFIELD_PLANE: return "EXFIELD_PLANE";
|
||||
default: return "FIELD_PLANE";
|
||||
}
|
||||
}
|
||||
|
||||
public static int StringToPlane(String str) {
|
||||
if (str == null) return FIELD_PLANE;
|
||||
if (str.equalsIgnoreCase("TEXT_PLANE")) return TEXT_PLANE;
|
||||
if (str.equalsIgnoreCase("COLOR_PLANE")) return COLOR_PLANE;
|
||||
if (str.equalsIgnoreCase("DBCS_PLANE")) return DBCS_PLANE;
|
||||
if (str.equalsIgnoreCase("GRID_PLANE")) return GRID_PLANE;
|
||||
if (str.equalsIgnoreCase("FIELD_PLANE")) return FIELD_PLANE;
|
||||
if (str.equalsIgnoreCase("EXFIELD_PLANE")) return EXFIELD_PLANE;
|
||||
try {
|
||||
return Integer.parseInt(str);
|
||||
} catch (NumberFormatException e) {
|
||||
return FIELD_PLANE;
|
||||
}
|
||||
}
|
||||
|
||||
public static String AttribToString(char c) {
|
||||
return "0x" + Integer.toHexString(c & 0xFFFF);
|
||||
}
|
||||
|
||||
public static char StringToAttrib(String str) {
|
||||
if (str == null || str.isEmpty()) return 0;
|
||||
str = str.trim();
|
||||
int xIdx = str.toLowerCase().indexOf('x');
|
||||
if (xIdx != -1) {
|
||||
return (char) Integer.parseInt(str.substring(xIdx + 1), 16);
|
||||
}
|
||||
return (char) Integer.parseInt(str);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean checkMatch(ECLPS ps, ECLOIA oia) {
|
||||
if (ps == null) return false;
|
||||
int totalRows = ps.getRows();
|
||||
int totalCols = ps.getCols();
|
||||
|
||||
if (row < 1 || row > totalRows || col < 1 || col > totalCols) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int addr = (row - 1) * totalCols + (col - 1);
|
||||
char[] buf = new char[1];
|
||||
ps.getPlane(plane, buf, addr, 1);
|
||||
return buf[0] == attrib;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(int indent, boolean full) {
|
||||
StringBuilder sb = new StringBuilder("<attrib ");
|
||||
sb.append("value=\"").append(AttribToString(attrib)).append("\" ");
|
||||
sb.append("row=\"").append(row).append("\" ");
|
||||
sb.append("col=\"").append(col).append("\" ");
|
||||
sb.append("plane=\"").append(PlaneToString(plane)).append("\" ");
|
||||
return formatAttributes(sb.toString(), full);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
package haus.nightmare.lib3270j.ecl.screenreco;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import haus.nightmare.lib3270j.ecl.ECLOIA;
|
||||
import haus.nightmare.lib3270j.ecl.ECLPS;
|
||||
|
||||
/**
|
||||
* Screen descriptor matching a rectangular block of text matching IBM Host On-Demand ECLSDBlock.
|
||||
*/
|
||||
public class ECLSDBlock extends ECLScreenDescriptor {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final int BLOCK_ABSOLUTE = 1;
|
||||
public static final int BLOCK_INRECT = 2;
|
||||
|
||||
private int blockType = BLOCK_INRECT;
|
||||
private int srow = 1;
|
||||
private int scol = 1;
|
||||
private int erow = -1;
|
||||
private int ecol = -1;
|
||||
private boolean caseSense = false;
|
||||
private ECLSDBlockString[] strings = new ECLSDBlockString[0];
|
||||
|
||||
public ECLSDBlock() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ECLSDBlock(int srow, int scol, boolean caseSense, boolean optional) {
|
||||
super(optional);
|
||||
this.blockType = BLOCK_ABSOLUTE;
|
||||
this.srow = srow;
|
||||
this.scol = scol;
|
||||
this.caseSense = caseSense;
|
||||
}
|
||||
|
||||
public ECLSDBlock(int srow, int scol, int erow, int ecol, boolean caseSense, boolean optional) {
|
||||
super(optional);
|
||||
this.blockType = BLOCK_INRECT;
|
||||
this.srow = srow;
|
||||
this.scol = scol;
|
||||
this.erow = erow;
|
||||
this.ecol = ecol;
|
||||
this.caseSense = caseSense;
|
||||
}
|
||||
|
||||
public ECLSDBlock(String[] textLines, int srow, int scol, boolean caseSense) {
|
||||
super(false);
|
||||
this.blockType = BLOCK_ABSOLUTE;
|
||||
this.srow = srow;
|
||||
this.scol = scol;
|
||||
this.caseSense = caseSense;
|
||||
setStrings(textLines);
|
||||
}
|
||||
|
||||
public int getBlockType() { return blockType; }
|
||||
public int GetBlockType() { return blockType; }
|
||||
public void setBlockType(int blockType) { this.blockType = blockType; }
|
||||
public void SetBlockType(int blockType) { setBlockType(blockType); }
|
||||
|
||||
public int getSRow() { return srow; }
|
||||
public int GetSRow() { return srow; }
|
||||
public void setSRow(int srow) { this.srow = srow; }
|
||||
public void SetSRow(int srow) { setSRow(srow); }
|
||||
|
||||
public int getSCol() { return scol; }
|
||||
public int GetSCol() { return scol; }
|
||||
public void setSCol(int scol) { this.scol = scol; }
|
||||
public void SetSCol(int scol) { setSCol(scol); }
|
||||
|
||||
public int getERow() { return erow; }
|
||||
public int GetERow() { return erow; }
|
||||
public void setERow(int erow) { this.erow = erow; }
|
||||
public void SetERow(int erow) { setERow(erow); }
|
||||
|
||||
public int getECol() { return ecol; }
|
||||
public int GetECol() { return ecol; }
|
||||
public void setECol(int ecol) { this.ecol = ecol; }
|
||||
public void SetECol(int ecol) { setECol(ecol); }
|
||||
|
||||
public boolean isCaseSense() { return caseSense; }
|
||||
public boolean IsCaseSense() { return caseSense; }
|
||||
public void setCaseSense(boolean caseSense) { this.caseSense = caseSense; }
|
||||
public void SetCaseSense(boolean caseSense) { setCaseSense(caseSense); }
|
||||
|
||||
public String[] getStrings() {
|
||||
String[] arr = new String[strings.length];
|
||||
for (int i = 0; i < strings.length; i++) {
|
||||
arr[i] = (strings[i] != null) ? strings[i].getText() : "";
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
public String[] GetStrings() { return getStrings(); }
|
||||
|
||||
public void setStrings(String[] textLines) {
|
||||
if (textLines == null) {
|
||||
this.strings = new ECLSDBlockString[0];
|
||||
return;
|
||||
}
|
||||
this.strings = new ECLSDBlockString[textLines.length];
|
||||
for (int i = 0; i < textLines.length; i++) {
|
||||
this.strings[i] = new ECLSDBlockString(textLines[i]);
|
||||
}
|
||||
}
|
||||
public void SetStrings(String[] textLines) { setStrings(textLines); }
|
||||
|
||||
public void setBlockStrings(ECLSDBlockString[] blockStrings) {
|
||||
this.strings = (blockStrings != null) ? blockStrings : new ECLSDBlockString[0];
|
||||
}
|
||||
|
||||
public void addString(String text) {
|
||||
ECLSDBlockString[] newArr = new ECLSDBlockString[strings.length + 1];
|
||||
System.arraycopy(strings, 0, newArr, 0, strings.length);
|
||||
newArr[strings.length] = new ECLSDBlockString(text);
|
||||
this.strings = newArr;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean checkMatch(ECLPS ps, ECLOIA oia) {
|
||||
if (ps == null) return false;
|
||||
if (strings == null || strings.length == 0) return true;
|
||||
|
||||
int totalRows = ps.getRows();
|
||||
int totalCols = ps.getCols();
|
||||
String[] lines = getStrings();
|
||||
|
||||
// 1. Absolute matching at (srow, scol)
|
||||
if (blockType == BLOCK_ABSOLUTE || (erow <= 0 && ecol <= 0 && srow > 0 && scol > 0)) {
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
int r0 = srow + i - 1;
|
||||
int c0 = scol - 1;
|
||||
if (r0 < 0 || r0 >= totalRows || c0 < 0 || c0 >= totalCols) return false;
|
||||
String target = lines[i];
|
||||
String onScreen = ps.getString(r0, c0, target.length());
|
||||
if (onScreen == null) return false;
|
||||
boolean eq = caseSense ? target.equals(onScreen) : target.equalsIgnoreCase(onScreen);
|
||||
if (!eq) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 2. Rectangular region matching
|
||||
int sr = (srow > 0) ? srow : 1;
|
||||
int sc = (scol > 0) ? scol : 1;
|
||||
int er = (erow > 0) ? Math.min(erow, totalRows) : totalRows;
|
||||
int ec = (ecol > 0) ? Math.min(ecol, totalCols) : totalCols;
|
||||
|
||||
if (sr > er || sc > ec) return false;
|
||||
int numLines = lines.length;
|
||||
if (er - sr + 1 < numLines) return false;
|
||||
|
||||
int rectWidth = ec - sc + 1;
|
||||
List<String> screenLines = new ArrayList<>();
|
||||
for (int r = sr; r <= er; r++) {
|
||||
String s = ps.getString(r - 1, sc - 1, rectWidth);
|
||||
screenLines.add(s != null ? s : "");
|
||||
}
|
||||
|
||||
String firstTarget = caseSense ? lines[0] : lines[0].toLowerCase();
|
||||
for (int i = 0; i <= screenLines.size() - numLines; i++) {
|
||||
String rowStr = caseSense ? screenLines.get(i) : screenLines.get(i).toLowerCase();
|
||||
int matchIdx = rowStr.indexOf(firstTarget);
|
||||
while (matchIdx != -1) {
|
||||
boolean allMatch = true;
|
||||
for (int j = 1; j < numLines; j++) {
|
||||
String nextRowStr = caseSense ? screenLines.get(i + j) : screenLines.get(i + j).toLowerCase();
|
||||
String nextTarget = caseSense ? lines[j] : lines[j].toLowerCase();
|
||||
if (matchIdx + nextTarget.length() > nextRowStr.length() ||
|
||||
!nextRowStr.startsWith(nextTarget, matchIdx)) {
|
||||
allMatch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allMatch) {
|
||||
return true;
|
||||
}
|
||||
matchIdx = rowStr.indexOf(firstTarget, matchIdx + 1);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(int indent, boolean full) {
|
||||
StringBuilder sb = new StringBuilder("<block ");
|
||||
if (srow > 0 || full) sb.append("row=\"").append(srow).append("\" ");
|
||||
if (scol > 0 || full) sb.append("col=\"").append(scol).append("\" ");
|
||||
if (blockType == BLOCK_INRECT && (erow > 0 || ecol > 0 || full)) {
|
||||
if (erow > 0 || full) sb.append("erow=\"").append(erow).append("\" ");
|
||||
if (ecol > 0 || full) sb.append("ecol=\"").append(ecol).append("\" ");
|
||||
}
|
||||
if (caseSense || full) sb.append("casesense=\"").append(caseSense).append("\" ");
|
||||
if (optional || full) sb.append("optional=\"").append(optional).append("\" ");
|
||||
if (invert || full) sb.append("invertmatch=\"").append(invert).append("\" ");
|
||||
if (hostid != null && !hostid.isEmpty()) sb.append("hostid=\"").append(escapeChars(hostid)).append("\" ");
|
||||
sb.append(">\n");
|
||||
|
||||
for (ECLSDBlockString s : strings) {
|
||||
sb.append(" ").append(s.format(indent + 1, full)).append("\n");
|
||||
}
|
||||
sb.append("</block>");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package haus.nightmare.lib3270j.ecl.screenreco;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Encapsulates an individual string line within an ECLSDBlock matching IBM Host On-Demand.
|
||||
*/
|
||||
public class ECLSDBlockString implements Serializable, Cloneable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String text = "";
|
||||
|
||||
public ECLSDBlockString() {}
|
||||
|
||||
public ECLSDBlockString(String text) {
|
||||
this.text = (text != null) ? text : "";
|
||||
}
|
||||
|
||||
public String getText() { return text; }
|
||||
public String GetText() { return text; }
|
||||
public String GetString() { return text; }
|
||||
public String getString() { return text; }
|
||||
public void setText(String text) { this.text = (text != null) ? text : ""; }
|
||||
public void SetText(String text) { setText(text); }
|
||||
public void SetString(String text) { setText(text); }
|
||||
public void setString(String text) { setText(text); }
|
||||
|
||||
public String format(int indent, boolean full) {
|
||||
return "<string value=\"" + ECLScreenDescriptor.escapeChars(text) + "\" />";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package haus.nightmare.lib3270j.ecl.screenreco;
|
||||
|
||||
import haus.nightmare.lib3270j.ecl.ECLField;
|
||||
import haus.nightmare.lib3270j.ecl.ECLFieldList;
|
||||
import haus.nightmare.lib3270j.ecl.ECLOIA;
|
||||
import haus.nightmare.lib3270j.ecl.ECLPS;
|
||||
|
||||
/**
|
||||
* Screen descriptor matching screen buffer checksum matching IBM Host On-Demand ECLSDChecksum.
|
||||
*/
|
||||
public class ECLSDChecksum extends ECLScreenDescriptor {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private int value = 0;
|
||||
|
||||
public ECLSDChecksum() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ECLSDChecksum(int value) {
|
||||
this(value, false);
|
||||
}
|
||||
|
||||
public ECLSDChecksum(int value, boolean optional) {
|
||||
super(optional);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() { return value; }
|
||||
public int GetValue() { return value; }
|
||||
public void setValue(int value) { this.value = value; }
|
||||
public void SetValue(int value) { setValue(value); }
|
||||
|
||||
public static int CalculateChecksum(ECLFieldList fieldList, int psSize) {
|
||||
int sum = 0;
|
||||
if (fieldList != null && fieldList.getFieldCount() > 0) {
|
||||
int count = fieldList.getFieldCount();
|
||||
sum = 17;
|
||||
ECLField current = null;
|
||||
for (int i = 0; i < count - 1; i++) {
|
||||
if (i == 0) {
|
||||
current = fieldList.getFirstField();
|
||||
}
|
||||
ECLField next = fieldList.getNextField(current);
|
||||
if (current != null && next != null) {
|
||||
int delta = next.getStart() - current.getStart() - 1;
|
||||
sum = sum * 37 + delta;
|
||||
}
|
||||
current = next;
|
||||
}
|
||||
ECLField last = (current == null) ? fieldList.getFirstField() : current;
|
||||
int endDelta = (last != null) ? (psSize - last.getStart()) : 0;
|
||||
sum = sum * 37 + endDelta;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean checkMatch(ECLPS ps, ECLOIA oia) {
|
||||
if (ps == null) return false;
|
||||
int calc = CalculateChecksum(ps.getFieldList(), ps.getSize());
|
||||
return calc == value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(int indent, boolean full) {
|
||||
StringBuilder sb = new StringBuilder("<checksum ");
|
||||
sb.append("value=\"").append(value).append("\" ");
|
||||
return formatAttributes(sb.toString(), full);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package haus.nightmare.lib3270j.ecl.screenreco;
|
||||
|
||||
import haus.nightmare.lib3270j.ecl.ECLOIA;
|
||||
import haus.nightmare.lib3270j.ecl.ECLPS;
|
||||
|
||||
/**
|
||||
* Screen descriptor matching cursor position matching IBM Host On-Demand ECLSDCursor.
|
||||
*/
|
||||
public class ECLSDCursor extends ECLScreenDescriptor {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private int row = 1;
|
||||
private int col = 1;
|
||||
private int pos = -1;
|
||||
|
||||
public ECLSDCursor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ECLSDCursor(int pos) {
|
||||
this(pos, false);
|
||||
}
|
||||
|
||||
public ECLSDCursor(int pos, boolean optional) {
|
||||
super(optional);
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
public ECLSDCursor(int row, int col) {
|
||||
this(row, col, false);
|
||||
}
|
||||
|
||||
public ECLSDCursor(int row, int col, boolean optional) {
|
||||
super(optional);
|
||||
this.row = row;
|
||||
this.col = col;
|
||||
}
|
||||
|
||||
public int getPos() { return pos; }
|
||||
public int GetPos() { return pos; }
|
||||
public void setPos(int pos) { this.pos = pos; }
|
||||
public void SetPos(int pos) { setPos(pos); }
|
||||
|
||||
public int getRow() { return row; }
|
||||
public int GetRow() { return row; }
|
||||
public void setRow(int row) { this.row = row; }
|
||||
public void SetRow(int row) { setRow(row); }
|
||||
|
||||
public int getCol() { return col; }
|
||||
public int GetCol() { return col; }
|
||||
public void setCol(int col) { this.col = col; }
|
||||
public void SetCol(int col) { setCol(col); }
|
||||
|
||||
@Override
|
||||
protected boolean checkMatch(ECLPS ps, ECLOIA oia) {
|
||||
if (ps == null) return false;
|
||||
if (pos > 0) {
|
||||
return (ps.getCursorPos() + 1) == pos;
|
||||
}
|
||||
// In ECLPS, getCursorRow() and getCursorCol() return 0-based indices.
|
||||
int curRow = ps.getCursorRow() + 1;
|
||||
int curCol = ps.getCursorCol() + 1;
|
||||
return (curRow == row && curCol == col);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(int indent, boolean full) {
|
||||
StringBuilder sb = new StringBuilder("<cursor ");
|
||||
if (pos > 0) {
|
||||
sb.append("position=\"").append(pos).append("\" ");
|
||||
} else {
|
||||
sb.append("row=\"").append(row).append("\" ");
|
||||
sb.append("col=\"").append(col).append("\" ");
|
||||
}
|
||||
return formatAttributes(sb.toString(), full);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package haus.nightmare.lib3270j.ecl.screenreco;
|
||||
|
||||
import haus.nightmare.lib3270j.ecl.ECLFieldList;
|
||||
import haus.nightmare.lib3270j.ecl.ECLOIA;
|
||||
import haus.nightmare.lib3270j.ecl.ECLPS;
|
||||
|
||||
/**
|
||||
* Screen descriptor matching total number of fields matching IBM Host On-Demand ECLSDFields.
|
||||
*/
|
||||
public class ECLSDFields extends ECLScreenDescriptor {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private int num = 0;
|
||||
|
||||
public ECLSDFields() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ECLSDFields(int num) {
|
||||
this(num, false);
|
||||
}
|
||||
|
||||
public ECLSDFields(int num, boolean optional) {
|
||||
super(optional);
|
||||
this.num = num;
|
||||
}
|
||||
|
||||
public int getNum() { return num; }
|
||||
public int GetNum() { return num; }
|
||||
public void setNum(int num) { this.num = num; }
|
||||
public void SetNum(int num) { setNum(num); }
|
||||
|
||||
@Override
|
||||
protected boolean checkMatch(ECLPS ps, ECLOIA oia) {
|
||||
if (ps == null) return false;
|
||||
ECLFieldList fl = ps.getFieldList();
|
||||
if (fl == null) return false;
|
||||
return fl.getFieldCount() == num;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(int indent, boolean full) {
|
||||
StringBuilder sb = new StringBuilder("<numfields ");
|
||||
sb.append("number=\"").append(num).append("\" ");
|
||||
return formatAttributes(sb.toString(), full);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package haus.nightmare.lib3270j.ecl.screenreco;
|
||||
|
||||
import haus.nightmare.lib3270j.ecl.ECLField;
|
||||
import haus.nightmare.lib3270j.ecl.ECLFieldList;
|
||||
import haus.nightmare.lib3270j.ecl.ECLOIA;
|
||||
import haus.nightmare.lib3270j.ecl.ECLPS;
|
||||
|
||||
/**
|
||||
* Screen descriptor matching unprotected input field count matching IBM Host On-Demand ECLSDInputFields.
|
||||
*/
|
||||
public class ECLSDInputFields extends ECLScreenDescriptor {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private int num = 0;
|
||||
|
||||
public ECLSDInputFields() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ECLSDInputFields(int num) {
|
||||
this(num, false);
|
||||
}
|
||||
|
||||
public ECLSDInputFields(int num, boolean optional) {
|
||||
super(optional);
|
||||
this.num = num;
|
||||
}
|
||||
|
||||
public int getNum() { return num; }
|
||||
public int GetNum() { return num; }
|
||||
public void setNum(int num) { this.num = num; }
|
||||
public void SetNum(int num) { setNum(num); }
|
||||
|
||||
@Override
|
||||
protected boolean checkMatch(ECLPS ps, ECLOIA oia) {
|
||||
if (ps == null) return false;
|
||||
ECLFieldList fl = ps.getFieldList();
|
||||
if (fl == null) return false;
|
||||
int inputCount = 0;
|
||||
for (ECLField f : fl.getFields()) {
|
||||
if (!f.isProtected()) {
|
||||
inputCount++;
|
||||
}
|
||||
}
|
||||
return inputCount == num;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(int indent, boolean full) {
|
||||
StringBuilder sb = new StringBuilder("<numinputfields ");
|
||||
sb.append("number=\"").append(num).append("\" ");
|
||||
return formatAttributes(sb.toString(), full);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package haus.nightmare.lib3270j.ecl.screenreco;
|
||||
|
||||
import haus.nightmare.lib3270j.ecl.ECLOIA;
|
||||
import haus.nightmare.lib3270j.ecl.ECLPS;
|
||||
|
||||
/**
|
||||
* Screen descriptor matching Operator Information Area (OIA) status matching IBM Host On-Demand ECLSDOIA.
|
||||
*/
|
||||
public class ECLSDOIA extends ECLScreenDescriptor {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final int OIA_DONTCARE = 0;
|
||||
public static final int OIA_NOTINHIBITED = 1;
|
||||
|
||||
private int oiaType = OIA_NOTINHIBITED;
|
||||
private Integer explicitInhibitStatus = null;
|
||||
|
||||
public ECLSDOIA() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ECLSDOIA(int type) {
|
||||
this(type, false);
|
||||
}
|
||||
|
||||
public ECLSDOIA(int type, boolean optional) {
|
||||
super(optional);
|
||||
this.oiaType = type;
|
||||
}
|
||||
|
||||
public ECLSDOIA(String status, boolean optional) {
|
||||
super(optional);
|
||||
setOIAType(status);
|
||||
}
|
||||
|
||||
public int getOIAType() { return oiaType; }
|
||||
public int GetOIAType() { return oiaType; }
|
||||
public void setOIAType(int type) { this.oiaType = type; this.explicitInhibitStatus = null; }
|
||||
public void SetOIAType(int type) { setOIAType(type); }
|
||||
|
||||
public void setOIAType(String status) {
|
||||
if (status == null) {
|
||||
this.oiaType = OIA_NOTINHIBITED;
|
||||
return;
|
||||
}
|
||||
if (status.equalsIgnoreCase("DONTCARE")) {
|
||||
this.oiaType = OIA_DONTCARE;
|
||||
} else if (status.equalsIgnoreCase("NOTINHIBITED") || status.equalsIgnoreCase("true")) {
|
||||
this.oiaType = OIA_NOTINHIBITED;
|
||||
} else if (status.equalsIgnoreCase("false")) {
|
||||
// Inhibited: inverted NOTINHIBITED or explicit
|
||||
this.oiaType = OIA_NOTINHIBITED;
|
||||
this.invert = true;
|
||||
} else {
|
||||
try {
|
||||
this.explicitInhibitStatus = Integer.parseInt(status);
|
||||
} catch (NumberFormatException e) {
|
||||
this.oiaType = OIA_NOTINHIBITED;
|
||||
}
|
||||
}
|
||||
}
|
||||
public void SetOIAType(String status) { setOIAType(status); }
|
||||
|
||||
public Integer getExplicitInhibitStatus() { return explicitInhibitStatus; }
|
||||
public void setExplicitInhibitStatus(Integer status) { this.explicitInhibitStatus = status; }
|
||||
|
||||
@Override
|
||||
protected boolean checkMatch(ECLPS ps, ECLOIA oia) {
|
||||
if (oia == null) return true;
|
||||
if (oiaType == OIA_DONTCARE) return true;
|
||||
|
||||
if (explicitInhibitStatus != null) {
|
||||
return oia.getInputInhibited() == explicitInhibitStatus;
|
||||
}
|
||||
|
||||
// OIA_NOTINHIBITED: input must not be inhibited
|
||||
return oia.getInputInhibited() == ECLOIA.INHIBIT_NOTINHIBITED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(int indent, boolean full) {
|
||||
StringBuilder sb = new StringBuilder("<oia ");
|
||||
if (explicitInhibitStatus != null) {
|
||||
sb.append("status=\"").append(explicitInhibitStatus).append("\" ");
|
||||
} else if (oiaType == OIA_DONTCARE) {
|
||||
sb.append("status=\"DONTCARE\" ");
|
||||
} else {
|
||||
sb.append("status=\"NOTINHIBITED\" input=\"true\" ");
|
||||
}
|
||||
return formatAttributes(sb.toString(), full);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
package haus.nightmare.lib3270j.ecl.screenreco;
|
||||
|
||||
import haus.nightmare.lib3270j.ecl.ECLOIA;
|
||||
import haus.nightmare.lib3270j.ecl.ECLPS;
|
||||
|
||||
/**
|
||||
* Screen descriptor matching text on presentation space matching IBM Host On-Demand ECLSDString.
|
||||
*/
|
||||
public class ECLSDString extends ECLScreenDescriptor {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final int STRING_ABSOLUTE = 1;
|
||||
public static final int STRING_INRECT = 2;
|
||||
|
||||
private int stringType = STRING_INRECT;
|
||||
private String text = "";
|
||||
private int srow = 1;
|
||||
private int scol = 1;
|
||||
private int erow = -1;
|
||||
private int ecol = -1;
|
||||
private boolean caseSense = false;
|
||||
private int pos = -1;
|
||||
private boolean wrap = false;
|
||||
|
||||
public ECLSDString() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ECLSDString(String text) {
|
||||
super(false);
|
||||
this.text = (text != null) ? text : "";
|
||||
this.srow = 0;
|
||||
this.scol = 0;
|
||||
this.erow = 0;
|
||||
this.ecol = 0;
|
||||
this.stringType = STRING_INRECT;
|
||||
}
|
||||
|
||||
public ECLSDString(String text, int pos, boolean caseSense) {
|
||||
this(text, pos, caseSense, false);
|
||||
}
|
||||
|
||||
public ECLSDString(String text, int pos, boolean caseSense, boolean optional) {
|
||||
super(optional);
|
||||
this.text = (text != null) ? text : "";
|
||||
this.pos = pos;
|
||||
this.caseSense = caseSense;
|
||||
this.stringType = STRING_ABSOLUTE;
|
||||
}
|
||||
|
||||
public ECLSDString(String text, int row, int col) {
|
||||
this(text, row, col, false, false);
|
||||
}
|
||||
|
||||
public ECLSDString(String text, int row, int col, boolean caseSense) {
|
||||
this(text, row, col, caseSense, false);
|
||||
}
|
||||
|
||||
public ECLSDString(String text, int row, int col, boolean caseSense, boolean optional) {
|
||||
super(optional);
|
||||
this.text = (text != null) ? text : "";
|
||||
this.srow = row;
|
||||
this.scol = col;
|
||||
this.erow = -1;
|
||||
this.ecol = -1;
|
||||
this.caseSense = caseSense;
|
||||
this.stringType = STRING_ABSOLUTE;
|
||||
}
|
||||
|
||||
public ECLSDString(String text, int srow, int scol, int erow, int ecol, boolean caseSense, boolean optional) {
|
||||
this(text, srow, scol, erow, ecol, caseSense, optional, false);
|
||||
}
|
||||
|
||||
public ECLSDString(String text, int srow, int scol, int erow, int ecol, boolean caseSense, boolean optional, boolean wrap) {
|
||||
super(optional);
|
||||
this.text = (text != null) ? text : "";
|
||||
this.srow = srow;
|
||||
this.scol = scol;
|
||||
this.erow = erow;
|
||||
this.ecol = ecol;
|
||||
this.caseSense = caseSense;
|
||||
this.wrap = wrap;
|
||||
this.stringType = STRING_INRECT;
|
||||
}
|
||||
|
||||
public String getText() { return text; }
|
||||
public String GetText() { return text; }
|
||||
public String GetString() { return text; }
|
||||
public String getString() { return text; }
|
||||
public void setText(String text) { this.text = (text != null) ? text : ""; }
|
||||
public void SetText(String text) { setText(text); }
|
||||
public void SetString(String text) { setText(text); }
|
||||
public void setString(String text) { setText(text); }
|
||||
|
||||
public int getRow() { return srow; }
|
||||
public int GetRow() { return srow; }
|
||||
public int getSRow() { return srow; }
|
||||
public int GetSRow() { return srow; }
|
||||
public void setRow(int row) { this.srow = row; }
|
||||
public void SetRow(int row) { setRow(row); }
|
||||
public void setSRow(int row) { setRow(row); }
|
||||
public void SetSRow(int row) { setRow(row); }
|
||||
|
||||
public int getCol() { return scol; }
|
||||
public int GetCol() { return scol; }
|
||||
public int getSCol() { return scol; }
|
||||
public int GetSCol() { return scol; }
|
||||
public void setCol(int col) { this.scol = col; }
|
||||
public void SetCol(int col) { setCol(col); }
|
||||
public void setSCol(int col) { setCol(col); }
|
||||
public void SetSCol(int col) { setCol(col); }
|
||||
|
||||
public int getERow() { return erow; }
|
||||
public int GetERow() { return erow; }
|
||||
public void setERow(int erow) { this.erow = erow; }
|
||||
public void SetERow(int erow) { setERow(erow); }
|
||||
|
||||
public int getECol() { return ecol; }
|
||||
public int GetECol() { return ecol; }
|
||||
public void setECol(int ecol) { this.ecol = ecol; }
|
||||
public void SetECol(int ecol) { setECol(ecol); }
|
||||
|
||||
public boolean isCaseSense() { return caseSense; }
|
||||
public boolean IsCaseSense() { return caseSense; }
|
||||
public void setCaseSense(boolean caseSense) { this.caseSense = caseSense; }
|
||||
public void SetCaseSense(boolean caseSense) { setCaseSense(caseSense); }
|
||||
|
||||
public boolean isWrap() { return wrap; }
|
||||
public boolean IsWrap() { return wrap; }
|
||||
public void setWrap(boolean wrap) { this.wrap = wrap; }
|
||||
public void SetWrap(boolean wrap) { setWrap(wrap); }
|
||||
|
||||
public int getStringType() { return stringType; }
|
||||
public int GetStringType() { return stringType; }
|
||||
public void setStringType(int stringType) { this.stringType = stringType; }
|
||||
public void SetStringType(int stringType) { setStringType(stringType); }
|
||||
|
||||
@Override
|
||||
protected boolean checkMatch(ECLPS ps, ECLOIA oia) {
|
||||
if (ps == null || text == null) return false;
|
||||
if (text.isEmpty()) return true;
|
||||
|
||||
int totalRows = ps.getRows();
|
||||
int totalCols = ps.getCols();
|
||||
|
||||
if (pos > 0) {
|
||||
int p0 = pos - 1;
|
||||
String onScreen = ps.getString(p0, text.length());
|
||||
if (onScreen == null) return false;
|
||||
return caseSense ? text.equals(onScreen) : text.equalsIgnoreCase(onScreen);
|
||||
}
|
||||
|
||||
// 1. Search anywhere on screen if row and col are not set (<= 0)
|
||||
if (srow <= 0 && scol <= 0 && erow <= 0 && ecol <= 0) {
|
||||
String fullScreen = ps.getString(0, totalRows * totalCols);
|
||||
if (fullScreen == null) return false;
|
||||
return caseSense ? fullScreen.contains(text) : fullScreen.toLowerCase().contains(text.toLowerCase());
|
||||
}
|
||||
|
||||
// 2. Absolute match at (srow, scol)
|
||||
if (stringType == STRING_ABSOLUTE || (erow <= 0 && ecol <= 0 && srow > 0 && scol > 0)) {
|
||||
int r0 = srow - 1;
|
||||
int c0 = scol - 1;
|
||||
if (r0 < 0 || r0 >= totalRows || c0 < 0 || c0 >= totalCols) return false;
|
||||
String onScreen = ps.getString(r0, c0, text.length());
|
||||
if (onScreen == null) return false;
|
||||
return caseSense ? text.equals(onScreen) : text.equalsIgnoreCase(onScreen);
|
||||
}
|
||||
|
||||
// 3. Rectangular region match (srow, scol, erow, ecol)
|
||||
int sr = (srow > 0) ? srow : 1;
|
||||
int sc = (scol > 0) ? scol : 1;
|
||||
int er = (erow > 0) ? Math.min(erow, totalRows) : totalRows;
|
||||
int ec = (ecol > 0) ? Math.min(ecol, totalCols) : totalCols;
|
||||
|
||||
if (sr > er || sc > ec) return false;
|
||||
|
||||
if (!wrap) {
|
||||
int len = ec - sc + 1;
|
||||
for (int r = sr; r <= er; r++) {
|
||||
String line = ps.getString(r - 1, sc - 1, len);
|
||||
if (line != null) {
|
||||
boolean found = caseSense ? line.contains(text) : line.toLowerCase().contains(text.toLowerCase());
|
||||
if (found) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int len = ec - sc + 1;
|
||||
for (int r = sr; r <= er; r++) {
|
||||
String line = ps.getString(r - 1, sc - 1, len);
|
||||
if (line != null) sb.append(line);
|
||||
}
|
||||
String block = sb.toString();
|
||||
return caseSense ? block.contains(text) : block.toLowerCase().contains(text.toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(int indent, boolean full) {
|
||||
StringBuilder sb = new StringBuilder("<string ");
|
||||
sb.append("value=\"").append(escapeChars(text)).append("\" ");
|
||||
if (srow > 0 || full) {
|
||||
sb.append("row=\"").append(srow).append("\" ");
|
||||
}
|
||||
if (scol > 0 || full) {
|
||||
sb.append("col=\"").append(scol).append("\" ");
|
||||
}
|
||||
if (stringType == STRING_INRECT && (erow > 0 || ecol > 0 || full)) {
|
||||
if (erow > 0 || full) sb.append("erow=\"").append(erow).append("\" ");
|
||||
if (ecol > 0 || full) sb.append("ecol=\"").append(ecol).append("\" ");
|
||||
}
|
||||
if (caseSense || full) {
|
||||
sb.append("casesense=\"").append(caseSense).append("\" ");
|
||||
}
|
||||
if (wrap || full) {
|
||||
sb.append("wrap=\"").append(wrap).append("\" ");
|
||||
}
|
||||
return formatAttributes(sb.toString(), full);
|
||||
}
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
package haus.nightmare.lib3270j.ecl.screenreco;
|
||||
|
||||
import java.io.Serializable;
|
||||
import haus.nightmare.lib3270j.ecl.ECLPS;
|
||||
import haus.nightmare.lib3270j.ecl.ECLOIA;
|
||||
|
||||
/**
|
||||
* Abstract base class for composite screen recognition descriptors matching IBM Host On-Demand.
|
||||
*/
|
||||
public abstract class ECLScreenDescriptor implements Serializable, Cloneable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected boolean optional = false;
|
||||
protected boolean match = false;
|
||||
protected boolean invert = false;
|
||||
protected String hostid = "";
|
||||
|
||||
protected ECLScreenDescriptor() {}
|
||||
|
||||
protected ECLScreenDescriptor(boolean optional) {
|
||||
this.optional = optional;
|
||||
}
|
||||
|
||||
public boolean isOptional() { return optional; }
|
||||
public boolean IsOptional() { return optional; }
|
||||
public void setOptional(boolean optional) { this.optional = optional; }
|
||||
public void SetOptional(boolean optional) { setOptional(optional); }
|
||||
|
||||
public boolean isMatch() { return match; }
|
||||
public boolean IsMatch() { return match; }
|
||||
public void setMatch(boolean match) { this.match = match; }
|
||||
public void SetMatch(boolean match) { setMatch(match); }
|
||||
|
||||
public boolean isInvertMatch() { return invert; }
|
||||
public boolean IsInvertMatch() { return invert; }
|
||||
public void setInvertMatch(boolean invert) { this.invert = invert; }
|
||||
public void SetInvertMatch(boolean invert) { setInvertMatch(invert); }
|
||||
|
||||
public String getHostid() { return hostid; }
|
||||
public String GetHostid() { return hostid; }
|
||||
public void setHostid(String hostid) { this.hostid = (hostid != null) ? hostid : ""; }
|
||||
public void SetHostid(String hostid) { setHostid(hostid); }
|
||||
|
||||
/**
|
||||
* Checks whether this descriptor matches against presentation space and/or OIA.
|
||||
* Takes invertmatch into account.
|
||||
*/
|
||||
public boolean matches(ECLPS ps, ECLOIA oia) {
|
||||
boolean m = checkMatch(ps, oia);
|
||||
boolean res = invert ? !m : m;
|
||||
setMatch(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
public boolean Matches(ECLPS ps, ECLOIA oia) {
|
||||
return matches(ps, oia);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal implementation of descriptor check without inversion.
|
||||
*/
|
||||
protected abstract boolean checkMatch(ECLPS ps, ECLOIA oia);
|
||||
|
||||
/**
|
||||
* Format this descriptor as an XML string.
|
||||
*/
|
||||
public abstract String format(int indent, boolean full);
|
||||
public String Format(int indent, boolean full) { return format(indent, full); }
|
||||
|
||||
protected String formatAttributes(String tagAndSpecificAttrs, boolean full) {
|
||||
StringBuilder sb = new StringBuilder(tagAndSpecificAttrs);
|
||||
if (optional || full) {
|
||||
sb.append("optional=\"").append(optional).append("\" ");
|
||||
}
|
||||
if (invert || full) {
|
||||
sb.append("invertmatch=\"").append(invert).append("\" ");
|
||||
}
|
||||
if (hostid != null && !hostid.isEmpty()) {
|
||||
sb.append("hostid=\"").append(escapeChars(hostid)).append("\" ");
|
||||
}
|
||||
sb.append("/>");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String escapeChars(String string) {
|
||||
if (string == null) return "";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < string.length(); i++) {
|
||||
char c = string.charAt(i);
|
||||
switch (c) {
|
||||
case '&': sb.append("&"); break;
|
||||
case '<': sb.append("<"); break;
|
||||
case '>': sb.append(">"); break;
|
||||
case '"': sb.append("""); break;
|
||||
case '\'': sb.append("'"); break;
|
||||
default: sb.append(c); break;
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
package haus.nightmare.lib3270j.ecl.util;
|
||||
|
||||
import haus.nightmare.lib3270j.ecl.ECLErr;
|
||||
|
||||
/**
|
||||
* Parses SendKeys strings into keystroke and mnemonic tokens.
|
||||
* Conforms 1:1 to IBM Host On-Demand (HoD) com.ibm.eNetwork.ECL.util.SendKeyTokenizer.
|
||||
*/
|
||||
public class SendKeyTokenizer {
|
||||
|
||||
private String sendString;
|
||||
private int stringIndex;
|
||||
private int stringLength;
|
||||
protected String className = this.getClass().getName();
|
||||
private boolean chunkPlainText = true;
|
||||
|
||||
public SendKeyTokenizer() {
|
||||
this.setSendKeyString(null);
|
||||
}
|
||||
|
||||
public SendKeyTokenizer(String string) {
|
||||
this.setSendKeyString(string);
|
||||
}
|
||||
|
||||
public SendKeyTokenizer(String string, boolean chunkPlainText) {
|
||||
this.setSendKeyString(string);
|
||||
this.chunkPlainText = chunkPlainText;
|
||||
}
|
||||
|
||||
public void setSendKeyString(String string) {
|
||||
this.stringLength = string != null ? string.length() : 0;
|
||||
this.sendString = string;
|
||||
this.stringIndex = 0;
|
||||
}
|
||||
|
||||
public String remainder() {
|
||||
if (this.stringIndex >= this.stringLength) {
|
||||
return "";
|
||||
}
|
||||
return this.sendString.substring(this.stringIndex);
|
||||
}
|
||||
|
||||
public boolean hasMoreTokens() {
|
||||
return this.stringLength > this.stringIndex;
|
||||
}
|
||||
|
||||
public boolean isChunkPlainText() {
|
||||
return chunkPlainText;
|
||||
}
|
||||
|
||||
public void setChunkPlainText(boolean chunkPlainText) {
|
||||
this.chunkPlainText = chunkPlainText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the next keystroke or mnemonic token.
|
||||
*
|
||||
* Escaped brackets:
|
||||
* "[[" returns "["
|
||||
* "]] " returns "]"
|
||||
*
|
||||
* Unterminated or unmatched brackets throw ECLErr("ECL0012").
|
||||
*/
|
||||
public String nextToken() throws ECLErr {
|
||||
if (this.stringIndex >= this.stringLength) {
|
||||
return null;
|
||||
}
|
||||
|
||||
char c = this.sendString.charAt(this.stringIndex);
|
||||
switch (c) {
|
||||
case '[': {
|
||||
this.stringIndex++;
|
||||
if (this.stringIndex >= this.stringLength) {
|
||||
throw new ECLErr(this.className + ":1", "ECL0012", 1);
|
||||
}
|
||||
char next = this.sendString.charAt(this.stringIndex);
|
||||
if (next == '[') {
|
||||
this.stringIndex++;
|
||||
return "[";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('[');
|
||||
boolean foundClose = false;
|
||||
while (this.stringIndex < this.stringLength) {
|
||||
char ch = this.sendString.charAt(this.stringIndex);
|
||||
if (ch == ']') {
|
||||
sb.append(']');
|
||||
this.stringIndex++;
|
||||
foundClose = true;
|
||||
break;
|
||||
}
|
||||
sb.append(ch);
|
||||
this.stringIndex++;
|
||||
}
|
||||
|
||||
if (!foundClose) {
|
||||
throw new ECLErr(this.className + ":2", "ECL0012", 1);
|
||||
}
|
||||
|
||||
String token = sb.toString();
|
||||
// HoD numeric keypad single digit shortcut [0]..[9] -> "0".."9"
|
||||
if (token.length() == 3 && token.charAt(0) == '[' && token.charAt(2) == ']') {
|
||||
char digit = token.charAt(1);
|
||||
if (digit >= '0' && digit <= '9') {
|
||||
return String.valueOf(digit);
|
||||
}
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
case ']': {
|
||||
this.stringIndex++;
|
||||
if (this.stringIndex >= this.stringLength) {
|
||||
throw new ECLErr(this.className + ":3", "ECL0012", 1);
|
||||
}
|
||||
char next = this.sendString.charAt(this.stringIndex);
|
||||
if (next == ']') {
|
||||
this.stringIndex++;
|
||||
return "]";
|
||||
}
|
||||
throw new ECLErr(this.className + ":4", "ECL0012", 1);
|
||||
}
|
||||
|
||||
default: {
|
||||
if (!this.chunkPlainText) {
|
||||
this.stringIndex++;
|
||||
return String.valueOf(c);
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (this.stringIndex < this.stringLength) {
|
||||
char ch = this.sendString.charAt(this.stringIndex);
|
||||
if (ch == '[' || ch == ']') {
|
||||
break;
|
||||
}
|
||||
sb.append(ch);
|
||||
this.stringIndex++;
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the next character token without AID key translations.
|
||||
*/
|
||||
public String nextTokenNoAid() throws ECLErr {
|
||||
if (this.stringIndex >= this.stringLength) {
|
||||
throw new ECLErr(this.className + ":1", "ECL0012", 1);
|
||||
}
|
||||
char c = this.sendString.charAt(this.stringIndex);
|
||||
this.stringIndex++;
|
||||
return String.valueOf(c);
|
||||
}
|
||||
}
|
||||
@@ -92,6 +92,14 @@ public class InputProcessor {
|
||||
if (fsm == null || fsm.getConnectionState() == null || !fsm.getConnectionState().isConnected()) {
|
||||
return OiaStatus.NOT_CONNECTED;
|
||||
}
|
||||
if (oia != null) {
|
||||
if (oia.isXProt()) {
|
||||
return OiaStatus.X_PROT;
|
||||
}
|
||||
if (oia.isXSystem()) {
|
||||
return OiaStatus.X_SYSTEM;
|
||||
}
|
||||
}
|
||||
if (keyboardLocked) {
|
||||
return OiaStatus.X_SYSTEM;
|
||||
}
|
||||
@@ -112,6 +120,11 @@ public class InputProcessor {
|
||||
public void setKeyboardLocked(boolean locked) {
|
||||
if (this.keyboardLocked != locked) {
|
||||
this.keyboardLocked = locked;
|
||||
if (!locked && oia != null) {
|
||||
oia.setInputInhibited(ECLConstants.INHIBIT_NOT_INHIBITED);
|
||||
} else if (locked && oia != null && oia.getInputInhibited() == ECLConstants.INHIBIT_NOT_INHIBITED) {
|
||||
oia.setInputInhibited(ECLConstants.INHIBIT_SYSTEM_LOCK);
|
||||
}
|
||||
if (lockStateListener != null) {
|
||||
lockStateListener.onLockStateChanged(locked);
|
||||
}
|
||||
@@ -859,6 +872,9 @@ public class InputProcessor {
|
||||
}
|
||||
lastAid = aidCode;
|
||||
setKeyboardLocked(true);
|
||||
if (oia != null) {
|
||||
oia.setInputInhibited(ECLConstants.INHIBIT_SYSTEM_LOCK);
|
||||
}
|
||||
byte[] data = new byte[] { (byte) aidCode };
|
||||
sendAidResponse(data);
|
||||
return;
|
||||
@@ -882,6 +898,9 @@ public class InputProcessor {
|
||||
|
||||
lastAid = aidCode;
|
||||
setKeyboardLocked(true);
|
||||
if (oia != null) {
|
||||
oia.setInputInhibited(ECLConstants.INHIBIT_SYSTEM_LOCK);
|
||||
}
|
||||
|
||||
if (fsm != null && fsm.getConnectionState() != null && fsm.getConnectionState().isSscp()) {
|
||||
// SSCP-LU Mode: send raw EBCDIC line data without AID or 3270 cursor address
|
||||
@@ -984,6 +1003,9 @@ public class InputProcessor {
|
||||
return;
|
||||
}
|
||||
setKeyboardLocked(true);
|
||||
if (oia != null) {
|
||||
oia.setInputInhibited(ECLConstants.INHIBIT_SYSTEM_LOCK);
|
||||
}
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
byte[] rma = buildReadModifiedInboundData(aidCode, false);
|
||||
@@ -1004,6 +1026,9 @@ public class InputProcessor {
|
||||
return;
|
||||
}
|
||||
setKeyboardLocked(true);
|
||||
if (oia != null) {
|
||||
oia.setInputInhibited(ECLConstants.INHIBIT_SYSTEM_LOCK);
|
||||
}
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
int cols = (screen != null && screen.getCols() > 0) ? screen.getCols() : 80;
|
||||
@@ -1735,11 +1760,110 @@ public class InputProcessor {
|
||||
public void processBackspace() { backspace(); }
|
||||
public void processEraseEOF() { eraseEof(); }
|
||||
public void processEraseInput() { eraseInput(); }
|
||||
public void processEraseField() { eraseField(); }
|
||||
public void processDup() { dup(); }
|
||||
public void processFieldMark() { fieldMark(); }
|
||||
public void processToggleInsert() { setInsertMode(!isInsertMode()); }
|
||||
public boolean processCurSel() { return cursorSelect(); }
|
||||
public boolean processCursorSelect() { return cursorSelect(); }
|
||||
public boolean processSelFld() { return selectField(); }
|
||||
public boolean processDeSelFld() { return deselectField(); }
|
||||
|
||||
public void processFieldStart() {
|
||||
if (screen == null) return;
|
||||
int cur = screen.getCursorAddress();
|
||||
if (screen.isFormatted()) {
|
||||
int faPos = screen.findFieldAttribute(cur);
|
||||
if (faPos >= 0) {
|
||||
int fieldStart = screen.incrementAddress(faPos);
|
||||
screen.setCursorAddress(fieldStart);
|
||||
}
|
||||
} else {
|
||||
int cols = screen.getCols();
|
||||
int row = cur / cols;
|
||||
screen.setCursorAddress(row * cols);
|
||||
}
|
||||
screen.updateDisplaySnapshot();
|
||||
}
|
||||
|
||||
public void eraseField() {
|
||||
if (screen == null) return;
|
||||
if (!screen.isFormatted()) {
|
||||
eraseEof();
|
||||
return;
|
||||
}
|
||||
int cur = screen.getCursorAddress();
|
||||
int faPos = screen.findFieldAttribute(cur);
|
||||
if (faPos < 0) return;
|
||||
byte faVal = screen.getCell(faPos).fa;
|
||||
if (faIsProtected(faVal & 0xFF)) return;
|
||||
|
||||
int fieldStart = screen.incrementAddress(faPos);
|
||||
int pos = fieldStart;
|
||||
int size = screen.getRows() * screen.getCols();
|
||||
int count = 0;
|
||||
while (!screen.getCell(pos).isFieldAttribute() && count < size) {
|
||||
ExtendedAttribute ea = screen.getCell(pos);
|
||||
ea.ec = 0;
|
||||
ea.ucs4 = 0;
|
||||
pos = screen.incrementAddress(pos);
|
||||
count++;
|
||||
}
|
||||
screen.getCell(faPos).fa = (byte) (screen.getCell(faPos).fa | FA_MODIFY);
|
||||
screen.setCursorAddress(fieldStart);
|
||||
screen.markAllChanged();
|
||||
screen.updateDisplaySnapshot();
|
||||
}
|
||||
|
||||
public boolean selectField() {
|
||||
if (screen == null || !screen.isFormatted()) return false;
|
||||
int cur = screen.getCursorAddress();
|
||||
int size = screen.getRows() * screen.getCols();
|
||||
int faPos = screen.findFieldAttribute(cur);
|
||||
if (faPos < 0) return false;
|
||||
ExtendedAttribute faCell = screen.getCell(faPos);
|
||||
int fa = faCell.fa & 0xFF;
|
||||
if (!haus.nightmare.lib3270j.protocol.DS3270Constants.faIsSelectable(fa)) return false;
|
||||
|
||||
int desPos = (faPos + 1) % size;
|
||||
ExtendedAttribute desCell = screen.getCell(desPos);
|
||||
int ebcdic = desCell.ec & 0xFF;
|
||||
char ascii = (char) desCell.ucs4;
|
||||
if (ebcdic == 0x6F || ascii == '?' || ascii == '\uFF1F') {
|
||||
desCell.ec = (byte) 0x6E;
|
||||
desCell.ucs4 = '>';
|
||||
faCell.fa |= haus.nightmare.lib3270j.protocol.DS3270Constants.FA_MODIFY;
|
||||
screen.markAllChanged();
|
||||
screen.updateDisplaySnapshot();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean deselectField() {
|
||||
if (screen == null || !screen.isFormatted()) return false;
|
||||
int cur = screen.getCursorAddress();
|
||||
int size = screen.getRows() * screen.getCols();
|
||||
int faPos = screen.findFieldAttribute(cur);
|
||||
if (faPos < 0) return false;
|
||||
ExtendedAttribute faCell = screen.getCell(faPos);
|
||||
int fa = faCell.fa & 0xFF;
|
||||
if (!haus.nightmare.lib3270j.protocol.DS3270Constants.faIsSelectable(fa)) return false;
|
||||
|
||||
int desPos = (faPos + 1) % size;
|
||||
ExtendedAttribute desCell = screen.getCell(desPos);
|
||||
int ebcdic = desCell.ec & 0xFF;
|
||||
char ascii = (char) desCell.ucs4;
|
||||
if (ebcdic == 0x6E || ascii == '>' || ascii == '\uFF1E') {
|
||||
desCell.ec = (byte) 0x6F;
|
||||
desCell.ucs4 = '?';
|
||||
faCell.fa &= ~haus.nightmare.lib3270j.protocol.DS3270Constants.FA_MODIFY;
|
||||
screen.markAllChanged();
|
||||
screen.updateDisplaySnapshot();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ========== File Transfer Support ==========
|
||||
|
||||
@@ -1852,34 +1976,46 @@ public class InputProcessor {
|
||||
|
||||
/**
|
||||
* Parse and execute IBM ECL standard mnemonic keystrokes (e.g. "USER[tab]PASS[enter]").
|
||||
* Fully compatible with IBM Host On-Demand SendKeyTokenizer and 120+ standard mnemonics.
|
||||
*/
|
||||
public void sendKeys(String keys) {
|
||||
if (keys == null || keys.isEmpty()) return;
|
||||
|
||||
int len = keys.length();
|
||||
int i = 0;
|
||||
while (i < len) {
|
||||
char c = keys.charAt(i);
|
||||
if (c == '[') {
|
||||
int end = keys.indexOf(']', i);
|
||||
if (end > i) {
|
||||
String token = keys.substring(i + 1, end).trim().toLowerCase();
|
||||
try {
|
||||
haus.nightmare.lib3270j.ecl.util.SendKeyTokenizer tokenizer =
|
||||
new haus.nightmare.lib3270j.ecl.util.SendKeyTokenizer(keys);
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
String token = tokenizer.nextToken();
|
||||
if (token == null) break;
|
||||
|
||||
if (token.length() == 1) {
|
||||
typeCharacter(token.charAt(0));
|
||||
} else if (token.startsWith("[") && token.endsWith("]")) {
|
||||
executeMnemonicToken(token);
|
||||
i = end + 1;
|
||||
continue;
|
||||
} else {
|
||||
for (int i = 0; i < token.length(); i++) {
|
||||
typeCharacter(token.charAt(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
typeCharacter(c);
|
||||
i++;
|
||||
} catch (haus.nightmare.lib3270j.ecl.ECLErr e) {
|
||||
log.warning("Syntax error in sendKeys: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void executeMnemonicToken(String token) {
|
||||
public void executeMnemonicToken(String rawToken) {
|
||||
if (rawToken == null || rawToken.isEmpty()) return;
|
||||
String token = rawToken.trim().toLowerCase();
|
||||
if (token.startsWith("[") && token.endsWith("]") && token.length() >= 2) {
|
||||
token = token.substring(1, token.length() - 1).trim();
|
||||
}
|
||||
|
||||
if (isNvtMode()) {
|
||||
try {
|
||||
switch (token) {
|
||||
case "enter":
|
||||
case "return":
|
||||
case "keypadenter":
|
||||
fsm.sendNVTString("\r\n");
|
||||
break;
|
||||
case "clear":
|
||||
@@ -1900,6 +2036,8 @@ public class InputProcessor {
|
||||
fsm.sendNVTString("\u001B[H");
|
||||
break;
|
||||
case "end":
|
||||
case "eof":
|
||||
case "fieldend":
|
||||
fsm.sendNVTString("\u001B[F");
|
||||
break;
|
||||
case "up":
|
||||
@@ -1922,6 +2060,7 @@ public class InputProcessor {
|
||||
case "pgup":
|
||||
fsm.sendNVTString("\u001B[5~");
|
||||
break;
|
||||
case "pagedn":
|
||||
case "pagedown":
|
||||
case "pgdn":
|
||||
fsm.sendNVTString("\u001B[6~");
|
||||
@@ -1936,6 +2075,7 @@ public class InputProcessor {
|
||||
break;
|
||||
case "attn":
|
||||
case "break":
|
||||
case "telnetbreak":
|
||||
fsm.sendNVTChar('\u0003');
|
||||
break;
|
||||
case "sysreq":
|
||||
@@ -1946,10 +2086,36 @@ public class InputProcessor {
|
||||
case "reset":
|
||||
setKeyboardLocked(false);
|
||||
break;
|
||||
case "enterreset":
|
||||
if (keyboardLocked) {
|
||||
setKeyboardLocked(false);
|
||||
} else {
|
||||
fsm.sendNVTString("\r\n");
|
||||
}
|
||||
break;
|
||||
case "keypad0": fsm.sendNVTChar('0'); break;
|
||||
case "keypad1": fsm.sendNVTChar('1'); break;
|
||||
case "keypad2": fsm.sendNVTChar('2'); break;
|
||||
case "keypad3": fsm.sendNVTChar('3'); break;
|
||||
case "keypad4": fsm.sendNVTChar('4'); break;
|
||||
case "keypad5": fsm.sendNVTChar('5'); break;
|
||||
case "keypad6": fsm.sendNVTChar('6'); break;
|
||||
case "keypad7": fsm.sendNVTChar('7'); break;
|
||||
case "keypad8": fsm.sendNVTChar('8'); break;
|
||||
case "keypad9": fsm.sendNVTChar('9'); break;
|
||||
case "keypad.": fsm.sendNVTChar('.'); break;
|
||||
case "keypad,": fsm.sendNVTChar(','); break;
|
||||
case "keypad-": fsm.sendNVTChar('-'); break;
|
||||
default:
|
||||
if (token.startsWith("pf") || token.startsWith("f")) {
|
||||
if (token.length() == 1 && Character.isDigit(token.charAt(0))) {
|
||||
fsm.sendNVTChar(token.charAt(0));
|
||||
} else if (token.startsWith("pf") || token.startsWith("f") || token.startsWith("vt-pf") || token.startsWith("spf")) {
|
||||
try {
|
||||
String numStr = token.startsWith("pf") ? token.substring(2) : token.substring(1);
|
||||
String numStr = token;
|
||||
if (numStr.startsWith("vt-pf")) numStr = numStr.substring(5);
|
||||
else if (numStr.startsWith("spf")) numStr = numStr.substring(3);
|
||||
else if (numStr.startsWith("pf")) numStr = numStr.substring(2);
|
||||
else if (numStr.startsWith("f")) numStr = numStr.substring(1);
|
||||
int fn = Integer.parseInt(numStr);
|
||||
sendNvtFunctionKey(fn);
|
||||
} catch (NumberFormatException ignored) {}
|
||||
@@ -2000,11 +2166,36 @@ public class InputProcessor {
|
||||
case "curright":
|
||||
cursorRight();
|
||||
break;
|
||||
case "pagedn":
|
||||
case "pagedown":
|
||||
case "pgdn":
|
||||
sendAid(AID_PF8);
|
||||
break;
|
||||
case "pageup":
|
||||
case "pgup":
|
||||
sendAid(AID_PF7);
|
||||
break;
|
||||
case "eof":
|
||||
case "fieldend":
|
||||
case "end":
|
||||
processFieldEnd();
|
||||
break;
|
||||
case "bof":
|
||||
case "fieldstart":
|
||||
processFieldStart();
|
||||
break;
|
||||
case "eraseeof":
|
||||
case "erase_eof":
|
||||
eraseEof();
|
||||
break;
|
||||
case "erasefld":
|
||||
case "erasefield":
|
||||
case "erase_field":
|
||||
eraseField();
|
||||
break;
|
||||
case "erinp":
|
||||
case "eraseinp":
|
||||
case "eraseinput":
|
||||
case "erase_input":
|
||||
eraseInput();
|
||||
break;
|
||||
@@ -2015,7 +2206,24 @@ public class InputProcessor {
|
||||
case "fieldmark":
|
||||
fieldMark();
|
||||
break;
|
||||
case "fldext":
|
||||
case "fieldexit":
|
||||
case "field+":
|
||||
case "field-":
|
||||
tab();
|
||||
break;
|
||||
case "+cr":
|
||||
if (graphicsPlane != null) {
|
||||
if (graphicsPlane.isGraphicCursorAttached()) {
|
||||
graphicsPlane.detachGraphicCursor();
|
||||
} else {
|
||||
graphicsPlane.attachGraphicCursor(graphicsPlane.getGraphicCursorX(), graphicsPlane.getGraphicCursorY());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "attn":
|
||||
case "break":
|
||||
case "telnetbreak":
|
||||
attn();
|
||||
break;
|
||||
case "sysreq":
|
||||
@@ -2024,10 +2232,18 @@ public class InputProcessor {
|
||||
case "reset":
|
||||
reset();
|
||||
break;
|
||||
case "enterreset":
|
||||
if (keyboardLocked) {
|
||||
reset();
|
||||
} else {
|
||||
sendAid(AID_ENTER);
|
||||
}
|
||||
break;
|
||||
case "insert":
|
||||
setInsertMode(!isInsertMode());
|
||||
break;
|
||||
case "delete":
|
||||
case "del":
|
||||
deleteChar();
|
||||
break;
|
||||
case "backspace":
|
||||
@@ -2035,9 +2251,13 @@ public class InputProcessor {
|
||||
backspace();
|
||||
break;
|
||||
case "wordtab":
|
||||
case "tabword":
|
||||
case "nextword":
|
||||
processWordTab(true);
|
||||
break;
|
||||
case "wordbacktab":
|
||||
case "backtabword":
|
||||
case "previousword":
|
||||
processWordTab(false);
|
||||
break;
|
||||
case "wordleft":
|
||||
@@ -2046,10 +2266,6 @@ public class InputProcessor {
|
||||
case "wordright":
|
||||
processWordRight();
|
||||
break;
|
||||
case "fieldend":
|
||||
case "end":
|
||||
processFieldEnd();
|
||||
break;
|
||||
case "deleteword":
|
||||
processDeleteWord();
|
||||
break;
|
||||
@@ -2058,6 +2274,12 @@ public class InputProcessor {
|
||||
case "select":
|
||||
cursorSelect();
|
||||
break;
|
||||
case "selfld":
|
||||
selectField();
|
||||
break;
|
||||
case "deselfld":
|
||||
deselectField();
|
||||
break;
|
||||
case "lightpen":
|
||||
processLightPen();
|
||||
break;
|
||||
@@ -2077,8 +2299,37 @@ public class InputProcessor {
|
||||
case "aplmode":
|
||||
toggleAplKeyboardMode();
|
||||
break;
|
||||
case "altview":
|
||||
if (screen != null) {
|
||||
screen.markAllChanged();
|
||||
screen.updateDisplaySnapshot();
|
||||
}
|
||||
break;
|
||||
case "dspsosi":
|
||||
if (screen != null) {
|
||||
screen.balanceSOSI();
|
||||
screen.markAllChanged();
|
||||
screen.updateDisplaySnapshot();
|
||||
}
|
||||
break;
|
||||
case "keypad0": typeCharacter('0'); break;
|
||||
case "keypad1": typeCharacter('1'); break;
|
||||
case "keypad2": typeCharacter('2'); break;
|
||||
case "keypad3": typeCharacter('3'); break;
|
||||
case "keypad4": typeCharacter('4'); break;
|
||||
case "keypad5": typeCharacter('5'); break;
|
||||
case "keypad6": typeCharacter('6'); break;
|
||||
case "keypad7": typeCharacter('7'); break;
|
||||
case "keypad8": typeCharacter('8'); break;
|
||||
case "keypad9": typeCharacter('9'); break;
|
||||
case "keypad.": typeCharacter('.'); break;
|
||||
case "keypad,": typeCharacter(','); break;
|
||||
case "keypad-": typeCharacter('-'); break;
|
||||
case "keypadenter": sendAid(AID_ENTER); break;
|
||||
default:
|
||||
if (token.startsWith("pf")) {
|
||||
if (token.length() == 1 && Character.isDigit(token.charAt(0))) {
|
||||
typeCharacter(token.charAt(0));
|
||||
} else if (token.startsWith("pf")) {
|
||||
try {
|
||||
int pfNum = Integer.parseInt(token.substring(2));
|
||||
if (pfNum >= 1 && pfNum <= 24) {
|
||||
@@ -2092,6 +2343,24 @@ public class InputProcessor {
|
||||
sendAid(AID_PA1 + (paNum - 1));
|
||||
}
|
||||
} catch (NumberFormatException ignored) {}
|
||||
} else if (token.startsWith("spf")) {
|
||||
try {
|
||||
int spfNum = Integer.parseInt(token.substring(3));
|
||||
if (spfNum >= 1 && spfNum <= 24) {
|
||||
sendAid(AID_PF1 + (spfNum - 1));
|
||||
}
|
||||
} catch (NumberFormatException ignored) {}
|
||||
} else if (token.startsWith("vt-pf")) {
|
||||
try {
|
||||
int vpfNum = Integer.parseInt(token.substring(5));
|
||||
if (vpfNum >= 1 && vpfNum <= 24) {
|
||||
sendAid(AID_PF1 + (vpfNum - 1));
|
||||
}
|
||||
} catch (NumberFormatException ignored) {}
|
||||
} else {
|
||||
// Recognized HoD Bidi / Layer / Print / GUI event tokens:
|
||||
// log or no-op safely without throwing unknown errors
|
||||
log.fine("Mnemonic token received: " + token);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -268,7 +268,7 @@ public class DS3270P {
|
||||
if (activeLuType == PrinterConstants.LU_TYPE_1_SCS && scs != null) {
|
||||
scs.flushLineBuffer();
|
||||
} else if (printPs != null) {
|
||||
printPs.flushPrintBuffer();
|
||||
printPs.endOfRecord();
|
||||
}
|
||||
if (pd != null) {
|
||||
pd.flush();
|
||||
|
||||
@@ -271,10 +271,14 @@ public class PD3270 {
|
||||
writeControlCode(enable ? PrinterDefinitionTable.CMD_START_SUPERSCRIPT : PrinterDefinitionTable.CMD_END_SUPERSCRIPT);
|
||||
}
|
||||
|
||||
private int activeCpi = PrinterConstants.DEFAULT_CPI;
|
||||
private int activeLpi = PrinterConstants.DEFAULT_LPI;
|
||||
|
||||
/**
|
||||
* Set Characters Per Inch (CPI) via PDT.
|
||||
*/
|
||||
public synchronized void setCPI(int cpi) {
|
||||
this.activeCpi = cpi;
|
||||
switch (cpi) {
|
||||
case 10: writeControlCode(PrinterDefinitionTable.CMD_SET_CPI_10); break;
|
||||
case 12: writeControlCode(PrinterDefinitionTable.CMD_SET_CPI_12); break;
|
||||
@@ -284,10 +288,15 @@ public class PD3270 {
|
||||
}
|
||||
}
|
||||
|
||||
public int getCPI() {
|
||||
return activeCpi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Lines Per Inch (LPI) via PDT.
|
||||
*/
|
||||
public synchronized void setLPI(int lpi) {
|
||||
this.activeLpi = lpi;
|
||||
switch (lpi) {
|
||||
case 6: writeControlCode(PrinterDefinitionTable.CMD_SET_LPI_6); break;
|
||||
case 8: writeControlCode(PrinterDefinitionTable.CMD_SET_LPI_8); break;
|
||||
@@ -295,6 +304,10 @@ public class PD3270 {
|
||||
}
|
||||
}
|
||||
|
||||
public int getLPI() {
|
||||
return activeLpi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process GDDM host print escape sequence or raw host passthrough.
|
||||
*/
|
||||
|
||||
@@ -308,12 +308,12 @@ public class PrintPS3270 {
|
||||
processWrite(data, offset, length, true);
|
||||
}
|
||||
|
||||
private void setCellFA(int addr, byte fa) {
|
||||
protected void setCellFA(int addr, byte fa) {
|
||||
attrPlane[addr] = fa;
|
||||
textPlane[addr] = 0x00; // Field attributes display as blanks/nulls
|
||||
}
|
||||
|
||||
private int decodeBufferAddress(int b1, int b2) {
|
||||
protected int decodeBufferAddress(int b1, int b2) {
|
||||
// Fast 3270 12-bit / 14-bit address calculation
|
||||
if ((b1 & 0xC0) == 0) {
|
||||
return ((b1 & 0x3F) << 8) | b2;
|
||||
@@ -321,6 +321,19 @@ public class PrintPS3270 {
|
||||
return ((b1 & 0x3F) << 6) | (b2 & 0x3F);
|
||||
}
|
||||
|
||||
public boolean isNonDisplayCell(int addr) {
|
||||
if (addr < 0 || addr >= bufferSize) return false;
|
||||
if (attrPlane[addr] != 0) return true;
|
||||
for (int i = 0; i < bufferSize; i++) {
|
||||
int checkAddr = (addr - i + bufferSize) % bufferSize;
|
||||
byte fa = attrPlane[checkAddr];
|
||||
if (fa != 0) {
|
||||
return (fa & 0x0C) == 0x0C;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format and print a specific row from the presentation buffer.
|
||||
*/
|
||||
@@ -331,11 +344,12 @@ public class PrintPS3270 {
|
||||
|
||||
char[] chars = new char[lineLen];
|
||||
for (int c = 0; c < lineLen; c++) {
|
||||
int ebc = textPlane[startAddr + c] & 0xFF;
|
||||
if (ebc == 0x00) {
|
||||
int addr = startAddr + c;
|
||||
if (isNonDisplayCell(addr)) {
|
||||
chars[c] = ' ';
|
||||
} else {
|
||||
chars[c] = translator.ebcdicToUnicode(ebc);
|
||||
int ebc = textPlane[addr] & 0xFF;
|
||||
chars[c] = (ebc == 0x00) ? ' ' : translator.ebcdicToUnicode(ebc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,6 +389,25 @@ public class PrintPS3270 {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush and dump formatted page to printer destination.
|
||||
*/
|
||||
public synchronized void flushPage() {
|
||||
flushPrintBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle End of Record (EOR) in LU Type 3 data stream.
|
||||
* Assembles and dumps formatted text buffer to configured output file or printer spool.
|
||||
*/
|
||||
public synchronized void endOfRecord() {
|
||||
cancelAutoFlush();
|
||||
flushPage();
|
||||
if (pd != null) {
|
||||
pd.flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush current printer buffer to PD3270 destination.
|
||||
*/
|
||||
|
||||
@@ -104,6 +104,198 @@ public class PrintPS3270DB extends PrintPS3270 {
|
||||
|
||||
// ========== Output Formatting with DBCS & Grid Lines ==========
|
||||
|
||||
@Override
|
||||
public synchronized void processWrite(byte[] data, int offset, int length, boolean eraseFirst) {
|
||||
if (eraseFirst) {
|
||||
erasePrintBuffer();
|
||||
}
|
||||
|
||||
int idx = offset + 1; // Skip command byte
|
||||
int end = offset + length;
|
||||
|
||||
if (idx >= end) return;
|
||||
|
||||
// WCC
|
||||
int wcc = data[idx++] & 0xFF;
|
||||
boolean startPrint = isStartPrint(wcc);
|
||||
this.currentPrintFormat = getPrintFormat(wcc);
|
||||
|
||||
byte currentColor = 0;
|
||||
byte currentHilite = 0;
|
||||
boolean inDbcs = false;
|
||||
|
||||
while (idx < end) {
|
||||
int b = data[idx++] & 0xFF;
|
||||
|
||||
if (inDbcs) {
|
||||
if (b == PrinterConstants.SCS_SI) {
|
||||
inDbcs = false;
|
||||
continue;
|
||||
}
|
||||
if (idx < end) {
|
||||
int b2 = data[idx++] & 0xFF;
|
||||
if (b2 == PrinterConstants.SCS_SI) {
|
||||
inDbcs = false;
|
||||
continue;
|
||||
}
|
||||
char unicodeChar;
|
||||
if (b == 0x40 && b2 == 0x40) {
|
||||
unicodeChar = '\u3000';
|
||||
} else {
|
||||
unicodeChar = translator.dbcsToUnicode(b, b2);
|
||||
if (unicodeChar == 0 || unicodeChar == 0xFFFF) {
|
||||
unicodeChar = '?';
|
||||
}
|
||||
}
|
||||
setDBCSCharAtAddress(bufferAddress, unicodeChar);
|
||||
colorPlane[bufferAddress] = currentColor;
|
||||
hilitePlane[bufferAddress] = currentHilite;
|
||||
bufferAddress = (bufferAddress + 2) % bufferSize;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (b == PrinterConstants.SCS_SO) {
|
||||
inDbcs = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (b) {
|
||||
case PrinterConstants.ORDER_SBA:
|
||||
if (idx + 1 < end) {
|
||||
int b1 = data[idx++] & 0xFF;
|
||||
int b2 = data[idx++] & 0xFF;
|
||||
bufferAddress = decodeBufferAddress(b1, b2) % bufferSize;
|
||||
}
|
||||
break;
|
||||
|
||||
case PrinterConstants.ORDER_SF:
|
||||
if (idx < end) {
|
||||
byte fa = data[idx++];
|
||||
setCellFA(bufferAddress, fa);
|
||||
bufferAddress = (bufferAddress + 1) % bufferSize;
|
||||
}
|
||||
break;
|
||||
|
||||
case PrinterConstants.ORDER_SFE:
|
||||
if (idx < end) {
|
||||
int pairCount = data[idx++] & 0xFF;
|
||||
byte fa = 0;
|
||||
for (int p = 0; p < pairCount && idx + 1 < end; p++) {
|
||||
int type = data[idx++] & 0xFF;
|
||||
int val = data[idx++] & 0xFF;
|
||||
if (type == 0x00 || type == 0xC0) {
|
||||
fa = (byte) val;
|
||||
} else if (type == PrinterConstants.SA_COLOR) {
|
||||
currentColor = (byte) val;
|
||||
} else if (type == PrinterConstants.SA_HILITE) {
|
||||
currentHilite = (byte) val;
|
||||
}
|
||||
}
|
||||
setCellFA(bufferAddress, fa);
|
||||
colorPlane[bufferAddress] = currentColor;
|
||||
hilitePlane[bufferAddress] = currentHilite;
|
||||
bufferAddress = (bufferAddress + 1) % bufferSize;
|
||||
}
|
||||
break;
|
||||
|
||||
case PrinterConstants.ORDER_SA:
|
||||
if (idx + 1 < end) {
|
||||
int type = data[idx++] & 0xFF;
|
||||
int val = data[idx++] & 0xFF;
|
||||
if (type == PrinterConstants.SA_COLOR) {
|
||||
currentColor = (byte) val;
|
||||
} else if (type == PrinterConstants.SA_HILITE) {
|
||||
currentHilite = (byte) val;
|
||||
} else if (type == PrinterConstants.SA_RESET) {
|
||||
currentColor = 0;
|
||||
currentHilite = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PrinterConstants.ORDER_RA:
|
||||
if (idx + 2 < end) {
|
||||
int b1 = data[idx++] & 0xFF;
|
||||
int b2 = data[idx++] & 0xFF;
|
||||
int stopAddr = decodeBufferAddress(b1, b2) % bufferSize;
|
||||
byte fillChar = data[idx++];
|
||||
if (stopAddr == bufferAddress) {
|
||||
Arrays.fill(textPlane, fillChar);
|
||||
} else {
|
||||
while (bufferAddress != stopAddr) {
|
||||
textPlane[bufferAddress] = fillChar;
|
||||
colorPlane[bufferAddress] = currentColor;
|
||||
hilitePlane[bufferAddress] = currentHilite;
|
||||
bufferAddress = (bufferAddress + 1) % bufferSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PrinterConstants.ORDER_EUA:
|
||||
if (idx + 1 < end) {
|
||||
int b1 = data[idx++] & 0xFF;
|
||||
int b2 = data[idx++] & 0xFF;
|
||||
int stopAddr = decodeBufferAddress(b1, b2) % bufferSize;
|
||||
while (bufferAddress != stopAddr) {
|
||||
textPlane[bufferAddress] = 0x00;
|
||||
dbcsPlane[bufferAddress] = DBCS_NONE;
|
||||
dbcsCharPlane[bufferAddress] = ' ';
|
||||
bufferAddress = (bufferAddress + 1) % bufferSize;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PrinterConstants.ORDER_IC:
|
||||
case PrinterConstants.ORDER_PT:
|
||||
break;
|
||||
|
||||
case PrinterConstants.ORDER_GE:
|
||||
if (idx < end) {
|
||||
byte geByte = data[idx++];
|
||||
textPlane[bufferAddress] = geByte;
|
||||
colorPlane[bufferAddress] = currentColor;
|
||||
hilitePlane[bufferAddress] = currentHilite;
|
||||
bufferAddress = (bufferAddress + 1) % bufferSize;
|
||||
}
|
||||
break;
|
||||
|
||||
case PrinterConstants.ORDER_NL:
|
||||
int curRow = bufferAddress / cols;
|
||||
bufferAddress = ((curRow + 1) * cols) % bufferSize;
|
||||
break;
|
||||
|
||||
case PrinterConstants.ORDER_EM:
|
||||
flushPage();
|
||||
break;
|
||||
|
||||
case PrinterConstants.ORDER_FF:
|
||||
pd.formFeed();
|
||||
break;
|
||||
|
||||
case PrinterConstants.ORDER_CR:
|
||||
bufferAddress = (bufferAddress / cols) * cols;
|
||||
break;
|
||||
|
||||
default:
|
||||
textPlane[bufferAddress] = (byte) b;
|
||||
dbcsPlane[bufferAddress] = DBCS_NONE;
|
||||
colorPlane[bufferAddress] = currentColor;
|
||||
hilitePlane[bufferAddress] = currentHilite;
|
||||
bufferAddress = (bufferAddress + 1) % bufferSize;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (startPrint) {
|
||||
cancelAutoFlush();
|
||||
flushPage();
|
||||
} else {
|
||||
scheduleAutoFlush();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void printLine(int row, int lineLen) {
|
||||
if (row < 0 || row >= rows) return;
|
||||
@@ -132,7 +324,13 @@ public class PrintPS3270DB extends PrintPS3270 {
|
||||
lineBuilder.append('│');
|
||||
}
|
||||
|
||||
if (dbcsPlane[addr] == DBCS_LEFT) {
|
||||
if (isNonDisplayCell(addr)) {
|
||||
if (dbcsPlane[addr] == DBCS_LEFT) {
|
||||
lineBuilder.append(" ");
|
||||
} else if (dbcsPlane[addr] == DBCS_NONE) {
|
||||
lineBuilder.append(' ');
|
||||
}
|
||||
} else if (dbcsPlane[addr] == DBCS_LEFT) {
|
||||
char ch = dbcsCharPlane[addr];
|
||||
lineBuilder.append(ch != 0 ? ch : ' ');
|
||||
} else if (dbcsPlane[addr] == DBCS_RIGHT) {
|
||||
|
||||
@@ -137,13 +137,28 @@ public class PrintSCS3270 {
|
||||
|
||||
switch (subOrder) {
|
||||
case PrinterConstants.SCS_SHF:
|
||||
case PrinterConstants.SCS_SHF_ALT:
|
||||
processSetHorizontalFormat(data, idx, sliceLen);
|
||||
break;
|
||||
case PrinterConstants.SCS_SVF:
|
||||
processSetVerticalFormat(data, idx, sliceLen);
|
||||
break;
|
||||
case PrinterConstants.SCS_SLD:
|
||||
processSetLineDensity(data, idx, sliceLen);
|
||||
case PrinterConstants.SCS_SLD_ALT:
|
||||
// 0xC6 can be SLD or legacy PPA
|
||||
if (subOrder == PrinterConstants.SCS_SLD && paramLen == 2 && idx + 3 < end &&
|
||||
(data[idx + 3] == PrinterConstants.POS_ABSOLUTE || data[idx + 3] == PrinterConstants.POS_RELATIVE)) {
|
||||
processPresentationPositionAdvancing(data, idx, sliceLen);
|
||||
} else {
|
||||
processSetLineDensity(data, idx, sliceLen);
|
||||
}
|
||||
break;
|
||||
case PrinterConstants.SCS_SPD: // 0xD2: Set Print Density or legacy SVF_ALT
|
||||
if (paramLen >= 5 && idx + 3 < end && (data[idx + 3] & 0xFF) != PrinterConstants.SPD_TYPE_ID) {
|
||||
processSetVerticalFormat(data, idx, sliceLen);
|
||||
} else {
|
||||
processSetPrintDensity(data, idx, sliceLen);
|
||||
}
|
||||
break;
|
||||
case PrinterConstants.SCS_STO:
|
||||
processSetTextOrientation(data, idx, sliceLen);
|
||||
@@ -154,9 +169,6 @@ public class PrintSCS3270 {
|
||||
case PrinterConstants.SCS_SEAC:
|
||||
processSetEnhancedAttribute(data, idx, sliceLen);
|
||||
break;
|
||||
case PrinterConstants.SCS_PPA:
|
||||
processPresentationPositionAdvancing(data, idx, sliceLen);
|
||||
break;
|
||||
case PrinterConstants.SCS_PPV:
|
||||
processPresentationPositionVertical(data, idx, sliceLen);
|
||||
break;
|
||||
@@ -270,6 +282,16 @@ public class PrintSCS3270 {
|
||||
processIRS();
|
||||
idx++;
|
||||
break;
|
||||
case PrinterConstants.SCS_PP:
|
||||
if (idx + 2 < end) {
|
||||
int ppFunc = data[idx + 1] & 0xFF;
|
||||
int ppVal = data[idx + 2] & 0xFF;
|
||||
processPPOrder(ppFunc, ppVal);
|
||||
idx += 3;
|
||||
} else {
|
||||
idx = end;
|
||||
}
|
||||
break;
|
||||
case PrinterConstants.SCS_SUB:
|
||||
processSUB();
|
||||
idx++;
|
||||
@@ -529,6 +551,26 @@ public class PrintSCS3270 {
|
||||
processSetLineDensity(data, offset, len);
|
||||
}
|
||||
|
||||
public synchronized void processSPD(byte[] data, int offset, int len) {
|
||||
processSetPrintDensity(data, offset, len);
|
||||
}
|
||||
|
||||
public synchronized void processPPOrder(int func, int val) {
|
||||
if (func == PrinterConstants.PP_HORIZ_ABS || func == PrinterConstants.POS_ABSOLUTE) {
|
||||
currentCol = Math.min(mpp, Math.max(leftMargin, val));
|
||||
} else if (func == PrinterConstants.PP_HORIZ_REL || func == PrinterConstants.POS_RELATIVE) {
|
||||
currentCol = Math.min(mpp, currentCol + val);
|
||||
} else if (func == PrinterConstants.PP_VERT_ABS) {
|
||||
while (currentRow < val && currentRow < bottomMargin) {
|
||||
processLF();
|
||||
}
|
||||
} else if (func == PrinterConstants.PP_VERT_REL) {
|
||||
for (int i = 0; i < val && currentRow < bottomMargin; i++) {
|
||||
processLF();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void processSTO(byte[] data, int offset, int len) {
|
||||
processSetTextOrientation(data, offset, len);
|
||||
}
|
||||
@@ -684,17 +726,27 @@ public class PrintSCS3270 {
|
||||
}
|
||||
|
||||
public synchronized void processSetHorizontalFormat(byte[] data, int offset, int len) {
|
||||
if (len < 4) return;
|
||||
int mppVal = data[offset + 3] & 0xFF;
|
||||
if (mppVal > 0) {
|
||||
this.mpp = mppVal;
|
||||
this.rightMargin = Math.min(this.rightMargin, this.mpp);
|
||||
if (len < 3) return;
|
||||
if (len >= 4) {
|
||||
int mppVal = data[offset + 3] & 0xFF;
|
||||
if (mppVal > 0) {
|
||||
this.mpp = mppVal;
|
||||
if (this.rightMargin > this.mpp) {
|
||||
this.rightMargin = this.mpp;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (len >= 5) {
|
||||
int lm = data[offset + 4] & 0xFF;
|
||||
if (lm > 0) {
|
||||
this.leftMargin = lm;
|
||||
}
|
||||
}
|
||||
if (len >= 6) {
|
||||
int lm = data[offset + 4] & 0xFF;
|
||||
int rm = data[offset + 5] & 0xFF;
|
||||
if (lm > 0) this.leftMargin = lm;
|
||||
if (rm > 0 && rm >= lm) this.rightMargin = rm;
|
||||
if (rm > 0 && rm >= this.leftMargin) {
|
||||
this.rightMargin = Math.min(rm, this.mpp);
|
||||
}
|
||||
}
|
||||
if (len > 6) {
|
||||
int tabCount = len - 6;
|
||||
@@ -705,20 +757,33 @@ public class PrintSCS3270 {
|
||||
Arrays.sort(tabs);
|
||||
this.horizontalTabs = tabs;
|
||||
}
|
||||
if (currentCol < leftMargin) {
|
||||
currentCol = leftMargin;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void processSetVerticalFormat(byte[] data, int offset, int len) {
|
||||
if (len < 4) return;
|
||||
int mplVal = data[offset + 3] & 0xFF;
|
||||
if (mplVal > 0) {
|
||||
this.mpl = mplVal;
|
||||
this.bottomMargin = Math.min(this.bottomMargin, this.mpl);
|
||||
if (len < 3) return;
|
||||
if (len >= 4) {
|
||||
int mplVal = data[offset + 3] & 0xFF;
|
||||
if (mplVal > 0) {
|
||||
this.mpl = mplVal;
|
||||
if (this.bottomMargin > this.mpl) {
|
||||
this.bottomMargin = this.mpl;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (len >= 5) {
|
||||
int tm = data[offset + 4] & 0xFF;
|
||||
if (tm > 0) {
|
||||
this.topMargin = tm;
|
||||
}
|
||||
}
|
||||
if (len >= 6) {
|
||||
int tm = data[offset + 4] & 0xFF;
|
||||
int bm = data[offset + 5] & 0xFF;
|
||||
if (tm > 0) this.topMargin = tm;
|
||||
if (bm > 0 && bm >= tm) this.bottomMargin = bm;
|
||||
if (bm > 0 && bm >= this.topMargin) {
|
||||
this.bottomMargin = Math.min(bm, this.mpl);
|
||||
}
|
||||
}
|
||||
if (len > 6) {
|
||||
int tabCount = len - 6;
|
||||
@@ -729,17 +794,81 @@ public class PrintSCS3270 {
|
||||
Arrays.sort(tabs);
|
||||
this.verticalTabs = tabs;
|
||||
}
|
||||
if (currentRow < topMargin) {
|
||||
currentRow = topMargin;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void processSetLineDensity(byte[] data, int offset, int len) {
|
||||
if (len < 4) return;
|
||||
int points = data[offset + 3] & 0xFF;
|
||||
if (points > 0) {
|
||||
// Line density in points / inch (72 points = 1 inch)
|
||||
// 12 points = 6 LPI, 9 points = 8 LPI, 18 points = 4 LPI
|
||||
int computedLpi = Math.max(1, 72 / points);
|
||||
setPrintDensity(this.cpi, computedLpi);
|
||||
if (len < 3) return;
|
||||
int count = data[offset + 2] & 0xFF;
|
||||
int points = 12; // default 12 points = 6 LPI
|
||||
if (count == 1 || len == 3) {
|
||||
points = 12;
|
||||
} else if (len >= 4) {
|
||||
points = data[offset + 3] & 0xFF;
|
||||
}
|
||||
|
||||
int computedLpi = 6;
|
||||
if (points == 6 || points == 12) {
|
||||
computedLpi = 6;
|
||||
} else if (points == 8 || points == 9) {
|
||||
computedLpi = 8;
|
||||
} else if (points == 4 || points == 18) {
|
||||
computedLpi = 4;
|
||||
} else if (points == 3 || points == 24) {
|
||||
computedLpi = 3;
|
||||
} else if (points > 0) {
|
||||
computedLpi = Math.max(1, 72 / points);
|
||||
}
|
||||
setPrintDensity(this.cpi, computedLpi);
|
||||
}
|
||||
|
||||
public synchronized void processSetPrintDensity(byte[] data, int offset, int len) {
|
||||
if (len < 3) return;
|
||||
int density = 10;
|
||||
if (len >= 5 && (data[offset + 3] & 0xFF) == PrinterConstants.SPD_TYPE_ID) {
|
||||
if (len >= 6) {
|
||||
int val = ((data[offset + 4] & 0xFF) << 8) | (data[offset + 5] & 0xFF);
|
||||
if (val > 0) {
|
||||
density = val;
|
||||
} else {
|
||||
density = data[offset + 5] & 0xFF;
|
||||
}
|
||||
} else {
|
||||
density = data[offset + 4] & 0xFF;
|
||||
}
|
||||
} else if (len >= 4) {
|
||||
density = data[offset + 3] & 0xFF;
|
||||
}
|
||||
|
||||
int effCpi = 10;
|
||||
boolean dw = false;
|
||||
if (density <= 5 && density > 0) {
|
||||
effCpi = 10;
|
||||
dw = true;
|
||||
} else if (density <= 6 && density > 0) {
|
||||
effCpi = 12;
|
||||
dw = true;
|
||||
} else if (density <= 8 && density > 0) {
|
||||
effCpi = 15;
|
||||
dw = true;
|
||||
} else if (density <= 10) {
|
||||
effCpi = 10;
|
||||
dw = false;
|
||||
} else if (density <= 12) {
|
||||
effCpi = 12;
|
||||
dw = false;
|
||||
} else if (density <= 15) {
|
||||
effCpi = 15;
|
||||
dw = false;
|
||||
} else {
|
||||
effCpi = 17;
|
||||
dw = false;
|
||||
}
|
||||
|
||||
setDoubleWidth(dw);
|
||||
setPrintDensity(effCpi, this.lpi);
|
||||
}
|
||||
|
||||
public synchronized void processSetTextOrientation(byte[] data, int offset, int len) {
|
||||
|
||||
@@ -90,6 +90,19 @@ public class PrintSCS3270DB extends PrintSCS3270 {
|
||||
this.dbcsCpi = cpi;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setPrintDensity(int cpi, int lpi) {
|
||||
super.setPrintDensity(cpi, lpi);
|
||||
this.dbcsCpi = Math.max(1, this.cpi / 2);
|
||||
}
|
||||
|
||||
public synchronized void endOfRecord() {
|
||||
if (dbcsMode) {
|
||||
processSI();
|
||||
}
|
||||
flushLineBuffer();
|
||||
}
|
||||
|
||||
// ========== Grid & Ruling Line Controls ==========
|
||||
|
||||
public synchronized void setGridLines(boolean left, boolean right, boolean top, boolean bottom) {
|
||||
@@ -219,14 +232,23 @@ public class PrintSCS3270DB extends PrintSCS3270 {
|
||||
}
|
||||
}
|
||||
|
||||
ensureLineBufferCapacity(currentCol + 2);
|
||||
|
||||
// Record grid line attributes for this cell
|
||||
if (lineGridFlags != null && currentCol < lineGridFlags.length) {
|
||||
lineGridFlags[currentCol] = (byte) activeGridFlags;
|
||||
if (currentCol + 1 > rightMargin || currentCol + 1 > mpp) {
|
||||
advanceToNextLine();
|
||||
}
|
||||
|
||||
lineBuffer[currentCol] = unicodeChar;
|
||||
ensureLineBufferCapacity(currentCol + 2);
|
||||
|
||||
// Record grid line attributes for this 2-column span
|
||||
if (lineGridFlags != null) {
|
||||
if (currentCol - 1 < lineGridFlags.length) {
|
||||
lineGridFlags[currentCol - 1] = (byte) activeGridFlags;
|
||||
}
|
||||
if (currentCol < lineGridFlags.length) {
|
||||
lineGridFlags[currentCol] = (byte) activeGridFlags;
|
||||
}
|
||||
}
|
||||
|
||||
lineBuffer[currentCol - 1] = unicodeChar;
|
||||
lineModified = true;
|
||||
|
||||
// Advance column by 2 (DBCS glyph takes 2 character columns)
|
||||
|
||||
@@ -42,6 +42,7 @@ public final class PrinterConstants {
|
||||
public static final int SCS_LF = 0x25; // Line Feed
|
||||
public static final int SCS_BEL = 0x2F; // Bell / Sound Alarm
|
||||
public static final int SCS_IRS = 0x33; // Index Return
|
||||
public static final int SCS_PP = 0x34; // Presentation Position (0x34 <fn> <pos>)
|
||||
public static final int SCS_TRN = 0x35; // Transparent Stream (0x35 <len> <bytes>)
|
||||
public static final int SCS_TRS = 0x35; // Transparent Stream alias
|
||||
public static final int SCS_NBS = 0x36; // Numeric Backspace
|
||||
@@ -53,16 +54,29 @@ public final class PrinterConstants {
|
||||
public static final int SCS_PREFIX_2B = 0x2B; // 2-byte SCS prefix
|
||||
public static final int SCS_SA = 0x28; // Set Attribute (0x28 <type> <val>)
|
||||
|
||||
// 0x2B Sub-orders
|
||||
public static final int SCS_PPV = 0xC4; // Presentation Position Vertical
|
||||
public static final int SCS_PPA = 0xC6; // Presentation Position Advancing (Horizontal)
|
||||
public static final int SCS_GEA = 0xC8; // Set Graphic Error Action (0x2B 0xC8)
|
||||
public static final int SCS_SHF = 0xD1; // Set Horizontal Format
|
||||
public static final int SCS_SVF = 0xD2; // Set Vertical Format
|
||||
public static final int SCS_STO = 0xD3; // Set Text Orientation
|
||||
public static final int SCS_SCS = 0xD4; // Select Character Set
|
||||
public static final int SCS_SEAC = 0xD5; // Set Enhanced Attribute / Highlight
|
||||
public static final int SCS_SLD = 0xD6; // Set Line Density
|
||||
// 0x2B Sub-orders (IBM SNA Character String standard & HoD v14 SCSConstants)
|
||||
public static final int SCS_SHF = 0xC1; // Set Horizontal Format (0x2B 0xC1)
|
||||
public static final int SCS_SHF_ALT = 0xD1; // Set Horizontal Format legacy alias
|
||||
public static final int SCS_SVF = 0xC2; // Set Vertical Format (0x2B 0xC2)
|
||||
public static final int SCS_SVF_ALT = 0xD2; // Set Vertical Format legacy alias
|
||||
public static final int SCS_SLD = 0xC6; // Set Line Density (0x2B 0xC6)
|
||||
public static final int SCS_SLD_ALT = 0xD6; // Set Line Density legacy alias
|
||||
public static final int SCS_SPD = 0xD2; // Set Print Density (0x2B 0xD2)
|
||||
public static final int SCS_PPV = 0xC4; // Presentation Position Vertical
|
||||
public static final int SCS_PPA = 0xC6; // Presentation Position Advancing (Horizontal legacy)
|
||||
public static final int SCS_GEA = 0xC8; // Set Graphic Error Action (0x2B 0xC8)
|
||||
public static final int SCS_STO = 0xD3; // Set Text Orientation
|
||||
public static final int SCS_SCS = 0xD4; // Select Character Set
|
||||
public static final int SCS_SEAC = 0xD5; // Set Enhanced Attribute / Highlight
|
||||
|
||||
// SPD Type identifiers
|
||||
public static final int SPD_TYPE_ID = 0x29; // Standard SPD parameter identifier (41)
|
||||
|
||||
// PP Sub-functions (Presentation Position)
|
||||
public static final int PP_VERT_ABS = 0xC4; // Set Absolute Vertical Position
|
||||
public static final int PP_VERT_REL = 0x4C; // Set Relative Vertical Position
|
||||
public static final int PP_HORIZ_ABS = 0xC8; // Set Absolute Horizontal Position
|
||||
public static final int PP_HORIZ_REL = 0x48; // Set Relative Horizontal Position
|
||||
|
||||
// SA Attribute Types
|
||||
public static final int SA_RESET = 0x00;
|
||||
|
||||
Reference in New Issue
Block a user