Listing of Source ../source/GOF/GofPushButtonIdentifier.javapackage se.entra.phantom.server;
import java.util.StringTokenizer;
import java.util.Vector;
/**
* This class identifies push button controls for the Gui-on-the-fly, from unused GofHostFields.
* @author J. Bergström
*/
public class GofPushButtonIdentifier extends GofControlIdentifierAdapter implements PhantomControlType
{
// ------------------
// INSTANCE VARIABLES
// ------------------
/**
* A vector holding the identification strings.
*/
private Vector<String> identStrings = new Vector<String>( );
/*
* Flag indicating if combined pushbutton definitions should be looked for.
*/
//private boolean doFindCombined = false;
/**
* The equal sign to be used together with the identification strings.
*/
private String equalSign;
/**
* The character used as separator for the push button combinations.
*/
private String combSign;
/**
* Indicates the way the pushbutton layout will be created.
* Valid values are:
* <pre>
* DEFAULT
* SIZE
* FONT
* SIZEANDFONT
* CLONE
* </pre>
*/
private String layout;
/**
* The value for the setting in the configuration file for the <code>nontemplatebutton</code>.
*/
private String nonTemplateButton;
/**
* The menu to use for non-template buttons. The default menu is <i>Functions</i>.
*/
private String menuName = "~Functions";
/**
* Menu items created for a panel. Will be emptied for each new panel.
*/
private Vector<PhantomMenuItem> menuItems;
// ----------------
// INSTANCE METHODS
// ----------------
/**
* Loads setting for the control from the server ini-file.
* @param confFile The server ini file.
* @param subsection The name of the GOF subsection that we are currently loading settings from.
*/
@Override
public void getControlSettings( IniFile confFile, String subsection )
{
String pushButtonIdent = confFile.getData( subsection, "pushbuttonident" );
parsePushButtonIdent( pushButtonIdent );
//String pushButtonCombination = confFile.getData( subsection, "pushbuttoncombination" );
//if( pushButtonCombination.equals( "1" ) == true )
// doFindCombined = true;
equalSign = confFile.getData( subsection, "pushbuttonequalsign" );
combSign = confFile.getData( subsection, "pushbuttoncombsign" );
layout = confFile.getData( subsection, "pushbuttonlayout" );
if( layout == null )
layout = "DEFAULT";
nonTemplateButton = confFile.getData( subsection, "nontemplatebutton" );
String value = confFile.getData( subsection, "nontemplatemenu" );
if( value != null && value.equals( "" ) == false )
menuName = value;
}
/**
* Identifies all the pushbutton controls from the <code>GofHostFields</code>. This is a
* little complicated since one GofHostField may correspond to one or several pushbuttons.
* @param gofRuntime The GuiOnTheFlyRuntime instance.
* @param areaIdentifier The areaIdentifier in which the entry fields should be identified..
* @param phantomHostScreen The Phantom host screen corresponding to the host screen.
* @param hostScreen The host screen that we are trying to build a GOF panel for.
* @param newPanel The newly created Gui-on-the-fly runtime panel.
*/
@Override
public void identifyCtrls( GuiOnTheFlyRuntime gofRuntime,
GofHostAreaIdentifier areaIdentifier,
PhantomHostScreen phantomHostScreen,
HostScreen hostScreen,
PhantomPanelData templPanel,
PhantomPanelData newPanel,
int offsetX,
int offsetY )
{
this.templPanel = templPanel;
Vector<GofHostField> gofHostFields = areaIdentifier.getAreasGofHostFields( );
Vector<GofPushButtonElement> pbElements = new Vector<GofPushButtonElement>( );
menuItems = new Vector<PhantomMenuItem>( );
for( int i = 0, s = gofHostFields.size( ); i < s; i++ )
{
GofHostField gofHostField = gofHostFields.elementAt( i );
if( gofHostField.hasBeenProcessed == false && gofHostField.isProtected( ) == true )
{
if( gofHostField.isEmpty( ) == false )
{
String text = gofHostField.getText( ).trim( );
if( text.equals( "" ) == false )
{
pbElements = findPushButtonElements( text );
if( pbElements.size( ) > 0 )
{
gofHostField.hasBeenProcessed = true;
createPushButtons( areaIdentifier,
pbElements,
text,
gofHostField,
phantomHostScreen,
hostScreen,
newPanel,
offsetX,
offsetY );
}
}
}
}
pbElements.removeAllElements( );
}
int s = menuItems.size( );
if( s > 0 )
{
PhantomMenuItem[] items = new PhantomMenuItem[s];
for( int i = 0; i < s; i++ )
{
items[i] = menuItems.elementAt( i );
}
PhantomMenu menu = new PhantomMenu( newPanel, 1000, items, menuName );
newPanel.addMenu( menu );
}
}
/**
* Parses the configuration setting for the pushbutton identifications, and splits
* it up into the identification strings, which are stored in a Vector.
* @param pushButtonIdent The setting from the configuration file.
*/
private void parsePushButtonIdent( String pushButtonIdent )
{
if( pushButtonIdent == null )
return;
StringTokenizer st = new StringTokenizer( pushButtonIdent, ", " );
while( st.hasMoreTokens( ) )
{
String s = st.nextToken( ).trim( );
if( s.equals( "" ) == false )
identStrings.addElement( s );
}
}
/**
* Finds all the push button elements in the text.
* @param text The text to search in.
*/
private Vector<GofPushButtonElement> findPushButtonElements( String text )
{
Vector<GofPushButtonElement> pbElements = new Vector<GofPushButtonElement>( );
for( int i = 0, s = text.length( ); i < s; i++ )
{
for( int j = 0, sj = identStrings.size( ); j < sj; j++ )
{
String ident = identStrings.elementAt( j );
int idLen = ident.length( );
if( i + idLen > text.length( ) )
break;
String textPart = text.substring( i, i + idLen );
textPart = changeToWC( textPart );
if( ident.equals( textPart ) == true )
{
GofPushButtonElement gpbe = null;
if( i > 0 )
{
int identEnd = i + textPart.length( );
String nxtChar = "";
if( identEnd < text.length( ) )
nxtChar = text.substring( identEnd, identEnd + 1 );
if( text.substring( i - 1, i ).equals( combSign ) == true )
{
gpbe = new GofPushButtonElement( i, ident + equalSign );
gpbe.combType = 2;
}
else if( nxtChar.equals( combSign ) )
{
gpbe = new GofPushButtonElement( i, ident + equalSign );
gpbe.combType = 1;
}
else if( nxtChar.equals( equalSign ) )
gpbe = new GofPushButtonElement( i, ident + equalSign );
}
else
{
int identEnd = i + textPart.length( );
String nxtChar = "";
if( identEnd < text.length( ) )
nxtChar = text.substring( identEnd, identEnd + 1 );
if( nxtChar.equals( combSign ) )
{
gpbe = new GofPushButtonElement( i, ident + equalSign );
gpbe.combType = 1;
}
else if( nxtChar.equals( equalSign ) )
gpbe = new GofPushButtonElement( i, ident + equalSign );
}
if( gpbe != null )
pbElements.addElement( gpbe );
i = i + idLen - 1;
break;
}
}
}
return pbElements;
}
private String changeToWC( String text )
{
char[] textc = text.toCharArray( );
for( int i = 0, s = textc.length; i < s; i++ )
{
if( textc[i] >= '0' && textc[i] <= '9' )
textc[i] = '#';
}
return new String( textc );
}
/*
* Will search for a single pushbutton identification string in a text. During
* the search it will check if there is a numeric character where the identification
* string has a numeric wildcard.
* <p>
* The numeric wildcard character in the identification string must be the hashmark '#'.
* @param text The text to search.
* @param ident The identification string to search for.
* @param startpos The startpos to search from.
* @return If a match was found, the startpos for the text matching the identification
* string, or -1 if no match.
*
private int findSubstrWithWildcards( String text, String ident, int startpos )
{
boolean isEqual = true;
int retVal = -1;
String sc = ident.substring( 0, 1 );
if( sc.equals( "#" ) == false )
{
int pos = text.indexOf( sc, startpos );
while( pos > -1 )
{
for( int i = 0, s = ident.length( ); i < s; i++ )
{
if( pos + i >= text.length( ) )
{
// End of text reached.
isEqual = false;
break;
}
char c1 = ident.charAt( i );
char c2 = text.charAt( pos + i );
if( c1 == '#' )
{
// Check for numeric character.
if( c2 < 0x30 || c2 > 0x39 )
{
isEqual = false;
break;
}
}
else if( c1 != c2 )
{
isEqual = false;
break;
}
}
if( isEqual == true )
{
// Substring found, stop searching for more.
retVal = pos;
break;
}
pos = text.indexOf( sc, pos + 1 );
isEqual = true;
}
}
else
{
// NOTYET! ident string starting with wildcard.
}
return retVal;
}*/
/**
* Creates push buttons or menu items from push button elements.
* This class takes every unused protected host field, and check if it has, what is
* called a pushbutton identification string. The pushbutton identification strings
* are text strings that identify a function key definition. The pushbutton
* identification strings are defined in the configuration file. When a host field is
* found to have one or more pushbutton identification string in it's text, a
* pushbutton element is created for each of them.
* <p>
* The pushbuttons elements text will also be analyzed for the right send key.
* <p>
* For each of the pushbutton elements, a push button or a menu item will be created.
* There are settings in the configuration file that determines which type of control
* that will be created.
* @param areaIdentifier The area identifier who's pushbutton elements are analyzed.
* @param pbElements A vector containing all the pbElements found in the currently processed hostfield.
* @param text The hostfield text.
* @param gofHostField The Gui-on-the-fly host field that is processed.
* @param phantomHostScreen The Phantom host screen corresponding to the host screen.
* @param hostScreen The host screen that we are trying to build a GOF panel for.
* @param newPanel The newly created Gui-on-the-fly runtime panel.
*/
private void createPushButtons( GofHostAreaIdentifier areaIdentifier,
Vector<GofPushButtonElement> pbElements,
String text,
GofHostField gofHostField,
PhantomHostScreen phantomHostScreen,
HostScreen hostScreen,
PhantomPanelData newPanel,
int offsetX,
int offsetY )
{
int prevCombEnd = -1;
for( int i = 0, s = pbElements.size( ); i < s; i++ )
{
GofPushButtonElement curPBElement = pbElements.elementAt( i );
GofPushButtonElement nxtPBElement;
if( i < pbElements.size( ) - 1 )
nxtPBElement = pbElements.elementAt( i + 1 );
else
nxtPBElement = null;
GofPushButtonElement nxtPBElement2;
if( i < pbElements.size( ) - 2 )
nxtPBElement2 = pbElements.elementAt( i + 2 );
else
nxtPBElement2 = null;
int x, cx, combPos, equalPos;
int y = gofHostField.getY( );
String key, keyText;
int txtStart = curPBElement.startpos;
int txtEnd = txtStart;
switch( curPBElement.combType )
{
case 1:
x = gofHostField.getX( ) + txtStart;
if( nxtPBElement2 != null )
txtEnd = nxtPBElement2.startpos;
else
txtEnd = text.length( );
txtEnd = getPrematureEnd( text, txtStart, txtEnd );
combPos = text.indexOf( combSign, txtStart );
if( combPos > txtStart )
key = text.substring( txtStart, combPos );
else
key = "";
equalPos = text.indexOf( equalSign, combPos );
combPos = text.lastIndexOf( combSign, txtEnd );
if( combPos > -1 && combPos < txtEnd )
keyText = text.substring( equalPos + 1, combPos );
else
keyText = "";
curPBElement.setSendKeyAndText( key + equalSign + keyText );
cx = keyText.length( ) + 4;
prevCombEnd = x + cx;
break;
case 2:
if( nxtPBElement2 != null )
txtEnd = nxtPBElement2.startpos;
else
txtEnd = text.length( );
txtEnd = getPrematureEnd( text, txtStart, txtEnd );
equalPos = text.indexOf( equalSign, txtStart );
if( equalPos > txtStart )
key = text.substring( txtStart, equalPos );
else
key = "";
combPos = text.lastIndexOf( combSign, txtEnd );
if( combPos > -1 && combPos < txtEnd )
keyText = text.substring( combPos + 1, txtEnd );
else
keyText = "";
curPBElement.setSendKeyAndText( key + equalSign + keyText );
cx = keyText.length( ) + 4;
if( prevCombEnd > -1 )
{
x = prevCombEnd + 1;
prevCombEnd = -1;
}
else
x = txtEnd - cx;
break;
default:
x = gofHostField.getX( ) + txtStart;
if( nxtPBElement != null )
txtEnd = nxtPBElement.startpos;
else
txtEnd = text.length( );
txtEnd = getPrematureEnd( text, txtStart, txtEnd );
curPBElement.setSendKeyAndText( text.substring( txtStart, txtEnd ).trim( ) );
cx = txtEnd - txtStart;
break;
}
// Create the PhantomHostField.
PhantomHostField phf = new PhantomHostField( phantomHostScreen, hostScreen, x, y, cx );
// Create the base control and pushbutton or menuitem.
createPushButtonOrMenuItem( areaIdentifier, newPanel, curPBElement, phf, x, y, cx, offsetX, offsetY );
}
}
/**
* Sometimes the end of the last pushbutton elements text will contain text that is not
* connected to the push button. This methods implements a simple algorithm to check for
* a premature end, by checking for at least two consecutive spaces in the text.
* @param text The text to search for a premature end.
* @param start The position to start the search from.
* @param end The position to stop the search from.
* @return The position of the premature end, or the stop position for the search if
* no premature end was found.
*/
private int getPrematureEnd( String text, int start, int end )
{
int p = text.indexOf( " ", start );
if( p > -1 && p < end )
return p;
else
return end;
}
/**
* Creates a push button or menu item from a single GofPushButtonElement.
* <p>
* There are several settings that will be taken from the configuration file,
* that are needed during the identification of the pushbutton controls.
* <p>
* There is one setting that should contain the pushbutton identification strings.
* This setting is a comma-separated list, with all the identification strings. This
* means, that the identification strings can't contain commas. The identification
* strings will be combined with the value of the pushbuttonequalsign setting, to
* create the real identification string to search for. The reason for that the equal
* sign is specified separately, is that if push button combinations are allowed, this
* class has to have the identification string without the equal sign.
* <p>
* It is possible to use a wildcard for numeric characters in the identification strings.
* The character used as a wildcard is the hash mark ('#').
* <p>
* The pushbuttonequalsign setting will usually be a equal sign ('=') or a colon (':').
* <p>
* Below is an example of pushbutton identification strings with wildcards, and a equal
* sign as the pushbuttonequalsign.
* <pre>
* pushbuttonident=PF#,PF##,F#,F##
* pushbuttonequalsign==
* </pre>
* Remember that the host field's text will be searched for matches in the same order as
* the identification strings are placed in the setting.
* <p>
* There is also a setting that specifies if push button combinations should be searched for.
* A pushbutton combination is when to push button definitions have been nestled together,
* separated by separator character. An example of a pushbutton combination could be:
* <pre>
* PF7/PF8=Previous/Next
* </pre>
* If the setting pushbuttoncombination is set to 1 (one), then this type of combination is searched
* for. This also requires that the pushbuttoncombsign be set to the separator character. In
* the above example, the separator character is the slash ('/'). Below these two setting are
* set to handle the above example:
* <pre>
* pushbuttoncombination=1
* pushbuttoncombsign=/
* </pre>
* <p>
* This class also has a setting that affects the look of the entry fields. This is the
* pushbuttonlayout setting. Valid values for this setting are:
* <pre>
* entryfieldlayout=DEFAULT
* entryfieldlayout=SIZE
* entryfieldlayout=FONT
* entryfieldlayout=SIZEANDFONT
* entryfieldlayout=CLONE
* </pre>
* <p>
* DEFAULT means that no settings are taken from the template panel. Size will be taken
* from the size used by the definition on the host screen. The panels default font will
* be used.
* <p>
* SIZE means that the size will be taken from the template panel, from a pushbutton with
* the id=PB_X. The panels default font will be used. If this control cannot be found,
* default values will be used.
* <p>
* FONT means that the font is taken from template panel, from a pushbutton with the id=PB_X.
* If this control cannot be found, default values will be used.
* <p>
* SIZEANDFONT means that the font and size are taken from template panel, from a pushbutton
* with the id=PB_X. If this control cannot be found, default values will be used.
* <p>
* CLONE means that the button on the template panel is cloned. Cloned means that the size,
* font, and an icon, if it exists, are taken from a pushbutton with the id=PB_Fnn (nn is
* one or two numeric characters, an exact match must be found). If this control cannot be
* found, default values will be used.
* <p>
* Any other value will be treated as DEFAULT.
* <p>
* There is a possibility to let pushbuttons not found in the template file be created as
* menu items instead. This is only possible when the layout is cloned from the template file,
* because pushbuttons not found there would get a different look from the cloned ones. For
* this there are two settings. The <code>nontemplatebutton</code> setting turns this option
* on and the <code>nontemplatemenu</code> setting specifies the menu name to use for the menu
* items. The value for the menu name can have a shortcut specified by placing a tilde ('~') in
* front of the character to be used as a shortcut. Below is an example of this setting.
* <pre>
* nontemplatebutton=MENU
* nontemplatemenu=~Functions
* </pre>
* @param areaIdentifier The area identifier who's pushbutton elements are analyzed.
* @param newPanel The newly created Gui-on-the-fly runtime panel.
* @param pbElement The pushbutton element that should be turned into a pushbutton or menuitem.
* @param phf The PhantomHostField that the current pushbutton element is part of.
* @param x The x-position.
* @param y The y-position.
* @param cx The length of the push button element in characters.
*/
private void createPushButtonOrMenuItem( GofHostAreaIdentifier areaIdentifier,
PhantomPanelData newPanel,
GofPushButtonElement pbElement,
PhantomHostField phf,
int x,
int y,
int cx,
int offsetX,
int offsetY )
{
PhantomControlBase bc;
PhantomCPushButton pb = null;
int pbCx = cx * GOF_GUIUNITX - 2;
int pbCy = GOF_GUIUNITY + 2;
int font = -1;
PhantomControl templateControl;
if( layout.equals( "SIZE" ) )
{
templateControl = templPanel.getControlFromID( "PB_X" );
if( templateControl != null && templateControl.controlBase.type == CTRLTYPE_BUTTON )
{
pbCx = templateControl.controlBase.cx;
pbCy = templateControl.controlBase.cy;
}
bc = new PhantomControlBase( GOF_MARGINX + ( x - offsetX ) * GOF_STEPX,
GOF_MARGINY + ( y - offsetY ) * GOF_STEPY - 1,
pbCx,
pbCy,
CTRLTYPE_BUTTON );
pb = new PhantomCPushButton( newPanel, bc, phf, pbElement.pbText );
pb.sendKey = pbElement.sendKey;
}
else if( layout.equals( "FONT" ) )
{
templateControl = templPanel.getControlFromID( "PB_X" );
if( templateControl != null && templateControl.controlBase.type == CTRLTYPE_BUTTON )
{
font = ( ( PhantomCPushButton )templateControl ).font;
}
bc = new PhantomControlBase( GOF_MARGINX + ( x - offsetX ) * GOF_STEPX,
GOF_MARGINY + ( y - offsetY ) * GOF_STEPY - 1,
pbCx,
pbCy,
CTRLTYPE_BUTTON );
pb = new PhantomCPushButton( newPanel, bc, phf, pbElement.pbText );
pb.font = font;
pb.sendKey = pbElement.sendKey;
}
else if( layout.equals( "SIZEANDFONT" ) )
{
templateControl = templPanel.getControlFromID( "PB_X" );
if( templateControl != null && templateControl.controlBase.type == CTRLTYPE_BUTTON )
{
pbCx = templateControl.controlBase.cx;
pbCy = templateControl.controlBase.cy;
font = ( ( PhantomCPushButton )templateControl ).font;
}
bc = new PhantomControlBase( GOF_MARGINX + ( x - offsetX ) * GOF_STEPX,
GOF_MARGINY + ( y - offsetY ) * GOF_STEPY - 1,
pbCx,
pbCy,
CTRLTYPE_BUTTON );
pb = new PhantomCPushButton( newPanel, bc, phf, pbElement.pbText );
pb.font = font;
pb.sendKey = pbElement.sendKey;
}
else if( layout.equals( "CLONE" ) )
{
templateControl = templPanel.getControlFromID( pbElement.layoutId );
if( templateControl != null && templateControl.controlBase.type == CTRLTYPE_BUTTON )
{
pb = ( PhantomCPushButton )( ( PhantomCPushButton )templateControl ).clone( );
pb.controlBase.x = GOF_MARGINX + ( x - offsetX ) * GOF_STEPX;
pb.controlBase.y = GOF_MARGINY + ( y - offsetY ) * GOF_STEPY - 1;
}
else if( templateControl == null && nonTemplateButton.equals( "MENU" ) )
{
PhantomMenuItem menuItem = new PhantomMenuItem( newPanel, 1000 + menuItems.size( ) + 1, pbElement.pbText, pbElement.sendKey );
menuItems.addElement( menuItem );
}
}
else
{
bc = new PhantomControlBase( GOF_MARGINX + ( x - offsetX ) * GOF_STEPX,
GOF_MARGINY + ( y - offsetY ) * GOF_STEPY - 1,
pbCx,
pbCy,
CTRLTYPE_BUTTON );
pb = new PhantomCPushButton( newPanel, bc, phf, pbElement.pbText );
pb.sendKey = pbElement.sendKey;
}
// Add the push button.
if( pb != null )
{
newPanel.addControl( pb );
areaIdentifier.addControl( pb );
}
}
// ==================================================================
// GofPushButtonElement subclass
// ==================================================================
/**
* The GofPushButtonIdentifier will make use of a private inner class named
* GofPushButtonElement. This is used to store information about the push button
* element found during the matching with identification strings. This information
* is the used during the creation of the pushbutton control or the menu item.
* <p>
* The GofPushButtonElement also has a method to get the send key string that will
* be attached to the control.
*/
private class GofPushButtonElement
{
/**
* The startposition of this element's text in the host field text.
*/
private int startpos;
/**
* The identification string that matched this push button element.
*/
private String ident;
/**
* The push button element's send key.
*/
private int sendKey;
/**
* The push button element's text.
*/
private String pbText;
/**
* The layout id to search for in the template for cloning.
*/
private String layoutId;
private int combType = 0;
// -----------
// CONSTRUCTOR
// -----------
/**
* Creates a new push button element.
* @param startpos The startposition of the element's text in the host field text.
* @param ident The identification string that matched this push button element.
*/
private GofPushButtonElement( int startpos, String ident )
{
this.startpos = startpos;
this.ident = ident;
}
// ----------------
// INSTANCE METHODS
// ----------------
/**
* Sets the push button element's send key and the text for pushbutton.
* @param text The original text for the push button element.
*/
private void setSendKeyAndText( String text )
{
if( text == null || text.equals( "" ) )
return;
int numStart = ident.indexOf( "#" );
int numEnd = ident.lastIndexOf( "#" );
String num = text.substring( numStart, numEnd + 1 ).trim( );
layoutId = "PB_F" + num;
String sendString = null;
try
{
int numVal = Integer.valueOf( num ).intValue( );
if( numVal > 0 && numVal < 10 )
{
sendString = "@" + num;
}
else if( numVal >= 10 && numVal <= 24 )
{
char[] c = new char[2];
c[0] = '@';
c[1] = ( char )( 'a' + ( numVal - 10 ) );
sendString = new String( c );
}
if( sendString != null )
{
for( int i = 0, s = HostSendKeys.phantomSendKey.length; i < s; i++ )
{
if( sendString.equals( HostSendKeys.phantomSendKey[i] ) )
{
sendKey = i + 1;
break;
}
}
}
}
catch( NumberFormatException e )
{
}
pbText = ( text.substring( ident.length( ) ) ).trim( );
}
}
}