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}