    001package org.vishia.commander;
    002
    003import java.io.File;
    004import java.util.LinkedList;
    005import java.util.List;
    006import java.util.Map;
    007import java.util.TreeMap;
    008
    009import org.vishia.cmd.CmdExecuter;
    010import org.vishia.cmd.CmdStore;
    011import org.vishia.cmd.JZtxtcmdExecuter;
    012import org.vishia.cmd.JZtxtcmdScript;
    013import org.vishia.cmd.PrepareCmd;
    014import org.vishia.fileRemote.FileRemote;
    015import org.vishia.gral.base.GralTable;
    016import org.vishia.gral.base.GralTextBox;
    017import org.vishia.gral.base.GralWidget;
    018import org.vishia.gral.base.GralWindow;
    019import org.vishia.gral.ifc.GralTableLine_ifc;
    020import org.vishia.gral.ifc.GralUserAction;
    021import org.vishia.gral.ifc.GralWidget_ifc;
    022import org.vishia.gral.ifc.GralWindow_ifc;
    023import org.vishia.gral.widget.GralCommandSelector;
    024import org.vishia.jztxtcmd.JZtxtcmd;
    025import org.vishia.mainCmd.MainCmdLogging_ifc;
    026import org.vishia.mainCmd.MainCmd_ifc;
    027import org.vishia.util.DataAccess;
    028import org.vishia.util.KeyCode;
    029
    030public class FcmdExecuter
    031{
    032
    033  /**Version, history and license. This String is visible in the about info.
    034   * <ul>
    035   * <li>2017-01-01 Hartmut uses {@link JZtxtcmdExecuter} and {@link CmdExecuter}. CmdQueue and CmdStore are obsolete.
    036   * <li>2016-08-28 Hartmut chg: The cfg file for jzcmd commands are named cmdjz.cfg anyway, in the directory given with cmdcfg:path/to/cmd.cfg.
    037   * <li>2011-10-00 Hartmut created
    038   * </ul>
    039   *
    040   * <b>Copyright/Copyleft</b>:<br>
    041   * For this source the LGPL Lesser General Public License,
    042   * published by the Free Software Foundation is valid.
    043   * It means:
    044   * <ol>
    045   * <li> You can use this source without any restriction for any desired purpose.
    046   * <li> You can redistribute copies of this source to everybody.
    047   * <li> Every user of this source, also the user of redistribute copies
    048   *    with or without payment, must accept this license for further using.
    049   * <li> But the LPGL is not appropriate for a whole software product,
    050   *    if this source is only a part of them. It means, the user
    051   *    must publish this part of source,
    052   *    but doesn't need to publish the whole source of the own product.
    053   * <li> You can study and modify (improve) this source
    054   *    for own using or for redistribution, but you have to license the
    055   *    modified sources likewise under this LGPL Lesser General Public License.
    056   *    You mustn't delete this Copyright/Copyleft inscription in this source file.
    057   * </ol>
    058   * If you intent to use this source without publishing its usage, you can get
    059   * a second license subscribing a special contract with the author.
    060   *
    061   * @author Hartmut Schorrig = hartmut.schorrig@vishia.de
    062   */
    063  //@SuppressWarnings("hiding")
    064  public static final String version = "2016-12-27";
    065
    066
    067
    068
    069  /**For output messages. */
    070  final MainCmd_ifc console;
    071
    072  private final Fcmd main;
    073
    074
    075
    076  GralWindow_ifc windConfirmExec = new GralWindow("-19..0,-47..0","execWindow", "confirm execute", GralWindow.windConcurrently);
    077
    078 // GralTable<CmdBlock> widgSelectExec = new GralTable<>("0..0,0..0", "execChoice", new int[]{47});
    079
    080  GralTable<JZtxtcmdScript.Subroutine> widgSelectJzExt = new GralTable<>("0..0,0..0", "execChoice", new int[]{47});
    081
    082  /**Store of all possible commands given in the command file. */
    083  //final CmdStore cmdStore = new CmdStore();
    084
    085  final Map<String, List<JZtxtcmdScript.Subroutine>> mapCmdExt = new TreeMap<String, List<JZtxtcmdScript.Subroutine>>();
    086
    087  /**The command queue to execute */
    088
    089  final CmdExecuter cmdExecuter;
    090
    091  /**Table contains some commands, can be selected and executed.
    092   * <ul>
    093   * <li>The table is filled in {@link #readCmdCfgSelectList(CmdStore, File, MainCmdLogging_ifc)}.
    094   * <li>Commands can be either operation system commands or c {@link JZtxtcmdScript.Subroutine} entry point.
    095   * They are stored in the list in user data of type {@link CmdBlock}.
    096   * <li>Execution of a command: see {@link GralCommandSelector#actionExecCmdWithFiles} respectively GralCommandSelector#actionOk(...)
    097   * <li>The arguments of a command are read from {@link CmdStore.CmdBlock#getArguments(org.vishia.cmd.CmdGetFileArgs_ifc)}.
    098   *   That deals with {@link Fcmd#getterFiles} because it is initialized with {@link GralCommandSelector#setGetterFiles(org.vishia.cmd.CmdGetFileArgs_ifc)}
    099   *
    100   * </ul>
    101   */
    102  final GralCommandSelector cmdSelector;
    103
    104
    105
    106  FcmdExecuter(MainCmd_ifc console, Appendable outStatus, Fcmd main)
    107  { this.main = main;
    108    this.console = console;
    109    //this.cmdQueue = new CmdQueue(outStatus);
    110    this.cmdExecuter = new CmdExecuter();
    111    cmdSelector = new GralCommandSelector("cmdSelector", 50, new int[]{0,-10}, 'A', cmdExecuter, main.gui.getOutputBox(), main.getterFileArguments);
    112  }
    113
    114
    115
    116  /**Builds the content of the confirm-execute window. The window is created static. It is shown
    117   * whenever it is used.  */
    118  void buildWindowConfirmExec()
    119  {
    120
    121
    122    windConfirmExec.createImplWidget_Gthread();
    123   // widgSelectExec.specifyActionChange("exec", actionExecCmdAfterChoice, null, GralWidget_ifc.ActionChangeWhen.onEnter);
    124    widgSelectJzExt.specifyActionChange("exec", actionJZextAfterChoice, null, GralWidget_ifc.ActionChangeWhen.onEnter);
    125  }
    126
    127
    128
    129
    130  String readCfgExt(File cfgFileCmdsForExt)
    131  { String error = null;
    132    JZtxtcmdScript script = null;
    133    try{
    134      script = JZtxtcmd.translateAndSetGenCtrl(cfgFileCmdsForExt, null, console);
    135    } catch(Throwable exc){
    136
    137      console.writeError("CmdStore - JZcmdScript;", exc);
    138      error = "CmdStore - JZcmdScript," + exc.getMessage();
    139    }
    140    if(error ==null) {
    141      for(JZtxtcmdScript.JZcmdClass jzclass: script.scriptClass().classes()) { // = e.getValue();
    142        List<JZtxtcmdScript.Subroutine> routines = new LinkedList<JZtxtcmdScript.Subroutine>();
    143        String ext = jzclass.cmpnName;
    144        if(ext.endsWith("__")) {
    145          ext = ext.substring(0, ext.length()-2); }  //especially for cmd__, cannot be a identifier.
    146        mapCmdExt.put(ext, routines);
    147        for(Object classOrSub: jzclass.listClassesAndSubroutines()) {
    148          if(classOrSub instanceof JZtxtcmdScript.Subroutine) {
    149            JZtxtcmdScript.Subroutine subRoutine = (JZtxtcmdScript.Subroutine) classOrSub;
    150            if(!subRoutine.name.startsWith("_")) { //ignore internal subroutines!
    151              routines.add(subRoutine);
    152            }
    153          }
    154        }
    155      }
    156    }
    157    return error;
    158  }
    159
    160
    161  public String readCmdCfgSelectList(JZtxtcmdScript.AddSub2List dst, File cfgFile, MainCmdLogging_ifc log)
    162  { File cmdCfgJbat = new File(cfgFile.getParentFile(), "cmdjz.cfg");
    163    return JZtxtcmd.readJZcmdCfg(dst, cmdCfgJbat, log, cmdExecuter);
    164  }
    165
    166
    167  /**
    168   * Action to set the working directory for the next command invocation. The
    169   * working directory is the directory in the focused file tab.
    170   *
    171   */
    172  GralUserAction actionSetCmdWorkingDir = new GralUserAction("actionSetCmdWorkingDir")
    173  {
    174    @Override public boolean userActionGui(int key, GralWidget infos, Object... params)
    175    {
    176      //GralWidget widgdFocus = main._gralMng.getWidgetInFocus();
    177      //FileSelector fileSel = idxFileSelector.get(widgdFocus.name);
    178      if (main.currentDir() != null) { // is a FileSelector focused yet?
    179        // if(widgdFocus.name.startsWith("file")){
    180        // int ixFilePanel = widgdFocus.name.charAt(4) - '0';
    181        // assert(ixFilePanel >=0 && ixFilePanel < fileSelector.length); //only
    182        // such names are registered.
    183        // FileSelector fileSel = fileSelector[ixFilePanel];
    184        //FileRemote file = fileSel.getSelectedFile();
    185        //cmdQueue.setWorkingDir(main.currentDir());
    186        cmdExecuter.setCurrentDir(main.currentDir());
    187      }
    188      return true;
    189    }
    190
    191  };
    192
    193
    194
    195
    196  /**
    197   * Action to set the command list from file. It is called from menu.
    198   *
    199   */
    200  GralUserAction actionSetCmdCfg = new GralUserAction("actionSetCmdCfg") {
    201    @Override public boolean userActionGui(int key, GralWidget infos, Object... params){
    202      if(KeyCode.isControlFunctionMouseUpOrMenu(key)){
    203        if (main.currentFile() != null) {
    204          cmdSelector.clear();
    205          String sError = readCmdCfgSelectList(cmdSelector.addJZsub2SelectTable, main.currentFile(), main.console);
    206          if(sError !=null) {
    207            System.err.println("readCmdCfg; from file " + main.cargs.fileCfgButtonCmds.getAbsolutePath()+ "; error: " + sError);
    208          }
    209        }
    210      }
    211      return true;
    212    }
    213
    214  };
    215
    216
    217
    218  /**Action to set the command list from actual file. It is called from menu.
    219   */
    220  GralUserAction actionSetCmdCfgAct = new GralUserAction("actionSetCmdCfgAct") {
    221    @Override public boolean userActionGui(int key, GralWidget infos, Object... params){
    222      if(KeyCode.isControlFunctionMouseUpOrMenu(key)){
    223        cmdSelector.clear();
    224        String sError = readCmdCfgSelectList(cmdSelector.addJZsub2SelectTable, main.cargs.fileCfgCmds, console);
    225        if(sError !=null){
    226          System.err.println("readCmdCfg; from file " + main.cargs.fileCfgButtonCmds.getAbsolutePath()+ "; error: " + sError);
    227        }
    228      }
    229      return true;
    230    }
    231
    232  };
    233
    234
    235  /**Action to open an editor for the command list from actual file. It is called from menu.
    236   */
    237  GralUserAction actionEditCmdCfgAct = new GralUserAction("actionEditCmdCfgAct") {
    238    @Override public boolean userActionGui(int key, GralWidget infos, Object... params){
    239      if(KeyCode.isControlFunctionMouseUpOrMenu(key)){
    240        main.openExtEditor(main.cargs.fileCfgCmds);
    241      }
    242      return true;
    243    }
    244
    245  };
    246
    247
    248
    249
    250  private void executeFileByExtension(File file){
    251    String ext;
    252    if(file !=null){
    253      String name = file.getName();
    254      int posDot = name.lastIndexOf('.');
    255      if(posDot >= 0){
    256        ext = name.substring(posDot+1);
    257      } else if(file.canExecute()){
    258        ext = ">";
    259      } else {
    260        ext = "???";
    261      }
    262      List<JZtxtcmdScript.Subroutine> listSub = mapCmdExt.get(ext.toLowerCase());
    263      if(listSub !=null){
    264        widgSelectJzExt.clearTable();
    265        GralTable<JZtxtcmdScript.Subroutine>.TableLineData firstLine = null;
    266        for(JZtxtcmdScript.Subroutine jzsub: listSub) {
    267          GralTable<JZtxtcmdScript.Subroutine>.TableLineData line = widgSelectJzExt.insertLine(jzsub.name, -1, null, jzsub);
    268          if(firstLine == null) { firstLine = line; }
    269          line.setCellText(jzsub.name, 0);
    270
    271        }
    272        widgSelectJzExt.setCurrentLine(firstLine, 0, 0); //set the first line to position 0.
    273        //windConfirmExec.setWindowVisible(true);
    274        windConfirmExec.setFocus();
    275
    276      }
    277
    278
    279
    280
    281      /*
    282      ExtCmd extensionCmd = extCmds.get(ext);
    283      if(extensionCmd !=null){
    284        widgSelectExec.clearTable();
    285        GralTable<CmdBlock>.TableLineData firstLine = null;
    286        for(CmdBlock block: extensionCmd.listCmd){
    287          GralTable<CmdBlock>.TableLineData line = widgSelectExec.insertLine(block.name, -1, null, block);
    288          if(firstLine == null) { firstLine = line; }
    289          line.setCellText(block.title, 0);
    290        }
    291        widgSelectExec.setCurrentLine(firstLine, 0, 0); //set the first line to position 0.
    292        //windConfirmExec.setWindowVisible(true);
    293        windConfirmExec.setFocus();
    294
    295      } else {
    296        console.writeError("no association found for extension ." + ext);
    297      }
    298      */
    299    } else{ System.err.println("FcmdExecuter.executeFileByExtension - no file selected;"); }
    300  }
    301
    302
    303
    304  GralUserAction actionExecuteFileByExtension = new GralUserAction("actionExecuteFileByExtension")
    305  { @Override public boolean userActionGui(int key, GralWidget widgd, Object... params)
    306    { if(KeyCode.isControlFunctionMouseUpOrMenu(key)){
    307        File file = main.currentFile();
    308        executeFileByExtension(file);
    309        return true;
    310      } else return false;
    311  } };
    312
    313  /**This action is associated to any {@link FcmdFileCard} as action on enter file.
    314   * The file is given as parameter then.
    315   */
    316  GralUserAction actionOnEnterFile = new GralUserAction("actionOnEnterFile")
    317  { @Override public boolean userActionGui(int key, GralWidget widgd, Object... params)
    318    { FileRemote file = (FileRemote)params[0];
    319      executeFileByExtension(file);
    320      return true;
    321    }
    322  };
    323
    324
    325
    326
    327
    328
    329  GralUserAction actionJZextAfterChoice = new GralUserAction("actionExecCmdAfterChoice")
    330  { @Override public boolean exec(int key, GralWidget_ifc widgd, Object... params)
    331  {
    332    if(key == KeyCode.enter || key == KeyCode.mouse1Up || key == KeyCode.mouse1Double){
    333      if(params.length > 0 && params[0] instanceof GralTableLine_ifc){
    334        @SuppressWarnings("unchecked")
    335        GralTableLine_ifc<JZtxtcmdScript.Subroutine> line = (GralTableLine_ifc<JZtxtcmdScript.Subroutine>)params[0];
    336        JZtxtcmdScript.Subroutine jzsub = line.getUserData();
    337        if(jzsub !=null){
    338          //PrepareCmd cmdp = cmd.getCmds().get(0);
    339          File[] files = main.getLastSelectedFiles(true, 1);
    340          List<DataAccess.Variable<Object>> args = new LinkedList<DataAccess.Variable<Object>>();
    341          DataAccess.Variable<Object> var = new DataAccess.Variable<Object>('F', "file1", files[0], true);
    342          args.add(var);
    343          cmdExecuter.addCmd(jzsub, args, main.gui.getOutputBox(), main.currentDir());
    344        } else {
    345          console.writeError("FcmdExecuter - cmd not found; ");
    346        }
    347      }
    348      windConfirmExec.setWindowVisible(false);
    349      return true;
    350    } else return false;
    351  }
    352};
    353
    354
    355
    356
    357
    358
    359  GralUserAction actionCmdFromOutputBox = new GralUserAction("actionCmdFromOutputBox")
    360  { @Override public boolean userActionGui(int key, GralWidget widgd, Object... params)
    361    { final char kindOfExecution = checkKeyOfExecution(key);
    362      if(kindOfExecution !=0){
    363        GralTextBox widgg = (GralTextBox)widgd;
    364        String text = widgg.getText();
    365        int cursorPos = widgg.getCursorPos();
    366        int start1 = text.lastIndexOf("\n>", cursorPos);
    367        int start2 = text.lastIndexOf("\n&", cursorPos);
    368        int start = start2 > start1 ? start2+1 : start1+1;  //note: on -1 it is 0, start of box
    369        String sCmd = text.substring(start+1, cursorPos);
    370        final File currentDir;
    371        if(main.currentDir() !=null){
    372          //note: executes it local:
    373          currentDir = main.currentDir();
    374        } else {
    375          currentDir = null;  //use any standard
    376        }
    377        final File[] files;
    378        if(sCmd.indexOf("<*")>=0){ //a file may need
    379          files= new File[3];
    380          int ix = -1;
    381          for(File fileName: main.selectedFiles123){
    382            if(fileName !=null){
    383              if(fileName !=null ){ files[++ix] = fileName; }
    384             // else { files[++ix] = new File(fileName.getParent() + "/" + fileName.getName()); }
    385            }
    386          }
    387        } else { files = null; }
    388        //cmdQueue.addCmd(sCmd, files, currentDir, kindOfExecution);
    389        cmdExecuter.addCmd(sCmd, null, main.gui.getOutputBox(), currentDir, null);
    390        return true;
    391      } else return false;
    392    }
    393  };
    394
    395
    396  /**User action to abort a running command.
    397   *
    398   */
    399  GralUserAction actionCmdAbort = new GralUserAction("actionCmdAbort")
    400  { @Override public boolean userActionGui(int key, GralWidget widgd, Object... params)
    401    { //cmdQueue.abortCmd();
    402      cmdExecuter.abortAllCmds();
    403      return true;
    404    }
    405  };
    406
    407
    408
    409
    410
    411
    412  private char checkKeyOfExecution(int key){
    413    final char kindOfExecution;
    414    if(key == main.keyActions.keyExecuteInJcmd) kindOfExecution = PrepareCmd.executeLocalPipes;
    415    else if(key == main.keyActions.keyExecuteStartProcess) kindOfExecution = PrepareCmd.executeStartProcess;
    416    else if(key == main.keyActions.keyExecuteInShell) kindOfExecution = PrepareCmd.executeInShellClose;
    417    else if(key == main.keyActions.keyExecuteInShellOpened) kindOfExecution = PrepareCmd.executeInShellOpened;
    418    else if(key == main.keyActions.keyExecuteAsJavaClass) kindOfExecution = PrepareCmd.executeJavaMain;
    419    else kindOfExecution = 0;
    420    return kindOfExecution;
    421  }
    422
    423
    424
    425
    426
    427
    428}