├── .project ├── README.md └── command-ui ├── .gitignore ├── CommandLine.ico ├── LICENSE ├── assembly.xml ├── curl-ui.cml ├── default.icu ├── find-ui.cml ├── misc ├── draft.txt ├── screenshots │ ├── CommandLineEditor.png │ ├── CommandLineEditor2.png │ ├── CommandLineEditor3.png │ ├── CommandLinePlayer.png │ ├── CommandLinePlayer2.png │ ├── CommandLinePlayer3.png │ └── CommandRunner.png └── web │ └── backlinking.txt ├── ping-ui.cml ├── pom.xml ├── src ├── main │ ├── java │ │ └── xy │ │ │ └── command │ │ │ ├── instance │ │ │ ├── AbstractCommandLinePartInstance.java │ │ │ ├── ArgumentGroupInstance.java │ │ │ ├── ArgumentPageInstance.java │ │ │ ├── ChoiceInstance.java │ │ │ ├── CommandLineInstance.java │ │ │ ├── DirectoryArgumentInstance.java │ │ │ ├── FileArgumentInstance.java │ │ │ ├── FixedArgumentInstance.java │ │ │ ├── InputArgumentInstance.java │ │ │ ├── MultiplePartInstance.java │ │ │ └── OptionalPartInstance.java │ │ │ ├── model │ │ │ ├── AbstractCommandLinePart.java │ │ │ ├── ArgumentGroup.java │ │ │ ├── ArgumentPage.java │ │ │ ├── Choice.java │ │ │ ├── CommandLine.java │ │ │ ├── CommandLineProject.java │ │ │ ├── DirectoryArgument.java │ │ │ ├── FileArgument.java │ │ │ ├── FixedArgument.java │ │ │ ├── InputArgument.java │ │ │ ├── MultiplePart.java │ │ │ └── OptionalPart.java │ │ │ └── ui │ │ │ ├── CommandLineUI.java │ │ │ ├── CommandMonitoringDialog.java │ │ │ ├── FieldInfoFromChoice.java │ │ │ ├── FieldInfoFromDirectoryArgument.java │ │ │ ├── FieldInfoFromFileArgument.java │ │ │ ├── FieldInfoFromInputArgument.java │ │ │ ├── FieldInfoFromMultiplePart.java │ │ │ ├── FieldInfoFromOptionalPart.java │ │ │ ├── TypeInfoSourceFromArgumentGroup.java │ │ │ ├── TypeInfoSourceFromChoice.java │ │ │ ├── TypeInfoSourceFromCommandLine.java │ │ │ ├── resource │ │ │ └── ClassInPackage.java │ │ │ └── util │ │ │ ├── CommandUIUtils.java │ │ │ ├── CountingFilenameFilter.java │ │ │ ├── DocumentOutputStream.java │ │ │ ├── FileUtils.java │ │ │ └── ValidationError.java │ └── resources │ │ └── xy │ │ └── command │ │ └── ui │ │ └── resource │ │ ├── ArgumentGroup.gif │ │ ├── ArgumentPage.gif │ │ ├── Choice.gif │ │ ├── CommandLine.gif │ │ ├── DirectoryArgument.gif │ │ ├── FileArgument.gif │ │ ├── FixedArgument.gif │ │ ├── InputArgument.gif │ │ ├── MultiplePart.gif │ │ ├── OptionalPart.gif │ │ ├── banner.jpg │ │ ├── baseFont.ttf │ │ ├── buttonBackground.png │ │ └── commandLine.icu └── test │ └── java │ └── xy │ └── command │ └── ui │ └── TestWithAutomation.java ├── test-specifications └── test.stt └── todo.txt /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | command-ui 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CommandUI 2 | ========= 3 | 4 | Change log 5 | - cross-platform jar added in the distribution 6 | - junit test added 7 | - javadoc added 8 | - in ALPHA stage 9 | - in Beta stage 10 | 11 | Usage 12 | - CommandUI[.exe] [<filePath> [--instanciate]] 13 | - <filePath>: path to a command line specification file (*.cml) 14 | - --instanciate: will only show the GUI generated from the <filePath> command line specification 15 | 16 | 17 | ![CommandLineEditor](/command-ui/misc/screenshots/CommandLineEditor3.png?raw=true) 18 | ![CommandLinePlayer](/command-ui/misc/screenshots/CommandLinePlayer3.png?raw=true) 19 | ![CommandRunner](/command-ui/misc/screenshots/CommandRunner.png?raw=true) 20 | 21 | -------------------------------------------------------------------------------- /command-ui/.gitignore: -------------------------------------------------------------------------------- 1 | /bin 2 | /target 3 | /.settings 4 | /.project 5 | /tmp-src 6 | /.classpath 7 | /tmp/ 8 | /test-reports/ 9 | -------------------------------------------------------------------------------- /command-ui/CommandLine.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotxyteam/CommandUI/18861730d94d150cb61ed16e371576c0a71d6bf2/command-ui/CommandLine.ico -------------------------------------------------------------------------------- /command-ui/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2018 OTK Software / DotXY Team 2 | 3 | (MIT License) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /command-ui/assembly.xml: -------------------------------------------------------------------------------- 1 | 5 | dist 6 | 7 | zip 8 | 9 | 10 | 11 | ${project.basedir} 12 | 13 | LICENSE 14 | 15 | 16 | .* 17 | 18 | 19 | 20 | ${project.basedir}/src 21 | 22 | .* 23 | 24 | 25 | 26 | ${project.basedir}/test-specifications 27 | 28 | .* 29 | 30 | 31 | 32 | ${project.build.directory} 33 | 34 | CommandUI 35 | CommandUI.exe 36 | 37 | 38 | .* 39 | 40 | 41 | 42 | 43 | 44 | ${project.build.directory}/command-ui-${project.version}-jar-with-dependencies.jar 45 | . 46 | ${project.build.directory}/command-ui-crossPlatform.jar 47 | 48 | 49 | -------------------------------------------------------------------------------- /command-ui/curl-ui.cml: -------------------------------------------------------------------------------- 1 | 2 | curl is a tool to transfer data from or to a server 3 | curl-ui 4 | 5 | 6 | Global 7 | 8 | 9 | 10 | Output to a file 11 | 12 | 13 | 14 | -o 15 | 16 | 17 | 18 | The file name 19 | 20 | 21 | 22 | false 23 | 24 | 25 | 26 | Verbose 27 | 28 | 29 | 30 | -v 31 | 32 | 33 | false 34 | 35 | 36 | 37 | 38 | Data 39 | 40 | 41 | 42 | Sends the specified datas in a POST request 43 | 44 | 45 | 46 | --data 47 | 48 | 49 | In the form: x=value 50 | The data 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | Server 59 | 60 | 61 | 62 | URL 63 | http://\www.google.com 64 | 65 | 66 | 67 | 68 | curl 69 | . 70 | -------------------------------------------------------------------------------- /command-ui/find-ui.cml: -------------------------------------------------------------------------------- 1 | 2 | search for files in a directory hierarchy 3 | find-ui 4 | 5 | 6 | Global Options 7 | 8 | 9 | 10 | Follow symbolic links 11 | 12 | 13 | 14 | -L 15 | 16 | 17 | false 18 | 19 | 20 | 21 | Directory 22 | <Choose> 23 | 24 | 25 | 26 | 27 | Tests 28 | 29 | 30 | 31 | Test List 32 | 33 | 34 | 35 | 36 | 37 | 38 | File was last accessed n minutes ago 39 | 40 | 41 | 42 | -amin 43 | 44 | 45 | 46 | n 47 | 5 48 | 49 | 50 | 51 | 52 | 53 | File is of type c 54 | 55 | 56 | 57 | -type 58 | 59 | 60 | 61 | 62 | 63 | 64 | file 65 | 66 | 67 | 68 | f 69 | 70 | 71 | 72 | 73 | 74 | directory 75 | 76 | 77 | 78 | d 79 | 80 | 81 | 82 | 83 | c 84 | 85 | 86 | 87 | 88 | Test Type 89 | 90 | 91 | 92 | 93 | 94 | 95 | find 96 | . 97 | -------------------------------------------------------------------------------- /command-ui/misc/draft.txt: -------------------------------------------------------------------------------- 1 | - There are 2 kinds of models: 2 | * those which are type info sources (CommandLine, Optional, Multiple) 3 | * those which are field info sources -------------------------------------------------------------------------------- /command-ui/misc/screenshots/CommandLineEditor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotxyteam/CommandUI/18861730d94d150cb61ed16e371576c0a71d6bf2/command-ui/misc/screenshots/CommandLineEditor.png -------------------------------------------------------------------------------- /command-ui/misc/screenshots/CommandLineEditor2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotxyteam/CommandUI/18861730d94d150cb61ed16e371576c0a71d6bf2/command-ui/misc/screenshots/CommandLineEditor2.png -------------------------------------------------------------------------------- /command-ui/misc/screenshots/CommandLineEditor3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotxyteam/CommandUI/18861730d94d150cb61ed16e371576c0a71d6bf2/command-ui/misc/screenshots/CommandLineEditor3.png -------------------------------------------------------------------------------- /command-ui/misc/screenshots/CommandLinePlayer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotxyteam/CommandUI/18861730d94d150cb61ed16e371576c0a71d6bf2/command-ui/misc/screenshots/CommandLinePlayer.png -------------------------------------------------------------------------------- /command-ui/misc/screenshots/CommandLinePlayer2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotxyteam/CommandUI/18861730d94d150cb61ed16e371576c0a71d6bf2/command-ui/misc/screenshots/CommandLinePlayer2.png -------------------------------------------------------------------------------- /command-ui/misc/screenshots/CommandLinePlayer3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotxyteam/CommandUI/18861730d94d150cb61ed16e371576c0a71d6bf2/command-ui/misc/screenshots/CommandLinePlayer3.png -------------------------------------------------------------------------------- /command-ui/misc/screenshots/CommandRunner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotxyteam/CommandUI/18861730d94d150cb61ed16e371576c0a71d6bf2/command-ui/misc/screenshots/CommandRunner.png -------------------------------------------------------------------------------- /command-ui/misc/web/backlinking.txt: -------------------------------------------------------------------------------- 1 | PUBLISHED: https://stackoverflow.com/questions/52366395/how-to-create-a-gui-to-send-commands-and-args-to-a-command-line-application/57277773#57277773 2 | PUBLISHED: https://askubuntu.com/questions/31172/need-an-interface-for-a-gui-shell-script-more-powerful-than-zenity/1162207#1162207 3 | PUBLISHED: https://stackoverflow.com/questions/20842687/rapidly-develop-gui-for-command-line/57278142#57278142 4 | REJECTED: https://stackoverflow.com/questions/2202434/should-i-create-a-java-gui-for-a-perl-command-line-program/57280407#57280407 5 | -------------------------------------------------------------------------------- /command-ui/ping-ui.cml: -------------------------------------------------------------------------------- 1 | 2 | send ICMP ECHO_REQUEST to network hosts 3 | ping-ui 4 | 5 | 6 | Settings 7 | 8 | 9 | Destination server name 10 | hostname 11 | localhost 12 | 13 | 14 | -c 15 | 16 | 17 | Stop after sending count ECHO_REQUEST packets. 18 | count 19 | 4 20 | 21 | 22 | 23 | 24 | /bin/ping 25 | . 26 | -------------------------------------------------------------------------------- /command-ui/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | xy 6 | command-ui 7 | 2.7.2 8 | Command UI 9 | 10 | 11 | com.github.dotxyteam 12 | custom-ui 13 | 6.0.1 14 | 15 | 16 | com.thoughtworks.xstream 17 | xstream 18 | 1.4.20 19 | 20 | 21 | com.github.dotxyteam 22 | swing-testing-toolkit 23 | 1.8.15 24 | test 25 | 26 | 27 | junit 28 | junit 29 | 4.12 30 | test 31 | 32 | 33 | 34 | 35 | 36 | 37 | org.apache.maven.plugins 38 | maven-compiler-plugin 39 | 3.2 40 | 41 | 1.8 42 | 1.8 43 | 44 | 45 | 46 | maven-assembly-plugin 47 | 48 | 49 | assembly-jar-with-dependencies 50 | package 51 | 52 | attached 53 | 54 | 55 | 56 | jar-with-dependencies 57 | 58 | 59 | 60 | xy.command.ui.CommandLineUI 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | org.apache.maven.plugins 69 | maven-antrun-plugin 70 | 71 | 72 | package 73 | 74 | run 75 | 76 | 77 | 78 | 108 | 110 | 112 | 113 | 114 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | com.akathist.maven.plugins.launch4j 126 | launch4j-maven-plugin 127 | 2.1.0 128 | 129 | 130 | l4j-gui 131 | verify 132 | 133 | launch4j 134 | 135 | 136 | gui 137 | target/CommandUI.exe 138 | CommandLine.ico 139 | target/command-ui-${version}-jar-with-dependencies.jar 140 | CommandUI 141 | 142 | xy.command.ui.CommandLineUI 143 | 144 | 145 | 1.8.0 146 | 1.17.9 147 | 148 | -Dxy.reflect.ui.infoCustomizationsToolsHidden=true 149 | -Dxy.command.ui.exeFile="%EXEFILE%" 150 | -Dxy.command.ui.defaultExeFile=CommandUI.exe 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | maven-assembly-plugin 159 | 160 | 161 | assembly-zip 162 | install 163 | 164 | attached 165 | 166 | 167 | 168 | assembly.xml 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/instance/AbstractCommandLinePartInstance.java: -------------------------------------------------------------------------------- 1 | package xy.command.instance; 2 | 3 | /** 4 | * The base class of command line model instance parts. 5 | * 6 | * @author olitank 7 | * 8 | */ 9 | public abstract class AbstractCommandLinePartInstance { 10 | 11 | /** 12 | * @return The resulting text argument that should be used to execute the 13 | * command line program. 14 | */ 15 | public abstract String getExecutionText(); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/instance/ArgumentGroupInstance.java: -------------------------------------------------------------------------------- 1 | package xy.command.instance; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import xy.command.model.AbstractCommandLinePart; 7 | import xy.command.model.ArgumentGroup; 8 | 9 | /** 10 | * The instance class of {@link ArgumentGroup}. 11 | * 12 | * @author olitank 13 | * 14 | */ 15 | public class ArgumentGroupInstance extends AbstractCommandLinePartInstance { 16 | 17 | public ArgumentGroup model; 18 | public List partInstances = new ArrayList(); 19 | 20 | /** 21 | * The main constructor. Builds an instance from the given model part object. 22 | * 23 | * @param model The model part object. 24 | */ 25 | public ArgumentGroupInstance(ArgumentGroup model) { 26 | this.model = model; 27 | for (AbstractCommandLinePart part : model.parts) { 28 | AbstractCommandLinePartInstance instance = part.instantiate(); 29 | if (instance == null) { 30 | continue; 31 | } 32 | partInstances.add(instance); 33 | } 34 | } 35 | 36 | @Override 37 | public String getExecutionText() { 38 | StringBuilder result = new StringBuilder(); 39 | int i = 0; 40 | for (AbstractCommandLinePartInstance partInstance : partInstances) { 41 | if (i > 0) { 42 | result.append(" "); 43 | } 44 | String partInstanceExecutionText = partInstance.getExecutionText(); 45 | if (partInstanceExecutionText == null) { 46 | continue; 47 | } 48 | result.append(partInstanceExecutionText); 49 | i++; 50 | } 51 | return result.toString(); 52 | } 53 | 54 | @Override 55 | public String toString() { 56 | StringBuilder result = new StringBuilder(); 57 | int i = 0; 58 | for (AbstractCommandLinePartInstance partInstance : partInstances) { 59 | if (i > 0) { 60 | result.append(", "); 61 | } 62 | result.append(partInstance.toString()); 63 | i++; 64 | } 65 | return result.toString(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/instance/ArgumentPageInstance.java: -------------------------------------------------------------------------------- 1 | package xy.command.instance; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import xy.command.model.AbstractCommandLinePart; 7 | import xy.command.model.ArgumentPage; 8 | 9 | /** 10 | * The instance class of {@link ArgumentPage}. 11 | * 12 | * @author olitank 13 | * 14 | */ 15 | public class ArgumentPageInstance { 16 | 17 | public ArgumentPage model; 18 | public List partInstances = new ArrayList(); 19 | 20 | /** 21 | * The main constructor. Builds an instance from the given model page object. 22 | * 23 | * @param model The model page object. 24 | */ 25 | public ArgumentPageInstance(ArgumentPage model) { 26 | this.model = model; 27 | for (AbstractCommandLinePart part : model.parts) { 28 | AbstractCommandLinePartInstance instance = part.instantiate(); 29 | if (instance == null) { 30 | continue; 31 | } 32 | partInstances.add(instance); 33 | } 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return model.title; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/instance/ChoiceInstance.java: -------------------------------------------------------------------------------- 1 | package xy.command.instance; 2 | 3 | import xy.command.model.Choice; 4 | 5 | /** 6 | * The instance class of {@link Choice}. 7 | * 8 | * @author olitank 9 | * 10 | */ 11 | public class ChoiceInstance extends AbstractCommandLinePartInstance { 12 | 13 | public Choice model; 14 | public ArgumentGroupInstance chosenPartInstance; 15 | 16 | /** 17 | * The main constructor. Builds an instance from the given model part object. 18 | * 19 | * @param model The model part object. 20 | */ 21 | public ChoiceInstance(Choice model) { 22 | this.model = model; 23 | if (model.options.size() > 0) { 24 | chosenPartInstance = (ArgumentGroupInstance) model.options.get(0).instantiate(); 25 | } 26 | } 27 | 28 | @Override 29 | public String getExecutionText() { 30 | return chosenPartInstance.getExecutionText(); 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | return model.title + "=" + chosenPartInstance; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/instance/CommandLineInstance.java: -------------------------------------------------------------------------------- 1 | package xy.command.instance; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import xy.command.model.ArgumentPage; 7 | import xy.command.model.CommandLine; 8 | 9 | /** 10 | * The instance class of {@link CommandLine}. 11 | * 12 | * @author olitank 13 | * 14 | */ 15 | public class CommandLineInstance extends AbstractCommandLinePartInstance { 16 | 17 | public CommandLine model; 18 | public List argumentPageInstances = new ArrayList(); 19 | 20 | /** 21 | * The main constructor. Builds an instance from the given model object. 22 | * 23 | * @param model The model object. 24 | */ 25 | public CommandLineInstance(CommandLine model) { 26 | this.model = model; 27 | for (ArgumentPage page : model.arguments) { 28 | ArgumentPageInstance instance = page.instantiate(); 29 | argumentPageInstances.add(instance); 30 | } 31 | } 32 | 33 | @Override 34 | public String getExecutionText() { 35 | StringBuilder result = new StringBuilder(); 36 | int i = 0; 37 | for (ArgumentPageInstance pageInstance : argumentPageInstances) { 38 | for (AbstractCommandLinePartInstance partInstance : pageInstance.partInstances) { 39 | if (i > 0) { 40 | result.append(" "); 41 | } 42 | String partInstanceExecutionText = partInstance.getExecutionText(); 43 | if (partInstanceExecutionText == null) { 44 | continue; 45 | } 46 | result.append(partInstanceExecutionText); 47 | i++; 48 | } 49 | } 50 | return result.toString(); 51 | } 52 | 53 | @Override 54 | public String toString() { 55 | StringBuilder result = new StringBuilder(); 56 | int i = 0; 57 | for (ArgumentPageInstance pageInstance : argumentPageInstances) { 58 | for (AbstractCommandLinePartInstance partInstance : pageInstance.partInstances) { 59 | if (i > 0) { 60 | result.append(", "); 61 | } 62 | result.append(partInstance.toString()); 63 | i++; 64 | } 65 | } 66 | return result.toString(); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/instance/DirectoryArgumentInstance.java: -------------------------------------------------------------------------------- 1 | package xy.command.instance; 2 | 3 | import xy.command.model.DirectoryArgument; 4 | import xy.command.ui.util.CommandUIUtils; 5 | 6 | /** 7 | * The instance class of {@link DirectoryArgument}. 8 | * 9 | * @author olitank 10 | * 11 | */ 12 | public class DirectoryArgumentInstance extends AbstractCommandLinePartInstance { 13 | 14 | public DirectoryArgument model; 15 | public String value; 16 | 17 | /** 18 | * The main constructor. Builds an instance from the given model part object. 19 | * 20 | * @param model The model part object. 21 | */ 22 | public DirectoryArgumentInstance(DirectoryArgument model) { 23 | this.model = model; 24 | value = model.defaultValue; 25 | } 26 | 27 | 28 | @Override 29 | public String getExecutionText() { 30 | return CommandUIUtils.quoteArgument(value); 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | return model.title + "=" + value; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/instance/FileArgumentInstance.java: -------------------------------------------------------------------------------- 1 | package xy.command.instance; 2 | 3 | import xy.command.model.FileArgument; 4 | import xy.command.ui.util.CommandUIUtils; 5 | 6 | /** 7 | * The instance class of {@link FileArgument}. 8 | * 9 | * @author olitank 10 | * 11 | */ 12 | public class FileArgumentInstance extends AbstractCommandLinePartInstance { 13 | 14 | public FileArgument model; 15 | public String value; 16 | 17 | /** 18 | * The main constructor. Builds an instance from the given model part object. 19 | * 20 | * @param model The model part object. 21 | */ 22 | public FileArgumentInstance(FileArgument model) { 23 | this.model = model; 24 | value = model.defaultValue; 25 | } 26 | 27 | @Override 28 | public String getExecutionText() { 29 | return CommandUIUtils.quoteArgument(value); 30 | } 31 | 32 | @Override 33 | public String toString() { 34 | return model.title + "=" + value; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/instance/FixedArgumentInstance.java: -------------------------------------------------------------------------------- 1 | package xy.command.instance; 2 | 3 | import xy.command.model.FixedArgument; 4 | import xy.command.ui.util.CommandUIUtils; 5 | 6 | /** 7 | * The instance class of {@link FixedArgument}. 8 | * 9 | * @author olitank 10 | * 11 | */ 12 | public class FixedArgumentInstance extends AbstractCommandLinePartInstance { 13 | 14 | public FixedArgument model; 15 | 16 | /** 17 | * The main constructor. Builds an instance from the given model part object. 18 | * 19 | * @param model The model part object. 20 | */ 21 | public FixedArgumentInstance(FixedArgument model) { 22 | this.model = model; 23 | } 24 | 25 | @Override 26 | public String getExecutionText() { 27 | return CommandUIUtils.quoteArgument(model.value); 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return model.value; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/instance/InputArgumentInstance.java: -------------------------------------------------------------------------------- 1 | package xy.command.instance; 2 | 3 | import xy.command.model.InputArgument; 4 | import xy.command.ui.util.CommandUIUtils; 5 | 6 | /** 7 | * The instance class of {@link InputArgument}. 8 | * 9 | * @author olitank 10 | * 11 | */ 12 | public class InputArgumentInstance extends AbstractCommandLinePartInstance { 13 | 14 | public InputArgument model; 15 | public String value; 16 | 17 | /** 18 | * The main constructor. Builds an instance from the given model part object. 19 | * 20 | * @param model The model part object. 21 | */ 22 | public InputArgumentInstance(InputArgument model) { 23 | this.model = model; 24 | value = model.defaultValue; 25 | } 26 | 27 | @Override 28 | public String getExecutionText() { 29 | return CommandUIUtils.quoteArgument(value); 30 | } 31 | 32 | @Override 33 | public String toString() { 34 | return model.title + "=" + value; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/instance/MultiplePartInstance.java: -------------------------------------------------------------------------------- 1 | package xy.command.instance; 2 | 3 | import java.util.Arrays; 4 | 5 | import xy.command.model.MultiplePart; 6 | 7 | /** 8 | * The instance class of {@link MultiplePart}. 9 | * 10 | * @author olitank 11 | * 12 | */ 13 | public class MultiplePartInstance extends AbstractCommandLinePartInstance { 14 | 15 | public MultiplePart model; 16 | public ArgumentGroupInstance[] argumentGroupInstances = new ArgumentGroupInstance[0]; 17 | 18 | /** 19 | * The main constructor. Builds an instance from the given model part object. 20 | * 21 | * @param model The model part object. 22 | */ 23 | public MultiplePartInstance(MultiplePart model) { 24 | this.model = model; 25 | } 26 | 27 | @Override 28 | public String getExecutionText() { 29 | StringBuilder result = new StringBuilder(); 30 | int i = 0; 31 | for (ArgumentGroupInstance instance : argumentGroupInstances) { 32 | if (i > 0) { 33 | result.append(" "); 34 | } 35 | result.append(instance.getExecutionText()); 36 | i++; 37 | } 38 | return result.toString(); 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return model.title + "=" + Arrays.toString(argumentGroupInstances); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/instance/OptionalPartInstance.java: -------------------------------------------------------------------------------- 1 | package xy.command.instance; 2 | 3 | import xy.command.model.OptionalPart; 4 | 5 | /** 6 | * The instance class of {@link OptionalPart}. 7 | * 8 | * @author olitank 9 | * 10 | */ 11 | public class OptionalPartInstance extends AbstractCommandLinePartInstance { 12 | 13 | public OptionalPart model; 14 | public ArgumentGroupInstance argumentGroupInstance = null; 15 | 16 | /** 17 | * The main constructor. Builds an instance from the given model part object. 18 | * 19 | * @param model The model part object. 20 | */ 21 | public OptionalPartInstance(OptionalPart model) { 22 | this.model = model; 23 | if (model.activeByDefault) { 24 | argumentGroupInstance = new ArgumentGroupInstance(model); 25 | } 26 | } 27 | 28 | @Override 29 | public String getExecutionText() { 30 | if (argumentGroupInstance == null) { 31 | return null; 32 | } else { 33 | return argumentGroupInstance.getExecutionText(); 34 | } 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return model.title + "=" + argumentGroupInstance; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/model/AbstractCommandLinePart.java: -------------------------------------------------------------------------------- 1 | package xy.command.model; 2 | 3 | import java.io.IOException; 4 | import java.io.Serializable; 5 | import java.io.Writer; 6 | 7 | import xy.command.instance.AbstractCommandLinePartInstance; 8 | 9 | /** 10 | * The base class of command line model parts. 11 | * 12 | * @author olitank 13 | * 14 | */ 15 | public abstract class AbstractCommandLinePart implements Serializable { 16 | 17 | protected static final long serialVersionUID = 1L; 18 | 19 | /** 20 | * @return An instance of this command line model part. 21 | */ 22 | public abstract AbstractCommandLinePartInstance instantiate(); 23 | 24 | /** 25 | * The description of this command line model part. 26 | */ 27 | public String description = ""; 28 | 29 | /** 30 | * Writes a description of this command line model part in a syntax close to the 31 | * POSIX Utility Argument Syntax. 32 | * 33 | * @param out The writer that will receive the description. 34 | * @throws IOException If thrown by the writer. 35 | */ 36 | public abstract void writetUsageText(Writer out) throws IOException; 37 | 38 | /** 39 | * Allows to validate the correctness of the properties of this command line 40 | * model part. 41 | * 42 | * @throws Exception If a property is not valid. 43 | */ 44 | public void validate() throws Exception { 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/model/ArgumentGroup.java: -------------------------------------------------------------------------------- 1 | package xy.command.model; 2 | 3 | import java.io.IOException; 4 | import java.io.Writer; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import xy.command.instance.AbstractCommandLinePartInstance; 9 | import xy.command.instance.ArgumentGroupInstance; 10 | 11 | /** 12 | * A collection of command line model parts. 13 | * 14 | * @author olitank 15 | * 16 | */ 17 | public class ArgumentGroup extends AbstractCommandLinePart { 18 | 19 | private static final long serialVersionUID = 1L; 20 | 21 | /** 22 | * The title of this command line model part. 23 | */ 24 | public String title = ""; 25 | 26 | /** 27 | * The children command line model parts. 28 | */ 29 | public List parts = new ArrayList(); 30 | 31 | @Override 32 | public AbstractCommandLinePartInstance instantiate() { 33 | return new ArgumentGroupInstance(this); 34 | } 35 | 36 | @Override 37 | public void writetUsageText(Writer out) throws IOException { 38 | boolean first = true; 39 | for (AbstractCommandLinePart part : parts) { 40 | if (!first) { 41 | out.append(" "); 42 | } 43 | try { 44 | part.writetUsageText(out); 45 | } catch (IOException e) { 46 | throw new AssertionError(e); 47 | } 48 | first = false; 49 | } 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | return title; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/model/ArgumentPage.java: -------------------------------------------------------------------------------- 1 | package xy.command.model; 2 | 3 | import java.io.Serializable; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | import xy.command.instance.ArgumentPageInstance; 8 | import xy.command.ui.util.ValidationError; 9 | 10 | /** 11 | * A collection of command line model parts that should be displayed together. 12 | * 13 | * @author olitank 14 | * 15 | */ 16 | public class ArgumentPage implements Serializable { 17 | 18 | protected static final long serialVersionUID = 1L; 19 | 20 | /** 21 | * The title of this command line model part. 22 | */ 23 | public String title = "Settings"; 24 | 25 | /** 26 | * The children command line model parts. 27 | */ 28 | public List parts = new ArrayList(); 29 | 30 | @Override 31 | public String toString() { 32 | return title; 33 | } 34 | 35 | /** 36 | * Allows to validate the correctness of the properties of this command line 37 | * model page. 38 | * 39 | * @throws Exception If a property is not valid. 40 | */ 41 | public void validate() throws Exception { 42 | if ((title == null) || (title.trim().length() == 0)) { 43 | throw new ValidationError("Enter the title"); 44 | } 45 | } 46 | 47 | /** 48 | * @return An instance of this command line model page. 49 | */ 50 | public ArgumentPageInstance instantiate() { 51 | return new ArgumentPageInstance(this); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/model/Choice.java: -------------------------------------------------------------------------------- 1 | package xy.command.model; 2 | 3 | import java.io.IOException; 4 | import java.io.Writer; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import xy.command.instance.AbstractCommandLinePartInstance; 9 | import xy.command.instance.ChoiceInstance; 10 | import xy.command.ui.util.ValidationError; 11 | 12 | /** 13 | * A collection of selectable exclusive command line model parts. 14 | * 15 | * @author olitank 16 | * 17 | */ 18 | public class Choice extends AbstractCommandLinePart { 19 | 20 | protected static final long serialVersionUID = 1L; 21 | 22 | /** 23 | * The list of selectable exclusive command line model parts. 24 | */ 25 | public List options = new ArrayList(); 26 | 27 | /** 28 | * The title of this command line model part. 29 | */ 30 | public String title = ""; 31 | 32 | @Override 33 | public String toString() { 34 | return title; 35 | } 36 | 37 | @Override 38 | public void writetUsageText(Writer out) throws IOException { 39 | out.append("("); 40 | boolean first = true; 41 | for (ArgumentGroup optionEntry : options) { 42 | if (!first) { 43 | out.append(" | "); 44 | } 45 | optionEntry.writetUsageText(out); 46 | first = false; 47 | } 48 | out.append(")"); 49 | } 50 | 51 | @Override 52 | public void validate() throws Exception { 53 | if ((title == null) || (title.trim().length() == 0)) { 54 | throw new ValidationError("Enter the title"); 55 | } 56 | } 57 | 58 | @Override 59 | public AbstractCommandLinePartInstance instantiate() { 60 | return new ChoiceInstance(this); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/model/CommandLine.java: -------------------------------------------------------------------------------- 1 | package xy.command.model; 2 | 3 | import java.io.IOException; 4 | import java.io.StringWriter; 5 | import java.io.Writer; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | import xy.command.instance.CommandLineInstance; 10 | import xy.command.ui.util.ValidationError; 11 | 12 | /** 13 | * The command line model class. Allows to specify the structure of the argument 14 | * list of any command line program. 15 | * 16 | * @author olitank 17 | * 18 | */ 19 | public class CommandLine extends AbstractCommandLinePart { 20 | 21 | private static final long serialVersionUID = 1L; 22 | 23 | /** 24 | * Title of the generated command line GUI. 25 | */ 26 | public String title = ""; 27 | 28 | /** 29 | * The list of argument pages. 30 | */ 31 | public List arguments = new ArrayList(); 32 | 33 | @Override 34 | public void writetUsageText(Writer out) throws IOException { 35 | boolean first = true; 36 | for (ArgumentPage page : arguments) { 37 | for (AbstractCommandLinePart part : page.parts) { 38 | if (!first) { 39 | out.append(" "); 40 | } 41 | try { 42 | part.writetUsageText(out); 43 | } catch (IOException e) { 44 | throw new AssertionError(e); 45 | } 46 | first = false; 47 | } 48 | } 49 | } 50 | 51 | /** 52 | * Allows to validate the correctness of the properties of this command line 53 | * model. 54 | * 55 | * @throws Exception If a property is not valid. 56 | */ 57 | public void validate() throws Exception { 58 | if ((title == null) || (title.trim().length() == 0)) { 59 | throw new ValidationError("Enter the title"); 60 | } 61 | } 62 | 63 | /** 64 | * @return An instance of this command line model. 65 | */ 66 | public CommandLineInstance instantiate() { 67 | return new CommandLineInstance(this); 68 | } 69 | 70 | /** 71 | * @return A description of this command line model in a syntax close to the 72 | * POSIX Utility Argument Syntax. 73 | */ 74 | public String getUsageText() { 75 | StringWriter out = new StringWriter(); 76 | try { 77 | writetUsageText(out); 78 | } catch (Exception e2) { 79 | return ""; 80 | } 81 | return out.toString(); 82 | } 83 | 84 | @Override 85 | public String toString() { 86 | return title; 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/model/CommandLineProject.java: -------------------------------------------------------------------------------- 1 | package xy.command.model; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.io.OutputStream; 10 | 11 | import javax.swing.SwingUtilities; 12 | 13 | import com.thoughtworks.xstream.XStream; 14 | import com.thoughtworks.xstream.security.AnyTypePermission; 15 | 16 | import xy.command.ui.CommandLineUI; 17 | import xy.command.ui.CommandMonitoringDialog; 18 | import xy.command.ui.util.FileUtils; 19 | import xy.command.ui.util.ValidationError; 20 | 21 | /** 22 | * This class allows to specify the structure of a command and its arguments in 23 | * order to generate GUI wrappers. 24 | * 25 | * @author olitank 26 | * 27 | */ 28 | public class CommandLineProject extends CommandLine { 29 | 30 | private static final long serialVersionUID = 1L; 31 | 32 | /** 33 | * Relative or absolute path of the executable file. 34 | */ 35 | public File executablePath = new File(""); 36 | 37 | /** 38 | * The directory from which the command will be executed. 39 | */ 40 | public File executionDir = new File("."); 41 | 42 | /** 43 | * Allows to validate the correctness of the properties of this command line 44 | * project. 45 | * 46 | * @throws Exception If a property is not valid. 47 | */ 48 | public void validate() throws Exception { 49 | super.validate(); 50 | if ((executablePath == null) || (executablePath.getPath().trim().length() == 0)) { 51 | throw new ValidationError("Enter the executable path"); 52 | } 53 | if ((executionDir == null) || (executionDir.getPath().trim().length() == 0)) { 54 | throw new ValidationError("Enter the execution directory"); 55 | } 56 | } 57 | 58 | /** 59 | * Loads a command line project file. 60 | * 61 | * @param input The input file. 62 | * @throws IOException If an error occurs during the loading process. 63 | */ 64 | public void loadFromFile(File input) throws IOException { 65 | FileInputStream stream = new FileInputStream(input); 66 | try { 67 | loadFromStream(stream); 68 | } finally { 69 | try { 70 | stream.close(); 71 | } catch (Exception ignore) { 72 | } 73 | } 74 | } 75 | 76 | /** 77 | * Saves the current command line project to a file. 78 | * 79 | * @param output The output file. 80 | * @throws IOException If an error occurs during the saving process. 81 | */ 82 | public void saveToFile(File output) throws IOException { 83 | ByteArrayOutputStream memoryStream = new ByteArrayOutputStream(); 84 | saveToStream(memoryStream); 85 | FileOutputStream stream = new FileOutputStream(output); 86 | try { 87 | stream.write(memoryStream.toByteArray()); 88 | } finally { 89 | try { 90 | stream.close(); 91 | } catch (Exception ignore) { 92 | } 93 | } 94 | } 95 | 96 | /** 97 | * Loads the command line project from a stream. 98 | * 99 | * @param input The input stream. 100 | */ 101 | public void loadFromStream(InputStream input) { 102 | XStream xstream = new XStream(); 103 | xstream.addPermission(AnyTypePermission.ANY); 104 | CommandLineProject loaded = (CommandLineProject) xstream.fromXML(input); 105 | title = loaded.title; 106 | description = loaded.description; 107 | executablePath = loaded.executablePath; 108 | executionDir = loaded.executionDir; 109 | arguments = loaded.arguments; 110 | } 111 | 112 | /** 113 | * Saves the current command line project to a stream. 114 | * 115 | * @param output The output stream. 116 | * @throws IOException If an error occurs during the saving process. 117 | */ 118 | public void saveToStream(OutputStream output) throws IOException { 119 | XStream xstream = new XStream(); 120 | xstream.addPermission(AnyTypePermission.ANY); 121 | xstream.toXML(this, output); 122 | } 123 | 124 | /** 125 | * Open a command dialog allowing to test any command. 126 | */ 127 | public void openCommandMonitoringDialog() { 128 | SwingUtilities.invokeLater(new Runnable() { 129 | @Override 130 | public void run() { 131 | CommandMonitoringDialog d = new CommandMonitoringDialog(null, null, new File(".")); 132 | d.setVisible(true); 133 | } 134 | }); 135 | } 136 | 137 | /** 138 | * Generates a set of files allowing to open the GUI specified by the current 139 | * project. 140 | * 141 | * @param targetDirectory The directory in which the files will be generated. 142 | * @throws Exception If an error occurs during the process. 143 | */ 144 | public void distribute(File targetDirectory) throws Exception { 145 | if (CommandLineUI.NORMAL_EXE_FILE_PATH == null) { 146 | throw new UnsupportedOperationException("The default executable file is not known"); 147 | } 148 | 149 | File exeFile = new File(CommandLineUI.NORMAL_EXE_FILE_PATH); 150 | String fileExtension = FileUtils.getFileNameExtension(exeFile.getName()); 151 | String fileName = title + ((fileExtension.length() > 0) ? ("." + fileExtension) : ""); 152 | File targetExeFile = new File(targetDirectory, fileName); 153 | FileUtils.copy(exeFile, targetExeFile); 154 | File targetProjectFile = new File(targetExeFile.getPath() + "." + CommandLineUI.PROJECT_FILE_EXTENSION); 155 | saveToFile(targetProjectFile); 156 | } 157 | 158 | } 159 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/model/DirectoryArgument.java: -------------------------------------------------------------------------------- 1 | package xy.command.model; 2 | 3 | import java.io.IOException; 4 | import java.io.Writer; 5 | 6 | import javax.swing.JFileChooser; 7 | 8 | import xy.command.instance.AbstractCommandLinePartInstance; 9 | import xy.command.instance.DirectoryArgumentInstance; 10 | import xy.command.ui.util.ValidationError; 11 | 12 | /** 13 | * A directory path command line model part. 14 | * 15 | * @author olitank 16 | * 17 | */ 18 | public class DirectoryArgument extends AbstractCommandLinePart { 19 | 20 | protected static final long serialVersionUID = 1L; 21 | 22 | /** 23 | * The title of this command line model part. 24 | */ 25 | public String title = ""; 26 | 27 | /** 28 | * This value will provided by default. 29 | */ 30 | public String defaultValue = ""; 31 | 32 | @Override 33 | public String toString() { 34 | return title; 35 | } 36 | 37 | @Override 38 | public void writetUsageText(Writer out) throws IOException { 39 | out.write("<"); 40 | if ((title == null) || (title.trim().length() == 0)) { 41 | out.write("arg"); 42 | } else { 43 | out.write(title.replaceAll("\\s", "_")); 44 | } 45 | out.write(">"); 46 | } 47 | 48 | @Override 49 | public void validate() throws Exception { 50 | if ((title == null) || (title.trim().length() == 0)) { 51 | throw new ValidationError("Enter the title"); 52 | } 53 | } 54 | 55 | /** 56 | * Configures the file browser. 57 | * 58 | * @param fileChooser The file browser. 59 | */ 60 | public void configureFileChooser(JFileChooser fileChooser) { 61 | fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); 62 | } 63 | 64 | @Override 65 | public AbstractCommandLinePartInstance instantiate() { 66 | return new DirectoryArgumentInstance(this); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/model/FileArgument.java: -------------------------------------------------------------------------------- 1 | package xy.command.model; 2 | 3 | import java.io.IOException; 4 | import java.io.Writer; 5 | 6 | import javax.swing.JFileChooser; 7 | 8 | import xy.command.instance.AbstractCommandLinePartInstance; 9 | import xy.command.instance.FileArgumentInstance; 10 | import xy.command.ui.util.ValidationError; 11 | 12 | /** 13 | * A file path command line model part. 14 | * 15 | * @author olitank 16 | * 17 | */ 18 | public class FileArgument extends AbstractCommandLinePart { 19 | 20 | protected static final long serialVersionUID = 1L; 21 | 22 | /** 23 | * The title of this command line model part. 24 | */ 25 | public String title = ""; 26 | 27 | /** 28 | * This value will provided by default. 29 | */ 30 | public String defaultValue = ""; 31 | 32 | /** 33 | * Configures the file browser. 34 | * 35 | * @param fileChooser The file browser. 36 | */ 37 | public void configureFileChooser(JFileChooser fileChooser) { 38 | fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return title; 44 | } 45 | 46 | @Override 47 | public void writetUsageText(Writer out) throws IOException { 48 | out.write("<"); 49 | if ((title == null) || (title.trim().length() == 0)) { 50 | out.write("arg"); 51 | } else { 52 | out.write(title.replaceAll("\\s", "_")); 53 | } 54 | out.write(">"); 55 | } 56 | 57 | @Override 58 | public void validate() throws Exception { 59 | if ((title == null) || (title.trim().length() == 0)) { 60 | throw new ValidationError("Enter the title"); 61 | } 62 | } 63 | 64 | @Override 65 | public AbstractCommandLinePartInstance instantiate() { 66 | return new FileArgumentInstance(this); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/model/FixedArgument.java: -------------------------------------------------------------------------------- 1 | package xy.command.model; 2 | 3 | import java.io.IOException; 4 | import java.io.Writer; 5 | 6 | import xy.command.instance.AbstractCommandLinePartInstance; 7 | import xy.command.instance.FixedArgumentInstance; 8 | import xy.command.ui.util.ValidationError; 9 | 10 | /** 11 | * A fixed command line model part. 12 | * 13 | * @author olitank 14 | * 15 | */ 16 | public class FixedArgument extends AbstractCommandLinePart { 17 | 18 | protected static final long serialVersionUID = 1L; 19 | 20 | /** 21 | * This is the fixed argument value. 22 | */ 23 | public String value = ""; 24 | 25 | @Override 26 | public String toString() { 27 | return value; 28 | } 29 | 30 | @Override 31 | public void writetUsageText(Writer out) throws IOException { 32 | out.write(value); 33 | } 34 | 35 | @Override 36 | public void validate() throws Exception { 37 | if ((value == null) || (value.trim().length() == 0)) { 38 | throw new ValidationError("Enter the value"); 39 | } 40 | } 41 | 42 | @Override 43 | public AbstractCommandLinePartInstance instantiate() { 44 | return new FixedArgumentInstance(this); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/model/InputArgument.java: -------------------------------------------------------------------------------- 1 | package xy.command.model; 2 | 3 | import java.io.IOException; 4 | import java.io.Writer; 5 | 6 | import xy.command.instance.AbstractCommandLinePartInstance; 7 | import xy.command.instance.InputArgumentInstance; 8 | import xy.command.ui.util.ValidationError; 9 | 10 | /** 11 | * A text input command line model part. 12 | * 13 | * @author olitank 14 | * 15 | */ 16 | public class InputArgument extends AbstractCommandLinePart { 17 | 18 | protected static final long serialVersionUID = 1L; 19 | 20 | /** 21 | * The title of this command line model part. 22 | */ 23 | public String title = ""; 24 | 25 | /** 26 | * This value will provided by default. 27 | */ 28 | public String defaultValue = ""; 29 | 30 | @Override 31 | public String toString() { 32 | return title; 33 | } 34 | 35 | @Override 36 | public void writetUsageText(Writer out) throws IOException { 37 | out.write("<"); 38 | if ((title == null) || (title.trim().length() == 0)) { 39 | out.write("arg"); 40 | } else { 41 | out.write(title.replaceAll("\\s", "_")); 42 | } 43 | out.write(">"); 44 | } 45 | 46 | @Override 47 | public void validate() throws Exception { 48 | if ((title == null) || (title.trim().length() == 0)) { 49 | throw new ValidationError("Enter the title"); 50 | } 51 | } 52 | 53 | @Override 54 | public AbstractCommandLinePartInstance instantiate() { 55 | return new InputArgumentInstance(this); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/model/MultiplePart.java: -------------------------------------------------------------------------------- 1 | package xy.command.model; 2 | 3 | import java.io.IOException; 4 | import java.io.Writer; 5 | 6 | import xy.command.instance.AbstractCommandLinePartInstance; 7 | import xy.command.instance.MultiplePartInstance; 8 | import xy.command.ui.util.ValidationError; 9 | 10 | /** 11 | * A collection of command line model parts that can be instantiated multiple 12 | * times. 13 | * 14 | * @author olitank 15 | * 16 | */ 17 | public class MultiplePart extends ArgumentGroup { 18 | 19 | protected static final long serialVersionUID = 1L; 20 | 21 | @Override 22 | public void validate() throws Exception { 23 | if ((title == null) || (title.trim().length() == 0)) { 24 | throw new ValidationError("Enter the title"); 25 | } 26 | } 27 | 28 | @Override 29 | public void writetUsageText(Writer out) throws IOException { 30 | out.write("("); 31 | super.writetUsageText(out); 32 | out.write(" ...)"); 33 | } 34 | 35 | @Override 36 | public AbstractCommandLinePartInstance instantiate() { 37 | return new MultiplePartInstance(this); 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return title; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/model/OptionalPart.java: -------------------------------------------------------------------------------- 1 | package xy.command.model; 2 | 3 | import java.io.IOException; 4 | import java.io.Writer; 5 | 6 | import xy.command.instance.AbstractCommandLinePartInstance; 7 | import xy.command.instance.OptionalPartInstance; 8 | import xy.command.ui.util.ValidationError; 9 | 10 | /** 11 | * A collection of command line model parts that may not be instantiated. 12 | * 13 | * @author olitank 14 | * 15 | */ 16 | public class OptionalPart extends ArgumentGroup { 17 | 18 | protected static final long serialVersionUID = 1L; 19 | 20 | /** 21 | * If true, the parts will be instantiated by default. 22 | */ 23 | public boolean activeByDefault = false; 24 | 25 | @Override 26 | public void validate() throws Exception { 27 | if ((title == null) || (title.trim().length() == 0)) { 28 | throw new ValidationError("Enter the title"); 29 | } 30 | } 31 | 32 | @Override 33 | public void writetUsageText(Writer out) throws IOException { 34 | out.write("["); 35 | super.writetUsageText(out); 36 | out.write("]"); 37 | } 38 | 39 | @Override 40 | public AbstractCommandLinePartInstance instantiate() { 41 | return new OptionalPartInstance(this); 42 | } 43 | 44 | @Override 45 | public String toString() { 46 | return title; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/ui/CommandLineUI.java: -------------------------------------------------------------------------------- 1 | package xy.command.ui; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import javax.swing.SwingUtilities; 6 | 7 | import xy.command.instance.ArgumentGroupInstance; 8 | import xy.command.instance.CommandLineInstance; 9 | import xy.command.model.CommandLineProject; 10 | import xy.reflect.ui.CustomizedUI; 11 | import xy.reflect.ui.control.swing.customizer.SwingCustomizer; 12 | import xy.reflect.ui.info.type.source.ITypeInfoSource; 13 | 14 | /** 15 | * The class specifying how the command line project and instance GUIs should 16 | * look and behave. The class is also responsible for generating the above GUIs. 17 | * 18 | * @author olitank 19 | * 20 | */ 21 | public class CommandLineUI extends CustomizedUI { 22 | 23 | public static void main(String[] args) throws Exception { 24 | final CommandLineUI ui = new CommandLineUI(); 25 | if ((CURRENT_EXE_FILE_PATH != null) && (NORMAL_EXE_FILE_PATH != null)) { 26 | File currentExeFile = new File(CURRENT_EXE_FILE_PATH); 27 | File normalExeFile = new File(NORMAL_EXE_FILE_PATH); 28 | boolean executingDistribution = !currentExeFile.getCanonicalPath().equals(normalExeFile.getCanonicalPath()); 29 | if (executingDistribution) { 30 | CommandLineProject object = new CommandLineProject(); 31 | object.loadFromFile(new File(CURRENT_EXE_FILE_PATH + "." + PROJECT_FILE_EXTENSION)); 32 | SwingUtilities.invokeLater(new Runnable() { 33 | @Override 34 | public void run() { 35 | ui.getRenderer().openObjectFrame(object.instantiate()); 36 | } 37 | }); 38 | return; 39 | } 40 | } 41 | CommandLineProject object = new CommandLineProject(); 42 | if (args.length >= 1) { 43 | object.loadFromFile(new File(args[0])); 44 | } 45 | SwingUtilities.invokeLater(new Runnable() { 46 | @Override 47 | public void run() { 48 | if ((args.length >= 2) && (args[1].equals("--instantiate"))) { 49 | ui.getRenderer().openObjectFrame(object.instantiate()); 50 | } else { 51 | ui.getRenderer().openObjectFrame(object); 52 | } 53 | } 54 | }); 55 | } 56 | 57 | public static final String NORMAL_EXE_FILE_PATH = System.getProperty("xy.command.ui.defaultExeFile"); 58 | public static final String CURRENT_EXE_FILE_PATH = System.getProperty("xy.command.ui.exeFile"); 59 | public static final String PROJECT_FILE_EXTENSION = "cml"; 60 | 61 | private static final String GUI_CUSTOMIZATIONS_RESOURCE_NAME = "commandLine.icu"; 62 | private static final String GUI_CUSTOMIZATIONS_RESOURCE_DIRECTORY = System 63 | .getProperty("xy.command.ui.alternateUICustomizationsFileDirectory"); 64 | 65 | private SwingCustomizer renderer; 66 | 67 | /** 68 | * The default constructor. It initializes the GUI system. 69 | */ 70 | public CommandLineUI() { 71 | if (GUI_CUSTOMIZATIONS_RESOURCE_DIRECTORY != null) { 72 | renderer = new SwingCustomizer(this, 73 | GUI_CUSTOMIZATIONS_RESOURCE_DIRECTORY + "/" + GUI_CUSTOMIZATIONS_RESOURCE_NAME); 74 | } else { 75 | try { 76 | getInfoCustomizations().loadFromStream(xy.command.ui.resource.ClassInPackage.class 77 | .getResourceAsStream(GUI_CUSTOMIZATIONS_RESOURCE_NAME), null); 78 | } catch (IOException e) { 79 | throw new AssertionError(e); 80 | } 81 | renderer = new SwingCustomizer(this, null); 82 | } 83 | } 84 | 85 | /** 86 | * @return The GUI renderer object. 87 | */ 88 | public SwingCustomizer getRenderer() { 89 | return renderer; 90 | } 91 | 92 | @Override 93 | public ITypeInfoSource getTypeInfoSource(Object object) { 94 | if (object instanceof CommandLineInstance) { 95 | return new TypeInfoSourceFromCommandLine(((CommandLineInstance) object).model, null); 96 | } else if (object instanceof ArgumentGroupInstance) { 97 | return new TypeInfoSourceFromArgumentGroup(((ArgumentGroupInstance) object).model, null); 98 | } else { 99 | return super.getTypeInfoSource(object); 100 | } 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/ui/CommandMonitoringDialog.java: -------------------------------------------------------------------------------- 1 | package xy.command.ui; 2 | 3 | import java.awt.BorderLayout; 4 | import java.awt.Color; 5 | import java.awt.Component; 6 | import java.awt.FlowLayout; 7 | import java.awt.Window; 8 | import java.awt.event.ActionEvent; 9 | import java.awt.event.ActionListener; 10 | import java.awt.image.BufferedImage; 11 | import java.io.ByteArrayOutputStream; 12 | import java.io.File; 13 | import java.io.IOException; 14 | import java.io.OutputStream; 15 | import java.lang.reflect.InvocationTargetException; 16 | 17 | import javax.swing.JButton; 18 | import javax.swing.JCheckBox; 19 | import javax.swing.JDialog; 20 | import javax.swing.JPanel; 21 | import javax.swing.JScrollPane; 22 | import javax.swing.JTextField; 23 | import javax.swing.JTextPane; 24 | import javax.swing.SwingUtilities; 25 | import javax.swing.border.EmptyBorder; 26 | import javax.swing.event.DocumentEvent; 27 | import javax.swing.event.DocumentListener; 28 | import javax.swing.plaf.ComponentUI; 29 | import javax.swing.text.AttributeSet; 30 | import javax.swing.text.BadLocationException; 31 | import javax.swing.text.DefaultCaret; 32 | import javax.swing.text.Document; 33 | import javax.swing.text.Element; 34 | import javax.swing.text.SimpleAttributeSet; 35 | import javax.swing.text.StyleConstants; 36 | 37 | import xy.command.ui.util.CommandUIUtils; 38 | import xy.reflect.ui.util.ReflectionUIError; 39 | 40 | /** 41 | * A dialog allowing to execute and monitor (view text output, errors, return 42 | * status, ...) commands. 43 | * 44 | * @author olitank 45 | * 46 | */ 47 | public class CommandMonitoringDialog extends JDialog { 48 | 49 | protected static final long serialVersionUID = 1L; 50 | 51 | protected final JPanel contentPanel = new JPanel(); 52 | protected Thread commandThread; 53 | protected JButton killOrCloseButton; 54 | protected JTextPane logTextControl; 55 | protected JCheckBox autoScrollControl; 56 | protected File workingDir; 57 | protected boolean killed = false; 58 | protected JPanel commandPanel; 59 | protected JTextField commandTextControl; 60 | protected JButton runButton; 61 | 62 | public static void main(String[] args) { 63 | try { 64 | 65 | CommandMonitoringDialog dialog = new CommandMonitoringDialog(null, "ping -n 10 localhost", null); 66 | dialog.setVisible(true); 67 | } catch (Exception e) { 68 | e.printStackTrace(); 69 | } 70 | } 71 | 72 | /** 73 | * 74 | * Creates the dialog. 75 | */ 76 | 77 | public CommandMonitoringDialog(Window owner, String command, File workingDir) { 78 | super(owner); 79 | this.workingDir = workingDir; 80 | 81 | setTitle("Command Execution"); 82 | setIconImage(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)); 83 | setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); 84 | setSize(640, 480); 85 | setLocationRelativeTo(null); 86 | getContentPane().setLayout(new BorderLayout()); 87 | contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); 88 | getContentPane().add(contentPanel, BorderLayout.CENTER); 89 | contentPanel.setLayout(new BorderLayout(0, 0)); 90 | { 91 | logTextControl = new NonWrappingTextPane(); 92 | logTextControl.setEditable(false); 93 | contentPanel.add(new JScrollPane(logTextControl)); 94 | } 95 | { 96 | 97 | JPanel buttonPane = new JPanel(); 98 | getContentPane().add(buttonPane, BorderLayout.SOUTH); 99 | buttonPane.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5)); 100 | { 101 | killOrCloseButton = new JButton(); 102 | killOrCloseButton.setText("Close"); 103 | killOrCloseButton.addActionListener(new ActionListener() { 104 | public void actionPerformed(ActionEvent e) { 105 | killOrClose(); 106 | } 107 | }); 108 | { 109 | { 110 | autoScrollControl = new JCheckBox("Auto-Scroll"); 111 | autoScrollControl.setSelected(true); 112 | autoScrollControl.addActionListener(new ActionListener() { 113 | @Override 114 | public void actionPerformed(ActionEvent e) { 115 | onAutoScrollChange(); 116 | } 117 | }); 118 | buttonPane.add(autoScrollControl); 119 | onAutoScrollChange(); 120 | } 121 | } 122 | killOrCloseButton.setActionCommand(""); 123 | buttonPane.add(killOrCloseButton); 124 | getRootPane().setDefaultButton(killOrCloseButton); 125 | } 126 | } 127 | { 128 | commandPanel = new JPanel(); 129 | getContentPane().add(commandPanel, BorderLayout.NORTH); 130 | commandPanel.setLayout(new BorderLayout(0, 0)); 131 | { 132 | runButton = new JButton("Run"); 133 | commandPanel.add(runButton, BorderLayout.WEST); 134 | runButton.addActionListener(new ActionListener() { 135 | @Override 136 | public void actionPerformed(ActionEvent e) { 137 | launchCommand(); 138 | } 139 | }); 140 | } 141 | { 142 | commandTextControl = new JTextField(); 143 | commandPanel.add(commandTextControl, BorderLayout.CENTER); 144 | } 145 | } 146 | limitLines(); 147 | if (command != null) { 148 | commandTextControl.setText(command); 149 | SwingUtilities.invokeLater(new Runnable() { 150 | @Override 151 | public void run() { 152 | launchCommand(); 153 | } 154 | }); 155 | } 156 | } 157 | 158 | @Override 159 | public void dispose() { 160 | if ((commandThread != null) && commandThread.isAlive()) { 161 | kill(); 162 | } 163 | super.dispose(); 164 | } 165 | 166 | protected void onAutoScrollChange() { 167 | DefaultCaret caret = (DefaultCaret) logTextControl.getCaret(); 168 | caret.setUpdatePolicy(autoScrollControl.isSelected() ? DefaultCaret.ALWAYS_UPDATE : DefaultCaret.NEVER_UPDATE); 169 | } 170 | 171 | protected void limitLines() { 172 | logTextControl.getDocument().addDocumentListener(new DocumentListener() { 173 | 174 | @Override 175 | public void insertUpdate(DocumentEvent e) { 176 | update(); 177 | } 178 | 179 | @Override 180 | public void removeUpdate(DocumentEvent e) { 181 | update(); 182 | } 183 | 184 | @Override 185 | public void changedUpdate(DocumentEvent e) { 186 | update(); 187 | } 188 | 189 | protected void update() { 190 | SwingUtilities.invokeLater(new Runnable() { 191 | @Override 192 | public void run() { 193 | limitLines(); 194 | } 195 | }); 196 | } 197 | 198 | protected void limitLines() { 199 | Document document = logTextControl.getDocument(); 200 | Element root = document.getDefaultRootElement(); 201 | while (root.getElementCount() > getMaximumlineCount()) { 202 | Element line = root.getElement(0); 203 | int end = line.getEndOffset(); 204 | try { 205 | document.remove(0, end); 206 | } catch (BadLocationException ble) { 207 | throw new AssertionError(ble); 208 | } 209 | } 210 | } 211 | }); 212 | } 213 | 214 | protected int getMaximumlineCount() { 215 | return 10000; 216 | } 217 | 218 | protected void launchCommand() { 219 | killOrCloseButton.setText("Kill"); 220 | runButton.setEnabled(false); 221 | commandTextControl.setEnabled(false); 222 | logTextControl.setText(""); 223 | commandThread = new Thread("Executing: " + commandTextControl.getText()) { 224 | @Override 225 | public void run() { 226 | try { 227 | write("\n", getTextAttributes(Color.GREEN.darker().darker())); 228 | int status = CommandUIUtils.runCommand(commandTextControl.getText(), true, 229 | new LogOutputStream(getTextAttributes(Color.BLACK)), 230 | new LogOutputStream(getTextAttributes(Color.RED)), workingDir); 231 | if (!killed) { 232 | write("\n (status=" + status + ")\n", 233 | getTextAttributes(Color.GREEN.darker().darker())); 234 | } 235 | } catch (final Throwable t) { 236 | if (!killed) { 237 | write("\n:\n" + new ReflectionUIError(t), getTextAttributes(Color.MAGENTA)); 238 | } 239 | } 240 | SwingUtilities.invokeLater(new Runnable() { 241 | @Override 242 | public void run() { 243 | commandTerminated(); 244 | } 245 | }); 246 | } 247 | }; 248 | commandThread.start(); 249 | } 250 | 251 | protected void commandTerminated() { 252 | killOrCloseButton.setText("Close"); 253 | runButton.setEnabled(true); 254 | commandTextControl.setEnabled(true); 255 | } 256 | 257 | protected AttributeSet getTextAttributes(Color color) { 258 | SimpleAttributeSet attributes = new SimpleAttributeSet(); 259 | StyleConstants.setForeground(attributes, color); 260 | return attributes; 261 | } 262 | 263 | protected void killOrClose() { 264 | if ((commandThread != null) && commandThread.isAlive()) { 265 | kill(); 266 | } else { 267 | CommandMonitoringDialog.this.dispose(); 268 | } 269 | } 270 | 271 | protected void kill() { 272 | write("\n\n\n\n", getTextAttributes(Color.RED)); 273 | killed = true; 274 | commandThread.interrupt(); 275 | } 276 | 277 | protected void write(final String string, final AttributeSet textAttributes) { 278 | Runnable runnable = new Runnable() { 279 | @Override 280 | public void run() { 281 | Document doc = logTextControl.getDocument(); 282 | try { 283 | doc.insertString(doc.getLength(), string, textAttributes); 284 | } catch (BadLocationException e) { 285 | throw new AssertionError(e); 286 | } 287 | } 288 | }; 289 | if (SwingUtilities.isEventDispatchThread()) { 290 | runnable.run(); 291 | } else { 292 | try { 293 | SwingUtilities.invokeAndWait(runnable); 294 | } catch (InterruptedException e) { 295 | throw new AssertionError(e); 296 | } catch (InvocationTargetException e) { 297 | throw new AssertionError(e); 298 | } 299 | } 300 | } 301 | 302 | protected static class NonWrappingTextPane extends JTextPane { 303 | 304 | private static final long serialVersionUID = 1L; 305 | 306 | public NonWrappingTextPane() { 307 | super(); 308 | } 309 | 310 | // Override getScrollableTracksViewportWidth 311 | // to preserve the full width of the text 312 | public boolean getScrollableTracksViewportWidth() { 313 | Component parent = getParent(); 314 | ComponentUI ui = getUI(); 315 | return parent != null ? (ui.getPreferredSize(this).width <= parent.getSize().width) : true; 316 | } 317 | 318 | } 319 | 320 | protected class LogOutputStream extends OutputStream { 321 | 322 | private AttributeSet textAttributes; 323 | 324 | private final ByteArrayOutputStream buf = new ByteArrayOutputStream(); 325 | 326 | public LogOutputStream(AttributeSet textAttributes) { 327 | this.textAttributes = textAttributes; 328 | } 329 | 330 | @Override 331 | public void flush() throws IOException { 332 | CommandMonitoringDialog.this.write(buf.toString("UTF-8"), textAttributes); 333 | buf.reset(); 334 | } 335 | 336 | @Override 337 | public void write(int b) throws IOException { 338 | buf.write(b); 339 | if (buf.toString().endsWith(System.lineSeparator())) { 340 | flush(); 341 | } 342 | } 343 | } 344 | 345 | } 346 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/ui/FieldInfoFromChoice.java: -------------------------------------------------------------------------------- 1 | package xy.command.ui; 2 | 3 | import java.util.Collections; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import xy.command.instance.ArgumentGroupInstance; 8 | import xy.command.instance.ChoiceInstance; 9 | import xy.command.instance.CommandLineInstance; 10 | import xy.command.model.AbstractCommandLinePart; 11 | import xy.command.model.ArgumentGroup; 12 | import xy.command.model.ArgumentPage; 13 | import xy.command.model.Choice; 14 | import xy.command.model.CommandLine; 15 | import xy.reflect.ui.info.InfoCategory; 16 | import xy.reflect.ui.info.ValueReturnMode; 17 | import xy.reflect.ui.info.field.IFieldInfo; 18 | import xy.reflect.ui.info.filter.IInfoFilter; 19 | import xy.reflect.ui.info.method.IMethodInfo; 20 | import xy.reflect.ui.info.type.ITypeInfo; 21 | import xy.reflect.ui.info.type.source.SpecificitiesIdentifier; 22 | import xy.reflect.ui.util.ReflectionUIError; 23 | 24 | /** 25 | * Specifies how a {@link Choice} should be displayed in a GUI. 26 | * 27 | * @author olitank 28 | * 29 | */ 30 | public class FieldInfoFromChoice implements IFieldInfo { 31 | 32 | private Choice choice; 33 | private ArgumentPage argumentPage; 34 | private AbstractCommandLinePart containingPart; 35 | private CommandLineUI commandLineUI; 36 | private ITypeInfo commandLineTypeInfo; 37 | 38 | public FieldInfoFromChoice(CommandLineUI commandLineUI, Choice choice, ArgumentPage argumentPage, 39 | AbstractCommandLinePart containingPart, ITypeInfo commandLineTypeInfo) { 40 | this.commandLineUI = commandLineUI; 41 | this.choice = choice; 42 | this.argumentPage = argumentPage; 43 | this.containingPart = containingPart; 44 | this.commandLineTypeInfo = commandLineTypeInfo; 45 | } 46 | 47 | @Override 48 | public String getName() { 49 | return choice.getClass().getName() + choice.hashCode(); 50 | } 51 | 52 | @Override 53 | public String getCaption() { 54 | return choice.title; 55 | } 56 | 57 | @Override 58 | public String getOnlineHelp() { 59 | return choice.description; 60 | } 61 | 62 | @Override 63 | public Map getSpecificProperties() { 64 | return Collections.emptyMap(); 65 | } 66 | 67 | @Override 68 | public List getAlternativeConstructors(Object object) { 69 | return null; 70 | } 71 | 72 | @Override 73 | public List getAlternativeListItemConstructors(Object object) { 74 | return null; 75 | } 76 | 77 | @Override 78 | public ITypeInfo getType() { 79 | return commandLineUI.getTypeInfo(new TypeInfoSourceFromChoice(commandLineUI, 80 | new SpecificitiesIdentifier(commandLineTypeInfo.getName(), getName()), choice)); 81 | } 82 | 83 | @Override 84 | public Object getValue(Object object) { 85 | if (containingPart instanceof CommandLine) { 86 | CommandLineInstance commandLineInstance = (CommandLineInstance) object; 87 | int argumentPageIndex = ((CommandLine) containingPart).arguments.indexOf(argumentPage); 88 | int indexInArgumentPage = argumentPage.parts.indexOf(choice); 89 | ChoiceInstance choiceInstance = (ChoiceInstance) commandLineInstance.argumentPageInstances 90 | .get(argumentPageIndex).partInstances.get(indexInArgumentPage); 91 | return choiceInstance.chosenPartInstance; 92 | } else if (containingPart instanceof ArgumentGroup) { 93 | ArgumentGroupInstance argumentGroupInstance = (ArgumentGroupInstance) object; 94 | int indexInArgumentGroup = ((ArgumentGroup) containingPart).parts.indexOf(choice); 95 | ChoiceInstance choiceInstance = (ChoiceInstance) argumentGroupInstance.partInstances 96 | .get(indexInArgumentGroup); 97 | return choiceInstance.chosenPartInstance; 98 | } else { 99 | throw new ReflectionUIError(); 100 | } 101 | } 102 | 103 | @Override 104 | public void setValue(Object object, Object value) { 105 | if (containingPart instanceof CommandLine) { 106 | CommandLineInstance commandLineInstance = (CommandLineInstance) object; 107 | int argumentPageIndex = ((CommandLine) containingPart).arguments.indexOf(argumentPage); 108 | int indexInArgumentPage = argumentPage.parts.indexOf(choice); 109 | ChoiceInstance choiceInstance = (ChoiceInstance) commandLineInstance.argumentPageInstances 110 | .get(argumentPageIndex).partInstances.get(indexInArgumentPage); 111 | choiceInstance.chosenPartInstance = (ArgumentGroupInstance) value; 112 | } else if (containingPart instanceof ArgumentGroup) { 113 | ArgumentGroupInstance argumentGroupInstance = (ArgumentGroupInstance) object; 114 | int indexInArgumentGroup = ((ArgumentGroup) containingPart).parts.indexOf(choice); 115 | ChoiceInstance choiceInstance = (ChoiceInstance) argumentGroupInstance.partInstances 116 | .get(indexInArgumentGroup); 117 | choiceInstance.chosenPartInstance = (ArgumentGroupInstance) value; 118 | } else { 119 | throw new ReflectionUIError(); 120 | } 121 | } 122 | 123 | @Override 124 | public boolean hasValueOptions(Object object) { 125 | return false; 126 | } 127 | 128 | @Override 129 | public Object[] getValueOptions(Object object) { 130 | return null; 131 | } 132 | 133 | @Override 134 | public Runnable getNextUpdateCustomUndoJob(Object object, Object newValue) { 135 | return null; 136 | } 137 | 138 | @Override 139 | public Runnable getPreviousUpdateCustomRedoJob(Object object, Object newValue) { 140 | return null; 141 | } 142 | 143 | @Override 144 | public boolean isNullValueDistinct() { 145 | return false; 146 | } 147 | 148 | @Override 149 | public boolean isGetOnly() { 150 | return false; 151 | } 152 | 153 | @Override 154 | public boolean isTransient() { 155 | return false; 156 | } 157 | 158 | @Override 159 | public String getNullValueLabel() { 160 | return null; 161 | } 162 | 163 | @Override 164 | public ValueReturnMode getValueReturnMode() { 165 | return ValueReturnMode.CALCULATED; 166 | } 167 | 168 | @Override 169 | public InfoCategory getCategory() { 170 | if (!(containingPart instanceof CommandLine)) { 171 | return null; 172 | } 173 | int argumentPageIndex = ((CommandLine) containingPart).arguments.indexOf(argumentPage); 174 | return new InfoCategory(argumentPage.title, argumentPageIndex, null); 175 | } 176 | 177 | @Override 178 | public boolean isFormControlMandatory() { 179 | return false; 180 | } 181 | 182 | @Override 183 | public boolean isFormControlEmbedded() { 184 | return true; 185 | } 186 | 187 | @Override 188 | public IInfoFilter getFormControlFilter() { 189 | return IInfoFilter.DEFAULT; 190 | } 191 | 192 | @Override 193 | public long getAutoUpdatePeriodMilliseconds() { 194 | return -1; 195 | } 196 | 197 | @Override 198 | public boolean isValueValidityDetectionEnabled() { 199 | return false; 200 | } 201 | 202 | @Override 203 | public boolean isHidden() { 204 | return false; 205 | } 206 | 207 | @Override 208 | public double getDisplayAreaHorizontalWeight() { 209 | return 1; 210 | } 211 | 212 | @Override 213 | public double getDisplayAreaVerticalWeight() { 214 | return 0; 215 | } 216 | 217 | @Override 218 | public boolean isDisplayAreaHorizontallyFilled() { 219 | return true; 220 | } 221 | 222 | @Override 223 | public boolean isDisplayAreaVerticallyFilled() { 224 | return false; 225 | } 226 | 227 | @Override 228 | public void onControlVisibilityChange(Object object, boolean visible) { 229 | } 230 | 231 | } 232 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/ui/FieldInfoFromDirectoryArgument.java: -------------------------------------------------------------------------------- 1 | package xy.command.ui; 2 | 3 | import java.io.File; 4 | import java.util.Collections; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | import xy.command.instance.ArgumentGroupInstance; 10 | import xy.command.instance.CommandLineInstance; 11 | import xy.command.instance.DirectoryArgumentInstance; 12 | import xy.command.model.AbstractCommandLinePart; 13 | import xy.command.model.ArgumentGroup; 14 | import xy.command.model.ArgumentPage; 15 | import xy.command.model.CommandLine; 16 | import xy.command.model.DirectoryArgument; 17 | import xy.reflect.ui.ReflectionUI; 18 | import xy.reflect.ui.control.swing.plugin.FileBrowserPlugin; 19 | import xy.reflect.ui.control.swing.plugin.FileBrowserPlugin.SelectionModeConfiguration; 20 | import xy.reflect.ui.info.InfoCategory; 21 | import xy.reflect.ui.info.ValueReturnMode; 22 | import xy.reflect.ui.info.field.IFieldInfo; 23 | import xy.reflect.ui.info.filter.IInfoFilter; 24 | import xy.reflect.ui.info.method.IMethodInfo; 25 | import xy.reflect.ui.info.type.DefaultTypeInfo; 26 | import xy.reflect.ui.info.type.ITypeInfo; 27 | import xy.reflect.ui.info.type.source.JavaTypeInfoSource; 28 | import xy.reflect.ui.info.type.source.SpecificitiesIdentifier; 29 | import xy.reflect.ui.util.ReflectionUIError; 30 | import xy.reflect.ui.util.ReflectionUIUtils; 31 | 32 | /** 33 | * Specifies how a {@link DirectoryArgument} should be displayed in a GUI. 34 | * 35 | * @author olitank 36 | * 37 | */ 38 | public class FieldInfoFromDirectoryArgument implements IFieldInfo { 39 | 40 | private DirectoryArgument directoryArgument; 41 | private ArgumentPage argumentPage; 42 | private AbstractCommandLinePart containingPart; 43 | private ReflectionUI reflectionUI; 44 | private ITypeInfo commandLineTypeInfo; 45 | 46 | public FieldInfoFromDirectoryArgument(ReflectionUI reflectionUI, DirectoryArgument directoryArgument, 47 | ArgumentPage argumentPage, AbstractCommandLinePart containingPart, ITypeInfo commandLineTypeInfo) { 48 | this.reflectionUI = reflectionUI; 49 | this.directoryArgument = directoryArgument; 50 | this.argumentPage = argumentPage; 51 | this.containingPart = containingPart; 52 | this.commandLineTypeInfo = commandLineTypeInfo; 53 | } 54 | 55 | @Override 56 | public String getName() { 57 | return directoryArgument.getClass().getName() + directoryArgument.hashCode(); 58 | } 59 | 60 | @Override 61 | public String getCaption() { 62 | return directoryArgument.title; 63 | } 64 | 65 | @Override 66 | public String getOnlineHelp() { 67 | return directoryArgument.description; 68 | } 69 | 70 | @Override 71 | public Map getSpecificProperties() { 72 | return Collections.emptyMap(); 73 | } 74 | 75 | @Override 76 | public List getAlternativeConstructors(Object object) { 77 | return null; 78 | } 79 | 80 | @Override 81 | public List getAlternativeListItemConstructors(Object object) { 82 | return null; 83 | } 84 | 85 | @Override 86 | public ITypeInfo getType() { 87 | return new DefaultTypeInfo(reflectionUI, new JavaTypeInfoSource(File.class, 88 | new SpecificitiesIdentifier(commandLineTypeInfo.getName(), getName()))) { 89 | 90 | @Override 91 | public Map getSpecificProperties() { 92 | Map result = new HashMap(super.getSpecificProperties()); 93 | FileBrowserPlugin plugin = new FileBrowserPlugin(); 94 | FileBrowserPlugin.FileBrowserConfiguration c = new FileBrowserPlugin.FileBrowserConfiguration(); 95 | c.selectionMode = SelectionModeConfiguration.DIRECTORIES_ONLY; 96 | ReflectionUIUtils.setFieldControlPluginIdentifier(result, plugin.getIdentifier()); 97 | ReflectionUIUtils.setFieldControlPluginConfiguration(result, plugin.getIdentifier(), c); 98 | return result; 99 | } 100 | 101 | }; 102 | } 103 | 104 | @Override 105 | public Object getValue(Object object) { 106 | if (containingPart instanceof CommandLine) { 107 | CommandLineInstance commandLineInstance = (CommandLineInstance) object; 108 | int argumentPageIndex = ((CommandLine) containingPart).arguments.indexOf(argumentPage); 109 | int indexInArgumentPage = argumentPage.parts.indexOf(directoryArgument); 110 | DirectoryArgumentInstance directoryArgumentInstance = (DirectoryArgumentInstance) commandLineInstance.argumentPageInstances 111 | .get(argumentPageIndex).partInstances.get(indexInArgumentPage); 112 | if (directoryArgumentInstance.value == null) { 113 | return null; 114 | } else { 115 | return new File(directoryArgumentInstance.value); 116 | } 117 | } else if (containingPart instanceof ArgumentGroup) { 118 | ArgumentGroupInstance argumentGroupInstance = (ArgumentGroupInstance) object; 119 | int indexInArgumentGroup = ((ArgumentGroup) containingPart).parts.indexOf(directoryArgument); 120 | DirectoryArgumentInstance directoryArgumentInstance = (DirectoryArgumentInstance) argumentGroupInstance.partInstances 121 | .get(indexInArgumentGroup); 122 | if (directoryArgumentInstance.value == null) { 123 | return null; 124 | } else { 125 | return new File(directoryArgumentInstance.value); 126 | } 127 | } else { 128 | throw new ReflectionUIError(); 129 | } 130 | } 131 | 132 | @Override 133 | public void setValue(Object object, Object value) { 134 | if (containingPart instanceof CommandLine) { 135 | CommandLineInstance commandLineInstance = (CommandLineInstance) object; 136 | int argumentPageIndex = ((CommandLine) containingPart).arguments.indexOf(argumentPage); 137 | int indexInArgumentPage = argumentPage.parts.indexOf(directoryArgument); 138 | DirectoryArgumentInstance directoryArgumentInstance = (DirectoryArgumentInstance) commandLineInstance.argumentPageInstances 139 | .get(argumentPageIndex).partInstances.get(indexInArgumentPage); 140 | if (value == null) { 141 | directoryArgumentInstance.value = null; 142 | } else { 143 | directoryArgumentInstance.value = ((File) value).getPath(); 144 | } 145 | } else if (containingPart instanceof ArgumentGroup) { 146 | ArgumentGroupInstance argumentGroupInstance = (ArgumentGroupInstance) object; 147 | int indexInArgumentGroup = ((ArgumentGroup) containingPart).parts.indexOf(directoryArgument); 148 | DirectoryArgumentInstance directoryArgumentInstance = (DirectoryArgumentInstance) argumentGroupInstance.partInstances 149 | .get(indexInArgumentGroup); 150 | if (value == null) { 151 | directoryArgumentInstance.value = null; 152 | } else { 153 | directoryArgumentInstance.value = ((File) value).getPath(); 154 | } 155 | } else { 156 | throw new ReflectionUIError(); 157 | } 158 | } 159 | 160 | @Override 161 | public boolean hasValueOptions(Object object) { 162 | return false; 163 | } 164 | 165 | @Override 166 | public Object[] getValueOptions(Object object) { 167 | return null; 168 | } 169 | 170 | @Override 171 | public Runnable getNextUpdateCustomUndoJob(Object object, Object newValue) { 172 | return null; 173 | } 174 | 175 | @Override 176 | public Runnable getPreviousUpdateCustomRedoJob(Object object, Object newValue) { 177 | return null; 178 | } 179 | 180 | @Override 181 | public boolean isNullValueDistinct() { 182 | return false; 183 | } 184 | 185 | @Override 186 | public boolean isGetOnly() { 187 | return false; 188 | } 189 | 190 | @Override 191 | public boolean isTransient() { 192 | return false; 193 | } 194 | 195 | @Override 196 | public String getNullValueLabel() { 197 | return null; 198 | } 199 | 200 | @Override 201 | public ValueReturnMode getValueReturnMode() { 202 | return ValueReturnMode.CALCULATED; 203 | } 204 | 205 | @Override 206 | public InfoCategory getCategory() { 207 | if (!(containingPart instanceof CommandLine)) { 208 | return null; 209 | } 210 | int argumentPageIndex = ((CommandLine) containingPart).arguments.indexOf(argumentPage); 211 | return new InfoCategory(argumentPage.title, argumentPageIndex, null); 212 | } 213 | 214 | @Override 215 | public boolean isFormControlMandatory() { 216 | return false; 217 | } 218 | 219 | @Override 220 | public boolean isFormControlEmbedded() { 221 | return false; 222 | } 223 | 224 | @Override 225 | public IInfoFilter getFormControlFilter() { 226 | return IInfoFilter.DEFAULT; 227 | } 228 | 229 | @Override 230 | public long getAutoUpdatePeriodMilliseconds() { 231 | return -1; 232 | } 233 | 234 | @Override 235 | public boolean isHidden() { 236 | return false; 237 | } 238 | 239 | @Override 240 | public double getDisplayAreaHorizontalWeight() { 241 | return 1; 242 | } 243 | 244 | @Override 245 | public double getDisplayAreaVerticalWeight() { 246 | return 0; 247 | } 248 | 249 | @Override 250 | public boolean isDisplayAreaHorizontallyFilled() { 251 | return true; 252 | } 253 | 254 | @Override 255 | public boolean isDisplayAreaVerticallyFilled() { 256 | return false; 257 | } 258 | 259 | @Override 260 | public void onControlVisibilityChange(Object object, boolean visible) { 261 | } 262 | 263 | @Override 264 | public boolean isValueValidityDetectionEnabled() { 265 | return false; 266 | } 267 | } 268 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/ui/FieldInfoFromFileArgument.java: -------------------------------------------------------------------------------- 1 | package xy.command.ui; 2 | 3 | import java.io.File; 4 | import java.util.Collections; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | import xy.command.instance.ArgumentGroupInstance; 10 | import xy.command.instance.CommandLineInstance; 11 | import xy.command.instance.FileArgumentInstance; 12 | import xy.command.model.AbstractCommandLinePart; 13 | import xy.command.model.ArgumentGroup; 14 | import xy.command.model.ArgumentPage; 15 | import xy.command.model.CommandLine; 16 | import xy.command.model.FileArgument; 17 | import xy.reflect.ui.ReflectionUI; 18 | import xy.reflect.ui.control.swing.plugin.FileBrowserPlugin; 19 | import xy.reflect.ui.control.swing.plugin.FileBrowserPlugin.SelectionModeConfiguration; 20 | import xy.reflect.ui.info.InfoCategory; 21 | import xy.reflect.ui.info.ValueReturnMode; 22 | import xy.reflect.ui.info.field.IFieldInfo; 23 | import xy.reflect.ui.info.filter.IInfoFilter; 24 | import xy.reflect.ui.info.method.IMethodInfo; 25 | import xy.reflect.ui.info.type.DefaultTypeInfo; 26 | import xy.reflect.ui.info.type.ITypeInfo; 27 | import xy.reflect.ui.info.type.source.JavaTypeInfoSource; 28 | import xy.reflect.ui.info.type.source.SpecificitiesIdentifier; 29 | import xy.reflect.ui.util.ReflectionUIError; 30 | import xy.reflect.ui.util.ReflectionUIUtils; 31 | 32 | /** 33 | * Specifies how a {@link FileArgument} should be displayed in a GUI. 34 | * 35 | * @author olitank 36 | * 37 | */ 38 | public class FieldInfoFromFileArgument implements IFieldInfo { 39 | 40 | private FileArgument fileArgument; 41 | private ArgumentPage argumentPage; 42 | private AbstractCommandLinePart containingPart; 43 | private ReflectionUI reflectionUI; 44 | private ITypeInfo commandLineTypeInfo; 45 | 46 | public FieldInfoFromFileArgument(ReflectionUI reflectionUI, FileArgument fileArgument, ArgumentPage argumentPage, 47 | AbstractCommandLinePart containingPart, ITypeInfo commandLineTypeInfo) { 48 | this.reflectionUI = reflectionUI; 49 | this.fileArgument = fileArgument; 50 | this.argumentPage = argumentPage; 51 | this.containingPart = containingPart; 52 | this.commandLineTypeInfo = commandLineTypeInfo; 53 | } 54 | 55 | @Override 56 | public String getName() { 57 | return fileArgument.getClass().getName() + fileArgument.hashCode(); 58 | } 59 | 60 | @Override 61 | public String getCaption() { 62 | return fileArgument.title; 63 | } 64 | 65 | @Override 66 | public String getOnlineHelp() { 67 | return fileArgument.description; 68 | } 69 | 70 | @Override 71 | public Map getSpecificProperties() { 72 | return Collections.emptyMap(); 73 | } 74 | 75 | @Override 76 | public List getAlternativeConstructors(Object object) { 77 | return null; 78 | } 79 | 80 | @Override 81 | public List getAlternativeListItemConstructors(Object object) { 82 | return null; 83 | } 84 | 85 | @Override 86 | public ITypeInfo getType() { 87 | return new DefaultTypeInfo(reflectionUI, new JavaTypeInfoSource(File.class, 88 | new SpecificitiesIdentifier(commandLineTypeInfo.getName(), getName()))) { 89 | 90 | @Override 91 | public Map getSpecificProperties() { 92 | Map result = new HashMap(super.getSpecificProperties()); 93 | FileBrowserPlugin plugin = new FileBrowserPlugin(); 94 | FileBrowserPlugin.FileBrowserConfiguration c = new FileBrowserPlugin.FileBrowserConfiguration(); 95 | c.selectionMode = SelectionModeConfiguration.FILES_ONLY; 96 | ReflectionUIUtils.setFieldControlPluginIdentifier(result, plugin.getIdentifier()); 97 | ReflectionUIUtils.setFieldControlPluginConfiguration(result, plugin.getIdentifier(), c); 98 | return result; 99 | } 100 | 101 | }; 102 | } 103 | 104 | @Override 105 | public Object getValue(Object object) { 106 | if (containingPart instanceof CommandLine) { 107 | CommandLineInstance commandLineInstance = (CommandLineInstance) object; 108 | int argumentPageIndex = ((CommandLine) containingPart).arguments.indexOf(argumentPage); 109 | int indexInArgumentPage = argumentPage.parts.indexOf(fileArgument); 110 | FileArgumentInstance fileArgumentInstance = (FileArgumentInstance) commandLineInstance.argumentPageInstances 111 | .get(argumentPageIndex).partInstances.get(indexInArgumentPage); 112 | if (fileArgumentInstance.value == null) { 113 | return null; 114 | } else { 115 | return new File(fileArgumentInstance.value); 116 | } 117 | } else if (containingPart instanceof ArgumentGroup) { 118 | ArgumentGroupInstance argumentGroupInstance = (ArgumentGroupInstance) object; 119 | int indexInArgumentGroup = ((ArgumentGroup) containingPart).parts.indexOf(fileArgument); 120 | FileArgumentInstance fileArgumentInstance = (FileArgumentInstance) argumentGroupInstance.partInstances 121 | .get(indexInArgumentGroup); 122 | if (fileArgumentInstance.value == null) { 123 | return null; 124 | } else { 125 | return new File(fileArgumentInstance.value); 126 | } 127 | } else { 128 | throw new ReflectionUIError(); 129 | } 130 | } 131 | 132 | @Override 133 | public void setValue(Object object, Object value) { 134 | if (containingPart instanceof CommandLine) { 135 | CommandLineInstance commandLineInstance = (CommandLineInstance) object; 136 | int argumentPageIndex = ((CommandLine) containingPart).arguments.indexOf(argumentPage); 137 | int indexInArgumentPage = argumentPage.parts.indexOf(fileArgument); 138 | FileArgumentInstance fileArgumentInstance = (FileArgumentInstance) commandLineInstance.argumentPageInstances 139 | .get(argumentPageIndex).partInstances.get(indexInArgumentPage); 140 | if (value == null) { 141 | fileArgumentInstance.value = null; 142 | } else { 143 | fileArgumentInstance.value = ((File) value).getPath(); 144 | } 145 | } else if (containingPart instanceof ArgumentGroup) { 146 | ArgumentGroupInstance argumentGroupInstance = (ArgumentGroupInstance) object; 147 | int indexInArgumentGroup = ((ArgumentGroup) containingPart).parts.indexOf(fileArgument); 148 | FileArgumentInstance fileArgumentInstance = (FileArgumentInstance) argumentGroupInstance.partInstances 149 | .get(indexInArgumentGroup); 150 | if (value == null) { 151 | fileArgumentInstance.value = null; 152 | } else { 153 | fileArgumentInstance.value = ((File) value).getPath(); 154 | } 155 | } else { 156 | throw new ReflectionUIError(); 157 | } 158 | } 159 | 160 | @Override 161 | public boolean hasValueOptions(Object object) { 162 | return false; 163 | } 164 | 165 | @Override 166 | public Object[] getValueOptions(Object object) { 167 | return null; 168 | } 169 | 170 | @Override 171 | public Runnable getNextUpdateCustomUndoJob(Object object, Object newValue) { 172 | return null; 173 | } 174 | 175 | @Override 176 | public Runnable getPreviousUpdateCustomRedoJob(Object object, Object newValue) { 177 | return null; 178 | } 179 | 180 | @Override 181 | public boolean isNullValueDistinct() { 182 | return false; 183 | } 184 | 185 | @Override 186 | public boolean isGetOnly() { 187 | return false; 188 | } 189 | 190 | @Override 191 | public boolean isTransient() { 192 | return false; 193 | } 194 | 195 | @Override 196 | public String getNullValueLabel() { 197 | return null; 198 | } 199 | 200 | @Override 201 | public ValueReturnMode getValueReturnMode() { 202 | return ValueReturnMode.CALCULATED; 203 | } 204 | 205 | @Override 206 | public InfoCategory getCategory() { 207 | if (!(containingPart instanceof CommandLine)) { 208 | return null; 209 | } 210 | int argumentPageIndex = ((CommandLine) containingPart).arguments.indexOf(argumentPage); 211 | return new InfoCategory(argumentPage.title, argumentPageIndex, null); 212 | } 213 | 214 | @Override 215 | public boolean isFormControlMandatory() { 216 | return false; 217 | } 218 | 219 | @Override 220 | public boolean isFormControlEmbedded() { 221 | return false; 222 | } 223 | 224 | @Override 225 | public IInfoFilter getFormControlFilter() { 226 | return IInfoFilter.DEFAULT; 227 | } 228 | 229 | @Override 230 | public long getAutoUpdatePeriodMilliseconds() { 231 | return -1; 232 | } 233 | 234 | @Override 235 | public boolean isHidden() { 236 | return false; 237 | } 238 | 239 | @Override 240 | public double getDisplayAreaHorizontalWeight() { 241 | return 1; 242 | } 243 | 244 | @Override 245 | public double getDisplayAreaVerticalWeight() { 246 | return 0; 247 | } 248 | 249 | @Override 250 | public boolean isDisplayAreaHorizontallyFilled() { 251 | return true; 252 | } 253 | 254 | @Override 255 | public boolean isDisplayAreaVerticallyFilled() { 256 | return false; 257 | } 258 | 259 | @Override 260 | public void onControlVisibilityChange(Object object, boolean visible) { 261 | } 262 | 263 | @Override 264 | public boolean isValueValidityDetectionEnabled() { 265 | return false; 266 | } 267 | } 268 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/ui/FieldInfoFromInputArgument.java: -------------------------------------------------------------------------------- 1 | package xy.command.ui; 2 | 3 | import java.util.Collections; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import xy.command.instance.ArgumentGroupInstance; 8 | import xy.command.instance.CommandLineInstance; 9 | import xy.command.instance.InputArgumentInstance; 10 | import xy.command.model.AbstractCommandLinePart; 11 | import xy.command.model.ArgumentGroup; 12 | import xy.command.model.ArgumentPage; 13 | import xy.command.model.CommandLine; 14 | import xy.command.model.InputArgument; 15 | import xy.reflect.ui.ReflectionUI; 16 | import xy.reflect.ui.info.InfoCategory; 17 | import xy.reflect.ui.info.ValueReturnMode; 18 | import xy.reflect.ui.info.field.IFieldInfo; 19 | import xy.reflect.ui.info.filter.IInfoFilter; 20 | import xy.reflect.ui.info.method.IMethodInfo; 21 | import xy.reflect.ui.info.type.ITypeInfo; 22 | import xy.reflect.ui.info.type.source.JavaTypeInfoSource; 23 | import xy.reflect.ui.info.type.source.SpecificitiesIdentifier; 24 | import xy.reflect.ui.util.ReflectionUIError; 25 | 26 | /** 27 | * Specifies how an {@link InputArgument} should be displayed in a GUI. 28 | * 29 | * @author olitank 30 | * 31 | */ 32 | public class FieldInfoFromInputArgument implements IFieldInfo { 33 | 34 | private InputArgument inputArgument; 35 | private ArgumentPage argumentPage; 36 | private AbstractCommandLinePart containingPart; 37 | private ReflectionUI reflectionUI; 38 | private ITypeInfo objectTypeInfo; 39 | 40 | public FieldInfoFromInputArgument(ReflectionUI reflectionUI, InputArgument inputArgument, ArgumentPage argumentPage, 41 | AbstractCommandLinePart containingPart, ITypeInfo objectTypeInfo) { 42 | this.reflectionUI = reflectionUI; 43 | this.inputArgument = inputArgument; 44 | this.argumentPage = argumentPage; 45 | this.containingPart = containingPart; 46 | this.objectTypeInfo = objectTypeInfo; 47 | } 48 | 49 | @Override 50 | public String getName() { 51 | return inputArgument.getClass().getName() + inputArgument.hashCode(); 52 | } 53 | 54 | @Override 55 | public String getCaption() { 56 | return inputArgument.title; 57 | } 58 | 59 | @Override 60 | public String getOnlineHelp() { 61 | return inputArgument.description; 62 | } 63 | 64 | @Override 65 | public Map getSpecificProperties() { 66 | return Collections.emptyMap(); 67 | } 68 | 69 | @Override 70 | public List getAlternativeConstructors(Object object) { 71 | return null; 72 | } 73 | 74 | @Override 75 | public List getAlternativeListItemConstructors(Object object) { 76 | return null; 77 | } 78 | 79 | @Override 80 | public ITypeInfo getType() { 81 | return reflectionUI.getTypeInfo( 82 | new JavaTypeInfoSource(String.class, new SpecificitiesIdentifier(objectTypeInfo.getName(), getName()))); 83 | } 84 | 85 | @Override 86 | public Object getValue(Object object) { 87 | if (containingPart instanceof CommandLine) { 88 | CommandLineInstance commandLineInstance = (CommandLineInstance) object; 89 | int argumentPageIndex = ((CommandLine) containingPart).arguments.indexOf(argumentPage); 90 | int indexInArgumentPage = argumentPage.parts.indexOf(inputArgument); 91 | InputArgumentInstance inputArgumentInstance = (InputArgumentInstance) commandLineInstance.argumentPageInstances 92 | .get(argumentPageIndex).partInstances.get(indexInArgumentPage); 93 | return inputArgumentInstance.value; 94 | } else if (containingPart instanceof ArgumentGroup) { 95 | ArgumentGroupInstance argumentGroupInstance = (ArgumentGroupInstance) object; 96 | int indexInArgumentGroup = ((ArgumentGroup) containingPart).parts.indexOf(inputArgument); 97 | InputArgumentInstance inputArgumentInstance = (InputArgumentInstance) argumentGroupInstance.partInstances 98 | .get(indexInArgumentGroup); 99 | return inputArgumentInstance.value; 100 | } else { 101 | throw new ReflectionUIError(); 102 | } 103 | } 104 | 105 | @Override 106 | public void setValue(Object object, Object value) { 107 | if (containingPart instanceof CommandLine) { 108 | CommandLineInstance commandLineInstance = (CommandLineInstance) object; 109 | int argumentPageIndex = ((CommandLine) containingPart).arguments.indexOf(argumentPage); 110 | int indexInArgumentPage = argumentPage.parts.indexOf(inputArgument); 111 | InputArgumentInstance inputArgumentInstance = (InputArgumentInstance) commandLineInstance.argumentPageInstances 112 | .get(argumentPageIndex).partInstances.get(indexInArgumentPage); 113 | inputArgumentInstance.value = (String) value; 114 | } else if (containingPart instanceof ArgumentGroup) { 115 | ArgumentGroupInstance argumentGroupInstance = (ArgumentGroupInstance) object; 116 | int indexInArgumentGroup = ((ArgumentGroup) containingPart).parts.indexOf(inputArgument); 117 | InputArgumentInstance inputArgumentInstance = (InputArgumentInstance) argumentGroupInstance.partInstances 118 | .get(indexInArgumentGroup); 119 | inputArgumentInstance.value = (String) value; 120 | } else { 121 | throw new ReflectionUIError(); 122 | } 123 | } 124 | 125 | @Override 126 | public boolean hasValueOptions(Object object) { 127 | return false; 128 | } 129 | 130 | @Override 131 | public Object[] getValueOptions(Object object) { 132 | return null; 133 | } 134 | 135 | @Override 136 | public Runnable getNextUpdateCustomUndoJob(Object object, Object newValue) { 137 | return null; 138 | } 139 | 140 | @Override 141 | public Runnable getPreviousUpdateCustomRedoJob(Object object, Object newValue) { 142 | return null; 143 | } 144 | 145 | @Override 146 | public boolean isNullValueDistinct() { 147 | return false; 148 | } 149 | 150 | @Override 151 | public boolean isGetOnly() { 152 | return false; 153 | } 154 | 155 | @Override 156 | public boolean isTransient() { 157 | return false; 158 | } 159 | 160 | @Override 161 | public String getNullValueLabel() { 162 | return null; 163 | } 164 | 165 | @Override 166 | public ValueReturnMode getValueReturnMode() { 167 | return ValueReturnMode.CALCULATED; 168 | } 169 | 170 | @Override 171 | public InfoCategory getCategory() { 172 | if (!(containingPart instanceof CommandLine)) { 173 | return null; 174 | } 175 | int argumentPageIndex = ((CommandLine) containingPart).arguments.indexOf(argumentPage); 176 | return new InfoCategory(argumentPage.title, argumentPageIndex, null); 177 | } 178 | 179 | @Override 180 | public boolean isFormControlMandatory() { 181 | return false; 182 | } 183 | 184 | @Override 185 | public boolean isFormControlEmbedded() { 186 | return false; 187 | } 188 | 189 | @Override 190 | public IInfoFilter getFormControlFilter() { 191 | return IInfoFilter.DEFAULT; 192 | } 193 | 194 | @Override 195 | public long getAutoUpdatePeriodMilliseconds() { 196 | return -1; 197 | } 198 | 199 | @Override 200 | public boolean isHidden() { 201 | return false; 202 | } 203 | 204 | @Override 205 | public double getDisplayAreaHorizontalWeight() { 206 | return 1; 207 | } 208 | 209 | @Override 210 | public double getDisplayAreaVerticalWeight() { 211 | return 0; 212 | } 213 | 214 | @Override 215 | public boolean isDisplayAreaHorizontallyFilled() { 216 | return true; 217 | } 218 | 219 | @Override 220 | public boolean isDisplayAreaVerticallyFilled() { 221 | return false; 222 | } 223 | 224 | @Override 225 | public void onControlVisibilityChange(Object object, boolean visible) { 226 | } 227 | 228 | @Override 229 | public boolean isValueValidityDetectionEnabled() { 230 | return false; 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/ui/FieldInfoFromMultiplePart.java: -------------------------------------------------------------------------------- 1 | package xy.command.ui; 2 | 3 | import java.io.InputStream; 4 | import java.io.OutputStream; 5 | import java.util.ArrayList; 6 | import java.util.Collections; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | import xy.command.instance.ArgumentGroupInstance; 11 | import xy.command.instance.CommandLineInstance; 12 | import xy.command.instance.MultiplePartInstance; 13 | import xy.command.model.AbstractCommandLinePart; 14 | import xy.command.model.ArgumentGroup; 15 | import xy.command.model.ArgumentPage; 16 | import xy.command.model.CommandLine; 17 | import xy.command.model.MultiplePart; 18 | import xy.reflect.ui.ReflectionUI; 19 | import xy.reflect.ui.info.ColorSpecification; 20 | import xy.reflect.ui.info.ITransaction; 21 | import xy.reflect.ui.info.InfoCategory; 22 | import xy.reflect.ui.info.ResourcePath; 23 | import xy.reflect.ui.info.ValidationSession; 24 | import xy.reflect.ui.info.ValueReturnMode; 25 | import xy.reflect.ui.info.field.IFieldInfo; 26 | import xy.reflect.ui.info.filter.IInfoFilter; 27 | import xy.reflect.ui.info.menu.MenuModel; 28 | import xy.reflect.ui.info.method.IMethodInfo; 29 | import xy.reflect.ui.info.type.ITypeInfo; 30 | import xy.reflect.ui.info.type.iterable.IListTypeInfo; 31 | import xy.reflect.ui.info.type.iterable.item.DetachedItemDetailsAccessMode; 32 | import xy.reflect.ui.info.type.iterable.item.IListItemDetailsAccessMode; 33 | import xy.reflect.ui.info.type.iterable.item.ItemPosition; 34 | import xy.reflect.ui.info.type.iterable.structure.DefaultListStructuralInfo; 35 | import xy.reflect.ui.info.type.iterable.structure.IListStructuralInfo; 36 | import xy.reflect.ui.info.type.iterable.util.IDynamicListAction; 37 | import xy.reflect.ui.info.type.iterable.util.IDynamicListProperty; 38 | import xy.reflect.ui.info.type.source.ITypeInfoSource; 39 | import xy.reflect.ui.info.type.source.PrecomputedTypeInfoSource; 40 | import xy.reflect.ui.info.type.source.SpecificitiesIdentifier; 41 | import xy.reflect.ui.undo.ListModificationFactory; 42 | import xy.reflect.ui.util.Mapper; 43 | import xy.reflect.ui.util.MiscUtils; 44 | import xy.reflect.ui.util.ReflectionUIError; 45 | import xy.reflect.ui.util.ReflectionUIUtils; 46 | 47 | /** 48 | * Specifies how a {@link MultiplePart} should be displayed in a GUI. 49 | * 50 | * @author olitank 51 | * 52 | */ 53 | public class FieldInfoFromMultiplePart implements IFieldInfo { 54 | 55 | private MultiplePart multiplePart; 56 | private ArgumentPage argumentPage; 57 | private AbstractCommandLinePart containingPart; 58 | private CommandLineUI commandLineUI; 59 | private ITypeInfo commandLineTypeInfo; 60 | 61 | public FieldInfoFromMultiplePart(CommandLineUI commandLineUI, MultiplePart multiplePart, ArgumentPage argumentPage, 62 | AbstractCommandLinePart containingPart, ITypeInfo commandLineTypeInfo) { 63 | this.commandLineUI = commandLineUI; 64 | this.multiplePart = multiplePart; 65 | this.argumentPage = argumentPage; 66 | this.containingPart = containingPart; 67 | this.commandLineTypeInfo = commandLineTypeInfo; 68 | } 69 | 70 | @Override 71 | public String getName() { 72 | return multiplePart.getClass().getName() + multiplePart.hashCode(); 73 | } 74 | 75 | @Override 76 | public String getCaption() { 77 | return multiplePart.title; 78 | } 79 | 80 | @Override 81 | public String getOnlineHelp() { 82 | return multiplePart.description; 83 | } 84 | 85 | @Override 86 | public Map getSpecificProperties() { 87 | return Collections.emptyMap(); 88 | } 89 | 90 | @Override 91 | public List getAlternativeConstructors(Object object) { 92 | return null; 93 | } 94 | 95 | @Override 96 | public List getAlternativeListItemConstructors(Object object) { 97 | return null; 98 | } 99 | 100 | @Override 101 | public ITypeInfo getType() { 102 | return new IListTypeInfo() { 103 | 104 | @Override 105 | public boolean isItemNodeValidityDetectionEnabled(ItemPosition itemPosition) { 106 | return false; 107 | } 108 | 109 | @Override 110 | public boolean isValidationRequired() { 111 | return false; 112 | } 113 | 114 | @Override 115 | public IFieldInfo getSelectionTargetField(ITypeInfo objectType) { 116 | return null; 117 | } 118 | 119 | @Override 120 | public Map getSpecificProperties() { 121 | return Collections.emptyMap(); 122 | } 123 | 124 | @Override 125 | public ITransaction createTransaction(Object object) { 126 | return null; 127 | } 128 | 129 | @Override 130 | public void onFormRefresh(Object object) { 131 | } 132 | 133 | @Override 134 | public Runnable getLastFormRefreshStateRestorationJob(Object object) { 135 | return null; 136 | } 137 | 138 | @Override 139 | public String getOnlineHelp() { 140 | return null; 141 | } 142 | 143 | @Override 144 | public String getName() { 145 | return FieldInfoFromMultiplePart.this.getName() + "-type"; 146 | } 147 | 148 | @Override 149 | public String getCaption() { 150 | return ""; 151 | } 152 | 153 | @Override 154 | public void validate(Object object, ValidationSession session) throws Exception { 155 | } 156 | 157 | @Override 158 | public String toString(Object object) { 159 | List result = new ArrayList(); 160 | for (Object item : toArray(object)) { 161 | result.add(ReflectionUIUtils.toString(commandLineUI, item)); 162 | } 163 | return MiscUtils.stringJoin(result, ", "); 164 | } 165 | 166 | @Override 167 | public boolean supports(Object object) { 168 | return object instanceof CommandLineInstance[]; 169 | } 170 | 171 | @Override 172 | public void save(Object object, OutputStream out) { 173 | throw new UnsupportedOperationException(); 174 | } 175 | 176 | @Override 177 | public boolean onFormVisibilityChange(Object object, boolean visible) { 178 | return false; 179 | } 180 | 181 | @Override 182 | public void load(Object object, InputStream in) { 183 | throw new UnsupportedOperationException(); 184 | } 185 | 186 | @Override 187 | public boolean isPrimitive() { 188 | return false; 189 | } 190 | 191 | @Override 192 | public boolean isModificationStackAccessible() { 193 | return false; 194 | } 195 | 196 | @Override 197 | public boolean isImmutable() { 198 | return false; 199 | } 200 | 201 | @Override 202 | public boolean isConcrete() { 203 | return true; 204 | } 205 | 206 | @Override 207 | public ITypeInfoSource getSource() { 208 | return new PrecomputedTypeInfoSource(this, 209 | new SpecificitiesIdentifier(commandLineTypeInfo.getName(), getName())); 210 | } 211 | 212 | @Override 213 | public List getPolymorphicInstanceSubTypes() { 214 | return Collections.emptyList(); 215 | } 216 | 217 | @Override 218 | public MethodsLayout getMethodsLayout() { 219 | return MethodsLayout.HORIZONTAL_FLOW; 220 | } 221 | 222 | @Override 223 | public List getMethods() { 224 | return Collections.emptyList(); 225 | } 226 | 227 | @Override 228 | public MenuModel getMenuModel() { 229 | return new MenuModel(); 230 | } 231 | 232 | @Override 233 | public ResourcePath getIconImagePath(Object object) { 234 | return null; 235 | } 236 | 237 | @Override 238 | public int getFormPreferredWidth() { 239 | return -1; 240 | } 241 | 242 | @Override 243 | public int getFormPreferredHeight() { 244 | return -1; 245 | } 246 | 247 | @Override 248 | public int getFormSpacing() { 249 | return ITypeInfo.DEFAULT_FORM_SPACING; 250 | } 251 | 252 | @Override 253 | public ColorSpecification getFormForegroundColor() { 254 | return null; 255 | } 256 | 257 | @Override 258 | public ResourcePath getFormBackgroundImagePath() { 259 | return null; 260 | } 261 | 262 | @Override 263 | public ColorSpecification getFormBackgroundColor() { 264 | return null; 265 | } 266 | 267 | @Override 268 | public ColorSpecification getFormBorderColor() { 269 | return null; 270 | } 271 | 272 | @Override 273 | public ColorSpecification getFormEditorForegroundColor() { 274 | return null; 275 | } 276 | 277 | @Override 278 | public ColorSpecification getFormEditorBackgroundColor() { 279 | return null; 280 | } 281 | 282 | @Override 283 | public ColorSpecification getFormButtonBackgroundColor() { 284 | return null; 285 | } 286 | 287 | @Override 288 | public ColorSpecification getFormButtonForegroundColor() { 289 | return null; 290 | } 291 | 292 | @Override 293 | public ResourcePath getFormButtonBackgroundImagePath() { 294 | return null; 295 | } 296 | 297 | @Override 298 | public ColorSpecification getFormButtonBorderColor() { 299 | return null; 300 | } 301 | 302 | @Override 303 | public ColorSpecification getCategoriesBackgroundColor() { 304 | return null; 305 | } 306 | 307 | @Override 308 | public ColorSpecification getCategoriesForegroundColor() { 309 | return null; 310 | } 311 | 312 | @Override 313 | public FieldsLayout getFieldsLayout() { 314 | return FieldsLayout.VERTICAL_FLOW; 315 | } 316 | 317 | @Override 318 | public List getFields() { 319 | return Collections.emptyList(); 320 | } 321 | 322 | @Override 323 | public List getConstructors() { 324 | return Collections.emptyList(); 325 | } 326 | 327 | @Override 328 | public CategoriesStyle getCategoriesStyle() { 329 | return CategoriesStyle.MODERN; 330 | } 331 | 332 | @Override 333 | public Object copy(Object object) { 334 | throw new UnsupportedOperationException(); 335 | } 336 | 337 | @Override 338 | public boolean canPersist() { 339 | return false; 340 | } 341 | 342 | @Override 343 | public boolean canCopy(Object object) { 344 | return false; 345 | } 346 | 347 | @Override 348 | public void replaceContent(Object listValue, Object[] array) { 349 | } 350 | 351 | @Override 352 | public boolean isRemovalAllowed() { 353 | return true; 354 | } 355 | 356 | @Override 357 | public boolean isMoveAllowed() { 358 | return true; 359 | } 360 | 361 | @Override 362 | public boolean areItemsAutomaticallyPositioned() { 363 | return false; 364 | } 365 | 366 | @Override 367 | public boolean isItemNullValueSupported() { 368 | return false; 369 | } 370 | 371 | @Override 372 | public ItemCreationMode getItemCreationMode() { 373 | return ItemCreationMode.UNDEFINED; 374 | } 375 | 376 | @Override 377 | public ToolsLocation getToolsLocation() { 378 | return ToolsLocation.EAST; 379 | } 380 | 381 | @Override 382 | public boolean isInsertionAllowed() { 383 | return true; 384 | } 385 | 386 | @Override 387 | public IListStructuralInfo getStructuralInfo() { 388 | return new DefaultListStructuralInfo(commandLineUI); 389 | } 390 | 391 | @Override 392 | public ITypeInfo getItemType() { 393 | return commandLineUI.getTypeInfo(new TypeInfoSourceFromArgumentGroup(multiplePart, null) { 394 | 395 | @Override 396 | public ITypeInfo buildTypeInfo(ReflectionUI reflectionUI) { 397 | return new TypeInfoFromArgumentGroup(commandLineUI) { 398 | 399 | @Override 400 | public String getName() { 401 | return super.getName() + "-item"; 402 | } 403 | 404 | @Override 405 | public String getCaption() { 406 | return ReflectionUIUtils.composeMessage(super.getCaption(), "Item"); 407 | } 408 | 409 | }; 410 | } 411 | 412 | }); 413 | } 414 | 415 | @Override 416 | public ValueReturnMode getItemReturnMode() { 417 | return ValueReturnMode.DIRECT_OR_PROXY; 418 | } 419 | 420 | @Override 421 | public List getDynamicProperties(List selection, 422 | Mapper listModificationFactoryAccessor) { 423 | return Collections.emptyList(); 424 | } 425 | 426 | @Override 427 | public List getDynamicActions(List selection, 428 | Mapper listModificationFactoryAccessor) { 429 | return Collections.emptyList(); 430 | } 431 | 432 | @Override 433 | public IListItemDetailsAccessMode getDetailsAccessMode() { 434 | return new DetachedItemDetailsAccessMode(); 435 | } 436 | 437 | @Override 438 | public Object fromArray(Object[] array) { 439 | ArgumentGroupInstance[] result = new ArgumentGroupInstance[array.length]; 440 | for (int i = 0; i < array.length; i++) { 441 | result[i] = (ArgumentGroupInstance) array[i]; 442 | } 443 | return result; 444 | } 445 | 446 | @Override 447 | public Object[] toArray(Object listValue) { 448 | ArgumentGroupInstance[] array = (ArgumentGroupInstance[]) listValue; 449 | Object[] result = new Object[array.length]; 450 | for (int i = 0; i < array.length; i++) { 451 | result[i] = array[i]; 452 | } 453 | return result; 454 | } 455 | 456 | @Override 457 | public boolean canViewItemDetails() { 458 | return true; 459 | } 460 | 461 | @Override 462 | public boolean canReplaceContent() { 463 | return false; 464 | } 465 | 466 | @Override 467 | public boolean canInstantiateFromArray() { 468 | return true; 469 | } 470 | }; 471 | 472 | } 473 | 474 | @Override 475 | public Object getValue(Object object) { 476 | if (containingPart instanceof CommandLine) { 477 | CommandLineInstance commandLineInstance = (CommandLineInstance) object; 478 | int argumentPageIndex = ((CommandLine) containingPart).arguments.indexOf(argumentPage); 479 | int indexInArgumentPage = argumentPage.parts.indexOf(multiplePart); 480 | MultiplePartInstance multiplePartInstance = (MultiplePartInstance) commandLineInstance.argumentPageInstances 481 | .get(argumentPageIndex).partInstances.get(indexInArgumentPage); 482 | return multiplePartInstance.argumentGroupInstances; 483 | } else if (containingPart instanceof ArgumentGroup) { 484 | ArgumentGroupInstance argumentGroupInstance = (ArgumentGroupInstance) object; 485 | int indexInArgumentGroup = ((ArgumentGroup) containingPart).parts.indexOf(multiplePart); 486 | MultiplePartInstance multiplePartInstance = (MultiplePartInstance) argumentGroupInstance.partInstances 487 | .get(indexInArgumentGroup); 488 | return multiplePartInstance.argumentGroupInstances; 489 | } else { 490 | throw new ReflectionUIError(); 491 | } 492 | } 493 | 494 | @Override 495 | public void setValue(Object object, Object value) { 496 | if (containingPart instanceof CommandLine) { 497 | CommandLineInstance commandLineInstance = (CommandLineInstance) object; 498 | int argumentPageIndex = ((CommandLine) containingPart).arguments.indexOf(argumentPage); 499 | int indexInArgumentPage = argumentPage.parts.indexOf(multiplePart); 500 | MultiplePartInstance multiplePartInstance = (MultiplePartInstance) commandLineInstance.argumentPageInstances 501 | .get(argumentPageIndex).partInstances.get(indexInArgumentPage); 502 | multiplePartInstance.argumentGroupInstances = (ArgumentGroupInstance[]) value; 503 | } else if (containingPart instanceof ArgumentGroup) { 504 | ArgumentGroupInstance argumentGroupInstance = (ArgumentGroupInstance) object; 505 | int indexInArgumentGroup = ((ArgumentGroup) containingPart).parts.indexOf(multiplePart); 506 | MultiplePartInstance multiplePartInstance = (MultiplePartInstance) argumentGroupInstance.partInstances 507 | .get(indexInArgumentGroup); 508 | multiplePartInstance.argumentGroupInstances = (ArgumentGroupInstance[]) value; 509 | } else { 510 | throw new ReflectionUIError(); 511 | } 512 | } 513 | 514 | @Override 515 | public boolean hasValueOptions(Object object) { 516 | return false; 517 | } 518 | 519 | @Override 520 | public Object[] getValueOptions(Object object) { 521 | return null; 522 | } 523 | 524 | @Override 525 | public Runnable getNextUpdateCustomUndoJob(Object object, Object newValue) { 526 | return null; 527 | } 528 | 529 | @Override 530 | public Runnable getPreviousUpdateCustomRedoJob(Object object, Object newValue) { 531 | return null; 532 | } 533 | 534 | @Override 535 | public boolean isNullValueDistinct() { 536 | return false; 537 | } 538 | 539 | @Override 540 | public boolean isGetOnly() { 541 | return false; 542 | } 543 | 544 | @Override 545 | public boolean isTransient() { 546 | return false; 547 | } 548 | 549 | @Override 550 | public String getNullValueLabel() { 551 | return null; 552 | } 553 | 554 | @Override 555 | public ValueReturnMode getValueReturnMode() { 556 | return ValueReturnMode.CALCULATED; 557 | } 558 | 559 | @Override 560 | public InfoCategory getCategory() { 561 | if (!(containingPart instanceof CommandLine)) { 562 | return null; 563 | } 564 | int argumentPageIndex = ((CommandLine) containingPart).arguments.indexOf(argumentPage); 565 | return new InfoCategory(argumentPage.title, argumentPageIndex, null); 566 | } 567 | 568 | @Override 569 | public boolean isFormControlMandatory() { 570 | return false; 571 | } 572 | 573 | @Override 574 | public boolean isFormControlEmbedded() { 575 | return false; 576 | } 577 | 578 | @Override 579 | public IInfoFilter getFormControlFilter() { 580 | return IInfoFilter.DEFAULT; 581 | } 582 | 583 | @Override 584 | public long getAutoUpdatePeriodMilliseconds() { 585 | return -1; 586 | } 587 | 588 | @Override 589 | public boolean isHidden() { 590 | return false; 591 | } 592 | 593 | @Override 594 | public double getDisplayAreaHorizontalWeight() { 595 | return 1; 596 | } 597 | 598 | @Override 599 | public double getDisplayAreaVerticalWeight() { 600 | return 0; 601 | } 602 | 603 | @Override 604 | public boolean isDisplayAreaHorizontallyFilled() { 605 | return true; 606 | } 607 | 608 | @Override 609 | public boolean isDisplayAreaVerticallyFilled() { 610 | return false; 611 | } 612 | 613 | @Override 614 | public void onControlVisibilityChange(Object object, boolean visible) { 615 | } 616 | 617 | @Override 618 | public boolean isValueValidityDetectionEnabled() { 619 | return false; 620 | } 621 | } 622 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/ui/FieldInfoFromOptionalPart.java: -------------------------------------------------------------------------------- 1 | package xy.command.ui; 2 | 3 | import java.util.Collections; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import xy.command.instance.ArgumentGroupInstance; 8 | import xy.command.instance.CommandLineInstance; 9 | import xy.command.instance.OptionalPartInstance; 10 | import xy.command.model.AbstractCommandLinePart; 11 | import xy.command.model.ArgumentGroup; 12 | import xy.command.model.ArgumentPage; 13 | import xy.command.model.CommandLine; 14 | import xy.command.model.FixedArgument; 15 | import xy.command.model.OptionalPart; 16 | import xy.reflect.ui.info.InfoCategory; 17 | import xy.reflect.ui.info.ValueReturnMode; 18 | import xy.reflect.ui.info.field.IFieldInfo; 19 | import xy.reflect.ui.info.filter.IInfoFilter; 20 | import xy.reflect.ui.info.method.IMethodInfo; 21 | import xy.reflect.ui.info.type.ITypeInfo; 22 | import xy.reflect.ui.info.type.source.JavaTypeInfoSource; 23 | import xy.reflect.ui.info.type.source.SpecificitiesIdentifier; 24 | import xy.reflect.ui.util.ReflectionUIError; 25 | 26 | /** 27 | * Specifies how an {@link OptionalPart} should be displayed in a GUI. 28 | * 29 | * @author olitank 30 | * 31 | */ 32 | public class FieldInfoFromOptionalPart implements IFieldInfo { 33 | 34 | private OptionalPart optionalPart; 35 | private ArgumentPage argumentPage; 36 | private AbstractCommandLinePart containingPart; 37 | private CommandLineUI commandLineUI; 38 | private ITypeInfo commandLineTypeInfo; 39 | 40 | public FieldInfoFromOptionalPart(CommandLineUI commandLineUI, OptionalPart optionalPart, ArgumentPage argumentPage, 41 | AbstractCommandLinePart containingPart, ITypeInfo commandLineTypeInfo) { 42 | this.commandLineUI = commandLineUI; 43 | this.optionalPart = optionalPart; 44 | this.argumentPage = argumentPage; 45 | this.containingPart = containingPart; 46 | this.commandLineTypeInfo = commandLineTypeInfo; 47 | } 48 | 49 | @Override 50 | public String getName() { 51 | return optionalPart.getClass().getName() + optionalPart.hashCode(); 52 | } 53 | 54 | @Override 55 | public String getCaption() { 56 | return optionalPart.title; 57 | } 58 | 59 | @Override 60 | public String getOnlineHelp() { 61 | return optionalPart.description; 62 | } 63 | 64 | @Override 65 | public Map getSpecificProperties() { 66 | return Collections.emptyMap(); 67 | } 68 | 69 | @Override 70 | public List getAlternativeConstructors(Object object) { 71 | return null; 72 | } 73 | 74 | @Override 75 | public List getAlternativeListItemConstructors(Object object) { 76 | return null; 77 | } 78 | 79 | private boolean isBoolean() { 80 | for (AbstractCommandLinePart childPart : optionalPart.parts) { 81 | if (!(childPart instanceof FixedArgument)) { 82 | return false; 83 | } 84 | } 85 | return true; 86 | } 87 | 88 | @Override 89 | public ITypeInfo getType() { 90 | if (isBoolean()) { 91 | return commandLineUI.getTypeInfo(new JavaTypeInfoSource(Boolean.class, 92 | new SpecificitiesIdentifier(commandLineTypeInfo.getName(), getName()))); 93 | } else { 94 | return commandLineUI.getTypeInfo(new TypeInfoSourceFromArgumentGroup(optionalPart, 95 | new SpecificitiesIdentifier(commandLineTypeInfo.getName(), getName()))); 96 | } 97 | } 98 | 99 | @Override 100 | public boolean isNullValueDistinct() { 101 | if (isBoolean()) { 102 | return false; 103 | } else { 104 | return true; 105 | } 106 | } 107 | 108 | @Override 109 | public Object getValue(Object object) { 110 | if (containingPart instanceof CommandLine) { 111 | CommandLineInstance commandLineInstance = (CommandLineInstance) object; 112 | int argumentPageIndex = ((CommandLine) containingPart).arguments.indexOf(argumentPage); 113 | int indexInArgumentPage = argumentPage.parts.indexOf(optionalPart); 114 | OptionalPartInstance optionalPartInstance = (OptionalPartInstance) commandLineInstance.argumentPageInstances 115 | .get(argumentPageIndex).partInstances.get(indexInArgumentPage); 116 | if (isBoolean()) { 117 | return (optionalPartInstance.argumentGroupInstance != null); 118 | } else { 119 | return optionalPartInstance.argumentGroupInstance; 120 | } 121 | } else if (containingPart instanceof ArgumentGroup) { 122 | ArgumentGroupInstance argumentGroupInstance = (ArgumentGroupInstance) object; 123 | int indexInArgumentGroup = ((ArgumentGroup) containingPart).parts.indexOf(optionalPart); 124 | OptionalPartInstance optionalPartInstance = (OptionalPartInstance) argumentGroupInstance.partInstances 125 | .get(indexInArgumentGroup); 126 | if (isBoolean()) { 127 | return (optionalPartInstance.argumentGroupInstance != null); 128 | } else { 129 | return optionalPartInstance.argumentGroupInstance; 130 | } 131 | } else { 132 | throw new ReflectionUIError(); 133 | } 134 | } 135 | 136 | @Override 137 | public void setValue(Object object, Object value) { 138 | if (containingPart instanceof CommandLine) { 139 | CommandLineInstance commandLineInstance = (CommandLineInstance) object; 140 | int argumentPageIndex = ((CommandLine) containingPart).arguments.indexOf(argumentPage); 141 | int indexInArgumentPage = argumentPage.parts.indexOf(optionalPart); 142 | OptionalPartInstance optionalPartInstance = (OptionalPartInstance) commandLineInstance.argumentPageInstances 143 | .get(argumentPageIndex).partInstances.get(indexInArgumentPage); 144 | if (isBoolean()) { 145 | optionalPartInstance.argumentGroupInstance = ((Boolean) value) ? new ArgumentGroupInstance(optionalPart) 146 | : null; 147 | } else { 148 | optionalPartInstance.argumentGroupInstance = (ArgumentGroupInstance) value; 149 | } 150 | } else if (containingPart instanceof ArgumentGroup) { 151 | ArgumentGroupInstance argumentGroupInstance = (ArgumentGroupInstance) object; 152 | int indexInArgumentGroup = ((ArgumentGroup) containingPart).parts.indexOf(optionalPart); 153 | OptionalPartInstance optionalPartInstance = (OptionalPartInstance) argumentGroupInstance.partInstances 154 | .get(indexInArgumentGroup); 155 | if (isBoolean()) { 156 | optionalPartInstance.argumentGroupInstance = ((Boolean) value) ? new ArgumentGroupInstance(optionalPart) 157 | : null; 158 | } else { 159 | optionalPartInstance.argumentGroupInstance = (ArgumentGroupInstance) value; 160 | } 161 | } else { 162 | throw new ReflectionUIError(); 163 | } 164 | } 165 | 166 | @Override 167 | public boolean hasValueOptions(Object object) { 168 | return false; 169 | } 170 | 171 | @Override 172 | public Object[] getValueOptions(Object object) { 173 | return null; 174 | } 175 | 176 | @Override 177 | public Runnable getNextUpdateCustomUndoJob(Object object, Object newValue) { 178 | return null; 179 | } 180 | 181 | @Override 182 | public Runnable getPreviousUpdateCustomRedoJob(Object object, Object newValue) { 183 | return null; 184 | } 185 | 186 | @Override 187 | public boolean isGetOnly() { 188 | return false; 189 | } 190 | 191 | @Override 192 | public boolean isTransient() { 193 | return false; 194 | } 195 | 196 | @Override 197 | public String getNullValueLabel() { 198 | return null; 199 | } 200 | 201 | @Override 202 | public ValueReturnMode getValueReturnMode() { 203 | return ValueReturnMode.CALCULATED; 204 | } 205 | 206 | @Override 207 | public InfoCategory getCategory() { 208 | if (!(containingPart instanceof CommandLine)) { 209 | return null; 210 | } 211 | int argumentPageIndex = ((CommandLine) containingPart).arguments.indexOf(argumentPage); 212 | return new InfoCategory(argumentPage.title, argumentPageIndex, null); 213 | } 214 | 215 | @Override 216 | public boolean isFormControlMandatory() { 217 | return false; 218 | } 219 | 220 | @Override 221 | public boolean isFormControlEmbedded() { 222 | return true; 223 | } 224 | 225 | @Override 226 | public IInfoFilter getFormControlFilter() { 227 | return IInfoFilter.DEFAULT; 228 | } 229 | 230 | @Override 231 | public long getAutoUpdatePeriodMilliseconds() { 232 | return -1; 233 | } 234 | 235 | @Override 236 | public boolean isHidden() { 237 | return false; 238 | } 239 | 240 | @Override 241 | public double getDisplayAreaHorizontalWeight() { 242 | return 1; 243 | } 244 | 245 | @Override 246 | public double getDisplayAreaVerticalWeight() { 247 | return 0; 248 | } 249 | 250 | @Override 251 | public boolean isDisplayAreaHorizontallyFilled() { 252 | return true; 253 | } 254 | 255 | @Override 256 | public boolean isDisplayAreaVerticallyFilled() { 257 | return false; 258 | } 259 | 260 | @Override 261 | public void onControlVisibilityChange(Object object, boolean visible) { 262 | } 263 | 264 | @Override 265 | public boolean isValueValidityDetectionEnabled() { 266 | return false; 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/ui/TypeInfoSourceFromArgumentGroup.java: -------------------------------------------------------------------------------- 1 | package xy.command.ui; 2 | 3 | import java.io.InputStream; 4 | import java.io.OutputStream; 5 | import java.util.ArrayList; 6 | import java.util.Collections; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | import xy.command.instance.ArgumentGroupInstance; 11 | import xy.command.model.AbstractCommandLinePart; 12 | import xy.command.model.ArgumentGroup; 13 | import xy.command.model.ArgumentPage; 14 | import xy.command.model.Choice; 15 | import xy.command.model.DirectoryArgument; 16 | import xy.command.model.FileArgument; 17 | import xy.command.model.FixedArgument; 18 | import xy.command.model.InputArgument; 19 | import xy.command.model.MultiplePart; 20 | import xy.command.model.OptionalPart; 21 | import xy.reflect.ui.ReflectionUI; 22 | import xy.reflect.ui.info.ColorSpecification; 23 | import xy.reflect.ui.info.ITransaction; 24 | import xy.reflect.ui.info.ResourcePath; 25 | import xy.reflect.ui.info.ValidationSession; 26 | import xy.reflect.ui.info.field.IFieldInfo; 27 | import xy.reflect.ui.info.menu.MenuModel; 28 | import xy.reflect.ui.info.method.AbstractConstructorInfo; 29 | import xy.reflect.ui.info.method.IMethodInfo; 30 | import xy.reflect.ui.info.method.InvocationData; 31 | import xy.reflect.ui.info.type.ITypeInfo; 32 | import xy.reflect.ui.info.type.source.ITypeInfoSource; 33 | import xy.reflect.ui.info.type.source.SpecificitiesIdentifier; 34 | import xy.reflect.ui.util.ReflectionUIError; 35 | 36 | /** 37 | * Specifies how an {@link ArgumentGroup} should be displayed in a GUI. 38 | * 39 | * @author olitank 40 | * 41 | */ 42 | public class TypeInfoSourceFromArgumentGroup implements ITypeInfoSource { 43 | 44 | private ArgumentGroup argumentGroup; 45 | private SpecificitiesIdentifier specificitiesIdentifier; 46 | 47 | public TypeInfoSourceFromArgumentGroup(ArgumentGroup argumentGroup, 48 | SpecificitiesIdentifier specificitiesIdentifier) { 49 | this.argumentGroup = argumentGroup; 50 | this.specificitiesIdentifier = specificitiesIdentifier; 51 | } 52 | 53 | @Override 54 | public int hashCode() { 55 | final int prime = 31; 56 | int result = 1; 57 | result = prime * result + ((argumentGroup == null) ? 0 : argumentGroup.hashCode()); 58 | result = prime * result + ((specificitiesIdentifier == null) ? 0 : specificitiesIdentifier.hashCode()); 59 | return result; 60 | } 61 | 62 | @Override 63 | public boolean equals(Object obj) { 64 | if (this == obj) 65 | return true; 66 | if (obj == null) 67 | return false; 68 | if (getClass() != obj.getClass()) 69 | return false; 70 | TypeInfoSourceFromArgumentGroup other = (TypeInfoSourceFromArgumentGroup) obj; 71 | if (argumentGroup == null) { 72 | if (other.argumentGroup != null) 73 | return false; 74 | } else if (!argumentGroup.equals(other.argumentGroup)) 75 | return false; 76 | if (specificitiesIdentifier == null) { 77 | if (other.specificitiesIdentifier != null) 78 | return false; 79 | } else if (!specificitiesIdentifier.equals(other.specificitiesIdentifier)) 80 | return false; 81 | return true; 82 | } 83 | 84 | @Override 85 | public SpecificitiesIdentifier getSpecificitiesIdentifier() { 86 | return specificitiesIdentifier; 87 | } 88 | 89 | @Override 90 | public ITypeInfo buildTypeInfo(ReflectionUI reflectionUI) { 91 | return new TypeInfoFromArgumentGroup((CommandLineUI) reflectionUI); 92 | } 93 | 94 | protected IFieldInfo getFieldInfoFromCommandLinePart(CommandLineUI commandLineUI, AbstractCommandLinePart part, 95 | ArgumentPage argumentPage, ITypeInfo commandLineTypeInfo) { 96 | if (part instanceof FixedArgument) { 97 | return null; 98 | } else if (part instanceof InputArgument) { 99 | return new FieldInfoFromInputArgument(commandLineUI, (InputArgument) part, null, argumentGroup, 100 | commandLineTypeInfo); 101 | } else if (part instanceof DirectoryArgument) { 102 | return new FieldInfoFromDirectoryArgument(commandLineUI, (DirectoryArgument) part, null, argumentGroup, 103 | commandLineTypeInfo); 104 | } else if (part instanceof FileArgument) { 105 | return new FieldInfoFromFileArgument(commandLineUI, (FileArgument) part, null, argumentGroup, 106 | commandLineTypeInfo); 107 | } else if (part instanceof Choice) { 108 | return new FieldInfoFromChoice(commandLineUI, (Choice) part, null, argumentGroup, commandLineTypeInfo); 109 | } else if (part instanceof OptionalPart) { 110 | return new FieldInfoFromOptionalPart(commandLineUI, (OptionalPart) part, null, argumentGroup, 111 | commandLineTypeInfo); 112 | } else if (part instanceof MultiplePart) { 113 | return new FieldInfoFromMultiplePart(commandLineUI, (MultiplePart) part, null, argumentGroup, 114 | commandLineTypeInfo); 115 | } else { 116 | throw new ReflectionUIError(); 117 | } 118 | } 119 | 120 | public class TypeInfoFromArgumentGroup implements ITypeInfo { 121 | 122 | private CommandLineUI commandLineUI; 123 | 124 | public TypeInfoFromArgumentGroup(CommandLineUI commandLineUI) { 125 | this.commandLineUI = commandLineUI; 126 | } 127 | 128 | @Override 129 | public int hashCode() { 130 | final int prime = 31; 131 | int result = 1; 132 | result = prime * result + getOuterType().hashCode(); 133 | return result; 134 | } 135 | 136 | @Override 137 | public boolean equals(Object obj) { 138 | if (this == obj) 139 | return true; 140 | if (obj == null) 141 | return false; 142 | if (getClass() != obj.getClass()) 143 | return false; 144 | TypeInfoFromArgumentGroup other = (TypeInfoFromArgumentGroup) obj; 145 | if (!getOuterType().equals(other.getOuterType())) 146 | return false; 147 | return true; 148 | } 149 | 150 | @Override 151 | public boolean isValidationRequired() { 152 | return false; 153 | } 154 | 155 | @Override 156 | public ITransaction createTransaction(Object object) { 157 | return null; 158 | } 159 | 160 | @Override 161 | public void onFormRefresh(Object object) { 162 | } 163 | 164 | @Override 165 | public Runnable getLastFormRefreshStateRestorationJob(Object object) { 166 | return null; 167 | } 168 | 169 | @Override 170 | public Map getSpecificProperties() { 171 | return Collections.emptyMap(); 172 | } 173 | 174 | @Override 175 | public String getOnlineHelp() { 176 | return null; 177 | } 178 | 179 | @Override 180 | public String getName() { 181 | return argumentGroup.getClass().getName() + argumentGroup.hashCode(); 182 | } 183 | 184 | @Override 185 | public String getCaption() { 186 | return argumentGroup.title; 187 | } 188 | 189 | @Override 190 | public void validate(Object object, ValidationSession session) throws Exception { 191 | } 192 | 193 | @Override 194 | public String toString(Object object) { 195 | return object.toString(); 196 | } 197 | 198 | @Override 199 | public boolean supports(Object object) { 200 | return (object instanceof ArgumentGroupInstance) 201 | && (((ArgumentGroupInstance) object).model == argumentGroup); 202 | } 203 | 204 | @Override 205 | public void save(Object object, OutputStream out) { 206 | throw new UnsupportedOperationException(); 207 | } 208 | 209 | @Override 210 | public boolean onFormVisibilityChange(Object object, boolean visible) { 211 | return false; 212 | } 213 | 214 | @Override 215 | public void load(Object object, InputStream in) { 216 | throw new UnsupportedOperationException(); 217 | } 218 | 219 | @Override 220 | public boolean isPrimitive() { 221 | return false; 222 | } 223 | 224 | @Override 225 | public boolean isModificationStackAccessible() { 226 | return true; 227 | } 228 | 229 | @Override 230 | public boolean isImmutable() { 231 | return false; 232 | } 233 | 234 | @Override 235 | public boolean isConcrete() { 236 | return true; 237 | } 238 | 239 | @Override 240 | public ITypeInfoSource getSource() { 241 | return TypeInfoSourceFromArgumentGroup.this; 242 | } 243 | 244 | @Override 245 | public List getPolymorphicInstanceSubTypes() { 246 | return Collections.emptyList(); 247 | } 248 | 249 | @Override 250 | public MethodsLayout getMethodsLayout() { 251 | return MethodsLayout.HORIZONTAL_FLOW; 252 | } 253 | 254 | @Override 255 | public List getMethods() { 256 | return Collections.emptyList(); 257 | } 258 | 259 | @Override 260 | public MenuModel getMenuModel() { 261 | return new MenuModel(); 262 | } 263 | 264 | @Override 265 | public ResourcePath getIconImagePath(Object object) { 266 | return null; 267 | } 268 | 269 | @Override 270 | public int getFormPreferredWidth() { 271 | return -1; 272 | } 273 | 274 | @Override 275 | public int getFormPreferredHeight() { 276 | return -1; 277 | } 278 | 279 | @Override 280 | public int getFormSpacing() { 281 | return ITypeInfo.DEFAULT_FORM_SPACING; 282 | } 283 | 284 | @Override 285 | public ColorSpecification getFormForegroundColor() { 286 | return null; 287 | } 288 | 289 | @Override 290 | public ResourcePath getFormBackgroundImagePath() { 291 | return null; 292 | } 293 | 294 | @Override 295 | public ColorSpecification getFormBackgroundColor() { 296 | return null; 297 | } 298 | 299 | @Override 300 | public ColorSpecification getFormBorderColor() { 301 | return null; 302 | } 303 | 304 | @Override 305 | public ColorSpecification getFormEditorForegroundColor() { 306 | return null; 307 | } 308 | 309 | @Override 310 | public ColorSpecification getFormEditorBackgroundColor() { 311 | return null; 312 | } 313 | 314 | @Override 315 | public ColorSpecification getFormButtonBackgroundColor() { 316 | return null; 317 | } 318 | 319 | @Override 320 | public ColorSpecification getFormButtonForegroundColor() { 321 | return null; 322 | } 323 | 324 | @Override 325 | public ResourcePath getFormButtonBackgroundImagePath() { 326 | return null; 327 | } 328 | 329 | @Override 330 | public ColorSpecification getFormButtonBorderColor() { 331 | return null; 332 | } 333 | 334 | @Override 335 | public ColorSpecification getCategoriesBackgroundColor() { 336 | return null; 337 | } 338 | 339 | @Override 340 | public ColorSpecification getCategoriesForegroundColor() { 341 | return null; 342 | } 343 | 344 | @Override 345 | public FieldsLayout getFieldsLayout() { 346 | return FieldsLayout.VERTICAL_FLOW; 347 | } 348 | 349 | @Override 350 | public List getFields() { 351 | List result = new ArrayList(); 352 | for (AbstractCommandLinePart part : argumentGroup.parts) { 353 | IFieldInfo field = getFieldInfoFromCommandLinePart(commandLineUI, part, null, this); 354 | if (field == null) { 355 | continue; 356 | } 357 | result.add(field); 358 | } 359 | return result; 360 | } 361 | 362 | @Override 363 | public List getConstructors() { 364 | return Collections.singletonList(new AbstractConstructorInfo() { 365 | 366 | @Override 367 | public Object invoke(Object parentObject, InvocationData invocationData) { 368 | return new ArgumentGroupInstance(argumentGroup); 369 | } 370 | 371 | @Override 372 | public ITypeInfo getReturnValueType() { 373 | return commandLineUI.getTypeInfo(TypeInfoSourceFromArgumentGroup.this); 374 | } 375 | 376 | }); 377 | } 378 | 379 | @Override 380 | public CategoriesStyle getCategoriesStyle() { 381 | return CategoriesStyle.MODERN; 382 | } 383 | 384 | @Override 385 | public boolean canPersist() { 386 | return false; 387 | } 388 | 389 | @Override 390 | public Object copy(Object object) { 391 | throw new UnsupportedOperationException(); 392 | } 393 | 394 | @Override 395 | public boolean canCopy(Object object) { 396 | return false; 397 | } 398 | 399 | private TypeInfoSourceFromArgumentGroup getOuterType() { 400 | return TypeInfoSourceFromArgumentGroup.this; 401 | } 402 | } 403 | 404 | } 405 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/ui/TypeInfoSourceFromChoice.java: -------------------------------------------------------------------------------- 1 | package xy.command.ui; 2 | 3 | import java.io.InputStream; 4 | import java.io.OutputStream; 5 | import java.util.ArrayList; 6 | import java.util.Collections; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | import xy.command.instance.CommandLineInstance; 11 | import xy.command.model.ArgumentGroup; 12 | import xy.command.model.Choice; 13 | import xy.reflect.ui.ReflectionUI; 14 | import xy.reflect.ui.info.ColorSpecification; 15 | import xy.reflect.ui.info.ITransaction; 16 | import xy.reflect.ui.info.ResourcePath; 17 | import xy.reflect.ui.info.ValidationSession; 18 | import xy.reflect.ui.info.field.IFieldInfo; 19 | import xy.reflect.ui.info.menu.MenuModel; 20 | import xy.reflect.ui.info.method.IMethodInfo; 21 | import xy.reflect.ui.info.type.ITypeInfo; 22 | import xy.reflect.ui.info.type.source.ITypeInfoSource; 23 | import xy.reflect.ui.info.type.source.SpecificitiesIdentifier; 24 | 25 | /** 26 | * Specifies how a {@link Choice} children should be displayed in a GUI. 27 | * 28 | * @author olitank 29 | * 30 | */ 31 | public class TypeInfoSourceFromChoice implements ITypeInfoSource { 32 | 33 | public class TypeInfoFromChoice implements ITypeInfo { 34 | private final CommandLineUI commandLineUI; 35 | 36 | private TypeInfoFromChoice(CommandLineUI commandLineUI) { 37 | this.commandLineUI = commandLineUI; 38 | } 39 | 40 | @Override 41 | public boolean isValidationRequired() { 42 | return false; 43 | } 44 | 45 | @Override 46 | public ITransaction createTransaction(Object object) { 47 | return null; 48 | } 49 | 50 | @Override 51 | public void onFormRefresh(Object object) { 52 | } 53 | 54 | @Override 55 | public Runnable getLastFormRefreshStateRestorationJob(Object object) { 56 | return null; 57 | } 58 | 59 | @Override 60 | public Map getSpecificProperties() { 61 | return Collections.emptyMap(); 62 | } 63 | 64 | @Override 65 | public String getOnlineHelp() { 66 | return null; 67 | } 68 | 69 | @Override 70 | public String getName() { 71 | return choice.getClass().getName() + choice.hashCode(); 72 | } 73 | 74 | @Override 75 | public String getCaption() { 76 | return ""; 77 | } 78 | 79 | @Override 80 | public void validate(Object object, ValidationSession session) throws Exception { 81 | } 82 | 83 | @Override 84 | public String toString(Object object) { 85 | return ""; 86 | } 87 | 88 | @Override 89 | public boolean supports(Object object) { 90 | return object instanceof CommandLineInstance; 91 | } 92 | 93 | @Override 94 | public void save(Object object, OutputStream out) { 95 | throw new UnsupportedOperationException(); 96 | } 97 | 98 | @Override 99 | public boolean onFormVisibilityChange(Object object, boolean visible) { 100 | return false; 101 | } 102 | 103 | @Override 104 | public void load(Object object, InputStream in) { 105 | throw new UnsupportedOperationException(); 106 | } 107 | 108 | @Override 109 | public boolean isPrimitive() { 110 | return false; 111 | } 112 | 113 | @Override 114 | public boolean isModificationStackAccessible() { 115 | return false; 116 | } 117 | 118 | @Override 119 | public boolean isImmutable() { 120 | return false; 121 | } 122 | 123 | @Override 124 | public boolean isConcrete() { 125 | return false; 126 | } 127 | 128 | @Override 129 | public ITypeInfoSource getSource() { 130 | return TypeInfoSourceFromChoice.this; 131 | } 132 | 133 | @Override 134 | public List getPolymorphicInstanceSubTypes() { 135 | List result = new ArrayList(); 136 | for (ArgumentGroup argumentGroup : choice.options) { 137 | ITypeInfo type = commandLineUI.getTypeInfo(new TypeInfoSourceFromArgumentGroup(argumentGroup, null)); 138 | result.add(type); 139 | } 140 | return result; 141 | } 142 | 143 | @Override 144 | public MethodsLayout getMethodsLayout() { 145 | return MethodsLayout.HORIZONTAL_FLOW; 146 | } 147 | 148 | @Override 149 | public List getMethods() { 150 | return Collections.emptyList(); 151 | } 152 | 153 | @Override 154 | public MenuModel getMenuModel() { 155 | return new MenuModel(); 156 | } 157 | 158 | @Override 159 | public ResourcePath getIconImagePath(Object object) { 160 | return null; 161 | } 162 | 163 | @Override 164 | public int getFormPreferredWidth() { 165 | return -1; 166 | } 167 | 168 | @Override 169 | public int getFormPreferredHeight() { 170 | return -1; 171 | } 172 | 173 | @Override 174 | public int getFormSpacing() { 175 | return ITypeInfo.DEFAULT_FORM_SPACING; 176 | } 177 | 178 | @Override 179 | public ColorSpecification getFormForegroundColor() { 180 | return null; 181 | } 182 | 183 | @Override 184 | public ResourcePath getFormBackgroundImagePath() { 185 | return null; 186 | } 187 | 188 | @Override 189 | public ColorSpecification getFormBackgroundColor() { 190 | return null; 191 | } 192 | 193 | @Override 194 | public ColorSpecification getFormBorderColor() { 195 | return null; 196 | } 197 | 198 | @Override 199 | public ColorSpecification getFormEditorForegroundColor() { 200 | return null; 201 | } 202 | 203 | @Override 204 | public ColorSpecification getFormEditorBackgroundColor() { 205 | return null; 206 | } 207 | 208 | @Override 209 | public ColorSpecification getFormButtonBackgroundColor() { 210 | return null; 211 | } 212 | 213 | @Override 214 | public ColorSpecification getFormButtonForegroundColor() { 215 | return null; 216 | } 217 | 218 | @Override 219 | public ResourcePath getFormButtonBackgroundImagePath() { 220 | return null; 221 | } 222 | 223 | @Override 224 | public ColorSpecification getFormButtonBorderColor() { 225 | return null; 226 | } 227 | 228 | @Override 229 | public ColorSpecification getCategoriesBackgroundColor() { 230 | return null; 231 | } 232 | 233 | @Override 234 | public ColorSpecification getCategoriesForegroundColor() { 235 | return null; 236 | } 237 | 238 | @Override 239 | public FieldsLayout getFieldsLayout() { 240 | return FieldsLayout.VERTICAL_FLOW; 241 | } 242 | 243 | @Override 244 | public List getFields() { 245 | return Collections.emptyList(); 246 | } 247 | 248 | @Override 249 | public List getConstructors() { 250 | return Collections.emptyList(); 251 | } 252 | 253 | @Override 254 | public CategoriesStyle getCategoriesStyle() { 255 | return CategoriesStyle.MODERN; 256 | } 257 | 258 | @Override 259 | public Object copy(Object object) { 260 | throw new UnsupportedOperationException(); 261 | } 262 | 263 | @Override 264 | public boolean canPersist() { 265 | return false; 266 | } 267 | 268 | @Override 269 | public boolean canCopy(Object object) { 270 | return false; 271 | } 272 | } 273 | 274 | private CommandLineUI commandLineUI; 275 | private SpecificitiesIdentifier specificitiesIdentifier; 276 | private Choice choice; 277 | 278 | public TypeInfoSourceFromChoice(CommandLineUI commandLineUI, SpecificitiesIdentifier specificitiesIdentifier, 279 | Choice choice) { 280 | this.commandLineUI = commandLineUI; 281 | this.specificitiesIdentifier = specificitiesIdentifier; 282 | this.choice = choice; 283 | } 284 | 285 | @Override 286 | public SpecificitiesIdentifier getSpecificitiesIdentifier() { 287 | return specificitiesIdentifier; 288 | } 289 | 290 | @Override 291 | public ITypeInfo buildTypeInfo(ReflectionUI reflectionUI) { 292 | return new TypeInfoFromChoice(commandLineUI); 293 | } 294 | 295 | } 296 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/ui/TypeInfoSourceFromCommandLine.java: -------------------------------------------------------------------------------- 1 | package xy.command.ui; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | 7 | import javax.swing.SwingUtilities; 8 | 9 | import xy.command.instance.CommandLineInstance; 10 | import xy.command.model.AbstractCommandLinePart; 11 | import xy.command.model.ArgumentPage; 12 | import xy.command.model.Choice; 13 | import xy.command.model.CommandLine; 14 | import xy.command.model.CommandLineProject; 15 | import xy.command.model.DirectoryArgument; 16 | import xy.command.model.FileArgument; 17 | import xy.command.model.FixedArgument; 18 | import xy.command.model.InputArgument; 19 | import xy.command.model.MultiplePart; 20 | import xy.command.model.OptionalPart; 21 | import xy.command.ui.util.CommandUIUtils; 22 | import xy.reflect.ui.ReflectionUI; 23 | import xy.reflect.ui.info.field.FieldInfoProxy; 24 | import xy.reflect.ui.info.field.IFieldInfo; 25 | import xy.reflect.ui.info.method.IMethodInfo; 26 | import xy.reflect.ui.info.method.InvocationData; 27 | import xy.reflect.ui.info.method.MethodInfoProxy; 28 | import xy.reflect.ui.info.type.DefaultTypeInfo; 29 | import xy.reflect.ui.info.type.ITypeInfo; 30 | import xy.reflect.ui.info.type.source.ITypeInfoSource; 31 | import xy.reflect.ui.info.type.source.JavaTypeInfoSource; 32 | import xy.reflect.ui.info.type.source.SpecificitiesIdentifier; 33 | import xy.reflect.ui.util.PrecomputedTypeInstanceWrapper; 34 | import xy.reflect.ui.util.ReflectionUIError; 35 | import xy.reflect.ui.util.ReflectionUIUtils; 36 | 37 | /** 38 | * Specifies how a {@link CommandLine} should be displayed in a GUI. 39 | * 40 | * @author olitank 41 | * 42 | */ 43 | public class TypeInfoSourceFromCommandLine implements ITypeInfoSource { 44 | 45 | private CommandLine commandLine; 46 | private SpecificitiesIdentifier specificitiesIdentifier; 47 | 48 | public TypeInfoSourceFromCommandLine(CommandLine commandLine, 49 | SpecificitiesIdentifier specificitiesIdentifier) { 50 | this.commandLine = commandLine; 51 | this.specificitiesIdentifier = specificitiesIdentifier; 52 | } 53 | 54 | @Override 55 | public int hashCode() { 56 | final int prime = 31; 57 | int result = 1; 58 | result = prime * result + ((commandLine == null) ? 0 : commandLine.hashCode()); 59 | result = prime * result + ((specificitiesIdentifier == null) ? 0 : specificitiesIdentifier.hashCode()); 60 | return result; 61 | } 62 | 63 | @Override 64 | public boolean equals(Object obj) { 65 | if (this == obj) 66 | return true; 67 | if (obj == null) 68 | return false; 69 | if (getClass() != obj.getClass()) 70 | return false; 71 | TypeInfoSourceFromCommandLine other = (TypeInfoSourceFromCommandLine) obj; 72 | if (commandLine == null) { 73 | if (other.commandLine != null) 74 | return false; 75 | } else if (!commandLine.equals(other.commandLine)) 76 | return false; 77 | if (specificitiesIdentifier == null) { 78 | if (other.specificitiesIdentifier != null) 79 | return false; 80 | } else if (!specificitiesIdentifier.equals(other.specificitiesIdentifier)) 81 | return false; 82 | return true; 83 | } 84 | 85 | @Override 86 | public SpecificitiesIdentifier getSpecificitiesIdentifier() { 87 | return specificitiesIdentifier; 88 | } 89 | 90 | @Override 91 | public ITypeInfo buildTypeInfo(ReflectionUI reflectionUI) { 92 | return new TypeInfo(reflectionUI); 93 | } 94 | 95 | protected IFieldInfo getFieldInfoFromCommandLinePart(CommandLineUI commandLineUI, AbstractCommandLinePart part, 96 | ArgumentPage argumentPage, ITypeInfo commandLineTypeInfo) { 97 | if (part instanceof FixedArgument) { 98 | return null; 99 | } else if (part instanceof InputArgument) { 100 | return new FieldInfoFromInputArgument(commandLineUI, (InputArgument) part, argumentPage, commandLine, 101 | commandLineTypeInfo); 102 | } else if (part instanceof DirectoryArgument) { 103 | return new FieldInfoFromDirectoryArgument(commandLineUI, (DirectoryArgument) part, argumentPage, 104 | commandLine, commandLineTypeInfo); 105 | } else if (part instanceof FileArgument) { 106 | return new FieldInfoFromFileArgument(commandLineUI, (FileArgument) part, argumentPage, commandLine, 107 | commandLineTypeInfo); 108 | } else if (part instanceof Choice) { 109 | return new FieldInfoFromChoice(commandLineUI, (Choice) part, argumentPage, commandLine, 110 | commandLineTypeInfo); 111 | } else if (part instanceof OptionalPart) { 112 | return new FieldInfoFromOptionalPart(commandLineUI, (OptionalPart) part, argumentPage, commandLine, 113 | commandLineTypeInfo); 114 | } else if (part instanceof MultiplePart) { 115 | return new FieldInfoFromMultiplePart(commandLineUI, (MultiplePart) part, argumentPage, commandLine, 116 | commandLineTypeInfo); 117 | } else { 118 | throw new ReflectionUIError(); 119 | } 120 | } 121 | 122 | protected class TypeInfo extends DefaultTypeInfo { 123 | 124 | public TypeInfo(ReflectionUI reflectionUI) { 125 | super(reflectionUI, new JavaTypeInfoSource(CommandLineInstance.class, null)); 126 | } 127 | 128 | @Override 129 | public String getCaption() { 130 | return commandLine.title; 131 | } 132 | 133 | @Override 134 | public String getOnlineHelp() { 135 | return commandLine.description; 136 | } 137 | 138 | @Override 139 | public List getMethods() { 140 | return Collections.singletonList(new ExecutionMethodInfo(reflectionUI)); 141 | } 142 | 143 | @Override 144 | public List getFields() { 145 | return Collections.singletonList(new CapsuleFieldInfo(reflectionUI)); 146 | } 147 | 148 | @Override 149 | public ITypeInfoSource getSource() { 150 | return TypeInfoSourceFromCommandLine.this; 151 | } 152 | 153 | } 154 | 155 | protected class Capsule { 156 | 157 | protected CommandLineInstance commandLineInstance; 158 | 159 | public Capsule(CommandLineInstance commandLineInstance) { 160 | super(); 161 | this.commandLineInstance = commandLineInstance; 162 | } 163 | 164 | public CommandLineInstance getCommandLineInstance() { 165 | return commandLineInstance; 166 | } 167 | 168 | } 169 | 170 | protected class CapsuleFieldInfo extends FieldInfoProxy { 171 | 172 | protected ReflectionUI reflectionUI; 173 | 174 | public CapsuleFieldInfo(ReflectionUI reflectionUI) { 175 | super(IFieldInfo.NULL_FIELD_INFO); 176 | this.reflectionUI = reflectionUI; 177 | } 178 | 179 | @Override 180 | public String getName() { 181 | return "capsule"; 182 | } 183 | 184 | @Override 185 | public String getCaption() { 186 | return ""; 187 | } 188 | 189 | @Override 190 | public void setValue(Object object, Object value) { 191 | throw new UnsupportedOperationException(); 192 | } 193 | 194 | @Override 195 | public boolean isFormControlMandatory() { 196 | return true; 197 | } 198 | 199 | @Override 200 | public boolean isFormControlEmbedded() { 201 | return true; 202 | } 203 | 204 | @Override 205 | public Object getValue(Object object) { 206 | return new PrecomputedTypeInstanceWrapper(new Capsule((CommandLineInstance) object), 207 | new CapsuleTypeInfo(reflectionUI)); 208 | } 209 | 210 | @Override 211 | public ITypeInfo getType() { 212 | return reflectionUI 213 | .getTypeInfo(new PrecomputedTypeInstanceWrapper.TypeInfoSource(new CapsuleTypeInfo(reflectionUI))); 214 | } 215 | 216 | } 217 | 218 | protected class CapsuleTypeInfo extends DefaultTypeInfo { 219 | 220 | public CapsuleTypeInfo(ReflectionUI reflectionUI) { 221 | super(reflectionUI, new JavaTypeInfoSource(Capsule.class, new SpecificitiesIdentifier( 222 | new TypeInfo(reflectionUI).getName(), new CapsuleFieldInfo(reflectionUI).getName()))); 223 | } 224 | 225 | @Override 226 | public String getCaption() { 227 | return commandLine.title + " - Settings"; 228 | } 229 | 230 | @Override 231 | public List getMethods() { 232 | return Collections.emptyList(); 233 | } 234 | 235 | @Override 236 | public List getFields() { 237 | List result = new ArrayList(); 238 | for (ArgumentPage argumentPage : commandLine.arguments) { 239 | for (AbstractCommandLinePart part : argumentPage.parts) { 240 | IFieldInfo field = getFieldInfoFromCommandLinePart((CommandLineUI) reflectionUI, part, argumentPage, this); 241 | if (field == null) { 242 | continue; 243 | } 244 | field = new FieldInfoProxy(field) { 245 | 246 | @Override 247 | public Object getValue(Object object) { 248 | return super.getValue(((Capsule) object).getCommandLineInstance()); 249 | } 250 | 251 | @Override 252 | public void setValue(Object object, Object value) { 253 | super.setValue(((Capsule) object).getCommandLineInstance(), value); 254 | } 255 | 256 | }; 257 | result.add(field); 258 | } 259 | } 260 | return result; 261 | } 262 | 263 | } 264 | 265 | protected class ExecutionMethodInfo extends MethodInfoProxy { 266 | 267 | protected ReflectionUI reflectionUI; 268 | 269 | public ExecutionMethodInfo(ReflectionUI reflectionUI) { 270 | super(IMethodInfo.NULL_METHOD_INFO); 271 | this.reflectionUI = reflectionUI; 272 | } 273 | 274 | @Override 275 | public String getName() { 276 | return "execute"; 277 | } 278 | 279 | @Override 280 | public String getSignature() { 281 | return ReflectionUIUtils.buildMethodSignature(this); 282 | } 283 | 284 | @Override 285 | public String getCaption() { 286 | return "Execute"; 287 | } 288 | 289 | @Override 290 | public boolean isReadOnly() { 291 | return true; 292 | } 293 | 294 | @Override 295 | public Object invoke(Object object, InvocationData invocationData) { 296 | final CommandLineProject project = (CommandLineProject) commandLine; 297 | final CommandLineInstance instance = (CommandLineInstance) object; 298 | final String commandText = CommandUIUtils.quoteArgument(project.executablePath.getPath()) + " " 299 | + instance.getExecutionText(); 300 | SwingUtilities.invokeLater(new Runnable() { 301 | @Override 302 | public void run() { 303 | CommandMonitoringDialog d = new CommandMonitoringDialog(null, commandText, project.executionDir); 304 | d.setVisible(true); 305 | } 306 | }); 307 | return null; 308 | } 309 | } 310 | 311 | } 312 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/ui/resource/ClassInPackage.java: -------------------------------------------------------------------------------- 1 | package xy.command.ui.resource; 2 | 3 | /** 4 | * Just used to reference the current package. 5 | * 6 | * @author olitank 7 | * 8 | */ 9 | public class ClassInPackage { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/ui/util/CommandUIUtils.java: -------------------------------------------------------------------------------- 1 | package xy.command.ui.util; 2 | 3 | import java.awt.BorderLayout; 4 | import java.awt.Component; 5 | import java.awt.FlowLayout; 6 | import java.io.File; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.io.OutputStream; 10 | import java.util.List; 11 | import java.util.StringTokenizer; 12 | import java.util.Vector; 13 | 14 | import javax.swing.BorderFactory; 15 | import javax.swing.JPanel; 16 | 17 | /** 18 | * Various utilities needed by the classes of the library. 19 | * 20 | * @author olitank 21 | * 22 | */ 23 | public class CommandUIUtils { 24 | 25 | public static Component flowInLayout(Component c, int flowLayoutAlignment) { 26 | JPanel result = new JPanel(); 27 | result.setLayout(new FlowLayout(flowLayoutAlignment)); 28 | result.add(c); 29 | return result; 30 | } 31 | 32 | public static Component withLabel(Component c, String title) { 33 | JPanel result = new JPanel(); 34 | result.setLayout(new BorderLayout()); 35 | result.add(c, BorderLayout.CENTER); 36 | result.setBorder(BorderFactory.createTitledBorder(title)); 37 | return result; 38 | } 39 | 40 | public static int runCommand(final String command, boolean wait, final OutputStream outReceiver, 41 | final OutputStream errReceiver, File workingDir) { 42 | String[] args = splitArguments(command); 43 | if (args.length == 0) { 44 | throw new RuntimeException("Executable file not specified"); 45 | } 46 | final Process process; 47 | try { 48 | process = Runtime.getRuntime().exec(args, null, workingDir); 49 | } catch (IOException e1) { 50 | throw new AssertionError("Command execution error: " + e1.toString()); 51 | } 52 | 53 | final Thread outputRedirector; 54 | { 55 | String reason = "Output Stream Consumption for command: " + command; 56 | if (outReceiver != null) { 57 | outputRedirector = redirectStream(process.getInputStream(), outReceiver, reason); 58 | } else { 59 | outputRedirector = redirectStream(process.getInputStream(), getNullOutputStream(), reason); 60 | } 61 | } 62 | 63 | final Thread errorRedirector; 64 | { 65 | String reason = "Error Stream Consumption for command: " + command; 66 | if (errReceiver != null) { 67 | errorRedirector = redirectStream(process.getErrorStream(), errReceiver, reason); 68 | } else { 69 | errorRedirector = redirectStream(process.getErrorStream(), getNullOutputStream(), reason); 70 | } 71 | } 72 | 73 | Thread cleaner = new Thread("Cleaner for command: " + command) { 74 | @Override 75 | public void run() { 76 | try { 77 | process.waitFor(); 78 | } catch (Exception e) { 79 | throw new AssertionError(e); 80 | } 81 | CommandUIUtils.sleep(1000); 82 | for (Thread thread : new Thread[] { outputRedirector, errorRedirector }) { 83 | if (thread.isAlive()) { 84 | thread.interrupt(); 85 | while (thread.isAlive()) { 86 | relieveCPU(); 87 | } 88 | } 89 | } 90 | try { 91 | process.getInputStream().close(); 92 | process.getErrorStream().close(); 93 | } catch (IOException e) { 94 | throw new AssertionError(e); 95 | } 96 | } 97 | }; 98 | 99 | cleaner.start(); 100 | 101 | if (!wait) { 102 | return 0; 103 | } 104 | 105 | try { 106 | cleaner.join(); 107 | } catch (InterruptedException e) { 108 | Thread.currentThread().interrupt(); 109 | } 110 | 111 | if (Thread.currentThread().isInterrupted()) { 112 | process.destroy(); 113 | return 0; 114 | } else { 115 | return process.exitValue(); 116 | } 117 | } 118 | 119 | public static void sleep(long durationMilliseconds) { 120 | try { 121 | Thread.sleep(durationMilliseconds); 122 | } catch (InterruptedException e) { 123 | Thread.currentThread().interrupt(); 124 | } 125 | } 126 | 127 | protected static OutputStream getNullOutputStream() { 128 | return new OutputStream() { 129 | @Override 130 | public void write(int b) throws IOException { 131 | } 132 | }; 133 | } 134 | 135 | public static OutputStream unifyOutputStreams(final OutputStream[] outputStreams) { 136 | return new OutputStream() { 137 | 138 | @Override 139 | public void write(int b) throws IOException { 140 | for (OutputStream out : outputStreams) { 141 | out.write(b); 142 | } 143 | } 144 | 145 | @Override 146 | public void write(byte[] b) throws IOException { 147 | for (OutputStream out : outputStreams) { 148 | out.write(b); 149 | } 150 | } 151 | 152 | @Override 153 | public void write(byte[] b, int off, int len) throws IOException { 154 | for (OutputStream out : outputStreams) { 155 | out.write(b, off, len); 156 | } 157 | } 158 | 159 | @Override 160 | public void flush() throws IOException { 161 | for (OutputStream out : outputStreams) { 162 | out.flush(); 163 | } 164 | } 165 | 166 | @Override 167 | public void close() throws IOException { 168 | for (OutputStream out : outputStreams) { 169 | out.close(); 170 | } 171 | } 172 | }; 173 | } 174 | 175 | public static Thread redirectStream(final InputStream src, final OutputStream dst, String reason) { 176 | Thread thread = new Thread("Stream Redirector (" + reason + ")") { 177 | public void run() { 178 | try { 179 | while (true) { 180 | if (src.available() > 0) { 181 | int b = src.read(); 182 | if (b == -1) { 183 | break; 184 | } 185 | try { 186 | dst.write(b); 187 | } catch (Throwable t) { 188 | throw new RuntimeException(t); 189 | } 190 | } else { 191 | if (isInterrupted()) { 192 | if (src.available() == 0) { 193 | break; 194 | } 195 | } else { 196 | relieveCPU(); 197 | } 198 | } 199 | } 200 | } catch (IOException e) { 201 | if (e.toString().toLowerCase().contains("stream closed")) { 202 | return; 203 | } 204 | throw new AssertionError(e); 205 | } 206 | } 207 | }; 208 | thread.start(); 209 | return thread; 210 | } 211 | 212 | public static void relieveCPU() { 213 | sleep(100); 214 | } 215 | 216 | public static String formatArgumentList(List argList) { 217 | StringBuilder result = new StringBuilder(); 218 | for (int i = 0; i < argList.size(); i++) { 219 | String arg = argList.get(i); 220 | if (i > 0) { 221 | result.append(" "); 222 | } 223 | result.append(arg); 224 | } 225 | return result.toString(); 226 | } 227 | 228 | public static String quoteArgument(String argument) { 229 | String[] argumentSplitByQuotes = argument.split("\"", -1); 230 | if (argumentSplitByQuotes.length == 1) { 231 | return "\"" + argument + "\""; 232 | } else { 233 | StringBuilder result = new StringBuilder(); 234 | for (int i = 0; i < argumentSplitByQuotes.length; i++) { 235 | if (i > 0) { 236 | result.append("'\"'"); 237 | } 238 | String elementOfArgumentSplitByQuotes = argumentSplitByQuotes[i]; 239 | result.append(quoteArgument(elementOfArgumentSplitByQuotes)); 240 | } 241 | return result.toString(); 242 | } 243 | } 244 | 245 | public static String[] splitArguments(String s) { 246 | if ((s == null) || (s.length() == 0)) { 247 | return new String[0]; 248 | } 249 | final int normal = 0; 250 | final int inQuote = 1; 251 | final int inDoubleQuote = 2; 252 | int state = normal; 253 | StringTokenizer tok = new StringTokenizer(s, "\"\' ", true); 254 | Vector v = new Vector(); 255 | StringBuilder current = new StringBuilder(); 256 | 257 | while (tok.hasMoreTokens()) { 258 | String nextTok = tok.nextToken(); 259 | switch (state) { 260 | case inQuote: 261 | if ("\'".equals(nextTok)) { 262 | state = normal; 263 | } else { 264 | current.append(nextTok); 265 | } 266 | break; 267 | case inDoubleQuote: 268 | if ("\"".equals(nextTok)) { 269 | state = normal; 270 | } else { 271 | current.append(nextTok); 272 | } 273 | break; 274 | default: 275 | if ("\'".equals(nextTok)) { 276 | state = inQuote; 277 | } else if ("\"".equals(nextTok)) { 278 | state = inDoubleQuote; 279 | } else if (" ".equals(nextTok)) { 280 | if (current.length() != 0) { 281 | v.addElement(current.toString()); 282 | current.setLength(0); 283 | } 284 | } else { 285 | current.append(nextTok); 286 | } 287 | break; 288 | } 289 | } 290 | 291 | if (current.length() != 0) { 292 | v.addElement(current.toString()); 293 | } 294 | 295 | if ((state == inQuote) || (state == inDoubleQuote)) { 296 | throw new RuntimeException("unbalanced quotes in " + s); 297 | } 298 | 299 | String[] args = new String[v.size()]; 300 | v.copyInto(args); 301 | return args; 302 | } 303 | 304 | } 305 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/ui/util/CountingFilenameFilter.java: -------------------------------------------------------------------------------- 1 | package xy.command.ui.util; 2 | 3 | import java.io.File; 4 | import java.io.FilenameFilter; 5 | 6 | /** 7 | * Proxy of {@link FilenameFilter} that just counts files and folders accepted 8 | * by the specified base object. 9 | * 10 | * @author olitank 11 | * 12 | */ 13 | public class CountingFilenameFilter implements FilenameFilter { 14 | protected int filteredCount = 0; 15 | protected FilenameFilter delegate; 16 | 17 | public CountingFilenameFilter(FilenameFilter delegate) { 18 | this.delegate = delegate; 19 | } 20 | 21 | public int getFilteredCount() { 22 | return filteredCount; 23 | } 24 | 25 | public FilenameFilter getDelegate() { 26 | return delegate; 27 | } 28 | 29 | @Override 30 | public boolean accept(File dir, String name) { 31 | boolean result = delegate.accept(dir, name); 32 | if (!result) { 33 | filteredCount++; 34 | } 35 | return result; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/ui/util/DocumentOutputStream.java: -------------------------------------------------------------------------------- 1 | package xy.command.ui.util; 2 | 3 | import java.io.OutputStream; 4 | 5 | import java.io.IOException; 6 | import java.lang.reflect.InvocationTargetException; 7 | 8 | import javax.swing.SwingUtilities; 9 | import javax.swing.text.*; 10 | 11 | /** 12 | * 13 | * An OutputStream implementation that places it's 14 | * 15 | * output in a swing text model (Document). The 16 | * 17 | * Document can be either a plain text or styled 18 | * 19 | * document implementation. If styled, the attributes 20 | * 21 | * assigned to the output stream will be used in 22 | * 23 | * the display of the output. 24 | * 25 | * 26 | * 27 | * @author Timothy Prinzing 28 | * 29 | * @version 1.1 02/05/99 30 | */ 31 | 32 | public class DocumentOutputStream extends OutputStream { 33 | 34 | /** 35 | * 36 | * Constructs an output stream that will output to the 37 | * 38 | * given document with the given set of character attributes. 39 | * 40 | * 41 | * 42 | * @param doc 43 | * the document to write to. 44 | * 45 | * @param a 46 | * the character attributes to use for the written 47 | * 48 | * text. 49 | */ 50 | 51 | public DocumentOutputStream(Document doc, AttributeSet a) { 52 | this.doc = doc; 53 | this.a = a; 54 | } 55 | 56 | /** 57 | * 58 | * Constructs an output stream that will output to the 59 | * 60 | * given document with whatever the default attributes 61 | * 62 | * are. 63 | * 64 | * 65 | * 66 | * @param doc 67 | * the document to write to. 68 | */ 69 | 70 | public DocumentOutputStream(Document doc) { 71 | this(doc, null); 72 | } 73 | 74 | /** 75 | * 76 | * Writes the specified byte to this output stream. 77 | * 78 | *

