view app/src/main/java/org/tn5250j/framework/tn5250/ScreenFields.java @ 516:3407f4741240

update copyrights
author Carl Byington <carl@five-ten-sg.com>
date Fri, 31 May 2024 11:17:53 -0600
parents d29cce60f393
children
line wrap: on
line source

/**
 * Title: tn5250J
 * Copyright:   Copyright (c) 2001
 * Company:
 * @author  Kenneth J. Pouncey
 * @version 0.5
 *
 * Description:
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this software; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307 USA
 *
 */
package org.tn5250j.framework.tn5250;

import static org.tn5250j.TN5250jConstants.CMD_READ_INPUT_FIELDS;
import static org.tn5250j.TN5250jConstants.CMD_READ_MDT_FIELDS;
import static org.tn5250j.TN5250jConstants.CMD_READ_MDT_IMMEDIATE_ALT;

import java.io.ByteArrayOutputStream;

import org.tn5250j.encoding.ICodePage;

public class ScreenFields {

    private ScreenField[] screenFields;
    private ScreenField currentField;
    private ScreenField saveCurrent;
    private int sizeFields;
    private boolean cpfExists;
    private int nextField;
    private int fieldIds;
    private Screen5250 screen;
    private boolean masterMDT;
    protected boolean currentModified;

    public ScreenFields(Screen5250 s) {
        screen = s;
        screenFields = new ScreenField[256];
    }

    protected void clearFFT() {
        sizeFields = nextField = fieldIds = 0;
        cpfExists = false;   // clear the cursor progression fields flag
        currentField = null;
        masterMDT = false;
    }

    protected boolean existsAtPos(int lastPos) {
        ScreenField sf = null;

        // from 14.6.12 for Start of Field Order 5940 function manual
        //  examine the format table for an entry that begins at the current
        //  starting address plus 1.
        for (int x = 0; x < sizeFields; x++) {
            sf = screenFields[x];

            if (lastPos == sf.startPos()) {
                currentField = sf;
                currentModified = false;
                return true;
            }
        }

        return false;
    }

    public boolean isMasterMDT() {
        return masterMDT;
    }

    protected void setMasterMDT() {
        masterMDT = true;
    }

    public boolean isCurrentField() {
        return currentField == null;
    }

    public boolean isCurrentFieldFER() {
        return currentField.isFER();
    }

    public boolean isCurrentFieldDupEnabled() {
        return currentField.isDupEnabled();
    }

    public boolean isCurrentFieldToUpper() {
        return currentField.isToUpper();
    }

    public boolean isCurrentFieldBypassField() {
        return currentField.isBypassField();
    }

    public boolean isCurrentFieldHighlightedEntry() {
        if (currentField != null)
            return currentField.isHiglightedEntry();
        else
            return false;
    }

    public boolean isCurrentFieldAutoEnter() {
        return currentField.isAutoEnter();
    }

    public boolean withinCurrentField(int pos) {
        return currentField.withinField(pos);
    }

    public boolean isCurrentFieldContinued() {
        return currentField.isContinued();
    }

    public boolean isCurrentFieldContinuedFirst() {
        return currentField.isContinuedFirst();
    }

    public boolean isCurrentFieldContinuedMiddle() {
        return currentField.isContinuedMiddle();
    }

    public boolean isCurrentFieldContinuedLast() {
        return currentField.isContinuedLast();
    }

    public boolean isCurrentFieldModified() {
        return currentModified;
    }

    /**
     * This routine is used to check if we can send the Aid key to the host
     *
     * Taken from Section  16.2.1.2 Enter/Rec Adv Key
     *
     * In the normal unlocked state, when the workstation operator presses the
     * Enter/Rec Adv key:
     *
     * 1. The 5494 checks for the completion of mandatory-fill, self-check, and
     *    right-adjust fields when in an active field. (An active field is one in
     *    which the workstation operator has begun entering data.) If the
     *    requirements of the field have not been satisfied, an error occurs.
     *
     * @return
     *
     */
    public boolean isCanSendAid() {
        // We also have to check if we are still in the field.
        if (currentField != null &&
                (currentField.getAdjustment() > 0 || currentField.isSignedNumeric())
                && currentModified && isInField()
                && !currentField.isCanSend())
            return false;
        else
            return true;
    }

    protected void saveCurrentField() {
        saveCurrent = currentField;
    }

    protected void restoreCurrentField() {
        currentField = saveCurrent;
    }

