001package org.vishia.gral.area9;
002
003import java.io.File;
004import java.io.FileWriter;
005import java.io.IOException;
006import java.io.Writer;
007import java.util.List;
008
009import org.vishia.communication.InterProcessCommFactorySocket;
010import org.vishia.gral.base.GralGraphicTimeOrder;
011import org.vishia.gral.base.GralShowMethods;
012import org.vishia.gral.base.GralWidget;
013import org.vishia.gral.base.GralMng;
014import org.vishia.gral.base.GralPanelContent;
015import org.vishia.gral.base.GralTabbedPanel;
016import org.vishia.gral.cfg.GralCfgData;
017import org.vishia.gral.cfg.GralCfgDesigner;
018import org.vishia.gral.cfg.GralCfgZbnf;
019import org.vishia.gral.ifc.GralMngBuild_ifc;
020import org.vishia.gral.ifc.GralMng_ifc;
021import org.vishia.gral.ifc.GralPlugUser2Gral_ifc;
022import org.vishia.gral.ifc.GralPlugUser_ifc;
023import org.vishia.gral.ifc.GralUserAction;
024import org.vishia.gral.ifc.GralWidget_ifc;
025import org.vishia.inspectorTarget.Inspector;
026import org.vishia.mainCmd.MainCmd_ifc;
027import org.vishia.mainCmd.Report;
028import org.vishia.msgDispatch.MsgDispatchSystemOutErr;
029import org.vishia.util.KeyCode;
030
031/**This class is the basic class for configurable GUI applications with 9-Area Main window.
032 * It works without any derivation, if only simple widgets are necessary.
033 * If additional capabilities are need, this class can uses as the super class.
034 * Some protected methods support overriding, especially:
035 * <ul>
036 * <li>{@link #initMain()}: initializes the GUI
037 * <li>{@link #stepMain()}: Will be invoked in the main loop.
038 * <li>{@link #finishMain()}: invoked on exit.
039 * </ul>
040 * Hint: call super.stepMain() etc. in an overridden method if necessary.
041 * <br><br>
042 * The class contains a {@link #main(String[])}. It is a complete ready to run application. 
043 * The content of the GUI can be controlled by a script. The command line arguments are parsed in
044 * {@link GralArea9MainCmd}, the universal or basic MainCmd for gral-GUI applications.
045 * <br><br>
046 * The configuration is done with {@link GralCfgZbnf} in the {@link #initMain()} routine.
047 * 
048 * <br><br>
049 * <br><br>
050 * <br><br>
051 * 
052 * <br>
053 * Registered user action can be used by script.
054 * <ul>
055 * <li>"cmdInvoke": The given parameter 'cmd' of the widget will be executed as command line.
056 *   It is usefull to start commands from this GUI for example with a button.
057 * </ul>
058 * A user plugin class can be plugged which can register some more user actions etc.
059 * @author Hartmut Schorrig.
060 *
061 */
062public class GuiCfg 
063{
064
065  /**The version, history and license.
066   * <ul>
067   * <li>2013-12-02 Hartmut new Parameter for {@link #GuiCfg(GuiCallingArgs, GralArea9MainCmd, GralPlugUser_ifc, GralPlugUser2Gral_ifc, List)}:
068   *    cfgConditions.
069   * <li>2012-09-17 Hartmut new: {@link #showMethods}
070   * <li>2011-10-12 Hartmut chg: ctor needs a {@link GralPlugUser_ifc} which may be null: A plugin may be instantiated
071   *   by reflection with String given class name. It may be possible to give it as parameter too.
072   * <li>2011-10-20 Hartmut chg: ctor needs a {@link GralPlugUser2Gral_ifc} which may be null.
073   *   Idea: a derived class should support it. Other Idea: either both via reflection or both maybe direct. 
074   * <li>2011-10-11 Hartmut new: Switches MainCmd-output to OutputBox.
075   * <li>2011-09-30 Hartmut new: menu 'Design/...' to edit fields and work with the {@link GralCfgDesigner}.
076   * <li>2011-09-18 Hartmut new: The main tab panel has the name 'mainTab' and it is registered in the {@link #_gralMng} now.
077   *     Generally an application may have more as one tabbed panels.
078   * <li>2011-09-10 Hartmut del: Remove dialogZbnfConfigurator, it was not used. It is the old solution.
079   * <li>2011-09-08 Hartmut del: Remove the message panel. It was a special solution. 
080   * <li>2011-08-08 Hartmut new: {@link #initMain()} as override-able method instead direct call of initializing.
081   * <li>2011-08-07 Hartmut chg: Now {@link GuiCallingArgs} as primary class, not an inner class here.
082   * <li>2011-08-07 Hartmut chg: Now {@link GralArea9MainCmd} as extra primary class.
083   * <li>2011-08-04 Hartmut chg: rename and move from org/vishia/guiCmdMenu/CmdMenu.java to org/vishia/gral/area9/GuiCfg.java.
084   *     It is a universal GUI which is configurable in content. Also it is a base class for some configurable GUI applications.
085   * <li>2011-08-04 Hartmut chg: Use {@link GralPanelContent} instead the special InspcGuiPanelContent.     
086   * <li>2011-08-04 Hartmut new: {@link #userInit()} as override-able method instead direct call of user.init(). 
087   *     Advantage: User can do anything in the derived class.
088   * <li>2011-08-04 Hartmut new: Use first key of argument --size: to determine the size. TODO parseArgs    
089   * <li>2011-07-31 Hartmut new: First usage as super class.
090   * <li>2010-01-01 Hartmut new: The base of this class was created with some applications.
091   * </ul>
092   * 
093   * <b>Copyright/Copyleft</b>:
094   * For this source the LGPL Lesser General Public License,
095   * published by the Free Software Foundation is valid.
096   * It means:
097   * <ol>
098   * <li> You can use this source without any restriction for any desired purpose.
099   * <li> You can redistribute copies of this source to everybody.
100   * <li> Every user of this source, also the user of redistribute copies
101   *    with or without payment, must accept this license for further using.
102   * <li> But the LPGL is not appropriate for a whole software product,
103   *    if this source is only a part of them. It means, the user
104   *    must publish this part of source,
105   *    but don't need to publish the whole source of the own product.
106   * <li> You can study and modify (improve) this source
107   *    for own using or for redistribution, but you have to license the
108   *    modified sources likewise under this LGPL Lesser General Public License.
109   *    You mustn't delete this Copyright/Copyleft inscription in this source file.
110   * </ol>
111   * If you are intent to use this sources without publishing its usage, you can get
112   * a second license subscribing a special contract with the author. 
113   * 
114   * @author Hartmut Schorrig = hartmut.schorrig@vishia.de
115   * 
116   * 
117   */
118  public final static int version = 0x20120303;
119  
120  /**Composition of a Inspector-Target instance. This is only to visit this application for debugging.
121   * Not necessary for functionality. */
122  private final Inspector inspector;
123  
124  /**To Output log informations. The ouput will be done in the output area of the graphic. */
125  public final Report console;
126
127  //protected final GralPanelContent panelContent;
128
129    
130
131
132  
133  
134
135
136/**The calling arguments of this class. It may be filled by command line invocation 
137 * but maybe given in a direct way too while calling this class in a Java environment. */
138final GuiCallingArgs cargs;
139
140/**The configuration data for graphical appearance. */
141public final GralCfgData guiCfgData;
142
143
144
145
146/**This instance helps to create the Dialog Widget as part of the whole window. It is used only in the constructor.
147 * Therewith it may be defined stack-locally. But it is better to show and explain if it is access-able at class level. */
148//GuiDialogZbnfControlled dialogZbnfConfigurator;   
149
150
151
152/**Some actions may be processed by a user implementation. */
153protected GralPlugUser_ifc user;
154
155protected final GralPlugUser2Gral_ifc plugUser2Gui;
156
157
158
159
160
161
162public final GralArea9_ifc gui;
163
164public final GralArea9Window guiW;
165
166public final MainCmd_ifc mainCmd;
167
168/**Especially for debug access to the singleton instance, start with _ to present on top of variables. */
169public GralMng _gralMng;
170
171
172/**Panel-Management-interface for the panels. */
173public GralMngBuild_ifc panelBuildIfc;
174
175public GralMng_ifc guiAccess;
176
177protected GralTabbedPanel mainTabPanel;
178
179
180private static GuiCfg singleton;
181
182/**ctor for the main class of the application. 
183 * The main class can be created in some other kinds as done in static main too.
184 * But it needs the {@link MainCmdWin}.
185 * <br><br>
186 * The ctor checks whether a gUI-configuration file is given. If not then the default configuration is used.
187 * It is especially for the Sample.
188 * <br><br>
189 * The the GUI will be completed with the content of the GUI-configuration file.  
190 *   
191 * @param cargs The given calling arguments.
192 * @param cmdGui The GUI-organization.
193 * @param plugUser2Gui maybe possible a instances which plugs the user instance to the GUI.
194 *   This instance may be defined in the context which calls this constructor.
195 *   Note: A user instance may be instantiated with the cmd line calling argument "-plugin=JAVACLASSPATH"  
196 */
197public GuiCfg(GuiCallingArgs cargs, GralArea9MainCmd cmdGui
198    , GralPlugUser_ifc plugUser, GralPlugUser2Gral_ifc plugUser2Gui
199    , List<String> cfgConditions) 
200{ if(singleton !=null) throw new IllegalArgumentException("class GuiCfg can instantiate only one time, a singleton!");
201  this.mainCmd = cmdGui;
202  this.gui = cmdGui.gui;
203  guiW = (GralArea9Window)gui;
204  this.cargs = cargs;
205  this.plugUser2Gui = plugUser2Gui;
206  this.console = gui.getMainCmd();  
207  this.guiCfgData = new GralCfgData(cfgConditions);
208  
209  if(plugUser !=null){
210    this.user = plugUser;
211  } else  if(cargs.sPluginClass !=null){
212    try{
213      Class<?> pluginClass = Class.forName(cargs.sPluginClass);
214      Object oUser = pluginClass.newInstance();
215      if(oUser instanceof GralPlugUser_ifc){
216        user = (GralPlugUser_ifc) oUser;
217      } else {
218        console.writeError("user-plugin - fault type: " + cargs.sPluginClass 
219          + "; it should be type of GuiPlugUser_ifc");
220      }
221    } catch (Exception exc){
222      user = null;
223      console.writeError("user-plugin - cannot instantiate: " + cargs.sPluginClass + "; "
224        + exc.getMessage());
225    }
226  }
227  
228  if(cargs.sInspectorOwnPort !=null){
229    inspector = new Inspector(cargs.sInspectorOwnPort);
230    inspector.start(this);
231  } else {
232    inspector = null; //don't use.
233  }
234  
235  _gralMng = cmdGui.gralMng; //cargs.graphicFactory.createPanelMng(null, 120,80, propertiesGui, null, log);
236  panelBuildIfc = _gralMng;
237  guiAccess = _gralMng;
238  userInit();
239  //panelContent = new PanelContent(user);
240  
241  if(user !=null){
242    user.registerMethods(panelBuildIfc);
243  }
244
245  //Register any user action. This should be done before the GUI-configuration is read.
246  panelBuildIfc.registerUserAction("cmdInvoke", cmdInvoke);
247  singleton = this;
248}
249
250
251public static GuiCfg get(){ return singleton; }
252
253public GralPlugUser_ifc getPluggedUser(){ return user; }
254
255
256
257/**Will be overridden... TODO InspcGui
258 * 
259 */
260protected void userInit()
261{
262  if(user !=null){
263    user.init(plugUser2Gui, _gralMng, guiCfgData.dataReplace, this.cargs, console.getLogMessageOutputConsole());
264  }
265  
266  
267}
268
269
270
271/**Code snippet for initializing the GUI area (panel). This snippet will be executed
272 * in the GUI-Thread if the GUI is created. 
273 */
274GralGraphicTimeOrder initGraphic = new GralGraphicTimeOrder("GuiCfg.initGraphic")
275{
276  @Override public void executeOrder()
277  {
278    _gralMng.selectPanel("primaryWindow");
279    _gralMng.setPosition(10, 16,5,20,0,'.');
280    initGuiAreas("A1C1");
281    //gralMng.gralDevice.removeDispatchListener(this);    
282    //countExecution();
283  }
284};
285
286
287/**Code snippet to run the ZBNF-configurator (text controlled GUI)
288 * 
289 */
290GralGraphicTimeOrder configGuiWithZbnf = new GralGraphicTimeOrder("GuiCfg.configGuiWithZbnf")
291{
292  
293  @Override public void executeOrder(){
294    panelBuildIfc.buildCfg(guiCfgData, cargs.fileGuiCfg);
295    _gralMng.initCfgDesigner();
296
297    //gralMng.gralDevice.removeDispatchListener(this);    
298    
299    //countExecution();
300      
301  }
302////
303};
304
305
306
307/**Initializes the areas for the panels and configure the panels.
308 * This routine can be overridden if other areas are need.
309 */
310protected void initGuiAreas(String sMainArea)
311{
312  gui.setFrameAreaBorders(20, 80, 60, 85);
313  gui.setStandardMenusGThread(new File("."), actionFile);
314  initMenuGralDesigner();
315  _gralMng.selectPanel("primaryWindow");
316  mainTabPanel = _gralMng.addTabbedPanel("mainTab", null, 0);
317  gui.addFrameArea(sMainArea, mainTabPanel); //dialogPanel);
318  Appendable out = gui.getOutputBox();
319  mainCmd.setOutputChannels(out, out);
320 
321}
322
323
324protected void initMenuGralDesigner()
325{
326  gui.addMenuBarArea9ItemGThread("GralDesignEnable", "&Design/e&Nable", _gralMng.actionDesignEditField);  
327  gui.addMenuBarArea9ItemGThread("GralDesignEditField", "&Design/Edit &field", _gralMng.actionDesignEditField);  
328  gui.addMenuBarArea9ItemGThread("GralDesignUpdatePanel", "&Design/update &Panel from cfg-file", _gralMng.actionReadPanelCfg);  
329  
330}
331
332
333
334protected void initMain()
335{
336  //create the basic appearance of the GUI. The execution sets dlgAccess:
337  System.out.println("GuiCfg.initMain() - addDispatchOrder initGraphic, wait for execution;");
338  _gralMng.gralDevice.addDispatchOrder(initGraphic);
339  
340  if(!initGraphic.awaitExecution(1, 0)){
341    System.out.println("GuiCfg.initMain() - initGraphic does not respond;");
342    throw new RuntimeException("unexpected fail of execution initGuiDialog");
343  }
344  System.out.println("GuiCfg.initMain() - await initGraphic ok;");
345      
346      
347  /**Creates the dialog elements while reading a config-file. */
348  //
349  //dialogVellMng.re
350  boolean bConfigDone = false;
351  if(cargs.fileGuiCfg != null){
352    //configGuiWithZbnf.ctDone(0);  //counter for done initialized.
353    if(cargs.fileGuiCfg.exists())
354    {
355      File fileSyntax = new File(cargs.sPathZbnf + "/dialog.zbnf");
356      GralCfgZbnf cfgZbnf = new GralCfgZbnf(console, fileSyntax);
357      System.out.println("GuiCfg - start parsing cfg file; " + cargs.fileGuiCfg.getAbsolutePath());
358      String sError = cfgZbnf.configureWithZbnf(cargs.fileGuiCfg, guiCfgData);
359      System.out.println("GuiCfg - finish parsing cfg file; ");
360      if(sError !=null){
361        console.writeError(sError);
362      } else {
363        //dialogZbnfConfigurator = new GuiDialogZbnfControlled((MainCmd_ifc)gui, fileSyntax);
364        //cfgBuilder = new GuiCfgBuilder(guiCfgData, panelBuildIfc, fileGui.getParentFile());
365        //panelBuildIfc.setCfgBuilder(cfgBuilder);
366        _gralMng.gralDevice.addDispatchOrder(configGuiWithZbnf);
367        bConfigDone = configGuiWithZbnf.awaitExecution(1, 10000);
368        if(!bConfigDone){
369          console.writeError("No configuration");
370        }  
371      }
372    } else {
373      console.writeError("Config file not found: " + cargs.fileGuiCfg.getAbsolutePath());
374    }
375  }    
376  try{ Thread.sleep(10);} catch(InterruptedException exc){}
377  //The GUI-dispatch-loop should know the change worker of the panel manager. Connect both:
378  try{ Thread.sleep(10);} catch(InterruptedException exc){}
379  //gets all prepared fields to show informations.
380  //oamShowValues.setFieldsToShow(panelBuildIfc.getShowFields());
381  
382}
383
384protected void stepMain(){}
385
386/**This routine is called on end of main-execution. This default implementation calls 
387 * {@link GralPlugUser_ifc#close()}.
388 * 
389 */
390protected void finishMain(){
391  if(user !=null){ try{ user.close(); } catch(IOException exc ){} }
392}
393
394
395public final void execute()
396{
397  initMain();
398  //guiAccess.insertInfo("msgOfDay", Integer.MAX_VALUE, "Test\tMsg");
399  //msgReceiver.start();
400  while(_gralMng.gralDevice.isRunning())
401  { stepMain();
402    try{ Thread.sleep(100);} 
403    catch (InterruptedException e)
404    { //dialogZbnfConfigurator.terminate();
405    }
406  }
407
408  if(inspector !=null) { 
409    inspector.shutdown(); 
410  }
411  finishMain();
412}
413
414
415
416public void showInfoBox(CharSequence text) {
417  GralMng mng = GralMng.get();
418  mng.showInfo(text);
419}
420
421public void setTextInfoBox(CharSequence text) {
422  GralMng.get().setInfo(text);
423}
424
425public void appendTextInfoBox(CharSequence text) {
426  GralMng.get().addInfo(text, false);
427}
428
429
430
431
432/**Registered as user action.
433 * 
434 */
435private final GralUserAction cmdInvoke = new GralUserAction("cmdInvoke")
436{ 
437  ProcessBuilder processBuilder = new ProcessBuilder("pwd");
438  
439  StringBuilder output = new StringBuilder();
440  StringBuilder error = new StringBuilder();
441   
442  @Override
443  public boolean exec(int cmd, GralWidget_ifc wdgi, Object... values)
444  {
445    if(KeyCode.isControlFunctionMouseUpOrMenu(cmd)){
446      GralWidget wdg = (GralWidget)wdgi;
447      output.setLength(0);
448      error.setLength(0);
449      mainCmd.executeCmdLine(processBuilder, wdg.sCmd, null, Report.info, output, error);
450      stop();
451      guiAccess.addText("output", output);  //adds the result to any widget with name "output"
452      //gui.executeCmdLine(widgetInfos.sCmd, 0, null, null);
453      return true;
454    } else return false;
455  }
456};
457
458
459protected GralUserAction actionFile = new GralUserAction("actionFile")
460{ @Override public boolean userActionGui(int key, GralWidget widg, Object... params)
461  {
462    if(KeyCode.isControlFunctionMouseUpOrMenu(key)){
463      String sError = null;
464      try{
465        Writer writer = new FileWriter(cargs.fileGuiCfg); //"save.cfg");
466        sError = _gralMng.saveCfg(writer);
467        writer.close();
468      } catch(java.io.IOException exc){
469        sError = "Problem open file ";
470      }
471      if(sError !=null){
472        console.writeError(sError);
473      }
474    }
475    return true;
476  }
477};
478
479
480
481/**The command-line-invocation (primary command-line-call). 
482 * @param args Some calling arguments are taken. This is the GUI-configuration especially.   
483 */
484public static void main(String[] args){ 
485  boolean bOk = true;
486  //
487  //Uses the commonly GuiCallingArgs class because here are not extra arguments.
488  GuiCallingArgs cargs = new GuiCallingArgs();
489  
490  //Redirect all outputs from System.out
491  MsgDispatchSystemOutErr.create("D:/DATA/msg/log$yyyy-MMM-dd-HH_mm$.log", 10000, 40000, 10000, 100);
492  //Initializes the GUI till a output window to show information.
493  GralArea9MainCmd cmdGui = new GralArea9MainCmd(cargs, args);  //implements MainCmd, parses calling arguments
494  //Initializes the graphic window and parse the parameter of args (command line parameter).
495  //Parameter errors will be output in the graphic window in its given output area.
496  bOk = cmdGui.parseArgumentsAndInitGraphic("Gui-Cfg", "3A3C");
497  
498  if(bOk){
499    //loads the named class, so it is existent as factory.
500    new InterProcessCommFactorySocket();
501    //
502    //the third parameter may be a plugin, use it in your application if necessary.
503    GuiCfg main = new GuiCfg(cargs, cmdGui, null, null, null);
504    //
505    //starts execution.
506    main.execute();
507  }    
508  cmdGui.exit();
509}
510
511
512
513void stop(){} //debug helper
514
515        
516        
517        
518}