001package org.vishia.commander;
002
003import java.io.Closeable;
004import java.io.File;
005import java.io.IOException;
006import java.util.ArrayList;
007import java.util.Iterator;
008import java.util.LinkedList;
009import java.util.List;
010import java.util.Map;
011import java.util.TreeMap;
012
013import org.vishia.cmd.CmdGetterArguments;
014import org.vishia.cmd.JZtxtcmdScript;
015import org.vishia.cmd.JZtxtcmdScript.JZcmdClass;
016import org.vishia.cmd.JZtxtcmdScript.Subroutine;
017import org.vishia.commander.target.FcmdtTarget;
018import org.vishia.commander.target.FcmdtTarget_ifc;
019import org.vishia.communication.InterProcessCommFactorySocket;
020import org.vishia.fileLocalAccessor.FileAccessorLocalJava7;
021import org.vishia.fileRemote.FileCluster;
022import org.vishia.fileRemote.FileRemote;
023import org.vishia.gral.area9.GuiCallingArgs;
024import org.vishia.gral.area9.GuiCfg;
025import org.vishia.gral.area9.GralArea9MainCmd;
026import org.vishia.gral.base.GralMenu;
027import org.vishia.gral.base.GralMng;
028import org.vishia.gral.base.GralPanelContent;
029import org.vishia.gral.base.GralWidget;
030import org.vishia.gral.ifc.GralMngBuild_ifc;
031import org.vishia.gral.ifc.GralUserAction;
032import org.vishia.gral.ifc.GralWidget_ifc;
033import org.vishia.gral.widget.GralFileSelector;
034import org.vishia.jztxtcmd.JZtxtcmd;
035import org.vishia.msgDispatch.MsgRedirectConsole;
036import org.vishia.util.DataAccess;
037import org.vishia.util.Debugutil;
038import org.vishia.util.KeyCode;
039
040/**This class is the main class of the-File-commander.
041 * @author Hartmut Schorrig
042 *
043 */
044public class Fcmd extends GuiCfg
045{
046
047
048  /**Version, history and license. This String is visible in the about info.
049   * <ul>
050   * <li>2017-08-27 {@link FcmdFavorPathSelector#actionDeselectDirtree} now removes all FileRemote instances of children
051   *   because a selection is not necessary furthermore. This is a 'refresh'. But the 'refresh' (F5, ctrl-R) should not change selection,
052   *   it must not delete this children-FileRemote. Only deselection is the key action for that.
053   * <li>2016-08-28 see {@link FcmdExecuter#sVersion}, {@link FcmdSettings#sVersion}
054   * <li>2015-07-18 Hartmut chg: Now the output of script errors while executing the JZcmd cmd script is visible
055   *   in the output window.  
056   * <li>2015-07-12 Hartmut new: Many fixes in the base classes for functionality. See all commit messages of the component.
057   * <li>2014-12-26 Hartmut new: {@link #refreshFilePanel(FileRemote)} can be called in any callback thread. 
058   * <li>2011-2013 some changes, see source files.
059   * <li>2011-10-00 Hartmut created
060   * </ul>
061   * 
062   * <b>Copyright/Copyleft</b>:<br>
063   * For this source the LGPL Lesser General Public License,
064   * published by the Free Software Foundation is valid.
065   * It means:
066   * <ol>
067   * <li> You can use this source without any restriction for any desired purpose.
068   * <li> You can redistribute copies of this source to everybody.
069   * <li> Every user of this source, also the user of redistribute copies
070   *    with or without payment, must accept this license for further using.
071   * <li> But the LPGL is not appropriate for a whole software product,
072   *    if this source is only a part of them. It means, the user
073   *    must publish this part of source,
074   *    but doesn't need to publish the whole source of the own product.
075   * <li> You can study and modify (improve) this source
076   *    for own using or for redistribution, but you have to license the
077   *    modified sources likewise under this LGPL Lesser General Public License.
078   *    You mustn't delete this Copyright/Copyleft inscription in this source file.
079   * </ol>
080   * If you intent to use this source without publishing its usage, you can get
081   * a second license subscribing a special contract with the author. 
082   * 
083   * @author Hartmut Schorrig = hartmut.schorrig@vishia.de
084   */
085  //@SuppressWarnings("hiding")
086  public static final String version = "2018-11-02";
087
088  
089  static class CallingArgs extends GuiCallingArgs
090  {
091    File fileCfgCmds;
092
093    File fileCmdsForExt;
094
095    File fileCfgButtonCmds;
096
097    File fileSelectTabPaths;
098    
099    File dirCfg;
100
101  }
102
103  /**
104   * This action is invoked for all general key pressed actions. It tests the
105   * key and switches to the concretely action for the pressed key. General keys
106   * are [F1] for help, [F4] for edit etc.
107   */
108  GralUserAction actionTest = new GralUserAction("actionTest")
109  {
110    @Override public boolean userActionGui(int key, GralWidget infos, Object... params)
111    {
112      GralMng.get().addInfo("Test\n", true);
113      return true;
114    }
115  };
116
117  /**
118   * This action is invoked for all general key pressed actions. It tests the
119   * key and switches to the concretely action for the pressed key. General keys
120   * are [F1] for help, [F4] for edit etc.
121   */
122  GralUserAction actionKey = new GralUserAction("actionKey")
123  {
124    @Override
125    public boolean userActionGui(String sIntension, GralWidget infos,
126        Object... params)
127    {
128      Debugutil.stop();
129      return true;
130    }
131  };
132
133  /**Key alt-F1 to select a directory/cmd list in a list of directories for the
134   * left panel. The original Norton Commander approach is to select a drive
135   * letter for windows. Selection of paths instead are adequate.
136   */
137  GralUserAction actionReadMsgConfig = new GralUserAction("actionReadMsgConfig")
138  {
139    @Override public boolean exec(int key, GralWidget_ifc widgi, Object... params){ 
140      if(KeyCode.isControlFunctionMouseUpOrMenu(key)){  //supress both mouse up and down reaction
141        if(cargs.msgConfig !=null && cargs.msgConfig.exists()){
142          msgDisp.readConfig(cargs.msgConfig);
143        }
144        return true;
145      } else return false;
146    }
147  };
148
149  /**Key alt-F1 to select a directory/cmd list in a list of directories for the
150   * left panel. The original Norton Commander approach is to select a drive
151   * letter for windows. Selection of paths instead are adequate.
152   */
153  GralUserAction selectCardThemesLeft = new GralUserAction("selectCardThemesLeft")
154  {
155    @Override public boolean userActionGui(int key, GralWidget infos, Object... params){ 
156      if(KeyCode.isControlFunctionMouseUpOrMenu(key)){  //supress both mouse up and down reaction
157        favorPathSelector.panelLeft.cardFavorThemes.wdgdTable.setFocus();
158        return true;
159      } else return false;
160    }
161  };
162
163  /**Key alt-F2 to select a directory/cmd list in a list of directories for the
164   * middle panel.
165   */
166  GralUserAction selectCardThemesMiddle = new GralUserAction("selectCardThemesMiddle")
167  {
168    @Override public boolean userActionGui(int key, GralWidget infos, Object... params){ 
169      if(KeyCode.isControlFunctionMouseUpOrMenu(key)){  //supress both mouse up and down reaction
170        favorPathSelector.panelMid.cardFavorThemes.wdgdTable.setFocus();
171        return true;
172      } else return false;
173    }
174  };
175
176  /**Key alt-F3 to select a directory/cmd list in a list of directories for the
177   * right panel.
178   */
179  GralUserAction selectCardThemesRight = new GralUserAction("selectCardThemesRight")
180  {
181    @Override public boolean userActionGui(int key, GralWidget infos, Object... params){ 
182      if(KeyCode.isControlFunctionMouseUpOrMenu(key)){
183        favorPathSelector.panelRight.cardFavorThemes.wdgdTable.setFocus();
184        return true;
185      } else return false;
186    }
187  };
188
189  /**Key sh-F1 to select a directory/cmd list in a list of directories for the
190   * right panel.
191   */
192  GralUserAction selectFileCardLeft = new GralUserAction("selectFileCardLeft")
193  {
194    @Override public boolean userActionGui(int key, GralWidget infos, Object... params){ 
195      if(KeyCode.isControlFunctionMouseUpOrMenu(key)){
196        favorPathSelector.panelLeft.setFocus();
197        return true;
198      } else return false;
199    }
200  };
201
202  /**Key sh-F2 to select a directory/cmd list in a list of directories for the
203   * right panel.
204   */
205  GralUserAction selectFileCardMid = new GralUserAction("selectFileCardMid")
206  {
207    @Override public boolean userActionGui(int key, GralWidget infos, Object... params){ 
208      if(KeyCode.isControlFunctionMouseUpOrMenu(key)){
209        favorPathSelector.panelMid.setFocus();
210        return true;
211      } else return false;
212    }
213  };
214
215  /**Key sh-F3 to select a directory/cmd list in a list of directories for the
216   * right panel.
217   */
218  GralUserAction selectFileCardRight = new GralUserAction("selectFileCardRight")
219  {
220    @Override public boolean userActionGui(int key, GralWidget infos, Object... params){ 
221      if(KeyCode.isControlFunctionMouseUpOrMenu(key)){
222        favorPathSelector.panelRight.setFocus();
223        return true;
224      } else return false;
225    }
226  };
227
228  /**Key sh-F3 to select a directory/cmd list in a list of directories for the
229   * right panel.
230   */
231  GralUserAction selectFileCardOther = new GralUserAction("selectFileCardOther")
232  {
233    @Override public boolean userActionGui(int key, GralWidget infos, Object... params){ 
234      if(KeyCode.isControlFunctionMouseUpOrMenu(key)){
235        if(lastFilePanels.size() >=2){
236          FcmdLeftMidRightPanel otherPanel = lastFilePanels.get(1);
237          otherPanel.setFocus();
238        }
239        return true;
240      } else return false;
241    }
242  };
243  
244
245  GralUserAction actionFocusPanelToLeft = new GralUserAction("FcmdLeftMidRightPanel.actionRightCard"){
246    @Override public boolean userActionGui(int actionCode, GralWidget widgd, Object... params){ 
247      FcmdLeftMidRightPanel actPanel = lastFilePanels.get(0);
248      if(actPanel.cc == 'm'){ favorPathSelector.panelLeft.setFocus(); }
249      else if(actPanel.cc == 'r'){ favorPathSelector.panelMid.setFocus(); }
250      return true; 
251    }
252  };
253  
254
255  GralUserAction actionFocusPanelToRight = new GralUserAction("FcmdLeftMidRightPanel.actionRightCard"){
256    @Override public boolean userActionGui(int actionCode, GralWidget widgd, Object... params){ 
257      FcmdLeftMidRightPanel actPanel = lastFilePanels.get(0);
258      if(actPanel.cc == 'm'){ favorPathSelector.panelRight.setFocus(); }
259      else if(actPanel.cc == 'l'){ favorPathSelector.panelMid.setFocus(); }
260      return true; 
261    }
262  };
263  
264
265  GralUserAction actionFocusFileCard = new GralUserAction("FcmdLeftMidRightPanel.actionFileCard"){
266    @Override public boolean userActionGui(int actionCode, GralWidget widgd, Object... params){ 
267      return true; 
268    }
269  };
270  
271
272  GralUserAction actionFocusThemeCard = new GralUserAction("FcmdLeftMidRightPanel.actionThemeCard"){
273    @Override public boolean userActionGui(int actionCode, GralWidget widgd, Object... params){ 
274      return true; 
275    }
276  };
277  
278
279  
280  
281
282  /**Action to focus the cmd card.
283   */
284  GralUserAction actionFocusCmdCard = new GralUserAction("actionFocusCmdCard")
285  {
286    @Override public boolean userActionGui(int key, GralWidget infos, Object... params){ 
287      if(KeyCode.isControlFunctionMouseUpOrMenu(key)){  //supress both mouse up and down reaction
288      executer.cmdSelector.wdgdTable.setFocus();
289      return true;
290      } else return false;
291    }
292  };
293  
294  
295  
296  GralUserAction actionFocusCardInPanelToLeft = new GralUserAction("FcmdLeftMidRightPanel.actionLeftCard"){
297    @Override public boolean userActionGui(int actionCode, GralWidget widgd, Object... params){ 
298      lastFilePanels.get(0).focusLeftCard();
299      return true; 
300    }
301  };
302  
303  
304  GralUserAction actionFocusCardInPanelToRight = new GralUserAction("FcmdLeftMidRightPanel.actionRightCard"){
305    @Override public boolean userActionGui(int actionCode, GralWidget widgd, Object... params){ 
306      //sets focus to right
307      lastFilePanels.get(0).focusRightCard();
308      return true; 
309    }
310  };
311  
312
313  
314  
315  void openExtEditor(File file){
316    JZtxtcmdScript.Subroutine jzsub = buttonCmds.get("edit");
317    if( jzsub == null ) {
318      mainCmd.writeError("internal problem - don't find 'edit' command. ");
319    } else {
320      String sMsg = "GralCommandSelector - put cmd;" + jzsub.toString();
321      System.out.println(sMsg);
322      List<DataAccess.Variable<Object>> args = new LinkedList< DataAccess.Variable<Object>>();
323      DataAccess.Variable<Object> var = new DataAccess.Variable<>('O', "file1", file, true);
324      args.add(var);
325      //executer.cmdQueue.addCmd(jzsub, args, file.getParentFile()); // to execute.
326      executer.cmdExecuter.addCmd(jzsub, args, Fcmd.this.gui.getOutputBox(), file.getParentFile());
327    }
328    
329  }
330  
331  
332
333  /**
334   * Key F4 for edit command. Its like Norton Commander.
335   */
336  GralUserAction actionEdit = new GralUserAction("actionEdit")
337  {
338    @Override public boolean exec(int key, GralWidget_ifc wdg, Object... params) {
339      if(KeyCode.isControlFunctionMouseUpOrMenu(key)){  //supress both mouse up and down reaction
340        JZtxtcmdScript.Subroutine jzsub = buttonCmds.get("edit");
341        if (jzsub == null) {
342          mainCmd.writeError("internal problem - don't find 'edit' command. ");
343        } else {
344        
345          String sMsg = "GralCommandSelector - put cmd;" + jzsub.toString();
346          System.out.println(sMsg);
347          List<DataAccess.Variable<Object>> args = main.getterFileArguments.getArguments(jzsub);
348          //executer.cmdQueue.addCmd(jzsub, args, Fcmd.this.currentFileCard.currentDir());  //to execute.
349          executer.cmdExecuter.addCmd(jzsub, args, Fcmd.this.gui.getOutputBox(), Fcmd.this.currentFileCard.currentDir());
350        }
351      }
352      return true;
353    }
354  };
355
356  
357  
358  /**This callback will be invoked in the drag event while the mouse is released in the destination. 
359   */
360  GralUserAction actionDragFileFromStatusLine = new GralUserAction("actionDragFileFromStatusLine"){
361    @Override public boolean userActionGui(int key, GralWidget widgd, Object... params) {
362      if(key == KeyCode.dragFiles){
363        String path = widgd.getValue();
364        String[][] sFiles = (String[][])params[0];  //sFiles has lenght 1
365        sFiles[0] = new String[1]; 
366        sFiles[0][0] = path;
367        Debugutil.stop();
368      }
369      return true;
370    }
371  };
372  
373  /**This implementation resolves the arguments for invoked commands with the capabilities of the Fcmd.
374   * Especially the following argument strings are supported:
375   * <ul>
376   * <li>
377   * </ul>
378   * This instance is used only locally (private). It is designated as protected for documentation.
379   */
380  protected CmdGetterArguments getterFileArguments = new CmdGetterArguments()
381  {
382    @Override public List<DataAccess.Variable<Object>> getArguments(JZtxtcmdScript.Subroutine subRoutine) {
383      FileRemote[] selFiles = getLastSelectedFiles(true, 1);  //The selected 3 files, maybe in one card too.
384      List<DataAccess.Variable<Object>> args = new LinkedList<DataAccess.Variable<Object>>();
385      if(subRoutine !=null) {
386        if(subRoutine.formalArgs !=null) {
387          for(JZtxtcmdScript.DefVariable arg :subRoutine.formalArgs){
388            String name1 = arg.getVariableIdent();
389            if(name1.equals("file1")){ args.add(new DataAccess.Variable<Object>('O', "file1", selFiles[0], true)); }
390            else if(name1.equals("file2")){ args.add(new DataAccess.Variable<Object>('O', "file2", selFiles[1], true)); }
391            else if(name1.equals("file3")){ args.add(new DataAccess.Variable<Object>('O', "file3", selFiles[2], true)); }
392            else if(name1.equals("dir1")){ args.add(new DataAccess.Variable<Object>('O', "dir1", selFiles[0] ==null ? null : selFiles[0].getParentFile(), true)); }
393            else if(name1.equals("dir2")){ 
394              FileRemote dir = null;
395              if(lastFilePanels.size() >=2){ 
396                FcmdFileCard fileCard = lastFilePanels.get(1).actFileCard;
397                if(fileCard !=null){ dir = fileCard.getCurrentDir(); }
398              }
399              args.add(new DataAccess.Variable<Object>('O', "dir2", dir, true)); 
400            } 
401            else if(name1.equals("dir3")){ 
402              FileRemote dir = null;
403              if(lastFilePanels.size() >=3){ 
404                FcmdFileCard fileCard = lastFilePanels.get(2).actFileCard;
405                if(fileCard !=null){ dir = fileCard.getCurrentDir(); }
406              }
407              args.add(new DataAccess.Variable<Object>('O', "dir3", dir, true)); 
408            } 
409            else if(name1.equals("listfiles1")) { 
410              List<FileRemote> files = null;
411              if(lastFilePanels.size() >=1){
412                FcmdLeftMidRightPanel filePanel = lastFilePanels.get(0);
413                FcmdFileCard fileCard = filePanel.actFileCard;
414                if(fileCard !=null){
415                  files = fileCard.getSelectedFiles(true, 1);   
416                }
417              }
418              args.add(new DataAccess.Variable<Object>('L', "listfiles1", files, true)); 
419            }
420            else if(name1.equals("listfiles2")) { 
421              List<FileRemote> files = null;
422              if(lastFilePanels.size() >=2){ 
423                FcmdFileCard fileCard = lastFilePanels.get(1).actFileCard;
424                if(fileCard !=null){ files = fileCard.getSelectedFiles(true, 1); }
425              }
426              args.add(new DataAccess.Variable<Object>('L', "listfiles2", files, true)); 
427            }
428            else {
429              System.err.println("failded argument name: " + name1);
430            }
431          }
432        }
433      } else {
434      
435      }
436      return args;
437    }
438    
439    @Override public final File getCurrDir(){ return Fcmd.this.currentFileCard.currentDir(); }
440  };
441
442
443
444  //MsgDispatchSystemOutErr msgDisp;
445  
446  /**Set the singleton reference before other instances are initialized which uses main. */
447  { Fcmd.main = this;
448  }
449  
450  
451  public JZtxtcmdScript.AddSub2List addButtonCmd = new JZtxtcmdScript.AddSub2List() {
452
453
454    @Override public void clear() { buttonCmds.clear(); }
455
456    @Override public void add2List(JZcmdClass jzclass, int level){} //not used
457  
458    @Override public void add2List(Subroutine jzsub, int level)
459    {
460      buttonCmds.put(jzsub.name, jzsub);
461    }
462    
463  };
464  
465
466  
467  final CallingArgs cargs;
468  
469  final MsgRedirectConsole msgDisp;
470  
471  final FileCluster fileCluster = FileRemote.clusterOfApplication;
472
473  // GralTabbedPanel tabbedPanelsLeft, tabbedPanelsMid, tabbedPanelsRight;
474
475  final FcmdWindowMng windMng = new FcmdWindowMng(this);
476
477  final FcmdButtons fButtons = new FcmdButtons(this);
478  
479  final FcmdStatusLine statusLine = new FcmdStatusLine(this);
480  
481  final String nameTextFieldInfo = "file-info";
482  
483  final String nameTextFieldFilePath = "file-path";
484  
485  final String nameTextFieldRunInfo = "run-info";
486  
487  GralPanelContent panelButtons;
488
489  
490  final FcmdFavorPathSelector favorPathSelector = new FcmdFavorPathSelector(mainCmd, this);
491
492  final FcmdExecuter executer = new FcmdExecuter(mainCmd, gui.getOutputBox(), this);
493
494  final FcmdSettings settings = new FcmdSettings(this);
495  
496  final FcmdStatus status = new FcmdStatus(this);
497  
498  final FcmdFileProps filePropsCmd = new FcmdFileProps(this);
499  
500  final FcmdView viewCmd = new FcmdView(this);
501  
502  final FcmdEdit editWind = new FcmdEdit(this);
503  
504  final FcmdCopyCmprDel copyCmd = new FcmdCopyCmprDel(this, FcmdCopyCmprDel.Ecmd.copy);
505  
506  final FcmdCopyCmprDel delCmd = new FcmdCopyCmprDel(this, FcmdCopyCmprDel.Ecmd.delete);
507  
508  final FcmdCopyCmprDel compareCmd = new FcmdCopyCmprDel(this, FcmdCopyCmprDel.Ecmd.compare);
509  
510  final FcmdMkDirFile mkCmd = new FcmdMkDirFile(this);
511
512  final FcmdDelete deleteCmd = new FcmdDelete(this);
513
514  final FcmdFilesCp filesCp = new FcmdFilesCp(this);
515
516  final FcmdKeyActions keyActions = new FcmdKeyActions(this);
517
518  /**
519   * Note: this should be the last aggregate of Fcmd because it uses some other ones. */
520  final FcmdIdents idents = new FcmdIdents(this);
521  
522  
523  /**The current directory of the last selected file. */
524  //FileRemote currentFile;
525
526  /**The last selected files of the three panels, [0] for left .. [2] for right. */
527  final File[] selectedFiles123 = new File[3];
528  
529  
530  /**The last selected file panels in its order of selection.
531   * This list contains max 3 entries. 
532   * To get the last selected files: The panel knows the last used file card there. 
533   */
534  List<FcmdLeftMidRightPanel> lastFilePanels = new LinkedList<FcmdLeftMidRightPanel>();
535  
536  /**The last used favor card or its last used file card.
537   * It is used for delete tab. */
538  FcmdFavorCard lastFavorCard;
539  
540  FcmdFileCard currentFileCard;
541  
542
543  final Map<String, GralFileSelector> idxFileSelector = new TreeMap<String, GralFileSelector>();
544
545  
546  FcmdtTarget_ifc target;
547  
548  
549  /**
550   * The commands which are used for some buttons or menu items from the
551   * JavaCommander itself.
552   */
553  final Map<String, JZtxtcmdScript.Subroutine> buttonCmds;
554
555  
556  final List<Closeable> threadsToClose = new LinkedList<Closeable>();
557  
558  /**Static reference for the main instance to access from any class in the package.
559   * This static instance is set firstly in constructor, all other constructors in this package
560   * can be used it therefore. Use {@link #main()}*/
561  private static Fcmd main;
562  
563  
564  public Fcmd(CallingArgs cargs, GralArea9MainCmd cmdgui)
565  {
566    super(cargs, cmdgui, null, null, null);
567    this.cargs = cargs;
568    //redirect all outputs to System.out, System.err and MainCmd to System.out and System.err with timestamp.
569    msgDisp = new MsgRedirectConsole(cmdgui, 0, null);
570    msgDisp.setIdThreadForMsgDispatching(Thread.currentThread().getId());
571    //msgDisp.msgDispatcher.setOutputRoutine(4, "MainLogFile", true, true, cmdgui.getLogMessageOutputFile());
572    //msgDisp.msgDispatcher.setOutputRange(0, 100000, 4, MsgDispatcher.mAdd, 0);
573    actionReadMsgConfig.exec(KeyCode.menuEntered, null);
574    
575    target = new FcmdtTarget();  //create the target itself, one process TODO experience with remote target.
576    buttonCmds = new TreeMap<String, JZtxtcmdScript.Subroutine>();
577    //executer.cmdQueue.setOutput(gui.getOutputBox(), null);
578  }
579
580  
581  /**Access the static instance of Fcmd.
582   * This static instance is set firstly in constructor, all other constructors in this package
583   * can be used it therefore.
584   */
585  static Fcmd main(){ return main; }
586  
587  
588  /**
589   * Initializes the areas for the panels and configure the panels. Note that
590   * the window is initialized with an output area already. This is used for
591   * output messages if problems occurs while build the rest of the GUI.
592   */
593  @Override
594  protected void initGuiAreas(String sAreaMainPanel)
595  {
596    //panelBuildIfc.registerUserAction("KeyAction",
597      //  keyActions.commanderKeyActions); // all key actions, registered central
598
599    gui.setFrameAreaBorders(30, 65, 70, 85); // x1, x2, y1, y2
600    //gui.setStandardMenusGThread(new File("."), actionFile);
601    //gui.addMenuItemGThread("menuBarFavorsLeft", idents.menuBarNavigationLeft, selectCardThemesLeft);
602    //gui.addMenuItemGThread("menuBarFavorsMiddle", idents.menuBarNavigationMiddle, selectCardThemesMiddle);
603    //gui.addMenuItemGThread("menuBarFavorsRight", idents.menuBarNavigationRight, selectCardThemesRight);
604    //gui.addMenuItemGThread("menuBarNavigatonCmd", idents.menuBarNavigatonCmd, actionFocusCmdCard);
605    
606    // gui.set
607
608    // Creates tab-Panels for the file lists and command lists.
609    _gralMng.selectPanel("primaryWindow");
610    favorPathSelector.panelLeft.tabbedPanelFileCards = _gralMng.addTabbedPanel("File0Tab", null, GralMngBuild_ifc.propZoomedPanel);
611    gui.addFrameArea("A1A1", favorPathSelector.panelLeft.tabbedPanelFileCards); // dialogPanel);
612
613    favorPathSelector.panelLeft.buildInitialTabs();
614    _gralMng.selectPanel("primaryWindow");
615    favorPathSelector.panelMid.tabbedPanelFileCards = _gralMng.addTabbedPanel("File1Tab", null, GralMngBuild_ifc.propZoomedPanel);
616    gui.addFrameArea("B1B1", favorPathSelector.panelMid.tabbedPanelFileCards); // dialogPanel);
617    favorPathSelector.panelMid.buildInitialTabs();
618
619    _gralMng.selectPanel("primaryWindow");
620    favorPathSelector.panelRight.tabbedPanelFileCards = _gralMng.addTabbedPanel("File2Tab", null, GralMngBuild_ifc.propZoomedPanel);
621    gui.addFrameArea("C1C1", favorPathSelector.panelRight.tabbedPanelFileCards); // dialogPanel);
622    favorPathSelector.panelRight.buildInitialTabs();
623
624    _gralMng.selectPanel("primaryWindow");
625    panelButtons = _gralMng.createGridPanel("Buttons", _gralMng.getColor("gr"), 1, 1, 10, 10);
626    gui.addFrameArea("A3C3", panelButtons); // dialogPanel);
627
628    filesCp.buildGraphic();
629    settings.buildWindow();  //F2
630    status.buildWindow();  //F2
631    filePropsCmd.buildWindow();  //F2
632    viewCmd.buildWindowView();   //F3
633    editWind.buildWindow();   //F3
634    copyCmd.buildWindowConfirmCopy("confirm copy / move / compare");
635    delCmd.buildWindowConfirmCopy("confirm delete");
636    compareCmd.buildWindowConfirmCopy("confirm compare");
637    mkCmd.buildWindowConfirmMk();
638    executer.buildWindowConfirmExec();
639    deleteCmd.buildWindowConfirmDelete(); //F8
640    favorPathSelector.buildWindowAddFavorite();
641
642    fButtons.initPanelButtons();
643    GralMenu menu = gui.getMenuBar();
644    menu.addMenuItem("MenuSetWorkingDir", "&Command/Set&WorkingDir", executer.actionSetCmdWorkingDir); // /
645    menu.addMenuItem("MenuCommandAbort", "&Command/&Abort", executer.actionCmdAbort); // /
646    // gui.addMenuItemGThread("&Command/E&xecute", actionSetCmdCurrentDir); ///
647    menu.addMenuItem("MenuCmdCfgSet", "&Command/CmdCf&g - read current file", executer.actionSetCmdCfg); // /
648    
649    menu.addMenuItem("menuHelp", idents.menuHelpBar, gui.getActionHelp());
650    menu.addMenuItem("menuAbout", idents.menuBarAbout, gui.getActionAbout());
651    menu.addMenuItem("MenuTestInfo", "&Help/&Infobox", actionTest); 
652    guiW.outputBox.setActionChange(executer.actionCmdFromOutputBox);
653    String sHelpUrlDir = cargs.dirHtmlHelp.getAbsolutePath();
654    gui.setHelpUrl(sHelpUrlDir + "/Fcmd.html");
655    lastFilePanels.clear();
656    lastFilePanels.add(favorPathSelector.panelMid);
657    lastFilePanels.add(favorPathSelector.panelRight);
658    lastFilePanels.add(favorPathSelector.panelLeft);
659    favorPathSelector.panelMid.cardFavorThemes.setFocus();
660  }
661
662  @Override
663  protected final void initMain()
664  {
665    if (cargs.fileCfgCmds == null) {
666      mainCmd.writeError("Argument cmdcfg:CONFIGFILE should be given.");
667      // mainCmd.e
668    } else if (cargs.fileCmdsForExt == null) {
669      mainCmd.writeError("Argument cmdext:CONFIGFILE should be given.");
670      // mainCmd.e
671    } else if (cargs.fileCfgButtonCmds == null) {
672      mainCmd.writeError("Argument cmdButton:CONFIGFILE should be given.");
673      // mainCmd.e
674    } else if (cargs.fileSelectTabPaths == null) {
675      mainCmd.writeError("Argument sel:SELECTFILE should be given.");
676      // mainCmd.e
677    } else {
678      String sError;
679      File fileCfg;
680      sError = executer.readCmdCfgSelectList(executer.cmdSelector.addJZsub2SelectTable, fileCfg = cargs.fileCfgCmds, console);
681      if(sError !=null) {
682        showInfoBox(sError);   
683      } else {
684        appendTextInfoBox("read config cmd");
685      }
686      if (sError == null) {
687        //sError = executer.readCmdFile(fileCfg = cargs.fileCmdsForExt);
688        sError = executer.readCfgExt(new File(cargs.dirCfg, "extjz.cfg"));
689      }
690      if (sError == null) {
691        sError = JZtxtcmd.readJZcmdCfg(addButtonCmd, fileCfg = cargs.fileCfgButtonCmds, console, executer.cmdExecuter);
692      }
693      if (sError == null) {
694        sError = favorPathSelector.readCfg(fileCfg = cargs.fileSelectTabPaths);
695      }
696      if (sError != null) {
697        mainCmd.writeError("Error reading " + fileCfg.getAbsolutePath() + ": "
698            + sError);
699      }
700    }
701    super.initMain(); // starts initializing of graphic. Do it after config
702                      // command selector!
703
704  }
705
706  /**
707   * Executing in the main thread loop. It handles commands.
708   * 
709   * @see org.vishia.gral.area9.GuiCfg#stepMain()
710   */
711  @Override public void stepMain()
712  {
713    Appendable writeStatusCmd = new Appendable(){
714
715      @Override public Appendable append(CharSequence csq) throws IOException
716      { statusLine.widgRunInfo.setText(csq);
717        return this;
718      }
719
720      @Override public Appendable append(char c) throws IOException
721      { if(c == '\0') statusLine.widgRunInfo.setText(" ");
722        else statusLine.widgRunInfo.setText("" + c);
723        return this;
724      }
725
726      @Override public Appendable append(CharSequence csq, int start, int end) throws IOException
727      { statusLine.widgRunInfo.setText(csq.subSequence(start, end));
728        return null;
729      }
730      
731    };
732    
733    //executer.cmdQueue.execCmds(writeStatusCmd);
734    executer.cmdExecuter.executeCmdQueue(false);
735    long time = System.currentTimeMillis();
736    favorPathSelector.panelLeft.checkRefresh(time);
737    favorPathSelector.panelMid.checkRefresh(time);
738    favorPathSelector.panelRight.checkRefresh(time);
739  }
740  
741  
742  
743  /**
744   * Executing in the main thread loop. It handles commands.
745   * 
746   * @see org.vishia.gral.area9.GuiCfg#stepMain()
747   */
748  @Override public void finishMain()
749  { 
750    try{
751      executer.cmdExecuter.close();  //finishes threads.
752      target.close();
753      FileAccessorLocalJava7.getInstance().close();
754    } catch(IOException exc){
755      
756    }
757  }
758  
759  
760  void setLastSelectedPanel(FcmdLeftMidRightPanel panel){
761    if(lastFilePanels.size() == 0){
762      lastFilePanels.add(0, panel);  //first time only
763    }
764    else if(lastFilePanels.get(0) != panel) {  //do nothing if the panel is the first one.
765      if(!lastFilePanels.remove(panel)){  //if it is in list on higher position
766        System.err.println("Fcmd - setLastSelectedPanel() faulty; try remove panel=" + panel.toString());
767        //The file panel should be known!
768      }
769      lastFilePanels.add(0, panel);
770    }
771
772  }
773
774  /**Get the last selected files in order of selection of the file panels.
775   * If the current file of any panel is marked, then all other marked files (but not directories)
776   * of this panel are taken as next files. But only 3 at all.
777   * It is possible to mark two files in one file panel to execute an application with them.
778   * New method since 2011-12-23
779   * @return array[3] of the last selected files in the file panels. It has always a length of 3
780   *   but not all elements are set ( they are ==null) if no files were selected before.
781   *   The returned instance is a new one, not referenced elsewhere. It can be stored
782   *   and it remains the situation of selection files independently of further user actions.
783   */
784  FileRemote[] getLastSelectedFiles(boolean bAlsoDirs, int mask){
785    FileRemote[] ret = new FileRemote[3];
786    int ix = -1;
787    Iterator<FcmdLeftMidRightPanel> iterPanel = lastFilePanels.iterator();
788    while(ix < 2 && iterPanel.hasNext() ){
789      FcmdLeftMidRightPanel panel = iterPanel.next();
790      //for(FcmdLeftMidRightPanel panel: lastFilePanels){
791      FcmdFileCard fileCard = panel.actFileCard;
792      if(fileCard !=null){
793        ret[++ix] = fileCard.currentFile();
794        if(fileCard.currentFile() !=null && fileCard.currentFile().isMarked(0x1)){
795          //if the current file is marked, use all marked files.
796          List<FileRemote> listFiles = fileCard.getSelectedFiles(bAlsoDirs, mask);
797          //NOTE: the currentFile was marked, but it was not existing after delete. In this case all is okay but listFiles is empty.
798          assert(listFiles !=null); // && listFiles.size() > 0);  //at least the current file is marked.
799          Iterator<FileRemote> iter= listFiles.iterator();
800          while(ix < 2 && iter.hasNext()){
801            FileRemote file = iter.next();
802            if(file != fileCard.currentFile()){
803              ret[++ix] = file;
804            }
805          }
806        }
807      } else {
808        //ret[++ix] = null;  //the panel hasn't a file selected now.
809      }
810    }
811    //Note: There may be less than 3 file panels, rest of files are null.
812    return ret;
813  }
814  
815
816  /**Get the last selected file cards in order of selection of the file panels.
817   * @return array[3] of the last selected file cards in the file panels. It has always a length of 3
818   *   but not all elements are set ( they are ==null) if the file cards are not opened before
819   *   in the panel.
820   *   The returned instance is a new one, not referenced elsewhere. It can be stored
821   *   and it remains the situation of selection files independently of further user actions.
822   */
823  FcmdFileCard[] getLastSelectedFileCards(){
824    FcmdFileCard[] ret = new FcmdFileCard[3];
825    int ix = -1;
826    for(FcmdLeftMidRightPanel panel: lastFilePanels){
827      FcmdFileCard fileCard = panel.actFileCard;
828      if(fileCard !=null){
829        ret[++ix] = fileCard;
830      } else {
831        ret[++ix] = null;  //the panel hasn't a file selected now.
832      }
833      if(ix >=2) break;  //prevent exception because older error
834    }
835    //Note: There may be less than 3 file panels, rest of files are null.
836    return ret;
837  }
838  
839  
840  
841  /**Get the last selected file cards in order of selection of the file panels.
842   * @return array[3] of the last selected file cards in the file panels. It has always a length of 3
843   *   but not all elements are set ( they are ==null) if the file cards are not opened before
844   *   in the panel.
845   *   The returned instance is a new one, not referenced elsewhere. It can be stored
846   *   and it remains the situation of selection files independently of further user actions.
847   */
848  List<File>[] getLastSelectedFilesPerCard(){
849    @SuppressWarnings("unchecked")
850    List<File>[] ret = new List[3];
851    int ix = -1;
852    for(FcmdLeftMidRightPanel panel: lastFilePanels){
853      FcmdFileCard fileCard = panel.actFileCard;
854      if(fileCard !=null){
855        List<FileRemote> list = fileCard.getSelectedFiles(true, 0x1);
856        ret[++ix] = new ArrayList<File>();
857        for(File file: list) { ret[ix].add(file); }
858      } else {
859        ret[++ix] = null;  //the panel hasn't a file selected now.
860      }
861      if(ix >=2) break;  //prevent exception because older error
862    }
863    //Note: There may be less than 3 file panels, rest of files are null.
864    return ret;
865  }
866  
867  
868  
869  
870  
871  /**Get the last selected file card in order of selection of the file panels.
872   * @return The file card reference.   */
873  FcmdFileCard getLastSelectedFileCard(){
874    
875    if(lastFavorCard!=null){
876      return lastFavorCard.fileTable;
877    } else {
878      return null;
879    }
880  }
881  
882  
883  
884  
885  FileRemote currentFile(){
886    if(this.currentFileCard == null) return null;
887    else return this.currentFileCard.currentFile();
888  }
889  
890
891  FileRemote currentDir(){
892    if(this.currentFileCard == null) return null;
893    else return this.currentFileCard.currentDir();
894  }
895  
896  
897  /**Refreshes the {@link FcmdFileCard} if the dir is the current one.
898   * This method can be invoked in any for example callback routine in any thread, which changes the content of directories.
899   * Note: It starts {@link GralFileSelector#fillIn(FileRemote, boolean)} which refreshes the files 
900   * @param fileOrDir The changed file or its directory. 
901   *   it is checked whether the directory is shown currently in one of the three file panels, then the panel will be refreshed.
902   *   If the directory is not shown yet then nothing is done. 
903   *   Note that a directory will be refreshed whenever it will be activated in a panel. 
904   */
905  protected void refreshFilePanel(FileRemote fileOrDir)
906  {
907    FileRemote dir = fileOrDir.isDirectory() ? fileOrDir: fileOrDir.getParentFile();
908    for(FcmdLeftMidRightPanel panel: lastFilePanels) {
909      if(panel !=null && panel.actFileCard !=null && panel.actFileCard.currentDir() == dir) {
910        panel.actFileCard.fillInCurrentDir();
911      }
912    }
913  }
914  
915  
916  
917  
918  
919  /**
920   * This class is instantiated in the static main routine and builds a command
921   * line interface and the graphical frame. The mainly functionality is
922   * contained in the super class.
923   */
924  private static class FcmdMainCmd extends GralArea9MainCmd
925  {
926
927    private final CallingArgs cargs;
928
929    public FcmdMainCmd(CallingArgs cargs, String[] args)
930    {
931      super(cargs, args);
932      this.cargs = cargs;
933      super.addAboutInfo("The.file.Commander");
934      super.addAboutInfo("made by Hartmut Schorrig, www.vishia.org, hartmut.schorrig@vishia.de");
935      super.addAboutInfo("Version-date: " + Fcmd.version);
936    }
937
938    @Override protected boolean testArgument(String arg, int nArg)
939    {
940      boolean bOk = true;
941      if (arg.startsWith("cfg:")) {
942        cargs.dirCfg = new File(arg.substring(4));
943      } else if (arg.startsWith("cmdcfg:")) {
944        cargs.fileCfgCmds = new File(arg.substring(7));
945      } else if (arg.startsWith("cmdext:")) {
946        cargs.fileCmdsForExt = new File(arg.substring(7));
947      } else if (arg.startsWith("cmdButton:")) {
948        cargs.fileCfgButtonCmds = new File(arg.substring(10));
949      } else if (arg.startsWith("sel:")) {
950        cargs.fileSelectTabPaths = new File(arg.substring(4));
951      } else {
952        bOk = super.testArgument(arg, nArg);
953      }
954      return bOk;
955    }
956    
957    @Override protected boolean checkArguments(){
958      boolean bOk = true;
959      if(cargs.dirCfg == null) { bOk = false; writeError("cmdline argument cfg:PATHCFG is missing"); }
960      if(bOk){
961        if(!cargs.dirCfg.exists()){ bOk = false; writeError("cmdline argument cfg is faulty:" + cargs.dirCfg.getAbsolutePath());}
962      }
963      if(bOk){
964        if(cargs.dirHtmlHelp ==null){ cargs.dirHtmlHelp = new File(cargs.dirCfg, "../help"); }
965        if(cargs.fileCfgCmds ==null){ cargs.fileCfgCmds = new File(cargs.dirCfg, "cmd.cfg"); }
966        if(cargs.fileCmdsForExt ==null){ cargs.fileCmdsForExt = new File(cargs.dirCfg, "ext.cfg"); }
967        if(cargs.fileCfgButtonCmds ==null){ cargs.fileCfgButtonCmds = new File(cargs.dirCfg, "cmdi.cfg"); }
968        if(cargs.fileSelectTabPaths ==null){ cargs.fileSelectTabPaths = new File(cargs.dirCfg, "path.cfg"); }
969      }
970      return bOk;
971    }
972
973  } // class MainCmd
974
975
976  static void testT1()
977  {
978    float R = 10000.0f;
979    float C = 0.000000001f;
980    float tStep = 0.0000001f;
981    float uc = 0.0f;
982    float ue = 1.0f;
983    for (int step = 0; step < 100; ++step) {
984      float iR = (ue - uc) / R;
985      uc = uc + iR / C * tStep;
986    }
987
988  }
989
990  /**
991   * The command-line-invocation (primary command-line-call.
992   * 
993   * @param args
994   *          Some calling arguments are taken. This is the GUI-configuration
995   *          especially.
996   */
997  public static void main(String[] args)
998  {
999    testT1();
1000    boolean bOk = true;
1001    CallingArgs cargs = new CallingArgs();
1002    // Initializes the GUI till a output window to show information.
1003    // Uses the commonly GuiMainCmd class because here are not extra arguments.
1004    GralArea9MainCmd cmdgui = new FcmdMainCmd(cargs, args); // implements MainCmd, parses
1005    //new GralMng(null, cmdgui);
1006    
1007    // calling arguments
1008    bOk = cmdgui.parseArgumentsAndInitGraphic("The.file.Commander", "2A2C", '.', "0+50,0+150");
1009
1010    /*
1011    try {
1012      cmdgui.parseArguments();
1013    } catch (Exception exception) {
1014      cmdgui.writeError("Cmdline argument error:", exception);
1015      cmdgui.setExitErrorLevel(MainCmd_ifc.exitWithArgumentError);
1016      bOk = false; // not exiting, show error in GUI
1017    }
1018    */
1019    if (bOk) {
1020      // Uses socket communication for InterprocessComm, therefore load the
1021      // factory.
1022      new InterProcessCommFactorySocket();
1023      //
1024      // Initialize this main class and execute.
1025      Fcmd main = new Fcmd(cargs, cmdgui);
1026      //main.msgDisp = MsgDispatchSystemOutErr.create();
1027      main.execute();
1028    }
1029    cmdgui.exit();
1030  }
1031
1032
1033  
1034
1035}