79 | * 80 | * Subclasses of OutputStream must provide an 81 | * 82 | * implementation for this method. 83 | * 84 | * 85 | * 86 | * @param b 87 | * the byte. 88 | * 89 | * @exception IOException 90 | * if an I/O error occurs. 91 | * 92 | * @since JDK1.0 93 | */ 94 | 95 | public void write(int b) throws IOException { 96 | one[0] = (byte) b; 97 | write(one, 0, 1); 98 | } 99 | 100 | /** 101 | * 102 | * Writes len bytes from the specified byte array 103 | * 104 | * starting at offset off to this output stream. 105 | * 106 | *

107 | * 108 | * The write method of OutputStream calls 109 | * 110 | * the write method of one argument on each of the bytes to be 111 | * 112 | * written out. Subclasses are encouraged to override this method and 113 | * 114 | * provide a more efficient implementation. 115 | * 116 | * 117 | * 118 | * @param b 119 | * the data. 120 | * 121 | * @param off 122 | * the start offset in the data. 123 | * 124 | * @param len 125 | * the number of bytes to write. 126 | * 127 | * @exception IOException 128 | * if an I/O error occurs. 129 | * 130 | * @since JDK1.0 131 | */ 132 | 133 | public void write(final byte b[], final int off, final int len) 134 | throws IOException { 135 | try { 136 | SwingUtilities.invokeAndWait(new Runnable() { 137 | 138 | @Override 139 | public void run() { 140 | try { 141 | doc.insertString(doc.getLength(), new String(b, off, len), 142 | a); 143 | } catch (BadLocationException ble) { 144 | throw new RuntimeException(ble); 145 | } 146 | } 147 | }); 148 | } catch (InterruptedException e) { 149 | throw new IOException(e); 150 | } catch (InvocationTargetException e) { 151 | throw new IOException(e); 152 | } 153 | 154 | } 155 | 156 | protected byte[] one = new byte[1]; 157 | 158 | protected Document doc; 159 | 160 | protected AttributeSet a; 161 | 162 | } 163 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/ui/util/FileUtils.java: -------------------------------------------------------------------------------- 1 | package xy.command.ui.util; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileOutputStream; 6 | import java.io.FilenameFilter; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | 10 | /** 11 | * Various utilities for dealing with files. 12 | * 13 | * @author olitank 14 | * 15 | */ 16 | public class FileUtils { 17 | 18 | public static String read(File file) throws Exception { 19 | return new String(readBinary(file)); 20 | } 21 | 22 | public static byte[] readBinary(File file) throws Exception { 23 | InputStream in = null; 24 | try { 25 | in = new FileInputStream(file); 26 | long length = file.length(); 27 | byte[] bytes = new byte[(int) length]; 28 | int offset = 0; 29 | int numRead = 0; 30 | while (offset < bytes.length && (numRead = in.read(bytes, offset, bytes.length - offset)) >= 0) { 31 | offset += numRead; 32 | } 33 | if (offset < bytes.length) { 34 | throw new IOException("Could not completely read file"); 35 | } 36 | in.close(); 37 | return bytes; 38 | } catch (IOException e) { 39 | throw new Exception("Unable to read file : '" + file.getAbsolutePath() + "': " + e.getMessage(), e); 40 | } finally { 41 | if (in != null) { 42 | try { 43 | in.close(); 44 | } catch (IOException e) { 45 | } 46 | } 47 | } 48 | } 49 | 50 | public static void write(File file, String text, boolean append) throws Exception { 51 | writeBinary(file, text.getBytes(), append); 52 | } 53 | 54 | public static void writeBinary(File file, byte[] bytes, boolean append) throws Exception { 55 | FileOutputStream out = null; 56 | try { 57 | out = new FileOutputStream(file); 58 | out.write(bytes); 59 | out.flush(); 60 | out.close(); 61 | } catch (IOException e) { 62 | throw new Exception("Unable to write file : '" + file.getAbsolutePath() + "': " + e.getMessage(), e); 63 | } finally { 64 | if (out != null) { 65 | try { 66 | out.close(); 67 | } catch (IOException e) { 68 | } 69 | } 70 | } 71 | 72 | } 73 | 74 | public static String removeFileNameExtension(String fileName) { 75 | String extension = getFileNameExtension(fileName); 76 | if (extension.length() > 0) { 77 | return fileName.substring(0, fileName.length() - ("." + extension).length()); 78 | } else { 79 | return fileName; 80 | } 81 | } 82 | 83 | public static String getFileNameExtension(String fileName) { 84 | int lastDotIndex = fileName.lastIndexOf("."); 85 | if (lastDotIndex == -1) { 86 | return ""; 87 | } else { 88 | return fileName.substring(lastDotIndex + 1); 89 | } 90 | } 91 | 92 | public static void copy(File src, File dst) throws Exception { 93 | copy(src, dst, true); 94 | } 95 | 96 | public static void copy(File src, File dst, boolean recusrsively) throws Exception { 97 | copy(src, dst, recusrsively, null); 98 | } 99 | 100 | public static void copy(File src, File dst, boolean recusrsively, FilenameFilter filenameFilter) throws Exception { 101 | try { 102 | if (src.isDirectory()) { 103 | mkDir(dst); 104 | if (recusrsively) { 105 | for (File srcChild : src.listFiles(filenameFilter)) { 106 | copy(srcChild, new File(dst, srcChild.getName()), recusrsively, filenameFilter); 107 | } 108 | } 109 | } else if (src.isFile()) { 110 | writeBinary(dst, readBinary(src), false); 111 | } else { 112 | throw new Exception("File not found: '" + src + "'", null); 113 | } 114 | } catch (Exception e) { 115 | throw new Exception("Unable to copy resource: '" + src.getAbsolutePath() + "' > '" + dst.getAbsolutePath() 116 | + "': " + e.getMessage(), e); 117 | } 118 | } 119 | 120 | public static void mkDir(File dir) throws Exception { 121 | if (dir.isDirectory()) { 122 | return; 123 | } 124 | final boolean success; 125 | try { 126 | success = dir.mkdir(); 127 | } catch (Exception e) { 128 | throw new Exception("Failed to create directory: '" + dir.getAbsolutePath() + "': " + e.getMessage(), e); 129 | } 130 | if (!success) { 131 | throw new Exception("Unable to create directory: '" + dir.getAbsolutePath() + "'", null); 132 | } 133 | } 134 | 135 | public static String getRelativePath(File child, File ancestor) { 136 | if (!FileUtils.isAncestor(ancestor, child)) { 137 | return null; 138 | } 139 | try { 140 | return child.getCanonicalPath().substring(ancestor.getCanonicalPath().length() + 1); 141 | } catch (IOException e) { 142 | throw new RuntimeException(e); 143 | } 144 | } 145 | 146 | public static boolean canonicallyEquals(File file1, File file2) { 147 | try { 148 | return file1.getCanonicalFile().equals(file2.getCanonicalFile()); 149 | } catch (IOException e) { 150 | throw new RuntimeException(e.toString(), e); 151 | } 152 | } 153 | 154 | public static File getCanonicalParent(File file) { 155 | try { 156 | return file.getCanonicalFile().getParentFile(); 157 | } catch (IOException e) { 158 | throw new RuntimeException(e); 159 | } 160 | } 161 | 162 | public static void delete(File file) throws Exception { 163 | delete(file, null); 164 | } 165 | 166 | public static void delete(File file, final FilenameFilter filter) throws Exception { 167 | if (file.isDirectory()) { 168 | CountingFilenameFilter countingFilter = (filter != null) ? new CountingFilenameFilter(filter) : null; 169 | for (File childFile : file.listFiles(countingFilter)) { 170 | delete(childFile, countingFilter); 171 | } 172 | if ((countingFilter != null) && countingFilter.getFilteredCount() > 0) { 173 | return; 174 | } 175 | } 176 | boolean success; 177 | try { 178 | success = file.delete(); 179 | } catch (Exception e) { 180 | throw new Exception("Failed to delete resource: '" + file.getAbsolutePath() + "'" + e.getMessage(), e); 181 | } 182 | if (!success) { 183 | throw new Exception("Unable to delete resource: '" + file.getAbsolutePath() + "'", null); 184 | } 185 | } 186 | 187 | public static void rename(File file, String destFileName) throws Exception { 188 | try { 189 | if (new File(destFileName).getParent() != null) { 190 | throw new Exception("Destination file name is not is not a local name: '" + destFileName + "'"); 191 | } 192 | File destFile = new File(file.getParent(), destFileName); 193 | boolean success = file.renameTo(destFile); 194 | if (!success) { 195 | throw new Exception("System error"); 196 | } 197 | } catch (Exception e) { 198 | throw new Exception("Failed to rename resource: '" + file.getAbsolutePath() + "' to '" + destFileName 199 | + "': " + e.getMessage(), e); 200 | } 201 | } 202 | 203 | public static boolean hasFileNameExtension(String fileName, String[] extensions) { 204 | for (String ext : extensions) { 205 | if (ext.toLowerCase().equals(getFileNameExtension(fileName).toLowerCase())) { 206 | return true; 207 | } 208 | } 209 | return false; 210 | } 211 | 212 | public static boolean isAncestor(File ancestor, File file) { 213 | File mayBeAncestor = getCanonicalParent(file); 214 | while (true) { 215 | if (mayBeAncestor == null) { 216 | return false; 217 | } 218 | if (canonicallyEquals(mayBeAncestor, ancestor)) { 219 | return true; 220 | } 221 | mayBeAncestor = getCanonicalParent(mayBeAncestor); 222 | } 223 | } 224 | 225 | } 226 | -------------------------------------------------------------------------------- /command-ui/src/main/java/xy/command/ui/util/ValidationError.java: -------------------------------------------------------------------------------- 1 | package xy.command.ui.util; 2 | 3 | /** 4 | * Error thrown when a command line model is not valid. 5 | * 6 | * @author olitank 7 | * 8 | */ 9 | public class ValidationError extends Exception { 10 | 11 | protected static final long serialVersionUID = 1L; 12 | 13 | public ValidationError() { 14 | super(); 15 | } 16 | 17 | public ValidationError(String message, Throwable cause) { 18 | super(message, cause); 19 | } 20 | 21 | public ValidationError(String message) { 22 | super(message); 23 | } 24 | 25 | public ValidationError(Throwable cause) { 26 | super(cause); 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return super.getMessage(); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /command-ui/src/main/resources/xy/command/ui/resource/ArgumentGroup.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotxyteam/CommandUI/18861730d94d150cb61ed16e371576c0a71d6bf2/command-ui/src/main/resources/xy/command/ui/resource/ArgumentGroup.gif -------------------------------------------------------------------------------- /command-ui/src/main/resources/xy/command/ui/resource/ArgumentPage.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotxyteam/CommandUI/18861730d94d150cb61ed16e371576c0a71d6bf2/command-ui/src/main/resources/xy/command/ui/resource/ArgumentPage.gif -------------------------------------------------------------------------------- /command-ui/src/main/resources/xy/command/ui/resource/Choice.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotxyteam/CommandUI/18861730d94d150cb61ed16e371576c0a71d6bf2/command-ui/src/main/resources/xy/command/ui/resource/Choice.gif -------------------------------------------------------------------------------- /command-ui/src/main/resources/xy/command/ui/resource/CommandLine.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotxyteam/CommandUI/18861730d94d150cb61ed16e371576c0a71d6bf2/command-ui/src/main/resources/xy/command/ui/resource/CommandLine.gif -------------------------------------------------------------------------------- /command-ui/src/main/resources/xy/command/ui/resource/DirectoryArgument.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotxyteam/CommandUI/18861730d94d150cb61ed16e371576c0a71d6bf2/command-ui/src/main/resources/xy/command/ui/resource/DirectoryArgument.gif -------------------------------------------------------------------------------- /command-ui/src/main/resources/xy/command/ui/resource/FileArgument.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotxyteam/CommandUI/18861730d94d150cb61ed16e371576c0a71d6bf2/command-ui/src/main/resources/xy/command/ui/resource/FileArgument.gif -------------------------------------------------------------------------------- /command-ui/src/main/resources/xy/command/ui/resource/FixedArgument.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotxyteam/CommandUI/18861730d94d150cb61ed16e371576c0a71d6bf2/command-ui/src/main/resources/xy/command/ui/resource/FixedArgument.gif -------------------------------------------------------------------------------- /command-ui/src/main/resources/xy/command/ui/resource/InputArgument.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotxyteam/CommandUI/18861730d94d150cb61ed16e371576c0a71d6bf2/command-ui/src/main/resources/xy/command/ui/resource/InputArgument.gif -------------------------------------------------------------------------------- /command-ui/src/main/resources/xy/command/ui/resource/MultiplePart.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotxyteam/CommandUI/18861730d94d150cb61ed16e371576c0a71d6bf2/command-ui/src/main/resources/xy/command/ui/resource/MultiplePart.gif -------------------------------------------------------------------------------- /command-ui/src/main/resources/xy/command/ui/resource/OptionalPart.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotxyteam/CommandUI/18861730d94d150cb61ed16e371576c0a71d6bf2/command-ui/src/main/resources/xy/command/ui/resource/OptionalPart.gif -------------------------------------------------------------------------------- /command-ui/src/main/resources/xy/command/ui/resource/banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotxyteam/CommandUI/18861730d94d150cb61ed16e371576c0a71d6bf2/command-ui/src/main/resources/xy/command/ui/resource/banner.jpg -------------------------------------------------------------------------------- /command-ui/src/main/resources/xy/command/ui/resource/baseFont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotxyteam/CommandUI/18861730d94d150cb61ed16e371576c0a71d6bf2/command-ui/src/main/resources/xy/command/ui/resource/baseFont.ttf -------------------------------------------------------------------------------- /command-ui/src/main/resources/xy/command/ui/resource/buttonBackground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotxyteam/CommandUI/18861730d94d150cb61ed16e371576c0a71d6bf2/command-ui/src/main/resources/xy/command/ui/resource/buttonBackground.png -------------------------------------------------------------------------------- /command-ui/src/test/java/xy/command/ui/TestWithAutomation.java: -------------------------------------------------------------------------------- 1 | package xy.command.ui; 2 | 3 | import java.io.File; 4 | import java.nio.file.Files; 5 | 6 | import org.junit.BeforeClass; 7 | import org.junit.Test; 8 | 9 | import xy.reflect.ui.undo.ModificationStack; 10 | import xy.reflect.ui.util.MiscUtils; 11 | import xy.reflect.ui.util.MoreSystemProperties; 12 | import xy.ui.testing.Tester; 13 | import xy.ui.testing.util.TestingUtils; 14 | 15 | public class TestWithAutomation { 16 | 17 | Tester tester = new Tester(); 18 | 19 | protected static void checkSystemProperty(String key, String expectedValue) { 20 | String value = System.getProperty(key); 21 | if (!MiscUtils.equalsOrBothNull(expectedValue, value)) { 22 | String errorMsg = "System property invalid value:\n" + "-D" + key + "=" + value + "\nExpected:\n" + "-D" 23 | + key + "=" + expectedValue; 24 | System.err.println(errorMsg); 25 | throw new AssertionError(errorMsg); 26 | 27 | } 28 | } 29 | 30 | public static void setupTestEnvironment() { 31 | checkSystemProperty(MoreSystemProperties.DEBUG, "true"); 32 | } 33 | 34 | @BeforeClass 35 | public static void beforeAllTests() { 36 | setupTestEnvironment(); 37 | TestingUtils.purgeAllReportsDirectory(); 38 | } 39 | 40 | @Test 41 | public void test() throws Exception { 42 | File comanndLineSpecFile = new File("test.cml"); 43 | if (comanndLineSpecFile.exists()) { 44 | Files.delete(comanndLineSpecFile.toPath()); 45 | } 46 | System.setProperty(ModificationStack.DEFAULT_CAPACITY_PROPERTY_KEY, "100"); 47 | try { 48 | TestingUtils.assertSuccessfulReplay(tester, new File( 49 | System.getProperty("command-ui.project.directory", "./") + "test-specifications/test.stt")); 50 | } finally { 51 | Files.delete(comanndLineSpecFile.toPath()); 52 | } 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /command-ui/todo.txt: -------------------------------------------------------------------------------- 1 | - get new exe icon 2 | - set part types icons 3 | - Allow to parse command syntax??? 4 | . Into clipboard??? In a new argument group??? Allow to choose 5 | - �fixed args only� optionalArg must be represented by a simple checkbox 6 | - Save/load settings option for instances 7 | - Display successful validation 8 | - Validation error for 9 | . Empty optionalArg, MultipleArg, choice, argument group 10 | 11 | For reflectionUI 12 | - List copy problem: modification of original modifies the copy and vice-versa 13 | - Undo tooltip empty 14 | - ListControl �Paste� must be before �Paste Before/After� 15 | 16 | 17 | - check parameter values not empty 18 | - allow to save player state 19 | - Context menu needed 20 | - command icon arg 21 | - add group layout??? 22 | - remove group label and add labelPart 23 | - use env path 24 | - change theme 25 | - make player themable 26 | --------------------------------------------------------------------------------