    protected void setCurrentField(ScreenField sf) {
        currentField = sf;
    }

    protected void setCurrentFieldMDT() {
        currentField.setMDT();
        currentModified = true;
        masterMDT = true;
    }

    protected void setCurrentFieldFFWs(int ffw1, int ffw2) {
        masterMDT = currentField.setFFWs(ffw1, ffw2);
    }


    protected ScreenField setField(int attr, int row, int col, int len, int ffw1,
                                   int ffw2, int fcw1, int fcw2) {
        ScreenField sf = null;
        screenFields[nextField] = new ScreenField(screen);
        screenFields[nextField].setField(attr, row, col, len, ffw1, ffw2, fcw1, fcw2);
        sf = screenFields[nextField++];
        sizeFields++;
        // set the field id if it is not a bypass field
        // this is used for cursor progression
        //  changed this because of problems not allocating field id's for
        //  all fields.  kjp 2002/10/21
//      if (!sf.isBypassField())
        sf.setFieldId(++fieldIds);

        // check if the cursor progression field flag should be set.
//      if ((fcw1 & 0x88) == 0x88)
        if (fcw1 == 0x88)
            cpfExists = true;

        if (currentField != null) {
            currentField.next = sf;
            sf.prev = currentField;
        }

        currentField = sf;

        // check if the Modified Data Tag was set while creating the field
        if (!masterMDT)
            masterMDT = currentField.mdt;

        currentModified = false;
        return currentField;
    }

    public ScreenField getField(int index) {
        return screenFields[index];
    }

    public ScreenField getCurrentField() {
        return currentField;
    }

    public int getCurrentFieldPos() {
        return currentField.getCurrentPos();
    }

    protected int getCurrentFieldShift() {
        return currentField.getFieldShift();
    }

    public String getCurrentFieldText() {
        return currentField.getText();
    }

    public int getCurrentFieldHighlightedAttr() {
        return currentField.getHighlightedAttr();
    }

    public int getSize() {
        return sizeFields;
    }

    public int getFieldCount() {
        return sizeFields;
    }

    protected boolean isInField(int pos) {
        return isInField(pos, true);
    }

    protected boolean isInField() {
        return isInField(screen.getLastPos(), true);
    }

    protected boolean isInField(int pos, boolean chgToField) {
        ScreenField sf;

        for (int x = 0; x < sizeFields; x++) {
            sf = screenFields[x];

            if (sf.withinField(pos)) {
                if (chgToField) {
                    if (!currentField.equals(sf))
                        currentModified = false;

                    currentField = sf;
                }

                return true;
            }
        }

        return false;
    }

    /**
     * Searches the collection for the target string and returns the iOhioField
     * object containing that string.  The string must be totally contained
     * within the field to be considered a match.
     *
     * @param targetString The target string.
     * @param startPos The row and column where to start the search. The position
     *                 is inclusive (for example, row 1, col 1 means that
     *                 position 1,1 will be used as the starting location and
     *                 1,1 will be included in the search).
     * @param length The length from startPos to include in the search.
     * @param dir An OHIO_DIRECTION value:
     *
     * <table BORDER COLS=3 WIDTH="50%" >
     * <tr><th>Constant </th><th>Value</th>
     *                            <th>Description</th></tr>
     * <tr><td>OS_OHIO_DIRECTION_FORWARD </td><td>0</td>
     *                            <td>Forward (beginning towards end)</td></tr>
     * <tr><td>OS_OHIO_DIRECTION_BACKWARD </td><td>1</td>
     *                            <td>Backward (end towards beginning)</td></tr>
     * </table>
     *       Constant Value Description
     *       ignoreCase - Indicates whether the search is case sensitive.
     *       True means that case will be ignored. False means the search will
     *       be case sensitive.
     * @return If found, an iOhioField object containing the target string. If
     *         not found, returns a null.
     */
    public ScreenField findByString(String targetString,
                                    int startPos,
                                    int length,
                                    int dir,
                                    boolean ignoreCase) {
        // first lets check if the string exists in the screen space
//      iOhioPosition pos = screen.findString(targetString, startPos, length,
//                                             dir, ignoreCase);
        // if it does exist then lets search the fields by the position that
        //  was found and return the results of that search.
//      if (pos != null) {
        return findByPosition(startPos);
//      }
        //return null;
    }

