    001package org.vishia.gral.cfg;
    002
    003import java.io.File;
    004import java.io.FileNotFoundException;
    005import java.io.IOException;
    006import java.io.InputStream;
    007import java.text.ParseException;
    008
    009import org.vishia.gral.ifc.GralMngBuild_ifc;
    010import org.vishia.mainCmd.MainCmd;
    011import org.vishia.mainCmd.MainCmdLogging_ifc;
    012import org.vishia.mainCmd.Report;
    013import org.vishia.util.StringPartFromFileLines;
    014import org.vishia.zbnf.ZbnfJavaOutput;
    015import org.vishia.zbnf.ZbnfParser;
    016
    017/**Class to read the configuration script for a Graphical User Interface. The syntax of the configuration
    018 * matches to the class {@link GralCfgData}, which contains all data of read configuration
    019 * after invoking the read method. That configuration data are associated in
    020 * {@link GralCfgBuilder#GuiCfgBuilder(GralCfgData, GralMngBuild_ifc, File)} and used in
    021 * {@link GralCfgBuilder#buildGui(org.vishia.msgDispatch.LogMessage, int)} to build the GUI appearance.
    022 * The building of the GUI with the {@link GralCfgData} can be done without this script reader too,
    023 * but this class reads that data from a script.
    024 *
    025 * @author Hartmut Schorrig
    026 *
    027 */
    028public class GralCfgZbnf
    029{
    030
    031  /**Version and history
    032   * <ul>
    033   * <li>2018-09-17 Now the syntax is contained in <code>org/vishia/gral/cfg/Syntax.zbnf</code> as file inside jar (ressource).
    034   *   It is read with {@link #getSyntaxFromJar()}
    035   * <li>2011-05-00 Hartmut created, the old ZbnfCfg.. class is obsolte now.
    036   * </ul>
    037   *
    038   * <b>Copyright/Copyleft</b>:<br>
    039   * For this source the LGPL Lesser General Public License,
    040   * published by the Free Software Foundation is valid.
    041   * It means:
    042   * <ol>
    043   * <li> You can use this source without any restriction for any desired purpose.
    044   * <li> You can redistribute copies of this source to everybody.
    045   * <li> Every user of this source, also the user of redistribute copies
    046   *    with or without payment, must accept this license for further using.
    047   * <li> But the LPGL is not appropriate for a whole software product,
    048   *    if this source is only a part of them. It means, the user
    049   *    must publish this part of source,
    050   *    but doesn't need to publish the whole source of the own product.
    051   * <li> You can study and modify (improve) this source
    052   *    for own using or for redistribution, but you have to license the
    053   *    modified sources likewise under this LGPL Lesser General Public License.
    054   *    You mustn't delete this Copyright/Copyleft inscription in this source file.
    055   * </ol>
    056   * If you intent to use this source without publishing its usage, you can get
    057   * a second license subscribing a special contract with the author.
    058   *
    059   * @author Hartmut Schorrig = hartmut.schorrig@vishia.de
    060   */
    061  public static final int version = 20120303;
    062
    063
    064  private final ZbnfParser parser;
    065
    066  private final ZbnfJavaOutput zbnfJavaOutput;
    067
    068  private final MainCmdLogging_ifc console;
    069
    070  private final File fileSyntax;
    071
    072  /**The standard syntax for graphic configuration.
    073   * Note: it is possible to use an abbreviated syntax with the same semantic if the constructor {@link GralCfgZbnf#GralCfgZbnf(Report, File)} is used.
    074   * This syntax is used with the constructor
    075   * */
    076  @Deprecated public final String XXXsyntaxStd =
    077    " GuiDialogZbnfControlled::=\n"
    078  + " [ size( <#?ySize> , <#?xSize> ) ;]\n"
    079  + " { DataReplace: <DataReplace>\n"
    080  + " | Type <Type>\n"
    081  + " | if <Conditional>\n"
    082  + " | <Element>    \n"
    083  + " } \\e.\n"
    084  + "\n"
    085  + "\n"
    086  + "Element::=\n"
    087  + "[@ <*:?positionString>:] \n"
    088  + "[ Led  ( <param?Led> ) ;\n"
    089  + "| Button ( <param?Button> ) ; \n"
    090  + "| SwitchButton ( <param?SwitchButton> ) ;\n"
    091  + "| ValueBar ( <param?ValueBar> ) ;\n"
    092  + "| InputTextline ( <param?InputTextline> ) ;\n"
    093  + "| InputField ( <param?InputTextline> ) ;\n"
    094  + "| InputBox ( <param?InputTextbox> ) ;\n"
    095  + "| InputFile ( <param?InputFile> ) ;\n"
    096  + "| Slider ( <param?Slider> ) ;\n"
    097  + "| Show ( <param?ShowField> ) ;\n"
    098  + "| <Table> \n"
    099  + "| <Text> \n"
    100  + "| <Imagefile>\n"
    101  + "| <Line>\n"
    102  + "| <Curveview>\n"
    103  + "## | <InputField>\n"
    104  + "| <FileInputField>\n"
    105  + "].\n"
    106  + "\n"
    107  + "\n"
    108  + "param::=\n"
    109  + " { [%top<?promptPosition=t>|%t<?promptPosition=t>|%r<?promptPosition=r>] : [<\"\"?prompt> | <*,)?prompt>]xxx"
    110  + " | cmd =  [<\"\"?cmd>|\\[<*\\]?cmd>\\]] \n"
    111  + " | text = [<\"\"?text>|<$-/?text>] \n"
    112  + " | name = [<\"\"?name>|<$-/?name>] \n"
    113  + " | info = [<\"\"?data>|<$-/?data>] \n"
    114  + " | data = [<\"\"?data>|<*,);\\ ?data>] \n"
    115  + " | action = [<\"\"?userAction>|<$-?userAction>] \n"
    116  + " | show = [<\"\"?showMethod>|<$?showMethod>] \n"
    117  + " | type = <$?type>\n"
    118  + " | format = [<\"\"?format>|<* ,);?format>]\n"
    119  + " | help = [<\"\"?help>|<* ,);?help>]\n"
    120  + " ##| prompt = [<\"\"?prompt>|<* ,);?prompt>]\n"
    121  + " | color = <colorName?color0> [ / <colorName?color1> ]\n"
    122  + " | dropFiles = [<\"\"?dropFiles>|<$-/\\.?dropFiles>]\n"
    123  + " | dropText = [<\"\"?dropText>|<$-/\\.?dropText>]\n"
    124  + " | dragFiles = [<\"\"?dragFiles>|<$-/\\.?dragFiles>]\n"
    125  + " | dragText = [<\"\"?dragText>|<$-/\\.?dragText>]\n"
    126  + " | <\"\"?text>\n"
    127  + " | <$-/\\.:?text>\n"
    128  + " ##| <*,)?text>\n"
    129  + " ? , \n"
    130  + "}.\n"
    131  + "\n"
    132  + "\n"
    133  + "Text::= Text ( [<\"\"?text>|<*)?text>]\n"
    134  + "    [ ,{ <!\\[ABC\\]?size> \n"
    135  + "       | <colorName> \n"
    136  + "         | color = <#x?colorValue> | <colorName>\n"
    137  + "       ? , }\n"
    138  + "    ]) ; .\n"
    139  + "\n"
    140  + "\n"
    141  + "Table::=Table ( [<\"\"?text>|<*)?text>] ) :\n"
    142  + "{ size ( { <#?columnWidth> ? + } x <#?height> ) \n"
    143  + "| cmd = [<\"\"?cmd>|\\[<*\\]?cmd>\\]] \n"
    144  + "| userAction = <$?userAction> \n"
    145  + "| name = [<\"\"?name>|<$?name>] ? , \n"
    146  + "} ; \n"
    147  + "\n"
    148  + "\n"
    149  + "Curveview::=Curveview ( <$?name> [ , <#?nrofPoints>][ , active<?activate>]) :\n"
    150  + "{<?line> line ( <$?name> \n"
    151  + "[ , { color = [<colorName>| <#x?colorValue>] \n"
    152  + " | offset = <#f?offset> \n"
    153  + " | scale = <#f?scale>\n"
    154  + " | data = [<\"\"?data>|<*,);\\ ?data>]\n"
    155  + "| nullLine = <#?nullLine>\n"
    156  + "? , } ] )                       ##line-parameter\n"
    157  + " ? , } ;.                            ##lines\n"
    158  + "\n"
    159  + "\n"
    160  + " Imagefile::= Imagefile \n"
    161  + "(  { <!\\[ABCDE\\]?size>\n"
    162  + "| name = <$?name>\n"
    163  + "| file = <\"\"?file>|<* ,)?file>\n"
    164  + "? , }\n"
    165  + ") ; ."
    166  + "Line::= Line ( {<colorName> | color = <#x?colorValue> |<?coord> <#f?x> , <#f?y> ? , } ) ;.\n"
    167  + "?en:Line/xCoord::=\"There may be at least 2, but more possible pairs of x,y for polygons.\".\n" +
    168  "colorName::=[<?color> red|green|blue|black|white|gray|brown|cyan|magenta|orange|amber|yellow|violet|purple\n" +
    169  "|rd|gn|bl|gr|bn|cy|ma|or|wh|bk|ye|or|vi|pk|pu|am\n" +
    170  "|lrd|lgn|lbl|lgr|lye|lor|lam|lma|lcy\n" +
    171  "|prd|pgn|pbl|pgr|pye|por|pam|pma|pcy\n" +
    172  "|drd|dgn|dbl|drg|dye|dor|dam|dma|dcy\n" +
    173  "]\n" +
    174  "\n"
    175 ;
    176
    177  /**The current directory is that directory, where the config file is located.
    178   * It is used if other files are given with relative path.*/
    179  File currentDir;
    180
    181  public GralCfgZbnf()
    182  { this.console = MainCmd.getLogging_ifc();
    183    this.fileSyntax = null;
    184    String syntax = getSyntaxFromJar();
    185    this.parser = new ZbnfParser(console);
    186    try{ this.parser.setSyntax(syntax); //Std);
    187    } catch(ParseException exc){
    188      throw new RuntimeException(exc);  //unexpected because syntax is given here.
    189    }
    190    this.zbnfJavaOutput = new ZbnfJavaOutput(console);
    191  }
    192
    193
    194  public GralCfgZbnf(Report log, File fileSyntax)
    195  { this.console = log;
    196    this.fileSyntax = fileSyntax;
    197    this.parser = new ZbnfParser(log);
    198    this.zbnfJavaOutput = new ZbnfJavaOutput(log);
    199  }
    200
    201
    202  /**
    203   * @return null if not found.
    204   */
    205  String getSyntaxFromJar() {
    206    String syntax = null;
    207    ClassLoader classLoader = ClassLoader.getSystemClassLoader();
    208    //classLoader.getResource("org.vishia.gral.cfg.Syntax.txt");
    209    InputStream in = classLoader.getResourceAsStream("org/vishia/gral/cfg/Syntax.zbnf");
    210    if(in == null) return null; //not found
    211    byte[] data = new byte[10000];
    212    try {
    213      int nBytes;
    214      do{
    215        nBytes = in.read(data);
    216        String sdata = new String(data, 0, nBytes);
    217        if(syntax == null) { syntax = sdata; }
    218        else { syntax += sdata; }
    219      } while(nBytes == data.length);
    220
    221    } catch (IOException e) {
    222      // TODO Auto-generated catch block
    223      e.printStackTrace();
    224    }
    225    return syntax;
    226  }
    227
    228
    229
    230  /**Configures the GUI using a description in a file. The syntax is described see {@link #configureWithZbnf(String, String)}.
    231   * Because the configuration is containing in a user-accessible file, it may be faulty.
    232   * Than a error message was written on the own Report output. Therefore this routine
    233   * should be called after the main application is started. See example in {@link org.vishia.appl.menu.Menu}.
    234   *
    235   *
    236   * @param sTitle Title line for the application
    237   * @param fileConfigurationZbnf File containing the configuration. The file should be exist and able to read.
    238   * @return true if successfully, false on any error. If false, an error message was written
    239   *         using the own Report-implementation.
    240   */
    241  public String configureWithZbnf(File fileConfigurationZbnf, GralCfgData destination)
    242  { String sError = null;
    243    File dirOfconfig = fileConfigurationZbnf.getParentFile();
    244    System.out.println("GralCfgZbnf - start parse cfg file; " + fileConfigurationZbnf.getAbsolutePath());
    245    //parses the configuration file and fill the configuration data.
    246    //Note: The building of the graphic appearance will be done in the graphic thread with this data later.
    247    sError = ZbnfJavaOutput.parseFileAndFillJavaObject(destination.getClass(), destination
    248      , fileConfigurationZbnf, fileSyntax, console, 0);
    249    if(sError != null)
    250    { return "Error reading config file" + sError;
    251    }
    252
    253
    254    StringPartFromFileLines spToParse = null;
    255    try
    256    { //spToParse = new StringPartFromFileLines(new File(sFileIn));
    257      spToParse = new StringPartFromFileLines(fileConfigurationZbnf, -1, null, null);
    258    }
    259    catch(FileNotFoundException exception)
    260    { sError = "file not found:" + fileConfigurationZbnf.getAbsolutePath();
    261      console.writeError(sError);
    262    }
    263    catch(IOException exception)
    264    { sError = "file read error:" + fileConfigurationZbnf.getAbsolutePath();
    265      console.writeError(sError);
    266    }
    267    if(spToParse != null)
    268    { //sError = configureWithZbnf(sTitle, spToParse, panel, dirOfconfig);
    269      spToParse.close();  //close the StringPart, it means it can't be used furthermore.
    270    }
    271    return sError;
    272  }
    273
    274
    275  /**Configures the GUI using a description in a file. The syntax is described see {@link #configureWithZbnf(String, String)}.
    276   * Because the configuration is containing in a user-accessible file, it may be faulty.
    277   * Than a error message was written on the own Report output. Therefore this routine
    278   * should be called after the main application is started. See example in {@link org.vishia.appl.menu.Menu}.
    279   *
    280   *
    281   * @param sTitle Title line for the application
    282   * @param fileConfigurationZbnf File containing the configuration. The file should be exist and able to read.
    283   * @return true if successfully, false on any error. If false, an error message was written
    284   *         using the own Report-implementation.
    285   */
    286  public void configureWithZbnf(CharSequence configurationZbnf, GralCfgData destination)
    287  throws ParseException
    288  { //parses the configuration file and fill the configuration data.
    289    //Note: The building of the graphic appearance will be done in the graphic thread with this data later.
    290    boolean bOk = parser.parse(configurationZbnf.toString());
    291    if(!bOk) {
    292      String sError = parser.getSyntaxErrorReport();
    293      throw new ParseException(sError, 0);
    294    }
    295    else {
    296      try{ zbnfJavaOutput.setContent(destination.getClass(), destination, parser.getFirstParseResult());
    297      } catch(Exception exc) {
    298        throw new RuntimeException(exc);  //unexpected because semantic and data structure is given here.
    299     }
    300    }
    301  }
    302
    303
    304
    305
    306}