view src/org/tn5250j/framework/tn5250/ScreenPlanes.java @ 105:1b5887a3bb1c

setField() needs to dirty the modified screen positions
author Carl Byington <carl@five-ten-sg.com>
date Wed, 18 Jun 2014 10:36:46 -0700
parents 044b1a951925
children 77ac18bc1b2f
line wrap: on
line source

/**
 * Title: ScreenPlanes.java
 * 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.*;

import java.util.Properties;

public class ScreenPlanes {

	private final Screen5250 scr;
	private int screenSize;
	private int numRows;
	private int numCols;
	private int errorLineNum;

	private static final int initAttr = 32;
	private static final char initChar = 0;

	protected char[] screen;   // text plane
	private char[] screenAttr;   // attribute plane
	private char[] screenGUI;   // gui plane
	private char[] screenIsAttr;
	private char[] fieldExtended;
	private char[] screenField;
	private char[] screenColor;   // color plane
	protected char[] screenExtended;   // extended plane
	private char[] screenIsChanged;

	private char[] initArray;

	private char[] errorLine;
	private char[] errorLineAttr;
	private char[] errorLineIsAttr;
	private char[] errorLineGui;

	public ScreenPlanes(Screen5250 s5250, int size) {

		scr = s5250;
		setSize(size);
	}

	protected void setSize(int newSize) {

		screenSize = newSize;

		numCols = 80;
		switch (newSize) {
		case 24:
			numRows = 24;
			break;
		case 27:
			numRows = 27;
			numCols = 132;
			break;

		}

		// this is used here when size changes
		setErrorLine(numRows);

		screenSize = numRows * numCols;
		screen = new char[screenSize];
		screenAttr = new char[screenSize];
		screenIsAttr = new char[screenSize];
		screenGUI = new char[screenSize];
		screenColor = new char[screenSize];
		screenExtended = new char[screenSize];
		fieldExtended = new char[screenSize];
		screenIsChanged = new char[screenSize];
		screenField = new char[screenSize];

		initArray = new char[screenSize];

		initalizePlanes();
	}

	protected void setErrorLine (int line) {

		// * NOTE * for developers I have changed the send qry to pass different
		//    parameters to the host so check setsize for setting error line as well.
		//
		if (line == 0 || line > numRows)
			errorLineNum = numRows;
		else
			errorLineNum = line;
	}

	/**
	 * Returns the current error line number
	 *
	 * @return current error line number
	 */
	protected int getErrorLine() {
		return errorLineNum;
	}

	protected void saveErrorLine() {

		// if there is already an error line saved then do not save it again
		//  This signifies that there was a previous error and the original error
		//  line was not restored yet.
		if (errorLine == null) {
			errorLine = new char[numCols];
			errorLineAttr = new char[numCols];
			errorLineIsAttr = new char[numCols];
			errorLineGui = new char[numCols];

			int r = scr.getPos(errorLineNum-1,0);

			for (int x = 0;x < numCols; x++) {
				errorLine[x] = screen[r+x];
				errorLineAttr[x] = screenAttr[r+x];
				errorLineIsAttr[x] = screenIsAttr[r+x];
				errorLineGui[x] = screenGUI[r+x];
			}
		}
	}

	/**
	 * Restores the error line characters from the save buffer.
	 *
	 * @see #saveErrorLine()
	 */
	protected void restoreErrorLine() {

		if (errorLine != null) {
			int r = scr.getPos(errorLineNum - 1, 0);

			for (int x = 0; x < numCols - 1; x++) {
				setScreenCharAndAttr(r+x,errorLine[x],errorLineAttr[x],
						(errorLineIsAttr[x] == '1' ? true : false));
				screenGUI[x] = errorLineGui[x];
			}

			errorLine = null;
			errorLineAttr = null;
			errorLineIsAttr = null;
			errorLineGui = null;
		}
	}

	protected boolean isErrorLineSaved() {
		return errorLine == null ? false : true;
	}

	protected void setScreenCharAndAttr(int pos, char c, int attr, boolean isAttr) {

		screen[pos] = c;
		screenAttr[pos] = (char)attr;
		disperseAttribute(pos,attr);
		screenIsAttr[pos] = (isAttr ? (char)1 : (char)0);
		screenGUI[pos] = NO_GUI;

	}

	protected void setScreenAttr(int pos, int attr, boolean isAttr) {

		screenAttr[pos] = (char)attr;
		screenIsAttr[pos] = isAttr ? (char)1 : (char)0;
		disperseAttribute(pos,attr);
		screenGUI[pos] = initChar;

	}

	protected void setScreenAttr(int pos, int attr) {

		screenAttr[pos] = (char)attr;
		//screenGUI[pos] = initChar;
		disperseAttribute(pos,attr);

	}

	protected void setScreenFieldAttr(int pos, int attr) {

		screenField[pos] = (char)attr;

	}

	protected final void setChar(int pos, char c) {
		screenIsChanged[pos] = screen[pos] == c ? '0' : '1';
		screen[pos] = c;
		if (screenIsAttr[pos] == 1)
			setScreenCharAndAttr(pos,c,32,false);

	}

	protected final char getChar(int pos) {
		return screen[pos];
	}

	protected final char getCharColor(int pos) {
		return screenColor[pos];
	}

	protected final int getCharAttr(int pos) {
		return screenAttr[pos];
	}

	protected final char getCharExtended(int pos) {
		return screenExtended[pos];
	}

	protected final boolean isAttributePlace(int pos) {
		return screenIsAttr[pos] == 1 ? true : false;
	}

	public final void setUseGUI(int pos, int which) {

		screenIsChanged[pos] = screenGUI[pos] == which ? '0' : '1';
		screenGUI[pos] = (char)which;
	}

	private void disperseAttribute(int pos, int attr) {

		char c = 0;
		char cs = 0;
		char ul = 0;
		char nd = 0;

		if(attr == 0)
			return;

		switch(attr) {
		case 32: // green normal
			c = ATTR_32;
			break;

		case 33: // green/revers
			c = ATTR_33;
			break;

		case 34: // white normal
			c = ATTR_34;
			break;

		case 35: // white/reverse
			c = ATTR_35;
			break;

		case 36: // green/underline
			c = ATTR_36;
			ul = EXTENDED_5250_UNDERLINE;
			break;

		case 37: // green/reverse/underline
			c = ATTR_37;
			ul = EXTENDED_5250_UNDERLINE;
			break;

		case 38: // white/underline
			c = ATTR_38;
			ul = EXTENDED_5250_UNDERLINE;
			break;

		case 39:
			nd = EXTENDED_5250_NON_DSP;
			break;

		case 40:
		case 42: // red/normal
			c = ATTR_40;
			break;

		case 41:
		case 43: // red/reverse
			c = ATTR_41;
			break;

		case 44:
		case 46: // red/underline
			c = ATTR_44;
			ul = EXTENDED_5250_UNDERLINE;
			break;

		case 45: // red/reverse/underline
			c = ATTR_45;
			ul = EXTENDED_5250_UNDERLINE;
			break;

		case 47:
			nd = EXTENDED_5250_NON_DSP;
			break;

		case 48:
			c = ATTR_48;
			cs = EXTENDED_5250_COL_SEP;
			break;

		case 49:
			c = ATTR_49;
			cs = EXTENDED_5250_COL_SEP;
			break;

		case 50:
			c = ATTR_50;
			cs = EXTENDED_5250_COL_SEP;
			break;

		case 51:
			c = ATTR_51;
			cs = EXTENDED_5250_COL_SEP;
			break;

		case 52:
			c = ATTR_52;
			//            colSep = true;
			ul = EXTENDED_5250_UNDERLINE;
			break;

		case 53:
			c = ATTR_53;
			//            colSep = true;
			ul = EXTENDED_5250_UNDERLINE;
			break;

		case 54:
			c = ATTR_54;
			//            colSep = true;
			ul = EXTENDED_5250_UNDERLINE;
			break;

		case 55:
			nd = EXTENDED_5250_NON_DSP;
			break;

		case 56: // pink
			c = ATTR_56;
			break;

		case 57: // pink/reverse
			c = ATTR_57;
			break;

		case 58: // blue/reverse
			c = ATTR_58;
			break;

		case 59: // blue
			c = ATTR_59;
			break;

		case 60: // pink/underline
			c = ATTR_60;
			ul = EXTENDED_5250_UNDERLINE;
			break;

		case 61: // pink/reverse/underline
			c = ATTR_61;
			ul = EXTENDED_5250_UNDERLINE;
			break;

		case 62: // blue/underline
			c = ATTR_62;
			ul = EXTENDED_5250_UNDERLINE;
			break;

		case 63:  // nondisplay
			nd = EXTENDED_5250_NON_DSP;
			cs = EXTENDED_5250_COL_SEP;
			break;
		default:
			c = ( COLOR_BG_BLACK << 8 & 0xff00) |
			( COLOR_FG_YELLOW & 0xff);
			break;

		}

		screenColor[pos] = c;
		screenExtended[pos] = (char)(ul | cs | nd);
	}

	protected void initalizePlanes () {

		char c = (COLOR_BG_BLACK << 8 & 0xff00) |
		(COLOR_FG_GREEN & 0xff);

		for (int y = 0;y < screenSize; y++) {

			screenAttr[y] = initAttr;
			screenColor[y] = c;

		}

		// here we will just copy the initialized plane onto the other planes
		// using arraycopy which will be faster.  I hope.

		System.arraycopy(initArray,0,screen,0,screenSize);
		System.arraycopy(initArray,0,screenGUI,0,screenSize);
		System.arraycopy(initArray,0,screenIsAttr,0,screenSize);
		System.arraycopy(initArray,0,screenExtended,0,screenSize);
		System.arraycopy(initArray,0,fieldExtended,0,screenSize);
		System.arraycopy(initArray,0,screenField,0,screenSize);
	}

	protected void initalizeFieldPlanes () {
		System.arraycopy(initArray,0,fieldExtended,0,screenSize);
		System.arraycopy(initArray,0,screenField,0,screenSize);
	}

	protected final int getWhichGUI(int pos) {

		return screenGUI[pos];
	}

	protected final boolean isChanged(int pos) {
		return screenIsChanged[pos] == 0 ? false : true;
	}

	protected final boolean isUseGui(int pos) {
		return screenGUI[pos] == NO_GUI ? false : true;
	}

	/**
	 * Return the data associated with the plane that is passed.
	 *
	 * @param from Position from which to start
	 * @param to Position to end
	 * @param plane From which plane to obtain the data
	 * @return Character array containing the data requested
	 */
	protected synchronized char[] getPlaneData(int from, int to, int plane) {

		int len = (to - from);

		char[] planeChars = new char[len + 1];

		switch (plane) {
		case PLANE_TEXT:
			System.arraycopy(screen, from, planeChars, 0, len);
			break;
		case PLANE_ATTR:
			System.arraycopy(screenAttr, from, planeChars, 0, len);
			break;
		case PLANE_COLOR:
			System.arraycopy(screenColor, from, planeChars, 0, len);
			break;
		case PLANE_EXTENDED:
			System.arraycopy(screenExtended, from, planeChars, 0, len);
			break;
		case PLANE_EXTENDED_GRAPHIC:
			System.arraycopy(screenGUI, from, planeChars, 0, len);
			break;
		case PLANE_FIELD:
			System.arraycopy(screenField, from, planeChars, 0, len);
			break;
		case PLANE_IS_ATTR_PLACE:
			System.arraycopy(screenIsAttr, from, planeChars, 0, len);
			break;
		default:
			System.arraycopy(screen, from, planeChars, 0, len);

		}
		return planeChars;

	}

	/**
	 * Converts a linear presentation space position to its corresponding row.
	 *
	 * @param pos The position to be converted
	 * @return The row which corresponds to the position given
	 * @throws OhioException
	 */
	private int convertPosToRow(int pos) {

		return (pos / numCols) + 1;

	}

	/**
	 * Converts a linear presentation space position to its corresponding column.
	 *
	 * @param pos The position to be converted
	 * @return The column which corresponds to the position given
	 * @throws OhioException
	 */
	private int convertPosToColumn(int pos) {

		return (pos % numCols) + 1;

	}

	/**
	 *
	 * Converts a row and column coordinate to its corresponding linear position.
	 *
	 * @param row - The row of the coordinate
	 * @param col - The column of the coordinate
	 * @return The linear position which corresponds to the coordinate given.
	 * @throws OhioException
	 */
	private int convertRowColToPos(int row, int col) {


		return (row - 1) * numCols + col -1;

	}


	/**
	 * <p>
	 *  GetScreen retrieves the various planes associated with the presentation
	 *  space. The data is returned as a linear array of character values in the
	 *  array provided. The array is not terminated by a null character except
	 *  when data is retrieved from the text plane, in which case a single null
	 *  character is appended.
	 *  </p>
	 *  <p>
	 *  The application must supply a buffer for the returned data and the length
	 *  of the buffer. Data is returned starting from the beginning of the
	 *  presentation space and continuing until the buffer is full or the entire
	 *  plane has been copied. For text plane data, the buffer must include one
	 *  extra position for the terminating null character.
	 *  <p>
	 *
	 * @param buffer
	 * @param bufferLength
	 * @param plane
	 * @return The number of characters copied to the buffer
	 * @throws OhioException
	 */
	public synchronized int GetScreen(char buffer[], int bufferLength, int plane) {

		return GetScreen(buffer,bufferLength,0,screenSize,plane);

	}

	/**
	 * <p>
	 *  GetScreen retrieves the various planes associated with the presentation
	 *  space. The data is returned as a linear array of character values in the
	 *  array provided. The array is not terminated by a null character except
	 *  when data is retrieved from the text plane, in which case a single null
	 *  character is appended.
	 * </p>
	 * <p>
	 * The application must supply a buffer for the returned data and the length
	 * of the buffer. Data is returned starting from the given position and
	 * continuing until the specified number of characters have been copied, the
	 * buffer is full or the entire plane has been copied. For text plane data,
	 * the buffer must include one extra position for the terminating null character.
	 * </p>
	 *
	 * @param buffer
	 * @param bufferLength
	 * @param from
	 * @param length
	 * @param plane
	 * @return The number of characters copied to the buffer
	 * @throws OhioException
	 */
	public synchronized int GetScreen(char buffer[], int bufferLength, int from,
			int length, int plane)
	{
		//      if(buffer == null)
		//         throw new OhioException(sessionVT.getSessionConfiguration(),
		//                     OhioScreen.class.getName(), "osohio.screen.ohio00300", 1);
		if(buffer == null)
			return 0;

		int min = Math.min(Math.min(buffer.length, bufferLength), screenSize);
		if ((from + min) > screenSize) {
			min = screenSize - from;
		}

		char[] pd = getPlaneData(from,from + min,plane);
		if(pd != null) {
			System.arraycopy(pd, 0, buffer, 0, min);
			return pd.length;
		}

		return 0;
	}

	/**
	 * <p>
	 *  GetScreen retrieves the various planes associated with the presentation
	 *  space. The data is returned as a linear array of character values in the
	 *  array provided. The array is not terminated by a null character except
	 *  when data is retrieved from the text plane, in which case a single null
	 *  character is appended.
	 *  </p>
	 *  <p>
	 *  The application must supply a buffer for the returned data and the length
	 *  of the buffer. Data is returned starting from the given coordinates and
	 *  continuing until the specified number of characters have been copied,
	 *  the buffer is full, or the entire plane has been copied. For text plane
	 *  data, the buffer must include one extra position for the terminating null
	 *  character.
	 *  </p>
	 *
	 * @param buffer
	 * @param bufferLength
	 * @param row
	 * @param col
	 * @param length
	 * @param plane
	 * @return The number of characters copied to the buffer.
	 * @throws OhioException
	 */
	public synchronized int GetScreen(char buffer[], int bufferLength, int row,
			int col, int length, int plane)
	//                                       throws OhioException {
	{
		// Call GetScreen function after converting row and column to
		// a position.
		return GetScreen(buffer,bufferLength, convertRowColToPos(row,col),
				length, plane);
	}

	/**
	 * <p>
	 *  GetScreenRect retrieves data from the various planes associated with the
	 *  presentation space. The data is returned as a linear array of character
	 *  values in the buffer provided.
	 *  </p>
	 *
	 * <p>
	 * The application supplies two positions that represent opposing corners of
	 * a rectangle within the presentation space. The starting and ending
	 * positions can have any spatial relationship to each other. The data
	 * returned starts from the row containing the upper-most point to the row
	 * containing the lower-most point, and from the left-most column to the
	 * right-most column.
	 * </p>
	 * <p>
	 * The specified buffer must be at least large enough to contain the number
	 * of characters in the rectangle. If the buffer is too small, no data is
	 * copied and zero is returned by the method. Otherwise, the method returns
	 * the number of characters copied.
	 * </p>
	 *
	 * @param buffer
	 * @param bufferLength
	 * @param startPos
	 * @param endPos
	 * @param plane
	 * @return The number of characters copied to the buffer
	 * @throws OhioException
	 */
	protected int GetScreenRect(char buffer[], int bufferLength,
			int startPos, int endPos, int plane)
	//                                             throws OhioException {
	{
		// We will use the row,col routine here because it is easier to use
		// row colum than it is for position since I wrote the other first and
		// am to lazy to implement it here
		// Maybe it would be faster to do it the other way?
		int startRow = convertPosToRow(startPos);
		int startCol = convertPosToColumn(startPos);
		int endRow = convertPosToRow(endPos);
		int endCol = convertPosToColumn(endPos);
		return GetScreenRect(buffer, bufferLength, startRow, startCol,
				endRow, endCol, plane);

	}

	/**
	 * <p>
	 *  GetScreenRect retrieves data from the various planes associated with the
	 *  presentation space. The data is returned as a linear array of character
	 *  values in the buffer provided. The buffer is not terminated by a null
	 *  character.
	 * </p>
	 * <p>
	 * The application supplies two coordinates that represent opposing corners
	 * of a rectangle within the presentation space. The starting and ending
	 * coordinates can have any spatial relationship to each other. The data
	 * returned starts from the row containing the upper-most point to the row
	 * containing the lower-most point, and from the left-most column to the
	 * right-most column.
	 * </p>
	 * <p>
	 * The specified buffer must be at least large enough to contain the number
	 * of characters in the rectangle. If the buffer is too small, no data is
	 * copied and zero is returned by the method. Otherwise, the method returns
	 * the number of characters copied.
	 * </p>
	 *
	 * @param buffer
	 * @param bufferLength
	 * @param startRow
	 * @param startCol
	 * @param endRow
	 * @param endCol
	 * @param plane
	 * @return The number characters copied to the buffer
	 * @throws OhioException
	 */
	protected int GetScreenRect(char buffer[], int bufferLength,
			int startRow, int startCol,
			int endRow, int endCol, int plane)
	//                                             throws OhioException {
	{
		// number of bytes obtained
		int numBytes = 0;

		// lets check the row range.  If they are reversed then we need to
		// place them in the correct order.
		if(startRow > endRow) {
			int r = startRow;
			startRow = endRow;
			endRow = r;
		}
		// lets check the column range.  If they are reversed then we need to
		// place them in the correct order.
		if(startCol > endCol) {
			int c = startCol;
			startCol = endCol;
			endCol = c;
		}
		int numCols = (endCol - startCol) + 1;
		int numRows = (endRow - startRow) + 1;

		// lets make sure it is within the bounds of the character array passed
		//  if not the return as zero bytes where read as per documentation.
		if(numCols * numRows <= bufferLength) {

			// make sure it is one larger.  I guess for other languanges to
			// reference like in C which is terminated by a zero byte at the end
			// of strings.
			char cb[] = new char[numCols + 1];
			int charOffset = 0;
			int bytes = 0;

			// now let's loop through and get the screen information for
			//  each row;
			for(int row = startRow; row <= endRow;) {
				if((bytes = GetScreen(cb, cb.length, row, startCol, numCols, plane)) != 0) {
					System.arraycopy(cb, 0, buffer, charOffset, numCols);
				}
				row++;
				charOffset += numCols;
				// make sure we count the number of bytes returned
				numBytes += bytes;
			}

		}

		return numBytes;
	}

	private int isOption(char[] screen,
			int x,
			int lenScreen,
			int numPref,
			int numSuff,
			char suff) {
		boolean hs =true;
		int sp = x;
		int os = 0;
		// check to the left for option
		while (--sp >=0 &&  screen[sp] <= ' ' ) {

			if (x - sp > numPref || screen[sp] == suff||
					screen[sp] == '.' ||
					screen[sp] == '*') {
				hs =false;
				break;
			}
		}

		// now lets check for how long the option is it has to be numPref or less
		os = sp;
		while (hs && --os > 0 && screen[os] > ' ' ) {

			if (sp - os >= numPref || screen[os] == suff ||
					screen[os] == '.' ||
					screen[os] == '*') {
				hs = false;
				break;
			}
		}
		if (sp - os > 1 && !Character.isDigit(screen[os+1])) {
			hs = false;
		}

		sp = x;

		if (Character.isDigit(screen[sp+1]))
			hs = false;
		// now lets make sure there are no more than numSuff spaces after option
		while (hs && (++sp < lenScreen && screen[sp] <= ' '
			|| screen[sp] == suff )) {
			if (sp - x >= numSuff || screen[sp] == suff ||
					screen[sp] == '.' ||
					screen[sp] == '*') {
				hs =false;
				break;
			}
		}
		if (hs && !Character.isLetterOrDigit(screen[sp]))
			hs = false;
		if (hs) {
			return os;
		}
		return -1;
	}

}