    /**
     * Searches the collection for the target position and returns the ScreenField
     * object containing that position.
     *
     * @param targetPosition The target row and column expressed as a linear
     *          position within the presentation space.
     *
     * @return If found, a ScreenField object containing the target position.
     *         If not found, returns a null.
     */
    public ScreenField findByPosition(int targetPosition) {
        ScreenField sf = null;

        for (int x = 0; x < sizeFields; x++) {
            sf = screenFields[x];

            if (sf.withinField(targetPosition)) {
                return sf;
            }
        }

        return null;
    }

    /**
     * Searches the collection for the target position and returns the ScreenField
     * object containing that position.
     *
     * @param row The beginning row to start search with in the presentation space.
     * @param col The beginning column to start search with in the presentation space.
     *
     * @return If found, a ScreenField object containing the target position.
     *         If not found, returns a null.
     */
    public ScreenField findByPosition(int row, int col) {
        return findByPosition(screen.getPos(row, col));
    }

    public ScreenField[] getFields() {
        ScreenField[] fields = new ScreenField[sizeFields];

        for (int x = 0; x < sizeFields; x++) {
            fields[x] = screenFields[x];
        }

        return fields;
    }

    public ScreenField getFirstInputField() {
        if (sizeFields <= 0)
            return null;

        int f = 0;
        ScreenField sf = screenFields[f];

        while (sf.isBypassField() && f++ < sizeFields) {
            sf = screenFields[f];
        }

        if (sf.isBypassField())
            return null;
        else
            return sf;
    }

    public void gotoFieldNext() {
        // sanity check - we were getting null pointers after a restore of screen
        //   and cursor was not positioned on a field when returned
        //   *** Note *** to myself
        //   maybe this is fixed I will have to check this some time
        int lastPos = screen.getLastPos();

        if (currentField == null && (sizeFields != 0) && !isInField(lastPos, true)) {
            int pos = lastPos;
            screen.setCursorOff();
            screen.advancePos();
            lastPos = screen.getLastPos();

            while (!isInField() && pos != lastPos) {
                screen.advancePos();
            }

            screen.setCursorOn();
        }

        // if we are still null do nothing
        if (currentField == null)
            return;

        ScreenField sf = currentField;

        if (!sf.withinField(lastPos)) {
            screen.setCursorOff();

            if (sizeFields > 0) {
                // lets get the current position so we can test if we have looped
                //    the screen and not found a valid field.
                int pos = lastPos;
                int savPos = lastPos;
                boolean done = false;

                do {
                    screen.advancePos();
                    lastPos = screen.getLastPos();

                    if (isInField(lastPos)
                            || pos == lastPos) {
                        if (!currentField.isBypassField()) {
                            screen.gotoField(currentField);
                            done = true;
                        }
                    }
                }
                while (!done && lastPos != savPos);
            }

            currentModified = false;
            screen.setCursorOn();
        }
        else {
            if (!cpfExists) {
                do {
                    sf = sf.next;
                }
                while (sf != null && sf.isBypassField());
            }
            else {
                int f = 0;
                int cp = sf.getCursorProgression();

                if (cp == 0) {
                    do {
                        sf = sf.next;
                    }
                    while (sf != null && sf.isBypassField());
                }
                else {
                    ScreenField sf1 = null;
                    boolean found = false;

                    while (!found && f < sizeFields) {
                        sf1 = screenFields[f++];

                        if (sf1.getFieldId() == cp)
                            found = true;
                    }

                    if (found)
                        sf = sf1;
                    else {
                        do {
                            sf = sf.next;
                        }
                        while (sf != null && sf.isBypassField());
                    }

                    sf1 = null;
                }
            }

            if (sf == null)
                screen.gotoField(1);
            else {
                currentField = sf;
                screen.gotoField(currentField);
            }

            currentModified = false;
        }
    }

