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}