Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/keenwrite.git
A .idea/codeStyles/codeStyleConfig.xml
1
1
<component name="ProjectCodeStyleConfiguration">
2
  <state>
3
    <option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
4
  </state>
5
</component>
A .idea/gradle.xml
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>
A .idea/misc.xml
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>
A .idea/vcs.xml
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>
A .idea/workspace.xml
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&#9;" />
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>
A BUILD.md
1
Build
2
===
3
4
Once the [requirements](README.md) are met, build the application as follows:
5
6
    gradle build
7
18
D LICENSE
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.
251
A LICENSE.md
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.
127
M R/pluralise.R
4040
  if( n != 1 ) {
4141
    if( pl.noninflective( s ) ||
42
				pl.suffix( "es", s ) ||
42
        pl.suffix( "es", s ) ||
4343
        pl.suffix( "fish", s ) ||
4444
        pl.suffix( "ois", s ) ||
...
134134
pl.noninflective <- function( s ) {
135135
  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"
188188
  )
189189
M README.md
88
Requirements
99
---
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/)
1114
1215
Quick Start
...
3942
License
4043
---
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).
4245
M build.gradle
55
repositories {
66
  jcenter()
7
  mavenCentral()
78
  
89
  maven {
...
2021
  compile 'org.fxmisc.richtext:richtextfx:0.8.1'
2122
  compile 'com.miglayout:miglayout-javafx:5.0'
22
  compile 'de.jensd:fontawesomefx-fontawesome:4.5.0'
2323
  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'
2828
  compile 'com.fasterxml.jackson.core:jackson-core:2.9.3'
2929
  compile 'com.fasterxml.jackson.core:jackson-databind:2.9.3'
3030
  compile 'com.fasterxml.jackson.core:jackson-annotations:2.9.3'
3131
  compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.9.3'
3232
  compile 'org.yaml:snakeyaml:1.19'
3333
  compile 'com.ximpleware:vtd-xml:2.13.4'
3434
  compile 'net.sf.saxon:Saxon-HE:9.8.0-7'
3535
  compile 'com.googlecode.juniversalchardet:juniversalchardet:1.0.3'
3636
  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')
3840
}
3941
40
version = '1.3.4'
42
version = '1.3.8'
4143
applicationName = 'scrivenvar'
4244
mainClassName = 'com.scrivenvar.Main'
...
6870
    baseName = applicationName
6971
    contents {
70
      from { ['LICENSE', 'README.md'] }
72
      from { ['LICENSE.md', 'README.md'] }
7173
      into( 'images' ) {
7274
        from { 'images' }
D executable.txt
11
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
M gradle.properties
1
org.gradle.jvmargs=-Xmx1G -XX:MaxPermSize=512m
2
13
A libs/fontawesomefx-commons-8.12.jar
Binary file
A libs/fontawesomefx-fontawesome-4.5.0.jar
Binary file
D libs/renjin-script-engine-0.8.2562-jar-with-dependencies.jar
Binary file
A libs/renjin-script-engine-0.9.2726-jar-with-dependencies.jar
Binary file
D licenses/MARKDOWN-WRITER-FX
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.
251
A licenses/MARKDOWN-WRITER-FX.md
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.
125
M src/main/java/com/scrivenvar/AbstractFileFactory.java
118118
   * Return the singleton Settings instance.
119119
   *
120
   * @return The settings for
120
   * @return A non-null instance.
121121
   */
122122
  private Settings getSettings() {
M src/main/java/com/scrivenvar/AbstractPane.java
2929
3030
import com.scrivenvar.service.Options;
31
3132
import java.util.prefs.Preferences;
33
3234
import org.tbee.javafx.scene.layout.fxml.MigPane;
3335
3436
/**
3537
 * Provides options to all subclasses.
3638
 *
3739
 * @author White Magic Software, Ltd.
3840
 */
3941
public abstract class AbstractPane extends MigPane {
4042
43
  /**
44
   * The options loaded from the service.
45
   */
4146
  private final Options options = Services.load( Options.class );
4247
48
  /**
49
   * Returns the persistent options for user settings.
50
   *
51
   * @return A non-null instance.
52
   */
4353
  protected Options getOptions() {
4454
    return this.options;
4555
  }
46
  
56
57
  /**
58
   * Returns a hierarchical set of preferences.
59
   *
60
   * @return A non-null instance.
61
   */
4762
  protected Preferences getState() {
4863
    return getOptions().getState();
M src/main/java/com/scrivenvar/Constants.java
2929
3030
import com.scrivenvar.service.Settings;
31
3132
import java.util.Collection;
3233
3334
/**
35
 * Defines application-wide default values.
36
 *
3437
 * @author White Magic Software, Ltd.
3538
 */
...
6164
  public static final String APP_TITLE = get( "application.title" );
6265
  public static final String APP_BUNDLE_NAME = get( "application.messages" );
66
6367
  // Prevent double events when updating files on Linux (save and timestamp).
6468
  public static final int APP_WATCHDOG_TIMEOUT = get( "application.watchdog.timeout", 100 );
...
97101
  // Takes two parameters: line number and column number.
98102
  public static final String STATUS_BAR_LINE = "Main.statusbar.line";
103
99104
  // "OK" text
100105
  public static final String STATUS_BAR_DEFAULT = get( "Main.statusbar.state.default" );
101106
  public static final String STATUS_PARSE_ERROR = "Main.statusbar.parse.error";
102107
103
  // Persistent storage settings.
104
  
105108
  /**
106109
   * Location of the definition source file.
107110
   */
108111
  public static final String PERSIST_DEFINITION_SOURCE = "definitionSource";
109
  
110
  
112
111113
  /**
112114
   * Content of the R startup script.
M src/main/java/com/scrivenvar/FileEditorTab.java
6868
public final class FileEditorTab extends Tab {
6969
70
  /**
71
   * 
72
   */
7073
  private final Notifier alertService = Services.load( Notifier.class );
7174
  private EditorPane editorPane;
M src/main/java/com/scrivenvar/FileEditorTabPane.java
3131
import static com.scrivenvar.FileType.*;
3232
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 {
603636
      preferences.put( "activeFile", filePath.toString() );
604637
    }
M src/main/java/com/scrivenvar/FileType.java
5151
  private final String type;
5252
53
  /**
54
   * Default constructor for enumerated file type.
55
   *
56
   * @param type Human-readable name for the file type.
57
   */
5358
  private FileType( final String type ) {
5459
    this.type = type;
...
8691
  }
8792
93
  /**
94
   * Returns the human-readable name for the file type.
95
   *
96
   * @return A non-null instance.
97
   */
8898
  private String getType() {
8999
    return this.type;
M src/main/java/com/scrivenvar/Main.java
131131
  }
132132
133
  /**
134
   * Watch for file system changes.
135
   */
133136
  private void initSnitch() {
134137
    setSnitchThread( new Thread( getSnitch() ) );
M src/main/java/com/scrivenvar/editors/VariableNameInjector.java
137137
  public void initKeyboardEventListeners( final FileEditorTab tab ) {
138138
    setFileEditorTab( tab );
139
    initKeyboardEventListeners();;
139
    initKeyboardEventListeners();
140140
  }
141141
M src/main/java/com/scrivenvar/processors/IdentityProcessor.java
5050
   * @param t The string to return, enclosed in "pre" tags.
5151
   *
52
   * @return t
52
   * @return The value of t wrapped in "pre" tags.
5353
   */
5454
  @Override
M src/main/java/com/scrivenvar/processors/InlineRProcessor.java
7777
7878
  /**
79
   * Initialises the R code so that R can find imported libraries.
7980
   *
80
   * @param workingDirectory
81
   * @param workingDirectory Location where R is to look for imports.
8182
   */
8283
  private void init( final Path workingDirectory ) {
...
9899
  }
99100
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
   */
100107
  private String getInitScript() throws IOException {
101108
    return getOptions().get( PERSIST_R_STARTUP, "" );
102109
  }
103110
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
   */
104121
  @Override
105122
  public String processLink( final String text ) {
M src/main/java/com/scrivenvar/service/Options.java
3232
3333
/**
34
 * Responsible for persistent options.
34
 * Responsible for persisting options.
3535
 *
3636
 * @author White Magic Software, Ltd.
M src/main/java/com/scrivenvar/service/Settings.java
9393
  public List<String> getStringSettingList( String property );
9494
95
9695
  /**
9796
   * Changes key's value. This will clear the old value before setting the