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}