    public void gotoFieldPrev() {
        ScreenField sf = currentField;
        int lastPos = screen.getLastPos();

        if (!sf.withinField(lastPos)) {
            screen.setCursorOff();

            if (sizeFields > 0) {
                // lets get the current position so we can test if we have looped
                //    the screen and not found a valid field.
                int pos = lastPos;
                int savPos = lastPos;
                boolean done = false;

                do {
                    screen.changePos(-1);
                    lastPos = screen.getLastPos();

                    if (isInField(lastPos)
                            || (pos == lastPos)) {
                        if (!currentField.isBypassField()) {
                            screen.gotoField(currentField);
                            done = true;
                        }
                    }
                }
                while (!done && lastPos != savPos);
            }

            screen.setCursorOn();
        }
        else {
            if (sf.startPos() == lastPos) {
                if (!cpfExists) {
                    do {
                        sf = sf.prev;
                    }
                    while (sf != null && sf.isBypassField());
                }
                else {
                    int f = 0;
                    int cp = sf.getFieldId();
                    ScreenField sf1 = null;
                    boolean found = false;

                    while (!found && f < sizeFields) {
                        sf1 = screenFields[f++];

                        if (sf1.getCursorProgression() == cp)
                            found = true;
                    }

                    if (found)
                        sf = sf1;
                    else {
                        do {
                            sf = sf.prev;
                        }
                        while (sf != null && sf.isBypassField());
                    }

                    sf1 = null;
                }
            }

            if (sf == null) {
                int size = sizeFields;
                sf = screenFields[size - 1];

                while (sf.isBypassField() && size-- > 0) {
                    sf = screenFields[size];
                }
            }

            currentField = sf;
            currentModified = false;
            screen.gotoField(currentField);
        }
    }

    protected void readFormatTable(ByteArrayOutputStream baosp, int readType, ICodePage codePage) {
        ScreenField sf;
        boolean isSigned = false;
        char c;

        if (masterMDT) {
            StringBuffer sb = new StringBuffer();

            for (int x = 0; x < sizeFields; x++) {
                isSigned = false;
                sf = screenFields[x];

                if (sf.mdt || (readType == CMD_READ_INPUT_FIELDS)) {
                    sb.setLength(0);
                    sb.append(sf.getText());

                    if (readType == CMD_READ_MDT_FIELDS ||
                            readType == CMD_READ_MDT_IMMEDIATE_ALT) {
                        int len = sb.length() - 1;

                        // we strip out all '\u0020' and less
                        while (len >= 0 &&
//                     (sb.charAt(len) <= ' ' || sb.charAt(len) >= '\uff20' )) {
                                (sb.charAt(len) < ' ' || sb.charAt(len) >= '\uff20')) {
                            // if we have the dup character and dup is enabled then we
                            //    stop here
                            if (sb.charAt(len) == 0x1C && sf.isDupEnabled())
                                break;

                            sb.deleteCharAt(len--);
                        }
                    }

//               System.out.println("field " + sf.toString());
//               System.out.println(">" + sb.toString() + "<");
//               System.out.println(" field is all nulls");
                    if (sf.isSignedNumeric() && sb.length() > 0 && sb.charAt(sb.length() - 1) == '-') {
                        isSigned = true;
                        sb.setLength(sb.length() - 1);
                    }

                    int len3 = sb.length();

                    if (len3 > 0 || (readType == CMD_READ_MDT_FIELDS ||
                                     readType == CMD_READ_MDT_IMMEDIATE_ALT)) {
                        if ((readType == CMD_READ_MDT_FIELDS ||
                                readType == CMD_READ_MDT_IMMEDIATE_ALT)) {
                            baosp.write(17);   // start of field data

                            if (sf.isSelectionField()) {
                                baosp.write(screen.getRow(sf.selectionPos) + 1);
                                baosp.write(screen.getCol(sf.selectionPos) + 1);
                            }
                            else {
                                baosp.write(sf.startRow() + 1);
                                baosp.write(sf.startCol() + 1);
                            }
                        }

//                  int len = sb.length();
                        if (sf.isSelectionField()) {
                            baosp.write(0);
                            baosp.write(sf.selectionIndex + 0x1F);
                        }
                        else {
                            for (int k = 0; k < len3; k++) {
                                c = sb.charAt(k);

                                // here we have to check for special instances of the
                                //    characters in the string field.  Attribute bytes
                                //    are encoded with an offset of \uff00
                                //    This is a hack !!!!!!!!!!!
                                //    See ScreenField object for a description
                                if (c < ' ' || c >= '\uff20') {
                                    // if it is an offset attribute byte we just pass
                                    //    it straight on to the output stream
                                    if (c >= '\uff20' && c <= '\uff3f') {
                                        baosp.write(c - '\uff00');
                                    }
                                    else

                                        // check for dup character
                                        if (c == 0x1C)
                                            baosp.write(c);
                                        else
                                            baosp.write(codePage.uni2ebcdic(' '));
                                }
                                else {
                                    if (isSigned && k == len3 - 1) {
                                        baosp.write(0xd0 | (0x0f & c));
                                    }
                                    else
                                        baosp.write(codePage.uni2ebcdic(c));
                                }
                            }
                        }
                    }
                }
            }
        }
    }

}