| 1 | ||
| 1 | <component name="ProjectCodeStyleConfiguration"> | |
| 2 | <state> | |
| 3 | <option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" /> | |
| 4 | </state> | |
| 5 | </component> |
| 1 | ||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | <project version="4"> | |
| 3 | <component name="GradleSettings"> | |
| 4 | <option name="linkedExternalProjectsSettings"> | |
| 5 | <GradleProjectSettings> | |
| 6 | <option name="distributionType" value="LOCAL" /> | |
| 7 | <option name="externalProjectPath" value="$PROJECT_DIR$" /> | |
| 8 | <option name="gradleHome" value="/opt/gradle" /> | |
| 9 | <option name="gradleJvm" value="#JAVA_HOME" /> | |
| 10 | <option name="modules"> | |
| 11 | <set> | |
| 12 | <option value="$PROJECT_DIR$" /> | |
| 13 | </set> | |
| 14 | </option> | |
| 15 | </GradleProjectSettings> | |
| 16 | </option> | |
| 17 | </component> | |
| 18 | </project> |
| 1 | ||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | <project version="4"> | |
| 3 | <component name="ExternalStorageConfigurationManager" enabled="true" /> | |
| 4 | <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="JDK1.8" project-jdk-type="JavaSDK"> | |
| 5 | <output url="file://$PROJECT_DIR$/out" /> | |
| 6 | </component> | |
| 7 | </project> |
| 1 | ||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | <project version="4"> | |
| 3 | <component name="VcsDirectoryMappings"> | |
| 4 | <mapping directory="$PROJECT_DIR$" vcs="Git" /> | |
| 5 | </component> | |
| 6 | </project> |
| 1 | ||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | <project version="4"> | |
| 3 | <component name="ChangeListManager"> | |
| 4 | <list default="true" id="3dcf7c8f-87b5-4d25-a804-39da40a621b8" name="Default Changelist" comment=""> | |
| 5 | <change afterPath="$PROJECT_DIR$/.idea/codeStyles/codeStyleConfig.xml" afterDir="false" /> | |
| 6 | <change afterPath="$PROJECT_DIR$/.idea/vcs.xml" afterDir="false" /> | |
| 7 | <change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" /> | |
| 8 | <change beforePath="$PROJECT_DIR$/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/build.gradle" afterDir="false" /> | |
| 9 | <change beforePath="$PROJECT_DIR$/executable.txt" beforeDir="false" /> | |
| 10 | <change beforePath="$PROJECT_DIR$/gradle.properties" beforeDir="false" afterPath="$PROJECT_DIR$/gradle.properties" afterDir="false" /> | |
| 11 | <change beforePath="$PROJECT_DIR$/libs/renjin-script-engine-0.9.2592-jar-with-dependencies.jar" beforeDir="false" afterPath="$PROJECT_DIR$/libs/renjin-script-engine-0.9.2707-jar-with-dependencies.jar" afterDir="false" /> | |
| 12 | <change beforePath="$PROJECT_DIR$/licenses/MARKDOWN-WRITER-FX" beforeDir="false" afterPath="$PROJECT_DIR$/licenses/MARKDOWN-WRITER-FX.md" afterDir="false" /> | |
| 13 | <change beforePath="$PROJECT_DIR$/src/main/java/com/scrivenvar/AbstractFileFactory.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/scrivenvar/AbstractFileFactory.java" afterDir="false" /> | |
| 14 | <change beforePath="$PROJECT_DIR$/src/main/java/com/scrivenvar/AbstractPane.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/scrivenvar/AbstractPane.java" afterDir="false" /> | |
| 15 | <change beforePath="$PROJECT_DIR$/src/main/java/com/scrivenvar/Constants.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/scrivenvar/Constants.java" afterDir="false" /> | |
| 16 | <change beforePath="$PROJECT_DIR$/src/main/java/com/scrivenvar/FileEditorTab.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/scrivenvar/FileEditorTab.java" afterDir="false" /> | |
| 17 | <change beforePath="$PROJECT_DIR$/src/main/java/com/scrivenvar/FileEditorTabPane.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/scrivenvar/FileEditorTabPane.java" afterDir="false" /> | |
| 18 | <change beforePath="$PROJECT_DIR$/src/main/java/com/scrivenvar/FileType.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/scrivenvar/FileType.java" afterDir="false" /> | |
| 19 | <change beforePath="$PROJECT_DIR$/src/main/java/com/scrivenvar/Main.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/scrivenvar/Main.java" afterDir="false" /> | |
| 20 | <change beforePath="$PROJECT_DIR$/src/main/java/com/scrivenvar/processors/IdentityProcessor.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/scrivenvar/processors/IdentityProcessor.java" afterDir="false" /> | |
| 21 | <change beforePath="$PROJECT_DIR$/src/main/java/com/scrivenvar/processors/InlineRProcessor.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/scrivenvar/processors/InlineRProcessor.java" afterDir="false" /> | |
| 22 | <change beforePath="$PROJECT_DIR$/src/main/java/com/scrivenvar/service/Options.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/scrivenvar/service/Options.java" afterDir="false" /> | |
| 23 | <change beforePath="$PROJECT_DIR$/src/main/java/com/scrivenvar/service/Settings.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/scrivenvar/service/Settings.java" afterDir="false" /> | |
| 24 | </list> | |
| 25 | <ignored path="$PROJECT_DIR$/.gradle/" /> | |
| 26 | <ignored path="$PROJECT_DIR$/build/" /> | |
| 27 | <ignored path="$PROJECT_DIR$/out/" /> | |
| 28 | <option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" /> | |
| 29 | <option name="SHOW_DIALOG" value="false" /> | |
| 30 | <option name="HIGHLIGHT_CONFLICTS" value="true" /> | |
| 31 | <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" /> | |
| 32 | <option name="LAST_RESOLUTION" value="IGNORE" /> | |
| 33 | </component> | |
| 34 | <component name="ExternalProjectsData"> | |
| 35 | <projectState path="$PROJECT_DIR$"> | |
| 36 | <ProjectState /> | |
| 37 | </projectState> | |
| 38 | </component> | |
| 39 | <component name="ExternalProjectsManager"> | |
| 40 | <system id="GRADLE"> | |
| 41 | <state> | |
| 42 | <task path="$PROJECT_DIR$"> | |
| 43 | <activation /> | |
| 44 | </task> | |
| 45 | <projects_view /> | |
| 46 | </state> | |
| 47 | </system> | |
| 48 | </component> | |
| 49 | <component name="FUSProjectUsageTrigger"> | |
| 50 | <session id="332180848"> | |
| 51 | <usages-collector id="statistics.lifecycle.project"> | |
| 52 | <counts> | |
| 53 | <entry key="project.open.time.2" value="1" /> | |
| 54 | <entry key="project.opened" value="1" /> | |
| 55 | </counts> | |
| 56 | </usages-collector> | |
| 57 | <usages-collector id="statistics.file.extensions.open"> | |
| 58 | <counts> | |
| 59 | <entry key="java" value="17" /> | |
| 60 | </counts> | |
| 61 | </usages-collector> | |
| 62 | <usages-collector id="statistics.file.types.open"> | |
| 63 | <counts> | |
| 64 | <entry key="JAVA" value="17" /> | |
| 65 | </counts> | |
| 66 | </usages-collector> | |
| 67 | <usages-collector id="statistics.file.extensions.edit"> | |
| 68 | <counts> | |
| 69 | <entry key="java" value="1995" /> | |
| 70 | <entry key="txt" value="19" /> | |
| 71 | </counts> | |
| 72 | </usages-collector> | |
| 73 | <usages-collector id="statistics.file.types.edit"> | |
| 74 | <counts> | |
| 75 | <entry key="JAVA" value="1995" /> | |
| 76 | <entry key="PLAIN_TEXT" value="19" /> | |
| 77 | </counts> | |
| 78 | </usages-collector> | |
| 79 | </session> | |
| 80 | </component> | |
| 81 | <component name="FileEditorManager"> | |
| 82 | <leaf> | |
| 83 | <file pinned="false" current-in-tab="false"> | |
| 84 | <entry file="file://$PROJECT_DIR$/src/main/java/com/scrivenvar/processors/AbstractProcessor.java"> | |
| 85 | <provider selected="true" editor-type-id="text-editor"> | |
| 86 | <state relative-caret-position="180"> | |
| 87 | <caret line="38" column="22" selection-start-line="38" selection-start-column="22" selection-end-line="38" selection-end-column="22" /> | |
| 88 | </state> | |
| 89 | </provider> | |
| 90 | </entry> | |
| 91 | </file> | |
| 92 | <file pinned="false" current-in-tab="false"> | |
| 93 | <entry file="file://$PROJECT_DIR$/src/main/java/com/scrivenvar/processors/CaretInsertionProcessor.java"> | |
| 94 | <provider selected="true" editor-type-id="text-editor"> | |
| 95 | <state relative-caret-position="-135"> | |
| 96 | <caret line="41" column="22" selection-start-line="41" selection-start-column="22" selection-end-line="41" selection-end-column="22" /> | |
| 97 | </state> | |
| 98 | </provider> | |
| 99 | </entry> | |
| 100 | </file> | |
| 101 | <file pinned="false" current-in-tab="false"> | |
| 102 | <entry file="file://$PROJECT_DIR$/src/main/java/com/scrivenvar/processors/CaretReplacementProcessor.java"> | |
| 103 | <provider selected="true" editor-type-id="text-editor"> | |
| 104 | <state relative-caret-position="165"> | |
| 105 | <caret line="38" column="13" selection-start-line="38" selection-start-column="13" selection-end-line="38" selection-end-column="13" /> | |
| 106 | </state> | |
| 107 | </provider> | |
| 108 | </entry> | |
| 109 | </file> | |
| 110 | <file pinned="false" current-in-tab="false"> | |
| 111 | <entry file="file://$PROJECT_DIR$/src/main/java/com/scrivenvar/processors/DefaultVariableProcessor.java"> | |
| 112 | <provider selected="true" editor-type-id="text-editor"> | |
| 113 | <state relative-caret-position="-101"> | |
| 114 | <caret line="38" column="13" selection-start-line="38" selection-start-column="13" selection-end-line="38" selection-end-column="13" /> | |
| 115 | </state> | |
| 116 | </provider> | |
| 117 | </entry> | |
| 118 | </file> | |
| 119 | <file pinned="false" current-in-tab="false"> | |
| 120 | <entry file="file://$PROJECT_DIR$/src/main/java/com/scrivenvar/processors/HTMLPreviewProcessor.java"> | |
| 121 | <provider selected="true" editor-type-id="text-editor"> | |
| 122 | <state relative-caret-position="439"> | |
| 123 | <caret line="71" lean-forward="true" selection-start-line="71" selection-end-line="71" /> | |
| 124 | </state> | |
| 125 | </provider> | |
| 126 | </entry> | |
| 127 | </file> | |
| 128 | <file pinned="false" current-in-tab="false"> | |
| 129 | <entry file="file://$PROJECT_DIR$/src/main/java/com/scrivenvar/processors/MarkdownCaretInsertionProcessor.java"> | |
| 130 | <provider selected="true" editor-type-id="text-editor"> | |
| 131 | <state relative-caret-position="150"> | |
| 132 | <caret line="38" column="13" selection-start-line="38" selection-start-column="13" selection-end-line="38" selection-end-column="13" /> | |
| 133 | </state> | |
| 134 | </provider> | |
| 135 | </entry> | |
| 136 | </file> | |
| 137 | <file pinned="false" current-in-tab="true"> | |
| 138 | <entry file="file://$PROJECT_DIR$/src/main/java/com/scrivenvar/processors/InlineRProcessor.java"> | |
| 139 | <provider selected="true" editor-type-id="text-editor"> | |
| 140 | <state relative-caret-position="300"> | |
| 141 | <caret line="104" selection-start-line="104" selection-end-line="104" /> | |
| 142 | </state> | |
| 143 | </provider> | |
| 144 | </entry> | |
| 145 | </file> | |
| 146 | </leaf> | |
| 147 | </component> | |
| 148 | <component name="Git.Settings"> | |
| 149 | <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" /> | |
| 150 | </component> | |
| 151 | <component name="GradleLocalSettings"> | |
| 152 | <option name="myGradleHomes"> | |
| 153 | <map> | |
| 154 | <entry key="$PROJECT_DIR$" value="/opt/gradle-4.10.2" /> | |
| 155 | </map> | |
| 156 | </option> | |
| 157 | <option name="myGradleVersions"> | |
| 158 | <map> | |
| 159 | <entry key="$PROJECT_DIR$" value="4.10.2" /> | |
| 160 | </map> | |
| 161 | </option> | |
| 162 | <option name="availableProjects"> | |
| 163 | <map> | |
| 164 | <entry> | |
| 165 | <key> | |
| 166 | <ExternalProjectPojo> | |
| 167 | <option name="name" value="scrivenvar" /> | |
| 168 | <option name="path" value="$PROJECT_DIR$" /> | |
| 169 | </ExternalProjectPojo> | |
| 170 | </key> | |
| 171 | <value> | |
| 172 | <list> | |
| 173 | <ExternalProjectPojo> | |
| 174 | <option name="name" value="scrivenvar" /> | |
| 175 | <option name="path" value="$PROJECT_DIR$" /> | |
| 176 | </ExternalProjectPojo> | |
| 177 | </list> | |
| 178 | </value> | |
| 179 | </entry> | |
| 180 | </map> | |
| 181 | </option> | |
| 182 | <option name="availableTasks"> | |
| 183 | <map> | |
| 184 | <entry key="$PROJECT_DIR$"> | |
| 185 | <value> | |
| 186 | <list> | |
| 187 | <ExternalTaskPojo> | |
| 188 | <option name="description" value="Displays the components produced by root project 'scrivenvar'. [incubating]" /> | |
| 189 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 190 | <option name="name" value="components" /> | |
| 191 | </ExternalTaskPojo> | |
| 192 | <ExternalTaskPojo> | |
| 193 | <option name="description" value="Assembles and tests this project and all projects that depend on it." /> | |
| 194 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 195 | <option name="name" value="buildDependents" /> | |
| 196 | </ExternalTaskPojo> | |
| 197 | <ExternalTaskPojo> | |
| 198 | <option name="description" value="Displays the sub-projects of root project 'scrivenvar'." /> | |
| 199 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 200 | <option name="name" value="projects" /> | |
| 201 | </ExternalTaskPojo> | |
| 202 | <ExternalTaskPojo> | |
| 203 | <option name="description" value="Assembles main classes." /> | |
| 204 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 205 | <option name="name" value="classes" /> | |
| 206 | </ExternalTaskPojo> | |
| 207 | <ExternalTaskPojo> | |
| 208 | <option name="description" value="Displays the dependent components of components in root project 'scrivenvar'. [incubating]" /> | |
| 209 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 210 | <option name="name" value="dependentComponents" /> | |
| 211 | </ExternalTaskPojo> | |
| 212 | <ExternalTaskPojo> | |
| 213 | <option name="description" value="Displays all buildscript dependencies declared in root project 'scrivenvar'." /> | |
| 214 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 215 | <option name="name" value="buildEnvironment" /> | |
| 216 | </ExternalTaskPojo> | |
| 217 | <ExternalTaskPojo> | |
| 218 | <option name="description" value="Runs this project as a JVM application" /> | |
| 219 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 220 | <option name="name" value="run" /> | |
| 221 | </ExternalTaskPojo> | |
| 222 | <ExternalTaskPojo> | |
| 223 | <option name="description" value="Generates Gradle wrapper files." /> | |
| 224 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 225 | <option name="name" value="wrapper" /> | |
| 226 | </ExternalTaskPojo> | |
| 227 | <ExternalTaskPojo> | |
| 228 | <option name="description" value="Assembles test classes." /> | |
| 229 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 230 | <option name="name" value="testClasses" /> | |
| 231 | </ExternalTaskPojo> | |
| 232 | <ExternalTaskPojo> | |
| 233 | <option name="description" value="Generates Javadoc API documentation for the main source code." /> | |
| 234 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 235 | <option name="name" value="javadoc" /> | |
| 236 | </ExternalTaskPojo> | |
| 237 | <ExternalTaskPojo> | |
| 238 | <option name="description" value="Creates OS specific scripts to run the project as a JVM application." /> | |
| 239 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 240 | <option name="name" value="startScripts" /> | |
| 241 | </ExternalTaskPojo> | |
| 242 | <ExternalTaskPojo> | |
| 243 | <option name="description" value="Assembles a jar archive containing the main classes." /> | |
| 244 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 245 | <option name="name" value="jar" /> | |
| 246 | </ExternalTaskPojo> | |
| 247 | <ExternalTaskPojo> | |
| 248 | <option name="description" value="Displays the configuration model of root project 'scrivenvar'. [incubating]" /> | |
| 249 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 250 | <option name="name" value="model" /> | |
| 251 | </ExternalTaskPojo> | |
| 252 | <ExternalTaskPojo> | |
| 253 | <option name="description" value="Installs the project as a distribution as-is." /> | |
| 254 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 255 | <option name="name" value="installDist" /> | |
| 256 | </ExternalTaskPojo> | |
| 257 | <ExternalTaskPojo> | |
| 258 | <option name="description" value="Processes main resources." /> | |
| 259 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 260 | <option name="name" value="processResources" /> | |
| 261 | </ExternalTaskPojo> | |
| 262 | <ExternalTaskPojo> | |
| 263 | <option name="description" value="Displays the tasks runnable from root project 'scrivenvar'." /> | |
| 264 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 265 | <option name="name" value="tasks" /> | |
| 266 | </ExternalTaskPojo> | |
| 267 | <ExternalTaskPojo> | |
| 268 | <option name="description" value="Assembles the main distributions" /> | |
| 269 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 270 | <option name="name" value="assembleDist" /> | |
| 271 | </ExternalTaskPojo> | |
| 272 | <ExternalTaskPojo> | |
| 273 | <option name="description" value="Initializes a new Gradle build." /> | |
| 274 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 275 | <option name="name" value="init" /> | |
| 276 | </ExternalTaskPojo> | |
| 277 | <ExternalTaskPojo> | |
| 278 | <option name="description" value="Runs the unit tests." /> | |
| 279 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 280 | <option name="name" value="test" /> | |
| 281 | </ExternalTaskPojo> | |
| 282 | <ExternalTaskPojo> | |
| 283 | <option name="description" value="Compiles main Java source." /> | |
| 284 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 285 | <option name="name" value="compileJava" /> | |
| 286 | </ExternalTaskPojo> | |
| 287 | <ExternalTaskPojo> | |
| 288 | <option name="description" value="Displays the insight into a specific dependency in root project 'scrivenvar'." /> | |
| 289 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 290 | <option name="name" value="dependencyInsight" /> | |
| 291 | </ExternalTaskPojo> | |
| 292 | <ExternalTaskPojo> | |
| 293 | <option name="description" value="Runs all checks." /> | |
| 294 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 295 | <option name="name" value="check" /> | |
| 296 | </ExternalTaskPojo> | |
| 297 | <ExternalTaskPojo> | |
| 298 | <option name="description" value="Assembles the outputs of this project." /> | |
| 299 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 300 | <option name="name" value="assemble" /> | |
| 301 | </ExternalTaskPojo> | |
| 302 | <ExternalTaskPojo> | |
| 303 | <option name="description" value="Deletes the build directory." /> | |
| 304 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 305 | <option name="name" value="clean" /> | |
| 306 | </ExternalTaskPojo> | |
| 307 | <ExternalTaskPojo> | |
| 308 | <option name="description" value="Compiles test Java source." /> | |
| 309 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 310 | <option name="name" value="compileTestJava" /> | |
| 311 | </ExternalTaskPojo> | |
| 312 | <ExternalTaskPojo> | |
| 313 | <option name="description" value="Displays all dependencies declared in root project 'scrivenvar'." /> | |
| 314 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 315 | <option name="name" value="dependencies" /> | |
| 316 | </ExternalTaskPojo> | |
| 317 | <ExternalTaskPojo> | |
| 318 | <option name="description" value="Processes test resources." /> | |
| 319 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 320 | <option name="name" value="processTestResources" /> | |
| 321 | </ExternalTaskPojo> | |
| 322 | <ExternalTaskPojo> | |
| 323 | <option name="description" value="Displays a help message." /> | |
| 324 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 325 | <option name="name" value="help" /> | |
| 326 | </ExternalTaskPojo> | |
| 327 | <ExternalTaskPojo> | |
| 328 | <option name="description" value="Assembles and tests this project." /> | |
| 329 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 330 | <option name="name" value="build" /> | |
| 331 | </ExternalTaskPojo> | |
| 332 | <ExternalTaskPojo> | |
| 333 | <option name="description" value="Assembles and tests this project and all projects it depends on." /> | |
| 334 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 335 | <option name="name" value="buildNeeded" /> | |
| 336 | </ExternalTaskPojo> | |
| 337 | <ExternalTaskPojo> | |
| 338 | <option name="description" value="Bundles the project as a distribution." /> | |
| 339 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 340 | <option name="name" value="distTar" /> | |
| 341 | </ExternalTaskPojo> | |
| 342 | <ExternalTaskPojo> | |
| 343 | <option name="description" value="Bundles the project as a distribution." /> | |
| 344 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 345 | <option name="name" value="distZip" /> | |
| 346 | </ExternalTaskPojo> | |
| 347 | <ExternalTaskPojo> | |
| 348 | <option name="description" value="Displays the properties of root project 'scrivenvar'." /> | |
| 349 | <option name="linkedExternalProjectPath" value="$PROJECT_DIR$" /> | |
| 350 | <option name="name" value="properties" /> | |
| 351 | </ExternalTaskPojo> | |
| 352 | </list> | |
| 353 | </value> | |
| 354 | </entry> | |
| 355 | </map> | |
| 356 | </option> | |
| 357 | <option name="modificationStamps"> | |
| 358 | <map> | |
| 359 | <entry key="$PROJECT_DIR$" value="6106128056000" /> | |
| 360 | <entry key="$PROJECT_DIR$/.gradle" value="0" /> | |
| 361 | <entry key="$PROJECT_DIR$/build.gradle" value="3956035851" /> | |
| 362 | <entry key="$PROJECT_DIR$/gradle.properties" value="4254081835" /> | |
| 363 | <entry key="$PROJECT_DIR$/settings.gradle" value="0" /> | |
| 364 | </map> | |
| 365 | </option> | |
| 366 | <option name="projectBuildClasspath"> | |
| 367 | <map> | |
| 368 | <entry key="$PROJECT_DIR$"> | |
| 369 | <value> | |
| 370 | <ExternalProjectBuildClasspathPojo> | |
| 371 | <option name="modulesBuildClasspath"> | |
| 372 | <map> | |
| 373 | <entry key="$PROJECT_DIR$"> | |
| 374 | <value> | |
| 375 | <ExternalModuleBuildClasspathPojo> | |
| 376 | <option name="path" value="$PROJECT_DIR$" /> | |
| 377 | </ExternalModuleBuildClasspathPojo> | |
| 378 | </value> | |
| 379 | </entry> | |
| 380 | </map> | |
| 381 | </option> | |
| 382 | <option name="name" value="scrivenvar" /> | |
| 383 | <option name="projectBuildClasspath"> | |
| 384 | <list> | |
| 385 | <option value="/opt/gradle/lib/gradle-api-metadata-4.10.2.jar" /> | |
| 386 | <option value="/opt/gradle/lib/gradle-wrapper-4.10.2.jar" /> | |
| 387 | <option value="/opt/gradle/lib/gradle-docs-4.10.2.jar" /> | |
| 388 | <option value="/opt/gradle/lib/gradle-kotlin-dsl-1.0-rc-6.jar" /> | |
| 389 | <option value="/opt/gradle/lib/gradle-kotlin-dsl-tooling-models-1.0-rc-6.jar" /> | |
| 390 | <option value="/opt/gradle/lib/gradle-core-4.10.2.jar" /> | |
| 391 | <option value="/opt/gradle/lib/ant-1.9.11.jar" /> | |
| 392 | <option value="/opt/gradle/lib/gradle-base-services-4.10.2.jar" /> | |
| 393 | <option value="/opt/gradle/lib/ant-launcher-1.9.11.jar" /> | |
| 394 | <option value="/opt/gradle/lib/groovy-all-2.4.15.jar" /> | |
| 395 | <option value="/opt/gradle/lib/gradle-core-api-4.10.2.jar" /> | |
| 396 | <option value="/opt/gradle/lib/gradle-runtime-api-info-4.10.2.jar" /> | |
| 397 | <option value="/opt/gradle/lib/gradle-build-option-4.10.2.jar" /> | |
| 398 | <option value="/opt/gradle/lib/gradle-base-services-groovy-4.10.2.jar" /> | |
| 399 | <option value="/opt/gradle/lib/gradle-persistent-cache-4.10.2.jar" /> | |
| 400 | <option value="/opt/gradle/lib/gradle-launcher-4.10.2.jar" /> | |
| 401 | <option value="/opt/gradle/lib/gradle-installation-beacon-4.10.2.jar" /> | |
| 402 | <option value="/opt/gradle/lib/gradle-cli-4.10.2.jar" /> | |
| 403 | <option value="/opt/gradle/lib/gradle-model-core-4.10.2.jar" /> | |
| 404 | <option value="/opt/gradle/lib/gradle-kotlin-dsl-tooling-builders-1.0-rc-6.jar" /> | |
| 405 | <option value="/opt/gradle/lib/gradle-native-4.10.2.jar" /> | |
| 406 | <option value="/opt/gradle/lib/gradle-tooling-api-4.10.2.jar" /> | |
| 407 | <option value="/opt/gradle/lib/gradle-build-cache-4.10.2.jar" /> | |
| 408 | <option value="/opt/gradle/lib/gradle-process-services-4.10.2.jar" /> | |
| 409 | <option value="/opt/gradle/lib/gradle-kotlin-dsl-provider-plugins-1.0-rc-6.jar" /> | |
| 410 | <option value="/opt/gradle/lib/gradle-resources-4.10.2.jar" /> | |
| 411 | <option value="/opt/gradle/lib/gradle-messaging-4.10.2.jar" /> | |
| 412 | <option value="/opt/gradle/lib/gradle-model-groovy-4.10.2.jar" /> | |
| 413 | <option value="/opt/gradle/lib/gradle-logging-4.10.2.jar" /> | |
| 414 | <option value="/opt/gradle/lib/gradle-jvm-services-4.10.2.jar" /> | |
| 415 | <option value="/opt/gradle/lib/plugins/gradle-testing-junit-platform-4.10.2.jar" /> | |
| 416 | <option value="/opt/gradle/lib/plugins/gradle-osgi-4.10.2.jar" /> | |
| 417 | <option value="/opt/gradle/lib/plugins/gradle-plugins-4.10.2.jar" /> | |
| 418 | <option value="/opt/gradle/lib/plugins/gradle-version-control-4.10.2.jar" /> | |
| 419 | <option value="/opt/gradle/lib/plugins/gradle-test-kit-4.10.2.jar" /> | |
| 420 | <option value="/opt/gradle/lib/plugins/gradle-diagnostics-4.10.2.jar" /> | |
| 421 | <option value="/opt/gradle/lib/plugins/gradle-resources-s3-4.10.2.jar" /> | |
| 422 | <option value="/opt/gradle/lib/plugins/gradle-composite-builds-4.10.2.jar" /> | |
| 423 | <option value="/opt/gradle/lib/plugins/gradle-language-scala-4.10.2.jar" /> | |
| 424 | <option value="/opt/gradle/lib/plugins/gradle-signing-4.10.2.jar" /> | |
| 425 | <option value="/opt/gradle/lib/plugins/gradle-plugin-use-4.10.2.jar" /> | |
| 426 | <option value="/opt/gradle/lib/plugins/ivy-2.2.0.jar" /> | |
| 427 | <option value="/opt/gradle/lib/plugins/gradle-code-quality-4.10.2.jar" /> | |
| 428 | <option value="/opt/gradle/lib/plugins/gradle-publish-4.10.2.jar" /> | |
| 429 | <option value="/opt/gradle/lib/plugins/gradle-platform-base-4.10.2.jar" /> | |
| 430 | <option value="/opt/gradle/lib/plugins/gradle-ivy-4.10.2.jar" /> | |
| 431 | <option value="/opt/gradle/lib/plugins/gradle-testing-native-4.10.2.jar" /> | |
| 432 | <option value="/opt/gradle/lib/plugins/gradle-language-java-4.10.2.jar" /> | |
| 433 | <option value="/opt/gradle/lib/plugins/gradle-ide-native-4.10.2.jar" /> | |
| 434 | <option value="/opt/gradle/lib/plugins/gradle-plugin-development-4.10.2.jar" /> | |
| 435 | <option value="/opt/gradle/lib/plugins/gradle-language-native-4.10.2.jar" /> | |
| 436 | <option value="/opt/gradle/lib/plugins/gradle-ear-4.10.2.jar" /> | |
| 437 | <option value="/opt/gradle/lib/plugins/gradle-resources-sftp-4.10.2.jar" /> | |
| 438 | <option value="/opt/gradle/lib/plugins/gradle-scala-4.10.2.jar" /> | |
| 439 | <option value="/opt/gradle/lib/plugins/gradle-testing-jvm-4.10.2.jar" /> | |
| 440 | <option value="/opt/gradle/lib/plugins/gradle-jacoco-4.10.2.jar" /> | |
| 441 | <option value="/opt/gradle/lib/plugins/gradle-antlr-4.10.2.jar" /> | |
| 442 | <option value="/opt/gradle/lib/plugins/gradle-dependency-management-4.10.2.jar" /> | |
| 443 | <option value="/opt/gradle/lib/plugins/gradle-tooling-native-4.10.2.jar" /> | |
| 444 | <option value="/opt/gradle/lib/plugins/gradle-tooling-api-builders-4.10.2.jar" /> | |
| 445 | <option value="/opt/gradle/lib/plugins/gradle-reporting-4.10.2.jar" /> | |
| 446 | <option value="/opt/gradle/lib/plugins/gradle-workers-4.10.2.jar" /> | |
| 447 | <option value="/opt/gradle/lib/plugins/gradle-resources-http-4.10.2.jar" /> | |
| 448 | <option value="/opt/gradle/lib/plugins/gradle-platform-native-4.10.2.jar" /> | |
| 449 | <option value="/opt/gradle/lib/plugins/gradle-resources-gcs-4.10.2.jar" /> | |
| 450 | <option value="/opt/gradle/lib/plugins/gradle-build-comparison-4.10.2.jar" /> | |
| 451 | <option value="/opt/gradle/lib/plugins/gradle-build-init-4.10.2.jar" /> | |
| 452 | <option value="/opt/gradle/lib/plugins/gradle-platform-jvm-4.10.2.jar" /> | |
| 453 | <option value="/opt/gradle/lib/plugins/gradle-testing-base-4.10.2.jar" /> | |
| 454 | <option value="/opt/gradle/lib/plugins/gradle-ide-4.10.2.jar" /> | |
| 455 | <option value="/opt/gradle/lib/plugins/gradle-ide-play-4.10.2.jar" /> | |
| 456 | <option value="/opt/gradle/lib/plugins/gradle-maven-4.10.2.jar" /> | |
| 457 | <option value="/opt/gradle/lib/plugins/gradle-build-cache-http-4.10.2.jar" /> | |
| 458 | <option value="/opt/gradle/lib/plugins/gradle-javascript-4.10.2.jar" /> | |
| 459 | <option value="/opt/gradle/lib/plugins/gradle-announce-4.10.2.jar" /> | |
| 460 | <option value="/opt/gradle/lib/plugins/gradle-language-groovy-4.10.2.jar" /> | |
| 461 | <option value="/opt/gradle/lib/plugins/gradle-platform-play-4.10.2.jar" /> | |
| 462 | <option value="/opt/gradle/lib/plugins/gradle-language-jvm-4.10.2.jar" /> | |
| 463 | </list> | |
| 464 | </option> | |
| 465 | </ExternalProjectBuildClasspathPojo> | |
| 466 | </value> | |
| 467 | </entry> | |
| 468 | </map> | |
| 469 | </option> | |
| 470 | <option name="projectSyncType"> | |
| 471 | <map> | |
| 472 | <entry key="$PROJECT_DIR$" value="RE_IMPORT" /> | |
| 473 | </map> | |
| 474 | </option> | |
| 475 | </component> | |
| 476 | <component name="IdeDocumentHistory"> | |
| 477 | <option name="CHANGED_PATHS"> | |
| 478 | <list> | |
| 479 | <option value="$PROJECT_DIR$/src/main/java/com/scrivenvar/AbstractFileFactory.java" /> | |
| 480 | <option value="$PROJECT_DIR$/src/main/java/com/scrivenvar/AbstractPane.java" /> | |
| 481 | <option value="$PROJECT_DIR$/src/main/java/com/scrivenvar/service/Options.java" /> | |
| 482 | <option value="$PROJECT_DIR$/src/main/java/com/scrivenvar/Constants.java" /> | |
| 483 | <option value="$PROJECT_DIR$/src/main/java/com/scrivenvar/FileEditorTabPane.java" /> | |
| 484 | <option value="$PROJECT_DIR$/src/main/java/com/scrivenvar/FileType.java" /> | |
| 485 | <option value="$PROJECT_DIR$/src/main/java/com/scrivenvar/Main.java" /> | |
| 486 | <option value="$PROJECT_DIR$/src/main/java/com/scrivenvar/processors/IdentityProcessor.java" /> | |
| 487 | <option value="$PROJECT_DIR$/src/main/java/com/scrivenvar/processors/InlineRProcessor.java" /> | |
| 488 | </list> | |
| 489 | </option> | |
| 490 | </component> | |
| 491 | <component name="ProjectFrameBounds"> | |
| 492 | <option name="x" value="238" /> | |
| 493 | <option name="y" value="312" /> | |
| 494 | <option name="width" value="1685" /> | |
| 495 | <option name="height" value="1141" /> | |
| 496 | </component> | |
| 497 | <component name="ProjectLevelVcsManager" settingsEditedManually="true" /> | |
| 498 | <component name="ProjectView"> | |
| 499 | <navigator proportions="" version="1"> | |
| 500 | <foldersAlwaysOnTop value="true" /> | |
| 501 | </navigator> | |
| 502 | <panes> | |
| 503 | <pane id="PackagesPane" /> | |
| 504 | <pane id="Scope" /> | |
| 505 | <pane id="ProjectPane"> | |
| 506 | <subPane> | |
| 507 | <expand> | |
| 508 | <path> | |
| 509 | <item name="scrivenvar" type="b2602c69:ProjectViewProjectNode" /> | |
| 510 | <item name="scrivenvar" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" /> | |
| 511 | </path> | |
| 512 | <path> | |
| 513 | <item name="scrivenvar" type="b2602c69:ProjectViewProjectNode" /> | |
| 514 | <item name="scrivenvar" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" /> | |
| 515 | <item name="src" type="462c0819:PsiDirectoryNode" /> | |
| 516 | </path> | |
| 517 | <path> | |
| 518 | <item name="scrivenvar" type="b2602c69:ProjectViewProjectNode" /> | |
| 519 | <item name="scrivenvar" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" /> | |
| 520 | <item name="src" type="462c0819:PsiDirectoryNode" /> | |
| 521 | <item name="main" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" /> | |
| 522 | </path> | |
| 523 | <path> | |
| 524 | <item name="scrivenvar" type="b2602c69:ProjectViewProjectNode" /> | |
| 525 | <item name="scrivenvar" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" /> | |
| 526 | <item name="src" type="462c0819:PsiDirectoryNode" /> | |
| 527 | <item name="main" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" /> | |
| 528 | <item name="java" type="462c0819:PsiDirectoryNode" /> | |
| 529 | </path> | |
| 530 | <path> | |
| 531 | <item name="scrivenvar" type="b2602c69:ProjectViewProjectNode" /> | |
| 532 | <item name="scrivenvar" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" /> | |
| 533 | <item name="src" type="462c0819:PsiDirectoryNode" /> | |
| 534 | <item name="main" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" /> | |
| 535 | <item name="java" type="462c0819:PsiDirectoryNode" /> | |
| 536 | <item name="scrivenvar" type="462c0819:PsiDirectoryNode" /> | |
| 537 | </path> | |
| 538 | <path> | |
| 539 | <item name="scrivenvar" type="b2602c69:ProjectViewProjectNode" /> | |
| 540 | <item name="scrivenvar" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" /> | |
| 541 | <item name="src" type="462c0819:PsiDirectoryNode" /> | |
| 542 | <item name="main" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" /> | |
| 543 | <item name="java" type="462c0819:PsiDirectoryNode" /> | |
| 544 | <item name="scrivenvar" type="462c0819:PsiDirectoryNode" /> | |
| 545 | <item name="processors" type="462c0819:PsiDirectoryNode" /> | |
| 546 | </path> | |
| 547 | </expand> | |
| 548 | <select /> | |
| 549 | </subPane> | |
| 550 | </pane> | |
| 551 | </panes> | |
| 552 | </component> | |
| 553 | <component name="PropertiesComponent"> | |
| 554 | <property name="com.android.tools.idea.instantapp.provision.ProvisionBeforeRunTaskProvider.myTimeStamp" value="1541653415064" /> | |
| 555 | <property name="settings.editor.selected.configurable" value="preferences.sourceCode.Java" /> | |
| 556 | </component> | |
| 557 | <component name="RunDashboard"> | |
| 558 | <option name="ruleStates"> | |
| 559 | <list> | |
| 560 | <RuleState> | |
| 561 | <option name="name" value="ConfigurationTypeDashboardGroupingRule" /> | |
| 562 | </RuleState> | |
| 563 | <RuleState> | |
| 564 | <option name="name" value="StatusDashboardGroupingRule" /> | |
| 565 | </RuleState> | |
| 566 | </list> | |
| 567 | </option> | |
| 568 | </component> | |
| 569 | <component name="RunManager"> | |
| 570 | <configuration name="Scrivenvar" type="GradleRunConfiguration" factoryName="Gradle"> | |
| 571 | <ExternalSystemSettings> | |
| 572 | <option name="executionName" /> | |
| 573 | <option name="externalProjectPath" value="$PROJECT_DIR$" /> | |
| 574 | <option name="externalSystemIdString" value="GRADLE" /> | |
| 575 | <option name="scriptParameters" value="" /> | |
| 576 | <option name="taskDescriptions"> | |
| 577 | <list /> | |
| 578 | </option> | |
| 579 | <option name="taskNames"> | |
| 580 | <list> | |
| 581 | <option value="run" /> | |
| 582 | </list> | |
| 583 | </option> | |
| 584 | <option name="vmOptions" value="" /> | |
| 585 | </ExternalSystemSettings> | |
| 586 | <method v="2" /> | |
| 587 | </configuration> | |
| 588 | <configuration default="true" type="GradleRunConfiguration" factoryName="Gradle"> | |
| 589 | <ExternalSystemSettings> | |
| 590 | <option name="executionName" /> | |
| 591 | <option name="externalProjectPath" value="" /> | |
| 592 | <option name="externalSystemIdString" value="GRADLE" /> | |
| 593 | <option name="scriptParameters" value="" /> | |
| 594 | <option name="taskDescriptions"> | |
| 595 | <list /> | |
| 596 | </option> | |
| 597 | <option name="taskNames"> | |
| 598 | <list /> | |
| 599 | </option> | |
| 600 | <option name="vmOptions" value="" /> | |
| 601 | </ExternalSystemSettings> | |
| 602 | <method v="2" /> | |
| 603 | </configuration> | |
| 604 | </component> | |
| 605 | <component name="SvnConfiguration"> | |
| 606 | <configuration /> | |
| 607 | </component> | |
| 608 | <component name="TaskManager"> | |
| 609 | <task active="true" id="Default" summary="Default task"> | |
| 610 | <changelist id="3dcf7c8f-87b5-4d25-a804-39da40a621b8" name="Default Changelist" comment="" /> | |
| 611 | <created>1541651873782</created> | |
| 612 | <option name="number" value="Default" /> | |
| 613 | <option name="presentableId" value="Default" /> | |
| 614 | <updated>1541651873782</updated> | |
| 615 | </task> | |
| 616 | <servers /> | |
| 617 | </component> | |
| 618 | <component name="ToolWindowManager"> | |
| 619 | <frame x="238" y="312" width="1685" height="1141" extended-state="0" /> | |
| 620 | <editor active="true" /> | |
| 621 | <layout> | |
| 622 | <window_info id="Image Layers" /> | |
| 623 | <window_info id="Designer" /> | |
| 624 | <window_info id="UI Designer" /> | |
| 625 | <window_info id="Capture Tool" /> | |
| 626 | <window_info id="Favorites" side_tool="true" /> | |
| 627 | <window_info active="true" content_ui="combo" id="Project" order="0" visible="true" weight="0.20626152" /> | |
| 628 | <window_info id="Structure" order="1" side_tool="true" weight="0.25" /> | |
| 629 | <window_info anchor="bottom" id="Version Control" show_stripe_button="false" /> | |
| 630 | <window_info anchor="bottom" id="Terminal" /> | |
| 631 | <window_info anchor="bottom" id="Event Log" side_tool="true" /> | |
| 632 | <window_info anchor="bottom" id="Build" weight="0.2127451" /> | |
| 633 | <window_info anchor="bottom" id="Message" order="0" /> | |
| 634 | <window_info anchor="bottom" id="Find" order="1" /> | |
| 635 | <window_info anchor="bottom" id="Run" order="2" visible="true" weight="0.32941177" /> | |
| 636 | <window_info anchor="bottom" id="Debug" order="3" weight="0.4" /> | |
| 637 | <window_info anchor="bottom" id="Cvs" order="4" weight="0.25" /> | |
| 638 | <window_info anchor="bottom" id="Inspection" order="5" weight="0.4" /> | |
| 639 | <window_info anchor="bottom" id="TODO" order="6" /> | |
| 640 | <window_info anchor="right" id="Palette" /> | |
| 641 | <window_info anchor="right" id="Gradle" /> | |
| 642 | <window_info anchor="right" id="Theme Preview" /> | |
| 643 | <window_info anchor="right" id="Capture Analysis" /> | |
| 644 | <window_info anchor="right" id="Palette	" /> | |
| 645 | <window_info anchor="right" id="Maven Projects" /> | |
| 646 | <window_info anchor="right" id="Commander" internal_type="SLIDING" order="0" type="SLIDING" weight="0.4" /> | |
| 647 | <window_info anchor="right" id="Ant Build" order="1" weight="0.25" /> | |
| 648 | <window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" /> | |
| 649 | </layout> | |
| 650 | </component> | |
| 651 | <component name="VcsContentAnnotationSettings"> | |
| 652 | <option name="myLimit" value="2678400000" /> | |
| 653 | </component> | |
| 654 | <component name="editorHistoryManager"> | |
| 655 | <entry file="file://$PROJECT_DIR$/src/main/java/com/scrivenvar/AbstractFileFactory.java"> | |
| 656 | <provider selected="true" editor-type-id="text-editor"> | |
| 657 | <state relative-caret-position="350"> | |
| 658 | <caret line="101" column="6" lean-forward="true" selection-start-line="101" selection-start-column="6" selection-end-line="101" selection-end-column="6" /> | |
| 659 | </state> | |
| 660 | </provider> | |
| 661 | </entry> | |
| 662 | <entry file="jar:///opt/jdk/src.zip!/java/util/prefs/Preferences.java"> | |
| 663 | <provider selected="true" editor-type-id="text-editor"> | |
| 664 | <state relative-caret-position="2775"> | |
| 665 | <caret line="223" column="22" selection-start-line="223" selection-start-column="22" selection-end-line="223" selection-end-column="22" /> | |
| 666 | </state> | |
| 667 | </provider> | |
| 668 | </entry> | |
| 669 | <entry file="file://$PROJECT_DIR$/src/main/java/com/scrivenvar/AbstractPane.java"> | |
| 670 | <provider selected="true" editor-type-id="text-editor"> | |
| 671 | <state> | |
| 672 | <folding> | |
| 673 | <element signature="e#1865#1866#0" expanded="true" /> | |
| 674 | <element signature="e#1894#1895#0" expanded="true" /> | |
| 675 | <element signature="e#2106#2107#0" expanded="true" /> | |
| 676 | <element signature="e#2146#2147#0" expanded="true" /> | |
| 677 | </folding> | |
| 678 | </state> | |
| 679 | </provider> | |
| 680 | </entry> | |
| 681 | <entry file="file://$PROJECT_DIR$/src/main/java/com/scrivenvar/service/Options.java"> | |
| 682 | <provider selected="true" editor-type-id="text-editor"> | |
| 683 | <state relative-caret-position="90"> | |
| 684 | <caret line="33" selection-start-line="33" selection-end-line="33" /> | |
| 685 | </state> | |
| 686 | </provider> | |
| 687 | </entry> | |
| 688 | <entry file="file://$PROJECT_DIR$/src/main/java/com/scrivenvar/FileType.java"> | |
| 689 | <provider selected="true" editor-type-id="text-editor"> | |
| 690 | <state relative-caret-position="558"> | |
| 691 | <caret line="95" column="33" selection-start-line="95" selection-start-column="33" selection-end-line="95" selection-end-column="33" /> | |
| 692 | <folding> | |
| 693 | <element signature="e#1987#1988#0" expanded="true" /> | |
| 694 | <element signature="e#2013#2014#0" expanded="true" /> | |
| 695 | </folding> | |
| 696 | </state> | |
| 697 | </provider> | |
| 698 | </entry> | |
| 699 | <entry file="file://$PROJECT_DIR$/src/main/java/com/scrivenvar/FileEditorTabPane.java"> | |
| 700 | <provider selected="true" editor-type-id="text-editor"> | |
| 701 | <state relative-caret-position="483"> | |
| 702 | <caret line="637" column="3" lean-forward="true" selection-start-line="637" selection-start-column="3" selection-end-line="637" selection-end-column="3" /> | |
| 703 | </state> | |
| 704 | </provider> | |
| 705 | </entry> | |
| 706 | <entry file="file://$PROJECT_DIR$/src/main/java/com/scrivenvar/Constants.java"> | |
| 707 | <provider selected="true" editor-type-id="text-editor"> | |
| 708 | <state relative-caret-position="240"> | |
| 709 | <caret line="44" column="5" lean-forward="true" selection-start-line="44" selection-start-column="5" selection-end-line="44" selection-end-column="5" /> | |
| 710 | </state> | |
| 711 | </provider> | |
| 712 | </entry> | |
| 713 | <entry file="file://$PROJECT_DIR$/src/main/java/com/scrivenvar/MainWindow.java"> | |
| 714 | <provider selected="true" editor-type-id="text-editor"> | |
| 715 | <state relative-caret-position="150"> | |
| 716 | <caret line="98" column="13" selection-start-line="98" selection-start-column="13" selection-end-line="98" selection-end-column="13" /> | |
| 717 | </state> | |
| 718 | </provider> | |
| 719 | </entry> | |
| 720 | <entry file="file://$PROJECT_DIR$/src/main/java/com/scrivenvar/Main.java"> | |
| 721 | <provider selected="true" editor-type-id="text-editor"> | |
| 722 | <state relative-caret-position="195"> | |
| 723 | <caret line="50" column="26" lean-forward="true" selection-start-line="50" selection-start-column="26" selection-end-line="50" selection-end-column="26" /> | |
| 724 | </state> | |
| 725 | </provider> | |
| 726 | </entry> | |
| 727 | <entry file="file://$PROJECT_DIR$/src/main/java/com/scrivenvar/processors/AbstractProcessor.java"> | |
| 728 | <provider selected="true" editor-type-id="text-editor"> | |
| 729 | <state relative-caret-position="180"> | |
| 730 | <caret line="38" column="22" selection-start-line="38" selection-start-column="22" selection-end-line="38" selection-end-column="22" /> | |
| 731 | </state> | |
| 732 | </provider> | |
| 733 | </entry> | |
| 734 | <entry file="file://$PROJECT_DIR$/src/main/java/com/scrivenvar/processors/CaretInsertionProcessor.java"> | |
| 735 | <provider selected="true" editor-type-id="text-editor"> | |
| 736 | <state relative-caret-position="-135"> | |
| 737 | <caret line="41" column="22" selection-start-line="41" selection-start-column="22" selection-end-line="41" selection-end-column="22" /> | |
| 738 | </state> | |
| 739 | </provider> | |
| 740 | </entry> | |
| 741 | <entry file="file://$PROJECT_DIR$/src/main/java/com/scrivenvar/processors/CaretReplacementProcessor.java"> | |
| 742 | <provider selected="true" editor-type-id="text-editor"> | |
| 743 | <state relative-caret-position="165"> | |
| 744 | <caret line="38" column="13" selection-start-line="38" selection-start-column="13" selection-end-line="38" selection-end-column="13" /> | |
| 745 | </state> | |
| 746 | </provider> | |
| 747 | </entry> | |
| 748 | <entry file="file://$PROJECT_DIR$/src/main/java/com/scrivenvar/processors/DefaultVariableProcessor.java"> | |
| 749 | <provider selected="true" editor-type-id="text-editor"> | |
| 750 | <state relative-caret-position="-101"> | |
| 751 | <caret line="38" column="13" selection-start-line="38" selection-start-column="13" selection-end-line="38" selection-end-column="13" /> | |
| 752 | </state> | |
| 753 | </provider> | |
| 754 | </entry> | |
| 755 | <entry file="file://$PROJECT_DIR$/src/main/java/com/scrivenvar/processors/MarkdownCaretInsertionProcessor.java"> | |
| 756 | <provider selected="true" editor-type-id="text-editor"> | |
| 757 | <state relative-caret-position="150"> | |
| 758 | <caret line="38" column="13" selection-start-line="38" selection-start-column="13" selection-end-line="38" selection-end-column="13" /> | |
| 759 | </state> | |
| 760 | </provider> | |
| 761 | </entry> | |
| 762 | <entry file="file://$PROJECT_DIR$/src/main/java/com/scrivenvar/processors/IdentityProcessor.java"> | |
| 763 | <provider selected="true" editor-type-id="text-editor"> | |
| 764 | <state relative-caret-position="210"> | |
| 765 | <caret line="40" column="76" lean-forward="true" selection-start-line="40" selection-start-column="76" selection-end-line="40" selection-end-column="76" /> | |
| 766 | </state> | |
| 767 | </provider> | |
| 768 | </entry> | |
| 769 | <entry file="file://$PROJECT_DIR$/src/main/java/com/scrivenvar/processors/HTMLPreviewProcessor.java"> | |
| 770 | <provider selected="true" editor-type-id="text-editor"> | |
| 771 | <state relative-caret-position="439"> | |
| 772 | <caret line="71" lean-forward="true" selection-start-line="71" selection-end-line="71" /> | |
| 773 | </state> | |
| 774 | </provider> | |
| 775 | </entry> | |
| 776 | <entry file="file://$PROJECT_DIR$/src/main/java/com/scrivenvar/processors/InlineRProcessor.java"> | |
| 777 | <provider selected="true" editor-type-id="text-editor"> | |
| 778 | <state relative-caret-position="300"> | |
| 779 | <caret line="104" selection-start-line="104" selection-end-line="104" /> | |
| 780 | </state> | |
| 781 | </provider> | |
| 782 | </entry> | |
| 783 | </component> | |
| 784 | <component name="masterDetails"> | |
| 785 | <states> | |
| 786 | <state key="ProjectJDKs.UI"> | |
| 787 | <settings> | |
| 788 | <last-edited>JDK1.8</last-edited> | |
| 789 | <splitter-proportions> | |
| 790 | <option name="proportions"> | |
| 791 | <list> | |
| 792 | <option value="0.2" /> | |
| 793 | </list> | |
| 794 | </option> | |
| 795 | </splitter-proportions> | |
| 796 | </settings> | |
| 797 | </state> | |
| 798 | </states> | |
| 799 | </component> | |
| 800 | </project> |
| 1 | Build | |
| 2 | === | |
| 3 | ||
| 4 | Once the [requirements](README.md) are met, build the application as follows: | |
| 5 | ||
| 6 | gradle build | |
| 7 | ||
| 1 | 8 |
| 1 | Copyright 2017 White Magic Software, Ltd. | |
| 2 | All rights reserved. | |
| 3 | ||
| 4 | Redistribution and use in source and binary forms, with or without | |
| 5 | modification, are permitted provided that the following conditions are met: | |
| 6 | ||
| 7 | * Redistributions of source code must retain the above copyright | |
| 8 | notice, this list of conditions and the following disclaimer. | |
| 9 | ||
| 10 | * Redistributions in binary form must reproduce the above copyright | |
| 11 | notice, this list of conditions and the following disclaimer in the | |
| 12 | documentation and/or other materials provided with the distribution. | |
| 13 | ||
| 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 15 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 16 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 17 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 18 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 20 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 21 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 22 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 25 | 1 |
| 1 | # License | |
| 2 | ||
| 3 | Copyright 2018 White Magic Software, Ltd. | |
| 4 | All rights reserved. | |
| 5 | ||
| 6 | Redistribution and use in source and binary forms, with or without | |
| 7 | modification, are permitted provided that the following conditions are met: | |
| 8 | ||
| 9 | * Redistributions of source code must retain the above copyright | |
| 10 | notice, this list of conditions and the following disclaimer. | |
| 11 | ||
| 12 | * Redistributions in binary form must reproduce the above copyright | |
| 13 | notice, this list of conditions and the following disclaimer in the | |
| 14 | documentation and/or other materials provided with the distribution. | |
| 15 | ||
| 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 17 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 18 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 19 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 20 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 21 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 22 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 24 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 26 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 1 | 27 |
| 40 | 40 | if( n != 1 ) { |
| 41 | 41 | if( pl.noninflective( s ) || |
| 42 | pl.suffix( "es", s ) || | |
| 42 | pl.suffix( "es", s ) || | |
| 43 | 43 | pl.suffix( "fish", s ) || |
| 44 | 44 | pl.suffix( "ois", s ) || |
| ... | ||
| 134 | 134 | pl.noninflective <- function( s ) { |
| 135 | 135 | v <- c( |
| 136 | "aircraft", | |
| 137 | "Bhutanese", | |
| 138 | "bison", | |
| 139 | "bream", | |
| 140 | "Burmese", | |
| 141 | "carp", | |
| 142 | "chassis", | |
| 143 | "Chinese", | |
| 144 | "clippers", | |
| 145 | "cod", | |
| 146 | "contretemps", | |
| 147 | "corps", | |
| 148 | "debris", | |
| 149 | "djinn", | |
| 150 | "eland", | |
| 151 | "elk", | |
| 152 | "flounder", | |
| 153 | "fracas", | |
| 154 | "gallows", | |
| 155 | "graffiti", | |
| 156 | "headquarters", | |
| 157 | "high-jinks", | |
| 158 | "homework", | |
| 159 | "hovercraft", | |
| 160 | "innings", | |
| 161 | "Japanese", | |
| 162 | "Lebanese", | |
| 163 | "mackerel", | |
| 164 | "means", | |
| 165 | "mews", | |
| 166 | "mice", | |
| 167 | "mumps", | |
| 168 | "news", | |
| 169 | "pincers", | |
| 170 | "pliers", | |
| 171 | "Portuguese", | |
| 172 | "proceedings", | |
| 173 | "salmon", | |
| 174 | "scissors", | |
| 175 | "sea-bass", | |
| 176 | "Senegalese", | |
| 177 | "shears", | |
| 178 | "Siamese", | |
| 179 | "Sinhalese", | |
| 180 | "spacecraft", | |
| 181 | "swine", | |
| 182 | "trout", | |
| 183 | "tuna", | |
| 184 | "Vietnamese", | |
| 185 | "watercraft", | |
| 186 | "whiting", | |
| 187 | "wildebeest" | |
| 136 | "aircraft", | |
| 137 | "Bhutanese", | |
| 138 | "bison", | |
| 139 | "bream", | |
| 140 | "Burmese", | |
| 141 | "carp", | |
| 142 | "chassis", | |
| 143 | "Chinese", | |
| 144 | "clippers", | |
| 145 | "cod", | |
| 146 | "contretemps", | |
| 147 | "corps", | |
| 148 | "debris", | |
| 149 | "djinn", | |
| 150 | "eland", | |
| 151 | "elk", | |
| 152 | "flounder", | |
| 153 | "fracas", | |
| 154 | "gallows", | |
| 155 | "graffiti", | |
| 156 | "headquarters", | |
| 157 | "high-jinks", | |
| 158 | "homework", | |
| 159 | "hovercraft", | |
| 160 | "innings", | |
| 161 | "Japanese", | |
| 162 | "Lebanese", | |
| 163 | "mackerel", | |
| 164 | "means", | |
| 165 | "mews", | |
| 166 | "mice", | |
| 167 | "mumps", | |
| 168 | "news", | |
| 169 | "pincers", | |
| 170 | "pliers", | |
| 171 | "Portuguese", | |
| 172 | "proceedings", | |
| 173 | "salmon", | |
| 174 | "scissors", | |
| 175 | "sea-bass", | |
| 176 | "Senegalese", | |
| 177 | "shears", | |
| 178 | "Siamese", | |
| 179 | "Sinhalese", | |
| 180 | "spacecraft", | |
| 181 | "swine", | |
| 182 | "trout", | |
| 183 | "tuna", | |
| 184 | "Vietnamese", | |
| 185 | "watercraft", | |
| 186 | "whiting", | |
| 187 | "wildebeest" | |
| 188 | 188 | ) |
| 189 | 189 | |
| 8 | 8 | Requirements |
| 9 | 9 | --- |
| 10 | [Java 8u40 or greater](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html). | |
| 10 | Download and install the following software packages: | |
| 11 | ||
| 12 | * [Java 8u40](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) (or newer) | |
| 13 | * [Gradle 4.4.1](https://gradle.org/) | |
| 11 | 14 | |
| 12 | 15 | Quick Start |
| ... | ||
| 39 | 42 | License |
| 40 | 43 | --- |
| 41 | This software is licensed under the [BSD 2-Clause License](LICENSE). | |
| 44 | This software is licensed under the [BSD 2-Clause License](LICENSE.md). | |
| 42 | 45 | |
| 5 | 5 | repositories { |
| 6 | 6 | jcenter() |
| 7 | mavenCentral() | |
| 7 | 8 | |
| 8 | 9 | maven { |
| ... | ||
| 20 | 21 | compile 'org.fxmisc.richtext:richtextfx:0.8.1' |
| 21 | 22 | compile 'com.miglayout:miglayout-javafx:5.0' |
| 22 | compile 'de.jensd:fontawesomefx-fontawesome:4.5.0' | |
| 23 | 23 | compile 'org.ahocorasick:ahocorasick:0.4.0' |
| 24 | compile 'com.vladsch.flexmark:flexmark:0.28.24' | |
| 25 | compile 'com.vladsch.flexmark:flexmark-ext-tables:0.28.24' | |
| 26 | compile 'com.vladsch.flexmark:flexmark-ext-superscript:0.28.24' | |
| 27 | compile 'com.vladsch.flexmark:flexmark-ext-gfm-strikethrough:0.28.24' | |
| 24 | compile 'com.vladsch.flexmark:flexmark:0.28.34' | |
| 25 | compile 'com.vladsch.flexmark:flexmark-ext-tables:0.28.34' | |
| 26 | compile 'com.vladsch.flexmark:flexmark-ext-superscript:0.28.34' | |
| 27 | compile 'com.vladsch.flexmark:flexmark-ext-gfm-strikethrough:0.28.34' | |
| 28 | 28 | compile 'com.fasterxml.jackson.core:jackson-core:2.9.3' |
| 29 | 29 | compile 'com.fasterxml.jackson.core:jackson-databind:2.9.3' |
| 30 | 30 | compile 'com.fasterxml.jackson.core:jackson-annotations:2.9.3' |
| 31 | 31 | compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.9.3' |
| 32 | 32 | compile 'org.yaml:snakeyaml:1.19' |
| 33 | 33 | compile 'com.ximpleware:vtd-xml:2.13.4' |
| 34 | 34 | compile 'net.sf.saxon:Saxon-HE:9.8.0-7' |
| 35 | 35 | compile 'com.googlecode.juniversalchardet:juniversalchardet:1.0.3' |
| 36 | 36 | compile 'org.apache.commons:commons-configuration2:2.2' |
| 37 | compile files('libs/renjin-script-engine-0.8.2562-jar-with-dependencies.jar') | |
| 37 | compile files('libs/fontawesomefx-commons-8.12.jar') | |
| 38 | compile files('libs/fontawesomefx-fontawesome-4.5.0.jar') | |
| 39 | compile files('libs/renjin-script-engine-0.9.2726-jar-with-dependencies.jar') | |
| 38 | 40 | } |
| 39 | 41 | |
| 40 | version = '1.3.4' | |
| 42 | version = '1.3.8' | |
| 41 | 43 | applicationName = 'scrivenvar' |
| 42 | 44 | mainClassName = 'com.scrivenvar.Main' |
| ... | ||
| 68 | 70 | baseName = applicationName |
| 69 | 71 | contents { |
| 70 | from { ['LICENSE', 'README.md'] } | |
| 72 | from { ['LICENSE.md', 'README.md'] } | |
| 71 | 73 | into( 'images' ) { |
| 72 | 74 | from { 'images' } |
| 1 | 1 | |
| 2 | https://github.com/bmuschko/gradle-izpack-plugin | |
| 3 | http://izpack.org/ | |
| 4 | ||
| 5 | https://github.com/TheBoegl/gradle-launch4j | |
| 6 | http://launch4j.sourceforge.net/ | |
| 7 | ||
| 8 | https://github.com/FibreFoX/javafx-gradle-plugin | |
| 9 | https://docs.oracle.com/javase/8/docs/technotes/guides/deploy/self-contained-packaging.html#A1324980 | |
| 10 | ||
| 11 | http://www.jwrapper.com/java-to-exe-free.html | |
| 12 | ||
| 13 | https://github.com/libgdx/packr | |
| 14 | ||
| 15 |
| 1 | org.gradle.jvmargs=-Xmx1G -XX:MaxPermSize=512m | |
| 2 | ||
| 1 | 3 |
| 1 | Copyright (c) 2015 Karl Tauber <karl at jformdesigner dot com> | |
| 2 | All rights reserved. | |
| 3 | ||
| 4 | Redistribution and use in source and binary forms, with or without | |
| 5 | modification, are permitted provided that the following conditions are met: | |
| 6 | ||
| 7 | * Redistributions of source code must retain the above copyright | |
| 8 | notice, this list of conditions and the following disclaimer. | |
| 9 | ||
| 10 | * Redistributions in binary form must reproduce the above copyright | |
| 11 | notice, this list of conditions and the following disclaimer in the | |
| 12 | documentation and/or other materials provided with the distribution. | |
| 13 | ||
| 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 15 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 16 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 17 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 18 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 20 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 21 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 22 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 25 | 1 |
| 1 | Copyright (c) 2015 Karl Tauber <karl@jformdesigner.com> | |
| 2 | All rights reserved. | |
| 3 | ||
| 4 | Redistribution and use in source and binary forms, with or without | |
| 5 | modification, are permitted provided that the following conditions are met: | |
| 6 | ||
| 7 | * Redistributions of source code must retain the above copyright | |
| 8 | notice, this list of conditions and the following disclaimer. | |
| 9 | ||
| 10 | * Redistributions in binary form must reproduce the above copyright | |
| 11 | notice, this list of conditions and the following disclaimer in the | |
| 12 | documentation and/or other materials provided with the distribution. | |
| 13 | ||
| 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 15 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 16 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 17 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 18 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 20 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 21 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 22 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 1 | 25 |
| 118 | 118 | * Return the singleton Settings instance. |
| 119 | 119 | * |
| 120 | * @return The settings for | |
| 120 | * @return A non-null instance. | |
| 121 | 121 | */ |
| 122 | 122 | private Settings getSettings() { |
| 29 | 29 | |
| 30 | 30 | import com.scrivenvar.service.Options; |
| 31 | ||
| 31 | 32 | import java.util.prefs.Preferences; |
| 33 | ||
| 32 | 34 | import org.tbee.javafx.scene.layout.fxml.MigPane; |
| 33 | 35 | |
| 34 | 36 | /** |
| 35 | 37 | * Provides options to all subclasses. |
| 36 | 38 | * |
| 37 | 39 | * @author White Magic Software, Ltd. |
| 38 | 40 | */ |
| 39 | 41 | public abstract class AbstractPane extends MigPane { |
| 40 | 42 | |
| 43 | /** | |
| 44 | * The options loaded from the service. | |
| 45 | */ | |
| 41 | 46 | private final Options options = Services.load( Options.class ); |
| 42 | 47 | |
| 48 | /** | |
| 49 | * Returns the persistent options for user settings. | |
| 50 | * | |
| 51 | * @return A non-null instance. | |
| 52 | */ | |
| 43 | 53 | protected Options getOptions() { |
| 44 | 54 | return this.options; |
| 45 | 55 | } |
| 46 | ||
| 56 | ||
| 57 | /** | |
| 58 | * Returns a hierarchical set of preferences. | |
| 59 | * | |
| 60 | * @return A non-null instance. | |
| 61 | */ | |
| 47 | 62 | protected Preferences getState() { |
| 48 | 63 | return getOptions().getState(); |
| 29 | 29 | |
| 30 | 30 | import com.scrivenvar.service.Settings; |
| 31 | ||
| 31 | 32 | import java.util.Collection; |
| 32 | 33 | |
| 33 | 34 | /** |
| 35 | * Defines application-wide default values. | |
| 36 | * | |
| 34 | 37 | * @author White Magic Software, Ltd. |
| 35 | 38 | */ |
| ... | ||
| 61 | 64 | public static final String APP_TITLE = get( "application.title" ); |
| 62 | 65 | public static final String APP_BUNDLE_NAME = get( "application.messages" ); |
| 66 | ||
| 63 | 67 | // Prevent double events when updating files on Linux (save and timestamp). |
| 64 | 68 | public static final int APP_WATCHDOG_TIMEOUT = get( "application.watchdog.timeout", 100 ); |
| ... | ||
| 97 | 101 | // Takes two parameters: line number and column number. |
| 98 | 102 | public static final String STATUS_BAR_LINE = "Main.statusbar.line"; |
| 103 | ||
| 99 | 104 | // "OK" text |
| 100 | 105 | public static final String STATUS_BAR_DEFAULT = get( "Main.statusbar.state.default" ); |
| 101 | 106 | public static final String STATUS_PARSE_ERROR = "Main.statusbar.parse.error"; |
| 102 | 107 | |
| 103 | // Persistent storage settings. | |
| 104 | ||
| 105 | 108 | /** |
| 106 | 109 | * Location of the definition source file. |
| 107 | 110 | */ |
| 108 | 111 | public static final String PERSIST_DEFINITION_SOURCE = "definitionSource"; |
| 109 | ||
| 110 | ||
| 112 | ||
| 111 | 113 | /** |
| 112 | 114 | * Content of the R startup script. |
| 68 | 68 | public final class FileEditorTab extends Tab { |
| 69 | 69 | |
| 70 | /** | |
| 71 | * | |
| 72 | */ | |
| 70 | 73 | private final Notifier alertService = Services.load( Notifier.class ); |
| 71 | 74 | private EditorPane editorPane; |
| 31 | 31 | import static com.scrivenvar.FileType.*; |
| 32 | 32 | import static com.scrivenvar.Messages.get; |
| 33 | import com.scrivenvar.predicates.files.FileTypePredicate; | |
| 34 | import com.scrivenvar.service.Options; | |
| 35 | import com.scrivenvar.service.Settings; | |
| 36 | import com.scrivenvar.service.events.Notification; | |
| 37 | import com.scrivenvar.service.events.Notifier; | |
| 38 | import static com.scrivenvar.service.events.Notifier.NO; | |
| 39 | import static com.scrivenvar.service.events.Notifier.YES; | |
| 40 | import com.scrivenvar.util.Utils; | |
| 41 | import java.io.File; | |
| 42 | import java.nio.file.Path; | |
| 43 | import java.util.ArrayList; | |
| 44 | import java.util.List; | |
| 45 | import java.util.function.Consumer; | |
| 46 | import java.util.prefs.Preferences; | |
| 47 | import java.util.stream.Collectors; | |
| 48 | import javafx.beans.property.ReadOnlyBooleanProperty; | |
| 49 | import javafx.beans.property.ReadOnlyBooleanWrapper; | |
| 50 | import javafx.beans.property.ReadOnlyObjectProperty; | |
| 51 | import javafx.beans.property.ReadOnlyObjectWrapper; | |
| 52 | import javafx.beans.value.ChangeListener; | |
| 53 | import javafx.beans.value.ObservableValue; | |
| 54 | import javafx.collections.ListChangeListener; | |
| 55 | import javafx.collections.ObservableList; | |
| 56 | import javafx.event.Event; | |
| 57 | import javafx.scene.Node; | |
| 58 | import javafx.scene.control.Alert; | |
| 59 | import javafx.scene.control.ButtonType; | |
| 60 | import javafx.scene.control.Tab; | |
| 61 | import javafx.scene.control.TabPane; | |
| 62 | import javafx.scene.control.TabPane.TabClosingPolicy; | |
| 63 | import javafx.scene.input.InputEvent; | |
| 64 | import javafx.stage.FileChooser; | |
| 65 | import javafx.stage.FileChooser.ExtensionFilter; | |
| 66 | import javafx.stage.Window; | |
| 67 | import org.fxmisc.richtext.StyledTextArea; | |
| 68 | import org.fxmisc.wellbehaved.event.EventPattern; | |
| 69 | import org.fxmisc.wellbehaved.event.InputMap; | |
| 70 | ||
| 71 | /** | |
| 72 | * Tab pane for file editors. | |
| 73 | * | |
| 74 | * @author Karl Tauber and White Magic Software, Ltd. | |
| 75 | */ | |
| 76 | public final class FileEditorTabPane extends TabPane { | |
| 77 | ||
| 78 | private final static String FILTER_EXTENSION_TITLES = "Dialog.file.choose.filter"; | |
| 79 | ||
| 80 | private final Options options = Services.load( Options.class ); | |
| 81 | private final Settings settings = Services.load( Settings.class ); | |
| 82 | private final Notifier notifyService = Services.load( Notifier.class ); | |
| 83 | ||
| 84 | private final ReadOnlyObjectWrapper<Path> openDefinition = new ReadOnlyObjectWrapper<>(); | |
| 85 | private final ReadOnlyObjectWrapper<FileEditorTab> activeFileEditor = new ReadOnlyObjectWrapper<>(); | |
| 86 | private final ReadOnlyBooleanWrapper anyFileEditorModified = new ReadOnlyBooleanWrapper(); | |
| 87 | ||
| 88 | /** | |
| 89 | * Constructs a new file editor tab pane. | |
| 90 | */ | |
| 91 | public FileEditorTabPane() { | |
| 92 | final ObservableList<Tab> tabs = getTabs(); | |
| 93 | ||
| 94 | setFocusTraversable( false ); | |
| 95 | setTabClosingPolicy( TabClosingPolicy.ALL_TABS ); | |
| 96 | ||
| 97 | addTabSelectionListener( | |
| 98 | (ObservableValue<? extends Tab> tabPane, | |
| 99 | final Tab oldTab, final Tab newTab) -> { | |
| 100 | ||
| 101 | if( newTab != null ) { | |
| 102 | activeFileEditor.set( (FileEditorTab)newTab ); | |
| 103 | } | |
| 104 | } | |
| 105 | ); | |
| 106 | ||
| 107 | final ChangeListener<Boolean> modifiedListener = (observable, oldValue, newValue) -> { | |
| 108 | for( final Tab tab : tabs ) { | |
| 109 | if( ((FileEditorTab)tab).isModified() ) { | |
| 110 | this.anyFileEditorModified.set( true ); | |
| 111 | break; | |
| 112 | } | |
| 113 | } | |
| 114 | }; | |
| 115 | ||
| 116 | tabs.addListener( | |
| 117 | (ListChangeListener<Tab>)change -> { | |
| 118 | while( change.next() ) { | |
| 119 | if( change.wasAdded() ) { | |
| 120 | change.getAddedSubList().stream().forEach( (tab) -> { | |
| 121 | ((FileEditorTab)tab).modifiedProperty().addListener( modifiedListener ); | |
| 122 | } ); | |
| 123 | } | |
| 124 | else if( change.wasRemoved() ) { | |
| 125 | change.getRemoved().stream().forEach( (tab) -> { | |
| 126 | ((FileEditorTab)tab).modifiedProperty().removeListener( modifiedListener ); | |
| 127 | } ); | |
| 128 | } | |
| 129 | } | |
| 130 | ||
| 131 | // Changes in the tabs may also change anyFileEditorModified property | |
| 132 | // (e.g. closed modified file) | |
| 133 | modifiedListener.changed( null, null, null ); | |
| 134 | } | |
| 135 | ); | |
| 136 | } | |
| 137 | ||
| 138 | /** | |
| 139 | * Delegates to the active file editor. | |
| 140 | * | |
| 141 | * @param <T> Event type. | |
| 142 | * @param <U> Consumer type. | |
| 143 | * @param event Event to pass to the editor. | |
| 144 | * @param consumer Consumer to pass to the editor. | |
| 145 | */ | |
| 146 | public <T extends Event, U extends T> void addEventListener( | |
| 147 | final EventPattern<? super T, ? extends U> event, | |
| 148 | final Consumer<? super U> consumer ) { | |
| 149 | getActiveFileEditor().addEventListener( event, consumer ); | |
| 150 | } | |
| 151 | ||
| 152 | /** | |
| 153 | * Delegates to the active file editor pane, and, ultimately, to its text | |
| 154 | * area. | |
| 155 | * | |
| 156 | * @param map The map of methods to events. | |
| 157 | */ | |
| 158 | public void addEventListener( final InputMap<InputEvent> map ) { | |
| 159 | getActiveFileEditor().addEventListener( map ); | |
| 160 | } | |
| 161 | ||
| 162 | /** | |
| 163 | * Remove a keyboard event listener from the active file editor. | |
| 164 | * | |
| 165 | * @param map The keyboard events to remove. | |
| 166 | */ | |
| 167 | public void removeEventListener( final InputMap<InputEvent> map ) { | |
| 168 | getActiveFileEditor().removeEventListener( map ); | |
| 169 | } | |
| 170 | ||
| 171 | /** | |
| 172 | * Allows observers to be notified when the current file editor tab changes. | |
| 173 | * | |
| 174 | * @param listener The listener to notify of tab change events. | |
| 175 | */ | |
| 176 | public void addTabSelectionListener( final ChangeListener<Tab> listener ) { | |
| 177 | // Observe the tab so that when a new tab is opened or selected, | |
| 178 | // a notification is kicked off. | |
| 179 | getSelectionModel().selectedItemProperty().addListener( listener ); | |
| 180 | } | |
| 181 | ||
| 182 | /** | |
| 183 | * Allows clients to manipulate the editor content directly. | |
| 184 | * | |
| 185 | * @return The text area for the active file editor. | |
| 186 | */ | |
| 187 | public StyledTextArea getEditor() { | |
| 188 | return getActiveFileEditor().getEditorPane().getEditor(); | |
| 189 | } | |
| 190 | ||
| 191 | public FileEditorTab getActiveFileEditor() { | |
| 192 | return this.activeFileEditor.get(); | |
| 193 | } | |
| 194 | ||
| 195 | public ReadOnlyObjectProperty<FileEditorTab> activeFileEditorProperty() { | |
| 196 | return this.activeFileEditor.getReadOnlyProperty(); | |
| 197 | } | |
| 198 | ||
| 199 | ReadOnlyBooleanProperty anyFileEditorModifiedProperty() { | |
| 200 | return this.anyFileEditorModified.getReadOnlyProperty(); | |
| 201 | } | |
| 202 | ||
| 203 | private FileEditorTab createFileEditor( final Path path ) { | |
| 204 | final FileEditorTab tab = new FileEditorTab( path ); | |
| 205 | ||
| 206 | tab.setOnCloseRequest( e -> { | |
| 207 | if( !canCloseEditor( tab ) ) { | |
| 208 | e.consume(); | |
| 209 | } | |
| 210 | } ); | |
| 211 | ||
| 212 | return tab; | |
| 213 | } | |
| 214 | ||
| 215 | /** | |
| 216 | * Called when the user selects New from the File menu. | |
| 217 | * | |
| 218 | * @return The newly added tab. | |
| 219 | */ | |
| 220 | void newEditor() { | |
| 221 | final FileEditorTab tab = createFileEditor( null ); | |
| 222 | ||
| 223 | getTabs().add( tab ); | |
| 224 | getSelectionModel().select( tab ); | |
| 225 | } | |
| 226 | ||
| 227 | void openFileDialog() { | |
| 228 | final String title = get( "Dialog.file.choose.open.title" ); | |
| 229 | final FileChooser dialog = createFileChooser( title ); | |
| 230 | final List<File> files = dialog.showOpenMultipleDialog( getWindow() ); | |
| 231 | ||
| 232 | if( files != null ) { | |
| 233 | openFiles( files ); | |
| 234 | } | |
| 235 | } | |
| 236 | ||
| 237 | /** | |
| 238 | * Opens the files into new editors, unless one of those files was a | |
| 239 | * definition file. The definition file is loaded into the definition pane, | |
| 240 | * but only the first one selected (multiple definition files will result in a | |
| 241 | * warning). | |
| 242 | * | |
| 243 | * @param files The list of non-definition files that the were requested to | |
| 244 | * open. | |
| 245 | * | |
| 246 | * @return A list of files that can be opened in text editors. | |
| 247 | */ | |
| 248 | private void openFiles( final List<File> files ) { | |
| 249 | final FileTypePredicate predicate | |
| 250 | = new FileTypePredicate( createExtensionFilter( DEFINITION ).getExtensions() ); | |
| 251 | ||
| 252 | // The user might have opened multiple definitions files. These will | |
| 253 | // be discarded from the text editable files. | |
| 254 | final List<File> definitions | |
| 255 | = files.stream().filter( predicate ).collect( Collectors.toList() ); | |
| 256 | ||
| 257 | // Create a modifiable list to remove any definition files that were | |
| 258 | // opened. | |
| 259 | final List<File> editors = new ArrayList<>( files ); | |
| 260 | ||
| 261 | if( editors.size() > 0 ) { | |
| 262 | saveLastDirectory( editors.get( 0 ) ); | |
| 263 | } | |
| 264 | ||
| 265 | editors.removeAll( definitions ); | |
| 266 | ||
| 267 | // Open editor-friendly files (e.g,. Markdown, XML) in new tabs. | |
| 268 | if( editors.size() > 0 ) { | |
| 269 | openEditors( editors, 0 ); | |
| 270 | } | |
| 271 | ||
| 272 | if( definitions.size() > 0 ) { | |
| 273 | openDefinition( definitions.get( 0 ) ); | |
| 274 | } | |
| 275 | } | |
| 276 | ||
| 277 | private void openEditors( final List<File> files, final int activeIndex ) { | |
| 278 | final int fileTally = files.size(); | |
| 279 | final List<Tab> tabs = getTabs(); | |
| 280 | ||
| 281 | // Close single unmodified "Untitled" tab. | |
| 282 | if( tabs.size() == 1 ) { | |
| 283 | final FileEditorTab fileEditor = (FileEditorTab)(tabs.get( 0 )); | |
| 284 | ||
| 285 | if( fileEditor.getPath() == null && !fileEditor.isModified() ) { | |
| 286 | closeEditor( fileEditor, false ); | |
| 287 | } | |
| 288 | } | |
| 289 | ||
| 290 | for( int i = 0; i < fileTally; i++ ) { | |
| 291 | final Path path = files.get( i ).toPath(); | |
| 292 | ||
| 293 | FileEditorTab fileEditorTab = findEditor( path ); | |
| 294 | ||
| 295 | // Only open new files. | |
| 296 | if( fileEditorTab == null ) { | |
| 297 | fileEditorTab = createFileEditor( path ); | |
| 298 | getTabs().add( fileEditorTab ); | |
| 299 | } | |
| 300 | ||
| 301 | // Select the first file in the list. | |
| 302 | if( i == activeIndex ) { | |
| 303 | getSelectionModel().select( fileEditorTab ); | |
| 304 | } | |
| 305 | } | |
| 306 | } | |
| 307 | ||
| 308 | /** | |
| 309 | * Returns a property that changes when a new definition file is opened. | |
| 310 | * | |
| 311 | * @return The path to a definition file that was opened. | |
| 312 | */ | |
| 313 | public ReadOnlyObjectProperty<Path> onOpenDefinitionFileProperty() { | |
| 314 | return getOnOpenDefinitionFile().getReadOnlyProperty(); | |
| 315 | } | |
| 316 | ||
| 317 | private ReadOnlyObjectWrapper<Path> getOnOpenDefinitionFile() { | |
| 318 | return this.openDefinition; | |
| 319 | } | |
| 320 | ||
| 321 | /** | |
| 322 | * Called when the user has opened a definition file (using the file open | |
| 323 | * dialog box). This will replace the current set of definitions for the | |
| 324 | * active tab. | |
| 325 | * | |
| 326 | * @param definition The file to open. | |
| 327 | */ | |
| 328 | private void openDefinition( final File definition ) { | |
| 329 | // TODO: Prevent reading this file twice when a new text document is opened. | |
| 330 | // (might be a matter of checking the value first). | |
| 331 | getOnOpenDefinitionFile().set( definition.toPath() ); | |
| 332 | } | |
| 333 | ||
| 334 | boolean saveEditor( final FileEditorTab tab ) { | |
| 335 | if( tab == null || !tab.isModified() ) { | |
| 336 | return true; | |
| 337 | } | |
| 338 | ||
| 339 | return tab.getPath() == null ? saveEditorAs( tab ) : tab.save(); | |
| 340 | } | |
| 341 | ||
| 342 | boolean saveEditorAs( final FileEditorTab tab ) { | |
| 343 | if( tab == null ) { | |
| 344 | return true; | |
| 345 | } | |
| 346 | ||
| 347 | getSelectionModel().select( tab ); | |
| 348 | ||
| 349 | final FileChooser fileChooser = createFileChooser( get( "Dialog.file.choose.save.title" ) ); | |
| 350 | final File file = fileChooser.showSaveDialog( getWindow() ); | |
| 351 | if( file == null ) { | |
| 352 | return false; | |
| 353 | } | |
| 354 | ||
| 355 | saveLastDirectory( file ); | |
| 356 | tab.setPath( file.toPath() ); | |
| 357 | ||
| 358 | return tab.save(); | |
| 359 | } | |
| 360 | ||
| 361 | boolean saveAllEditors() { | |
| 362 | boolean success = true; | |
| 363 | ||
| 364 | for( FileEditorTab fileEditor : getAllEditors() ) { | |
| 365 | if( !saveEditor( fileEditor ) ) { | |
| 366 | success = false; | |
| 367 | } | |
| 368 | } | |
| 369 | ||
| 370 | return success; | |
| 371 | } | |
| 372 | ||
| 373 | /** | |
| 374 | * Answers whether the file has had modifications. ' | |
| 375 | * | |
| 376 | * @param tab THe tab to check for modifications. | |
| 377 | * | |
| 378 | * @return false The file is unmodified. | |
| 379 | */ | |
| 380 | boolean canCloseEditor( final FileEditorTab tab ) { | |
| 381 | if( !tab.isModified() ) { | |
| 382 | return true; | |
| 383 | } | |
| 384 | ||
| 385 | final Notification message = getNotifyService().createNotification( | |
| 386 | Messages.get( "Alert.file.close.title" ), | |
| 387 | Messages.get( "Alert.file.close.text" ), | |
| 388 | tab.getText() | |
| 389 | ); | |
| 390 | ||
| 391 | final Alert alert = getNotifyService().createConfirmation( | |
| 392 | getWindow(), message ); | |
| 393 | final ButtonType response = alert.showAndWait().get(); | |
| 394 | ||
| 395 | return response == YES ? saveEditor( tab ) : response == NO; | |
| 396 | } | |
| 397 | ||
| 398 | private Notifier getNotifyService() { | |
| 399 | return this.notifyService; | |
| 400 | } | |
| 401 | ||
| 402 | boolean closeEditor( FileEditorTab fileEditor, boolean save ) { | |
| 403 | if( fileEditor == null ) { | |
| 404 | return true; | |
| 405 | } | |
| 406 | ||
| 407 | final Tab tab = fileEditor; | |
| 408 | ||
| 409 | if( save ) { | |
| 410 | Event event = new Event( tab, tab, Tab.TAB_CLOSE_REQUEST_EVENT ); | |
| 411 | Event.fireEvent( tab, event ); | |
| 412 | ||
| 413 | if( event.isConsumed() ) { | |
| 414 | return false; | |
| 415 | } | |
| 416 | } | |
| 417 | ||
| 418 | getTabs().remove( tab ); | |
| 419 | ||
| 420 | if( tab.getOnClosed() != null ) { | |
| 421 | Event.fireEvent( tab, new Event( Tab.CLOSED_EVENT ) ); | |
| 422 | } | |
| 423 | ||
| 424 | return true; | |
| 425 | } | |
| 426 | ||
| 427 | boolean closeAllEditors() { | |
| 428 | final FileEditorTab[] allEditors = getAllEditors(); | |
| 429 | final FileEditorTab activeEditor = getActiveFileEditor(); | |
| 430 | ||
| 431 | // try to save active tab first because in case the user decides to cancel, | |
| 432 | // then it stays active | |
| 433 | if( activeEditor != null && !canCloseEditor( activeEditor ) ) { | |
| 434 | return false; | |
| 435 | } | |
| 436 | ||
| 437 | // This should be called any time a tab changes. | |
| 438 | persistPreferences(); | |
| 439 | ||
| 440 | // save modified tabs | |
| 441 | for( int i = 0; i < allEditors.length; i++ ) { | |
| 442 | final FileEditorTab fileEditor = allEditors[ i ]; | |
| 443 | ||
| 444 | if( fileEditor == activeEditor ) { | |
| 445 | continue; | |
| 446 | } | |
| 447 | ||
| 448 | if( fileEditor.isModified() ) { | |
| 449 | // activate the modified tab to make its modified content visible to the user | |
| 450 | getSelectionModel().select( i ); | |
| 451 | ||
| 452 | if( !canCloseEditor( fileEditor ) ) { | |
| 453 | return false; | |
| 454 | } | |
| 455 | } | |
| 456 | } | |
| 457 | ||
| 458 | // Close all tabs. | |
| 459 | for( final FileEditorTab fileEditor : allEditors ) { | |
| 460 | if( !closeEditor( fileEditor, false ) ) { | |
| 461 | return false; | |
| 462 | } | |
| 463 | } | |
| 464 | ||
| 465 | return getTabs().isEmpty(); | |
| 466 | } | |
| 467 | ||
| 468 | private FileEditorTab[] getAllEditors() { | |
| 469 | final ObservableList<Tab> tabs = getTabs(); | |
| 470 | final int length = tabs.size(); | |
| 471 | final FileEditorTab[] allEditors = new FileEditorTab[ length ]; | |
| 472 | ||
| 473 | for( int i = 0; i < length; i++ ) { | |
| 474 | allEditors[ i ] = (FileEditorTab)tabs.get( i ); | |
| 475 | } | |
| 476 | ||
| 477 | return allEditors; | |
| 478 | } | |
| 479 | ||
| 480 | /** | |
| 481 | * Returns the file editor tab that has the given path. | |
| 482 | * | |
| 483 | * @return null No file editor tab for the given path was found. | |
| 484 | */ | |
| 485 | private FileEditorTab findEditor( final Path path ) { | |
| 486 | for( final Tab tab : getTabs() ) { | |
| 487 | final FileEditorTab fileEditor = (FileEditorTab)tab; | |
| 488 | ||
| 489 | if( fileEditor.isPath( path ) ) { | |
| 490 | return fileEditor; | |
| 491 | } | |
| 492 | } | |
| 493 | ||
| 494 | return null; | |
| 495 | } | |
| 496 | ||
| 497 | private FileChooser createFileChooser( String title ) { | |
| 498 | final FileChooser fileChooser = new FileChooser(); | |
| 499 | ||
| 500 | fileChooser.setTitle( title ); | |
| 501 | fileChooser.getExtensionFilters().addAll( | |
| 502 | createExtensionFilters() ); | |
| 503 | ||
| 504 | final String lastDirectory = getPreferences().get( "lastDirectory", null ); | |
| 505 | File file = new File( (lastDirectory != null) ? lastDirectory : "." ); | |
| 506 | ||
| 507 | if( !file.isDirectory() ) { | |
| 508 | file = new File( "." ); | |
| 509 | } | |
| 510 | ||
| 511 | fileChooser.setInitialDirectory( file ); | |
| 512 | return fileChooser; | |
| 513 | } | |
| 514 | ||
| 515 | private List<ExtensionFilter> createExtensionFilters() { | |
| 516 | final List<ExtensionFilter> list = new ArrayList<>(); | |
| 517 | ||
| 518 | // TODO: Return a list of all properties that match the filter prefix. | |
| 519 | // This will allow dynamic filters to be added and removed just by | |
| 520 | // updating the properties file. | |
| 521 | list.add( createExtensionFilter( SOURCE ) ); | |
| 522 | list.add( createExtensionFilter( DEFINITION ) ); | |
| 523 | list.add( createExtensionFilter( XML ) ); | |
| 524 | list.add( createExtensionFilter( ALL ) ); | |
| 525 | return list; | |
| 526 | } | |
| 527 | ||
| 528 | /** | |
| 529 | * Returns a filter for file name extensions recognized by the application | |
| 530 | * that can be opened by the user. | |
| 531 | * | |
| 532 | * @param filetype Used to find the globbing pattern for extensions. | |
| 533 | * | |
| 534 | * @return A filename filter suitable for use by a FileDialog instance. | |
| 535 | */ | |
| 536 | private ExtensionFilter createExtensionFilter( final FileType filetype ) { | |
| 537 | final String tKey = String.format( "%s.title.%s", FILTER_EXTENSION_TITLES, filetype ); | |
| 538 | final String eKey = String.format( "%s.%s", GLOB_PREFIX_FILE, filetype ); | |
| 539 | ||
| 540 | return new ExtensionFilter( Messages.get( tKey ), getExtensions( eKey ) ); | |
| 541 | } | |
| 542 | ||
| 543 | private List<String> getExtensions( final String key ) { | |
| 544 | return getSettings().getStringSettingList( key ); | |
| 545 | } | |
| 546 | ||
| 547 | private void saveLastDirectory( final File file ) { | |
| 548 | getPreferences().put( "lastDirectory", file.getParent() ); | |
| 549 | } | |
| 550 | ||
| 551 | public void restorePreferences() { | |
| 552 | int activeIndex = 0; | |
| 553 | ||
| 554 | final Preferences preferences = getPreferences(); | |
| 555 | final String[] fileNames = Utils.getPrefsStrings( preferences, "file" ); | |
| 556 | final String activeFileName = preferences.get( "activeFile", null ); | |
| 557 | ||
| 558 | final ArrayList<File> files = new ArrayList<>( fileNames.length ); | |
| 559 | ||
| 560 | for( final String fileName : fileNames ) { | |
| 561 | final File file = new File( fileName ); | |
| 562 | ||
| 563 | if( file.exists() ) { | |
| 564 | files.add( file ); | |
| 565 | ||
| 566 | if( fileName.equals( activeFileName ) ) { | |
| 567 | activeIndex = files.size() - 1; | |
| 568 | } | |
| 569 | } | |
| 570 | } | |
| 571 | ||
| 572 | if( files.isEmpty() ) { | |
| 573 | newEditor(); | |
| 574 | } | |
| 575 | else { | |
| 576 | openEditors( files, activeIndex ); | |
| 577 | } | |
| 578 | } | |
| 579 | ||
| 580 | public void persistPreferences() { | |
| 581 | final ObservableList<Tab> allEditors = getTabs(); | |
| 582 | final List<String> fileNames = new ArrayList<>( allEditors.size() ); | |
| 583 | ||
| 584 | for( final Tab tab : allEditors ) { | |
| 585 | final FileEditorTab fileEditor = (FileEditorTab)tab; | |
| 586 | final Path filePath = fileEditor.getPath(); | |
| 587 | ||
| 588 | if( filePath != null ) { | |
| 589 | fileNames.add( filePath.toString() ); | |
| 590 | } | |
| 591 | } | |
| 592 | ||
| 593 | final Preferences preferences = getPreferences(); | |
| 594 | Utils.putPrefsStrings( preferences, "file", fileNames.toArray( new String[ fileNames.size() ] ) ); | |
| 595 | ||
| 596 | final FileEditorTab activeEditor = getActiveFileEditor(); | |
| 597 | final Path filePath = activeEditor == null ? null : activeEditor.getPath(); | |
| 598 | ||
| 599 | if( filePath == null ) { | |
| 600 | preferences.remove( "activeFile" ); | |
| 601 | } | |
| 602 | else { | |
| 33 | ||
| 34 | import com.scrivenvar.predicates.files.FileTypePredicate; | |
| 35 | import com.scrivenvar.service.Options; | |
| 36 | import com.scrivenvar.service.Settings; | |
| 37 | import com.scrivenvar.service.events.Notification; | |
| 38 | import com.scrivenvar.service.events.Notifier; | |
| 39 | ||
| 40 | import static com.scrivenvar.service.events.Notifier.NO; | |
| 41 | import static com.scrivenvar.service.events.Notifier.YES; | |
| 42 | ||
| 43 | import com.scrivenvar.util.Utils; | |
| 44 | ||
| 45 | import java.io.File; | |
| 46 | import java.nio.file.Path; | |
| 47 | import java.util.ArrayList; | |
| 48 | import java.util.List; | |
| 49 | import java.util.function.Consumer; | |
| 50 | import java.util.prefs.Preferences; | |
| 51 | import java.util.stream.Collectors; | |
| 52 | ||
| 53 | import javafx.beans.property.ReadOnlyBooleanProperty; | |
| 54 | import javafx.beans.property.ReadOnlyBooleanWrapper; | |
| 55 | import javafx.beans.property.ReadOnlyObjectProperty; | |
| 56 | import javafx.beans.property.ReadOnlyObjectWrapper; | |
| 57 | import javafx.beans.value.ChangeListener; | |
| 58 | import javafx.beans.value.ObservableValue; | |
| 59 | import javafx.collections.ListChangeListener; | |
| 60 | import javafx.collections.ObservableList; | |
| 61 | import javafx.event.Event; | |
| 62 | import javafx.scene.Node; | |
| 63 | import javafx.scene.control.Alert; | |
| 64 | import javafx.scene.control.ButtonType; | |
| 65 | import javafx.scene.control.Tab; | |
| 66 | import javafx.scene.control.TabPane; | |
| 67 | import javafx.scene.control.TabPane.TabClosingPolicy; | |
| 68 | import javafx.scene.input.InputEvent; | |
| 69 | import javafx.stage.FileChooser; | |
| 70 | import javafx.stage.FileChooser.ExtensionFilter; | |
| 71 | import javafx.stage.Window; | |
| 72 | import org.fxmisc.richtext.StyledTextArea; | |
| 73 | import org.fxmisc.wellbehaved.event.EventPattern; | |
| 74 | import org.fxmisc.wellbehaved.event.InputMap; | |
| 75 | ||
| 76 | /** | |
| 77 | * Tab pane for file editors. | |
| 78 | * | |
| 79 | * @author Karl Tauber and White Magic Software, Ltd. | |
| 80 | */ | |
| 81 | public final class FileEditorTabPane extends TabPane { | |
| 82 | ||
| 83 | private final static String FILTER_EXTENSION_TITLES = "Dialog.file.choose.filter"; | |
| 84 | ||
| 85 | private final Options options = Services.load( Options.class ); | |
| 86 | private final Settings settings = Services.load( Settings.class ); | |
| 87 | private final Notifier notifyService = Services.load( Notifier.class ); | |
| 88 | ||
| 89 | private final ReadOnlyObjectWrapper<Path> openDefinition = new ReadOnlyObjectWrapper<>(); | |
| 90 | private final ReadOnlyObjectWrapper<FileEditorTab> activeFileEditor = new ReadOnlyObjectWrapper<>(); | |
| 91 | private final ReadOnlyBooleanWrapper anyFileEditorModified = new ReadOnlyBooleanWrapper(); | |
| 92 | ||
| 93 | /** | |
| 94 | * Constructs a new file editor tab pane. | |
| 95 | */ | |
| 96 | public FileEditorTabPane() { | |
| 97 | final ObservableList<Tab> tabs = getTabs(); | |
| 98 | ||
| 99 | setFocusTraversable( false ); | |
| 100 | setTabClosingPolicy( TabClosingPolicy.ALL_TABS ); | |
| 101 | ||
| 102 | addTabSelectionListener( | |
| 103 | ( ObservableValue<? extends Tab> tabPane, | |
| 104 | final Tab oldTab, final Tab newTab ) -> { | |
| 105 | ||
| 106 | if( newTab != null ) { | |
| 107 | activeFileEditor.set( (FileEditorTab) newTab ); | |
| 108 | } | |
| 109 | } | |
| 110 | ); | |
| 111 | ||
| 112 | final ChangeListener<Boolean> modifiedListener = ( observable, oldValue, newValue ) -> { | |
| 113 | for( final Tab tab : tabs ) { | |
| 114 | if( ((FileEditorTab) tab).isModified() ) { | |
| 115 | this.anyFileEditorModified.set( true ); | |
| 116 | break; | |
| 117 | } | |
| 118 | } | |
| 119 | }; | |
| 120 | ||
| 121 | tabs.addListener( | |
| 122 | (ListChangeListener<Tab>) change -> { | |
| 123 | while( change.next() ) { | |
| 124 | if( change.wasAdded() ) { | |
| 125 | change.getAddedSubList().stream().forEach( ( tab ) -> { | |
| 126 | ((FileEditorTab) tab).modifiedProperty().addListener( modifiedListener ); | |
| 127 | } ); | |
| 128 | } else if( change.wasRemoved() ) { | |
| 129 | change.getRemoved().stream().forEach( ( tab ) -> { | |
| 130 | ((FileEditorTab) tab).modifiedProperty().removeListener( modifiedListener ); | |
| 131 | } ); | |
| 132 | } | |
| 133 | } | |
| 134 | ||
| 135 | // Changes in the tabs may also change anyFileEditorModified property | |
| 136 | // (e.g. closed modified file) | |
| 137 | modifiedListener.changed( null, null, null ); | |
| 138 | } | |
| 139 | ); | |
| 140 | } | |
| 141 | ||
| 142 | /** | |
| 143 | * Delegates to the active file editor. | |
| 144 | * | |
| 145 | * @param <T> Event type. | |
| 146 | * @param <U> Consumer type. | |
| 147 | * @param event Event to pass to the editor. | |
| 148 | * @param consumer Consumer to pass to the editor. | |
| 149 | */ | |
| 150 | public <T extends Event, U extends T> void addEventListener( | |
| 151 | final EventPattern<? super T, ? extends U> event, | |
| 152 | final Consumer<? super U> consumer ) { | |
| 153 | getActiveFileEditor().addEventListener( event, consumer ); | |
| 154 | } | |
| 155 | ||
| 156 | /** | |
| 157 | * Delegates to the active file editor pane, and, ultimately, to its text | |
| 158 | * area. | |
| 159 | * | |
| 160 | * @param map The map of methods to events. | |
| 161 | */ | |
| 162 | public void addEventListener( final InputMap<InputEvent> map ) { | |
| 163 | getActiveFileEditor().addEventListener( map ); | |
| 164 | } | |
| 165 | ||
| 166 | /** | |
| 167 | * Remove a keyboard event listener from the active file editor. | |
| 168 | * | |
| 169 | * @param map The keyboard events to remove. | |
| 170 | */ | |
| 171 | public void removeEventListener( final InputMap<InputEvent> map ) { | |
| 172 | getActiveFileEditor().removeEventListener( map ); | |
| 173 | } | |
| 174 | ||
| 175 | /** | |
| 176 | * Allows observers to be notified when the current file editor tab changes. | |
| 177 | * | |
| 178 | * @param listener The listener to notify of tab change events. | |
| 179 | */ | |
| 180 | public void addTabSelectionListener( final ChangeListener<Tab> listener ) { | |
| 181 | // Observe the tab so that when a new tab is opened or selected, | |
| 182 | // a notification is kicked off. | |
| 183 | getSelectionModel().selectedItemProperty().addListener( listener ); | |
| 184 | } | |
| 185 | ||
| 186 | /** | |
| 187 | * Allows clients to manipulate the editor content directly. | |
| 188 | * | |
| 189 | * @return The text area for the active file editor. | |
| 190 | */ | |
| 191 | public StyledTextArea getEditor() { | |
| 192 | return getActiveFileEditor().getEditorPane().getEditor(); | |
| 193 | } | |
| 194 | ||
| 195 | /** | |
| 196 | * Returns the tab that has keyboard focus. | |
| 197 | * | |
| 198 | * @return A non-null instance. | |
| 199 | */ | |
| 200 | public FileEditorTab getActiveFileEditor() { | |
| 201 | return this.activeFileEditor.get(); | |
| 202 | } | |
| 203 | ||
| 204 | /** | |
| 205 | * Returns the property corresponding to the tab that has focus. | |
| 206 | * | |
| 207 | * @return A non-null instance. | |
| 208 | */ | |
| 209 | public ReadOnlyObjectProperty<FileEditorTab> activeFileEditorProperty() { | |
| 210 | return this.activeFileEditor.getReadOnlyProperty(); | |
| 211 | } | |
| 212 | ||
| 213 | /** | |
| 214 | * Property that can answer whether the text has been modified. | |
| 215 | * | |
| 216 | * @return A non-null instance, true meaning the content has not been saved. | |
| 217 | */ | |
| 218 | ReadOnlyBooleanProperty anyFileEditorModifiedProperty() { | |
| 219 | return this.anyFileEditorModified.getReadOnlyProperty(); | |
| 220 | } | |
| 221 | ||
| 222 | /** | |
| 223 | * Creates a new editor instance from the given path. | |
| 224 | * | |
| 225 | * @param path The file to open. | |
| 226 | * @return A non-null instance. | |
| 227 | */ | |
| 228 | private FileEditorTab createFileEditor( final Path path ) { | |
| 229 | final FileEditorTab tab = new FileEditorTab( path ); | |
| 230 | ||
| 231 | tab.setOnCloseRequest( e -> { | |
| 232 | if( !canCloseEditor( tab ) ) { | |
| 233 | e.consume(); | |
| 234 | } | |
| 235 | } ); | |
| 236 | ||
| 237 | return tab; | |
| 238 | } | |
| 239 | ||
| 240 | /** | |
| 241 | * Called when the user selects New from the File menu. | |
| 242 | * | |
| 243 | * @return The newly added tab. | |
| 244 | */ | |
| 245 | void newEditor() { | |
| 246 | final FileEditorTab tab = createFileEditor( null ); | |
| 247 | ||
| 248 | getTabs().add( tab ); | |
| 249 | getSelectionModel().select( tab ); | |
| 250 | } | |
| 251 | ||
| 252 | void openFileDialog() { | |
| 253 | final String title = get( "Dialog.file.choose.open.title" ); | |
| 254 | final FileChooser dialog = createFileChooser( title ); | |
| 255 | final List<File> files = dialog.showOpenMultipleDialog( getWindow() ); | |
| 256 | ||
| 257 | if( files != null ) { | |
| 258 | openFiles( files ); | |
| 259 | } | |
| 260 | } | |
| 261 | ||
| 262 | /** | |
| 263 | * Opens the files into new editors, unless one of those files was a | |
| 264 | * definition file. The definition file is loaded into the definition pane, | |
| 265 | * but only the first one selected (multiple definition files will result in a | |
| 266 | * warning). | |
| 267 | * | |
| 268 | * @param files The list of non-definition files that the were requested to | |
| 269 | * open. | |
| 270 | * @return A list of files that can be opened in text editors. | |
| 271 | */ | |
| 272 | private void openFiles( final List<File> files ) { | |
| 273 | final FileTypePredicate predicate | |
| 274 | = new FileTypePredicate( createExtensionFilter( DEFINITION ).getExtensions() ); | |
| 275 | ||
| 276 | // The user might have opened multiple definitions files. These will | |
| 277 | // be discarded from the text editable files. | |
| 278 | final List<File> definitions | |
| 279 | = files.stream().filter( predicate ).collect( Collectors.toList() ); | |
| 280 | ||
| 281 | // Create a modifiable list to remove any definition files that were | |
| 282 | // opened. | |
| 283 | final List<File> editors = new ArrayList<>( files ); | |
| 284 | ||
| 285 | if( editors.size() > 0 ) { | |
| 286 | saveLastDirectory( editors.get( 0 ) ); | |
| 287 | } | |
| 288 | ||
| 289 | editors.removeAll( definitions ); | |
| 290 | ||
| 291 | // Open editor-friendly files (e.g,. Markdown, XML) in new tabs. | |
| 292 | if( editors.size() > 0 ) { | |
| 293 | openEditors( editors, 0 ); | |
| 294 | } | |
| 295 | ||
| 296 | if( definitions.size() > 0 ) { | |
| 297 | openDefinition( definitions.get( 0 ) ); | |
| 298 | } | |
| 299 | } | |
| 300 | ||
| 301 | private void openEditors( final List<File> files, final int activeIndex ) { | |
| 302 | final int fileTally = files.size(); | |
| 303 | final List<Tab> tabs = getTabs(); | |
| 304 | ||
| 305 | // Close single unmodified "Untitled" tab. | |
| 306 | if( tabs.size() == 1 ) { | |
| 307 | final FileEditorTab fileEditor = (FileEditorTab) (tabs.get( 0 )); | |
| 308 | ||
| 309 | if( fileEditor.getPath() == null && !fileEditor.isModified() ) { | |
| 310 | closeEditor( fileEditor, false ); | |
| 311 | } | |
| 312 | } | |
| 313 | ||
| 314 | for( int i = 0; i < fileTally; i++ ) { | |
| 315 | final Path path = files.get( i ).toPath(); | |
| 316 | ||
| 317 | FileEditorTab fileEditorTab = findEditor( path ); | |
| 318 | ||
| 319 | // Only open new files. | |
| 320 | if( fileEditorTab == null ) { | |
| 321 | fileEditorTab = createFileEditor( path ); | |
| 322 | getTabs().add( fileEditorTab ); | |
| 323 | } | |
| 324 | ||
| 325 | // Select the first file in the list. | |
| 326 | if( i == activeIndex ) { | |
| 327 | getSelectionModel().select( fileEditorTab ); | |
| 328 | } | |
| 329 | } | |
| 330 | } | |
| 331 | ||
| 332 | /** | |
| 333 | * Returns a property that changes when a new definition file is opened. | |
| 334 | * | |
| 335 | * @return The path to a definition file that was opened. | |
| 336 | */ | |
| 337 | public ReadOnlyObjectProperty<Path> onOpenDefinitionFileProperty() { | |
| 338 | return getOnOpenDefinitionFile().getReadOnlyProperty(); | |
| 339 | } | |
| 340 | ||
| 341 | private ReadOnlyObjectWrapper<Path> getOnOpenDefinitionFile() { | |
| 342 | return this.openDefinition; | |
| 343 | } | |
| 344 | ||
| 345 | /** | |
| 346 | * Called when the user has opened a definition file (using the file open | |
| 347 | * dialog box). This will replace the current set of definitions for the | |
| 348 | * active tab. | |
| 349 | * | |
| 350 | * @param definition The file to open. | |
| 351 | */ | |
| 352 | private void openDefinition( final File definition ) { | |
| 353 | // TODO: Prevent reading this file twice when a new text document is opened. | |
| 354 | // (might be a matter of checking the value first). | |
| 355 | getOnOpenDefinitionFile().set( definition.toPath() ); | |
| 356 | } | |
| 357 | ||
| 358 | /** | |
| 359 | * Called when the contents of the editor are to be saved. | |
| 360 | * | |
| 361 | * @param tab The tab containing content to save. | |
| 362 | * @return true The contents were saved (or needn't be saved). | |
| 363 | */ | |
| 364 | public boolean saveEditor( final FileEditorTab tab ) { | |
| 365 | if( tab == null || !tab.isModified() ) { | |
| 366 | return true; | |
| 367 | } | |
| 368 | ||
| 369 | return tab.getPath() == null ? saveEditorAs( tab ) : tab.save(); | |
| 370 | } | |
| 371 | ||
| 372 | /** | |
| 373 | * Opens the Save As dialog for the user to save the content under a new | |
| 374 | * path. | |
| 375 | * | |
| 376 | * @param tab The tab with contents to save. | |
| 377 | * @return true The contents were saved, or the tab was null. | |
| 378 | */ | |
| 379 | public boolean saveEditorAs( final FileEditorTab tab ) { | |
| 380 | if( tab == null ) { | |
| 381 | return true; | |
| 382 | } | |
| 383 | ||
| 384 | getSelectionModel().select( tab ); | |
| 385 | ||
| 386 | final FileChooser fileChooser = createFileChooser( get( "Dialog.file.choose.save.title" ) ); | |
| 387 | final File file = fileChooser.showSaveDialog( getWindow() ); | |
| 388 | if( file == null ) { | |
| 389 | return false; | |
| 390 | } | |
| 391 | ||
| 392 | saveLastDirectory( file ); | |
| 393 | tab.setPath( file.toPath() ); | |
| 394 | ||
| 395 | return tab.save(); | |
| 396 | } | |
| 397 | ||
| 398 | boolean saveAllEditors() { | |
| 399 | boolean success = true; | |
| 400 | ||
| 401 | for( FileEditorTab fileEditor : getAllEditors() ) { | |
| 402 | if( !saveEditor( fileEditor ) ) { | |
| 403 | success = false; | |
| 404 | } | |
| 405 | } | |
| 406 | ||
| 407 | return success; | |
| 408 | } | |
| 409 | ||
| 410 | /** | |
| 411 | * Answers whether the file has had modifications. ' | |
| 412 | * | |
| 413 | * @param tab THe tab to check for modifications. | |
| 414 | * @return false The file is unmodified. | |
| 415 | */ | |
| 416 | boolean canCloseEditor( final FileEditorTab tab ) { | |
| 417 | if( !tab.isModified() ) { | |
| 418 | return true; | |
| 419 | } | |
| 420 | ||
| 421 | final Notification message = getNotifyService().createNotification( | |
| 422 | Messages.get( "Alert.file.close.title" ), | |
| 423 | Messages.get( "Alert.file.close.text" ), | |
| 424 | tab.getText() | |
| 425 | ); | |
| 426 | ||
| 427 | final Alert alert = getNotifyService().createConfirmation( | |
| 428 | getWindow(), message ); | |
| 429 | final ButtonType response = alert.showAndWait().get(); | |
| 430 | ||
| 431 | return response == YES ? saveEditor( tab ) : response == NO; | |
| 432 | } | |
| 433 | ||
| 434 | private Notifier getNotifyService() { | |
| 435 | return this.notifyService; | |
| 436 | } | |
| 437 | ||
| 438 | boolean closeEditor( FileEditorTab fileEditor, boolean save ) { | |
| 439 | if( fileEditor == null ) { | |
| 440 | return true; | |
| 441 | } | |
| 442 | ||
| 443 | final Tab tab = fileEditor; | |
| 444 | ||
| 445 | if( save ) { | |
| 446 | Event event = new Event( tab, tab, Tab.TAB_CLOSE_REQUEST_EVENT ); | |
| 447 | Event.fireEvent( tab, event ); | |
| 448 | ||
| 449 | if( event.isConsumed() ) { | |
| 450 | return false; | |
| 451 | } | |
| 452 | } | |
| 453 | ||
| 454 | getTabs().remove( tab ); | |
| 455 | ||
| 456 | if( tab.getOnClosed() != null ) { | |
| 457 | Event.fireEvent( tab, new Event( Tab.CLOSED_EVENT ) ); | |
| 458 | } | |
| 459 | ||
| 460 | return true; | |
| 461 | } | |
| 462 | ||
| 463 | boolean closeAllEditors() { | |
| 464 | final FileEditorTab[] allEditors = getAllEditors(); | |
| 465 | final FileEditorTab activeEditor = getActiveFileEditor(); | |
| 466 | ||
| 467 | // try to save active tab first because in case the user decides to cancel, | |
| 468 | // then it stays active | |
| 469 | if( activeEditor != null && !canCloseEditor( activeEditor ) ) { | |
| 470 | return false; | |
| 471 | } | |
| 472 | ||
| 473 | // This should be called any time a tab changes. | |
| 474 | persistPreferences(); | |
| 475 | ||
| 476 | // save modified tabs | |
| 477 | for( int i = 0; i < allEditors.length; i++ ) { | |
| 478 | final FileEditorTab fileEditor = allEditors[ i ]; | |
| 479 | ||
| 480 | if( fileEditor == activeEditor ) { | |
| 481 | continue; | |
| 482 | } | |
| 483 | ||
| 484 | if( fileEditor.isModified() ) { | |
| 485 | // activate the modified tab to make its modified content visible to the user | |
| 486 | getSelectionModel().select( i ); | |
| 487 | ||
| 488 | if( !canCloseEditor( fileEditor ) ) { | |
| 489 | return false; | |
| 490 | } | |
| 491 | } | |
| 492 | } | |
| 493 | ||
| 494 | // Close all tabs. | |
| 495 | for( final FileEditorTab fileEditor : allEditors ) { | |
| 496 | if( !closeEditor( fileEditor, false ) ) { | |
| 497 | return false; | |
| 498 | } | |
| 499 | } | |
| 500 | ||
| 501 | return getTabs().isEmpty(); | |
| 502 | } | |
| 503 | ||
| 504 | private FileEditorTab[] getAllEditors() { | |
| 505 | final ObservableList<Tab> tabs = getTabs(); | |
| 506 | final int length = tabs.size(); | |
| 507 | final FileEditorTab[] allEditors = new FileEditorTab[ length ]; | |
| 508 | ||
| 509 | for( int i = 0; i < length; i++ ) { | |
| 510 | allEditors[ i ] = (FileEditorTab) tabs.get( i ); | |
| 511 | } | |
| 512 | ||
| 513 | return allEditors; | |
| 514 | } | |
| 515 | ||
| 516 | /** | |
| 517 | * Returns the file editor tab that has the given path. | |
| 518 | * | |
| 519 | * @return null No file editor tab for the given path was found. | |
| 520 | */ | |
| 521 | private FileEditorTab findEditor( final Path path ) { | |
| 522 | for( final Tab tab : getTabs() ) { | |
| 523 | final FileEditorTab fileEditor = (FileEditorTab) tab; | |
| 524 | ||
| 525 | if( fileEditor.isPath( path ) ) { | |
| 526 | return fileEditor; | |
| 527 | } | |
| 528 | } | |
| 529 | ||
| 530 | return null; | |
| 531 | } | |
| 532 | ||
| 533 | private FileChooser createFileChooser( String title ) { | |
| 534 | final FileChooser fileChooser = new FileChooser(); | |
| 535 | ||
| 536 | fileChooser.setTitle( title ); | |
| 537 | fileChooser.getExtensionFilters().addAll( | |
| 538 | createExtensionFilters() ); | |
| 539 | ||
| 540 | final String lastDirectory = getPreferences().get( "lastDirectory", null ); | |
| 541 | File file = new File( (lastDirectory != null) ? lastDirectory : "." ); | |
| 542 | ||
| 543 | if( !file.isDirectory() ) { | |
| 544 | file = new File( "." ); | |
| 545 | } | |
| 546 | ||
| 547 | fileChooser.setInitialDirectory( file ); | |
| 548 | return fileChooser; | |
| 549 | } | |
| 550 | ||
| 551 | private List<ExtensionFilter> createExtensionFilters() { | |
| 552 | final List<ExtensionFilter> list = new ArrayList<>(); | |
| 553 | ||
| 554 | // TODO: Return a list of all properties that match the filter prefix. | |
| 555 | // This will allow dynamic filters to be added and removed just by | |
| 556 | // updating the properties file. | |
| 557 | list.add( createExtensionFilter( SOURCE ) ); | |
| 558 | list.add( createExtensionFilter( DEFINITION ) ); | |
| 559 | list.add( createExtensionFilter( XML ) ); | |
| 560 | list.add( createExtensionFilter( ALL ) ); | |
| 561 | return list; | |
| 562 | } | |
| 563 | ||
| 564 | /** | |
| 565 | * Returns a filter for file name extensions recognized by the application | |
| 566 | * that can be opened by the user. | |
| 567 | * | |
| 568 | * @param filetype Used to find the globbing pattern for extensions. | |
| 569 | * @return A filename filter suitable for use by a FileDialog instance. | |
| 570 | */ | |
| 571 | private ExtensionFilter createExtensionFilter( final FileType filetype ) { | |
| 572 | final String tKey = String.format( "%s.title.%s", FILTER_EXTENSION_TITLES, filetype ); | |
| 573 | final String eKey = String.format( "%s.%s", GLOB_PREFIX_FILE, filetype ); | |
| 574 | ||
| 575 | return new ExtensionFilter( Messages.get( tKey ), getExtensions( eKey ) ); | |
| 576 | } | |
| 577 | ||
| 578 | private List<String> getExtensions( final String key ) { | |
| 579 | return getSettings().getStringSettingList( key ); | |
| 580 | } | |
| 581 | ||
| 582 | private void saveLastDirectory( final File file ) { | |
| 583 | getPreferences().put( "lastDirectory", file.getParent() ); | |
| 584 | } | |
| 585 | ||
| 586 | public void restorePreferences() { | |
| 587 | int activeIndex = 0; | |
| 588 | ||
| 589 | final Preferences preferences = getPreferences(); | |
| 590 | final String[] fileNames = Utils.getPrefsStrings( preferences, "file" ); | |
| 591 | final String activeFileName = preferences.get( "activeFile", null ); | |
| 592 | ||
| 593 | final ArrayList<File> files = new ArrayList<>( fileNames.length ); | |
| 594 | ||
| 595 | for( final String fileName : fileNames ) { | |
| 596 | final File file = new File( fileName ); | |
| 597 | ||
| 598 | if( file.exists() ) { | |
| 599 | files.add( file ); | |
| 600 | ||
| 601 | if( fileName.equals( activeFileName ) ) { | |
| 602 | activeIndex = files.size() - 1; | |
| 603 | } | |
| 604 | } | |
| 605 | } | |
| 606 | ||
| 607 | if( files.isEmpty() ) { | |
| 608 | newEditor(); | |
| 609 | } else { | |
| 610 | openEditors( files, activeIndex ); | |
| 611 | } | |
| 612 | } | |
| 613 | ||
| 614 | public void persistPreferences() { | |
| 615 | final ObservableList<Tab> allEditors = getTabs(); | |
| 616 | final List<String> fileNames = new ArrayList<>( allEditors.size() ); | |
| 617 | ||
| 618 | for( final Tab tab : allEditors ) { | |
| 619 | final FileEditorTab fileEditor = (FileEditorTab) tab; | |
| 620 | final Path filePath = fileEditor.getPath(); | |
| 621 | ||
| 622 | if( filePath != null ) { | |
| 623 | fileNames.add( filePath.toString() ); | |
| 624 | } | |
| 625 | } | |
| 626 | ||
| 627 | final Preferences preferences = getPreferences(); | |
| 628 | Utils.putPrefsStrings( preferences, "file", fileNames.toArray( new String[ fileNames.size() ] ) ); | |
| 629 | ||
| 630 | final FileEditorTab activeEditor = getActiveFileEditor(); | |
| 631 | final Path filePath = activeEditor == null ? null : activeEditor.getPath(); | |
| 632 | ||
| 633 | if( filePath == null ) { | |
| 634 | preferences.remove( "activeFile" ); | |
| 635 | } else { | |
| 603 | 636 | preferences.put( "activeFile", filePath.toString() ); |
| 604 | 637 | } |
| 51 | 51 | private final String type; |
| 52 | 52 | |
| 53 | /** | |
| 54 | * Default constructor for enumerated file type. | |
| 55 | * | |
| 56 | * @param type Human-readable name for the file type. | |
| 57 | */ | |
| 53 | 58 | private FileType( final String type ) { |
| 54 | 59 | this.type = type; |
| ... | ||
| 86 | 91 | } |
| 87 | 92 | |
| 93 | /** | |
| 94 | * Returns the human-readable name for the file type. | |
| 95 | * | |
| 96 | * @return A non-null instance. | |
| 97 | */ | |
| 88 | 98 | private String getType() { |
| 89 | 99 | return this.type; |
| 131 | 131 | } |
| 132 | 132 | |
| 133 | /** | |
| 134 | * Watch for file system changes. | |
| 135 | */ | |
| 133 | 136 | private void initSnitch() { |
| 134 | 137 | setSnitchThread( new Thread( getSnitch() ) ); |
| 137 | 137 | public void initKeyboardEventListeners( final FileEditorTab tab ) { |
| 138 | 138 | setFileEditorTab( tab ); |
| 139 | initKeyboardEventListeners();; | |
| 139 | initKeyboardEventListeners(); | |
| 140 | 140 | } |
| 141 | 141 |
| 50 | 50 | * @param t The string to return, enclosed in "pre" tags. |
| 51 | 51 | * |
| 52 | * @return t | |
| 52 | * @return The value of t wrapped in "pre" tags. | |
| 53 | 53 | */ |
| 54 | 54 | @Override |
| 77 | 77 | |
| 78 | 78 | /** |
| 79 | * Initialises the R code so that R can find imported libraries. | |
| 79 | 80 | * |
| 80 | * @param workingDirectory | |
| 81 | * @param workingDirectory Location where R is to look for imports. | |
| 81 | 82 | */ |
| 82 | 83 | private void init( final Path workingDirectory ) { |
| ... | ||
| 98 | 99 | } |
| 99 | 100 | |
| 101 | /** | |
| 102 | * Loads the R init script from the applciation's persisted preferences. | |
| 103 | * | |
| 104 | * @return A non-null String, possibly empty. | |
| 105 | * @throws IOException Could not load the init script. | |
| 106 | */ | |
| 100 | 107 | private String getInitScript() throws IOException { |
| 101 | 108 | return getOptions().get( PERSIST_R_STARTUP, "" ); |
| 102 | 109 | } |
| 103 | 110 | |
| 111 | /** | |
| 112 | * Evaluates all R statements in the source document and inserts the | |
| 113 | * calculated value into the generated document. | |
| 114 | * | |
| 115 | * @param text The document text that includes variables that should be | |
| 116 | * replaced with values when rendered as HTML. | |
| 117 | * | |
| 118 | * @return The generated document with output from all R statements | |
| 119 | * substituted with value returned from their execution. | |
| 120 | */ | |
| 104 | 121 | @Override |
| 105 | 122 | public String processLink( final String text ) { |
| 32 | 32 | |
| 33 | 33 | /** |
| 34 | * Responsible for persistent options. | |
| 34 | * Responsible for persisting options. | |
| 35 | 35 | * |
| 36 | 36 | * @author White Magic Software, Ltd. |
| 93 | 93 | public List<String> getStringSettingList( String property ); |
| 94 | 94 | |
| 95 | ||
| 96 | 95 | /** |
| 97 | 96 | * Changes key's value. This will clear the old value before setting the |