    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}